ts-procedures 5.5.0 → 5.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -0
- package/agent_config/claude-code/skills/guide/api-reference.md +177 -0
- package/agent_config/claude-code/skills/guide/patterns.md +107 -0
- package/agent_config/copilot/copilot-instructions.md +80 -0
- package/agent_config/cursor/cursorrules +80 -0
- package/build/client/call.d.ts +14 -0
- package/build/client/call.js +47 -0
- package/build/client/call.js.map +1 -0
- package/build/client/call.test.d.ts +1 -0
- package/build/client/call.test.js +124 -0
- package/build/client/call.test.js.map +1 -0
- package/build/client/errors.d.ts +25 -0
- package/build/client/errors.js +33 -0
- package/build/client/errors.js.map +1 -0
- package/build/client/errors.test.d.ts +1 -0
- package/build/client/errors.test.js +41 -0
- package/build/client/errors.test.js.map +1 -0
- package/build/client/fetch-adapter.d.ts +12 -0
- package/build/client/fetch-adapter.js +156 -0
- package/build/client/fetch-adapter.js.map +1 -0
- package/build/client/fetch-adapter.test.d.ts +1 -0
- package/build/client/fetch-adapter.test.js +271 -0
- package/build/client/fetch-adapter.test.js.map +1 -0
- package/build/client/hooks.d.ts +17 -0
- package/build/client/hooks.js +40 -0
- package/build/client/hooks.js.map +1 -0
- package/build/client/hooks.test.d.ts +1 -0
- package/build/client/hooks.test.js +163 -0
- package/build/client/hooks.test.js.map +1 -0
- package/build/client/index.d.ts +22 -0
- package/build/client/index.js +67 -0
- package/build/client/index.js.map +1 -0
- package/build/client/index.test.d.ts +1 -0
- package/build/client/index.test.js +231 -0
- package/build/client/index.test.js.map +1 -0
- package/build/client/request-builder.d.ts +13 -0
- package/build/client/request-builder.js +53 -0
- package/build/client/request-builder.js.map +1 -0
- package/build/client/request-builder.test.d.ts +1 -0
- package/build/client/request-builder.test.js +160 -0
- package/build/client/request-builder.test.js.map +1 -0
- package/build/client/stream.d.ts +27 -0
- package/build/client/stream.js +118 -0
- package/build/client/stream.js.map +1 -0
- package/build/client/stream.test.d.ts +1 -0
- package/build/client/stream.test.js +228 -0
- package/build/client/stream.test.js.map +1 -0
- package/build/client/types.d.ts +78 -0
- package/build/client/types.js +3 -0
- package/build/client/types.js.map +1 -0
- package/build/codegen/bin/cli.d.ts +17 -0
- package/build/codegen/bin/cli.js +149 -0
- package/build/codegen/bin/cli.js.map +1 -0
- package/build/codegen/bin/cli.test.d.ts +1 -0
- package/build/codegen/bin/cli.test.js +83 -0
- package/build/codegen/bin/cli.test.js.map +1 -0
- package/build/codegen/e2e.test.d.ts +1 -0
- package/build/codegen/e2e.test.js +321 -0
- package/build/codegen/e2e.test.js.map +1 -0
- package/build/codegen/emit-errors.d.ts +9 -0
- package/build/codegen/emit-errors.js +30 -0
- package/build/codegen/emit-errors.js.map +1 -0
- package/build/codegen/emit-errors.test.d.ts +1 -0
- package/build/codegen/emit-errors.test.js +110 -0
- package/build/codegen/emit-errors.test.js.map +1 -0
- package/build/codegen/emit-index.d.ts +6 -0
- package/build/codegen/emit-index.js +49 -0
- package/build/codegen/emit-index.js.map +1 -0
- package/build/codegen/emit-index.test.d.ts +1 -0
- package/build/codegen/emit-index.test.js +83 -0
- package/build/codegen/emit-index.test.js.map +1 -0
- package/build/codegen/emit-scope.d.ts +6 -0
- package/build/codegen/emit-scope.js +194 -0
- package/build/codegen/emit-scope.js.map +1 -0
- package/build/codegen/emit-scope.test.d.ts +1 -0
- package/build/codegen/emit-scope.test.js +276 -0
- package/build/codegen/emit-scope.test.js.map +1 -0
- package/build/codegen/emit-types.d.ts +14 -0
- package/build/codegen/emit-types.js +40 -0
- package/build/codegen/emit-types.js.map +1 -0
- package/build/codegen/emit-types.test.d.ts +1 -0
- package/build/codegen/emit-types.test.js +82 -0
- package/build/codegen/emit-types.test.js.map +1 -0
- package/build/codegen/group-routes.d.ts +23 -0
- package/build/codegen/group-routes.js +46 -0
- package/build/codegen/group-routes.js.map +1 -0
- package/build/codegen/group-routes.test.d.ts +1 -0
- package/build/codegen/group-routes.test.js +131 -0
- package/build/codegen/group-routes.test.js.map +1 -0
- package/build/codegen/index.d.ts +11 -0
- package/build/codegen/index.js +13 -0
- package/build/codegen/index.js.map +1 -0
- package/build/codegen/pipeline.d.ts +14 -0
- package/build/codegen/pipeline.js +49 -0
- package/build/codegen/pipeline.js.map +1 -0
- package/build/codegen/pipeline.test.d.ts +1 -0
- package/build/codegen/pipeline.test.js +151 -0
- package/build/codegen/pipeline.test.js.map +1 -0
- package/build/codegen/resolve-envelope.d.ts +7 -0
- package/build/codegen/resolve-envelope.js +26 -0
- package/build/codegen/resolve-envelope.js.map +1 -0
- package/build/codegen/resolve-envelope.test.d.ts +1 -0
- package/build/codegen/resolve-envelope.test.js +69 -0
- package/build/codegen/resolve-envelope.test.js.map +1 -0
- package/build/implementations/http/doc-registry.test.js +27 -1
- package/build/implementations/http/doc-registry.test.js.map +1 -1
- package/build/implementations/http/express-rpc/index.js +1 -0
- package/build/implementations/http/express-rpc/index.js.map +1 -1
- package/build/implementations/http/express-rpc/index.test.js +1 -1
- package/build/implementations/http/express-rpc/index.test.js.map +1 -1
- package/build/implementations/http/hono-api/index.js +2 -0
- package/build/implementations/http/hono-api/index.js.map +1 -1
- package/build/implementations/http/hono-api/index.test.js +9 -0
- package/build/implementations/http/hono-api/index.test.js.map +1 -1
- package/build/implementations/http/hono-rpc/index.js +1 -0
- package/build/implementations/http/hono-rpc/index.js.map +1 -1
- package/build/implementations/http/hono-rpc/index.test.js +1 -1
- package/build/implementations/http/hono-rpc/index.test.js.map +1 -1
- package/build/implementations/http/hono-stream/index.js +17 -1
- package/build/implementations/http/hono-stream/index.js.map +1 -1
- package/build/implementations/http/hono-stream/index.test.js +61 -0
- package/build/implementations/http/hono-stream/index.test.js.map +1 -1
- package/build/implementations/http/hono-stream/types.d.ts +4 -13
- package/build/implementations/types.d.ts +5 -0
- package/build/index.js +8 -1
- package/build/index.js.map +1 -1
- package/package.json +12 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
let ajscValidated = false;
|
|
2
|
+
async function validateAjscFormat() {
|
|
3
|
+
if (ajscValidated)
|
|
4
|
+
return;
|
|
5
|
+
ajscValidated = true;
|
|
6
|
+
const { TypescriptConverter } = await import('ajsc');
|
|
7
|
+
const probe = new TypescriptConverter({ type: 'string' }, { inlineTypes: true });
|
|
8
|
+
const probeCode = probe.code.trim();
|
|
9
|
+
if (probeCode !== 'string') {
|
|
10
|
+
console.warn(`[ts-procedures-codegen] ajsc output format may have changed. Expected "string" for { type: "string" }, got: "${probeCode}"`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Converts a JSON Schema to a TypeScript type string using ajsc.
|
|
15
|
+
*
|
|
16
|
+
* Returns `export type ${typeName} = ${code}` where code is the inline type
|
|
17
|
+
* body from TypescriptConverter with inlineTypes: true.
|
|
18
|
+
*
|
|
19
|
+
* Returns undefined for undefined or null schema.
|
|
20
|
+
*/
|
|
21
|
+
export async function jsonSchemaToTypeString(typeName, schema, options) {
|
|
22
|
+
if (schema == null)
|
|
23
|
+
return undefined;
|
|
24
|
+
await validateAjscFormat();
|
|
25
|
+
const { TypescriptConverter } = await import('ajsc');
|
|
26
|
+
const converter = new TypescriptConverter(schema, {
|
|
27
|
+
...options,
|
|
28
|
+
inlineTypes: true,
|
|
29
|
+
});
|
|
30
|
+
let code = converter.code.trim();
|
|
31
|
+
if (!code) {
|
|
32
|
+
throw new Error(`[ts-procedures-codegen] ajsc produced empty output for type "${typeName}". Schema: ${JSON.stringify(schema)}`);
|
|
33
|
+
}
|
|
34
|
+
// Strip any 'export type X = ' or 'type X = ' prefix ajsc might add
|
|
35
|
+
code = code.replace(/^(?:export\s+)?type\s+\w+\s*=\s*/, '');
|
|
36
|
+
// Remove trailing semicolons and newlines
|
|
37
|
+
code = code.replace(/;\s*$/, '').trim();
|
|
38
|
+
return `export type ${typeName} = ${code}`;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=emit-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-types.js","sourceRoot":"","sources":["../../src/codegen/emit-types.ts"],"names":[],"mappings":"AAMA,IAAI,aAAa,GAAG,KAAK,CAAA;AACzB,KAAK,UAAU,kBAAkB;IAC/B,IAAI,aAAa;QAAE,OAAM;IACzB,aAAa,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAA;IACpD,MAAM,KAAK,GAAG,IAAI,mBAAmB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;IAChF,MAAM,SAAS,GAAI,KAAK,CAAC,IAAe,CAAC,IAAI,EAAE,CAAA;IAC/C,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,gHAAgH,SAAS,GAAG,CAAC,CAAA;IAC5I,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,QAAgB,EAChB,MAA2C,EAC3C,OAAqB;IAErB,IAAI,MAAM,IAAI,IAAI;QAAE,OAAO,SAAS,CAAA;IAEpC,MAAM,kBAAkB,EAAE,CAAA;IAE1B,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAA;IAEpD,MAAM,SAAS,GAAG,IAAI,mBAAmB,CAAC,MAAiC,EAAE;QAC3E,GAAG,OAAO;QACV,WAAW,EAAE,IAAI;KAClB,CAAC,CAAA;IAEF,IAAI,IAAI,GAAI,SAAS,CAAC,IAAe,CAAC,IAAI,EAAE,CAAA;IAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,gEAAgE,QAAQ,cAAc,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAC/G,CAAA;IACH,CAAC;IACD,oEAAoE;IACpE,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAA;IAC3D,0CAA0C;IAC1C,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAEvC,OAAO,eAAe,QAAQ,MAAM,IAAI,EAAE,CAAA;AAC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { jsonSchemaToTypeString } from './emit-types.js';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Tests
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
describe('jsonSchemaToTypeString', () => {
|
|
7
|
+
it('converts a simple object schema with required fields', async () => {
|
|
8
|
+
const schema = {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
id: { type: 'string' },
|
|
12
|
+
},
|
|
13
|
+
required: ['id'],
|
|
14
|
+
};
|
|
15
|
+
const result = await jsonSchemaToTypeString('MyType', schema);
|
|
16
|
+
expect(result).toBe('export type MyType = { id: string; }');
|
|
17
|
+
});
|
|
18
|
+
it('includes optional marker for non-required fields', async () => {
|
|
19
|
+
const schema = {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
id: { type: 'string' },
|
|
23
|
+
name: { type: 'string' },
|
|
24
|
+
},
|
|
25
|
+
required: ['id'],
|
|
26
|
+
};
|
|
27
|
+
const result = await jsonSchemaToTypeString('User', schema);
|
|
28
|
+
expect(result).toBe('export type User = { id: string; name?: string; }');
|
|
29
|
+
});
|
|
30
|
+
it('converts a string enum schema', async () => {
|
|
31
|
+
const schema = {
|
|
32
|
+
type: 'string',
|
|
33
|
+
enum: ['a', 'b'],
|
|
34
|
+
};
|
|
35
|
+
const result = await jsonSchemaToTypeString('Status', schema);
|
|
36
|
+
expect(result).toBe('export type Status = "a" | "b"');
|
|
37
|
+
});
|
|
38
|
+
it('converts a plain string schema', async () => {
|
|
39
|
+
const schema = { type: 'string' };
|
|
40
|
+
const result = await jsonSchemaToTypeString('Id', schema);
|
|
41
|
+
expect(result).toBe('export type Id = string');
|
|
42
|
+
});
|
|
43
|
+
it('returns undefined for undefined schema', async () => {
|
|
44
|
+
const result = await jsonSchemaToTypeString('Missing', undefined);
|
|
45
|
+
expect(result).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
it('uses the typeName in the export statement', async () => {
|
|
48
|
+
const schema = { type: 'number' };
|
|
49
|
+
const result = await jsonSchemaToTypeString('Count', schema);
|
|
50
|
+
expect(result).toMatch(/^export type Count = /);
|
|
51
|
+
});
|
|
52
|
+
it('handles already-clean inline output', async () => {
|
|
53
|
+
// Existing schemas still work — no regression
|
|
54
|
+
const schema = {
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: { id: { type: 'string' } },
|
|
57
|
+
required: ['id'],
|
|
58
|
+
};
|
|
59
|
+
const result = await jsonSchemaToTypeString('MyType', schema);
|
|
60
|
+
expect(result).toBe('export type MyType = { id: string; }');
|
|
61
|
+
});
|
|
62
|
+
it('strips "export type Root = " prefix and does not double-wrap', async () => {
|
|
63
|
+
vi.resetModules();
|
|
64
|
+
vi.doMock('ajsc', () => ({
|
|
65
|
+
TypescriptConverter: class {
|
|
66
|
+
code;
|
|
67
|
+
constructor(_schema, _opts) {
|
|
68
|
+
this.code = '\n\nexport type Root = { id: string; };\n';
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
}));
|
|
72
|
+
const { jsonSchemaToTypeString: fn } = await import('./emit-types.js');
|
|
73
|
+
const result = await fn('MyType', { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] });
|
|
74
|
+
// Should be the clean body, not double-wrapped
|
|
75
|
+
expect(result).toBe('export type MyType = { id: string; }');
|
|
76
|
+
expect(result).not.toContain('export type Root');
|
|
77
|
+
expect(result).not.toContain('export type MyType = export type');
|
|
78
|
+
vi.doUnmock('ajsc');
|
|
79
|
+
vi.resetModules();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=emit-types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-types.test.js","sourceRoot":"","sources":["../../src/codegen/emit-types.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnyHttpRouteDoc } from '../implementations/types.js';
|
|
2
|
+
export interface ScopeGroup {
|
|
3
|
+
scopeKey: string;
|
|
4
|
+
camelCase: string;
|
|
5
|
+
routes: AnyHttpRouteDoc[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes a scope value to a string key:
|
|
9
|
+
* - string → returned as-is
|
|
10
|
+
* - string[] → joined with '-'
|
|
11
|
+
* - undefined → 'default'
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeScope(scope: string | string[] | undefined): string;
|
|
14
|
+
/**
|
|
15
|
+
* Converts a hyphenated scope key to camelCase.
|
|
16
|
+
* e.g. 'admin-users' → 'adminUsers', 'users' → 'users'
|
|
17
|
+
*/
|
|
18
|
+
export declare function scopeToCamelCase(scope: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Groups an array of route docs into a Map keyed by normalized scope.
|
|
21
|
+
* Routes without a scope emit a console.warn and are grouped under 'default'.
|
|
22
|
+
*/
|
|
23
|
+
export declare function groupRoutesByScope(routes: AnyHttpRouteDoc[]): Map<string, ScopeGroup>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a scope value to a string key:
|
|
3
|
+
* - string → returned as-is
|
|
4
|
+
* - string[] → joined with '-'
|
|
5
|
+
* - undefined → 'default'
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeScope(scope) {
|
|
8
|
+
if (scope === undefined)
|
|
9
|
+
return 'default';
|
|
10
|
+
if (Array.isArray(scope))
|
|
11
|
+
return scope.join('-');
|
|
12
|
+
return scope;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Converts a hyphenated scope key to camelCase.
|
|
16
|
+
* e.g. 'admin-users' → 'adminUsers', 'users' → 'users'
|
|
17
|
+
*/
|
|
18
|
+
export function scopeToCamelCase(scope) {
|
|
19
|
+
const parts = scope.split('-');
|
|
20
|
+
return parts
|
|
21
|
+
.map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1))
|
|
22
|
+
.join('');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Groups an array of route docs into a Map keyed by normalized scope.
|
|
26
|
+
* Routes without a scope emit a console.warn and are grouped under 'default'.
|
|
27
|
+
*/
|
|
28
|
+
export function groupRoutesByScope(routes) {
|
|
29
|
+
const groups = new Map();
|
|
30
|
+
for (const route of routes) {
|
|
31
|
+
const rawScope = 'scope' in route ? route.scope : undefined;
|
|
32
|
+
if (rawScope === undefined) {
|
|
33
|
+
console.warn(`[ts-procedures] Route "${route.name}" has no scope — it will be grouped under "default".`);
|
|
34
|
+
}
|
|
35
|
+
const scopeKey = normalizeScope(rawScope);
|
|
36
|
+
const camelCase = scopeToCamelCase(scopeKey);
|
|
37
|
+
let group = groups.get(scopeKey);
|
|
38
|
+
if (group === undefined) {
|
|
39
|
+
group = { scopeKey, camelCase, routes: [] };
|
|
40
|
+
groups.set(scopeKey, group);
|
|
41
|
+
}
|
|
42
|
+
group.routes.push(route);
|
|
43
|
+
}
|
|
44
|
+
return groups;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=group-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-routes.js","sourceRoot":"","sources":["../../src/codegen/group-routes.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAoC;IACjE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAChD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC9B,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACnB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAClE;SACA,IAAI,CAAC,EAAE,CAAC,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAyB;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAA;IAE5C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,CAAC,CAAC,CAAE,KAAuC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9F,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CACV,0BAA0B,KAAK,CAAC,IAAI,sDAAsD,CAC3F,CAAA;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;QACzC,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAE5C,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;YAC3C,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QAC7B,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { normalizeScope, scopeToCamelCase, groupRoutesByScope } from './group-routes.js';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Fixtures
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const rpcRouteUsers = {
|
|
7
|
+
kind: 'rpc',
|
|
8
|
+
name: 'GetUser',
|
|
9
|
+
path: '/users/1',
|
|
10
|
+
method: 'post',
|
|
11
|
+
scope: 'users',
|
|
12
|
+
version: 1,
|
|
13
|
+
jsonSchema: {},
|
|
14
|
+
};
|
|
15
|
+
const rpcRouteAdmin = {
|
|
16
|
+
kind: 'rpc',
|
|
17
|
+
name: 'DeleteUser',
|
|
18
|
+
path: '/admin-users/1',
|
|
19
|
+
method: 'post',
|
|
20
|
+
scope: ['admin', 'users'],
|
|
21
|
+
version: 1,
|
|
22
|
+
jsonSchema: {},
|
|
23
|
+
};
|
|
24
|
+
const rpcRouteUsers2 = {
|
|
25
|
+
kind: 'rpc',
|
|
26
|
+
name: 'ListUsers',
|
|
27
|
+
path: '/users/1',
|
|
28
|
+
method: 'post',
|
|
29
|
+
scope: 'users',
|
|
30
|
+
version: 1,
|
|
31
|
+
jsonSchema: {},
|
|
32
|
+
};
|
|
33
|
+
const apiRouteNoScope = {
|
|
34
|
+
kind: 'api',
|
|
35
|
+
name: 'HealthCheck',
|
|
36
|
+
path: '/health',
|
|
37
|
+
method: 'get',
|
|
38
|
+
fullPath: '/api/health',
|
|
39
|
+
jsonSchema: {},
|
|
40
|
+
};
|
|
41
|
+
const apiRouteWithScope = {
|
|
42
|
+
kind: 'api',
|
|
43
|
+
name: 'ListPosts',
|
|
44
|
+
path: '/posts',
|
|
45
|
+
method: 'get',
|
|
46
|
+
fullPath: '/api/posts',
|
|
47
|
+
scope: 'posts',
|
|
48
|
+
jsonSchema: {},
|
|
49
|
+
};
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// normalizeScope
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
describe('normalizeScope', () => {
|
|
54
|
+
it('returns a string scope as-is', () => {
|
|
55
|
+
expect(normalizeScope('users')).toBe('users');
|
|
56
|
+
});
|
|
57
|
+
it('joins a string array scope with hyphens', () => {
|
|
58
|
+
expect(normalizeScope(['admin', 'users'])).toBe('admin-users');
|
|
59
|
+
});
|
|
60
|
+
it('returns "default" for undefined scope', () => {
|
|
61
|
+
expect(normalizeScope(undefined)).toBe('default');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// scopeToCamelCase
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
describe('scopeToCamelCase', () => {
|
|
68
|
+
it('returns a single word as-is', () => {
|
|
69
|
+
expect(scopeToCamelCase('users')).toBe('users');
|
|
70
|
+
});
|
|
71
|
+
it('converts a hyphenated scope to camelCase', () => {
|
|
72
|
+
expect(scopeToCamelCase('admin-users')).toBe('adminUsers');
|
|
73
|
+
});
|
|
74
|
+
it('converts multi-segment hyphenated scope', () => {
|
|
75
|
+
expect(scopeToCamelCase('super-admin-users')).toBe('superAdminUsers');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// groupRoutesByScope
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
describe('groupRoutesByScope', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
84
|
+
});
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
vi.restoreAllMocks();
|
|
87
|
+
});
|
|
88
|
+
it('groups routes by their scope', () => {
|
|
89
|
+
const routes = [rpcRouteUsers, rpcRouteUsers2];
|
|
90
|
+
const groups = groupRoutesByScope(routes);
|
|
91
|
+
expect(groups.size).toBe(1);
|
|
92
|
+
expect(groups.has('users')).toBe(true);
|
|
93
|
+
const usersGroup = groups.get('users');
|
|
94
|
+
expect(usersGroup.scopeKey).toBe('users');
|
|
95
|
+
expect(usersGroup.camelCase).toBe('users');
|
|
96
|
+
expect(usersGroup.routes).toHaveLength(2);
|
|
97
|
+
});
|
|
98
|
+
it('handles array scopes by joining with hyphens', () => {
|
|
99
|
+
const routes = [rpcRouteAdmin];
|
|
100
|
+
const groups = groupRoutesByScope(routes);
|
|
101
|
+
expect(groups.has('admin-users')).toBe(true);
|
|
102
|
+
const group = groups.get('admin-users');
|
|
103
|
+
expect(group.scopeKey).toBe('admin-users');
|
|
104
|
+
expect(group.camelCase).toBe('adminUsers');
|
|
105
|
+
expect(group.routes).toHaveLength(1);
|
|
106
|
+
});
|
|
107
|
+
it('groups routes from multiple scopes', () => {
|
|
108
|
+
const routes = [rpcRouteUsers, rpcRouteAdmin, apiRouteWithScope];
|
|
109
|
+
const groups = groupRoutesByScope(routes);
|
|
110
|
+
expect(groups.size).toBe(3);
|
|
111
|
+
expect(groups.has('users')).toBe(true);
|
|
112
|
+
expect(groups.has('admin-users')).toBe(true);
|
|
113
|
+
expect(groups.has('posts')).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
it('warns on missing scope and groups into "default"', () => {
|
|
116
|
+
const routes = [apiRouteNoScope];
|
|
117
|
+
const groups = groupRoutesByScope(routes);
|
|
118
|
+
expect(console.warn).toHaveBeenCalled();
|
|
119
|
+
expect(groups.has('default')).toBe(true);
|
|
120
|
+
const defaultGroup = groups.get('default');
|
|
121
|
+
expect(defaultGroup.scopeKey).toBe('default');
|
|
122
|
+
expect(defaultGroup.camelCase).toBe('default');
|
|
123
|
+
expect(defaultGroup.routes).toHaveLength(1);
|
|
124
|
+
});
|
|
125
|
+
it('does not warn when all routes have scopes', () => {
|
|
126
|
+
const routes = [rpcRouteUsers, apiRouteWithScope];
|
|
127
|
+
groupRoutesByScope(routes);
|
|
128
|
+
expect(console.warn).not.toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=group-routes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-routes.test.js","sourceRoot":"","sources":["../../src/codegen/group-routes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ResolveInput } from './resolve-envelope.js';
|
|
2
|
+
import type { AjscOptions } from './emit-types.js';
|
|
3
|
+
export interface GenerateClientOptions extends ResolveInput {
|
|
4
|
+
outDir: string;
|
|
5
|
+
ajsc?: AjscOptions;
|
|
6
|
+
clientImportPath?: string;
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateClient(options: GenerateClientOptions): Promise<void>;
|
|
10
|
+
export type { AjscOptions } from './emit-types.js';
|
|
11
|
+
export type { ResolveInput } from './resolve-envelope.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { resolveEnvelope } from './resolve-envelope.js';
|
|
2
|
+
import { runPipeline } from './pipeline.js';
|
|
3
|
+
export async function generateClient(options) {
|
|
4
|
+
const envelope = await resolveEnvelope(options);
|
|
5
|
+
await runPipeline({
|
|
6
|
+
envelope,
|
|
7
|
+
outDir: options.outDir,
|
|
8
|
+
ajsc: options.ajsc,
|
|
9
|
+
clientImportPath: options.clientImportPath,
|
|
10
|
+
dryRun: options.dryRun,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codegen/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAqB,MAAM,uBAAuB,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAU3C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA8B;IACjE,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAA;IAC/C,MAAM,WAAW,CAAC;QAChB,QAAQ;QACR,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DocEnvelope } from '../implementations/types.js';
|
|
2
|
+
import type { AjscOptions } from './emit-types.js';
|
|
3
|
+
export interface PipelineOptions {
|
|
4
|
+
envelope: DocEnvelope;
|
|
5
|
+
outDir: string;
|
|
6
|
+
ajsc?: AjscOptions;
|
|
7
|
+
clientImportPath?: string;
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface GeneratedFile {
|
|
11
|
+
path: string;
|
|
12
|
+
code: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function runPipeline(options: PipelineOptions): Promise<GeneratedFile[]>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { groupRoutesByScope } from './group-routes.js';
|
|
5
|
+
import { emitScopeFile } from './emit-scope.js';
|
|
6
|
+
import { emitIndexFile } from './emit-index.js';
|
|
7
|
+
import { emitErrorsFile } from './emit-errors.js';
|
|
8
|
+
export async function runPipeline(options) {
|
|
9
|
+
const { envelope, outDir, ajsc: ajscOpts, clientImportPath, dryRun = false } = options;
|
|
10
|
+
const hash = createHash('md5').update(JSON.stringify(envelope)).digest('hex');
|
|
11
|
+
const hashComment = `// Source hash: ${hash}`;
|
|
12
|
+
const groups = groupRoutesByScope(envelope.routes);
|
|
13
|
+
const groupArray = Array.from(groups.values());
|
|
14
|
+
const files = [];
|
|
15
|
+
for (const group of groupArray) {
|
|
16
|
+
const rawCode = await emitScopeFile(group, ajscOpts, clientImportPath);
|
|
17
|
+
const lines = rawCode.split('\n');
|
|
18
|
+
lines.splice(1, 0, hashComment);
|
|
19
|
+
const code = lines.join('\n');
|
|
20
|
+
files.push({ path: join(outDir, `${group.scopeKey}.ts`), code });
|
|
21
|
+
}
|
|
22
|
+
const errorsCode = await emitErrorsFile(envelope.errors, ajscOpts, clientImportPath);
|
|
23
|
+
const hasErrors = errorsCode != null;
|
|
24
|
+
if (errorsCode != null) {
|
|
25
|
+
const errorsLines = errorsCode.split('\n');
|
|
26
|
+
errorsLines.splice(1, 0, hashComment);
|
|
27
|
+
const errorsWithHash = errorsLines.join('\n');
|
|
28
|
+
files.push({ path: join(outDir, '_errors.ts'), code: errorsWithHash });
|
|
29
|
+
}
|
|
30
|
+
const rawIndexCode = emitIndexFile(groupArray, clientImportPath, hasErrors);
|
|
31
|
+
const indexLines = rawIndexCode.split('\n');
|
|
32
|
+
indexLines.splice(1, 0, hashComment);
|
|
33
|
+
const indexCode = indexLines.join('\n');
|
|
34
|
+
files.push({ path: join(outDir, 'index.ts'), code: indexCode });
|
|
35
|
+
if (dryRun) {
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
const bytes = Buffer.byteLength(file.code, 'utf-8');
|
|
38
|
+
console.log(`[dry-run] Would write: ${file.path} (${bytes} bytes)`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
await mkdir(outDir, { recursive: true });
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
await writeFile(file.path, file.code, 'utf-8');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return files;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/codegen/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { generateClient } from './index.js';
|
|
3
|
+
import { runPipeline } from './pipeline.js';
|
|
4
|
+
import { mkdirSync, rmSync, readFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Fixtures
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const envelope = {
|
|
11
|
+
basePath: '/api',
|
|
12
|
+
headers: [],
|
|
13
|
+
errors: [],
|
|
14
|
+
routes: [
|
|
15
|
+
{
|
|
16
|
+
kind: 'rpc',
|
|
17
|
+
name: 'GetUser',
|
|
18
|
+
path: '/users/1',
|
|
19
|
+
method: 'post',
|
|
20
|
+
scope: 'users',
|
|
21
|
+
version: 1,
|
|
22
|
+
jsonSchema: {
|
|
23
|
+
body: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: { id: { type: 'string' } },
|
|
26
|
+
required: ['id'],
|
|
27
|
+
},
|
|
28
|
+
response: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: { name: { type: 'string' } },
|
|
31
|
+
required: ['name'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
kind: 'rpc',
|
|
37
|
+
name: 'CreateInvoice',
|
|
38
|
+
path: '/billing/1',
|
|
39
|
+
method: 'post',
|
|
40
|
+
scope: 'billing',
|
|
41
|
+
version: 1,
|
|
42
|
+
jsonSchema: {
|
|
43
|
+
body: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: { amount: { type: 'number' } },
|
|
46
|
+
required: ['amount'],
|
|
47
|
+
},
|
|
48
|
+
response: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: { invoiceId: { type: 'string' } },
|
|
51
|
+
required: ['invoiceId'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Helpers
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
function makeTmpDir() {
|
|
61
|
+
const dir = join(tmpdir(), `ts-proc-pipeline-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
62
|
+
mkdirSync(dir, { recursive: true });
|
|
63
|
+
return dir;
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Tests
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
describe('generateClient pipeline', () => {
|
|
69
|
+
let tmpDir;
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
if (tmpDir && existsSync(tmpDir)) {
|
|
72
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
it('creates scope file for each unique scope (users.ts, billing.ts)', async () => {
|
|
76
|
+
tmpDir = makeTmpDir();
|
|
77
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
78
|
+
expect(existsSync(join(tmpDir, 'users.ts'))).toBe(true);
|
|
79
|
+
expect(existsSync(join(tmpDir, 'billing.ts'))).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
it('creates index.ts', async () => {
|
|
82
|
+
tmpDir = makeTmpDir();
|
|
83
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
84
|
+
expect(existsSync(join(tmpDir, 'index.ts'))).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it('users.ts contains bindUsersScope function', async () => {
|
|
87
|
+
tmpDir = makeTmpDir();
|
|
88
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
89
|
+
const content = readFileSync(join(tmpDir, 'users.ts'), 'utf-8');
|
|
90
|
+
expect(content).toContain('bindUsersScope');
|
|
91
|
+
expect(content).toContain('GetUser');
|
|
92
|
+
});
|
|
93
|
+
it('billing.ts contains bindBillingScope function', async () => {
|
|
94
|
+
tmpDir = makeTmpDir();
|
|
95
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
96
|
+
const content = readFileSync(join(tmpDir, 'billing.ts'), 'utf-8');
|
|
97
|
+
expect(content).toContain('bindBillingScope');
|
|
98
|
+
expect(content).toContain('CreateInvoice');
|
|
99
|
+
});
|
|
100
|
+
it('index.ts exports from both scope files and has createScopeBindings', async () => {
|
|
101
|
+
tmpDir = makeTmpDir();
|
|
102
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
103
|
+
const content = readFileSync(join(tmpDir, 'index.ts'), 'utf-8');
|
|
104
|
+
expect(content).toContain("from './users'");
|
|
105
|
+
expect(content).toContain("from './billing'");
|
|
106
|
+
expect(content).toContain('createScopeBindings');
|
|
107
|
+
});
|
|
108
|
+
it('creates outDir if it does not exist', async () => {
|
|
109
|
+
tmpDir = makeTmpDir();
|
|
110
|
+
const nested = join(tmpDir, 'nested', 'output');
|
|
111
|
+
await generateClient({ envelope, outDir: nested });
|
|
112
|
+
expect(existsSync(join(nested, 'index.ts'))).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
it('all generated files have the auto-generated header comment', async () => {
|
|
115
|
+
tmpDir = makeTmpDir();
|
|
116
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
117
|
+
for (const file of ['users.ts', 'billing.ts', 'index.ts']) {
|
|
118
|
+
const content = readFileSync(join(tmpDir, file), 'utf-8');
|
|
119
|
+
expect(content).toContain('// Auto-generated by ts-procedures-codegen — do not edit');
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
it('generated files include source hash comment', async () => {
|
|
123
|
+
tmpDir = makeTmpDir();
|
|
124
|
+
await generateClient({ envelope, outDir: tmpDir });
|
|
125
|
+
for (const file of ['users.ts', 'billing.ts', 'index.ts']) {
|
|
126
|
+
const content = readFileSync(join(tmpDir, file), 'utf-8');
|
|
127
|
+
const lines = content.split('\n');
|
|
128
|
+
expect(lines[1]).toMatch(/^\/\/ Source hash: [a-f0-9]{32}$/);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
it('dry-run mode does not create files on disk', async () => {
|
|
132
|
+
tmpDir = makeTmpDir();
|
|
133
|
+
const dryDir = join(tmpDir, 'dry-output');
|
|
134
|
+
await runPipeline({ envelope, outDir: dryDir, dryRun: true });
|
|
135
|
+
expect(existsSync(dryDir)).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
it('dry-run mode returns generated file entries', async () => {
|
|
138
|
+
tmpDir = makeTmpDir();
|
|
139
|
+
const dryDir = join(tmpDir, 'dry-output');
|
|
140
|
+
const files = await runPipeline({ envelope, outDir: dryDir, dryRun: true });
|
|
141
|
+
expect(files.length).toBe(3); // users.ts, billing.ts, index.ts
|
|
142
|
+
const paths = files.map((f) => f.path);
|
|
143
|
+
expect(paths).toContain(join(dryDir, 'users.ts'));
|
|
144
|
+
expect(paths).toContain(join(dryDir, 'billing.ts'));
|
|
145
|
+
expect(paths).toContain(join(dryDir, 'index.ts'));
|
|
146
|
+
for (const file of files) {
|
|
147
|
+
expect(file.code).toContain('// Auto-generated by ts-procedures-codegen — do not edit');
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=pipeline.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.test.js","sourceRoot":"","sources":["../../src/codegen/pipeline.test.ts"],"names":[],"mappings":"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"}
|