🚀. Socket Launch Week Day 2:Introducing Manifest Alerts.Learn more
Sign In

@contractkit/plugin-typescript

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@contractkit/plugin-typescript - npm Package Compare versions

Comparing version
0.26.0
to
0.27.0
+5
-5
.turbo/turbo-build$colon$ci.log

@@ -8,7 +8,7 @@ $ eslint --max-warnings=0 && pnpm run build

ESM Build start
ESM dist/index.js 150.35 KB
ESM dist/index.js.map 328.43 KB
ESM ⚡️ Build success in 348ms
ESM dist/index.js 152.62 KB
ESM dist/index.js.map 335.05 KB
ESM ⚡️ Build success in 416ms
DTS Build start
DTS ⚡️ Build success in 7174ms
DTS dist/index.d.ts 1.82 KB
DTS ⚡️ Build success in 5954ms
DTS dist/index.d.ts 2.35 KB

@@ -6,13 +6,13 @@ $ vitest run --coverage

✓ tests/codegen-contract.test.ts (127 tests) 167ms
✓ tests/codegen-operation.test.ts (89 tests) 187ms
✓ tests/codegen-sdk.test.ts (132 tests) 186ms
✓ tests/codegen-plain-types.test.ts (61 tests) 51ms
✓ tests/codegen-server.test.ts (19 tests) 74ms
✓ tests/pipeline.test.ts (25 tests) 177ms
✓ tests/codegen-contract.test.ts (127 tests) 150ms
✓ tests/codegen-operation.test.ts (89 tests) 151ms
✓ tests/codegen-sdk.test.ts (138 tests) 206ms
✓ tests/codegen-plain-types.test.ts (61 tests) 34ms
✓ tests/codegen-server.test.ts (22 tests) 103ms
✓ tests/pipeline.test.ts (25 tests) 171ms
 Test Files  6 passed (6)
 Tests  453 passed (453)
 Start at  19:14:39
 Duration  7.36s (transform 4.18s, setup 0ms, import 14.22s, tests 841ms, environment 12ms)
 Tests  462 passed (462)
 Start at  15:55:38
 Duration  7.14s (transform 4.98s, setup 0ms, import 13.67s, tests 815ms, environment 1ms)

@@ -23,10 +23,10 @@  % Coverage report from v8

-------------------|---------|----------|---------|---------|-------------------
All files | 80.05 | 75.37 | 83.66 | 82.64 |
src | 79.83 | 75.06 | 83.24 | 82.41 |
All files | 82.85 | 77.33 | 85.78 | 85.48 |
src | 82.7 | 77.05 | 85.52 | 85.31 |
...n-contract.ts | 87.92 | 82.7 | 90.08 | 89.06 | ...1085,1090-1091
...-operation.ts | 78.41 | 74.7 | 78.94 | 79.9 | ...80-691,696-697
...lain-types.ts | 89.08 | 78.37 | 96.66 | 92.3 | ...31,243,249,301
codegen-sdk.ts | 88.09 | 82.56 | 87.32 | 91.32 | ...1108-1109,1112
index.ts | 60.23 | 47.91 | 63.04 | 65.37 | ...08-811,827-846
path-utils.ts | 41.04 | 31.32 | 78.57 | 42.47 | ...64-168,179-219
codegen-sdk.ts | 88.33 | 83.2 | 87.67 | 91.47 | ...1186-1187,1190
index.ts | 70.05 | 60.38 | 75 | 74.74 | ...45-848,864-883
path-utils.ts | 68.65 | 46.98 | 100 | 72.56 | ...48-151,199-214
ts-render.ts | 82.19 | 85.39 | 72.22 | 87.09 | 56,90,126,157-165

@@ -33,0 +33,0 @@ tests | 90.38 | 90.9 | 89.28 | 93.47 |

# @contractkit/contractkit-plugin-typescript
## 0.27.0
### Minor Changes
- 0d3b8e2: Add opt-in `sdk.scaffold` to the TypeScript plugin, which emits a starter `package.json` and `tsconfig.json` at the SDK `baseDir` so generated output is a buildable, publishable package. Dependencies are derived from the contracts (`zod` when `zod: true`; `luxon`/`@types/luxon` when a date/time scalar is used). Scaffold files are write-once: a new `ctx.emitFile(path, content, { ifAbsent: true })` option writes them only when absent and never overwrites or orphan-deletes them, so disabling `scaffold` or editing the files later is always safe.
### Patch Changes
- Updated dependencies [0d3b8e2]
- @contractkit/core@0.22.0
## 0.26.0

@@ -4,0 +15,0 @@

@@ -26,5 +26,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">80.05% </span>
<span class="strong">82.85% </span>
<span class="quiet">Statements</span>
<span class='fraction'>2039/2547</span>
<span class='fraction'>2127/2567</span>
</div>

@@ -34,5 +34,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">75.37% </span>
<span class="strong">77.33% </span>
<span class="quiet">Branches</span>
<span class='fraction'>1240/1645</span>
<span class='fraction'>1286/1663</span>
</div>

