@contractkit/plugin-typescript 0.28.2 → 0.29.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.
@@ -5,9 +5,9 @@ $ tsup src/index.ts --format esm --sourcemap --dts && tsc --emitDeclarationOnly
5
5
  CLI tsup v8.5.1
6
6
  CLI Target: esnext
7
7
  ESM Build start
8
- ESM dist/index.js 176.01 KB
9
- ESM dist/index.js.map 388.17 KB
10
- ESM ⚡️ Build success in 473ms
8
+ ESM dist/index.js 178.19 KB
9
+ ESM dist/index.js.map 395.78 KB
10
+ ESM ⚡️ Build success in 396ms
11
11
  DTS Build start
12
- DTS ⚡️ Build success in 5954ms
13
- DTS dist/index.d.ts 3.71 KB
12
+ DTS ⚡️ Build success in 6065ms
13
+ DTS dist/index.d.ts 4.55 KB
@@ -3,34 +3,34 @@ $ vitest run --coverage
3
3
   RUN  v4.1.5 /home/runner/work/ContractKit/ContractKit/packages/plugin-typescript
4
4
  Coverage enabled with v8
5
5
 
6
- ✓ tests/codegen-contract.test.ts (128 tests) 233ms
7
- ✓ tests/codegen-operation.test.ts (91 tests) 103ms
8
- ✓ tests/codegen-sdk.test.ts (140 tests) 276ms
9
- ✓ tests/codegen-plain-types.test.ts (61 tests) 42ms
10
- ✓ tests/codegen-server.test.ts (22 tests) 91ms
11
- ✓ tests/pipeline.test.ts (28 tests) 224ms
12
- ✓ tests/codegen-mcp.test.ts (24 tests) 98ms
13
- ✓ tests/escaping-security.test.ts (18 tests) 51ms
6
+ ✓ tests/codegen-contract.test.ts (128 tests) 221ms
7
+ ✓ tests/codegen-sdk.test.ts (140 tests) 252ms
8
+ ✓ tests/codegen-operation.test.ts (113 tests) 255ms
9
+ ✓ tests/codegen-server.test.ts (25 tests) 110ms
10
+ ✓ tests/codegen-plain-types.test.ts (66 tests) 35ms
11
+ ✓ tests/pipeline.test.ts (28 tests) 217ms
12
+ ✓ tests/escaping-security.test.ts (18 tests) 27ms
13
+ ✓ tests/codegen-mcp.test.ts (24 tests) 67ms
14
14
 
15
15
   Test Files  8 passed (8)
16
-  Tests  512 passed (512)
17
-  Start at  16:29:52
18
-  Duration  9.09s (transform 4.13s, setup 0ms, import 16.79s, tests 1.12s, environment 1ms)
16
+  Tests  542 passed (542)
17
+  Start at  12:07:42
18
+  Duration  9.60s (transform 5.83s, setup 0ms, import 18.92s, tests 1.18s, environment 1ms)
19
19
 
20
20
   % Coverage report from v8
21
21
  -------------------|---------|----------|---------|---------|-------------------
22
22
  File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
23
23
  -------------------|---------|----------|---------|---------|-------------------
24
- All files | 81.49 | 76.01 | 84.56 | 84.05 |
25
- src | 81.33 | 75.75 | 84.25 | 83.87 |
26
- ...n-contract.ts | 88.1 | 82.91 | 90.08 | 89.26 | ...1088,1093-1094
24
+ All files | 82.66 | 77.13 | 85.59 | 85.15 |
25
+ src | 82.52 | 76.89 | 85.35 | 85 |
26
+ ...n-contract.ts | 88.1 | 82.91 | 90.08 | 89.26 | ...1095,1100-1101
27
27
  codegen-mcp.ts | 82.67 | 75.47 | 84.61 | 85.9 | ...85,290-291,374
28
- ...-operation.ts | 78.46 | 74.7 | 78.94 | 79.9 | ...99-710,715-716
29
- ...lain-types.ts | 91.52 | 81.65 | 96.87 | 94.4 | ...23,143,249,255
28
+ ...-operation.ts | 80.12 | 77.35 | 79.22 | 81.36 | ...59-770,775-776
29
+ ...lain-types.ts | 91.57 | 81.98 | 96.87 | 94.44 | ...31,157,269,275
30
30
  codegen-sdk.ts | 88.37 | 83.2 | 87.83 | 91.48 | ...1187-1188,1191
31
- index.ts | 60.04 | 48.95 | 65.45 | 63.82 | ...1002,1018-1037
32
- path-utils.ts | 69.56 | 50 | 100 | 73.5 | ...65-168,216-231
33
- ts-render.ts | 84.21 | 86.66 | 75 | 89.23 | 68,141,172-180
31
+ index.ts | 66.25 | 53.64 | 72.72 | 70.29 | ...1022,1038-1057
32
+ path-utils.ts | 70.28 | 51.13 | 100 | 73.5 | ...65-168,216-231
33
+ ts-render.ts | 85 | 87.36 | 79.16 | 89.23 | 83,159,192-200
34
34
  tests | 90.38 | 90.9 | 89.28 | 93.47 |
35
35
  helpers.ts | 90.38 | 90.9 | 89.28 | 93.47 | 110-118
36
36
  -------------------|---------|----------|---------|---------|-------------------
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @contractkit/contractkit-plugin-typescript
2
2
 
