@lunora/server 1.0.0-alpha.30 → 1.0.0-alpha.32

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.
Files changed (61) hide show
  1. package/dist/data-model.mjs +0 -1
  2. package/dist/drizzle.mjs +1 -1
  3. package/dist/index.d.mts +105 -8
  4. package/dist/index.d.ts +105 -8
  5. package/dist/index.mjs +1 -29
  6. package/dist/packem_shared/LunoraEnvError-CgpI2Mm_.mjs +3 -0
  7. package/dist/packem_shared/LunoraError-LVhdU0Lo.mjs +1 -0
  8. package/dist/packem_shared/PRESENCE_DEFAULT_TTL_MS-CF_9uiu1.mjs +1 -0
  9. package/dist/packem_shared/allowAll-BnyNbJZT.mjs +1 -0
  10. package/dist/packem_shared/asBucketStorage-1pFfH-Tn.mjs +1 -0
  11. package/dist/packem_shared/bindOrm-Bp9hsM2q.mjs +1 -0
  12. package/dist/packem_shared/buildRlsReadRegistry-WdiqSj87.mjs +1 -0
  13. package/dist/packem_shared/composePluginMiddleware-COr09CXA.mjs +1 -0
  14. package/dist/packem_shared/createPolicyDsl-sV1swpkD.mjs +1 -0
  15. package/dist/packem_shared/createSecrets-CgVPiW2C.mjs +1 -0
  16. package/dist/packem_shared/defineAggregateIndex-CYuH6IbJ.mjs +1 -0
  17. package/dist/packem_shared/defineIdentity-B7gfAgxx.mjs +1 -0
  18. package/dist/packem_shared/defineMigration-Bfpwxv2f.mjs +1 -0
  19. package/dist/packem_shared/defineMutator-8Kz0j1Kt.mjs +1 -0
  20. package/dist/packem_shared/defineShape-CyuRfwHz.mjs +1 -0
  21. package/dist/packem_shared/defineStorageRule-BDu01PUn.mjs +1 -0
  22. package/dist/packem_shared/functions-CDC08CWY.mjs +1 -0
  23. package/dist/packem_shared/httpAction-C14NuF3V.mjs +4 -0
  24. package/dist/packem_shared/initLunora-CHh1EmR4.mjs +1 -0
  25. package/dist/packem_shared/mask-C6Bi78qj.mjs +1 -0
  26. package/dist/packem_shared/onConnect-CEtRmUpJ.mjs +1 -0
  27. package/dist/packem_shared/policy-tag-Dprt9JWo.mjs +1 -0
  28. package/dist/packem_shared/protectPublic-BhKewPqm.mjs +1 -0
  29. package/dist/packem_shared/rls-_iVsPvhX.mjs +1 -0
  30. package/dist/packem_shared/run-middleware-BeEEqmdE.mjs +1 -0
  31. package/dist/packem_shared/storageRules-BptPZbi8.mjs +1 -0
  32. package/dist/rls/testing.mjs +1 -49
  33. package/dist/types.d.mts +76 -0
  34. package/dist/types.d.ts +76 -0
  35. package/dist/types.mjs +1 -31
  36. package/package.json +4 -4
  37. package/dist/packem_shared/LunoraEnvError-BGmd1Qs0.mjs +0 -187
  38. package/dist/packem_shared/LunoraError-WbxmrpxR.mjs +0 -9
  39. package/dist/packem_shared/PRESENCE_DEFAULT_TTL_MS-Cr0i4mTv.mjs +0 -114
  40. package/dist/packem_shared/asBucketStorage-Cnxd9y2q.mjs +0 -11
  41. package/dist/packem_shared/bindOrm-CaY7Wq9Z.mjs +0 -147
  42. package/dist/packem_shared/buildRlsReadRegistry-2uk_GfiH.mjs +0 -107
  43. package/dist/packem_shared/composePluginMiddleware-z62dttBo.mjs +0 -103
  44. package/dist/packem_shared/createPolicyDsl-By3QB4he.mjs +0 -32
  45. package/dist/packem_shared/createSecrets-DwaR2rNG.mjs +0 -58
  46. package/dist/packem_shared/defineAggregateIndex-cdo0g-un.mjs +0 -349
  47. package/dist/packem_shared/defineIdentity-DiX4zM9x.mjs +0 -35
  48. package/dist/packem_shared/defineMigration-Hx01yIht.mjs +0 -10
  49. package/dist/packem_shared/defineMutator-EIXAWhs9.mjs +0 -11
  50. package/dist/packem_shared/defineShape-C5scNOrf.mjs +0 -18
  51. package/dist/packem_shared/defineStorageRule-B5nL4Z1P.mjs +0 -23
  52. package/dist/packem_shared/functions-Di9FUNkf.mjs +0 -5
  53. package/dist/packem_shared/httpAction-DCXoYPIk.mjs +0 -355
  54. package/dist/packem_shared/initLunora-D0Wuki7S.mjs +0 -115
  55. package/dist/packem_shared/mask-BepaW7YN.mjs +0 -334
  56. package/dist/packem_shared/onConnect-CIPXKPyw.mjs +0 -13
  57. package/dist/packem_shared/policy-tag-DvpVH2tv.mjs +0 -13
  58. package/dist/packem_shared/protectPublic-BlcGpiRc.mjs +0 -15
  59. package/dist/packem_shared/rls-BaDQf7MG.mjs +0 -595
  60. package/dist/packem_shared/run-middleware-I6EiQfxL.mjs +0 -20
  61. package/dist/packem_shared/storageRules-6QxzDOcx.mjs +0 -88
@@ -1 +0,0 @@
1
-
package/dist/drizzle.mjs CHANGED
@@ -1 +1 @@
1
- export * from 'drizzle-orm/sqlite-core';
1
+ export*from"drizzle-orm/sqlite-core";
package/dist/index.d.mts CHANGED
@@ -1396,6 +1396,20 @@ interface TableBuilder<Shape extends Record<string, Validator> = Record<string,
1396
1396
  index: (name: string, fields: ReadonlyArray<string>, options?: {
1397
1397
  unique?: boolean;
1398
1398
  }) => TableBuilder<Shape>;
1399
+ /**
1400
+ * Name the column holding the owning user's id, so "only the owner sees these
1401
+ * rows" is declared once here rather than restated in every shape.
1402
+ *
1403
+ * A `defineShape({ table, owner: true })` over this table derives its predicate
1404
+ * from the field: the subscriber's verified `ctx.auth.userId` must match, and an
1405
+ * anonymous subscriber is denied. Pairs naturally with `.shardBy(field)` on the
1406
+ * same column — the shard key routes the storage, `ownedBy` states who the rows
1407
+ * belong to — but the two are independent and either can be used alone.
1408
+ *
1409
+ * This is a *shape* declaration, not an RLS policy: it narrows what a shape
1410
+ * replicates. Guarding procedure reads/writes is still `rls(...)`'s job.
1411
+ */
1412
+ ownedBy: (field: keyof Shape & string) => TableBuilder<Shape>;
1399
1413
  /**
1400
1414
  * Opt this table OUT of secure-by-default RLS. Under a schema marked
1401
1415
  * `.rls("required")`, every table is protected (the write path denies raw,
@@ -1878,6 +1892,13 @@ interface DatabaseWriterLike {
1878
1892
  delete: (id: string, expectedTable?: string, options?: {
1879
1893
  hard?: boolean;
1880
1894
  }) => Promise<void>;
1895
+ /** Uncapped, chunked erase of a whole table. The RLS wrapper gates each row like a single delete. */
1896
+ deleteAll?: (tableName: string, options?: {
1897
+ chunkSize?: number;
1898
+ hard?: boolean;
1899
+ }) => Promise<{
1900
+ deleted: number;
1901
+ }>;
1881
1902
  deleteMany: (ids: ReadonlyArray<string>, options?: {
1882
1903
  limit?: number;
1883
1904
  }, expectedTable?: string) => Promise<{
@@ -1965,6 +1986,18 @@ interface DatabaseWriterLike {
1965
1986
  rankPage: (tableName: string, indexName: string, options?: RankPageArgs) => Promise<QueryPage>;
1966
1987
  replace: (id: string, document: Record<string, unknown>, expectedTable?: string) => Promise<void>;
1967
1988
  restore?: (id: string, expectedTable?: string) => Promise<void>;
1989
+ /**
1990
+ * Whole-shard erase. The RLS wrapper deliberately **fails this closed** rather
1991
+ * than wrapping it — see the wrapper's `wipeShard`.
1992
+ */
1993
+ wipeShard?: (options?: {
1994
+ chunkSize?: number;
1995
+ exclude?: ReadonlyArray<string>;
1996
+ tables?: ReadonlyArray<string>;
1997
+ }) => Promise<{
1998
+ deleted: number;
1999
+ tables: Record<string, number>;
2000
+ }>;
1968
2001
  }
1969
2002
  /**
1970
2003
  * What a procedure's `ctx.db` must structurally satisfy for the middleware
@@ -1987,6 +2020,41 @@ interface RlsContextIn {
1987
2020
  db: RlsDatabase;
1988
2021
  }
1989
2022
  declare const rls: <Context extends RlsContextIn = RlsContextIn>(policies: ReadonlyArray<Policy<Context>>, options?: RlsOptions) => Middleware<Context, Context>;
2023
+ /**
2024
+ * A predicate matching **no** rows — the deny decision.
2025
+ *
2026
+ * `{ OR: [] }` is a disjunction over zero branches, which the where-compiler
2027
+ * folds to a constant false. Use it (never a bare `{}`) for the unauthorized
2028
+ * branch of a shape or policy predicate:
2029
+ *
2030
+ * ```ts
2031
+ * where: (ctx, { userId }) => (ctx.auth.userId === userId ? { userId } : deny())
2032
+ * ```
2033
+ *
2034
+ * A fresh object per call, so a caller can safely spread or extend the result.
2035
+ */
2036
+ declare const deny: () => WhereInput;
2037
+ /**
2038
+ * A predicate matching **every** row — no restriction beyond whatever it is
2039
+ * AND-composed with. The honest spelling of "this branch adds no filter", where a
2040
+ * bare `{}` reads like an oversight.
2041
+ */
2042
+ declare const allowAll: () => WhereInput;
2043
+ /**
2044
+ * `true` when `where` is the vacuously-false deny predicate — i.e. an `OR` over
2045
+ * zero branches, carrying no other constraint. Used by the runtime to short-circuit
2046
+ * a denied read instead of compiling and running SQL that provably matches nothing.
2047
+ */
2048
+ declare const isDeny: (where: WhereInput) => boolean;
2049
+ /**
2050
+ * Normalize a boolean-or-predicate decision to a {@link WhereInput}.
2051
+ *
2052
+ * The authoring surfaces accept `true`/`false` as sugar — they read far better
2053
+ * than the sentinel objects in an ownership check — and every consumer downstream
2054
+ * wants a plain predicate. `undefined` means "no opinion" and maps to
2055
+ * {@link allowAll}, matching the RLS `PolicyDecision` contract.
2056
+ */
2057
+ declare const toWhereInput: (decision: WhereInput | boolean | undefined) => WhereInput;
1990
2058
  /**
1991
2059
  * One `rls()` tag's read policies for a table, paired with the role→permission
1992
2060
  * grants of that SAME middleware. Keeping the role map per-group is what lets a
@@ -2059,6 +2127,24 @@ interface ShapeDefinition<Args extends ValidatorMap = ValidatorMap, Context = Qu
2059
2127
  * intent.
2060
2128
  */
2061
2129
  readonly columns?: ReadonlyArray<string>;
2130
+ /**
2131
+ * Restrict this shape to rows the **subscriber owns**, without writing the
2132
+ * predicate by hand.
2133
+ *
2134
+ * `true` uses the owning column declared by `.ownedBy(field)` on the table;
2135
+ * `"field"` names the owning column here instead (for a table that has no
2136
+ * `.ownedBy()`, or a shape that scopes by a different column).
2137
+ *
2138
+ * The derived predicate is `{ [field]: ctx.auth.userId }`, AND-composed with
2139
+ * the shape's own `where` when both are present, and an anonymous subscriber is denied
2140
+ * outright. Because the value comes from the socket's verified identity rather
2141
+ * than from `args`, a client cannot ask for another user's partition at all —
2142
+ * strictly safer than accepting a `userId` arg and comparing it.
2143
+ *
2144
+ * This is the primitive for the "every shape repeats the same ownership check"
2145
+ * pattern: with it, an owner-scoped shape needs no `where` at all.
2146
+ */
2147
+ readonly owner?: string | true;
2062
2148
  /** Logical table this shape replicates a partition of. */
2063
2149
  readonly table: string;
2064
2150
  /**
@@ -2067,21 +2153,32 @@ interface ShapeDefinition<Args extends ValidatorMap = ValidatorMap, Context = Qu
2067
2153
  * `ctx` (identity/auth the client can't forge) and the validated client
2068
2154
  * `args`; returns a {@link WhereInput} using the same operator set as the
2069
2155
  * SQL compiler (`eq`/`in`/`lt`/… + `AND`/`OR`/`NOT`).
2156
+ *
2157
+ * `true`/`false` are accepted as sugar for "no further restriction" / "deny" —
2158
+ * `false` compiles to the vacuously-false predicate, so a denial branch can
2159
+ * never be mistyped as the everything-matches `{}`. Optional when `owner` is
2160
+ * set; otherwise required.
2070
2161
  */
2071
- readonly where: (context: Context, args: InferValidatorMap<Args>) => WhereInput;
2162
+ readonly where?: (context: Context, args: InferValidatorMap<Args>) => WhereInput | boolean;
2072
2163
  }
