cvx-kit 0.0.8 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/README.md +14 -10
- package/ROADMAP.md +126 -0
- package/dist/agent-tools.d.mts +45 -0
- package/dist/agent-tools.mjs +2 -0
- package/dist/agent-tools.mjs.map +1 -0
- package/dist/auth.d.mts +9 -1
- package/dist/auth.mjs +1 -1
- package/dist/auth.mjs.map +1 -1
- package/dist/components/approvals/_generated/api.d.mts +2 -0
- package/dist/components/approvals/_generated/api.mjs.map +1 -1
- package/dist/components/approvals/_generated/component.d.mts +7 -0
- package/dist/components/approvals/_generated/dataModel.d.mts +1 -1
- package/dist/components/approvals/client.d.mts +4 -4
- package/dist/components/approvals/client.mjs +1 -1
- package/dist/components/approvals/client.mjs.map +1 -1
- package/dist/components/approvals/constants.d.mts +8 -2
- package/dist/components/approvals/constants.mjs +1 -1
- package/dist/components/approvals/constants.mjs.map +1 -1
- package/dist/components/approvals/decisions.mjs +1 -1
- package/dist/components/approvals/decisions.mjs.map +1 -1
- package/dist/components/approvals/health.d.mts +15 -0
- package/dist/components/approvals/health.mjs +2 -0
- package/dist/components/approvals/health.mjs.map +1 -0
- package/dist/components/approvals/requests.mjs +1 -1
- package/dist/components/approvals/requests.mjs.map +1 -1
- package/dist/components/approvals/schema.js +1 -0
- package/dist/components/approvals/validators.d.mts +119 -2
- package/dist/components/approvals/validators.mjs +1 -1
- package/dist/components/approvals/validators.mjs.map +1 -1
- package/dist/components/approvals/workflow_steps.d.mts +2 -25
- package/dist/components/approvals/workflow_steps.mjs.map +1 -1
- package/dist/components/foundation/_generated/dataModel.d.mts +1 -1
- package/dist/components/foundation/client.d.mts +26 -9
- package/dist/components/foundation/client.mjs.map +1 -1
- package/dist/components/foundation/modules/query/query.d.mts +19 -8
- package/dist/components/foundation/modules/query/query.mjs.map +1 -1
- package/dist/components/foundation/{schema.mjs → schema.js} +0 -1
- package/dist/crud.d.mts +79 -0
- package/dist/crud.mjs +2 -0
- package/dist/crud.mjs.map +1 -0
- package/dist/index.d.mts +9 -4
- package/dist/index.mjs +1 -1
- package/dist/middleware.d.mts +46 -0
- package/dist/middleware.mjs +2 -0
- package/dist/middleware.mjs.map +1 -0
- package/dist/state-machine.d.mts +18 -0
- package/dist/state-machine.mjs +2 -0
- package/dist/state-machine.mjs.map +1 -0
- package/dist/tenancy.d.mts +1 -1
- package/dist/webhooks.d.mts +164 -0
- package/dist/webhooks.mjs +2 -0
- package/dist/webhooks.mjs.map +1 -0
- package/dist/zod-table.d.mts +34 -3
- package/dist/zod-table.mjs +1 -1
- package/dist/zod-table.mjs.map +1 -1
- package/docs/agent-tools.md +41 -0
- package/docs/approvals.md +50 -2
- package/docs/crud.md +62 -0
- package/docs/llms.md +8 -1
- package/docs/plans/2026-08-14-001-feat-v0.1.0-feature-set-plan.md +461 -0
- package/docs/upgrading.md +175 -0
- package/docs/webhooks.md +58 -0
- package/package.json +25 -2
- package/scripts/convex-config-bridge.mjs +41 -3
- package/scripts/extract-changelog.mjs +29 -0
- package/scripts/smoke-packed-components.mjs +374 -0
- package/src/test.ts +2 -2
- package/dist/components/approvals/schema.mjs +0 -2
- package/dist/components/approvals/schema.mjs.map +0 -1
- package/dist/components/foundation/schema.mjs.map +0 -1
- /package/dist/components/approvals/{schema.d.mts → schema.d.ts} +0 -0
- /package/dist/components/foundation/{schema.d.mts → schema.d.ts} +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to cvx-kit are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
|
|
6
|
+
**Semver contract (from 0.1.0):** while on 0.x, breaking changes land only on
|
|
7
|
+
minor bumps; patches are additive or fixes. The breaking window formally
|
|
8
|
+
closes at the follow-up consolidation release (package-name decision + full
|
|
9
|
+
export-name API audit) — until then, the six 0.1.0 helper surfaces may still
|
|
10
|
+
be renamed in a minor. Every release tag gets a GitHub Release whose notes
|
|
11
|
+
are this file's matching section.
|
|
12
|
+
|
|
13
|
+
## [Unreleased]
|
|
14
|
+
|
|
15
|
+
## [0.1.1] - 2026-08-17
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Package Convex component schemas exclusively as discoverable `schema.js` and
|
|
20
|
+
`schema.d.ts` files. This restores the approvals tables and the
|
|
21
|
+
`approvalDecisions.by_runId_and_decidedAt` and
|
|
22
|
+
`approvalDecisions.by_runId_and_stepKey_and_actor_actorRef` indexes without
|
|
23
|
+
consumer `patchedDependencies` workarounds or canonicalization conflicts.
|
|
24
|
+
- Keep compiled component imports aligned with the discoverable `schema.js`
|
|
25
|
+
filename when runtime functions use the schema directly.
|
|
26
|
+
- Include `stepKey` in the public approval callback evidence contract and
|
|
27
|
+
export canonical Zod and Convex callback validators for strict consumers.
|
|
28
|
+
- Use component-safe cursor pagination for approval request lists instead of
|
|
29
|
+
Convex's app-only built-in `.paginate()` implementation.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Packed-tarball content checks and clean anonymous-deployment smoke tests for
|
|
34
|
+
every bundled component under both Bun and npm installation.
|
|
35
|
+
- `components.approvals.health.check`, which verifies the approvals schema
|
|
36
|
+
version and required decision indexes with an actionable failure diagnostic.
|
|
37
|
+
- Supported Convex, Zod, Bun, Node.js, and npm versions plus an approvals
|
|
38
|
+
packaging migration note.
|
|
39
|
+
- Packed callback and paginated-list smoke coverage through real host wrappers.
|
|
40
|
+
|
|
41
|
+
## [0.1.0] - 2026-08-14
|
|
42
|
+
|
|
43
|
+
The big one: the full helper surface, in one release.
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **Pagination bridge** — `paginated(dto)` boundary schemas
|
|
48
|
+
(`cvx-kit/zod-table`) and an `include(...).paginate(opts, transform?)`
|
|
49
|
+
terminal (`cvx-kit/auth`): cursor pagination bounded by the same maxRows
|
|
50
|
+
policy as `execute`. Under row-level security, pages may be shorter than
|
|
51
|
+
`numItems` (filtered rows); cursors remain correct.
|
|
52
|
+
- **CRUD command factory** — `createCrudCommands` (`cvx-kit/crud`):
|
|
53
|
+
create/update/archive operations generated from a zodTable, fully inside
|
|
54
|
+
the audited command pipeline; soft-delete only; `enrich` is required for
|
|
55
|
+
tenantTables (fails fast with `CRUD_ENRICH_REQUIRED`).
|
|
56
|
+
- **State-machine helper** — `createStateMachine` (`cvx-kit/state-machine`):
|
|
57
|
+
typed transition legality from constants tuples; `assert` throws
|
|
58
|
+
`INVALID_TRANSITION` via the injected ErrorFactory, dropping straight into
|
|
59
|
+
command guards.
|
|
60
|
+
- **Rate-limit middleware** — `rateLimit` (`cvx-kit/middleware`): the first
|
|
61
|
+
packaged middleware, over an injected `@convex-dev/rate-limiter` instance
|
|
62
|
+
(structural typing — zero new kit dependencies). Keyed by `ctx.tenant` by
|
|
63
|
+
default; a missing key is a configuration error
|
|
64
|
+
(`RATE_LIMIT_KEY_MISSING`), never a silent shared bucket.
|
|
65
|
+
- **Webhook boundary** — `createWebhookBoundary`, `recordWebhookEvent`,
|
|
66
|
+
`webhookEventsTable` (`cvx-kit/webhooks`): raw-body signature verification
|
|
67
|
+
(fail closed), natural-key dedup transactional inside the target internal
|
|
68
|
+
mutation, host-owned dedup table.
|
|
69
|
+
- **Agent tool generator** — `createAgentTools` (`cvx-kit/agent-tools`):
|
|
70
|
+
tool records from the table tool masks, shape-compatible with
|
|
71
|
+
`@convex-dev/agent`'s `createTool` without depending on it; mutation
|
|
72
|
+
handlers route through command executors so agents get audited commands.
|
|
73
|
+
- **Typed middleware context** — `Command.middleware<Ctx, Extension>` /
|
|
74
|
+
`Query.middleware<Ctx, Extension>`: `next({ context })` is typed against
|
|
75
|
+
the declared extension; registries and operations accept typed middleware
|
|
76
|
+
without casts (`AnyCommandMiddleware`/`AnyQueryMiddleware` variance seam).
|
|
77
|
+
- **Upgrade guide** — `docs/upgrading.md` ships in the package: old way →
|
|
78
|
+
new way per feature for consumers on 0.0.x.
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
|
|
82
|
+
- `tools.update` / `tools.id` masks now use `jsonSafeZid` instead of `zid`,
|
|
83
|
+
so ids present as plain strings in generated JSON schemas (compile-time
|
|
84
|
+
`Id<...>` types preserved).
|
|
85
|
+
- Release workflow now creates a GitHub Release with this file's section as
|
|
86
|
+
notes, and action pins are updated past the Node 20 deprecation.
|
|
87
|
+
|
|
88
|
+
## [0.0.8] - 2026-08-14
|
|
89
|
+
|
|
90
|
+
- Composable next()-based middleware for Command and Query kernels, inside
|
|
91
|
+
pipeline invariants (registry-wide + per-operation, context enrichment,
|
|
92
|
+
result re-parse).
|
|
93
|
+
|
|
94
|
+
## [0.0.7] - 2026-08-14
|
|
95
|
+
|
|
96
|
+
- `systemQuery` constructor: internal, include-equipped, RLS-unwrapped.
|
|
97
|
+
BREAKING: `createAuthFunctions` config requires the `internalQuery` builder.
|
|
98
|
+
|
|
99
|
+
## [0.0.6] - 2026-08-14
|
|
100
|
+
|
|
101
|
+
- Materialized `convex.config.js` bridges (Convex CLI discovers components by
|
|
102
|
+
that literal filename). BREAKING: mount via
|
|
103
|
+
`cvx-kit/components/<name>/convex.config`; client facades no longer
|
|
104
|
+
default-export the component config.
|
|
105
|
+
|
|
106
|
+
## [0.0.5] - 2026-08-14
|
|
107
|
+
|
|
108
|
+
- BREAKING: the Foundation facade is the only runtime surface — kernel
|
|
109
|
+
classes and execution utilities destructure from the instance.
|
|
110
|
+
|
|
111
|
+
## [0.0.4] - 2026-08-14
|
|
112
|
+
|
|
113
|
+
- Tarball ships only `dist`, `docs`, and the source test helper
|
|
114
|
+
(`.npmignore`); `cvx-kit/test` registers compiled dist modules.
|
|
115
|
+
|
|
116
|
+
## [0.0.3] - 2026-08-14
|
|
117
|
+
|
|
118
|
+
- Opt-in tenancy and security controls: `tenantTable`, `createModule`,
|
|
119
|
+
`security` config on `createAuthFunctions` (role rules + tenant RLS),
|
|
120
|
+
`ctx.tenant`, `cvx-kit/tenancy`, `tenantOwnership` trigger. Command
|
|
121
|
+
guards, permission checks, and the aggregate allowlist.
|
|
122
|
+
|
|
123
|
+
## [0.0.2] - 2026-08-13
|
|
124
|
+
|
|
125
|
+
- Shipped package documentation (architecture, conventions, migration,
|
|
126
|
+
llms) at `docs/`; opinionated timestamps on every table; single-path
|
|
127
|
+
component mounts.
|
|
128
|
+
|
|
129
|
+
## [0.0.1] - 2026-08-13
|
|
130
|
+
|
|
131
|
+
- Initial release: foundation + approvals components, zod-table boundaries,
|
|
132
|
+
auth constructors, triggers, audited command protocol.
|
package/README.md
CHANGED
|
@@ -13,6 +13,9 @@ bun add cvx-kit
|
|
|
13
13
|
# or: npm install cvx-kit
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Supported versions: Convex `^1.43.0`, Zod `^4.0.0`, Bun `1.3+`, and Node.js
|
|
17
|
+
`24+` with npm `11+`. The library runtime is ESM-only.
|
|
18
|
+
|
|
16
19
|
## Toolchain
|
|
17
20
|
|
|
18
21
|
- `bun install` — dependencies
|
|
@@ -36,6 +39,10 @@ authored in [`src/docs/`](./src/docs/):
|
|
|
36
39
|
- [`triggers.md`](./src/docs/triggers.md) — trigger registry, timestamps/append-only/no-delete
|
|
37
40
|
- [`approvals.md`](./src/docs/approvals.md) — declarative approval workflows
|
|
38
41
|
- [`tenancy.md`](./src/docs/tenancy.md) — row-level security (roles) with opt-in multi-tenant isolation
|
|
42
|
+
- [`crud.md`](./src/docs/crud.md) — the CRUD command factory
|
|
43
|
+
- [`webhooks.md`](./src/docs/webhooks.md) — the sanctioned webhook boundary
|
|
44
|
+
- [`agent-tools.md`](./src/docs/agent-tools.md) — agent tools that are audited commands
|
|
45
|
+
- [`upgrading.md`](./src/docs/upgrading.md) — 0.0.x → 0.1.0, old way → new way
|
|
39
46
|
- [`maintainability.md`](./src/docs/maintainability.md) — keeping a Convex app maintainable long-term
|
|
40
47
|
- [`migration.md`](./src/docs/migration.md) — restructuring an existing raw Convex project into this architecture
|
|
41
48
|
- [`llms.md`](./src/docs/llms.md) — condensed reference to paste into an LLM/agent context
|
|
@@ -186,6 +193,12 @@ registerApprovals(t)
|
|
|
186
193
|
|
|
187
194
|
## Releasing
|
|
188
195
|
|
|
196
|
+
Every release also creates a GitHub Release whose notes are the matching
|
|
197
|
+
[CHANGELOG](./CHANGELOG.md) section (extracted by
|
|
198
|
+
`scripts/extract-changelog.mjs` in the release workflow).
|
|
199
|
+
|
|
200
|
+
### OIDC setup
|
|
201
|
+
|
|
189
202
|
Publishing uses [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/)
|
|
190
203
|
(OIDC) — no tokens stored anywhere. The release workflow authenticates via
|
|
191
204
|
GitHub's OIDC and npm generates provenance attestations automatically.
|
|
@@ -205,13 +218,4 @@ One-time setup (already-published package required first):
|
|
|
205
218
|
|
|
206
219
|
## Roadmap
|
|
207
220
|
|
|
208
|
-
|
|
209
|
-
--dry-run`) into this repo's suite as the portability guarantee.
|
|
210
|
-
- [ ] `createArchitectureTest(rules)` helper so consuming projects get the
|
|
211
|
-
boundary guardrails (no inline tables/enums, single facade per
|
|
212
|
-
component) on day one.
|
|
213
|
-
- [ ] WorkOS scaffold generator for `auth.ts` / `auth.config.ts` / `http.ts`.
|
|
214
|
-
- [ ] Audit facade helpers (fingerprinted cursors, bounded windows) over any
|
|
215
|
-
`convex-audit-log` instance.
|
|
216
|
-
- [ ] Decide the published name/scope before `npm publish` (`cvx-kit` is a
|
|
217
|
-
working title).
|
|
221
|
+
See [ROADMAP.md](./ROADMAP.md) — milestones from 0.1.0 through 1.0.0.
|
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Roadmap to 1.0.0
|
|
2
|
+
|
|
3
|
+
Where cvx-kit is going and what "stable" will mean. Tracked with checkboxes;
|
|
4
|
+
each milestone ships as one minor version. From `0.1.0` on, **breaking
|
|
5
|
+
changes only land on minor bumps** (0.x semver: minor = breaking, patch =
|
|
6
|
+
fix/additive) and every release gets a CHANGELOG entry.
|
|
7
|
+
|
|
8
|
+
## 0.1.0 — the big one: API consolidation + the feature set
|
|
9
|
+
|
|
10
|
+
Goal: one release that both closes the breaking window AND ships the full
|
|
11
|
+
helper surface, so consumers adopt a complete kit once instead of chasing
|
|
12
|
+
minors. Everything here may still rename freely — that's why the features
|
|
13
|
+
belong in this milestone: they land already conforming to the frozen names.
|
|
14
|
+
|
|
15
|
+
### Consolidation (the last breaking pass)
|
|
16
|
+
|
|
17
|
+
- [ ] Decide the published name (`cvx-kit` is a working title) and, if it
|
|
18
|
+
changes, publish under the final name with `cvx-kit` deprecated.
|
|
19
|
+
- [ ] API audit: review every exported name, option key, and error code
|
|
20
|
+
against `conventions.md`'s own naming grammar; freeze the error-code
|
|
21
|
+
taxonomy (`KitError` codes) as a documented tuple.
|
|
22
|
+
- [x] Typed middleware context accumulation: `next({ context })` currently
|
|
23
|
+
merges loosely; tighten so enrichment widens the downstream ctx type
|
|
24
|
+
(TanStack-style), without breaking the loose form.
|
|
25
|
+
- [x] Introduce `CHANGELOG.md` + release notes on the GitHub tag; adopt the
|
|
26
|
+
0.x semver contract above. (GitHub Releases automated in release.yml.)
|
|
27
|
+
- [ ] CI hardening: add `--dry-run` pack + `attw` (Are The Types Wrong) next
|
|
28
|
+
to publint; bump the deprecated actions pins.
|
|
29
|
+
|
|
30
|
+
### Features
|
|
31
|
+
|
|
32
|
+
- [x] **Pagination bridge** — `paginated(table.publicDto)` arg/return
|
|
33
|
+
helpers over Convex's pagination validators, and an
|
|
34
|
+
`include(...).paginate(opts)` terminal next to `.execute(limit)`:
|
|
35
|
+
cursors, not just bounded `take`.
|
|
36
|
+
- [x] **CRUD command factory** — `createCrudCommands(table, policy)`
|
|
37
|
+
generating the standard create/update/archive operations from a
|
|
38
|
+
zodTable's masks: command input from `commandFields`, audit derivation
|
|
39
|
+
from the aggregate, timestamps/tenant already structural. The single
|
|
40
|
+
biggest remaining per-entity boilerplate.
|
|
41
|
+
- [x] **State-machine helper** — `createStateMachine(STATES, transitions)`
|
|
42
|
+
typed against the constants tuple, returning `isTransitionLegal` /
|
|
43
|
+
`assertTransition` that drop straight into a command `guard`.
|
|
44
|
+
- [x] **Rate-limit middleware factory** — the first official middleware:
|
|
45
|
+
`rateLimit({ key: (ctx) => ctx.tenant, ... })` over
|
|
46
|
+
`@convex-dev/rate-limiter`, packaged as `Command.middleware` /
|
|
47
|
+
`Query.middleware` and the template for future middleware.
|
|
48
|
+
- [x] **Webhook boundary helper** — signature verification + event dedup by
|
|
49
|
+
natural key (`${event}:${id}:${updatedAt}`) + delegation to a
|
|
50
|
+
`system*` function: the one boundary that genuinely needs dedup, as a
|
|
51
|
+
first-class helper.
|
|
52
|
+
- [x] **Agent tool generator** — `createAgentTools(table, executors)`
|
|
53
|
+
emitting `@convex-dev/agent` tool definitions from the existing
|
|
54
|
+
`tools.*` masks + `jsonSafeZid`, with handlers routed through the
|
|
55
|
+
command protocol — agents get audited commands, never raw db access.
|
|
56
|
+
|
|
57
|
+
Each feature ships with its own doc page (or section), tests on the real
|
|
58
|
+
Convex runtime where applicable, and an `llms.md` entry.
|
|
59
|
+
|
|
60
|
+
## 0.2.0 — guardrails as a product
|
|
61
|
+
|
|
62
|
+
Goal: the conventions the docs prescribe become importable tests, so a
|
|
63
|
+
consumer gets the origin app's discipline on day one — enforced against the
|
|
64
|
+
by-then-frozen 0.1.0 names.
|
|
65
|
+
|
|
66
|
+
- [ ] `createArchitectureTest(rules)` — glob-based rule runner with the
|
|
67
|
+
standard rules built in (no raw builders outside functions.ts, no
|
|
68
|
+
inline tables/enums, no sibling-domain imports, no deep component
|
|
69
|
+
imports, facades mount once), each rule fixture-proved, extensible
|
|
70
|
+
with app-specific rules.
|
|
71
|
+
- [ ] Tenancy exhaustiveness helper: assert every `tenantTable` is in the
|
|
72
|
+
registry and vice versa; assert internal builders accept no tenant arg.
|
|
73
|
+
- [ ] `llms.md` conformance check: an automated test that every export in
|
|
74
|
+
its tables exists with that signature (also an rc gate — build it here).
|
|
75
|
+
- [ ] Port the approvals copyability test (cp -r + tsc) into this repo's
|
|
76
|
+
suite as the permanent portability guarantee for both components.
|
|
77
|
+
|
|
78
|
+
## 0.3.0 — scaffolding
|
|
79
|
+
|
|
80
|
+
Goal: the first hour of a new app is generated, not hand-written.
|
|
81
|
+
|
|
82
|
+
- [ ] WorkOS scaffold generator: `auth.ts`, `auth.config.ts`, `http.ts`,
|
|
83
|
+
`functions.ts`, `foundation.ts`, `triggers.ts` from one command.
|
|
84
|
+
- [ ] Audit facade helpers over any `convex-audit-log` instance:
|
|
85
|
+
fingerprinted cursors, bounded windows, admin readers.
|
|
86
|
+
- [ ] Decide on the optional idempotency/replay component (deferred from
|
|
87
|
+
0.0.x — only if a consumer demonstrates the need beyond Convex's
|
|
88
|
+
exactly-once mutation delivery).
|
|
89
|
+
|
|
90
|
+
## 1.0.0-rc — proving it
|
|
91
|
+
|
|
92
|
+
Entry gates, not work items. The rc ships when all are true:
|
|
93
|
+
|
|
94
|
+
- [ ] Two real applications run the latest kit in production-like use for
|
|
95
|
+
several weeks (the multi-tenant integration and one more).
|
|
96
|
+
- [ ] One full minor cycle with zero breaking changes needed.
|
|
97
|
+
- [ ] Docs complete and verified: the `llms.md` conformance check (built in
|
|
98
|
+
0.2.0) green in CI.
|
|
99
|
+
- [ ] CI matrix: bun + node LTS, convex peer-range min and latest.
|
|
100
|
+
- [ ] Public-API test coverage: every exported runtime symbol exercised by
|
|
101
|
+
at least one test.
|
|
102
|
+
|
|
103
|
+
## 1.0.0
|
|
104
|
+
|
|
105
|
+
- [ ] Freeze the export surface; document the semver contract (what counts
|
|
106
|
+
as breaking, deprecation policy of one minor with warnings).
|
|
107
|
+
- [ ] `MIGRATING.md` from 0.x.
|
|
108
|
+
- [ ] Provenance, README badges, and a docs site or expanded README landing.
|
|
109
|
+
|
|
110
|
+
## Candidates (recorded, not committed)
|
|
111
|
+
|
|
112
|
+
- Observability sink adapters: OTel/Axiom-shaped formatters for the
|
|
113
|
+
injectable `emit`, so `command.execution` events land in real telemetry
|
|
114
|
+
without per-consumer mapping.
|
|
115
|
+
- Migration companion: a thin `@convex-dev/migrations` wrapper aligned with
|
|
116
|
+
zodTable epochs ("make optional field required after backfill" as a
|
|
117
|
+
declared step), closing the loop with `migration.md`.
|
|
118
|
+
|
|
119
|
+
## Explicitly out of scope for 1.0
|
|
120
|
+
|
|
121
|
+
- General idempotency store (platform already covers single-call
|
|
122
|
+
exactly-once; boundary dedup is the webhook helper's job).
|
|
123
|
+
- Frontend helpers/React bindings.
|
|
124
|
+
- Multi-provider auth abstractions beyond the injected-policy seam
|
|
125
|
+
(`createAuthFunctions` already accepts any provider via `getAuthUser`/
|
|
126
|
+
`mapRole`/`verifyMembership`).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/agent-tools.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A framework-agnostic tool record: directly spreadable into
|
|
5
|
+
* @convex-dev/agent's createTool ({ description, args, handler }) and
|
|
6
|
+
* adaptable to ai-sdk tool(). The kit imports neither framework — checked
|
|
7
|
+
* against registry snapshots on 2026-08-14; re-verify at install time.
|
|
8
|
+
*/
|
|
9
|
+
type AgentToolRecord = {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
args: z.ZodType;
|
|
13
|
+
handler: (ctx: never, input: never) => Promise<unknown>;
|
|
14
|
+
};
|
|
15
|
+
type ToolTable = {
|
|
16
|
+
tableName: string;
|
|
17
|
+
tools: {
|
|
18
|
+
insert: z.ZodType;
|
|
19
|
+
update: z.ZodType;
|
|
20
|
+
id: z.ZodType;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
type ToolHandler = (ctx: never, input: never) => Promise<unknown>;
|
|
24
|
+
type AgentToolHandlers = {
|
|
25
|
+
/** Mutations: route through command executors — agents get audited commands. */
|
|
26
|
+
create?: ToolHandler;
|
|
27
|
+
update?: ToolHandler;
|
|
28
|
+
archive?: ToolHandler;
|
|
29
|
+
/** Reads: caller-supplied query handlers (reads do not route through commands). */
|
|
30
|
+
get?: ToolHandler;
|
|
31
|
+
list?: ToolHandler;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Emits agent tool definitions from the existing table tool masks: args are
|
|
35
|
+
* the masks (jsonSafeZid keeps ids primitive in generated JSON schemas),
|
|
36
|
+
* names are `<tableName>_<verb>`, and only the kinds you supply handlers for
|
|
37
|
+
* are emitted. Wire mutation handlers to createCrudCommands executors (or
|
|
38
|
+
* your own) so every agent action is an audited command.
|
|
39
|
+
*/
|
|
40
|
+
declare function createAgentTools(table: ToolTable, handlers: AgentToolHandlers, options?: {
|
|
41
|
+
descriptions?: Partial<Record<keyof AgentToolHandlers, string>>;
|
|
42
|
+
}): Record<string, AgentToolRecord>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { AgentToolHandlers, AgentToolRecord, createAgentTools };
|
|
45
|
+
//# sourceMappingURL=agent-tools.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{convexToZod as e}from"convex-helpers/server/zod4";import{paginationOptsValidator as t}from"convex/server";import{z as n}from"zod";const r=n.object({paginationOpts:e(t)}).strict();function i(e,t,n){let i=e.tableName,a={create:e.tools.insert,update:e.tools.update,archive:e.tools.id,get:e.tools.id,list:r},o={create:`Create a ${i} record`,update:`Update fields of an existing ${i} record`,archive:`Archive (soft-delete) a ${i} record`,get:`Fetch one ${i} record by id`,list:`List ${i} records, paginated`},s={};for(let e of Object.keys(a)){let r=t[e];r&&(s[`${i}_${e}`]={name:`${i}_${e}`,description:n?.descriptions?.[e]??o[e],args:a[e],handler:r})}return s}export{i as createAgentTools};
|
|
2
|
+
//# sourceMappingURL=agent-tools.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-tools.mjs","names":[],"sources":["../src/agent-tools.ts"],"sourcesContent":["import { convexToZod } from 'convex-helpers/server/zod4'\nimport { paginationOptsValidator } from 'convex/server'\nimport { z } from 'zod'\n\n/**\n * A framework-agnostic tool record: directly spreadable into\n * @convex-dev/agent's createTool ({ description, args, handler }) and\n * adaptable to ai-sdk tool(). The kit imports neither framework — checked\n * against registry snapshots on 2026-08-14; re-verify at install time.\n */\nexport type AgentToolRecord = {\n\tname: string\n\tdescription: string\n\targs: z.ZodType\n\thandler: (ctx: never, input: never) => Promise<unknown>\n}\n\ntype ToolTable = {\n\ttableName: string\n\ttools: {\n\t\tinsert: z.ZodType\n\t\tupdate: z.ZodType\n\t\tid: z.ZodType\n\t}\n}\n\ntype ToolHandler = (ctx: never, input: never) => Promise<unknown>\n\nexport type AgentToolHandlers = {\n\t/** Mutations: route through command executors — agents get audited commands. */\n\tcreate?: ToolHandler\n\tupdate?: ToolHandler\n\tarchive?: ToolHandler\n\t/** Reads: caller-supplied query handlers (reads do not route through commands). */\n\tget?: ToolHandler\n\tlist?: ToolHandler\n}\n\nconst listArgs = z\n\t.object({ paginationOpts: convexToZod(paginationOptsValidator) })\n\t.strict()\n\n/**\n * Emits agent tool definitions from the existing table tool masks: args are\n * the masks (jsonSafeZid keeps ids primitive in generated JSON schemas),\n * names are `<tableName>_<verb>`, and only the kinds you supply handlers for\n * are emitted. Wire mutation handlers to createCrudCommands executors (or\n * your own) so every agent action is an audited command.\n */\nexport function createAgentTools(\n\ttable: ToolTable,\n\thandlers: AgentToolHandlers,\n\toptions?: { descriptions?: Partial<Record<keyof AgentToolHandlers, string>> },\n): Record<string, AgentToolRecord> {\n\tconst name = table.tableName\n\tconst masks: Record<keyof AgentToolHandlers, z.ZodType> = {\n\t\tcreate: table.tools.insert,\n\t\tupdate: table.tools.update,\n\t\tarchive: table.tools.id,\n\t\tget: table.tools.id,\n\t\tlist: listArgs,\n\t}\n\tconst defaults: Record<keyof AgentToolHandlers, string> = {\n\t\tcreate: `Create a ${name} record`,\n\t\tupdate: `Update fields of an existing ${name} record`,\n\t\tarchive: `Archive (soft-delete) a ${name} record`,\n\t\tget: `Fetch one ${name} record by id`,\n\t\tlist: `List ${name} records, paginated`,\n\t}\n\tconst tools: Record<string, AgentToolRecord> = {}\n\tfor (const verb of Object.keys(masks) as (keyof AgentToolHandlers)[]) {\n\t\tconst handler = handlers[verb]\n\t\tif (!handler) continue\n\t\ttools[`${name}_${verb}`] = {\n\t\t\tname: `${name}_${verb}`,\n\t\t\tdescription: options?.descriptions?.[verb] ?? defaults[verb],\n\t\t\targs: masks[verb],\n\t\t\thandler,\n\t\t}\n\t}\n\treturn tools\n}\n"],"mappings":"yIAsCA,MAAM,EAAW,EACf,OAAO,CAAE,eAAgB,EAAY,CAAuB,CAAE,CAAC,CAAC,CAChE,OAAO,EAST,SAAgB,EACf,EACA,EACA,EACkC,CAClC,IAAM,EAAO,EAAM,UACb,EAAoD,CACzD,OAAQ,EAAM,MAAM,OACpB,OAAQ,EAAM,MAAM,OACpB,QAAS,EAAM,MAAM,GACrB,IAAK,EAAM,MAAM,GACjB,KAAM,CACP,EACM,EAAoD,CACzD,OAAQ,YAAY,EAAK,SACzB,OAAQ,gCAAgC,EAAK,SAC7C,QAAS,2BAA2B,EAAK,SACzC,IAAK,aAAa,EAAK,eACvB,KAAM,QAAQ,EAAK,oBACpB,EACM,EAAyC,CAAC,EAChD,IAAK,IAAM,KAAQ,OAAO,KAAK,CAAK,EAAkC,CACrE,IAAM,EAAU,EAAS,GACpB,IACL,EAAM,GAAG,EAAK,GAAG,KAAU,CAC1B,KAAM,GAAG,EAAK,GAAG,IACjB,YAAa,GAAS,eAAe,IAAS,EAAS,GACvD,KAAM,EAAM,GACZ,SACD,EACD,CACA,OAAO,CACR"}
|
package/dist/auth.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ErrorFactory } from "./errors.mjs";
|
|
2
2
|
import { RLSConfig, Rules } from "./tenancy.mjs";
|
|
3
|
-
import { ActionBuilder, DocumentByInfo, GenericActionCtx, GenericDataModel, GenericMutationCtx, GenericQueryCtx, GenericTableInfo, IndexNames, IndexRange, IndexRangeBuilder, MutationBuilder, NamedIndex, Query, QueryBuilder, QueryInitializer, TableNamesInDataModel, UserIdentity } from "convex/server";
|
|
3
|
+
import { ActionBuilder, DocumentByInfo, GenericActionCtx, GenericDataModel, GenericMutationCtx, GenericQueryCtx, GenericTableInfo, IndexNames, IndexRange, IndexRangeBuilder, MutationBuilder, NamedIndex, PaginationOptions, PaginationResult, Query, QueryBuilder, QueryInitializer, TableNamesInDataModel, UserIdentity } from "convex/server";
|
|
4
4
|
import { Triggers } from "convex-helpers/server/triggers";
|
|
5
5
|
//#region src/auth.d.ts
|
|
6
6
|
/** The default vocabulary; every app can supply its own via the Role generic. */
|
|
@@ -112,6 +112,14 @@ type IncludedQuery<Table extends GenericTableInfo> = {
|
|
|
112
112
|
otherwise(select: (query: QueryInitializer<Table>) => Query<Table>): Query<Table>;
|
|
113
113
|
resolve(): Query<Table>;
|
|
114
114
|
execute<Result = Awaited<ReturnType<Query<Table>['take']>>>(limit: number, transform?: (data: Awaited<ReturnType<Query<Table>['take']>>) => Result | Promise<Result>): Promise<Result>;
|
|
115
|
+
/**
|
|
116
|
+
* Cursor pagination over the selected indexed query. numItems is bounded
|
|
117
|
+
* by the same maxRows policy as execute(). Under row-level security a
|
|
118
|
+
* page may be shorter than numItems (rejected rows are filtered after
|
|
119
|
+
* pagination); cursors remain correct. Pair with paginated(dto) from
|
|
120
|
+
* cvx-kit/zod-table for the boundary schemas.
|
|
121
|
+
*/
|
|
122
|
+
paginate<Item = DocumentByInfo<Table>>(opts: PaginationOptions, transform?: (page: DocumentByInfo<Table>[]) => Item[] | Promise<Item[]>): Promise<PaginationResult<Item>>;
|
|
115
123
|
};
|
|
116
124
|
type Include = <Table extends GenericTableInfo>(query: QueryInitializer<Table>) => IncludedQuery<Table>;
|
|
117
125
|
/** Builds an include() that selects the first matching indexed query and bounds the read. */
|
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";function c(e){let t=e?.trim().toLowerCase();return t===`member`?`writer`:t===`reader`||t===`writer`||t===`admin`?t:null}function l(t){let n=t?.errors??e,r=t?.maxRows??100;function i(e,t){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:async(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}}}return e=>i(e)}function u(c){let u=c.errors??e,d=c.triggers?e=>c.triggers.wrapDB(e):c.wrapDB??(e=>e),f=l({errors:u,maxRows:c.maxIncludedQueryRows});async function p(e){let t=await e.auth.getUserIdentity(),n=t?await c.getAuthUser(e):null;if(!t||!n)return u.throw({code:`UNAUTHENTICATED`});let r=t.organization,i=r&&typeof r==`object`&&`organizationId`in r&&typeof r.organizationId==`string`?r.organizationId:typeof t.org_id==`string`?t.org_id:null;if(!i)return u.throw({code:`UNAUTHENTICATED`});let a=r&&typeof r==`object`&&`role`in r&&typeof r.role==`string`?r.role:typeof t.role==`string`?t.role:void 0,o=c.mapRole(a);if(!o)return u.throw({code:`FORBIDDEN`});let s={identity:t,user:Object.freeze({id:n.id}),org:Object.freeze({organizationId:i,role:o}),role:o,actor:Object.freeze({userId:n.id,organizationId:i,role:o})};return Object.freeze({...s,tenant:c.security?.tenancy?.resolve?.(s)??i})}let m=c.security?{defaultPolicy:c.security.defaultPolicy??(c.security.tenancy?`deny`:`allow`)}:void 0;function h(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 g(e,t){let n=h(t);return n?{...e,db:r({},e.db,n,m)}:e}function _(e,t){let n=h(t);return n?{...e,db:i({},e.db,n,m)}:e}async function v(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 u.throw({code:`FORBIDDEN`})}function y(e,t){if(!t.includes(e))return u.throw({code:`FORBIDDEN`})}async function b(e){let t=await p(e);return{ctx:{...g(e,t),include:f,...t},args:{}}}async function x(e){let t=await p(e);return{ctx:{..._(d(e),t),include:f,...t},args:{}}}async function S(e){let t=await p(e),n=await v(t.user.id,t.org.organizationId);if(!n)return{ctx:{...e,...t},args:{}};let r=c.mapRole(n.roleSlug);if(!r)return u.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 C(...e){return s(c.query,{args:{},input:async t=>{let n=await b(t);return y(n.ctx.actor.role,e),n}})}function w(...e){return o(c.mutation,{args:{},input:async t=>{let n=await x(t);return y(n.ctx.actor.role,e),n}})}function T(...e){return a(c.action,{args:{},input:async t=>{let n=await S(t);return y(n.ctx.actor.role,e),n}})}return{include:f,authenticatedUser:p,roleQuery:C,roleMutation:w,roleAction:T,authQuery:s(c.query,{args:{},input:b}),authMutation:o(c.mutation,{args:{},input:x}),authAction:a(c.action,{args:{},input:S}),adminQuery:C(...c.adminRoles),adminMutation:w(...c.adminRoles),adminAction:T(...c.adminRoles),systemQuery:s(c.internalQuery,{args:{},input:async e=>({ctx:{...e,include:f},args:{}})}),systemMutation:o(c.internalMutation,{args:{},input:async e=>({ctx:{...d(e),include:f},args:{}})}),systemAction:a(c.internalAction,{args:{},input:async e=>({ctx:e,args:{}})})}}export{u as createAuthFunctions,l as createInclude,c as defaultRoleMap};
|
|
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";function c(e){let t=e?.trim().toLowerCase();return t===`member`?`writer`:t===`reader`||t===`writer`||t===`admin`?t:null}function l(t){let n=t?.errors??e,r=t?.maxRows??100;function i(e,t){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:async(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},paginate:async(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 e=>i(e)}function u(c){let u=c.errors??e,d=c.triggers?e=>c.triggers.wrapDB(e):c.wrapDB??(e=>e),f=l({errors:u,maxRows:c.maxIncludedQueryRows});async function p(e){let t=await e.auth.getUserIdentity(),n=t?await c.getAuthUser(e):null;if(!t||!n)return u.throw({code:`UNAUTHENTICATED`});let r=t.organization,i=r&&typeof r==`object`&&`organizationId`in r&&typeof r.organizationId==`string`?r.organizationId:typeof t.org_id==`string`?t.org_id:null;if(!i)return u.throw({code:`UNAUTHENTICATED`});let a=r&&typeof r==`object`&&`role`in r&&typeof r.role==`string`?r.role:typeof t.role==`string`?t.role:void 0,o=c.mapRole(a);if(!o)return u.throw({code:`FORBIDDEN`});let s={identity:t,user:Object.freeze({id:n.id}),org:Object.freeze({organizationId:i,role:o}),role:o,actor:Object.freeze({userId:n.id,organizationId:i,role:o})};return Object.freeze({...s,tenant:c.security?.tenancy?.resolve?.(s)??i})}let m=c.security?{defaultPolicy:c.security.defaultPolicy??(c.security.tenancy?`deny`:`allow`)}:void 0;function h(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 g(e,t){let n=h(t);return n?{...e,db:r({},e.db,n,m)}:e}function _(e,t){let n=h(t);return n?{...e,db:i({},e.db,n,m)}:e}async function v(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 u.throw({code:`FORBIDDEN`})}function y(e,t){if(!t.includes(e))return u.throw({code:`FORBIDDEN`})}async function b(e){let t=await p(e);return{ctx:{...g(e,t),include:f,...t},args:{}}}async function x(e){let t=await p(e);return{ctx:{..._(d(e),t),include:f,...t},args:{}}}async function S(e){let t=await p(e),n=await v(t.user.id,t.org.organizationId);if(!n)return{ctx:{...e,...t},args:{}};let r=c.mapRole(n.roleSlug);if(!r)return u.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 C(...e){return s(c.query,{args:{},input:async t=>{let n=await b(t);return y(n.ctx.actor.role,e),n}})}function w(...e){return o(c.mutation,{args:{},input:async t=>{let n=await x(t);return y(n.ctx.actor.role,e),n}})}function T(...e){return a(c.action,{args:{},input:async t=>{let n=await S(t);return y(n.ctx.actor.role,e),n}})}return{include:f,authenticatedUser:p,roleQuery:C,roleMutation:w,roleAction:T,authQuery:s(c.query,{args:{},input:b}),authMutation:o(c.mutation,{args:{},input:x}),authAction:a(c.action,{args:{},input:S}),adminQuery:C(...c.adminRoles),adminMutation:w(...c.adminRoles),adminAction:T(...c.adminRoles),systemQuery:s(c.internalQuery,{args:{},input:async e=>({ctx:{...e,include:f},args:{}})}),systemMutation:o(c.internalMutation,{args:{},input:async e=>({ctx:{...d(e),include:f},args:{}})}),systemAction:a(c.internalAction,{args:{},input:async e=>({ctx:e,args:{}})})}}export{u as createAuthFunctions,l as createInclude,c as defaultRoleMap};
|
|
2
2
|
//# sourceMappingURL=auth.mjs.map
|
package/dist/auth.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.mjs","names":[],"sources":["../src/auth.ts"],"sourcesContent":["import {\n\tzCustomAction,\n\tzCustomMutation,\n\tzCustomQuery,\n} from 'convex-helpers/server/zod4'\nimport type {\n\tActionBuilder,\n\tDocumentByInfo,\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<\n\tDataModel extends GenericDataModel,\n\tRole extends string,\n> = {\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<\n\tDataModel extends GenericDataModel,\n\tRole extends string,\n> = {\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: (\n\t\tctx: AnyAuthContext<DataModel>,\n\t) => 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/** 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?: (\n\t\tctx: GenericMutationCtx<DataModel>,\n\t) => 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' ||\n\t\tnormalized === 'writer' ||\n\t\tnormalized === '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<\n\t\t\t\tDocumentByInfo<Table>,\n\t\t\t\tNamedIndex<Table, IndexName>\n\t\t\t>,\n\t\t) => IndexRange,\n\t\tshouldMatch?: boolean,\n\t): IncludedQuery<Table>\n\totherwise(\n\t\tselect: (query: QueryInitializer<Table>) => Query<Table>,\n\t): Query<Table>\n\tresolve(): Query<Table>\n\texecute<Result = Awaited<ReturnType<Query<Table>['take']>>>(\n\t\tlimit: number,\n\t\ttransform?: (\n\t\t\tdata: Awaited<ReturnType<Query<Table>['take']>>,\n\t\t) => Result | Promise<Result>,\n\t): Promise<Result>\n}\n\nexport type Include = <Table extends GenericTableInfo>(\n\tquery: QueryInitializer<Table>,\n) => IncludedQuery<Table>\n\n/** Builds an include() that selects the first matching indexed query and bounds the read. */\nexport function createInclude(options?: {\n\terrors?: ErrorFactory\n\tmaxRows?: number\n}): 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\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: async (limit, transform) => {\n\t\t\t\tif (!Number.isSafeInteger(limit) || limit < 1 || limit > maxRows) {\n\t\t\t\t\treturn errors.throw({\n\t\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\t\tmessage: `A bounded query limit must be from 1 to ${maxRows}`,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconst data = await (selected ?? query.fullTableScan()).take(limit)\n\t\t\t\treturn transform ? transform(data) : (data as never)\n\t\t\t},\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>) {\n\tconst errors = config.errors ?? defaultErrors\n\tconst wrapDB = config.triggers\n\t\t? (ctx: GenericMutationCtx<DataModel>) =>\n\t\t\t\t(config.triggers as Triggers<DataModel>).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(\n\t\tctx: AnyAuthContext<DataModel>,\n\t): 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\tconst organization = identity.organization\n\t\tconst organizationId =\n\t\t\torganization &&\n\t\t\ttypeof organization === 'object' &&\n\t\t\t'organizationId' in organization &&\n\t\t\ttypeof organization.organizationId === 'string'\n\t\t\t\t? organization.organizationId\n\t\t\t\t: typeof identity.org_id === 'string'\n\t\t\t\t\t? identity.org_id\n\t\t\t\t\t: null\n\t\tif (!organizationId) return errors.throw({ code: 'UNAUTHENTICATED' })\n\t\tconst organizationRole =\n\t\t\torganization &&\n\t\t\ttypeof organization === 'object' &&\n\t\t\t'role' in organization &&\n\t\t\ttypeof organization.role === 'string'\n\t\t\t\t? organization.role\n\t\t\t\t: typeof identity.role === 'string'\n\t\t\t\t\t? identity.role\n\t\t\t\t\t: undefined\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 ??\n\t\t\t\t\t(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<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(\n\t\t\t\tcreateTenantRules<DataModel>(bundle.tenant, security.tenancy.tables),\n\t\t\t)\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 as never, 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 as never, 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:\n\t\t\t\t\tconfig.security?.tenancy?.resolve?.(verified) ??\n\t\t\t\t\tmembership.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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.mjs","names":[],"sources":["../src/auth.ts"],"sourcesContent":["import {\n\tzCustomAction,\n\tzCustomMutation,\n\tzCustomQuery,\n} 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<\n\tDataModel extends GenericDataModel,\n\tRole extends string,\n> = {\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<\n\tDataModel extends GenericDataModel,\n\tRole extends string,\n> = {\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: (\n\t\tctx: AnyAuthContext<DataModel>,\n\t) => 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/** 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?: (\n\t\tctx: GenericMutationCtx<DataModel>,\n\t) => 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' ||\n\t\tnormalized === 'writer' ||\n\t\tnormalized === '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<\n\t\t\t\tDocumentByInfo<Table>,\n\t\t\t\tNamedIndex<Table, IndexName>\n\t\t\t>,\n\t\t) => IndexRange,\n\t\tshouldMatch?: boolean,\n\t): IncludedQuery<Table>\n\totherwise(\n\t\tselect: (query: QueryInitializer<Table>) => Query<Table>,\n\t): Query<Table>\n\tresolve(): Query<Table>\n\texecute<Result = Awaited<ReturnType<Query<Table>['take']>>>(\n\t\tlimit: number,\n\t\ttransform?: (\n\t\t\tdata: Awaited<ReturnType<Query<Table>['take']>>,\n\t\t) => 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<Item = DocumentByInfo<Table>>(\n\t\topts: PaginationOptions,\n\t\ttransform?: (\n\t\t\tpage: DocumentByInfo<Table>[],\n\t\t) => 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/** Builds an include() that selects the first matching indexed query and bounds the read. */\nexport function createInclude(options?: {\n\terrors?: ErrorFactory\n\tmaxRows?: number\n}): 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\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: async (limit, transform) => {\n\t\t\t\tif (!Number.isSafeInteger(limit) || limit < 1 || limit > maxRows) {\n\t\t\t\t\treturn errors.throw({\n\t\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\t\tmessage: `A bounded query limit must be from 1 to ${maxRows}`,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconst data = await (selected ?? query.fullTableScan()).take(limit)\n\t\t\t\treturn transform ? transform(data) : (data as never)\n\t\t\t},\n\t\t\tpaginate: async (opts, transform) => {\n\t\t\t\tif (\n\t\t\t\t\t!Number.isSafeInteger(opts.numItems) ||\n\t\t\t\t\topts.numItems < 1 ||\n\t\t\t\t\topts.numItems > maxRows\n\t\t\t\t) {\n\t\t\t\t\treturn errors.throw({\n\t\t\t\t\t\tcode: 'INVALID_REQUEST_BOUNDARY',\n\t\t\t\t\t\tmessage: `A page size must be from 1 to ${maxRows}`,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconst result = await (selected ?? query.fullTableScan()).paginate(opts)\n\t\t\t\tif (!transform) return result as never\n\t\t\t\treturn { ...result, page: await transform(result.page) } as never\n\t\t\t},\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>) {\n\tconst errors = config.errors ?? defaultErrors\n\tconst wrapDB = config.triggers\n\t\t? (ctx: GenericMutationCtx<DataModel>) =>\n\t\t\t\t(config.triggers as Triggers<DataModel>).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(\n\t\tctx: AnyAuthContext<DataModel>,\n\t): 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\tconst organization = identity.organization\n\t\tconst organizationId =\n\t\t\torganization &&\n\t\t\ttypeof organization === 'object' &&\n\t\t\t'organizationId' in organization &&\n\t\t\ttypeof organization.organizationId === 'string'\n\t\t\t\t? organization.organizationId\n\t\t\t\t: typeof identity.org_id === 'string'\n\t\t\t\t\t? identity.org_id\n\t\t\t\t\t: null\n\t\tif (!organizationId) return errors.throw({ code: 'UNAUTHENTICATED' })\n\t\tconst organizationRole =\n\t\t\torganization &&\n\t\t\ttypeof organization === 'object' &&\n\t\t\t'role' in organization &&\n\t\t\ttypeof organization.role === 'string'\n\t\t\t\t? organization.role\n\t\t\t\t: typeof identity.role === 'string'\n\t\t\t\t\t? identity.role\n\t\t\t\t\t: undefined\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 ??\n\t\t\t\t\t(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<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(\n\t\t\t\tcreateTenantRules<DataModel>(bundle.tenant, security.tenancy.tables),\n\t\t\t)\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 as never, 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 as never, 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:\n\t\t\t\t\tconfig.security?.tenancy?.resolve?.(verified) ??\n\t\t\t\t\tmembership.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"],"mappings":"mQAoJA,SAAgB,EAAe,EAAuC,CACrE,IAAM,EAAa,GAAU,KAAK,CAAC,CAAC,YAAY,EAEhD,OADI,IAAe,SAAiB,SAC7B,IAAe,UACrB,IAAe,UACf,IAAe,QACb,EACA,IACJ,CA+CA,SAAgB,EAAc,EAGlB,CACX,IAAM,EAAS,GAAS,QAAU,EAC5B,EAAU,GAAS,SAAW,IAEpC,SAAS,EACR,EACA,EACuB,CACvB,MAAO,CACN,MAAO,EAAO,IACb,GAAY,GAAiC,KAC1C,EAAO,EAAO,CAAQ,EACtB,EAAO,EAAO,EAAO,EAAO,CAAK,CAAC,EACtC,UAAW,EAAW,EAAY,EAAc,KAC/C,GAAY,CAAC,EACV,EAAO,EAAO,CAAQ,EACtB,EAAO,EAAO,EAAM,UAAU,EAAW,CAAU,CAAC,EACxD,UAAY,GAAW,GAAY,EAAO,CAAK,EAC/C,YAAe,GAAY,EAAM,cAAc,EAC/C,QAAS,MAAO,EAAO,IAAc,CACpC,GAAI,CAAC,OAAO,cAAc,CAAK,GAAK,EAAQ,GAAK,EAAQ,EACxD,OAAO,EAAO,MAAM,CACnB,KAAM,2BACN,QAAS,2CAA2C,GACrD,CAAC,EAEF,IAAM,EAAO,MAAO,GAAY,EAAM,cAAc,EAAA,CAAG,KAAK,CAAK,EACjE,OAAO,EAAY,EAAU,CAAI,EAAK,CACvC,EACA,SAAU,MAAO,EAAM,IAAc,CACpC,GACC,CAAC,OAAO,cAAc,EAAK,QAAQ,GACnC,EAAK,SAAW,GAChB,EAAK,SAAW,EAEhB,OAAO,EAAO,MAAM,CACnB,KAAM,2BACN,QAAS,iCAAiC,GAC3C,CAAC,EAEF,IAAM,EAAS,MAAO,GAAY,EAAM,cAAc,EAAA,CAAG,SAAS,CAAI,EAEtE,OADK,EACE,CAAE,GAAG,EAAQ,KAAM,MAAM,EAAU,EAAO,IAAI,CAAE,EADhC,CAExB,CACD,CACD,CAEA,MAAQ,IAAU,EAAO,CAAK,CAC/B,CAUA,SAAgB,EAGd,EAA8C,CAC/C,IAAM,EAAS,EAAO,QAAU,EAC1B,EAAS,EAAO,SAClB,GACA,EAAO,SAAiC,OAAO,CAAG,EAClD,EAAO,SAAY,GAAQ,GACzB,EAAU,EAAc,CAC7B,SACA,QAAS,EAAO,oBACjB,CAAC,EAED,eAAe,EACd,EAC4B,CAC5B,IAAM,EAAW,MAAM,EAAI,KAAK,gBAAgB,EAC1C,EAAO,EAAW,MAAM,EAAO,YAAY,CAAG,EAAI,KACxD,GAAI,CAAC,GAAY,CAAC,EAAM,OAAO,EAAO,MAAM,CAAE,KAAM,iBAAkB,CAAC,EACvE,IAAM,EAAe,EAAS,aACxB,EACL,GACA,OAAO,GAAiB,UACxB,mBAAoB,GACpB,OAAO,EAAa,gBAAmB,SACpC,EAAa,eACb,OAAO,EAAS,QAAW,SAC1B,EAAS,OACT,KACL,GAAI,CAAC,EAAgB,OAAO,EAAO,MAAM,CAAE,KAAM,iBAAkB,CAAC,EACpE,IAAM,EACL,GACA,OAAO,GAAiB,UACxB,SAAU,GACV,OAAO,EAAa,MAAS,SAC1B,EAAa,KACb,OAAO,EAAS,MAAS,SACxB,EAAS,KACT,IAAA,GACC,EAAO,EAAO,QAAQ,CAAgB,EAC5C,GAAI,CAAC,EAAM,OAAO,EAAO,MAAM,CAAE,KAAM,WAAY,CAAC,EACpD,IAAM,EAAO,CACZ,WACA,KAAM,OAAO,OAAO,CAAE,GAAI,EAAK,EAAG,CAAC,EACnC,IAAK,OAAO,OAAO,CAAE,iBAAgB,MAAK,CAAC,EAC3C,OACA,MAAO,OAAO,OAAO,CAAE,OAAQ,EAAK,GAAI,iBAAgB,MAAK,CAAC,CAC/D,EACA,OAAO,OAAO,OAAO,CACpB,GAAG,EACH,OAAQ,EAAO,UAAU,SAAS,UAAU,CAAI,GAAK,CACtD,CAAC,CACF,CAEA,IAAM,EAAwC,EAAO,SAClD,CACA,cACC,EAAO,SAAS,gBACf,EAAO,SAAS,QAAU,OAAS,QACtC,EACC,IAAA,GAEH,SAAS,EACR,EACwC,CACxC,IAAM,EAAW,EAAO,SACxB,GAAI,CAAC,EAAU,OACf,IAAM,EAAoC,CAAC,EAO3C,OANI,EAAS,SACZ,EAAK,KACJ,EAA6B,EAAO,OAAQ,EAAS,QAAQ,MAAM,CACpE,EAEG,EAAS,OAAO,EAAK,KAAK,EAAS,MAAM,CAAM,CAAC,EAC7C,EAAK,SAAW,EAAI,EAAK,GAAK,EAAa,GAAG,CAAI,CAC1D,CAEA,SAAS,EACR,EACA,EAC6B,CAC7B,IAAM,EAAQ,EAAc,CAAM,EAElC,OADK,EACE,CACN,GAAG,EACH,GAAI,EAAmB,CAAC,EAAG,EAAI,GAAI,EAAgB,CAAc,CAClE,EAJmB,CAKpB,CAEA,SAAS,EACR,EACA,EACgC,CAChC,IAAM,EAAQ,EAAc,CAAM,EAIlC,OAHK,EAGE,CACN,GAAG,EACH,GAAI,EAAmB,CAAC,EAAG,EAAI,GAAI,EAAgB,CAAc,CAClE,EANmB,CAOpB,CAEA,eAAe,EAAmB,EAAgB,EAAwB,CACzE,GAAI,CAAC,EAAO,iBAAkB,OAAO,KACrC,GAAI,CACH,IAAM,EAAa,MAAM,EAAO,iBAAiB,CAChD,SACA,gBACD,CAAC,EACD,GAAI,GAAc,EAAW,iBAAmB,EAC/C,OAAO,CAET,MAAQ,CAER,CACA,OAAO,EAAO,MAAM,CAAE,KAAM,WAAY,CAAC,CAC1C,CAEA,SAAS,EAAY,EAAY,EAA0B,CAC1D,GAAI,CAAC,EAAQ,SAAS,CAAI,EAAG,OAAO,EAAO,MAAM,CAAE,KAAM,WAAY,CAAC,CACvE,CAEA,eAAe,EAAW,EAAiC,CAC1D,IAAM,EAAS,MAAM,EAAkB,CAAG,EAC1C,MAAO,CACN,IAAK,CAAE,GAAG,EAAa,EAAK,CAAM,EAAG,UAAS,GAAG,CAAO,EACxD,KAAM,CAAC,CACR,CACD,CAEA,eAAe,EAAc,EAAoC,CAChE,IAAM,EAAS,MAAM,EAAkB,CAAG,EAC1C,MAAO,CACN,IAAK,CAAE,GAAG,EAAa,EAAO,CAAG,EAAG,CAAM,EAAG,UAAS,GAAG,CAAO,EAChE,KAAM,CAAC,CACR,CACD,CAEA,eAAe,EAAY,EAAkC,CAC5D,IAAM,EAAgB,MAAM,EAAkB,CAAG,EAC3C,EAAa,MAAM,EACxB,EAAc,KAAK,GACnB,EAAc,IAAI,cACnB,EACA,GAAI,CAAC,EAAY,MAAO,CAAE,IAAK,CAAE,GAAG,EAAK,GAAG,CAAc,EAAG,KAAM,CAAC,CAAE,EACtE,IAAM,EAAO,EAAO,QAAQ,EAAW,QAAQ,EAC/C,GAAI,CAAC,EAAM,OAAO,EAAO,MAAM,CAAE,KAAM,WAAY,CAAC,EACpD,IAAM,EAAW,CAChB,SAAU,EAAc,SACxB,KAAM,EAAc,KACpB,IAAK,OAAO,OAAO,CAClB,eAAgB,EAAW,eAC3B,MACD,CAAC,EACD,OACA,MAAO,OAAO,OAAO,CACpB,OAAQ,EAAc,KAAK,GAC3B,eAAgB,EAAW,eAC3B,MACD,CAAC,CACF,EACA,MAAO,CACN,IAAK,CACJ,GAAG,EACH,GAAG,EAEH,OACC,EAAO,UAAU,SAAS,UAAU,CAAQ,GAC5C,EAAW,cACb,EACA,KAAM,CAAC,CACR,CACD,CAGA,SAAS,EAAU,GAAG,EAA0B,CAC/C,OAAO,EAAa,EAAO,MAAO,CACjC,KAAM,CAAC,EACP,MAAO,KAAO,IAAQ,CACrB,IAAM,EAAgB,MAAM,EAAW,CAAG,EAE1C,OADA,EAAY,EAAc,IAAI,MAAM,KAAM,CAAO,EAC1C,CACR,CACD,CAAC,CACF,CAGA,SAAS,EAAa,GAAG,EAA0B,CAClD,OAAO,EAAgB,EAAO,SAAU,CACvC,KAAM,CAAC,EACP,MAAO,KAAO,IAAQ,CACrB,IAAM,EAAgB,MAAM,EAAc,CAAG,EAE7C,OADA,EAAY,EAAc,IAAI,MAAM,KAAM,CAAO,EAC1C,CACR,CACD,CAAC,CACF,CAGA,SAAS,EAAW,GAAG,EAA0B,CAChD,OAAO,EAAc,EAAO,OAAQ,CACnC,KAAM,CAAC,EACP,MAAO,KAAO,IAAQ,CACrB,IAAM,EAAgB,MAAM,EAAY,CAAG,EAE3C,OADA,EAAY,EAAc,IAAI,MAAM,KAAM,CAAO,EAC1C,CACR,CACD,CAAC,CACF,CAEA,MAAO,CACN,UACA,oBACA,YACA,eACA,aACA,UAAW,EAAa,EAAO,MAAO,CAAE,KAAM,CAAC,EAAG,MAAO,CAAW,CAAC,EACrE,aAAc,EAAgB,EAAO,SAAU,CAC9C,KAAM,CAAC,EACP,MAAO,CACR,CAAC,EACD,WAAY,EAAc,EAAO,OAAQ,CACxC,KAAM,CAAC,EACP,MAAO,CACR,CAAC,EACD,WAAY,EAAU,GAAG,EAAO,UAAU,EAC1C,cAAe,EAAa,GAAG,EAAO,UAAU,EAChD,YAAa,EAAW,GAAG,EAAO,UAAU,EAC5C,YAAa,EAAa,EAAO,cAAe,CAC/C,KAAM,CAAC,EACP,MAAO,KAAO,KAAS,CAAE,IAAK,CAAE,GAAG,EAAK,SAAQ,EAAG,KAAM,CAAC,CAAE,EAC7D,CAAC,EACD,eAAgB,EAAgB,EAAO,iBAAkB,CACxD,KAAM,CAAC,EACP,MAAO,KAAO,KAAS,CAAE,IAAK,CAAE,GAAG,EAAO,CAAG,EAAG,SAAQ,EAAG,KAAM,CAAC,CAAE,EACrE,CAAC,EACD,aAAc,EAAc,EAAO,eAAgB,CAClD,KAAM,CAAC,EACP,MAAO,KAAO,KAAS,CAAE,MAAK,KAAM,CAAC,CAAE,EACxC,CAAC,CACF,CACD"}
|
|
@@ -5,6 +5,7 @@ import { workflow_steps_d_exports } from "../workflow_steps.mjs";
|
|
|
5
5
|
import { client_d_exports } from "../client.mjs";
|
|
6
6
|
import { decisions_d_exports } from "../decisions.mjs";
|
|
7
7
|
import { functions_d_exports } from "../functions.mjs";
|
|
8
|
+
import { health_d_exports } from "../health.mjs";
|
|
8
9
|
import { requests_d_exports } from "../requests.mjs";
|
|
9
10
|
import { workflow_d_exports } from "../workflow.mjs";
|
|
10
11
|
import { ApiFromModules, FilterApi, FunctionReference } from "convex/server";
|
|
@@ -15,6 +16,7 @@ declare const fullApi: ApiFromModules<{
|
|
|
15
16
|
constants: typeof constants_d_exports;
|
|
16
17
|
decisions: typeof decisions_d_exports;
|
|
17
18
|
functions: typeof functions_d_exports;
|
|
19
|
+
health: typeof health_d_exports;
|
|
18
20
|
requests: typeof requests_d_exports;
|
|
19
21
|
validators: typeof validators_d_exports;
|
|
20
22
|
workflow: typeof workflow_d_exports;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.mjs","names":[],"sources":["../../../../src/components/approvals/_generated/api.ts"],"sourcesContent":["/* eslint-disable */\n/**\n * Generated `api` utility.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport type * as audit from \"../audit.js\";\nimport type * as client from \"../client.js\";\nimport type * as constants from \"../constants.js\";\nimport type * as decisions from \"../decisions.js\";\nimport type * as functions from \"../functions.js\";\nimport type * as requests from \"../requests.js\";\nimport type * as validators from \"../validators.js\";\nimport type * as workflow from \"../workflow.js\";\nimport type * as workflow_steps from \"../workflow_steps.js\";\n\nimport type {\n ApiFromModules,\n FilterApi,\n FunctionReference,\n} from \"convex/server\";\nimport { anyApi, componentsGeneric } from \"convex/server\";\n\nconst fullApi: ApiFromModules<{\n audit: typeof audit;\n client: typeof client;\n constants: typeof constants;\n decisions: typeof decisions;\n functions: typeof functions;\n requests: typeof requests;\n validators: typeof validators;\n workflow: typeof workflow;\n workflow_steps: typeof workflow_steps;\n}> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's public API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = api.myModule.myFunction;\n * ```\n */\nexport const api: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"public\">\n> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's internal API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = internal.myModule.myFunction;\n * ```\n */\nexport const internal: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"internal\">\n> = anyApi as any;\n\nexport const components = componentsGeneric() as unknown as {\n workflow: import(\"@convex-dev/workflow/_generated/component.js\").ComponentApi<\"workflow\">;\n auditLog: import(\"convex-audit-log/_generated/component.js\").ComponentApi<\"auditLog\">;\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.mjs","names":[],"sources":["../../../../src/components/approvals/_generated/api.ts"],"sourcesContent":["/* eslint-disable */\n/**\n * Generated `api` utility.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport type * as audit from \"../audit.js\";\nimport type * as client from \"../client.js\";\nimport type * as constants from \"../constants.js\";\nimport type * as decisions from \"../decisions.js\";\nimport type * as functions from \"../functions.js\";\nimport type * as health from \"../health.js\";\nimport type * as requests from \"../requests.js\";\nimport type * as validators from \"../validators.js\";\nimport type * as workflow from \"../workflow.js\";\nimport type * as workflow_steps from \"../workflow_steps.js\";\n\nimport type {\n ApiFromModules,\n FilterApi,\n FunctionReference,\n} from \"convex/server\";\nimport { anyApi, componentsGeneric } from \"convex/server\";\n\nconst fullApi: ApiFromModules<{\n audit: typeof audit;\n client: typeof client;\n constants: typeof constants;\n decisions: typeof decisions;\n functions: typeof functions;\n health: typeof health;\n requests: typeof requests;\n validators: typeof validators;\n workflow: typeof workflow;\n workflow_steps: typeof workflow_steps;\n}> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's public API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = api.myModule.myFunction;\n * ```\n */\nexport const api: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"public\">\n> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's internal API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = internal.myModule.myFunction;\n * ```\n */\nexport const internal: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"internal\">\n> = anyApi as any;\n\nexport const components = componentsGeneric() as unknown as {\n workflow: import(\"@convex-dev/workflow/_generated/component.js\").ComponentApi<\"workflow\">;\n auditLog: import(\"convex-audit-log/_generated/component.js\").ComponentApi<\"auditLog\">;\n};\n"],"mappings":"8DAiDA,MAAa,EAGT,EAUS,EAGT,EAES,EAAa,EAAkB"}
|
|
@@ -52,6 +52,13 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
52
52
|
stepKey: string;
|
|
53
53
|
}>, Name>;
|
|
54
54
|
};
|
|
55
|
+
health: {
|
|
56
|
+
check: FunctionReference<"query", "internal", Record<string, never>, {
|
|
57
|
+
requiredIndexes: Array<string>;
|
|
58
|
+
schemaVersion: 1;
|
|
59
|
+
status: "ready";
|
|
60
|
+
}, Name>;
|
|
61
|
+
};
|
|
55
62
|
requests: {
|
|
56
63
|
cancel: FunctionReference<"mutation", "internal", {
|
|
57
64
|
actor: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import _default from "../schema.
|
|
1
|
+
import _default from "../schema.js";
|
|
2
2
|
import { DataModelFromSchemaDefinition, DocumentByName, SystemTableNames, TableNamesInDataModel } from "convex/server";
|
|
3
3
|
import { GenericId } from "convex/values";
|
|
4
4
|
//#region src/components/approvals/_generated/dataModel.d.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ComponentApi } from "./_generated/component.mjs";
|
|
2
2
|
import { ApprovalDecision } from "./constants.mjs";
|
|
3
|
-
import { ApprovalActor, ApprovalMetadata, ApprovalWorkflowDescriptor } from "./validators.mjs";
|
|
4
|
-
import { ApprovalActionStep, ApprovalBranchStep,
|
|
3
|
+
import { ApprovalActor, ApprovalCallbackInput, ApprovalMetadata, ApprovalWorkflowDescriptor, approvalCallbackArgs, approvalCallbackInput } from "./validators.mjs";
|
|
4
|
+
import { ApprovalActionStep, ApprovalBranchStep, ApprovalDecisionStep, ApprovalDefinition, ApprovalMutationStep, ApprovalNotifyStep, ApprovalWorkflowStep, CreateApprovalHandle } from "./workflow_steps.mjs";
|
|
5
5
|
import { FunctionArgs, FunctionReference, FunctionReturnType, GenericDataModel, GenericMutationCtx, GenericQueryCtx } from "convex/server";
|
|
6
6
|
declare namespace client_d_exports {
|
|
7
|
-
export { ApprovalAuditCleanupInput, ApprovalAuditHistoryInput, ApprovalDecisionInput, ApprovalEvidenceItem, ApprovalStartInput, ApprovalStatus, Approvals, ApprovalsOptions, ConfiguredApprovalWorkflow };
|
|
7
|
+
export { ApprovalAuditCleanupInput, ApprovalAuditHistoryInput, ApprovalCallbackInput, ApprovalDecisionInput, ApprovalEvidenceItem, ApprovalStartInput, ApprovalStatus, Approvals, ApprovalsOptions, ConfiguredApprovalWorkflow, approvalCallbackArgs, approvalCallbackInput };
|
|
8
8
|
}
|
|
9
9
|
type ApprovalsOptions = Readonly<{
|
|
10
10
|
createHandle?: CreateApprovalHandle;
|
|
@@ -93,5 +93,5 @@ declare class ConfiguredApprovalWorkflow<Component extends ComponentApi = Compon
|
|
|
93
93
|
restart<DataModel extends GenericDataModel>(ctx: GenericMutationCtx<DataModel>, runId: string): Promise<FunctionReturnType<Component['requests']['restart']>>;
|
|
94
94
|
}
|
|
95
95
|
//#endregion
|
|
96
|
-
export { ApprovalAuditCleanupInput, ApprovalAuditHistoryInput, ApprovalDecisionInput, ApprovalEvidenceItem, ApprovalStartInput, ApprovalStatus, Approvals, ApprovalsOptions, ConfiguredApprovalWorkflow, client_d_exports };
|
|
96
|
+
export { ApprovalAuditCleanupInput, ApprovalAuditHistoryInput, type ApprovalCallbackInput, ApprovalDecisionInput, ApprovalEvidenceItem, ApprovalStartInput, ApprovalStatus, Approvals, ApprovalsOptions, ConfiguredApprovalWorkflow, approvalCallbackArgs, approvalCallbackInput, client_d_exports };
|
|
97
97
|
//# sourceMappingURL=client.d.mts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{approvalCallbackArgs as e,approvalCallbackInput as t}from"./validators.mjs";import{compileApprovalDescriptor as n}from"./workflow_steps.mjs";var r=class{component;createHandle;constructor(e,t={}){this.component=e,this.createHandle=t.createHandle}cleanupAudit(e,t){return e.runMutation(this.component.audit.cleanup,t)}mutation(e,t){return Object.freeze({kind:`mutation`,key:e,handler:t.handler,retry:t.retry??!1})}action(e,t){return Object.freeze({kind:`action`,key:e,handler:t.handler,retry:t.retry??!1})}notify(e,t){return Object.freeze({kind:`notify`,key:e,handler:t.handler,retry:t.retry??!1})}decision(e,t){return Object.freeze({kind:`decision`,key:e,decisions:Object.freeze([...t.decisions]),quorum:Object.freeze({...t.quorum}),makerChecker:t.makerChecker??!1,...t.expiresAfterMs===void 0?{}:{expiresAfterMs:t.expiresAfterMs}})}branch(e,t){return Object.freeze({kind:`branch`,key:e,...t})}define(e){let t=a({name:e.name,compatibilityKey:e.compatibilityKey??e.name,steps:e.steps});return new i(this.component,t,this.createHandle)}},i=class{name;compatibilityKey;steps;component;definition;createHandle;constructor(e,t,n){this.component=e,this.definition=t,this.name=t.name,this.compatibilityKey=t.compatibilityKey,this.steps=t.steps,this.createHandle=n,Object.freeze(this)}descriptor(){return n(this.definition,this.createHandle)}async start(e,t){return e.runMutation(this.component.requests.start,{...t,workflow:await this.descriptor()})}decide(e,t,n){return e.runMutation(this.component.decisions.decide,{...t,actor:n,compatibilityKey:this.compatibilityKey})}evidence(e,t){return e.runQuery(this.component.decisions.list,{runId:t})}auditHistory(e,t){return e.runQuery(this.component.audit.history,t)}cancel(e,t,n){return e.runMutation(this.component.requests.cancel,{runId:t,actor:n,compatibilityKey:this.compatibilityKey})}status(e,t){return e.runQuery(this.component.requests.status,{runId:t,compatibilityKey:this.compatibilityKey})}list(e,t){return e.runQuery(this.component.requests.list,t)}restart(e,t){return e.runMutation(this.component.requests.restart,{runId:t,compatibilityKey:this.compatibilityKey})}};function a(e){return Object.freeze({...e,steps:Object.freeze(e.steps.map(e=>e.kind===`decision`?Object.freeze({...e,decisions:Object.freeze([...e.decisions]),quorum:Object.freeze({...e.quorum})}):Object.freeze({...e})))})}export{r as Approvals,i as ConfiguredApprovalWorkflow,e as approvalCallbackArgs,t as approvalCallbackInput};
|
|
2
2
|
//# sourceMappingURL=client.mjs.map
|