@@ -42,5 +42,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">83.66% </span>
<span class="strong">85.78% </span>
<span class="quiet">Functions</span>
<span class='fraction'>338/404</span>
<span class='fraction'>350/408</span>
</div>

@@ -50,5 +50,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">82.64% </span>
<span class="strong">85.48% </span>
<span class="quiet">Lines</span>
<span class='fraction'>1786/2161</span>
<span class='fraction'>1861/2177</span>
</div>

@@ -86,14 +86,14 @@

<tbody><tr>
<td class="file medium" data-value="src"><a href="src/index.html">src</a></td>
<td data-value="79.83" class="pic medium">
<div class="chart"><div class="cover-fill" style="width: 79%"></div><div class="cover-empty" style="width: 21%"></div></div>
<td class="file high" data-value="src"><a href="src/index.html">src</a></td>
<td data-value="82.7" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 82%"></div><div class="cover-empty" style="width: 18%"></div></div>
</td>
<td data-value="79.83" class="pct medium">79.83%</td>
<td data-value="2495" class="abs medium">1992/2495</td>
<td data-value="75.06" class="pct medium">75.06%</td>
<td data-value="1612" class="abs medium">1210/1612</td>
<td data-value="83.24" class="pct high">83.24%</td>
<td data-value="376" class="abs high">313/376</td>
<td data-value="82.41" class="pct high">82.41%</td>
<td data-value="2115" class="abs high">1743/2115</td>
<td data-value="82.7" class="pct high">82.7%</td>
<td data-value="2515" class="abs high">2080/2515</td>
<td data-value="77.05" class="pct medium">77.05%</td>
<td data-value="1630" class="abs medium">1256/1630</td>
<td data-value="85.52" class="pct high">85.52%</td>
<td data-value="380" class="abs high">325/380</td>
<td data-value="85.31" class="pct high">85.31%</td>
<td data-value="2131" class="abs high">1818/2131</td>
</tr>

@@ -124,3 +124,3 @@

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -127,0 +127,0 @@ <script src="prettify.js"></script>

@@ -393,28 +393,28 @@

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-yes">19x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-no">&nbsp;</span>

@@ -428,10 +428,10 @@ <span class="cline-any cline-no">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">65x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -449,3 +449,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">5x</span>

@@ -456,11 +456,11 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">97x</span>
<span class="cline-any cline-yes">100x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">73x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -473,4 +473,4 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">73x</span>
<span class="cline-any cline-yes">73x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">17x</span>

@@ -481,4 +481,4 @@ <span class="cline-any cline-yes">17x</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">73x</span>
<span class="cline-any cline-yes">73x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -490,20 +490,20 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">73x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">75x</span>
<span class="cline-any cline-yes">112x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">78x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -530,3 +530,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">91x</span>
<span class="cline-any cline-yes">93x</span>
<span class="cline-any cline-yes">16x</span>

@@ -539,15 +539,15 @@ <span class="cline-any cline-yes">7x</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">77x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-yes">80x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">55x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-yes">57x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -587,13 +587,13 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">106x</span>
<span class="cline-any cline-yes">109x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -995,3 +995,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -998,0 +998,0 @@ <script src="../prettify.js"></script>

@@ -26,5 +26,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">79.83% </span>
<span class="strong">82.7% </span>
<span class="quiet">Statements</span>
<span class='fraction'>1992/2495</span>
<span class='fraction'>2080/2515</span>
</div>

@@ -34,5 +34,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">75.06% </span>
<span class="strong">77.05% </span>
<span class="quiet">Branches</span>
<span class='fraction'>1210/1612</span>
<span class='fraction'>1256/1630</span>
</div>

@@ -42,5 +42,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">83.24% </span>
<span class="strong">85.52% </span>
<span class="quiet">Functions</span>
<span class='fraction'>313/376</span>
<span class='fraction'>325/380</span>
</div>

@@ -50,5 +50,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">82.41% </span>
<span class="strong">85.31% </span>
<span class="quiet">Lines</span>
<span class='fraction'>1743/2115</span>
<span class='fraction'>1818/2131</span>
</div>

@@ -68,3 +68,3 @@

</div>
<div class='status-line medium'></div>
<div class='status-line high'></div>
<div class="pad1">

@@ -133,13 +133,13 @@ <table class="coverage-summary">

<td class="file high" data-value="codegen-sdk.ts"><a href="codegen-sdk.ts.html">codegen-sdk.ts</a></td>
<td data-value="88.09" class="pic high">
<td data-value="88.33" class="pic high">
<div class="chart"><div class="cover-fill" style="width: 88%"></div><div class="cover-empty" style="width: 12%"></div></div>
</td>
<td data-value="88.09" class="pct high">88.09%</td>
<td data-value="630" class="abs high">555/630</td>
<td data-value="82.56" class="pct high">82.56%</td>
<td data-value="367" class="abs high">303/367</td>
<td data-value="87.32" class="pct high">87.32%</td>
<td data-value="71" class="abs high">62/71</td>
<td data-value="91.32" class="pct high">91.32%</td>
<td data-value="553" class="abs high">505/553</td>
<td data-value="88.33" class="pct high">88.33%</td>
<td data-value="643" class="abs high">568/643</td>
<td data-value="83.2" class="pct high">83.2%</td>
<td data-value="375" class="abs high">312/375</td>
<td data-value="87.67" class="pct high">87.67%</td>
<td data-value="73" class="abs high">64/73</td>
<td data-value="91.47" class="pct high">91.47%</td>
<td data-value="563" class="abs high">515/563</td>
</tr>