3
+ ## 0.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 79e3049: Fix scalar response bodies in generated Koa routers, which emitted the `.ck` scalar name verbatim as a TypeScript type (`const result: binary`). Only `string`, `number`, `boolean`, `bigint`, `null` and `unknown` compiled by coincidence; `binary`, `int`, `uuid`, `datetime` and friends produced invalid code. Scalars now render as the type the handler actually receives: `binary` → `Buffer`, `int` → `number`, `datetime` → luxon `DateTime`, `interval` → `string`, `json` → `_JsonValue`.
8
+
9
+ Generated routers now also import `Duration` and `Interval` from luxon and emit the `_ZodInterval` helper when an operation uses those scalars, instead of referencing undefined names.
10
+
11
+ Plain type files emitted for the server render `binary` as `Buffer` rather than `Blob`. SDK output is unchanged. The standalone `types` sub-generator gained a `target` option (`"client" | "server"`, default `"client"`) to select between the two.
12
+
3
13
  ## 0.28.2
4
14
 
5
15
  ### Patch Changes
package/README.md CHANGED
@@ -94,6 +94,10 @@ Generates plain TypeScript interface/type files from `contract` declarations. No
94
94
  |---|---|---|---|
95
95
  | `baseDir` | `string` | `rootDir` | Base directory for output files |
96
96
  | `output` | `string` | `"{filename}.types.ts"` | Path template for type files |
97
+ | `target` | `"client" \| "server"` | `"client"` | Runtime the types describe. Affects scalars whose TypeScript type is runtime-specific: `binary` renders as `Buffer` for `server` and `Blob` for `client` |
98
+
99
+ The `server` and `sdk` sub-generators set `target` themselves (`server` and `client` respectively), so
100
+ their plain-type output already matches the runtime that consumes it.
97
101
 
98
102
  ## Path templates
99
103
 
@@ -1,4 +1,5 @@
1
1
  import type { ContractRootNode, ModelNode, ContractTypeNode, ObjectMode } from '@contractkit/core';
2
+ import type { TsRenderTarget } from './ts-render.js';
2
3
  /**
3
4
  * Maps a ContractKit object mode to its Zod constructor name.
4
5
  *
@@ -17,6 +18,12 @@ export interface ContractCodegenContext {
17
18
  modelsWithOutput?: Set<string>;
18
19
  /** If set, import JsonValue from this path instead of re-declaring it (avoids barrel re-export conflicts) */
19
20
  jsonValueImportPath?: string;
21
+ /**
22
+ * Runtime the emitted plain types describe. Only affects scalars whose TypeScript type differs
23
+ * per runtime (`binary` → `Buffer` on the server, `Blob` in the client). Ignored by
24
+ * `generateContract`, whose Zod schemas are server-shaped by construction. Default `'client'`.
25
+ */
26
+ target?: TsRenderTarget;
20
27
  }
21
28
  /**
22
29
  * Compute which models need Input variants, including transitive dependencies.
@@ -1 +1 @@
1
- {"version":3,"file":"codegen-contract.d.ts","sourceRoot":"","sources":["../src/codegen-contract.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EAET,gBAAgB,EAWhB,UAAU,EACb,MAAM,mBAAmB,CAAC;AAQ3B;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAStD;AAID,4GAA4G;AAC5G,MAAM,WAAW,sBAAsB;IACnC,sDAAsD;IACtD,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,8DAA8D;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,6GAA6G;IAC7G,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAID;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,uBAAuB,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAsCzH;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAkEjG;AAgVD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,EAAE,OAAO,GAAG,QAAQ,EAAE,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CA6B5H;AAkOD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAuDvH;AA2BD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAsCvH;AA0CD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAuB7E;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7E;AAED,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAiBjE;AAED,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAcpE;AAED,0EAA0E;AAC1E,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CA4BvG;AAmCD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CA6D/D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAgB3F;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD"}
1
+ {"version":3,"file":"codegen-contract.d.ts","sourceRoot":"","sources":["../src/codegen-contract.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EAET,gBAAgB,EAWhB,UAAU,EACb,MAAM,mBAAmB,CAAC;AAO3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAStD;AAID,4GAA4G;AAC5G,MAAM,WAAW,sBAAsB;IACnC,sDAAsD;IACtD,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,8DAA8D;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,6GAA6G;IAC7G,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;CAC3B;AAID;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,uBAAuB,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAsCzH;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAkEjG;AAgVD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,EAAE,OAAO,GAAG,QAAQ,EAAE,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CA6B5H;AAkOD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAuDvH;AA2BD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAsCvH;AA0CD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAuB7E;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7E;AAED,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAiBjE;AAED,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAcpE;AAED,0EAA0E;AAC1E,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CA4BvG;AAmCD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CA6D/D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAgB3F;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"codegen-operation.d.ts","sourceRoot":"","sources":["../src/codegen-operation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAA2B,MAAM,mBAAmB,CAAC;AAmC7H;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAkE5F;AAID,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,qFAAqF;IACrF,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,yHAAyH;AACzH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CA4EnF;AAsKD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAY7H;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,eAAe,GAAG,MAAM,CAqBzE;AAmXD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWnD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ/E"}
1
+ {"version":3,"file":"codegen-operation.d.ts","sourceRoot":"","sources":["../src/codegen-operation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAA2C,MAAM,mBAAmB,CAAC;AAmC7I;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAkE5F;AAID,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,qFAAqF;IACrF,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,yHAAyH;AACzH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAuFnF;AAyKD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAY7H;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,eAAe,GAAG,MAAM,CAqBzE;AAiaD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWnD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ/E"}
@@ -5,6 +5,9 @@ import type { ContractCodegenContext } from './codegen-contract.js';
5
5
  * Unlike `generateContract()` which produces Zod schemas, this emits
6
6
  * vanilla TypeScript `interface` and `type` declarations suitable
7
7
  * for SDK consumers that don't need runtime validation.
8
+ *
9
+ * @param context Import resolution and Input/Output variant sets. `context.target` selects the
10
+ * runtime the types describe (`'server'` renders `binary` as `Buffer`, `'client'` as `Blob`).
8
11
  */
