cvx-kit 0.1.12 → 0.1.14

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 (79) hide show
  1. package/AGENTS.md +47 -0
  2. package/CHANGELOG.md +36 -0
  3. package/README.md +144 -0
  4. package/dist/auth.d.mts +3 -1
  5. package/dist/auth.mjs +1 -1
  6. package/dist/auth.mjs.map +1 -1
  7. package/dist/index.d.mts +5 -2
  8. package/dist/index.mjs +1 -1
  9. package/dist/modules/contracts/binding.d.mts +13 -1
  10. package/dist/modules/contracts/binding.mjs +1 -1
  11. package/dist/modules/contracts/binding.mjs.map +1 -1
  12. package/dist/modules/effect/api-zod.d.mts +1 -1
  13. package/dist/modules/effect/command.d.mts +13 -9
  14. package/dist/modules/effect/command.mjs.map +1 -1
  15. package/dist/modules/effect/domain.d.mts +31 -3
  16. package/dist/modules/effect/domain.mjs.map +1 -1
  17. package/dist/modules/effect/query.d.mts +6 -5
  18. package/dist/modules/effect/query.mjs.map +1 -1
  19. package/dist/modules/foundation/foundation.d.mts +14 -13
  20. package/dist/modules/foundation/foundation.mjs.map +1 -1
  21. package/dist/modules/foundation/operation.d.mts +20 -1
  22. package/dist/modules/foundation/operation.mjs.map +1 -1
  23. package/dist/oxlint/architecture.d.mts +2 -0
  24. package/dist/oxlint/architecture.mjs +1 -1
  25. package/dist/oxlint/architecture.mjs.map +1 -1
  26. package/dist/oxlint/ast.d.mts +10 -1
  27. package/dist/oxlint/ast.mjs +1 -1
  28. package/dist/oxlint/ast.mjs.map +1 -1
  29. package/dist/oxlint.d.mts +1 -1
  30. package/dist/oxlint.mjs +1 -1
  31. package/dist/oxlint.mjs.map +1 -1
  32. package/dist/querying/cursors.d.mts +45 -0
  33. package/dist/querying/cursors.mjs +2 -0
  34. package/dist/querying/cursors.mjs.map +1 -0
  35. package/dist/querying/execution.d.mts +30 -0
  36. package/dist/querying/execution.mjs +2 -0
  37. package/dist/querying/execution.mjs.map +1 -0
  38. package/dist/querying/filters.d.mts +136 -0
  39. package/dist/querying/filters.mjs +2 -0
  40. package/dist/querying/filters.mjs.map +1 -0
  41. package/dist/querying/planner.d.mts +50 -0
  42. package/dist/querying/planner.mjs +2 -0
  43. package/dist/querying/planner.mjs.map +1 -0
  44. package/dist/querying/relationships.d.mts +41 -0
  45. package/dist/querying/relationships.mjs +2 -0
  46. package/dist/querying/relationships.mjs.map +1 -0
  47. package/dist/querying/security.d.mts +107 -0
  48. package/dist/querying/security.mjs +2 -0
  49. package/dist/querying/security.mjs.map +1 -0
  50. package/dist/querying.d.mts +39 -0
  51. package/dist/querying.mjs +2 -0
  52. package/dist/querying.mjs.map +1 -0
  53. package/dist/relations-public.d.mts +2 -0
  54. package/dist/relations-public.mjs +1 -0
  55. package/dist/relations.d.mts +155 -0
  56. package/dist/relations.mjs +2 -0
  57. package/dist/relations.mjs.map +1 -0
  58. package/dist/zod-convex.d.mts +10 -0
  59. package/dist/zod-convex.mjs +2 -0
  60. package/dist/zod-convex.mjs.map +1 -0
  61. package/dist/zod-registration.d.mts +10 -0
  62. package/dist/zod-registration.mjs +2 -0
  63. package/dist/zod-registration.mjs.map +1 -0
  64. package/dist/zod-table.d.mts +63 -8
  65. package/dist/zod-table.mjs +1 -1
  66. package/dist/zod-table.mjs.map +1 -1
  67. package/docs/conventions.md +12 -0
  68. package/docs/domain-contracts.md +42 -9
  69. package/docs/llms.md +15 -5
  70. package/docs/oxlint.md +129 -25
  71. package/docs/querying.md +293 -0
  72. package/docs/zod-table.md +93 -13
  73. package/package.json +11 -1
  74. package/scripts/owned-process.mjs +140 -0
  75. package/scripts/owned-process.test.mjs +107 -0
  76. package/scripts/smoke-packed-querying.mjs +296 -0
  77. package/scripts/test-packed-effect.mjs +10 -1
  78. package/scripts/test-packed-oxlint.mjs +5 -1
  79. package/scripts/test-packed-querying.mjs +185 -0
package/AGENTS.md ADDED
@@ -0,0 +1,47 @@
1
+ # Orchestration
2
+
3
+ <!-- Orchestration -->
4
+
5
+ Use T3 Code to orchestrate the agents the new orchestrator V2 allows you to orchestrate multiple models for working together, I have some recommendations for model selection and orchestration:
6
+
7
+ ## Models
8
+
9
+ | Provider | Heavy | Medium | Light |
10
+ | -------- | ----------- | ----------- | ---------------------- |
11
+ | OpenAI | gpt-6-astra | gpt-6.1-sol | gpt-6-luna |
12
+ | Claude | flabel-5.1 | opus-5.5 | sonnet-5.5 / haiku-5.5 |
13
+
14
+ Haiku and Luna are very special models for short tasks such as research file reader and those tasks that wont consume more than 100K tokens.
15
+
16
+ ## Workflow
17
+
18
+ I have a workflow for implementing features and working which contains some skills within the process they don't fallow an order but depending how deep we are on context we use it but those skills are:
19
+
20
+ - **ce-explain**: This I used it to verify if the AI is aligned with the user's intent, then got a back and forth conversation with the user to explain the feature and the context of the feature including research on the libraries internet and packages.
21
+ - **ce-plan**: This I used it to plan the feature implementation.
22
+ - **ce-work**: This I used it to work on the feature implementation.
23
+
24
+ These are goated skills that are used to implement features and work on them, but the real workflow for implementation itself is:
25
+
26
+ | Planners | workers | low workers | researcher | reviewers |
27
+ | ----------- | ----------- | ----------- | ---------------------- | ----------- |
28
+ | gpt-6-astra | gpt-6.1-sol | gpt-6-luna | gpt-6-luna | gpt-6-astra |
29
+ | flabel-5.1 | opus-5.5 | sonnet-5.5 | sonnet-5.5 / haiku-5.5 | N/A |
30
+
31
+ Invoke **reviewers** for code review, implementation review, and security review on changed code. Use **gpt-6-astra** at **Low** effort for that role.
32
+
33
+ After the planning and research session I sent the `ce-work` message to the main thread with the fallowing context:
34
+ "Work on this feature into a goal with multiple agents and make sure you test every phase. And you do a code review and an implementation review as well. Make sure every phase is tested before go to the other one And commit it as well. Make a security review to make sure everything is working correctly. Use a browser or any test you need to make sure you cover the needed and everything is working correctly."
35
+
36
+ with the fallowing effort:
37
+
38
+ | Model | Recommended Effort |
39
+ | ----------- | --------------------------------------------- |
40
+ | gpt-6-astra | Medium / Low worker; Low reviewer |
41
+ | flabel-5.1 | low |
42
+ | opus-5.5 | low |
43
+ | gpt-6-luna | low(fast) |
44
+ | gpt-6.1-sol | medium(fast) |
45
+ | sonnet-5.5 | medium |
46
+
47
+ <!-- Orchestration -->
package/CHANGELOG.md CHANGED
@@ -12,6 +12,42 @@ are this file's matching section.
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [0.1.14] - 2026-10-11
16
+
17
+ ### Added
18
+
19
+ - Typed relational queries with scalar and relationship filters, conditional indexes, global ascending or descending order, and bounded stream pagination.
20
+ - Explicit relationship declarations for direct, self, and junction relationships, with paginated child continuations.
21
+ - Managed query authorization, shared read budgets, and encrypted cursors bound to the query, principal, tenant, and parent relationship.
22
+ - Table DTO options for validated IDs and extensions, including `toPublicDto(row, true)`, plus native-derived `paginationOpts` and page DTO helpers.
23
+ - Oxlint enforcement for manual ID projections, copied pagination contracts, and unsafe relational query boundaries.
24
+ - Dedicated querying documentation and updated table and rule documentation in `src/docs`.
25
+
26
+ ### Fixed
27
+
28
+ - Preserve shared validator graphs during native auth registration to avoid repeated validator expansion.
29
+
30
+ ### Verified
31
+
32
+ - Source, type, rule, and packed-consumer checks; 308 independently audited relational stress sequences across installed and minimum peer versions.
33
+ - 33 HTTP responses exercised encrypted cursor pagination and rejection paths on a local Convex backend. Hosted production performance remains unmeasured.
34
+
35
+ ## [0.1.13] - 2026-10-10
36
+
37
+ ### Added
38
+
39
+ - Implement contracted operations with `command.handler(handler, options?)` and
40
+ `query.handler(handler, options?)` in both Promise and Effect registries.
41
+ - Infer each handler's input and result from its operation object key, without
42
+ repeating the operation name; preserve existing named helpers.
43
+
44
+ ### Verified
45
+
46
+ - Cover contract binding, validation, audits, and handler inference with 684
47
+ runtime tests and strict type fixtures.
48
+ - Compile the documentation examples and test packed npm/Bun consumers with
49
+ and without Effect.
50
+
15
51
  ## [0.1.12] - 2026-10-10
16
52
 
17
53
  ### Added
package/README.md CHANGED
@@ -83,6 +83,150 @@ under application control.
83
83
  `zodVariantTable` covers discriminated-union tables; `jsonSafeZid` keeps
84
84
  LLM-tool JSON schemas primitive while preserving the `Id<...>` type.
85
85
 
