@ewhauser/world-celld 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/worker.d.ts CHANGED
@@ -52,6 +52,7 @@ interface WorkerEnv {
52
52
  WORKFLOW_QUEUE_PAYLOADS?: QueuePayloadStore;
53
53
  WORLD_SECRET?: string;
54
54
  WORKFLOW_CALLBACK_SECRET?: string;
55
+ WORKFLOW_DEPLOYMENT_URLS?: string;
55
56
  WORKFLOW_RETENTION_MS?: string | number;
56
57
  WORKFLOW_RETENTION_BATCH_SIZE?: string | number;
57
58
  }
@@ -304,6 +305,10 @@ interface RunLifecycleStub {
304
305
  claimId: string;
305
306
  token?: string;
306
307
  }): Promise<Hook | null>;
308
+ getCommittedHook(request: {
309
+ hookId: string;
310
+ token?: string;
311
+ }): Promise<Hook | null>;
307
312
  }
308
313
  interface HookIndexEnv {
309
314
  WORKFLOW_DB?: CellNamespaceLike<RunLifecycleStub>;
@@ -491,6 +496,15 @@ declare class WorkflowRunDO extends DurableObject {
491
496
  claimId: string;
492
497
  token?: string;
493
498
  }): Promise<Hook | null>;
499
+ /**
500
+ * Read-only twin of resolveExpiredHookClaim for index repair: the committed
501
+ * hook of a live run, or null. It fences nothing, so a shard may ask while
502
+ * the hook's creation is still in flight.
503
+ */
504
+ getCommittedHook(request: {
505
+ hookId: string;
506
+ token?: string;
507
+ }): Promise<Hook | null>;
494
508
  /** Single authoritative lifecycle answer used after derivative compaction. */
495
509
  getLifecycleStatus(): Promise<RunLifecycleStatus>;
496
510
  getStep(stepId: string): Promise<RunReadOutcome<Step | null>>;
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","names":[],"sources":["../src/worker/queue-payload-store.ts","../src/worker/router.ts","../src/worker/do-base.ts","../src/retention.ts","../src/apply-event.ts","../src/stream-protocol.ts","../src/indexes.ts","../src/config.ts","../src/worker/durable-objects/hook-index-shared.ts","../src/worker/durable-objects/HookIdDO.ts","../src/worker/durable-objects/HookTokenDO.ts","../src/worker/durable-objects/RunCatalogDO.ts","../src/worker/durable-objects/StreamDO.ts","../src/worker/durable-objects/WorkflowRunDO.ts","../src/worker/worker.ts"],"mappings":"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"}
1
+ {"version":3,"file":"worker.d.ts","names":[],"sources":["../src/worker/queue-payload-store.ts","../src/worker/router.ts","../src/worker/do-base.ts","../src/retention.ts","../src/apply-event.ts","../src/stream-protocol.ts","../src/indexes.ts","../src/config.ts","../src/worker/durable-objects/hook-index-shared.ts","../src/worker/durable-objects/HookIdDO.ts","../src/worker/durable-objects/HookTokenDO.ts","../src/worker/durable-objects/RunCatalogDO.ts","../src/worker/durable-objects/StreamDO.ts","../src/worker/durable-objects/WorkflowRunDO.ts","../src/worker/worker.ts"],"mappings":"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"}
package/dist/worker.js CHANGED
@@ -107,6 +107,142 @@ function deliveryQueueClaim(envelope, runStub) {
107
107
  return envelope.claimScope === "run" && envelope.runId ? runQueueClaim(runStub(envelope.runId), claimName) : cellQueueClaim(runStub(claimName));
108
108
  }
109
109
  //#endregion
