@lunora/do 1.0.0-alpha.21 → 1.0.0-alpha.22
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 +28 -90
- package/dist/index.d.ts +28 -90
- package/dist/index.mjs +17 -17
- package/dist/packem_shared/{AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs → AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs} +5 -3
- package/dist/packem_shared/{CDC_LOG_TABLE-DSycmnDf.mjs → CDC_LOG_TABLE-DZSVKRr7.mjs} +1 -1
- package/dist/packem_shared/{ConflictError-C0STs6bU.mjs → ConflictError-CLoq37xH.mjs} +4 -5
- package/dist/packem_shared/{CountRlsUnsupportedError-28ZvvwKS.mjs → CountRlsUnsupportedError-BGxj0pgS.mjs} +4 -4
- package/dist/packem_shared/{DATA_MIGRATION_STATE_TABLE-DfPxn8I0.mjs → DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs} +3 -1
- package/dist/packem_shared/{DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs → DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs} +8 -6
- package/dist/packem_shared/NotFoundError-C70b9hLw.mjs +9 -0
- package/dist/packem_shared/{NotUniqueError-Do5h_jiW.mjs → NotUniqueError-D1U5SBFR.mjs} +63 -55
- package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs → RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs} +6 -5
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-BfPNp3Jh.mjs → ROOT_DO_SIZE_WARN_BYTES-BQoX61l-.mjs} +18 -37
- package/dist/packem_shared/{applyOnDelete-BQ-8ZlZ1.mjs → applyOnDelete-CAwZfp-5.mjs} +4 -3
- package/dist/packem_shared/{backfillAggregateIndexes-BZsOqDXP.mjs → backfillAggregateIndexes-DDoT-UUI.mjs} +1 -1
- package/dist/packem_shared/{compileWhereSql-MW_Lk8nJ.mjs → compileWhereSql-DE6yfRcQ.mjs} +2 -1
- package/dist/packem_shared/{createSystemReader-8CzSZP9V.mjs → createSystemReader-D12eNH13.mjs} +4 -2
- package/dist/packem_shared/{ctx-db-shapes-0RaIOy7J.mjs → ctx-db-shapes-Cz9dHyh1.mjs} +1 -1
- package/dist/packem_shared/{isSourceDue-9mJRJ9Ld.mjs → isSourceDue-BptUN8CR.mjs} +3 -2
- package/dist/packem_shared/{materializeExternalRows-Bj6EXy50.mjs → materializeExternalRows-DNcvoLRT.mjs} +2 -2
- package/dist/packem_shared/{runShardMigrations-nIwoQeOK.mjs → runShardMigrations-DeZr0KZp.mjs} +1 -1
- package/package.json +2 -1
- package/dist/packem_shared/NotFoundError-CMuMZt81.mjs +0 -10
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
2
|
import { SQL } from 'drizzle-orm';
|
|
2
3
|
import { DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
|
|
3
4
|
/**
|
|
@@ -110,17 +111,13 @@ interface GroupByEntry {
|
|
|
110
111
|
value: AggregateResult;
|
|
111
112
|
}
|
|
112
113
|
/**
|
|
113
|
-
* Thrown when `count` runs in an RLS-restricted ctx.
|
|
114
|
-
* (`
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* the operation is invalid in this context, not malformed.
|
|
114
|
+
* Thrown when `count` runs in an RLS-restricted ctx. A `LunoraError` subclass
|
|
115
|
+
* (`code: "COUNT_RLS_UNSUPPORTED"`, `status: 422`) recognised structurally by the
|
|
116
|
+
* runtime's error mapper (via `isLunoraError`), so `@lunora/do` needs no runtime
|
|
117
|
+
* dependency on `@lunora/server`. 422 = the operation is invalid in this context,
|
|
118
|
+
* not malformed.
|
|
119
119
|
*/
|
|
120
|
-
declare class CountRlsUnsupportedError extends
|
|
121
|
-
readonly code: string;
|
|
122
|
-
override readonly name = "LunoraError";
|
|
123
|
-
readonly status: number;
|
|
120
|
+
declare class CountRlsUnsupportedError extends LunoraError {
|
|
124
121
|
constructor(table?: string);
|
|
125
122
|
}
|
|
126
123
|
/**
|
|
@@ -761,37 +758,6 @@ declare class ReactiveCache {
|
|
|
761
758
|
* everyone. Anonymous/subscription callers pass `null` (their own bucket).
|
|
762
759
|
*/
|
|
763
760
|
declare const reactiveCacheKey: (functionPath: string, args: Record<string, unknown>, identity: null | string) => string;
|
|
764
|
-
/**
|
|
765
|
-
* `ctx.db.system` — a best-effort, read-only reader over Lunora's *system*
|
|
766
|
-
* tables.
|
|
767
|
-
*
|
|
768
|
-
* Convex surfaces a handful of read-only system tables (`_scheduled_functions`,
|
|
769
|
-
* `_storage`, ...) through `ctx.db.system`. Lunora mirrors that surface, but with
|
|
770
|
-
* one load-bearing caveat: **the data these tables expose does not live in the
|
|
771
|
-
* shard's SQLite**. Scheduled functions live in the `SchedulerDO`; storage
|
|
772
|
-
* objects live in R2. So unlike `ctx.db.<table>` — which reads the same
|
|
773
|
-
* transactional SQLite snapshot the mutation writes into — `ctx.db.system`
|
|
774
|
-
* reaches across a network/DO boundary on every call.
|
|
775
|
-
*
|
|
776
|
-
* Consequences callers must keep in mind:
|
|
777
|
-
*
|
|
778
|
-
* Asynchronous + eventually consistent: each `collect()` / `get()` issues a fresh
|
|
779
|
-
* read against the backing source. A row a mutation just scheduled may not yet be
|
|
780
|
-
* visible; a job that just fired may still appear pending.
|
|
781
|
-
*
|
|
782
|
-
* NOT part of the transaction snapshot: reading a system table inside a mutation
|
|
783
|
-
* does not pin it; there is no OCC guard and no subscription dependency is
|
|
784
|
-
* recorded. Treat the result as a point-in-time best effort.
|
|
785
|
-
*
|
|
786
|
-
* Read-only: there is no `insert`/`patch`/`delete`. Mutate scheduled jobs via
|
|
787
|
-
* `ctx.scheduler`, storage objects via `ctx.storage`.
|
|
788
|
-
*
|
|
789
|
-
* The reader is intentionally minimal: `query(table).collect()` returns the full
|
|
790
|
-
* list (no indexes, no filtering, no pagination) and `get(table, id)` resolves a
|
|
791
|
-
* single row. That matches Convex's system-table read surface closely enough for
|
|
792
|
-
* the studio / introspection use cases without re-implementing the query
|
|
793
|
-
* planner against a remote source.
|
|
794
|
-
*/
|
|
795
761
|
/** The system tables `ctx.db.system` can read. */
|
|
796
762
|
type SystemTableName = "_scheduled_functions" | "_storage";
|
|
797
763
|
/**
|
|
@@ -1893,14 +1859,12 @@ interface DatabaseWriterLike {
|
|
|
1893
1859
|
system?: SystemDatabaseReader;
|
|
1894
1860
|
}
|
|
1895
1861
|
/**
|
|
1896
|
-
* Thrown by `.unique()` when more than one row matches.
|
|
1897
|
-
*
|
|
1898
|
-
* cross-package
|
|
1899
|
-
*
|
|
1862
|
+
* Thrown by `.unique()` when more than one row matches. A `LunoraError` subclass
|
|
1863
|
+
* (`code: "NOT_UNIQUE"`, `status: 400`) recognised structurally by the
|
|
1864
|
+
* cross-package transport mapper (via `isLunoraError`) without an `instanceof`
|
|
1865
|
+
* check against `@lunora/do`.
|
|
1900
1866
|
*/
|
|
1901
|
-
declare class NotUniqueError extends
|
|
1902
|
-
readonly code: string;
|
|
1903
|
-
readonly status: number;
|
|
1867
|
+
declare class NotUniqueError extends LunoraError {
|
|
1904
1868
|
constructor(message?: string);
|
|
1905
1869
|
}
|
|
1906
1870
|
/**
|
|
@@ -3449,13 +3413,11 @@ declare const clearCapturedMail: (sql: SqlExec) => {
|
|
|
3449
3413
|
/**
|
|
3450
3414
|
* Thrown by `findFirstOrThrow` when no document matches the query.
|
|
3451
3415
|
*
|
|
3452
|
-
*
|
|
3453
|
-
*
|
|
3454
|
-
* `instanceof` check against `@lunora/do`.
|
|
3416
|
+
* A `LunoraError` subclass (`code: "NOT_FOUND"`, `status: 404`) so the
|
|
3417
|
+
* cross-package transport mapper maps it to a 404 structurally (via
|
|
3418
|
+
* `isLunoraError`) without an `instanceof` check against `@lunora/do`.
|
|
3455
3419
|
*/
|
|
3456
|
-
declare class NotFoundError extends
|
|
3457
|
-
readonly code: string;
|
|
3458
|
-
readonly status: number;
|
|
3420
|
+
declare class NotFoundError extends LunoraError {
|
|
3459
3421
|
constructor(message?: string);
|
|
3460
3422
|
}
|
|
3461
3423
|
/**
|
|
@@ -3691,24 +3653,6 @@ interface LogEventInput {
|
|
|
3691
3653
|
* that want the raw values.
|
|
3692
3654
|
*/
|
|
3693
3655
|
/**
|
|
3694
|
-
* Secure-by-default write-path guard for `ctx.db`.
|
|
3695
|
-
*
|
|
3696
|
-
* When a schema is marked `defineSchema(...).rls("required")`, the generated
|
|
3697
|
-
* user-facing ctx wraps its writer with {@link guardWriter}. The guard denies
|
|
3698
|
-
* every read/write against a PROTECTED table (any table not marked `.public()`)
|
|
3699
|
-
* so a procedure that forgot `.use(rls(policies))` fails CLOSED — it can never
|
|
3700
|
-
* silently see or mutate a protected table through the unwrapped writer.
|
|
3701
|
-
*
|
|
3702
|
-
* The guard is transparent to the RLS middleware: it hangs the UNWRAPPED writer
|
|
3703
|
-
* off {@link RLS_UNWRAP_SYMBOL}, so `@lunora/server`'s `rls()` middleware
|
|
3704
|
-
* recovers the raw writer (via the same `Symbol.for` key — no cross-package
|
|
3705
|
-
* import) to evaluate policies and issue policy-filtered reads without tripping
|
|
3706
|
-
* the guard. Only procedures that NEVER engaged RLS keep talking to the guard.
|
|
3707
|
-
*
|
|
3708
|
-
* Admin / migration / studio writers (built from `createShardCtxDb` WITHOUT
|
|
3709
|
-
* `enforceRls`) are never guarded — they are trusted system paths.
|
|
3710
|
-
*/
|
|
3711
|
-
/**
|
|
3712
3656
|
* Well-known symbol the guard hangs the unwrapped writer off of. `Symbol.for`
|
|
3713
3657
|
* (the cross-realm global registry) lets `@lunora/server`'s RLS middleware read
|
|
3714
3658
|
* it WITHOUT importing this module — both sides reference the same registered
|
|
@@ -3717,14 +3661,12 @@ interface LogEventInput {
|
|
|
3717
3661
|
declare const RLS_UNWRAP_SYMBOL: symbol;
|
|
3718
3662
|
/**
|
|
3719
3663
|
* Thrown when a raw (non-RLS) handler touches a protected table under a
|
|
3720
|
-
* `.rls("required")` schema.
|
|
3721
|
-
*
|
|
3722
|
-
* deliberately avoid a hard `@lunora/do` runtime dependency —
|
|
3723
|
-
*
|
|
3724
|
-
*/
|
|
3725
|
-
declare class RlsRequiredError extends
|
|
3726
|
-
readonly code: string;
|
|
3727
|
-
readonly status: number;
|
|
3664
|
+
* `.rls("required")` schema. A `LunoraError` subclass (`code: "RLS_REQUIRED"`,
|
|
3665
|
+
* `status: 403`) recognised structurally across packages (via `isLunoraError`) —
|
|
3666
|
+
* which deliberately avoid a hard `@lunora/do` runtime dependency — without an
|
|
3667
|
+
* `instanceof` check. `table` is kept as an own property.
|
|
3668
|
+
*/
|
|
3669
|
+
declare class RlsRequiredError extends LunoraError {
|
|
3728
3670
|
readonly table: string;
|
|
3729
3671
|
constructor(table: string);
|
|
3730
3672
|
}
|
|
@@ -6587,18 +6529,14 @@ type ConflictKind = "conflict" | "occ" | "restrict" | "trigger" | "unique";
|
|
|
6587
6529
|
* Thrown by mutation handlers when an optimistic-concurrency check fails (or a
|
|
6588
6530
|
* related write guard trips — see {@link ConflictKind}).
|
|
6589
6531
|
*
|
|
6590
|
-
*
|
|
6591
|
-
*
|
|
6592
|
-
*
|
|
6593
|
-
*
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
*/
|
|
6597
|
-
declare class ConflictError extends Error {
|
|
6598
|
-
readonly code: string;
|
|
6532
|
+
* A `LunoraError` subclass (`code: "CONFLICT"`, `status: 409`) so the runtime/DO
|
|
6533
|
+
* transport mappers recognise it structurally (via `isLunoraError`) — structural
|
|
6534
|
+
* callers across packages still avoid a hard `instanceof` dependency on
|
|
6535
|
+
* `@lunora/do`. `kind` is kept as an own property for the metrics layer.
|
|
6536
|
+
*/
|
|
6537
|
+
declare class ConflictError extends LunoraError {
|
|
6599
6538
|
/** Why the conflict fired; `occ` is the contention signal the metrics layer counts. */
|
|
6600
6539
|
readonly kind: ConflictKind;
|
|
6601
|
-
readonly status: number;
|
|
6602
6540
|
constructor(message?: string, kind?: ConflictKind);
|
|
6603
6541
|
}
|
|
6604
6542
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
2
|
import { SQL } from 'drizzle-orm';
|
|
2
3
|
import { DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
|
|
3
4
|
/**
|
|
@@ -110,17 +111,13 @@ interface GroupByEntry {
|
|
|
110
111
|
value: AggregateResult;
|
|
111
112
|
}
|
|
112
113
|
/**
|
|
113
|
-
* Thrown when `count` runs in an RLS-restricted ctx.
|
|
114
|
-
* (`
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* the operation is invalid in this context, not malformed.
|
|
114
|
+
* Thrown when `count` runs in an RLS-restricted ctx. A `LunoraError` subclass
|
|
115
|
+
* (`code: "COUNT_RLS_UNSUPPORTED"`, `status: 422`) recognised structurally by the
|
|
116
|
+
* runtime's error mapper (via `isLunoraError`), so `@lunora/do` needs no runtime
|
|
117
|
+
* dependency on `@lunora/server`. 422 = the operation is invalid in this context,
|
|
118
|
+
* not malformed.
|
|
119
119
|
*/
|
|
120
|
-
declare class CountRlsUnsupportedError extends
|
|
121
|
-
readonly code: string;
|
|
122
|
-
override readonly name = "LunoraError";
|
|
123
|
-
readonly status: number;
|
|
120
|
+
declare class CountRlsUnsupportedError extends LunoraError {
|
|
124
121
|
constructor(table?: string);
|
|
125
122
|
}
|
|
126
123
|
/**
|
|
@@ -761,37 +758,6 @@ declare class ReactiveCache {
|
|
|
761
758
|
* everyone. Anonymous/subscription callers pass `null` (their own bucket).
|
|
762
759
|
*/
|
|
763
760
|
declare const reactiveCacheKey: (functionPath: string, args: Record<string, unknown>, identity: null | string) => string;
|
|
764
|
-
/**
|
|
765
|
-
* `ctx.db.system` — a best-effort, read-only reader over Lunora's *system*
|
|
766
|
-
* tables.
|
|
767
|
-
*
|
|
768
|
-
* Convex surfaces a handful of read-only system tables (`_scheduled_functions`,
|
|
769
|
-
* `_storage`, ...) through `ctx.db.system`. Lunora mirrors that surface, but with
|
|
770
|
-
* one load-bearing caveat: **the data these tables expose does not live in the
|
|
771
|
-
* shard's SQLite**. Scheduled functions live in the `SchedulerDO`; storage
|
|
772
|
-
* objects live in R2. So unlike `ctx.db.<table>` — which reads the same
|
|
773
|
-
* transactional SQLite snapshot the mutation writes into — `ctx.db.system`
|
|
774
|
-
* reaches across a network/DO boundary on every call.
|
|
775
|
-
*
|
|
776
|
-
* Consequences callers must keep in mind:
|
|
777
|
-
*
|
|
778
|
-
* Asynchronous + eventually consistent: each `collect()` / `get()` issues a fresh
|
|
779
|
-
* read against the backing source. A row a mutation just scheduled may not yet be
|
|
780
|
-
* visible; a job that just fired may still appear pending.
|
|
781
|
-
*
|
|
782
|
-
* NOT part of the transaction snapshot: reading a system table inside a mutation
|
|
783
|
-
* does not pin it; there is no OCC guard and no subscription dependency is
|
|
784
|
-
* recorded. Treat the result as a point-in-time best effort.
|
|
785
|
-
*
|
|
786
|
-
* Read-only: there is no `insert`/`patch`/`delete`. Mutate scheduled jobs via
|
|
787
|
-
* `ctx.scheduler`, storage objects via `ctx.storage`.
|
|
788
|
-
*
|
|
789
|
-
* The reader is intentionally minimal: `query(table).collect()` returns the full
|
|
790
|
-
* list (no indexes, no filtering, no pagination) and `get(table, id)` resolves a
|
|
791
|
-
* single row. That matches Convex's system-table read surface closely enough for
|
|
792
|
-
* the studio / introspection use cases without re-implementing the query
|
|
793
|
-
* planner against a remote source.
|
|
794
|
-
*/
|
|
795
761
|
/** The system tables `ctx.db.system` can read. */
|
|
796
762
|
type SystemTableName = "_scheduled_functions" | "_storage";
|
|
797
763
|
/**
|
|
@@ -1893,14 +1859,12 @@ interface DatabaseWriterLike {
|
|
|
1893
1859
|
system?: SystemDatabaseReader;
|
|
1894
1860
|
}
|
|
1895
1861
|
/**
|
|
1896
|
-
* Thrown by `.unique()` when more than one row matches.
|
|
1897
|
-
*
|
|
1898
|
-
* cross-package
|
|
1899
|
-
*
|
|
1862
|
+
* Thrown by `.unique()` when more than one row matches. A `LunoraError` subclass
|
|
1863
|
+
* (`code: "NOT_UNIQUE"`, `status: 400`) recognised structurally by the
|
|
1864
|
+
* cross-package transport mapper (via `isLunoraError`) without an `instanceof`
|
|
1865
|
+
* check against `@lunora/do`.
|
|
1900
1866
|
*/
|
|
1901
|
-
declare class NotUniqueError extends
|
|
1902
|
-
readonly code: string;
|
|
1903
|
-
readonly status: number;
|
|
1867
|
+
declare class NotUniqueError extends LunoraError {
|
|
1904
1868
|
constructor(message?: string);
|
|
1905
1869
|
}
|
|
1906
1870
|
/**
|
|
@@ -3449,13 +3413,11 @@ declare const clearCapturedMail: (sql: SqlExec) => {
|
|
|
3449
3413
|
/**
|
|
3450
3414
|
* Thrown by `findFirstOrThrow` when no document matches the query.
|
|
3451
3415
|
*
|
|
3452
|
-
*
|
|
3453
|
-
*
|
|
3454
|
-
* `instanceof` check against `@lunora/do`.
|
|
3416
|
+
* A `LunoraError` subclass (`code: "NOT_FOUND"`, `status: 404`) so the
|
|
3417
|
+
* cross-package transport mapper maps it to a 404 structurally (via
|
|
3418
|
+
* `isLunoraError`) without an `instanceof` check against `@lunora/do`.
|
|
3455
3419
|
*/
|
|
3456
|
-
declare class NotFoundError extends
|
|
3457
|
-
readonly code: string;
|
|
3458
|
-
readonly status: number;
|
|
3420
|
+
declare class NotFoundError extends LunoraError {
|
|
3459
3421
|
constructor(message?: string);
|
|
3460
3422
|
}
|
|
3461
3423
|
/**
|
|
@@ -3691,24 +3653,6 @@ interface LogEventInput {
|
|
|
3691
3653
|
* that want the raw values.
|
|
3692
3654
|
*/
|
|
3693
3655
|
/**
|
|
3694
|
-
* Secure-by-default write-path guard for `ctx.db`.
|
|
3695
|
-
*
|
|
3696
|
-
* When a schema is marked `defineSchema(...).rls("required")`, the generated
|
|
3697
|
-
* user-facing ctx wraps its writer with {@link guardWriter}. The guard denies
|
|
3698
|
-
* every read/write against a PROTECTED table (any table not marked `.public()`)
|
|
3699
|
-
* so a procedure that forgot `.use(rls(policies))` fails CLOSED — it can never
|
|
3700
|
-
* silently see or mutate a protected table through the unwrapped writer.
|
|
3701
|
-
*
|
|
3702
|
-
* The guard is transparent to the RLS middleware: it hangs the UNWRAPPED writer
|
|
3703
|
-
* off {@link RLS_UNWRAP_SYMBOL}, so `@lunora/server`'s `rls()` middleware
|
|
3704
|
-
* recovers the raw writer (via the same `Symbol.for` key — no cross-package
|
|
3705
|
-
* import) to evaluate policies and issue policy-filtered reads without tripping
|
|
3706
|
-
* the guard. Only procedures that NEVER engaged RLS keep talking to the guard.
|
|
3707
|
-
*
|
|
3708
|
-
* Admin / migration / studio writers (built from `createShardCtxDb` WITHOUT
|
|
3709
|
-
* `enforceRls`) are never guarded — they are trusted system paths.
|
|
3710
|
-
*/
|
|
3711
|
-
/**
|
|
3712
3656
|
* Well-known symbol the guard hangs the unwrapped writer off of. `Symbol.for`
|
|
3713
3657
|
* (the cross-realm global registry) lets `@lunora/server`'s RLS middleware read
|
|
3714
3658
|
* it WITHOUT importing this module — both sides reference the same registered
|
|
@@ -3717,14 +3661,12 @@ interface LogEventInput {
|
|
|
3717
3661
|
declare const RLS_UNWRAP_SYMBOL: symbol;
|
|
3718
3662
|
/**
|
|
3719
3663
|
* Thrown when a raw (non-RLS) handler touches a protected table under a
|
|
3720
|
-
* `.rls("required")` schema.
|
|
3721
|
-
*
|
|
3722
|
-
* deliberately avoid a hard `@lunora/do` runtime dependency —
|
|
3723
|
-
*
|
|
3724
|
-
*/
|
|
3725
|
-
declare class RlsRequiredError extends
|
|
3726
|
-
readonly code: string;
|
|
3727
|
-
readonly status: number;
|
|
3664
|
+
* `.rls("required")` schema. A `LunoraError` subclass (`code: "RLS_REQUIRED"`,
|
|
3665
|
+
* `status: 403`) recognised structurally across packages (via `isLunoraError`) —
|
|
3666
|
+
* which deliberately avoid a hard `@lunora/do` runtime dependency — without an
|
|
3667
|
+
* `instanceof` check. `table` is kept as an own property.
|
|
3668
|
+
*/
|
|
3669
|
+
declare class RlsRequiredError extends LunoraError {
|
|
3728
3670
|
readonly table: string;
|
|
3729
3671
|
constructor(table: string);
|
|
3730
3672
|
}
|
|
@@ -6587,18 +6529,14 @@ type ConflictKind = "conflict" | "occ" | "restrict" | "trigger" | "unique";
|
|
|
6587
6529
|
* Thrown by mutation handlers when an optimistic-concurrency check fails (or a
|
|
6588
6530
|
* related write guard trips — see {@link ConflictKind}).
|
|
6589
6531
|
*
|
|
6590
|
-
*
|
|
6591
|
-
*
|
|
6592
|
-
*
|
|
6593
|
-
*
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
*/
|
|
6597
|
-
declare class ConflictError extends Error {
|
|
6598
|
-
readonly code: string;
|
|
6532
|
+
* A `LunoraError` subclass (`code: "CONFLICT"`, `status: 409`) so the runtime/DO
|
|
6533
|
+
* transport mappers recognise it structurally (via `isLunoraError`) — structural
|
|
6534
|
+
* callers across packages still avoid a hard `instanceof` dependency on
|
|
6535
|
+
* `@lunora/do`. `kind` is kept as an own property for the metrics layer.
|
|
6536
|
+
*/
|
|
6537
|
+
declare class ConflictError extends LunoraError {
|
|
6599
6538
|
/** Why the conflict fired; `occ` is the contention signal the metrics layer counts. */
|
|
6600
6539
|
readonly kind: ConflictKind;
|
|
6601
|
-
readonly status: number;
|
|
6602
6540
|
constructor(message?: string, kind?: ConflictKind);
|
|
6603
6541
|
}
|
|
6604
6542
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
export { exportShardRows, exportShardTable, importShardRows, parseExportShardArgs, parseImportShardArgs, selectExportTables, validateImportRow } from './packem_shared/exportShardRows-DZEhUeyI.mjs';
|
|
2
|
-
export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, normalizeCountArgument, throwingScheduler } from './packem_shared/AGGREGATE_SQL_FUNCTION-
|
|
2
|
+
export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, normalizeCountArgument, throwingScheduler } from './packem_shared/AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
|
|
3
3
|
export { aggregateTableName, coerceAggregateNumber, encodeAggregateKey, foldAggregateTally, readAggregateValue } from './packem_shared/aggregateTableName-CxNqY1Sl.mjs';
|
|
4
|
-
export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-
|
|
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-
|
|
7
|
-
export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-
|
|
6
|
+
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-D1U5SBFR.mjs';
|
|
7
|
+
export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-DB3IYUR3.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-Cx9HUPJj.mjs';
|
|
11
|
-
export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-
|
|
12
|
-
export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-
|
|
11
|
+
export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-DNcvoLRT.mjs';
|
|
12
|
+
export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-BptUN8CR.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-DSUQ5fX9.mjs';
|
|
15
15
|
export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
|
|
16
16
|
export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/MAIL_RETENTION-CPpgl-dX.mjs';
|
|
17
|
-
export { default as NotFoundError } from './packem_shared/NotFoundError-
|
|
17
|
+
export { default as NotFoundError } from './packem_shared/NotFoundError-C70b9hLw.mjs';
|
|
18
18
|
export { armRestore, readBookmark } from './packem_shared/armRestore-BJk53Ro8.mjs';
|
|
19
19
|
export { applySelect, buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys, softDeleteScope } from './packem_shared/applySelect-BvZdFUBT.mjs';
|
|
20
20
|
export { RANK_TIEBREAK, encodePartitionKey, matchesRankStaticWhere, rankTableName, resolveRankPartition, sortColumnName } from './packem_shared/RANK_TIEBREAK-CXhdcA1o.mjs';
|
|
21
21
|
export { ReactiveCache, reactiveCacheKey } from './packem_shared/ReactiveCache-BYlSGY0N.mjs';
|
|
22
22
|
export { serveRelationFanout } from './packem_shared/serveRelationFanout-C5axmGDj.mjs';
|
|
23
|
-
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-
|
|
24
|
-
export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-
|
|
25
|
-
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-
|
|
23
|
+
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs';
|
|
24
|
+
export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-CAwZfp-5.mjs';
|
|
25
|
+
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs';
|
|
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-ilPZsVwu.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-BQoX61l-.mjs';
|
|
30
30
|
export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-BsAbi5Mn.mjs';
|
|
31
31
|
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-dDcFE1YZ.mjs';
|
|
32
|
-
export { createSystemReader } from './packem_shared/createSystemReader-
|
|
33
|
-
export { ConflictError } from './packem_shared/ConflictError-
|
|
32
|
+
export { createSystemReader } from './packem_shared/createSystemReader-D12eNH13.mjs';
|
|
33
|
+
export { ConflictError } from './packem_shared/ConflictError-CLoq37xH.mjs';
|
|
34
34
|
export { hasTrigger, runTriggers } from './packem_shared/hasTrigger-5N6_Fx0A.mjs';
|
|
35
|
-
export { compileWhereSql } from './packem_shared/compileWhereSql-
|
|
36
|
-
export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-
|
|
37
|
-
export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-
|
|
38
|
-
export { runShardMigrations } from './packem_shared/runShardMigrations-
|
|
35
|
+
export { compileWhereSql } from './packem_shared/compileWhereSql-DE6yfRcQ.mjs';
|
|
36
|
+
export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
37
|
+
export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-DDoT-UUI.mjs';
|
|
38
|
+
export { runShardMigrations } from './packem_shared/runShardMigrations-DeZr0KZp.mjs';
|
|
39
39
|
export { stableStringify } from './packem_shared/stableStringify-MydiuScU.mjs';
|
|
40
40
|
export { s as subscriptionListDeltas } from './packem_shared/subscription-delivery-CK8qga-k.mjs';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const COUNT_OPTION_KEYS = /* @__PURE__ */ new Set(["baseWhere", "relationBaseWhere", "restrictsCounts", "where"]);
|
|
2
4
|
const matchesStaticWhere = (document, predicate) => {
|
|
3
5
|
for (const [field, expected] of Object.entries(predicate)) {
|
|
@@ -38,16 +40,16 @@ const AGGREGATE_SQL_FUNCTION = { avg: "AVG", count: "COUNT", max: "MAX", min: "M
|
|
|
38
40
|
const aggregateSqlFunction = (op) => {
|
|
39
41
|
const sqlFunction = AGGREGATE_SQL_FUNCTION[op];
|
|
40
42
|
if (sqlFunction === void 0) {
|
|
41
|
-
throw new
|
|
43
|
+
throw new LunoraError("INTERNAL", `unknown aggregate op "${op}": expected one of ${Object.keys(AGGREGATE_SQL_FUNCTION).join(", ")}`);
|
|
42
44
|
}
|
|
43
45
|
return sqlFunction;
|
|
44
46
|
};
|
|
45
47
|
const throwingScheduler = {
|
|
46
48
|
runAfter: () => {
|
|
47
|
-
throw new
|
|
49
|
+
throw new LunoraError("INTERNAL", "ctx.scheduler: no scheduler configured for triggers. Pass `scheduler` to the ctx-db factory.");
|
|
48
50
|
},
|
|
49
51
|
runAt: () => {
|
|
50
|
-
throw new
|
|
52
|
+
throw new LunoraError("INTERNAL", "ctx.scheduler: no scheduler configured for triggers. Pass `scheduler` to the ctx-db factory.");
|
|
51
53
|
}
|
|
52
54
|
};
|
|
53
55
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
2
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
3
|
-
import { ConflictError } from './ConflictError-
|
|
3
|
+
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
4
4
|
|
|
5
5
|
const CDC_LOG_TABLE = "__cdc_log";
|
|
6
6
|
const migrateCdcLog = (sql$1) => {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
3
|
+
class ConflictError extends LunoraError {
|
|
3
4
|
/** Why the conflict fired; `occ` is the contention signal the metrics layer counts. */
|
|
4
5
|
kind;
|
|
5
|
-
status = 409;
|
|
6
6
|
constructor(message = "Optimistic concurrency conflict", kind = "conflict") {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = "ConflictError";
|
|
7
|
+
super("CONFLICT", message, { name: "ConflictError" });
|
|
9
8
|
this.kind = kind;
|
|
10
9
|
}
|
|
11
10
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
status = 422;
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
3
|
+
class CountRlsUnsupportedError extends LunoraError {
|
|
5
4
|
constructor(table) {
|
|
6
5
|
super(
|
|
6
|
+
"COUNT_RLS_UNSUPPORTED",
|
|
7
7
|
table === void 0 ? "count() is not supported in an RLS-restricted context" : `count() is not supported on table "${table}" inside an RLS-restricted context`
|
|
8
8
|
);
|
|
9
9
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const DATA_MIGRATION_STATE_TABLE = "__lunora_migrations";
|
|
2
4
|
const DEFAULT_BATCH_SIZE = 100;
|
|
3
5
|
const STALE_CLAIM_TIMEOUT_MS = 3e4;
|
|
@@ -128,7 +130,7 @@ const runDataMigration = async (options) => {
|
|
|
128
130
|
const batchSize = options.batchSize ?? migration.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
129
131
|
const transform = direction === "up" ? migration.up : migration.down;
|
|
130
132
|
if (!transform) {
|
|
131
|
-
throw new
|
|
133
|
+
throw new LunoraError("INTERNAL", `data migration "${migration.id}" has no \`${direction}\` transform`);
|
|
132
134
|
}
|
|
133
135
|
let cursor = null;
|
|
134
136
|
let processed = 0;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { distinctValues } from './applyOnDelete-CAwZfp-5.mjs';
|
|
2
3
|
|
|
3
4
|
const RELATION_EXISTS_KEY = "__relationExists";
|
|
4
5
|
|
|
@@ -43,7 +44,7 @@ const containsRelationPredicate = (where, schema, tableName) => {
|
|
|
43
44
|
};
|
|
44
45
|
const assertFlatPredicate = (where, schema, tableName, op) => {
|
|
45
46
|
if (where && containsRelationPredicate(where, schema, tableName)) {
|
|
46
|
-
throw new
|
|
47
|
+
throw new LunoraError("INTERNAL", `relation-crossing predicates are not supported in ${op}() — use them in findMany/findFirst or an RLS read policy`);
|
|
47
48
|
}
|
|
48
49
|
};
|
|
49
50
|
const projectChildKeys = async (relation, childWhere, projectField, context, escalatable) => {
|
|
@@ -58,7 +59,8 @@ const projectChildKeys = async (relation, childWhere, projectField, context, esc
|
|
|
58
59
|
if (escalatable) {
|
|
59
60
|
return KEY_OVERFLOW;
|
|
60
61
|
}
|
|
61
|
-
throw new
|
|
62
|
+
throw new LunoraError(
|
|
63
|
+
"INTERNAL",
|
|
62
64
|
`relation predicate on "${relation.table}" matched ${String(keys.length)} rows, exceeding the ${String(context.maxRelationKeys)}-key limit; narrow the predicate (a same-shard EXISTS push-down lifts this cap)`
|
|
63
65
|
);
|
|
64
66
|
}
|
|
@@ -67,7 +69,7 @@ const projectChildKeys = async (relation, childWhere, projectField, context, esc
|
|
|
67
69
|
const compileOperator = async (operator, relation, childWhere, context, escalatable) => {
|
|
68
70
|
const meta = RELATION_OPERATOR_META[operator];
|
|
69
71
|
if (!meta) {
|
|
70
|
-
throw new
|
|
72
|
+
throw new LunoraError("INTERNAL", `unknown relation operator "${operator}"`);
|
|
71
73
|
}
|
|
72
74
|
const { clause, project } = joinColumns(relation);
|
|
73
75
|
const keys = await projectChildKeys(relation, meta.negateChild ? { NOT: childWhere } : childWhere, project, context, escalatable);
|
|
@@ -85,7 +87,7 @@ const compileOperator = async (operator, relation, childWhere, context, escalata
|
|
|
85
87
|
const buildExistsMarker = async (operator, relation, childWhere, parentTable, context) => {
|
|
86
88
|
const meta = RELATION_OPERATOR_META[operator];
|
|
87
89
|
if (!meta) {
|
|
88
|
-
throw new
|
|
90
|
+
throw new LunoraError("INTERNAL", `unknown relation operator "${operator}"`);
|
|
89
91
|
}
|
|
90
92
|
const base = context.relationBaseWhere?.(relation.table);
|
|
91
93
|
const predicatePart = meta.negateChild ? { NOT: childWhere } : childWhere;
|
|
@@ -97,7 +99,7 @@ const buildExistsMarker = async (operator, relation, childWhere, parentTable, co
|
|
|
97
99
|
const assertCardinality = (operator, name, relation) => {
|
|
98
100
|
const meta = RELATION_OPERATOR_META[operator];
|
|
99
101
|
if (meta && meta.kind !== relation.kind) {
|
|
100
|
-
throw new
|
|
102
|
+
throw new LunoraError("INTERNAL", `relation operator "${operator}" requires a to-${meta.kind} relation, but "${name}" is to-${relation.kind}`);
|
|
101
103
|
}
|
|
102
104
|
};
|
|
103
105
|
const resolveRelationNode = async (name, relation, predicate, parentTable, context) => {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
2
|
import { sql } from 'drizzle-orm';
|
|
2
|
-
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-
|
|
3
|
+
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
|
|
3
4
|
import { encodeAggregateKey, foldAggregateTally, aggregateTableName, coerceAggregateNumber, readAggregateValue } from './aggregateTableName-CxNqY1Sl.mjs';
|
|
4
|
-
import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-
|
|
5
|
-
import { appendCdcChange } from './CDC_LOG_TABLE-
|
|
6
|
-
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-
|
|
5
|
+
import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-BGxj0pgS.mjs';
|
|
6
|
+
import { appendCdcChange } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
7
|
+
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
7
8
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
8
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';
|
|
9
10
|
import { param } from './renderSql-D6eUcn2N.mjs';
|
|
@@ -12,18 +13,18 @@ import { stringifySearchText, ftsTableName, tokenizeSearch, buildFtsMatch, score
|
|
|
12
13
|
import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
|
|
13
14
|
import { SCAN_DEP } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
14
15
|
import { decodeCursor, normalizeOrderKeys, buildSeekWhere, applySelect, encodeCursor, softDeleteScope, buildSeekBeforeWhere } from './applySelect-BvZdFUBT.mjs';
|
|
15
|
-
import NotFoundError from './NotFoundError-
|
|
16
|
-
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-
|
|
17
|
-
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-
|
|
18
|
-
import { guardWriter } from './RLS_UNWRAP_SYMBOL-
|
|
19
|
-
import { createSystemReader } from './createSystemReader-
|
|
20
|
-
import { ConflictError } from './ConflictError-
|
|
16
|
+
import NotFoundError from './NotFoundError-C70b9hLw.mjs';
|
|
17
|
+
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs';
|
|
18
|
+
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-CAwZfp-5.mjs';
|
|
19
|
+
import { guardWriter } from './RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs';
|
|
20
|
+
import { createSystemReader } from './createSystemReader-D12eNH13.mjs';
|
|
21
|
+
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
21
22
|
import { runTriggers } from './hasTrigger-5N6_Fx0A.mjs';
|
|
22
|
-
import { compileWhereSql } from './compileWhereSql-
|
|
23
|
-
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-
|
|
23
|
+
import { compileWhereSql } from './compileWhereSql-DE6yfRcQ.mjs';
|
|
24
|
+
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-DDoT-UUI.mjs';
|
|
24
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';
|
|
25
|
-
export { runShardMigrations } from './runShardMigrations-
|
|
26
|
-
export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-
|
|
26
|
+
export { runShardMigrations } from './runShardMigrations-DeZr0KZp.mjs';
|
|
27
|
+
export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
27
28
|
|
|
28
29
|
const rankIndexFieldsUnchanged = (index, previous, next) => {
|
|
29
30
|
const fields = [...index.partitionBy ?? [], ...index.sortBy.map((key) => key.field), ...index.where ? Object.keys(index.where) : []];
|
|
@@ -422,11 +423,11 @@ const computeRankPage = (deps, tableName, indexName, rankPageOptions) => {
|
|
|
422
423
|
const { assertRankPartitionLocal, ensureRankBackfilled, onRead, schema } = deps;
|
|
423
424
|
const definition = schema.tables[tableName];
|
|
424
425
|
if (!definition) {
|
|
425
|
-
throw new
|
|
426
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
426
427
|
}
|
|
427
428
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
428
429
|
if (!index) {
|
|
429
|
-
throw new
|
|
430
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
430
431
|
}
|
|
431
432
|
assertRankPartitionLocal(tableName, definition, index);
|
|
432
433
|
onRead(tableName, SCAN_DEP);
|
|
@@ -474,7 +475,7 @@ const computeRankPage = (deps, tableName, indexName, rankPageOptions) => {
|
|
|
474
475
|
const CLIENT_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
475
476
|
const assertValidClientId = (clientId) => {
|
|
476
477
|
if (!CLIENT_ID_PATTERN.test(clientId)) {
|
|
477
|
-
throw new
|
|
478
|
+
throw new LunoraError("INTERNAL", `invalid clientId ${JSON.stringify(clientId)}: a client-supplied row id must be a UUID`);
|
|
478
479
|
}
|
|
479
480
|
};
|
|
480
481
|
const MAX_TRIGGER_DEPTH = 50;
|
|
@@ -518,14 +519,17 @@ const createSearchBuilder = (search, tableName) => {
|
|
|
518
519
|
const builder = {
|
|
519
520
|
eq: (field, value) => {
|
|
520
521
|
if (!search.definition.filterFields?.includes(field)) {
|
|
521
|
-
throw new
|
|
522
|
+
throw new LunoraError("INTERNAL", `field "${field}" is not a filter field of search index "${search.indexName}" on table "${tableName}"`);
|
|
522
523
|
}
|
|
523
524
|
search.filters.push({ field, value });
|
|
524
525
|
return builder;
|
|
525
526
|
},
|
|
526
527
|
search: (field, query) => {
|
|
527
528
|
if (field !== search.definition.field) {
|
|
528
|
-
throw new
|
|
529
|
+
throw new LunoraError(
|
|
530
|
+
"INTERNAL",
|
|
531
|
+
`search index "${search.indexName}" on table "${tableName}" indexes "${search.definition.field}", not "${field}"`
|
|
532
|
+
);
|
|
529
533
|
}
|
|
530
534
|
const stage = search;
|
|
531
535
|
stage.field = field;
|
|
@@ -706,19 +710,16 @@ const paginateStage = (sql$1, tableName, stage, options, scopeCondition) => {
|
|
|
706
710
|
page
|
|
707
711
|
};
|
|
708
712
|
};
|
|
709
|
-
class NotUniqueError extends
|
|
710
|
-
code = "NOT_UNIQUE";
|
|
711
|
-
status = 400;
|
|
713
|
+
class NotUniqueError extends LunoraError {
|
|
712
714
|
constructor(message = "unique() found more than one matching document") {
|
|
713
|
-
super(message);
|
|
714
|
-
this.name = "NotUniqueError";
|
|
715
|
+
super("NOT_UNIQUE", message, { name: "NotUniqueError" });
|
|
715
716
|
}
|
|
716
717
|
}
|
|
717
718
|
const ID_WHITESPACE_PATTERN = /\s/u;
|
|
718
719
|
const NUL_CHARACTER = String.fromCodePoint(0);
|
|
719
720
|
const normalizeIdStructurally = (schema, tableName, id) => {
|
|
720
721
|
if (!schema.tables[tableName]) {
|
|
721
|
-
throw new
|
|
722
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
722
723
|
}
|
|
723
724
|
if (typeof id !== "string" || id.length === 0 || ID_WHITESPACE_PATTERN.test(id) || id.includes(NUL_CHARACTER)) {
|
|
724
725
|
return null;
|
|
@@ -728,7 +729,7 @@ const normalizeIdStructurally = (schema, tableName, id) => {
|
|
|
728
729
|
const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
729
730
|
const tableDefinition = schema.tables[tableName];
|
|
730
731
|
if (!tableDefinition) {
|
|
731
|
-
throw new
|
|
732
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
732
733
|
}
|
|
733
734
|
const scopeWhere = softDeleteScope(tableDefinition.softDeleteMode, void 0);
|
|
734
735
|
const scopeCondition = scopeWhere ? compileWhereSql(scopeWhere, doWhereSqlStrategy) : void 0;
|
|
@@ -742,7 +743,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
742
743
|
const runSearchFetch = (limit) => {
|
|
743
744
|
const { search } = stage;
|
|
744
745
|
if (!search) {
|
|
745
|
-
throw new
|
|
746
|
+
throw new LunoraError("INTERNAL", "runSearchFetch called without a staged search");
|
|
746
747
|
}
|
|
747
748
|
const filtered = stage.inMemoryFilters.length > 0;
|
|
748
749
|
const engineLimit = filtered ? void 0 : limit;
|
|
@@ -825,7 +826,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
825
826
|
// eslint-disable-next-line @typescript-eslint/require-await -- TableReaderLike returns Promises (the D1 twin awaits real I/O); the DO impl is synchronous over local SQLite
|
|
826
827
|
async paginate(options) {
|
|
827
828
|
if (stage.search) {
|
|
828
|
-
throw new
|
|
829
|
+
throw new LunoraError("INTERNAL", "pagination is not supported on search queries; use .take(n) or .collect()");
|
|
829
830
|
}
|
|
830
831
|
return paginateStage(sql$1, tableName, stage, options, scopeCondition);
|
|
831
832
|
},
|
|
@@ -844,7 +845,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
844
845
|
withIndex(indexName, range) {
|
|
845
846
|
const definition = tableDefinition.indexes.find((index) => index.name === indexName);
|
|
846
847
|
if (!definition) {
|
|
847
|
-
throw new
|
|
848
|
+
throw new LunoraError("INTERNAL", `unknown index "${indexName}" on table "${tableName}"`);
|
|
848
849
|
}
|
|
849
850
|
onIndexUse(tableName, indexName, "index");
|
|
850
851
|
stage.indexName = indexName;
|
|
@@ -857,7 +858,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
857
858
|
withSearchIndex(indexName, search) {
|
|
858
859
|
const definition = (tableDefinition.searchIndexes ?? []).find((index) => index.name === indexName);
|
|
859
860
|
if (!definition) {
|
|
860
|
-
throw new
|
|
861
|
+
throw new LunoraError("INTERNAL", `unknown search index "${indexName}" on table "${tableName}"`);
|
|
861
862
|
}
|
|
862
863
|
onIndexUse(tableName, indexName, "search");
|
|
863
864
|
const searchStage = {
|
|
@@ -871,7 +872,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
871
872
|
stage.search = searchStage;
|
|
872
873
|
search(createSearchBuilder(searchStage, tableName));
|
|
873
874
|
if (!searchStage.hasQuery) {
|
|
874
|
-
throw new
|
|
875
|
+
throw new LunoraError("INTERNAL", `search index "${indexName}" on table "${tableName}" requires a .search(field, query) call`);
|
|
875
876
|
}
|
|
876
877
|
return reader;
|
|
877
878
|
}
|
|
@@ -913,7 +914,10 @@ const applyOnUpdate = (definition, provided, target, auth) => {
|
|
|
913
914
|
const assertNoExplicitUndefined = (op, document) => {
|
|
914
915
|
for (const field of Object.keys(document)) {
|
|
915
916
|
if (document[field] === void 0) {
|
|
916
|
-
throw new
|
|
917
|
+
throw new LunoraError(
|
|
918
|
+
"INTERNAL",
|
|
919
|
+
`Cannot ${op} field '${field}' to undefined — use null to clear a nullable field, or omit the key to leave it unchanged.`
|
|
920
|
+
);
|
|
917
921
|
}
|
|
918
922
|
}
|
|
919
923
|
};
|
|
@@ -993,7 +997,10 @@ const createShardCtxDb = (options) => {
|
|
|
993
997
|
const routeBackend = (table, op) => {
|
|
994
998
|
if (isGlobalTable(table)) {
|
|
995
999
|
if (!globalDb) {
|
|
996
|
-
throw new
|
|
1000
|
+
throw new LunoraError(
|
|
1001
|
+
"INTERNAL",
|
|
1002
|
+
`cross-backend ${op} for global table '${table}' requires a globalDb writer — pass one to createShardCtxDb({ globalDb })`
|
|
1003
|
+
);
|
|
997
1004
|
}
|
|
998
1005
|
return globalDb;
|
|
999
1006
|
}
|
|
@@ -1005,7 +1012,7 @@ const createShardCtxDb = (options) => {
|
|
|
1005
1012
|
return void 0;
|
|
1006
1013
|
}
|
|
1007
1014
|
if (!globalDb) {
|
|
1008
|
-
throw new
|
|
1015
|
+
throw new LunoraError("INTERNAL", `${op} on global table '${tableName}' requires a globalDb writer — pass one to createShardCtxDb({ globalDb })`);
|
|
1009
1016
|
}
|
|
1010
1017
|
return globalDb;
|
|
1011
1018
|
};
|
|
@@ -1036,7 +1043,7 @@ const createShardCtxDb = (options) => {
|
|
|
1036
1043
|
}
|
|
1037
1044
|
const definition = schema.tables[relationTable];
|
|
1038
1045
|
if (!definition) {
|
|
1039
|
-
throw new
|
|
1046
|
+
throw new LunoraError("INTERNAL", `unknown table: ${relationTable}`);
|
|
1040
1047
|
}
|
|
1041
1048
|
onRead(relationTable, SCAN_DEP);
|
|
1042
1049
|
const softScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
@@ -1153,7 +1160,7 @@ const createShardCtxDb = (options) => {
|
|
|
1153
1160
|
}
|
|
1154
1161
|
const definition = schema.tables[tableName];
|
|
1155
1162
|
if (!definition) {
|
|
1156
|
-
throw new
|
|
1163
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1157
1164
|
}
|
|
1158
1165
|
aggregateSqlFunction(aggOptions.op);
|
|
1159
1166
|
if (aggOptions.op === "count") {
|
|
@@ -1165,7 +1172,7 @@ const createShardCtxDb = (options) => {
|
|
|
1165
1172
|
});
|
|
1166
1173
|
}
|
|
1167
1174
|
if (!aggOptions.field) {
|
|
1168
|
-
throw new
|
|
1175
|
+
throw new LunoraError("INTERNAL", `aggregate(${tableName}, { op: "${aggOptions.op}" }): "field" is required for non-count reducers`);
|
|
1169
1176
|
}
|
|
1170
1177
|
onRead(tableName, SCAN_DEP);
|
|
1171
1178
|
const aggScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
@@ -1207,7 +1214,7 @@ const createShardCtxDb = (options) => {
|
|
|
1207
1214
|
}
|
|
1208
1215
|
const definition = schema.tables[tableName];
|
|
1209
1216
|
if (!definition) {
|
|
1210
|
-
throw new
|
|
1217
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1211
1218
|
}
|
|
1212
1219
|
const countOptions = normalizeCountArgument(whereOrOptions);
|
|
1213
1220
|
if (countOptions.restrictsCounts) {
|
|
@@ -1338,7 +1345,7 @@ const createShardCtxDb = (options) => {
|
|
|
1338
1345
|
}
|
|
1339
1346
|
const findManyDefinition = schema.tables[tableName];
|
|
1340
1347
|
if (!findManyDefinition) {
|
|
1341
|
-
throw new
|
|
1348
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1342
1349
|
}
|
|
1343
1350
|
const isFullScan = !args.where && !args.baseWhere;
|
|
1344
1351
|
if (isFullScan) {
|
|
@@ -1451,13 +1458,13 @@ const createShardCtxDb = (options) => {
|
|
|
1451
1458
|
}
|
|
1452
1459
|
const definition = schema.tables[tableName];
|
|
1453
1460
|
if (!definition) {
|
|
1454
|
-
throw new
|
|
1461
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1455
1462
|
}
|
|
1456
1463
|
onRead(tableName, SCAN_DEP);
|
|
1457
1464
|
const agg = groupOptions.agg ?? { op: "count" };
|
|
1458
1465
|
aggregateSqlFunction(agg.op);
|
|
1459
1466
|
if (agg.op !== "count" && !agg.field) {
|
|
1460
|
-
throw new
|
|
1467
|
+
throw new LunoraError("INTERNAL", `groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1461
1468
|
}
|
|
1462
1469
|
const groupScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1463
1470
|
const effective = mergeWhere(mergeWhere(groupOptions.baseWhere, groupOptions.where), groupScope);
|
|
@@ -1502,7 +1509,7 @@ const createShardCtxDb = (options) => {
|
|
|
1502
1509
|
} else {
|
|
1503
1510
|
const { field } = agg;
|
|
1504
1511
|
if (field === void 0) {
|
|
1505
|
-
throw new
|
|
1512
|
+
throw new LunoraError("INTERNAL", `groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1506
1513
|
}
|
|
1507
1514
|
select.push(sql`${sql.raw(aggregateSqlFunction(agg.op))}(${jsonPathSql(field)}) AS value`);
|
|
1508
1515
|
}
|
|
@@ -1535,7 +1542,7 @@ const createShardCtxDb = (options) => {
|
|
|
1535
1542
|
}
|
|
1536
1543
|
const definition = schema.tables[tableName];
|
|
1537
1544
|
if (!definition) {
|
|
1538
|
-
throw new
|
|
1545
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1539
1546
|
}
|
|
1540
1547
|
const withDefaults = applyInsertDefaults(definition, document, auth);
|
|
1541
1548
|
runRowValidators(definition, withDefaults);
|
|
@@ -1584,7 +1591,7 @@ const createShardCtxDb = (options) => {
|
|
|
1584
1591
|
}
|
|
1585
1592
|
const definition = schema.tables[tableName];
|
|
1586
1593
|
if (!definition) {
|
|
1587
|
-
throw new
|
|
1594
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1588
1595
|
}
|
|
1589
1596
|
ensureBackfilledForTable(tableName);
|
|
1590
1597
|
ensureRankBackfilledForTable(tableName);
|
|
@@ -1624,12 +1631,12 @@ const createShardCtxDb = (options) => {
|
|
|
1624
1631
|
await global.patch(id, patch);
|
|
1625
1632
|
return;
|
|
1626
1633
|
}
|
|
1627
|
-
throw new
|
|
1634
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1628
1635
|
}
|
|
1629
1636
|
const { docJson: existingJson, row: existing, tableName } = located;
|
|
1630
1637
|
const tableDefinition = schema.tables[tableName];
|
|
1631
1638
|
if (!tableDefinition) {
|
|
1632
|
-
throw new
|
|
1639
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1633
1640
|
}
|
|
1634
1641
|
onRead(tableName, id);
|
|
1635
1642
|
assertNoExplicitUndefined("patch", patch);
|
|
@@ -1681,11 +1688,11 @@ const createShardCtxDb = (options) => {
|
|
|
1681
1688
|
onIndexUse(tableName, indexName, "rank");
|
|
1682
1689
|
const definition = schema.tables[tableName];
|
|
1683
1690
|
if (!definition) {
|
|
1684
|
-
throw new
|
|
1691
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1685
1692
|
}
|
|
1686
1693
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
1687
1694
|
if (!index) {
|
|
1688
|
-
throw new
|
|
1695
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
1689
1696
|
}
|
|
1690
1697
|
assertRankPartitionLocal(tableName, definition, index);
|
|
1691
1698
|
if (rankOptions.restrictsCounts) {
|
|
@@ -1726,17 +1733,18 @@ const createShardCtxDb = (options) => {
|
|
|
1726
1733
|
// eslint-disable-next-line @typescript-eslint/require-await -- DatabaseWriterLike returns Promises (the D1 twin awaits I/O); the body is synchronous SQLite
|
|
1727
1734
|
async rankBefore(tableName, indexName, rankBeforeOptions) {
|
|
1728
1735
|
if (isGlobalTable(tableName)) {
|
|
1729
|
-
throw new
|
|
1736
|
+
throw new LunoraError(
|
|
1737
|
+
"INTERNAL",
|
|
1730
1738
|
`rankBefore is not supported on the global (.global()) table '${tableName}' — cross-shard rank cursors apply only to sharded tables`
|
|
1731
1739
|
);
|
|
1732
1740
|
}
|
|
1733
1741
|
const definition = schema.tables[tableName];
|
|
1734
1742
|
if (!definition) {
|
|
1735
|
-
throw new
|
|
1743
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1736
1744
|
}
|
|
1737
1745
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
1738
1746
|
if (!index) {
|
|
1739
|
-
throw new
|
|
1747
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
1740
1748
|
}
|
|
1741
1749
|
if (rankBeforeOptions.restrictsCounts) {
|
|
1742
1750
|
throw new CountRlsUnsupportedError(tableName);
|
|
@@ -1774,11 +1782,11 @@ const createShardCtxDb = (options) => {
|
|
|
1774
1782
|
await global.restore(id);
|
|
1775
1783
|
return;
|
|
1776
1784
|
}
|
|
1777
|
-
throw new
|
|
1785
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1778
1786
|
}
|
|
1779
1787
|
const field = schema.tables[located.tableName]?.softDeleteMode?.field;
|
|
1780
1788
|
if (!field) {
|
|
1781
|
-
throw new
|
|
1789
|
+
throw new LunoraError("INTERNAL", `ctx.db.restore: table "${located.tableName}" is not a .softDelete() table`);
|
|
1782
1790
|
}
|
|
1783
1791
|
const wasDeleted = located.row[field] !== null && located.row[field] !== void 0;
|
|
1784
1792
|
await writer.patch(id, { [field]: null }, expectedTable);
|
|
@@ -1794,12 +1802,12 @@ const createShardCtxDb = (options) => {
|
|
|
1794
1802
|
await global.replace(id, document);
|
|
1795
1803
|
return;
|
|
1796
1804
|
}
|
|
1797
|
-
throw new
|
|
1805
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1798
1806
|
}
|
|
1799
1807
|
const { docJson: existingJson, row: previous, tableName } = located;
|
|
1800
1808
|
const tableDefinition = schema.tables[tableName];
|
|
1801
1809
|
if (!tableDefinition) {
|
|
1802
|
-
throw new
|
|
1810
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1803
1811
|
}
|
|
1804
1812
|
assertNoExplicitUndefined("replace", document);
|
|
1805
1813
|
const creationTime = typeof document["_creationTime"] === "number" ? document["_creationTime"] : clock();
|
package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs → RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs}
RENAMED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const RLS_UNWRAP_SYMBOL = /* @__PURE__ */ Symbol.for("lunora.ctxdb.rls-unwrap");
|
|
2
|
-
class RlsRequiredError extends
|
|
3
|
-
code = "RLS_REQUIRED";
|
|
4
|
-
status = 403;
|
|
4
|
+
class RlsRequiredError extends LunoraError {
|
|
5
5
|
table;
|
|
6
6
|
constructor(table) {
|
|
7
7
|
super(
|
|
8
|
-
|
|
8
|
+
"RLS_REQUIRED",
|
|
9
|
+
`ctx.db access to "${table}" is denied: the schema is marked .rls("required"), so this table is protected. Apply RLS with .use(rls(policies)) in the procedure, or mark the table .public() to opt it out.`,
|
|
10
|
+
{ name: "RlsRequiredError" }
|
|
9
11
|
);
|
|
10
|
-
this.name = "RlsRequiredError";
|
|
11
12
|
this.table = table;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { LunoraError, toErrorBody } from '@lunora/errors';
|
|
1
2
|
import { drizzle } from 'drizzle-orm/durable-sqlite';
|
|
2
3
|
import { e as encodeWire, a as awaitWsDrain, t as trySendFrame, d as decodeWire, s as subscriptionListDeltas, b as sendDeltaFrames } from './subscription-delivery-CK8qga-k.mjs';
|
|
3
4
|
import { parseExportShardArgs, parseImportShardArgs } from './exportShardRows-DZEhUeyI.mjs';
|
|
4
5
|
import { recordAuthEvent, readAuthMetrics } from './AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
|
|
5
|
-
import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-
|
|
6
|
+
import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs';
|
|
6
7
|
import { SCAN_DEP, createDependencyTracker, tableFromDepKey } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
7
8
|
import { readFunctionMetricsTotals, readFunctionMetricIndexHits, recordFunctionMetric, mergeScanAttribution, readFunctionMetrics, readFunctionMetricBuckets } from './FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
8
9
|
import { createFanoutCounters, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, selectMatchingIds, ADMIN_FUNCTIONS, findStorageReferences, listTables, summarizeSubscriptions, summarizeFanoutTopics, readTablePage, facetColumn, FLAGS_FUNCTION_PREFIX, recordFanoutPass, MAX_PAGE_SIZE } from './ADMIN_FUNCTIONS-DSUQ5fX9.mjs';
|
|
@@ -14,10 +15,10 @@ import { stableStringify } from './stableStringify-MydiuScU.mjs';
|
|
|
14
15
|
import { redact, standardRules } from '@visulima/redact';
|
|
15
16
|
import { i as isDevEnvironment, c as buildSettings, b as buildSecurityAudit } from './security-audit-CucgBice.mjs';
|
|
16
17
|
import { runReadonlySql } from './MAX_SQL_ROWS-dDcFE1YZ.mjs';
|
|
17
|
-
import { ConflictError } from './ConflictError-
|
|
18
|
+
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
18
19
|
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';
|
|
19
|
-
import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-
|
|
20
|
-
import { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-
|
|
20
|
+
import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
21
|
+
import { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
21
22
|
|
|
22
23
|
const MAX_BATCH_ENTRIES = 500;
|
|
23
24
|
|
|
@@ -199,7 +200,7 @@ const shapeRoutingKey = (name, args) => stableStringify({ args: args ?? {}, name
|
|
|
199
200
|
const DEFAULT_PROMOTION_THRESHOLDS = { tDown: 4e3, tUp: 8e3 };
|
|
200
201
|
const nextPromotionState = (current, subscribers, thresholds = DEFAULT_PROMOTION_THRESHOLDS) => {
|
|
201
202
|
if (thresholds.tDown >= thresholds.tUp) {
|
|
202
|
-
throw new
|
|
203
|
+
throw new LunoraError("INTERNAL", `invalid promotion thresholds: tDown (${String(thresholds.tDown)}) must be < tUp (${String(thresholds.tUp)})`);
|
|
203
204
|
}
|
|
204
205
|
if (current === "owned") {
|
|
205
206
|
return subscribers >= thresholds.tUp ? "promoted" : "owned";
|
|
@@ -305,7 +306,7 @@ const envPositiveInt = (env, key, fallback) => {
|
|
|
305
306
|
};
|
|
306
307
|
const RELAY_MULTICAST_IDENTITY = {};
|
|
307
308
|
const assertNeverFrame = (frame) => {
|
|
308
|
-
throw new
|
|
309
|
+
throw new LunoraError("INTERNAL", `unhandled relay frame: ${JSON.stringify(frame)}`);
|
|
309
310
|
};
|
|
310
311
|
const asRelayNamespace = (value) => {
|
|
311
312
|
if (value === null || typeof value !== "object") {
|
|
@@ -4009,27 +4010,11 @@ class ShardDO {
|
|
|
4009
4010
|
*/
|
|
4010
4011
|
// eslint-disable-next-line class-methods-use-this -- cohesive DO instance method (groups with the request handlers); kept non-static so subclasses can override the error mapping
|
|
4011
4012
|
errorToResponse(error) {
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
if (error && typeof error === "object" && error.name === "ValidationError") {
|
|
4016
|
-
const message = error instanceof Error ? error.message : "validation failed";
|
|
4017
|
-
return jsonResponse({ error: { code: "VALIDATION_ERROR", message } }, 400);
|
|
4018
|
-
}
|
|
4019
|
-
if (error && typeof error === "object" && error.name === "LunoraError") {
|
|
4020
|
-
const lunoraError = error;
|
|
4021
|
-
const status = typeof lunoraError.status === "number" ? lunoraError.status : 500;
|
|
4022
|
-
const body = {
|
|
4023
|
-
code: lunoraError.code ?? "INTERNAL",
|
|
4024
|
-
message: lunoraError.message ?? "internal error"
|
|
4025
|
-
};
|
|
4026
|
-
if (lunoraError.data !== void 0) {
|
|
4027
|
-
body.data = encodeWire(lunoraError.data);
|
|
4028
|
-
}
|
|
4029
|
-
return jsonResponse({ error: body }, status);
|
|
4013
|
+
const { body, redacted, status } = toErrorBody(error, { encodeData: encodeWire, fallbackCode: "RPC_FAILED", redactedMessage: "internal error" });
|
|
4014
|
+
if (redacted) {
|
|
4015
|
+
console.error("[@lunora/do] internal error:", error);
|
|
4030
4016
|
}
|
|
4031
|
-
|
|
4032
|
-
return jsonResponse({ error: { code: "RPC_FAILED", message: "internal error" } }, 500);
|
|
4017
|
+
return jsonResponse({ error: body }, status);
|
|
4033
4018
|
}
|
|
4034
4019
|
/**
|
|
4035
4020
|
* Batch dispatch (plan 088). Applies each `calls[]` entry through the SAME
|
|
@@ -5007,7 +4992,6 @@ class ShardDO {
|
|
|
5007
4992
|
* 4. On normal completion send `{type:"complete"}`; on throw send
|
|
5008
4993
|
* `{type:"error"}`. Either way drop the controller.
|
|
5009
4994
|
*/
|
|
5010
|
-
// eslint-disable-next-line sonarjs/cognitive-complexity -- the stream lifecycle (ack → chunk pump → complete/error) plus the structured-vs-redacted error branch is the wire protocol and reads clearer inline than split across helpers sharing the controller + socket
|
|
5011
4995
|
async handleStream(ws, id, functionPath, args) {
|
|
5012
4996
|
const iterable = this.executeStream(functionPath, args);
|
|
5013
4997
|
if (!iterable) {
|
|
@@ -5047,16 +5031,13 @@ class ShardDO {
|
|
|
5047
5031
|
ws.send(JSON.stringify({ id, type: "complete" }));
|
|
5048
5032
|
}
|
|
5049
5033
|
} catch (error) {
|
|
5050
|
-
const {
|
|
5051
|
-
|
|
5052
|
-
if (!isStructured) {
|
|
5034
|
+
const { body, redacted } = toErrorBody(error, { fallbackCode: "INTERNAL_SERVER_ERROR", redactedMessage: "internal error" });
|
|
5035
|
+
if (redacted) {
|
|
5053
5036
|
console.error("[@lunora/do] unhandled stream error:", error);
|
|
5054
5037
|
}
|
|
5055
|
-
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
5056
|
-
const message = isStructured ? rawMessage : "internal error";
|
|
5057
5038
|
ws.send(
|
|
5058
5039
|
JSON.stringify({
|
|
5059
|
-
error: { code:
|
|
5040
|
+
error: { code: body.code, message: body.message },
|
|
5060
5041
|
id,
|
|
5061
5042
|
type: "error"
|
|
5062
5043
|
})
|
|
@@ -5338,8 +5319,8 @@ class ShardDO {
|
|
|
5338
5319
|
resolved = this.resolveShape(shape.name, shape.args ?? {}, identity);
|
|
5339
5320
|
} catch (error) {
|
|
5340
5321
|
this.recordShapeError(`shape:seed:${subId}`, error);
|
|
5341
|
-
const
|
|
5342
|
-
return { code, message:
|
|
5322
|
+
const { body } = toErrorBody(error, { fallbackCode: "SHAPE_RESOLVE_FAILED", redactedMessage: "shape resolution failed" });
|
|
5323
|
+
return { code: body.code, message: body.message };
|
|
5343
5324
|
}
|
|
5344
5325
|
if (!resolved) {
|
|
5345
5326
|
return { code: "SHAPE_NOT_FOUND", message: `shape "${shape.name}" not found or not permitted` };
|
|
@@ -5351,8 +5332,8 @@ class ShardDO {
|
|
|
5351
5332
|
return await this.seedOpLogShape(ws, subId, shape, resolved);
|
|
5352
5333
|
} catch (error) {
|
|
5353
5334
|
this.recordShapeError(`shape:seed:${subId}`, error);
|
|
5354
|
-
const
|
|
5355
|
-
return { code, message:
|
|
5335
|
+
const { body } = toErrorBody(error, { fallbackCode: "SHAPE_SEED_FAILED", redactedMessage: "shape seed failed" });
|
|
5336
|
+
return { code: body.code, message: body.message };
|
|
5356
5337
|
}
|
|
5357
5338
|
}
|
|
5358
5339
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
2
|
import { applySelect } from './applySelect-BvZdFUBT.mjs';
|
|
2
3
|
|
|
3
4
|
const projectChildren = (documents, nested) => nested.select ? applySelect(documents, nested.select, nested.with) : documents;
|
|
@@ -27,13 +28,13 @@ const resolveWith = async (options) => {
|
|
|
27
28
|
}
|
|
28
29
|
const parentDefinition = schema.tables[tableName];
|
|
29
30
|
if (!parentDefinition) {
|
|
30
|
-
throw new
|
|
31
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
31
32
|
}
|
|
32
33
|
const relationMap = parentDefinition.relationMap ?? {};
|
|
33
34
|
const requireRelation = (name) => {
|
|
34
35
|
const relation = relationMap[name];
|
|
35
36
|
if (!relation) {
|
|
36
|
-
throw new
|
|
37
|
+
throw new LunoraError("INTERNAL", `unknown relation "${name}" on table "${tableName}"`);
|
|
37
38
|
}
|
|
38
39
|
return relation;
|
|
39
40
|
};
|
|
@@ -145,7 +146,7 @@ const applyRelationOnDelete = async (options, holderTable, relation) => {
|
|
|
145
146
|
const applyOnDelete = async (options) => {
|
|
146
147
|
const { schema, tableName } = options;
|
|
147
148
|
if (!schema.tables[tableName]) {
|
|
148
|
-
throw new
|
|
149
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
149
150
|
}
|
|
150
151
|
for (const [holderTable, holderDefinition] of Object.entries(schema.tables)) {
|
|
151
152
|
const relations = holderDefinition.relationMap;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
|
-
import { matchesStaticWhere } from './AGGREGATE_SQL_FUNCTION-
|
|
2
|
+
import { matchesStaticWhere } from './AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
|
|
3
3
|
import { encodeAggregateKey, foldAggregateTally, aggregateTableName } from './aggregateTableName-CxNqY1Sl.mjs';
|
|
4
4
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
5
5
|
import { D as DOC_COLUMN, r as rowToDocument, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT } from './do-sql-BCHCWtrD.mjs';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
2
|
import { sql } from 'drizzle-orm';
|
|
2
3
|
|
|
3
4
|
const RELATION_EXISTS_KEY = "__relationExists";
|
|
@@ -94,7 +95,7 @@ const STRUCTURAL_KEYS = /* @__PURE__ */ new Set(["AND", "NOT", "OR", RELATION_EX
|
|
|
94
95
|
const compileStructuralKey = (key, value, strategy) => {
|
|
95
96
|
if (key === RELATION_EXISTS_KEY) {
|
|
96
97
|
if (!strategy.relationExists) {
|
|
97
|
-
throw new
|
|
98
|
+
throw new LunoraError("INTERNAL", "encountered a relation EXISTS marker without a relationExists strategy hook");
|
|
98
99
|
}
|
|
99
100
|
return strategy.relationExists(value);
|
|
100
101
|
}
|
package/dist/packem_shared/{createSystemReader-8CzSZP9V.mjs → createSystemReader-D12eNH13.mjs}
RENAMED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const toScheduledFunctionDoc = (record) => {
|
|
2
4
|
const doc = {
|
|
3
5
|
args: record["args"] ?? {},
|
|
@@ -40,13 +42,13 @@ const toStorageMetadata = (object) => {
|
|
|
40
42
|
const createSystemReader = (options = {}) => {
|
|
41
43
|
const requireScheduler = () => {
|
|
42
44
|
if (!options.scheduler) {
|
|
43
|
-
throw new
|
|
45
|
+
throw new LunoraError("INTERNAL", 'ctx.db.system.query("_scheduled_functions"): no scheduler configured. Pass `scheduler` to createShardDO().');
|
|
44
46
|
}
|
|
45
47
|
return options.scheduler;
|
|
46
48
|
};
|
|
47
49
|
const requireStorage = () => {
|
|
48
50
|
if (!options.storage) {
|
|
49
|
-
throw new
|
|
51
|
+
throw new LunoraError("INTERNAL", 'ctx.db.system.query("_storage"): no storage configured. Pass `storage` to createShardDO().');
|
|
50
52
|
}
|
|
51
53
|
return options.storage;
|
|
52
54
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
2
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
3
3
|
import { D as DOC_COLUMN, r as rowToDocument, j as jsonPathSql } from './do-sql-BCHCWtrD.mjs';
|
|
4
|
-
import { compileWhereSql } from './compileWhereSql-
|
|
4
|
+
import { compileWhereSql } from './compileWhereSql-DE6yfRcQ.mjs';
|
|
5
5
|
import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
|
|
6
6
|
|
|
7
7
|
const shapeWhereStrategy = { fieldRef: jsonPathSql, serialize: serializeSqlValue };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { runExternalSourceTick } from './materializeExternalRows-DNcvoLRT.mjs';
|
|
2
3
|
|
|
3
4
|
const liftSourceId = (row, options = {}) => {
|
|
4
5
|
const { idColumn = "id", map } = options;
|
|
5
6
|
const idValue = row[idColumn];
|
|
6
7
|
if (idValue === void 0 || idValue === null) {
|
|
7
|
-
throw new
|
|
8
|
+
throw new LunoraError("INTERNAL", `external-source: row is missing id column "${idColumn}"`);
|
|
8
9
|
}
|
|
9
10
|
if (typeof idValue !== "string" && typeof idValue !== "number" && typeof idValue !== "bigint") {
|
|
10
11
|
throw new TypeError(`external-source: id column "${idColumn}" must be a string or number`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { applyCdcChanges } from './CDC_LOG_TABLE-
|
|
2
|
-
import { s as selectShapeRows } from './ctx-db-shapes-
|
|
1
|
+
import { applyCdcChanges } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
2
|
+
import { s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
3
3
|
import { diffExternalSource, projectExternalSourceRow } from './diffExternalSource-Cx9HUPJj.mjs';
|
|
4
4
|
import { stableStringify } from './stableStringify-MydiuScU.mjs';
|
|
5
5
|
|
package/dist/packem_shared/{runShardMigrations-nIwoQeOK.mjs → runShardMigrations-DeZr0KZp.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-DZSVKRr7.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.22",
|
|
4
4
|
"description": "Lunora Durable Objects: ShardDO (SQLite, OCC, hibernated WebSocket subscriptions) and SessionDO",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
+
"@lunora/errors": "1.0.0-alpha.1",
|
|
49
50
|
"@visulima/redact": "3.0.0-alpha.14",
|
|
50
51
|
"drizzle-orm": "^0.45.2"
|
|
51
52
|
},
|