cvx-kit 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +1 -0
  2. package/dist/auth.d.mts +52 -5
  3. package/dist/auth.mjs +1 -1
  4. package/dist/auth.mjs.map +1 -1
  5. package/dist/components/foundation/client.d.mts +40 -3
  6. package/dist/components/foundation/client.mjs +1 -1
  7. package/dist/components/foundation/client.mjs.map +1 -1
  8. package/dist/index.d.mts +6 -5
  9. package/dist/index.mjs +1 -1
  10. package/dist/tenancy.d.mts +34 -0
  11. package/dist/tenancy.mjs +2 -0
  12. package/dist/tenancy.mjs.map +1 -0
  13. package/dist/triggers.d.mts +9 -1
  14. package/dist/triggers.mjs +1 -1
  15. package/dist/triggers.mjs.map +1 -1
  16. package/dist/zod-table.d.mts +21 -1
  17. package/dist/zod-table.mjs +1 -1
  18. package/dist/zod-table.mjs.map +1 -1
  19. package/docs/auth.md +10 -0
  20. package/docs/commands.md +56 -4
  21. package/docs/conventions.md +21 -0
  22. package/docs/explain/modules-and-multitenancy.html +469 -0
  23. package/docs/llms.md +16 -4
  24. package/docs/tenancy.md +179 -0
  25. package/docs/triggers.md +5 -0
  26. package/docs/zod-table.md +23 -0
  27. package/package.json +6 -8
  28. package/src/test.ts +7 -5
  29. package/src/auth.ts +0 -360
  30. package/src/components/approvals/_generated/api.ts +0 -69
  31. package/src/components/approvals/_generated/component.ts +0 -335
  32. package/src/components/approvals/_generated/dataModel.ts +0 -60
  33. package/src/components/approvals/_generated/server.ts +0 -156
  34. package/src/components/approvals/audit.ts +0 -148
  35. package/src/components/approvals/client.ts +0 -321
  36. package/src/components/approvals/constants.ts +0 -51
  37. package/src/components/approvals/convex.config.ts +0 -10
  38. package/src/components/approvals/decisions.ts +0 -376
  39. package/src/components/approvals/functions.ts +0 -27
  40. package/src/components/approvals/requests.ts +0 -240
  41. package/src/components/approvals/schema.ts +0 -23
  42. package/src/components/approvals/validators.ts +0 -272
  43. package/src/components/approvals/workflow.ts +0 -204
  44. package/src/components/approvals/workflow_steps.ts +0 -189
  45. package/src/components/foundation/_generated/api.ts +0 -62
  46. package/src/components/foundation/_generated/component.ts +0 -29
  47. package/src/components/foundation/_generated/dataModel.ts +0 -60
  48. package/src/components/foundation/_generated/server.ts +0 -156
  49. package/src/components/foundation/client.ts +0 -190
  50. package/src/components/foundation/convex.config.ts +0 -3
  51. package/src/components/foundation/functions.ts +0 -10
  52. package/src/components/foundation/modules/command/__tests__/command.test.ts +0 -106
  53. package/src/components/foundation/modules/command/command.ts +0 -154
  54. package/src/components/foundation/modules/observability/__tests__/observability.test.ts +0 -79
  55. package/src/components/foundation/modules/observability/observability.ts +0 -95
  56. package/src/components/foundation/modules/query/__tests__/query.test.ts +0 -25
  57. package/src/components/foundation/modules/query/query.ts +0 -47
  58. package/src/components/foundation/result.ts +0 -77
  59. package/src/components/foundation/schema.ts +0 -4
  60. package/src/components/foundation/telemetry.ts +0 -23
  61. package/src/errors.ts +0 -25
  62. package/src/index.ts +0 -41
  63. package/src/triggers.ts +0 -90
  64. package/src/zod-table.ts +0 -197
  65. /package/docs/{convex-architecture-explainer.html → explain/convex-architecture-explainer.html} +0 -0