110
+ //#region src/deployment-routing.ts
111
+ function validateUrl(value, deploymentId) {
112
+ if (typeof value !== "string" || value.length === 0) throw new Error(`world-celld: deployment URL for ${deploymentId} must be a non-empty string`);
113
+ let url;
114
+ try {
115
+ url = new URL(value);
116
+ } catch {
117
+ throw new Error(`world-celld: deployment URL for ${deploymentId} must be absolute`);
118
+ }
119
+ if (url.protocol !== "http:" && url.protocol !== "https:" || url.username || url.password || url.search || url.hash) throw new Error(`world-celld: deployment URL for ${deploymentId} is invalid`);
120
+ return url.href.replace(/\/$/, "");
121
+ }
122
+ function validateDeploymentUrls(value) {
123
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("world-celld: deployment URLs must be an object");
124
+ const urls = Object.create(null);
125
+ for (const [id, url] of Object.entries(value)) {
126
+ if (!id || id.trim() !== id) throw new Error("world-celld: deployment URL IDs must be non-empty and unpadded");
127
+ urls[id] = validateUrl(url, id);
128
+ }
129
+ return urls;
130
+ }
131
+ function configuredDeploymentUrl(urls, deploymentId) {
132
+ if (!Object.hasOwn(urls, deploymentId)) throw new Error(`world-celld: no callback URL configured for deployment ${deploymentId}`);
133
+ return urls[deploymentId];
134
+ }
135
+ function parseDeploymentUrls(value) {
136
+ if (value === void 0 || value === "") return void 0;
137
+ let parsed;
138
+ try {
139
+ parsed = JSON.parse(value);
140
+ } catch {
141
+ throw new Error("world-celld: WORKFLOW_DEPLOYMENT_URLS must be a JSON object");
142
+ }
143
+ return validateDeploymentUrls(parsed);
144
+ }
145
+ //#endregion
146
+ //#region src/vendor/shared/serialization.ts
147
+ /** Standard Date fields used across all worlds */
148
+ const DATE_FIELDS = /* @__PURE__ */ new Set([
149
+ "createdAt",
150
+ "updatedAt",
151
+ "startedAt",
152
+ "completedAt",
153
+ "retryAfter"
154
+ ]);
155
+ /**
156
+ * JSON reviver that converts ISO date strings to Date objects.
157
+ * Use with JSON.parse(json, dateReviver).
158
+ */
159
+ function dateReviver(key, value) {
160
+ if (DATE_FIELDS.has(key) && typeof value === "string") {
161
+ const date = new Date(value);
162
+ return Number.isNaN(date.getTime()) ? value : date;
163
+ }
164
+ return value;
165
+ }
166
+ /**
167
+ * Base64 helpers. Modified vs upstream: implemented without Buffer so this
168
+ * module is safe inside the celld worker bundle (workerd has no Buffer
169
+ * global). Uses the native Uint8Array base64 methods where the runtime has
170
+ * them (Node >= 25, current V8) and falls back to atob/btoa elsewhere.
171
+ */
172
+ const nativeToBase64 = Uint8Array.prototype.toBase64;
173
+ const nativeFromBase64 = Uint8Array.fromBase64;
174
+ /** Small enough to stay far below engine argument-count limits and fast to spread. */
175
+ const FALLBACK_ENCODE_CHUNK = 4096;
176
+ /** @internal Exported for tests; use b64encode. */
177
+ function b64encodeFallback(bytes) {
178
+ let bin = "";
179
+ for (let i = 0; i < bytes.length; i += FALLBACK_ENCODE_CHUNK) bin += String.fromCharCode.apply(null, bytes.subarray(i, i + FALLBACK_ENCODE_CHUNK));
180
+ return btoa(bin);
181
+ }
182
+ /** @internal Exported for tests; use b64decode. */
183
+ function b64decodeFallback(text) {
184
+ const bin = atob(text);
185
+ const out = new Uint8Array(bin.length);
186
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
187
+ return out;
188
+ }
189
+ function b64encode(bytes) {
190
+ return nativeToBase64 ? nativeToBase64.call(bytes) : b64encodeFallback(bytes);
191
+ }
192
+ function b64decode(text) {
193
+ return nativeFromBase64 ? nativeFromBase64(text) : b64decodeFallback(text);
194
+ }
195
+ /**
196
+ * JSON replacer that encodes Uint8Array as a tagged object with base64 data.
197
+ */
198
+ function uint8ArrayReplacer(_key, value) {
199
+ if (value instanceof Uint8Array) return {
200
+ __type: "Uint8Array",
201
+ data: b64encode(value)
202
+ };
203
+ return value;
204
+ }
205
+ /**
206
+ * JSON reviver that decodes tagged Uint8Array objects and ISO date strings.
207
+ * Supports both:
208
+ * - New format: { __type: 'Uint8Array', data: '<base64>' }
209
+ * - Legacy format: { __uint8array: true, data: [1, 2, 3] }
210
+ */
211
+ function uint8ArrayReviver(key, value) {
212
+ if (value && typeof value === "object") {
213
+ const obj = value;
214
+ if (obj.__type === "Uint8Array") {
215
+ if (typeof obj.data !== "string") throw new SyntaxError("Malformed Uint8Array tag");
216
+ try {
217
+ return b64decode(obj.data);
218
+ } catch {
219
+ throw new SyntaxError("Malformed Uint8Array tag");
220
+ }
221
+ }
222
+ if (obj.__uint8array === true) {
223
+ if (!Array.isArray(obj.data) || !obj.data.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)) throw new SyntaxError("Malformed legacy Uint8Array tag");
224
+ return new Uint8Array(obj.data);
225
+ }
226
+ }
227
+ return dateReviver(key, value);
228
+ }
229
+ /** Stringify with Uint8Array support. */
230
+ function stringify(value) {
231
+ return JSON.stringify(value, uint8ArrayReplacer);
232
+ }
233
+ /** Parse with Uint8Array and Date support. */
234
+ function parse(text) {
235
+ return JSON.parse(text, uint8ArrayReviver);
236
+ }
237
+ //#endregion
238
+ //#region src/vendor/shared/util.ts
239
+ function compact(obj) {
240
+ const value = {};
241
+ for (const key in obj) if (obj[key] !== null) value[key] = obj[key];
242
+ else value[key] = void 0;
243
+ return value;
244
+ }
245
+ //#endregion
110
246
  //#region src/worker/queue-delivery.ts
