@lunora/platform 1.0.0-alpha.5 → 1.0.0-alpha.51

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.
@@ -141,6 +141,16 @@ interface SchedulerHost {
141
141
  * presence is the host's declaration that dynamic cron works, exactly as
142
142
  * with `SocketHost.setTag`. A caller that finds it absent must fall
143
143
  * back to the target's declarative configuration.
144
+ *
145
+ * **Nothing in the framework calls this today.** `@lunora/platform-node`
146
+ * implements it (parser, persistence, timer re-arm) and the conformance
147
+ * suite is its only caller: no runtime walks an app's declared crons — the
148
+ * generated `LUNORA_CRONS` map — into it. The only cron dispatch that ships
149
+ * is `@lunora/runtime`'s, reached from Cloudflare's `scheduled()` handler,
150
+ * which is declarative and never touches this method. So a host that
151
+ * implements `cron` gains nothing until that wiring exists, and an app
152
+ * declaring crons on such a host has none of them fire. Wire it before
153
+ * treating a `cron`-bearing host as one that runs declared schedules.
144
154
  */
145
155
  cron?: (cron: string, functionPath: string, args?: Record<string, unknown>) => Promise<void>;
146
156
  /**
@@ -180,20 +190,32 @@ interface SchedulerHost {
180
190
  schedule: (functionPath: string, args: Record<string, unknown>, options?: ScheduleOptions) => Promise<ScheduledJob>;
181
191
  }
182
192
  /**
183
- * `ShardDirectory` — the provider-neutral contract for resolving shard keys to
184
- * callable stubs. On Cloudflare this is backed by `DurableObjectNamespace`
185
- * (`idFromName` + `get` + `jurisdiction`). On another provider it may be an
186
- * actor registry, a consistent-hash router, or a local in-process map.
193
+ * Edge geography → placement region, shared by `@lunora/runtime` (which reads
194
+ * `request.cf` to pick where a shard, replica, or region-local socket should
195
+ * live) and `@lunora/do` (which parses a region out of its own DO name). Kept
196
+ * here — inlined into each consumer's bundle — so the two sides can never drift
197
+ * on the region vocabulary without creating a runtime dependency edge between
198
+ * the packages.
187
199
  *
188
- * The engine relies on two capabilities:
189
- * 1. **Deterministic placement** — a shard key always resolves to the same
190
- * logical shard (`idForName`).
191
- * 2. **RPC dispatch** — a resolved stub can receive a `fetch` request (or
192
- * equivalent RPC call) that the shard handles.
200
+ * The values are Cloudflare's Durable Object location hints, which is also the
201
+ * only vocabulary a Lunora deployment needs today: a region is *only* ever used
202
+ * as a placement hint and as a name segment, never as data. Wrong-but-close is
203
+ * fine by construction — a misrouted read is one longer hop, never a wrong
204
+ * answer — so this maps coarsely and returns `undefined` rather than guessing
205
+ * when the request carries no usable geography.
193
206
  *
194
- * Placement hints (jurisdiction, region) are provider-mapped and may be
195
- * unsupported per the capability matrix.
207
+ * Zero-dependency by design (see the repo's `shared/` rules): only relative /
208
+ * builtin imports, named exports, no `.js` extensions.
209
+ */
210
+ /**
211
+ * The placement regions a name may carry and a hint may request — Cloudflare's
212
+ * `DurableObjectLocationHint` values, listed so the set can be validated at a
213
+ * trust boundary (a region parsed out of a DO name is attacker-influenced input
214
+ * on any route that mints names from a client-supplied shard key).
196
215
  */
216
+ declare const REGION_HINTS: readonly ["wnam", "enam", "sam", "weur", "eeur", "apac", "apac-ne", "apac-se", "oc", "afr", "me"];
217
+ /** One placement region. Structurally identical to Cloudflare's `DurableObjectLocationHint`. */
218
+ type RegionHint = (typeof REGION_HINTS)[number];
197
219
  /**
198
220
  * Cloudflare Durable Object jurisdictions restrict where a DO runs and
199
221
  * persists data, for data-residency / compliance regimes (GDPR, FedRAMP, US
@@ -206,6 +228,23 @@ interface SchedulerHost {
206
228
  * leave them unsupported.
207
229
  */
208
230
  type ShardJurisdiction = "eu" | "fedramp" | "us" | (Record<never, never> & string);
231
+ /**
232
+ * A geographic placement region — where a shard should be created, when the
233
+ * caller has an opinion.
234
+ *
235
+ * One vocabulary, defined once: `shared/region-hint.ts` owns the region list
236
+ * (it is also what derives a region from edge geography), and this contract
237
+ * re-exports it rather than restating the strings. A second list is how the two
238
+ * ends of a placement request drift apart.
239
+ *
240
+ * Unlike a jurisdiction — a hard constraint the caller must fail closed on — a
241
+ * region is **best effort and advisory**: a provider may ignore it, and on
242
+ * Cloudflare it is honoured only by the call that first creates the object.
243
+ * Everything downstream must work identically whether the hint was honoured,
244
+ * ignored, or never supplied, and no caller may treat a resolved stub's
245
+ * location as known.
246
+ */
247
+ type ShardRegionHint = RegionHint;
209
248
  /**
210
249
  * A resolved shard stub. The engine calls `fetch` (or an equivalent RPC
211
250
  * method) to dispatch work to the shard.
@@ -222,9 +261,9 @@ interface ShardStub {
222
261
  */
223
262
  interface DirectShardDirectory {
224
263
  /** Resolve an opaque id (from `idForName`) to a stub, when the provider has ids. */
225
- get?: (id: unknown) => ShardStub;
264
+ get?: (id: unknown, locationHint?: ShardRegionHint) => ShardStub;
226
265
  /** Resolve a shard key to a stub. */
227
- getByName: (name: string) => ShardStub;
266
+ getByName: (name: string, locationHint?: ShardRegionHint) => ShardStub;
228
267
  /** Derive a stable, opaque shard id from a shard key, when the provider has ids. */
229
268
  idForName?: (name: string) => unknown;
230
269
  /** See {@link ShardDirectory}. */
@@ -237,7 +276,7 @@ interface DirectShardDirectory {
237
276
  */
238
277
  interface TwoStepShardDirectory {
239
278
  /** Resolve an opaque id (from `idForName`) to a stub. */
240
- get: (id: unknown) => ShardStub;
279
+ get: (id: unknown, locationHint?: ShardRegionHint) => ShardStub;
241
280
  /**
242
281
  * Absent — the discriminant that selects the two-step branch.
243
282
  */
@@ -269,8 +308,13 @@ type ShardDirectory = DirectShardDirectory | TwoStepShardDirectory;
269
308
  * Resolve a shard key to a stub against either directory shape. Uses direct
270
309
  * name lookup when the provider has it, and falls back to the two-step
271
310
  * `idForName` + `get` dance otherwise.
311
+ *
312
+ * `locationHint` is forwarded to whichever branch runs. It is advisory in
313
+ * both: a provider with no placement concept ignores the extra argument, which
314
+ * is exactly what an implementation written against the pre-placement
315
+ * signature does.
272
316
  */
273
- declare const resolveShard: (directory: ShardDirectory, name: string) => ShardStub;
317
+ declare const resolveShard: (directory: ShardDirectory, name: string, locationHint?: ShardRegionHint) => ShardStub;
274
318
  /**
275
319
  * `ShardHost` — the provider-neutral contract for a single-writer, durable
276
320
  * shard execution slot. On Cloudflare this is backed by one Durable Object
@@ -301,22 +345,47 @@ type SqlRow = Record<string, unknown>;
301
345
  /**
302
346
  * The result of one statement: a cursor over its rows.
303
347
  *
304
- * Every member here is required, because the engine uses all three and a host
305
- * that omits one fails at runtime rather than at compile time. That is not
306
- * hypothetical — an earlier revision of this contract made `toArray` optional
307
- * and offered a `rowsAffected` nothing reads, which meant a host could satisfy
308
- * the type and still be unusable.
348
+ * The three members the ENGINE uses are required, because a host that omits one
349
+ * fails at runtime rather than at compile time. That is not hypothetical — an
350
+ * earlier revision of this contract made `toArray` optional and offered a
351
+ * `rowsAffected` nothing reads, which meant a host could satisfy the type and
352
+ * still be unusable.
309
353
  *
310
354
  * Iteration is part of the contract because read paths stream cursors directly
311
355
  * rather than buffering; `toArray` is the buffered form, and `one` is the
312
356
  * exactly-one-row form used by lookups and aggregates.
357
+ *
358
+ * `columnNames` / `raw` are the exception and are deliberately optional: no
359
+ * engine path needs them, one admin read-back reports a better result when they
360
+ * are there, and that surface degrades explicitly when they are not. Requiring
361
+ * them would make a host unusable over a detail it can live without.
313
362
  */
314
363
  interface ShardSqlCursor<Row = SqlRow> extends Iterable<Row> {
364
+ /**
365
+ * The result columns in SELECT order, as the statement declares them, before
366
+ * a row object collapses them into keys. Mirrors Cloudflare
367
+ * `SqlStorageCursor`'s field of the same name.
368
+ *
369
+ * Optional, and absent is a supported answer rather than a bug: a host
370
+ * supplies it when its driver has one (Cloudflare's cursor, better-sqlite3's
371
+ * `Statement#columns`, `node:sqlite`'s `columns()` from Node 22.14 on) and
372
+ * omits it otherwise. A reader with it can report a result faithfully;
373
+ * without it, a zero-row result has no column list at all and two same-named
374
+ * result columns (`SELECT u.id, o.id`) collapse to one.
375
+ */
376
+ readonly columnNames?: string[];
315
377
  /**
316
378
  * The single row this statement produced.
317
379
  * @throws when the result does not hold exactly one row.
318
380
  */
319
381
  one: () => Row;
382
+ /**
383
+ * The rows as positional value arrays aligned with `columnNames` rather
384
+ * than as objects — the only shape that survives two result columns sharing
385
+ * a name. Optional alongside `columnNames` (a host offers both or neither),
386
+ * and consuming it consumes the cursor: call it *or* `toArray`, never both.
387
+ */
388
+ raw?: () => IterableIterator<unknown[]>;
320
389
  /** Buffer every row. */
321
390
  toArray: () => Row[];
322
391
  }
@@ -340,17 +409,6 @@ interface ShardSqlExec {
340
409
  /** Execute a SQL statement with optional bound parameters. */
341
410
  exec: <Row = SqlRow>(query: string, ...bindings: ReadonlyArray<unknown>) => ShardSqlCursor<Row>;
342
411
  }
343
- /**
344
- * Async SQL executor used by the engine's higher-level paths (global tables,
345
- * metrics, auth). Already defined in `@lunora/sql-store` as `SqlExec`; this
346
- * alias keeps the platform contract self-contained.
347
- */
348
- interface ShardAsyncSqlExec {
349
- all: (sql: string, params: ReadonlyArray<unknown>) => Promise<SqlRow[]>;
350
- run: (sql: string, params: ReadonlyArray<unknown>) => Promise<{
351
- rowsAffected: number;
352
- }>;
353
- }
354
412
  /**
355
413
  * Alarm scheduling for a shard. Alarms are durable: they survive host
356
414
  * recycling and fire at the requested timestamp.
@@ -368,16 +426,21 @@ interface ShardAlarms {
368
426
  }
369
427
  /**
370
428
  * The core shard host contract. One instance per shard key.
429
+ *
430
+ * **At most one LIVE instance per shard key, at any moment — a requirement,
431
+ * not a convention.** `ShardDO` keeps correctness-bearing state in memory on
432
+ * that basis: its in-flight dispatch claim (`@lunora/do`'s `InFlightClaims`)
433
+ * declines a second concurrent delivery of the same idempotency id only because
434
+ * every delivery for the shard reaches the same instance, and treats a missing
435
+ * claim as "the holder is gone" only because a replaced instance takes its
436
+ * running handlers with it. A host that could run two instances of one shard
437
+ * side by side (a second Node process, a celld failover that overlaps the old
438
+ * cell) would let an action run twice concurrently. Cloudflare Durable Objects
439
+ * provide this natively; every other host must enforce it.
371
440
  */
372
441
  interface ShardHost {
373
442
  /** Durable alarm scheduling for the shard. */
374
443
  alarms: ShardAlarms;
375
- /**
376
- * Async SQL executor for engine paths that need promise-based row access
377
- * (global tables, metrics, auth). Hosts may implement this over the same
378
- * underlying storage as `sql`.
379
- */
380
- asyncSql?: ShardAsyncSqlExec;
381
444
  /**
382
445
  * Run `fn` with exclusive ownership of the shard. Concurrent calls are
383
446
  * queued; no two closures run at once for the same shard key. On
@@ -560,9 +623,26 @@ interface SocketHost {
560
623
  * durable tag minted at accept (Cloudflare), a registry key, a `WeakMap`.
561
624
  *
562
625
  * Must answer consistently for the same socket within a wake AND across a
563
- * recycle, since the engine uses it to reassociate a rehydrated socket with
564
- * its subscription state. Callers outside the O(subscribers) loops are the
565
- * intended consumers; do not reach for this per socket per frame.
626
+ * recycle. Callers outside the O(subscribers) loops are the intended
627
+ * consumers; do not reach for this per socket per frame.
628
+ *
629
+ * **Who actually calls it, since the previous wording named the wrong
630
+ * caller.** It said "the engine uses it to reassociate a rehydrated socket
631
+ * with its subscription state"; the engine does no such thing. Per-socket
632
+ * state is keyed on the handle object itself (`ShardRunner.socketFor`, over
633
+ * {@link SocketHost.handleFor}), and durable connection identity is the
634
+ * engine's own `connectionId` — a UUID minted at upgrade and stamped onto the
635
+ * socket attachment, which is what survives hibernation. `@lunora/shard-engine`
636
+ * and `@lunora/do` dispatch to `handleFor`, `getSockets` and `accept`, and to
637
+ * nothing else on this interface.
638
+ *
639
+ * `idFor` is the portable **identity oracle** instead: the conformance suite
640
+ * compares sockets through it (a host is allowed to hand back a different
641
+ * wrapper object for the same socket, so object identity is not a legal
642
+ * assertion), and it is how a host's own recycle plumbing addresses a socket
643
+ * by id. That is a real job and it is why this stays required — every host
644
+ * has to answer it for the TCK regardless — but implement it as a test and
645
+ * tooling contract, not as something on the frame path.
566
646
  *
567
647
  * **A socket this host never {@link SocketHost.accept}ed** (a foreign socket
568
648
  * the runtime hands back — a whisper sender in another pool, a relay peer)
@@ -605,4 +685,4 @@ interface SocketHost {
605
685
  */
606
686
  setTag?: (socket: SocketHandle, tag: string) => void;
607
687
  }
608
- export { DirectShardDirectory as D, ScheduleOptions as S, TwoStepShardDirectory as T, ScheduledJob as a, ScheduledJobStatus as b, SchedulerHost as c, ShardAlarms as d, ShardAsyncSqlExec as e, ShardDirectory as f, ShardHost as g, ShardJurisdiction as h, ShardKvListOptions as i, ShardKvStore as j, ShardSqlCursor as k, ShardSqlExec as l, ShardStub as m, SocketHandle as n, SocketHost as o, SqlRow as p, resolveShard as r };
688
+ export { DirectShardDirectory as D, ScheduleOptions as S, TwoStepShardDirectory as T, ScheduledJob as a, ScheduledJobStatus as b, SchedulerHost as c, ShardAlarms as d, ShardDirectory as e, ShardHost as f, ShardJurisdiction as g, ShardKvListOptions as h, ShardKvStore as i, ShardRegionHint as j, ShardSqlCursor as k, ShardSqlExec as l, ShardStub as m, SocketHandle as n, SocketHost as o, SqlRow as p, resolveShard as r };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/platform",
3
- "version": "1.0.0-alpha.5",
3
+ "version": "1.0.0-alpha.51",
4
4
  "description": "Provider-neutral host contracts for Lunora: shard/socket/directory/scheduler interfaces, binding projections, and the platform capability matrix",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -1 +0,0 @@
1
- const e={id:"cloudflare",name:"Cloudflare",features:{shardedState:{level:"native",note:"Durable Objects with SQLite"},globalTables:{level:"native",note:"D1 with Sessions API"},websocketHibernation:{level:"native",note:"DO WebSocket hibernation"},localSql:{level:"native",note:"state.storage.sql (SQLite)"},shardAlarms:{level:"native",note:"state.storage.setAlarm"},crossShardFanout:{level:"emulated",note:"Lunora query coordinator + relay tier over Durable Objects"},queues:{level:"native",note:"Cloudflare Queues"},workflows:{level:"native",note:"Cloudflare Workflows"},scheduler:{level:"emulated",note:"SchedulerDO (Lunora, on DO alarms) + declarative Cron Triggers; no runtime cron registration"},objectStorage:{level:"native",note:"R2"},keyValueStore:{level:"native",note:"Workers KV"},vectorStore:{level:"native",note:"Vectorize; query/upsert namespace scoping is native (remote filter), but getByIds/deleteByIds id-path tenant isolation is facade-enforced (client-side verification) since Vectorize's id operations take no namespace option"},ai:{level:"native",note:"Workers AI"},browser:{level:"native",note:"Browser Rendering"},containers:{level:"native",note:"Cloudflare Containers"},analytics:{level:"native",note:"Analytics Engine"},pipelines:{level:"native",note:"Cloudflare Pipelines"},mail:{level:"emulated",note:"Resend (third-party) via Cloudflare Queues"},secrets:{level:"native",note:"Secrets Store"},hyperdrive:{level:"native",note:"Cloudflare Hyperdrive"}}},t={id:"node",name:"Node",features:{shardedState:{level:"emulated",note:"One better-sqlite3 database per shard key, one process — no distributed placement or failover"},globalTables:{level:"unsupported",note:"No replicated SQL store (D1-equivalent) implemented"},websocketHibernation:{level:"emulated",note:"In-process socket registry; attachments/tags survive a simulated recycle, not a process restart, and nothing is ever actually evicted from memory"},localSql:{level:"native",note:"better-sqlite3 (synchronous, embedded)"},shardAlarms:{level:"unsupported",note:"In-process bookkeeping only — the armed timer clears state and never wakes anything; no dispatch, and nothing re-arms across a restart"},crossShardFanout:{level:"unsupported",note:"No query coordinator / relay tier implemented"},queues:{level:"unsupported",note:"No Cloudflare Queues equivalent implemented"},workflows:{level:"unsupported",note:"No Cloudflare Workflows equivalent implemented"},scheduler:{level:"unsupported",note:"Jobs are stored and timed but never dispatched — no delivery, no retries; also not durable across a process restart"},objectStorage:{level:"unsupported",note:"No R2/S3-equivalent binding implemented"},keyValueStore:{level:"emulated",note:"better-sqlite3 table behind the ShardKvStore API — not a dedicated KV product"},vectorStore:{level:"unsupported",note:"No Vectorize-equivalent binding implemented"},ai:{level:"unsupported",note:"No Workers AI-equivalent binding implemented"},browser:{level:"unsupported",note:"No headless-browser binding implemented"},containers:{level:"unsupported",note:"No container orchestration implemented"},analytics:{level:"unsupported",note:"No Analytics Engine-equivalent binding implemented"},pipelines:{level:"unsupported",note:"No Pipelines-equivalent binding implemented"},mail:{level:"unsupported",note:"@lunora/mail's queue-backed sends need a queues binding, which this target does not provide"},secrets:{level:"unsupported",note:"No Secrets Store-equivalent binding implemented (a real host would likely map this to env vars)"},hyperdrive:{level:"unsupported",note:"No connection-pooling binding implemented"}}};export{e as CLOUDFLARE_CAPABILITIES,t as NODE_CAPABILITIES};
@@ -1 +0,0 @@
1
- import{DatabaseSync as R}from"node:sqlite";let b=0,S=0;const j=()=>(b+=1,`socket-${b}`),C=()=>(S+=1,`job-${S}`),q=n=>n===void 0?null:n,E=n=>typeof n=="string"?new TextEncoder().encode(n).buffer:n instanceof ArrayBuffer?n:ArrayBuffer.isView(n)?n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength):new ArrayBuffer(0),O=()=>{const n=new R(":memory:"),s={alarmAt:null,alarmTimeout:null,pending:[],running:!1},l=new Map,f=new Map,u=new Map,x={exec:(e,...t)=>{const a=n.prepare(e),r=t.map(q),o=e.trim().toLowerCase().startsWith("select")?a.all(...r):(a.run(...r),[]);return{[Symbol.iterator]:()=>o[Symbol.iterator](),one:()=>{if(o.length!==1)throw new Error(`expected exactly one row, got ${String(o.length)}`);return o[0]},toArray:()=>[...o]}}},M={all:async(e,t)=>n.prepare(e).all(...t),run:async(e,t)=>{const a=n.prepare(e).run(...t);return{rowsAffected:Number(a.changes)}}},h=()=>{if(s.running||s.pending.length===0)return;const e=s.pending.shift();e!==void 0&&(s.running=!0,e.function_().then(e.resolve,e.reject).finally(()=>{s.running=!1,h()}))},F=e=>new Promise((t,a)=>{s.pending.push({function_:e,reject:r=>{a(r)},resolve:r=>{t(r)}}),h()});let g=Promise.resolve();const p=async e=>{n.exec("BEGIN");try{const t=await e();return n.exec("COMMIT"),t}catch(t){throw n.exec("ROLLBACK"),t}},D={alarms:{delete:()=>{s.alarmAt=null,s.alarmTimeout!==null&&(clearTimeout(s.alarmTimeout),s.alarmTimeout=null)},get:()=>s.alarmAt,set:e=>{const t=typeof e=="number"?e:e.getTime();s.alarmAt=t,s.alarmTimeout!==null&&clearTimeout(s.alarmTimeout);const a=Math.max(0,t-Date.now());s.alarmTimeout=setTimeout(()=>{s.alarmAt=null,s.alarmTimeout=null},a)}},asyncSql:M,runSerialized:F,sql:x,transaction:e=>{const t=g.then(()=>p(e),()=>p(e));return g=t.then(()=>{},()=>{}),t},waitUntil:()=>{}},c=new WeakMap,w=e=>{const t={bufferedAmount:e.bufferedAmount,close:(a,r)=>{e.closed=!0},deserializeAttachment:()=>e.attachment,send:a=>{e.received.push(typeof a=="string"?a:E(a))},serializeAttachment:a=>{e.attachment=a,f.set(e.id,a)}};return e.handle=t,c.set(t,e.id),t},P={accept:(e,t,a)=>{const r=j(),o={attachment:t,bufferedAmount:0,closed:!1,raw:e,handle:null,id:r,received:[],tags:new Set(a)};return l.set(r,o),u.set(r,new Set(a)),t!==void 0&&f.set(r,t),w(o)},getSockets:e=>{const t=[...l.values()];return(e===void 0?t:t.filter(a=>a.tags.has(e))).map(a=>a.handle)},handleFor:e=>[...l.values()].find(t=>t.raw===e)?.handle,idFor:e=>{const t=c.get(e);if(t===void 0)throw new Error("reference host: idFor called with a handle this host never issued");return t},removeTag:(e,t)=>{const a=l.get(c.get(e)??"");a!==void 0&&(t===void 0?a.tags.clear():a.tags.delete(t),u.set(c.get(e)??"",new Set(a.tags)))},setTag:(e,t)=>{const a=c.get(e)??"",r=l.get(a);r!==void 0&&(r.tags.add(t),u.set(a,new Set(r.tags)))}},y={get:e=>({fetch:async()=>new Response(String(e))}),getByName:e=>({fetch:async()=>new Response(e)}),idForName:e=>`shard:${e}`,jurisdiction:e=>y},d=new Map,k={delete:async e=>d.delete(e),get:async e=>d.get(e),list:async e=>{const t=e?.prefix??"",a=new Map;for(const[r,o]of d)r.startsWith(t)&&a.set(r,o);return a},put:async(e,t)=>{d.set(e,structuredClone(t))}},i=new Map,m=new Map,v=new Set,T=(e,t)=>({attempts:t.attempts,functionPath:t.functionPath,id:e,scheduledFor:t.scheduledFor});return{awaitAlarmFired:async e=>{await new Promise(t=>{setTimeout(t,Math.max(0,e-Date.now())+30)})},awaitJobDispatched:async e=>{const t=i.get(e);return t!==void 0&&await new Promise(a=>{setTimeout(a,Math.max(0,t.scheduledFor-Date.now())+30)}),v.has(e)},cleanup:()=>{n.close(),s.alarmTimeout!==null&&clearTimeout(s.alarmTimeout);for(const e of i.values())clearTimeout(e.timer)},directory:y,kv:k,readFrames:e=>(l.get(c.get(e)??"")?.received??[]).filter(t=>typeof t=="string"),restoreSocket:(e,t)=>{const a={attachment:t,bufferedAmount:0,closed:!1,handle:null,id:e,raw:void 0,received:[],tags:new Set(u.get(e))};return l.set(e,a),w(a)},scheduler:{cancel:async e=>{const t=i.get(e);return t===void 0?!1:(clearTimeout(t.timer),i.delete(e),!0)},cron:async()=>{},deadLetter:{list:async()=>[...m].map(([e,t])=>T(e,t)),requeue:async e=>{const t=m.get(e);return t===void 0?!1:(m.delete(e),i.set(e,{...t,attempts:0,timer:void 0}),!0)}},list:async()=>[...i].map(([e,t])=>T(e,t)),schedule:async(e,t,a)=>{const r=C();let o;a?.at===void 0?o=Date.now()+(a?.delayMs??0):o=typeof a.at=="number"?a.at:a.at.getTime();const B=Math.max(0,o-Date.now()),L=setTimeout(()=>{const A=i.get(r);A!==void 0&&(A.attempts+=1),v.add(r),i.delete(r)},B);return i.set(r,{args:t,attempts:0,functionPath:e,options:a??{},scheduledFor:o,timer:L}),{id:r,scheduledFor:o}}},simulateDeadLetter:async e=>{const t=i.get(e);return t===void 0?!1:(clearTimeout(t.timer),i.delete(e),m.set(e,{...t,attempts:(t.options.retry?.maxAttempts??5)+1,timer:void 0}),!0)},shard:D,simulateRecycle:()=>{l.clear()},socket:P}};export{O as createReferenceHost};
@@ -1 +0,0 @@
1
- const t=(e,o)=>e.getByName!==void 0?e.getByName(o):e.get(e.idForName(o));export{t as resolveShard};