@lunora/do 1.0.0-alpha.32 → 1.0.0-alpha.33
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 +71 -21
- package/dist/index.d.ts +71 -21
- package/dist/index.mjs +6 -6
- package/dist/packem_shared/{CDC_LOG_TABLE-DjJEHiM2.mjs → CDC_LOG_TABLE-uwOJxJJZ.mjs} +1 -1
- package/dist/packem_shared/{NotUniqueError-BigrdT_W.mjs → NotUniqueError-Ca21uDuU.mjs} +3 -3
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-BWz51mpB.mjs → ROOT_DO_SIZE_WARN_BYTES-afQHUhyA.mjs} +71 -31
- package/dist/packem_shared/{isSoftDeleted-i5kKh6Up.mjs → isSoftDeleted-YLKR6JYw.mjs} +39 -5
- package/dist/packem_shared/{materializeExternalRows-FyA5Rwn4.mjs → materializeExternalRows-DlQWMlw_.mjs} +5 -2
- package/dist/packem_shared/{runShardMigrations-BGx4v2B6.mjs → runShardMigrations-DFzx6Qld.mjs} +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -2499,13 +2499,31 @@ interface ExternalSourceLike {
|
|
|
2499
2499
|
softDeleteColumn?: string;
|
|
2500
2500
|
tenantBy?: (shardKey: string) => ReadonlyArray<unknown>;
|
|
2501
2501
|
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Coerce a driver-native value that `stableStringify` can't represent (see
|
|
2504
|
+
* `shared/stable-key.ts`) into its JSON-safe form: a `Date` → its ISO string, a
|
|
2505
|
+
* `bigint` → its decimal string. Every other value passes through unchanged.
|
|
2506
|
+
*
|
|
2507
|
+
* node-pg / postgres-js / mysql2 return `timestamp`/`datetime` columns as JS
|
|
2508
|
+
* `Date` and `bigint`/`int8` columns as `bigint` — both throw a `TypeError` out of
|
|
2509
|
+
* `stableStringify` (used by the full-pull diff and the incremental content
|
|
2510
|
+
* short-circuit), which bricks ingest for any table with such a column (e.g. the
|
|
2511
|
+
* canonical `cursor: { column: "updated_at" }` incremental config). This is the
|
|
2512
|
+
* single boundary where driver-native types cross into DO SQLite JSON; a new
|
|
2513
|
+
* source driver (or a new non-JSON column type) must be normalized here too.
|
|
2514
|
+
* `shared/stable-key.ts`'s throw contract is intentionally left unchanged — this
|
|
2515
|
+
* normalizes the value *before* it can ever reach that encoder.
|
|
2516
|
+
*/
|
|
2517
|
+
|
|
2502
2518
|
/**
|
|
2503
2519
|
* Lift an external row to a Lunora document: the `idColumn` value becomes a
|
|
2504
2520
|
* stringified `_id`, then either `map` shapes the body or every other column is
|
|
2505
2521
|
* copied verbatim. Throws on a missing/null id, and on a non-scalar id, so a
|
|
2506
2522
|
* misconfigured query fails loudly instead of materializing rows under the literal
|
|
2507
2523
|
* id `"undefined"` (or collapsing many rows onto one id). Shared with
|
|
2508
|
-
* `@lunora/hyperdrive`'s `projectSourceRow`.
|
|
2524
|
+
* `@lunora/hyperdrive`'s `projectSourceRow`. The returned document's values are
|
|
2525
|
+
* normalized (see {@link normalizeSourceValue}) so a `Date`/`bigint` column never
|
|
2526
|
+
* reaches `stableStringify` un-normalized.
|
|
2509
2527
|
*/
|
|
2510
2528
|
declare const liftSourceId: (row: Record<string, unknown>, options?: {
|
|
2511
2529
|
idColumn?: string;
|
|
@@ -4402,6 +4420,19 @@ declare abstract class ShardDO {
|
|
|
4402
4420
|
private static rootSizeWarned;
|
|
4403
4421
|
/** Test-only: reset the static "warned once" flag. */
|
|
4404
4422
|
static resetRootSizeWarning(): void;
|
|
4423
|
+
/**
|
|
4424
|
+
* Compute the shared poll alarm's next wake time from both tiers' signals.
|
|
4425
|
+
* Global shapes need the fixed `GLOBAL_SHAPE_POLL_INTERVAL_MS` floor whenever
|
|
4426
|
+
* any are subscribed (a global table has no per-DO op-log, so it can only be
|
|
4427
|
+
* polled). External-source ingest instead reports the earliest NEXT-DUE
|
|
4428
|
+
* timestamp across its non-manual sources (or `undefined` when none exist) —
|
|
4429
|
+
* a source with a large `refresh.everyMs` must sleep until it's actually due,
|
|
4430
|
+
* not spin at the global-shape floor. Returns `undefined` when NEITHER tier
|
|
4431
|
+
* has pending work, so the DO can go fully idle instead of re-arming for no
|
|
4432
|
+
* reason; otherwise the earlier of the two candidate times (never later than
|
|
4433
|
+
* `nowMs`, so a source that's already due arms essentially immediately).
|
|
4434
|
+
*/
|
|
4435
|
+
private static nextPollAlarmTarget;
|
|
4405
4436
|
protected state: ShardDOState;
|
|
4406
4437
|
protected env: unknown;
|
|
4407
4438
|
/**
|
|
@@ -4733,12 +4764,17 @@ declare abstract class ShardDO {
|
|
|
4733
4764
|
/** Hibernation API: invoked on socket error. */
|
|
4734
4765
|
webSocketError(_ws: WebSocket, _error: unknown): void;
|
|
4735
4766
|
/**
|
|
4736
|
-
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes
|
|
4737
|
-
*
|
|
4738
|
-
*
|
|
4739
|
-
*
|
|
4740
|
-
*
|
|
4741
|
-
*
|
|
4767
|
+
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes
|
|
4768
|
+
* AND external-source (`.source(...)`) ingest, which share one alarm. The
|
|
4769
|
+
* runtime wakes this when the poll alarm armed by `scheduleGlobalPoll` fires;
|
|
4770
|
+
* it refreshes every subscribed global shape (diff-poke from the global
|
|
4771
|
+
* backend), materializes any due sourced tables, and re-arms at
|
|
4772
|
+
* {@link ShardDO.nextPollAlarmTarget} — the fixed floor while global shapes
|
|
4773
|
+
* are subscribed, or the earliest source next-due time when only ingest
|
|
4774
|
+
* remains (so a 1-hour-`refresh` source sleeps ~1 hour instead of waking
|
|
4775
|
+
* every 2 s). With neither tier pending, the alarm is not re-armed and the DO
|
|
4776
|
+
* goes idle. A base-only / global-free / source-free DO never arms it, so
|
|
4777
|
+
* this stays dormant there.
|
|
4742
4778
|
*/
|
|
4743
4779
|
alarm(): Promise<void>;
|
|
4744
4780
|
/** Subclasses implement function dispatch. */
|
|
@@ -5405,16 +5441,23 @@ declare abstract class ShardDO {
|
|
|
5405
5441
|
/**
|
|
5406
5442
|
* Poll external-source (`.source(...)`) tables once (plan 077): materialize
|
|
5407
5443
|
* each sourced table's freshly-pulled tenant slice into this DO's SQLite. The
|
|
5408
|
-
* base `ShardDO` has no sourced tables, so it returns `
|
|
5409
|
-
* stays dormant — zero behavior change for every existing DO. The
|
|
5410
|
-
* subclass overrides it to, per sourced table, build a
|
|
5411
|
-
* writer, read the tenant slice from Hyperdrive under this
|
|
5412
|
-
* run `runExternalSourceTick` (read local baseline → diff
|
|
5413
|
-
* validated CDC writer).
|
|
5414
|
-
*
|
|
5415
|
-
*
|
|
5444
|
+
* base `ShardDO` has no sourced tables, so it returns `undefined` and the
|
|
5445
|
+
* ingest tier stays dormant — zero behavior change for every existing DO. The
|
|
5446
|
+
* codegen subclass overrides it to, per sourced table, build a
|
|
5447
|
+
* `createShardCtxDb` writer, read the tenant slice from Hyperdrive under this
|
|
5448
|
+
* DO's shard key, and run `runExternalSourceTick` (read local baseline → diff
|
|
5449
|
+
* → apply via the validated CDC writer).
|
|
5450
|
+
*
|
|
5451
|
+
* Returns the EARLIEST next-due timestamp (absolute epoch ms) across every
|
|
5452
|
+
* non-manual sourced table — `polledAt.get(table) ?? now` plus that source's
|
|
5453
|
+
* `refresh.everyMs` — or `undefined` when every sourced table is
|
|
5454
|
+
* `refresh: "manual"` (or there are none). NOT a bare active count: the
|
|
5455
|
+
* shared poll alarm ({@link ShardDO.alarm}) uses this to re-arm at the exact
|
|
5456
|
+
* next time ingest needs to run, instead of spinning at the fixed
|
|
5457
|
+
* `GLOBAL_SHAPE_POLL_INTERVAL_MS` floor for a source whose `refresh.everyMs`
|
|
5458
|
+
* is, say, an hour away.
|
|
5416
5459
|
*/
|
|
5417
|
-
protected pollExternalSources(): Promise<number>;
|
|
5460
|
+
protected pollExternalSources(): Promise<number | undefined>;
|
|
5418
5461
|
/**
|
|
5419
5462
|
* Arm the shared poll alarm for external-source ingest (plan 077). The alarm is
|
|
5420
5463
|
* shared with the global-shape poll tier; the codegen subclass calls this once
|
|
@@ -6414,11 +6457,18 @@ declare abstract class ShardDO {
|
|
|
6414
6457
|
*/
|
|
6415
6458
|
private saveGlobalSnapshot;
|
|
6416
6459
|
/**
|
|
6417
|
-
* Arm the poll alarm
|
|
6418
|
-
*
|
|
6419
|
-
*
|
|
6420
|
-
*
|
|
6421
|
-
*
|
|
6460
|
+
* Arm the poll alarm if one isn't already pending. Idempotent — every
|
|
6461
|
+
* global-shape seed calls it, but only the first arms the alarm. Degrades to
|
|
6462
|
+
* a no-op when the runtime exposes no `setAlarm` (the unit harness): a global
|
|
6463
|
+
* shape is then seed-only, which the poll-loop tests assert by driving
|
|
6464
|
+
* {@link ShardDO.alarm} directly.
|
|
6465
|
+
*
|
|
6466
|
+
* `atMs` lets {@link ShardDO.alarm} re-arm at a computed target — the
|
|
6467
|
+
* earlier of the fixed global-shape floor and the earliest external-source
|
|
6468
|
+
* next-due time — instead of always the fixed floor. Every OTHER caller
|
|
6469
|
+
* (a fresh global-shape seed, {@link ShardDO.scheduleSourcePoll}'s initial
|
|
6470
|
+
* kick) omits it and gets the original `GLOBAL_SHAPE_POLL_INTERVAL_MS`
|
|
6471
|
+
* default, since neither knows a more precise due time yet.
|
|
6422
6472
|
*/
|
|
6423
6473
|
private scheduleGlobalPoll;
|
|
6424
6474
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -2499,13 +2499,31 @@ interface ExternalSourceLike {
|
|
|
2499
2499
|
softDeleteColumn?: string;
|
|
2500
2500
|
tenantBy?: (shardKey: string) => ReadonlyArray<unknown>;
|
|
2501
2501
|
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Coerce a driver-native value that `stableStringify` can't represent (see
|
|
2504
|
+
* `shared/stable-key.ts`) into its JSON-safe form: a `Date` → its ISO string, a
|
|
2505
|
+
* `bigint` → its decimal string. Every other value passes through unchanged.
|
|
2506
|
+
*
|
|
2507
|
+
* node-pg / postgres-js / mysql2 return `timestamp`/`datetime` columns as JS
|
|
2508
|
+
* `Date` and `bigint`/`int8` columns as `bigint` — both throw a `TypeError` out of
|
|
2509
|
+
* `stableStringify` (used by the full-pull diff and the incremental content
|
|
2510
|
+
* short-circuit), which bricks ingest for any table with such a column (e.g. the
|
|
2511
|
+
* canonical `cursor: { column: "updated_at" }` incremental config). This is the
|
|
2512
|
+
* single boundary where driver-native types cross into DO SQLite JSON; a new
|
|
2513
|
+
* source driver (or a new non-JSON column type) must be normalized here too.
|
|
2514
|
+
* `shared/stable-key.ts`'s throw contract is intentionally left unchanged — this
|
|
2515
|
+
* normalizes the value *before* it can ever reach that encoder.
|
|
2516
|
+
*/
|
|
2517
|
+
|
|
2502
2518
|
/**
|
|
2503
2519
|
* Lift an external row to a Lunora document: the `idColumn` value becomes a
|
|
2504
2520
|
* stringified `_id`, then either `map` shapes the body or every other column is
|
|
2505
2521
|
* copied verbatim. Throws on a missing/null id, and on a non-scalar id, so a
|
|
2506
2522
|
* misconfigured query fails loudly instead of materializing rows under the literal
|
|
2507
2523
|
* id `"undefined"` (or collapsing many rows onto one id). Shared with
|
|
2508
|
-
* `@lunora/hyperdrive`'s `projectSourceRow`.
|
|
2524
|
+
* `@lunora/hyperdrive`'s `projectSourceRow`. The returned document's values are
|
|
2525
|
+
* normalized (see {@link normalizeSourceValue}) so a `Date`/`bigint` column never
|
|
2526
|
+
* reaches `stableStringify` un-normalized.
|
|
2509
2527
|
*/
|
|
2510
2528
|
declare const liftSourceId: (row: Record<string, unknown>, options?: {
|
|
2511
2529
|
idColumn?: string;
|
|
@@ -4402,6 +4420,19 @@ declare abstract class ShardDO {
|
|
|
4402
4420
|
private static rootSizeWarned;
|
|
4403
4421
|
/** Test-only: reset the static "warned once" flag. */
|
|
4404
4422
|
static resetRootSizeWarning(): void;
|
|
4423
|
+
/**
|
|
4424
|
+
* Compute the shared poll alarm's next wake time from both tiers' signals.
|
|
4425
|
+
* Global shapes need the fixed `GLOBAL_SHAPE_POLL_INTERVAL_MS` floor whenever
|
|
4426
|
+
* any are subscribed (a global table has no per-DO op-log, so it can only be
|
|
4427
|
+
* polled). External-source ingest instead reports the earliest NEXT-DUE
|
|
4428
|
+
* timestamp across its non-manual sources (or `undefined` when none exist) —
|
|
4429
|
+
* a source with a large `refresh.everyMs` must sleep until it's actually due,
|
|
4430
|
+
* not spin at the global-shape floor. Returns `undefined` when NEITHER tier
|
|
4431
|
+
* has pending work, so the DO can go fully idle instead of re-arming for no
|
|
4432
|
+
* reason; otherwise the earlier of the two candidate times (never later than
|
|
4433
|
+
* `nowMs`, so a source that's already due arms essentially immediately).
|
|
4434
|
+
*/
|
|
4435
|
+
private static nextPollAlarmTarget;
|
|
4405
4436
|
protected state: ShardDOState;
|
|
4406
4437
|
protected env: unknown;
|
|
4407
4438
|
/**
|
|
@@ -4733,12 +4764,17 @@ declare abstract class ShardDO {
|
|
|
4733
4764
|
/** Hibernation API: invoked on socket error. */
|
|
4734
4765
|
webSocketError(_ws: WebSocket, _error: unknown): void;
|
|
4735
4766
|
/**
|
|
4736
|
-
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes
|
|
4737
|
-
*
|
|
4738
|
-
*
|
|
4739
|
-
*
|
|
4740
|
-
*
|
|
4741
|
-
*
|
|
4767
|
+
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes
|
|
4768
|
+
* AND external-source (`.source(...)`) ingest, which share one alarm. The
|
|
4769
|
+
* runtime wakes this when the poll alarm armed by `scheduleGlobalPoll` fires;
|
|
4770
|
+
* it refreshes every subscribed global shape (diff-poke from the global
|
|
4771
|
+
* backend), materializes any due sourced tables, and re-arms at
|
|
4772
|
+
* {@link ShardDO.nextPollAlarmTarget} — the fixed floor while global shapes
|
|
4773
|
+
* are subscribed, or the earliest source next-due time when only ingest
|
|
4774
|
+
* remains (so a 1-hour-`refresh` source sleeps ~1 hour instead of waking
|
|
4775
|
+
* every 2 s). With neither tier pending, the alarm is not re-armed and the DO
|
|
4776
|
+
* goes idle. A base-only / global-free / source-free DO never arms it, so
|
|
4777
|
+
* this stays dormant there.
|
|
4742
4778
|
*/
|
|
4743
4779
|
alarm(): Promise<void>;
|
|
4744
4780
|
/** Subclasses implement function dispatch. */
|
|
@@ -5405,16 +5441,23 @@ declare abstract class ShardDO {
|
|
|
5405
5441
|
/**
|
|
5406
5442
|
* Poll external-source (`.source(...)`) tables once (plan 077): materialize
|
|
5407
5443
|
* each sourced table's freshly-pulled tenant slice into this DO's SQLite. The
|
|
5408
|
-
* base `ShardDO` has no sourced tables, so it returns `
|
|
5409
|
-
* stays dormant — zero behavior change for every existing DO. The
|
|
5410
|
-
* subclass overrides it to, per sourced table, build a
|
|
5411
|
-
* writer, read the tenant slice from Hyperdrive under this
|
|
5412
|
-
* run `runExternalSourceTick` (read local baseline → diff
|
|
5413
|
-
* validated CDC writer).
|
|
5414
|
-
*
|
|
5415
|
-
*
|
|
5444
|
+
* base `ShardDO` has no sourced tables, so it returns `undefined` and the
|
|
5445
|
+
* ingest tier stays dormant — zero behavior change for every existing DO. The
|
|
5446
|
+
* codegen subclass overrides it to, per sourced table, build a
|
|
5447
|
+
* `createShardCtxDb` writer, read the tenant slice from Hyperdrive under this
|
|
5448
|
+
* DO's shard key, and run `runExternalSourceTick` (read local baseline → diff
|
|
5449
|
+
* → apply via the validated CDC writer).
|
|
5450
|
+
*
|
|
5451
|
+
* Returns the EARLIEST next-due timestamp (absolute epoch ms) across every
|
|
5452
|
+
* non-manual sourced table — `polledAt.get(table) ?? now` plus that source's
|
|
5453
|
+
* `refresh.everyMs` — or `undefined` when every sourced table is
|
|
5454
|
+
* `refresh: "manual"` (or there are none). NOT a bare active count: the
|
|
5455
|
+
* shared poll alarm ({@link ShardDO.alarm}) uses this to re-arm at the exact
|
|
5456
|
+
* next time ingest needs to run, instead of spinning at the fixed
|
|
5457
|
+
* `GLOBAL_SHAPE_POLL_INTERVAL_MS` floor for a source whose `refresh.everyMs`
|
|
5458
|
+
* is, say, an hour away.
|
|
5416
5459
|
*/
|
|
5417
|
-
protected pollExternalSources(): Promise<number>;
|
|
5460
|
+
protected pollExternalSources(): Promise<number | undefined>;
|
|
5418
5461
|
/**
|
|
5419
5462
|
* Arm the shared poll alarm for external-source ingest (plan 077). The alarm is
|
|
5420
5463
|
* shared with the global-shape poll tier; the codegen subclass calls this once
|
|
@@ -6414,11 +6457,18 @@ declare abstract class ShardDO {
|
|
|
6414
6457
|
*/
|
|
6415
6458
|
private saveGlobalSnapshot;
|
|
6416
6459
|
/**
|
|
6417
|
-
* Arm the poll alarm
|
|
6418
|
-
*
|
|
6419
|
-
*
|
|
6420
|
-
*
|
|
6421
|
-
*
|
|
6460
|
+
* Arm the poll alarm if one isn't already pending. Idempotent — every
|
|
6461
|
+
* global-shape seed calls it, but only the first arms the alarm. Degrades to
|
|
6462
|
+
* a no-op when the runtime exposes no `setAlarm` (the unit harness): a global
|
|
6463
|
+
* shape is then seed-only, which the poll-loop tests assert by driving
|
|
6464
|
+
* {@link ShardDO.alarm} directly.
|
|
6465
|
+
*
|
|
6466
|
+
* `atMs` lets {@link ShardDO.alarm} re-arm at a computed target — the
|
|
6467
|
+
* earlier of the fixed global-shape floor and the earliest external-source
|
|
6468
|
+
* next-due time — instead of always the fixed floor. Every OTHER caller
|
|
6469
|
+
* (a fresh global-shape seed, {@link ShardDO.scheduleSourcePoll}'s initial
|
|
6470
|
+
* kick) omits it and gets the original `GLOBAL_SHAPE_POLL_INTERVAL_MS`
|
|
6471
|
+
* default, since neither knows a more precise due time yet.
|
|
6422
6472
|
*/
|
|
6423
6473
|
private scheduleGlobalPoll;
|
|
6424
6474
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -3,13 +3,13 @@ export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, norma
|
|
|
3
3
|
export { aggregateTableName, coerceAggregateNumber, encodeAggregateKey, foldAggregateTally, readAggregateValue } from './packem_shared/aggregateTableName-CxNqY1Sl.mjs';
|
|
4
4
|
export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-BGxj0pgS.mjs';
|
|
5
5
|
export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, ensureAuthMetricsTables, readAuthMetrics, recordAuthEvent } from './packem_shared/AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
|
|
6
|
-
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-
|
|
6
|
+
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-Ca21uDuU.mjs';
|
|
7
7
|
export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-CYwBpyTr.mjs';
|
|
8
8
|
export { SCAN_DEP, createDependencyTracker, depKey } from './packem_shared/SCAN_DEP-DLJF8dsj.mjs';
|
|
9
9
|
export { renderSql } from './packem_shared/renderSql-D6eUcn2N.mjs';
|
|
10
10
|
export { diffExternalSource } from './packem_shared/diffExternalSource-CovHfdyo.mjs';
|
|
11
|
-
export { materializeExternalRows, materializeExternalRowsIncremental, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-
|
|
12
|
-
export { isSoftDeleted, isSourceDue, liftSourceId, pullExternalSourceIncrementalTick, pullExternalSourceTick } from './packem_shared/isSoftDeleted-
|
|
11
|
+
export { materializeExternalRows, materializeExternalRowsIncremental, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-DlQWMlw_.mjs';
|
|
12
|
+
export { isSoftDeleted, isSourceDue, liftSourceId, pullExternalSourceIncrementalTick, pullExternalSourceTick } from './packem_shared/isSoftDeleted-YLKR6JYw.mjs';
|
|
13
13
|
export { FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, ensureFunctionMetricsTables, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, recordFunctionMetric } from './packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
14
14
|
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-CAHLZMj8.mjs';
|
|
15
15
|
export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
|
|
@@ -26,16 +26,16 @@ export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_share
|
|
|
26
26
|
export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/buildFtsMatch-BLEMawrp.mjs';
|
|
27
27
|
export { M as MIN_ADMIN_TOKEN_LENGTH, a as MIN_AUTH_SECRET_LENGTH, b as buildSecurityAudit } from './packem_shared/security-audit-CucgBice.mjs';
|
|
28
28
|
export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-BnSKgVO4.mjs';
|
|
29
|
-
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-
|
|
29
|
+
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-afQHUhyA.mjs';
|
|
30
30
|
export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-D99roc-r.mjs';
|
|
31
31
|
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-iFAA8FbD.mjs';
|
|
32
32
|
export { createSystemReader } from './packem_shared/createSystemReader-D12eNH13.mjs';
|
|
33
33
|
export { ConflictError } from './packem_shared/ConflictError-CLoq37xH.mjs';
|
|
34
34
|
export { hasTrigger, runTriggers } from './packem_shared/hasTrigger-5N6_Fx0A.mjs';
|
|
35
35
|
export { compileWhereSql } from './packem_shared/compileWhereSql-DE6yfRcQ.mjs';
|
|
36
|
-
export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-
|
|
36
|
+
export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-uwOJxJJZ.mjs';
|
|
37
37
|
export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-DDoT-UUI.mjs';
|
|
38
|
-
export { runShardMigrations } from './packem_shared/runShardMigrations-
|
|
38
|
+
export { runShardMigrations } from './packem_shared/runShardMigrations-DFzx6Qld.mjs';
|
|
39
39
|
export { stableStringify } from './packem_shared/stableStringify-mC40mZts.mjs';
|
|
40
40
|
export { stableWireKey } from './packem_shared/stableWireKey-DKuXO7T5.mjs';
|
|
41
41
|
export { subscriptionListDeltas } from './packem_shared/subscriptionListDeltas-CT76bYny.mjs';
|
|
@@ -79,7 +79,7 @@ const bumpCdcEpoch = (sql$1) => {
|
|
|
79
79
|
};
|
|
80
80
|
const applyCdcChange = async (writer, change) => {
|
|
81
81
|
if (change.op === "delete") {
|
|
82
|
-
await writer.delete(change.id);
|
|
82
|
+
await writer.delete(change.id, change.table);
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
const document = change.doc ?? {};
|
|
@@ -3,8 +3,8 @@ import { sql } from 'drizzle-orm';
|
|
|
3
3
|
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
|
|
4
4
|
import { encodeAggregateKey, foldAggregateTally, aggregateTableName, coerceAggregateNumber, readAggregateValue } from './aggregateTableName-CxNqY1Sl.mjs';
|
|
5
5
|
import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-BGxj0pgS.mjs';
|
|
6
|
-
import { appendCdcChange } from './CDC_LOG_TABLE-
|
|
7
|
-
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-
|
|
6
|
+
import { appendCdcChange } from './CDC_LOG_TABLE-uwOJxJJZ.mjs';
|
|
7
|
+
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-uwOJxJJZ.mjs';
|
|
8
8
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
9
9
|
import { i as isFtsAvailable, D as DOC_COLUMN$1, r as rowToDocument, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT, d as aggUpsertSql, j as jsonPathSql, q as quoteIdentifier, t as tableColumns, e as qualifiedJsonPathSql } from './do-sql-BCHCWtrD.mjs';
|
|
10
10
|
import { param } from './renderSql-D6eUcn2N.mjs';
|
|
@@ -23,7 +23,7 @@ import { runTriggers } from './hasTrigger-5N6_Fx0A.mjs';
|
|
|
23
23
|
import { compileWhereSql } from './compileWhereSql-DE6yfRcQ.mjs';
|
|
24
24
|
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-DDoT-UUI.mjs';
|
|
25
25
|
export { C as CLIENT_WATERMARK_TABLE, G as GLOBAL_SHAPE_SNAPSHOT_TABLE, I as IDEMPOTENCY_TABLE, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, e as deleteGlobalShapeSnapshotsForConnection, m as migrateClientWatermark, b as migrateGlobalShapeSnapshot, r as readClientWatermark, f as readGlobalShapeSnapshot, g as readIdempotent, t as trimIdempotent, w as writeGlobalShapeSnapshot, h as writeIdempotent } from './ctx-db-idempotency-BdcNpvY4.mjs';
|
|
26
|
-
export { runShardMigrations } from './runShardMigrations-
|
|
26
|
+
export { runShardMigrations } from './runShardMigrations-DFzx6Qld.mjs';
|
|
27
27
|
export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
28
28
|
|
|
29
29
|
const rankIndexFieldsUnchanged = (index, previous, next) => {
|
|
@@ -21,7 +21,7 @@ import { i as isDevEnvironment, c as buildSettings, b as buildSecurityAudit } fr
|
|
|
21
21
|
import { runReadonlySql } from './MAX_SQL_ROWS-iFAA8FbD.mjs';
|
|
22
22
|
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
23
23
|
import { e as deleteGlobalShapeSnapshotsForConnection, g as readIdempotent, h as writeIdempotent, t as trimIdempotent, r as readClientWatermark, m as migrateClientWatermark, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, f as readGlobalShapeSnapshot, w as writeGlobalShapeSnapshot } from './ctx-db-idempotency-BdcNpvY4.mjs';
|
|
24
|
-
import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-
|
|
24
|
+
import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-uwOJxJJZ.mjs';
|
|
25
25
|
import { stableStringify } from './stableStringify-mC40mZts.mjs';
|
|
26
26
|
import { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
27
27
|
|
|
@@ -2088,6 +2088,25 @@ class ShardDO {
|
|
|
2088
2088
|
static resetRootSizeWarning() {
|
|
2089
2089
|
ShardDO.rootSizeWarned = false;
|
|
2090
2090
|
}
|
|
2091
|
+
/**
|
|
2092
|
+
* Compute the shared poll alarm's next wake time from both tiers' signals.
|
|
2093
|
+
* Global shapes need the fixed `GLOBAL_SHAPE_POLL_INTERVAL_MS` floor whenever
|
|
2094
|
+
* any are subscribed (a global table has no per-DO op-log, so it can only be
|
|
2095
|
+
* polled). External-source ingest instead reports the earliest NEXT-DUE
|
|
2096
|
+
* timestamp across its non-manual sources (or `undefined` when none exist) —
|
|
2097
|
+
* a source with a large `refresh.everyMs` must sleep until it's actually due,
|
|
2098
|
+
* not spin at the global-shape floor. Returns `undefined` when NEITHER tier
|
|
2099
|
+
* has pending work, so the DO can go fully idle instead of re-arming for no
|
|
2100
|
+
* reason; otherwise the earlier of the two candidate times (never later than
|
|
2101
|
+
* `nowMs`, so a source that's already due arms essentially immediately).
|
|
2102
|
+
*/
|
|
2103
|
+
static nextPollAlarmTarget(globalShapesRemaining, nextSourceDueAt, nowMs) {
|
|
2104
|
+
const globalTarget = globalShapesRemaining > 0 ? nowMs + ShardDO.GLOBAL_SHAPE_POLL_INTERVAL_MS : void 0;
|
|
2105
|
+
if (globalTarget === void 0) {
|
|
2106
|
+
return nextSourceDueAt === void 0 ? void 0 : Math.max(nextSourceDueAt, nowMs);
|
|
2107
|
+
}
|
|
2108
|
+
return nextSourceDueAt === void 0 ? globalTarget : Math.min(globalTarget, nextSourceDueAt);
|
|
2109
|
+
}
|
|
2091
2110
|
state;
|
|
2092
2111
|
env;
|
|
2093
2112
|
/**
|
|
@@ -2709,31 +2728,38 @@ class ShardDO {
|
|
|
2709
2728
|
webSocketError(_ws, _error) {
|
|
2710
2729
|
}
|
|
2711
2730
|
/**
|
|
2712
|
-
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes
|
|
2713
|
-
*
|
|
2714
|
-
*
|
|
2715
|
-
*
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2731
|
+
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes
|
|
2732
|
+
* AND external-source (`.source(...)`) ingest, which share one alarm. The
|
|
2733
|
+
* runtime wakes this when the poll alarm armed by `scheduleGlobalPoll` fires;
|
|
2734
|
+
* it refreshes every subscribed global shape (diff-poke from the global
|
|
2735
|
+
* backend), materializes any due sourced tables, and re-arms at
|
|
2736
|
+
* {@link ShardDO.nextPollAlarmTarget} — the fixed floor while global shapes
|
|
2737
|
+
* are subscribed, or the earliest source next-due time when only ingest
|
|
2738
|
+
* remains (so a 1-hour-`refresh` source sleeps ~1 hour instead of waking
|
|
2739
|
+
* every 2 s). With neither tier pending, the alarm is not re-armed and the DO
|
|
2740
|
+
* goes idle. A base-only / global-free / source-free DO never arms it, so
|
|
2741
|
+
* this stays dormant there.
|
|
2718
2742
|
*/
|
|
2719
2743
|
async alarm() {
|
|
2720
2744
|
this.globalPollScheduled = false;
|
|
2721
|
-
let
|
|
2745
|
+
let globalShapesRemaining;
|
|
2722
2746
|
try {
|
|
2723
|
-
|
|
2747
|
+
globalShapesRemaining = await this.pollGlobalShapes();
|
|
2724
2748
|
} catch (error) {
|
|
2725
2749
|
this.recordShapeError("shape:poll", error);
|
|
2726
|
-
|
|
2750
|
+
globalShapesRemaining = 1;
|
|
2727
2751
|
}
|
|
2752
|
+
let nextSourceDueAt;
|
|
2728
2753
|
try {
|
|
2729
|
-
|
|
2754
|
+
nextSourceDueAt = await this.pollExternalSources();
|
|
2730
2755
|
} catch (error) {
|
|
2731
2756
|
this.recordShapeError("source:poll", error);
|
|
2732
|
-
|
|
2757
|
+
nextSourceDueAt = Date.now() + ShardDO.GLOBAL_SHAPE_POLL_INTERVAL_MS;
|
|
2733
2758
|
}
|
|
2734
2759
|
await this.flushChangedTables();
|
|
2735
|
-
|
|
2736
|
-
|
|
2760
|
+
const nextAlarmAt = ShardDO.nextPollAlarmTarget(globalShapesRemaining, nextSourceDueAt, Date.now());
|
|
2761
|
+
if (nextAlarmAt !== void 0) {
|
|
2762
|
+
await this.scheduleGlobalPoll(nextAlarmAt);
|
|
2737
2763
|
}
|
|
2738
2764
|
}
|
|
2739
2765
|
/**
|
|
@@ -3881,18 +3907,25 @@ class ShardDO {
|
|
|
3881
3907
|
/**
|
|
3882
3908
|
* Poll external-source (`.source(...)`) tables once (plan 077): materialize
|
|
3883
3909
|
* each sourced table's freshly-pulled tenant slice into this DO's SQLite. The
|
|
3884
|
-
* base `ShardDO` has no sourced tables, so it returns `
|
|
3885
|
-
* stays dormant — zero behavior change for every existing DO. The
|
|
3886
|
-
* subclass overrides it to, per sourced table, build a
|
|
3887
|
-
* writer, read the tenant slice from Hyperdrive under this
|
|
3888
|
-
* run `runExternalSourceTick` (read local baseline → diff
|
|
3889
|
-
* validated CDC writer).
|
|
3890
|
-
*
|
|
3891
|
-
*
|
|
3910
|
+
* base `ShardDO` has no sourced tables, so it returns `undefined` and the
|
|
3911
|
+
* ingest tier stays dormant — zero behavior change for every existing DO. The
|
|
3912
|
+
* codegen subclass overrides it to, per sourced table, build a
|
|
3913
|
+
* `createShardCtxDb` writer, read the tenant slice from Hyperdrive under this
|
|
3914
|
+
* DO's shard key, and run `runExternalSourceTick` (read local baseline → diff
|
|
3915
|
+
* → apply via the validated CDC writer).
|
|
3916
|
+
*
|
|
3917
|
+
* Returns the EARLIEST next-due timestamp (absolute epoch ms) across every
|
|
3918
|
+
* non-manual sourced table — `polledAt.get(table) ?? now` plus that source's
|
|
3919
|
+
* `refresh.everyMs` — or `undefined` when every sourced table is
|
|
3920
|
+
* `refresh: "manual"` (or there are none). NOT a bare active count: the
|
|
3921
|
+
* shared poll alarm ({@link ShardDO.alarm}) uses this to re-arm at the exact
|
|
3922
|
+
* next time ingest needs to run, instead of spinning at the fixed
|
|
3923
|
+
* `GLOBAL_SHAPE_POLL_INTERVAL_MS` floor for a source whose `refresh.everyMs`
|
|
3924
|
+
* is, say, an hour away.
|
|
3892
3925
|
*/
|
|
3893
3926
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass implements the real Hyperdrive-backed poll
|
|
3894
3927
|
pollExternalSources() {
|
|
3895
|
-
return Promise.resolve(0);
|
|
3928
|
+
return Promise.resolve(void 0);
|
|
3896
3929
|
}
|
|
3897
3930
|
/**
|
|
3898
3931
|
* Arm the shared poll alarm for external-source ingest (plan 077). The alarm is
|
|
@@ -6171,13 +6204,20 @@ class ShardDO {
|
|
|
6171
6204
|
}
|
|
6172
6205
|
}
|
|
6173
6206
|
/**
|
|
6174
|
-
* Arm the poll alarm
|
|
6175
|
-
*
|
|
6176
|
-
*
|
|
6177
|
-
*
|
|
6178
|
-
*
|
|
6179
|
-
|
|
6180
|
-
|
|
6207
|
+
* Arm the poll alarm if one isn't already pending. Idempotent — every
|
|
6208
|
+
* global-shape seed calls it, but only the first arms the alarm. Degrades to
|
|
6209
|
+
* a no-op when the runtime exposes no `setAlarm` (the unit harness): a global
|
|
6210
|
+
* shape is then seed-only, which the poll-loop tests assert by driving
|
|
6211
|
+
* {@link ShardDO.alarm} directly.
|
|
6212
|
+
*
|
|
6213
|
+
* `atMs` lets {@link ShardDO.alarm} re-arm at a computed target — the
|
|
6214
|
+
* earlier of the fixed global-shape floor and the earliest external-source
|
|
6215
|
+
* next-due time — instead of always the fixed floor. Every OTHER caller
|
|
6216
|
+
* (a fresh global-shape seed, {@link ShardDO.scheduleSourcePoll}'s initial
|
|
6217
|
+
* kick) omits it and gets the original `GLOBAL_SHAPE_POLL_INTERVAL_MS`
|
|
6218
|
+
* default, since neither knows a more precise due time yet.
|
|
6219
|
+
*/
|
|
6220
|
+
async scheduleGlobalPoll(atMs) {
|
|
6181
6221
|
if (this.globalPollScheduled) {
|
|
6182
6222
|
return;
|
|
6183
6223
|
}
|
|
@@ -6187,7 +6227,7 @@ class ShardDO {
|
|
|
6187
6227
|
}
|
|
6188
6228
|
this.globalPollScheduled = true;
|
|
6189
6229
|
try {
|
|
6190
|
-
await setAlarm.call(this.state.storage, Date.now() + ShardDO.GLOBAL_SHAPE_POLL_INTERVAL_MS);
|
|
6230
|
+
await setAlarm.call(this.state.storage, atMs ?? Date.now() + ShardDO.GLOBAL_SHAPE_POLL_INTERVAL_MS);
|
|
6191
6231
|
} catch {
|
|
6192
6232
|
this.globalPollScheduled = false;
|
|
6193
6233
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
2
|
import { sql } from 'drizzle-orm';
|
|
3
3
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
4
|
-
import { runExternalSourceTick, materializeExternalRowsIncremental } from './materializeExternalRows-
|
|
4
|
+
import { runExternalSourceTick, materializeExternalRowsIncremental } from './materializeExternalRows-DlQWMlw_.mjs';
|
|
5
5
|
|
|
6
6
|
const SOURCE_CURSOR_TABLE = "__lunora_source_cursor";
|
|
7
7
|
const serializeCursor = (value) => {
|
|
@@ -96,6 +96,28 @@ const writeSourceCursor = (sql$1, table, shardKey, state) => {
|
|
|
96
96
|
);
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
+
const normalizeSourceValue = (value) => {
|
|
100
|
+
if (value instanceof Date) {
|
|
101
|
+
return value.toISOString();
|
|
102
|
+
}
|
|
103
|
+
if (typeof value === "bigint") {
|
|
104
|
+
return String(value);
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
return value.map((element) => normalizeSourceValue(element));
|
|
108
|
+
}
|
|
109
|
+
if (value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
110
|
+
return normalizeSourceDocument(value);
|
|
111
|
+
}
|
|
112
|
+
return value;
|
|
113
|
+
};
|
|
114
|
+
const normalizeSourceDocument = (document) => {
|
|
115
|
+
const normalized = {};
|
|
116
|
+
for (const [key, value] of Object.entries(document)) {
|
|
117
|
+
normalized[key] = normalizeSourceValue(value);
|
|
118
|
+
}
|
|
119
|
+
return normalized;
|
|
120
|
+
};
|
|
99
121
|
const liftSourceId = (row, options = {}) => {
|
|
100
122
|
const { idColumn = "id", map } = options;
|
|
101
123
|
const idValue = row[idColumn];
|
|
@@ -107,7 +129,7 @@ const liftSourceId = (row, options = {}) => {
|
|
|
107
129
|
}
|
|
108
130
|
const id = String(idValue);
|
|
109
131
|
if (map) {
|
|
110
|
-
return { ...map(row), _id: id };
|
|
132
|
+
return normalizeSourceDocument({ ...map(row), _id: id });
|
|
111
133
|
}
|
|
112
134
|
const body = {};
|
|
113
135
|
for (const [key, value] of Object.entries(row)) {
|
|
@@ -115,7 +137,7 @@ const liftSourceId = (row, options = {}) => {
|
|
|
115
137
|
body[key] = value;
|
|
116
138
|
}
|
|
117
139
|
}
|
|
118
|
-
return { ...body, _id: id };
|
|
140
|
+
return normalizeSourceDocument({ ...body, _id: id });
|
|
119
141
|
};
|
|
120
142
|
const isSourceDue = (refresh, lastPolledMs, nowMs) => {
|
|
121
143
|
if (refresh === "manual") {
|
|
@@ -157,7 +179,12 @@ const pullExternalSourceIncrementalTick = async (sql, writer, client, table, sou
|
|
|
157
179
|
let applied;
|
|
158
180
|
if (state.watermark === null || reconcileDue) {
|
|
159
181
|
slice = await pullAndLift(client, source.query, tenantParameters, source);
|
|
160
|
-
|
|
182
|
+
const { softDeleteColumn } = source;
|
|
183
|
+
const documents = softDeleteColumn ? slice.documents.filter((_document, index) => {
|
|
184
|
+
const row = slice.rows[index];
|
|
185
|
+
return !(row && isSoftDeleted(row, softDeleteColumn));
|
|
186
|
+
}) : slice.documents;
|
|
187
|
+
({ applied } = await runExternalSourceTick(sql, writer, documents, { columns: source.columns, table }));
|
|
161
188
|
} else {
|
|
162
189
|
slice = await pullAndLift(client, cursor.query, [...tenantParameters, deserializeCursor(state.watermark)], source);
|
|
163
190
|
const { softDeleteColumn } = source;
|
|
@@ -176,8 +203,15 @@ const pullExternalSourceIncrementalTick = async (sql, writer, client, table, sou
|
|
|
176
203
|
`external-source: table "${table}" (mode "incremental") pulled ${String(slice.rows.length)} rows but none carry the cursor column "${cursor.column}" — the seed \`query\` must project it (matching \`cursor.query\`'s alias), or the watermark can never advance.`
|
|
177
204
|
);
|
|
178
205
|
}
|
|
206
|
+
const noRowCarriesCursor = slice.rows.length > 0 && slice.rows.every((row) => row[cursor.column] === null || row[cursor.column] === void 0);
|
|
207
|
+
if (!fullPull && noRowCarriesCursor) {
|
|
208
|
+
throw new LunoraError(
|
|
209
|
+
"INTERNAL",
|
|
210
|
+
`external-source: table "${table}" (mode "incremental") pulled ${String(slice.rows.length)} rows but none carry the cursor column "${cursor.column}" — \`cursor.query\` must project it (matching the seed \`query\`'s alias), or the watermark can never advance and every tick re-pulls the same stranded slice.`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
179
213
|
writeSourceCursor(sql, table, shardKey, { lastReconcileMs: fullPull ? nowMs : state.lastReconcileMs, watermark });
|
|
180
214
|
return { applied };
|
|
181
215
|
};
|
|
182
216
|
|
|
183
|
-
export { isSoftDeleted, isSourceDue, liftSourceId, pullExternalSourceIncrementalTick, pullExternalSourceTick };
|
|
217
|
+
export { isSoftDeleted, isSourceDue, liftSourceId, normalizeSourceValue, pullExternalSourceIncrementalTick, pullExternalSourceTick };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyCdcChanges } from './CDC_LOG_TABLE-
|
|
1
|
+
import { applyCdcChanges } from './CDC_LOG_TABLE-uwOJxJJZ.mjs';
|
|
2
2
|
import { s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
3
3
|
import { diffExternalSource, projectExternalSourceRow } from './diffExternalSource-CovHfdyo.mjs';
|
|
4
4
|
import { stableStringify } from './stableStringify-mC40mZts.mjs';
|
|
@@ -15,7 +15,10 @@ const materializeExternalRowsIncremental = async (writer, pulled, options) => {
|
|
|
15
15
|
const value = projectExternalSourceRow(source, columns);
|
|
16
16
|
const id = String(value._id);
|
|
17
17
|
if (deletedIds?.has(id)) {
|
|
18
|
-
|
|
18
|
+
const existing = await writer.get(id, table);
|
|
19
|
+
if (existing) {
|
|
20
|
+
changes.push({ id, op: "delete", seq: 0, table, ts: 0 });
|
|
21
|
+
}
|
|
19
22
|
continue;
|
|
20
23
|
}
|
|
21
24
|
const stored = await writer.get(id, table);
|
package/dist/packem_shared/{runShardMigrations-BGx4v2B6.mjs → runShardMigrations-DFzx6Qld.mjs}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
2
|
import { aggregateTableName } from './aggregateTableName-CxNqY1Sl.mjs';
|
|
3
|
-
import { migrateCdcLog, migrateCdcMeta } from './CDC_LOG_TABLE-
|
|
3
|
+
import { migrateCdcLog, migrateCdcMeta } from './CDC_LOG_TABLE-uwOJxJJZ.mjs';
|
|
4
4
|
import { m as migrateClientWatermark, a as migrateIdempotency, b as migrateGlobalShapeSnapshot } from './ctx-db-idempotency-BdcNpvY4.mjs';
|
|
5
5
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
6
6
|
import { D as DOC_COLUMN, j as jsonPathSql, c as createIndexSql, t as tableColumns, i as isFtsAvailable, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT } from './do-sql-BCHCWtrD.mjs';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/do",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.33",
|
|
4
4
|
"description": "Lunora Durable Objects: ShardDO (SQLite, OCC, hibernated WebSocket subscriptions) and SessionDO",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@lunora/errors": "1.0.0-alpha.5",
|
|
50
|
-
"@lunora/fingerprint": "1.0.0-alpha.
|
|
50
|
+
"@lunora/fingerprint": "1.0.0-alpha.3",
|
|
51
51
|
"@visulima/redact": "3.0.0",
|
|
52
52
|
"drizzle-orm": "^0.45.2"
|
|
53
53
|
},
|