111
247
  /** Internal delivery contract. No Request/Response objects cross the RPC boundary. */
112
248
  const MAX_QUEUE_DELIVERY_RESPONSE_BYTES = 65536;
@@ -193,6 +329,17 @@ async function deliverQueueMessage(env, secret, input, attempt) {
193
329
  return { kind: "complete" };
194
330
  }
195
331
  }
332
+ const deploymentUrls = parseDeploymentUrls(env.WORKFLOW_DEPLOYMENT_URLS);
333
+ let targetBaseUrl = envelope.targetBaseUrl;
334
+ if (deploymentUrls && envelope.runId) {
335
+ const stored = await runStub(envelope.runId).getRun();
336
+ if (!stored.ok) throw new Error("world-celld: cannot route an expired run");
337
+ const initialId = parse(body).runInput?.deploymentId;
338
+ const pinnedId = stored.value?.deploymentId ?? initialId;
339
+ if (typeof pinnedId !== "string" || pinnedId.length === 0) throw new Error(`world-celld: no pinned deployment for run ${envelope.runId}`);
340
+ if (stored.value && initialId !== void 0 && initialId !== pinnedId) throw new Error(`world-celld: queue run deployment hints disagree for ${envelope.runId}`);
341
+ targetBaseUrl = configuredDeploymentUrl(deploymentUrls, pinnedId);
342
+ }
196
343
  const headers = {
197
344
  "content-type": "application/json",
198
345
  "x-vqs-queue-name": envelope.queueName,
@@ -200,13 +347,13 @@ async function deliverQueueMessage(env, secret, input, attempt) {
200
347
  "x-vqs-message-attempt": String(attempt)
201
348
  };
202
349
  if (env.WORKFLOW_CALLBACK_SECRET) headers["x-workflow-callback-secret"] = env.WORKFLOW_CALLBACK_SECRET;
203
- const callback = await fetch(`${envelope.targetBaseUrl.replace(/\/$/, "")}/.well-known/workflow/v1/flow`, {
350
+ const callback = await fetch(`${targetBaseUrl.replace(/\/$/, "")}/.well-known/workflow/v1/flow`, {
204
351
  method: "POST",
205
352
  headers,
206
353
  body,
207
354
  signal: AbortSignal.timeout(3e5)
208
355
  });
209
- if (callback.ok || PERMANENT_QUEUE_STATUSES.has(callback.status)) {
356
+ if (callback.ok || !deploymentUrls && PERMANENT_QUEUE_STATUSES.has(callback.status) || !envelope.runId && PERMANENT_QUEUE_STATUSES.has(callback.status)) {
210
357
  await callback.body?.cancel().catch(() => void 0);
211
358
  if (envelope.payloadKey) {
212
359
  await payloadStore.delete(envelope.payloadKey);
@@ -247,92 +394,6 @@ async function deliverQueueMessage(env, secret, input, attempt) {
247
394
  }
248
395
  }
249
396
  //#endregion
250
- //#region src/vendor/shared/serialization.ts
251
- /** Standard Date fields used across all worlds */
252
- const DATE_FIELDS = /* @__PURE__ */ new Set([
253
- "createdAt",
254
- "updatedAt",
255
- "startedAt",
256
- "completedAt",
257
- "retryAfter"
258
- ]);
259
- /**
260
- * JSON reviver that converts ISO date strings to Date objects.
261
- * Use with JSON.parse(json, dateReviver).
262
- */
263
- function dateReviver(key, value) {
264
- if (DATE_FIELDS.has(key) && typeof value === "string") {
265
- const date = new Date(value);
266
- return Number.isNaN(date.getTime()) ? value : date;
267
- }
268
- return value;
269
- }
270
- /**
271
- * Base64 helpers. Modified vs upstream: implemented without Buffer so this
272
- * module is safe inside the celld worker bundle (workerd has no Buffer
273
- * global). Uses the native Uint8Array base64 methods where the runtime has
274
- * them (Node >= 25, current V8) and falls back to atob/btoa elsewhere.
275
- */
276
- const nativeToBase64 = Uint8Array.prototype.toBase64;
277
- const nativeFromBase64 = Uint8Array.fromBase64;
278
- /** Small enough to stay far below engine argument-count limits and fast to spread. */
279
- const FALLBACK_ENCODE_CHUNK = 4096;
280
- /** @internal Exported for tests; use b64encode. */
281
- function b64encodeFallback(bytes) {
282
- let bin = "";
283
- for (let i = 0; i < bytes.length; i += FALLBACK_ENCODE_CHUNK) bin += String.fromCharCode.apply(null, bytes.subarray(i, i + FALLBACK_ENCODE_CHUNK));
284
- return btoa(bin);
285
- }
286
- /** @internal Exported for tests; use b64decode. */
287
- function b64decodeFallback(text) {
288
- const bin = atob(text);
289
- const out = new Uint8Array(bin.length);
290
- for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
291
- return out;
292
- }
293
- function b64encode(bytes) {
294
- return nativeToBase64 ? nativeToBase64.call(bytes) : b64encodeFallback(bytes);
295
- }
296
- function b64decode(text) {
297
- return nativeFromBase64 ? nativeFromBase64(text) : b64decodeFallback(text);
298
- }
299
- /**
300
- * JSON reviver that decodes tagged Uint8Array objects and ISO date strings.
301
- * Supports both:
302
- * - New format: { __type: 'Uint8Array', data: '<base64>' }
303
- * - Legacy format: { __uint8array: true, data: [1, 2, 3] }
304
- */
305
- function uint8ArrayReviver(key, value) {
306
- if (value && typeof value === "object") {
307
- const obj = value;
308
- if (obj.__type === "Uint8Array") {
309
- if (typeof obj.data !== "string") throw new SyntaxError("Malformed Uint8Array tag");
310
- try {
311
- return b64decode(obj.data);
312
- } catch {
313
- throw new SyntaxError("Malformed Uint8Array tag");
314
- }
315
- }
316
- if (obj.__uint8array === true) {
317
- if (!Array.isArray(obj.data) || !obj.data.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)) throw new SyntaxError("Malformed legacy Uint8Array tag");
318
- return new Uint8Array(obj.data);
319
- }
320
- }
321
- return dateReviver(key, value);
322
- }
323
- /** Parse with Uint8Array and Date support. */
324
- function parse(text) {
325
- return JSON.parse(text, uint8ArrayReviver);
326
- }
327
- //#endregion
328
- //#region src/vendor/shared/util.ts
329
- function compact(obj) {
330
- const value = {};
331
- for (const key in obj) if (obj[key] !== null) value[key] = obj[key];
332
- else value[key] = void 0;
333
- return value;
334
- }
335
- //#endregion
336
397
  //#region src/apply-event.ts
337
398
  /** Storage key for the run entity. */
338
399
  const RUN_KEY = "run";
@@ -2683,6 +2744,70 @@ async function resolveExpiredHookClaim(env, owner, claimId, token) {
2683
2744
  token
2684
2745
  });
2685
2746
  }
2747
+ /** Read-only owner check used by index repair; unlike the resolver it never fences. */
2748
+ async function getCommittedHook(env, owner, token) {
2749
+ const namespace = env.WORKFLOW_DB;
2750
+ if (!namespace) throw new Error("world-celld hook index missing WORKFLOW_DB binding");
2751
+ return await namespace.get(namespace.idFromName(owner.runId)).getCommittedHook({
2752
+ hookId: owner.hookId,
2753
+ token
2754
+ });
2755
+ }
2756
+ function warnRepair(action, owner) {
2757
+ console.warn(`world-celld ${action} hook index record for run ${owner.runId} hook ${owner.hookId}`);
2758
+ }
2759
+ function warnRepublished(owner) {
2760
+ warnRepair("republished", owner);
2761
+ }
2762
+ /**
2763
+ * Publish the record for a claim whose hook committed in its run but whose
2764
+ * creating client stopped before finalizing. The write applies only while the
2765
+ * observed claim is unchanged, so a concurrent release or finalize wins.
2766
+ * Returns the record now stored for the key, if any.
2767
+ */
2768
+ async function publishCommittedClaim(storage, env, keys, token) {
2769
+ const observed = await storage.get(keys.claim);
2770
+ if (!observed) return null;
2771
+ const hook = await getCommittedHook(env, observed.owner, token);
2772
+ if (!hook) return null;
2773
+ const serialized = stringify(hook);
2774
+ const published = await storage.transaction(async (txn) => {
2775
+ const values = await txn.get([keys.record, keys.claim]);
2776
+ const indexed = values.get(keys.record);
2777
+ if (indexed !== void 0) return {
2778
+ raw: indexed,
2779
+ written: false
2780
+ };
2781
+ const claim = values.get(keys.claim);
2782
+ if (claim?.claimId !== observed.claimId) return {
2783
+ raw: null,
2784
+ written: false
2785
+ };
2786
+ await txn.put(keys.record, serialized);
2787
+ await txn.delete([keys.claim, claim.deadlineKey]);
2788
+ return {
2789
+ raw: serialized,
2790
+ written: true
2791
+ };
2792
+ });
2793
+ if (!published.written) return published.raw;
2794
+ warnRepublished(observed.owner);
2795
+ return await confirmRepublished(storage, env, keys.record, observed.owner, token) ? serialized : null;
2796
+ }
2797
+ /**
2798
+ * Re-ask the owner after a repair write. A hook disposed between the owner's
2799
+ * answer and the write would otherwise keep a record whose index release was
2800
+ * already spent, so withdraw it.
2801
+ */
2802
+ async function confirmRepublished(storage, env, record, owner, token) {
2803
+ if (await getCommittedHook(env, owner, token)) return true;
2804
+ await storage.transaction(async (txn) => {
2805
+ const indexed = await txn.get(record);
2806
+ if (indexed !== void 0 && sameOwner(ownerFromSerializedHook(indexed), owner)) await txn.delete(record);
2807
+ });
2808
+ warnRepair("withdrew", owner);
2809
+ return false;
2810
+ }
2686
2811
  //#endregion
2687
2812
  //#region src/worker/durable-objects/HookIdDO.ts
2688
2813
  const MAX_RELEASE_BATCH$1 = 64;
@@ -2705,7 +2830,10 @@ var HookIdDO = class extends DurableObject {
2705
2830
  return typeof this.env.clock === "function" ? this.env.clock() : Date.now();
2706
2831
  }
2707
2832
  async get(hookId) {
2708
- const raw = await this.ctx.storage.get(recordKey$1(hookId));
2833
+ const raw = await this.ctx.storage.get(recordKey$1(hookId)) ?? await publishCommittedClaim(this.ctx.storage, this.env, {
2834
+ record: recordKey$1(hookId),
2835
+ claim: claimKey$1(hookId)
2836
+ });
2709
2837
  if (!raw) return null;
2710
2838
  const owner = ownerFromSerializedHook(raw);
2711
2839
  return await runIsActive(this.env, owner.runId) ? raw : null;
@@ -2870,8 +2998,9 @@ var HookIdDO = class extends DurableObject {
2870
2998
  const claim = observed.get(claimKey$1(item.hookId));
2871
2999
  if (!claim || claim.claimId !== item.claimId || claim.expiresAt > now) return;
2872
3000
  const hook = await resolveExpiredHookClaim(this.env, claim.owner, claim.claimId);
2873
- committed.set(claimKey$1(item.hookId), hook !== null);
3001
+ committed.set(claimKey$1(item.hookId), hook);
2874
3002
  }));
3003
+ const published = [];
2875
3004
  await this.ctx.storage.transaction(async (txn) => {
2876
3005
  const claims = await txn.get(page.map(([, item]) => claimKey$1(item.hookId)));
2877
3006
  const deletes = [];
@@ -2881,8 +3010,15 @@ var HookIdDO = class extends DurableObject {
2881
3010
  const snapshot = observed.get(key);
2882
3011
  if (claim?.claimId !== item.claimId || claim.expiresAt > now) deletes.push(deadline);
2883
3012
  else if (claim.claimId === snapshot?.claimId && claim.expiresAt === snapshot.expiresAt) {
2884
- if (committed.get(key)) await this.renewClaim(txn, item.hookId, claim, now);
2885
- else deletes.push(deadline, key);
3013
+ const hook = committed.get(key);
3014
+ if (hook) {
3015
+ await txn.put(recordKey$1(item.hookId), stringify(hook));
3016
+ published.push({
3017
+ hookId: item.hookId,
3018
+ owner: claim.owner
3019
+ });
3020
+ }
3021
+ deletes.push(deadline, key);
2886
3022
  }
2887
3023
  }
2888
3024
  for (let offset = 0; offset < deletes.length; offset += 128) await txn.delete(deletes.slice(offset, offset + 128));
@@ -2897,6 +3033,10 @@ var HookIdDO = class extends DurableObject {
2897
3033
  if (nextAt === void 0) await txn.deleteAlarm();
2898
3034
  else await txn.setAlarm(Math.max(now + 1, nextAt));
2899
3035
  });
3036
+ for (const { hookId, owner } of published) {
3037
+ warnRepublished(owner);
3038
+ await confirmRepublished(this.ctx.storage, this.env, recordKey$1(hookId), owner);
3039
+ }
2900
3040
  }
2901
3041
  };