2073
2164
  /** A {@link ShapeDefinition} plus the codegen discovery marker and a dispatch-shaped `compileWhere`. */
2074
2165
  interface RegisteredShape<Args extends ValidatorMap = ValidatorMap, Context = QueryCtx> extends ShapeDefinition<Args, Context> {
2075
2166
  readonly __lunoraShape: true;
2076
2167
  /**
2077
- * Validate `rawArgs`, then evaluate `where` under the trusted `ctx` and
2078
- * return its {@link WhereInput}. Used by the generated DO's `resolveShape`
2079
- * override: `ctx` is erased to `unknown` at this dispatch boundary (the DO
2080
- * builds it from the socket's verified identity and hands it back as the
2081
- * concrete {@link QueryContext} the predicate expects), exactly like
2168
+ * Validate `rawArgs`, then evaluate the shape's predicate under the trusted
2169
+ * `ctx` and return its {@link WhereInput}. Used by the generated DO's
2170
+ * `resolveShape` override: `ctx` is erased to `unknown` at this dispatch
2171
+ * boundary (the DO builds it from the socket's verified identity and hands it
2172
+ * back as the concrete {@link QueryContext} the predicate expects), exactly like
2082
2173
  * `RegisteredLunoraFunction.handler` erases its context.
2174
+ *
2175
+ * `options.ownerField` carries the table's `.ownedBy(field)` column, which only
2176
+ * the caller (the DO, holding the schema) can look up — it is what resolves an
2177
+ * `owner: true` shape. Omitted for an `owner: "field"` or plain `where` shape.
2083
2178
  */
2084
- readonly compileWhere: (context: unknown, rawArgs: Record<string, unknown>) => WhereInput;
2179
+ readonly compileWhere: (context: unknown, rawArgs: Record<string, unknown>, options?: {
2180
+ ownerField?: string;
2181
+ }) => WhereInput;
2085
2182
  }
2086
2183
  /** Declare a replication shape. See the module docs for runtime semantics. */
2087
2184
  declare const defineShape: <Args extends ValidatorMap = ValidatorMap, Context = QueryCtx>(definition: ShapeDefinition<Args, Context>) => RegisteredShape<Args, Context>;
@@ -2168,4 +2265,4 @@ interface StorageContextIn {
2168
2265
  }
2169
2266
  declare const storageRules: <Context extends StorageContextIn = StorageContextIn>(rules: ReadonlyArray<StorageRule<Context>>, options?: StorageRulesOptions) => Middleware<Context, Context>;
2170
2267
  declare const VERSION = "0.0.0";
2171
- export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefineIdentityOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExposeConfig, 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 IdentityContract, type IdentityRejectMode, type IdentityValidation, type InferArgs, type InferEnv, type InferIdentity, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, 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, defineIdentity, defineMigration, defineMutator, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineShape, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, httpAction, httpRoute, httpRouter, initLunora, installPlugins, isSafeHeaderValue, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules };
2268
+ export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefineIdentityOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExposeConfig, 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 IdentityContract, type IdentityRejectMode, type IdentityValidation, type InferArgs, type InferEnv, type InferIdentity, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, 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, allowAll, asBucketStorage, bindOrm, bindTableFacade, buildRlsReadRegistry, composePluginMiddleware, composeShapeReadWhere, createPolicyDsl, createSecrets, defineAggregateIndex, defineComponent, defineEnv, defineIdentity, defineMigration, defineMutator, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineShape, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, deny, httpAction, httpRoute, httpRouter, initLunora, installPlugins, isDeny, isSafeHeaderValue, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules, toWhereInput };
package/dist/index.d.ts CHANGED
@@ -1396,6 +1396,20 @@ interface TableBuilder<Shape extends Record<string, Validator> = Record<string,
1396
1396
  index: (name: string, fields: ReadonlyArray<string>, options?: {
1397
1397
  unique?: boolean;
1398
1398
  }) => TableBuilder<Shape>;
1399
+ /**
1400
+ * Name the column holding the owning user's id, so "only the owner sees these
1401
+ * rows" is declared once here rather than restated in every shape.
1402
+ *
1403
+ * A `defineShape({ table, owner: true })` over this table derives its predicate
1404
+ * from the field: the subscriber's verified `ctx.auth.userId` must match, and an
1405
+ * anonymous subscriber is denied. Pairs naturally with `.shardBy(field)` on the
1406
+ * same column — the shard key routes the storage, `ownedBy` states who the rows
1407
+ * belong to — but the two are independent and either can be used alone.
1408
+ *
1409
+ * This is a *shape* declaration, not an RLS policy: it narrows what a shape
1410
+ * replicates. Guarding procedure reads/writes is still `rls(...)`'s job.
1411
+ */
1412
+ ownedBy: (field: keyof Shape & string) => TableBuilder<Shape>;
1399
1413
  /**
1400
1414
  * Opt this table OUT of secure-by-default RLS. Under a schema marked
1401
1415
  * `.rls("required")`, every table is protected (the write path denies raw,
@@ -1878,6 +1892,13 @@ interface DatabaseWriterLike {
1878
1892
  delete: (id: string, expectedTable?: string, options?: {
1879
1893
  hard?: boolean;
1880
1894
  }) => Promise<void>;
1895
+ /** Uncapped, chunked erase of a whole table. The RLS wrapper gates each row like a single delete. */
1896
+ deleteAll?: (tableName: string, options?: {
1897
+ chunkSize?: number;
1898
+ hard?: boolean;
1899
+ }) => Promise<{
1900
+ deleted: number;
1901
+ }>;
1881
1902
  deleteMany: (ids: ReadonlyArray<string>, options?: {
1882
1903
  limit?: number;
1883
1904
  }, expectedTable?: string) => Promise<{
@@ -1965,6 +1986,18 @@ interface DatabaseWriterLike {
1965
1986
  rankPage: (tableName: string, indexName: string, options?: RankPageArgs) => Promise<QueryPage>;
1966
1987
  replace: (id: string, document: Record<string, unknown>, expectedTable?: string) => Promise<void>;
1967
1988
  restore?: (id: string, expectedTable?: string) => Promise<void>;
1989
+ /**
1990
+ * Whole-shard erase. The RLS wrapper deliberately **fails this closed** rather
1991
+ * than wrapping it — see the wrapper's `wipeShard`.
1992
+ */
1993
+ wipeShard?: (options?: {
1994
+ chunkSize?: number;
1995
+ exclude?: ReadonlyArray<string>;
1996
+ tables?: ReadonlyArray<string>;
1997
+ }) => Promise<{
1998
+ deleted: number;
1999
+ tables: Record<string, number>;
2000
+ }>;
1968
2001
  }
1969
2002
  /**
1970
2003
  * What a procedure's `ctx.db` must structurally satisfy for the middleware
@@ -1987,6 +2020,41 @@ interface RlsContextIn {
1987
2020
  db: RlsDatabase;
1988
2021
  }
1989
2022
  declare const rls: <Context extends RlsContextIn = RlsContextIn>(policies: ReadonlyArray<Policy<Context>>, options?: RlsOptions) => Middleware<Context, Context>;
2023
+ /**
2024
+ * A predicate matching **no** rows — the deny decision.
2025
+ *
2026
+ * `{ OR: [] }` is a disjunction over zero branches, which the where-compiler
2027
+ * folds to a constant false. Use it (never a bare `{}`) for the unauthorized
2028
+ * branch of a shape or policy predicate:
2029
+ *
2030
+ * ```ts
2031
+ * where: (ctx, { userId }) => (ctx.auth.userId === userId ? { userId } : deny())
2032
+ * ```
2033
+ *
2034
+ * A fresh object per call, so a caller can safely spread or extend the result.
2035
+ */
2036
+ declare const deny: () => WhereInput;
2037
+ /**
2038
+ * A predicate matching **every** row — no restriction beyond whatever it is
2039
+ * AND-composed with. The honest spelling of "this branch adds no filter", where a
2040
+ * bare `{}` reads like an oversight.
2041
+ */
2042
+ declare const allowAll: () => WhereInput;
2043
+ /**
2044
+ * `true` when `where` is the vacuously-false deny predicate — i.e. an `OR` over
2045
+ * zero branches, carrying no other constraint. Used by the runtime to short-circuit
2046
+ * a denied read instead of compiling and running SQL that provably matches nothing.
2047
+ */
2048
+ declare const isDeny: (where: WhereInput) => boolean;
2049
+ /**
2050
+ * Normalize a boolean-or-predicate decision to a {@link WhereInput}.
2051
+ *
2052
+ * The authoring surfaces accept `true`/`false` as sugar — they read far better
2053
+ * than the sentinel objects in an ownership check — and every consumer downstream
2054
+ * wants a plain predicate. `undefined` means "no opinion" and maps to
2055
+ * {@link allowAll}, matching the RLS `PolicyDecision` contract.
2056
+ */
2057
+ declare const toWhereInput: (decision: WhereInput | boolean | undefined) => WhereInput;
1990
2058
  /**
1991
2059
  * One `rls()` tag's read policies for a table, paired with the role→permission
1992
2060
  * grants of that SAME middleware. Keeping the role map per-group is what lets a
@@ -2059,6 +2127,24 @@ interface ShapeDefinition<Args extends ValidatorMap = ValidatorMap, Context = Qu
2059
2127
  * intent.
2060
2128
  */
2061
2129
  readonly columns?: ReadonlyArray<string>;
2130
+ /**
2131
+ * Restrict this shape to rows the **subscriber owns**, without writing the
2132
+ * predicate by hand.
2133
+ *
2134
+ * `true` uses the owning column declared by `.ownedBy(field)` on the table;
2135
+ * `"field"` names the owning column here instead (for a table that has no
2136
+ * `.ownedBy()`, or a shape that scopes by a different column).
2137
+ *
2138
+ * The derived predicate is `{ [field]: ctx.auth.userId }`, AND-composed with
2139
+ * the shape's own `where` when both are present, and an anonymous subscriber is denied
2140
+ * outright. Because the value comes from the socket's verified identity rather
2141
+ * than from `args`, a client cannot ask for another user's partition at all —
2142
+ * strictly safer than accepting a `userId` arg and comparing it.
2143
+ *
2144
+ * This is the primitive for the "every shape repeats the same ownership check"
2145
+ * pattern: with it, an owner-scoped shape needs no `where` at all.
2146
+ */
2147
+ readonly owner?: string | true;
2062
2148
  /** Logical table this shape replicates a partition of. */
2063
2149
  readonly table: string;
2064
2150
  /**
@@ -2067,21 +2153,32 @@ interface ShapeDefinition<Args extends ValidatorMap = ValidatorMap, Context = Qu
2067
2153
  * `ctx` (identity/auth the client can't forge) and the validated client
2068
2154
  * `args`; returns a {@link WhereInput} using the same operator set as the
2069
2155
  * SQL compiler (`eq`/`in`/`lt`/… + `AND`/`OR`/`NOT`).
2156
+ *
2157
+ * `true`/`false` are accepted as sugar for "no further restriction" / "deny" —
2158
+ * `false` compiles to the vacuously-false predicate, so a denial branch can
2159
+ * never be mistyped as the everything-matches `{}`. Optional when `owner` is
2160
+ * set; otherwise required.
2070
2161
  */
2071
- readonly where: (context: Context, args: InferValidatorMap<Args>) => WhereInput;
2162
+ readonly where?: (context: Context, args: InferValidatorMap<Args>) => WhereInput | boolean;
2072
2163
  }
2073
2164
  /** A {@link ShapeDefinition} plus the codegen discovery marker and a dispatch-shaped `compileWhere`. */
