@lunora/server 1.0.0-alpha.1 → 1.0.0-alpha.10
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/README.md +5 -1
- package/__assets__/package-og.svg +1 -1
- package/dist/data-model.d.mts +104 -16
- package/dist/data-model.d.ts +104 -16
- package/dist/index.d.mts +269 -25
- package/dist/index.d.ts +269 -25
- package/dist/index.mjs +16 -12
- package/dist/packem_shared/{LunoraError-DhggBJZF.mjs → LunoraError-DN7Zhhvu.mjs} +4 -1
- package/dist/packem_shared/{definePresence-D5LtwGl0.mjs → PRESENCE_DEFAULT_TTL_MS-D8viLY1S.mjs} +4 -4
- package/dist/packem_shared/{bindTableFacade-DCuyr46L.mjs → bindOrm-Ce57S3N9.mjs} +58 -1
- package/dist/packem_shared/buildRlsReadRegistry-1jexWrb3.mjs +107 -0
- package/dist/packem_shared/createSecrets-TsIP9lOa.mjs +55 -0
- package/dist/packem_shared/{defineAggregateIndex-DzqxtAyV.mjs → defineAggregateIndex-ZdyU78gh.mjs} +58 -3
- package/dist/packem_shared/defineMutator-EIXAWhs9.mjs +11 -0
- package/dist/packem_shared/defineShape-CJ27Wx7o.mjs +17 -0
- package/dist/packem_shared/functions-Di9FUNkf.mjs +5 -0
- package/dist/packem_shared/{httpAction-B7FYUEgr.mjs → httpAction-FLwfsePg.mjs} +1 -1
- package/dist/packem_shared/{initLunora-CATvPsVt.mjs → initLunora-lxwHTEV3.mjs} +17 -3
- package/dist/packem_shared/{mask-CkZJHHMM.mjs → mask-BV_jNzsN.mjs} +2 -2
- package/dist/packem_shared/policy-tag-DvpVH2tv.mjs +13 -0
- package/dist/packem_shared/{rls-Zhf5wEeJ.mjs → rls-2Jhd0uev.mjs} +22 -4
- package/dist/packem_shared/{storageRules-4a30FSpI.mjs → storageRules-Cje6Woea.mjs} +1 -1
- package/dist/rls/testing.mjs +1 -1
- package/dist/types.d.mts +130 -2
- package/dist/types.d.ts +130 -2
- package/package.json +5 -5
- /package/dist/packem_shared/{defineEnv-DjFkpkSP.mjs → LunoraEnvError-DjFkpkSP.mjs} +0 -0
- /package/dist/packem_shared/{defineSchemaExtension-Ck5_TUO8.mjs → composePluginMiddleware-Ck5_TUO8.mjs} +0 -0
- /package/dist/packem_shared/{definePolicy-De67zPDS.mjs → createPolicyDsl-De67zPDS.mjs} +0 -0
package/dist/types.d.mts
CHANGED
|
@@ -5,6 +5,14 @@ type ArgsValidator = ValidatorMap;
|
|
|
5
5
|
type InferArgs<A extends ArgsValidator> = InferValidatorMap<A>;
|
|
6
6
|
/** Storage backend for a `.global()` table: D1 (default) or a Postgres/MySQL database via Cloudflare Hyperdrive (PlanetScale, Neon, …). */
|
|
7
7
|
type GlobalBackend = "d1" | "hyperdrive";
|
|
8
|
+
/**
|
|
9
|
+
* Cloudflare Durable Object data-residency jurisdiction declared via
|
|
10
|
+
* `defineSchema(...).jurisdiction("…")`. Restricts where every DO the app
|
|
11
|
+
* reaches runs and persists data (GDPR, FedRAMP, US data residency). Widening
|
|
12
|
+
* union — Cloudflare adds values over time.
|
|
13
|
+
* @see https://developers.cloudflare.com/durable-objects/reference/data-location/
|
|
14
|
+
*/
|
|
15
|
+
type DurableObjectJurisdiction = "eu" | "fedramp" | "us";
|
|
8
16
|
/** How a table is routed at runtime. */
|
|
9
17
|
type ShardMode = {
|
|
10
18
|
backend?: GlobalBackend;
|
|
@@ -15,6 +23,51 @@ type ShardMode = {
|
|
|
15
23
|
} | {
|
|
16
24
|
kind: "root";
|
|
17
25
|
};
|
|
26
|
+
/** Poll cadence for a sourced table — `"manual"` (pull only on an explicit trigger) or a fixed interval. */
|
|
27
|
+
type ExternalSourceRefresh = "manual" | {
|
|
28
|
+
everyMs: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Delete-detection mode for external-source ingest. `"full-pull"` (default) reads
|
|
32
|
+
* the whole tenant membership each tick and diffs it, so it observes upstream
|
|
33
|
+
* deletes; `"incremental"` pulls only changed rows (cheap) and is blind to deletes
|
|
34
|
+
* unless paired with a soft-delete column or a `reconcileEveryMs` full-pull sweep.
|
|
35
|
+
*/
|
|
36
|
+
type ExternalSourceMode = "full-pull" | "incremental";
|
|
37
|
+
/**
|
|
38
|
+
* Config for `.source(...)` (plan 077): declares a table as **materialized from an
|
|
39
|
+
* external Postgres/MySQL behind Cloudflare Hyperdrive**, not written by user
|
|
40
|
+
* mutations. A system-driven poll loop reads the tenant slice and lands it in the
|
|
41
|
+
* DO's SQLite (via the validated CDC writer), after which `defineShape` carries it
|
|
42
|
+
* to clients unchanged. Orthogonal to `shardMode` — a sourced table almost always
|
|
43
|
+
* also `.shardBy()`s, in which case `tenantBy` is the mandatory tenant-isolation
|
|
44
|
+
* boundary (enforced by the `external_source_unscoped` advisor lint).
|
|
45
|
+
*/
|
|
46
|
+
interface ExternalSourceDefinition {
|
|
47
|
+
/** The wrangler Hyperdrive binding name the poll loop reads from. */
|
|
48
|
+
binding: string;
|
|
49
|
+
/** Project the materialized rows to these columns (passed to the membership diff). Omit ⇒ the full mapped document. */
|
|
50
|
+
columns?: ReadonlyArray<string>;
|
|
51
|
+
/** Column whose value becomes the Lunora `_id`. Defaults to `"id"`. */
|
|
52
|
+
idColumn?: string;
|
|
53
|
+
/** Transform an external row into the stored document body. Omit ⇒ every selected column except `idColumn` is copied. */
|
|
54
|
+
map?: (row: Record<string, unknown>) => Record<string, unknown>;
|
|
55
|
+
/** Delete-detection mode. Defaults to `"full-pull"`. */
|
|
56
|
+
mode?: ExternalSourceMode;
|
|
57
|
+
/** The full tenant-membership query, with driver-native placeholders (`$1` / `?`). `tenantBy` binds its params. */
|
|
58
|
+
query: string;
|
|
59
|
+
/** `"incremental"` only: run a full-pull reconcile this often to garbage-collect tombstones the incremental path can't see. */
|
|
60
|
+
reconcileEveryMs?: number;
|
|
61
|
+
/** Poll cadence, or `"manual"`. Omit ⇒ the runtime's size-scaled default. */
|
|
62
|
+
refresh?: ExternalSourceRefresh;
|
|
63
|
+
/**
|
|
64
|
+
* **Mandatory under `.shardBy()`**: map this DO's shard key → the query's bound
|
|
65
|
+
* params, so a tenant DO can only ever pull its own rows. An unscoped sourced +
|
|
66
|
+
* sharded table replicates the whole multitenant table into every shard — the
|
|
67
|
+
* `external_source_unscoped` advisor lint fails the build when this is absent.
|
|
68
|
+
*/
|
|
69
|
+
tenantBy?: (shardKey: string) => ReadonlyArray<unknown>;
|
|
70
|
+
}
|
|
18
71
|
interface IndexDefinition {
|
|
19
72
|
fields: ReadonlyArray<string>;
|
|
20
73
|
name: string;
|
|
@@ -130,6 +183,14 @@ interface TableDefinition<Shape extends Record<string, Validator> = Record<strin
|
|
|
130
183
|
* without scanning the underlying table.
|
|
131
184
|
*/
|
|
132
185
|
aggregateIndexes: ReadonlyArray<AggregateIndexDefinition>;
|
|
186
|
+
/**
|
|
187
|
+
* Set by `.source(...)` (named `externalSource`, not `source`, so the data
|
|
188
|
+
* field doesn't collide with the fluent `.source()` builder method — same
|
|
189
|
+
* convention as `shardBy()`/`shardMode`). When present, the table is
|
|
190
|
+
* materialized from an external Hyperdrive-backed database by a system poll
|
|
191
|
+
* loop rather than user mutations. Implies `isExternallyManaged`.
|
|
192
|
+
*/
|
|
193
|
+
externalSource?: ExternalSourceDefinition;
|
|
133
194
|
indexes: ReadonlyArray<IndexDefinition>;
|
|
134
195
|
/**
|
|
135
196
|
* `true` when `.externallyManaged()` was called — the table's rows are
|
|
@@ -165,6 +226,20 @@ interface TableDefinition<Shape extends Record<string, Validator> = Record<strin
|
|
|
165
226
|
shape: Shape;
|
|
166
227
|
shardMode: ShardMode;
|
|
167
228
|
/**
|
|
229
|
+
* Set by `.softDelete()` (named `softDeleteMode`, not `softDelete`, so the
|
|
230
|
+
* data field doesn't collide with the fluent `.softDelete()` builder method —
|
|
231
|
+
* same convention as `shardBy()`/`shardMode`). When present, the table carries
|
|
232
|
+
* a nullable timestamp column (`field`, default `deletedAt`):
|
|
233
|
+
* `ctx.db.<table>.delete()` flips it instead of physically removing the row,
|
|
234
|
+
* and **list reads** (`findMany`/`findFirst`/`query()`/`count`/`aggregate`/
|
|
235
|
+
* relation loads) hide rows whose `field` is set unless
|
|
236
|
+
* `includeDeleted: true` is passed. By-id `get`/`patch`/`replace` and
|
|
237
|
+
* `restore` are unaffected. Absent ⇒ deletes are physical, as before.
|
|
238
|
+
*/
|
|
239
|
+
softDeleteMode?: {
|
|
240
|
+
field: string;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
168
243
|
* Declared lifecycle triggers keyed by accessor name; empty unless
|
|
169
244
|
* `.triggers()` was called. Named `triggerMap` (not `triggers`) so the
|
|
170
245
|
* fluent `.triggers((t) => …)` builder method doesn't collide with this
|
|
@@ -614,6 +689,31 @@ interface Workflows {
|
|
|
614
689
|
/** Resolve the handle for a declared workflow by export name. */
|
|
615
690
|
get: <Params = Record<string, unknown>>(name: string) => WorkflowHandle<Params>;
|
|
616
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Structural projection of workers-types' `SecretsStoreSecret` binding — the
|
|
694
|
+
* per-secret `secrets_store_secrets[]` binding whose `.get()` resolves the
|
|
695
|
+
* secret value (or throws if it does not exist). Mirrored structurally so the
|
|
696
|
+
* runtime resolves it without a workerd type dependency.
|
|
697
|
+
*/
|
|
698
|
+
interface SecretsStoreSecretLike {
|
|
699
|
+
get: () => Promise<string>;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* `ctx.secrets` — read account-level secrets bound via Cloudflare Secrets Store.
|
|
703
|
+
* A core built-in (always present on every context, like `ctx.log`): a binding
|
|
704
|
+
* named in wrangler's `secrets_store_secrets[]` is read by its binding name.
|
|
705
|
+
*
|
|
706
|
+
* ```ts
|
|
707
|
+
* const apiKey = await ctx.secrets.get("STRIPE_KEY");
|
|
708
|
+
* ```
|
|
709
|
+
*
|
|
710
|
+
* The lookup is async (the platform fetches and decrypts on first read);
|
|
711
|
+
* reading an undeclared name throws a directed error naming the bound secrets.
|
|
712
|
+
*/
|
|
713
|
+
interface Secrets {
|
|
714
|
+
/** Resolve a Secrets Store secret by its wrangler binding name. */
|
|
715
|
+
get: (name: string) => Promise<string>;
|
|
716
|
+
}
|
|
617
717
|
/** Lifecycle phase relative to the SQL write. */
|
|
618
718
|
type TriggerTiming = "after" | "before";
|
|
619
719
|
/** The CRUD operation a trigger reacts to. `patch` and `replace` both map to `update`. */
|
|
@@ -899,7 +999,7 @@ interface VectorRecord {
|
|
|
899
999
|
}
|
|
900
1000
|
/**
|
|
901
1001
|
* Read-only vector surface exposed on {@link QueryCtx}. Mirrors the read half
|
|
902
|
-
* of `@lunora/vectors`' `LunoraVectors` so the live adapter is assignable.
|
|
1002
|
+
* of `@lunora/bindings/vectors`' `LunoraVectors` so the live adapter is assignable.
|
|
903
1003
|
*/
|
|
904
1004
|
interface VectorSearchReader {
|
|
905
1005
|
getByIds: (indexName: string, ids: ReadonlyArray<string>) => Promise<ReadonlyArray<VectorRecord>>;
|
|
@@ -953,6 +1053,14 @@ interface QueryCtx {
|
|
|
953
1053
|
/** Structured, function-attributed logger; see {@link LunoraLogger}. */
|
|
954
1054
|
readonly log: LunoraLogger;
|
|
955
1055
|
/**
|
|
1056
|
+
* Wall-clock time (epoch ms) the function began, captured once so the whole
|
|
1057
|
+
* handler sees a single stable value. Query/mutation handlers must be
|
|
1058
|
+
* deterministic — they may be re-run on OCC retry / subscription re-eval — so
|
|
1059
|
+
* read time through `ctx.now` instead of `Date.now()` (the latter is flagged
|
|
1060
|
+
* by the `nondeterministic_query_mutation` advisor). Actions may use `Date.now()`.
|
|
1061
|
+
*/
|
|
1062
|
+
readonly now: number;
|
|
1063
|
+
/**
|
|
956
1064
|
* Compose a read-only subquery in-process, reusing this query's read
|
|
957
1065
|
* context (same transaction, same `db`). Executes the referenced query's
|
|
958
1066
|
* handler directly — no fresh DO RPC round-trip — so it observes the exact
|
|
@@ -961,6 +1069,8 @@ interface QueryCtx {
|
|
|
961
1069
|
* Mirrors Convex's `ctx.runQuery`.
|
|
962
1070
|
*/
|
|
963
1071
|
readonly runQuery: <A extends ArgsValidator, R>(reference: RegisteredQuery<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1072
|
+
/** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
|
|
1073
|
+
readonly secrets: Secrets;
|
|
964
1074
|
readonly storage: ReadOnlyStorage;
|
|
965
1075
|
readonly vectors: VectorSearchReader;
|
|
966
1076
|
}
|
|
@@ -977,6 +1087,14 @@ interface MutationCtx {
|
|
|
977
1087
|
/** Structured, function-attributed logger; see {@link LunoraLogger}. */
|
|
978
1088
|
readonly log: LunoraLogger;
|
|
979
1089
|
/**
|
|
1090
|
+
* Wall-clock time (epoch ms) the function began, captured once so the whole
|
|
1091
|
+
* handler sees a single stable value. Mutation handlers must be deterministic
|
|
1092
|
+
* — they may be re-run on OCC retry — so read time through `ctx.now` instead
|
|
1093
|
+
* of `Date.now()` (the latter is flagged by the `nondeterministic_query_mutation`
|
|
1094
|
+
* advisor). Actions may use `Date.now()`.
|
|
1095
|
+
*/
|
|
1096
|
+
readonly now: number;
|
|
1097
|
+
/**
|
|
980
1098
|
* Compose a submutation in-process, reusing this mutation's `db` writer.
|
|
981
1099
|
* Executes the referenced mutation's handler directly — no fresh DO RPC —
|
|
982
1100
|
* so its writes apply through the same shard invocation as the enclosing
|
|
@@ -993,6 +1111,8 @@ interface MutationCtx {
|
|
|
993
1111
|
*/
|
|
994
1112
|
readonly runQuery: <A extends ArgsValidator, R>(reference: RegisteredQuery<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
995
1113
|
readonly scheduler: Scheduler;
|
|
1114
|
+
/** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
|
|
1115
|
+
readonly secrets: Secrets;
|
|
996
1116
|
readonly storage: ReadOnlyStorage;
|
|
997
1117
|
readonly vectors: VectorSearch;
|
|
998
1118
|
/** Start / resume / inspect durable workflows; see {@link Workflows}. */
|
|
@@ -1011,10 +1131,18 @@ interface ActionCtx {
|
|
|
1011
1131
|
readonly ip?: string;
|
|
1012
1132
|
/** Structured, function-attributed logger; see {@link LunoraLogger}. */
|
|
1013
1133
|
readonly log: LunoraLogger;
|
|
1134
|
+
/**
|
|
1135
|
+
* Wall-clock time (epoch ms) the action began, captured once for convenience
|
|
1136
|
+
* and parity with query/mutation `ctx.now`. Actions run exactly once, so they
|
|
1137
|
+
* may also use ambient `Date.now()` freely.
|
|
1138
|
+
*/
|
|
1139
|
+
readonly now: number;
|
|
1014
1140
|
readonly runAction: <A extends ArgsValidator, R>(reference: RegisteredAction<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1015
1141
|
readonly runMutation: <A extends ArgsValidator, R>(reference: RegisteredMutation<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1016
1142
|
readonly runQuery: <A extends ArgsValidator, R>(reference: RegisteredQuery<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1017
1143
|
readonly scheduler: Scheduler;
|
|
1144
|
+
/** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
|
|
1145
|
+
readonly secrets: Secrets;
|
|
1018
1146
|
readonly storage: Storage;
|
|
1019
1147
|
readonly vectors: VectorSearch;
|
|
1020
1148
|
/** Start / resume / inspect durable workflows; see {@link Workflows}. */
|
|
@@ -1026,4 +1154,4 @@ interface ActionCtx {
|
|
|
1026
1154
|
*/
|
|
1027
1155
|
type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
|
|
1028
1156
|
declare const anyApi: AnyApi;
|
|
1029
|
-
export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
|
|
1157
|
+
export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type Secrets, type SecretsStoreSecretLike, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,14 @@ type ArgsValidator = ValidatorMap;
|
|
|
5
5
|
type InferArgs<A extends ArgsValidator> = InferValidatorMap<A>;
|
|
6
6
|
/** Storage backend for a `.global()` table: D1 (default) or a Postgres/MySQL database via Cloudflare Hyperdrive (PlanetScale, Neon, …). */
|
|
7
7
|
type GlobalBackend = "d1" | "hyperdrive";
|
|
8
|
+
/**
|
|
9
|
+
* Cloudflare Durable Object data-residency jurisdiction declared via
|
|
10
|
+
* `defineSchema(...).jurisdiction("…")`. Restricts where every DO the app
|
|
11
|
+
* reaches runs and persists data (GDPR, FedRAMP, US data residency). Widening
|
|
12
|
+
* union — Cloudflare adds values over time.
|
|
13
|
+
* @see https://developers.cloudflare.com/durable-objects/reference/data-location/
|
|
14
|
+
*/
|
|
15
|
+
type DurableObjectJurisdiction = "eu" | "fedramp" | "us";
|
|
8
16
|
/** How a table is routed at runtime. */
|
|
9
17
|
type ShardMode = {
|
|
10
18
|
backend?: GlobalBackend;
|
|
@@ -15,6 +23,51 @@ type ShardMode = {
|
|
|
15
23
|
} | {
|
|
16
24
|
kind: "root";
|
|
17
25
|
};
|
|
26
|
+
/** Poll cadence for a sourced table — `"manual"` (pull only on an explicit trigger) or a fixed interval. */
|
|
27
|
+
type ExternalSourceRefresh = "manual" | {
|
|
28
|
+
everyMs: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Delete-detection mode for external-source ingest. `"full-pull"` (default) reads
|
|
32
|
+
* the whole tenant membership each tick and diffs it, so it observes upstream
|
|
33
|
+
* deletes; `"incremental"` pulls only changed rows (cheap) and is blind to deletes
|
|
34
|
+
* unless paired with a soft-delete column or a `reconcileEveryMs` full-pull sweep.
|
|
35
|
+
*/
|
|
36
|
+
type ExternalSourceMode = "full-pull" | "incremental";
|
|
37
|
+
/**
|
|
38
|
+
* Config for `.source(...)` (plan 077): declares a table as **materialized from an
|
|
39
|
+
* external Postgres/MySQL behind Cloudflare Hyperdrive**, not written by user
|
|
40
|
+
* mutations. A system-driven poll loop reads the tenant slice and lands it in the
|
|
41
|
+
* DO's SQLite (via the validated CDC writer), after which `defineShape` carries it
|
|
42
|
+
* to clients unchanged. Orthogonal to `shardMode` — a sourced table almost always
|
|
43
|
+
* also `.shardBy()`s, in which case `tenantBy` is the mandatory tenant-isolation
|
|
44
|
+
* boundary (enforced by the `external_source_unscoped` advisor lint).
|
|
45
|
+
*/
|
|
46
|
+
interface ExternalSourceDefinition {
|
|
47
|
+
/** The wrangler Hyperdrive binding name the poll loop reads from. */
|
|
48
|
+
binding: string;
|
|
49
|
+
/** Project the materialized rows to these columns (passed to the membership diff). Omit ⇒ the full mapped document. */
|
|
50
|
+
columns?: ReadonlyArray<string>;
|
|
51
|
+
/** Column whose value becomes the Lunora `_id`. Defaults to `"id"`. */
|
|
52
|
+
idColumn?: string;
|
|
53
|
+
/** Transform an external row into the stored document body. Omit ⇒ every selected column except `idColumn` is copied. */
|
|
54
|
+
map?: (row: Record<string, unknown>) => Record<string, unknown>;
|
|
55
|
+
/** Delete-detection mode. Defaults to `"full-pull"`. */
|
|
56
|
+
mode?: ExternalSourceMode;
|
|
57
|
+
/** The full tenant-membership query, with driver-native placeholders (`$1` / `?`). `tenantBy` binds its params. */
|
|
58
|
+
query: string;
|
|
59
|
+
/** `"incremental"` only: run a full-pull reconcile this often to garbage-collect tombstones the incremental path can't see. */
|
|
60
|
+
reconcileEveryMs?: number;
|
|
61
|
+
/** Poll cadence, or `"manual"`. Omit ⇒ the runtime's size-scaled default. */
|
|
62
|
+
refresh?: ExternalSourceRefresh;
|
|
63
|
+
/**
|
|
64
|
+
* **Mandatory under `.shardBy()`**: map this DO's shard key → the query's bound
|
|
65
|
+
* params, so a tenant DO can only ever pull its own rows. An unscoped sourced +
|
|
66
|
+
* sharded table replicates the whole multitenant table into every shard — the
|
|
67
|
+
* `external_source_unscoped` advisor lint fails the build when this is absent.
|
|
68
|
+
*/
|
|
69
|
+
tenantBy?: (shardKey: string) => ReadonlyArray<unknown>;
|
|
70
|
+
}
|
|
18
71
|
interface IndexDefinition {
|
|
19
72
|
fields: ReadonlyArray<string>;
|
|
20
73
|
name: string;
|
|
@@ -130,6 +183,14 @@ interface TableDefinition<Shape extends Record<string, Validator> = Record<strin
|
|
|
130
183
|
* without scanning the underlying table.
|
|
131
184
|
*/
|
|
132
185
|
aggregateIndexes: ReadonlyArray<AggregateIndexDefinition>;
|
|
186
|
+
/**
|
|
187
|
+
* Set by `.source(...)` (named `externalSource`, not `source`, so the data
|
|
188
|
+
* field doesn't collide with the fluent `.source()` builder method — same
|
|
189
|
+
* convention as `shardBy()`/`shardMode`). When present, the table is
|
|
190
|
+
* materialized from an external Hyperdrive-backed database by a system poll
|
|
191
|
+
* loop rather than user mutations. Implies `isExternallyManaged`.
|
|
192
|
+
*/
|
|
193
|
+
externalSource?: ExternalSourceDefinition;
|
|
133
194
|
indexes: ReadonlyArray<IndexDefinition>;
|
|
134
195
|
/**
|
|
135
196
|
* `true` when `.externallyManaged()` was called — the table's rows are
|
|
@@ -165,6 +226,20 @@ interface TableDefinition<Shape extends Record<string, Validator> = Record<strin
|
|
|
165
226
|
shape: Shape;
|
|
166
227
|
shardMode: ShardMode;
|
|
167
228
|
/**
|
|
229
|
+
* Set by `.softDelete()` (named `softDeleteMode`, not `softDelete`, so the
|
|
230
|
+
* data field doesn't collide with the fluent `.softDelete()` builder method —
|
|
231
|
+
* same convention as `shardBy()`/`shardMode`). When present, the table carries
|
|
232
|
+
* a nullable timestamp column (`field`, default `deletedAt`):
|
|
233
|
+
* `ctx.db.<table>.delete()` flips it instead of physically removing the row,
|
|
234
|
+
* and **list reads** (`findMany`/`findFirst`/`query()`/`count`/`aggregate`/
|
|
235
|
+
* relation loads) hide rows whose `field` is set unless
|
|
236
|
+
* `includeDeleted: true` is passed. By-id `get`/`patch`/`replace` and
|
|
237
|
+
* `restore` are unaffected. Absent ⇒ deletes are physical, as before.
|
|
238
|
+
*/
|
|
239
|
+
softDeleteMode?: {
|
|
240
|
+
field: string;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
168
243
|
* Declared lifecycle triggers keyed by accessor name; empty unless
|
|
169
244
|
* `.triggers()` was called. Named `triggerMap` (not `triggers`) so the
|
|
170
245
|
* fluent `.triggers((t) => …)` builder method doesn't collide with this
|
|
@@ -614,6 +689,31 @@ interface Workflows {
|
|
|
614
689
|
/** Resolve the handle for a declared workflow by export name. */
|
|
615
690
|
get: <Params = Record<string, unknown>>(name: string) => WorkflowHandle<Params>;
|
|
616
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Structural projection of workers-types' `SecretsStoreSecret` binding — the
|
|
694
|
+
* per-secret `secrets_store_secrets[]` binding whose `.get()` resolves the
|
|
695
|
+
* secret value (or throws if it does not exist). Mirrored structurally so the
|
|
696
|
+
* runtime resolves it without a workerd type dependency.
|
|
697
|
+
*/
|
|
698
|
+
interface SecretsStoreSecretLike {
|
|
699
|
+
get: () => Promise<string>;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* `ctx.secrets` — read account-level secrets bound via Cloudflare Secrets Store.
|
|
703
|
+
* A core built-in (always present on every context, like `ctx.log`): a binding
|
|
704
|
+
* named in wrangler's `secrets_store_secrets[]` is read by its binding name.
|
|
705
|
+
*
|
|
706
|
+
* ```ts
|
|
707
|
+
* const apiKey = await ctx.secrets.get("STRIPE_KEY");
|
|
708
|
+
* ```
|
|
709
|
+
*
|
|
710
|
+
* The lookup is async (the platform fetches and decrypts on first read);
|
|
711
|
+
* reading an undeclared name throws a directed error naming the bound secrets.
|
|
712
|
+
*/
|
|
713
|
+
interface Secrets {
|
|
714
|
+
/** Resolve a Secrets Store secret by its wrangler binding name. */
|
|
715
|
+
get: (name: string) => Promise<string>;
|
|
716
|
+
}
|
|
617
717
|
/** Lifecycle phase relative to the SQL write. */
|
|
618
718
|
type TriggerTiming = "after" | "before";
|
|
619
719
|
/** The CRUD operation a trigger reacts to. `patch` and `replace` both map to `update`. */
|
|
@@ -899,7 +999,7 @@ interface VectorRecord {
|
|
|
899
999
|
}
|
|
900
1000
|
/**
|
|
901
1001
|
* Read-only vector surface exposed on {@link QueryCtx}. Mirrors the read half
|
|
902
|
-
* of `@lunora/vectors`' `LunoraVectors` so the live adapter is assignable.
|
|
1002
|
+
* of `@lunora/bindings/vectors`' `LunoraVectors` so the live adapter is assignable.
|
|
903
1003
|
*/
|
|
904
1004
|
interface VectorSearchReader {
|
|
905
1005
|
getByIds: (indexName: string, ids: ReadonlyArray<string>) => Promise<ReadonlyArray<VectorRecord>>;
|
|
@@ -953,6 +1053,14 @@ interface QueryCtx {
|
|
|
953
1053
|
/** Structured, function-attributed logger; see {@link LunoraLogger}. */
|
|
954
1054
|
readonly log: LunoraLogger;
|
|
955
1055
|
/**
|
|
1056
|
+
* Wall-clock time (epoch ms) the function began, captured once so the whole
|
|
1057
|
+
* handler sees a single stable value. Query/mutation handlers must be
|
|
1058
|
+
* deterministic — they may be re-run on OCC retry / subscription re-eval — so
|
|
1059
|
+
* read time through `ctx.now` instead of `Date.now()` (the latter is flagged
|
|
1060
|
+
* by the `nondeterministic_query_mutation` advisor). Actions may use `Date.now()`.
|
|
1061
|
+
*/
|
|
1062
|
+
readonly now: number;
|
|
1063
|
+
/**
|
|
956
1064
|
* Compose a read-only subquery in-process, reusing this query's read
|
|
957
1065
|
* context (same transaction, same `db`). Executes the referenced query's
|
|
958
1066
|
* handler directly — no fresh DO RPC round-trip — so it observes the exact
|
|
@@ -961,6 +1069,8 @@ interface QueryCtx {
|
|
|
961
1069
|
* Mirrors Convex's `ctx.runQuery`.
|
|
962
1070
|
*/
|
|
963
1071
|
readonly runQuery: <A extends ArgsValidator, R>(reference: RegisteredQuery<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1072
|
+
/** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
|
|
1073
|
+
readonly secrets: Secrets;
|
|
964
1074
|
readonly storage: ReadOnlyStorage;
|
|
965
1075
|
readonly vectors: VectorSearchReader;
|
|
966
1076
|
}
|
|
@@ -977,6 +1087,14 @@ interface MutationCtx {
|
|
|
977
1087
|
/** Structured, function-attributed logger; see {@link LunoraLogger}. */
|
|
978
1088
|
readonly log: LunoraLogger;
|
|
979
1089
|
/**
|
|
1090
|
+
* Wall-clock time (epoch ms) the function began, captured once so the whole
|
|
1091
|
+
* handler sees a single stable value. Mutation handlers must be deterministic
|
|
1092
|
+
* — they may be re-run on OCC retry — so read time through `ctx.now` instead
|
|
1093
|
+
* of `Date.now()` (the latter is flagged by the `nondeterministic_query_mutation`
|
|
1094
|
+
* advisor). Actions may use `Date.now()`.
|
|
1095
|
+
*/
|
|
1096
|
+
readonly now: number;
|
|
1097
|
+
/**
|
|
980
1098
|
* Compose a submutation in-process, reusing this mutation's `db` writer.
|
|
981
1099
|
* Executes the referenced mutation's handler directly — no fresh DO RPC —
|
|
982
1100
|
* so its writes apply through the same shard invocation as the enclosing
|
|
@@ -993,6 +1111,8 @@ interface MutationCtx {
|
|
|
993
1111
|
*/
|
|
994
1112
|
readonly runQuery: <A extends ArgsValidator, R>(reference: RegisteredQuery<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
995
1113
|
readonly scheduler: Scheduler;
|
|
1114
|
+
/** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
|
|
1115
|
+
readonly secrets: Secrets;
|
|
996
1116
|
readonly storage: ReadOnlyStorage;
|
|
997
1117
|
readonly vectors: VectorSearch;
|
|
998
1118
|
/** Start / resume / inspect durable workflows; see {@link Workflows}. */
|
|
@@ -1011,10 +1131,18 @@ interface ActionCtx {
|
|
|
1011
1131
|
readonly ip?: string;
|
|
1012
1132
|
/** Structured, function-attributed logger; see {@link LunoraLogger}. */
|
|
1013
1133
|
readonly log: LunoraLogger;
|
|
1134
|
+
/**
|
|
1135
|
+
* Wall-clock time (epoch ms) the action began, captured once for convenience
|
|
1136
|
+
* and parity with query/mutation `ctx.now`. Actions run exactly once, so they
|
|
1137
|
+
* may also use ambient `Date.now()` freely.
|
|
1138
|
+
*/
|
|
1139
|
+
readonly now: number;
|
|
1014
1140
|
readonly runAction: <A extends ArgsValidator, R>(reference: RegisteredAction<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1015
1141
|
readonly runMutation: <A extends ArgsValidator, R>(reference: RegisteredMutation<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1016
1142
|
readonly runQuery: <A extends ArgsValidator, R>(reference: RegisteredQuery<A, R>, args: InferArgs<A>) => Promise<R>;
|
|
1017
1143
|
readonly scheduler: Scheduler;
|
|
1144
|
+
/** Read account-level secrets from Cloudflare Secrets Store; see {@link Secrets}. */
|
|
1145
|
+
readonly secrets: Secrets;
|
|
1018
1146
|
readonly storage: Storage;
|
|
1019
1147
|
readonly vectors: VectorSearch;
|
|
1020
1148
|
/** Start / resume / inspect durable workflows; see {@link Workflows}. */
|
|
@@ -1026,4 +1154,4 @@ interface ActionCtx {
|
|
|
1026
1154
|
*/
|
|
1027
1155
|
type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
|
|
1028
1156
|
declare const anyApi: AnyApi;
|
|
1029
|
-
export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
|
|
1157
|
+
export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, type ExternalSourceDefinition, type ExternalSourceMode, type ExternalSourceRefresh, type FunctionKind, type FunctionVisibility, type GlobalBackend, type IndexDefinition, type IndexRangeBuilder, type InferArgs, type LifecycleEvent, type LifecycleEventKind, type LunoraLogger, type MutationCtx, type OnDeleteAction, type PaginationOptions, type PaginationResult, type QueryCtx, type RankIndexDefinition, type RankSortKey, type ReadOnlyStorage, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationDefinition, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type Schema, type SearchFilterBuilder, type SearchIndexDefinition, type Secrets, type SecretsStoreSecretLike, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableDefinition, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerBuilder, type TriggerCtx, type TriggerDatabase, type TriggerDefinition, type TriggerDeleteEvent, type TriggerEvent, type TriggerGroupByEntry, type TriggerGroupByOptions, type TriggerHandler, type TriggerInsertEvent, type TriggerOp, type TriggerQueryArgs, type TriggerQueryPage, type TriggerRankOptions, type TriggerRankPageOptions, type TriggerRankResult, type TriggerRow, type TriggerTiming, type TriggerUpdateEvent, type VectorEmbedder, type VectorIndexDefinition, type VectorMatch, type VectorMatches, type VectorMetric, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/server",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
4
|
"description": "Server primitives for Lunora: defineSchema, defineTable, query, mutation, and action",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backend",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"directory": "packages/server"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist",
|
|
28
|
+
"./dist",
|
|
29
29
|
"README.md",
|
|
30
30
|
"LICENSE.md",
|
|
31
31
|
"__assets__"
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
"access": "public"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@lunora/scheduler": "1.0.0-alpha.
|
|
66
|
-
"@lunora/values": "1.0.0-alpha.
|
|
65
|
+
"@lunora/scheduler": "1.0.0-alpha.4",
|
|
66
|
+
"@lunora/values": "1.0.0-alpha.3",
|
|
67
67
|
"drizzle-orm": "^0.45.2",
|
|
68
|
-
"hono": "^4.12.
|
|
68
|
+
"hono": "^4.12.27"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": "^22.15.0 || >=24.11.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|