2902
3042
  //#endregion
@@ -2921,7 +3061,10 @@ var HookTokenDO = class extends DurableObject {
2921
3061
  return typeof this.env.clock === "function" ? this.env.clock() : Date.now();
2922
3062
  }
2923
3063
  async get(token) {
2924
- const raw = await this.ctx.storage.get(recordKey(token));
3064
+ const raw = await this.ctx.storage.get(recordKey(token)) ?? await publishCommittedClaim(this.ctx.storage, this.env, {
3065
+ record: recordKey(token),
3066
+ claim: claimKey(token)
3067
+ }, token);
2925
3068
  if (!raw) return null;
2926
3069
  const owner = ownerFromSerializedHook(raw);
2927
3070
  return await runIsActive(this.env, owner.runId) ? raw : null;
@@ -3085,8 +3228,9 @@ var HookTokenDO = class extends DurableObject {
3085
3228
  const claim = observed.get(claimKey(item.token));
3086
3229
  if (!claim || claim.claimId !== item.claimId || claim.expiresAt > now) return;
3087
3230
  const hook = await resolveExpiredHookClaim(this.env, claim.owner, claim.claimId, item.token);
3088
- committed.set(claimKey(item.token), hook !== null);
3231
+ committed.set(claimKey(item.token), hook);
3089
3232
  }));
