cvx-kit 0.1.2 → 0.1.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.
- package/CHANGELOG.md +38 -0
- package/README.md +69 -24
- package/dist/agent-tools.d.mts +28 -12
- package/dist/agent-tools.mjs +1 -1
- package/dist/agent-tools.mjs.map +1 -1
- package/dist/auth.d.mts +4 -2
- package/dist/auth.mjs +1 -1
- package/dist/auth.mjs.map +1 -1
- package/dist/components/approvals/_generated/api.d.mts +1 -1
- package/dist/components/approvals/audit.mjs +1 -1
- package/dist/components/approvals/audit.mjs.map +1 -1
- package/dist/components/approvals/client.d.mts +1 -1
- package/dist/components/approvals/client.mjs +1 -1
- package/dist/components/approvals/client.mjs.map +1 -1
- package/dist/components/approvals/constants.mjs.map +1 -1
- package/dist/components/approvals/decisions.d.mts +6 -7
- package/dist/components/approvals/decisions.mjs +1 -1
- package/dist/components/approvals/decisions.mjs.map +1 -1
- package/dist/components/approvals/functions.mjs +1 -1
- package/dist/components/approvals/functions.mjs.map +1 -1
- package/dist/components/approvals/health.mjs.map +1 -1
- package/dist/components/approvals/requests.mjs.map +1 -1
- package/dist/components/approvals/validators.mjs.map +1 -1
- package/dist/components/approvals/workflow.d.mts +1 -1
- package/dist/components/approvals/workflow.mjs +1 -1
- package/dist/components/approvals/workflow.mjs.map +1 -1
- package/dist/components/approvals/workflow_steps.d.mts +3 -3
- package/dist/components/approvals/workflow_steps.mjs +1 -1
- package/dist/components/approvals/workflow_steps.mjs.map +1 -1
- package/dist/components/foundation/client.d.mts +27 -28
- package/dist/components/foundation/client.mjs +1 -1
- package/dist/components/foundation/client.mjs.map +1 -1
- package/dist/components/foundation/modules/command/command.d.mts +17 -8
- package/dist/components/foundation/modules/command/command.mjs +1 -1
- package/dist/components/foundation/modules/command/command.mjs.map +1 -1
- package/dist/components/foundation/modules/observability/observability.d.mts +1 -1
- package/dist/components/foundation/modules/observability/observability.mjs +1 -1
- package/dist/components/foundation/modules/observability/observability.mjs.map +1 -1
- package/dist/components/foundation/modules/query/query.d.mts +8 -8
- package/dist/components/foundation/modules/query/query.mjs +1 -1
- package/dist/components/foundation/modules/query/query.mjs.map +1 -1
- package/dist/components/foundation/operation.d.mts +74 -0
- package/dist/components/foundation/operation.mjs +2 -0
- package/dist/components/foundation/operation.mjs.map +1 -0
- package/dist/components/foundation/result.d.mts +1 -1
- package/dist/components/foundation/result.mjs.map +1 -1
- package/dist/components/foundation/telemetry.mjs +1 -1
- package/dist/components/foundation/telemetry.mjs.map +1 -1
- package/dist/crud.d.mts +177 -16
- package/dist/crud.mjs +1 -1
- package/dist/crud.mjs.map +1 -1
- package/dist/middleware.d.mts +7 -7
- package/dist/middleware.mjs +1 -1
- package/dist/middleware.mjs.map +1 -1
- package/dist/oxlint.d.mts +9 -0
- package/dist/oxlint.mjs +2 -0
- package/dist/oxlint.mjs.map +1 -0
- package/dist/tenancy.mjs +1 -1
- package/dist/tenancy.mjs.map +1 -1
- package/dist/triggers.mjs +1 -1
- package/dist/triggers.mjs.map +1 -1
- package/dist/webhooks.d.mts +17 -106
- package/dist/webhooks.mjs.map +1 -1
- package/dist/zod-table.d.mts +47 -91
- package/dist/zod-table.mjs +1 -1
- package/dist/zod-table.mjs.map +1 -1
- package/docs/approvals.md +57 -56
- package/docs/architecture.md +1 -1
- package/docs/auth.md +57 -33
- package/docs/commands.md +159 -44
- package/docs/conventions.md +40 -40
- package/docs/crud.md +5 -5
- package/docs/llms.md +117 -71
- package/docs/maintainability.md +4 -4
- package/docs/migration.md +33 -33
- package/docs/tenancy.md +5 -8
- package/docs/triggers.md +4 -2
- package/docs/upgrading.md +74 -7
- package/docs/zod-table.md +70 -45
- package/package.json +41 -28
- package/scripts/convex-config-bridge.mjs +7 -18
- package/scripts/extract-changelog.mjs +1 -1
- package/scripts/smoke-packed-components.mjs +35 -75
- package/scripts/test-packed-ids.mjs +149 -0
- package/scripts/test-packed-oxlint.mjs +121 -0
- package/src/test.ts +9 -17
- package/docs/plans/2026-08-14-001-feat-v0.1.0-feature-set-plan.md +0 -461
- package/docs/plans/2026-08-21-0930-feat-resolve-organization-hook-plan.md +0 -178
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const root = join(import.meta.dirname, '..')
|
|
7
|
+
const temporary = mkdtempSync(join(tmpdir(), 'cvx-kit-ids-'))
|
|
8
|
+
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
|
|
9
|
+
function run(command, args, cwd) {
|
|
10
|
+
return execFileSync(command, args, {
|
|
11
|
+
cwd,
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
stdio: 'pipe',
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
run('bun', ['pm', 'pack', '--destination', temporary, '--ignore-scripts'], root)
|
|
18
|
+
for (const installer of ['npm', 'bun']) {
|
|
19
|
+
const fixture = join(temporary, installer)
|
|
20
|
+
mkdirSync(fixture)
|
|
21
|
+
writeFileSync(
|
|
22
|
+
join(fixture, 'package.json'),
|
|
23
|
+
JSON.stringify({
|
|
24
|
+
private: true,
|
|
25
|
+
type: 'module',
|
|
26
|
+
dependencies: {
|
|
27
|
+
'cvx-kit': `file:${join(temporary, `cvx-kit-${manifest.version}.tgz`)}`,
|
|
28
|
+
'convex-helpers': '0.1.123',
|
|
29
|
+
convex: manifest.devDependencies.convex,
|
|
30
|
+
zod: manifest.devDependencies.zod,
|
|
31
|
+
},
|
|
32
|
+
devDependencies: {
|
|
33
|
+
'convex-test': manifest.devDependencies['convex-test'],
|
|
34
|
+
'vite-plus': manifest.devDependencies['vite-plus'],
|
|
35
|
+
'@edge-runtime/vm': manifest.devDependencies['@edge-runtime/vm'],
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
)
|
|
39
|
+
run(installer, ['install', '--ignore-scripts'], fixture)
|
|
40
|
+
writeFileSync(
|
|
41
|
+
join(fixture, 'probe.mjs'),
|
|
42
|
+
`
|
|
43
|
+
import { strict as assert } from 'node:assert'
|
|
44
|
+
import { tenantTable, zodToConvex as kitConverter, zid as kitId } from 'cvx-kit/zod-table'
|
|
45
|
+
import { zid, zodToConvex } from 'convex-helpers/server/zod4'
|
|
46
|
+
import { z } from 'zod'
|
|
47
|
+
const table = tenantTable('children', id => ({
|
|
48
|
+
parentId: id('parents'), nested: z.object({ parentId: id('parents') }),
|
|
49
|
+
}), { commandFields: ['parentId', 'nested'], publicFields: ['parentId', 'nested'] })
|
|
50
|
+
for (const validator of [
|
|
51
|
+
zodToConvex(zid('parents')), table.table.validator.fields.parentId,
|
|
52
|
+
zodToConvex(table.storage).fields.parentId,
|
|
53
|
+
zodToConvex(table.commandInput).fields.parentId,
|
|
54
|
+
zodToConvex(table.publicDto).fields.parentId,
|
|
55
|
+
zodToConvex(table.storage).fields.nested.fields.parentId,
|
|
56
|
+
kitConverter(kitId('parents')),
|
|
57
|
+
kitConverter(table.commandInput).fields.nested.fields.parentId,
|
|
58
|
+
kitConverter(table.publicDto).fields.nested.fields.parentId,
|
|
59
|
+
]) {
|
|
60
|
+
assert.equal(validator.kind, 'id', 'exported schema lost ID validation')
|
|
61
|
+
assert.equal(validator.tableName, 'parents')
|
|
62
|
+
}
|
|
63
|
+
`,
|
|
64
|
+
)
|
|
65
|
+
run('node', ['probe.mjs'], fixture)
|
|
66
|
+
for (const testFile of ['command.test.ts', 'command-lifecycle.test.ts']) {
|
|
67
|
+
const source = readFileSync(join(root, 'test', testFile), 'utf8')
|
|
68
|
+
.replace('../src/components/foundation/client', 'cvx-kit/components/foundation')
|
|
69
|
+
.replace(
|
|
70
|
+
"const modules = import.meta.glob('./fixture/**/*.ts')",
|
|
71
|
+
"const modules = { './_generated/server.ts': async () => ({}) }",
|
|
72
|
+
)
|
|
73
|
+
writeFileSync(join(fixture, testFile), source)
|
|
74
|
+
}
|
|
75
|
+
for (const testFile of ['zod-table.test.ts', 'agent-tools.test.ts']) {
|
|
76
|
+
const source = readFileSync(join(root, 'test', testFile), 'utf8')
|
|
77
|
+
.replaceAll('../src/zod-table', 'cvx-kit/zod-table')
|
|
78
|
+
.replaceAll('../src/agent-tools', 'cvx-kit/agent-tools')
|
|
79
|
+
writeFileSync(join(fixture, testFile), source)
|
|
80
|
+
}
|
|
81
|
+
writeFileSync(
|
|
82
|
+
join(fixture, 'command-types.ts'),
|
|
83
|
+
readFileSync(join(root, 'test/command-types.ts'), 'utf8').replace(
|
|
84
|
+
'../src/components/foundation/client',
|
|
85
|
+
'cvx-kit/components/foundation',
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
writeFileSync(
|
|
89
|
+
join(fixture, 'registration.test.ts'),
|
|
90
|
+
`
|
|
91
|
+
import { convexTest } from 'convex-test'
|
|
92
|
+
import { defineSchema, defineTable } from 'convex/server'
|
|
93
|
+
import { v } from 'convex/values'
|
|
94
|
+
import { registerFoundation, registerApprovals } from 'cvx-kit/test'
|
|
95
|
+
import { it } from 'vite-plus/test'
|
|
96
|
+
it('registers concrete and generic backends from the packed package', () => {
|
|
97
|
+
const modules = { './_generated/server.ts': async () => ({}) }
|
|
98
|
+
const concrete = convexTest(defineSchema({ items: defineTable({ name: v.string() }) }), modules)
|
|
99
|
+
const generic = convexTest(undefined, modules)
|
|
100
|
+
for (const backend of [concrete, generic]) {
|
|
101
|
+
registerFoundation(backend)
|
|
102
|
+
registerApprovals(backend)
|
|
103
|
+
registerFoundation(backend, 'customFoundation')
|
|
104
|
+
registerApprovals(backend, 'customApprovals')
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
`,
|
|
108
|
+
)
|
|
109
|
+
run(
|
|
110
|
+
join(root, 'node_modules/.bin/tsc'),
|
|
111
|
+
[
|
|
112
|
+
'--noEmit',
|
|
113
|
+
'--strict',
|
|
114
|
+
'--skipLibCheck',
|
|
115
|
+
'--target',
|
|
116
|
+
'es2025',
|
|
117
|
+
'--module',
|
|
118
|
+
'esnext',
|
|
119
|
+
'--moduleResolution',
|
|
120
|
+
'bundler',
|
|
121
|
+
'--types',
|
|
122
|
+
'vite/client',
|
|
123
|
+
'command-types.ts',
|
|
124
|
+
'registration.test.ts',
|
|
125
|
+
'zod-table.test.ts',
|
|
126
|
+
'agent-tools.test.ts',
|
|
127
|
+
],
|
|
128
|
+
fixture,
|
|
129
|
+
)
|
|
130
|
+
run(
|
|
131
|
+
join(fixture, 'node_modules/.bin/vp'),
|
|
132
|
+
[
|
|
133
|
+
'test',
|
|
134
|
+
'run',
|
|
135
|
+
'registration.test.ts',
|
|
136
|
+
'command.test.ts',
|
|
137
|
+
'command-lifecycle.test.ts',
|
|
138
|
+
'zod-table.test.ts',
|
|
139
|
+
'agent-tools.test.ts',
|
|
140
|
+
],
|
|
141
|
+
fixture,
|
|
142
|
+
)
|
|
143
|
+
console.log(
|
|
144
|
+
`${installer}: packed IDs, table/tool types, registration, and command lifecycle pass with host convex-helpers 0.1.123`,
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
} finally {
|
|
148
|
+
rmSync(temporary, { recursive: true, force: true })
|
|
149
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { strict as assert } from 'node:assert'
|
|
2
|
+
import { execFileSync, spawnSync } from 'node:child_process'
|
|
3
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import { join } from 'node:path'
|
|
6
|
+
import { rules } from '../dist/oxlint.mjs'
|
|
7
|
+
|
|
8
|
+
const root = join(import.meta.dirname, '..')
|
|
9
|
+
const temporary = mkdtempSync(join(tmpdir(), 'cvx-kit-oxlint-'))
|
|
10
|
+
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
|
|
11
|
+
const ruleNames = Object.keys(rules)
|
|
12
|
+
assert.equal(ruleNames.length, 6)
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
run('bun', ['pm', 'pack', '--destination', temporary, '--ignore-scripts'], root)
|
|
16
|
+
for (const installer of ['npm', 'bun']) {
|
|
17
|
+
const fixture = join(temporary, installer)
|
|
18
|
+
mkdirSync(join(fixture, 'src/components/example'), { recursive: true })
|
|
19
|
+
writeFileSync(
|
|
20
|
+
join(fixture, 'package.json'),
|
|
21
|
+
JSON.stringify({
|
|
22
|
+
private: true,
|
|
23
|
+
type: 'module',
|
|
24
|
+
dependencies: {
|
|
25
|
+
'cvx-kit': `file:${join(temporary, `cvx-kit-${manifest.version}.tgz`)}`,
|
|
26
|
+
convex: manifest.devDependencies.convex,
|
|
27
|
+
'convex-helpers': manifest.devDependencies['convex-helpers'],
|
|
28
|
+
zod: manifest.devDependencies.zod,
|
|
29
|
+
},
|
|
30
|
+
devDependencies: { oxlint: manifest.devDependencies.oxlint },
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
33
|
+
run(installer, ['install', '--ignore-scripts'], fixture)
|
|
34
|
+
writeFileSync(
|
|
35
|
+
join(fixture, '.oxlintrc.json'),
|
|
36
|
+
JSON.stringify({
|
|
37
|
+
jsPlugins: [{ name: 'cvx', specifier: 'cvx-kit/oxlint' }],
|
|
38
|
+
rules: {
|
|
39
|
+
...Object.fromEntries(ruleNames.map((name) => [`cvx/${name}`, 'error'])),
|
|
40
|
+
'cvx/no-internal-reexports': ['error', { entryPoints: ['src/public.ts'] }],
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
)
|
|
44
|
+
writeFileSync(
|
|
45
|
+
join(fixture, 'src/public.ts'),
|
|
46
|
+
"export { run } from './components/example/client'\n",
|
|
47
|
+
)
|
|
48
|
+
writeFileSync(
|
|
49
|
+
join(fixture, 'src/components/example/client.ts'),
|
|
50
|
+
'export function run() { return 1 }\n',
|
|
51
|
+
)
|
|
52
|
+
const oxlint = join(fixture, 'node_modules/.bin/oxlint')
|
|
53
|
+
run(oxlint, ['--config', '.oxlintrc.json', 'src'], fixture)
|
|
54
|
+
writeFileSync(
|
|
55
|
+
join(fixture, 'src/components/example/bad.ts'),
|
|
56
|
+
`
|
|
57
|
+
import { defineTable } from 'convex/server'
|
|
58
|
+
import { host } from '../../host'
|
|
59
|
+
function helper() { return process.env.SECRET }
|
|
60
|
+
const privateHelper = () => helper()
|
|
61
|
+
export const table = defineTable({})
|
|
62
|
+
export { host }
|
|
63
|
+
export const value = privateHelper()
|
|
64
|
+
`,
|
|
65
|
+
)
|
|
66
|
+
writeFileSync(
|
|
67
|
+
join(fixture, 'src/host.ts'),
|
|
68
|
+
"export const host = 1\nimport './components/example/bad'\n",
|
|
69
|
+
)
|
|
70
|
+
const invalid = spawnSync(oxlint, ['--config', '.oxlintrc.json', '--format', 'json', 'src'], {
|
|
71
|
+
cwd: fixture,
|
|
72
|
+
encoding: 'utf8',
|
|
73
|
+
})
|
|
74
|
+
assert.ifError(invalid.error)
|
|
75
|
+
assert.equal(invalid.status, 1, invalid.stderr)
|
|
76
|
+
const diagnostics = JSON.parse(invalid.stdout).diagnostics
|
|
77
|
+
for (const name of ruleNames) {
|
|
78
|
+
assert.ok(
|
|
79
|
+
diagnostics.some((item) => item.code === `cvx(${name})`),
|
|
80
|
+
`${installer}: missing ${name}: ${invalid.stdout}`,
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
writeFileSync(
|
|
84
|
+
join(fixture, 'plugin-types.ts'),
|
|
85
|
+
`
|
|
86
|
+
import plugin, { rules, type RuleName } from 'cvx-kit/oxlint'
|
|
87
|
+
import type { Plugin, Rule } from '@oxlint/plugins'
|
|
88
|
+
const compatible: Plugin = plugin
|
|
89
|
+
const name: RuleName = 'component-boundaries'
|
|
90
|
+
const rule: Rule = rules[name]
|
|
91
|
+
void compatible
|
|
92
|
+
void rule
|
|
93
|
+
`,
|
|
94
|
+
)
|
|
95
|
+
run(
|
|
96
|
+
join(root, 'node_modules/.bin/tsc'),
|
|
97
|
+
[
|
|
98
|
+
'--noEmit',
|
|
99
|
+
'--strict',
|
|
100
|
+
'--skipLibCheck',
|
|
101
|
+
'--target',
|
|
102
|
+
'es2025',
|
|
103
|
+
'--module',
|
|
104
|
+
'esnext',
|
|
105
|
+
'--moduleResolution',
|
|
106
|
+
'bundler',
|
|
107
|
+
'plugin-types.ts',
|
|
108
|
+
],
|
|
109
|
+
fixture,
|
|
110
|
+
)
|
|
111
|
+
console.log(
|
|
112
|
+
`${installer}: packed Oxlint plugin loads, all six rules report, and declarations typecheck`,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
} finally {
|
|
116
|
+
rmSync(temporary, { recursive: true, force: true })
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function run(command, args, cwd) {
|
|
120
|
+
return execFileSync(command, args, { cwd, encoding: 'utf8', stdio: 'pipe' })
|
|
121
|
+
}
|
package/src/test.ts
CHANGED
|
@@ -6,29 +6,21 @@
|
|
|
6
6
|
* registers the COMPILED component modules from dist, so dist is the only
|
|
7
7
|
* code the package ships.
|
|
8
8
|
*/
|
|
9
|
+
import type { TestConvex } from 'convex-test'
|
|
10
|
+
import type { GenericSchema, SchemaDefinition } from 'convex/server'
|
|
9
11
|
import approvalsSchema from '../dist/components/approvals/schema.js'
|
|
10
12
|
import foundationSchema from '../dist/components/foundation/schema.js'
|
|
11
13
|
|
|
12
|
-
const foundationModules = import.meta.glob(
|
|
13
|
-
|
|
14
|
-
)
|
|
15
|
-
const approvalsModules = import.meta.glob(
|
|
16
|
-
'../dist/components/approvals/**/*.mjs',
|
|
17
|
-
)
|
|
14
|
+
const foundationModules = import.meta.glob('../dist/components/foundation/**/*.mjs')
|
|
15
|
+
const approvalsModules = import.meta.glob('../dist/components/approvals/**/*.mjs')
|
|
18
16
|
|
|
19
|
-
type RegistersComponents =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
modules: Record<string, () => Promise<unknown>>,
|
|
24
|
-
) => void
|
|
25
|
-
}
|
|
17
|
+
type RegistersComponents = Pick<
|
|
18
|
+
TestConvex<SchemaDefinition<GenericSchema, boolean>>,
|
|
19
|
+
'registerComponent'
|
|
20
|
+
>
|
|
26
21
|
|
|
27
22
|
/** Registers the foundation component under its default install name. */
|
|
28
|
-
export function registerFoundation(
|
|
29
|
-
t: RegistersComponents,
|
|
30
|
-
name = 'foundation',
|
|
31
|
-
) {
|
|
23
|
+
export function registerFoundation(t: RegistersComponents, name = 'foundation') {
|
|
32
24
|
t.registerComponent(name, foundationSchema, foundationModules)
|
|
33
25
|
}
|
|
34
26
|
|