@@ -149,28 +149,28 @@

<td class="file medium" data-value="index.ts"><a href="index.ts.html">index.ts</a></td>
<td data-value="60.23" class="pic medium">
<div class="chart"><div class="cover-fill" style="width: 60%"></div><div class="cover-empty" style="width: 40%"></div></div>
<td data-value="70.05" class="pic medium">
<div class="chart"><div class="cover-fill" style="width: 70%"></div><div class="cover-empty" style="width: 30%"></div></div>
</td>
<td data-value="60.23" class="pct medium">60.23%</td>
<td data-value="337" class="abs medium">203/337</td>
<td data-value="47.91" class="pct low">47.91%</td>
<td data-value="144" class="abs low">69/144</td>
<td data-value="63.04" class="pct medium">63.04%</td>
<td data-value="46" class="abs medium">29/46</td>
<td data-value="65.37" class="pct medium">65.37%</td>
<td data-value="283" class="abs medium">185/283</td>
<td data-value="70.05" class="pct medium">70.05%</td>
<td data-value="344" class="abs medium">241/344</td>
<td data-value="60.38" class="pct medium">60.38%</td>
<td data-value="154" class="abs medium">93/154</td>
<td data-value="75" class="pct medium">75%</td>
<td data-value="48" class="abs medium">36/48</td>
<td data-value="74.74" class="pct medium">74.74%</td>
<td data-value="289" class="abs medium">216/289</td>
</tr>
<tr>
<td class="file low" data-value="path-utils.ts"><a href="path-utils.ts.html">path-utils.ts</a></td>
<td data-value="41.04" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 41%"></div><div class="cover-empty" style="width: 59%"></div></div>
<td class="file medium" data-value="path-utils.ts"><a href="path-utils.ts.html">path-utils.ts</a></td>
<td data-value="68.65" class="pic medium">
<div class="chart"><div class="cover-fill" style="width: 68%"></div><div class="cover-empty" style="width: 32%"></div></div>
</td>
<td data-value="41.04" class="pct low">41.04%</td>
<td data-value="134" class="abs low">55/134</td>
<td data-value="31.32" class="pct low">31.32%</td>
<td data-value="83" class="abs low">26/83</td>
<td data-value="78.57" class="pct medium">78.57%</td>
<td data-value="14" class="abs medium">11/14</td>
<td data-value="42.47" class="pct low">42.47%</td>
<td data-value="113" class="abs low">48/113</td>
<td data-value="68.65" class="pct medium">68.65%</td>
<td data-value="134" class="abs medium">92/134</td>
<td data-value="46.98" class="pct low">46.98%</td>
<td data-value="83" class="abs low">39/83</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="14" class="abs high">14/14</td>
<td data-value="72.56" class="pct medium">72.56%</td>
<td data-value="113" class="abs medium">82/113</td>
</tr>

@@ -201,3 +201,3 @@

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -204,0 +204,0 @@ <script src="../prettify.js"></script>

@@ -26,5 +26,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">41.04% </span>
<span class="strong">68.65% </span>
<span class="quiet">Statements</span>
<span class='fraction'>55/134</span>
<span class='fraction'>92/134</span>
</div>

@@ -34,5 +34,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">31.32% </span>
<span class="strong">46.98% </span>
<span class="quiet">Branches</span>
<span class='fraction'>26/83</span>
<span class='fraction'>39/83</span>
</div>

@@ -42,5 +42,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">78.57% </span>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>11/14</span>
<span class='fraction'>14/14</span>
</div>

@@ -50,5 +50,5 @@

<div class='fl pad1y space-right2'>
<span class="strong">42.47% </span>
<span class="strong">72.56% </span>
<span class="quiet">Lines</span>
<span class='fraction'>48/113</span>
<span class='fraction'>82/113</span>
</div>

@@ -68,3 +68,3 @@

</div>
<div class='status-line low'></div>
<div class='status-line medium'></div>
<pre><table class="coverage">

@@ -298,18 +298,18 @@ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">22x</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">18x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">18x</span>
<span class="cline-any cline-yes">18x</span>
<span class="cline-any cline-yes">18x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">63x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-yes">27x</span>
<span class="cline-any cline-yes">81x</span>
<span class="cline-any cline-no">&nbsp;</span>

@@ -320,3 +320,3 @@ <span class="cline-any cline-no">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">18x</span>
<span class="cline-any cline-yes">21x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -372,12 +372,12 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-yes">8x</span>
<span class="cline-any cline-no">&nbsp;</span>

@@ -431,13 +431,13 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -449,18 +449,18 @@ <span class="cline-any cline-no">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -474,25 +474,25 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -515,3 +515,3 @@ <span class="cline-any cline-no">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -648,3 +648,3 @@ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { resolve, join, relative, dirname } from 'node:path';

