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,82 @@
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.openapiCommand = openapiCommand;
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 openapiCommand(opts) {
45
+ try {
46
+ const spec = await (0, api_client_1.fetchOpenApiSpec)({
47
+ env: opts.env,
48
+ title: opts.title,
49
+ version: opts.apiVersion,
50
+ serverUrl: opts.server,
51
+ });
52
+ const json = JSON.stringify(spec, null, 2) + "\n";
53
+ if (opts.out) {
54
+ const outPath = path.resolve(opts.out);
55
+ const dir = path.dirname(outPath);
56
+ if (!fs.existsSync(dir)) {
57
+ fs.mkdirSync(dir, { recursive: true });
58
+ }
59
+ fs.writeFileSync(outPath, json, "utf-8");
60
+ console.log("");
61
+ console.log(chalk_1.default.green(` OpenAPI spec written to ${chalk_1.default.bold(opts.out)}`));
62
+ // Show summary
63
+ const specObj = spec;
64
+ const paths = specObj.paths || {};
65
+ const pathCount = Object.keys(paths).length;
66
+ let operationCount = 0;
67
+ for (const methods of Object.values(paths)) {
68
+ operationCount += Object.keys(methods).length;
69
+ }
70
+ console.log(chalk_1.default.gray(` ${pathCount} path${pathCount !== 1 ? "s" : ""}, ${operationCount} operation${operationCount !== 1 ? "s" : ""}`));
71
+ console.log("");
72
+ }
73
+ else {
74
+ process.stdout.write(json);
75
+ }
76
+ }
77
+ catch (err) {
78
+ if (err instanceof Error) {
79
+ console.error(chalk_1.default.red(`\n Error: ${err.message}\n`));
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,11 @@
1
+ export interface OverviewOptions {
2
+ env?: string;
3
+ json?: boolean;
4
+ }
5
+ /**
6
+ * `trickle overview` — Compact API overview with inline type signatures.
7
+ *
8
+ * Shows all observed routes with their return type shapes, making it easy to
9
+ * understand your entire API surface at a glance. Like `git log --oneline` for APIs.
10
+ */
11
+ export declare function overviewCommand(opts: OverviewOptions): Promise<void>;
@@ -0,0 +1,266 @@
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.overviewCommand = overviewCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const api_client_1 = require("../api-client");
9
+ const config_1 = require("../config");
10
+ const helpers_1 = require("../ui/helpers");
11
+ /**
12
+ * `trickle overview` — Compact API overview with inline type signatures.
13
+ *
14
+ * Shows all observed routes with their return type shapes, making it easy to
15
+ * understand your entire API surface at a glance. Like `git log --oneline` for APIs.
16
+ */
17
+ async function overviewCommand(opts) {
18
+ const backendUrl = (0, config_1.getBackendUrl)();
19
+ // Check backend
20
+ try {
21
+ const res = await fetch(`${backendUrl}/api/health`, { signal: AbortSignal.timeout(3000) });
22
+ if (!res.ok)
23
+ throw new Error("not ok");
24
+ }
25
+ catch {
26
+ console.error(chalk_1.default.red(`\n Cannot reach trickle backend at ${chalk_1.default.bold(backendUrl)}\n`));
27
+ process.exit(1);
28
+ }
29
+ // Fetch all functions
30
+ const result = await (0, api_client_1.listFunctions)({ env: opts.env, limit: 500 });
31
+ const { functions } = result;
32
+ if (functions.length === 0) {
33
+ console.log(chalk_1.default.yellow("\n No observed routes yet."));
34
+ console.log(chalk_1.default.gray(" Run ") + chalk_1.default.white("trickle capture") + chalk_1.default.gray(" or ") + chalk_1.default.white("trickle dev") + chalk_1.default.gray(" to start observing.\n"));
35
+ return;
36
+ }
37
+ // Fetch latest type snapshot for each function
38
+ const routes = [];
39
+ for (const fn of functions) {
40
+ try {
41
+ const typesResult = await (0, api_client_1.listTypes)(fn.id, { env: opts.env, limit: 1 });
42
+ const snapshot = typesResult.snapshots[0];
43
+ const returnType = snapshot
44
+ ? (typeof snapshot.return_type === "string"
45
+ ? JSON.parse(snapshot.return_type)
46
+ : snapshot.return_type)
47
+ : null;
48
+ const argsType = snapshot
49
+ ? (typeof snapshot.args_type === "string"
50
+ ? JSON.parse(snapshot.args_type)
51
+ : snapshot.args_type)
52
+ : null;
53
+ const { method, path: routePath } = parseRoute(fn.function_name);
54
+ routes.push({
55
+ name: fn.function_name,
56
+ method,
57
+ path: routePath,
58
+ module: fn.module,
59
+ environment: fn.environment,
60
+ lastSeen: fn.last_seen_at,
61
+ argsSignature: argsType ? compactSignature(argsType, 60) : "",
62
+ returnSignature: returnType ? compactSignature(returnType, 60) : "unknown",
63
+ fieldCount: returnType ? countFields(returnType) : 0,
64
+ });
65
+ }
66
+ catch {
67
+ // Skip functions with errors
68
+ const { method, path: routePath } = parseRoute(fn.function_name);
69
+ routes.push({
70
+ name: fn.function_name,
71
+ method,
72
+ path: routePath,
73
+ module: fn.module,
74
+ environment: fn.environment,
75
+ lastSeen: fn.last_seen_at,
76
+ argsSignature: "",
77
+ returnSignature: "?",
78
+ fieldCount: 0,
79
+ });
80
+ }
81
+ }
82
+ // JSON output
83
+ if (opts.json) {
84
+ console.log(JSON.stringify({ routes, total: routes.length }, null, 2));
85
+ return;
86
+ }
87
+ // Group by module
88
+ const byModule = new Map();
89
+ for (const r of routes) {
90
+ const mod = r.module || "default";
91
+ if (!byModule.has(mod))
92
+ byModule.set(mod, []);
93
+ byModule.get(mod).push(r);
94
+ }
95
+ console.log("");
96
+ console.log(chalk_1.default.bold(" trickle overview"));
97
+ console.log(chalk_1.default.gray(" " + "─".repeat(60)));
98
+ console.log(chalk_1.default.gray(` ${routes.length} route${routes.length === 1 ? "" : "s"} observed`));
99
+ if (opts.env) {
100
+ console.log(chalk_1.default.gray(` Environment: ${opts.env}`));
101
+ }
102
+ console.log(chalk_1.default.gray(" " + "─".repeat(60)));
103
+ // Find the longest method for alignment
104
+ const maxMethodLen = Math.max(...routes.map((r) => r.method.length));
105
+ const maxPathLen = Math.min(30, Math.max(...routes.map((r) => r.path.length)));
106
+ for (const [mod, modRoutes] of byModule) {
107
+ console.log("");
108
+ if (byModule.size > 1) {
109
+ console.log(chalk_1.default.gray(` ┌─ ${mod}`));
110
+ }
111
+ // Sort routes: GET before POST before PUT before DELETE, then by path
112
+ const methodOrder = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 };
113
+ modRoutes.sort((a, b) => {
114
+ const orderA = methodOrder[a.method] ?? 5;
115
+ const orderB = methodOrder[b.method] ?? 5;
116
+ if (orderA !== orderB)
117
+ return orderA - orderB;
118
+ return a.path.localeCompare(b.path);
119
+ });
120
+ for (const route of modRoutes) {
121
+ const methodColor = getMethodColor(route.method);
122
+ const methodStr = route.method.padEnd(maxMethodLen);
123
+ const pathStr = route.path.padEnd(maxPathLen);
124
+ const age = (0, helpers_1.relativeTime)(route.lastSeen);
125
+ // Build the line
126
+ const prefix = byModule.size > 1 ? " │ " : " ";
127
+ const line = prefix +
128
+ methodColor(methodStr) +
129
+ " " +
130
+ chalk_1.default.white(pathStr) +
131
+ chalk_1.default.gray(" → ") +
132
+ chalk_1.default.cyan(route.returnSignature) +
133
+ chalk_1.default.gray(` ${age}`);
134
+ console.log(line);
135
+ // Show request body if present and non-empty
136
+ if (route.argsSignature && route.argsSignature !== "{ }") {
137
+ const argsLine = prefix +
138
+ " ".repeat(maxMethodLen) +
139
+ " " +
140
+ " ".repeat(maxPathLen) +
141
+ chalk_1.default.gray(" ← ") +
142
+ chalk_1.default.yellow(route.argsSignature);
143
+ console.log(argsLine);
144
+ }
145
+ }
146
+ if (byModule.size > 1) {
147
+ console.log(chalk_1.default.gray(" └─"));
148
+ }
149
+ }
150
+ console.log("");
151
+ const totalFields = routes.reduce((sum, r) => sum + r.fieldCount, 0);
152
+ console.log(chalk_1.default.gray(` ${routes.length} routes, ${totalFields} fields observed`) +
153
+ chalk_1.default.gray(` · ${backendUrl}`));
154
+ console.log("");
155
+ }
156
+ function parseRoute(functionName) {
157
+ const spaceIdx = functionName.indexOf(" ");
158
+ if (spaceIdx > 0) {
159
+ return {
160
+ method: functionName.slice(0, spaceIdx),
161
+ path: functionName.slice(spaceIdx + 1),
162
+ };
163
+ }
164
+ return { method: "", path: functionName };
165
+ }
166
+ function getMethodColor(method) {
167
+ switch (method) {
168
+ case "GET": return chalk_1.default.green;
169
+ case "POST": return chalk_1.default.yellow;
170
+ case "PUT": return chalk_1.default.blue;
171
+ case "PATCH": return chalk_1.default.magenta;
172
+ case "DELETE": return chalk_1.default.red;
173
+ default: return chalk_1.default.white;
174
+ }
175
+ }
176
+ /**
177
+ * Render a compact type signature from a TypeNode.
178
+ * Truncates to maxLen characters.
179
+ */
180
+ function compactSignature(node, maxLen) {
181
+ const sig = renderCompact(node);
182
+ if (sig.length <= maxLen)
183
+ return sig;
184
+ return sig.slice(0, maxLen - 1) + "…";
185
+ }
186
+ function renderCompact(node) {
187
+ switch (node.kind) {
188
+ case "primitive":
189
+ return node.name;
190
+ case "object": {
191
+ const props = node.properties;
192
+ const keys = Object.keys(props);
193
+ if (keys.length === 0)
194
+ return "{ }";
195
+ const parts = [];
196
+ for (const key of keys) {
197
+ const val = props[key];
198
+ const valStr = renderCompactShort(val);
199
+ parts.push(`${key}: ${valStr}`);
200
+ }
201
+ const full = `{ ${parts.join(", ")} }`;
202
+ if (full.length <= 60)
203
+ return full;
204
+ // Truncate: show first few fields
205
+ let result = "{ ";
206
+ for (let i = 0; i < parts.length; i++) {
207
+ if (i > 0)
208
+ result += ", ";
209
+ if (result.length + parts[i].length > 55 && i > 0) {
210
+ result += `…+${parts.length - i}`;
211
+ break;
212
+ }
213
+ result += parts[i];
214
+ }
215
+ return result + " }";
216
+ }
217
+ case "array": {
218
+ const element = node.element;
219
+ return `${renderCompact(element)}[]`;
220
+ }
221
+ case "union": {
222
+ const members = node.members;
223
+ return members.map(renderCompactShort).join(" | ");
224
+ }
225
+ default:
226
+ return node.kind;
227
+ }
228
+ }
229
+ function renderCompactShort(node) {
230
+ switch (node.kind) {
231
+ case "primitive":
232
+ return node.name;
233
+ case "object": {
234
+ const props = node.properties;
235
+ const keys = Object.keys(props);
236
+ if (keys.length === 0)
237
+ return "{}";
238
+ if (keys.length <= 3) {
239
+ return `{${keys.join(", ")}}`;
240
+ }
241
+ return `{${keys.slice(0, 2).join(", ")}, …+${keys.length - 2}}`;
242
+ }
243
+ case "array":
244
+ return `${renderCompactShort(node.element)}[]`;
245
+ case "union": {
246
+ const members = node.members;
247
+ return members.map(renderCompactShort).join(" | ");
248
+ }
249
+ default:
250
+ return node.kind;
251
+ }
252
+ }
253
+ function countFields(node) {
254
+ if (node.kind === "object") {
255
+ const props = node.properties;
256
+ let count = Object.keys(props).length;
257
+ for (const val of Object.values(props)) {
258
+ count += countFields(val);
259
+ }
260
+ return count;
261
+ }
262
+ if (node.kind === "array") {
263
+ return countFields(node.element);
264
+ }
265
+ return 0;
266
+ }
@@ -0,0 +1,11 @@
1
+ export interface PackOptions {
2
+ out?: string;
3
+ env?: string;
4
+ }
5
+ /**
6
+ * `trickle pack` — Export all observed types as a portable bundle.
7
+ *
8
+ * Creates a JSON file containing all functions and their type snapshots
9
+ * that can be shared, committed to version control, or imported elsewhere.
10
+ */
11
+ export declare function packCommand(opts: PackOptions): Promise<void>;
@@ -0,0 +1,133 @@
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.packCommand = packCommand;
40
+ const fs = __importStar(require("fs"));
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const api_client_1 = require("../api-client");
43
+ const config_1 = require("../config");
44
+ /**
45
+ * `trickle pack` — Export all observed types as a portable bundle.
46
+ *
47
+ * Creates a JSON file containing all functions and their type snapshots
48
+ * that can be shared, committed to version control, or imported elsewhere.
49
+ */
50
+ async function packCommand(opts) {
51
+ const backendUrl = (0, config_1.getBackendUrl)();
52
+ // Check backend
53
+ try {
54
+ const res = await fetch(`${backendUrl}/api/health`, { signal: AbortSignal.timeout(3000) });
55
+ if (!res.ok)
56
+ throw new Error("not ok");
57
+ }
58
+ catch {
59
+ console.error(chalk_1.default.red(`\n Cannot reach trickle backend at ${chalk_1.default.bold(backendUrl)}\n`));
60
+ process.exit(1);
61
+ }
62
+ // Use stderr for status when writing JSON to stdout
63
+ const log = opts.out ? console.log : (...args) => process.stderr.write(args.join(" ") + "\n");
64
+ log("");
65
+ log(chalk_1.default.bold(" trickle pack"));
66
+ log(chalk_1.default.gray(" " + "─".repeat(50)));
67
+ // Fetch all functions
68
+ const result = await (0, api_client_1.listFunctions)({ env: opts.env, limit: 10000 });
69
+ const { functions } = result;
70
+ if (functions.length === 0) {
71
+ log(chalk_1.default.yellow(" No observed types to pack."));
72
+ log(chalk_1.default.gray(" Run ") + chalk_1.default.white("trickle capture") + chalk_1.default.gray(" or ") + chalk_1.default.white("trickle dev") + chalk_1.default.gray(" first.\n"));
73
+ process.exit(1);
74
+ }
75
+ log(chalk_1.default.gray(` Packing ${functions.length} functions...`));
76
+ // Fetch snapshots for each function
77
+ const packedFunctions = [];
78
+ let totalSnapshots = 0;
79
+ for (const fn of functions) {
80
+ const typesResult = await (0, api_client_1.listTypes)(fn.id, { env: opts.env, limit: 100 });
81
+ const snapshots = [];
82
+ for (const snap of typesResult.snapshots) {
83
+ snapshots.push({
84
+ typeHash: snap.type_hash,
85
+ env: snap.env,
86
+ argsType: snap.args_type,
87
+ returnType: snap.return_type,
88
+ sampleInput: snap.sample_input || undefined,
89
+ sampleOutput: snap.sample_output || undefined,
90
+ observedAt: snap.observed_at,
91
+ });
92
+ }
93
+ if (snapshots.length > 0) {
94
+ packedFunctions.push({
95
+ functionName: fn.function_name,
96
+ module: fn.module,
97
+ language: fn.language,
98
+ environment: fn.environment,
99
+ snapshots,
100
+ });
101
+ totalSnapshots += snapshots.length;
102
+ }
103
+ }
104
+ const bundle = {
105
+ version: 1,
106
+ createdAt: new Date().toISOString(),
107
+ source: backendUrl,
108
+ functions: packedFunctions,
109
+ stats: {
110
+ totalFunctions: packedFunctions.length,
111
+ totalSnapshots,
112
+ },
113
+ };
114
+ const json = JSON.stringify(bundle, null, 2);
115
+ if (opts.out) {
116
+ fs.writeFileSync(opts.out, json, "utf-8");
117
+ log(chalk_1.default.green(` Packed ${packedFunctions.length} functions (${totalSnapshots} snapshots)`));
118
+ log(chalk_1.default.gray(` Written to ${opts.out}`));
119
+ const sizeKb = (Buffer.byteLength(json, "utf-8") / 1024).toFixed(1);
120
+ log(chalk_1.default.gray(` Size: ${sizeKb}KB`));
121
+ log("");
122
+ log(chalk_1.default.gray(" Share this file or import it with:"));
123
+ log(chalk_1.default.white(` trickle unpack ${opts.out}`));
124
+ log("");
125
+ }
126
+ else {
127
+ // Write JSON to stdout for piping
128
+ process.stdout.write(json + "\n");
129
+ // Summary to stderr
130
+ log(chalk_1.default.green(` Packed ${packedFunctions.length} functions (${totalSnapshots} snapshots)`));
131
+ log("");
132
+ }
133
+ }
@@ -0,0 +1,13 @@
1
+ export interface ProxyOptions {
2
+ target: string;
3
+ port?: string;
4
+ }
5
+ /**
6
+ * `trickle proxy` — Transparent reverse proxy that captures API types.
7
+ *
8
+ * Sits between the frontend and backend, forwarding all requests while
9
+ * observing request/response shapes and sending type observations to
10
+ * the trickle backend. Works with any backend language or framework —
11
+ * no instrumentation needed.
12
+ */
13
+ export declare function proxyCommand(opts: ProxyOptions): Promise<void>;