86
+ ### `cvx-kit/relations` and `cvx-kit/querying`
87
+
88
+ See the [querying guide](./src/docs/querying.md),
89
+ [DTO parameters](./src/docs/zod-table.md#public-dto-parameters), and
90
+ [consumer rule reference](./src/docs/oxlint.md#dto-and-pagination-diagnostics).
91
+
92
+ Declare relationships once in `convex/relations.ts`, then configure the engine
93
+ once in `convex/querying.ts`. Both factories are also available from the package
94
+ root. The relations subpath exposes declarations and public types; executor
95
+ metadata and managed reader capabilities are internal.
96
+
97
+ ```ts
98
+ // convex/relations.ts
99
+ import { defineRelations } from 'cvx-kit/relations'
100
+ import './domain/tasks/table' // Establish native indexes before compiling the registry.
101
+ import { tasks, labels, edges } from './domain/tasks/schema'
102
+
103
+ export const relations = defineRelations({ tasks, labels, edges }, (r) => ({
104
+ tasks: {
105
+ referenceTask: r.one.tasks({ from: r.tasks.reference, to: r.tasks._id }),
106
+ labels: r.many.labels({
107
+ from: r.tasks._id.through(r.edges.task),
108
+ to: r.labels._id.through(r.edges.label),
109
+ }),
110
+ },
111
+ }))
112
+ ```
113
+
114
+ The tables must be object-shaped `zodTable` or `tenantTable` boundaries, with
115
+ indexes supporting each declared lookup. Names can distinguish multiple edges
116
+ to the same table; references can point to the same table. A one edge returns a
117
+ public DTO or `null`. A many edge returns a bounded native page. Junction output
118
+ preserves duplicate edge occurrences, even when target reads are memoized.
119
+ Missing and unreadable targets have the same public result.
120
+
121
+ ```ts
122
+ // convex/querying.ts
123
+ import { createQueryEngine } from 'cvx-kit/querying'
124
+ import schema from './schema'
125
+ import { relations } from './relations'
126
+ import { cursor } from './functions'
127
+
128
+ export const querying = createQueryEngine({
129
+ schema,
130
+ relations,
131
+ cursor,
132
+ })
133
+ ```
134
+
135
+ `cursor.keys` is a server-only map of key IDs to 64-byte `Uint8Array` secrets.
136
+ Keep key material out of arguments, client code, and logs. The default codec
137
+ uses authenticated AES-SIV encryption without a plaintext fallback; identical
138
+ payloads under the same binding reveal equality. Tokens bind filters, selected
139
+ output, index, order, relation ancestry, principal/tenant/security scope, and
140
+ registry/policy/engine versions. Page-size changes alone remain valid. Retain
141
+ old keys during rotation when existing cursors should continue working.
142
+
143
+ Use the registry's validators in domain contracts and an authenticated Query
144
+ registry handler:
145
+
146
+ ```ts
147
+ const options = relations.tables.tasks.paginationOpts({
148
+ department: true,
149
+ status: true,
150
+ labels: { name: true },
151
+ })
152
+ const result = relations.tables.tasks.pageDto({ labels: true })
153
+
154
+ // In the Query operation's handler, ctx comes from createAuthFunctions.authQuery.
155
+ const page = await querying(ctx)
156
+ .tasks.where({ tenant: ctx.tenant })
157
+ .with({ labels: true })
158
+ .paginate(args)
159
+
160
+ // A separate authenticated child endpoint validates parent with tasks.schema.shape._id.
161
+ const nextLabels = await querying(ctx)
162
+ .tasks.relation(parent, 'labels')
163
+ .paginate({ numItems: 25, cursor: page.page[0].labels.continueCursor })
164
+ ```
165
+
166
+ Select filterable stored fields explicitly, including server-owned fields when
167
+ needed. Public DTO fields do not determine filter eligibility. Scalar predicates
168
+ support equality, ranges, `and`, `or`, and `not`; many predicates use `some` or
169
+ `none`. Eligibility and composed read authorization run before parents fill a
170
+ page. Parent, junction, target, and continuation reads all recheck authorization.
171
+ `include` and `paginated(dto)` retain their existing behavior independently.
172
+
173
+ Chain `.when(value, 'index_name')` to choose the first present condition: `false`,
174
+ `0`, and `''` are present; `null` and `undefined` are absent. The gate does not
175
+ bind an index field; validated filters and server `.where(...)` constraints do.
176
+ An incompatible explicit choice fails. Automatic selection uses the longest
177
+ usable equality prefix, then stable index-name order, with creation-time fallback.
178
+ `order: 'desc'` reverses the chosen native index order. Native continuation,
179
+ split/end cursors, and page status are preserved, with external tokens protected.
180
+
181
+ Page sizes are positive integers up to 100; central `maxPageSize` may lower that
182
+ ceiling. Central budgets bound read operations, index ranges, raw candidates,
183
+ observed/reserved document bytes, fan-out, depth, and memo entries across a
184
+ request, including policy reads. Native request read limits may lower ceilings.
185
+ An incomplete eligibility proof throws `MANAGED_READ_BUDGET`; it is never an
186
+ empty exhausted page or a negative predicate. Output relationship depth is at
187
+ most four. Traversal executes in the caller's query transaction and may require
188
+ many reads. Application/helper accounting does not measure physical platform I/O.
189
+
190
+ Kit auth query contexts carry the engine's private read capability. Unknown
191
+ contexts fail closed unless a centrally configured trusted adapter attests their
192
+ query reader, effective policy, and security scope. Mutation/action contexts,
193
+ variant tables, search/vector optimization, arbitrary predicates/projections,
194
+ and custom sorts are outside this API.
195
+
196
+ For manual projection, `tasks.toPublicDto(row)` still omits IDs and unselected
197
+ storage fields. `tasks.toPublicDto(row, true)` or `{ _id: true }` adds the branded
198
+ ID only. Computed extensions use matching schemas:
199
+
200
+ ```ts
201
+ const extend = { url: z.url() }
202
+ const dto = tasks.toPublicDto(row, {
203
+ _id: true,
204
+ extend,
205
+ values: { url: `https://example.test/tasks/${row._id}` },
206
+ })
207
+ const returnSchema = tasks.dto({ _id: true, extend })
208
+ ```
209
+
210
+ To migrate, replace manual ID spreads with the shorthand and copied pagination
211
+ objects with `paginationOpts`. Move eligibility filters before bounded reads by
212
+ expressing them in the engine. Replace recognized unbounded relationship
213
+ collections with declared many pages and authenticated continuation endpoints.
214
+ Consumer diagnostics identify these patterns when kit/native provenance is known;
215
+ predicate movement has no automatic fix. Keep declarations in root
216
+ `relations.ts`/`querying.ts` and contracts and Query registries in their domain.
217
+
218
+ The [packed executable example](./test/fixture-packed-querying/convex/) includes
219
+ domain tables, contracts, authenticated API adapters, one/self/named/many/junction
220
+ edges, and child continuation. Its `.template` files become ordinary TypeScript
221
+ in isolated consumers; `bun run test:package:querying` installs the tarball on
222
+ installed and minimum peers, checks strict declarations and consumer rules, and
223
+ runs the full independent stress oracle and focused tie, output, replay, and
224
+ authorization-revocation probes. For a bounded anonymous local native proof,
225
+ run `node scripts/smoke-packed-querying.mjs <retained-packed-proof-directory>`
226
+ after the package check. It uses the same tarball and central default budgets.
227
+ Package publishing and application
228
+ migration remain separate work.
229
+
86
230
  ### `cvx-kit/auth`
87
231
 
88
232
  `createAuthFunctions` builds the six auth-aware constructors from injected
package/dist/auth.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ErrorFactory } from "./errors.mjs";
2
2
  import { RLSConfig, Rules } from "./tenancy.mjs";
3
+ import { SecurityPolicyContext } from "./querying/security.mjs";
3
4
  import { CustomBuilder } from "convex-helpers/server/zod4";
4
5
  import { ActionBuilder, DocumentByInfo, GenericActionCtx, GenericDataModel, GenericMutationCtx, GenericQueryCtx, GenericTableInfo, IndexNames, IndexRange, IndexRangeBuilder, MutationBuilder, NamedIndex, PaginationOptions, PaginationResult, Query, QueryBuilder, QueryInitializer, TableNamesInDataModel, UserIdentity } from "convex/server";
5
6
  import { Triggers } from "convex-helpers/server/triggers";
@@ -46,7 +47,7 @@ export type SecurityConfig<DataModel extends GenericDataModel, Role extends stri
46
47
  * composed AND-wise with tenant isolation. E.g. gate `modify` on a table
47
48
  * to admin roles.
48
49
  */
49
- rules?: (bundle: AuthBundle<Role>) => Rules<unknown, DataModel>;
50
+ rules?: (bundle: AuthBundle<Role>) => Rules<SecurityPolicyContext<DataModel>, DataModel>;
50
51
  /**
51
52
  * Policy for tables with no rule. Defaults to 'deny' when tenancy is
52
53
  * configured (unlisted tables are unreachable — fail closed), 'allow'
@@ -184,4 +185,5 @@ export declare function createInclude(options?: {
184
185
  */
185
186
  export declare function createAuthFunctions<DataModel extends GenericDataModel, const Role extends string = DefaultRole>(config: AuthFunctionsConfig<DataModel, Role>): AuthFunctions<DataModel, Role>;
186
187
  //#endregion
188
+ export type { SecurityPolicyContext };
187
189
  //# sourceMappingURL=auth.d.mts.map
package/dist/auth.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{defaultErrors as e}from"./errors.mjs";import{composeRules as t,createTenantRules as n,wrapDatabaseReader as r,wrapDatabaseWriter as i}from"./tenancy.mjs";import{zCustomAction as a,zCustomMutation as o,zCustomQuery as s}from"convex-helpers/server/zod4";import{z as c}from"zod";function l(e){let t=e?.trim().toLowerCase();return t===`member`?`writer`:t===`reader`||t===`writer`||t===`admin`?t:null}function u(t){let n=t?.errors??e,r=t?.maxRows??100;function i(e,t){async function a(i,a){if(!Number.isSafeInteger(i)||i<1||i>r)return n.throw({code:`INVALID_REQUEST_BOUNDARY`,message:`A bounded query limit must be from 1 to ${r}`});let o=await(t??e.fullTableScan()).take(i);return a?a(o):o}async function o(i,a){if(!Number.isSafeInteger(i.numItems)||i.numItems<1||i.numItems>r)return n.throw({code:`INVALID_REQUEST_BOUNDARY`,message:`A page size must be from 1 to ${r}`});let o=await(t??e.fullTableScan()).paginate(i);return a?{...o,page:await a(o.page)}:o}return{when:(n,r)=>t||n==null?i(e,t):i(e,r(e,n)),matching:(n,r,a=!0)=>t||!a?i(e,t):i(e,e.withIndex(n,r)),otherwise:n=>t??n(e),resolve:()=>t??e.fullTableScan(),execute:a,paginate:o}}return e=>i(e)}function d(c){let l=c.errors??e,d=c.triggers,p=d?e=>d.wrapDB(e):c.wrapDB??(e=>e),m=u({errors:l,maxRows:c.maxIncludedQueryRows});async function h(e){let t=await e.auth.getUserIdentity(),n=t?await c.getAuthUser(e):null;if(!t||!n)return l.throw({code:`UNAUTHENTICATED`});let r,i;if(c.resolveOrganization){let a=null;try{a=await c.resolveOrganization({ctx:e,identity:t,user:n})}catch{}if(!a)return l.throw({code:`FORBIDDEN`});r=a.organizationId,i=a.roleSlug}else{let e=f.parse(t),n=e.organization?.organizationId??e.org_id;if(!n)return l.throw({code:`UNAUTHENTICATED`});r=n,i=e.organization?.role??e.role}let a=c.mapRole(i);if(!a)return l.throw({code:`FORBIDDEN`});let o={identity:t,user:Object.freeze({id:n.id}),org:Object.freeze({organizationId:r,role:a}),role:a,actor:Object.freeze({userId:n.id,organizationId:r,role:a})};return Object.freeze({...o,tenant:c.security?.tenancy?.resolve?.(o)??r})}let g=c.security?{defaultPolicy:c.security.defaultPolicy??(c.security.tenancy?`deny`:`allow`)}:void 0;function _(e){let r=c.security;if(!r)return;let i=[];return r.tenancy&&i.push(n(e.tenant,r.tenancy.tables)),r.rules&&i.push(r.rules(e)),i.length===1?i[0]:t(...i)}function v(e,t){let n=_(t);return n?{...e,db:r({},e.db,n,g)}:e}function y(e,t){let n=_(t);return n?{...e,db:i({},e.db,n,g)}:e}async function b(e,t){if(!c.verifyMembership)return null;try{let n=await c.verifyMembership({userId:e,organizationId:t});if(n&&n.organizationId===t)return n}catch{}return l.throw({code:`FORBIDDEN`})}function x(e,t){if(!t.includes(e))return l.throw({code:`FORBIDDEN`})}async function S(e){let t=await h(e);return{ctx:{...v(e,t),include:m,...t},args:{}}}async function C(e){let t=await h(e);return{ctx:{...y(p(e),t),include:m,...t},args:{}}}async function w(e){let t=await h(e),n=await b(t.user.id,t.org.organizationId);if(!n)return{ctx:{...e,...t},args:{}};let r=c.mapRole(n.roleSlug);if(!r)return l.throw({code:`FORBIDDEN`});let i={identity:t.identity,user:t.user,org:Object.freeze({organizationId:n.organizationId,role:r}),role:r,actor:Object.freeze({userId:t.user.id,organizationId:n.organizationId,role:r})};return{ctx:{...e,...i,tenant:c.security?.tenancy?.resolve?.(i)??n.organizationId},args:{}}}function T(...e){return s(c.query,{args:{},input:async t=>{let n=await S(t);return x(n.ctx.actor.role,e),n}})}function E(...e){return o(c.mutation,{args:{},input:async t=>{let n=await C(t);return x(n.ctx.actor.role,e),n}})}function D(...e){return a(c.action,{args:{},input:async t=>{let n=await w(t);return x(n.ctx.actor.role,e),n}})}return{include:m,authenticatedUser:h,roleQuery:T,roleMutation:E,roleAction:D,authQuery:s(c.query,{args:{},input:S}),authMutation:o(c.mutation,{args:{},input:C}),authAction:a(c.action,{args:{},input:w}),adminQuery:T(...c.adminRoles),adminMutation:E(...c.adminRoles),adminAction:D(...c.adminRoles),systemQuery:s(c.internalQuery,{args:{},input:async e=>({ctx:{...e,include:m},args:{}})}),systemMutation:o(c.internalMutation,{args:{},input:async e=>({ctx:{...p(e),include:m},args:{}})}),systemAction:a(c.internalAction,{args:{},input:async e=>({ctx:e,args:{}})})}}const f=c.object({organization:c.object({organizationId:c.string().optional().catch(void 0),role:c.string().optional().catch(void 0)}).optional().catch(void 0),org_id:c.string().optional().catch(void 0),role:c.string().optional().catch(void 0)});export{d as createAuthFunctions,u as createInclude,l as defaultRoleMap};
1
+ import{zCustomAction as e,zCustomMutation as t,zCustomQuery as n}from"./zod-registration.mjs";import{defaultErrors as r}from"./errors.mjs";import{registerQueryReader as i,suppliedPolicyRules as a}from"./querying/security.mjs";import{composeRules as o,createTenantRules as s,wrapDatabaseReader as c,wrapDatabaseWriter as l}from"./tenancy.mjs";import{z as u}from"zod";function d(e){let t=e?.trim().toLowerCase();return t===`member`?`writer`:t===`reader`||t===`writer`||t===`admin`?t:null}function f(e){let t=e?.errors??r,n=e?.maxRows??100;function i(e,r){async function a(i,a){if(!Number.isSafeInteger(i)||i<1||i>n)return t.throw({code:`INVALID_REQUEST_BOUNDARY`,message:`A bounded query limit must be from 1 to ${n}`});let o=await(r??e.fullTableScan()).take(i);return a?a(o):o}async function o(i,a){if(!Number.isSafeInteger(i.numItems)||i.numItems<1||i.numItems>n)return t.throw({code:`INVALID_REQUEST_BOUNDARY`,message:`A page size must be from 1 to ${n}`});let o=await(r??e.fullTableScan()).paginate(i);return a?{...o,page:await a(o.page)}:o}return{when:(t,n)=>r||t==null?i(e,r):i(e,n(e,t)),matching:(t,n,a=!0)=>r||!a?i(e,r):i(e,e.withIndex(t,n)),otherwise:t=>r??t(e),resolve:()=>r??e.fullTableScan(),execute:a,paginate:o}}return e=>i(e)}function p(u){let d=u.errors??r,p=u.triggers,h=p?e=>p.wrapDB(e):u.wrapDB??(e=>e),g=f({errors:d,maxRows:u.maxIncludedQueryRows});async function _(e){let t=await e.auth.getUserIdentity(),n=t?await u.getAuthUser(e):null;if(!t||!n)return d.throw({code:`UNAUTHENTICATED`});let r,i;if(u.resolveOrganization){let a=null;try{a=await u.resolveOrganization({ctx:e,identity:t,user:n})}catch{}if(!a)return d.throw({code:`FORBIDDEN`});r=a.organizationId,i=a.roleSlug}else{let e=m.parse(t),n=e.organization?.organizationId??e.org_id;if(!n)return d.throw({code:`UNAUTHENTICATED`});r=n,i=e.organization?.role??e.role}let a=u.mapRole(i);if(!a)return d.throw({code:`FORBIDDEN`});let o={identity:t,user:Object.freeze({id:n.id}),org:Object.freeze({organizationId:r,role:a}),role:a,actor:Object.freeze({userId:n.id,organizationId:r,role:a})};return Object.freeze({...o,tenant:u.security?.tenancy?.resolve?.(o)??r})}let v=u.security?{defaultPolicy:u.security.defaultPolicy??(u.security.tenancy?`deny`:`allow`)}:void 0;function y(e){let t=u.security;if(!t)return;let n=[];return t.tenancy&&n.push(s(e.tenant,t.tenancy.tables)),t.rules&&n.push(t.rules(e)),n.length===1?n[0]:o(...n)}function b(e,t){let n=y(t),r=v?.defaultPolicy??`allow`,o=n?c({db:e.db},e.db,a(e.db,n,r),v):e.db;return{...e,db:i(e.db,o,{scope:{mode:`authenticated`,principal:t.user.id,organization:t.org.organizationId,tenant:t.tenant,role:t.role},rules:n??{},defaultPolicy:r})}}function x(e,t){let n=y(t);return n?{...e,db:l({db:e.db},e.db,a(e.db,n,v?.defaultPolicy??`allow`),v)}:e}async function S(e,t){if(!u.verifyMembership)return null;try{let n=await u.verifyMembership({userId:e,organizationId:t});if(n&&n.organizationId===t)return n}catch{}return d.throw({code:`FORBIDDEN`})}function C(e,t){if(!t.includes(e))return d.throw({code:`FORBIDDEN`})}async function w(e){let t=await _(e);return{ctx:{...b(e,t),include:g,...t},args:{}}}async function T(e){let t=await _(e);return{ctx:{...x(h(e),t),include:g,...t},args:{}}}async function E(e){let t=await _(e),n=await S(t.user.id,t.org.organizationId);if(!n)return{ctx:{...e,...t},args:{}};let r=u.mapRole(n.roleSlug);if(!r)return d.throw({code:`FORBIDDEN`});let i={identity:t.identity,user:t.user,org:Object.freeze({organizationId:n.organizationId,role:r}),role:r,actor:Object.freeze({userId:t.user.id,organizationId:n.organizationId,role:r})};return{ctx:{...e,...i,tenant:u.security?.tenancy?.resolve?.(i)??n.organizationId},args:{}}}function D(...e){return n(u.query,{args:{},input:async t=>{let n=await w(t);return C(n.ctx.actor.role,e),n}})}function O(...e){return t(u.mutation,{args:{},input:async t=>{let n=await T(t);return C(n.ctx.actor.role,e),n}})}function k(...t){return e(u.action,{args:{},input:async e=>{let n=await E(e);return C(n.ctx.actor.role,t),n}})}return{include:g,authenticatedUser:_,roleQuery:D,roleMutation:O,roleAction:k,authQuery:n(u.query,{args:{},input:w}),authMutation:t(u.mutation,{args:{},input:T}),authAction:e(u.action,{args:{},input:E}),adminQuery:D(...u.adminRoles),adminMutation:O(...u.adminRoles),adminAction:k(...u.adminRoles),systemQuery:n(u.internalQuery,{args:{},input:async e=>({ctx:{...e,include:g,db:i(e.db,e.db,{scope:{mode:`system`,principal:null,organization:null,tenant:null,role:null},rules:{},defaultPolicy:`allow`})},args:{}})}),systemMutation:t(u.internalMutation,{args:{},input:async e=>({ctx:{...h(e),include:g},args:{}})}),systemAction:e(u.internalAction,{args:{},input:async e=>({ctx:e,args:{}})})}}const m=u.object({organization:u.object({organizationId:u.string().optional().catch(void 0),role:u.string().optional().catch(void 0)}).optional().catch(void 0),org_id:u.string().optional().catch(void 0),role:u.string().optional().catch(void 0)});export{p as createAuthFunctions,f as createInclude,d as defaultRoleMap};
2
2
  //# sourceMappingURL=auth.mjs.map
package/dist/auth.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.mjs","names":["defaultRoleMap","normalized","roleSlug","createInclude","errors","options","defaultErrors","maxRows","attach","execute","limit","data","selected","query","transform","paginate","opts","result","value","select","shouldMatch","indexName","indexRange","createAuthFunctions","config","triggers","wrapDB","ctx","include","authenticatedUser","identity","user","organizationId","organizationRole","resolved","claims","organizationClaims","claimedOrganizationId","role","base","securityConfig","securityRules","security","sets","createTenantRules","bundle","composeRules","secureReader","rules","wrapDatabaseReader","secureWriter","wrapDatabaseWriter","verifiedMembership","membership","requireRole","allowed","queryInput","mutationInput","actionInput","authenticated","verified","roleQuery","zCustomQuery","roleMutation","zCustomMutation","roleAction","zCustomAction","z"],"sources":["../src/auth.ts"],"sourcesContent":["import { z } from 'zod'\nimport { zCustomAction, zCustomMutation, zCustomQuery } from 'convex-helpers/server/zod4'\nimport type { CustomBuilder } from 'convex-helpers/server/zod4'\nimport type {\n\tActionBuilder,\n\tDocumentByInfo,\n\tPaginationOptions,\n\tPaginationResult,\n\tGenericActionCtx,\n\tGenericDataModel,\n\tGenericMutationCtx,\n\tGenericQueryCtx,\n\tGenericTableInfo,\n\tIndexNames,\n\tIndexRange,\n\tIndexRangeBuilder,\n\tMutationBuilder,\n\tNamedIndex,\n\tQuery,\n\tQueryBuilder,\n\tQueryInitializer,\n\tUserIdentity,\n} from 'convex/server'\nimport type { Triggers } from 'convex-helpers/server/triggers'\nimport type { TableNamesInDataModel } from 'convex/server'\nimport { defaultErrors, type ErrorFactory } from './errors'\nimport {\n\tcomposeRules,\n\tcreateTenantRules,\n\twrapDatabaseReader,\n\twrapDatabaseWriter,\n\ttype RLSConfig,\n\ttype Rules,\n} from './tenancy'\n\n/** The default vocabulary; every app can supply its own via the Role generic. */\nexport type DefaultRole = 'reader' | 'writer' | 'admin'\n\nexport type Actor<Role extends string> = Readonly<{\n\tuserId: string\n\torganizationId: string\n\trole: Role\n}>\n\nexport type AuthBundle<Role extends string> = Readonly<{\n\tidentity: UserIdentity\n\tuser: Readonly<{ id: string }>\n\torg: Readonly<{ organizationId: string; role: Role }>\n\trole: Role\n\tactor: Actor<Role>\n\t/** The resolved tenant — security.tenancy.resolve, or the organization id. */\n\ttenant: string\n}>\n\n/**\n * Row-level security configuration. Tenant isolation and role-level rules\n * compose (AND) onto the same wrapped database: queries get a wrapped\n * reader, mutations get triggers first, then a wrapped writer.\n */\nexport type SecurityConfig<DataModel extends GenericDataModel, Role extends string> = {\n\t/**\n\t * Tenant isolation. `tables` is THE registry: every listed table gets\n\t * read/insert/modify gated on row.tenant === ctx.tenant. Pair with\n\t * tenantTable (schema) and tenantOwnership (triggers) on the same list.\n\t */\n\ttenancy?: {\n\t\ttables: readonly TableNamesInDataModel<DataModel>[]\n\t\t/** Maps the auth bundle to the tenant; defaults to org.organizationId. */\n\t\tresolve?: (bundle: Omit<AuthBundle<Role>, 'tenant'>) => string\n\t}\n\t/**\n\t * Role-level (or any policy) rules derived from the authenticated bundle,\n\t * composed AND-wise with tenant isolation. E.g. gate `modify` on a table\n\t * to admin roles.\n\t */\n\trules?: (bundle: AuthBundle<Role>) => Rules<unknown, DataModel>\n\t/**\n\t * Policy for tables with no rule. Defaults to 'deny' when tenancy is\n\t * configured (unlisted tables are unreachable — fail closed), 'allow'\n\t * otherwise.\n\t */\n\tdefaultPolicy?: RLSConfig['defaultPolicy']\n}\n\ntype AnyAuthContext<DataModel extends GenericDataModel> =\n\t| GenericQueryCtx<DataModel>\n\t| GenericMutationCtx<DataModel>\n\t| GenericActionCtx<DataModel>\n\nexport type AuthFunctionsConfig<DataModel extends GenericDataModel, Role extends string> = {\n\t/** The consumer's generated function builders (from ./_generated/server). */\n\tquery: QueryBuilder<DataModel, 'public'>\n\tmutation: MutationBuilder<DataModel, 'public'>\n\taction: ActionBuilder<DataModel, 'public'>\n\tinternalQuery: QueryBuilder<DataModel, 'internal'>\n\tinternalMutation: MutationBuilder<DataModel, 'internal'>\n\tinternalAction: ActionBuilder<DataModel, 'internal'>\n\t/** Resolves the synchronized principal, e.g. (ctx) => authKit.getAuthUser(ctx). */\n\tgetAuthUser: (ctx: AnyAuthContext<DataModel>) => Promise<{ id: string } | null>\n\t/**\n\t * Maps an identity role slug onto the app's role vocabulary. Returning\n\t * null rejects the caller with FORBIDDEN — unknown roles never pass.\n\t */\n\tmapRole: (roleSlug?: string) => Role | null\n\t/** Roles allowed through the admin* constructors. */\n\tadminRoles: readonly NoInfer<Role>[]\n\t/**\n\t * Live membership check for actions (queries/mutations trust the JWT).\n\t * Authentication fails closed with FORBIDDEN when verification errors.\n\t * Omit to let actions trust the JWT like queries do.\n\t */\n\tverifyMembership?: (input: {\n\t\tuserId: string\n\t\torganizationId: string\n\t}) => Promise<{ organizationId: string; roleSlug: string } | null>\n\t/**\n\t * Resolves organization authority from the app's own data for identity\n\t * providers whose tokens carry no org claims. When configured, its result\n\t * overrides claim-based resolution; null or an error rejects with FORBIDDEN\n\t * (fail closed). In actions the ctx has no db — resolve via ctx.runQuery.\n\t */\n\tresolveOrganization?: (input: {\n\t\tctx: AnyAuthContext<DataModel>\n\t\tidentity: UserIdentity\n\t\tuser: { id: string }\n\t}) => Promise<{ organizationId: string; roleSlug: string } | null>\n\t/** Host error policy; defaults to throwing KitError. */\n\terrors?: ErrorFactory\n\t/**\n\t * Application trigger registry. When set, every authMutation,\n\t * roleMutation, and systemMutation write runs through triggers.wrapDB —\n\t * evaluations registered on tables fire structurally.\n\t */\n\ttriggers?: Triggers<DataModel>\n\t/** Lower-level alternative to `triggers`: a custom ctx wrapper. */\n\twrapDB?: (ctx: GenericMutationCtx<DataModel>) => GenericMutationCtx<DataModel>\n\t/** Upper bound for include() reads. */\n\tmaxIncludedQueryRows?: number\n\t/**\n\t * Row-level security: tenant isolation (from a table registry) and\n\t * role-level rules, applied structurally inside every auth*, role*, and\n\t * admin* constructor. system* constructors stay unwrapped (trusted).\n\t */\n\tsecurity?: SecurityConfig<DataModel, Role>\n}\n\n/** WorkOS-style default: `member` writes; reader/writer/admin pass through. */\nexport function defaultRoleMap(roleSlug?: string): DefaultRole | null {\n\tconst normalized = roleSlug?.trim().toLowerCase()\n\tif (normalized === 'member') return 'writer'\n\treturn normalized === 'reader' || normalized === 'writer' || normalized === 'admin'\n\t\t? normalized\n\t\t: null\n}\n\nexport type IncludedQuery<Table extends GenericTableInfo> = {\n\twhen<Value>(\n\t\tvalue: Value | null | undefined,\n\t\tselect: (query: QueryInitializer<Table>, value: Value) => Query<Table>,\n\t): IncludedQuery<Table>\n\tmatching<IndexName extends IndexNames<Table>>(\n\t\tindexName: IndexName,\n\t\tindexRange?: (\n\t\t\tquery: IndexRangeBuilder<DocumentByInfo<Table>, NamedIndex<Table, IndexName>>,\n\t\t) => IndexRange,\n\t\tshouldMatch?: boolean,\n\t): IncludedQuery<Table>\n\totherwise(select: (query: QueryInitializer<Table>) => Query<Table>): Query<Table>\n\tresolve(): Query<Table>\n\texecute(limit: number): Promise<DocumentByInfo<Table>[]>\n\texecute<Result>(\n\t\tlimit: number,\n\t\ttransform: (data: Awaited<ReturnType<Query<Table>['take']>>) => Result | Promise<Result>,\n\t): Promise<Result>\n\t/**\n\t * Cursor pagination over the selected indexed query. numItems is bounded\n\t * by the same maxRows policy as execute(). Under row-level security a\n\t * page may be shorter than numItems (rejected rows are filtered after\n\t * pagination); cursors remain correct. Pair with paginated(dto) from\n\t * cvx-kit/zod-table for the boundary schemas.\n\t */\n\tpaginate(opts: PaginationOptions): Promise<PaginationResult<DocumentByInfo<Table>>>\n\tpaginate<Item>(\n\t\topts: PaginationOptions,\n\t\ttransform: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>,\n\t): Promise<PaginationResult<Item>>\n}\n\nexport type Include = <Table extends GenericTableInfo>(\n\tquery: QueryInitializer<Table>,\n) => IncludedQuery<Table>\n\n/**\n * Keep native contexts symbolic in published declarations. Inferred spreads\n * copy build-time Convex methods and override the consumer's native context.\n */\nexport type AuthFunctions<DataModel extends GenericDataModel, Role extends string = DefaultRole> = {\n\tinclude: Include\n\tauthenticatedUser: (ctx: AnyAuthContext<DataModel>) => Promise<AuthBundle<Role>>\n\tauthQuery: CustomBuilder<\n\t\t'query',\n\t\t{},\n\t\tGenericQueryCtx<DataModel> & AuthBundle<Role> & { include: Include },\n\t\t{},\n\t\tGenericQueryCtx<DataModel>,\n\t\t'public',\n\t\tobject\n\t>\n\tauthMutation: CustomBuilder<\n\t\t'mutation',\n\t\t{},\n\t\tGenericMutationCtx<DataModel> & AuthBundle<Role> & { include: Include },\n\t\t{},\n\t\tGenericMutationCtx<DataModel>,\n\t\t'public',\n\t\tobject\n\t>\n\tauthAction: CustomBuilder<\n\t\t'action',\n\t\t{},\n\t\tGenericActionCtx<DataModel> & AuthBundle<Role>,\n\t\t{},\n\t\tGenericActionCtx<DataModel>,\n\t\t'public',\n\t\tobject\n\t>\n\troleQuery: (...allowed: readonly Role[]) => AuthFunctions<DataModel, Role>['authQuery']\n\troleMutation: (...allowed: readonly Role[]) => AuthFunctions<DataModel, Role>['authMutation']\n\troleAction: (...allowed: readonly Role[]) => AuthFunctions<DataModel, Role>['authAction']\n\tadminQuery: AuthFunctions<DataModel, Role>['authQuery']\n\tadminMutation: AuthFunctions<DataModel, Role>['authMutation']\n\tadminAction: AuthFunctions<DataModel, Role>['authAction']\n\tsystemQuery: CustomBuilder<\n\t\t'query',\n\t\t{},\n\t\tGenericQueryCtx<DataModel> & { include: Include },\n\t\t{},\n\t\tGenericQueryCtx<DataModel>,\n\t\t'internal',\n\t\tobject\n\t>\n\tsystemMutation: CustomBuilder<\n\t\t'mutation',\n\t\t{},\n\t\tGenericMutationCtx<DataModel> & { include: Include },\n\t\t{},\n\t\tGenericMutationCtx<DataModel>,\n\t\t'internal',\n\t\tobject\n\t>\n\tsystemAction: CustomBuilder<\n\t\t'action',\n\t\t{},\n\t\tGenericActionCtx<DataModel>,\n\t\t{},\n\t\tGenericActionCtx<DataModel>,\n\t\t'internal',\n\t\tobject\n\t>\n}\n\n/** Builds an include() that selects the first matching indexed query and bounds the read. */\nexport function createInclude(options?: { errors?: ErrorFactory; maxRows?: number }): Include {\n\tconst errors = options?.errors ?? defaultErrors\n\tconst maxRows = options?.maxRows ?? 100\n\n\tfunction attach<Table extends GenericTableInfo>(\n\t\tquery: QueryInitializer<Table>,\n\t\tselected?: Query<Table>,\n\t): IncludedQuery<Table> {\n\t\tfunction execute(limit: number): Promise<DocumentByInfo<Table>[]>\n\t\tfunction execute<Result>(\n\t\t\tlimit: number,\n\t\t\ttransform: (data: DocumentByInfo<Table>[]) => Result | Promise<Result>,\n\t\t): Promise<Result>\n\t\tasync function execute<Result>(\n\t\t\tlimit: number,\n\t\t\ttransform?: (data: DocumentByInfo<Table>[]) => Result | Promise<Result>,\n\t\t) {\n\t\t\tif (!Number.isSafeInteger(limit) || limit < 1 || limit > maxRows) {\n\t\t\t\treturn errors.throw({\n\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\tmessage: `A bounded query limit must be from 1 to ${maxRows}`,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst data = await (selected ?? query.fullTableScan()).take(limit)\n\t\t\treturn transform ? transform(data) : data\n\t\t}\n\t\tfunction paginate(opts: PaginationOptions): Promise<PaginationResult<DocumentByInfo<Table>>>\n\t\tfunction paginate<Item>(\n\t\t\topts: PaginationOptions,\n\t\t\ttransform: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>,\n\t\t): Promise<PaginationResult<Item>>\n\t\tasync function paginate<Item>(\n\t\t\topts: PaginationOptions,\n\t\t\ttransform?: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>,\n\t\t) {\n\t\t\tif (!Number.isSafeInteger(opts.numItems) || opts.numItems < 1 || opts.numItems > maxRows) {\n\t\t\t\treturn errors.throw({\n\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\tmessage: `A page size must be from 1 to ${maxRows}`,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst result = await (selected ?? query.fullTableScan()).paginate(opts)\n\t\t\treturn transform ? { ...result, page: await transform(result.page) } : result\n\t\t}\n\t\treturn {\n\t\t\twhen: (value, select) =>\n\t\t\t\tselected || value === undefined || value === null\n\t\t\t\t\t? attach(query, selected)\n\t\t\t\t\t: attach(query, select(query, value)),\n\t\t\tmatching: (indexName, indexRange, shouldMatch = true) =>\n\t\t\t\tselected || !shouldMatch\n\t\t\t\t\t? attach(query, selected)\n\t\t\t\t\t: attach(query, query.withIndex(indexName, indexRange)),\n\t\t\totherwise: (select) => selected ?? select(query),\n\t\t\tresolve: () => selected ?? query.fullTableScan(),\n\t\t\texecute,\n\t\t\tpaginate,\n\t\t}\n\t}\n\n\treturn (query) => attach(query)\n}\n\n/**\n * Builds the auth-aware function constructors from the host's injected\n * policy: identity resolution, the app's own role vocabulary, live\n * membership verification for actions, trigger wrapping for mutations,\n * and errors. Role-based access is first-class — every constructor family\n * has a role-gated variant (roleQuery/roleMutation/roleAction), and the\n * admin* constructors are just that gate applied to config.adminRoles.\n */\nexport function createAuthFunctions<\n\tDataModel extends GenericDataModel,\n\tconst Role extends string = DefaultRole,\n>(config: AuthFunctionsConfig<DataModel, Role>): AuthFunctions<DataModel, Role> {\n\tconst errors = config.errors ?? defaultErrors\n\tconst triggers = config.triggers\n\tconst wrapDB = triggers\n\t\t? (ctx: GenericMutationCtx<DataModel>) => triggers.wrapDB(ctx)\n\t\t: (config.wrapDB ?? ((ctx) => ctx))\n\tconst include = createInclude({\n\t\terrors,\n\t\tmaxRows: config.maxIncludedQueryRows,\n\t})\n\n\tasync function authenticatedUser(ctx: AnyAuthContext<DataModel>): Promise<AuthBundle<Role>> {\n\t\tconst identity = await ctx.auth.getUserIdentity()\n\t\tconst user = identity ? await config.getAuthUser(ctx) : null\n\t\tif (!identity || !user) return errors.throw({ code: 'UNAUTHENTICATED' })\n\t\tlet organizationId: string\n\t\tlet organizationRole: string | undefined\n\t\tif (config.resolveOrganization) {\n\t\t\t// The hook is the organization authority — claims are skipped\n\t\t\t// entirely. Authentication fails closed when it errors or abstains.\n\t\t\tlet resolved: { organizationId: string; roleSlug: string } | null = null\n\t\t\ttry {\n\t\t\t\tresolved = await config.resolveOrganization({ ctx, identity, user })\n\t\t\t} catch {\n\t\t\t\t// Authentication fails closed when the hook cannot resolve.\n\t\t\t}\n\t\t\tif (!resolved) return errors.throw({ code: 'FORBIDDEN' })\n\t\t\torganizationId = resolved.organizationId\n\t\t\torganizationRole = resolved.roleSlug\n\t\t} else {\n\t\t\tconst claims = organizationClaims.parse(identity)\n\t\t\tconst claimedOrganizationId = claims.organization?.organizationId ?? claims.org_id\n\t\t\tif (!claimedOrganizationId) return errors.throw({ code: 'UNAUTHENTICATED' })\n\t\t\torganizationId = claimedOrganizationId\n\t\t\torganizationRole = claims.organization?.role ?? claims.role\n\t\t}\n\t\tconst role = config.mapRole(organizationRole)\n\t\tif (!role) return errors.throw({ code: 'FORBIDDEN' })\n\t\tconst base = {\n\t\t\tidentity,\n\t\t\tuser: Object.freeze({ id: user.id }),\n\t\t\torg: Object.freeze({ organizationId, role }),\n\t\t\trole,\n\t\t\tactor: Object.freeze({ userId: user.id, organizationId, role }),\n\t\t}\n\t\treturn Object.freeze({\n\t\t\t...base,\n\t\t\ttenant: config.security?.tenancy?.resolve?.(base) ?? organizationId,\n\t\t})\n\t}\n\n\tconst securityConfig: RLSConfig | undefined = config.security\n\t\t? {\n\t\t\t\tdefaultPolicy:\n\t\t\t\t\tconfig.security.defaultPolicy ?? (config.security.tenancy ? 'deny' : 'allow'),\n\t\t\t}\n\t\t: undefined\n\n\tfunction securityRules(bundle: AuthBundle<Role>): Rules<unknown, DataModel> | undefined {\n\t\tconst security = config.security\n\t\tif (!security) return undefined\n\t\tconst sets: Rules<unknown, DataModel>[] = []\n\t\tif (security.tenancy) {\n\t\t\tsets.push(createTenantRules<DataModel>(bundle.tenant, security.tenancy.tables))\n\t\t}\n\t\tif (security.rules) sets.push(security.rules(bundle))\n\t\treturn sets.length === 1 ? sets[0] : composeRules(...sets)\n\t}\n\n\tfunction secureReader(\n\t\tctx: GenericQueryCtx<DataModel>,\n\t\tbundle: AuthBundle<Role>,\n\t): GenericQueryCtx<DataModel> {\n\t\tconst rules = securityRules(bundle)\n\t\tif (!rules) return ctx\n\t\treturn {\n\t\t\t...ctx,\n\t\t\tdb: wrapDatabaseReader({}, ctx.db, rules, securityConfig),\n\t\t}\n\t}\n\n\tfunction secureWriter(\n\t\tctx: GenericMutationCtx<DataModel>,\n\t\tbundle: AuthBundle<Role>,\n\t): GenericMutationCtx<DataModel> {\n\t\tconst rules = securityRules(bundle)\n\t\tif (!rules) return ctx\n\t\t// Triggers wrap first (ctx already trigger-wrapped by the caller),\n\t\t// then row-level security wraps the triggered db — order matters.\n\t\treturn {\n\t\t\t...ctx,\n\t\t\tdb: wrapDatabaseWriter({}, ctx.db, rules, securityConfig),\n\t\t}\n\t}\n\n\tasync function verifiedMembership(userId: string, organizationId: string) {\n\t\tif (!config.verifyMembership) return null\n\t\ttry {\n\t\t\tconst membership = await config.verifyMembership({\n\t\t\t\tuserId,\n\t\t\t\torganizationId,\n\t\t\t})\n\t\t\tif (membership && membership.organizationId === organizationId) {\n\t\t\t\treturn membership\n\t\t\t}\n\t\t} catch {\n\t\t\t// Authentication fails closed when membership cannot be verified.\n\t\t}\n\t\treturn errors.throw({ code: 'FORBIDDEN' })\n\t}\n\n\tfunction requireRole(role: Role, allowed: readonly Role[]) {\n\t\tif (!allowed.includes(role)) return errors.throw({ code: 'FORBIDDEN' })\n\t}\n\n\tasync function queryInput(ctx: GenericQueryCtx<DataModel>) {\n\t\tconst bundle = await authenticatedUser(ctx)\n\t\treturn {\n\t\t\tctx: { ...secureReader(ctx, bundle), include, ...bundle },\n\t\t\targs: {},\n\t\t}\n\t}\n\n\tasync function mutationInput(ctx: GenericMutationCtx<DataModel>) {\n\t\tconst bundle = await authenticatedUser(ctx)\n\t\treturn {\n\t\t\tctx: { ...secureWriter(wrapDB(ctx), bundle), include, ...bundle },\n\t\t\targs: {},\n\t\t}\n\t}\n\n\tasync function actionInput(ctx: GenericActionCtx<DataModel>) {\n\t\tconst authenticated = await authenticatedUser(ctx)\n\t\tconst membership = await verifiedMembership(\n\t\t\tauthenticated.user.id,\n\t\t\tauthenticated.org.organizationId,\n\t\t)\n\t\tif (!membership) return { ctx: { ...ctx, ...authenticated }, args: {} }\n\t\tconst role = config.mapRole(membership.roleSlug)\n\t\tif (!role) return errors.throw({ code: 'FORBIDDEN' })\n\t\tconst verified = {\n\t\t\tidentity: authenticated.identity,\n\t\t\tuser: authenticated.user,\n\t\t\torg: Object.freeze({\n\t\t\t\torganizationId: membership.organizationId,\n\t\t\t\trole,\n\t\t\t}),\n\t\t\trole,\n\t\t\tactor: Object.freeze({\n\t\t\t\tuserId: authenticated.user.id,\n\t\t\t\torganizationId: membership.organizationId,\n\t\t\t\trole,\n\t\t\t}),\n\t\t}\n\t\treturn {\n\t\t\tctx: {\n\t\t\t\t...ctx,\n\t\t\t\t...verified,\n\t\t\t\t// Tenant re-derives from the live-verified organization.\n\t\t\t\ttenant: config.security?.tenancy?.resolve?.(verified) ?? membership.organizationId,\n\t\t\t},\n\t\t\targs: {},\n\t\t}\n\t}\n\n\t/** Query constructor allowing only the given roles. */\n\tfunction roleQuery(...allowed: readonly Role[]) {\n\t\treturn zCustomQuery(config.query, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => {\n\t\t\t\tconst authenticated = await queryInput(ctx)\n\t\t\t\trequireRole(authenticated.ctx.actor.role, allowed)\n\t\t\t\treturn authenticated\n\t\t\t},\n\t\t})\n\t}\n\n\t/** Mutation constructor allowing only the given roles. */\n\tfunction roleMutation(...allowed: readonly Role[]) {\n\t\treturn zCustomMutation(config.mutation, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => {\n\t\t\t\tconst authenticated = await mutationInput(ctx)\n\t\t\t\trequireRole(authenticated.ctx.actor.role, allowed)\n\t\t\t\treturn authenticated\n\t\t\t},\n\t\t})\n\t}\n\n\t/** Action constructor allowing only the given roles (post live verification). */\n\tfunction roleAction(...allowed: readonly Role[]) {\n\t\treturn zCustomAction(config.action, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => {\n\t\t\t\tconst authenticated = await actionInput(ctx)\n\t\t\t\trequireRole(authenticated.ctx.actor.role, allowed)\n\t\t\t\treturn authenticated\n\t\t\t},\n\t\t})\n\t}\n\n\treturn {\n\t\tinclude,\n\t\tauthenticatedUser,\n\t\troleQuery,\n\t\troleMutation,\n\t\troleAction,\n\t\tauthQuery: zCustomQuery(config.query, { args: {}, input: queryInput }),\n\t\tauthMutation: zCustomMutation(config.mutation, {\n\t\t\targs: {},\n\t\t\tinput: mutationInput,\n\t\t}),\n\t\tauthAction: zCustomAction(config.action, {\n\t\t\targs: {},\n\t\t\tinput: actionInput,\n\t\t}),\n\t\tadminQuery: roleQuery(...config.adminRoles),\n\t\tadminMutation: roleMutation(...config.adminRoles),\n\t\tadminAction: roleAction(...config.adminRoles),\n\t\tsystemQuery: zCustomQuery(config.internalQuery, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => ({ ctx: { ...ctx, include }, args: {} }),\n\t\t}),\n\t\tsystemMutation: zCustomMutation(config.internalMutation, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => ({ ctx: { ...wrapDB(ctx), include }, args: {} }),\n\t\t}),\n\t\tsystemAction: zCustomAction(config.internalAction, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => ({ ctx, args: {} }),\n\t\t}),\n\t}\n}\n\nconst organizationClaims = z.object({\n\torganization: z\n\t\t.object({\n\t\t\torganizationId: z.string().optional().catch(undefined),\n\t\t\trole: z.string().optional().catch(undefined),\n\t\t})\n\t\t.optional()\n\t\t.catch(undefined),\n\torg_id: z.string().optional().catch(undefined),\n\trole: z.string().optional().catch(undefined),\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"auth.mjs","names":["defaultRoleMap","normalized","roleSlug","createInclude","errors","options","defaultErrors","maxRows","attach","execute","limit","data","selected","query","transform","paginate","opts","result","value","select","shouldMatch","indexName","indexRange","createAuthFunctions","config","triggers","wrapDB","ctx","include","authenticatedUser","identity","user","organizationId","organizationRole","resolved","claims","organizationClaims","claimedOrganizationId","role","base","securityConfig","securityRules","security","sets","createTenantRules","bundle","composeRules","secureReader","rules","defaultPolicy","ordinary","wrapDatabaseReader","suppliedPolicyRules","registerQueryReader","secureWriter","wrapDatabaseWriter","verifiedMembership","membership","requireRole","allowed","queryInput","mutationInput","actionInput","authenticated","verified","roleQuery","zCustomQuery","roleMutation","zCustomMutation","roleAction","zCustomAction","z"],"sources":["../src/auth.ts"],"sourcesContent":["import { z } from 'zod'\nimport { zCustomAction, zCustomMutation, zCustomQuery } from './zod-registration'\nimport type { CustomBuilder } from 'convex-helpers/server/zod4'\nimport type {\n\tActionBuilder,\n\tDocumentByInfo,\n\tPaginationOptions,\n\tPaginationResult,\n\tGenericActionCtx,\n\tGenericDataModel,\n\tGenericMutationCtx,\n\tGenericQueryCtx,\n\tGenericTableInfo,\n\tIndexNames,\n\tIndexRange,\n\tIndexRangeBuilder,\n\tMutationBuilder,\n\tNamedIndex,\n\tQuery,\n\tQueryBuilder,\n\tQueryInitializer,\n\tUserIdentity,\n} from 'convex/server'\nimport type { Triggers } from 'convex-helpers/server/triggers'\nimport type { TableNamesInDataModel } from 'convex/server'\nimport { defaultErrors, type ErrorFactory } from './errors'\nimport {\n\tregisterQueryReader,\n\tsuppliedPolicyRules,\n\ttype SecurityPolicyContext,\n} from './querying/security'\nexport type { SecurityPolicyContext } from './querying/security'\nimport {\n\tcomposeRules,\n\tcreateTenantRules,\n\twrapDatabaseReader,\n\twrapDatabaseWriter,\n\ttype RLSConfig,\n\ttype Rules,\n} from './tenancy'\n\n/** The default vocabulary; every app can supply its own via the Role generic. */\nexport type DefaultRole = 'reader' | 'writer' | 'admin'\n\nexport type Actor<Role extends string> = Readonly<{\n\tuserId: string\n\torganizationId: string\n\trole: Role\n}>\n\nexport type AuthBundle<Role extends string> = Readonly<{\n\tidentity: UserIdentity\n\tuser: Readonly<{ id: string }>\n\torg: Readonly<{ organizationId: string; role: Role }>\n\trole: Role\n\tactor: Actor<Role>\n\t/** The resolved tenant — security.tenancy.resolve, or the organization id. */\n\ttenant: string\n}>\n\n/**\n * Row-level security configuration. Tenant isolation and role-level rules\n * compose (AND) onto the same wrapped database: queries get a wrapped\n * reader, mutations get triggers first, then a wrapped writer.\n */\nexport type SecurityConfig<DataModel extends GenericDataModel, Role extends string> = {\n\t/**\n\t * Tenant isolation. `tables` is THE registry: every listed table gets\n\t * read/insert/modify gated on row.tenant === ctx.tenant. Pair with\n\t * tenantTable (schema) and tenantOwnership (triggers) on the same list.\n\t */\n\ttenancy?: {\n\t\ttables: readonly TableNamesInDataModel<DataModel>[]\n\t\t/** Maps the auth bundle to the tenant; defaults to org.organizationId. */\n\t\tresolve?: (bundle: Omit<AuthBundle<Role>, 'tenant'>) => string\n\t}\n\t/**\n\t * Role-level (or any policy) rules derived from the authenticated bundle,\n\t * composed AND-wise with tenant isolation. E.g. gate `modify` on a table\n\t * to admin roles.\n\t */\n\trules?: (bundle: AuthBundle<Role>) => Rules<SecurityPolicyContext<DataModel>, DataModel>\n\t/**\n\t * Policy for tables with no rule. Defaults to 'deny' when tenancy is\n\t * configured (unlisted tables are unreachable — fail closed), 'allow'\n\t * otherwise.\n\t */\n\tdefaultPolicy?: RLSConfig['defaultPolicy']\n}\n\ntype AnyAuthContext<DataModel extends GenericDataModel> =\n\t| GenericQueryCtx<DataModel>\n\t| GenericMutationCtx<DataModel>\n\t| GenericActionCtx<DataModel>\n\nexport type AuthFunctionsConfig<DataModel extends GenericDataModel, Role extends string> = {\n\t/** The consumer's generated function builders (from ./_generated/server). */\n\tquery: QueryBuilder<DataModel, 'public'>\n\tmutation: MutationBuilder<DataModel, 'public'>\n\taction: ActionBuilder<DataModel, 'public'>\n\tinternalQuery: QueryBuilder<DataModel, 'internal'>\n\tinternalMutation: MutationBuilder<DataModel, 'internal'>\n\tinternalAction: ActionBuilder<DataModel, 'internal'>\n\t/** Resolves the synchronized principal, e.g. (ctx) => authKit.getAuthUser(ctx). */\n\tgetAuthUser: (ctx: AnyAuthContext<DataModel>) => Promise<{ id: string } | null>\n\t/**\n\t * Maps an identity role slug onto the app's role vocabulary. Returning\n\t * null rejects the caller with FORBIDDEN — unknown roles never pass.\n\t */\n\tmapRole: (roleSlug?: string) => Role | null\n\t/** Roles allowed through the admin* constructors. */\n\tadminRoles: readonly NoInfer<Role>[]\n\t/**\n\t * Live membership check for actions (queries/mutations trust the JWT).\n\t * Authentication fails closed with FORBIDDEN when verification errors.\n\t * Omit to let actions trust the JWT like queries do.\n\t */\n\tverifyMembership?: (input: {\n\t\tuserId: string\n\t\torganizationId: string\n\t}) => Promise<{ organizationId: string; roleSlug: string } | null>\n\t/**\n\t * Resolves organization authority from the app's own data for identity\n\t * providers whose tokens carry no org claims. When configured, its result\n\t * overrides claim-based resolution; null or an error rejects with FORBIDDEN\n\t * (fail closed). In actions the ctx has no db — resolve via ctx.runQuery.\n\t */\n\tresolveOrganization?: (input: {\n\t\tctx: AnyAuthContext<DataModel>\n\t\tidentity: UserIdentity\n\t\tuser: { id: string }\n\t}) => Promise<{ organizationId: string; roleSlug: string } | null>\n\t/** Host error policy; defaults to throwing KitError. */\n\terrors?: ErrorFactory\n\t/**\n\t * Application trigger registry. When set, every authMutation,\n\t * roleMutation, and systemMutation write runs through triggers.wrapDB —\n\t * evaluations registered on tables fire structurally.\n\t */\n\ttriggers?: Triggers<DataModel>\n\t/** Lower-level alternative to `triggers`: a custom ctx wrapper. */\n\twrapDB?: (ctx: GenericMutationCtx<DataModel>) => GenericMutationCtx<DataModel>\n\t/** Upper bound for include() reads. */\n\tmaxIncludedQueryRows?: number\n\t/**\n\t * Row-level security: tenant isolation (from a table registry) and\n\t * role-level rules, applied structurally inside every auth*, role*, and\n\t * admin* constructor. system* constructors stay unwrapped (trusted).\n\t */\n\tsecurity?: SecurityConfig<DataModel, Role>\n}\n\n/** WorkOS-style default: `member` writes; reader/writer/admin pass through. */\nexport function defaultRoleMap(roleSlug?: string): DefaultRole | null {\n\tconst normalized = roleSlug?.trim().toLowerCase()\n\tif (normalized === 'member') return 'writer'\n\treturn normalized === 'reader' || normalized === 'writer' || normalized === 'admin'\n\t\t? normalized\n\t\t: null\n}\n\nexport type IncludedQuery<Table extends GenericTableInfo> = {\n\twhen<Value>(\n\t\tvalue: Value | null | undefined,\n\t\tselect: (query: QueryInitializer<Table>, value: Value) => Query<Table>,\n\t): IncludedQuery<Table>\n\tmatching<IndexName extends IndexNames<Table>>(\n\t\tindexName: IndexName,\n\t\tindexRange?: (\n\t\t\tquery: IndexRangeBuilder<DocumentByInfo<Table>, NamedIndex<Table, IndexName>>,\n\t\t) => IndexRange,\n\t\tshouldMatch?: boolean,\n\t): IncludedQuery<Table>\n\totherwise(select: (query: QueryInitializer<Table>) => Query<Table>): Query<Table>\n\tresolve(): Query<Table>\n\texecute(limit: number): Promise<DocumentByInfo<Table>[]>\n\texecute<Result>(\n\t\tlimit: number,\n\t\ttransform: (data: Awaited<ReturnType<Query<Table>['take']>>) => Result | Promise<Result>,\n\t): Promise<Result>\n\t/**\n\t * Cursor pagination over the selected indexed query. numItems is bounded\n\t * by the same maxRows policy as execute(). Under row-level security a\n\t * page may be shorter than numItems (rejected rows are filtered after\n\t * pagination); cursors remain correct. Pair with paginated(dto) from\n\t * cvx-kit/zod-table for the boundary schemas.\n\t */\n\tpaginate(opts: PaginationOptions): Promise<PaginationResult<DocumentByInfo<Table>>>\n\tpaginate<Item>(\n\t\topts: PaginationOptions,\n\t\ttransform: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>,\n\t): Promise<PaginationResult<Item>>\n}\n\nexport type Include = <Table extends GenericTableInfo>(\n\tquery: QueryInitializer<Table>,\n) => IncludedQuery<Table>\n\n/**\n * Keep native contexts symbolic in published declarations. Inferred spreads\n * copy build-time Convex methods and override the consumer's native context.\n */\nexport type AuthFunctions<DataModel extends GenericDataModel, Role extends string = DefaultRole> = {\n\tinclude: Include\n\tauthenticatedUser: (ctx: AnyAuthContext<DataModel>) => Promise<AuthBundle<Role>>\n\tauthQuery: CustomBuilder<\n\t\t'query',\n\t\t{},\n\t\tGenericQueryCtx<DataModel> & AuthBundle<Role> & { include: Include },\n\t\t{},\n\t\tGenericQueryCtx<DataModel>,\n\t\t'public',\n\t\tobject\n\t>\n\tauthMutation: CustomBuilder<\n\t\t'mutation',\n\t\t{},\n\t\tGenericMutationCtx<DataModel> & AuthBundle<Role> & { include: Include },\n\t\t{},\n\t\tGenericMutationCtx<DataModel>,\n\t\t'public',\n\t\tobject\n\t>\n\tauthAction: CustomBuilder<\n\t\t'action',\n\t\t{},\n\t\tGenericActionCtx<DataModel> & AuthBundle<Role>,\n\t\t{},\n\t\tGenericActionCtx<DataModel>,\n\t\t'public',\n\t\tobject\n\t>\n\troleQuery: (...allowed: readonly Role[]) => AuthFunctions<DataModel, Role>['authQuery']\n\troleMutation: (...allowed: readonly Role[]) => AuthFunctions<DataModel, Role>['authMutation']\n\troleAction: (...allowed: readonly Role[]) => AuthFunctions<DataModel, Role>['authAction']\n\tadminQuery: AuthFunctions<DataModel, Role>['authQuery']\n\tadminMutation: AuthFunctions<DataModel, Role>['authMutation']\n\tadminAction: AuthFunctions<DataModel, Role>['authAction']\n\tsystemQuery: CustomBuilder<\n\t\t'query',\n\t\t{},\n\t\tGenericQueryCtx<DataModel> & { include: Include },\n\t\t{},\n\t\tGenericQueryCtx<DataModel>,\n\t\t'internal',\n\t\tobject\n\t>\n\tsystemMutation: CustomBuilder<\n\t\t'mutation',\n\t\t{},\n\t\tGenericMutationCtx<DataModel> & { include: Include },\n\t\t{},\n\t\tGenericMutationCtx<DataModel>,\n\t\t'internal',\n\t\tobject\n\t>\n\tsystemAction: CustomBuilder<\n\t\t'action',\n\t\t{},\n\t\tGenericActionCtx<DataModel>,\n\t\t{},\n\t\tGenericActionCtx<DataModel>,\n\t\t'internal',\n\t\tobject\n\t>\n}\n\n/** Builds an include() that selects the first matching indexed query and bounds the read. */\nexport function createInclude(options?: { errors?: ErrorFactory; maxRows?: number }): Include {\n\tconst errors = options?.errors ?? defaultErrors\n\tconst maxRows = options?.maxRows ?? 100\n\n\tfunction attach<Table extends GenericTableInfo>(\n\t\tquery: QueryInitializer<Table>,\n\t\tselected?: Query<Table>,\n\t): IncludedQuery<Table> {\n\t\tfunction execute(limit: number): Promise<DocumentByInfo<Table>[]>\n\t\tfunction execute<Result>(\n\t\t\tlimit: number,\n\t\t\ttransform: (data: DocumentByInfo<Table>[]) => Result | Promise<Result>,\n\t\t): Promise<Result>\n\t\tasync function execute<Result>(\n\t\t\tlimit: number,\n\t\t\ttransform?: (data: DocumentByInfo<Table>[]) => Result | Promise<Result>,\n\t\t) {\n\t\t\tif (!Number.isSafeInteger(limit) || limit < 1 || limit > maxRows) {\n\t\t\t\treturn errors.throw({\n\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\tmessage: `A bounded query limit must be from 1 to ${maxRows}`,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst data = await (selected ?? query.fullTableScan()).take(limit)\n\t\t\treturn transform ? transform(data) : data\n\t\t}\n\t\tfunction paginate(opts: PaginationOptions): Promise<PaginationResult<DocumentByInfo<Table>>>\n\t\tfunction paginate<Item>(\n\t\t\topts: PaginationOptions,\n\t\t\ttransform: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>,\n\t\t): Promise<PaginationResult<Item>>\n\t\tasync function paginate<Item>(\n\t\t\topts: PaginationOptions,\n\t\t\ttransform?: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>,\n\t\t) {\n\t\t\tif (!Number.isSafeInteger(opts.numItems) || opts.numItems < 1 || opts.numItems > maxRows) {\n\t\t\t\treturn errors.throw({\n\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\tmessage: `A page size must be from 1 to ${maxRows}`,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst result = await (selected ?? query.fullTableScan()).paginate(opts)\n\t\t\treturn transform ? { ...result, page: await transform(result.page) } : result\n\t\t}\n\t\treturn {\n\t\t\twhen: (value, select) =>\n\t\t\t\tselected || value === undefined || value === null\n\t\t\t\t\t? attach(query, selected)\n\t\t\t\t\t: attach(query, select(query, value)),\n\t\t\tmatching: (indexName, indexRange, shouldMatch = true) =>\n\t\t\t\tselected || !shouldMatch\n\t\t\t\t\t? attach(query, selected)\n\t\t\t\t\t: attach(query, query.withIndex(indexName, indexRange)),\n\t\t\totherwise: (select) => selected ?? select(query),\n\t\t\tresolve: () => selected ?? query.fullTableScan(),\n\t\t\texecute,\n\t\t\tpaginate,\n\t\t}\n\t}\n\n\treturn (query) => attach(query)\n}\n\n/**\n * Builds the auth-aware function constructors from the host's injected\n * policy: identity resolution, the app's own role vocabulary, live\n * membership verification for actions, trigger wrapping for mutations,\n * and errors. Role-based access is first-class — every constructor family\n * has a role-gated variant (roleQuery/roleMutation/roleAction), and the\n * admin* constructors are just that gate applied to config.adminRoles.\n */\nexport function createAuthFunctions<\n\tDataModel extends GenericDataModel,\n\tconst Role extends string = DefaultRole,\n>(config: AuthFunctionsConfig<DataModel, Role>): AuthFunctions<DataModel, Role> {\n\tconst errors = config.errors ?? defaultErrors\n\tconst triggers = config.triggers\n\tconst wrapDB = triggers\n\t\t? (ctx: GenericMutationCtx<DataModel>) => triggers.wrapDB(ctx)\n\t\t: (config.wrapDB ?? ((ctx) => ctx))\n\tconst include = createInclude({\n\t\terrors,\n\t\tmaxRows: config.maxIncludedQueryRows,\n\t})\n\n\tasync function authenticatedUser(ctx: AnyAuthContext<DataModel>): Promise<AuthBundle<Role>> {\n\t\tconst identity = await ctx.auth.getUserIdentity()\n\t\tconst user = identity ? await config.getAuthUser(ctx) : null\n\t\tif (!identity || !user) return errors.throw({ code: 'UNAUTHENTICATED' })\n\t\tlet organizationId: string\n\t\tlet organizationRole: string | undefined\n\t\tif (config.resolveOrganization) {\n\t\t\t// The hook is the organization authority — claims are skipped\n\t\t\t// entirely. Authentication fails closed when it errors or abstains.\n\t\t\tlet resolved: { organizationId: string; roleSlug: string } | null = null\n\t\t\ttry {\n\t\t\t\tresolved = await config.resolveOrganization({ ctx, identity, user })\n\t\t\t} catch {\n\t\t\t\t// Authentication fails closed when the hook cannot resolve.\n\t\t\t}\n\t\t\tif (!resolved) return errors.throw({ code: 'FORBIDDEN' })\n\t\t\torganizationId = resolved.organizationId\n\t\t\torganizationRole = resolved.roleSlug\n\t\t} else {\n\t\t\tconst claims = organizationClaims.parse(identity)\n\t\t\tconst claimedOrganizationId = claims.organization?.organizationId ?? claims.org_id\n\t\t\tif (!claimedOrganizationId) return errors.throw({ code: 'UNAUTHENTICATED' })\n\t\t\torganizationId = claimedOrganizationId\n\t\t\torganizationRole = claims.organization?.role ?? claims.role\n\t\t}\n\t\tconst role = config.mapRole(organizationRole)\n\t\tif (!role) return errors.throw({ code: 'FORBIDDEN' })\n\t\tconst base = {\n\t\t\tidentity,\n\t\t\tuser: Object.freeze({ id: user.id }),\n\t\t\torg: Object.freeze({ organizationId, role }),\n\t\t\trole,\n\t\t\tactor: Object.freeze({ userId: user.id, organizationId, role }),\n\t\t}\n\t\treturn Object.freeze({\n\t\t\t...base,\n\t\t\ttenant: config.security?.tenancy?.resolve?.(base) ?? organizationId,\n\t\t})\n\t}\n\n\tconst securityConfig: RLSConfig | undefined = config.security\n\t\t? {\n\t\t\t\tdefaultPolicy:\n\t\t\t\t\tconfig.security.defaultPolicy ?? (config.security.tenancy ? 'deny' : 'allow'),\n\t\t\t}\n\t\t: undefined\n\n\tfunction securityRules(\n\t\tbundle: AuthBundle<Role>,\n\t): Rules<SecurityPolicyContext<DataModel>, DataModel> | undefined {\n\t\tconst security = config.security\n\t\tif (!security) return undefined\n\t\tconst sets: Rules<SecurityPolicyContext<DataModel>, DataModel>[] = []\n\t\tif (security.tenancy) {\n\t\t\tsets.push(createTenantRules<DataModel>(bundle.tenant, security.tenancy.tables))\n\t\t}\n\t\tif (security.rules) sets.push(security.rules(bundle))\n\t\treturn sets.length === 1 ? sets[0] : composeRules(...sets)\n\t}\n\n\tfunction secureReader(\n\t\tctx: GenericQueryCtx<DataModel>,\n\t\tbundle: AuthBundle<Role>,\n\t): GenericQueryCtx<DataModel> {\n\t\tconst rules = securityRules(bundle)\n\t\tconst defaultPolicy = securityConfig?.defaultPolicy ?? 'allow'\n\t\tconst ordinary = rules\n\t\t\t? wrapDatabaseReader(\n\t\t\t\t\t{ db: ctx.db },\n\t\t\t\t\tctx.db,\n\t\t\t\t\tsuppliedPolicyRules(ctx.db, rules, defaultPolicy),\n\t\t\t\t\tsecurityConfig,\n\t\t\t\t)\n\t\t\t: ctx.db\n\t\treturn {\n\t\t\t...ctx,\n\t\t\tdb: registerQueryReader(ctx.db, ordinary, {\n\t\t\t\tscope: {\n\t\t\t\t\tmode: 'authenticated',\n\t\t\t\t\tprincipal: bundle.user.id,\n\t\t\t\t\torganization: bundle.org.organizationId,\n\t\t\t\t\ttenant: bundle.tenant,\n\t\t\t\t\trole: bundle.role,\n\t\t\t\t},\n\t\t\t\trules: rules ?? {},\n\t\t\t\tdefaultPolicy,\n\t\t\t}),\n\t\t}\n\t}\n\n\tfunction secureWriter(\n\t\tctx: GenericMutationCtx<DataModel>,\n\t\tbundle: AuthBundle<Role>,\n\t): GenericMutationCtx<DataModel> {\n\t\tconst rules = securityRules(bundle)\n\t\tif (!rules) return ctx\n\t\t// Triggers wrap first (ctx already trigger-wrapped by the caller),\n\t\t// then row-level security wraps the triggered db — order matters.\n\t\treturn {\n\t\t\t...ctx,\n\t\t\tdb: wrapDatabaseWriter(\n\t\t\t\t{ db: ctx.db },\n\t\t\t\tctx.db,\n\t\t\t\tsuppliedPolicyRules(ctx.db, rules, securityConfig?.defaultPolicy ?? 'allow'),\n\t\t\t\tsecurityConfig,\n\t\t\t),\n\t\t}\n\t}\n\n\tasync function verifiedMembership(userId: string, organizationId: string) {\n\t\tif (!config.verifyMembership) return null\n\t\ttry {\n\t\t\tconst membership = await config.verifyMembership({\n\t\t\t\tuserId,\n\t\t\t\torganizationId,\n\t\t\t})\n\t\t\tif (membership && membership.organizationId === organizationId) {\n\t\t\t\treturn membership\n\t\t\t}\n\t\t} catch {\n\t\t\t// Authentication fails closed when membership cannot be verified.\n\t\t}\n\t\treturn errors.throw({ code: 'FORBIDDEN' })\n\t}\n\n\tfunction requireRole(role: Role, allowed: readonly Role[]) {\n\t\tif (!allowed.includes(role)) return errors.throw({ code: 'FORBIDDEN' })\n\t}\n\n\tasync function queryInput(ctx: GenericQueryCtx<DataModel>) {\n\t\tconst bundle = await authenticatedUser(ctx)\n\t\treturn {\n\t\t\tctx: { ...secureReader(ctx, bundle), include, ...bundle },\n\t\t\targs: {},\n\t\t}\n\t}\n\n\tasync function mutationInput(ctx: GenericMutationCtx<DataModel>) {\n\t\tconst bundle = await authenticatedUser(ctx)\n\t\treturn {\n\t\t\tctx: { ...secureWriter(wrapDB(ctx), bundle), include, ...bundle },\n\t\t\targs: {},\n\t\t}\n\t}\n\n\tasync function actionInput(ctx: GenericActionCtx<DataModel>) {\n\t\tconst authenticated = await authenticatedUser(ctx)\n\t\tconst membership = await verifiedMembership(\n\t\t\tauthenticated.user.id,\n\t\t\tauthenticated.org.organizationId,\n\t\t)\n\t\tif (!membership) return { ctx: { ...ctx, ...authenticated }, args: {} }\n\t\tconst role = config.mapRole(membership.roleSlug)\n\t\tif (!role) return errors.throw({ code: 'FORBIDDEN' })\n\t\tconst verified = {\n\t\t\tidentity: authenticated.identity,\n\t\t\tuser: authenticated.user,\n\t\t\torg: Object.freeze({\n\t\t\t\torganizationId: membership.organizationId,\n\t\t\t\trole,\n\t\t\t}),\n\t\t\trole,\n\t\t\tactor: Object.freeze({\n\t\t\t\tuserId: authenticated.user.id,\n\t\t\t\torganizationId: membership.organizationId,\n\t\t\t\trole,\n\t\t\t}),\n\t\t}\n\t\treturn {\n\t\t\tctx: {\n\t\t\t\t...ctx,\n\t\t\t\t...verified,\n\t\t\t\t// Tenant re-derives from the live-verified organization.\n\t\t\t\ttenant: config.security?.tenancy?.resolve?.(verified) ?? membership.organizationId,\n\t\t\t},\n\t\t\targs: {},\n\t\t}\n\t}\n\n\t/** Query constructor allowing only the given roles. */\n\tfunction roleQuery(...allowed: readonly Role[]) {\n\t\treturn zCustomQuery(config.query, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => {\n\t\t\t\tconst authenticated = await queryInput(ctx)\n\t\t\t\trequireRole(authenticated.ctx.actor.role, allowed)\n\t\t\t\treturn authenticated\n\t\t\t},\n\t\t})\n\t}\n\n\t/** Mutation constructor allowing only the given roles. */\n\tfunction roleMutation(...allowed: readonly Role[]) {\n\t\treturn zCustomMutation(config.mutation, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => {\n\t\t\t\tconst authenticated = await mutationInput(ctx)\n\t\t\t\trequireRole(authenticated.ctx.actor.role, allowed)\n\t\t\t\treturn authenticated\n\t\t\t},\n\t\t})\n\t}\n\n\t/** Action constructor allowing only the given roles (post live verification). */\n\tfunction roleAction(...allowed: readonly Role[]) {\n\t\treturn zCustomAction(config.action, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => {\n\t\t\t\tconst authenticated = await actionInput(ctx)\n\t\t\t\trequireRole(authenticated.ctx.actor.role, allowed)\n\t\t\t\treturn authenticated\n\t\t\t},\n\t\t})\n\t}\n\n\treturn {\n\t\tinclude,\n\t\tauthenticatedUser,\n\t\troleQuery,\n\t\troleMutation,\n\t\troleAction,\n\t\tauthQuery: zCustomQuery(config.query, { args: {}, input: queryInput }),\n\t\tauthMutation: zCustomMutation(config.mutation, {\n\t\t\targs: {},\n\t\t\tinput: mutationInput,\n\t\t}),\n\t\tauthAction: zCustomAction(config.action, {\n\t\t\targs: {},\n\t\t\tinput: actionInput,\n\t\t}),\n\t\tadminQuery: roleQuery(...config.adminRoles),\n\t\tadminMutation: roleMutation(...config.adminRoles),\n\t\tadminAction: roleAction(...config.adminRoles),\n\t\tsystemQuery: zCustomQuery(config.internalQuery, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => ({\n\t\t\t\tctx: {\n\t\t\t\t\t...ctx,\n\t\t\t\t\tinclude,\n\t\t\t\t\tdb: registerQueryReader(ctx.db, ctx.db, {\n\t\t\t\t\t\tscope: {\n\t\t\t\t\t\t\tmode: 'system',\n\t\t\t\t\t\t\tprincipal: null,\n\t\t\t\t\t\t\torganization: null,\n\t\t\t\t\t\t\ttenant: null,\n\t\t\t\t\t\t\trole: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t\trules: {},\n\t\t\t\t\t\tdefaultPolicy: 'allow',\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\targs: {},\n\t\t\t}),\n\t\t}),\n\t\tsystemMutation: zCustomMutation(config.internalMutation, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => ({ ctx: { ...wrapDB(ctx), include }, args: {} }),\n\t\t}),\n\t\tsystemAction: zCustomAction(config.internalAction, {\n\t\t\targs: {},\n\t\t\tinput: async (ctx) => ({ ctx, args: {} }),\n\t\t}),\n\t}\n}\n\nconst organizationClaims = z.object({\n\torganization: z\n\t\t.object({\n\t\t\torganizationId: z.string().optional().catch(undefined),\n\t\t\trole: z.string().optional().catch(undefined),\n\t\t})\n\t\t.optional()\n\t\t.catch(undefined),\n\torg_id: z.string().optional().catch(undefined),\n\trole: z.string().optional().catch(undefined),\n})\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -5,10 +5,13 @@ import { Actor, AuthBundle, AuthFunctions, AuthFunctionsConfig, DefaultRole, Inc
5
5
  import { AnyQueryMiddleware, QueryMiddleware } from "./components/foundation/modules/query/query.mjs";
6
6
  import { AnyCommandMiddleware, ApplicationCommand, AuditEntryInput, AuditWriter, AuditedOperation, AuditedRegistry, CommandConstructor, CommandDefaults, CommandMiddleware, Foundation, FoundationOptions, PermissionChecker } from "./components/foundation/client.mjs";
7
7
  import { CrudConfig, createCrudCommands } from "./crud.mjs";
8
- import { TIMESTAMP_FIELDS, TableBoundaryOptions, createModule, jsonSafeZid, paginated, tenantTable, zodTable, zodVariantTable } from "./zod-table.mjs";
8
+ import { ScalarFilters, ScalarSelection, ServerFilter } from "./querying/filters.mjs";
9
+ import { DtoOptions, TIMESTAMP_FIELDS, TableBoundaryOptions, createModule, jsonSafeZid, paginated, tenantTable, zodTable, zodVariantTable } from "./zod-table.mjs";
9
10
  import { RateLimiterLike, rateLimit } from "./middleware.mjs";
10
11
  import { WebhookBoundaryConfig, createWebhookBoundary, recordWebhookEvent, webhookEventsTable } from "./webhooks.mjs";
11
12
  import { createStateMachine } from "./state-machine.mjs";
12
13
  import { Change, Trigger, Triggers, appendOnly, createTriggers, noDelete, tenantOwnership, timestamps } from "./triggers.mjs";
13
14
  import { FoundationRegistry, FoundationRegistryOptions, createFoundation } from "./modules/foundation/foundation.mjs";
14
- export { type Actor, type AgentToolHandlers, type AgentToolRecord, type AnyCommandMiddleware, type AnyQueryMiddleware, type ApplicationCommand, type AuditEntryInput, type AuditWriter, type AuditedOperation, type AuditedRegistry, type AuthBundle, type AuthFunctions, type AuthFunctionsConfig, type Change, type CommandConstructor, type CommandDefaults, type CommandMiddleware, type CrudConfig, type DefaultRole, type ErrorFactory, Foundation, type FoundationOptions, type FoundationRegistry, type FoundationRegistryOptions, type Include, type IncludedQuery, KitError, type PermissionChecker, type QueryMiddleware, type RLSConfig, type RateLimiterLike, type Rules, type SecurityConfig, TENANT_FIELD, TIMESTAMP_FIELDS, type TableBoundaryOptions, type Trigger, Triggers, type WebhookBoundaryConfig, appendOnly, assertTenantOwned, composeRules, createAgentTools, createAuthFunctions, createCrudCommands, createFoundation, createInclude, createModule, createStateMachine, createTenantRules, createTriggers, createWebhookBoundary, defaultErrors, defaultRoleMap, jsonSafeZid, noDelete, paginated, rateLimit, recordWebhookEvent, requireTenantReference, tenantOwnership, tenantTable, timestamps, webhookEventsTable, zodTable, zodVariantTable };
15
+ import { FieldReference, RelationBuilder, RelationDeclarations, RelationEdge, RelationFilterSelection, RelationFilters, RelationRegistry, RelationRegistryIdentity, RelationRow, RelationSelection, RelationTable, RelationTableHelpers, RelationTables, ThroughReference, defineRelations } from "./relations.mjs";
16
+ import { QueryEngineConfig, createQueryEngine } from "./querying.mjs";
17
+ export { type Actor, type AgentToolHandlers, type AgentToolRecord, type AnyCommandMiddleware, type AnyQueryMiddleware, type ApplicationCommand, type AuditEntryInput, type AuditWriter, type AuditedOperation, type AuditedRegistry, type AuthBundle, type AuthFunctions, type AuthFunctionsConfig, type Change, type CommandConstructor, type CommandDefaults, type CommandMiddleware, type CrudConfig, type DefaultRole, type DtoOptions, type ErrorFactory, type FieldReference, Foundation, type FoundationOptions, type FoundationRegistry, type FoundationRegistryOptions, type Include, type IncludedQuery, KitError, type PermissionChecker, type QueryEngineConfig, type QueryMiddleware, type RLSConfig, type RateLimiterLike, type RelationBuilder, type RelationDeclarations, type RelationEdge, type RelationFilterSelection, type RelationFilters, type RelationRegistry, type RelationRegistryIdentity, type RelationRow, type RelationSelection, type RelationTable, type RelationTableHelpers, type RelationTables, type Rules, type ScalarFilters, type ScalarSelection, type SecurityConfig, type ServerFilter, TENANT_FIELD, TIMESTAMP_FIELDS, type TableBoundaryOptions, type ThroughReference, type Trigger, Triggers, type WebhookBoundaryConfig, appendOnly, assertTenantOwned, composeRules, createAgentTools, createAuthFunctions, createCrudCommands, createFoundation, createInclude, createModule, createQueryEngine, createStateMachine, createTenantRules, createTriggers, createWebhookBoundary, defaultErrors, defaultRoleMap, defineRelations, jsonSafeZid, noDelete, paginated, rateLimit, recordWebhookEvent, requireTenantReference, tenantOwnership, tenantTable, timestamps, webhookEventsTable, zodTable, zodVariantTable };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createAgentTools as e}from"./agent-tools.mjs";import{KitError as t,defaultErrors as n}from"./errors.mjs";import{TENANT_FIELD as r,assertTenantOwned as i,composeRules as a,createTenantRules as o,requireTenantReference as s}from"./tenancy.mjs";import{createAuthFunctions as c,createInclude as l,defaultRoleMap as u}from"./auth.mjs";import{createCrudCommands as d}from"./crud.mjs";import{TIMESTAMP_FIELDS as f,createModule as p,jsonSafeZid as m,paginated as h,tenantTable as g,zodTable as _,zodVariantTable as v}from"./zod-table.mjs";import{rateLimit as y}from"./middleware.mjs";import{createWebhookBoundary as b,recordWebhookEvent as x,webhookEventsTable as S}from"./webhooks.mjs";import{createStateMachine as C}from"./state-machine.mjs";import{Triggers as w,appendOnly as T,createTriggers as E,noDelete as D,tenantOwnership as O,timestamps as k}from"./triggers.mjs";import{Foundation as A}from"./components/foundation/client.mjs";import{createFoundation as j}from"./modules/foundation/foundation.mjs";export{A as Foundation,t as KitError,r as TENANT_FIELD,f as TIMESTAMP_FIELDS,w as Triggers,T as appendOnly,i as assertTenantOwned,a as composeRules,e as createAgentTools,c as createAuthFunctions,d as createCrudCommands,j as createFoundation,l as createInclude,p as createModule,C as createStateMachine,o as createTenantRules,E as createTriggers,b as createWebhookBoundary,n as defaultErrors,u as defaultRoleMap,m as jsonSafeZid,D as noDelete,h as paginated,y as rateLimit,x as recordWebhookEvent,s as requireTenantReference,O as tenantOwnership,g as tenantTable,k as timestamps,S as webhookEventsTable,_ as zodTable,v as zodVariantTable};
1
+ import{createAgentTools as e}from"./agent-tools.mjs";import{KitError as t,defaultErrors as n}from"./errors.mjs";import{TENANT_FIELD as r,assertTenantOwned as i,composeRules as a,createTenantRules as o,requireTenantReference as s}from"./tenancy.mjs";import{createAuthFunctions as c,createInclude as l,defaultRoleMap as u}from"./auth.mjs";import{createCrudCommands as d}from"./crud.mjs";import{TIMESTAMP_FIELDS as f,createModule as p,jsonSafeZid as m,paginated as h,tenantTable as g,zodTable as _,zodVariantTable as v}from"./zod-table.mjs";import{rateLimit as y}from"./middleware.mjs";import{createWebhookBoundary as b,recordWebhookEvent as x,webhookEventsTable as S}from"./webhooks.mjs";import{createStateMachine as C}from"./state-machine.mjs";import{Triggers as w,appendOnly as T,createTriggers as E,noDelete as D,tenantOwnership as O,timestamps as k}from"./triggers.mjs";import{Foundation as A}from"./components/foundation/client.mjs";import{createFoundation as j}from"./modules/foundation/foundation.mjs";import{defineRelations as M}from"./relations.mjs";import{createQueryEngine as N}from"./querying.mjs";export{A as Foundation,t as KitError,r as TENANT_FIELD,f as TIMESTAMP_FIELDS,w as Triggers,T as appendOnly,i as assertTenantOwned,a as composeRules,e as createAgentTools,c as createAuthFunctions,d as createCrudCommands,j as createFoundation,l as createInclude,p as createModule,N as createQueryEngine,C as createStateMachine,o as createTenantRules,E as createTriggers,b as createWebhookBoundary,n as defaultErrors,u as defaultRoleMap,M as defineRelations,m as jsonSafeZid,D as noDelete,h as paginated,y as rateLimit,x as recordWebhookEvent,s as requireTenantReference,O as tenantOwnership,g as tenantTable,k as timestamps,S as webhookEventsTable,_ as zodTable,v as zodVariantTable};
@@ -1,5 +1,17 @@
1
- import { DomainContract } from "./domain.mjs";
1
+ import { DomainContract, DomainOperationContract } from "./domain.mjs";
2
2
  //#region src/modules/contracts/binding.d.ts
3
+ declare const declaredSchemas: unique symbol;
4
+ /** Private evidence for contextual inference; schemas are installed only at registration. */
5
+ export type DeclaredSchemas<Entry> = {
6
+ readonly [declaredSchemas]: Entry;
7
+ };
8
+ export type BoundOperations<Operations extends Readonly<Record<keyof Entries, {
9
+ handler: (...arguments_: never[]) => unknown;
10
+ }>>, Entries extends Readonly<Record<string, DomainOperationContract>>> = { [Key in keyof Entries]: Entries[Key] & Operations[Key] & {
11
+ input: Entries[Key]['input'];
12
+ result: Entries[Key]['result'];
13
+ handler: Operations[Key]['handler'];
14
+ }; };
3
15
  /** Both adapters bind declarations through the same configuration boundary. */
4
16
  export declare function domainHelpers(entries: Readonly<Record<string, object>>): {
5
17
  [k: string]: (implementation: object) => {};
@@ -1,2 +1,2 @@
1
- const e=[`input`,`result`,`classification`,`replayResult`,`wire`],t=/* @__PURE__ */ new WeakMap;function n(e){return Object.fromEntries(Object.keys(e).map(t=>[t,n=>r(t,e[t],n)]))}function r(n,r,i){for(let e of[`handler`,`audit`,`prepare`,`guard`,`middleware`,`context`])if(Object.prototype.hasOwnProperty.call(r,e))throw Error(`Domain contract ${n} cannot contain ${e}`);for(let t of e)if(Object.prototype.hasOwnProperty.call(i,t))throw Error(`Contracted operation ${n} cannot override ${t}`);let a={...i,...r};return t.set(a,{key:n,declaration:r}),a}function i(n,r,i,a){if(a!==void 0&&typeof a!=`function`)throw Error(`Invalid registry audit callback`);let o=r?.[i];if(r&&!o)throw Error(`Domain contract has no ${i} section`);let s=Object.keys(n);if(o&&(s.length!==Object.keys(o).length||s.some(e=>!Object.prototype.hasOwnProperty.call(o,e))))throw Error(`Contract operation keys must match exactly`);let c=s.map(r=>{let s=n[r];if(o){let n=t.get(s);if(!n||n.key!==r||n.declaration!==o[r]||e.some(e=>s[e]!==o[r][e]))throw Error(`Operation ${r} must use its own contract helper`)}let c={...s};if(c.wire&&=Object.freeze({...c.wire}),i===`commands`){let e=c.audit;if(e!==void 0&&typeof e!=`function`)throw Error(`Invalid audit for ${r}`);if(e===void 0){if(!a)throw Error(`Command ${r} requires an audit callback`);c.audit=(e,t)=>a({operation:r,input:e.command,result:e.result},t)}}return[r,Object.freeze(c)]});return Object.freeze(Object.fromEntries(c))}export{r as bindDomainImplementation,n as domainHelpers,i as snapshotOperations};
1
+ const e=[`input`,`result`,`classification`,`replayResult`,`wire`],t=/* @__PURE__ */ new WeakMap,n=/* @__PURE__ */ new WeakMap;function r(e){let t=Object.fromEntries(Object.keys(e).map(t=>[t,n=>i(t,e[t],n)])),r=t.handler;return t.handler=(t,i)=>{if(typeof t!=`function`&&r)return r(t);if(typeof t!=`function`)throw Error(`Invalid operation handler`);let a={...i,handler:t};return n.set(a,e),a},t}function i(n,r,i){for(let e of[`handler`,`audit`,`prepare`,`guard`,`middleware`,`context`])if(Object.prototype.hasOwnProperty.call(r,e))throw Error(`Domain contract ${n} cannot contain ${e}`);for(let t of e)if(Object.prototype.hasOwnProperty.call(i,t))throw Error(`Contracted operation ${n} cannot override ${t}`);let a={...i,...r};return t.set(a,{key:n,declaration:r}),a}function a(r,a,o,s){if(s!==void 0&&typeof s!=`function`)throw Error(`Invalid registry audit callback`);let c=a?.[o];if(a&&!c)throw Error(`Domain contract has no ${o} section`);let l=Object.keys(r);if(c&&(l.length!==Object.keys(c).length||l.some(e=>!Object.prototype.hasOwnProperty.call(c,e))))throw Error(`Contract operation keys must match exactly`);let u=l.map(a=>{let l=r[a];if(c){if(n.has(l)){if(n.get(l)!==c)throw Error(`Operation ${a} must use its own contract helper`);l=i(a,c[a],l)}let r=t.get(l);if(!r||r.key!==a||r.declaration!==c[a]||e.some(e=>l[e]!==c[a][e]))throw Error(`Operation ${a} must use its own contract helper`)}let u={...l};if(u.wire&&=Object.freeze({...u.wire}),o===`commands`){let e=u.audit;if(e!==void 0&&typeof e!=`function`)throw Error(`Invalid audit for ${a}`);if(e===void 0){if(!s)throw Error(`Command ${a} requires an audit callback`);u.audit=(e,t)=>s({operation:a,input:e.command,result:e.result},t)}}return[a,Object.freeze(u)]});return Object.freeze(Object.fromEntries(u))}export{i as bindDomainImplementation,r as domainHelpers,a as snapshotOperations};
2
2
  //# sourceMappingURL=binding.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"binding.mjs","names":["protectedFields","bindings","domainHelpers","entries","key","bindDomainImplementation","implementation","field","declaration","definition","snapshotOperations","audit","declarations","contract","section","keys","operations","original","binding","override","resolution","context"],"sources":["../../../src/modules/contracts/binding.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters, anti-slop/no-unsafe-dictionary-type, anti-slop/no-known-value-widening, anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns -- Configuration boundary validates heterogeneous own-key records and callback presence; validators remain opaque identities. */\nimport type { DomainContract } from './domain'\n\n// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\nconst protectedFields = ['input', 'result', 'classification', 'replayResult', 'wire'] as const\nconst bindings = new WeakMap<object, { key: string; declaration: object }>()\n\n/** Both adapters bind declarations through the same configuration boundary. */\nexport function domainHelpers(entries: Readonly<Record<string, object>>) {\n\treturn Object.fromEntries(\n\t\tObject.keys(entries).map((key) => [\n\t\t\tkey,\n\t\t\t(implementation: object) => bindDomainImplementation(key, entries[key], implementation),\n\t\t]),\n\t)\n}\n\n/** Bind only opaque schema references; never invoke user callbacks at construction. */\nexport function bindDomainImplementation(key: string, declaration: object, implementation: object) {\n\tfor (const field of ['handler', 'audit', 'prepare', 'guard', 'middleware', 'context']) {\n\t\tif (Object.prototype.hasOwnProperty.call(declaration, field))\n\t\t\tthrow Error(`Domain contract ${key} cannot contain ${field}`)\n\t}\n\tfor (const field of protectedFields) {\n\t\tif (Object.prototype.hasOwnProperty.call(implementation, field))\n\t\t\tthrow Error(`Contracted operation ${key} cannot override ${field}`)\n\t}\n\tconst definition = { ...implementation, ...declaration }\n\tbindings.set(definition, { key, declaration })\n\treturn definition\n}\n\n/** Snapshot records and verify key ownership before the executor closes over them. */\nexport function snapshotOperations(\n\toperations: Readonly<Record<string, object>>,\n\tcontract: DomainContract | undefined,\n\tsection: 'commands' | 'queries',\n\taudit?: (resolution: never, context: never) => unknown,\n) {\n\tif (audit !== undefined && typeof audit !== 'function')\n\t\tthrow Error('Invalid registry audit callback')\n\tconst declarations = contract?.[section]\n\tif (contract && !declarations) throw Error(`Domain contract has no ${section} section`)\n\tconst keys = Object.keys(operations)\n\tif (\n\t\tdeclarations &&\n\t\t(keys.length !== Object.keys(declarations).length ||\n\t\t\tkeys.some((key) => !Object.prototype.hasOwnProperty.call(declarations, key)))\n\t)\n\t\tthrow Error('Contract operation keys must match exactly')\n\tconst entries = keys.map((key) => {\n\t\tconst original = operations[key]\n\t\tif (declarations) {\n\t\t\tconst binding = bindings.get(original)\n\t\t\tif (\n\t\t\t\t!binding ||\n\t\t\t\tbinding.key !== key ||\n\t\t\t\tbinding.declaration !== declarations[key] ||\n\t\t\t\tprotectedFields.some(\n\t\t\t\t\t(field) =>\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t(original as Record<string, unknown>)[field] !==\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t(declarations[key] as Record<string, unknown>)[field],\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tthrow Error(`Operation ${key} must use its own contract helper`)\n\t\t}\n\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\tconst definition = { ...original } as Record<string, unknown>\n\t\tif (definition.wire) {\n\t\t\t// SAFETY: wire is configuration, while its schema stays an opaque reference.\n\t\t\tdefinition.wire = Object.freeze({ ...(definition.wire as object) })\n\t\t}\n\t\tif (section === 'commands') {\n\t\t\tconst override = definition.audit\n\t\t\tif (override !== undefined && typeof override !== 'function')\n\t\t\t\tthrow Error(`Invalid audit for ${key}`)\n\t\t\tif (override === undefined) {\n\t\t\t\tif (!audit) throw Error(`Command ${key} requires an audit callback`)\n\t\t\t\tdefinition.audit = (resolution: { command: unknown; result: unknown }, context: unknown) =>\n\t\t\t\t\taudit(\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t{ operation: key, input: resolution.command, result: resolution.result } as never,\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\tcontext as never,\n\t\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\treturn [key, Object.freeze(definition)] as const\n\t})\n\treturn Object.freeze(Object.fromEntries(entries))\n}\n"],"mappings":"AAIA,MAAMA,EAAkB,CAAC,QAAS,SAAU,iBAAkB,eAAgB,MAAM,EAC9EC,kBAAW,IAAI,QAGrB,SAAgBC,EAAc,EAA2C,CACxE,OAAO,OAAO,YACb,OAAO,KAAKC,CAAO,CAAC,CAAC,IAAK,GAAQ,CACjCC,EACC,GAA2BC,EAAyBD,EAAKD,EAAQC,GAAME,CAAc,CACvF,CAAC,CACF,CACD,CAGA,SAAgBD,EAAyB,EAAa,EAAqB,EAAwB,CAClG,IAAK,IAAME,IAAS,CAAC,UAAW,QAAS,UAAW,QAAS,aAAc,SAAS,EACnF,GAAI,OAAO,UAAU,eAAe,KAAKC,EAAaD,CAAK,EAC1D,MAAM,MAAM,mBAAmBH,EAAI,kBAAkBG,GAAO,EAE9D,IAAK,IAAMA,KAASP,EACnB,GAAI,OAAO,UAAU,eAAe,KAAKM,EAAgBC,CAAK,EAC7D,MAAM,MAAM,wBAAwBH,EAAI,mBAAmBG,GAAO,EAEpE,IAAME,EAAa,CAAE,GAAGH,EAAgB,GAAGE,CAAY,EAEvD,OADAP,EAAS,IAAIQ,EAAY,CAAE,MAAK,aAAY,CAAC,EACtCA,CACR,CAGA,SAAgBC,EACf,EACA,EACA,EACA,EACC,CACD,GAAIC,IAAU,IAAA,IAAa,OAAOA,GAAU,WAC3C,MAAM,MAAM,iCAAiC,EAC9C,IAAMC,EAAeC,IAAWC,GAChC,GAAID,GAAY,CAACD,EAAc,MAAM,MAAM,0BAA0BE,EAAQ,SAAS,EACtF,IAAMC,EAAO,OAAO,KAAKC,CAAU,EACnC,GACCJ,IACCG,EAAK,SAAW,OAAO,KAAKH,CAAY,CAAC,CAAC,QAC1CG,EAAK,KAAM,GAAQ,CAAC,OAAO,UAAU,eAAe,KAAKH,EAAcR,CAAG,CAAC,GAE5E,MAAM,MAAM,4CAA4C,EACzD,IAAMD,EAAUY,EAAK,IAAK,GAAQ,CACjC,IAAME,EAAWD,EAAWZ,GAC5B,GAAIQ,EAAc,CACjB,IAAMM,EAAUjB,EAAS,IAAIgB,CAAQ,EACrC,GACC,CAACC,GACDA,EAAQ,MAAQd,GAChBc,EAAQ,cAAgBN,EAAaR,IACrCJ,EAAgB,KACd,GAECiB,EAAqCV,KAErCK,EAAaR,EAAI,CAA6BG,EACjD,EAEA,MAAM,MAAM,aAAaH,EAAI,kCAAkC,CACjE,CAEA,IAAMK,EAAa,CAAE,GAAGQ,CAAS,EAKjC,GAJA,AAECR,EAAW,OAAO,OAAO,OAAO,CAAE,GAAIA,EAAW,IAAgB,CAAC,EAE/DK,IAAY,WAAY,CAC3B,IAAMK,EAAWV,EAAW,MAC5B,GAAIU,IAAa,IAAA,IAAa,OAAOA,GAAa,WACjD,MAAM,MAAM,qBAAqBf,GAAK,EACvC,GAAIe,IAAa,IAAA,GAAW,CAC3B,GAAI,CAACR,EAAO,MAAM,MAAM,WAAWP,EAAI,4BAA4B,EACnE,EAAW,OAAS,EAAmD,IACtEO,EAEC,CAAE,UAAWP,EAAK,MAAOgB,EAAW,QAAS,OAAQA,EAAW,MAAO,EAEvEC,CACD,CACF,CACD,CAEA,MAAO,CAACjB,EAAK,OAAO,OAAOK,CAAU,CAAC,CACvC,CAAC,EACD,OAAO,OAAO,OAAO,OAAO,YAAYN,CAAO,CAAC,CACjD"}
1
+ {"version":3,"file":"binding.mjs","names":["protectedFields","bindings","pending","domainHelpers","helpers","entries","key","bindDomainImplementation","implementation","namedHandler","handler","options","field","declaration","definition","snapshotOperations","audit","declarations","contract","section","keys","operations","original","binding","override","resolution","context"],"sources":["../../../src/modules/contracts/binding.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters, anti-slop/no-unsafe-dictionary-type, anti-slop/no-known-value-widening, anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns -- Configuration boundary validates heterogeneous own-key records and callback presence; validators remain opaque identities. */\nimport type { DomainContract, DomainOperationContract } from './domain'\n\ndeclare const declaredSchemas: unique symbol\n/** Private evidence for contextual inference; schemas are installed only at registration. */\nexport type DeclaredSchemas<Entry> = { readonly [declaredSchemas]: Entry }\nexport type BoundOperations<\n\tOperations extends Readonly<\n\t\tRecord<keyof Entries, { handler: (...arguments_: never[]) => unknown }>\n\t>,\n\tEntries extends Readonly<Record<string, DomainOperationContract>>,\n> = {\n\t[Key in keyof Entries]: Entries[Key] &\n\t\tOperations[Key] & {\n\t\t\tinput: Entries[Key]['input']\n\t\t\tresult: Entries[Key]['result']\n\t\t\thandler: Operations[Key]['handler']\n\t\t}\n}\n\n// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\nconst protectedFields = ['input', 'result', 'classification', 'replayResult', 'wire'] as const\nconst bindings = new WeakMap<object, { key: string; declaration: object }>()\nconst pending = new WeakMap<object, Readonly<Record<string, object>>>()\n\n/** Both adapters bind declarations through the same configuration boundary. */\nexport function domainHelpers(entries: Readonly<Record<string, object>>) {\n\tconst helpers = Object.fromEntries(\n\t\tObject.keys(entries).map((key) => [\n\t\t\tkey,\n\t\t\t(implementation: object) => bindDomainImplementation(key, entries[key], implementation),\n\t\t]),\n\t)\n\tconst namedHandler = helpers.handler\n\thelpers.handler = (handler: Function | object, options?: object) => {\n\t\tif (typeof handler !== 'function' && namedHandler) return namedHandler(handler)\n\t\tif (typeof handler !== 'function') throw Error('Invalid operation handler')\n\t\tconst implementation = { ...options, handler }\n\t\tpending.set(implementation, entries)\n\t\treturn implementation\n\t}\n\treturn helpers\n}\n\n/** Bind only opaque schema references; never invoke user callbacks at construction. */\nexport function bindDomainImplementation(key: string, declaration: object, implementation: object) {\n\tfor (const field of ['handler', 'audit', 'prepare', 'guard', 'middleware', 'context']) {\n\t\tif (Object.prototype.hasOwnProperty.call(declaration, field))\n\t\t\tthrow Error(`Domain contract ${key} cannot contain ${field}`)\n\t}\n\tfor (const field of protectedFields) {\n\t\tif (Object.prototype.hasOwnProperty.call(implementation, field))\n\t\t\tthrow Error(`Contracted operation ${key} cannot override ${field}`)\n\t}\n\tconst definition = { ...implementation, ...declaration }\n\tbindings.set(definition, { key, declaration })\n\treturn definition\n}\n\n/** Snapshot records and verify key ownership before the executor closes over them. */\nexport function snapshotOperations(\n\toperations: Readonly<Record<string, object>>,\n\tcontract: DomainContract | undefined,\n\tsection: 'commands' | 'queries',\n\taudit?: (resolution: never, context: never) => unknown,\n) {\n\tif (audit !== undefined && typeof audit !== 'function')\n\t\tthrow Error('Invalid registry audit callback')\n\tconst declarations = contract?.[section]\n\tif (contract && !declarations) throw Error(`Domain contract has no ${section} section`)\n\tconst keys = Object.keys(operations)\n\tif (\n\t\tdeclarations &&\n\t\t(keys.length !== Object.keys(declarations).length ||\n\t\t\tkeys.some((key) => !Object.prototype.hasOwnProperty.call(declarations, key)))\n\t)\n\t\tthrow Error('Contract operation keys must match exactly')\n\tconst entries = keys.map((key) => {\n\t\tlet original = operations[key]\n\t\tif (declarations) {\n\t\t\tif (pending.has(original)) {\n\t\t\t\tif (pending.get(original) !== declarations)\n\t\t\t\t\tthrow Error(`Operation ${key} must use its own contract helper`)\n\t\t\t\toriginal = bindDomainImplementation(key, declarations[key], original)\n\t\t\t}\n\t\t\tconst binding = bindings.get(original)\n\t\t\tif (\n\t\t\t\t!binding ||\n\t\t\t\tbinding.key !== key ||\n\t\t\t\tbinding.declaration !== declarations[key] ||\n\t\t\t\tprotectedFields.some(\n\t\t\t\t\t(field) =>\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t(original as Record<string, unknown>)[field] !==\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t(declarations[key] as Record<string, unknown>)[field],\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tthrow Error(`Operation ${key} must use its own contract helper`)\n\t\t}\n\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\tconst definition = { ...original } as Record<string, unknown>\n\t\tif (definition.wire) {\n\t\t\t// SAFETY: wire is configuration, while its schema stays an opaque reference.\n\t\t\tdefinition.wire = Object.freeze({ ...(definition.wire as object) })\n\t\t}\n\t\tif (section === 'commands') {\n\t\t\tconst override = definition.audit\n\t\t\tif (override !== undefined && typeof override !== 'function')\n\t\t\t\tthrow Error(`Invalid audit for ${key}`)\n\t\t\tif (override === undefined) {\n\t\t\t\tif (!audit) throw Error(`Command ${key} requires an audit callback`)\n\t\t\t\tdefinition.audit = (resolution: { command: unknown; result: unknown }, context: unknown) =>\n\t\t\t\t\taudit(\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t{ operation: key, input: resolution.command, result: resolution.result } as never,\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\tcontext as never,\n\t\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\treturn [key, Object.freeze(definition)] as const\n\t})\n\treturn Object.freeze(Object.fromEntries(entries))\n}\n"],"mappings":"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"}
@@ -3,9 +3,9 @@ import { EffectApiContext, EffectApiHandlerValue, EffectApiOptions, EffectApiSer
3
3
  import { CustomBuilder } from "convex-helpers/server/zod4";
4
4
  import { ArgsArrayToObject, DefaultFunctionArgs, FunctionVisibility } from "convex/server";
5
5
  import { ObjectType, PropertyValidators } from "convex/values";
6
- import { Scope } from "effect";
7
6
  import { Registration } from "convex-helpers/server/customFunctions";
8
7
  import * as zCore from "zod/v4/core";
8
+ import { Scope } from "effect";
9
9
  //#region src/modules/effect/api-zod.d.ts
10
10
  type Fields = Record<string, zCore.$ZodType>;
11
11
  type ArgumentsValidator = Fields | zCore.$ZodObject<Fields> | void;