&nbsp;
export function <span class="fstat-no" title="function not covered" >computeSdkTypeOutPath(</span>
export function computeSdkTypeOutPath(
filePath: string,

@@ -654,14 +654,14 @@ rootDir: string,

commonRoot: string,
meta: Record&lt;string, string&gt; = <span class="branch-0 cbranch-no" title="branch not covered" >{},</span>
meta: Record&lt;string, string&gt; = {},
): string | null {
<span class="cstat-no" title="statement not covered" > if (!filePath.endsWith('.ck')) <span class="cstat-no" title="statement not covered" >return null;</span></span>
const baseName = <span class="cstat-no" title="statement not covered" >filePath.split('/').pop()!;</span>
const defaultOutName = <span class="cstat-no" title="statement not covered" >baseName.replace(/\.ck$/, '.ts');</span>
const <span class="cstat-no" title="statement not covered" >baseOutDir = resolve(rootDir);</span>
const <span class="cstat-no" title="statement not covered" >relDir = relative(commonRoot, dirname(filePath));</span>
const filename = <span class="cstat-no" title="statement not covered" >baseName.replace(/\.ck$/, '');</span>
<span class="missing-if-branch" title="if path not taken" >I</span>if (!filePath.endsWith('.ck')) <span class="cstat-no" title="statement not covered" >return null;</span>
const baseName = filePath.split('/').pop()!;
const defaultOutName = baseName.replace(/\.ck$/, '.ts');
const baseOutDir = resolve(rootDir);
const relDir = relative(commonRoot, dirname(filePath));
const filename = baseName.replace(/\.ck$/, '');
&nbsp;
<span class="cstat-no" title="statement not covered" > if (TEMPLATE_VAR_RE.test(typeOutput)) {</span>
const resolved = <span class="cstat-no" title="statement not covered" >resolveTemplate(typeOutput, { filename, dir: relDir, ext: 'ck', ...meta });</span>
<span class="cstat-no" title="statement not covered" > if (includesFilename(resolved)) <span class="cstat-no" title="statement not covered" >return join(baseOutDir, resolved);</span></span>
<span class="missing-if-branch" title="else path not taken" >E</span>if (TEMPLATE_VAR_RE.test(typeOutput)) {
const resolved = resolveTemplate(typeOutput, { filename, dir: relDir, ext: 'ck', ...meta });
<span class="missing-if-branch" title="else path not taken" >E</span>if (includesFilename(resolved)) return join(baseOutDir, resolved);
<span class="cstat-no" title="statement not covered" > return join(baseOutDir, resolved, defaultOutName);</span>

@@ -676,14 +676,14 @@ }

for (const outPath of contractPaths) {
const <span class="cstat-no" title="statement not covered" >dir = dirname(outPath);</span>
const group = <span class="cstat-no" title="statement not covered" >byDir.get(dir) ?? [];</span>
<span class="cstat-no" title="statement not covered" > group.push(outPath);</span>
<span class="cstat-no" title="statement not covered" > byDir.set(dir, group);</span>
const dir = dirname(outPath);
const group = byDir.get(dir) ?? [];
group.push(outPath);
byDir.set(dir, group);
}
const results: { outPath: string; content: string }[] = [];
for (const [dir, files] of byDir) {
const exports = <span class="cstat-no" title="statement not covered" >files</span>
.map(<span class="fstat-no" title="function not covered" >f =&gt; <span class="cstat-no" title="statement not covered" >`</span>export * from './${f.split('/').pop()!.replace(/\.ts$/, '.js')}';`)</span>
const exports = files
.map(f =&gt; `export * from './${f.split('/').pop()!.replace(/\.ts$/, '.js')}';`)
.sort()
.join('\n');
<span class="cstat-no" title="statement not covered" > results.push({ outPath: join(dir, 'index.ts'), content: `// Auto-generated barrel file\n${exports}\n` });</span>
results.push({ outPath: join(dir, 'index.ts'), content: `// Auto-generated barrel file\n${exports}\n` });
}

@@ -693,28 +693,28 @@ return results;

&nbsp;
export function <span class="fstat-no" title="function not covered" >computePubliclyReachableTypes(</span>
export function computePubliclyReachableTypes(
opAsts: OpRootNode[],
contractAsts: ContractRootNode[],
modelsWithInput: Set&lt;string&gt;,
modelsWithOutput: Set&lt;string&gt; = <span class="branch-0 cbranch-no" title="branch not covered" >new Set(),</span>
modelsWithOutput: Set&lt;string&gt; = new Set(),
): Set&lt;string&gt; | null {
<span class="cstat-no" title="statement not covered" > if (opAsts.length === 0) <span class="cstat-no" title="statement not covered" >return null;</span></span>
const reachable = <span class="cstat-no" title="statement not covered" >new Set&lt;string&gt;();</span>
<span class="cstat-no" title="statement not covered" > for (const opAst of opAsts) {</span>
<span class="cstat-no" title="statement not covered" > for (const name of collectPublicTypeNames(opAst, modelsWithInput, modelsWithOutput)) <span class="cstat-no" title="statement not covered" >reachable.add(name);</span></span>
<span class="missing-if-branch" title="if path not taken" >I</span>if (opAsts.length === 0) <span class="cstat-no" title="statement not covered" >return null;</span>
const reachable = new Set&lt;string&gt;();
for (const opAst of opAsts) {
for (const name of collectPublicTypeNames(opAst, modelsWithInput, modelsWithOutput)) reachable.add(name);
}
const modelDeps = <span class="cstat-no" title="statement not covered" >new Map&lt;string, Set&lt;string&gt;&gt;();</span>
<span class="cstat-no" title="statement not covered" > for (const contractAst of contractAsts) {</span>
<span class="cstat-no" title="statement not covered" > for (const model of contractAst.models) {</span>
const deps = <span class="cstat-no" title="statement not covered" >new Set&lt;string&gt;();</span>
<span class="cstat-no" title="statement not covered" > if (model.bases) <span class="cstat-no" title="statement not covered" >for (const b of model.bases) <span class="cstat-no" title="statement not covered" >deps.add(b);</span></span></span>
<span class="cstat-no" title="statement not covered" > if (model.type<span class="cstat-no" title="statement not covered" >) collectTypeRefs(model.type, deps);</span></span>
<span class="cstat-no" title="statement not covered" > for (const field of model.fields<span class="cstat-no" title="statement not covered" >) collectTypeRefs(field.type, deps);</span></span>
<span class="cstat-no" title="statement not covered" > modelDeps.set(model.name, deps);</span>
const modelDeps = new Map&lt;string, Set&lt;string&gt;&gt;();
for (const contractAst of contractAsts) {
for (const model of contractAst.models) {
const deps = new Set&lt;string&gt;();
<span class="missing-if-branch" title="if path not taken" >I</span>if (model.bases) <span class="cstat-no" title="statement not covered" >for (const b of model.bases) <span class="cstat-no" title="statement not covered" >deps.add(b);</span></span>
<span class="missing-if-branch" title="if path not taken" >I</span>if (model.type<span class="cstat-no" title="statement not covered" >) collectTypeRefs(model.type, deps);</span>
for (const field of model.fields) collectTypeRefs(field.type, deps);
modelDeps.set(model.name, deps);
}
}
const frontier = <span class="cstat-no" title="statement not covered" >[...reachable];</span>
<span class="cstat-no" title="statement not covered" > while (frontier.length &gt; 0) {</span>
const name = <span class="cstat-no" title="statement not covered" >frontier.pop()!;</span>
const baseName = <span class="cstat-no" title="statement not covered" >name.endsWith('Input') ? name.slice(0, -5) : name.endsWith('Output') ? name.slice(0, -6) : name;</span>
<span class="cstat-no" title="statement not covered" > for (const dep of modelDeps.get(baseName) ?? []) {</span>
const frontier = [...reachable];
while (frontier.length &gt; 0) {
const name = frontier.pop()!;
const baseName = name.endsWith('Input') ? <span class="branch-0 cbranch-no" title="branch not covered" >name.slice(0, -5) : n</span>ame.endsWith('Output') ? <span class="branch-0 cbranch-no" title="branch not covered" >name.slice(0, -6) : n</span>ame;
for (const dep of modelDeps.get(baseName) ?? <span class="branch-1 cbranch-no" title="branch not covered" >[])</span> {
<span class="cstat-no" title="statement not covered" > if (!reachable.has(dep)) {</span>

@@ -740,3 +740,3 @@ <span class="cstat-no" title="statement not covered" > reachable.add(dep);</span>

}
<span class="cstat-no" title="statement not covered" > return reachable;</span>
return reachable;
}

@@ -750,3 +750,3 @@ &nbsp;</pre></td></tr></table></pre>

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -753,0 +753,0 @@ <script src="../prettify.js"></script>

@@ -240,3 +240,3 @@

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">178x</span>
<span class="cline-any cline-yes">181x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -258,5 +258,5 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">347x</span>
<span class="cline-any cline-yes">353x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">170x</span>
<span class="cline-any cline-yes">173x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -286,3 +286,3 @@ <span class="cline-any cline-yes">20x</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">119x</span>
<span class="cline-any cline-yes">122x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -298,3 +298,3 @@ <span class="cline-any cline-yes">2x</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">170x</span>
<span class="cline-any cline-yes">173x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -304,3 +304,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">116x</span>
<span class="cline-any cline-yes">118x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -317,3 +317,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -383,3 +383,3 @@ <span class="cline-any cline-yes">4x</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">95x</span>
<span class="cline-any cline-yes">98x</span>
<span class="cline-any cline-yes">8x</span>

@@ -587,3 +587,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -590,0 +590,0 @@ <script src="../prettify.js"></script>

@@ -344,7 +344,7 @@

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">905x</span>
<span class="cline-any cline-yes">919x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">325x</span>
<span class="cline-any cline-yes">330x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -381,3 +381,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">208x</span>
<span class="cline-any cline-yes">211x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -394,3 +394,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">265x</span>
<span class="cline-any cline-yes">270x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -407,3 +407,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">181x</span>
<span class="cline-any cline-yes">184x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -418,3 +418,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">140x</span>
<span class="cline-any cline-yes">143x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -454,12 +454,12 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">123x</span>
<span class="cline-any cline-yes">123x</span>
<span class="cline-any cline-yes">126x</span>
<span class="cline-any cline-yes">126x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">104x</span>
<span class="cline-any cline-yes">104x</span>
<span class="cline-any cline-yes">107x</span>
<span class="cline-any cline-yes">107x</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">97x</span>
<span class="cline-any cline-yes">100x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -478,6 +478,6 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">213x</span>
<span class="cline-any cline-yes">213x</span>
<span class="cline-any cline-yes">213x</span>
<span class="cline-any cline-yes">213x</span>
<span class="cline-any cline-yes">216x</span>
<span class="cline-any cline-yes">216x</span>
<span class="cline-any cline-yes">216x</span>
<span class="cline-any cline-yes">216x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -496,8 +496,8 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">203x</span>
<span class="cline-any cline-yes">203x</span>
<span class="cline-any cline-yes">206x</span>
<span class="cline-any cline-yes">206x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">199x</span>
<span class="cline-any cline-yes">202x</span>
<span class="cline-any cline-neutral">&nbsp;</span>

@@ -822,3 +822,3 @@ <span class="cline-any cline-neutral">&nbsp;</span>

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -825,0 +825,0 @@ <script src="../prettify.js"></script>

@@ -104,3 +104,3 @@

<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2026-06-12T19:14:46.813Z
at 2026-06-16T15:55:46.002Z
</div>

@@ -107,0 +107,0 @@ <script src="../prettify.js"></script>

@@ -78,3 +78,25 @@ import type { OpRootNode } from '@contractkit/core';

export declare function generateSdkOptions(): string;
/** Which optional runtime deps the generated SDK references, derived from the contracts it covers. */
export interface SdkScaffoldDeps {
/** Zod schema files are emitted (`config.zod`) — the SDK imports `zod`. */
zod: boolean;
/** Any covered model uses a `date`/`time`/`datetime`/`interval` scalar — the SDK imports `luxon`. */
luxon: boolean;
}
/**
* Generate a starter `package.json` for a generated SDK package. Emitted with
* `ifAbsent` semantics — written once, then owned by the user — so the dependency
* ranges here are only ever a starting point, never re-applied on later builds.
*/
export declare function generateSdkPackageJson(input: {
name: string;
deps: SdkScaffoldDeps;
}): string;
/**
* Generate a standalone `tsconfig.json` for a generated SDK package. Deliberately
* self-contained (no workspace `extends`) so the scaffold works in a freshly
* `npm init`'d package outside this monorepo. Emitted with `ifAbsent` semantics.
*/
export declare function generateSdkTsconfig(): string;
/**
* Reference to a per-file leaf client emitted to its own `*.client.ts`. Used by the

@@ -81,0 +103,0 @@ * aggregator to import the class and wire it as either a top-level `sdk.<prop>` or a

@@ -1,1 +0,1 @@

{"version":3,"file":"codegen-sdk.d.ts","sourceRoot":"","sources":["../src/codegen-sdk.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"codegen-sdk.d.ts","sourceRoot":"","sources":["../src/codegen-sdk.ts"],"names":[],"mappings":"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"}

@@ -28,2 +28,11 @@ import type { ContractKitPlugin } from '@contractkit/core';

includeInternal?: boolean;
/**
* Emit a starter `package.json` and `tsconfig.json` at the SDK `baseDir` so the
* generated output is a buildable, publishable package on its own. Opt-in and
* write-once: the files are created only when absent and are never overwritten or
* cleaned up on later builds, so any edits you make to them are preserved.
* Dependency ranges are derived from the contracts (always `zod` when `zod: true`;
* `luxon` when any covered model uses a date/time/datetime/interval scalar).
*/
scaffold?: boolean;
}

@@ -30,0 +39,0 @@ export interface ZodConfig {

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,iBAAiB,EAQpB,MAAM,mBAAmB,CAAC;AA0C3B,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;CAC7B;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,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;CACvB;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"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,iBAAiB,EAQpB,MAAM,mBAAmB,CAAC;AA6C3B,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,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;CACvB;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"}
{
"name": "@contractkit/plugin-typescript",
"version": "0.26.0",
"version": "0.27.0",
"description": "ContractKit built-in plugin: TypeScript codegen (SDK clients, Koa routers, Zod schemas, plain types)",

@@ -29,3 +29,3 @@ "author": {

"dependencies": {
"@contractkit/core": "0.21.0"
"@contractkit/core": "0.22.0"
},

@@ -32,0 +32,0 @@ "devDependencies": {

@@ -962,3 +962,81 @@ import type { OpRootNode, OpRouteNode, OpOperationNode, OpRequestBodyNode, ContractTypeNode, ParamSource } from '@contractkit/core';

// ─── Scaffold files (package.json / tsconfig.json) ─────────────────────────
/** Pinned dependency ranges for scaffolded SDK packages. Kept in one place so they're easy to bump. */
const SCAFFOLD_DEP_VERSIONS = {
zod: '^4.3.6',
luxon: '^3.5.0',
typesLuxon: '^3.4.2',
typescript: '^6.0.3',
} as const;
/** Which optional runtime deps the generated SDK references, derived from the contracts it covers. */
export interface SdkScaffoldDeps {
/** Zod schema files are emitted (`config.zod`) — the SDK imports `zod`. */
zod: boolean;
/** Any covered model uses a `date`/`time`/`datetime`/`interval` scalar — the SDK imports `luxon`. */
luxon: boolean;
}
/**
* Generate a starter `package.json` for a generated SDK package. Emitted with
* `ifAbsent` semantics — written once, then owned by the user — so the dependency
* ranges here are only ever a starting point, never re-applied on later builds.
*/
export function generateSdkPackageJson(input: { name: string; deps: SdkScaffoldDeps }): string {
const dependencies: Record<string, string> = {};
if (input.deps.zod) dependencies.zod = SCAFFOLD_DEP_VERSIONS.zod;
if (input.deps.luxon) dependencies.luxon = SCAFFOLD_DEP_VERSIONS.luxon;
const devDependencies: Record<string, string> = { typescript: SCAFFOLD_DEP_VERSIONS.typescript };
if (input.deps.luxon) devDependencies['@types/luxon'] = SCAFFOLD_DEP_VERSIONS.typesLuxon;
const pkg = {
name: input.name,
version: '0.0.0',
type: 'module',
main: './dist/index.js',
types: './dist/index.d.ts',
exports: {
'.': {
types: './dist/index.d.ts',
import: './dist/index.js',
},
},
files: ['dist'],
scripts: {
build: 'tsc -p tsconfig.json',
},
...(Object.keys(dependencies).length > 0 ? { dependencies } : {}),
devDependencies,
};
return JSON.stringify(pkg, null, 4) + '\n';
}
/**
* Generate a standalone `tsconfig.json` for a generated SDK package. Deliberately
* self-contained (no workspace `extends`) so the scaffold works in a freshly
* `npm init`'d package outside this monorepo. Emitted with `ifAbsent` semantics.
*/
export function generateSdkTsconfig(): string {
const tsconfig = {
compilerOptions: {
target: 'ES2022',
module: 'NodeNext',
moduleResolution: 'NodeNext',
declaration: true,
outDir: './dist',
rootDir: './src',
strict: true,
esModuleInterop: true,
skipLibCheck: true,
forceConsistentCasingInFileNames: true,
},
include: ['src'],
exclude: ['dist', 'node_modules'],
};
return JSON.stringify(tsconfig, null, 4) + '\n';
}
/**
* Reference to a per-file leaf client emitted to its own `*.client.ts`. Used by the

@@ -965,0 +1043,0 @@ * aggregator to import the class and wire it as either a top-level `sdk.<prop>` or a

import { resolve, join, relative, dirname, basename } from 'node:path';
import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, rmdirSync } from 'node:fs';
import { generateContract } from './codegen-contract.js';
import { generateContract, rootNeedsScalar } from './codegen-contract.js';
import { generateOp } from './codegen-operation.js';

@@ -37,4 +37,7 @@ import type {

hasPublicOperations,
generateSdkPackageJson,
generateSdkTsconfig,
type SdkClientInfo,
type SdkAreaInfo,
type SdkScaffoldDeps,
} from './codegen-sdk.js';

@@ -84,2 +87,11 @@ import { generatePlainTypes } from './codegen-plain-types.js';

includeInternal?: boolean;
/**
* Emit a starter `package.json` and `tsconfig.json` at the SDK `baseDir` so the
* generated output is a buildable, publishable package on its own. Opt-in and
* write-once: the files are created only when absent and are never overwritten or
* cleaned up on later builds, so any edits you make to them are preserved.
* Dependency ranges are derived from the contracts (always `zod` when `zod: true`;
* `luxon` when any covered model uses a date/time/datetime/interval scalar).
*/
scaffold?: boolean;
}

@@ -170,4 +182,4 @@

for (const { relativePath, content } of result.filesToWrite) {
ctx.emitFile(relativePath, content);
for (const { relativePath, content, ifAbsent } of result.filesToWrite) {
ctx.emitFile(relativePath, content, ifAbsent ? { ifAbsent: true } : undefined);
}

@@ -697,2 +709,27 @@

});
// ── Scaffold files (opt-in, write-once) ──
// Emitted at the SDK package root with `ifAbsent` so they're created once and
// then owned by the user. Deps are derived from the contracts actually surfaced
// into the SDK: zod when schema output is on, luxon when any covered model uses a
// date/time/datetime/interval scalar.
if (config.scaffold) {
const coveredRoots = sdkContractEntries.map(e => e.ast);
const deps: SdkScaffoldDeps = {
zod: !!config.zod,
luxon: coveredRoots.some(
r => rootNeedsScalar(r, 'datetime') || rootNeedsScalar(r, 'date') || rootNeedsScalar(r, 'time') || rootNeedsScalar(r, 'interval'),
),
};
globalFiles.push({
relativePath: join(sdkBase, 'package.json'),
content: generateSdkPackageJson({ name: sdkName ?? 'sdk', deps }),
ifAbsent: true,
});
globalFiles.push({
relativePath: join(sdkBase, 'tsconfig.json'),
content: generateSdkTsconfig(),
ifAbsent: true,
});
}
}

@@ -699,0 +736,0 @@

@@ -306,1 +306,108 @@ import { describe, it, expect } from 'vitest';

});
describe('createTypescriptPlugin (sdk) — scaffold', () => {
// ctx variant that records the ifAbsent flag passed to emitFile.
function makeScaffoldCtx(rootDir = '/project', options: Record<string, unknown> = {}): PluginContext & {
emitted: Map<string, { content: string; ifAbsent?: boolean }>;
} {
const emitted = new Map<string, { content: string; ifAbsent?: boolean }>();
return {
rootDir,
options,
cacheEnabled: true,
cacheDir: `${rootDir}/.contractkit/cache`,
emitFile: (outPath: string, content: string, opts?: { ifAbsent?: boolean }) => {
emitted.set(outPath, { content, ifAbsent: opts?.ifAbsent });
},
emitted,
};
}
function find(emitted: Map<string, { content: string; ifAbsent?: boolean }>, suffix: string) {
for (const [path, value] of emitted) if (path.endsWith(suffix)) return { path, ...value };
return undefined;
}
function eventInputs() {
// An op that responds with the Event model (has a datetime field) so the type
// is publicly reachable and surfaces into the SDK.
const root = opRoot(
[opRoute('/events', [opOperation('get', { sdk: 'getEvent', responses: [opResponse(200, 'Event', 'application/json')] })])],
'/project/contracts/events.ck',
);
return {
contractRoots: [contractRoot([model('Event', [field('id', scalarType('uuid')), field('at', scalarType('datetime'))])], '/project/contracts/events.ck')],
opRoots: [root],
modelOutPaths: new Map<string, string>(),
modelsWithInput: new Set<string>(),
modelsWithOutput: new Set<string>(),
};
}
it('does not emit scaffold files unless scaffold is enabled', async () => {
const plugin = createTypescriptPlugin(
{ sdk: { baseDir: 'packages/sdk', output: { sdk: 'src/sdk.ts', clients: 'src/{filename}.client.ts', types: 'src/types/{filename}.ts' } } },
'/project',
);
const ctx = makeScaffoldCtx();
await plugin.generateTargets!(eventInputs(), ctx);
expect(find(ctx.emitted, 'package.json')).toBeUndefined();
expect(find(ctx.emitted, 'tsconfig.json')).toBeUndefined();
});
it('emits package.json and tsconfig.json at the SDK baseDir as ifAbsent files', async () => {
const plugin = createTypescriptPlugin(
{
sdk: {
baseDir: 'packages/sdk',
name: 'my-sdk',
zod: true,
scaffold: true,
output: { sdk: 'src/sdk.ts', clients: 'src/{filename}.client.ts', types: 'src/types/{filename}.ts' },
},
},
'/project',
);
const ctx = makeScaffoldCtx();
await plugin.generateTargets!(eventInputs(), ctx);
const pkg = find(ctx.emitted, 'packages/sdk/package.json');
const tsconfig = find(ctx.emitted, 'packages/sdk/tsconfig.json');
expect(pkg).toBeDefined();
expect(tsconfig).toBeDefined();
// Both are write-once scaffold files.
expect(pkg!.ifAbsent).toBe(true);
expect(tsconfig!.ifAbsent).toBe(true);
// Name carried from sdk.name; zod (enabled) and luxon (datetime field) detected.
const parsed = JSON.parse(pkg!.content);
expect(parsed.name).toBe('my-sdk');
expect(parsed.dependencies.zod).toBeDefined();
expect(parsed.dependencies.luxon).toBeDefined();
});
it('omits luxon when no covered model uses a date/time scalar', async () => {
const root = opRoot(
[opRoute('/things', [opOperation('get', { sdk: 'getThing', responses: [opResponse(200, 'Thing', 'application/json')] })])],
'/project/contracts/things.ck',
);
const plugin = createTypescriptPlugin(
{ sdk: { baseDir: 'packages/sdk', scaffold: true, output: { sdk: 'src/sdk.ts', clients: 'src/{filename}.client.ts', types: 'src/types/{filename}.ts' } } },
'/project',
);
const ctx = makeScaffoldCtx();
await plugin.generateTargets!(
{
contractRoots: [contractRoot([model('Thing', [field('id', scalarType('uuid'))])], '/project/contracts/things.ck')],
opRoots: [root],
modelOutPaths: new Map<string, string>(),
modelsWithInput: new Set<string>(),
modelsWithOutput: new Set<string>(),
},
ctx,
);
const pkg = JSON.parse(find(ctx.emitted, 'packages/sdk/package.json')!.content);
expect(pkg.dependencies?.luxon).toBeUndefined();
// zod also absent (zod not enabled) → no dependencies block at all.
expect(pkg.dependencies).toBeUndefined();
});
});

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display