@lunora/do 1.0.0-alpha.109 → 1.0.0-alpha.110
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/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SchemaLike, DatabaseWriterLike, CrossShardReadArgs, CdcChange, FilterClause, ExportRow, MigrationDirection, ReactiveCache, ShapeProbeCounters, GlobalPollCounters, ReactiveCacheOptions, ShardSocketLike, TransactionHeadroomTracker, LifecycleDispatchInfo, MigrationRunResult, SearchBackfillProgress, TableIndexInfo, ColumnMeta, AdvisoryFinding, AdvisorProcedure, RlsPoliciesResult, MaskPoliciesResult, StorageRulesResult, StudioFeaturesResult, FlagsResult, SubscriptionIdentity, QueuesResult, WorkflowsResult, ImportShardResult, ShardRankPageResult, SubscriptionQuery, ShapeSubscriptionQuery, MutationDelta, KeyRange, ResolvedShape, ShapeRow, TtlSweepSpec, TransactionLimits, IndexKeyEntry, SqlExec, CdcChangeKey } from '@lunora/shard-engine';
|
|
1
|
+
import { SchemaLike, DatabaseWriterLike, CrossShardReadArgs, CdcChange, FilterClause, ExportRow, MigrationDirection, ReadFootprint, DependencyTracker, ReactiveCache, ShapeProbeCounters, GlobalPollCounters, ReactiveCacheOptions, ShardSocketLike, TransactionHeadroomTracker, LifecycleDispatchInfo, MigrationRunResult, SearchBackfillProgress, TableIndexInfo, ColumnMeta, AdvisoryFinding, AdvisorProcedure, RlsPoliciesResult, MaskPoliciesResult, StorageRulesResult, StudioFeaturesResult, FlagsResult, SubscriptionIdentity, QueuesResult, WorkflowsResult, ImportShardResult, ShardRankPageResult, SubscriptionQuery, ShapeSubscriptionQuery, MutationDelta, KeyRange, ResolvedShape, ShapeRow, TtlSweepSpec, TransactionLimits, IndexKeyEntry, SqlExec, CdcChangeKey } from '@lunora/shard-engine';
|
|
2
2
|
export { type AdvisorProcedure, type AdvisoryFinding, type AggregateIndexDefinitionLike, type DataMigrationLike, type DatabaseWriterLike, type ExportRow, type ExternalSourceLike, type FlagsResult, type ImportShardResult, type KeyRange, type MaskPoliciesResult, type MigrationRunResult, type MutationDelta, type QueuesResult, REPROJECTION_MIGRATION_PREFIX, type RankIndexDefinitionLike, type RlsPoliciesResult, type SchedulerLike, type SchemaLike, type SearchBackfillProgress, type ShardRankPageResult, type SourceClientLike, type SqlExec, type StorageRulesResult, type StudioFeaturesResult, type SystemReaderStorageLike, type TransactionHeadroomTracker, UNVOUCHABLE_DEP, type ValidatorLike, type WhereInput, type WorkflowsResult, type WriteHook, applyCdcChanges, assertShapeShardable, backfillSearchIndexes, buildReprojectionMigration, clearMemoryTables, countLegacyRows, createReadFootprint, createShardCtxDb, exportShardRows, importShardRows, isSourceDue, markUnvouchableReads, pullExternalSourceIncrementalTick, pullExternalSourceTick, reprojectionMigrationId, reprojectionTables, runDataMigration, runShardMigrations, subscriptionListDeltas } from '@lunora/shard-engine';
|
|
3
|
-
import { DatabaseInstrumentation, MetricHistoryOptions, LogEventInput,
|
|
3
|
+
import { ContextLogLevel, DatabaseInstrumentation, MetricHistoryOptions, LogEventInput, TraceAnchor, ContextTracer, ContextFetch, ContextMetrics } from '@lunora/observability';
|
|
4
4
|
import { DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
|
|
5
5
|
export { type ShardPlatform, type WorkerPlatform, type WorkerPlatformOptions, createShardAlarms, createShardDirectory, createShardHost, createShardKvStore, createShardPlatform, createSocketHost, createWorkerPlatform } from '@lunora/platform-cloudflare';
|
|
6
6
|
/**
|
|
@@ -744,24 +744,95 @@ type ClientMutationClass = {
|
|
|
744
744
|
kind: "already" | "gap" | "next";
|
|
745
745
|
};
|
|
746
746
|
/**
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
747
|
+
* The read-set / cache-hit attribution for ONE `/rpc` dispatch, filled in by
|
|
748
|
+
* {@link ShardDO.runCachedQuery} and read back by {@link ShardDO.recordRequestLog}.
|
|
749
|
+
*
|
|
750
|
+
* A mutable object THREADED BY VALUE rather than a `currentRequest*` field on
|
|
751
|
+
* the instance, for the same reason `dispatchHeadroom` and `dispatchTrace`
|
|
752
|
+
* already are: a Durable Object serves concurrent `/rpc` dispatches, and every
|
|
753
|
+
* one of these values is written after the handler's awaits. Off a shared field
|
|
754
|
+
* they were whatever the LAST dispatch to resolve wrote — so the request log
|
|
755
|
+
* filed one request's cache hit and read tables under another's, and a sibling's
|
|
756
|
+
* prologue/epilogue could blank them out entirely. Both fields stay `undefined`
|
|
757
|
+
* when the dispatch never reached the cache (a write/action, a cache-less shard,
|
|
758
|
+
* or a query that fell through the re-entry guard) — the request log renders
|
|
759
|
+
* that as "unknown" rather than asserting a read set.
|
|
760
|
+
*/
|
|
761
|
+
interface QueryAttribution {
|
|
762
|
+
cacheHit?: boolean;
|
|
763
|
+
readTables?: Set<string>;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* The reactive-cache read capture for ONE query dispatch: the dependency
|
|
767
|
+
* tracker the cache indexes the entry by, plus the range footprint its
|
|
768
|
+
* range-precise invalidation reads.
|
|
769
|
+
*
|
|
770
|
+
* Minted by {@link ShardDO.runCachedQuery} and threaded BY VALUE — handed to
|
|
771
|
+
* its `run` callback, on through `handleRpc`'s fourth parameter, and into the
|
|
772
|
+
* generated `buildCtx`, which binds it into the ctx-db read hooks via
|
|
773
|
+
* {@link ShardDO.getCtxDbReadHook} / {@link ShardDO.getCtxDbReadRangeHook}. It
|
|
774
|
+
* is NOT an instance field: a Durable Object serves concurrent `/rpc`
|
|
775
|
+
* dispatches, and a shared field holds one capture for all of them — the second
|
|
776
|
+
* query's reads would land in the first one's dep set and the second would be
|
|
777
|
+
* skipped by the re-entry guard entirely (never read from the cache, never
|
|
778
|
+
* stored).
|
|
779
|
+
*
|
|
780
|
+
* `AsyncLocalStorage` would carry it implicitly, but workerd only enables ALS
|
|
781
|
+
* under `nodejs_compat` and shard DOs run the slimmer `sqlite_compat` profile —
|
|
782
|
+
* see the header of `@lunora/shard-engine`'s `dependency-tracker.ts`.
|
|
783
|
+
*/
|
|
784
|
+
interface QueryReadScope {
|
|
785
|
+
/** Range footprint for this dispatch — the `onReadRange` channel. */
|
|
786
|
+
footprint: ReadFootprint;
|
|
787
|
+
/** Dependency tracker for this dispatch — the `onRead` channel. */
|
|
788
|
+
tracker: DependencyTracker;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Shard-level configuration passed through `super(state, env, …)` by the
|
|
792
|
+
* generated subclass, which sources every key from the app's
|
|
793
|
+
* `createShardDO(config)` argument. A bag rather than positional args so
|
|
794
|
+
* subclasses don't break when a knob lands.
|
|
751
795
|
*/
|
|
752
796
|
interface ShardDOOptions {
|
|
797
|
+
/**
|
|
798
|
+
* Whether every writer this shard builds spreads {@link ShardDO.ctxDbTuning}.
|
|
799
|
+
* The emitter sets it, because it is the only thing that can see inside the
|
|
800
|
+
* generated `buildCtx` and the admin/maintenance writers to know.
|
|
801
|
+
*
|
|
802
|
+
* Left unset (a hand-written subclass), {@link ShardDO.recordChangedTable}
|
|
803
|
+
* keeps its coarse per-table invalidation backstop, so a writer that never
|
|
804
|
+
* received the cache cannot serve a pre-write read. Set wrongly, it would
|
|
805
|
+
* disable that backstop — which is why it is declared rather than inferred
|
|
806
|
+
* from a call to the accessor.
|
|
807
|
+
*/
|
|
808
|
+
ctxDbCacheWired?: boolean;
|
|
809
|
+
/**
|
|
810
|
+
* Ceiling on the join keys one relation-crossing `where` predicate may pull
|
|
811
|
+
* back via semijoin pre-resolution before failing closed. Reaches
|
|
812
|
+
* `createShardCtxDb` through {@link ShardDO.ctxDbTuning}; `undefined` keeps
|
|
813
|
+
* the engine default (`DEFAULT_MAX_RELATION_KEYS`).
|
|
814
|
+
*/
|
|
815
|
+
maxRelationKeys?: number;
|
|
753
816
|
/**
|
|
754
817
|
* Enable the per-shard reactive query cache. When provided, the dispatch
|
|
755
|
-
* path
|
|
756
|
-
* `(functionPath, stable-stringified args)`.
|
|
757
|
-
*
|
|
818
|
+
* path routes every registered `query` through {@link ShardDO.runCachedQuery},
|
|
819
|
+
* memoizing results by `(identity, functionPath, stable-stringified args)`.
|
|
820
|
+
* Omit for the zero-overhead default (every dispatch re-runs the handler).
|
|
758
821
|
*
|
|
759
|
-
* The cache is invisible to the WS subscription bridge: invalidations
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
822
|
+
* The cache is invisible to the WS subscription bridge: invalidations land
|
|
823
|
+
* via the ctx-db write hooks (the `cache` option {@link ShardDO.ctxDbTuning}
|
|
824
|
+
* supplies) BEFORE the broadcast goes out, so subscribers that re-run their
|
|
825
|
+
* queries in response always observe the post-write state.
|
|
763
826
|
*/
|
|
764
827
|
reactiveCache?: ReactiveCacheOptions;
|
|
828
|
+
/**
|
|
829
|
+
* Resolution policy for relation-crossing `where` predicates whose child is
|
|
830
|
+
* co-located in this shard — `"auto"` (cost-based, the engine default),
|
|
831
|
+
* `"always"` (inline correlated EXISTS) or `"never"` (universal semijoin).
|
|
832
|
+
* All three return identical rows. Reaches `createShardCtxDb` through
|
|
833
|
+
* {@link ShardDO.ctxDbTuning}.
|
|
834
|
+
*/
|
|
835
|
+
relationExistsPushDown?: "always" | "auto" | "never";
|
|
765
836
|
}
|
|
766
837
|
/**
|
|
767
838
|
* Threshold at which a `__root__` DO triggers the size warning. 1 GiB —
|
|
@@ -900,15 +971,14 @@ declare abstract class ShardDO {
|
|
|
900
971
|
protected state: ShardDOState;
|
|
901
972
|
protected env: unknown;
|
|
902
973
|
/**
|
|
903
|
-
* Opt-in per-shard reactive query cache.
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
* undefined and the dispatch path runs with zero cache overhead.
|
|
974
|
+
* Opt-in per-shard reactive query cache. Instantiated when the generated
|
|
975
|
+
* subclass passes `reactiveCache` through
|
|
976
|
+
* `super(state, env, { reactiveCache: { … } })`; otherwise undefined and the
|
|
977
|
+
* dispatch path runs with zero cache overhead.
|
|
908
978
|
*
|
|
909
|
-
* The cache is per-shard and in-memory only — it is lost on DO restart
|
|
910
|
-
*
|
|
911
|
-
*
|
|
979
|
+
* The cache is per-shard and in-memory only — it is lost on DO restart and
|
|
980
|
+
* on workerd hibernation. That's fine: a cold shard simply re-runs the query
|
|
981
|
+
* on the first call.
|
|
912
982
|
*/
|
|
913
983
|
protected readonly reactiveCache: ReactiveCache | undefined;
|
|
914
984
|
/**
|
|
@@ -933,6 +1003,21 @@ declare abstract class ShardDO {
|
|
|
933
1003
|
* changelog proved their table had not moved.
|
|
934
1004
|
*/
|
|
935
1005
|
protected globalPoll: GlobalPollCounters;
|
|
1006
|
+
/** ctx-db relation knobs from {@link ShardDOOptions}, handed on by {@link ShardDO.ctxDbTuning}. */
|
|
1007
|
+
private readonly ctxDbRelationOptions;
|
|
1008
|
+
/**
|
|
1009
|
+
* Whether {@link ShardDO.ctxDbTuning} has been consulted, i.e. whether the
|
|
1010
|
+
* subclass's `createShardCtxDb` call is wired to the precise, per-row
|
|
1011
|
+
* invalidation half of the cache contract.
|
|
1012
|
+
*
|
|
1013
|
+
* It gates a coarse fallback in {@link ShardDO.recordChangedTable}: a shard
|
|
1014
|
+
* whose writer never received the cache would otherwise keep serving
|
|
1015
|
+
* memoized results across writes — stale reads, silently. The fallback drops
|
|
1016
|
+
* every entry on a written table, which is strictly more invalidation than
|
|
1017
|
+
* the wired path does, so the two never disagree about correctness; only
|
|
1018
|
+
* about hit rate.
|
|
1019
|
+
*/
|
|
1020
|
+
private readonly ctxDbCacheWired;
|
|
936
1021
|
/**
|
|
937
1022
|
* The host-neutral engine runner. `fetch` and `alarm` delegate through it, so
|
|
938
1023
|
* the dispatch entry points name a platform contract rather than a Durable
|
|
@@ -1369,32 +1454,15 @@ declare abstract class ShardDO {
|
|
|
1369
1454
|
* raw events — production aggregation ships to a collector via the sink.
|
|
1370
1455
|
*/
|
|
1371
1456
|
private readonly metricSeries;
|
|
1372
|
-
/**
|
|
1373
|
-
* In-flight dependency tracker for the currently-executing query. Set by
|
|
1374
|
-
* `runCachedQuery` so the ctx-db hooks (wired via `onRead`) can
|
|
1375
|
-
* stamp deps without threading the tracker explicitly through every
|
|
1376
|
-
* generated handler signature. Cleared in the `finally` of the same
|
|
1377
|
-
* call so a leaked tracker can never bleed into a sibling RPC.
|
|
1378
|
-
*/
|
|
1379
|
-
private currentTracker;
|
|
1380
|
-
/**
|
|
1381
|
-
* In-flight range footprint (the `onReadRange` channel) for the
|
|
1382
|
-
* currently-executing cached query. Set by `runCachedQuery` alongside
|
|
1383
|
-
* `currentTracker` so `getCtxDbReadRangeHook` — and the range-marking half
|
|
1384
|
-
* of `getCtxDbReadHook` — can stamp it without threading it explicitly
|
|
1385
|
-
* through every generated handler signature. `ReactiveCache.run`'s ranges
|
|
1386
|
-
* thunk reads it lazily, AFTER the handler resolves, so it always sees the
|
|
1387
|
-
* footprint's final state. Cleared in the same `finally` as `currentTracker`.
|
|
1388
|
-
*/
|
|
1389
|
-
private currentReadFootprint;
|
|
1390
1457
|
/**
|
|
1391
1458
|
* Tables the in-flight dispatch full-scanned (read via `SCAN_DEP`, no index
|
|
1392
1459
|
* / point lookup). Allocated at the top of each `/rpc` dispatch and drained
|
|
1393
1460
|
* into `recordFunctionCall` once the handler returns, so the durable
|
|
1394
1461
|
* `__lunora_metrics_scans` attribution can pin a slow function to the
|
|
1395
|
-
* table(s) it scanned. Independent of
|
|
1396
|
-
*
|
|
1397
|
-
* even on a cache-less shard.
|
|
1462
|
+
* table(s) it scanned. Independent of the per-dispatch
|
|
1463
|
+
* {@link QueryReadScope} (which only exists when the reactive cache is
|
|
1464
|
+
* enabled), so the causal signal is collected even on a cache-less shard.
|
|
1465
|
+
* Stamped by `getCtxDbReadHook`.
|
|
1398
1466
|
*/
|
|
1399
1467
|
private currentScannedTables;
|
|
1400
1468
|
/**
|
|
@@ -1414,18 +1482,6 @@ declare abstract class ShardDO {
|
|
|
1414
1482
|
* down with it.
|
|
1415
1483
|
*/
|
|
1416
1484
|
private currentTransactionHeadroom;
|
|
1417
|
-
/**
|
|
1418
|
-
* Read-tables + cache-hit captured for the current `/rpc` dispatch, so the
|
|
1419
|
-
* dispatch site can fold them into the durable request log
|
|
1420
|
-
* (`request-log.ts`). Populated by `runCachedQuery` — the one place that
|
|
1421
|
-
* both holds the per-query dependency tracker AND learns whether the
|
|
1422
|
-
* reactive cache served the result — and reset per request in `fetch`.
|
|
1423
|
-
* `undefined`/empty when the reactive cache is disabled or the path is a
|
|
1424
|
-
* write/action (which doesn't run through the cache), which is exactly why
|
|
1425
|
-
* the request log treats those fields as "unknown" rather than asserting a
|
|
1426
|
-
* read set on the hot path.
|
|
1427
|
-
*/
|
|
1428
|
-
private currentRequestReadTables;
|
|
1429
1485
|
/**
|
|
1430
1486
|
* Per-DISTINCT-statement SQL samples collected during the current `/rpc`
|
|
1431
1487
|
* dispatch by the instrumented `sql` getter, keyed by the raw query text.
|
|
@@ -1471,8 +1527,6 @@ declare abstract class ShardDO {
|
|
|
1471
1527
|
* leaderboard contribution reads as partial rather than complete.
|
|
1472
1528
|
*/
|
|
1473
1529
|
private currentStmtSamplesTruncated;
|
|
1474
|
-
/** Whether the current dispatch's cached query was served from cache; `undefined` until `runCachedQuery` resolves one. */
|
|
1475
|
-
private currentRequestCacheHit;
|
|
1476
1530
|
constructor(state: ShardDOState, env: unknown, options?: ShardDOOptions);
|
|
1477
1531
|
/**
|
|
1478
1532
|
* Worker-side fetch entry point. Delegates to the host-neutral
|
|
@@ -1534,8 +1588,17 @@ declare abstract class ShardDO {
|
|
|
1534
1588
|
* their own tracker (`dispatchLifecycle`, `handleRunAs`) omit it and the
|
|
1535
1589
|
* codegen subclass falls back to `this.transactionHeadroom()`, unchanged from
|
|
1536
1590
|
* before this parameter existed.
|
|
1591
|
+
*
|
|
1592
|
+
* `scope` is the same shape of BY-VALUE thread for the reactive cache: the
|
|
1593
|
+
* `/rpc` query path routes through {@link ShardDO.runCachedQuery}, which
|
|
1594
|
+
* mints a {@link QueryReadScope} per dispatch and passes it here so the ctx
|
|
1595
|
+
* this dispatch builds stamps reads into ITS OWN tracker and footprint.
|
|
1596
|
+
* Implementations must hand it to `getCtxDbReadHook(scope)` /
|
|
1597
|
+
* `getCtxDbReadRangeHook(scope)` on the `createShardCtxDb(...)` call that
|
|
1598
|
+
* builds the ctx; both factories return unbound (tracker-less) hooks when it
|
|
1599
|
+
* is omitted, which is what every non-cached dispatch passes.
|
|
1537
1600
|
*/
|
|
1538
|
-
abstract handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker): Promise<unknown>;
|
|
1601
|
+
abstract handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker, scope?: QueryReadScope): Promise<unknown>;
|
|
1539
1602
|
/**
|
|
1540
1603
|
* The registered function paths to dispatch on a lifecycle moment —
|
|
1541
1604
|
* `connect`/`disconnect` per socket, `init` once per Durable Object instance,
|
|
@@ -2614,30 +2677,36 @@ declare abstract class ShardDO {
|
|
|
2614
2677
|
iterator: (signal: AbortSignal) => AsyncIterable<unknown>;
|
|
2615
2678
|
};
|
|
2616
2679
|
/**
|
|
2617
|
-
* Wrap a query handler in the reactive cache. The
|
|
2618
|
-
*
|
|
2619
|
-
*
|
|
2620
|
-
*
|
|
2621
|
-
*
|
|
2622
|
-
*
|
|
2623
|
-
*
|
|
2624
|
-
*
|
|
2625
|
-
*
|
|
2680
|
+
* Wrap a query handler in the reactive cache. The `/rpc` dispatch path calls
|
|
2681
|
+
* this for every path {@link ShardDO.isQueryFunction} recognises, so a
|
|
2682
|
+
* subclass does NOT wrap its own `handleRpc` — see the re-entry guard below
|
|
2683
|
+
* for why doing both would be worse than doing neither. When the cache is
|
|
2684
|
+
* configured we key by `(identity, functionPath, stable-stringified args)`,
|
|
2685
|
+
* mint a fresh {@link QueryReadScope} (dep tracker + read footprint) and
|
|
2686
|
+
* hand it to `run` — which threads it through `handleRpc` into the ctx the
|
|
2687
|
+
* handler reads through, so this dispatch's reads stamp THIS dispatch's
|
|
2688
|
+
* tracker even while a sibling dispatch is parked on an await. When the
|
|
2689
|
+
* cache is absent we just call `run()` with no scope — same shape, zero
|
|
2690
|
+
* overhead.
|
|
2691
|
+
*
|
|
2692
|
+
* Subclasses must ALSO pass `getCtxDbReadHook(scope)` as the `onRead`
|
|
2626
2693
|
* option on their `createShardCtxDb(...)` call so the tracker actually
|
|
2627
|
-
* collects deps. Without that wiring the cache
|
|
2628
|
-
*
|
|
2629
|
-
*
|
|
2630
|
-
*
|
|
2631
|
-
*
|
|
2632
|
-
*
|
|
2633
|
-
*
|
|
2634
|
-
*
|
|
2694
|
+
* collects deps. Without that wiring the cache memoizes results with empty
|
|
2695
|
+
* dep sets, so the write hooks never invalidate them — the
|
|
2696
|
+
* {@link ReactiveCache} class is contract-neutral about who fills `deps`,
|
|
2697
|
+
* and dep-less entries survive `invalidate` AND `invalidateTable` alike, so
|
|
2698
|
+
* neither the ctx-db hooks nor the {@link ShardDO.recordChangedTable}
|
|
2699
|
+
* backstop can rescue that omission.
|
|
2700
|
+
*
|
|
2701
|
+
* The scope's {@link ReadFootprint} is the ranges channel:
|
|
2702
|
+
* `getCtxDbReadRangeHook(scope)` — and the range-marking half of
|
|
2703
|
+
* `getCtxDbReadHook(scope)` — stamp it. Its
|
|
2635
2704
|
* `ranges()` is handed to `reactiveCache.run` as a LAZY 4th argument (a
|
|
2636
2705
|
* thunk, evaluated only after `run()` resolves), the same deferral
|
|
2637
2706
|
* `deps` already relies on: the footprint is only complete once the
|
|
2638
2707
|
* handler has actually run. Subclasses that also want range-precise
|
|
2639
|
-
* invalidation should pass `getCtxDbReadRangeHook()` as `onReadRange`
|
|
2640
|
-
* the same `createShardCtxDb(...)` call — mirroring `onRead` above. A
|
|
2708
|
+
* invalidation should pass `getCtxDbReadRangeHook(scope)` as `onReadRange`
|
|
2709
|
+
* on the same `createShardCtxDb(...)` call — mirroring `onRead` above. A
|
|
2641
2710
|
* subclass that only wires `onRead` still works: `ranges()` degrades to
|
|
2642
2711
|
* `undefined` and every read is treated as a whole-table dependency, per
|
|
2643
2712
|
* `ReactiveCache.run`'s own default. When `onReadRange` IS wired, a table
|
|
@@ -2647,22 +2716,24 @@ declare abstract class ShardDO {
|
|
|
2647
2716
|
* method's body. Only a table read EXCLUSIVELY through provable ranges
|
|
2648
2717
|
* gets range-precise invalidation instead.
|
|
2649
2718
|
*/
|
|
2650
|
-
protected runCachedQuery<R>(functionPath: string, args: Record<string, unknown>, run: () => Promise<R
|
|
2719
|
+
protected runCachedQuery<R>(functionPath: string, args: Record<string, unknown>, run: (scope?: QueryReadScope) => Promise<R>, attribution?: QueryAttribution, outer?: QueryReadScope): Promise<R>;
|
|
2651
2720
|
/**
|
|
2652
2721
|
* Returns an `onRead` callback suitable to hand to `createShardCtxDb`'s
|
|
2653
|
-
* `onRead` option
|
|
2654
|
-
*
|
|
2722
|
+
* `onRead` option, BOUND to the dispatch whose {@link QueryReadScope} is
|
|
2723
|
+
* passed in. `runCachedQuery` mints that scope and threads it through
|
|
2724
|
+
* `handleRpc`; a dispatch with no cache scope (a mutation, an action, a
|
|
2725
|
+
* cache-less shard) passes nothing and gets a hook that stamps no deps — so
|
|
2655
2726
|
* subclasses can wire this hook unconditionally without checking whether
|
|
2656
2727
|
* the cache is enabled.
|
|
2657
2728
|
*
|
|
2658
2729
|
* It ALSO records the table into {@link currentScannedTables} whenever the
|
|
2659
|
-
* read was a full-table scan (the `SCAN_DEP` sentinel)
|
|
2660
|
-
* into `recordFunctionCall` after dispatch to build the
|
|
2661
|
-
* full-scan attribution —
|
|
2662
|
-
* the reactive cache is off, since the causal signal is
|
|
2663
|
-
* caching.
|
|
2730
|
+
* read was a full-table scan (the `SCAN_DEP` sentinel), scope or no scope.
|
|
2731
|
+
* That set is drained into `recordFunctionCall` after dispatch to build the
|
|
2732
|
+
* durable per-function full-scan attribution — unlike the tracker, it's
|
|
2733
|
+
* collected even when the reactive cache is off, since the causal signal is
|
|
2734
|
+
* independent of caching.
|
|
2664
2735
|
*
|
|
2665
|
-
* It ALSO marks the table unnarrowable on
|
|
2736
|
+
* It ALSO marks the table unnarrowable on the scope's `footprint`,
|
|
2666
2737
|
* mirroring `executeSubscription`'s wiring (which hands a single
|
|
2667
2738
|
* `ReadFootprint`'s `onRead`/`onReadRange` pair straight to `buildCtx`).
|
|
2668
2739
|
* `ctx-db.ts`'s reader calls this `onRead` and `onReadRange` mutually
|
|
@@ -2672,19 +2743,20 @@ declare abstract class ShardDO {
|
|
|
2672
2743
|
* "read this table outside a range" signal {@link ReadFootprint.ranges}
|
|
2673
2744
|
* needs to drop that table from the narrowed set.
|
|
2674
2745
|
*/
|
|
2675
|
-
protected getCtxDbReadHook(): (table: string, idOrScan?: string) => void;
|
|
2746
|
+
protected getCtxDbReadHook(scope?: QueryReadScope): (table: string, idOrScan?: string) => void;
|
|
2676
2747
|
/**
|
|
2677
2748
|
* Returns an `onReadRange` callback suitable to hand to
|
|
2678
|
-
* `createShardCtxDb`'s `onReadRange` option, alongside
|
|
2679
|
-
* as `onRead` on the same call — the pairing
|
|
2680
|
-
* uses via `ReadFootprint`. Stamps the
|
|
2681
|
-
*
|
|
2682
|
-
* can wire this hook unconditionally regardless of
|
|
2683
|
-
* enabled. Without this wiring `runCachedQuery`'s
|
|
2684
|
-
* observes an empty footprint and every cached query
|
|
2685
|
-
* whole-table dependency — safe, just not
|
|
2686
|
-
|
|
2687
|
-
|
|
2749
|
+
* `createShardCtxDb`'s `onReadRange` option, alongside
|
|
2750
|
+
* `getCtxDbReadHook(scope)` as `onRead` on the same call — the pairing
|
|
2751
|
+
* `executeSubscription` already uses via `ReadFootprint`. Stamps the
|
|
2752
|
+
* footprint of the {@link QueryReadScope} passed in and is a no-op when
|
|
2753
|
+
* none is, so subclasses can wire this hook unconditionally regardless of
|
|
2754
|
+
* whether the cache is enabled. Without this wiring `runCachedQuery`'s
|
|
2755
|
+
* ranges thunk always observes an empty footprint and every cached query
|
|
2756
|
+
* degrades to the prior whole-table dependency — safe, just not
|
|
2757
|
+
* range-precise.
|
|
2758
|
+
*/
|
|
2759
|
+
protected getCtxDbReadRangeHook(scope?: QueryReadScope): (range: KeyRange) => void;
|
|
2688
2760
|
/**
|
|
2689
2761
|
* Read hook recording which declared indexes a query actually exercises.
|
|
2690
2762
|
* Two destinations, both stamped here so a single hook serves the live and
|
|
@@ -2698,6 +2770,52 @@ declare abstract class ShardDO {
|
|
|
2698
2770
|
* to `createShardCtxDb` by the generated subclass.
|
|
2699
2771
|
*/
|
|
2700
2772
|
protected getCtxDbIndexUseHook(): (table: string, indexName: string) => void;
|
|
2773
|
+
/**
|
|
2774
|
+
* The `createShardCtxDb` options this DO's configuration decides, as one
|
|
2775
|
+
* spreadable slice: the reactive cache (invalidation half of the contract)
|
|
2776
|
+
* plus the two relation-resolution knobs from {@link ShardDOOptions}.
|
|
2777
|
+
*
|
|
2778
|
+
* The generated `buildCtx` spreads this FIRST into its `createShardCtxDb`
|
|
2779
|
+
* call, so a per-request option it sets afterwards still wins:
|
|
2780
|
+
*
|
|
2781
|
+
* ```ts
|
|
2782
|
+
* createShardCtxDb({ ...this.ctxDbTuning(), auth: …, schema, sql, … })
|
|
2783
|
+
* ```
|
|
2784
|
+
*
|
|
2785
|
+
* One accessor rather than three, because it is one decision — "how this
|
|
2786
|
+
* deployment configured its ctx-db" — and the emitter should not have to
|
|
2787
|
+
* grow a line per knob. Only keys the app actually set are present, so
|
|
2788
|
+
* spreading never overwrites an engine default with `undefined`.
|
|
2789
|
+
*
|
|
2790
|
+
* Handing over `cache` is what makes writes invalidate at row + index-range
|
|
2791
|
+
* precision (`ctx-db.ts` calls `cache.invalidate(table, id, indexKeys)` on
|
|
2792
|
+
* every `insert`/`patch`/`replace`/`delete`). EVERY writer the emitter builds
|
|
2793
|
+
* spreads this — the user-facing ctx and all three admin/maintenance writers —
|
|
2794
|
+
* because a writer that skips it leaves post-write reads answering from the
|
|
2795
|
+
* pre-write snapshot.
|
|
2796
|
+
*
|
|
2797
|
+
* Pure: it reports the slice and records nothing. Whether the emitter actually
|
|
2798
|
+
* wired it is a fact the emitter knows statically and declares through
|
|
2799
|
+
* {@link ShardDOOptions.ctxDbCacheWired}; inferring it from a call to this
|
|
2800
|
+
* accessor made reading the slice — in a test, or to log it — silently disarm
|
|
2801
|
+
* the invalidation backstop in {@link ShardDO.recordChangedTable}.
|
|
2802
|
+
*/
|
|
2803
|
+
protected ctxDbTuning(): {
|
|
2804
|
+
cache?: ReactiveCache;
|
|
2805
|
+
maxRelationKeys?: number;
|
|
2806
|
+
relationExistsPushDown?: "always" | "auto" | "never";
|
|
2807
|
+
};
|
|
2808
|
+
/**
|
|
2809
|
+
* Whether `functionPath` names a registered `query` — the only kind whose
|
|
2810
|
+
* result may be memoized by the reactive cache.
|
|
2811
|
+
*
|
|
2812
|
+
* The base class has no function registry, so the default is `false`: the
|
|
2813
|
+
* conservative answer, since caching an `action` would skip its outbound
|
|
2814
|
+
* side effects on a hit and caching a `mutation` is meaningless. The
|
|
2815
|
+
* codegen-generated subclass overrides it with the real `LUNORA_FUNCTIONS`
|
|
2816
|
+
* lookup, which is what production dispatch uses.
|
|
2817
|
+
*/
|
|
2818
|
+
protected isQueryFunction(_functionPath: string): boolean;
|
|
2701
2819
|
/**
|
|
2702
2820
|
* Ceilings for one transaction. The base class uses the engine defaults
|
|
2703
2821
|
* (sized for a 128 MiB Durable Object isolate); a subclass overrides this
|
|
@@ -3547,10 +3665,15 @@ declare abstract class ShardDO {
|
|
|
3547
3665
|
* The correlated fields all come from data the dispatch already holds, with
|
|
3548
3666
|
* no extra hot-path bookkeeping. `tablesWritten` is snapshotted from
|
|
3549
3667
|
* `pendingChangedTables` by the caller before `flushChangedTables` drains it.
|
|
3550
|
-
* `tablesRead` and `cacheHit`
|
|
3551
|
-
*
|
|
3552
|
-
* the
|
|
3553
|
-
*
|
|
3668
|
+
* `tablesRead` and `cacheHit` arrive in `attribution`, the per-dispatch
|
|
3669
|
+
* object `beginDispatch` minted and `runCachedQuery` filled in — passed BY
|
|
3670
|
+
* VALUE for the same reason `trace` is, since both are read here, after the
|
|
3671
|
+
* handler's awaits, where a shared field belongs to whichever concurrent
|
|
3672
|
+
* dispatch resolved last. They are present only for cached query paths — a
|
|
3673
|
+
* write/action doesn't run through the cache, an instance with the reactive
|
|
3674
|
+
* cache disabled never captures them, and a query that hit the re-entry
|
|
3675
|
+
* guard passed through uncached — and are left empty/`undefined` rather
|
|
3676
|
+
* than recomputed here.
|
|
3554
3677
|
* `subscriptionsReRun` is left `0`: the write-driven subscription refresh
|
|
3555
3678
|
* runs off the response path via `waitUntil` (see `flushChangedTables`), so a
|
|
3556
3679
|
* per-request count isn't available synchronously at this site, and threading
|
|
@@ -3711,7 +3834,7 @@ declare abstract class ShardDO {
|
|
|
3711
3834
|
* per identity), and a flag read ({@link FLAGS_FUNCTION_PREFIX}) evaluates
|
|
3712
3835
|
* the provider with the subscriber's identity (per-user targeting). Sharing
|
|
3713
3836
|
* one socket's result with another would leak one identity's rows/flags to a
|
|
3714
|
-
* different identity, so this predicate gates {@link resolveReactiveOutcomeDeduped}
|
|
3837
|
+
* different identity, so this predicate gates {@link ShardDO.resolveReactiveOutcomeDeduped}
|
|
3715
3838
|
* shut for them.
|
|
3716
3839
|
*/
|
|
3717
3840
|
protected isIdentityIndependent(functionPath: string): boolean;
|
|
@@ -3835,15 +3958,20 @@ declare abstract class ShardDO {
|
|
|
3835
3958
|
* run would have to fan one failure to every sharing socket while preserving
|
|
3836
3959
|
* the "leave memo untouched ⇒ re-run next flush" contract.
|
|
3837
3960
|
*
|
|
3838
|
-
* The
|
|
3839
|
-
*
|
|
3840
|
-
*
|
|
3841
|
-
* `
|
|
3842
|
-
*
|
|
3843
|
-
*
|
|
3844
|
-
*
|
|
3845
|
-
*
|
|
3846
|
-
*
|
|
3961
|
+
* The opt-in {@link ReactiveCache} (`ShardDOOptions.reactiveCache`) does NOT
|
|
3962
|
+
* cover this, despite the shared key shape: it wraps `/rpc` query dispatch
|
|
3963
|
+
* (see {@link ShardDO.runCachedQuery}), while a refresh runs through
|
|
3964
|
+
* `executeSubscription`, which never consults it. It cannot, either — a
|
|
3965
|
+
* subscription's re-run is only half about the value. The other half is the
|
|
3966
|
+
* `tables`/`ranges` footprint it reports, which is what decides whether the
|
|
3967
|
+
* NEXT write re-runs it; a cache hit produces a value with no footprint, so
|
|
3968
|
+
* routing refreshes through the cache would quietly empty every memo's
|
|
3969
|
+
* dependency set and stop the subscription updating at all.
|
|
3970
|
+
*
|
|
3971
|
+
* So this fan-out stands as characterized. Collapsing it needs a dedup that
|
|
3972
|
+
* shares the footprint alongside the value — {@link ShardDO.resolveReactiveOutcomeDeduped}
|
|
3973
|
+
* is that, per flush, for the identity-independent subset — not a second
|
|
3974
|
+
* memo bolted into this loop.
|
|
3847
3975
|
*/
|
|
3848
3976
|
/**
|
|
3849
3977
|
* Count and log a subscription-delivery error that its caller is about to
|
|
@@ -4493,11 +4621,6 @@ declare abstract class ShardDO {
|
|
|
4493
4621
|
private deliverWhisperLocal;
|
|
4494
4622
|
private readAttachment;
|
|
4495
4623
|
}
|
|
4496
|
-
/**
|
|
4497
|
-
* @deprecated Renamed to {@link TelemetrySink} — it carries spans and metrics as
|
|
4498
|
-
* well as logs. Kept as an alias so existing import sites keep working.
|
|
4499
|
-
*/
|
|
4500
|
-
type LogSink = TelemetrySink;
|
|
4501
4624
|
/** Conventional DO instance name, passed to `idFromName` to address the single registry instance. */
|
|
4502
4625
|
declare const SHARD_REGISTRY_DO_NAME: string;
|
|
4503
4626
|
/**
|
|
@@ -4557,4 +4680,4 @@ declare class ShardRegistryDO {
|
|
|
4557
4680
|
/** The in-memory map as a JSON-safe `table → [keys]` object. */
|
|
4558
4681
|
private serializeTables;
|
|
4559
4682
|
}
|
|
4560
|
-
export { type HibernatableWebSocket, type
|
|
4683
|
+
export { type HibernatableWebSocket, type QueryReadScope, ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, type RunShardApplyCdcArgs, type RunShardApplyCdcResult, type RunShardBulkDeleteArgs, type RunShardBulkDeleteResult, type RunShardExportArgs, type RunShardImportArgs, type RunShardMigrationArgs, type RunShardRankBeforeArgs, type RunShardRankPageArgs, type RunShardWriteArgs, type RunShardWriteResult, SESSION_DO_TTL_DEFAULT, SHARD_REGISTRY_DO_NAME, SessionDO, type SessionRecord, ShardDO, type ShardDOOptions, type ShardDOState, ShardRegistryDO, type SubscriptionOutcome, type TelemetrySink, type TraceRefLike, serveRelationFanout };
|