2074
2165
  interface RegisteredShape<Args extends ValidatorMap = ValidatorMap, Context = QueryCtx> extends ShapeDefinition<Args, Context> {
2075
2166
  readonly __lunoraShape: true;
2076
2167
  /**
2077
- * Validate `rawArgs`, then evaluate `where` under the trusted `ctx` and
2078
- * return its {@link WhereInput}. Used by the generated DO's `resolveShape`
2079
- * override: `ctx` is erased to `unknown` at this dispatch boundary (the DO
2080
- * builds it from the socket's verified identity and hands it back as the
2081
- * concrete {@link QueryContext} the predicate expects), exactly like
2168
+ * Validate `rawArgs`, then evaluate the shape's predicate under the trusted
2169
+ * `ctx` and return its {@link WhereInput}. Used by the generated DO's
2170
+ * `resolveShape` override: `ctx` is erased to `unknown` at this dispatch
2171
+ * boundary (the DO builds it from the socket's verified identity and hands it
2172
+ * back as the concrete {@link QueryContext} the predicate expects), exactly like
2082
2173
  * `RegisteredLunoraFunction.handler` erases its context.
2174
+ *
2175
+ * `options.ownerField` carries the table's `.ownedBy(field)` column, which only
2176
+ * the caller (the DO, holding the schema) can look up — it is what resolves an
2177
+ * `owner: true` shape. Omitted for an `owner: "field"` or plain `where` shape.
2083
2178
  */
2084
- readonly compileWhere: (context: unknown, rawArgs: Record<string, unknown>) => WhereInput;
2179
+ readonly compileWhere: (context: unknown, rawArgs: Record<string, unknown>, options?: {
2180
+ ownerField?: string;
2181
+ }) => WhereInput;
2085
2182
  }
2086
2183
  /** Declare a replication shape. See the module docs for runtime semantics. */
2087
2184
  declare const defineShape: <Args extends ValidatorMap = ValidatorMap, Context = QueryCtx>(definition: ShapeDefinition<Args, Context>) => RegisteredShape<Args, Context>;
@@ -2168,4 +2265,4 @@ interface StorageContextIn {
2168
2265
  }
2169
2266
  declare const storageRules: <Context extends StorageContextIn = StorageContextIn>(rules: ReadonlyArray<StorageRule<Context>>, options?: StorageRulesOptions) => Middleware<Context, Context>;
2170
2267
  declare const VERSION = "0.0.0";
