trickle-cli 0.1.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.
Files changed (125) hide show
  1. package/dist/api-client.d.ts +208 -0
  2. package/dist/api-client.js +237 -0
  3. package/dist/commands/annotate.d.ts +6 -0
  4. package/dist/commands/annotate.js +433 -0
  5. package/dist/commands/audit.d.ts +7 -0
  6. package/dist/commands/audit.js +82 -0
  7. package/dist/commands/auto.d.ts +8 -0
  8. package/dist/commands/auto.js +268 -0
  9. package/dist/commands/capture.d.ts +14 -0
  10. package/dist/commands/capture.js +271 -0
  11. package/dist/commands/check.d.ts +6 -0
  12. package/dist/commands/check.js +408 -0
  13. package/dist/commands/codegen.d.ts +21 -0
  14. package/dist/commands/codegen.js +129 -0
  15. package/dist/commands/coverage.d.ts +13 -0
  16. package/dist/commands/coverage.js +126 -0
  17. package/dist/commands/dashboard.d.ts +1 -0
  18. package/dist/commands/dashboard.js +83 -0
  19. package/dist/commands/dev.d.ts +14 -0
  20. package/dist/commands/dev.js +319 -0
  21. package/dist/commands/diff.d.ts +7 -0
  22. package/dist/commands/diff.js +79 -0
  23. package/dist/commands/docs.d.ts +13 -0
  24. package/dist/commands/docs.js +383 -0
  25. package/dist/commands/errors.d.ts +7 -0
  26. package/dist/commands/errors.js +180 -0
  27. package/dist/commands/export.d.ts +18 -0
  28. package/dist/commands/export.js +238 -0
  29. package/dist/commands/functions.d.ts +6 -0
  30. package/dist/commands/functions.js +71 -0
  31. package/dist/commands/infer.d.ts +14 -0
  32. package/dist/commands/infer.js +275 -0
  33. package/dist/commands/init.d.ts +5 -0
  34. package/dist/commands/init.js +395 -0
  35. package/dist/commands/mock.d.ts +5 -0
  36. package/dist/commands/mock.js +232 -0
  37. package/dist/commands/openapi.d.ts +8 -0
  38. package/dist/commands/openapi.js +82 -0
  39. package/dist/commands/overview.d.ts +11 -0
  40. package/dist/commands/overview.js +266 -0
  41. package/dist/commands/pack.d.ts +11 -0
  42. package/dist/commands/pack.js +133 -0
  43. package/dist/commands/proxy.d.ts +13 -0
  44. package/dist/commands/proxy.js +312 -0
  45. package/dist/commands/replay.d.ts +14 -0
  46. package/dist/commands/replay.js +289 -0
  47. package/dist/commands/run.d.ts +17 -0
  48. package/dist/commands/run.js +997 -0
  49. package/dist/commands/sample.d.ts +13 -0
  50. package/dist/commands/sample.js +260 -0
  51. package/dist/commands/search.d.ts +5 -0
  52. package/dist/commands/search.js +80 -0
  53. package/dist/commands/stubs.d.ts +6 -0
  54. package/dist/commands/stubs.js +187 -0
  55. package/dist/commands/tail.d.ts +4 -0
  56. package/dist/commands/tail.js +76 -0
  57. package/dist/commands/test-gen.d.ts +13 -0
  58. package/dist/commands/test-gen.js +237 -0
  59. package/dist/commands/trace.d.ts +14 -0
  60. package/dist/commands/trace.js +417 -0
  61. package/dist/commands/types.d.ts +7 -0
  62. package/dist/commands/types.js +128 -0
  63. package/dist/commands/unpack.d.ts +11 -0
  64. package/dist/commands/unpack.js +166 -0
  65. package/dist/commands/validate.d.ts +13 -0
  66. package/dist/commands/validate.js +310 -0
  67. package/dist/commands/watch.d.ts +9 -0
  68. package/dist/commands/watch.js +267 -0
  69. package/dist/config.d.ts +1 -0
  70. package/dist/config.js +66 -0
  71. package/dist/formatters/diff-formatter.d.ts +5 -0
  72. package/dist/formatters/diff-formatter.js +43 -0
  73. package/dist/formatters/type-formatter.d.ts +22 -0
  74. package/dist/formatters/type-formatter.js +135 -0
  75. package/dist/index.d.ts +2 -0
  76. package/dist/index.js +419 -0
  77. package/dist/local-codegen.d.ts +22 -0
  78. package/dist/local-codegen.js +762 -0
  79. package/dist/ui/badges.d.ts +16 -0
  80. package/dist/ui/badges.js +71 -0
  81. package/dist/ui/helpers.d.ts +13 -0
  82. package/dist/ui/helpers.js +85 -0
  83. package/package.json +23 -0
  84. package/src/api-client.ts +407 -0
  85. package/src/commands/annotate.ts +450 -0
  86. package/src/commands/audit.ts +103 -0
  87. package/src/commands/auto.ts +268 -0
  88. package/src/commands/capture.ts +257 -0
  89. package/src/commands/check.ts +437 -0
  90. package/src/commands/codegen.ts +128 -0
  91. package/src/commands/coverage.ts +170 -0
  92. package/src/commands/dashboard.ts +46 -0
  93. package/src/commands/dev.ts +323 -0
  94. package/src/commands/diff.ts +99 -0
  95. package/src/commands/docs.ts +392 -0
  96. package/src/commands/errors.ts +205 -0
  97. package/src/commands/export.ts +287 -0
  98. package/src/commands/functions.ts +81 -0
  99. package/src/commands/infer.ts +260 -0
  100. package/src/commands/init.ts +419 -0
  101. package/src/commands/mock.ts +220 -0
  102. package/src/commands/openapi.ts +53 -0
  103. package/src/commands/overview.ts +310 -0
  104. package/src/commands/pack.ts +139 -0
  105. package/src/commands/proxy.ts +314 -0
  106. package/src/commands/replay.ts +356 -0
  107. package/src/commands/run.ts +1190 -0
  108. package/src/commands/sample.ts +259 -0
  109. package/src/commands/search.ts +107 -0
  110. package/src/commands/stubs.ts +211 -0
  111. package/src/commands/tail.ts +94 -0
  112. package/src/commands/test-gen.ts +236 -0
  113. package/src/commands/trace.ts +440 -0
  114. package/src/commands/types.ts +161 -0
  115. package/src/commands/unpack.ts +179 -0
  116. package/src/commands/validate.ts +368 -0
  117. package/src/commands/watch.ts +277 -0
  118. package/src/config.ts +38 -0
  119. package/src/formatters/diff-formatter.ts +51 -0
  120. package/src/formatters/type-formatter.ts +161 -0
  121. package/src/index.ts +454 -0
  122. package/src/local-codegen.ts +859 -0
  123. package/src/ui/badges.ts +66 -0
  124. package/src/ui/helpers.ts +80 -0
  125. package/tsconfig.json +8 -0
