/*
RFC-0179: deterministic placement of a site on the shared, sharded delivery backbone.
resolveShard maps a stable siteId + region + tier onto a concrete queue / DLQ / dedup-namespace
set, so the shared queues replace RFC-0176's per-client queue without a central registry — the
mapping is recomputable from content alone. Pure: no I/O, no platform bindings.
- Do not create or call Cloudflare resources — this is a pure naming/placement function.
- Do not read system.md or any file — callers pass region/tier explicitly.
- RFC-0179: initial implementation.
- RFC-0181: the Cloudflare-queue naming here is SUPERSEDED for the EU delivery path (Upstash QStash/Redis, see qstash.ts). Retained for the deferred WfP/CF-hosted topology; not used for EU lead delivery.
*/
/** Closed catalog of delivery jurisdictions (RFC-0179). Drives residency sharding. */
export const DELIVERY_REGIONS = ["eu", "us"] as const;
export type DeliveryRegion = (typeof DELIVERY_REGIONS)[number];
/** Execution tier on the shared backbone (RFC-0179). */
export const DELIVERY_TIERS = ["shared", "dedicated"] as const;
export type DeliveryTier = (typeof DELIVERY_TIERS)[number];
/** Resolved placement of a site on the shared delivery backbone (RFC-0179). */
export interface ShardAssignment {
siteId: string;
region: DeliveryRegion;
tier: DeliveryTier;
/** Shared-pool shard index, or -1 for a dedicated queue. */
shardIndex: number;
/** Queue name, e.g. "gogol-int-eu-shared-02" or "gogol-int-eu-ded-acme". */
queue: string;
/** Dead-letter queue name (queue + "-dlq"). */
dlq: string;
/** Region dedup KV namespace title, e.g. "gogol-int-dedup-eu". */
dedupNamespace: string;
/** Consumer Worker name bound to `queue` (one consumer per queue). */
consumer: string;
}
/** Options for resolveShard. `shardCount` is the size of the region's shared pool. */
export interface ResolveShardOptions {
tier?: DeliveryTier;
/** Number of queues in the region's shared pool. Must be ≥ 1. Default 4. */
shardCount?: number;
}
/**
* Deterministic 32-bit FNV-1a hash of a string. Stable across runtimes (no
* dependency on Math.random or hash seeds), so a siteId always lands on the same
* shard — the property re-sharding safety and registry-free placement rely on.
*/
export function fnv1a(input: string): number {
let hash = 0x811c9dc5;
for (let i = 0; i < input.length; i += 1) {
hash ^= input.charCodeAt(i);
// hash *= 16777619, kept in 32-bit unsigned space.
hash = Math.imul(hash, 0x01000193) >>> 0;
}
return hash >>> 0;
}
/** Two-digit shard suffix ("00".."99"+) for stable, sortable queue names. */
function shardSuffix(index: number): string {
return index < 10 ? `0${index}` : String(index);
}
/**
* Sanitize a siteId into a Cloudflare-safe resource-name segment: lowercase,
* alphanumeric + single dashes. Keeps names deterministic for dedicated queues.
*/
function safeSegment(siteId: string): string {
return siteId
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 40);
}
/**
* Resolve a site's place on the shared, sharded delivery backbone (RFC-0179).
*
* - `shared` tier: the site is hashed into one of `shardCount` queues in the
* region's shared pool — `gogol-int-{region}-shared-{NN}`. Blast radius is
* bounded to 1/shardCount of the pool.
* - `dedicated` tier: the site gets its own queue `gogol-int-{region}-ded-{siteId}`
* so a noisy/high-volume client cannot exhaust a shared pool's backlog.
*
* Dedup is a single region-scoped KV namespace in both tiers (keys are
* `{siteId}:{eventId}:{dest}`, unlimited per namespace).
*
* Pure + deterministic: the same inputs always yield the same assignment, so the
* placement is recomputable from content with no central registry.
*/
export function resolveShard(
siteId: string,
region: DeliveryRegion,
opts: ResolveShardOptions = {},
): ShardAssignment {
if (!siteId) throw new Error("resolveShard: siteId is required");
const tier: DeliveryTier = opts.tier ?? "shared";
const shardCount = Math.max(1, opts.shardCount ?? 4);
const dedupNamespace = `gogol-int-dedup-${region}`;
if (tier === "dedicated") {
const queue = `gogol-int-${region}-ded-${safeSegment(siteId)}`;
return {
siteId,
region,
tier,
shardIndex: -1,
queue,
dlq: `${queue}-dlq`,
dedupNamespace,
consumer: `${queue}-consumer`,
};
}
const shardIndex = fnv1a(siteId) % shardCount;
const queue = `gogol-int-${region}-shared-${shardSuffix(shardIndex)}`;
return {
siteId,
region,
tier,
shardIndex,
queue,
dlq: `${queue}-dlq`,
dedupNamespace,
consumer: `${queue}-consumer`,
};
}