@lunora/server 1.0.0-alpha.6 → 1.0.0-alpha.8
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 +4 -0
- package/dist/index.d.mts +163 -3
- package/dist/index.d.ts +163 -3
- package/dist/index.mjs +7 -4
- package/dist/packem_shared/{PRESENCE_DEFAULT_TTL_MS-BgBQsqQ-.mjs → PRESENCE_DEFAULT_TTL_MS-C7j9gY_d.mjs} +2 -2
- package/dist/packem_shared/buildRlsReadRegistry-CkxuS69B.mjs +107 -0
- package/dist/packem_shared/{defineAggregateIndex-C2gT1GzM.mjs → defineAggregateIndex-ZdyU78gh.mjs} +39 -0
- 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/{initLunora-CATvPsVt.mjs → initLunora-lxwHTEV3.mjs} +17 -3
- package/dist/packem_shared/policy-tag-DvpVH2tv.mjs +13 -0
- package/dist/packem_shared/{rls-Bi9HiyDC.mjs → rls-ClmjkkxZ.mjs} +3 -1
- package/dist/rls/testing.mjs +1 -1
- package/dist/types.d.mts +54 -1
- package/dist/types.d.ts +54 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -93,6 +93,10 @@ The builder chain is `<builder>.input(validators).<kind>(handler)`, plus `.use(m
|
|
|
93
93
|
|
|
94
94
|
> **Determinism:** `query` and `mutation` handlers must be deterministic — they may be re-run on OCC retry or subscription re-evaluation. Read the current time from **`ctx.now`** (epoch ms, captured once per execution — also on `ActionCtx`) instead of `Date.now()`; compute randomness and network results in an `action` (`crypto.randomUUID()`, `fetch`) and pass them into the mutation as arguments. The `nondeterministic_query_mutation` advisor flags `Date.now()`/`Math.random()`/`fetch` in query/mutation handlers.
|
|
95
95
|
|
|
96
|
+
### Local-first sync engine
|
|
97
|
+
|
|
98
|
+
`defineShape` declares a **partial replication shape** (a named table view with a server-resolved `where` predicate, AND-composed with RLS) and `defineMutator` declares a **custom mutator** (an authoritative `server` impl plus an optional optimistic `client` twin). Both are discovered by codegen and drive the [local-first sync engine](https://lunora.sh/docs/concepts/local-first) — clients subscribe to shapes over the poke diff protocol and push optimistic writes rebased over the server's authoritative result. The client-side runtime lives in [`@lunora/db`](https://www.npmjs.com/package/@lunora/db).
|
|
99
|
+
|
|
96
100
|
> This README covers the basics. For the full API, options, and guides, see the **[documentation](https://lunora.sh/docs/packages/server)**.
|
|
97
101
|
|
|
98
102
|
## Related
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Validator, Infer, v } from '@lunora/values';
|
|
1
|
+
import { Validator, Infer, ValidatorMap, InferValidatorMap, v } from '@lunora/values';
|
|
2
2
|
export { type ColumnValidator, type Id, type Infer, ValidationError, type Validator, type ValidatorKind, v } from '@lunora/values';
|
|
3
|
-
import { ArgsValidator, InferArgs, RegisteredAction, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.mjs";
|
|
3
|
+
import { ArgsValidator, InferArgs, RegisteredAction, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.mjs";
|
|
4
4
|
export { type AnyApi, type AuthState, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LunoraLogger, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, 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 VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.mjs";
|
|
5
5
|
import { Context, Hono } from 'hono';
|
|
6
6
|
import { b as Permission, R as Role, T as TypedDefinePolicyInput, a as Policy, D as DefinePolicyInput, W as WhereInput, c as RlsOptions } from "./packem_shared/types.d-DmvyEMD6.mjs";
|
|
@@ -896,6 +896,55 @@ interface RegisteredMigration extends MigrationDefinition {
|
|
|
896
896
|
/** Declare an online data migration. See the module docs for runtime semantics. */
|
|
897
897
|
declare const defineMigration: (definition: MigrationDefinition) => RegisteredMigration;
|
|
898
898
|
/**
|
|
899
|
+
* A mutator declaration. `server` is authoritative; `client` is the optimistic
|
|
900
|
+
* twin (optional — omit it to let the optimistic write fall through to the
|
|
901
|
+
* server round-trip with no local preview). Both receive the same validated
|
|
902
|
+
* `args`.
|
|
903
|
+
*/
|
|
904
|
+
interface MutatorDefinition<Args extends ValidatorMap = ValidatorMap, ServerContext = MutationCtx, ClientTx = unknown, R = unknown> {
|
|
905
|
+
/**
|
|
906
|
+
* Validator for the mutator's arguments. Validated on the DO before `server`
|
|
907
|
+
* runs and (when present) on the client before `client` runs, so both impls
|
|
908
|
+
* see the same parsed shape. Omit for a parameterless mutator.
|
|
909
|
+
*/
|
|
910
|
+
readonly args?: Args;
|
|
911
|
+
/**
|
|
912
|
+
* Optimistic client implementation. Runs in a TanStack DB transaction
|
|
913
|
+
* against the local collections; its writes are applied immediately and
|
|
914
|
+
* automatically rolled back / rebased as the authoritative result syncs
|
|
915
|
+
* back. Pure and side-effect-free beyond the local store. Omit to skip the
|
|
916
|
+
* local preview.
|
|
917
|
+
*/
|
|
918
|
+
readonly client?: (tx: ClientTx, args: InferValidatorMap<Args>) => Promise<void> | void;
|
|
919
|
+
/**
|
|
920
|
+
* Authoritative server implementation. Runs inside the shard DO with a full
|
|
921
|
+
* {@link MutationContext} (`ctx.db` writer); its writes append to `__cdc_log`
|
|
922
|
+
* and poke back to subscribers. This is the source of truth — the client
|
|
923
|
+
* impl is only a prediction of it.
|
|
924
|
+
*/
|
|
925
|
+
readonly server: (context: ServerContext, args: InferValidatorMap<Args>) => Promise<R> | R;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* A {@link MutatorDefinition} plus the codegen discovery marker and a
|
|
929
|
+
* dispatch-shaped `handler` (validates `args`, then runs `server`) so the DO
|
|
930
|
+
* invokes a mutator exactly like a registered procedure.
|
|
931
|
+
*/
|
|
932
|
+
interface RegisteredMutator<Args extends ValidatorMap = ValidatorMap, ServerContext = MutationCtx, ClientTx = unknown, R = unknown> extends MutatorDefinition<Args, ServerContext, ClientTx, R> {
|
|
933
|
+
readonly __lunoraMutator: true;
|
|
934
|
+
/** Validate `rawArgs`, then run the authoritative `server` impl. Used by the DO push path. */
|
|
935
|
+
readonly handler: (context: ServerContext, rawArgs: Record<string, unknown>) => Promise<R>;
|
|
936
|
+
/**
|
|
937
|
+
* Marks the dispatch kind so codegen can register the mutator in the same
|
|
938
|
+
* `LUNORA_FUNCTIONS` table queries/mutations use — the DO's `handleRpc`
|
|
939
|
+
* reads `kind === "mutation"` to wrap the authoritative `server` impl in the
|
|
940
|
+
* shard's BEGIN/COMMIT span (all-or-nothing writes), exactly like an
|
|
941
|
+
* ordinary `mutation`.
|
|
942
|
+
*/
|
|
943
|
+
readonly kind: "mutation";
|
|
944
|
+
}
|
|
945
|
+
/** Declare a custom mutator. See the module docs for runtime semantics. */
|
|
946
|
+
declare const defineMutator: <Args extends ValidatorMap = ValidatorMap, ServerContext = MutationCtx, ClientTx = unknown, R = unknown>(definition: MutatorDefinition<Args, ServerContext, ClientTx, R>) => RegisteredMutator<Args, ServerContext, ClientTx, R>;
|
|
947
|
+
/**
|
|
899
948
|
* The prefixed tables a single plugin `P` contributes, or an empty map when it
|
|
900
949
|
* ships no schema extension. Mirrors {@link PrefixedTables} at the plugin level
|
|
901
950
|
* so {@link InstalledTables} can fold a tuple of plugins.
|
|
@@ -1222,6 +1271,19 @@ interface TableBuilder<Shape extends Record<string, Validator> = Record<string,
|
|
|
1222
1271
|
softDelete: (options?: {
|
|
1223
1272
|
field?: string;
|
|
1224
1273
|
}) => TableBuilder<Shape>;
|
|
1274
|
+
/**
|
|
1275
|
+
* Materialize this table from an external Postgres/MySQL behind Cloudflare
|
|
1276
|
+
* Hyperdrive (plan 077). A system-driven poll loop reads the tenant slice
|
|
1277
|
+
* (`query`, with params bound from `tenantBy`) and lands it in the DO's SQLite,
|
|
1278
|
+
* after which `defineShape` carries it to clients unchanged. Implies
|
|
1279
|
+
* `.externallyManaged()` (rows come from the ingest loop, not user mutations).
|
|
1280
|
+
*
|
|
1281
|
+
* Orthogonal to `.shardBy()` — combine them for per-tenant DOs. **Under
|
|
1282
|
+
* `.shardBy()` `tenantBy` is mandatory** (the tenant-isolation boundary); the
|
|
1283
|
+
* `external_source_unscoped` advisor lint fails the build when it is absent, and
|
|
1284
|
+
* `external_source_on_global` rejects combining `.source()` with `.global()`.
|
|
1285
|
+
*/
|
|
1286
|
+
source: (definition: ExternalSourceDefinition) => TableBuilder<Shape>;
|
|
1225
1287
|
/** Declare named lifecycle triggers fired inline within the write path. */
|
|
1226
1288
|
triggers: (build: (t: TriggerBuilder<Shape>) => Record<string, TriggerDefinition>) => TableBuilder<Shape>;
|
|
1227
1289
|
/** Declare a vector index over a single text field on this table. */
|
|
@@ -1735,6 +1797,104 @@ interface RlsContextIn {
|
|
|
1735
1797
|
}
|
|
1736
1798
|
declare const rls: <Context extends RlsContextIn = RlsContextIn>(policies: ReadonlyArray<Policy<Context>>, options?: RlsOptions) => Middleware<Context, Context>;
|
|
1737
1799
|
/**
|
|
1800
|
+
* One `rls()` tag's read policies for a table, paired with the role→permission
|
|
1801
|
+
* grants of that SAME middleware. Keeping the role map per-group is what lets a
|
|
1802
|
+
* policy's `auth.can(...)` resolve against its own middleware's roles — never a
|
|
1803
|
+
* permission registered on a different `rls()` step.
|
|
1804
|
+
*/
|
|
1805
|
+
interface ScopedReadPolicies {
|
|
1806
|
+
readonly policies: ReadonlyArray<Policy>;
|
|
1807
|
+
readonly rolePermissions: ReadonlyMap<string, ReadonlySet<string>>;
|
|
1808
|
+
}
|
|
1809
|
+
/** Table-indexed read-policy groups, each scoped to the roles of the rls() middleware that declared it. */
|
|
1810
|
+
interface RlsReadRegistry {
|
|
1811
|
+
readonly byTable: ReadonlyMap<string, ReadonlyArray<ScopedReadPolicies>>;
|
|
1812
|
+
}
|
|
1813
|
+
/** The trusted, server-resolved facts a shape's RLS evaluation runs under. */
|
|
1814
|
+
interface ShapeReadWhereRequest {
|
|
1815
|
+
/** The shape ctx (the procedure context a policy `when` reads as `ctx`). */
|
|
1816
|
+
readonly ctx: unknown;
|
|
1817
|
+
/** Resolved identity claims (the socket's verified identity), or `null` when anonymous. */
|
|
1818
|
+
readonly identity: Record<string, unknown> | null;
|
|
1819
|
+
/** `true` when the schema is `.rls("required")` — gates the fail-closed branch. */
|
|
1820
|
+
readonly rlsRequired: boolean;
|
|
1821
|
+
/** Role labels the request carries (drives `auth.can(...)`). */
|
|
1822
|
+
readonly roles: ReadonlyArray<string>;
|
|
1823
|
+
/** The shape's own predicate (`where(ctx, args)`). */
|
|
1824
|
+
readonly shapeWhere: WhereInput;
|
|
1825
|
+
/** Logical table the shape replicates. */
|
|
1826
|
+
readonly table: string;
|
|
1827
|
+
/** `true` when the table is `.public()` (exempt from `.rls("required")` denial). */
|
|
1828
|
+
readonly tablePublic: boolean;
|
|
1829
|
+
/** Verified user id, or `null` when anonymous. */
|
|
1830
|
+
readonly userId: null | string;
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1833
|
+
* Build the read-policy registry from the registered functions (pass
|
|
1834
|
+
* `Object.values(LUNORA_FUNCTIONS)`). Only `on: "read"` policies are collected,
|
|
1835
|
+
* grouped per `rls()` middleware so each group keeps its own role→permission map
|
|
1836
|
+
* (a `(table, when)` pair is de-duplicated within a tag). A tag reused across
|
|
1837
|
+
* several procedures (a shared `const guard = rls(...)`) is folded once. This
|
|
1838
|
+
* mirrors the request-time `rls()` path exactly: a policy's `auth.can(...)`
|
|
1839
|
+
* resolves against the roles of the middleware that declared it, never a union.
|
|
1840
|
+
*/
|
|
1841
|
+
declare const buildRlsReadRegistry: (functions: Iterable<unknown>) => RlsReadRegistry;
|
|
1842
|
+
/**
|
|
1843
|
+
* Compute the effective `where` a shape replicates: the table's RLS read
|
|
1844
|
+
* base-where AND the shape's own predicate. Returns the shape predicate
|
|
1845
|
+
* unchanged for a table with no read policy (a `.public()` or non-RLS table),
|
|
1846
|
+
* and the FALSE sentinel (replicate nothing) when a `.rls("required")` schema
|
|
1847
|
+
* exposes a protected, policy-less table.
|
|
1848
|
+
*/
|
|
1849
|
+
declare const composeShapeReadWhere: (registry: RlsReadRegistry, request: ShapeReadWhereRequest) => WhereInput;
|
|
1850
|
+
/**
|
|
1851
|
+
* A shape declaration. `where` receives the trusted procedure context and the
|
|
1852
|
+
* validated client args and returns the same {@link WhereInput} shape the RLS
|
|
1853
|
+
* DSL uses, so the DO can AND-merge it with the table's read base-where via the
|
|
1854
|
+
* existing where-compiler (zero second predicate implementation).
|
|
1855
|
+
*/
|
|
1856
|
+
interface ShapeDefinition<Args extends ValidatorMap = ValidatorMap, Context = QueryCtx> {
|
|
1857
|
+
/**
|
|
1858
|
+
* Validator for the client-supplied shape parameters. Validated on the DO
|
|
1859
|
+
* before `where` runs, so a malformed `args` envelope is rejected at the
|
|
1860
|
+
* subscription boundary rather than silently widening the partition. Omit
|
|
1861
|
+
* for a parameterless shape.
|
|
1862
|
+
*/
|
|
1863
|
+
readonly args?: Args;
|
|
1864
|
+
/**
|
|
1865
|
+
* Project the replicated rows to these columns (the system columns `_id` and
|
|
1866
|
+
* `_creationTime` are always included). Omit to replicate every column. An
|
|
1867
|
+
* empty array is rejected — it would replicate no data, which is never the
|
|
1868
|
+
* intent.
|
|
1869
|
+
*/
|
|
1870
|
+
readonly columns?: ReadonlyArray<string>;
|
|
1871
|
+
/** Logical table this shape replicates a partition of. */
|
|
1872
|
+
readonly table: string;
|
|
1873
|
+
/**
|
|
1874
|
+
* Predicate selecting the rows this shape replicates. AND-composed with the
|
|
1875
|
+
* table's RLS read base-where on the DO. Runs server-side with a trusted
|
|
1876
|
+
* `ctx` (identity/auth the client can't forge) and the validated client
|
|
1877
|
+
* `args`; returns a {@link WhereInput} using the same operator set as the
|
|
1878
|
+
* SQL compiler (`eq`/`in`/`lt`/… + `AND`/`OR`/`NOT`).
|
|
1879
|
+
*/
|
|
1880
|
+
readonly where: (context: Context, args: InferValidatorMap<Args>) => WhereInput;
|
|
1881
|
+
}
|
|
1882
|
+
/** A {@link ShapeDefinition} plus the codegen discovery marker and a dispatch-shaped `compileWhere`. */
|
|
1883
|
+
interface RegisteredShape<Args extends ValidatorMap = ValidatorMap, Context = QueryCtx> extends ShapeDefinition<Args, Context> {
|
|
1884
|
+
readonly __lunoraShape: true;
|
|
1885
|
+
/**
|
|
1886
|
+
* Validate `rawArgs`, then evaluate `where` under the trusted `ctx` and
|
|
1887
|
+
* return its {@link WhereInput}. Used by the generated DO's `resolveShape`
|
|
1888
|
+
* override: `ctx` is erased to `unknown` at this dispatch boundary (the DO
|
|
1889
|
+
* builds it from the socket's verified identity and hands it back as the
|
|
1890
|
+
* concrete {@link QueryContext} the predicate expects), exactly like
|
|
1891
|
+
* `RegisteredLunoraFunction.handler` erases its context.
|
|
1892
|
+
*/
|
|
1893
|
+
readonly compileWhere: (context: unknown, rawArgs: Record<string, unknown>) => WhereInput;
|
|
1894
|
+
}
|
|
1895
|
+
/** Declare a replication shape. See the module docs for runtime semantics. */
|
|
1896
|
+
declare const defineShape: <Args extends ValidatorMap = ValidatorMap, Context = QueryCtx>(definition: ShapeDefinition<Args, Context>) => RegisteredShape<Args, Context>;
|
|
1897
|
+
/**
|
|
1738
1898
|
* Operations a storage rule can gate. `read` covers `download` / `getMetadata`
|
|
1739
1899
|
* / `getSignedUrl` / `getUrl`; `write` covers `store` / `generateUploadUrl`;
|
|
1740
1900
|
* `delete` is `delete`; `list` is a prefix listing (governed via the file
|
|
@@ -1817,4 +1977,4 @@ interface StorageContextIn {
|
|
|
1817
1977
|
}
|
|
1818
1978
|
declare const storageRules: <Context extends StorageContextIn = StorageContextIn>(rules: ReadonlyArray<StorageRule<Context>>, options?: StorageRulesOptions) => Middleware<Context, Context>;
|
|
1819
1979
|
declare const VERSION = "0.0.0";
|
|
1820
|
-
export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExtendableSchema, type FacadeEntry, type FacadeWriterLike, type FunctionKind, type HttpActionCtx, type HttpActionHandler, type HttpMethod, type HttpRoute, type HttpRouteBuilder, type HttpRouteFactory, type HttpRouteHandlerOptions, type HttpStreamHandlerOptions, type InferArgs, type InferEnv, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, type LunoraErrorCode, type LunoraHttpApp, type LunoraHttpEnv, type LunoraRouteHandler, type ManyRelation, type MaskColumns, type MaskContext, type MaskFn, type MaskOptions, type MaskPolicies, type MaskStrategy, type Middleware, type MiddlewareNext, type MigrationDefinition, type MigrationDocument, type MigrationTransform, type MutationBuilder, type MutationCtx, type OnDeleteAction, type OneRelation, type OrmLike, DEFAULT_TTL_MS as PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, type Permission, type Plugin, type Policy, type PrefixedTables, type PresenceComponent, type PresenceFunctions, type PresenceMember, type ProtectPublicOptions, type QueryBuilder, type QueryCtx, type RankIndexDefinition, type RankIndexOptions, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMigration, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationBuilder, type RelationDefinition, type RlsOptions, type Role, type Schema, type SchemaExtension, type StorageOperation, type StorageRule, type StorageRuleContext, type StorageRuleDecision, type StorageRulesOptions, type TableBuilder, type TableDefinition, type TerminalKind, type TriggerBuilder, type TriggerDefinition, type TypedDefinePolicyInput, VERSION, type VectorEmbedder, type VectorIndexDefinition, type VectorIndexOptions, type VectorMetric, type VectorizeOptions, type WhereInput, asBucketStorage, bindOrm, bindTableFacade, composePluginMiddleware, createPolicyDsl, createSecrets, defineAggregateIndex, defineComponent, defineEnv, defineMigration, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, httpAction, httpRoute, httpRouter, initLunora, installPlugins, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules };
|
|
1980
|
+
export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExtendableSchema, type FacadeEntry, type FacadeWriterLike, type FunctionKind, type HttpActionCtx, type HttpActionHandler, type HttpMethod, type HttpRoute, type HttpRouteBuilder, type HttpRouteFactory, type HttpRouteHandlerOptions, type HttpStreamHandlerOptions, type InferArgs, type InferEnv, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, type LunoraErrorCode, type LunoraHttpApp, type LunoraHttpEnv, type LunoraRouteHandler, type ManyRelation, type MaskColumns, type MaskContext, type MaskFn, type MaskOptions, type MaskPolicies, type MaskStrategy, type Middleware, type MiddlewareNext, type MigrationDefinition, type MigrationDocument, type MigrationTransform, type MutationBuilder, type MutationCtx, type MutatorDefinition, type OnDeleteAction, type OneRelation, type OrmLike, DEFAULT_TTL_MS as PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, type Permission, type Plugin, type Policy, type PrefixedTables, type PresenceComponent, type PresenceFunctions, type PresenceMember, type ProtectPublicOptions, type QueryBuilder, type QueryCtx, type RankIndexDefinition, type RankIndexOptions, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMigration, type RegisteredMutation, type RegisteredMutator, type RegisteredQuery, type RegisteredShape, type RegisteredStream, type RelationBuilder, type RelationDefinition, type RlsOptions, type RlsReadRegistry, type Role, type Schema, type SchemaExtension, type ShapeDefinition, type ShapeReadWhereRequest, type StorageOperation, type StorageRule, type StorageRuleContext, type StorageRuleDecision, type StorageRulesOptions, type TableBuilder, type TableDefinition, type TerminalKind, type TriggerBuilder, type TriggerDefinition, type TypedDefinePolicyInput, VERSION, type VectorEmbedder, type VectorIndexDefinition, type VectorIndexOptions, type VectorMetric, type VectorizeOptions, type WhereInput, asBucketStorage, bindOrm, bindTableFacade, buildRlsReadRegistry, composePluginMiddleware, composeShapeReadWhere, createPolicyDsl, createSecrets, defineAggregateIndex, defineComponent, defineEnv, defineMigration, defineMutator, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineShape, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, httpAction, httpRoute, httpRouter, initLunora, installPlugins, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Validator, Infer, v } from '@lunora/values';
|
|
1
|
+
import { Validator, Infer, ValidatorMap, InferValidatorMap, v } from '@lunora/values';
|
|
2
2
|
export { type ColumnValidator, type Id, type Infer, ValidationError, type Validator, type ValidatorKind, v } from '@lunora/values';
|
|
3
|
-
import { ArgsValidator, InferArgs, RegisteredAction, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.js";
|
|
3
|
+
import { ArgsValidator, InferArgs, RegisteredAction, ActionCtx, MutationCtx, RegisteredMutation, QueryCtx, RegisteredQuery, RegisteredStream, FunctionKind, Secrets, LifecycleEvent, RegisteredLifecycleHook, TableDefinition, RegisteredFunction, VectorIndexDefinition, Schema, AggregateOp, DurableObjectJurisdiction, RelationDefinition, GlobalBackend, OnDeleteAction, ExternalSourceDefinition, TriggerBuilder, TriggerDefinition, VectorEmbedder, VectorMetric, AggregateIndexDefinition, RankIndexDefinition } from "./types.js";
|
|
4
4
|
export { type AnyApi, type AuthState, type DatabaseReader, type DatabaseWriter, type FunctionVisibility, type IndexDefinition, type IndexRangeBuilder, type LifecycleEventKind, type LunoraLogger, type PaginationOptions, type PaginationResult, type RankSortKey, type ReadOnlyStorage, type ScheduledFunctionDoc, type ScheduledJob, type Scheduler, type SearchFilterBuilder, type SearchIndexDefinition, type ShardMode, type Storage, type StorageMetadata, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemTableName, type TableReader, type TableVectorIndex, type TriggerAggregateOptions, type TriggerCtx, type TriggerDatabase, 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 VectorMatch, type VectorMatches, type VectorQueryInput, type VectorRecord, type VectorSearch, type VectorSearchReader, type VectorUpsertInput, type WorkflowCreateOptions, type WorkflowHandle, type WorkflowInstance, type WorkflowInstanceStatus, type WorkflowStatusResult, type Workflows, anyApi } from "./types.js";
|
|
5
5
|
import { Context, Hono } from 'hono';
|
|
6
6
|
import { b as Permission, R as Role, T as TypedDefinePolicyInput, a as Policy, D as DefinePolicyInput, W as WhereInput, c as RlsOptions } from "./packem_shared/types.d-BDY0FYHK.js";
|
|
@@ -896,6 +896,55 @@ interface RegisteredMigration extends MigrationDefinition {
|
|
|
896
896
|
/** Declare an online data migration. See the module docs for runtime semantics. */
|
|
897
897
|
declare const defineMigration: (definition: MigrationDefinition) => RegisteredMigration;
|
|
898
898
|
/**
|
|
899
|
+
* A mutator declaration. `server` is authoritative; `client` is the optimistic
|
|
900
|
+
* twin (optional — omit it to let the optimistic write fall through to the
|
|
901
|
+
* server round-trip with no local preview). Both receive the same validated
|
|
902
|
+
* `args`.
|
|
903
|
+
*/
|
|
904
|
+
interface MutatorDefinition<Args extends ValidatorMap = ValidatorMap, ServerContext = MutationCtx, ClientTx = unknown, R = unknown> {
|
|
905
|
+
/**
|
|
906
|
+
* Validator for the mutator's arguments. Validated on the DO before `server`
|
|
907
|
+
* runs and (when present) on the client before `client` runs, so both impls
|
|
908
|
+
* see the same parsed shape. Omit for a parameterless mutator.
|
|
909
|
+
*/
|
|
910
|
+
readonly args?: Args;
|
|
911
|
+
/**
|
|
912
|
+
* Optimistic client implementation. Runs in a TanStack DB transaction
|
|
913
|
+
* against the local collections; its writes are applied immediately and
|
|
914
|
+
* automatically rolled back / rebased as the authoritative result syncs
|
|
915
|
+
* back. Pure and side-effect-free beyond the local store. Omit to skip the
|
|
916
|
+
* local preview.
|
|
917
|
+
*/
|
|
918
|
+
readonly client?: (tx: ClientTx, args: InferValidatorMap<Args>) => Promise<void> | void;
|
|
919
|
+
/**
|
|
920
|
+
* Authoritative server implementation. Runs inside the shard DO with a full
|
|
921
|
+
* {@link MutationContext} (`ctx.db` writer); its writes append to `__cdc_log`
|
|
922
|
+
* and poke back to subscribers. This is the source of truth — the client
|
|
923
|
+
* impl is only a prediction of it.
|
|
924
|
+
*/
|
|
925
|
+
readonly server: (context: ServerContext, args: InferValidatorMap<Args>) => Promise<R> | R;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* A {@link MutatorDefinition} plus the codegen discovery marker and a
|
|
929
|
+
* dispatch-shaped `handler` (validates `args`, then runs `server`) so the DO
|
|
930
|
+
* invokes a mutator exactly like a registered procedure.
|
|
931
|
+
*/
|
|
932
|
+
interface RegisteredMutator<Args extends ValidatorMap = ValidatorMap, ServerContext = MutationCtx, ClientTx = unknown, R = unknown> extends MutatorDefinition<Args, ServerContext, ClientTx, R> {
|
|
933
|
+
readonly __lunoraMutator: true;
|
|
934
|
+
/** Validate `rawArgs`, then run the authoritative `server` impl. Used by the DO push path. */
|
|
935
|
+
readonly handler: (context: ServerContext, rawArgs: Record<string, unknown>) => Promise<R>;
|
|
936
|
+
/**
|
|
937
|
+
* Marks the dispatch kind so codegen can register the mutator in the same
|
|
938
|
+
* `LUNORA_FUNCTIONS` table queries/mutations use — the DO's `handleRpc`
|
|
939
|
+
* reads `kind === "mutation"` to wrap the authoritative `server` impl in the
|
|
940
|
+
* shard's BEGIN/COMMIT span (all-or-nothing writes), exactly like an
|
|
941
|
+
* ordinary `mutation`.
|
|
942
|
+
*/
|
|
943
|
+
readonly kind: "mutation";
|
|
944
|
+
}
|
|
945
|
+
/** Declare a custom mutator. See the module docs for runtime semantics. */
|
|
946
|
+
declare const defineMutator: <Args extends ValidatorMap = ValidatorMap, ServerContext = MutationCtx, ClientTx = unknown, R = unknown>(definition: MutatorDefinition<Args, ServerContext, ClientTx, R>) => RegisteredMutator<Args, ServerContext, ClientTx, R>;
|
|
947
|
+
/**
|
|
899
948
|
* The prefixed tables a single plugin `P` contributes, or an empty map when it
|
|
900
949
|
* ships no schema extension. Mirrors {@link PrefixedTables} at the plugin level
|
|
901
950
|
* so {@link InstalledTables} can fold a tuple of plugins.
|
|
@@ -1222,6 +1271,19 @@ interface TableBuilder<Shape extends Record<string, Validator> = Record<string,
|
|
|
1222
1271
|
softDelete: (options?: {
|
|
1223
1272
|
field?: string;
|
|
1224
1273
|
}) => TableBuilder<Shape>;
|
|
1274
|
+
/**
|
|
1275
|
+
* Materialize this table from an external Postgres/MySQL behind Cloudflare
|
|
1276
|
+
* Hyperdrive (plan 077). A system-driven poll loop reads the tenant slice
|
|
1277
|
+
* (`query`, with params bound from `tenantBy`) and lands it in the DO's SQLite,
|
|
1278
|
+
* after which `defineShape` carries it to clients unchanged. Implies
|
|
1279
|
+
* `.externallyManaged()` (rows come from the ingest loop, not user mutations).
|
|
1280
|
+
*
|
|
1281
|
+
* Orthogonal to `.shardBy()` — combine them for per-tenant DOs. **Under
|
|
1282
|
+
* `.shardBy()` `tenantBy` is mandatory** (the tenant-isolation boundary); the
|
|
1283
|
+
* `external_source_unscoped` advisor lint fails the build when it is absent, and
|
|
1284
|
+
* `external_source_on_global` rejects combining `.source()` with `.global()`.
|
|
1285
|
+
*/
|
|
1286
|
+
source: (definition: ExternalSourceDefinition) => TableBuilder<Shape>;
|
|
1225
1287
|
/** Declare named lifecycle triggers fired inline within the write path. */
|
|
1226
1288
|
triggers: (build: (t: TriggerBuilder<Shape>) => Record<string, TriggerDefinition>) => TableBuilder<Shape>;
|
|
1227
1289
|
/** Declare a vector index over a single text field on this table. */
|
|
@@ -1735,6 +1797,104 @@ interface RlsContextIn {
|
|
|
1735
1797
|
}
|
|
1736
1798
|
declare const rls: <Context extends RlsContextIn = RlsContextIn>(policies: ReadonlyArray<Policy<Context>>, options?: RlsOptions) => Middleware<Context, Context>;
|
|
1737
1799
|
/**
|
|
1800
|
+
* One `rls()` tag's read policies for a table, paired with the role→permission
|
|
1801
|
+
* grants of that SAME middleware. Keeping the role map per-group is what lets a
|
|
1802
|
+
* policy's `auth.can(...)` resolve against its own middleware's roles — never a
|
|
1803
|
+
* permission registered on a different `rls()` step.
|
|
1804
|
+
*/
|
|
1805
|
+
interface ScopedReadPolicies {
|
|
1806
|
+
readonly policies: ReadonlyArray<Policy>;
|
|
1807
|
+
readonly rolePermissions: ReadonlyMap<string, ReadonlySet<string>>;
|
|
1808
|
+
}
|
|
1809
|
+
/** Table-indexed read-policy groups, each scoped to the roles of the rls() middleware that declared it. */
|
|
1810
|
+
interface RlsReadRegistry {
|
|
1811
|
+
readonly byTable: ReadonlyMap<string, ReadonlyArray<ScopedReadPolicies>>;
|
|
1812
|
+
}
|
|
1813
|
+
/** The trusted, server-resolved facts a shape's RLS evaluation runs under. */
|
|
1814
|
+
interface ShapeReadWhereRequest {
|
|
1815
|
+
/** The shape ctx (the procedure context a policy `when` reads as `ctx`). */
|
|
1816
|
+
readonly ctx: unknown;
|
|
1817
|
+
/** Resolved identity claims (the socket's verified identity), or `null` when anonymous. */
|
|
1818
|
+
readonly identity: Record<string, unknown> | null;
|
|
1819
|
+
/** `true` when the schema is `.rls("required")` — gates the fail-closed branch. */
|
|
1820
|
+
readonly rlsRequired: boolean;
|
|
1821
|
+
/** Role labels the request carries (drives `auth.can(...)`). */
|
|
1822
|
+
readonly roles: ReadonlyArray<string>;
|
|
1823
|
+
/** The shape's own predicate (`where(ctx, args)`). */
|
|
1824
|
+
readonly shapeWhere: WhereInput;
|
|
1825
|
+
/** Logical table the shape replicates. */
|
|
1826
|
+
readonly table: string;
|
|
1827
|
+
/** `true` when the table is `.public()` (exempt from `.rls("required")` denial). */
|
|
1828
|
+
readonly tablePublic: boolean;
|
|
1829
|
+
/** Verified user id, or `null` when anonymous. */
|
|
1830
|
+
readonly userId: null | string;
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1833
|
+
* Build the read-policy registry from the registered functions (pass
|
|
1834
|
+
* `Object.values(LUNORA_FUNCTIONS)`). Only `on: "read"` policies are collected,
|
|
1835
|
+
* grouped per `rls()` middleware so each group keeps its own role→permission map
|
|
1836
|
+
* (a `(table, when)` pair is de-duplicated within a tag). A tag reused across
|
|
1837
|
+
* several procedures (a shared `const guard = rls(...)`) is folded once. This
|
|
1838
|
+
* mirrors the request-time `rls()` path exactly: a policy's `auth.can(...)`
|
|
1839
|
+
* resolves against the roles of the middleware that declared it, never a union.
|
|
1840
|
+
*/
|
|
1841
|
+
declare const buildRlsReadRegistry: (functions: Iterable<unknown>) => RlsReadRegistry;
|
|
1842
|
+
/**
|
|
1843
|
+
* Compute the effective `where` a shape replicates: the table's RLS read
|
|
1844
|
+
* base-where AND the shape's own predicate. Returns the shape predicate
|
|
1845
|
+
* unchanged for a table with no read policy (a `.public()` or non-RLS table),
|
|
1846
|
+
* and the FALSE sentinel (replicate nothing) when a `.rls("required")` schema
|
|
1847
|
+
* exposes a protected, policy-less table.
|
|
1848
|
+
*/
|
|
1849
|
+
declare const composeShapeReadWhere: (registry: RlsReadRegistry, request: ShapeReadWhereRequest) => WhereInput;
|
|
1850
|
+
/**
|
|
1851
|
+
* A shape declaration. `where` receives the trusted procedure context and the
|
|
1852
|
+
* validated client args and returns the same {@link WhereInput} shape the RLS
|
|
1853
|
+
* DSL uses, so the DO can AND-merge it with the table's read base-where via the
|
|
1854
|
+
* existing where-compiler (zero second predicate implementation).
|
|
1855
|
+
*/
|
|
1856
|
+
interface ShapeDefinition<Args extends ValidatorMap = ValidatorMap, Context = QueryCtx> {
|
|
1857
|
+
/**
|
|
1858
|
+
* Validator for the client-supplied shape parameters. Validated on the DO
|
|
1859
|
+
* before `where` runs, so a malformed `args` envelope is rejected at the
|
|
1860
|
+
* subscription boundary rather than silently widening the partition. Omit
|
|
1861
|
+
* for a parameterless shape.
|
|
1862
|
+
*/
|
|
1863
|
+
readonly args?: Args;
|
|
1864
|
+
/**
|
|
1865
|
+
* Project the replicated rows to these columns (the system columns `_id` and
|
|
1866
|
+
* `_creationTime` are always included). Omit to replicate every column. An
|
|
1867
|
+
* empty array is rejected — it would replicate no data, which is never the
|
|
1868
|
+
* intent.
|
|
1869
|
+
*/
|
|
1870
|
+
readonly columns?: ReadonlyArray<string>;
|
|
1871
|
+
/** Logical table this shape replicates a partition of. */
|
|
1872
|
+
readonly table: string;
|
|
1873
|
+
/**
|
|
1874
|
+
* Predicate selecting the rows this shape replicates. AND-composed with the
|
|
1875
|
+
* table's RLS read base-where on the DO. Runs server-side with a trusted
|
|
1876
|
+
* `ctx` (identity/auth the client can't forge) and the validated client
|
|
1877
|
+
* `args`; returns a {@link WhereInput} using the same operator set as the
|
|
1878
|
+
* SQL compiler (`eq`/`in`/`lt`/… + `AND`/`OR`/`NOT`).
|
|
1879
|
+
*/
|
|
1880
|
+
readonly where: (context: Context, args: InferValidatorMap<Args>) => WhereInput;
|
|
1881
|
+
}
|
|
1882
|
+
/** A {@link ShapeDefinition} plus the codegen discovery marker and a dispatch-shaped `compileWhere`. */
|
|
1883
|
+
interface RegisteredShape<Args extends ValidatorMap = ValidatorMap, Context = QueryCtx> extends ShapeDefinition<Args, Context> {
|
|
1884
|
+
readonly __lunoraShape: true;
|
|
1885
|
+
/**
|
|
1886
|
+
* Validate `rawArgs`, then evaluate `where` under the trusted `ctx` and
|
|
1887
|
+
* return its {@link WhereInput}. Used by the generated DO's `resolveShape`
|
|
1888
|
+
* override: `ctx` is erased to `unknown` at this dispatch boundary (the DO
|
|
1889
|
+
* builds it from the socket's verified identity and hands it back as the
|
|
1890
|
+
* concrete {@link QueryContext} the predicate expects), exactly like
|
|
1891
|
+
* `RegisteredLunoraFunction.handler` erases its context.
|
|
1892
|
+
*/
|
|
1893
|
+
readonly compileWhere: (context: unknown, rawArgs: Record<string, unknown>) => WhereInput;
|
|
1894
|
+
}
|
|
1895
|
+
/** Declare a replication shape. See the module docs for runtime semantics. */
|
|
1896
|
+
declare const defineShape: <Args extends ValidatorMap = ValidatorMap, Context = QueryCtx>(definition: ShapeDefinition<Args, Context>) => RegisteredShape<Args, Context>;
|
|
1897
|
+
/**
|
|
1738
1898
|
* Operations a storage rule can gate. `read` covers `download` / `getMetadata`
|
|
1739
1899
|
* / `getSignedUrl` / `getUrl`; `write` covers `store` / `generateUploadUrl`;
|
|
1740
1900
|
* `delete` is `delete`; `list` is a prefix listing (governed via the file
|
|
@@ -1817,4 +1977,4 @@ interface StorageContextIn {
|
|
|
1817
1977
|
}
|
|
1818
1978
|
declare const storageRules: <Context extends StorageContextIn = StorageContextIn>(rules: ReadonlyArray<StorageRule<Context>>, options?: StorageRulesOptions) => Middleware<Context, Context>;
|
|
1819
1979
|
declare const VERSION = "0.0.0";
|
|
1820
|
-
export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExtendableSchema, type FacadeEntry, type FacadeWriterLike, type FunctionKind, type HttpActionCtx, type HttpActionHandler, type HttpMethod, type HttpRoute, type HttpRouteBuilder, type HttpRouteFactory, type HttpRouteHandlerOptions, type HttpStreamHandlerOptions, type InferArgs, type InferEnv, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, type LunoraErrorCode, type LunoraHttpApp, type LunoraHttpEnv, type LunoraRouteHandler, type ManyRelation, type MaskColumns, type MaskContext, type MaskFn, type MaskOptions, type MaskPolicies, type MaskStrategy, type Middleware, type MiddlewareNext, type MigrationDefinition, type MigrationDocument, type MigrationTransform, type MutationBuilder, type MutationCtx, type OnDeleteAction, type OneRelation, type OrmLike, DEFAULT_TTL_MS as PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, type Permission, type Plugin, type Policy, type PrefixedTables, type PresenceComponent, type PresenceFunctions, type PresenceMember, type ProtectPublicOptions, type QueryBuilder, type QueryCtx, type RankIndexDefinition, type RankIndexOptions, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMigration, type RegisteredMutation, type RegisteredQuery, type RegisteredStream, type RelationBuilder, type RelationDefinition, type RlsOptions, type Role, type Schema, type SchemaExtension, type StorageOperation, type StorageRule, type StorageRuleContext, type StorageRuleDecision, type StorageRulesOptions, type TableBuilder, type TableDefinition, type TerminalKind, type TriggerBuilder, type TriggerDefinition, type TypedDefinePolicyInput, VERSION, type VectorEmbedder, type VectorIndexDefinition, type VectorIndexOptions, type VectorMetric, type VectorizeOptions, type WhereInput, asBucketStorage, bindOrm, bindTableFacade, composePluginMiddleware, createPolicyDsl, createSecrets, defineAggregateIndex, defineComponent, defineEnv, defineMigration, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, httpAction, httpRoute, httpRouter, initLunora, installPlugins, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules };
|
|
1980
|
+
export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExtendableSchema, type FacadeEntry, type FacadeWriterLike, type FunctionKind, type HttpActionCtx, type HttpActionHandler, type HttpMethod, type HttpRoute, type HttpRouteBuilder, type HttpRouteFactory, type HttpRouteHandlerOptions, type HttpStreamHandlerOptions, type InferArgs, type InferEnv, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, type LunoraErrorCode, type LunoraHttpApp, type LunoraHttpEnv, type LunoraRouteHandler, type ManyRelation, type MaskColumns, type MaskContext, type MaskFn, type MaskOptions, type MaskPolicies, type MaskStrategy, type Middleware, type MiddlewareNext, type MigrationDefinition, type MigrationDocument, type MigrationTransform, type MutationBuilder, type MutationCtx, type MutatorDefinition, type OnDeleteAction, type OneRelation, type OrmLike, DEFAULT_TTL_MS as PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, type Permission, type Plugin, type Policy, type PrefixedTables, type PresenceComponent, type PresenceFunctions, type PresenceMember, type ProtectPublicOptions, type QueryBuilder, type QueryCtx, type RankIndexDefinition, type RankIndexOptions, type RegisteredAction, type RegisteredFunction, type RegisteredLifecycleHook, type RegisteredMigration, type RegisteredMutation, type RegisteredMutator, type RegisteredQuery, type RegisteredShape, type RegisteredStream, type RelationBuilder, type RelationDefinition, type RlsOptions, type RlsReadRegistry, type Role, type Schema, type SchemaExtension, type ShapeDefinition, type ShapeReadWhereRequest, type StorageOperation, type StorageRule, type StorageRuleContext, type StorageRuleDecision, type StorageRulesOptions, type TableBuilder, type TableDefinition, type TerminalKind, type TriggerBuilder, type TriggerDefinition, type TypedDefinePolicyInput, VERSION, type VectorEmbedder, type VectorIndexDefinition, type VectorIndexOptions, type VectorMetric, type VectorizeOptions, type WhereInput, asBucketStorage, bindOrm, bindTableFacade, buildRlsReadRegistry, composePluginMiddleware, composeShapeReadWhere, createPolicyDsl, createSecrets, defineAggregateIndex, defineComponent, defineEnv, defineMigration, defineMutator, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineShape, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, httpAction, httpRoute, httpRouter, initLunora, installPlugins, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as asBucketStorage } from './packem_shared/asBucketStorage-Cnxd9y2q.mjs';
|
|
2
|
-
export { initLunora } from './packem_shared/initLunora-
|
|
2
|
+
export { initLunora } from './packem_shared/initLunora-lxwHTEV3.mjs';
|
|
3
3
|
export { createSecrets } from './packem_shared/createSecrets-TsIP9lOa.mjs';
|
|
4
4
|
export { LunoraEnvError, defineEnv, redactSecrets } from './packem_shared/LunoraEnvError-DjFkpkSP.mjs';
|
|
5
5
|
export { LunoraError } from './packem_shared/LunoraError-DhggBJZF.mjs';
|
|
@@ -7,17 +7,20 @@ export { bindOrm, bindTableFacade } from './packem_shared/bindOrm-Ce57S3N9.mjs';
|
|
|
7
7
|
export { httpAction, httpRoute, httpRouter, serveStorageObject } from './packem_shared/httpAction-B7FYUEgr.mjs';
|
|
8
8
|
export { onConnect, onDisconnect } from './packem_shared/onConnect-CIPXKPyw.mjs';
|
|
9
9
|
export { defineMigration } from './packem_shared/defineMigration-CAJLr6fx.mjs';
|
|
10
|
+
export { defineMutator } from './packem_shared/defineMutator-EIXAWhs9.mjs';
|
|
10
11
|
export { composePluginMiddleware, defineComponent, definePlugin, defineSchemaExtension, installPlugins, mergeSchemaExtension } from './packem_shared/composePluginMiddleware-Ck5_TUO8.mjs';
|
|
11
|
-
export { PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, definePresence, presenceExtension } from './packem_shared/PRESENCE_DEFAULT_TTL_MS-
|
|
12
|
+
export { PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, definePresence, presenceExtension } from './packem_shared/PRESENCE_DEFAULT_TTL_MS-C7j9gY_d.mjs';
|
|
12
13
|
export { protectPublic } from './packem_shared/protectPublic-BjFkQ_Or.mjs';
|
|
13
|
-
export { defineAggregateIndex, defineRankIndex, defineSchema, defineTable, defineVectorIndex } from './packem_shared/defineAggregateIndex-
|
|
14
|
+
export { defineAggregateIndex, defineRankIndex, defineSchema, defineTable, defineVectorIndex } from './packem_shared/defineAggregateIndex-ZdyU78gh.mjs';
|
|
15
|
+
export { defineShape } from './packem_shared/defineShape-CJ27Wx7o.mjs';
|
|
14
16
|
export { anyApi } from './types.mjs';
|
|
15
17
|
export { cronJobs } from '@lunora/scheduler';
|
|
16
18
|
export { ValidationError, v } from '@lunora/values';
|
|
19
|
+
export { buildRlsReadRegistry, composeShapeReadWhere } from './packem_shared/buildRlsReadRegistry-CkxuS69B.mjs';
|
|
17
20
|
export { createPolicyDsl, definePermission, definePolicies, definePolicy, defineRole } from './packem_shared/createPolicyDsl-De67zPDS.mjs';
|
|
18
21
|
export { defineStorageRule, defineStorageRules } from './packem_shared/defineStorageRule-qu0mpilX.mjs';
|
|
19
22
|
export { mask } from './packem_shared/mask-eCUYOwhd.mjs';
|
|
20
|
-
export { rls } from './packem_shared/rls-
|
|
23
|
+
export { rls } from './packem_shared/rls-ClmjkkxZ.mjs';
|
|
21
24
|
export { storageRules } from './packem_shared/storageRules-4a30FSpI.mjs';
|
|
22
25
|
|
|
23
26
|
const VERSION = "0.0.0";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { v } from '@lunora/values';
|
|
2
|
-
import { initLunora } from './initLunora-
|
|
2
|
+
import { initLunora } from './initLunora-lxwHTEV3.mjs';
|
|
3
3
|
import { LunoraError } from './LunoraError-DhggBJZF.mjs';
|
|
4
4
|
import { onDisconnect } from './onConnect-CIPXKPyw.mjs';
|
|
5
5
|
import { defineSchemaExtension, defineComponent } from './composePluginMiddleware-Ck5_TUO8.mjs';
|
|
6
|
-
import { defineTable } from './defineAggregateIndex-
|
|
6
|
+
import { defineTable } from './defineAggregateIndex-ZdyU78gh.mjs';
|
|
7
7
|
|
|
8
8
|
const DEFAULT_TTL_MS = 3e4;
|
|
9
9
|
const MAX_DATA_BYTES = 4096;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { indexRolePermissions, computeReadBaseWhere, permissionName } from './rls-ClmjkkxZ.mjs';
|
|
2
|
+
import { r as readRlsTag } from './policy-tag-DvpVH2tv.mjs';
|
|
3
|
+
|
|
4
|
+
const FALSE_PREDICATE = { OR: [] };
|
|
5
|
+
const readEntryTags = (entry) => {
|
|
6
|
+
const hoisted = entry?.rls?.tags;
|
|
7
|
+
if (hoisted) {
|
|
8
|
+
return hoisted;
|
|
9
|
+
}
|
|
10
|
+
const tag = readRlsTag(entry);
|
|
11
|
+
return tag ? [tag] : [];
|
|
12
|
+
};
|
|
13
|
+
const addTagToRegistry = (byTable, tag) => {
|
|
14
|
+
const rolePermissions = indexRolePermissions(tag.roles);
|
|
15
|
+
const seenWhenByTable = /* @__PURE__ */ new Map();
|
|
16
|
+
const policiesByTable = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const policy of tag.policies) {
|
|
18
|
+
if (policy.on !== "read") {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const seen = seenWhenByTable.get(policy.table) ?? /* @__PURE__ */ new Set();
|
|
22
|
+
if (seen.has(policy.when)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
seen.add(policy.when);
|
|
26
|
+
seenWhenByTable.set(policy.table, seen);
|
|
27
|
+
const list = policiesByTable.get(policy.table) ?? [];
|
|
28
|
+
list.push(policy);
|
|
29
|
+
policiesByTable.set(policy.table, list);
|
|
30
|
+
}
|
|
31
|
+
for (const [table, policies] of policiesByTable) {
|
|
32
|
+
const groups = byTable.get(table) ?? [];
|
|
33
|
+
groups.push({ policies, rolePermissions });
|
|
34
|
+
byTable.set(table, groups);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const isFalsePredicate = (where) => {
|
|
38
|
+
const or = where.OR;
|
|
39
|
+
return Array.isArray(or) && or.length === 0 && Object.keys(where).length === 1;
|
|
40
|
+
};
|
|
41
|
+
const andMerge = (injected, caller) => {
|
|
42
|
+
if (!injected || Object.keys(injected).length === 0) {
|
|
43
|
+
return caller;
|
|
44
|
+
}
|
|
45
|
+
if (isFalsePredicate(injected)) {
|
|
46
|
+
return injected;
|
|
47
|
+
}
|
|
48
|
+
if (Object.keys(caller).length === 0) {
|
|
49
|
+
return injected;
|
|
50
|
+
}
|
|
51
|
+
return { AND: [injected, caller] };
|
|
52
|
+
};
|
|
53
|
+
const evaluateGroupBaseWhere = (group, request) => {
|
|
54
|
+
const granted = /* @__PURE__ */ new Set();
|
|
55
|
+
for (const roleName of request.roles) {
|
|
56
|
+
for (const name of group.rolePermissions.get(roleName) ?? []) {
|
|
57
|
+
granted.add(name);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return computeReadBaseWhere(group.policies, {
|
|
61
|
+
auth: {
|
|
62
|
+
can: (permission) => granted.has(permissionName(permission)),
|
|
63
|
+
identity: request.identity,
|
|
64
|
+
roles: request.roles,
|
|
65
|
+
userId: request.userId
|
|
66
|
+
},
|
|
67
|
+
ctx: request.ctx
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
const resolveReadBaseWhere = (registry, request) => {
|
|
71
|
+
const groups = registry.byTable.get(request.table);
|
|
72
|
+
if (!groups || groups.length === 0) {
|
|
73
|
+
return request.rlsRequired && !request.tablePublic ? FALSE_PREDICATE : void 0;
|
|
74
|
+
}
|
|
75
|
+
const predicates = [];
|
|
76
|
+
for (const group of groups) {
|
|
77
|
+
const base = evaluateGroupBaseWhere(group, request);
|
|
78
|
+
if (base === void 0) {
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
if (isFalsePredicate(base)) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
predicates.push(base);
|
|
85
|
+
}
|
|
86
|
+
if (predicates.length === 0) {
|
|
87
|
+
return FALSE_PREDICATE;
|
|
88
|
+
}
|
|
89
|
+
return predicates.length === 1 ? predicates[0] : { OR: predicates };
|
|
90
|
+
};
|
|
91
|
+
const buildRlsReadRegistry = (functions) => {
|
|
92
|
+
const byTable = /* @__PURE__ */ new Map();
|
|
93
|
+
const seenTags = /* @__PURE__ */ new Set();
|
|
94
|
+
for (const entry of functions) {
|
|
95
|
+
for (const tag of readEntryTags(entry)) {
|
|
96
|
+
if (seenTags.has(tag)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
seenTags.add(tag);
|
|
100
|
+
addTagToRegistry(byTable, tag);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { byTable };
|
|
104
|
+
};
|
|
105
|
+
const composeShapeReadWhere = (registry, request) => andMerge(resolveReadBaseWhere(registry, request), request.shapeWhere);
|
|
106
|
+
|
|
107
|
+
export { buildRlsReadRegistry, composeShapeReadWhere };
|
package/dist/packem_shared/{defineAggregateIndex-C2gT1GzM.mjs → defineAggregateIndex-ZdyU78gh.mjs}
RENAMED
|
@@ -41,6 +41,7 @@ const defineTable = (inputShape) => {
|
|
|
41
41
|
let isExternallyManaged = false;
|
|
42
42
|
let isPublic = false;
|
|
43
43
|
let softDelete;
|
|
44
|
+
let externalSource;
|
|
44
45
|
const builder = {
|
|
45
46
|
aggregateIndex(name, options) {
|
|
46
47
|
const op = options?.op ?? "count";
|
|
@@ -63,6 +64,9 @@ const defineTable = (inputShape) => {
|
|
|
63
64
|
get aggregateIndexes() {
|
|
64
65
|
return aggregateIndexes;
|
|
65
66
|
},
|
|
67
|
+
get externalSource() {
|
|
68
|
+
return externalSource;
|
|
69
|
+
},
|
|
66
70
|
externallyManaged() {
|
|
67
71
|
isExternallyManaged = true;
|
|
68
72
|
return builder;
|
|
@@ -137,6 +141,17 @@ const defineTable = (inputShape) => {
|
|
|
137
141
|
get softDeleteMode() {
|
|
138
142
|
return softDelete;
|
|
139
143
|
},
|
|
144
|
+
source(definition) {
|
|
145
|
+
if (!definition.binding) {
|
|
146
|
+
throw new Error("source: `binding` is required (the wrangler Hyperdrive binding name)");
|
|
147
|
+
}
|
|
148
|
+
if (!definition.query) {
|
|
149
|
+
throw new Error("source: `query` is required (the tenant-membership SQL)");
|
|
150
|
+
}
|
|
151
|
+
externalSource = definition;
|
|
152
|
+
isExternallyManaged = true;
|
|
153
|
+
return builder;
|
|
154
|
+
},
|
|
140
155
|
softDelete(options) {
|
|
141
156
|
const field = options?.field ?? "deletedAt";
|
|
142
157
|
softDelete = { field };
|
|
@@ -243,9 +258,33 @@ const attachStandaloneIndexes = (tables, aggregateIndexes, rankIndexes) => {
|
|
|
243
258
|
table.rankIndexes.push(index);
|
|
244
259
|
}
|
|
245
260
|
};
|
|
261
|
+
const validateExternalSources = (tables) => {
|
|
262
|
+
for (const [name, table] of Object.entries(tables)) {
|
|
263
|
+
const source = table.externalSource;
|
|
264
|
+
if (!source) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (table.shardMode.kind === "global") {
|
|
268
|
+
throw new Error(
|
|
269
|
+
`defineSchema: table "${name}" cannot be both .source() and .global() — a sourced table materializes into a shard DO's SQLite, a global table lives in the external tier`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
if (table.shardMode.kind === "shardBy" && !source.tenantBy) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`defineSchema: sourced + .shardBy() table "${name}" needs a \`tenantBy\` mapper — without it every tenant's DO would run the same unscoped query and replicate the whole multitenant table (a cross-tenant leak). Add \`tenantBy: (shardKey) => [shardKey]\` binding the shard key into the query's parameters.`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
if (source.mode === "incremental") {
|
|
278
|
+
throw new Error(
|
|
279
|
+
`defineSchema: table "${name}" uses \`mode: "incremental"\`, which is not yet implemented — only "full-pull" (the default) is supported. Remove \`mode\` or set it to "full-pull".`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
246
284
|
const defineSchema = (tables, vectorIndexes = {}, aggregateIndexes = {}, rankIndexes = {}) => {
|
|
247
285
|
fillIndexTableNames(tables);
|
|
248
286
|
attachStandaloneIndexes(tables, aggregateIndexes, rankIndexes);
|
|
287
|
+
validateExternalSources(tables);
|
|
249
288
|
return withExtend({ tables, vectorIndexes });
|
|
250
289
|
};
|
|
251
290
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { v as validateArgs } from './functions-Di9FUNkf.mjs';
|
|
2
|
+
|
|
3
|
+
const defineMutator = (definition) => {
|
|
4
|
+
const handler = async (context, rawArgs) => {
|
|
5
|
+
const parsed = validateArgs(definition.args ?? {}, rawArgs);
|
|
6
|
+
return definition.server(context, parsed);
|
|
7
|
+
};
|
|
8
|
+
return { __lunoraMutator: true, ...definition, handler, kind: "mutation" };
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { defineMutator };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { v as validateArgs } from './functions-Di9FUNkf.mjs';
|
|
2
|
+
|
|
3
|
+
const defineShape = (definition) => {
|
|
4
|
+
if (definition.table.trim() === "") {
|
|
5
|
+
throw new Error("defineShape: `table` must be a non-empty string");
|
|
6
|
+
}
|
|
7
|
+
if (definition.columns?.length === 0) {
|
|
8
|
+
throw new Error("defineShape: `columns` must list at least one column when provided");
|
|
9
|
+
}
|
|
10
|
+
const compileWhere = (context, rawArgs) => {
|
|
11
|
+
const parsed = validateArgs(definition.args ?? {}, rawArgs);
|
|
12
|
+
return definition.where(context, parsed);
|
|
13
|
+
};
|
|
14
|
+
return { __lunoraShape: true, ...definition, compileWhere };
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { defineShape };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { v as validateArgs } from './functions-Di9FUNkf.mjs';
|
|
2
|
+
import { r as readRlsTag } from './policy-tag-DvpVH2tv.mjs';
|
|
2
3
|
import { r as runMiddlewareChain } from './run-middleware-CYQOuoV6.mjs';
|
|
3
4
|
|
|
4
|
-
const validateArgs = (validators, args) => parseValidatorMap(validators, args, "args");
|
|
5
|
-
|
|
6
5
|
const runMiddleware = (middlewares, baseContext) => runMiddlewareChain(middlewares, baseContext, (context) => context);
|
|
7
6
|
const makeHandler = (args, middlewares, userHandler, output) => async (context, rawArgs) => {
|
|
8
7
|
const parsed = validateArgs(args, rawArgs);
|
|
@@ -35,16 +34,29 @@ const makeStreamHandler = (args, middlewares, userHandler) => (context, rawArgs,
|
|
|
35
34
|
}
|
|
36
35
|
})();
|
|
37
36
|
};
|
|
37
|
+
const collectRls = (middlewares) => {
|
|
38
|
+
const tags = [];
|
|
39
|
+
for (const middleware of middlewares) {
|
|
40
|
+
const tag = readRlsTag(middleware);
|
|
41
|
+
if (!tag) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
tags.push(tag);
|
|
45
|
+
}
|
|
46
|
+
return tags.length > 0 ? { tags } : void 0;
|
|
47
|
+
};
|
|
38
48
|
const makeBuilder = (kind, state, visibility) => {
|
|
39
49
|
return {
|
|
40
50
|
__lunoraProcedure: kind,
|
|
41
51
|
...visibility ? { __lunoraVisibility: visibility } : {},
|
|
42
52
|
input: (validators) => makeBuilder(kind, { ...state, args: { ...state.args, ...validators } }, visibility),
|
|
43
53
|
[kind]: (userHandler) => {
|
|
54
|
+
const rls = collectRls(state.middlewares);
|
|
44
55
|
return {
|
|
45
56
|
args: state.args,
|
|
46
57
|
handler: makeHandler(state.args, state.middlewares, userHandler, state.output),
|
|
47
58
|
kind,
|
|
59
|
+
...rls ? { rls } : {},
|
|
48
60
|
...visibility ? { visibility } : {}
|
|
49
61
|
};
|
|
50
62
|
},
|
|
@@ -55,10 +67,12 @@ const makeBuilder = (kind, state, visibility) => {
|
|
|
55
67
|
// unconditionally keeps the runtime free of per-kind branching.
|
|
56
68
|
...kind === "query" ? {
|
|
57
69
|
stream: (userHandler) => {
|
|
70
|
+
const rls = collectRls(state.middlewares);
|
|
58
71
|
return {
|
|
59
72
|
args: state.args,
|
|
60
73
|
handler: makeStreamHandler(state.args, state.middlewares, userHandler),
|
|
61
74
|
kind: "stream",
|
|
75
|
+
...rls ? { rls } : {},
|
|
62
76
|
...visibility ? { visibility } : {}
|
|
63
77
|
};
|
|
64
78
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const RLS_TAG = /* @__PURE__ */ Symbol.for("lunora.rls.middleware-policies");
|
|
2
|
+
const tagRlsMiddleware = (middleware, tag) => {
|
|
3
|
+
Object.defineProperty(middleware, RLS_TAG, { configurable: true, enumerable: false, value: tag });
|
|
4
|
+
return middleware;
|
|
5
|
+
};
|
|
6
|
+
const readRlsTag = (middleware) => {
|
|
7
|
+
if (middleware === null || typeof middleware !== "function" && typeof middleware !== "object") {
|
|
8
|
+
return void 0;
|
|
9
|
+
}
|
|
10
|
+
return middleware[RLS_TAG];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { readRlsTag as r, tagRlsMiddleware as t };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LunoraError } from './LunoraError-DhggBJZF.mjs';
|
|
2
2
|
import { bindTableFacade, bindOrm } from './bindOrm-Ce57S3N9.mjs';
|
|
3
|
+
import { t as tagRlsMiddleware } from './policy-tag-DvpVH2tv.mjs';
|
|
3
4
|
|
|
4
5
|
const DEFAULT_BATCH_LIMIT = 500;
|
|
5
6
|
const assertBatchLimit = (count, limit, op) => {
|
|
@@ -532,7 +533,7 @@ const indexRolePermissions = (roles) => {
|
|
|
532
533
|
const rls = (policies, options = {}) => {
|
|
533
534
|
const perTable = indexByTable(policies);
|
|
534
535
|
const rolePermissions = indexRolePermissions(options.roles);
|
|
535
|
-
|
|
536
|
+
const middleware = async ({ ctx, next }) => {
|
|
536
537
|
const auth = ctx.auth ?? {};
|
|
537
538
|
const identity = await auth.getIdentity?.() ?? null;
|
|
538
539
|
const roles = auth.roles ?? [];
|
|
@@ -562,6 +563,7 @@ const rls = (policies, options = {}) => {
|
|
|
562
563
|
}
|
|
563
564
|
return next({ ctx: extension });
|
|
564
565
|
};
|
|
566
|
+
return tagRlsMiddleware(middleware, { policies, roles: options.roles ?? [] });
|
|
565
567
|
};
|
|
566
568
|
|
|
567
569
|
export { computeReadBaseWhere, evaluateWrite, indexRolePermissions, matchesWhere, permissionName, rls };
|
package/dist/rls/testing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { indexRolePermissions, computeReadBaseWhere, matchesWhere, evaluateWrite, permissionName } from '../packem_shared/rls-
|
|
1
|
+
import { indexRolePermissions, computeReadBaseWhere, matchesWhere, evaluateWrite, permissionName } from '../packem_shared/rls-ClmjkkxZ.mjs';
|
|
2
2
|
|
|
3
3
|
const expectPolicy = (policies, options = {}) => {
|
|
4
4
|
const rolePermissions = indexRolePermissions(options.roles);
|
package/dist/types.d.mts
CHANGED
|
@@ -23,6 +23,51 @@ type ShardMode = {
|
|
|
23
23
|
} | {
|
|
24
24
|
kind: "root";
|
|
25
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
|
+
}
|
|
26
71
|
interface IndexDefinition {
|
|
27
72
|
fields: ReadonlyArray<string>;
|
|
28
73
|
name: string;
|
|
@@ -138,6 +183,14 @@ interface TableDefinition<Shape extends Record<string, Validator> = Record<strin
|
|
|
138
183
|
* without scanning the underlying table.
|
|
139
184
|
*/
|
|
140
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;
|
|
141
194
|
indexes: ReadonlyArray<IndexDefinition>;
|
|
142
195
|
/**
|
|
143
196
|
* `true` when `.externallyManaged()` was called — the table's rows are
|
|
@@ -1101,4 +1154,4 @@ interface ActionCtx {
|
|
|
1101
1154
|
*/
|
|
1102
1155
|
type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
|
|
1103
1156
|
declare const anyApi: AnyApi;
|
|
1104
|
-
export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, 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 };
|
|
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
|
@@ -23,6 +23,51 @@ type ShardMode = {
|
|
|
23
23
|
} | {
|
|
24
24
|
kind: "root";
|
|
25
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
|
+
}
|
|
26
71
|
interface IndexDefinition {
|
|
27
72
|
fields: ReadonlyArray<string>;
|
|
28
73
|
name: string;
|
|
@@ -138,6 +183,14 @@ interface TableDefinition<Shape extends Record<string, Validator> = Record<strin
|
|
|
138
183
|
* without scanning the underlying table.
|
|
139
184
|
*/
|
|
140
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;
|
|
141
194
|
indexes: ReadonlyArray<IndexDefinition>;
|
|
142
195
|
/**
|
|
143
196
|
* `true` when `.externallyManaged()` was called — the table's rows are
|
|
@@ -1101,4 +1154,4 @@ interface ActionCtx {
|
|
|
1101
1154
|
*/
|
|
1102
1155
|
type AnyApi = Record<string, Record<string, RegisteredFunction<ArgsValidator, unknown, FunctionKind>>>;
|
|
1103
1156
|
declare const anyApi: AnyApi;
|
|
1104
|
-
export { type ActionCtx, type AggregateIndexDefinition, type AggregateOp, type AnyApi, type ArgsValidator, type AuthState, type DatabaseReader, type DatabaseWriter, type DurableObjectJurisdiction, 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 };
|
|
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 };
|