3233
+ const published = [];
3090
3234
  await this.ctx.storage.transaction(async (txn) => {
3091
3235
  const claims = await txn.get(page.map(([, item]) => claimKey(item.token)));
3092
3236
  const deletes = [];
@@ -3096,8 +3240,15 @@ var HookTokenDO = class extends DurableObject {
3096
3240
  const snapshot = observed.get(key);
3097
3241
  if (claim?.claimId !== item.claimId || claim.expiresAt > now) deletes.push(deadline);
3098
3242
  else if (claim.claimId === snapshot?.claimId && claim.expiresAt === snapshot.expiresAt) {
3099
- if (committed.get(key)) await this.renewClaim(txn, item.token, claim, now);
3100
- else deletes.push(deadline, key);
3243
+ const hook = committed.get(key);
3244
+ if (hook) {
3245
+ await txn.put(recordKey(item.token), stringify(hook));
3246
+ published.push({
3247
+ token: item.token,
3248
+ owner: claim.owner
3249
+ });
3250
+ }
3251
+ deletes.push(deadline, key);
3101
3252
  }
3102
3253
  }
3103
3254
  for (let offset = 0; offset < deletes.length; offset += 128) await txn.delete(deletes.slice(offset, offset + 128));
@@ -3112,6 +3263,10 @@ var HookTokenDO = class extends DurableObject {
3112
3263
  if (nextAt === void 0) await txn.deleteAlarm();
3113
3264
  else await txn.setAlarm(Math.max(now + 1, nextAt));
3114
3265
  });
3266
+ for (const { token, owner } of published) {
3267
+ warnRepublished(owner);
3268
+ await confirmRepublished(this.ctx.storage, this.env, recordKey(token), owner, token);
3269
+ }
3115
3270
  }