9
12
  export declare function generatePlainTypes(root: ContractRootNode, context?: ContractCodegenContext): string;
10
13
  //# sourceMappingURL=codegen-plain-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codegen-plain-types.d.ts","sourceRoot":"","sources":["../src/codegen-plain-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAwB,MAAM,mBAAmB,CAAC;AAEhF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAapE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CA2CnG"}
1
+ {"version":3,"file":"codegen-plain-types.d.ts","sourceRoot":"","sources":["../src/codegen-plain-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAwB,MAAM,mBAAmB,CAAC;AAEhF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAcpE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CA4CnG"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ContractKitPlugin } from '@contractkit/core';
2
+ /** Koa server output: routers, and the type or Zod schema files they import. */
2
3
  export interface ServerConfig {
3
4
  /** Directory (relative to rootDir) where server files are written. Default: rootDir. */
4
5
  baseDir?: string;
@@ -15,6 +16,7 @@ export interface ServerConfig {
15
16
  /** Whether to emit handlers for `internal` operations. Default true. */
16
17
  includeInternal?: boolean;
17
18
  }
19
+ /** TypeScript SDK client output: the client class, per-area operation clients, and their types. */
18
20
  export interface SdkConfig {
19
21
  baseDir?: string;
20
22
  name?: string;
@@ -35,14 +37,23 @@ export interface SdkConfig {
35
37
  */
36
38
  scaffold?: boolean;
37
39
  }
40
+ /** Standalone Zod schema output, independent of the server and SDK sub-generators. */
38
41
  export interface ZodConfig {
39
42
  baseDir?: string;
40
43
  output?: string;
41
44
  }
45
+ /** Standalone plain TypeScript type output, independent of the server and SDK sub-generators. */
42
46
  export interface TypesConfig {
43
47
  baseDir?: string;
44
48
  output?: string;
49
+ /**
50
+ * Runtime the emitted types describe. Affects scalars whose TypeScript type is runtime-specific:
51
+ * `binary` renders as `Buffer` for `'server'` and `Blob` for `'client'`. Default `'client'`.
52
+ * The `server` and `sdk` sub-generators set this themselves.
53
+ */
54
+ target?: 'client' | 'server';
45
55
  }
56
+ /** MCP tool output: per-op-file handlers, the aggregator, and the optional POST route. */
46
57
  export interface McpConfig {
47
58
  /** Directory (relative to rootDir) where MCP files are written. Default: rootDir. */
48
59
  baseDir?: string;
@@ -69,6 +80,7 @@ export interface McpConfig {
69
80
  /** Whether to expose operations marked `internal` as MCP tools. Default false. */
70
81
  includeInternal?: boolean;
71
82
  }
83
+ /** Top-level plugin config. Each sub-config that is present enables its sub-generator. */
72
84
  export interface TypescriptPluginConfig {
73
85
  server?: ServerConfig;
74
86
  sdk?: SdkConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,iBAAiB,EAQpB,MAAM,mBAAmB,CAAC;AA8C3B,MAAM,WAAW,YAAY;IACzB,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6HAA6H;IAC7H,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE;QACL,8EAA8E;QAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,+EAA+E;QAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACtB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QACL,oHAAoH;QACpH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,0GAA0G;QAC1G,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,yFAAyF;QACzF,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;;WAIG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACnC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,GAAG,CAAC,EAAE,SAAS,CAAC;CACnB;AAID,yGAAyG;AACzG,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAO9C,QAAA,MAAM,MAAM,EAAE,iBAMb,CAAC;AAEF,eAAe,MAAM,CAAC;AAEtB,2GAA2G;AAC3G,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAOzG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,iBAAiB,EAQpB,MAAM,mBAAmB,CAAC;AA8C3B,gFAAgF;AAChF,MAAM,WAAW,YAAY;IACzB,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6HAA6H;IAC7H,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE;QACL,8EAA8E;QAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,+EAA+E;QAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,mGAAmG;AACnG,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,sFAAsF;AACtF,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iGAAiG;AACjG,MAAM,WAAW,WAAW;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAChC;AAED,0FAA0F;AAC1F,MAAM,WAAW,SAAS;IACtB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QACL,oHAAoH;QACpH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,0GAA0G;QAC1G,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,yFAAyF;QACzF,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;;WAIG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,0FAA0F;AAC1F,MAAM,WAAW,sBAAsB;IACnC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,GAAG,CAAC,EAAE,SAAS,CAAC;CACnB;AAID,yGAAyG;AACzG,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAO9C,QAAA,MAAM,MAAM,EAAE,iBAMb,CAAC;AAEF,eAAe,MAAM,CAAC;AAEtB,2GAA2G;AAC3G,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAOzG"}
package/dist/index.js CHANGED
@@ -31,41 +31,41 @@ function headerNameToProperty(name) {
31
31
  }).join("");
32
32
  }
33
33
  __name(headerNameToProperty, "headerNameToProperty");
34
- function renderTsType(type) {
34
+ function renderTsType(type, target = "client") {
35
35
  switch (type.kind) {
36
36
  case "scalar":
37
- return renderTsScalar(type.name);
37
+ return renderTsScalar(type.name, target);
38
38
  case "array": {
39
- const inner = renderTsType(type.item);
39
+ const inner = renderTsType(type.item, target);
40
40
  const needsParens = type.item.kind === "union" || type.item.kind === "discriminatedUnion" || type.item.kind === "intersection" || type.item.kind === "enum";
41
41
  return needsParens ? `(${inner})[]` : `${inner}[]`;
42
42
  }
43
43
  case "tuple":
44
- return `[${type.items.map(renderTsType).join(", ")}]`;
44
+ return `[${type.items.map((i) => renderTsType(i, target)).join(", ")}]`;
45
45
  case "record":
46
- return `Record<${renderTsType(type.key)}, ${renderTsType(type.value)}>`;
46
+ return `Record<${renderTsType(type.key, target)}, ${renderTsType(type.value, target)}>`;
47
47
  case "enum":
48
48
  return type.values.map((v) => `'${escapeSingleQuoted(v)}'`).join(" | ");
49
49
  case "literal":
50
50
  return typeof type.value === "string" ? `'${escapeSingleQuoted(type.value)}'` : String(type.value);
51
51
  case "union":
52
- return type.members.map(renderTsType).join(" | ");
52
+ return type.members.map((m) => renderTsType(m, target)).join(" | ");
53
53
  case "discriminatedUnion":
54
- return type.members.map(renderTsType).join(" | ");
54
+ return type.members.map((m) => renderTsType(m, target)).join(" | ");
55
55
  case "intersection":
56
- return type.members.map(renderTsType).join(" & ");
56
+ return type.members.map((m) => renderTsType(m, target)).join(" & ");
57
57
  case "ref":
58
58
  return type.name;
59
59
  case "lazy":
60
- return renderTsType(type.inner);
60
+ return renderTsType(type.inner, target);
61
61
  case "inlineObject":
62
- return renderTsInlineObject(type.fields);
62
+ return renderTsInlineObject(type.fields, target);
63
63
  default:
64
64
  return "unknown";
65
65
  }
66
66
  }
67
67
  __name(renderTsType, "renderTsType");
68
- function renderTsScalar(name) {
68
+ function renderTsScalar(name, target) {
69
69
  switch (name) {
70
70
  case "string":
71
71
  case "email":
@@ -92,7 +92,7 @@ function renderTsScalar(name) {
92
92
  case "object":
93
93
  return "Record<string, unknown>";
94
94
  case "binary":
95
- return "Blob";
95
+ return target === "server" ? "Buffer" : "Blob";
96
96
  case "json":
97
97
  return "JsonValue";
98
98
  default: {
@@ -102,61 +102,61 @@ function renderTsScalar(name) {
102
102
  }
103
103
  }
104
104
  __name(renderTsScalar, "renderTsScalar");
105
- function renderTsInlineObject(fields) {
105
+ function renderTsInlineObject(fields, target) {
106
106
  const entries = fields.map((f) => {
107
107
  const opt = f.optional ? "?" : "";
108
- return `${quoteKey(f.name)}${opt}: ${renderTsType(f.type)}`;
108
+ return `${quoteKey(f.name)}${opt}: ${renderTsType(f.type, target)}`;
109
109
  });
110
110
  return `{ ${entries.join("; ")} }`;
111
111
  }
112
112
  __name(renderTsInlineObject, "renderTsInlineObject");
113
- function renderInputTsType(type, modelsWithInput) {
114
- if (!modelsWithInput || modelsWithInput.size === 0) return renderTsType(type);
113
+ function renderInputTsType(type, modelsWithInput, target = "client") {
114
+ if (!modelsWithInput || modelsWithInput.size === 0) return renderTsType(type, target);
115
115
  switch (type.kind) {
116
116
  case "ref":
117
117
  return modelsWithInput.has(type.name) ? `${type.name}Input` : type.name;
118
118
  case "array": {
119
- const inner = renderInputTsType(type.item, modelsWithInput);
119
+ const inner = renderInputTsType(type.item, modelsWithInput, target);
120
120
  const needsParens = type.item.kind === "union" || type.item.kind === "discriminatedUnion" || type.item.kind === "intersection" || type.item.kind === "enum";
121
121
  return needsParens ? `(${inner})[]` : `${inner}[]`;
122
122
  }
123
123
  case "intersection":
124
- return type.members.map((m) => renderInputTsType(m, modelsWithInput)).join(" & ");
124
+ return type.members.map((m) => renderInputTsType(m, modelsWithInput, target)).join(" & ");
125
125
  case "union":
126
- return type.members.map((m) => renderInputTsType(m, modelsWithInput)).join(" | ");
126
+ return type.members.map((m) => renderInputTsType(m, modelsWithInput, target)).join(" | ");
127
127
  case "discriminatedUnion":
128
- return type.members.map((m) => renderInputTsType(m, modelsWithInput)).join(" | ");
128
+ return type.members.map((m) => renderInputTsType(m, modelsWithInput, target)).join(" | ");
129
129
  case "inlineObject":
130
- return `{ ${type.fields.map((f) => `${quoteKey(f.name)}${f.optional ? "?" : ""}: ${renderInputTsType(f.type, modelsWithInput)}`).join("; ")} }`;
130
+ return `{ ${type.fields.map((f) => `${quoteKey(f.name)}${f.optional ? "?" : ""}: ${renderInputTsType(f.type, modelsWithInput, target)}`).join("; ")} }`;
131
131
  case "lazy":
132
- return renderInputTsType(type.inner, modelsWithInput);
132
+ return renderInputTsType(type.inner, modelsWithInput, target);
133
133
  default:
134
- return renderTsType(type);
134
+ return renderTsType(type, target);
135
135
  }
136
136
  }
137
137
  __name(renderInputTsType, "renderInputTsType");
138
- function renderOutputTsType(type, modelsWithOutput) {
139
- if (!modelsWithOutput || modelsWithOutput.size === 0) return renderTsType(type);
138
+ function renderOutputTsType(type, modelsWithOutput, target = "client") {
139
+ if (!modelsWithOutput || modelsWithOutput.size === 0) return renderTsType(type, target);
140
140
  switch (type.kind) {
141
141
  case "ref":
142
142
  return modelsWithOutput.has(type.name) ? `${type.name}Output` : type.name;
143
143
  case "array": {
144
- const inner = renderOutputTsType(type.item, modelsWithOutput);
144
+ const inner = renderOutputTsType(type.item, modelsWithOutput, target);
145
145
  const needsParens = type.item.kind === "union" || type.item.kind === "discriminatedUnion" || type.item.kind === "intersection" || type.item.kind === "enum";
146
146
  return needsParens ? `(${inner})[]` : `${inner}[]`;
147
147
  }
148
148
  case "intersection":
149
- return type.members.map((m) => renderOutputTsType(m, modelsWithOutput)).join(" & ");
149
+ return type.members.map((m) => renderOutputTsType(m, modelsWithOutput, target)).join(" & ");
150
150
  case "union":
151
- return type.members.map((m) => renderOutputTsType(m, modelsWithOutput)).join(" | ");
151
+ return type.members.map((m) => renderOutputTsType(m, modelsWithOutput, target)).join(" | ");
152
152
  case "discriminatedUnion":
153
- return type.members.map((m) => renderOutputTsType(m, modelsWithOutput)).join(" | ");
153
+ return type.members.map((m) => renderOutputTsType(m, modelsWithOutput, target)).join(" | ");
154
154
  case "inlineObject":
155
- return `{ ${type.fields.map((f) => `${quoteKey(f.name)}${f.optional ? "?" : ""}: ${renderOutputTsType(f.type, modelsWithOutput)}`).join("; ")} }`;
155
+ return `{ ${type.fields.map((f) => `${quoteKey(f.name)}${f.optional ? "?" : ""}: ${renderOutputTsType(f.type, modelsWithOutput, target)}`).join("; ")} }`;
156
156
  case "lazy":
157
- return renderOutputTsType(type.inner, modelsWithOutput);
157
+ return renderOutputTsType(type.inner, modelsWithOutput, target);
158
158
  default:
159
- return renderTsType(type);
159
+ return renderTsType(type, target);
160
160
  }
161
161
  }
162
162
  __name(renderOutputTsType, "renderOutputTsType");
@@ -1200,8 +1200,12 @@ function generateOp(root, options = {}) {
1200
1200
  if (types.length > 0) {
1201
1201
  body.push(...generateTypeImports(types, root.file, options));
1202
1202
  }
1203
- if (opNeedsDateTime(root)) {
1204
- body.push(`import { DateTime } from 'luxon';`);
1203
+ const luxonImports = [];
1204
+ if (opNeedsDateTime(root)) luxonImports.push("DateTime");
1205
+ if (opNeedsScalar(root, "duration")) luxonImports.push("Duration");
1206
+ if (opNeedsScalar(root, "interval")) luxonImports.push("Interval");
1207
+ if (luxonImports.length > 0) {
1208
+ body.push(`import { ${luxonImports.join(", ")} } from 'luxon';`);
1205
1209
  }
1206
1210
  if (needsParseAndValidate) {
1207
1211
  body.push(`import { parseAndValidate } from '@maroonedsoftware/zod';`);
@@ -1216,6 +1220,9 @@ function generateOp(root, options = {}) {
1216
1220
  if (opNeedsScalar(root, "datetime")) {
1217
1221
  helpers.push(`const _ZodDatetime = z.preprocess((val) => typeof val === 'string' ? DateTime.fromISO(val) : val, z.custom<DateTime>((val) => val instanceof DateTime && val.isValid, { message: 'Must be in ISO 8601 format' }));`);
1218
1222
  }
1223
+ if (opNeedsScalar(root, "interval")) {
1224
+ helpers.push(`const _ZodInterval = z.preprocess((val) => typeof val === 'string' ? Interval.fromISO(val) : val, z.custom<Interval>((val) => val instanceof Interval && val.isValid, { message: 'Must be an ISO 8601 interval' })).transform(val => val.toISO()!);`);
1225
+ }
1219
1226
  if (opNeedsScalar(root, "json")) {
1220
1227
  helpers.push(`type _JsonValue = string | number | boolean | null | _JsonValue[] | { [key: string]: _JsonValue };`);
1221
1228
  helpers.push(`const _ZodJson: z.ZodType<_JsonValue> = z.lazy(() => z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(_ZodJson), z.record(z.string(), _ZodJson)]));`);
@@ -1325,7 +1332,7 @@ function generateHandler(route, op, root, options) {
1325
1332
  const serviceParts = inferService(op, route, file);
1326
1333
  const respHeaders = primaryResponse2?.headers ?? [];
1327
1334
  const hasRespHeaders = respHeaders.length > 0;
1328
- const headersAnnotation = hasRespHeaders ? `{ ${respHeaders.map((h) => `${quoteKey(headerNameToProperty(h.name))}${h.optional ? "?" : ""}: ${renderOutputTsType(h.type, options.modelsWithOutput)}`).join("; ")} }` : "";
1335
+ const headersAnnotation = hasRespHeaders ? `{ ${respHeaders.map((h) => `${quoteKey(headerNameToProperty(h.name))}${h.optional ? "?" : ""}: ${renderOutputTsType(h.type, options.modelsWithOutput, "server")}`).join("; ")} }` : "";
1329
1336
  if (primaryResponse2?.bodyType) {
1330
1337
  const { annotation, prelude } = formatTypeAnnotation(primaryResponse2.bodyType, options.modelsWithOutput);
1331
1338
  if (prelude) {
@@ -1419,6 +1426,45 @@ function buildArgs(route, op) {
1419
1426
  return args.join(", ");
1420
1427
  }
1421
1428
  __name(buildArgs, "buildArgs");
1429
+ function serverTsScalar(name) {
1430
+ switch (name) {
1431
+ case "string":
1432
+ case "email":
1433
+ case "url":
1434
+ case "uuid":
1435
+ return "string";
1436
+ case "number":
1437
+ case "int":
1438
+ return "number";
1439
+ case "bigint":
1440
+ return "bigint";
1441
+ case "boolean":
1442
+ return "boolean";
1443
+ case "date":
1444
+ case "time":
1445
+ case "datetime":
1446
+ return "DateTime";
1447
+ case "duration":
1448
+ return "Duration";
1449
+ case "interval":
1450
+ return "string";
1451
+ case "binary":
1452
+ return "Buffer";
1453
+ case "json":
1454
+ return "_JsonValue";
1455
+ case "object":
1456
+ return "Record<string, unknown>";
1457
+ case "null":
1458
+ return "null";
1459
+ case "unknown":
1460
+ return "unknown";
1461
+ default: {
1462
+ const _exhaustive = name;
1463
+ throw new Error(`plugin-typescript: unmapped scalar '${String(_exhaustive)}' \u2014 add a case`);
1464
+ }
1465
+ }
1466
+ }
1467
+ __name(serverTsScalar, "serverTsScalar");
1422
1468
  function formatTypeAnnotation(bodyType, modelsWithOutput) {
1423
1469
  if (bodyType.kind === "array") {
1424
1470
  const inner = formatTypeAnnotation(bodyType.item, modelsWithOutput);
@@ -1434,7 +1480,7 @@ function formatTypeAnnotation(bodyType, modelsWithOutput) {
1434
1480
  };
1435
1481
  }
1436
1482
  if (bodyType.kind === "scalar") return {
1437
- annotation: bodyType.name
1483
+ annotation: serverTsScalar(bodyType.name)
1438
1484
  };
1439
1485
  const schema = renderType(bodyType);
1440
1486
  return {
@@ -2807,6 +2853,7 @@ __name(generateSdkAggregator, "generateSdkAggregator");
2807
2853
  import { relative as relative4, dirname as dirname4 } from "path";
2808
2854
  import { computeModelsWithOutput, collectExternalOutputRefs } from "@contractkit/core";
2809
2855
  function generatePlainTypes(root, context) {
2856
+ const target = context?.target ?? "client";
2810
2857
  const externalRefs = collectExternalRefs(root);
2811
2858
  const lines = [];
2812
2859
  const externalModelsWithInput = context?.modelsWithInput ?? /* @__PURE__ */ new Set();
@@ -2848,21 +2895,21 @@ function generatePlainTypes(root, context) {
2848
2895
  m
2849
2896
  ]));
2850
2897
  for (const model of topoSortModels(root.models)) {
2851
- lines.push(...generateModel2(model, context?.currentOutPath, allModelsWithInput, allModelsWithOutput, modelMap));
2898
+ lines.push(...generateModel2(model, target, context?.currentOutPath, allModelsWithInput, allModelsWithOutput, modelMap));
2852
2899
  lines.push("");
2853
2900
  }
2854
2901
  return lines.join("\n");
2855
2902
  }
2856
2903
  __name(generatePlainTypes, "generatePlainTypes");
2857
- function generateModel2(model, outPath, modelsWithInput, modelsWithOutput, modelMap) {
2904
+ function generateModel2(model, target, outPath, modelsWithInput, modelsWithOutput, modelMap) {
2858
2905
  if (model.type) {
2859
- return generateTypeAlias2(model, outPath, modelsWithInput, modelsWithOutput);
2906
+ return generateTypeAlias2(model, target, outPath, modelsWithInput, modelsWithOutput);
2860
2907
  }
2861
2908
  const needsInputSplit = model.fields.some((f) => f.visibility !== "normal") || (modelsWithInput?.has(model.name) ?? false);
2862
- const lines = needsInputSplit ? generateVisibilityModel(model, outPath, modelsWithInput, modelMap) : generateSimpleModel2(model, outPath, modelMap);
2909
+ const lines = needsInputSplit ? generateVisibilityModel(model, target, outPath, modelsWithInput, modelMap) : generateSimpleModel2(model, target, outPath, modelMap);
2863
2910
  if (modelsWithOutput?.has(model.name)) {
2864
2911
  lines.push("");
2865
- lines.push(...generateOutputModel(model, modelsWithOutput));
2912
+ lines.push(...generateOutputModel(model, target, modelsWithOutput));
2866
2913
  }
2867
2914
  return lines;
2868
2915
  }
@@ -2899,15 +2946,15 @@ function generateComments2(model, outPath) {
2899
2946
  return lines;
2900
2947
  }
2901
2948
  __name(generateComments2, "generateComments");
2902
- function generateTypeAlias2(model, outPath, modelsWithInput, modelsWithOutput) {
2949
+ function generateTypeAlias2(model, target, outPath, modelsWithInput, modelsWithOutput) {
2903
2950
  const lines = [];
2904
2951
  lines.push(...generateComments2(model, outPath));
2905
- lines.push(`export type ${model.name} = ${renderTsType(model.type)};`);
2952
+ lines.push(`export type ${model.name} = ${renderTsType(model.type, target)};`);
2906
2953
  if (modelsWithInput?.has(model.name)) {
2907
- lines.push(`export type ${model.name}Input = ${renderInputTsType(model.type, modelsWithInput)};`);
2954
+ lines.push(`export type ${model.name}Input = ${renderInputTsType(model.type, modelsWithInput, target)};`);
2908
2955
  }
2909
2956
  if (modelsWithOutput?.has(model.name)) {
2910
- lines.push(`export type ${model.name}Output = ${renderOutputTsType(model.type, modelsWithOutput)};`);
2957
+ lines.push(`export type ${model.name}Output = ${renderOutputTsType(model.type, modelsWithOutput, target)};`);
2911
2958
  }
2912
2959
  return lines;
2913
2960
  }
@@ -2920,20 +2967,20 @@ function buildExtendsClause(bases, overrideNames, baseNameResolver) {
2920
2967
  return ` extends ${wrapped.join(", ")}`;
2921
2968
  }
2922
2969
  __name(buildExtendsClause, "buildExtendsClause");
2923
- function generateSimpleModel2(model, outPath, modelMap) {
2970
+ function generateSimpleModel2(model, target, outPath, modelMap) {
2924
2971
  const lines = [];
2925
2972
  lines.push(...generateComments2(model, outPath));
2926
2973
  const bases = model.bases ?? [];
2927
2974
  const overrideNames = computeOverrideNames(model, modelMap);
2928
2975
  lines.push(`export interface ${model.name}${buildExtendsClause(bases, overrideNames, (b) => b)} {`);
2929
2976
  for (const field of model.fields) {
2930
- lines.push(` ${renderField2(field)}`);
2977
+ lines.push(` ${renderField2(field, target)}`);
2931
2978
  }
2932
2979
  lines.push("}");
2933
2980
  return lines;
2934
2981
  }
2935
2982
  __name(generateSimpleModel2, "generateSimpleModel");
2936
- function generateVisibilityModel(model, outPath, modelsWithInput, modelMap) {
2983
+ function generateVisibilityModel(model, target, outPath, modelsWithInput, modelMap) {
2937
2984
  const lines = [];
2938
2985
  lines.push(...generateComments2(model, outPath));
2939
2986
  const bases = model.bases ?? [];
@@ -2941,7 +2988,7 @@ function generateVisibilityModel(model, outPath, modelsWithInput, modelMap) {
2941
2988
  const readFields = model.fields.filter((f) => f.visibility !== "writeonly");
2942
2989
  lines.push(`export interface ${model.name}${buildExtendsClause(bases, overrideNames, (b) => b)} {`);
2943
2990
  for (const field of readFields) {
2944
- lines.push(` ${renderField2(field)}`);
2991
+ lines.push(` ${renderField2(field, target)}`);
2945
2992
  }
2946
2993
  lines.push("}");
2947
2994
  lines.push("");
@@ -2949,7 +2996,7 @@ function generateVisibilityModel(model, outPath, modelsWithInput, modelMap) {
2949
2996
  const inputResolver = /* @__PURE__ */ __name((b) => modelsWithInput?.has(b) ? `${b}Input` : b, "inputResolver");
2950
2997
  lines.push(`export interface ${model.name}Input${buildExtendsClause(bases, overrideNames, inputResolver)} {`);
2951
2998
  for (const field of writeFields) {
2952
- lines.push(` ${modelsWithInput ? renderInputField2(field, modelsWithInput) : renderField2(field)}`);
2999
+ lines.push(` ${modelsWithInput ? renderInputField2(field, modelsWithInput, target) : renderField2(field, target)}`);
2953
3000
  }
2954
3001
  lines.push("}");
2955
3002
  return lines;
@@ -2969,9 +3016,9 @@ ${body}
2969
3016
  ${line}`;
2970
3017
  }
2971
3018
  __name(withFieldJsDoc, "withFieldJsDoc");
2972
- function renderField2(field) {
3019
+ function renderField2(field, target) {
2973
3020
  const opt = field.optional || field.default !== void 0 ? "?" : "";
2974
- let typeStr = renderTsType(field.type);
3021
+ let typeStr = renderTsType(field.type, target);
2975
3022
  if (field.nullable) typeStr += " | null";
2976
3023
  const line = `${quoteKey(field.name)}${opt}: ${typeStr};`;
2977
3024
  const jsdocParts = [];
@@ -2980,9 +3027,9 @@ function renderField2(field) {
2980
3027
  return withFieldJsDoc(jsdocParts, line);
2981
3028
  }
2982
3029
  __name(renderField2, "renderField");
2983
- function renderInputField2(field, modelsWithInput) {
3030
+ function renderInputField2(field, modelsWithInput, target) {
2984
3031
  const opt = field.optional || field.default !== void 0 ? "?" : "";
2985
- let typeStr = renderInputTsType(field.type, modelsWithInput);
3032
+ let typeStr = renderInputTsType(field.type, modelsWithInput, target);
2986
3033
  if (field.nullable) typeStr += " | null";
2987
3034
  const line = `${quoteKey(field.name)}${opt}: ${typeStr};`;
2988
3035
  const jsdocParts = [];
@@ -3005,7 +3052,7 @@ function applyOutputCase(name, c) {
3005
3052
  return camelToPascal2(name);
3006
3053
  }
3007
3054
  __name(applyOutputCase, "applyOutputCase");
3008
- function generateOutputModel(model, modelsWithOutput) {
3055
+ function generateOutputModel(model, target, modelsWithOutput) {
3009
3056
  const lines = [];
3010
3057
  const outputCase = model.outputCase && model.outputCase !== "camel" ? model.outputCase : void 0;
3011
3058
  const readFields = model.fields.filter((f) => f.visibility !== "writeonly");
@@ -3013,23 +3060,23 @@ function generateOutputModel(model, modelsWithOutput) {
3013
3060
  const baseExt = model.bases?.[0] && modelsWithOutput.has(model.bases?.[0]) ? ` extends ${model.bases?.[0]}Output` : model.bases?.[0] ? ` extends ${model.bases?.[0]}` : "";
3014
3061
  lines.push(`export interface ${model.name}Output${baseExt} {`);
3015
3062
  for (const field of readFields) {
3016
- lines.push(` ${renderOutputField(field, model.outputCase, modelsWithOutput)}`);
3063
+ lines.push(` ${renderOutputField(field, model.outputCase, modelsWithOutput, target)}`);
3017
3064
  }
3018
3065
  lines.push("}");
3019
3066
  return lines;
3020
3067
  }
3021
3068
  lines.push(`export interface ${model.name}Output {`);
3022
3069
  for (const field of readFields) {
3023
- lines.push(` ${renderOutputField(field, outputCase, modelsWithOutput)}`);
3070
+ lines.push(` ${renderOutputField(field, outputCase, modelsWithOutput, target)}`);
3024
3071
  }
3025
3072
  lines.push("}");
3026
3073
  return lines;
3027
3074
  }
3028
3075
  __name(generateOutputModel, "generateOutputModel");
3029
- function renderOutputField(field, outputCase, modelsWithOutput) {
3076
+ function renderOutputField(field, outputCase, modelsWithOutput, target) {
3030
3077
  const opt = field.optional || field.default !== void 0 ? "?" : "";
3031
3078
  const key = applyOutputCase(field.name, outputCase);
3032
- let typeStr = renderOutputTsType(field.type, modelsWithOutput);
3079
+ let typeStr = renderOutputTsType(field.type, modelsWithOutput, target);
3033
3080
  if (field.nullable) typeStr += " | null";
3034
3081
  const line = `${quoteKey(key)}${opt}: ${typeStr};`;
3035
3082
  const jsdocParts = [];
@@ -3856,7 +3903,9 @@ function collectServerOutput(config, rootDir, inputs, units) {
3856
3903
  modelOutPaths: serverModelOutPaths,
3857
3904
  currentOutPath: typeOutPath,
3858
3905
  modelsWithInput,
3859
- modelsWithOutput
3906
+ modelsWithOutput,
3907
+ // These types are consumed by Koa handlers, so `binary` is a Buffer, not a Blob.
3908
+ target: "server"
3860
3909
  };
3861
3910
  const content = config.zod ? generateContract(ast, renderCtx) : generatePlainTypes(ast, renderCtx);
3862
3911
  return [
@@ -4368,7 +4417,8 @@ function collectTypesOutput(config, rootDir, inputs, units) {
4368
4417
  modelOutPaths,
4369
4418
  currentOutPath: outPath,
4370
4419
  modelsWithInput,
4371
- modelsWithOutput
4420
+ modelsWithOutput,
4421
+ target: config.target
4372
4422
  })
4373
4423
  }
4374
4424
  ], "render")