ts-procedures 5.10.0 → 5.12.0
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/agent_config/bin/postinstall.mjs +3 -3
- package/agent_config/bin/setup.mjs +22 -11
- package/agent_config/claude-code/agents/ts-procedures-architect.md +2 -2
- package/agent_config/claude-code/skills/{guide → ts-procedures}/SKILL.md +1 -1
- package/agent_config/claude-code/skills/{guide → ts-procedures}/api-reference.md +11 -8
- package/agent_config/claude-code/skills/{guide → ts-procedures}/patterns.md +8 -2
- package/agent_config/claude-code/skills/{review → ts-procedures-review}/SKILL.md +3 -3
- package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/SKILL.md +2 -2
- package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/client.md +4 -4
- package/agent_config/copilot/copilot-instructions.md +6 -5
- package/agent_config/cursor/cursorrules +6 -5
- package/agent_config/lib/install-claude.mjs +35 -87
- package/build/codegen/e2e.test.js +21 -14
- package/build/codegen/e2e.test.js.map +1 -1
- package/build/codegen/emit-index.d.ts +7 -3
- package/build/codegen/emit-index.js +33 -20
- package/build/codegen/emit-index.js.map +1 -1
- package/build/codegen/emit-index.test.js +69 -45
- package/build/codegen/emit-index.test.js.map +1 -1
- package/build/codegen/pipeline.js +4 -5
- package/build/codegen/pipeline.js.map +1 -1
- package/build/codegen/pipeline.test.js +4 -4
- package/build/codegen/pipeline.test.js.map +1 -1
- package/build/src/client/call.d.ts +14 -0
- package/build/src/client/call.js +47 -0
- package/build/src/client/call.js.map +1 -0
- package/build/src/client/call.test.d.ts +1 -0
- package/build/src/client/call.test.js +124 -0
- package/build/src/client/call.test.js.map +1 -0
- package/build/src/client/errors.d.ts +25 -0
- package/build/src/client/errors.js +33 -0
- package/build/src/client/errors.js.map +1 -0
- package/build/src/client/errors.test.d.ts +1 -0
- package/build/src/client/errors.test.js +41 -0
- package/build/src/client/errors.test.js.map +1 -0
- package/build/src/client/fetch-adapter.d.ts +12 -0
- package/build/src/client/fetch-adapter.js +156 -0
- package/build/src/client/fetch-adapter.js.map +1 -0
- package/build/src/client/fetch-adapter.test.d.ts +1 -0
- package/build/src/client/fetch-adapter.test.js +271 -0
- package/build/src/client/fetch-adapter.test.js.map +1 -0
- package/build/src/client/hooks.d.ts +17 -0
- package/build/src/client/hooks.js +40 -0
- package/build/src/client/hooks.js.map +1 -0
- package/build/src/client/hooks.test.d.ts +1 -0
- package/build/src/client/hooks.test.js +163 -0
- package/build/src/client/hooks.test.js.map +1 -0
- package/build/src/client/index.d.ts +22 -0
- package/build/src/client/index.js +67 -0
- package/build/src/client/index.js.map +1 -0
- package/build/src/client/index.test.d.ts +1 -0
- package/build/src/client/index.test.js +231 -0
- package/build/src/client/index.test.js.map +1 -0
- package/build/src/client/request-builder.d.ts +13 -0
- package/build/src/client/request-builder.js +53 -0
- package/build/src/client/request-builder.js.map +1 -0
- package/build/src/client/request-builder.test.d.ts +1 -0
- package/build/src/client/request-builder.test.js +160 -0
- package/build/src/client/request-builder.test.js.map +1 -0
- package/build/src/client/stream.d.ts +27 -0
- package/build/src/client/stream.js +118 -0
- package/build/src/client/stream.js.map +1 -0
- package/build/src/client/stream.test.d.ts +1 -0
- package/build/src/client/stream.test.js +228 -0
- package/build/src/client/stream.test.js.map +1 -0
- package/build/src/client/types.d.ts +78 -0
- package/build/src/client/types.js +3 -0
- package/build/src/client/types.js.map +1 -0
- package/build/src/codegen/bin/cli.d.ts +45 -0
- package/build/src/codegen/bin/cli.js +246 -0
- package/build/src/codegen/bin/cli.js.map +1 -0
- package/build/src/codegen/bin/cli.test.d.ts +1 -0
- package/build/src/codegen/bin/cli.test.js +220 -0
- package/build/src/codegen/bin/cli.test.js.map +1 -0
- package/build/src/codegen/constants.d.ts +1 -0
- package/build/src/codegen/constants.js +2 -0
- package/build/src/codegen/constants.js.map +1 -0
- package/build/src/codegen/e2e.test.d.ts +1 -0
- package/build/src/codegen/e2e.test.js +464 -0
- package/build/src/codegen/e2e.test.js.map +1 -0
- package/build/src/codegen/emit-client-runtime.d.ts +9 -0
- package/build/src/codegen/emit-client-runtime.js +99 -0
- package/build/src/codegen/emit-client-runtime.js.map +1 -0
- package/build/src/codegen/emit-client-runtime.test.d.ts +1 -0
- package/build/src/codegen/emit-client-runtime.test.js +78 -0
- package/build/src/codegen/emit-client-runtime.test.js.map +1 -0
- package/build/src/codegen/emit-client-types.d.ts +8 -0
- package/build/src/codegen/emit-client-types.js +25 -0
- package/build/src/codegen/emit-client-types.js.map +1 -0
- package/build/src/codegen/emit-client-types.test.d.ts +1 -0
- package/build/src/codegen/emit-client-types.test.js +33 -0
- package/build/src/codegen/emit-client-types.test.js.map +1 -0
- package/build/src/codegen/emit-errors.d.ts +19 -0
- package/build/src/codegen/emit-errors.js +59 -0
- package/build/src/codegen/emit-errors.js.map +1 -0
- package/build/src/codegen/emit-errors.test.d.ts +1 -0
- package/build/src/codegen/emit-errors.test.js +175 -0
- package/build/src/codegen/emit-errors.test.js.map +1 -0
- package/build/src/codegen/emit-index.d.ts +12 -0
- package/build/src/codegen/emit-index.js +41 -0
- package/build/src/codegen/emit-index.js.map +1 -0
- package/build/src/codegen/emit-index.test.d.ts +1 -0
- package/build/src/codegen/emit-index.test.js +106 -0
- package/build/src/codegen/emit-index.test.js.map +1 -0
- package/build/src/codegen/emit-scope.d.ts +15 -0
- package/build/src/codegen/emit-scope.js +299 -0
- package/build/src/codegen/emit-scope.js.map +1 -0
- package/build/src/codegen/emit-scope.test.d.ts +1 -0
- package/build/src/codegen/emit-scope.test.js +559 -0
- package/build/src/codegen/emit-scope.test.js.map +1 -0
- package/build/src/codegen/emit-types.d.ts +43 -0
- package/build/src/codegen/emit-types.js +111 -0
- package/build/src/codegen/emit-types.js.map +1 -0
- package/build/src/codegen/emit-types.test.d.ts +1 -0
- package/build/src/codegen/emit-types.test.js +184 -0
- package/build/src/codegen/emit-types.test.js.map +1 -0
- package/build/src/codegen/group-routes.d.ts +23 -0
- package/build/src/codegen/group-routes.js +46 -0
- package/build/src/codegen/group-routes.js.map +1 -0
- package/build/src/codegen/group-routes.test.d.ts +1 -0
- package/build/src/codegen/group-routes.test.js +131 -0
- package/build/src/codegen/group-routes.test.js.map +1 -0
- package/build/src/codegen/index.d.ts +15 -0
- package/build/src/codegen/index.js +16 -0
- package/build/src/codegen/index.js.map +1 -0
- package/build/src/codegen/naming.d.ts +7 -0
- package/build/src/codegen/naming.js +21 -0
- package/build/src/codegen/naming.js.map +1 -0
- package/build/src/codegen/naming.test.d.ts +1 -0
- package/build/src/codegen/naming.test.js +40 -0
- package/build/src/codegen/naming.test.js.map +1 -0
- package/build/src/codegen/pipeline.d.ts +17 -0
- package/build/src/codegen/pipeline.js +78 -0
- package/build/src/codegen/pipeline.js.map +1 -0
- package/build/src/codegen/pipeline.test.d.ts +1 -0
- package/build/src/codegen/pipeline.test.js +269 -0
- package/build/src/codegen/pipeline.test.js.map +1 -0
- package/build/src/codegen/resolve-envelope.d.ts +7 -0
- package/build/src/codegen/resolve-envelope.js +46 -0
- package/build/src/codegen/resolve-envelope.js.map +1 -0
- package/build/src/codegen/resolve-envelope.test.d.ts +1 -0
- package/build/src/codegen/resolve-envelope.test.js +69 -0
- package/build/src/codegen/resolve-envelope.test.js.map +1 -0
- package/build/src/errors.d.ts +33 -0
- package/build/src/errors.js +91 -0
- package/build/src/errors.js.map +1 -0
- package/build/src/errors.test.d.ts +1 -0
- package/build/src/errors.test.js +122 -0
- package/build/src/errors.test.js.map +1 -0
- package/build/src/exports.d.ts +7 -0
- package/build/src/exports.js +8 -0
- package/build/src/exports.js.map +1 -0
- package/build/src/implementations/http/doc-registry.d.ts +12 -0
- package/build/src/implementations/http/doc-registry.js +114 -0
- package/build/src/implementations/http/doc-registry.js.map +1 -0
- package/build/src/implementations/http/doc-registry.test.d.ts +1 -0
- package/build/src/implementations/http/doc-registry.test.js +347 -0
- package/build/src/implementations/http/doc-registry.test.js.map +1 -0
- package/build/src/implementations/http/express-rpc/index.d.ts +94 -0
- package/build/src/implementations/http/express-rpc/index.js +185 -0
- package/build/src/implementations/http/express-rpc/index.js.map +1 -0
- package/build/src/implementations/http/express-rpc/index.test.d.ts +1 -0
- package/build/src/implementations/http/express-rpc/index.test.js +684 -0
- package/build/src/implementations/http/express-rpc/index.test.js.map +1 -0
- package/build/src/implementations/http/express-rpc/types.d.ts +11 -0
- package/build/src/implementations/http/express-rpc/types.js +2 -0
- package/build/src/implementations/http/express-rpc/types.js.map +1 -0
- package/build/src/implementations/http/hono-api/index.d.ts +102 -0
- package/build/src/implementations/http/hono-api/index.js +341 -0
- package/build/src/implementations/http/hono-api/index.js.map +1 -0
- package/build/src/implementations/http/hono-api/index.test.d.ts +1 -0
- package/build/src/implementations/http/hono-api/index.test.js +992 -0
- package/build/src/implementations/http/hono-api/index.test.js.map +1 -0
- package/build/src/implementations/http/hono-api/types.d.ts +13 -0
- package/build/src/implementations/http/hono-api/types.js +2 -0
- package/build/src/implementations/http/hono-api/types.js.map +1 -0
- package/build/src/implementations/http/hono-rpc/index.d.ts +92 -0
- package/build/src/implementations/http/hono-rpc/index.js +161 -0
- package/build/src/implementations/http/hono-rpc/index.js.map +1 -0
- package/build/src/implementations/http/hono-rpc/index.test.d.ts +1 -0
- package/build/src/implementations/http/hono-rpc/index.test.js +803 -0
- package/build/src/implementations/http/hono-rpc/index.test.js.map +1 -0
- package/build/src/implementations/http/hono-rpc/types.d.ts +11 -0
- package/build/src/implementations/http/hono-rpc/types.js +2 -0
- package/build/src/implementations/http/hono-rpc/types.js.map +1 -0
- package/build/src/implementations/http/hono-stream/index.d.ts +120 -0
- package/build/src/implementations/http/hono-stream/index.js +309 -0
- package/build/src/implementations/http/hono-stream/index.js.map +1 -0
- package/build/src/implementations/http/hono-stream/index.test.d.ts +1 -0
- package/build/src/implementations/http/hono-stream/index.test.js +1356 -0
- package/build/src/implementations/http/hono-stream/index.test.js.map +1 -0
- package/build/src/implementations/http/hono-stream/types.d.ts +15 -0
- package/build/src/implementations/http/hono-stream/types.js +2 -0
- package/build/src/implementations/http/hono-stream/types.js.map +1 -0
- package/build/src/implementations/types.d.ts +142 -0
- package/build/src/implementations/types.js +2 -0
- package/build/src/implementations/types.js.map +1 -0
- package/build/src/index.d.ts +165 -0
- package/build/src/index.js +253 -0
- package/build/src/index.js.map +1 -0
- package/build/src/index.test.d.ts +1 -0
- package/build/src/index.test.js +890 -0
- package/build/src/index.test.js.map +1 -0
- package/build/src/schema/compute-schema.d.ts +35 -0
- package/build/src/schema/compute-schema.js +41 -0
- package/build/src/schema/compute-schema.js.map +1 -0
- package/build/src/schema/compute-schema.test.d.ts +1 -0
- package/build/src/schema/compute-schema.test.js +107 -0
- package/build/src/schema/compute-schema.test.js.map +1 -0
- package/build/src/schema/extract-json-schema.d.ts +2 -0
- package/build/src/schema/extract-json-schema.js +12 -0
- package/build/src/schema/extract-json-schema.js.map +1 -0
- package/build/src/schema/extract-json-schema.test.d.ts +1 -0
- package/build/src/schema/extract-json-schema.test.js +23 -0
- package/build/src/schema/extract-json-schema.test.js.map +1 -0
- package/build/src/schema/parser.d.ts +28 -0
- package/build/src/schema/parser.js +170 -0
- package/build/src/schema/parser.js.map +1 -0
- package/build/src/schema/parser.test.d.ts +1 -0
- package/build/src/schema/parser.test.js +120 -0
- package/build/src/schema/parser.test.js.map +1 -0
- package/build/src/schema/resolve-schema-lib.d.ts +12 -0
- package/build/src/schema/resolve-schema-lib.js +11 -0
- package/build/src/schema/resolve-schema-lib.js.map +1 -0
- package/build/src/schema/resolve-schema-lib.test.d.ts +1 -0
- package/build/src/schema/resolve-schema-lib.test.js +17 -0
- package/build/src/schema/resolve-schema-lib.test.js.map +1 -0
- package/build/src/schema/types.d.ts +8 -0
- package/build/src/schema/types.js +2 -0
- package/build/src/schema/types.js.map +1 -0
- package/build/src/stack-utils.d.ts +25 -0
- package/build/src/stack-utils.js +95 -0
- package/build/src/stack-utils.js.map +1 -0
- package/build/src/stack-utils.test.d.ts +1 -0
- package/build/src/stack-utils.test.js +80 -0
- package/build/src/stack-utils.test.js.map +1 -0
- package/docs/ai-agent-setup.md +7 -6
- package/docs/client-and-codegen.md +9 -6
- package/package.json +1 -1
- package/src/codegen/e2e.test.ts +23 -14
- package/src/codegen/emit-index.test.ts +72 -45
- package/src/codegen/emit-index.ts +43 -20
- package/src/codegen/pipeline.test.ts +4 -4
- package/src/codegen/pipeline.ts +4 -5
- /package/agent_config/claude-code/skills/{guide → ts-procedures}/anti-patterns.md +0 -0
- /package/agent_config/claude-code/skills/{review → ts-procedures-review}/checklist.md +0 -0
- /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/express-rpc.md +0 -0
- /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-api.md +0 -0
- /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-rpc.md +0 -0
- /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-stream.md +0 -0
- /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/procedure.md +0 -0
- /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/stream-procedure.md +0 -0
|
@@ -64,19 +64,19 @@ function updateMarkedFile(targetPath, sourceRelativePath) {
|
|
|
64
64
|
|
|
65
65
|
// ─── Auto-update ──────────────────────────────────────────
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const claudeSkillDir = join(projectRoot, '.claude', 'skills', 'ts-procedures');
|
|
68
68
|
const cursorFile = join(projectRoot, '.cursorrules');
|
|
69
69
|
const copilotFile = join(projectRoot, '.github', 'copilot-instructions.md');
|
|
70
70
|
|
|
71
71
|
// Check if any target was previously set up
|
|
72
|
-
const hasAnySetup = existsSync(
|
|
72
|
+
const hasAnySetup = existsSync(claudeSkillDir) || existsSync(cursorFile) || existsSync(copilotFile);
|
|
73
73
|
|
|
74
74
|
if (hasAnySetup) {
|
|
75
75
|
try {
|
|
76
76
|
const updated = [];
|
|
77
77
|
|
|
78
78
|
// Auto-update Claude Code files
|
|
79
|
-
if (existsSync(
|
|
79
|
+
if (existsSync(claudeSkillDir)) {
|
|
80
80
|
const { installClaude } = await import('../lib/install-claude.mjs');
|
|
81
81
|
installClaude(projectRoot);
|
|
82
82
|
updated.push('Claude Code');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
3
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
4
|
import { join, dirname, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { createInterface } from 'node:readline';
|
|
@@ -23,7 +23,7 @@ function printUsage() {
|
|
|
23
23
|
Usage: npx ts-procedures-setup [targets...] [options]
|
|
24
24
|
|
|
25
25
|
Targets:
|
|
26
|
-
claude Install Claude Code
|
|
26
|
+
claude Install Claude Code skills and architect agent into .claude/
|
|
27
27
|
cursor Copy ts-procedures rules to .cursorrules
|
|
28
28
|
copilot Copy ts-procedures instructions to .github/copilot-instructions.md
|
|
29
29
|
all Set up all targets (default)
|
|
@@ -89,12 +89,24 @@ function isFileOutdated(targetPath, expectedContent) {
|
|
|
89
89
|
|
|
90
90
|
function setupClaude({ dryRun, check } = {}) {
|
|
91
91
|
if (dryRun) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
// Mirror install-claude.mjs: copy every file under each source skill dir, plus the agent.
|
|
93
|
+
const claudeFiles = [];
|
|
94
|
+
const skillsSrc = join(AGENT_CONFIG_DIR, 'claude-code', 'skills');
|
|
95
|
+
for (const skill of ['ts-procedures', 'ts-procedures-review', 'ts-procedures-scaffold']) {
|
|
96
|
+
const walk = (dir, prefix) => {
|
|
97
|
+
for (const entry of readdirSync(dir)) {
|
|
98
|
+
const full = join(dir, entry);
|
|
99
|
+
if (statSync(full).isDirectory()) {
|
|
100
|
+
walk(full, `${prefix}/${entry}`);
|
|
101
|
+
} else {
|
|
102
|
+
claudeFiles.push(`${prefix}/${entry}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
walk(join(skillsSrc, skill), `.claude/skills/${skill}`);
|
|
107
|
+
}
|
|
108
|
+
claudeFiles.push('.claude/agents/ts-procedures-architect.md');
|
|
109
|
+
|
|
98
110
|
console.log('\n Claude Code (dry run)');
|
|
99
111
|
console.log(' ─────────────────────');
|
|
100
112
|
for (const f of claudeFiles) {
|
|
@@ -116,9 +128,8 @@ function setupClaude({ dryRun, check } = {}) {
|
|
|
116
128
|
console.log(` ${f}`);
|
|
117
129
|
}
|
|
118
130
|
console.log('');
|
|
119
|
-
console.log('
|
|
120
|
-
console.log(' Agent:
|
|
121
|
-
console.log(' Reference: Auto-loaded via .claude/rules/ts-procedures.md\n');
|
|
131
|
+
console.log(' Skills: ts-procedures, ts-procedures-scaffold, ts-procedures-review');
|
|
132
|
+
console.log(' Agent: ts-procedures-architect (architecture planning)\n');
|
|
122
133
|
return false;
|
|
123
134
|
}
|
|
124
135
|
|
|
@@ -4,14 +4,14 @@ description: "Architecture planning agent for ts-procedures RPC applications. Us
|
|
|
4
4
|
model: sonnet
|
|
5
5
|
disallowedTools: Write, Edit
|
|
6
6
|
skills:
|
|
7
|
-
-
|
|
7
|
+
- ts-procedures
|
|
8
8
|
color: blue
|
|
9
9
|
effort: high
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
You are an architecture planning agent for applications built with **ts-procedures**, a TypeScript RPC framework that creates type-safe, schema-validated procedure calls. You help developers plan APIs by deciding procedure structure, schema design, context shape, and HTTP integration strategy.
|
|
13
13
|
|
|
14
|
-
The full ts-procedures framework reference is preloaded via the
|
|
14
|
+
The full ts-procedures framework reference is preloaded via the `ts-procedures` skill — use it for API details, schema rules, error classes, and HTTP builder specifics.
|
|
15
15
|
|
|
16
16
|
## Your Process
|
|
17
17
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: ts-procedures
|
|
3
3
|
description: "TypeScript RPC framework reference for ts-procedures — schema validation, error handling, HTTP builders, streaming, and code generation. Use when writing, reviewing, or debugging procedures, configuring HTTP builders, or designing schemas."
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
@@ -719,7 +719,7 @@ function createClient<TScopes>(config: {
|
|
|
719
719
|
|
|
720
720
|
- `config.adapter` — Transport adapter implementing `ClientAdapter`. Use `createFetchAdapter()` for fetch-based transport.
|
|
721
721
|
- `config.basePath` — Base URL prepended to all request paths (e.g., `'http://localhost:3000'`).
|
|
722
|
-
- `config.scopes` — Factory function that receives a raw `ClientInstance` and returns the typed scope object.
|
|
722
|
+
- `config.scopes` — Factory function that receives a raw `ClientInstance` and returns the typed scope object. The generated `create${ServiceName}Bindings` export (defaults to `createApiBindings`; pass `--service-name <Name>` to rename).
|
|
723
723
|
- `config.hooks` — Optional global hooks applied to every call. Can be overridden per call.
|
|
724
724
|
|
|
725
725
|
### Return Value
|
|
@@ -739,12 +739,12 @@ interface ClientHooks {
|
|
|
739
739
|
|
|
740
740
|
```typescript
|
|
741
741
|
import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
742
|
-
import {
|
|
742
|
+
import { createApiBindings, Api } from './generated/api'
|
|
743
743
|
|
|
744
744
|
const client = createClient({
|
|
745
745
|
adapter: createFetchAdapter(),
|
|
746
746
|
basePath: 'http://localhost:3000',
|
|
747
|
-
scopes:
|
|
747
|
+
scopes: createApiBindings,
|
|
748
748
|
hooks: {
|
|
749
749
|
onBeforeRequest(ctx) {
|
|
750
750
|
ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
|
|
@@ -754,6 +754,8 @@ const client = createClient({
|
|
|
754
754
|
})
|
|
755
755
|
|
|
756
756
|
const user = await client.users.GetUser({ pathParams: { id: '123' } })
|
|
757
|
+
|
|
758
|
+
// Reach types via the namespace: Api.Users.GetUser.Params, Api.Errors.ProcedureError
|
|
757
759
|
```
|
|
758
760
|
|
|
759
761
|
---
|
|
@@ -835,14 +837,15 @@ async function generateClient(options: {
|
|
|
835
837
|
| `--depluralize` | Singularize array item type names (ignored with `--no-namespace-types`) |
|
|
836
838
|
| `--array-item-naming <value>` | Postfix for array item type names (ignored with `--no-namespace-types`) |
|
|
837
839
|
| `--uncountable-words <list>` | Comma-separated words to skip singularization (ignored with `--no-namespace-types`) |
|
|
838
|
-
| `--service-name <name>` |
|
|
840
|
+
| `--service-name <name>` | Names the service namespace and binding factory (e.g., `Auth` → `export namespace Auth { ... }` + `createAuthBindings`). Also prefixes `${Name}Errors` and `${Name}ProcedureErrorUnion` in `_errors.ts`. **Default: `Api`.** |
|
|
839
841
|
|
|
840
842
|
### Generated Output
|
|
841
843
|
|
|
842
844
|
- One `.ts` file per scope (e.g., `users.ts`, `events.ts`)
|
|
843
|
-
- A root `index.ts`
|
|
845
|
+
- A root `index.ts` that imports each scope as a namespace (`import * as users from './users'`), exports a `create${ServiceName}Bindings` factory (defaults to `createApiBindings`), and — when namespace mode is on — wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block (defaults to `Api`). Errors are folded in as `${ServiceName}.Errors`.
|
|
846
|
+
- No `export *` re-exports — consumers reach types via `${ServiceName}.<Scope>.<Route>.Params` etc.
|
|
844
847
|
- Each scope file exports fully-typed callable functions and TypeScript types
|
|
845
|
-
- By default, types are wrapped in `export namespace Scope { export namespace Route { ... } }` (disable with `--no-namespace-types`)
|
|
848
|
+
- By default, types are wrapped in `export namespace Scope { export namespace Route { ... } }` (disable with `--no-namespace-types`; this also disables the outer service namespace in `index.ts`)
|
|
846
849
|
|
|
847
850
|
### Example
|
|
848
851
|
|
|
@@ -890,9 +893,9 @@ interface TypedStream<TYield, TReturn> extends AsyncIterable<TYield> {
|
|
|
890
893
|
|
|
891
894
|
```typescript
|
|
892
895
|
import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
893
|
-
import {
|
|
896
|
+
import { createApiBindings } from './generated/api'
|
|
894
897
|
|
|
895
|
-
const client = createClient({ adapter: createFetchAdapter(), basePath: '...', scopes:
|
|
898
|
+
const client = createClient({ adapter: createFetchAdapter(), basePath: '...', scopes: createApiBindings })
|
|
896
899
|
|
|
897
900
|
const stream = client.events.WatchNotifications({ filter: 'all' })
|
|
898
901
|
|
|
@@ -791,12 +791,13 @@ app.get('/docs', (c) => c.json(docs.toJSON()))
|
|
|
791
791
|
|
|
792
792
|
```typescript
|
|
793
793
|
import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
794
|
-
import {
|
|
794
|
+
import { createApiBindings, Api } from './generated/api'
|
|
795
|
+
// With --service-name <Name>: import { create<Name>Bindings, <Name> } from './generated/api'
|
|
795
796
|
|
|
796
797
|
const client = createClient({
|
|
797
798
|
adapter: createFetchAdapter(),
|
|
798
799
|
basePath: 'http://localhost:3000',
|
|
799
|
-
scopes:
|
|
800
|
+
scopes: createApiBindings,
|
|
800
801
|
hooks: {
|
|
801
802
|
onBeforeRequest(ctx) {
|
|
802
803
|
ctx.request.headers = {
|
|
@@ -815,6 +816,11 @@ const client = createClient({
|
|
|
815
816
|
|
|
816
817
|
// Fully typed — params and response inferred from server schemas
|
|
817
818
|
const user = await client.users.GetUser({ pathParams: { id: '123' } })
|
|
819
|
+
|
|
820
|
+
// Reach types via the service namespace:
|
|
821
|
+
// Api.Users.GetUser.Params
|
|
822
|
+
// Api.Users.GetUser.Response
|
|
823
|
+
// Api.Errors.ProcedureError
|
|
818
824
|
```
|
|
819
825
|
|
|
820
826
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: review
|
|
2
|
+
name: ts-procedures-review
|
|
3
3
|
description: "Review ts-procedures code for pattern adherence, schema correctness, error handling, and signal propagation."
|
|
4
4
|
argument-hint: "<path>"
|
|
5
5
|
allowed-tools: Read Grep Glob
|
|
@@ -16,7 +16,7 @@ Parse `$ARGUMENTS` as a file or directory path. If a directory, review all `.ts`
|
|
|
16
16
|
1. Read the target file(s).
|
|
17
17
|
2. Identify ts-procedures imports (`ts-procedures`, `ts-procedures/express-rpc`, `ts-procedures/hono-rpc`, `ts-procedures/hono-stream`, `ts-procedures/hono-api`, `ts-procedures/http`, `ts-procedures/http-docs`) to determine file types.
|
|
18
18
|
3. Check each file against the categorized checklist in [checklist.md](checklist.md).
|
|
19
|
-
4. For detailed code examples of each violation pattern, reference [anti-patterns.md](../
|
|
19
|
+
4. For detailed code examples of each violation pattern, reference [anti-patterns.md](../ts-procedures/anti-patterns.md) — it shows 20 common mistakes with before/after code fixes and severity ratings.
|
|
20
20
|
5. Output findings grouped by severity.
|
|
21
21
|
|
|
22
22
|
## Output Format
|
|
@@ -45,4 +45,4 @@ After individual findings, provide:
|
|
|
45
45
|
## Reference
|
|
46
46
|
|
|
47
47
|
See [checklist.md](checklist.md) for the complete categorized checklist by file type.
|
|
48
|
-
See [anti-patterns.md](../
|
|
48
|
+
See [anti-patterns.md](../ts-procedures/anti-patterns.md) for detailed code examples of each violation.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: scaffold
|
|
2
|
+
name: ts-procedures-scaffold
|
|
3
3
|
description: "Generate ts-procedures implementations with correct patterns — procedures, streams, Express RPC, Hono RPC, Hono streaming, REST APIs, and client setup."
|
|
4
4
|
argument-hint: "<type> <Name>"
|
|
5
5
|
allowed-tools: Read Write
|
|
@@ -19,7 +19,7 @@ If either argument is missing, ask the user for `<type>` and `<Name>`.
|
|
|
19
19
|
- `{{Name}}` — PascalCase as given (e.g., `UserProfile`)
|
|
20
20
|
- `{{name}}` — camelCase (e.g., `userProfile`)
|
|
21
21
|
- For URL scopes and file paths, use kebab-case (e.g., `user-profile`)
|
|
22
|
-
4. Read the template file from
|
|
22
|
+
4. Read the template file from `templates/$0.md` (relative to this skill directory).
|
|
23
23
|
5. Replace all `{{Name}}` and `{{name}}` placeholders with the appropriate variants.
|
|
24
24
|
6. Generate the implementation file(s) following the template exactly.
|
|
25
25
|
7. Also generate a colocated test file following ts-procedures test conventions.
|
package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/client.md
RENAMED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
7
|
-
import {
|
|
8
|
-
// With --service-name: import { create{{Name}}Bindings } from './generated/api'
|
|
7
|
+
import { createApiBindings, Api } from './generated/api'
|
|
8
|
+
// With --service-name {{Name}}: import { create{{Name}}Bindings, {{Name}} } from './generated/api'
|
|
9
9
|
|
|
10
10
|
// Create the typed client
|
|
11
11
|
export const {{name}}Client = createClient({
|
|
12
12
|
adapter: createFetchAdapter(),
|
|
13
13
|
basePath: 'http://localhost:3000', // TODO: configure base URL
|
|
14
|
-
scopes:
|
|
15
|
-
// With --service-name: scopes: create{{Name}}Bindings,
|
|
14
|
+
scopes: createApiBindings,
|
|
15
|
+
// With --service-name {{Name}}: scopes: create{{Name}}Bindings,
|
|
16
16
|
hooks: {
|
|
17
17
|
onBeforeRequest(ctx) {
|
|
18
18
|
// TODO: add auth headers, request IDs, etc.
|
|
@@ -320,8 +320,8 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
320
320
|
# --config ./codegen.config.json --service-name Auth
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
-
Generates one `.ts` file per scope plus a root `index.ts`
|
|
324
|
-
By default, types are wrapped in nested TS namespaces (`Scope.Route.Params`), JSDoc comments are emitted, and output is self-contained (no runtime dependency on `ts-procedures`). Use `--no-namespace-types` to revert to flat type names (`RouteParams`).
|
|
323
|
+
Generates one `.ts` file per scope plus a root `index.ts` that imports each scope as a namespace and exports a `create${ServiceName}Bindings` factory (defaults to `createApiBindings`; pass `--service-name <Name>` to rename). When namespace mode is on (the default), `index.ts` also wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block so types are reachable as `Api.Users.GetUser.Params`, `Api.Errors.ProcedureError`, etc. The errors file (`_errors.ts`) emits `${ServiceName}Errors` and `${ServiceName}ProcedureErrorUnion` (defaults: `ApiErrors`, `ApiProcedureErrorUnion`).
|
|
324
|
+
By default, types are wrapped in nested TS namespaces (`Scope.Route.Params`), JSDoc comments are emitted, and output is self-contained (no runtime dependency on `ts-procedures`). Use `--no-namespace-types` to revert to flat type names (`RouteParams`); this also disables the outer service namespace in `index.ts` and skips importing `_errors` from there.
|
|
325
325
|
Note: ajsc formatting options (`--enum-style enum`, `--depluralize`, etc.) only take effect in namespace mode (the default). They are ignored with `--no-namespace-types`.
|
|
326
326
|
Supports config file: `ts-procedures-codegen.config.json` (auto-loaded from CWD) or `--config <path>`.
|
|
327
327
|
|
|
@@ -329,12 +329,13 @@ Supports config file: `ts-procedures-codegen.config.json` (auto-loaded from CWD)
|
|
|
329
329
|
|
|
330
330
|
```typescript
|
|
331
331
|
import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
332
|
-
import {
|
|
332
|
+
import { createApiBindings, Api } from './generated/api'
|
|
333
|
+
// With --service-name <Name>: import { create<Name>Bindings, <Name> } from './generated/api'
|
|
333
334
|
|
|
334
335
|
const client = createClient({
|
|
335
336
|
adapter: createFetchAdapter(),
|
|
336
337
|
basePath: 'http://localhost:3000',
|
|
337
|
-
scopes:
|
|
338
|
+
scopes: createApiBindings,
|
|
338
339
|
hooks: {
|
|
339
340
|
onBeforeRequest(ctx) {
|
|
340
341
|
ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
|
|
@@ -346,7 +347,7 @@ const client = createClient({
|
|
|
346
347
|
},
|
|
347
348
|
})
|
|
348
349
|
|
|
349
|
-
// Fully typed — params and response inferred from server schemas
|
|
350
|
+
// Fully typed — params and response inferred from server schemas; type aliases live under Api.<Scope>.<Route>.
|
|
350
351
|
const user = await client.users.GetUser({ pathParams: { id: '123' } })
|
|
351
352
|
|
|
352
353
|
// Per-call hook override
|
|
@@ -320,8 +320,8 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
320
320
|
# --config ./codegen.config.json --service-name Auth
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
-
Generates one `.ts` file per scope plus a root `index.ts`
|
|
324
|
-
By default, types are wrapped in nested TS namespaces (`Scope.Route.Params`), JSDoc comments are emitted, and output is self-contained (no runtime dependency on `ts-procedures`). Use `--no-namespace-types` to revert to flat type names (`RouteParams`).
|
|
323
|
+
Generates one `.ts` file per scope plus a root `index.ts` that imports each scope as a namespace and exports a `create${ServiceName}Bindings` factory (defaults to `createApiBindings`; pass `--service-name <Name>` to rename). When namespace mode is on (the default), `index.ts` also wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block so types are reachable as `Api.Users.GetUser.Params`, `Api.Errors.ProcedureError`, etc. The errors file (`_errors.ts`) emits `${ServiceName}Errors` and `${ServiceName}ProcedureErrorUnion` (defaults: `ApiErrors`, `ApiProcedureErrorUnion`).
|
|
324
|
+
By default, types are wrapped in nested TS namespaces (`Scope.Route.Params`), JSDoc comments are emitted, and output is self-contained (no runtime dependency on `ts-procedures`). Use `--no-namespace-types` to revert to flat type names (`RouteParams`); this also disables the outer service namespace in `index.ts` and skips importing `_errors` from there.
|
|
325
325
|
Note: ajsc formatting options (`--enum-style enum`, `--depluralize`, etc.) only take effect in namespace mode (the default). They are ignored with `--no-namespace-types`.
|
|
326
326
|
Supports config file: `ts-procedures-codegen.config.json` (auto-loaded from CWD) or `--config <path>`.
|
|
327
327
|
|
|
@@ -329,12 +329,13 @@ Supports config file: `ts-procedures-codegen.config.json` (auto-loaded from CWD)
|
|
|
329
329
|
|
|
330
330
|
```typescript
|
|
331
331
|
import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
332
|
-
import {
|
|
332
|
+
import { createApiBindings, Api } from './generated/api'
|
|
333
|
+
// With --service-name <Name>: import { create<Name>Bindings, <Name> } from './generated/api'
|
|
333
334
|
|
|
334
335
|
const client = createClient({
|
|
335
336
|
adapter: createFetchAdapter(),
|
|
336
337
|
basePath: 'http://localhost:3000',
|
|
337
|
-
scopes:
|
|
338
|
+
scopes: createApiBindings,
|
|
338
339
|
hooks: {
|
|
339
340
|
onBeforeRequest(ctx) {
|
|
340
341
|
ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
|
|
@@ -346,7 +347,7 @@ const client = createClient({
|
|
|
346
347
|
},
|
|
347
348
|
})
|
|
348
349
|
|
|
349
|
-
// Fully typed — params and response inferred from server schemas
|
|
350
|
+
// Fully typed — params and response inferred from server schemas; type aliases live under Api.<Scope>.<Route>.
|
|
350
351
|
const user = await client.users.GetUser({ pathParams: { id: '123' } })
|
|
351
352
|
|
|
352
353
|
// Per-call hook override
|
|
@@ -1,109 +1,57 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cpSync, mkdirSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = dirname(__filename);
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return `<!-- Auto-generated by ts-procedures@${version}. Updated on npm install/update. Do not edit. -->\n\n`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function stripFrontmatter(content) {
|
|
25
|
-
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
|
26
|
-
return match ? match[1].trim() : content.trim();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function ensureDir(dir) {
|
|
30
|
-
if (!existsSync(dir)) {
|
|
31
|
-
mkdirSync(dir, { recursive: true });
|
|
7
|
+
const SOURCE_DIR = join(__dirname, '..', 'claude-code');
|
|
8
|
+
|
|
9
|
+
const SKILL_NAMES = ['ts-procedures', 'ts-procedures-review', 'ts-procedures-scaffold'];
|
|
10
|
+
const AGENT_FILES = ['ts-procedures-architect.md'];
|
|
11
|
+
|
|
12
|
+
function listFilesRecursive(dir) {
|
|
13
|
+
const out = [];
|
|
14
|
+
for (const entry of readdirSync(dir)) {
|
|
15
|
+
const full = join(dir, entry);
|
|
16
|
+
if (statSync(full).isDirectory()) {
|
|
17
|
+
for (const nested of listFilesRecursive(full)) out.push(join(entry, nested));
|
|
18
|
+
} else {
|
|
19
|
+
out.push(entry);
|
|
20
|
+
}
|
|
32
21
|
}
|
|
22
|
+
return out;
|
|
33
23
|
}
|
|
34
24
|
|
|
35
25
|
/**
|
|
36
26
|
* Install Claude Code integration files into a project's .claude/ directory.
|
|
37
27
|
*
|
|
38
28
|
* Creates:
|
|
39
|
-
* .claude/
|
|
40
|
-
* .claude/
|
|
41
|
-
* .claude/
|
|
42
|
-
* .claude/agents/ts-procedures-architect.md
|
|
29
|
+
* .claude/skills/ts-procedures/ — Framework reference skill
|
|
30
|
+
* .claude/skills/ts-procedures-scaffold/ — Scaffold skill (templates included)
|
|
31
|
+
* .claude/skills/ts-procedures-review/ — Review skill
|
|
32
|
+
* .claude/agents/ts-procedures-architect.md — Architecture planning agent
|
|
43
33
|
*
|
|
44
34
|
* @param {string} projectRoot — Absolute path to the consuming project's root
|
|
45
35
|
* @returns {{ files: string[] }} — List of created/updated file paths (relative to projectRoot)
|
|
46
36
|
*/
|
|
47
37
|
export function installClaude(projectRoot) {
|
|
48
38
|
const claudeDir = join(projectRoot, '.claude');
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
39
|
+
const skillsDest = join(claudeDir, 'skills');
|
|
40
|
+
const agentsDest = join(claudeDir, 'agents');
|
|
41
|
+
mkdirSync(skillsDest, { recursive: true });
|
|
42
|
+
mkdirSync(agentsDest, { recursive: true });
|
|
52
43
|
|
|
53
|
-
ensureDir(rulesDir);
|
|
54
|
-
ensureDir(commandsDir);
|
|
55
|
-
ensureDir(agentsDir);
|
|
56
|
-
|
|
57
|
-
const autoHeader = makeAutoHeader();
|
|
58
44
|
const files = [];
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
writeFileSync(join(rulesDir, 'ts-procedures.md'), autoHeader + guideBody, 'utf-8');
|
|
72
|
-
files.push('.claude/rules/ts-procedures.md');
|
|
73
|
-
|
|
74
|
-
// 2. Scaffold command
|
|
75
|
-
const scaffoldSkill = readFileSync(join(SKILLS_DIR, 'scaffold', 'SKILL.md'), 'utf-8');
|
|
76
|
-
const scaffoldBasePath = 'node_modules/ts-procedures/agent_config/claude-code/skills/scaffold';
|
|
77
|
-
const scaffoldBody = stripFrontmatter(scaffoldSkill)
|
|
78
|
-
// Replace ${CLAUDE_SKILL_DIR} template path with node_modules path
|
|
79
|
-
.replace(
|
|
80
|
-
'`${CLAUDE_SKILL_DIR}/templates/$0.md`',
|
|
81
|
-
`\`${scaffoldBasePath}/templates/$0.md\``
|
|
82
|
-
)
|
|
83
|
-
// Replace Workflow section — skill cross-references don't apply outside the plugin
|
|
84
|
-
.replace(/\n## Workflow[\s\S]*$/, '');
|
|
85
|
-
|
|
86
|
-
writeFileSync(join(commandsDir, 'ts-procedures-scaffold.md'), autoHeader + scaffoldBody, 'utf-8');
|
|
87
|
-
files.push('.claude/commands/ts-procedures-scaffold.md');
|
|
88
|
-
|
|
89
|
-
// 3. Review command
|
|
90
|
-
const reviewSkill = readFileSync(join(SKILLS_DIR, 'review', 'SKILL.md'), 'utf-8');
|
|
91
|
-
const reviewBasePath = 'node_modules/ts-procedures/agent_config/claude-code/skills/review';
|
|
92
|
-
const reviewBody = stripFrontmatter(reviewSkill)
|
|
93
|
-
// Replace relative markdown links with node_modules paths
|
|
94
|
-
.replace(/\[checklist\.md\]\(checklist\.md\)/g, `\`${reviewBasePath}/checklist.md\``)
|
|
95
|
-
.replace(
|
|
96
|
-
/\[anti-patterns\.md\]\(\.\.\/guide\/anti-patterns\.md\)/g,
|
|
97
|
-
`\`${guideBasePath}/anti-patterns.md\``
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
writeFileSync(join(commandsDir, 'ts-procedures-review.md'), autoHeader + reviewBody, 'utf-8');
|
|
101
|
-
files.push('.claude/commands/ts-procedures-review.md');
|
|
102
|
-
|
|
103
|
-
// 4. Architect agent
|
|
104
|
-
const architectAgent = readFileSync(join(AGENTS_DIR, 'ts-procedures-architect.md'), 'utf-8');
|
|
105
|
-
writeFileSync(join(agentsDir, 'ts-procedures-architect.md'), autoHeader + architectAgent, 'utf-8');
|
|
106
|
-
files.push('.claude/agents/ts-procedures-architect.md');
|
|
107
|
-
|
|
45
|
+
for (const skill of SKILL_NAMES) {
|
|
46
|
+
const src = join(SOURCE_DIR, 'skills', skill);
|
|
47
|
+
cpSync(src, join(skillsDest, skill), { recursive: true, force: true });
|
|
48
|
+
for (const rel of listFilesRecursive(src)) {
|
|
49
|
+
files.push(`.claude/skills/${skill}/${rel}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const agent of AGENT_FILES) {
|
|
53
|
+
cpSync(join(SOURCE_DIR, 'agents', agent), join(agentsDest, agent), { force: true });
|
|
54
|
+
files.push(`.claude/agents/${agent}`);
|
|
55
|
+
}
|
|
108
56
|
return { files };
|
|
109
57
|
}
|
|
@@ -239,35 +239,35 @@ describe('E2E: generateClient full pipeline', () => {
|
|
|
239
239
|
expect(yieldTypeBody).not.toContain('retry');
|
|
240
240
|
});
|
|
241
241
|
// ── index.ts ───────────────────────────────────────────────────────────────
|
|
242
|
-
it('index.ts contains
|
|
242
|
+
it('index.ts contains the default Api bindings factory', async () => {
|
|
243
243
|
tmpDir = makeTmpDir();
|
|
244
244
|
await generateClient({ envelope, outDir: tmpDir });
|
|
245
245
|
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
246
|
-
expect(content).toContain('
|
|
246
|
+
expect(content).toContain('createApiBindings');
|
|
247
247
|
});
|
|
248
|
-
it('index.ts
|
|
248
|
+
it('index.ts imports the users scope as a namespace', async () => {
|
|
249
249
|
tmpDir = makeTmpDir();
|
|
250
250
|
await generateClient({ envelope, outDir: tmpDir });
|
|
251
251
|
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
252
|
-
expect(content).toContain("from './users'");
|
|
252
|
+
expect(content).toContain("import * as users from './users'");
|
|
253
253
|
});
|
|
254
|
-
it('index.ts
|
|
254
|
+
it('index.ts imports the events scope as a namespace', async () => {
|
|
255
255
|
tmpDir = makeTmpDir();
|
|
256
256
|
await generateClient({ envelope, outDir: tmpDir });
|
|
257
257
|
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
258
|
-
expect(content).toContain("from './events'");
|
|
258
|
+
expect(content).toContain("import * as events from './events'");
|
|
259
259
|
});
|
|
260
|
-
it('index.ts
|
|
260
|
+
it('index.ts uses bindUsersScope through the namespace', async () => {
|
|
261
261
|
tmpDir = makeTmpDir();
|
|
262
262
|
await generateClient({ envelope, outDir: tmpDir });
|
|
263
263
|
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
264
|
-
expect(content).toContain('bindUsersScope');
|
|
264
|
+
expect(content).toContain('users.bindUsersScope(client)');
|
|
265
265
|
});
|
|
266
|
-
it('index.ts
|
|
266
|
+
it('index.ts uses bindEventsScope through the namespace', async () => {
|
|
267
267
|
tmpDir = makeTmpDir();
|
|
268
268
|
await generateClient({ envelope, outDir: tmpDir });
|
|
269
269
|
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
270
|
-
expect(content).toContain('bindEventsScope');
|
|
270
|
+
expect(content).toContain('events.bindEventsScope(client)');
|
|
271
271
|
});
|
|
272
272
|
// ── _errors.ts ─────────────────────────────────────────────────────────────
|
|
273
273
|
it('_errors.ts file exists when envelope has errors with schemas', async () => {
|
|
@@ -281,19 +281,26 @@ describe('E2E: generateClient full pipeline', () => {
|
|
|
281
281
|
const content = readFileSync(join(tmpDir, '_errors.ts'), 'utf-8');
|
|
282
282
|
expect(content).toContain('export type ProcedureError =');
|
|
283
283
|
});
|
|
284
|
-
it('_errors.ts contains ProcedureErrorUnion', async () => {
|
|
284
|
+
it('_errors.ts contains the service-prefixed ProcedureErrorUnion', async () => {
|
|
285
285
|
tmpDir = makeTmpDir();
|
|
286
286
|
await generateClient({ envelope, outDir: tmpDir });
|
|
287
287
|
const content = readFileSync(join(tmpDir, '_errors.ts'), 'utf-8');
|
|
288
|
-
expect(content).toContain('export type
|
|
288
|
+
expect(content).toContain('export type ApiProcedureErrorUnion =');
|
|
289
289
|
expect(content).toContain('ProcedureError');
|
|
290
290
|
expect(content).toContain('ProcedureValidationError');
|
|
291
291
|
});
|
|
292
|
-
it('index.ts
|
|
292
|
+
it('index.ts does not import _errors when namespaceTypes is off', async () => {
|
|
293
293
|
tmpDir = makeTmpDir();
|
|
294
294
|
await generateClient({ envelope, outDir: tmpDir });
|
|
295
295
|
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
296
|
-
expect(content).toContain("
|
|
296
|
+
expect(content).not.toContain("from './_errors'");
|
|
297
|
+
});
|
|
298
|
+
it('index.ts folds errors into the service namespace when namespaceTypes is on', async () => {
|
|
299
|
+
tmpDir = makeTmpDir();
|
|
300
|
+
await generateClient({ envelope, outDir: tmpDir, namespaceTypes: true });
|
|
301
|
+
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
302
|
+
expect(content).toContain("import * as _errorsModule from './_errors'");
|
|
303
|
+
expect(content).toContain('export import Errors = _errorsModule.ApiErrors');
|
|
297
304
|
});
|
|
298
305
|
it('_errors.ts is not generated when no errors have schemas', async () => {
|
|
299
306
|
tmpDir = makeTmpDir();
|