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,383 @@
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.docsCommand = docsCommand;
40
+ const fs = __importStar(require("fs"));
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const api_client_1 = require("../api-client");
43
+ /**
44
+ * `trickle docs` — Generate API documentation from observed runtime types.
45
+ *
46
+ * Produces clean Markdown (or self-contained HTML) documenting every
47
+ * observed API route with request/response types and example payloads.
48
+ */
49
+ async function docsCommand(opts) {
50
+ const title = opts.title || "API Documentation";
51
+ // Fetch data
52
+ let routes;
53
+ let typesContent;
54
+ let totalFunctions;
55
+ try {
56
+ const [mockConfig, codegen, funcList] = await Promise.all([
57
+ (0, api_client_1.fetchMockConfig)(),
58
+ (0, api_client_1.fetchCodegen)({ env: opts.env }),
59
+ (0, api_client_1.listFunctions)({ env: opts.env, limit: 500 }),
60
+ ]);
61
+ routes = mockConfig.routes;
62
+ typesContent = codegen.types;
63
+ totalFunctions = funcList.total;
64
+ }
65
+ catch {
66
+ console.error(chalk_1.default.red("\n Cannot connect to trickle backend."));
67
+ console.error(chalk_1.default.gray(" Is the backend running?\n"));
68
+ process.exit(1);
69
+ }
70
+ if (routes.length === 0) {
71
+ console.error(chalk_1.default.yellow("\n No observed API routes to document."));
72
+ console.error(chalk_1.default.gray(" Instrument your app and make some requests first.\n"));
73
+ process.exit(0);
74
+ }
75
+ // Parse type definitions to map route names to their types
76
+ const typeMap = buildTypeMap(typesContent);
77
+ // Group routes by resource
78
+ const groups = groupRoutesByResource(routes);
79
+ // Generate markdown
80
+ const markdown = generateMarkdown(title, groups, typeMap, totalFunctions);
81
+ if (opts.html) {
82
+ const html = wrapInHtml(title, markdown);
83
+ if (opts.out) {
84
+ fs.writeFileSync(opts.out, html, "utf-8");
85
+ console.log(chalk_1.default.green(`\n API docs written to ${chalk_1.default.bold(opts.out)}`));
86
+ console.log(chalk_1.default.gray(` ${routes.length} routes documented\n`));
87
+ }
88
+ else {
89
+ console.log(html);
90
+ }
91
+ }
92
+ else {
93
+ if (opts.out) {
94
+ fs.writeFileSync(opts.out, markdown, "utf-8");
95
+ console.log(chalk_1.default.green(`\n API docs written to ${chalk_1.default.bold(opts.out)}`));
96
+ console.log(chalk_1.default.gray(` ${routes.length} routes documented\n`));
97
+ }
98
+ else {
99
+ console.log(markdown);
100
+ }
101
+ }
102
+ }
103
+ function groupRoutesByResource(routes) {
104
+ const groups = {};
105
+ for (const route of routes) {
106
+ const parts = route.path.split("/").filter(Boolean);
107
+ let resource;
108
+ if (parts[0] === "api" && parts.length >= 2) {
109
+ resource = `/${parts[0]}/${parts[1]}`;
110
+ }
111
+ else {
112
+ resource = `/${parts[0] || "root"}`;
113
+ }
114
+ if (!groups[resource])
115
+ groups[resource] = [];
116
+ groups[resource].push(route);
117
+ }
118
+ // Sort groups alphabetically, routes by method order
119
+ const methodOrder = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 };
120
+ const result = [];
121
+ for (const [resource, resourceRoutes] of Object.entries(groups).sort((a, b) => a[0].localeCompare(b[0]))) {
122
+ resourceRoutes.sort((a, b) => {
123
+ const ma = methodOrder[a.method] ?? 5;
124
+ const mb = methodOrder[b.method] ?? 5;
125
+ if (ma !== mb)
126
+ return ma - mb;
127
+ return a.path.localeCompare(b.path);
128
+ });
129
+ result.push({ resource, routes: resourceRoutes });
130
+ }
131
+ return result;
132
+ }
133
+ /**
134
+ * Extract type definitions from generated TypeScript code and map them
135
+ * to route function names.
136
+ */
137
+ function buildTypeMap(typesContent) {
138
+ const map = new Map();
139
+ if (!typesContent)
140
+ return map;
141
+ // Find interface/type blocks and their associated route comments
142
+ const blocks = typesContent.split(/(?=\/\*\*|export interface|export type)/);
143
+ let currentComment = "";
144
+ for (const block of blocks) {
145
+ if (block.startsWith("/**")) {
146
+ currentComment = block;
147
+ continue;
148
+ }
149
+ const match = block.match(/export (?:interface|type) (\w+)/);
150
+ if (match) {
151
+ const typeName = match[1];
152
+ // Clean up the block
153
+ const cleanBlock = block.trim();
154
+ if (cleanBlock) {
155
+ map.set(typeName, cleanBlock);
156
+ }
157
+ }
158
+ currentComment = "";
159
+ }
160
+ return map;
161
+ }
162
+ function toPascalCase(name) {
163
+ return name
164
+ .replace(/[^a-zA-Z0-9]+/g, " ")
165
+ .split(/\s+/)
166
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
167
+ .join("");
168
+ }
169
+ function generateMarkdown(title, groups, typeMap, totalFunctions) {
170
+ const lines = [];
171
+ const now = new Date().toISOString().split("T")[0];
172
+ lines.push(`# ${title}`);
173
+ lines.push("");
174
+ lines.push(`> Auto-generated by [trickle](https://github.com/yiheinchai/trickle) from runtime-observed types.`);
175
+ lines.push(`> Generated on ${now} — ${totalFunctions} functions observed.`);
176
+ lines.push("");
177
+ // Table of contents
178
+ lines.push("## Table of Contents");
179
+ lines.push("");
180
+ for (const group of groups) {
181
+ const anchor = group.resource.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
182
+ lines.push(`- [${group.resource}](#${anchor})`);
183
+ }
184
+ lines.push("");
185
+ lines.push("---");
186
+ lines.push("");
187
+ // Route groups
188
+ for (const group of groups) {
189
+ lines.push(`## ${group.resource}`);
190
+ lines.push("");
191
+ for (const route of group.routes) {
192
+ const methodBadge = `\`${route.method}\``;
193
+ lines.push(`### ${methodBadge} ${route.path}`);
194
+ lines.push("");
195
+ // Metadata
196
+ const observed = route.observedAt ? new Date(route.observedAt).toISOString().split("T")[0] : "unknown";
197
+ lines.push(`*Last observed: ${observed}*`);
198
+ lines.push("");
199
+ // Request body
200
+ const hasBody = ["POST", "PUT", "PATCH"].includes(route.method);
201
+ if (hasBody && route.sampleInput) {
202
+ const input = route.sampleInput;
203
+ const body = input.body || input;
204
+ if (body && typeof body === "object" && Object.keys(body).length > 0) {
205
+ lines.push("**Request Body**");
206
+ lines.push("");
207
+ lines.push("```typescript");
208
+ lines.push(formatTypeFromSample(body));
209
+ lines.push("```");
210
+ lines.push("");
211
+ lines.push("<details>");
212
+ lines.push("<summary>Example</summary>");
213
+ lines.push("");
214
+ lines.push("```json");
215
+ lines.push(JSON.stringify(body, null, 2));
216
+ lines.push("```");
217
+ lines.push("</details>");
218
+ lines.push("");
219
+ }
220
+ }
221
+ // Response
222
+ if (route.sampleOutput) {
223
+ // Try to find the TypeScript type
224
+ const typeName = toPascalCase(route.functionName);
225
+ const responseTypeName = typeName + "Response";
226
+ const typeBlock = typeMap.get(responseTypeName);
227
+ lines.push("**Response**");
228
+ lines.push("");
229
+ if (typeBlock) {
230
+ lines.push("```typescript");
231
+ lines.push(typeBlock);
232
+ lines.push("```");
233
+ }
234
+ else {
235
+ lines.push("```typescript");
236
+ lines.push(formatTypeFromSample(route.sampleOutput));
237
+ lines.push("```");
238
+ }
239
+ lines.push("");
240
+ lines.push("<details>");
241
+ lines.push("<summary>Example Response</summary>");
242
+ lines.push("");
243
+ lines.push("```json");
244
+ lines.push(JSON.stringify(route.sampleOutput, null, 2));
245
+ lines.push("```");
246
+ lines.push("</details>");
247
+ lines.push("");
248
+ }
249
+ lines.push("---");
250
+ lines.push("");
251
+ }
252
+ }
253
+ // Footer
254
+ lines.push("*Generated by trickle — runtime type observability for JavaScript and Python.*");
255
+ lines.push("");
256
+ return lines.join("\n");
257
+ }
258
+ /**
259
+ * Infer a TypeScript type string from a sample JSON value.
260
+ */
261
+ function formatTypeFromSample(value, indent = 0) {
262
+ const pad = " ".repeat(indent);
263
+ if (value === null)
264
+ return `${pad}null`;
265
+ if (value === undefined)
266
+ return `${pad}undefined`;
267
+ switch (typeof value) {
268
+ case "string": return `${pad}string`;
269
+ case "number": return `${pad}number`;
270
+ case "boolean": return `${pad}boolean`;
271
+ }
272
+ if (Array.isArray(value)) {
273
+ if (value.length === 0)
274
+ return `${pad}unknown[]`;
275
+ const elementType = formatTypeFromSample(value[0], 0);
276
+ if (elementType.includes("\n")) {
277
+ // Multi-line element
278
+ return `${pad}Array<${formatTypeFromSample(value[0], indent).trimStart()}>`;
279
+ }
280
+ return `${pad}${elementType.trim()}[]`;
281
+ }
282
+ if (typeof value === "object") {
283
+ const obj = value;
284
+ const keys = Object.keys(obj);
285
+ if (keys.length === 0)
286
+ return `${pad}{}`;
287
+ const lines = [];
288
+ lines.push(`${pad}{`);
289
+ for (const key of keys) {
290
+ const val = obj[key];
291
+ const valType = formatTypeFromSample(val, indent + 1).trimStart();
292
+ lines.push(`${pad} ${key}: ${valType};`);
293
+ }
294
+ lines.push(`${pad}}`);
295
+ return lines.join("\n");
296
+ }
297
+ return `${pad}unknown`;
298
+ }
299
+ /**
300
+ * Wrap markdown in a self-contained HTML document with a simple renderer.
301
+ */
302
+ function wrapInHtml(title, markdown) {
303
+ // Escape for embedding in JS
304
+ const escapedMd = markdown
305
+ .replace(/\\/g, "\\\\")
306
+ .replace(/`/g, "\\`")
307
+ .replace(/\$/g, "\\$");
308
+ return `<!DOCTYPE html>
309
+ <html lang="en">
310
+ <head>
311
+ <meta charset="UTF-8">
312
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
313
+ <title>${escapeHtml(title)}</title>
314
+ <style>
315
+ * { margin: 0; padding: 0; box-sizing: border-box; }
316
+ body {
317
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
318
+ line-height: 1.6; color: #1a1a2e; background: #fafafa;
319
+ max-width: 900px; margin: 0 auto; padding: 2rem 1.5rem;
320
+ }
321
+ h1 { font-size: 2rem; margin-bottom: 0.5rem; border-bottom: 2px solid #e0e0e0; padding-bottom: 0.5rem; }
322
+ h2 { font-size: 1.5rem; margin-top: 2rem; margin-bottom: 0.75rem; color: #2d3748; border-bottom: 1px solid #e2e8f0; padding-bottom: 0.3rem; }
323
+ h3 { font-size: 1.1rem; margin-top: 1.5rem; margin-bottom: 0.5rem; }
324
+ p { margin-bottom: 0.75rem; }
325
+ blockquote { border-left: 3px solid #cbd5e0; padding-left: 1rem; color: #718096; margin-bottom: 1rem; }
326
+ code { background: #f0f0f0; padding: 0.15em 0.4em; border-radius: 3px; font-size: 0.9em; }
327
+ pre { background: #1a1a2e; color: #e2e8f0; padding: 1rem; border-radius: 6px; overflow-x: auto; margin-bottom: 1rem; }
328
+ pre code { background: none; padding: 0; color: inherit; }
329
+ hr { border: none; border-top: 1px solid #e2e8f0; margin: 1.5rem 0; }
330
+ em { color: #718096; }
331
+ strong { color: #2d3748; }
332
+ ul { padding-left: 1.5rem; margin-bottom: 0.75rem; }
333
+ li { margin-bottom: 0.25rem; }
334
+ a { color: #3182ce; text-decoration: none; }
335
+ a:hover { text-decoration: underline; }
336
+ details { margin-bottom: 1rem; }
337
+ summary { cursor: pointer; color: #3182ce; font-weight: 500; margin-bottom: 0.5rem; }
338
+ summary:hover { text-decoration: underline; }
339
+ /* Method badges */
340
+ code:first-child { font-weight: bold; }
341
+ </style>
342
+ </head>
343
+ <body>
344
+ <div id="content"></div>
345
+ <script>
346
+ // Simple markdown renderer
347
+ function renderMd(md) {
348
+ let html = md;
349
+ // Code blocks (fenced)
350
+ html = html.replace(/\`\`\`(\\w*)\\n([\\s\\S]*?)\`\`\`/g, '<pre><code class="lang-$1">$2</code></pre>');
351
+ // Inline code
352
+ html = html.replace(/\`([^\`]+)\`/g, '<code>$1</code>');
353
+ // Headers
354
+ html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
355
+ html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
356
+ html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
357
+ // Blockquotes
358
+ html = html.replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>');
359
+ // Bold
360
+ html = html.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
361
+ // Italic
362
+ html = html.replace(/\\*(.+?)\\*/g, '<em>$1</em>');
363
+ // Links
364
+ html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href="$2">$1</a>');
365
+ // Unordered lists
366
+ html = html.replace(/^- (.+)$/gm, '<li>$1</li>');
367
+ html = html.replace(/(<li>.*<\\/li>\\n?)+/g, '<ul>$&</ul>');
368
+ // HR
369
+ html = html.replace(/^---$/gm, '<hr>');
370
+ // Details/summary (passthrough)
371
+ // Paragraphs
372
+ html = html.replace(/^(?!<[hupbold]|<li|<ul|<hr|<details|<summary|<\\/|<pre|<blockquote)(.+)$/gm, '<p>$1</p>');
373
+ return html;
374
+ }
375
+ const md = \`${escapedMd}\`;
376
+ document.getElementById('content').innerHTML = renderMd(md);
377
+ </script>
378
+ </body>
379
+ </html>`;
380
+ }
381
+ function escapeHtml(str) {
382
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
383
+ }
@@ -0,0 +1,7 @@
1
+ export interface ErrorsListOptions {
2
+ env?: string;
3
+ since?: string;
4
+ function?: string;
5
+ limit?: string;
6
+ }
7
+ export declare function errorsCommand(idOrUndefined: string | undefined, opts: ErrorsListOptions): Promise<void>;
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.errorsCommand = errorsCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const cli_table3_1 = __importDefault(require("cli-table3"));
9
+ const api_client_1 = require("../api-client");
10
+ const badges_1 = require("../ui/badges");
11
+ const helpers_1 = require("../ui/helpers");
12
+ const type_formatter_1 = require("../formatters/type-formatter");
13
+ async function errorsCommand(idOrUndefined, opts) {
14
+ // If an ID was provided, show detail mode
15
+ if (idOrUndefined !== undefined) {
16
+ const id = parseInt(idOrUndefined, 10);
17
+ if (isNaN(id)) {
18
+ console.error(chalk_1.default.red(`\n Invalid error ID: "${idOrUndefined}"\n`));
19
+ process.exit(1);
20
+ }
21
+ await showErrorDetail(id);
22
+ return;
23
+ }
24
+ // List mode
25
+ let sinceIso;
26
+ if (opts.since) {
27
+ try {
28
+ sinceIso = (0, helpers_1.parseSince)(opts.since);
29
+ }
30
+ catch (err) {
31
+ if (err instanceof Error) {
32
+ console.error(chalk_1.default.red(`\n ${err.message}\n`));
33
+ }
34
+ process.exit(1);
35
+ }
36
+ }
37
+ const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;
38
+ const result = await (0, api_client_1.listErrors)({
39
+ env: opts.env,
40
+ functionName: opts.function,
41
+ since: sinceIso,
42
+ limit,
43
+ });
44
+ const { errors } = result;
45
+ if (errors.length === 0) {
46
+ console.log(chalk_1.default.yellow("\n No errors found.\n"));
47
+ if (opts.env || opts.since || opts.function) {
48
+ console.log(chalk_1.default.gray(" Try adjusting your filters.\n"));
49
+ }
50
+ return;
51
+ }
52
+ console.log("");
53
+ const table = new cli_table3_1.default({
54
+ head: [
55
+ chalk_1.default.cyan.bold("ID"),
56
+ chalk_1.default.cyan.bold("Function"),
57
+ chalk_1.default.cyan.bold("Error Type"),
58
+ chalk_1.default.cyan.bold("Message"),
59
+ chalk_1.default.cyan.bold("Env"),
60
+ chalk_1.default.cyan.bold("Time"),
61
+ ],
62
+ style: {
63
+ head: [],
64
+ border: ["gray"],
65
+ },
66
+ colWidths: [8, 22, 18, 36, 12, 12],
67
+ wordWrap: true,
68
+ chars: {
69
+ top: "─",
70
+ "top-mid": "┬",
71
+ "top-left": "┌",
72
+ "top-right": "┐",
73
+ bottom: "─",
74
+ "bottom-mid": "┴",
75
+ "bottom-left": "└",
76
+ "bottom-right": "┘",
77
+ left: "│",
78
+ "left-mid": "├",
79
+ mid: "─",
80
+ "mid-mid": "┼",
81
+ right: "│",
82
+ "right-mid": "┤",
83
+ middle: "│",
84
+ },
85
+ });
86
+ for (const err of errors) {
87
+ table.push([
88
+ chalk_1.default.gray(String(err.id)),
89
+ chalk_1.default.white((0, helpers_1.truncate)(err.function_name || "", 20)),
90
+ (0, badges_1.errorTypeBadge)(err.error_type),
91
+ (0, helpers_1.truncate)(err.error_message, 34),
92
+ (0, badges_1.envBadge)(err.env),
93
+ (0, badges_1.timeBadge)(err.occurred_at),
94
+ ]);
95
+ }
96
+ console.log(table.toString());
97
+ console.log(chalk_1.default.gray(`\n Showing ${chalk_1.default.white.bold(String(errors.length))} errors`) +
98
+ (result.total > errors.length
99
+ ? chalk_1.default.gray(` of ${result.total} total`)
100
+ : "") +
101
+ "\n");
102
+ }
103
+ async function showErrorDetail(id) {
104
+ const result = await (0, api_client_1.getError)(id);
105
+ const { error: err, snapshot } = result;
106
+ console.log("");
107
+ console.log(chalk_1.default.red.bold(" ━━━ Error Detail ━━━"));
108
+ console.log("");
109
+ // Error header
110
+ console.log(` ${(0, badges_1.errorTypeBadge)(err.error_type)} ${(0, badges_1.envBadge)(err.env)}`);
111
+ console.log("");
112
+ console.log(chalk_1.default.white.bold(` ${err.error_message}`));
113
+ console.log(chalk_1.default.gray(` ${(0, helpers_1.relativeTime)(err.occurred_at)} (${err.occurred_at})`));
114
+ // Stack trace
115
+ if (err.stack_trace) {
116
+ console.log("");
117
+ console.log(chalk_1.default.gray(" ── Stack Trace ──"));
118
+ console.log("");
119
+ const lines = err.stack_trace.split("\n");
120
+ for (const line of lines) {
121
+ if (line.trim().startsWith("at ")) {
122
+ console.log(chalk_1.default.gray(` ${line.trim()}`));
123
+ }
124
+ else {
125
+ console.log(chalk_1.default.red(` ${line.trim()}`));
126
+ }
127
+ }
128
+ }
129
+ // Type context
130
+ console.log("");
131
+ console.log(chalk_1.default.cyan.bold(" ── Type Context at Point of Failure ──"));
132
+ console.log("");
133
+ console.log(chalk_1.default.gray(" Function: ") + chalk_1.default.white.bold(err.function_name || `id:${err.function_id}`));
134
+ console.log(chalk_1.default.gray(" Module: ") + chalk_1.default.white(err.module || "unknown"));
135
+ if (err.args_type) {
136
+ console.log("");
137
+ console.log(chalk_1.default.gray(" Input types:"));
138
+ console.log(` ${(0, type_formatter_1.formatType)(err.args_type, 4)}`);
139
+ }
140
+ if (err.return_type) {
141
+ console.log("");
142
+ console.log(chalk_1.default.gray(" Return type:"));
143
+ console.log(` ${(0, type_formatter_1.formatType)(err.return_type, 4)}`);
144
+ }
145
+ if (err.args_snapshot !== undefined && err.args_snapshot !== null) {
146
+ console.log("");
147
+ console.log(chalk_1.default.gray(" Sample data:"));
148
+ const json = JSON.stringify(err.args_snapshot, null, 2);
149
+ if (json) {
150
+ const lines = json.split("\n");
151
+ for (const line of lines) {
152
+ const colored = line
153
+ .replace(/"([^"]+)":/g, (_, key) => `${chalk_1.default.white(`"${key}"`)}:`)
154
+ .replace(/: "([^"]*)"/g, (_, val) => `: ${chalk_1.default.green(`"${val}"`)}`)
155
+ .replace(/: (\d+\.?\d*)/g, (_, val) => `: ${chalk_1.default.yellow(val)}`)
156
+ .replace(/: (true|false)/g, (_, val) => `: ${chalk_1.default.blue(val)}`)
157
+ .replace(/: (null)/g, (_, val) => `: ${chalk_1.default.gray(val)}`);
158
+ console.log(` ${colored}`);
159
+ }
160
+ }
161
+ }
162
+ // Expected types (from the latest non-error snapshot)
163
+ if (snapshot) {
164
+ console.log("");
165
+ console.log(chalk_1.default.green.bold(" ── Expected Types (Happy Path) ──"));
166
+ console.log("");
167
+ console.log(chalk_1.default.gray(" Last successful snapshot:") + ` ${(0, badges_1.envBadge)(snapshot.env)} ${(0, badges_1.timeBadge)(snapshot.observed_at)}`);
168
+ if (snapshot.args_type) {
169
+ console.log("");
170
+ console.log(chalk_1.default.gray(" Expected input types:"));
171
+ console.log(` ${(0, type_formatter_1.formatType)(snapshot.args_type, 4)}`);
172
+ }
173
+ if (snapshot.return_type) {
174
+ console.log("");
175
+ console.log(chalk_1.default.gray(" Expected return type:"));
176
+ console.log(` ${(0, type_formatter_1.formatType)(snapshot.return_type, 4)}`);
177
+ }
178
+ }
179
+ console.log("");
180
+ }
@@ -0,0 +1,18 @@
1
+ export interface ExportOptions {
2
+ dir?: string;
3
+ env?: string;
4
+ }
5
+ /**
6
+ * `trickle export` — Generate all output formats into a directory at once.
7
+ *
8
+ * Creates a complete `.trickle/` directory with:
9
+ * - types.d.ts — TypeScript type declarations
10
+ * - api-client.ts — Typed fetch-based API client
11
+ * - handlers.d.ts — Express handler type aliases
12
+ * - schemas.ts — Zod validation schemas
13
+ * - hooks.ts — TanStack React Query hooks
14
+ * - guards.ts — Runtime type guard functions
15
+ * - openapi.json — OpenAPI 3.0 specification
16
+ * - api.test.ts — Generated API test scaffolds
17
+ */
18
+ export declare function exportCommand(opts: ExportOptions): Promise<void>;