@@ -0,0 +1,408 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.checkCommand = checkCommand;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const api_client_1 = require("../api-client");
44
+ /**
45
+ * Recursively diff two type nodes and classify changes as breaking or non-breaking.
46
+ *
47
+ * Breaking changes (for responses):
48
+ * - Field removed from response object
49
+ * - Field type changed in response
50
+ * - Array element type changed
51
+ *
52
+ * Non-breaking changes (for responses):
53
+ * - Field added to response object
54
+ *
55
+ * Breaking changes (for requests/args):
56
+ * - New required field added to request body
57
+ * - Field type changed in request
58
+ *
59
+ * Non-breaking changes (for requests/args):
60
+ * - Field removed from request (server no longer requires it)
61
+ */
62
+ function classifyChanges(baseline, current, basePath, context) {
63
+ const changes = [];
64
+ const b = baseline;
65
+ const c = current;
66
+ if (!b || !c)
67
+ return changes;
68
+ // Different kinds
69
+ if (b.kind !== c.kind) {
70
+ changes.push({
71
+ functionName: "",
72
+ severity: "breaking",
73
+ description: `Type changed from ${b.kind} to ${c.kind}`,
74
+ path: basePath || "(root)",
75
+ });
76
+ return changes;
77
+ }
78
+ switch (b.kind) {
79
+ case "primitive": {
80
+ if (b.name !== c.name) {
81
+ changes.push({
82
+ functionName: "",
83
+ severity: "breaking",
84
+ description: `Type changed from ${b.name} to ${c.name}`,
85
+ path: basePath || "(root)",
86
+ });
87
+ }
88
+ break;
89
+ }
90
+ case "object": {
91
+ const bProps = b.properties;
92
+ const cProps = c.properties;
93
+ const bKeys = new Set(Object.keys(bProps || {}));
94
+ const cKeys = new Set(Object.keys(cProps || {}));
95
+ // Fields in baseline but not in current
96
+ for (const key of bKeys) {
97
+ const childPath = basePath ? `${basePath}.${key}` : key;
98
+ if (!cKeys.has(key)) {
99
+ if (context === "response") {
100
+ // Removing a response field is breaking (clients may depend on it)
101
+ changes.push({
102
+ functionName: "",
103
+ severity: "breaking",
104
+ description: `Field removed from response`,
105
+ path: childPath,
106
+ });
107
+ }
108
+ else {
109
+ // Removing a request field is non-breaking (server no longer needs it)
110
+ changes.push({
111
+ functionName: "",
112
+ severity: "non-breaking",
113
+ description: `Field removed from request (no longer required)`,
114
+ path: childPath,
115
+ });
116
+ }
117
+ }
118
+ else {
119
+ // Recursively check
120
+ changes.push(...classifyChanges(bProps[key], cProps[key], childPath, context));
121
+ }
122
+ }
123
+ // Fields in current but not in baseline
124
+ for (const key of cKeys) {
125
+ if (!bKeys.has(key)) {
126
+ const childPath = basePath ? `${basePath}.${key}` : key;
127
+ if (context === "response") {
128
+ // Adding a response field is non-breaking
129
+ changes.push({
130
+ functionName: "",
131
+ severity: "non-breaking",
132
+ description: `Field added to response`,
133
+ path: childPath,
134
+ });
135
+ }
136
+ else {
137
+ // Adding a request field is breaking (callers don't send it yet)
138
+ changes.push({
139
+ functionName: "",
140
+ severity: "breaking",
141
+ description: `New required field added to request`,
142
+ path: childPath,
143
+ });
144
+ }
145
+ }
146
+ }
147
+ break;
148
+ }
149
+ case "array": {
150
+ const bEl = b.element;
151
+ const cEl = c.element;
152
+ changes.push(...classifyChanges(bEl, cEl, `${basePath || "(root)"}[]`, context));
153
+ break;
154
+ }
155
+ case "tuple": {
156
+ const bEls = b.elements;
157
+ const cEls = c.elements;
158
+ const maxLen = Math.max(bEls?.length || 0, cEls?.length || 0);
159
+ for (let i = 0; i < maxLen; i++) {
160
+ const elPath = `${basePath || "(root)"}[${i}]`;
161
+ if (i >= (bEls?.length || 0)) {
162
+ changes.push({
163
+ functionName: "",
164
+ severity: context === "response" ? "non-breaking" : "breaking",
165
+ description: `Element added`,
166
+ path: elPath,
167
+ });
168
+ }
169
+ else if (i >= (cEls?.length || 0)) {
170
+ changes.push({
171
+ functionName: "",
172
+ severity: "breaking",
173
+ description: `Element removed`,
174
+ path: elPath,
175
+ });
176
+ }
177
+ else {
178
+ changes.push(...classifyChanges(bEls[i], cEls[i], elPath, context));
179
+ }
180
+ }
181
+ break;
182
+ }
183
+ case "union": {
184
+ const bMembers = b.members.map((m) => JSON.stringify(m));
185
+ const cMembers = c.members.map((m) => JSON.stringify(m));
186
+ const bSet = new Set(bMembers);
187
+ const cSet = new Set(cMembers);
188
+ for (const m of bMembers) {
189
+ if (!cSet.has(m)) {
190
+ changes.push({
191
+ functionName: "",
192
+ severity: "breaking",
193
+ description: `Union member removed`,
194
+ path: basePath || "(root)",
195
+ });
196
+ }
197
+ }
198
+ for (const m of cMembers) {
199
+ if (!bSet.has(m)) {
200
+ changes.push({
201
+ functionName: "",
202
+ severity: "non-breaking",
203
+ description: `Union member added`,
204
+ path: basePath || "(root)",
205
+ });
206
+ }
207
+ }
208
+ break;
209
+ }
210
+ case "map": {
211
+ changes.push(...classifyChanges(b.value, c.value, `${basePath}<value>`, context));
212
+ break;
213
+ }
214
+ case "set": {
215
+ changes.push(...classifyChanges(b.element, c.element, `${basePath}<element>`, context));
216
+ break;
217
+ }
218
+ case "promise": {
219
+ changes.push(...classifyChanges(b.resolved, c.resolved, basePath, context));
220
+ break;
221
+ }
222
+ // unknown, function — no deep diff
223
+ }
224
+ return changes;
225
+ }
226
+ async function checkCommand(opts) {
227
+ try {
228
+ // Mode 1: Save current snapshot
229
+ if (opts.save) {
230
+ const snapshot = await (0, api_client_1.fetchSnapshot)({ env: opts.env });
231
+ if (snapshot.functions.length === 0) {
232
+ console.error(chalk_1.default.yellow("\n No functions observed yet. Run your app first to populate types.\n"));
233
+ process.exit(1);
234
+ }
235
+ const outPath = path.resolve(opts.save);
236
+ const dir = path.dirname(outPath);
237
+ if (!fs.existsSync(dir)) {
238
+ fs.mkdirSync(dir, { recursive: true });
239
+ }
240
+ fs.writeFileSync(outPath, JSON.stringify(snapshot, null, 2) + "\n", "utf-8");
241
+ console.log("");
242
+ console.log(chalk_1.default.green(` Baseline saved to ${chalk_1.default.bold(opts.save)}`));
243
+ console.log(chalk_1.default.gray(` ${snapshot.functions.length} function${snapshot.functions.length !== 1 ? "s" : ""} captured at ${snapshot.createdAt}`));
244
+ console.log("");
245
+ return;
246
+ }
247
+ // Mode 2: Check against baseline
248
+ if (opts.against) {
249
+ const baselinePath = path.resolve(opts.against);
250
+ if (!fs.existsSync(baselinePath)) {
251
+ console.error(chalk_1.default.red(`\n Baseline file not found: ${opts.against}\n`));
252
+ process.exit(1);
253
+ }
254
+ let baseline;
255
+ try {
256
+ baseline = JSON.parse(fs.readFileSync(baselinePath, "utf-8"));
257
+ }
258
+ catch {
259
+ console.error(chalk_1.default.red(`\n Invalid baseline file: ${opts.against}\n`));
260
+ process.exit(1);
261
+ return; // unreachable but satisfies TS
262
+ }
263
+ const current = await (0, api_client_1.fetchSnapshot)({ env: opts.env });
264
+ if (current.functions.length === 0) {
265
+ console.error(chalk_1.default.yellow("\n No functions observed yet. Run your app first to populate types.\n"));
266
+ process.exit(1);
267
+ }
268
+ console.log("");
269
+ console.log(chalk_1.default.white.bold(" trickle check"));
270
+ console.log(chalk_1.default.gray(` Baseline: ${opts.against} (${baseline.createdAt})`));
271
+ console.log(chalk_1.default.gray(` Current: ${current.functions.length} functions observed`));
272
+ console.log(chalk_1.default.gray(" " + "─".repeat(50)));
273
+ // Build lookup maps
274
+ const baselineMap = new Map();
275
+ for (const fn of baseline.functions) {
276
+ baselineMap.set(fn.name, fn);
277
+ }
278
+ const currentMap = new Map();
279
+ for (const fn of current.functions) {
280
+ currentMap.set(fn.name, fn);
281
+ }
282
+ const allChanges = [];
283
+ const removedFunctions = [];
284
+ const addedFunctions = [];
285
+ // Check for removed functions
286
+ for (const [name] of baselineMap) {
287
+ if (!currentMap.has(name)) {
288
+ removedFunctions.push(name);
289
+ allChanges.push({
290
+ functionName: name,
291
+ severity: "breaking",
292
+ description: "Function/route removed entirely",
293
+ path: "(function)",
294
+ });
295
+ }
296
+ }
297
+ // Check for added functions
298
+ for (const [name] of currentMap) {
299
+ if (!baselineMap.has(name)) {
300
+ addedFunctions.push(name);
301
+ allChanges.push({
302
+ functionName: name,
303
+ severity: "non-breaking",
304
+ description: "New function/route added",
305
+ path: "(function)",
306
+ });
307
+ }
308
+ }
309
+ // Check for type changes in existing functions
310
+ for (const [name, baselineFn] of baselineMap) {
311
+ const currentFn = currentMap.get(name);
312
+ if (!currentFn)
313
+ continue;
314
+ // Compare return types (response)
315
+ const returnChanges = classifyChanges(baselineFn.returnType, currentFn.returnType, "response", "response");
316
+ for (const change of returnChanges) {
317
+ change.functionName = name;
318
+ allChanges.push(change);
319
+ }
320
+ // Compare args types (request)
321
+ const argsChanges = classifyChanges(baselineFn.argsType, currentFn.argsType, "request", "request");
322
+ for (const change of argsChanges) {
323
+ change.functionName = name;
324
+ allChanges.push(change);
325
+ }
326
+ }
327
+ // Separate breaking vs non-breaking
328
+ const breaking = allChanges.filter((c) => c.severity === "breaking");
329
+ const nonBreaking = allChanges.filter((c) => c.severity === "non-breaking");
330
+ // Display results
331
+ if (breaking.length === 0 && nonBreaking.length === 0) {
332
+ console.log("");
333
+ console.log(chalk_1.default.green(" No type changes detected. API is compatible with baseline."));
334
+ console.log("");
335
+ return;
336
+ }
337
+ if (breaking.length > 0) {
338
+ console.log("");
339
+ console.log(chalk_1.default.red.bold(` ${breaking.length} BREAKING CHANGE${breaking.length !== 1 ? "S" : ""}`));
340
+ console.log("");
341
+ // Group by function
342
+ const grouped = new Map();
343
+ for (const change of breaking) {
344
+ const list = grouped.get(change.functionName) || [];
345
+ list.push(change);
346
+ grouped.set(change.functionName, list);
347
+ }
348
+ for (const [fnName, changes] of grouped) {
349
+ console.log(chalk_1.default.white(` ${fnName}`));
350
+ for (const change of changes) {
351
+ console.log(chalk_1.default.red(" ✗ ") +
352
+ chalk_1.default.gray(change.path) +
353
+ chalk_1.default.red(` — ${change.description}`));
354
+ }
355
+ }
356
+ }
357
+ if (nonBreaking.length > 0) {
358
+ console.log("");
359
+ console.log(chalk_1.default.yellow(` ${nonBreaking.length} non-breaking change${nonBreaking.length !== 1 ? "s" : ""}`));
360
+ console.log("");
361
+ const grouped = new Map();
362
+ for (const change of nonBreaking) {
363
+ const list = grouped.get(change.functionName) || [];
364
+ list.push(change);
365
+ grouped.set(change.functionName, list);
366
+ }
367
+ for (const [fnName, changes] of grouped) {
368
+ console.log(chalk_1.default.white(` ${fnName}`));
369
+ for (const change of changes) {
370
+ console.log(chalk_1.default.green(" + ") +
371
+ chalk_1.default.gray(change.path) +
372
+ chalk_1.default.gray(` — ${change.description}`));
373
+ }
374
+ }
375
+ }
376
+ console.log("");
377
+ // Summary
378
+ if (breaking.length > 0) {
379
+ console.log(chalk_1.default.red.bold(" FAIL") + chalk_1.default.red(` — ${breaking.length} breaking change${breaking.length !== 1 ? "s" : ""} detected`));
380
+ console.log("");
381
+ process.exit(1);
382
+ }
383
+ else {
384
+ console.log(chalk_1.default.green.bold(" PASS") + chalk_1.default.green(` — ${nonBreaking.length} non-breaking change${nonBreaking.length !== 1 ? "s" : ""}, no breaking changes`));
385
+ console.log("");
386
+ }
387
+ return;
388
+ }
389
+ // No flags — show usage
390
+ console.log("");
391
+ console.log(chalk_1.default.white.bold(" trickle check") + chalk_1.default.gray(" — detect breaking API changes"));
392
+ console.log("");
393
+ console.log(chalk_1.default.white(" Save a baseline:"));
394
+ console.log(chalk_1.default.cyan(" trickle check --save baseline.json"));
395
+ console.log("");
396
+ console.log(chalk_1.default.white(" Check against baseline:"));
397
+ console.log(chalk_1.default.cyan(" trickle check --against baseline.json"));
398
+ console.log("");
399
+ console.log(chalk_1.default.gray(" Exit code 0 = compatible, exit code 1 = breaking changes"));
400
+ console.log("");
401
+ }
402
+ catch (err) {
403
+ if (err instanceof Error) {
404
+ console.error(chalk_1.default.red(`\n Error: ${err.message}\n`));
405
+ }
406
+ process.exit(1);
407
+ }
408
+ }
@@ -0,0 +1,21 @@
1
+ export interface CodegenOptions {
2
+ out?: string;
3
+ env?: string;
4
+ python?: boolean;
5
+ client?: boolean;
6
+ handlers?: boolean;
7
+ zod?: boolean;
8
+ reactQuery?: boolean;
9
+ guards?: boolean;
10
+ middleware?: boolean;
11
+ msw?: boolean;
12
+ jsonSchema?: boolean;
13
+ swr?: boolean;
14
+ pydantic?: boolean;
15
+ classValidator?: boolean;
16
+ graphql?: boolean;
17
+ trpc?: boolean;
18
+ axios?: boolean;
19
+ watch?: boolean;
20
+ }
21
+ export declare function codegenCommand(functionName: string | undefined, opts: CodegenOptions): Promise<void>;
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.codegenCommand = codegenCommand;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const api_client_1 = require("../api-client");
44
+ async function codegenCommand(functionName, opts) {
45
+ const language = opts.python ? "python" : undefined;
46
+ const format = opts.axios ? "axios" : opts.trpc ? "trpc" : opts.graphql ? "graphql" : opts.classValidator ? "class-validator" : opts.pydantic ? "pydantic" : opts.swr ? "swr" : opts.jsonSchema ? "json-schema" : opts.msw ? "msw" : opts.middleware ? "middleware" : opts.guards ? "guards" : opts.reactQuery ? "react-query" : opts.zod ? "zod" : opts.handlers ? "handlers" : opts.client ? "client" : undefined;
47
+ async function generate() {
48
+ const result = await (0, api_client_1.fetchCodegen)({
49
+ functionName,
50
+ env: opts.env,
51
+ language,
52
+ format,
53
+ });
54
+ return result.types;
55
+ }
56
+ if (opts.watch) {
57
+ console.log(chalk_1.default.gray("\n Watching for type changes (polling every 5s)...\n"));
58
+ console.log(chalk_1.default.gray(" Press Ctrl+C to stop.\n"));
59
+ let lastOutput = "";
60
+ const poll = async () => {
61
+ try {
62
+ const types = await generate();
63
+ if (types !== lastOutput) {
64
+ lastOutput = types;
65
+ if (opts.out) {
66
+ writeToFile(opts.out, types, opts.python);
67
+ console.log(chalk_1.default.green(` Updated ${chalk_1.default.bold(opts.out)}`) +
68
+ chalk_1.default.gray(` at ${new Date().toLocaleTimeString()}`));
69
+ }
70
+ else {
71
+ console.clear();
72
+ console.log(types);
73
+ }
74
+ }
75
+ }
76
+ catch (err) {
77
+ if (err instanceof Error) {
78
+ console.error(chalk_1.default.red(` Error: ${err.message}`));
79
+ }
80
+ }
81
+ };
82
+ await poll();
83
+ const interval = setInterval(poll, 5000);
84
+ // Keep process alive until Ctrl+C
85
+ process.on("SIGINT", () => {
86
+ clearInterval(interval);
87
+ console.log(chalk_1.default.gray("\n Stopped watching.\n"));
88
+ process.exit(0);
89
+ });
90
+ // Prevent the process from exiting
91
+ await new Promise(() => { });
92
+ return;
93
+ }
94
+ // One-shot generation
95
+ try {
96
+ const types = await generate();
97
+ if (opts.out) {
98
+ writeToFile(opts.out, types, opts.python);
99
+ const ext = opts.python ? ".pyi" : ".d.ts";
100
+ console.log("");
101
+ console.log(chalk_1.default.green(` Types written to ${chalk_1.default.bold(opts.out)}`));
102
+ console.log(chalk_1.default.gray(` ${countInterfaces(types)} type definitions generated.`));
103
+ console.log("");
104
+ }
105
+ else {
106
+ console.log("");
107
+ console.log(types);
108
+ }
109
+ }
110
+ catch (err) {
111
+ if (err instanceof Error) {
112
+ console.error(chalk_1.default.red(`\n Error: ${err.message}\n`));
113
+ }
114
+ process.exit(1);
115
+ }
116
+ }
117
+ function writeToFile(filePath, content, _python) {
118
+ const resolvedPath = path.resolve(filePath);
119
+ const dir = path.dirname(resolvedPath);
120
+ if (!fs.existsSync(dir)) {
121
+ fs.mkdirSync(dir, { recursive: true });
122
+ }
123
+ fs.writeFileSync(resolvedPath, content, "utf-8");
124
+ }
125
+ function countInterfaces(types) {
126
+ const tsMatches = types.match(/export (interface|type) /g);
127
+ const pyMatches = types.match(/class \w+\(TypedDict\)/g);
128
+ return (tsMatches?.length ?? 0) + (pyMatches?.length ?? 0);
129
+ }
@@ -0,0 +1,13 @@
1
+ export interface CoverageOptions {
2
+ env?: string;
3
+ json?: boolean;
4
+ failUnder?: string;
5
+ staleHours?: string;
6
+ }
7
+ /**
8
+ * `trickle coverage` — Type observation health report.
9
+ *
10
+ * Shows per-function type coverage, staleness, variant counts,
11
+ * error counts, and an overall health score. Useful for CI gates.
12
+ */
13
+ export declare function coverageCommand(opts: CoverageOptions): Promise<void>;