@@ -1,148 +0,0 @@
1
- import { AuditLog, type AuditEventInput } from 'convex-audit-log'
2
- import { v } from 'convex/values'
3
-
4
- import { components } from './_generated/api'
5
- import { mutation, query, type MutationCtx } from './_generated/server'
6
- import {
7
- APPROVAL_AUDIT_RETENTION_CATEGORY,
8
- MAX_APPROVAL_AUDIT_CLEANUP_BATCH_SIZE,
9
- MAX_APPROVAL_AUDIT_RETENTION_DAYS,
10
- MIN_APPROVAL_AUDIT_RETENTION_DAYS,
11
- } from './constants'
12
-
13
- export type ApprovalAuditTransition = Readonly<{
14
- action: string
15
- actorRef?: string
16
- runId: string
17
- resourceType: string
18
- resourceRef: string
19
- transition: string
20
- severity?: AuditEventInput['severity']
21
- }>
22
-
23
- export type ApprovalAuditProjection = Readonly<{
24
- action: string
25
- actorRef?: string
26
- correlationKey: string
27
- transition: string
28
- }>
29
-
30
- export const approvalAudit = new AuditLog(components.auditLog, {
31
- samplingEnabled: false,
32
- })
33
-
34
- export const history = query({
35
- args: {
36
- resourceType: v.string(),
37
- resourceRef: v.string(),
38
- limit: v.optional(v.number()),
39
- },
40
- returns: v.array(
41
- v.object({
42
- action: v.string(),
43
- actorRef: v.optional(v.string()),
44
- correlationKey: v.string(),
45
- transition: v.string(),
46
- }),
47
- ),
48
- handler: async (ctx, input) => {
49
- const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 100), 100))
50
- const events = await approvalAudit.queryByResource(ctx, {
51
- resourceType: input.resourceType,
52
- resourceId: input.resourceRef,
53
- limit,
54
- })
55
- const unique = new Map<string, ApprovalAuditProjection>()
56
- for (const event of events) {
57
- const projection = auditProjection(event)
58
- if (projection) unique.set(projection.correlationKey, projection)
59
- }
60
- return [...unique.values()]
61
- },
62
- })
63
-
64
- export const cleanup = mutation({
65
- args: {
66
- olderThanDays: v.number(),
67
- batchSize: v.number(),
68
- },
69
- returns: v.number(),
70
- handler: (ctx, input) => {
71
- const olderThanDays = boundedInteger(
72
- input.olderThanDays,
73
- MIN_APPROVAL_AUDIT_RETENTION_DAYS,
74
- MAX_APPROVAL_AUDIT_RETENTION_DAYS,
75
- 'olderThanDays',
76
- )
77
- const batchSize = boundedInteger(
78
- input.batchSize,
79
- 1,
80
- MAX_APPROVAL_AUDIT_CLEANUP_BATCH_SIZE,
81
- 'batchSize',
82
- )
83
- return approvalAudit.cleanup(ctx, {
84
- olderThanDays,
85
- batchSize,
86
- retentionCategory: APPROVAL_AUDIT_RETENTION_CATEGORY,
87
- })
88
- },
89
- })
90
-
91
- export function approvalAuditEvent(
92
- input: ApprovalAuditTransition,
93
- ): AuditEventInput {
94
- return {
95
- action: input.action,
96
- ...(input.actorRef === undefined ? {} : { actorId: input.actorRef }),
97
- resourceType: input.resourceType,
98
- resourceId: input.resourceRef,
99
- severity: input.severity ?? 'info',
100
- tags: ['approvals'],
101
- retentionCategory: APPROVAL_AUDIT_RETENTION_CATEGORY,
102
- metadata: {
103
- correlationKey: `${input.runId}:${input.transition}`,
104
- runId: input.runId,
105
- transition: input.transition,
106
- },
107
- }
108
- }
109
-
110
- export async function logApprovalTransition(
111
- ctx: MutationCtx,
112
- input: ApprovalAuditTransition,
113
- ): Promise<void> {
114
- await approvalAudit.log(ctx, approvalAuditEvent(input))
115
- }
116
-
117
- function boundedInteger(
118
- value: number,
119
- minimum: number,
120
- maximum: number,
121
- name: string,
122
- ): number {
123
- if (!Number.isInteger(value) || value < minimum || value > maximum)
124
- throw new Error(
125
- `${name} must be an integer between ${minimum} and ${maximum}`,
126
- )
127
- return value
128
- }
129
-
130
- function auditProjection(event: unknown): ApprovalAuditProjection | null {
131
- if (!event || typeof event !== 'object') return null
132
- const value = event as Record<string, unknown>
133
- const metadata = value.metadata
134
- if (!metadata || typeof metadata !== 'object') return null
135
- const details = metadata as Record<string, unknown>
136
- if (
137
- typeof value.action !== 'string' ||
138
- typeof details.correlationKey !== 'string' ||
139
- typeof details.transition !== 'string'
140
- )
141
- return null
142
- return {
143
- action: value.action,
144
- ...(typeof value.actorId === 'string' ? { actorRef: value.actorId } : {}),
145
- correlationKey: details.correlationKey,
146
- transition: details.transition,
147
- }
148
- }
@@ -1,321 +0,0 @@
1
- import type {
2
- FunctionArgs,
3
- FunctionReference,
4
- FunctionReturnType,
5
- GenericDataModel,
6
- GenericMutationCtx,
7
- GenericQueryCtx,
8
- } from 'convex/server'
9
-
10
- import type { ComponentApi } from './_generated/component'
11
- import type { ApprovalDecision } from './constants'
12
- import type {
13
- ApprovalActor,
14
- ApprovalMetadata,
15
- ApprovalWorkflowDescriptor,
16
- } from './validators'
17
- import {
18
- compileApprovalDescriptor,
19
- type ApprovalActionStep,
20
- type ApprovalBranchStep,
21
- type ApprovalDecisionStep,
22
- type ApprovalDefinition,
23
- type ApprovalMutationStep,
24
- type ApprovalNotifyStep,
25
- type ApprovalWorkflowStep,
26
- type ApprovalCallbackInput,
27
- type CreateApprovalHandle,
28
- } from './workflow_steps'
29
-
30
- export type ApprovalsOptions = Readonly<{
31
- createHandle?: CreateApprovalHandle
32
- }>
33
-
34
- export type ApprovalStartInput = Readonly<{
35
- scopeRef: string
36
- resourceType: string
37
- resourceRef: string
38
- requester: ApprovalActor
39
- metadata?: ApprovalMetadata
40
- }>
41
-
42
- export type ApprovalDecisionInput = Readonly<{
43
- runId: string
44
- decision: ApprovalDecision
45
- reason?: string
46
- }>
47
-
48
- export type ApprovalEvidenceItem = Readonly<{
49
- stepKey: string
50
- actorRef: string
51
- decision: ApprovalDecision
52
- reason?: string
53
- decidedAt: number
54
- }>
55
-
56
- export type ApprovalAuditHistoryInput = Readonly<{
57
- resourceType: string
58
- resourceRef: string
59
- limit?: number
60
- }>
61
-
62
- export type ApprovalAuditCleanupInput = Readonly<{
63
- olderThanDays: number
64
- batchSize: number
65
- }>
66
-
67
- export type ApprovalStatus = FunctionReturnType<
68
- ComponentApi['requests']['status']
69
- >
70
-
71
- export class Approvals<Component extends ComponentApi = ComponentApi> {
72
- private readonly component: Component
73
- private readonly createHandle: CreateApprovalHandle | undefined
74
-
75
- constructor(component: Component, options: ApprovalsOptions = {}) {
76
- this.component = component
77
- this.createHandle = options.createHandle
78
- }
79
-
80
- cleanupAudit<DataModel extends GenericDataModel>(
81
- ctx: GenericMutationCtx<DataModel>,
82
- input: ApprovalAuditCleanupInput,
83
- ): Promise<FunctionReturnType<Component['audit']['cleanup']>> {
84
- return ctx.runMutation(this.component.audit.cleanup, input)
85
- }
86
-
87
- mutation(
88
- key: string,
89
- options: Readonly<{
90
- handler: FunctionReference<
91
- 'mutation',
92
- 'internal',
93
- ApprovalCallbackInput,
94
- unknown
95
- >
96
- retry?: boolean
97
- }>,
98
- ): ApprovalMutationStep {
99
- return Object.freeze({
100
- kind: 'mutation',
101
- key,
102
- handler: options.handler,
103
- retry: options.retry ?? false,
104
- })
105
- }
106
-
107
- action(
108
- key: string,
109
- options: Readonly<{
110
- handler: FunctionReference<
111
- 'action',
112
- 'internal',
113
- ApprovalCallbackInput,
114
- unknown
115
- >
116
- retry?: boolean
117
- }>,
118
- ): ApprovalActionStep {
119
- return Object.freeze({
120
- kind: 'action',
121
- key,
122
- handler: options.handler,
123
- retry: options.retry ?? false,
124
- })
125
- }
126
-
127
- notify(
128
- key: string,
129
- options: Readonly<{
130
- handler: FunctionReference<
131
- 'action',
132
- 'internal',
133
- ApprovalCallbackInput,
134
- unknown
135
- >
136
- retry?: boolean
137
- }>,
138
- ): ApprovalNotifyStep {
139
- return Object.freeze({
140
- kind: 'notify',
141
- key,
142
- handler: options.handler,
143
- retry: options.retry ?? false,
144
- })
145
- }
146
-
147
- decision(
148
- key: string,
149
- options: Readonly<{
150
- decisions: readonly ApprovalDecision[]
151
- quorum: Readonly<{ kind: 'count'; approvals: number }>
152
- makerChecker?: boolean
153
- expiresAfterMs?: number
154
- }>,
155
- ): ApprovalDecisionStep {
156
- return Object.freeze({
157
- kind: 'decision',
158
- key,
159
- decisions: Object.freeze([...options.decisions]),
160
- quorum: Object.freeze({ ...options.quorum }),
161
- makerChecker: options.makerChecker ?? false,
162
- ...(options.expiresAfterMs === undefined
163
- ? {}
164
- : { expiresAfterMs: options.expiresAfterMs }),
165
- })
166
- }
167
-
168
- branch(
169
- key: string,
170
- options: Readonly<{
171
- approvedStepKey: string
172
- rejectedStepKey: string
173
- }>,
174
- ): ApprovalBranchStep {
175
- return Object.freeze({ kind: 'branch', key, ...options })
176
- }
177
-
178
- define(
179
- input: Readonly<{
180
- name: string
181
- compatibilityKey?: string
182
- steps: readonly ApprovalWorkflowStep[]
183
- }>,
184
- ): ConfiguredApprovalWorkflow<Component> {
185
- const definition = freezeDefinition({
186
- name: input.name,
187
- compatibilityKey: input.compatibilityKey ?? input.name,
188
- steps: input.steps,
189
- })
190
- return new ConfiguredApprovalWorkflow(
191
- this.component,
192
- definition,
193
- this.createHandle,
194
- )
195
- }
196
- }
197
-
198
- export class ConfiguredApprovalWorkflow<
199
- Component extends ComponentApi = ComponentApi,
200
- > {
201
- readonly name: string
202
- readonly compatibilityKey: string
203
- readonly steps: readonly ApprovalWorkflowStep[]
204
-
205
- private readonly component: Component
206
- private readonly definition: ApprovalDefinition
207
- private readonly createHandle: CreateApprovalHandle | undefined
208
-
209
- constructor(
210
- component: Component,
211
- definition: ApprovalDefinition,
212
- createHandle?: CreateApprovalHandle,
213
- ) {
214
- this.component = component
215
- this.definition = definition
216
- this.name = definition.name
217
- this.compatibilityKey = definition.compatibilityKey
218
- this.steps = definition.steps
219
- this.createHandle = createHandle
220
- Object.freeze(this)
221
- }
222
-
223
- descriptor(): Promise<Readonly<ApprovalWorkflowDescriptor>> {
224
- return compileApprovalDescriptor(this.definition, this.createHandle)
225
- }
226
-
227
- async start<DataModel extends GenericDataModel>(
228
- ctx: GenericMutationCtx<DataModel>,
229
- input: ApprovalStartInput,
230
- ): Promise<FunctionReturnType<Component['requests']['start']>> {
231
- return ctx.runMutation(this.component.requests.start, {
232
- ...input,
233
- workflow: await this.descriptor(),
234
- })
235
- }
236
-
237
- decide<DataModel extends GenericDataModel>(
238
- ctx: GenericMutationCtx<DataModel>,
239
- input: ApprovalDecisionInput,
240
- actor: ApprovalActor,
241
- ): Promise<FunctionReturnType<Component['decisions']['decide']>> {
242
- return ctx.runMutation(this.component.decisions.decide, {
243
- ...input,
244
- actor,
245
- compatibilityKey: this.compatibilityKey,
246
- })
247
- }
248
-
249
- evidence<DataModel extends GenericDataModel>(
250
- ctx: GenericQueryCtx<DataModel>,
251
- runId: string,
252
- ): Promise<FunctionReturnType<Component['decisions']['list']>> {
253
- return ctx.runQuery(this.component.decisions.list, { runId })
254
- }
255
-
256
- auditHistory<DataModel extends GenericDataModel>(
257
- ctx: GenericQueryCtx<DataModel>,
258
- input: ApprovalAuditHistoryInput,
259
- ): Promise<FunctionReturnType<Component['audit']['history']>> {
260
- return ctx.runQuery(this.component.audit.history, input)
261
- }
262
-
263
- cancel<DataModel extends GenericDataModel>(
264
- ctx: GenericMutationCtx<DataModel>,
265
- runId: string,
266
- actor: ApprovalActor,
267
- ): Promise<FunctionReturnType<Component['requests']['cancel']>> {
268
- return ctx.runMutation(this.component.requests.cancel, {
269
- runId,
270
- actor,
271
- compatibilityKey: this.compatibilityKey,
272
- })
273
- }
274
-
275
- status<DataModel extends GenericDataModel>(
276
- ctx: GenericQueryCtx<DataModel>,
277
- runId: string,
278
- ): Promise<ApprovalStatus | null> {
279
- return ctx.runQuery(this.component.requests.status, {
280
- runId,
281
- compatibilityKey: this.compatibilityKey,
282
- })
283
- }
284
-
285
- list<DataModel extends GenericDataModel>(
286
- ctx: GenericQueryCtx<DataModel>,
287
- input: FunctionArgs<Component['requests']['list']>,
288
- ): Promise<FunctionReturnType<Component['requests']['list']>> {
289
- return ctx.runQuery(this.component.requests.list, input)
290
- }
291
-
292
- restart<DataModel extends GenericDataModel>(
293
- ctx: GenericMutationCtx<DataModel>,
294
- runId: string,
295
- ): Promise<FunctionReturnType<Component['requests']['restart']>> {
296
- return ctx.runMutation(this.component.requests.restart, {
297
- runId,
298
- compatibilityKey: this.compatibilityKey,
299
- })
300
- }
301
- }
302
-
303
- function freezeDefinition(definition: ApprovalDefinition): ApprovalDefinition {
304
- return Object.freeze({
305
- ...definition,
306
- steps: Object.freeze(
307
- definition.steps.map((step) => {
308
- if (step.kind === 'decision')
309
- return Object.freeze({
310
- ...step,
311
- decisions: Object.freeze([...step.decisions]),
312
- quorum: Object.freeze({ ...step.quorum }),
313
- })
314
- return Object.freeze({ ...step })
315
- }),
316
- ),
317
- })
318
- }
319
-
320
- // Component definition as default export: `import approvals from "cvx-kit/components/approvals"` → app.use(approvals)
321
- export { default } from "./convex.config"
@@ -1,51 +0,0 @@
1
- export const APPROVAL_RUN_STATES = [
2
- 'pending',
3
- 'approved',
4
- 'rejected',
5
- 'expired',
6
- 'canceled',
7
- ] as const
8
-
9
- export const APPROVAL_DECISIONS = ['approved', 'rejected'] as const
10
-
11
- export const APPROVAL_EXECUTION_STATES = [
12
- 'inProgress',
13
- 'completed',
14
- 'canceled',
15
- 'failed',
16
- ] as const
17
-
18
- export const APPROVAL_STEP_KINDS = [
19
- 'mutation',
20
- 'action',
21
- 'notify',
22
- 'decision',
23
- 'branch',
24
- ] as const
25
-
26
- export const APPROVAL_QUORUM_KINDS = ['count'] as const
27
-
28
- export const APPROVAL_CALLBACK_KINDS = ['mutation', 'action'] as const
29
-
30
- export const APPROVAL_DESCRIPTOR_SCHEMA_VERSION = 1 as const
31
-
32
- export const APPROVAL_AUDIT_RETENTION_CATEGORY = 'approval-protocol'
33
- export const MIN_APPROVAL_AUDIT_RETENTION_DAYS = 1
34
- export const MAX_APPROVAL_AUDIT_RETENTION_DAYS = 3_650
35
- export const MAX_APPROVAL_AUDIT_CLEANUP_BATCH_SIZE = 100
36
-
37
- export const MAX_APPROVAL_REFERENCE_LENGTH = 256
38
- export const MAX_APPROVAL_NAME_LENGTH = 96
39
- export const MAX_APPROVAL_REASON_LENGTH = 500
40
- export const MAX_APPROVAL_CAPABILITIES = 32
41
- export const MAX_APPROVAL_METADATA_ENTRIES = 32
42
- export const MAX_APPROVAL_METADATA_KEY_LENGTH = 64
43
- export const MAX_APPROVAL_METADATA_VALUE_LENGTH = 512
44
- export const MAX_APPROVAL_WORKFLOW_STEPS = 32
45
- export const MAX_APPROVAL_DECISIONS_PER_STEP = 8
46
-
47
- export type ApprovalRunState = (typeof APPROVAL_RUN_STATES)[number]
48
- export type ApprovalDecision = (typeof APPROVAL_DECISIONS)[number]
49
- export type ApprovalExecutionState = (typeof APPROVAL_EXECUTION_STATES)[number]
50
- export type ApprovalStepKind = (typeof APPROVAL_STEP_KINDS)[number]
51
- export type ApprovalCallbackKind = (typeof APPROVAL_CALLBACK_KINDS)[number]
@@ -1,10 +0,0 @@
1
- import workflow from '@convex-dev/workflow/convex.config'
2
- import auditLog from 'convex-audit-log/convex.config.js'
3
- import { defineComponent } from 'convex/server'
4
-
5
- const approvals = defineComponent('approvals')
6
-
7
- approvals.use(workflow, { name: 'workflow' })
8
- approvals.use(auditLog, { name: 'auditLog' })
9
-
10
- export default approvals