cvx-kit 0.1.8 → 0.1.11
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 +32 -0
- package/README.md +28 -28
- package/dist/agent-tools.d.mts +5 -5
- package/dist/agent-tools.mjs.map +1 -1
- package/dist/auth.d.mts +39 -289
- package/dist/auth.mjs.map +1 -1
- package/dist/components/approvals/_generated/api.d.mts +3 -4
- package/dist/components/approvals/_generated/api.mjs.map +1 -1
- package/dist/components/approvals/_generated/component.d.mts +1 -2
- package/dist/components/approvals/_generated/dataModel.d.mts +4 -5
- package/dist/components/approvals/_generated/server.d.mts +12 -13
- package/dist/components/approvals/_generated/server.mjs.map +1 -1
- package/dist/components/approvals/audit.d.mts +8 -8
- package/dist/components/approvals/audit.mjs +1 -1
- package/dist/components/approvals/audit.mjs.map +1 -1
- package/dist/components/approvals/client.d.mts +10 -10
- package/dist/components/approvals/client.mjs.map +1 -1
- package/dist/components/approvals/constants.d.mts +30 -30
- package/dist/components/approvals/constants.mjs.map +1 -1
- package/dist/components/approvals/convex.config.mjs.map +1 -1
- package/dist/components/approvals/decisions.d.mts +6 -6
- package/dist/components/approvals/decisions.mjs.map +1 -1
- package/dist/components/approvals/functions.d.mts +3 -3
- package/dist/components/approvals/functions.mjs.map +1 -1
- package/dist/components/approvals/health.d.mts +2 -2
- package/dist/components/approvals/health.mjs.map +1 -1
- package/dist/components/approvals/requests.d.mts +8 -8
- package/dist/components/approvals/requests.mjs.map +1 -1
- package/dist/components/approvals/validators.d.mts +29 -29
- package/dist/components/approvals/validators.mjs +1 -1
- package/dist/components/approvals/validators.mjs.map +1 -1
- package/dist/components/approvals/workflow.d.mts +3 -3
- package/dist/components/approvals/workflow.mjs.map +1 -1
- package/dist/components/approvals/workflow_steps.d.mts +15 -15
- package/dist/components/approvals/workflow_steps.mjs.map +1 -1
- package/dist/components/foundation/_generated/api.d.mts +3 -4
- package/dist/components/foundation/_generated/api.mjs.map +1 -1
- package/dist/components/foundation/_generated/component.d.mts +1 -2
- package/dist/components/foundation/_generated/dataModel.d.mts +4 -5
- package/dist/components/foundation/_generated/server.d.mts +12 -13
- package/dist/components/foundation/_generated/server.mjs.map +1 -1
- package/dist/components/foundation/client.d.mts +13 -13
- package/dist/components/foundation/client.mjs.map +1 -1
- package/dist/components/foundation/convex.config.mjs.map +1 -1
- package/dist/components/foundation/functions.d.mts +2 -2
- package/dist/components/foundation/functions.mjs.map +1 -1
- package/dist/components/foundation/modules/command/command.d.mts +14 -14
- package/dist/components/foundation/modules/command/command.mjs.map +1 -1
- package/dist/components/foundation/modules/command/lifecycle.d.mts +12 -13
- package/dist/components/foundation/modules/command/lifecycle.mjs.map +1 -1
- package/dist/components/foundation/modules/observability/observability.d.mts +4 -4
- package/dist/components/foundation/modules/observability/observability.mjs.map +1 -1
- package/dist/components/foundation/modules/query/query.d.mts +5 -5
- package/dist/components/foundation/modules/query/query.mjs.map +1 -1
- package/dist/components/foundation/operation.d.mts +5 -6
- package/dist/components/foundation/operation.mjs.map +1 -1
- package/dist/components/foundation/result.d.mts +6 -6
- package/dist/components/foundation/result.mjs.map +1 -1
- package/dist/components/foundation/telemetry.d.mts +2 -2
- package/dist/components/foundation/telemetry.mjs.map +1 -1
- package/dist/crud.d.mts +6 -5
- package/dist/crud.mjs.map +1 -1
- package/dist/effect.d.mts +3 -2
- package/dist/effect.mjs +1 -1
- package/dist/errors.d.mts +4 -4
- package/dist/errors.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/middleware.d.mts +2 -3
- package/dist/middleware.mjs.map +1 -1
- package/dist/modules/contracts/contract.d.mts +12 -13
- package/dist/modules/contracts/contract.mjs.map +1 -1
- package/dist/modules/contracts/convex.d.mts +3 -5
- package/dist/modules/contracts/convex.mjs.map +1 -1
- package/dist/modules/contracts/errors.d.mts +8 -9
- package/dist/modules/contracts/errors.mjs +1 -1
- package/dist/modules/contracts/errors.mjs.map +1 -1
- package/dist/modules/contracts/exposure.d.mts +13 -14
- package/dist/modules/contracts/exposure.mjs +1 -1
- package/dist/modules/contracts/exposure.mjs.map +1 -1
- package/dist/modules/contracts/idempotency.d.mts +15 -16
- package/dist/modules/contracts/idempotency.mjs +1 -1
- package/dist/modules/contracts/idempotency.mjs.map +1 -1
- package/dist/modules/contracts/standard.d.mts +2 -3
- package/dist/modules/contracts/standard.mjs.map +1 -1
- package/dist/modules/contracts/workflow.d.mts +26 -27
- package/dist/modules/contracts/workflow.mjs.map +1 -1
- package/dist/modules/effect/api-runtime.d.mts +10 -11
- package/dist/modules/effect/api-runtime.mjs +1 -1
- package/dist/modules/effect/api-runtime.mjs.map +1 -1
- package/dist/modules/effect/api-zod.d.mts +2 -3
- package/dist/modules/effect/api-zod.mjs.map +1 -1
- package/dist/modules/effect/api.d.mts +4 -5
- package/dist/modules/effect/api.mjs.map +1 -1
- package/dist/modules/effect/auth.d.mts +43 -0
- package/dist/modules/effect/auth.mjs +2 -0
- package/dist/modules/effect/auth.mjs.map +1 -0
- package/dist/modules/effect/client.d.mts +1 -1
- package/dist/modules/effect/client.mjs +1 -1
- package/dist/modules/effect/command.d.mts +4 -5
- package/dist/modules/effect/command.mjs +1 -1
- package/dist/modules/effect/command.mjs.map +1 -1
- package/dist/modules/effect/crud.d.mts +7 -8
- package/dist/modules/effect/crud.mjs +1 -1
- package/dist/modules/effect/crud.mjs.map +1 -1
- package/dist/modules/effect/errors.d.mts +1 -2
- package/dist/modules/effect/errors.mjs.map +1 -1
- package/dist/modules/effect/foundation.d.mts +3 -4
- package/dist/modules/effect/foundation.mjs.map +1 -1
- package/dist/modules/effect/idempotency.d.mts +2 -3
- package/dist/modules/effect/idempotency.mjs.map +1 -1
- package/dist/modules/effect/normalize.d.mts +2 -3
- package/dist/modules/effect/normalize.mjs.map +1 -1
- package/dist/modules/effect/operation.d.mts +17 -18
- package/dist/modules/effect/operation.mjs.map +1 -1
- package/dist/modules/effect/query.d.mts +3 -4
- package/dist/modules/effect/query.mjs +1 -1
- package/dist/modules/effect/query.mjs.map +1 -1
- package/dist/modules/effect/schema.d.mts +8 -9
- package/dist/modules/effect/schema.mjs.map +1 -1
- package/dist/modules/effect/workflow.d.mts +5 -6
- package/dist/modules/effect/workflow.mjs +1 -1
- package/dist/modules/effect/workflow.mjs.map +1 -1
- package/dist/oxlint/architecture.d.mts +6 -7
- package/dist/oxlint/architecture.mjs +1 -1
- package/dist/oxlint/architecture.mjs.map +1 -1
- package/dist/oxlint/ast.d.mts +22 -23
- package/dist/oxlint/ast.mjs +1 -1
- package/dist/oxlint/ast.mjs.map +1 -1
- package/dist/oxlint/ownership.d.mts +2 -3
- package/dist/oxlint/ownership.mjs +1 -1
- package/dist/oxlint/ownership.mjs.map +1 -1
- package/dist/oxlint.d.mts +4 -4
- package/dist/oxlint.mjs +1 -1
- package/dist/oxlint.mjs.map +1 -1
- package/dist/state-machine.d.mts +1 -2
- package/dist/state-machine.mjs.map +1 -1
- package/dist/tenancy.d.mts +6 -6
- package/dist/tenancy.mjs.map +1 -1
- package/dist/triggers.d.mts +6 -6
- package/dist/triggers.mjs.map +1 -1
- package/dist/webhooks.d.mts +5 -6
- package/dist/webhooks.mjs.map +1 -1
- package/dist/zod-table.d.mts +10 -10
- package/dist/zod-table.mjs.map +1 -1
- package/docs/auth.md +131 -1
- package/docs/effect.md +8 -2
- package/docs/llms.md +41 -20
- package/docs/oxlint.md +1 -1
- package/docs/upgrading.md +9 -1
- package/docs/zod-table.md +1 -1
- package/package.json +21 -15
- package/scripts/test-packed-auth.mjs +72 -0
- package/scripts/test-packed-effect.mjs +2 -1
- package/scripts/test-packed-ids.mjs +2 -2
- package/dist/node_modules/@standard-schema/spec/dist/index.d.mts +0 -79
package/docs/auth.md
CHANGED
|
@@ -64,9 +64,139 @@ export const {
|
|
|
64
64
|
Every function in the app is then built from these — raw `query`/`mutation`
|
|
65
65
|
imports from `_generated/server` appear **only** in this file.
|
|
66
66
|
|
|
67
|
+
## One shared Effect function foundation
|
|
68
|
+
|
|
69
|
+
Use `createEffectAuthFunctions` from `cvx-kit/effect` in `convex/functions.ts`
|
|
70
|
+
to configure all twelve constructors once. Its first argument is the same
|
|
71
|
+
`AuthFunctionsConfig` used by `createAuthFunctions`; its second argument has
|
|
72
|
+
six explicit policies: `query`, `mutation`, `action`, `systemQuery`,
|
|
73
|
+
`systemMutation`, and `systemAction`. Each accepts `services`, `context`, and
|
|
74
|
+
`mapError`, like `effectZodApiBuilder`. Pass `{}` when no additions are needed.
|
|
75
|
+
|
|
76
|
+
Type the auth config with your generated `DataModel` and role vocabulary,
|
|
77
|
+
then let the factory infer its generics from both arguments. Do not supply
|
|
78
|
+
partial generic arguments, which would fix the remaining inference defaults.
|
|
79
|
+
The following public-package example defines a reusable app factory; the
|
|
80
|
+
host passes its auth, membership, trigger, and RLS policy as `config`.
|
|
81
|
+
|
|
82
|
+
<!-- packed-effect-example -->
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import {
|
|
86
|
+
defineSchema,
|
|
87
|
+
defineTable,
|
|
88
|
+
makeFunctionReference,
|
|
89
|
+
type DataModelFromSchemaDefinition,
|
|
90
|
+
type GenericQueryCtx,
|
|
91
|
+
type GenericMutationCtx,
|
|
92
|
+
} from 'convex/server'
|
|
93
|
+
import { v } from 'convex/values'
|
|
94
|
+
import { Effect } from 'effect'
|
|
95
|
+
import { z } from 'zod'
|
|
96
|
+
import type { AuthFunctionsConfig, AuthBundle } from 'cvx-kit/auth'
|
|
97
|
+
import { createEffectAuthFunctions, createEffectFoundation } from 'cvx-kit/effect'
|
|
98
|
+
|
|
99
|
+
const schema = defineSchema({ notes: defineTable({ tenant: v.string(), title: v.string() }) })
|
|
100
|
+
type Model = DataModelFromSchemaDefinition<typeof schema>
|
|
101
|
+
type Role = 'owner' | 'viewer'
|
|
102
|
+
const input = z.object({ title: z.string().trim().min(1) })
|
|
103
|
+
const saveRef = makeFunctionReference<'mutation', z.input<typeof input>, null>('notes:save')
|
|
104
|
+
|
|
105
|
+
export function createApplicationFunctions(config: AuthFunctionsConfig<Model, Role>) {
|
|
106
|
+
const foundation = createEffectFoundation({
|
|
107
|
+
observability: {
|
|
108
|
+
enabled: false,
|
|
109
|
+
classifyError: () => ({ outcome: 'failed', errorCode: 'FAILED' }),
|
|
110
|
+
},
|
|
111
|
+
writeAudit: () => undefined, // supply the app's transactional audit writer in production
|
|
112
|
+
})
|
|
113
|
+
const queries = foundation.Query({
|
|
114
|
+
context: (ctx: (GenericQueryCtx<Model> | GenericMutationCtx<Model>) & AuthBundle<Role>) => ctx,
|
|
115
|
+
operations: ({ query }) => ({
|
|
116
|
+
actor: query({
|
|
117
|
+
input: z.object({}),
|
|
118
|
+
result: z.string(),
|
|
119
|
+
handler: (_input, ctx) => ctx.actor.userId,
|
|
120
|
+
}),
|
|
121
|
+
}),
|
|
122
|
+
})
|
|
123
|
+
const commands = foundation.Command({
|
|
124
|
+
context: (ctx: GenericMutationCtx<Model> & AuthBundle<Role>) => ctx,
|
|
125
|
+
operations: ({ command }) => ({
|
|
126
|
+
save: command({
|
|
127
|
+
input,
|
|
128
|
+
result: z.null(),
|
|
129
|
+
classification: 'business',
|
|
130
|
+
audit: () => null,
|
|
131
|
+
handler: (args, ctx) =>
|
|
132
|
+
Effect.promise(async () => {
|
|
133
|
+
await ctx.db.insert('notes', { title: args.title, tenant: ctx.tenant })
|
|
134
|
+
return null
|
|
135
|
+
}),
|
|
136
|
+
}),
|
|
137
|
+
}),
|
|
138
|
+
})
|
|
139
|
+
const functions = createEffectAuthFunctions(config, {
|
|
140
|
+
query: { context: (ctx) => ({ queries: queries.withContext(ctx) }) },
|
|
141
|
+
mutation: {
|
|
142
|
+
context: (ctx) => ({
|
|
143
|
+
queries: queries.withContext(ctx),
|
|
144
|
+
commands: commands.withContext(ctx),
|
|
145
|
+
}),
|
|
146
|
+
},
|
|
147
|
+
action: {
|
|
148
|
+
context: (ctx) => ({
|
|
149
|
+
commands: {
|
|
150
|
+
save: (args: z.input<typeof input>) =>
|
|
151
|
+
Effect.promise(() => ctx.runMutation(saveRef, args)),
|
|
152
|
+
},
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
systemQuery: {},
|
|
156
|
+
systemMutation: {},
|
|
157
|
+
systemAction: {},
|
|
158
|
+
})
|
|
159
|
+
const save = functions.roleMutation('owner')({
|
|
160
|
+
args: input.shape,
|
|
161
|
+
returns: z.null(),
|
|
162
|
+
handler: (ctx, args) => ctx.commands.exec('save', args),
|
|
163
|
+
})
|
|
164
|
+
return { ...functions, save }
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Export the returned constructors once from `convex/functions.ts`, and export
|
|
169
|
+
`save` at the registered `notes:save` mutation path. Endpoint modules can then
|
|
170
|
+
use `ctx.commands` or `ctx.queries` directly. The callbacks run per invocation
|
|
171
|
+
after auth, role checks, triggers/RLS wrapping, and live action membership
|
|
172
|
+
refresh. Binding is lazy; do not cache an authenticated `withContext` handle
|
|
173
|
+
at module scope. Denied requests never run the callbacks.
|
|
174
|
+
|
|
175
|
+
| Policy | Available authority and capabilities |
|
|
176
|
+
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
177
|
+
| `query` | Trusted auth bundle, secured DB reader, `include`; bind read registries only. |
|
|
178
|
+
| `mutation` | Trusted auth bundle, secured triggered DB writer, `include`; bind queries and mutation commands. |
|
|
179
|
+
| `action` | Live-verified auth bundle, `runQuery`/`runMutation`; use action-compatible registries or forward to registered functions. No DB or `include`. |
|
|
180
|
+
| `systemQuery` / `systemMutation` / `systemAction` | Existing internal authority, configured separately. No fabricated actor or inherited public handles; system mutations retain triggers and bypass public RLS as before. |
|
|
181
|
+
|
|
182
|
+
Every auth/role/admin constructor of a kind shares that kind's policy. System
|
|
183
|
+
policies are deliberately explicit; choose their trusted capabilities rather
|
|
184
|
+
than synthesizing public credentials. An action forwarding to `runMutation`
|
|
185
|
+
creates a separate registered mutation transaction; it does not turn the
|
|
186
|
+
whole action into a transaction or carry its live role into that mutation's
|
|
187
|
+
JWT-based auth policy.
|
|
188
|
+
|
|
189
|
+
Additions cannot replace native or auth context keys: static checks reject
|
|
190
|
+
known collisions and runtime checks also reject inherited keys before the
|
|
191
|
+
handler executes. Put class-based handles under named properties in the
|
|
192
|
+
returned plain record. Scoped services, required Effect services, Zod raw and
|
|
193
|
+
parsed argument/result types, function references, and error projection retain
|
|
194
|
+
the existing adapter's behavior. Let failures escape registered mutations so
|
|
195
|
+
nested command writes, triggers, and audit writes roll back together.
|
|
196
|
+
|
|
67
197
|
## Shared Effect execution after authentication
|
|
68
198
|
|
|
69
|
-
|
|
199
|
+
For an individual constructor, wrap the builder returned by `createAuthFunctions` with
|
|
70
200
|
`effectZodApiBuilder` from `cvx-kit/effect`. The original constructor resolves
|
|
71
201
|
authentication, authorization, tenant policy, and the wrapped database before
|
|
72
202
|
the service provider runs. Keep that ordering when adding Effect; use the Zod
|
package/docs/effect.md
CHANGED
|
@@ -384,11 +384,17 @@ only when you want a typed error channel.
|
|
|
384
384
|
The [command guide](./commands.md) documents the current lifecycle and migration
|
|
385
385
|
steps; the [deprecated API reference](./commands-legacy.md) retains old examples.
|
|
386
386
|
The [authentication guide](./auth.md)
|
|
387
|
-
shows
|
|
387
|
+
shows the shared `createEffectAuthFunctions(config, policies)` factory and how
|
|
388
|
+
to wrap individual trusted builders with `effectZodApiBuilder`, so auth,
|
|
388
389
|
tenancy, validators, row-level policies, and triggers run through their
|
|
389
390
|
existing builder before Effect request services are provisioned.
|
|
390
391
|
|
|
391
|
-
|
|
392
|
+
For an app-wide foundation, configure `query`, `mutation`, and `action` policies
|
|
393
|
+
once with `createEffectAuthFunctions` and explicit separate system policies.
|
|
394
|
+
Query handles bind readers, mutation handles bind the secured triggered writer,
|
|
395
|
+
and action handles use `runMutation` rather than a mutation database.
|
|
396
|
+
|
|
397
|
+
Optional request context can also be added through the existing Effect API adapter's
|
|
392
398
|
`context` callback. Bind selected registries with `commands.withContext(value)`
|
|
393
399
|
and consume `ctx.commands.exec(name, input)` through the application's existing
|
|
394
400
|
function helper names. Keep dependencies local to each feature; explicit execution
|
package/docs/llms.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
cvx-kit is a reusable Convex application kit: zod table boundaries, auth-aware
|
|
23
23
|
function constructors, a trigger registry, an audited command protocol
|
|
24
24
|
(Foundation component), and a declarative approvals component. Peer deps:
|
|
25
|
-
`convex ^1.
|
|
25
|
+
`convex ^1.46.0`, `zod ^4.5.4`; command implementations also install
|
|
26
26
|
`effect >=4.0.1 <5` and import `cvx-kit/effect`.
|
|
27
27
|
|
|
28
28
|
**Command API selection:** use `createEffectFoundation` and declare handlers
|
|
@@ -38,12 +38,13 @@ copy that API into new implementations.
|
|
|
38
38
|
`convex/functions.ts`** (the `createAuthFunctions` call). All other
|
|
39
39
|
functions use `authQuery/authMutation/authAction`, `roleQuery/...`,
|
|
40
40
|
`adminQuery/...` (public) or `systemQuery/systemMutation/systemAction` (internal),
|
|
41
|
-
|
|
41
|
+
built once with `createEffectAuthFunctions(config, policies)` from `cvx-kit/effect`
|
|
42
|
+
for shared Effect handles, or individually wrapped with `effectZodApiBuilder`.
|
|
42
43
|
This is what guarantees auth, triggers, and bounded reads.
|
|
43
44
|
3. **Every public query returns DTOs** via `<table>.toPublicDto(row)` —
|
|
44
45
|
runtime redaction, not just types.
|
|
45
46
|
4. **Every read is bounded**: `ctx.include(ctx.db.query('t')).matching(...)
|
|
46
|
-
.execute(limit)` with `1 ≤ limit ≤ 100`. `.resolve()` falls back to a full
|
|
47
|
+
.execute(limit)` with `1 ≤ limit ≤ 100`. `.resolve()` falls back to a full
|
|
47
48
|
table scan — avoid it.
|
|
48
49
|
5. **State changes are Effect commands**: declare
|
|
49
50
|
`Command({ context, operations: ({ command }) => ({ ... }), defaults })`.
|
|
@@ -78,23 +79,23 @@ copy that API into new implementations.
|
|
|
78
79
|
|
|
79
80
|
## Exports map
|
|
80
81
|
|
|
81
|
-
| Import | Provides
|
|
82
|
-
| ------------------------------- |
|
|
83
|
-
| `cvx-kit` | Non-Effect helpers and component clients; import the optional Effect facade explicitly from `cvx-kit/effect`.
|
|
84
|
-
| `cvx-kit/zod-table` | `zodTable`, `tenantTable`, `createModule`, `paginated`, `zodVariantTable`, `jsonSafeZid`, `TIMESTAMP_FIELDS`
|
|
85
|
-
| `cvx-kit/effect` | Recommended command/query API: `createEffectFoundation`, `effectApiBuilder`, `effectZodApiBuilder`, `createEffectCrud`, idempotency/workflow adapters and operation tools. |
|
|
86
|
-
| `cvx-kit/auth` | `createAuthFunctions` (incl. optional `security` RLS config), `createInclude`, `defaultRoleMap`
|
|
87
|
-
| `cvx-kit/tenancy` | `createTenantRules`, `composeRules`, `requireTenantReference`, `assertTenantOwned`, `TENANT_FIELD`
|
|
88
|
-
| `cvx-kit/crud` | Compatibility CRUD factory using the deprecated Promise command facade; use `createEffectCrud` from `cvx-kit/effect` for new domains.
|
|
89
|
-
| `cvx-kit/state-machine` | `createStateMachine` — typed transitions from constants tuples; `assert` drops into command guards
|
|
90
|
-
| `cvx-kit/middleware` | `rateLimit` — packaged middleware over an injected rate-limiter instance; keyed by `ctx.tenant`, missing key = config error
|
|
91
|
-
| `cvx-kit/webhooks` | `createWebhookBoundary`, `recordWebhookEvent`, `webhookEventsTable` — raw-body verify, natural-key dedup in the mutation
|
|
92
|
-
| `cvx-kit/agent-tools` | `createAgentTools` — tool records from table masks; mutation handlers route through command executors
|
|
93
|
-
| `cvx-kit/triggers` | `createTriggers`, `timestamps`, `appendOnly`, `noDelete`, `tenantOwnership`, `Triggers`
|
|
94
|
-
| `cvx-kit/errors` | `KitError`, `defaultErrors`, `ErrorFactory`
|
|
95
|
-
| `cvx-kit/components/foundation` | Component client and types; `Foundation.Command` is deprecated. The component and other capabilities remain available. New command registries use `cvx-kit/effect`.
|
|
96
|
-
| `cvx-kit/components/approvals` | `Approvals` client; default export = component config for `app.use`
|
|
97
|
-
| `cvx-kit/test` | `registerFoundation(t)`, `registerApprovals(t)` for convex-test
|
|
82
|
+
| Import | Provides |
|
|
83
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `cvx-kit` | Non-Effect helpers and component clients; import the optional Effect facade explicitly from `cvx-kit/effect`. |
|
|
85
|
+
| `cvx-kit/zod-table` | `zodTable`, `tenantTable`, `createModule`, `paginated`, `zodVariantTable`, `jsonSafeZid`, `TIMESTAMP_FIELDS` |
|
|
86
|
+
| `cvx-kit/effect` | Recommended command/query API: `createEffectFoundation`, `createEffectAuthFunctions`, `effectApiBuilder`, `effectZodApiBuilder`, `createEffectCrud`, idempotency/workflow adapters and operation tools. |
|
|
87
|
+
| `cvx-kit/auth` | `createAuthFunctions` (incl. optional `security` RLS config), `createInclude`, `defaultRoleMap` |
|
|
88
|
+
| `cvx-kit/tenancy` | `createTenantRules`, `composeRules`, `requireTenantReference`, `assertTenantOwned`, `TENANT_FIELD` |
|
|
89
|
+
| `cvx-kit/crud` | Compatibility CRUD factory using the deprecated Promise command facade; use `createEffectCrud` from `cvx-kit/effect` for new domains. |
|
|
90
|
+
| `cvx-kit/state-machine` | `createStateMachine` — typed transitions from constants tuples; `assert` drops into command guards |
|
|
91
|
+
| `cvx-kit/middleware` | `rateLimit` — packaged middleware over an injected rate-limiter instance; keyed by `ctx.tenant`, missing key = config error |
|
|
92
|
+
| `cvx-kit/webhooks` | `createWebhookBoundary`, `recordWebhookEvent`, `webhookEventsTable` — raw-body verify, natural-key dedup in the mutation |
|
|
93
|
+
| `cvx-kit/agent-tools` | `createAgentTools` — tool records from table masks; mutation handlers route through command executors |
|
|
94
|
+
| `cvx-kit/triggers` | `createTriggers`, `timestamps`, `appendOnly`, `noDelete`, `tenantOwnership`, `Triggers` |
|
|
95
|
+
| `cvx-kit/errors` | `KitError`, `defaultErrors`, `ErrorFactory` |
|
|
96
|
+
| `cvx-kit/components/foundation` | Component client and types; `Foundation.Command` is deprecated. The component and other capabilities remain available. New command registries use `cvx-kit/effect`. |
|
|
97
|
+
| `cvx-kit/components/approvals` | `Approvals` client; default export = component config for `app.use` |
|
|
98
|
+
| `cvx-kit/test` | `registerFoundation(t)`, `registerApprovals(t)` for convex-test |
|
|
98
99
|
|
|
99
100
|
## Minimal app wiring (the five root files)
|
|
100
101
|
|
|
@@ -291,3 +292,23 @@ Optional request context can be added through the existing Effect API adapter's
|
|
|
291
292
|
and consume `ctx.commands.exec(name, input)` through the application's existing
|
|
292
293
|
function helper names. Keep dependencies local to each feature; explicit execution
|
|
293
294
|
and input-only command handlers remain supported. See [optional context injection](./command-context.md).
|
|
295
|
+
|
|
296
|
+
## Shared auth and Effect context
|
|
297
|
+
|
|
298
|
+
Configure `createEffectAuthFunctions` once in `convex/functions.ts` using a typed
|
|
299
|
+
`AuthFunctionsConfig<DataModel, Role>` and inferred factory generics. Supply six
|
|
300
|
+
explicit policies: `query`, `mutation`, `action`, `systemQuery`, `systemMutation`,
|
|
301
|
+
and `systemAction`; use `{}` for no additions. Each supports `services`,
|
|
302
|
+
`context`, and `mapError`. All auth/role/admin constructors share the policy
|
|
303
|
+
for their kind. Services and context initialize only after successful auth and
|
|
304
|
+
role checks, using the secured DB and refreshed live action membership.
|
|
305
|
+
|
|
306
|
+
Bind query registries only in queries. Mutations can bind queries and commands
|
|
307
|
+
with their secured triggered writer. Actions have no DB; bind action-compatible
|
|
308
|
+
registries or delegate with `runMutation`/`runQuery`. Each registered mutation
|
|
309
|
+
has its own transaction and JWT auth; an action is not one transaction. Configure
|
|
310
|
+
internal system authority separately, without fabricated actors or inherited
|
|
311
|
+
public handles. Return plain records with handles under named keys; native/auth
|
|
312
|
+
key collisions are rejected, including inherited keys at runtime. Keep bound
|
|
313
|
+
handles request-local, return lazy Effects, and let failures escape mutations
|
|
314
|
+
for rollback. See `auth.md` for a packed-compiled shared factory example.
|
package/docs/oxlint.md
CHANGED
|
@@ -27,7 +27,7 @@ Loading a plugin does not enable its rules. For example:
|
|
|
27
27
|
|
|
28
28
|
With Vite+, place those fields under `lint` in `vite.config.ts`. The plugin
|
|
29
29
|
exports a default plugin object, named `rules`, and the `RuleName` type. It is
|
|
30
|
-
tested with Oxlint 1.
|
|
30
|
+
tested with Oxlint 1.87.0 and Vite+ 1.1.0.
|
|
31
31
|
|
|
32
32
|
All rules default to `convex/` relative to the linter's working directory.
|
|
33
33
|
For another location, set `convexDir` on **each enabled rule**:
|
package/docs/upgrading.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Upgrading to 0.1.0 — the new way of things
|
|
2
2
|
|
|
3
|
+
## Current dependency requirements
|
|
4
|
+
|
|
5
|
+
Install Convex 1.46 or newer and convex-helpers 0.1.127 or newer (below 0.2.0).
|
|
6
|
+
These minimums match workflow 0.4.10. Regenerate your lockfile after updating.
|
|
7
|
+
Auth declarations retain native Convex context types across package versions;
|
|
8
|
+
the regression fixture also checks Convex 1.45, which is below the current
|
|
9
|
+
full-package dependency minimum.
|
|
10
|
+
|
|
3
11
|
## Current command API — Effect declarations
|
|
4
12
|
|
|
5
13
|
`Foundation.Command` and its separate `exec({ operation, handler })` API are
|
|
@@ -67,7 +75,7 @@ Install `convex-helpers` as a direct peer, using one compatible instance:
|
|
|
67
75
|
bun add cvx-kit@0.1.3 convex-helpers@0.1.124
|
|
68
76
|
```
|
|
69
77
|
|
|
70
|
-
The peer range
|
|
78
|
+
The peer range was `>=0.1.123 <0.2.0`. Remove overrides that force a
|
|
71
79
|
separate helper copy and regenerate the installation without discarding
|
|
72
80
|
unrelated dependency choices. This release is validated with Convex 1.45.0,
|
|
73
81
|
Zod 4.5.4, and convex-test 0.0.56.
|
package/docs/zod-table.md
CHANGED
|
@@ -29,7 +29,7 @@ export const documents = zodTable(
|
|
|
29
29
|
|
|
30
30
|
### Shared ID validation (0.1.3)
|
|
31
31
|
|
|
32
|
-
Install one compatible `convex-helpers` peer (`>=0.1.
|
|
32
|
+
Install one compatible `convex-helpers` peer (`>=0.1.127 <0.2.0`) alongside
|
|
33
33
|
cvx-kit. ID metadata lives in a helper-instance registry: copying schemas
|
|
34
34
|
between separately installed helper instances can silently turn an ID into
|
|
35
35
|
`v.any()`. An exact nested dependency previously caused that failure even
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cvx-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Reusable Convex application kit: foundation kernels, approvals component, zod table boundaries, WorkOS-backed auth function constructors, and audited command protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"component",
|
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"test:package:ids": "bun run build && node scripts/test-packed-ids.mjs",
|
|
134
134
|
"test:package:oxlint": "bun run build && node scripts/test-packed-oxlint.mjs",
|
|
135
135
|
"test:package:effect": "bun run build && node scripts/test-packed-effect.mjs",
|
|
136
|
+
"test:package:auth": "bun run build && node scripts/test-packed-auth.mjs",
|
|
136
137
|
"test:package:smoke:effect": "bun run build && node scripts/smoke-packed-effect.mjs",
|
|
137
138
|
"test:package:smoke:bun": "bun scripts/smoke-packed-components.mjs bun",
|
|
138
139
|
"test:package:smoke:npm": "node scripts/smoke-packed-components.mjs npm",
|
|
@@ -143,28 +144,30 @@
|
|
|
143
144
|
"release:minor": "npm version minor && git push --follow-tags"
|
|
144
145
|
},
|
|
145
146
|
"dependencies": {
|
|
146
|
-
"@convex-dev/workflow": "0.4.
|
|
147
|
-
"@oxlint/plugins": "1.
|
|
147
|
+
"@convex-dev/workflow": "0.4.10",
|
|
148
|
+
"@oxlint/plugins": "1.87.0",
|
|
149
|
+
"@standard-schema/spec": "^1.1.0",
|
|
148
150
|
"convex-audit-log": "^0.2.0",
|
|
149
|
-
"oxc-parser": "0.
|
|
151
|
+
"oxc-parser": "0.153.0",
|
|
150
152
|
"oxc-resolver": "11.24.2"
|
|
151
153
|
},
|
|
152
154
|
"devDependencies": {
|
|
153
155
|
"@edge-runtime/vm": "^5.0.0",
|
|
154
|
-
"@types/node": "^26.6.
|
|
155
|
-
"convex": "1.
|
|
156
|
-
"convex-helpers": "0.1.
|
|
157
|
-
"convex-test": "^0.0.
|
|
158
|
-
"effect": "4.0.
|
|
159
|
-
"oxlint": "1.
|
|
160
|
-
"publint": "^0.3.
|
|
156
|
+
"@types/node": "^26.6.5",
|
|
157
|
+
"convex": "1.46.0",
|
|
158
|
+
"convex-helpers": "0.1.128",
|
|
159
|
+
"convex-test": "^0.0.61",
|
|
160
|
+
"effect": "4.0.2",
|
|
161
|
+
"oxlint": "1.87.0",
|
|
162
|
+
"publint": "^0.3.25",
|
|
161
163
|
"typescript": "7.0.2",
|
|
162
|
-
"vite
|
|
163
|
-
"
|
|
164
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
|
|
165
|
+
"vite-plus": "1.1.0",
|
|
166
|
+
"zod": "4.6.5"
|
|
164
167
|
},
|
|
165
168
|
"peerDependencies": {
|
|
166
|
-
"convex": "^1.
|
|
167
|
-
"convex-helpers": ">=0.1.
|
|
169
|
+
"convex": "^1.46.0",
|
|
170
|
+
"convex-helpers": ">=0.1.127 <0.2.0",
|
|
168
171
|
"effect": ">=4.0.1 <5",
|
|
169
172
|
"zod": "^4.5.4"
|
|
170
173
|
},
|
|
@@ -173,6 +176,9 @@
|
|
|
173
176
|
"optional": true
|
|
174
177
|
}
|
|
175
178
|
},
|
|
179
|
+
"overrides": {
|
|
180
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.1.0"
|
|
181
|
+
},
|
|
176
182
|
"devEngines": {
|
|
177
183
|
"packageManager": {
|
|
178
184
|
"name": "bun",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { basename, join, resolve } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const root = resolve(import.meta.dirname, '..')
|
|
7
|
+
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
|
|
8
|
+
const temporary = mkdtempSync(join(tmpdir(), 'cvx-kit-auth-'))
|
|
9
|
+
function run(command, args, cwd) {
|
|
10
|
+
try {
|
|
11
|
+
return execFileSync(command, args, { cwd, encoding: 'utf8', stdio: 'pipe' })
|
|
12
|
+
} catch (error) {
|
|
13
|
+
if (!args.includes('install')) {
|
|
14
|
+
process.stderr.write(error.stdout ?? '')
|
|
15
|
+
process.stderr.write(error.stderr ?? '')
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`${command} ${args.join(' ')} failed in ${basename(cwd)}`, {
|
|
18
|
+
cause: error.code,
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
run('bun', ['pm', 'pack', '--ignore-scripts', '--destination', temporary], root)
|
|
24
|
+
const tarball = join(temporary, `${manifest.name}-${manifest.version}.tgz`)
|
|
25
|
+
// 1.45 is a declaration regression target, below the current workflow peer floor.
|
|
26
|
+
for (const convex of ['1.45.0', '1.46.0']) {
|
|
27
|
+
const fixture = mkdtempSync(join(temporary, `convex-${convex}-`))
|
|
28
|
+
writeFileSync(
|
|
29
|
+
join(fixture, 'package.json'),
|
|
30
|
+
JSON.stringify({
|
|
31
|
+
private: true,
|
|
32
|
+
type: 'module',
|
|
33
|
+
dependencies: {
|
|
34
|
+
'cvx-kit': `file:${tarball}`,
|
|
35
|
+
convex,
|
|
36
|
+
'convex-helpers': manifest.devDependencies['convex-helpers'],
|
|
37
|
+
effect: manifest.devDependencies.effect,
|
|
38
|
+
zod: manifest.devDependencies.zod,
|
|
39
|
+
typescript: manifest.devDependencies.typescript,
|
|
40
|
+
'@types/node': manifest.devDependencies['@types/node'],
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
)
|
|
44
|
+
writeFileSync(
|
|
45
|
+
join(fixture, 'auth.ts'),
|
|
46
|
+
readFileSync(join(root, 'test/auth-native-context-types.ts')),
|
|
47
|
+
)
|
|
48
|
+
writeFileSync(
|
|
49
|
+
join(fixture, 'shared-auth.ts'),
|
|
50
|
+
readFileSync(join(root, 'test/effect-auth-types.ts')),
|
|
51
|
+
)
|
|
52
|
+
writeFileSync(
|
|
53
|
+
join(fixture, 'tsconfig.json'),
|
|
54
|
+
JSON.stringify({
|
|
55
|
+
compilerOptions: {
|
|
56
|
+
strict: true,
|
|
57
|
+
noEmit: true,
|
|
58
|
+
skipLibCheck: true,
|
|
59
|
+
target: 'ES2025',
|
|
60
|
+
module: 'ESNext',
|
|
61
|
+
moduleResolution: 'bundler',
|
|
62
|
+
},
|
|
63
|
+
include: ['auth.ts', 'shared-auth.ts'],
|
|
64
|
+
}),
|
|
65
|
+
)
|
|
66
|
+
run('bun', ['install', '--ignore-scripts'], fixture)
|
|
67
|
+
run('bun', ['x', '--no-install', 'tsc', '--project', 'tsconfig.json'], fixture)
|
|
68
|
+
console.log(`Packed auth native contexts pass on Convex ${convex}`)
|
|
69
|
+
}
|
|
70
|
+
} finally {
|
|
71
|
+
rmSync(temporary, { recursive: true, force: true })
|
|
72
|
+
}
|
|
@@ -15,7 +15,7 @@ const root = resolve(import.meta.dirname, '..')
|
|
|
15
15
|
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
|
|
16
16
|
const temporary = mkdtempSync(join(tmpdir(), 'cvx-kit-effect-'))
|
|
17
17
|
const effectVersion = '4.0.1'
|
|
18
|
-
const helpersVersion = '0.1.
|
|
18
|
+
const helpersVersion = '0.1.127'
|
|
19
19
|
const nodeTypesVersion = '26.6.1'
|
|
20
20
|
const domainGuidePath = join(root, 'src/docs/domain-operations.md')
|
|
21
21
|
const domainGuideImports = new Set([
|
|
@@ -396,6 +396,7 @@ try {
|
|
|
396
396
|
'effect-foundation-types.ts',
|
|
397
397
|
'effect-api-types.ts',
|
|
398
398
|
'effect-api-zod-types.ts',
|
|
399
|
+
'effect-auth-types.ts',
|
|
399
400
|
'effect-registry-review-types.ts',
|
|
400
401
|
'operation-contract-types.ts',
|
|
401
402
|
'effect-schema-types.ts',
|
|
@@ -25,7 +25,7 @@ try {
|
|
|
25
25
|
type: 'module',
|
|
26
26
|
dependencies: {
|
|
27
27
|
'cvx-kit': `file:${join(temporary, `cvx-kit-${manifest.version}.tgz`)}`,
|
|
28
|
-
'convex-helpers': '0.1.
|
|
28
|
+
'convex-helpers': '0.1.127',
|
|
29
29
|
convex: manifest.devDependencies.convex,
|
|
30
30
|
zod: manifest.devDependencies.zod,
|
|
31
31
|
},
|
|
@@ -142,7 +142,7 @@ it('registers concrete and generic backends from the packed package', () => {
|
|
|
142
142
|
fixture,
|
|
143
143
|
)
|
|
144
144
|
console.log(
|
|
145
|
-
`${installer}: packed IDs, table/tool types, registration, and command lifecycle pass with host convex-helpers 0.1.
|
|
145
|
+
`${installer}: packed IDs, table/tool types, registration, and command lifecycle pass with host convex-helpers 0.1.127`,
|
|
146
146
|
)
|
|
147
147
|
}
|
|
148
148
|
} finally {
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
//#region node_modules/@standard-schema/spec/dist/index.d.ts
|
|
2
|
-
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
3
|
-
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
4
|
-
/** The Standard properties. */
|
|
5
|
-
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
6
|
-
}
|
|
7
|
-
declare namespace StandardTypedV1 {
|
|
8
|
-
/** The Standard Typed properties interface. */
|
|
9
|
-
interface Props<Input = unknown, Output = Input> {
|
|
10
|
-
/** The version number of the standard. */
|
|
11
|
-
readonly version: 1;
|
|
12
|
-
/** The vendor name of the schema library. */
|
|
13
|
-
readonly vendor: string;
|
|
14
|
-
/** Inferred types associated with the schema. */
|
|
15
|
-
readonly types?: Types<Input, Output> | undefined;
|
|
16
|
-
}
|
|
17
|
-
/** The Standard Typed types interface. */
|
|
18
|
-
interface Types<Input = unknown, Output = Input> {
|
|
19
|
-
/** The input type of the schema. */
|
|
20
|
-
readonly input: Input;
|
|
21
|
-
/** The output type of the schema. */
|
|
22
|
-
readonly output: Output;
|
|
23
|
-
}
|
|
24
|
-
/** Infers the input type of a Standard Typed. */
|
|
25
|
-
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
26
|
-
/** Infers the output type of a Standard Typed. */
|
|
27
|
-
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
28
|
-
}
|
|
29
|
-
/** The Standard Schema interface. */
|
|
30
|
-
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
31
|
-
/** The Standard Schema properties. */
|
|
32
|
-
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
33
|
-
}
|
|
34
|
-
declare namespace StandardSchemaV1 {
|
|
35
|
-
/** The Standard Schema properties interface. */
|
|
36
|
-
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
37
|
-
/** Validates unknown input values. */
|
|
38
|
-
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
39
|
-
}
|
|
40
|
-
/** The result interface of the validate function. */
|
|
41
|
-
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
42
|
-
/** The result interface if validation succeeds. */
|
|
43
|
-
interface SuccessResult<Output> {
|
|
44
|
-
/** The typed output value. */
|
|
45
|
-
readonly value: Output;
|
|
46
|
-
/** A falsy value for `issues` indicates success. */
|
|
47
|
-
readonly issues?: undefined;
|
|
48
|
-
}
|
|
49
|
-
interface Options {
|
|
50
|
-
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
51
|
-
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
52
|
-
}
|
|
53
|
-
/** The result interface if validation fails. */
|
|
54
|
-
interface FailureResult {
|
|
55
|
-
/** The issues of failed validation. */
|
|
56
|
-
readonly issues: ReadonlyArray<Issue>;
|
|
57
|
-
}
|
|
58
|
-
/** The issue interface of the failure output. */
|
|
59
|
-
interface Issue {
|
|
60
|
-
/** The error message of the issue. */
|
|
61
|
-
readonly message: string;
|
|
62
|
-
/** The path of the issue, if any. */
|
|
63
|
-
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
64
|
-
}
|
|
65
|
-
/** The path segment interface of the issue. */
|
|
66
|
-
interface PathSegment {
|
|
67
|
-
/** The key representing a path segment. */
|
|
68
|
-
readonly key: PropertyKey;
|
|
69
|
-
}
|
|
70
|
-
/** The Standard types interface. */
|
|
71
|
-
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
72
|
-
/** Infers the input type of a Standard. */
|
|
73
|
-
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
74
|
-
/** Infers the output type of a Standard. */
|
|
75
|
-
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
76
|
-
}
|
|
77
|
-
//#endregion
|
|
78
|
-
export { StandardSchemaV1, StandardTypedV1 };
|
|
79
|
-
//# sourceMappingURL=index.d.mts.map
|