Runs on Deno Deploy using its KV store. Pings indexnow, ping-o-matic and webSub for new items in rss feeds from listed sites.
This guide walks you through setting up and deploying a Deno Deploy script for multi-site IndexNow, Ping-O-Matic and webSub submission.
This script uses Environment Variables for storing configuration of API keys and site details, and Deno KV (Key-Value Store) for persistent storage of SITE_CONFIG
and lastCheckedTime
for each feed. It handles multiple feeds, checks for new and updated posts, and pings IndexNow, Ping-O-Matic and webSub.
-
Deno Deploy Project Environment Variables: Store the following in the env vars for your project:
- ADMIN_USERNAME, ADMIN_PASSWORD - credentials to log into the /admin screen
- INDEXNOW_API_ESOLIABLOG_1 etc - the indexnow api key (add as many as needed, and enter their names in the SITE_CONFIG array in /admin as needed)
-
Deno KV (Key-Value Store):
Deno.openKv()
is used to get a connection to Deno Deploy's built-in, persistent key-value store.getLastChecked
andsetLastChecked
functions use KV to store the timestamp of the last successful check for each individual feed ID. This ensures that if the script runs again, it only processes posts published/updated since the last time that specific feed was checked.- Each object in the
SITE_CONFIG
array represents a single feed you want to monitor.id
: A unique identifier for the feed (e.g., "myblog-en", "news-ja"). Used for Deno KV storage.host
: The domain of the site for IndexNow.feedUrl
: The URL of the JSON feed.indexNowKeyEnv
: The name of the environment variable where the IndexNow API key for this site is stored (e.g.,"INDEXNOW_API_KEY_YOURSITE1"
). This allows you to have different IndexNow keys if needed, or share one across feeds for the same domain.pingOMatic
: An object containing details for Ping-O-Matic.title
: The title of your blog/site.blogUrl
: The main URL of your blog/site.rssUrl
: The URL of your RSS feed.
-
isPostNewOrUpdated
Function:- This function checks for both
date_published
(or similar) anddate_modified
(orupdated_at
). - It compares the post's date against the
lastCheckedTime
retrieved from Deno KV. - Adjust the
publishedDate
andupdatedDate
lines within this function to accurately parse dates from your specific JSON feed formats. Look for fields likedate_published
,published
,date
,modified
,updated_at
, etc.
- This function checks for both
-
pingPingOMatic
Function:- Takes the
siteConfig
object directly to accesstitle
,blogUrl
, andrssUrl
. - Constructs the Ping-O-Matic URL with
encodeURIComponent
for safety. - Pings Ping-O-Matic with a
GET
request.
- Takes the
-
Main Execution Flow:
- The
addEventListener("fetch", ...)
block is the entry point for Deno Deploy. - It fetches the
SITE_CONFIG
environment variable, parses it as JSON. - It then iterates through each configured site/feed and calls
processFeed
for each.Promise.all
allows them to run concurrently, speeding things up.
- The
-
Create a Deno Deploy Project: log into your Deno Deploy account, create a project and link it to github. Select
main.ts
as the entrypoint. -
Confirm
main.ts
: inspect the feeds you'll monitor, then update themain.ts
file, updating theisPostNewOrUpdated
function to correctly extract the dates in your actual feeds. The script covers a lot of what you'll typically find but you never know. -
Set Environment Variables in Deno Deploy Project Settings: admin screen basic auth credentials as mentioned above, and as many indexnow keys as needed for what you'll store in
SITE_CONFIG
. -
Run Admin Screen and Add SITE_CONFIG: check your Deno Deploy project's URL, access it with
/admin
, fill the array of objects and save. See the samples in the root of this project. Make the indexnow variable names match what you stored in your env vars. -
Redeploy: Once environment variables are set, Deno Deploy should automatically trigger a redeployment. If not, manually redeploy your project.
-
Set Up Cron Job: the
main.ts
callscron.ts
, which contains a cron definition. Edit as needed, being aware that your account could be flagged for abuse if you cause it to run too often. If you're posting once or twice a week, then a once-daily cron run is more than enough.
Now you can manage your site pings from Deno Deploy!
The main.ts
is written in TypeScript. The core difference between JavaScript (.js
) and TypeScript (.ts
) is type checking. TypeScript allows you to explicitly define the types of your variables, function parameters, and return values. This helps catch errors before you even run your code, leading to more robust and maintainable applications. Deno natively supports TypeScript, so it's a seamless experience.
-
File Extension:
- Main executable is
main.ts
. This tells Deno (and your code editor) to treat the file as a TypeScript file and apply type checking.
- Main executable is
-
Type Definitions (Interfaces):
PingOMaticConfig
: Defines the expected shape of thepingOMatic
object.SiteConfig
: Defines the structure for each site's configuration. NoticepingOMatic?: PingOMaticConfig;
– the?
makespingOMatic
an optional property, meaning aSiteConfig
object might or might not have it. This is good for flexibility if some sites don't use Ping-O-Matic.Post
: Defines the expected properties for an individual post item in your JSON feed. I've added optional?
forurl
,date_published
, etc., because your code already handles their potential absence.[key: string]: unknown;
is a way to tell TypeScript that this object might have other properties whose types you don't explicitly know or need to check.JsonFeed
: Defines the overall structure of your JSON feed.- Why? Interfaces are the cornerstone of TypeScript. They allow you to describe the "contract" for your data shapes. This helps TypeScript understand what properties are available on an object and their types, preventing typos (e.g.,
post.urlz
would be caught) and making the code more readable.
-
Type Annotations (
: Type
):- You'll see
: string
,: number
,: Date | null
,: Promise<void>
,: SiteConfig[]
, etc., added after variable declarations and function parameters. const TWENTY_FOUR_HOURS_IN_MS: number = ...
: Explicitly statesTWENTY_FOUR_HOURS_IN_MS
is a number.url: string
: Theurl
parameter offetchJsonFeed
must be a string.: Promise<JsonFeed | null>
: ThefetchJsonFeed
function promises to return either aJsonFeed
object ornull
.error: unknown
: When catching errors intry...catch
blocks, TypeScript defaults tounknown
because an error can be of any type.event: FetchEvent
: In theaddEventListener("fetch", ...)
callback, theevent
object is specifically aFetchEvent
in Deno Deploy's context.- Why? These annotations tell TypeScript the expected type. If you try to pass a number to a function expecting a string, or assign a string to a variable meant for a number, TypeScript will flag it as an error before runtime. This is invaluable for preventing bugs.
- You'll see
-
Type Assertions (
as Type
):return (await response.json()) as JsonFeed;
infetchJsonFeed
.const publishedDate: Date = new Date((post.date_published || post.published || post.date) as string);
- Why? Sometimes, TypeScript's inference isn't enough, or you know more about the type than TypeScript can automatically deduce.
response.json()
returnsPromise<any>
, but you know it will be aJsonFeed
.new Date()
expects astring
(among other types), and whilepost.date_published
etc. might beundefined
, the||
operator ensures that if a value is present, it will be a string. Theas string
tells TypeScript, "Trust me, if there's a value here, it's a string."
-
Handling
undefined
andnull
:- TypeScript's strict null checks are often enabled by default (especially in Deno). This means variables can't be
null
orundefined
unless explicitly declared (e.g.,Date | null
). - You'll see more explicit checks like
if (!siteConfig.pingOMatic)
to handle optional properties gracefully, which is a good practice anyway.
- TypeScript's strict null checks are often enabled by default (especially in Deno). This means variables can't be
- Early Bug Detection: Catch typos, type mismatches, and common programming errors during development, not at runtime.
- Improved Readability: Type annotations act as documentation, making it easier for you and others to understand what data a function expects and returns.
- Better Tooling: Code editors (like VS Code) use TypeScript to provide much richer autocompletion, refactoring tools, and inline error checking.
- Easier Refactoring: When you change a type or property name, TypeScript helps you find all places in your codebase that need updating.
- Scalability: For larger projects, TypeScript helps manage complexity by enforcing structure and consistency.