3116
3271
  };
3117
3272
  //#endregion
@@ -4162,6 +4317,23 @@ var WorkflowRunDO = class extends DurableObject {
4162
4317
  return null;
4163
4318
  });
4164
4319
  }
4320
+ /**
4321
+ * Read-only twin of resolveExpiredHookClaim for index repair: the committed
4322
+ * hook of a live run, or null. It fences nothing, so a shard may ask while
4323
+ * the hook's creation is still in flight.
4324
+ */
4325
+ async getCommittedHook(request) {
4326
+ if (typeof request?.hookId !== "string" || request.hookId.length === 0 || request.token !== void 0 && typeof request.token !== "string") throw new TypeError("world-celld committed hook lookup is invalid");
4327
+ return await this.ctx.storage.transaction(async (txn) => {
4328
+ const { tombstone } = await this.retentionState(txn);
4329
+ if (tombstone) return null;
4330
+ const run = await txn.get("run");
4331
+ if (!run || isTerminalWorkflowRunStatus(run.status)) return null;
4332
+ const hook = await txn.get(`${HOOK_KEY_PREFIX}${request.hookId}`);
4333
+ if (!hook || request.token !== void 0 && hook.token !== request.token) return null;
4334
+ return hook;
4335
+ });
4336
+ }
4165
4337
  /** Single authoritative lifecycle answer used after derivative compaction. */
4166
4338
  async getLifecycleStatus() {
4167
4339
  return await this.ctx.storage.transaction(async (txn) => {