2171
- export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefineIdentityOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExposeConfig, 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 IdentityContract, type IdentityRejectMode, type IdentityValidation, type InferArgs, type InferEnv, type InferIdentity, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, 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, defineIdentity, defineMigration, defineMutator, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineShape, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, httpAction, httpRoute, httpRouter, initLunora, installPlugins, isSafeHeaderValue, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules };
2268
+ export { type ActionBuilder, type ActionCtx, type AggregateIndexDefinition, type AggregateIndexOptions, type AggregateOp, type ArgsValidator, type Component, type ComponentFunctions, type CreateOptions, type DataModelInit, type DefineComponentOptions, type DefineIdentityOptions, type DefinePluginOptions, type DefinePolicyInput, type DefinePresenceOptions, type DefineStorageRuleInput, type DurableObjectJurisdiction, type EmptyArgs, type EnvAccessor, type EnvKeyFailure, type EnvShape, type ExposeConfig, 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 IdentityContract, type IdentityRejectMode, type IdentityValidation, type InferArgs, type InferEnv, type InferIdentity, type InlineAggregateIndexOptions, type InlineRankIndexOptions, type InternalActionBuilder, type InternalMutationBuilder, type InternalQueryBuilder, type LifecycleEvent, type LifecycleHandler, type LunoraBuilders, LunoraEnvError, LunoraError, 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, allowAll, asBucketStorage, bindOrm, bindTableFacade, buildRlsReadRegistry, composePluginMiddleware, composeShapeReadWhere, createPolicyDsl, createSecrets, defineAggregateIndex, defineComponent, defineEnv, defineIdentity, defineMigration, defineMutator, definePermission, definePlugin, definePolicies, definePolicy, definePresence, defineRankIndex, defineRole, defineSchema, defineSchemaExtension, defineShape, defineStorageRule, defineStorageRules, defineTable, defineVectorIndex, deny, httpAction, httpRoute, httpRouter, initLunora, installPlugins, isDeny, isSafeHeaderValue, mask, mergeSchemaExtension, onConnect, onDisconnect, presenceExtension, protectPublic, redactSecrets, rls, serveStorageObject, storageRules, toWhereInput };
package/dist/index.mjs CHANGED
@@ -1,29 +1 @@
1
- export { default as asBucketStorage } from './packem_shared/asBucketStorage-Cnxd9y2q.mjs';
2
- export { initLunora } from './packem_shared/initLunora-D0Wuki7S.mjs';
3
- export { createSecrets } from './packem_shared/createSecrets-DwaR2rNG.mjs';
4
- export { LunoraEnvError, defineEnv, redactSecrets } from './packem_shared/LunoraEnvError-BGmd1Qs0.mjs';
5
- export { LunoraError } from './packem_shared/LunoraError-WbxmrpxR.mjs';
6
- export { bindOrm, bindTableFacade } from './packem_shared/bindOrm-CaY7Wq9Z.mjs';
7
- export { httpAction, httpRoute, httpRouter, isSafeHeaderValue, serveStorageObject } from './packem_shared/httpAction-DCXoYPIk.mjs';
8
- export { defineIdentity } from './packem_shared/defineIdentity-DiX4zM9x.mjs';
9
- export { onConnect, onDisconnect } from './packem_shared/onConnect-CIPXKPyw.mjs';
10
- export { defineMigration } from './packem_shared/defineMigration-Hx01yIht.mjs';
11
- export { defineMutator } from './packem_shared/defineMutator-EIXAWhs9.mjs';
12
- export { composePluginMiddleware, defineComponent, definePlugin, defineSchemaExtension, installPlugins, mergeSchemaExtension } from './packem_shared/composePluginMiddleware-z62dttBo.mjs';
13
- export { PRESENCE_DEFAULT_TTL_MS, PRESENCE_TABLE, definePresence, presenceExtension } from './packem_shared/PRESENCE_DEFAULT_TTL_MS-Cr0i4mTv.mjs';
14
- export { protectPublic } from './packem_shared/protectPublic-BlcGpiRc.mjs';
15
- export { defineAggregateIndex, defineRankIndex, defineSchema, defineTable, defineVectorIndex } from './packem_shared/defineAggregateIndex-cdo0g-un.mjs';
16
- export { defineShape } from './packem_shared/defineShape-C5scNOrf.mjs';
17
- export { anyApi } from './types.mjs';
18
- export { cronJobs } from '@lunora/scheduler';
19
- export { ValidationError, v } from '@lunora/values';
20
- export { buildRlsReadRegistry, composeShapeReadWhere } from './packem_shared/buildRlsReadRegistry-2uk_GfiH.mjs';
21
- export { createPolicyDsl, definePermission, definePolicies, definePolicy, defineRole } from './packem_shared/createPolicyDsl-By3QB4he.mjs';
22
- export { defineStorageRule, defineStorageRules } from './packem_shared/defineStorageRule-B5nL4Z1P.mjs';
23
- export { mask } from './packem_shared/mask-BepaW7YN.mjs';
24
- export { rls } from './packem_shared/rls-BaDQf7MG.mjs';
25
- export { storageRules } from './packem_shared/storageRules-6QxzDOcx.mjs';
26
-
27
- const VERSION = "0.0.0";
28
-
29
- export { VERSION };
1
+ import{default as t}from"./packem_shared/asBucketStorage-1pFfH-Tn.mjs";import{initLunora as i}from"./packem_shared/initLunora-CHh1EmR4.mjs";import{createSecrets as a}from"./packem_shared/createSecrets-CgVPiW2C.mjs";import{LunoraEnvError as d,defineEnv as m,redactSecrets as x}from"./packem_shared/LunoraEnvError-CgpI2Mm_.mjs";import{LunoraError as c}from"./packem_shared/LunoraError-LVhdU0Lo.mjs";import{bindOrm as u,bindTableFacade as E}from"./packem_shared/bindOrm-Bp9hsM2q.mjs";import{httpAction as g,httpRoute as R,httpRouter as P,isSafeHeaderValue as h,serveStorageObject as b}from"./packem_shared/httpAction-C14NuF3V.mjs";import{defineIdentity as A}from"./packem_shared/defineIdentity-B7gfAgxx.mjs";import{onConnect as L,onDisconnect as T}from"./packem_shared/onConnect-CEtRmUpJ.mjs";import{defineMigration as C}from"./packem_shared/defineMigration-Bfpwxv2f.mjs";import{defineMutator as M}from"./packem_shared/defineMutator-8Kz0j1Kt.mjs";import{composePluginMiddleware as _,defineComponent as k,definePlugin as N,defineSchemaExtension as O,installPlugins as w,mergeSchemaExtension as B}from"./packem_shared/composePluginMiddleware-COr09CXA.mjs";import{PRESENCE_DEFAULT_TTL_MS as W,PRESENCE_TABLE as j,definePresence as H,presenceExtension as J}from"./packem_shared/PRESENCE_DEFAULT_TTL_MS-CF_9uiu1.mjs";import{protectPublic as q}from"./packem_shared/protectPublic-BhKewPqm.mjs";import{defineAggregateIndex as G,defineRankIndex as K,defineSchema as Q,defineTable as X,defineVectorIndex as Y}from"./packem_shared/defineAggregateIndex-CYuH6IbJ.mjs";import{defineShape as $}from"./packem_shared/defineShape-CyuRfwHz.mjs";import{anyApi as oe}from"./types.mjs";import{cronJobs as te}from"@lunora/scheduler";import{ValidationError as ie,v as fe}from"@lunora/values";import{allowAll as pe,deny as de,isDeny as me,toWhereInput as xe}from"./packem_shared/allowAll-BnyNbJZT.mjs";import{buildRlsReadRegistry as ce,composeShapeReadWhere as le}from"./packem_shared/buildRlsReadRegistry-WdiqSj87.mjs";import{createPolicyDsl as Ee,definePermission as Se,definePolicies as ge,definePolicy as Re,defineRole as Pe}from"./packem_shared/createPolicyDsl-sV1swpkD.mjs";import{defineStorageRule as be,defineStorageRules as ye}from"./packem_shared/defineStorageRule-BDu01PUn.mjs";import{mask as Ie}from"./packem_shared/mask-C6Bi78qj.mjs";import{rls as Te}from"./packem_shared/rls-_iVsPvhX.mjs";import{storageRules as Ce}from"./packem_shared/storageRules-BptPZbi8.mjs";const e="0.0.0";export{d as LunoraEnvError,c as LunoraError,W as PRESENCE_DEFAULT_TTL_MS,j as PRESENCE_TABLE,e as VERSION,ie as ValidationError,pe as allowAll,oe as anyApi,t as asBucketStorage,u as bindOrm,E as bindTableFacade,ce as buildRlsReadRegistry,_ as composePluginMiddleware,le as composeShapeReadWhere,Ee as createPolicyDsl,a as createSecrets,te as cronJobs,G as defineAggregateIndex,k as defineComponent,m as defineEnv,A as defineIdentity,C as defineMigration,M as defineMutator,Se as definePermission,N as definePlugin,ge as definePolicies,Re as definePolicy,H as definePresence,K as defineRankIndex,Pe as defineRole,Q as defineSchema,O as defineSchemaExtension,$ as defineShape,be as defineStorageRule,ye as defineStorageRules,X as defineTable,Y as defineVectorIndex,de as deny,g as httpAction,R as httpRoute,P as httpRouter,i as initLunora,w as installPlugins,me as isDeny,h as isSafeHeaderValue,Ie as mask,B as mergeSchemaExtension,L as onConnect,T as onDisconnect,J as presenceExtension,q as protectPublic,x as redactSecrets,Te as rls,b as serveStorageObject,Ce as storageRules,xe as toWhereInput,fe as v};
@@ -0,0 +1,3 @@
1
+ import{LunoraError as d}from"@lunora/errors";import{optionalInner as v}from"@lunora/values";const y=[/^sk_/u,/^pk_/u,/^rk_/u,/^ghp_/u,/^gho_/u,/^ghs_/u,/^ghr_/u,/^github_pat_/u,/^xox[baprs]-/u,/^AKIA/u,/^AIza/u,/^Bearer\s/u],b=/[\w./+-]{24,}/gu,A=/^[\w./+-]+$/u,_=/\b(?:(?:sk|pk|rk|ghp|gho|ghs|ghr)_[\w./+-]*|github_pat_[\w./+-]*|xox[baprs]-[\w./+-]*)/gu,E=/\b(?:AKIA|AIza)[\w./+-]+|Bearer\s+[\w./+-]+/gu,$=/\b([a-z][\w.+-]*:\/\/[\w.%+-]+):[\w.%+-]+@/gu,l="[redacted]",h=/(?:KEY|PASSWORD|SECRET|TOKEN)$/u,I=r=>{if(y.some(t=>t.test(r)))return!0;const e=r.trim();return e.length>=24&&A.test(e)},x=/(["'])(?<inner>(?:\\.|(?!\1).)*)\1/gu,S=/\b(?<key>[A-Za-z_]\w*)\s*[=:]\s*\S+/gu,N=r=>{let e=r;return e=e.replaceAll(x,(t,...n)=>{const s=n.at(-1);return s?.inner!==void 0&&I(s.inner)?l:t}),e=e.replaceAll($,(t,n)=>`${n}:${l}@`),e=e.replaceAll(_,l),e=e.replaceAll(E,l),e=e.replaceAll(S,(t,...n)=>{const s=n.at(-1);return s?.key!==void 0&&h.test(s.key)?`${s.key}=${l}`:t}),e=e.replaceAll(b,l),e},L=(r,e,t)=>{const n=N(r);return typeof t=="string"&&t!==""&&h.test(e)?n.replaceAll(t,l):n};class f extends d{failures;constructor(e){const t=e.map(n=>` - ${n.key}: ${n.message}`).join(`
2
+ `);super("ENV_INVALID",`Invalid environment (${String(e.length)} key(s)):
3
+ ${t}`,{name:"LunoraEnvError"}),this.failures=e}}const K=new Set(["1","on","true","yes"]),O=new Set(["0","false","no","off"]),j=/^-?\d+$/u,m=r=>{if(r.kind!=="optional")return r.kind;const e=v(r);return e?m(e):r.kind},z=(r,e)=>{if(typeof e!="string")return e;switch(m(r)){case"bigint":return j.test(e.trim())?BigInt(e.trim()):e;case"boolean":{const t=e.trim().toLowerCase();return K.has(t)?!0:O.has(t)?!1:e}case"number":{const t=e.trim();if(t==="")return e;const n=Number(t);return Number.isNaN(n)?e:n}default:return e}},k=(r,e,t,n)=>{const s=t[r];if(s===void 0&&e.kind==="optional")return{ok:!0,value:void 0};const a=e.safeParse(z(e,s));return a.ok?{ok:!0,value:a.value}:(n.push({key:r,message:L(a.error.message,r,s)}),{ok:!1})},w=r=>{if(typeof r!="object"||r===null)throw new f([{key:"<env>",message:`expected an object, received ${r===null?"null":typeof r}`}]);return r},B=r=>{const e=Object.keys(r),t=new WeakMap,n=(s=>{const a=w(s);let i=t.get(a);i===void 0&&(i=new Map,t.set(a,i));const c=i,p=u=>{if(c.has(u))return c.get(u);const o=[],g=k(u,r[u],a,o);if(!g.ok)throw new f(o);return c.set(u,g.value),g.value};return new Proxy({},{get(u,o){if(!(typeof o!="string"||!(o in r)))return p(o)},getOwnPropertyDescriptor(u,o){if(typeof o=="string"&&o in r)return{configurable:!0,enumerable:!0,value:p(o),writable:!1}},has(u,o){return typeof o=="string"&&o in r},ownKeys(){return e}})});return n.parse=s=>{const a=w(s),i=[],c={};for(const p of e){const u=k(p,r[p],a,i);u.ok&&u.value!==void 0&&(c[p]=u.value)}if(i.length>0)throw new f(i);return c},n};export{f as LunoraEnvError,B as defineEnv,N as redactSecrets};
@@ -0,0 +1 @@
1
+ import{LunoraError as s}from"@lunora/errors";class u extends s{constructor(r,o,a){super(r,o,{data:a})}}export{u as LunoraError};
@@ -0,0 +1 @@
1
+ import{v as o}from"@lunora/values";import{initLunora as E}from"./initLunora-CHh1EmR4.mjs";import{LunoraError as p}from"./LunoraError-LVhdU0Lo.mjs";import{onDisconnect as v}from"./onConnect-CEtRmUpJ.mjs";import{defineSchemaExtension as q,defineComponent as R}from"./composePluginMiddleware-COr09CXA.mjs";import{defineTable as _}from"./defineAggregateIndex-CYuH6IbJ.mjs";const D=3e4,y=4096,l="presence",h="present",c=`${l}_${h}`,M=q(l,{tables:{[h]:_({data:o.optional(o.record(o.string(),o.any())),lastSeen:o.number(),roomId:o.string(),sessionId:o.string(),userId:o.optional(o.string())}).index("byRoomSession",["roomId","sessionId"]).index("byRoom",["roomId"])}}),{mutation:b,query:T}=E.dataModel().create(),C=(u={})=>{const m=u.ttlMs??D,f=Math.max(0,Math.min(u.disconnectGraceMs??0,m)),w=b.input({data:o.optional(o.record(o.string(),o.any())),roomId:o.string(),sessionId:o.string()}).mutation(async({args:t,ctx:s})=>{const r=Date.now(),i=s.auth.userId??void 0;if(t.data!==void 0&&new TextEncoder().encode(JSON.stringify(t.data)).length>y)throw new p("BAD_REQUEST",`presence data exceeds the ${String(y)}-byte limit`);const e=await s.db.query(c).withIndex("byRoomSession",n=>n.eq("roomId",t.roomId).eq("sessionId",t.sessionId)).first();if(e&&(e.userId??void 0)!==i)throw new p("FORBIDDEN","presence heartbeat denied: this (roomId, sessionId) is held by another identity");const a={lastSeen:r,roomId:t.roomId,sessionId:t.sessionId,...t.data===void 0?{}:{data:t.data},...i===void 0?{}:{userId:i}};return await(e?s.db.patch(e._id,a):s.db.insert(c,a)),{lastSeen:r}}),S=T.input({roomId:o.string()}).query(async({args:t,ctx:s})=>{const r=Date.now()-m,i=(await s.db.query(c).withIndex("byRoom",n=>n.eq("roomId",t.roomId)).collect()).filter(n=>n.lastSeen>r).toSorted((n,d)=>d.lastSeen-n.lastSeen),e=new Set,a=[];for(const n of i){const d=n.userId;if(d!==void 0){if(e.has(d))continue;e.add(d)}const I={lastSeen:n.lastSeen,roomId:n.roomId};d!==void 0&&(I.userId=d),n.data!==void 0&&(I.data=n.data),a.push(I)}return a}),g={...b.input({roomId:o.string()}).mutation(async({args:t,ctx:s})=>{const r=Date.now()-m,i=await s.db.query(c).withIndex("byRoom",e=>e.eq("roomId",t.roomId)).filter(e=>e.lastSeen<=r).collect();return await Promise.all(i.map(e=>s.db.delete(e._id))),{deleted:i.length}}),visibility:"internal"},x=v(async(t,s)=>{const r=s.context?.roomId,i=s.context?.sessionId;if(typeof r!="string"||typeof i!="string")return;const e=await t.db.query(c).withIndex("byRoomSession",d=>d.eq("roomId",r).eq("sessionId",i)).first();if(!e)return;const a=s.userId??void 0;if((e.userId??void 0)!==a)return;if(f===0){await t.db.delete(e._id);return}const n=Math.min(e.lastSeen,Date.now()+f-m);await t.db.patch(e._id,{lastSeen:n})});return R(l,{extension:M,functions:{disconnect:x,heartbeat:w,listPresent:S,sweep:g}})};export{D as PRESENCE_DEFAULT_TTL_MS,c as PRESENCE_TABLE,C as definePresence,M as presenceExtension};
@@ -0,0 +1 @@
1
+ const t=()=>({OR:[]}),a=()=>({}),r=s=>Array.isArray(s.OR)&&s.OR.length===0&&Object.keys(s).length===1,l=s=>s===!0||s===void 0?a():s===!1?t():s;export{a as allowAll,t as deny,r as isDeny,l as toWhereInput};
@@ -0,0 +1 @@
1
+ const n=u=>{const t=u??{};if(typeof t.bucket=="function")return t;const e={...t,bucketName:"default"};return e.bucket=()=>e,e};export{n as default};
@@ -0,0 +1 @@
1
+ import{LunoraError as o}from"@lunora/errors";const c=e=>typeof e=="object"&&e!==null&&e.code==="CONFLICT"&&e.kind==="unique",l=(e,a,n)=>{const i=typeof a=="string"?[a]:a;if(i.length===0)throw new o("INTERNAL",`ctx.db.${e}.upsert: "target" must name at least one field`);const t={};for(const r of i){if(!(r in n))throw new o("INTERNAL",`ctx.db.${e}.upsert: target field "${r}" is missing from the create document`);t[r]=n[r]}return t},w=(e,a)=>{const n=async(t,r)=>{if(r?.skipDuplicates!==!0)return e.insert(a,t);try{return await e.insert(a,t)}catch(s){if(c(s))return null;throw s}},i=async({create:t,target:r,update:s})=>{const h=l(a,r,t),d=await e.findFirst(a,{where:h});return d&&typeof d._id=="string"?(await e.patch(d._id,s??t,a),{created:!1,id:d._id}):{created:!0,id:await e.insert(a,t)}};return{aggregate:t=>e.aggregate(a,t),count:t=>e.count(a,t),delete:t=>e.delete(t,a),deleteMany:(t,r)=>{if(Array.isArray(t)){if(e.deleteMany===void 0)throw new o("INTERNAL",`ctx.db.${a}.deleteMany is unavailable: this writer has no batch delete`);return e.deleteMany(t,r,a)}if(e.deleteWhere===void 0)throw new o("INTERNAL",`ctx.db.${a}.deleteMany({ where }) is unavailable: this writer has no where-based delete`);const s=t;return e.deleteWhere(a,s.where,{limit:s.limit})},exists:async t=>await e.findFirst(a,t===void 0?void 0:{where:t})!==null,findFirst:t=>e.findFirst(a,t),findFirstOrThrow:t=>e.findFirstOrThrow(a,t),findMany:t=>e.findMany(a,t),get:t=>e.get(t,a),groupBy:t=>e.groupBy(a,t),hardDelete:t=>e.delete(t,a,{hard:!0}),insert:n,insertMany:(t,r)=>{if(e.insertMany===void 0)throw new o("INTERNAL",`ctx.db.${a}.insertMany is unavailable: this writer has no batch insert`);return e.insertMany(a,t,r)},patch:(t,r)=>e.patch(t,r,a),patchMany:(t,r)=>{if(Array.isArray(t)){if(e.patchMany===void 0)throw new o("INTERNAL",`ctx.db.${a}.patchMany is unavailable: this writer has no batch patch`);return e.patchMany(t.map(h=>({id:h.id,patch:h.values})),r,a)}if(e.patchWhere===void 0)throw new o("INTERNAL",`ctx.db.${a}.patchMany({ where, values }) is unavailable: this writer has no where-based patch`);const s=t;return e.patchWhere(a,{patch:s.values,where:s.where},{limit:s.limit})},rank:(t,r)=>e.rank(a,t,r),rankPage:(t,r)=>e.rankPage(a,t,r),replace:(t,r)=>e.replace(t,r,a),restore:async t=>{if(!e.restore)throw new o("INTERNAL",`ctx.db.${a}.restore is unavailable: this writer has no restore (is the table .softDelete()?)`);await e.restore(t,a)},upsert:i,upsertMany:async({rows:t,target:r})=>{const s=[];for(const h of t)s.push(await i({create:h.create,target:r,update:h.update}));return s},withGeoIndex:(t,r)=>e.query(a).withGeoIndex(t,r),withSearchIndex:(t,r)=>e.query(a).withSearchIndex(t,r)}},p=e=>{const a=n=>{const i=e[n];if(!i)throw new o("INTERNAL",`unknown table: ${n}`);return i};return{delete:(n,i)=>a(n).delete(i),insert:n=>({values:i=>a(n).insert(i)}),query:e,replace:(n,i)=>({with:t=>a(n).replace(i,t)}),update:(n,i)=>({set:t=>a(n).patch(i,t)})}};export{p as bindOrm,w as bindTableFacade};
@@ -0,0 +1 @@
1
+ import{indexRolePermissions as f,computeReadBaseWhere as h,permissionName as d}from"./rls-_iVsPvhX.mjs";import{l as u}from"./policy-tag-Dprt9JWo.mjs";import{deny as p}from"./allowAll-BnyNbJZT.mjs";const c=p(),b=t=>{const e=t?.rls?.tags;if(e)return e;const o=u(t);return o?[o]:[]},g=(t,e)=>{const o=f(e.roles),r=new Map,n=new Map;for(const s of e.policies){if(s.on!=="read")continue;const a=r.get(s.table)??new Set;if(a.has(s.when))continue;a.add(s.when),r.set(s.table,a);const i=n.get(s.table)??[];i.push(s),n.set(s.table,i)}for(const[s,a]of n){const i=t.get(s)??[];i.push({policies:a,rolePermissions:o}),t.set(s,i)}},l=t=>{const e=t.OR;return Array.isArray(e)&&e.length===0&&Object.keys(t).length===1},m=(t,e)=>!t||Object.keys(t).length===0?e:l(t)||Object.keys(e).length===0?t:{AND:[t,e]},y=(t,e)=>{const o=new Set;for(const r of e.roles)for(const n of t.rolePermissions.get(r)??[])o.add(n);return h(t.policies,{auth:{can:r=>o.has(d(r)),identity:e.identity,roles:e.roles,userId:e.userId},ctx:e.ctx})},R=(t,e)=>{const o=t.byTable.get(e.table);if(!o||o.length===0)return e.rlsRequired&&!e.tablePublic?c:void 0;const r=[];for(const n of o){const s=y(n,e);if(s===void 0)return;l(s)||r.push(s)}return r.length===0?c:r.length===1?r[0]:{OR:r}},x=t=>{const e=new Map,o=new Set;for(const r of t)for(const n of b(r))o.has(n)||(o.add(n),g(e,n));return{byTable:e}},S=(t,e)=>m(R(t,e),e.shapeWhere);export{x as buildRlsReadRegistry,S as composeShapeReadWhere};
@@ -0,0 +1 @@
1
+ import{LunoraError as x}from"@lunora/errors";import{l as h}from"./run-middleware-BeEEqmdE.mjs";const l=(n,e)=>`${n}_${e}`,m=(n,e,t)=>t.has(n)?l(e,n):n,b=(n,e,t,s)=>{const i=l(e,s),d=o=>o===""?i:m(o,e,t),a={};for(const[o,f]of Object.entries(n.relationMap))a[o]={...f,table:m(f.table,e,t)};const c=n.aggregateIndexes.map(o=>({...o,on:d(o.on)})),r=n.rankIndexes.map(o=>({...o,on:d(o.on)}));return{...n,aggregateIndexes:c,rankIndexes:r,relationMap:a}},g=(n,e)=>{if(!n)throw new x("INTERNAL","defineSchemaExtension: `key` is required and must be a non-empty string");return{key:n,tables:e.tables,...e.vectorIndexes?{vectorIndexes:e.vectorIndexes}:{}}},u=((n,e)=>{if(!n)throw new x("INTERNAL","definePlugin: `key` is required and must be a non-empty string");if(e.extension&&e.extension.key!==n)throw new x("INTERNAL",`definePlugin("${n}"): extension key "${e.extension.key}" does not match plugin key`);return{key:n,...e.extension?{extension:e.extension}:{},...e.middleware?{middleware:e.middleware}:{}}}),k=(n,e)=>({...u(n,{...e.extension?{extension:e.extension}:{},...e.middleware?{middleware:e.middleware}:{}}),functions:e.functions??{}}),w=(n,e)=>{const{key:t}=e,s=new Set(Object.keys(e.tables)),i={...n.tables};for(const[a,c]of Object.entries(e.tables)){const r=l(t,a);if(Object.hasOwn(i,r))throw new x("INTERNAL",`defineSchema(...).extend("${t}"): table "${r}" already exists in the base schema — another extension with the same key already contributed it`);i[r]=b(c,t,s,a)}const d={...n.vectorIndexes};if(e.vectorIndexes)for(const[a,c]of Object.entries(e.vectorIndexes)){const r=l(t,a);if(Object.hasOwn(d,r))throw new x("INTERNAL",`defineSchema(...).extend("${t}"): vector index "${r}" already exists in the base schema — another extension with the same key already contributed it`);d[r]={...c,table:m(c.table,t,s)}}return{rlsMode:n.rlsMode,tables:i,vectorIndexes:d}},p=(n,e)=>{let t=n;for(const s of e)s.extension&&(t=w(t,s.extension));return t},E=n=>{const e=n.map(t=>t.middleware).filter(t=>t!==void 0);return(async({ctx:t,next:s})=>h(e,t,i=>s({ctx:i})))};export{E as composePluginMiddleware,k as defineComponent,u as definePlugin,g as defineSchemaExtension,p as installPlugins,w as mergeSchemaExtension};
@@ -0,0 +1 @@
1
+ import{LunoraError as r}from"@lunora/errors";const l=e=>({on:e.on,table:e.table,when:e.when}),s=()=>e=>({on:e.on,table:e.table,when:e.when}),c=(e,n={})=>({name:e,...n}),d=e=>{const n=new Map;for(const o of e){const i=JSON.stringify([o.table,o.on]),t=n.get(i)??new Set;if(t.has(o.when))throw new r("INTERNAL",`definePolicies: duplicate policy for (table "${o.table}", on "${o.on}") — the same decision function is registered more than once. Multiple distinct policies per (table, on) are allowed (reads OR, writes AND); remove the duplicate.`);t.add(o.when),n.set(i,t)}return e},f=(e,n={})=>({name:e,...n});export{s as createPolicyDsl,c as definePermission,d as definePolicies,l as definePolicy,f as defineRole};
@@ -0,0 +1 @@
1
+ import{LunoraError as n}from"@lunora/errors";const o=["put","list","delete","getWithMetadata","head","createMultipartUpload","idFromName","newUniqueId","getByName","send","sendBatch","writeDataPoint","create","createBatch"],a=t=>{if(typeof t!="object"||t===null)return!1;const e=t;return typeof e.get!="function"?!1:!o.some(r=>typeof e[r]=="function")},c=t=>({get:async e=>{const r=t[e];if(!a(r))throw new n("INTERNAL",`ctx.secrets: no Secrets Store binding named "${e}". Add a \`secrets_store_secrets[]\` entry (binding "${e}", pointing at your store + secret) to wrangler.jsonc — \`ctx.secrets\` reads a Secrets Store binding, not a plain \`.dev.vars\` value.`);return r.get()}});export{c as createSecrets};
@@ -0,0 +1 @@
1
+ import{LunoraError as s}from"@lunora/errors";import{isOrWrapsFromValidator as B,v as E}from"@lunora/values";import{mergeSchemaExtension as A}from"./composePluginMiddleware-COr09CXA.mjs";const L={many:(e,r)=>({field:r.field,kind:"many",references:r.references??"_id",table:e}),one:(e,r)=>({field:r.field,kind:"one",onDelete:r.onDelete,references:r.references??"_id",table:e})},u=(e,r,a)=>({handler:a,op:r,timing:e}),R=()=>({afterDelete:e=>u("after","delete",e),afterInsert:e=>u("after","insert",e),afterUpdate:e=>u("after","update",e),beforeDelete:e=>u("before","delete",e),beforeInsert:e=>u("before","insert",e),beforeUpdate:e=>u("before","update",e)}),F=e=>{const r={...e};for(const[t,n]of Object.entries(r))if(B(n))throw new s("INTERNAL",`defineTable: column "${t}" uses v.from() which is args-only — table columns need a concrete v.* type`);const a=[],o=[],d=[],h=[],g={},b=[],p={},$=R(),y=[];let f={kind:"root"},m=!1,w=!1,I,x,N,v;const i={aggregateIndex(t,n){const l=n?.op??"count";if(l!=="count"&&!n?.field)throw new s("INTERNAL",`aggregateIndex "${t}": op "${l}" requires a "field"`);return a.push({by:n?.by,field:n?.field,name:t,on:"",op:l,where:n?.where}),i},get aggregateIndexes(){return a},get externalSource(){return v},externallyManaged(){return m=!0,i},geoIndex(t,n){return o.push({field:n.field,name:t,precision:n.precision}),i},get geoIndexes(){return o},global(t){return f={backend:t?.backend??"d1",kind:"global"},i},get isExternallyManaged(){return m},get isPublic(){return w},index(t,n,l){return d.push({fields:n,name:t,unique:l?.unique??!1}),i},get indexes(){return d},ownedBy(t){return I=t,i},get ownerField(){return I},public(){return w=!0,i},rankIndex(t,n){if(!n.sortBy||n.sortBy.length===0)throw new s("INTERNAL",`rankIndex "${t}": "sortBy" is required and must list at least one key`);const l=n.sortBy.map(k=>({direction:k.direction??"asc",field:k.field}));return h.push({name:t,on:"",partitionBy:n.partitionBy,sortBy:l,where:n.where}),i},get rankIndexes(){return h},get relationMap(){return g},relations(t){return Object.assign(g,t(L)),i},searchIndex(t,n){return b.push({field:n.field,filterFields:n.filterFields,name:t}),i},get searchIndexes(){return b},shape:r,shardBy(t){return f={field:t,kind:"shardBy"},i},get shardMode(){return f},get softDeleteMode(){return x},source(t){if(!t.binding)throw new s("INTERNAL","source: `binding` is required (the wrangler Hyperdrive binding name)");if(!t.query)throw new s("INTERNAL","source: `query` is required (the tenant-membership SQL)");return v=t,m=!0,i},softDelete(t){const n=t?.field??"deletedAt";return x={field:n},n in r||(r[n]=E.optional(E.number().nullable())),i},get triggerMap(){return p},triggers(t){return Object.assign(p,t($)),i},ttl(t,n){return N={after:n?.after,field:t},i},get ttlPolicy(){return N},get vectorIndexes(){return y},vectorize(t,n){return y.push({dimensions:n.dimensions,embed:n.embed,field:t,metadata:n.metadata,metric:n.metric,name:n.index}),i}};return i},H=e=>({dimensions:e.dimensions,embed:e.embed,kind:"vectorIndex",metadata:e.metadata,metric:e.metric,select:e.source.select,table:e.source.table}),K=(e,r)=>{const a=r.op??"count";if(a!=="count"&&!r.field)throw new s("INTERNAL",`aggregateIndex "${e}": op "${a}" requires a "field"`);return{by:r.by,field:r.field,name:e,on:r.on,op:a,where:r.where}},V=(e,r)=>{if(!r.sortBy||r.sortBy.length===0)throw new s("INTERNAL",`rankIndex "${e}": "sortBy" is required and must list at least one key`);const a=r.sortBy.map(o=>({direction:o.direction??"asc",field:o.field}));return{name:e,on:r.table,partitionBy:r.partitionBy,sortBy:a,where:r.where}},c=e=>({...e,extend(r){return c(A(e,r))},jurisdiction(r){return c(e)},rls(r){return c({...e,rlsMode:r})}}),T=e=>{for(const[r,a]of Object.entries(e)){for(const o of a.aggregateIndexes)o.on===""&&(o.on=r);for(const o of a.rankIndexes)o.on===""&&(o.on=r)}},q=(e,r,a)=>{for(const o of Object.values(r)){const d=e[o.on];if(!d)throw new s("INTERNAL",`defineAggregateIndex "${o.name}": unknown table "${o.on}"`);d.aggregateIndexes.push(o)}for(const o of Object.values(a)){const d=e[o.on];if(!d)throw new s("INTERNAL",`defineRankIndex "${o.name}": unknown table "${o.on}"`);d.rankIndexes.push(o)}},S=e=>{if(e.cursor)return"cursor";if(e.reconcileEveryMs!==void 0)return"reconcileEveryMs";if(e.softDeleteColumn!==void 0)return"softDeleteColumn"},M=(e,r)=>{const a=r.mode==="incremental";if(r.mode!==void 0&&r.mode!=="full-pull"&&!a)throw new s("INTERNAL",`defineSchema: table "${e}" uses \`mode: ${JSON.stringify(r.mode)}\` — supported modes are "full-pull" (default) and "incremental".`);if(!a){const o=S(r);if(o)throw new s("INTERNAL",`defineSchema: table "${e}" sets \`${o}\` but is not \`mode: "incremental"\` — that knob only applies to incremental ingest. Set \`mode: "incremental"\` or remove \`${o}\`.`);return}if(!r.cursor?.column||!r.cursor.query)throw new s("INTERNAL",`defineSchema: table "${e}" is \`mode: "incremental"\` but has no \`cursor\` — add \`cursor: { column: "updated_at", query: "… WHERE … > $N" }\` binding the watermark as the trailing parameter.`);if(r.reconcileEveryMs===void 0&&r.softDeleteColumn===void 0)throw new s("INTERNAL",`defineSchema: table "${e}" is \`mode: "incremental"\` with no delete-visibility path — an incremental pull never sees upstream deletes, so it would accumulate phantom rows. Add \`reconcileEveryMs\` (a periodic full-pull sweep) or \`softDeleteColumn\` (an upstream tombstone column).`)},D=e=>{for(const[r,a]of Object.entries(e)){const o=a.externalSource;if(o){if(a.shardMode.kind==="global")throw new s("INTERNAL",`defineSchema: table "${r}" cannot be both .source() and .global() — a sourced table materializes into a shard DO's SQLite, a global table lives in the external tier`);if(a.shardMode.kind==="shardBy"&&!o.tenantBy)throw new s("INTERNAL",`defineSchema: sourced + .shardBy() table "${r}" 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.`);M(r,o)}}},_=(e,r={},a={},o={})=>(T(e),q(e,a,o),D(e),c({tables:e,vectorIndexes:r}));export{K as defineAggregateIndex,V as defineRankIndex,_ as defineSchema,F as defineTable,H as defineVectorIndex};
@@ -0,0 +1 @@
1
+ import{LunoraError as d}from"@lunora/errors";import{parseValidatorMap as s,ValidationError as l}from"@lunora/values";const u=new Set(["array","bigint","boolean","bytes","date","null","number","object","optional","record","timestamp"]),I=(n,o={})=>{const r=n,e=r.userId;if(e===void 0||u.has(e.kind))throw new d("INTERNAL","defineIdentity: the claim map must declare a required string `userId` validator (e.g. `v.string()` or `v.id(...)`)");const a=o.onInvalid??"anonymous";return{__lunoraIdentity:!0,claims:r,onInvalid:a,validate:i=>{try{return s(r,i,"identity"),{ok:!0}}catch(t){return{error:t instanceof l?t.message:String(t),ok:!1}}}}};export{I as defineIdentity};
@@ -0,0 +1 @@
1
+ import{LunoraError as i}from"@lunora/errors";const n=r=>{if(r.id.trim()==="")throw new i("INTERNAL","defineMigration: `id` must be a non-empty string");return{__lunoraMigration:!0,...r}};export{n as defineMigration};
@@ -0,0 +1 @@
1
+ import{s as e}from"./functions-CDC08CWY.mjs";const s=r=>({__lunoraMutator:!0,...r,handler:async(n,t)=>{const o=e(r.args??{},t);return r.server(n,o)},kind:"mutation"});export{s as defineMutator};
@@ -0,0 +1 @@
1
+ import{LunoraError as t}from"@lunora/errors";import{s}from"./functions-CDC08CWY.mjs";import{toWhereInput as w,deny as u}from"./allowAll-BnyNbJZT.mjs";const p=e=>e?.auth?.userId??void 0,b=e=>{if(e.table.trim()==="")throw new t("INTERNAL","defineShape: `table` must be a non-empty string");if(e.columns?.length===0)throw new t("INTERNAL","defineShape: `columns` must list at least one column when provided");if(!e.where&&e.owner===void 0)throw new t("INTERNAL",`defineShape: shape on table "${e.table}" needs a \`where\` predicate or an \`owner\` (\`owner: true\` uses the table's .ownedBy(field), \`owner: "field"\` names the column) — a shape with neither would replicate the whole table`);return{__lunoraShape:!0,...e,compileWhere:(n,h,d)=>{const l=s(e.args??{},h),r=e.where?w(e.where(n,l)):void 0;if(e.owner===void 0)return r;const o=e.owner===!0?d?.ownerField:e.owner;if(o===void 0||o==="")throw new t("INTERNAL",`defineShape: shape on table "${e.table}" declares \`owner: true\` but the table has no \`.ownedBy(field)\` — add it to the table, or name the column directly with \`owner: "field"\``);const a=p(n);if(a===void 0)return u();const i={[o]:a};return r===void 0?i:{AND:[i,r]}}}};export{b as defineShape};
@@ -0,0 +1 @@
1
+ import{LunoraError as i}from"@lunora/errors";const c=r=>({bucket:r.bucket,on:r.on,prefix:r.prefix,when:r.when}),f=r=>{const n=new Map;for(const e of r){const t=JSON.stringify([e.bucket,e.on,e.prefix]),o=n.get(t)??new Set;if(o.has(e.when))throw new i("INTERNAL",`defineStorageRules: duplicate rule for (bucket "${e.bucket}", on "${e.on}"${e.prefix===void 0?"":`, prefix "${e.prefix}"`}) — the same decision function is registered more than once. Multiple distinct rules per (bucket, on) are allowed (they OR); remove the duplicate.`);o.add(e.when),n.set(t,o)}return r};export{c as defineStorageRule,f as defineStorageRules};
@@ -0,0 +1 @@
1
+ import{parseValidatorMap as o}from"@lunora/values";const s=(r,a)=>o(r,a,"args");export{s};
@@ -0,0 +1,4 @@
1
+ import{toErrorBody as E}from"@lunora/errors";import{parseValidatorMap as R,ValidationError as v}from"@lunora/values";import{Hono as P}from"hono";import{LunoraError as p}from"./LunoraError-LVhdU0Lo.mjs";const H=e=>async t=>e(t.get("lunora"),t.req.raw),z=()=>{const e=new P;return e.use("*",async(t,a)=>{const r=t.env.__lunoraCtx;if(!r)throw new p("INTERNAL_SERVER_ERROR","HttpActionCtx was not injected — mount httpRouter() on createWorker(), which supplies it per request.");t.set("lunora",r),await a()}),e},k=e=>e.kind==="optional"?e._meta?.inner??e:e,y=(e,t)=>{switch(e){case"bigint":try{return BigInt(t)}catch{return t}case"boolean":return t==="true"||t==="1"?!0:t==="false"||t==="0"?!1:t;case"number":return t===""?Number.NaN:Number(t);default:return t}},_=(e,t,a)=>{const r=k(e);if(r.kind==="array"){const o=t.req.queries(a);if(o===void 0)return;const n=r._meta?.inner;return o.map(c=>y(n?.kind??"string",c))}const s=t.req.query(a);return s===void 0?void 0:y(r.kind,s)},S=(e,t)=>{const a={};for(const r of Object.keys(e)){const s=e[r];s&&(a[r]=_(s,t,r))}return R(e,a,"searchParams")},N=(e,t)=>{const a=t.req.param(),r={};for(const s of Object.keys(e)){const o=e[s];if(!o)continue;const n=a[s];r[s]=n===void 0?void 0:y(k(o).kind,n)}return R(e,r,"params")},x=async(e,t)=>{let a;try{a=await t.req.json()}catch{throw new p("BAD_REQUEST","Invalid JSON body")}if(typeof a!="object"||a===null||Array.isArray(a))throw new p("BAD_REQUEST","Expected a JSON object body");return R(e,a,"body")},A=(e,t)=>{try{return e.parse(t)}catch(a){throw a instanceof v?new p("INTERNAL_SERVER_ERROR",`Response did not match the declared output schema: ${a.message}`):a}},O=e=>{if(e instanceof v)return Response.json({code:"BAD_REQUEST",error:e.message},{status:400});if(e instanceof p){const{body:t,redacted:a,status:r}=E(e,{fallbackCode:"INTERNAL_SERVER_ERROR",redactedMessage:"Internal error"});return a&&console.error("[lunora] http action error (redacted on the wire):",e),Response.json({code:t.code,error:t.message},{status:r})}throw e},q=(e,t)=>async a=>{try{const r=a.get("lunora"),s=Object.keys(e.searchParams).length>0?S(e.searchParams,a):{},o=Object.keys(e.params).length>0?N(e.params,a):{},n=Object.keys(e.body).length>0?await x(e.body,a):{},c=await t({body:n,ctx:r,params:o,searchParams:s}),i=e.output?A(e.output,c):c,u={};e.cacheControl&&(u["cache-control"]=e.cacheControl),e.cacheTag&&(u["cache-tag"]=e.cacheTag),e.vary&&(u.vary=e.vary);const m=Object.keys(u).length>0;return i===void 0?new Response(null,{headers:m?u:void 0,status:204}):Response.json(i,{headers:m?u:void 0})}catch(r){return O(r)}},g=(e,t)=>{const a=JSON.stringify(e);return`${t?`event: ${t}
2
+ `:""}data: ${a}
3
+
4
+ `},C=(e,t)=>async a=>{let r,s;try{r=Object.keys(e.searchParams).length>0?S(e.searchParams,a):{},s=Object.keys(e.params).length>0?N(e.params,a):{}}catch(d){return O(d)}const o=a.get("lunora"),n=a.req.raw,c=new TextEncoder,i=new AbortController;if(n.signal.aborted)return i.abort(),new Response(new ReadableStream({start:d=>{d.close()}}),{headers:{"cache-control":"no-cache, no-transform","content-type":"text/event-stream; charset=utf-8","x-accel-buffering":"no"}});const u=()=>{i.abort()};n.signal.addEventListener("abort",u,{once:!0});const m=new ReadableStream({cancel(){n.signal.removeEventListener("abort",u),i.abort()},async start(d){try{const f=t({ctx:o,params:s,request:n,searchParams:r,signal:i.signal});for await(const b of f){if(i.signal.aborted)break;d.enqueue(c.encode(g(b)))}d.enqueue(c.encode(g({},"complete")))}catch(f){const{body:b,redacted:j}=E(f,{fallbackCode:"INTERNAL_SERVER_ERROR",redactedMessage:"Internal error"});j&&console.error("[lunora] unhandled stream handler error:",f),d.enqueue(c.encode(g({code:b.code,message:b.message},"error")))}finally{n.signal.removeEventListener("abort",u),d.close()}}}),T={"cache-control":"no-cache, no-transform","content-type":"text/event-stream; charset=utf-8","x-accel-buffering":"no"};return new Response(m,{headers:T})},l=e=>({body:t=>l({...e,body:{...e.body,...t}}),cacheControl:t=>l({...e,cacheControl:t}),cacheTag:t=>l({...e,cacheTag:t}),handler:t=>q(e,t),output:t=>l({...e,output:t}),params:t=>l({...e,params:{...e.params,...t}}),searchParams:t=>l({...e,searchParams:{...e.searchParams,...t}}),stream:t=>C(e,t),vary:t=>l({...e,vary:t})}),h=e=>t=>l({body:{},method:e,params:{},path:t,searchParams:{}}),U={delete:h("DELETE"),get:h("GET"),head:h("HEAD"),options:h("OPTIONS"),patch:h("PATCH"),post:h("POST"),put:h("PUT")},$=/^bytes=(\d*)-(\d*)$/,w=e=>e.startsWith('"')||e.startsWith('W/"')?e:`"${e}"`,I=e=>{for(let t=0;t<e.length;t+=1){const a=e.codePointAt(t);if(a===13||a===10||a===0)return!1}return!0},L=(e,t)=>{if(e===null)return{kind:"full"};const a=$.exec(e.trim());if(!a)return{kind:"full"};const r=a[1]??"",s=a[2]??"";if(r===""&&s==="")return{kind:"full"};let o,n;if(r===""){const c=Number(s);if(c===0)return{kind:"unsatisfiable"};o=Math.max(0,t-c),n=t-1}else o=Number(r),n=s===""?t-1:Math.min(Number(s),t-1);return o>n||o>=t?{kind:"unsatisfiable"}:{end:n,kind:"partial",start:o}},W=async(e,t,a)=>{const r=await e.storage.download(t);if(!r)return new Response("Not Found",{status:404});const s=r.httpMetadata?.contentType,o={"accept-ranges":"bytes","content-type":s!==void 0&&I(s)?s:"application/octet-stream",etag:w(r.etag)};r.sha256Base64!==void 0&&(o["repr-digest"]=`sha-256=:${r.sha256Base64}:`);const n=L(a.headers.get("range"),r.size);if(n.kind==="unsatisfiable")return r.body?.cancel().catch(()=>{}),new Response("Range Not Satisfiable",{headers:{"accept-ranges":"bytes","content-range":`bytes */${String(r.size)}`,"content-type":"text/plain; charset=utf-8",etag:w(r.etag)},status:416});if(n.kind==="full")return new Response(r.body,{headers:{...o,"content-length":String(r.size)},status:200});r.body?.cancel().catch(()=>{});const c=n.end-n.start+1,i=await e.storage.download(t,{range:{length:c,offset:n.start}});return i?new Response(i.body,{headers:{...o,"content-length":String(c),"content-range":`bytes ${String(n.start)}-${String(n.end)}/${String(r.size)}`},status:206}):new Response("Not Found",{status:404})};export{H as httpAction,U as httpRoute,z as httpRouter,I as isSafeHeaderValue,W as serveStorageObject};
@@ -0,0 +1 @@
1
+ import{s as c}from"./functions-CDC08CWY.mjs";import{l as g}from"./policy-tag-Dprt9JWo.mjs";import{l as p}from"./run-middleware-BeEEqmdE.mjs";const x=(r,e)=>p(r,e,a=>a),w=(r,e,a,t)=>async(i,o)=>{const d=c(r,o),n=await x(e,i),l=await a({args:d,ctx:n});return t?t.parse(l):l},y=(r,e,a)=>(t,i,o)=>{const d=c(r,i);return(async function*(){const n=await x(e,t),l=a({args:d,ctx:n,signal:o})[Symbol.asyncIterator]();try{for(;;){if(o.aborted)return;const u=await l.next();if(u.done||o.aborted)return;yield u.value}}finally{await l.return?.()}})()},m=r=>{const e=[];for(const a of r){const t=g(a);t&&e.push(t)}return e.length>0?{tags:e}:void 0},s=(r,e,a)=>({__lunoraProcedure:r,...a?{__lunoraVisibility:a}:{},input:t=>s(r,{...e,args:{...e.args,...t}},a),[r]:t=>{const i=m(e.middlewares);return{args:e.args,...e.expose?{expose:e.expose}:{},handler:w(e.args,e.middlewares,t,e.output),kind:r,...i?{rls:i}:{},...a?{visibility:a}:{},...e.x402?{x402:e.x402}:{}}},output:t=>s(r,{...e,output:t},a),...r==="query"?{stream:t=>{const i=m(e.middlewares);return{args:e.args,...e.expose?{expose:e.expose}:{},handler:y(e.args,e.middlewares,t),kind:"stream",...i?{rls:i}:{},...a?{visibility:a}:{},...e.x402?{x402:e.x402}:{}}}}:{},use:t=>s(r,{...e,middlewares:[...e.middlewares,t]},a),...a?{}:{expose:t=>s(r,{...e,expose:t},a)},...a?{}:{x402:t=>s(r,{...e,x402:t},a)}}),q={dataModel:()=>({create:r=>({action:s("action",{args:{},middlewares:[]}),internalAction:s("action",{args:{},middlewares:[]},"internal"),internalMutation:s("mutation",{args:{},middlewares:[]},"internal"),internalQuery:s("query",{args:{},middlewares:[]},"internal"),mutation:s("mutation",{args:{},middlewares:[]}),query:s("query",{args:{},middlewares:[]})})})};export{q as initLunora};
@@ -0,0 +1 @@
1
+ import{LunoraError as g}from"./LunoraError-LVhdU0Lo.mjs";import{bindOrm as N,bindTableFacade as x}from"./bindOrm-Bp9hsM2q.mjs";const S=a=>typeof a=="string"?a:a.name,I=a=>{const i=new Map;for(const s of a??[])i.set(s.name,new Set((s.permissions??[]).map(c=>S(c))));return i},M=a=>{let i=2166136261;for(let s=0;s<a.length;s+=1)i^=a.codePointAt(s)??0,i=Math.imul(i,16777619);return(i>>>0).toString(16).padStart(8,"0")},O=(a,i,s)=>{try{return a==="redact"?null:a==="hash"?i==null?i:M(typeof i=="string"?i:JSON.stringify(i)):a(i,s)}catch{return null}},h=(a,i,s)=>{const c={...a};for(const[f,w]of Object.entries(i))f in c&&(c[f]=O(w,a[f],{...s,column:f,row:a}));return c},m=(a,i,s)=>({...a,page:a.page.map(c=>h(c,i,s))}),A=(a,i,s,c)=>{if(typeof a!="function")return;const f=new Set,w=()=>new Proxy({},{get:()=>y=>(typeof y=="string"&&f.add(y),w())});a(w());for(const y of f)if(y in i)throw new g("MASK_UNSUPPORTED",`${c}() filtering "${s}" by masked column "${y}" is not supported`)},k=a=>{if(typeof a!="object"||a===null||Array.isArray(a))return!1;const i=a;return typeof i.findMany=="function"&&typeof i.withSearchIndex=="function"},v=(a,i,s)=>{const c=(t,r,n)=>({collect:async()=>(await t.collect()).map(e=>h(e,r,s)),filter:e=>c(t.filter(o=>e(h(o,r,s))),r,n),first:async()=>{const e=await t.first();return e?h(e,r,s):null},order:e=>c(t.order(e),r,n),paginate:async e=>m(await t.paginate(e),r,s),take:async e=>(await t.take(e)).map(o=>h(o,r,s)),unique:async()=>{const e=await t.unique();return e?h(e,r,s):null},withIndex:(e,o)=>(A(o,r,n,"withIndex"),c(t.withIndex(e,o),r,n)),withSearchIndex:(e,o)=>(A(o,r,n,"withSearchIndex"),c(t.withSearchIndex(e,o),r,n)),withGeoIndex:(e,o)=>c(t.withGeoIndex(e,o),r,n)}),f=async(t,r)=>{if(a.lookupById){const d=await a.lookupById(t,r);return d?{row:d.row,tableName:i.has(d.tableName)?d.tableName:void 0}:{row:null,tableName:void 0}}const n=await a.get(t,r);if(!n)return{row:null,tableName:void 0};let e;r===void 0?e=[...i.keys()]:i.has(r)?e=[r]:e=[];const o=await Promise.all(e.map(async d=>(await a.findFirst(d,{limit:1,where:{_id:t}}))?._id===t?d:void 0));return{row:n,tableName:o.find(d=>d!==void 0)}},w=(t,r,n)=>{const e=i.get(t);if(!e)return;const o=r.find(d=>typeof d=="string"&&d in e);if(o!==void 0)throw new g("MASK_UNSUPPORTED",`${n}() over masked column "${o}" on "${t}" is not supported`)},y=(t,r)=>{if(!(!t||typeof t!="object"||Array.isArray(t)))for(const[n,e]of Object.entries(t))if(n==="AND"||n==="OR"){if(Array.isArray(e))for(const o of e)y(o,r)}else n==="NOT"?y(e,r):n.startsWith("__")||r.add(n)},u=(t,r,n)=>{const e=i.get(t);if(!e||r===void 0)return;const o=new Set;y(r,o);for(const d of o)if(d in e)throw new g("MASK_UNSUPPORTED",`${n}() filtering "${t}" by masked column "${d}" is not supported`)},l=(t,r,n)=>{const e=i.get(t);if(!(!e||!Array.isArray(r))){for(const o of r)if(o&&typeof o=="object"&&!Array.isArray(o)){for(const d of Object.keys(o))if(d in e)throw new g("MASK_UNSUPPORTED",`${n}() ordering "${t}" by masked column "${d}" is not supported`)}}},p={...a,async deleteWhere(t,r,n){if(u(t,r,"deleteMany({ where })"),a.deleteWhere===void 0)throw new g("INTERNAL",`ctx.db.${t}.deleteMany({ where }) is unavailable: this writer has no where-based delete`);return a.deleteWhere(t,r,n)},async patchWhere(t,r,n){if(u(t,r.where,"patchMany({ where })"),a.patchWhere===void 0)throw new g("INTERNAL",`ctx.db.${t}.patchMany({ where }) is unavailable: this writer has no where-based patch`);return a.patchWhere(t,r,n)},aggregate(t,r){return w(t,[r.field],"aggregate"),u(t,r.where,"aggregate"),a.aggregate(t,r)},count(t,r){const n=r&&typeof r=="object"&&!Array.isArray(r)?r:void 0,e=n&&("where"in n||"baseWhere"in n||"restrictsCounts"in n)?n.where:r;return u(t,e,"count"),n&&u(t,n.baseWhere,"count"),a.count(t,r)},async findFirst(t,r){u(t,r?.where,"findFirst"),u(t,r?.baseWhere,"findFirst"),l(t,r?.orderBy,"findFirst");const n=await a.findFirst(t,r),e=i.get(t);return n&&e?h(n,e,s):n},async findFirstOrThrow(t,r){u(t,r?.where,"findFirstOrThrow"),u(t,r?.baseWhere,"findFirstOrThrow"),l(t,r?.orderBy,"findFirstOrThrow");const n=await a.findFirstOrThrow(t,r),e=i.get(t);return e?h(n,e,s):n},async findMany(t,r){u(t,r?.where,"findMany"),u(t,r?.baseWhere,"findMany"),l(t,r?.orderBy,"findMany");const n=await a.findMany(t,r),e=i.get(t);return e?m(n,e,s):n},async get(t,r){const{row:n,tableName:e}=await f(t,r),o=e===void 0?void 0:i.get(e);return!n||!o?n:h(n,o,s)},groupBy(t,r){return w(t,[...r.by,r.agg?.field],"groupBy"),u(t,r.where,"groupBy"),a.groupBy(t,r)},query(t){const r=a.query(t),n=i.get(t);return n?c(r,n,t):r},async rankPage(t,r,n){const e=await a.rankPage(t,r,n),o=i.get(t);return o?m(e,o,s):e}},b=p;for(const t of i.keys())k(a[t])&&(b[t]=x(p,t));return p},F=(a,i={})=>{const s=new Map(Object.entries(a)),c=I(i.roles);return async({ctx:f,next:w})=>{const y=f.auth??{},u=await y.getIdentity?.()??null,l=y.roles??[],p=new Set;for(const e of l)for(const o of c.get(e)??[])p.add(o);const b={auth:{can:e=>p.has(S(e)),identity:u,roles:l,userId:y.userId??null},ctx:f};if(i.bypass?.(b))return w();const t=v(f.db,s,b),r={db:t},{orm:n}=f;return n!==null&&typeof n=="object"&&(r.orm=N(t)),w({ctx:r})}};export{F as mask};
@@ -0,0 +1 @@
1
+ const i=(n,c)=>({args:{},handler:(t,e)=>c(t,e),kind:"mutation",lifecycle:n,visibility:"internal"}),o=n=>i("connect",n),s=n=>i("disconnect",n);export{o as onConnect,s as onDisconnect};
@@ -0,0 +1 @@
1
+ const o=Symbol.for("lunora.rls.middleware-policies"),l=(e,r)=>(Object.defineProperty(e,o,{configurable:!0,enumerable:!1,value:r}),e),t=e=>{if(!(e===null||typeof e!="function"&&typeof e!="object"))return e[o]};export{t as l,l as r};
@@ -0,0 +1 @@
1
+ import{l as n}from"./run-middleware-BeEEqmdE.mjs";const e=t=>{const r=[t.rateLimit,t.captcha,...t.use??[]].filter(c=>c!==void 0);return async({ctx:c,next:o})=>n(r,c,i=>o({ctx:i}))};export{e as protectPublic};
@@ -0,0 +1 @@
1
+ import{LunoraError as p}from"./LunoraError-LVhdU0Lo.mjs";import{bindOrm as x,bindTableFacade as P}from"./bindOrm-Bp9hsM2q.mjs";import{r as U}from"./policy-tag-Dprt9JWo.mjs";import{deny as j}from"./allowAll-BnyNbJZT.mjs";const S=500,N=(t,r,s)=>{const i=r??S;if(t>i)throw new p("BAD_REQUEST",`${s}: batch of ${String(t)} exceeds the limit of ${String(i)} (raise options.limit or chunk the call)`)},F=j(),C=Symbol.for("lunora.ctxdb.rls-unwrap"),$=t=>{const r=new Map;for(const s of t){const i=r.get(s.table)??[];i.push(s),r.set(s.table,i)}return r},q=(t,r)=>{const s=[];let i=!1;for(const u of t){if(u.on!=="read")continue;const c=u.when(r);if(c!==void 0){if(c===!0){i=!0;break}c!==!1&&s.push(c)}}if(!i)return s.length===0?F:s.length===1?s[0]:{OR:s}},D=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),L=["contains","eq","gt","gte","in","isNull","lt","lte","ne","notIn"],m=t=>{const r=typeof t;return r==="number"||r==="string"||r==="bigint"},z=(t,r)=>!("lt"in r&&(!m(t)||!m(r.lt)||t>=r.lt)||"lte"in r&&(!m(t)||!m(r.lte)||t>r.lte)||"gt"in r&&(!m(t)||!m(r.gt)||t<=r.gt)||"gte"in r&&(!m(t)||!m(r.gte)||t<r.gte)),Q=(t,r)=>{if("in"in r){const s=r.in;if(!Array.isArray(s)||!s.includes(t))return!1}if("notIn"in r){const s=r.notIn;if(Array.isArray(s)&&s.includes(t))return!1}if("contains"in r){const s=r.contains;if(typeof t!="string"||typeof s!="string"||!t.includes(s))return!1}return!("isNull"in r&&r.isNull===!0!=(t==null))},G=(t,r)=>"eq"in r&&t!==r.eq||"ne"in r&&t===r.ne?!1:Q(t,r)&&z(t,r),H=(t,r,s,i)=>r==="AND"?Array.isArray(s)&&s.every(u=>i(t,u)):r==="OR"?Array.isArray(s)&&s.some(u=>i(t,u)):!i(t,s??{}),I=t=>t==="AND"||t==="OR"||t==="NOT",J=t=>D(t)&&Object.keys(t).every(r=>L.includes(r)),K=["every","is","isNot","none","some"],V=t=>D(t)&&Object.keys(t).length>0&&Object.keys(t).every(r=>K.includes(r)),R=t=>Object.keys(t).some(r=>{const s=t[r];return I(r)?r==="NOT"?R(s??{}):Array.isArray(s)&&s.some(i=>R(i??{})):V(s)}),k=(t,r)=>{for(const s of Object.keys(r)){const i=r[s];if(I(s)){if(!H(t,s,i,k))return!1;continue}const u=t[s];if(J(i)){if(!G(u,i))return!1;continue}if(u!==i)return!1}return!0},X=(t,r,s)=>{const i=t.when({...r,row:s});if(i===void 0||i===!0)return!0;if(i===!1)return!1;if(R(i))throw new p("RELATION_PREDICATE_UNSUPPORTED","relation predicates are not supported in write policies; use a read policy or a flat column check");return k(s,i)},Y=(t,r,s)=>{const i=t.when(r);if(i===void 0||i===!0)return s===void 0||X(t,r,s);if(i===!1)return!1;if(R(i))throw new p("RELATION_PREDICATE_UNSUPPORTED","relation predicates are not supported in write policies; use a read policy or a flat column check");return!r.row||!k(r.row,i)?!1:s===void 0||k(s,i)},M=(t,r,s,i)=>{let u=!1;for(const c of t)if(c.on===r&&(u=!0,!Y(c,s,i)))return!1;return u},E=t=>t??{},Z=new Set(["baseWhere","relationBaseWhere","restrictsCounts","where"]),ee=(t,r)=>r===void 0?!0:t==="restrictsCounts"?typeof r=="boolean":t==="relationBaseWhere"?typeof r=="function":D(r),te=t=>{const r=Object.keys(t);return r.length===0?!1:r.every(s=>Z.has(s)&&ee(s,t[s]))},re=t=>t===void 0?{}:D(t)&&te(t)?t:{where:t},b=(t,r)=>!r||Object.keys(r).length===0?t:!t||Object.keys(t).length===0?r:{AND:[r,t]},ne=t=>{if(typeof t!="object"||t===null||Array.isArray(t))return!1;const r=t;return typeof r.findMany=="function"&&typeof r.withSearchIndex=="function"},ae=(t,r,s,i)=>{const u=new Map,c=e=>{const n=u.get(e);if(n)return n;const a=s.get(e);if(!a||a.length===0||!a.some(l=>l.on==="read")){const l={baseWhere:void 0,restricts:!1};return u.set(e,l),l}const o={baseWhere:q(a,i),restricts:!0};return u.set(e,o),o},f=e=>c(e).restricts?r:t,y=e=>c(e).baseWhere,v=async(e,n)=>{if(r.lookupById){const h=await r.lookupById(e,n);return h?{row:h.row,tableName:s.has(h.tableName)?h.tableName:void 0}:{row:null,tableName:void 0}}const a=await r.get(e,n);if(!a)return{row:null,tableName:void 0};const o=n!==void 0&&s.has(n)?[n]:[],l=n===void 0?[...s.keys()]:o,d=await Promise.all(l.map(async h=>(await r.findFirst(h,{limit:1,where:{_id:e}}))?._id===e?h:void 0));return{row:a,tableName:d.find(h=>h!==void 0)}},B=async(e,n)=>{const a=await v(e,n);return a.row&&a.tableName!==void 0?{row:a.row,tableName:a.tableName}:void 0},w=async(e,n,a,o,l)=>{const d=await B(e,l);if(!d)return a(t);const h=s.get(d.tableName);if(h){const _=o?o(d.row):void 0;if(!M(h,n,{...i,row:d.row},_))throw new p("FORBIDDEN",`${n} denied by policy`)}return a(r)},W=(e,n)=>{const{baseWhere:a,restricts:o}=c(e);if(o)throw new p("COUNT_RLS_UNSUPPORTED",`${n}() is not supported on "${e}" inside an RLS-restricted context`);return a},O=t.rankBefore,g={...t,async count(e,n){const{baseWhere:a,restricts:o}=c(e),l=re(n);return f(e).count(e,{...l,baseWhere:b(l.baseWhere,a),relationBaseWhere:y,restrictsCounts:(l.restrictsCounts??!1)||o})},delete:(e,n,a)=>w(e,"delete",o=>o.delete(e,n,a),void 0,n),async deleteAll(e,n){const a=Math.max(1,n?.chunkSize??S),{baseWhere:o}=c(e);let l=0;for(;;){const d=(await f(e).findMany(e,{baseWhere:o,limit:a,relationBaseWhere:y})).page.map(h=>String(h._id));if(d.length===0)break;for(const h of d)await w(h,"delete",_=>_.delete(h,void 0,n?.hard===void 0?void 0:{hard:n.hard})),l+=1;if(d.length<a)break}return{deleted:l}},async deleteMany(e,n,a){N(e.length,n?.limit,"deleteMany");for(const o of e)await w(o,"delete",l=>l.delete(o,a),void 0,a);return{deleted:e.length}},async deleteWhere(e,n,a){const{baseWhere:o}=c(e),l=(await f(e).findMany(e,{baseWhere:b(n,o),relationBaseWhere:y})).page.map(d=>String(d._id));return N(l.length,a?.limit,"deleteWhere"),g.deleteMany(l,a)},async findFirst(e,n){const{baseWhere:a}=c(e);return f(e).findFirst(e,{...E(n),baseWhere:b(n?.baseWhere,a),relationBaseWhere:y})},async findFirstOrThrow(e,n){const{baseWhere:a}=c(e);return f(e).findFirstOrThrow(e,{...E(n),baseWhere:b(n?.baseWhere,a),relationBaseWhere:y})},async findMany(e,n){const{baseWhere:a}=c(e);return f(e).findMany(e,{...E(n),baseWhere:b(n?.baseWhere,a),relationBaseWhere:y})},async get(e,n){const a=await v(e,n);if(!a.row)return null;if(a.tableName===void 0)return t.get(e,n);const{baseWhere:o,restricts:l}=c(a.tableName);if(!l)return t.get(e,n);if(!o)return a.row;const d=await r.findFirst(a.tableName,{baseWhere:o,limit:1,where:{_id:e}});return d?._id===e?d:null},async insert(e,n){const a=s.get(e);if(a){if(!M(a,"insert",{...i,row:n}))throw new p("FORBIDDEN",`insert on "${e}" denied by policy`);return r.insert(e,n)}return t.insert(e,n)},async insertMany(e,n,a){N(n.length,a?.limit,"insertMany");const o=s.get(e);if(o){for(const l of n)if(!M(o,"insert",{...i,row:l}))throw new p("FORBIDDEN",`insert on "${e}" denied by policy`);return r.insertMany(e,n,a)}return t.insertMany(e,n,a)},async insertManyUnsafe(e,n,a){N(n.length,a?.limit,"insertManyUnsafe");const o=s.get(e);if(o){for(const l of n)if(!M(o,"insert",{...i,row:l}))throw new p("FORBIDDEN",`insert on "${e}" denied by policy`);return r.insertManyUnsafe(e,n,a)}return t.insertManyUnsafe(e,n,a)},patch:(e,n,a)=>w(e,"update",o=>o.patch(e,n,a),o=>({...o,...n}),a),async patchMany(e,n,a){N(e.length,n?.limit,"patchMany");for(const o of e)await w(o.id,"update",l=>l.patch(o.id,o.patch,a),l=>({...l,...o.patch}),a);return{patched:e.length}},async patchWhere(e,n,a){const{baseWhere:o}=c(e),l=(await f(e).findMany(e,{baseWhere:b(n.where,o),relationBaseWhere:y})).page.map(d=>({id:String(d._id),patch:n.patch}));return N(l.length,a?.limit,"patchWhere"),g.patchMany(l,a)},query(e){const{baseWhere:n}=c(e),a=f(e).query(e);return n?a.filter(o=>k(o,n)):a},restore:(e,n)=>w(e,"update",async a=>{const o=a.restore??r.restore;if(!o)throw new p("BAD_REQUEST","restore is not supported by this writer");await o(e,n)},void 0,n),replace:(e,n,a)=>w(e,"update",o=>o.replace(e,n,a),o=>({...n,_creationTime:n._creationTime??o._creationTime,_id:o._id}),a),aggregate(e,n){const{baseWhere:a}=c(e);return f(e).aggregate(e,{...n,baseWhere:b(n.baseWhere,a),relationBaseWhere:y})},groupBy(e,n){const{baseWhere:a}=c(e);return f(e).groupBy(e,{...n,baseWhere:b(n.baseWhere,a),relationBaseWhere:y})},rank(e,n,a){const o=W(e,"rank");return f(e).rank(e,n,{...a,baseWhere:b(a.baseWhere,o)})},rankPage(e,n,a){const o=W(e,"rankPage");return f(e).rankPage(e,n,{...a,baseWhere:b(a?.baseWhere,o)})},wipeShard(){throw new p("FORBIDDEN","ctx.db.wipeShard() is unavailable under rls(): a whole-shard erase can't be policy-gated per row, and erasing only policy-visible rows would silently leave data behind. Run it from an internalMutation, or use ctx.db.deleteAll(table) per table.",{status:403})},...O?{rankBefore:(e,n,a)=>(W(e,"rankBefore"),(f(e).rankBefore??O)(e,n,a))}:{}},A=g;for(const e of s.keys())ne(t[e])&&(A[e]=P(g,e));return g},T=t=>typeof t=="string"?t:t.name,se=t=>{const r=new Map;for(const s of t??[])r.set(s.name,new Set((s.permissions??[]).map(i=>T(i))));return r},ue=(t,r={})=>{const s=$(t),i=se(r.roles);return U(async({ctx:u,next:c})=>{const f=u.auth??{},y=await f.getIdentity?.()??null,v=f.roles??[],B=new Set;for(const n of v)for(const a of i.get(n)??[])B.add(a);const w={auth:{can:n=>B.has(T(n)),identity:y,roles:v,userId:f.userId??null},ctx:u},W=u.db,O=W[C]??W,g=ae(W,O,s,w),A={db:g},{orm:e}=u;return e!==null&&typeof e=="object"&&(A.orm=x(g)),c({ctx:A})},{policies:t,roles:r.roles??[]})};export{q as computeReadBaseWhere,M as evaluateWrite,se as indexRolePermissions,k as matchesWhere,T as permissionName,ue as rls};
@@ -0,0 +1 @@
1
+ import{LunoraError as i}from"@lunora/errors";const m=async(a,l,s)=>{let o=-1;const c=async(r,t)=>{if(r<=o)throw new i("INTERNAL","middleware next() called multiple times");o=r;const e=a[r];return e?await e({ctx:t,next:(n=>c(r+1,n?.ctx?{...t,...n.ctx}:t))}):s(t)};return c(0,l)};export{m as l};
@@ -0,0 +1 @@
1
+ import{LunoraError as S}from"./LunoraError-LVhdU0Lo.mjs";const b=t=>typeof t=="string"?t:t.name,v=(t=[])=>{const e=new Map;for(const s of t){const a=new Set;for(const i of s.permissions??[])a.add(b(i));e.set(s.name,a)}return e},N=(t,e)=>t===void 0||e.startsWith(t),R=t=>{const e=t[1],s=typeof e=="object"&&e!==null?e.method:void 0;return typeof s=="string"&&s.toUpperCase()==="PUT"?"write":"read"},$=[["delete","delete"],["download","read"],["generateUploadUrl","write"],["getMetadata","read"],["getSignedUrl",R],["getUrl","read"],["store","write"]],E=(t,e={})=>{const s=v(e.roles);return async({ctx:a,next:i})=>{const l=a.auth??{},h=await l.getIdentity?.()??null,g=l.roles??[],y=new Set;for(const o of g)for(const r of s.get(o)??[])y.add(r);const k={can:o=>y.has(b(o)),identity:h,roles:g,userId:l.userId??null},x=(o,r,c)=>{const f=t.filter(n=>n.on===o&&n.bucket===c);if(f.length===0)return;const u={auth:k,ctx:a,key:r};if(!f.some(n=>N(n.prefix,r)&&n.when(u)===!0))throw new S("FORBIDDEN",`storage ${o} on "${r}" in bucket "${c}" denied by access rule`)},p=o=>{const r=o.bucketName??"default",c={bucketName:r};for(const[u,n]of $){const m=o[u];typeof m=="function"&&(c[u]=(...d)=>{const U=typeof d[0]=="string"?d[0]:"",I=typeof n=="function"?n(d):n;return x(I,U,r),m(...d)})}const{bucket:f}=o;return typeof f=="function"&&(c.bucket=u=>p(f(u))),c},w=a.storage;return w===void 0?i():i({ctx:{storage:p(w)}})}};export{E as storageRules};