@fold-run/cli 0.1.2 → 0.2.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 (82) hide show
  1. package/dist/commands/completions.d.ts +1 -0
  2. package/dist/commands/completions.js +195 -0
  3. package/dist/commands/completions.js.map +1 -0
  4. package/dist/commands/config.d.ts +4 -0
  5. package/dist/commands/config.js +75 -0
  6. package/dist/commands/config.js.map +1 -0
  7. package/dist/commands/delete.d.ts +1 -0
  8. package/dist/commands/delete.js +8 -0
  9. package/dist/commands/delete.js.map +1 -1
  10. package/dist/commands/deploy.d.ts +1 -0
  11. package/dist/commands/deploy.js +59 -17
  12. package/dist/commands/deploy.js.map +1 -1
  13. package/dist/commands/dev.d.ts +1 -0
  14. package/dist/commands/dev.js +53 -34
  15. package/dist/commands/dev.js.map +1 -1
  16. package/dist/commands/doctor.d.ts +1 -0
  17. package/dist/commands/doctor.js +138 -0
  18. package/dist/commands/doctor.js.map +1 -0
  19. package/dist/commands/domains.d.ts +11 -0
  20. package/dist/commands/domains.js +111 -0
  21. package/dist/commands/domains.js.map +1 -0
  22. package/dist/commands/env-vars.d.ts +1 -0
  23. package/dist/commands/env-vars.js +8 -1
  24. package/dist/commands/env-vars.js.map +1 -1
  25. package/dist/commands/init.d.ts +1 -0
  26. package/dist/commands/init.js +104 -6
  27. package/dist/commands/init.js.map +1 -1
  28. package/dist/commands/invoke.d.ts +9 -0
  29. package/dist/commands/invoke.js +89 -0
  30. package/dist/commands/invoke.js.map +1 -0
  31. package/dist/commands/link.d.ts +4 -0
  32. package/dist/commands/link.js +77 -0
  33. package/dist/commands/link.js.map +1 -0
  34. package/dist/commands/login.js +8 -6
  35. package/dist/commands/login.js.map +1 -1
  36. package/dist/commands/logs.js +31 -1
  37. package/dist/commands/logs.js.map +1 -1
  38. package/dist/commands/schedules.d.ts +3 -1
  39. package/dist/commands/schedules.js +41 -21
  40. package/dist/commands/schedules.js.map +1 -1
  41. package/dist/commands/secrets.d.ts +3 -1
  42. package/dist/commands/secrets.js +9 -2
  43. package/dist/commands/secrets.js.map +1 -1
  44. package/dist/commands/status.js +48 -28
  45. package/dist/commands/status.js.map +1 -1
  46. package/dist/commands/templates.js +24 -17
  47. package/dist/commands/templates.js.map +1 -1
  48. package/dist/commands/tenant.d.ts +4 -0
  49. package/dist/commands/tenant.js +82 -0
  50. package/dist/commands/tenant.js.map +1 -0
  51. package/dist/commands/webhooks.d.ts +3 -1
  52. package/dist/commands/webhooks.js +31 -18
  53. package/dist/commands/webhooks.js.map +1 -1
  54. package/dist/commands/whoami.d.ts +1 -0
  55. package/dist/commands/whoami.js +39 -0
  56. package/dist/commands/whoami.js.map +1 -0
  57. package/dist/index.js +107 -34
  58. package/dist/index.js.map +1 -1
  59. package/dist/lib/api.d.ts +1 -0
  60. package/dist/lib/api.js +30 -0
  61. package/dist/lib/api.js.map +1 -1
  62. package/dist/lib/bundler.js +124 -18
  63. package/dist/lib/bundler.js.map +1 -1
  64. package/dist/lib/colorize.d.ts +5 -0
  65. package/dist/lib/colorize.js +28 -0
  66. package/dist/lib/colorize.js.map +1 -0
  67. package/dist/lib/cron.d.ts +13 -0
  68. package/dist/lib/cron.js +107 -0
  69. package/dist/lib/cron.js.map +1 -0
  70. package/dist/lib/manifest.d.ts +31 -0
  71. package/dist/lib/manifest.js +195 -0
  72. package/dist/lib/manifest.js.map +1 -0
  73. package/dist/lib/prompt.d.ts +27 -0
  74. package/dist/lib/prompt.js +160 -0
  75. package/dist/lib/prompt.js.map +1 -1
  76. package/dist/lib/spinner.d.ts +14 -0
  77. package/dist/lib/spinner.js +52 -0
  78. package/dist/lib/spinner.js.map +1 -0
  79. package/dist/lib/version-check.d.ts +9 -0
  80. package/dist/lib/version-check.js +54 -0
  81. package/dist/lib/version-check.js.map +1 -0
  82. package/package.json +10 -11
@@ -2,40 +2,113 @@ import { build } from 'esbuild';
2
2
  /**
3
3
  * Dev shim for @fold-run/runtime — stubs all platform bindings for local development.
4
4
  * Injected by the esbuild plugin when bundling for `fold dev`.
5
+ *
6
+ * Stubs provide functional in-memory implementations for KV and Storage,
7
+ * logged no-ops for AI/Queue/Vectorize, and middleware support in defineHandler.
5
8
  */
6
9
  const FOLD_RUNTIME_DEV_SHIM = `
7
10
  class DevKV {
8
11
  constructor() { this._store = new Map(); }
9
- async get(key) { return this._store.get(key) ?? null; }
10
- async put(key, value) { this._store.set(key, value); }
12
+ async get(key, opts) {
13
+ const val = this._store.get(key);
14
+ if (val === undefined) return null;
15
+ if (opts?.type === 'json') return JSON.parse(val);
16
+ if (opts?.type === 'arrayBuffer') return new TextEncoder().encode(val).buffer;
17
+ return val;
18
+ }
19
+ async put(key, value, opts) {
20
+ const str = typeof value === 'string' ? value : '[binary]';
21
+ this._store.set(key, str);
22
+ if (opts?.expirationTtl) {
23
+ setTimeout(() => this._store.delete(key), opts.expirationTtl * 1000);
24
+ }
25
+ }
11
26
  async delete(key) { this._store.delete(key); }
12
27
  async list(opts) {
13
- const keys = [...this._store.keys()].filter(k => !opts?.prefix || k.startsWith(opts.prefix));
14
- return { keys: keys.slice(0, opts?.limit ?? 1000).map(name => ({ name })) };
28
+ const all = [...this._store.keys()];
29
+ const filtered = opts?.prefix ? all.filter(k => k.startsWith(opts.prefix)) : all;
30
+ const limited = filtered.slice(0, opts?.limit ?? 1000);
31
+ return { keys: limited.map(name => ({ name })), list_complete: limited.length === filtered.length, cursor: undefined };
15
32
  }
16
33
  }
34
+
17
35
  class DevStorage {
18
- async put() { console.warn('[fold dev] Storage binding not available locally'); }
19
- async get() { return null; }
20
- async delete() {}
21
- async list() { return { objects: [] }; }
36
+ constructor() { this._store = new Map(); }
37
+ async put(key, value) {
38
+ let body;
39
+ if (typeof value === 'string') body = value;
40
+ else if (value instanceof ArrayBuffer) body = new TextDecoder().decode(value);
41
+ else body = '[stream/blob]';
42
+ const obj = { key, size: body.length, etag: Math.random().toString(36).slice(2), uploaded: new Date(), body };
43
+ this._store.set(key, obj);
44
+ return { key: obj.key, size: obj.size, etag: obj.etag, uploaded: obj.uploaded };
45
+ }
46
+ async get(key) {
47
+ const obj = this._store.get(key);
48
+ if (!obj) return null;
49
+ const body = obj.body;
50
+ return {
51
+ key: obj.key, size: obj.size, etag: obj.etag, uploaded: obj.uploaded,
52
+ body: new ReadableStream({ start(c) { c.enqueue(new TextEncoder().encode(body)); c.close(); } }),
53
+ bodyUsed: false,
54
+ text: async () => body,
55
+ json: async () => JSON.parse(body),
56
+ arrayBuffer: async () => new TextEncoder().encode(body).buffer,
57
+ blob: async () => new Blob([body]),
58
+ };
59
+ }
60
+ async head(key) {
61
+ const obj = this._store.get(key);
62
+ if (!obj) return null;
63
+ return { key: obj.key, size: obj.size, etag: obj.etag, uploaded: obj.uploaded };
64
+ }
65
+ async delete(keys) {
66
+ const arr = Array.isArray(keys) ? keys : [keys];
67
+ for (const k of arr) this._store.delete(k);
68
+ }
69
+ async list(opts) {
70
+ const all = [...this._store.keys()];
71
+ const filtered = opts?.prefix ? all.filter(k => k.startsWith(opts.prefix)) : all;
72
+ const limited = filtered.slice(0, opts?.limit ?? 1000);
73
+ return {
74
+ objects: limited.map(k => { const o = this._store.get(k); return { key: o.key, size: o.size, etag: o.etag, uploaded: o.uploaded }; }),
75
+ truncated: limited.length < filtered.length,
76
+ cursor: undefined,
77
+ delimitedPrefixes: [],
78
+ };
79
+ }
22
80
  }
81
+
23
82
  class DevDB {
24
- prepare() {
25
- const noop = { bind: () => noop, first: async () => null, all: async () => ({ results: [] }), run: async () => ({ success: true, meta: {} }) };
83
+ prepare(query) {
84
+ console.log('[fold dev] DB.prepare:', query.slice(0, 80));
85
+ const noop = { bind: () => noop, first: async () => null, all: async () => ({ results: [], success: true }), run: async () => ({ success: true, meta: {} }) };
26
86
  return noop;
27
87
  }
88
+ async batch(stmts) { console.log('[fold dev] DB.batch:', stmts.length, 'statements'); return []; }
89
+ async exec(query) { console.log('[fold dev] DB.exec:', query.slice(0, 80)); return { count: 0, duration: 0 }; }
28
90
  }
91
+
29
92
  class DevAI {
30
- async run(model) {
31
- console.warn('[fold dev] AI.run("' + model + '") is not available locally');
93
+ async run(model, inputs) {
94
+ console.warn('[fold dev] AI.run("' + model + '") returns empty stub. Use fold deploy to test with real models.');
32
95
  return {};
33
96
  }
34
97
  }
98
+
35
99
  class DevQueue {
36
- async send(body) { console.log('[fold dev] Queue.send:', body); }
100
+ async send(body) { console.log('[fold dev] Queue.send:', JSON.stringify(body).slice(0, 200)); }
37
101
  async sendBatch(messages) { console.log('[fold dev] Queue.sendBatch:', messages.length, 'messages'); }
38
102
  }
103
+
104
+ class DevVectorize {
105
+ async insert(vectors) { console.warn('[fold dev] Vectorize.insert:', vectors.length, 'vectors — stub'); return { count: vectors.length, ids: vectors.map(v => v.id) }; }
106
+ async upsert(vectors) { console.warn('[fold dev] Vectorize.upsert:', vectors.length, 'vectors — stub'); return { count: vectors.length, ids: vectors.map(v => v.id) }; }
107
+ async query() { return { matches: [], count: 0 }; }
108
+ async getByIds() { return []; }
109
+ async deleteByIds(ids) { return { count: ids.length, ids }; }
110
+ }
111
+
39
112
  class FoldContext {
40
113
  constructor(request, env) {
41
114
  this.request = request;
@@ -44,33 +117,66 @@ class FoldContext {
44
117
  this.db = new DevDB();
45
118
  this.ai = new DevAI();
46
119
  this.queue = new DevQueue();
120
+ this.vectorize = new DevVectorize();
47
121
  this.tenantId = undefined;
122
+ this._waitUntil = null;
48
123
  const managed = new Set(['AI', 'VECTORIZE', 'KV', 'DB', 'STORAGE', 'QUEUE', 'FOLD_TENANT_ID']);
49
124
  this.env = Object.fromEntries(
50
125
  Object.entries(env).filter(([k, v]) => !managed.has(k) && typeof v === 'string').map(([k, v]) => [k, v])
51
126
  );
52
127
  }
128
+ waitUntil(promise) { if (this._waitUntil) this._waitUntil(promise); }
53
129
  json(data, status = 200) { return Response.json(data, { status }); }
54
130
  text(body, status = 200) { return new Response(body, { status, headers: { 'content-type': 'text/plain' } }); }
131
+ async body() { return this.request.json(); }
132
+ query(name) { return new URL(this.request.url).searchParams.get(name); }
133
+ queries() { return Object.fromEntries(new URL(this.request.url).searchParams.entries()); }
134
+ header(name) { return this.request.headers.get(name); }
55
135
  stream(generator) {
56
136
  const { readable, writable } = new TransformStream();
57
137
  const writer = writable.getWriter();
58
138
  const enc = new TextEncoder();
59
139
  (async () => {
60
140
  try { for await (const chunk of generator()) await writer.write(enc.encode(chunk)); }
61
- finally { await writer.close(); }
141
+ catch (err) { try { await writer.write(enc.encode('event: error\\ndata: ' + JSON.stringify({ error: err?.message ?? 'Stream error' }) + '\\n\\n')); } catch {} }
142
+ finally { try { await writer.close(); } catch {} }
62
143
  })();
63
- return new Response(readable, { headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' } });
144
+ return new Response(readable, { headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache', 'connection': 'keep-alive' } });
64
145
  }
65
146
  }
147
+
148
+ function composeMiddleware(middleware, handler) {
149
+ return (ctx) => {
150
+ let index = 0;
151
+ const dispatch = () => {
152
+ if (index < middleware.length) { const mw = middleware[index++]; return Promise.resolve(mw(ctx, dispatch)); }
153
+ return Promise.resolve(handler(ctx));
154
+ };
155
+ return dispatch();
156
+ };
157
+ }
158
+
66
159
  export function defineHandler(handlerOrOptions) {
67
- const fetchFn = typeof handlerOrOptions === 'function' ? handlerOrOptions : handlerOrOptions.fetch;
160
+ const isOptions = typeof handlerOrOptions !== 'function';
161
+ const rawFetchFn = isOptions ? handlerOrOptions.fetch : handlerOrOptions;
162
+ const middleware = isOptions ? handlerOrOptions.middleware : undefined;
163
+ const scheduledFn = isOptions ? handlerOrOptions.scheduled : undefined;
164
+ const fetchFn = middleware?.length ? composeMiddleware(middleware, rawFetchFn) : rawFetchFn;
68
165
  return {
69
- async fetch(request, env) {
166
+ async fetch(request, env, ctx) {
70
167
  const context = new FoldContext(request, env ?? {});
168
+ context._waitUntil = ctx?.waitUntil?.bind(ctx);
71
169
  try { return await fetchFn(context); }
72
170
  catch (err) { return Response.json({ error: err instanceof Error ? err.message : 'Internal error' }, { status: 500 }); }
73
171
  },
172
+ ...(scheduledFn && {
173
+ async scheduled(event, env, ctx) {
174
+ const req = new Request('https://scheduled.internal/__scheduled', { method: 'POST' });
175
+ const context = new FoldContext(req, env ?? {});
176
+ context._waitUntil = ctx?.waitUntil?.bind(ctx);
177
+ await scheduledFn(context, event);
178
+ }
179
+ }),
74
180
  };
75
181
  }
76
182
  export { FoldContext };
@@ -103,7 +209,7 @@ export async function bundleFile(entryPoint, opts = {}) {
103
209
  write: false,
104
210
  format: 'esm',
105
211
  target: 'esnext',
106
- platform: 'browser', // Workers runtime is closer to browser than node
212
+ platform: 'browser',
107
213
  minify: !opts.dev,
108
214
  treeShaking: true,
109
215
  conditions: ['worker', 'browser'],
@@ -1 +1 @@
1
- {"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../src/lib/bundler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAe,MAAM,SAAS,CAAC;AAE7C;;;GAGG;AACH,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuE7B,CAAC;AAEF,qEAAqE;AACrE,MAAM,oBAAoB,GAAW;IACnC,IAAI,EAAE,kBAAkB;IACxB,KAAK,CAAC,KAAK;QACT,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzD,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,kBAAkB;SAC9B,CAAC,CAAC,CAAC;QACJ,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACnE,QAAQ,EAAE,qBAAqB;YAC/B,MAAM,EAAE,IAAI;SACb,CAAC,CAAC,CAAC;IACN,CAAC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB,EAAE,OAA0B,EAAE;IAC/E,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;QACzB,WAAW,EAAE,CAAC,UAAU,CAAC;QACzB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,SAAS,EAAE,iDAAiD;QACtE,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG;QACjB,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;QACjC,2EAA2E;QAC3E,yEAAyE;QACzE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,mBAAmB,CAAC;QAC7E,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE;KAChD,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../src/lib/bundler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAe,MAAM,SAAS,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8K7B,CAAC;AAEF,qEAAqE;AACrE,MAAM,oBAAoB,GAAW;IACnC,IAAI,EAAE,kBAAkB;IACxB,KAAK,CAAC,KAAK;QACT,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzD,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,kBAAkB;SAC9B,CAAC,CAAC,CAAC;QACJ,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACnE,QAAQ,EAAE,qBAAqB;YAC/B,MAAM,EAAE,IAAI;SACb,CAAC,CAAC,CAAC;IACN,CAAC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB,EAAE,OAA0B,EAAE;IAC/E,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;QACzB,WAAW,EAAE,CAAC,UAAU,CAAC;QACzB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,SAAS;QACnB,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG;QACjB,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;QACjC,2EAA2E;QAC3E,yEAAyE;QACzE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,mBAAmB,CAAC;QAC7E,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE;KAChD,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Colorize a JSON string for terminal display.
3
+ * Applies syntax highlighting to keys, strings, numbers, booleans, and null.
4
+ */
5
+ export declare function colorizeJson(json: string): string;
@@ -0,0 +1,28 @@
1
+ // Lightweight JSON syntax highlighting for terminal output.
2
+ // No dependencies — uses ANSI escape codes directly.
3
+ const RESET = '\x1b[0m';
4
+ const CYAN = '\x1b[36m'; // keys
5
+ const GREEN = '\x1b[32m'; // strings
6
+ const YELLOW = '\x1b[33m'; // numbers
7
+ const MAGENTA = '\x1b[35m'; // booleans, null
8
+ /**
9
+ * Colorize a JSON string for terminal display.
10
+ * Applies syntax highlighting to keys, strings, numbers, booleans, and null.
11
+ */
12
+ export function colorizeJson(json) {
13
+ return json.replace(/("(?:\\.|[^"\\])*")\s*(:)?|(\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b)|(\bnull\b|\btrue\b|\bfalse\b)/g, (match, str, colon, num, lit) => {
14
+ if (str) {
15
+ // It's a string — is it a key (followed by :) or a value?
16
+ if (colon) {
17
+ return `${CYAN}${str}${RESET}:`;
18
+ }
19
+ return `${GREEN}${str}${RESET}`;
20
+ }
21
+ if (num)
22
+ return `${YELLOW}${num}${RESET}`;
23
+ if (lit)
24
+ return `${MAGENTA}${lit}${RESET}`;
25
+ return match;
26
+ });
27
+ }
28
+ //# sourceMappingURL=colorize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colorize.js","sourceRoot":"","sources":["../../src/lib/colorize.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,qDAAqD;AAErD,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,OAAO;AAChC,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,UAAU;AACpC,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,UAAU;AACrC,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,iBAAiB;AAE7C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CACjB,gGAAgG,EAChG,CAAC,KAAK,EAAE,GAAuB,EAAE,KAAyB,EAAE,GAAuB,EAAE,GAAuB,EAAE,EAAE;QAC9G,IAAI,GAAG,EAAE,CAAC;YACR,0DAA0D;YAC1D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,GAAG,IAAI,GAAG,GAAG,GAAG,KAAK,GAAG,CAAC;YAClC,CAAC;YACD,OAAO,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,EAAE,CAAC;QAClC,CAAC;QACD,IAAI,GAAG;YAAE,OAAO,GAAG,MAAM,GAAG,GAAG,GAAG,KAAK,EAAE,CAAC;QAC1C,IAAI,GAAG;YAAE,OAAO,GAAG,OAAO,GAAG,GAAG,GAAG,KAAK,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface CronValidationResult {
2
+ valid: boolean;
3
+ error?: string;
4
+ }
5
+ /**
6
+ * Validate a cron expression.
7
+ * Returns { valid: true } or { valid: false, error: "..." }
8
+ */
9
+ export declare function validateCron(expression: string): CronValidationResult;
10
+ /**
11
+ * Format a cron validation error with usage hint.
12
+ */
13
+ export declare function formatCronError(error: string): string;
@@ -0,0 +1,107 @@
1
+ // Cron expression validator for standard 5-field cron format:
2
+ // minute hour day-of-month month day-of-week
3
+ // Supports: numbers, ranges (1-5), steps (e.g. every 5), lists (1,3,5), wildcards (*)
4
+ const CRON_FIELDS = [
5
+ { name: 'minute', min: 0, max: 59 },
6
+ { name: 'hour', min: 0, max: 23 },
7
+ { name: 'day of month', min: 1, max: 31 },
8
+ { name: 'month', min: 1, max: 12 },
9
+ { name: 'day of week', min: 0, max: 7 }, // 0 and 7 are both Sunday
10
+ ];
11
+ // Validate a single cron field value (e.g., "5", "1-10", "1,5,10")
12
+ function validateField(value, field) {
13
+ // Wildcard
14
+ if (value === '*') {
15
+ return null;
16
+ }
17
+ // Step values: */5 or 1-10/2
18
+ if (value.includes('/')) {
19
+ const [range, stepStr] = value.split('/');
20
+ const step = parseInt(stepStr, 10);
21
+ if (Number.isNaN(step) || step < 1) {
22
+ return `invalid step value "${stepStr}" in ${field.name}`;
23
+ }
24
+ // Validate the range part
25
+ if (range !== '*') {
26
+ const rangeError = validateField(range, field);
27
+ if (rangeError)
28
+ return rangeError;
29
+ }
30
+ return null;
31
+ }
32
+ // List values: 1,5,10
33
+ if (value.includes(',')) {
34
+ const parts = value.split(',');
35
+ for (const part of parts) {
36
+ const error = validateField(part.trim(), field);
37
+ if (error)
38
+ return error;
39
+ }
40
+ return null;
41
+ }
42
+ // Range values: 1-10
43
+ if (value.includes('-')) {
44
+ const [startStr, endStr] = value.split('-');
45
+ const start = parseInt(startStr, 10);
46
+ const end = parseInt(endStr, 10);
47
+ if (Number.isNaN(start) || Number.isNaN(end)) {
48
+ return `invalid range "${value}" in ${field.name}`;
49
+ }
50
+ if (start < field.min || start > field.max) {
51
+ return `${field.name} start value ${start} out of range (${field.min}-${field.max})`;
52
+ }
53
+ if (end < field.min || end > field.max) {
54
+ return `${field.name} end value ${end} out of range (${field.min}-${field.max})`;
55
+ }
56
+ if (start > end) {
57
+ return `invalid range "${value}" in ${field.name}: start > end`;
58
+ }
59
+ return null;
60
+ }
61
+ // Single number
62
+ const num = parseInt(value, 10);
63
+ if (Number.isNaN(num)) {
64
+ return `invalid value "${value}" in ${field.name}`;
65
+ }
66
+ if (num < field.min || num > field.max) {
67
+ return `${field.name} value ${num} out of range (${field.min}-${field.max})`;
68
+ }
69
+ return null;
70
+ }
71
+ /**
72
+ * Validate a cron expression.
73
+ * Returns { valid: true } or { valid: false, error: "..." }
74
+ */
75
+ export function validateCron(expression) {
76
+ const trimmed = expression.trim();
77
+ if (!trimmed) {
78
+ return { valid: false, error: 'cron expression cannot be empty' };
79
+ }
80
+ const fields = trimmed.split(/\s+/);
81
+ if (fields.length !== 5) {
82
+ return {
83
+ valid: false,
84
+ error: `expected 5 fields (minute hour day month weekday), got ${fields.length}`,
85
+ };
86
+ }
87
+ for (let i = 0; i < 5; i++) {
88
+ const error = validateField(fields[i], CRON_FIELDS[i]);
89
+ if (error) {
90
+ return { valid: false, error };
91
+ }
92
+ }
93
+ return { valid: true };
94
+ }
95
+ /**
96
+ * Format a cron validation error with usage hint.
97
+ */
98
+ export function formatCronError(error) {
99
+ return `Invalid cron expression: ${error}
100
+
101
+ Format: <minute> <hour> <day> <month> <weekday>
102
+ Examples:
103
+ */5 * * * * Every 5 minutes
104
+ 0 9 * * 1-5 9 AM on weekdays
105
+ 0 0 1 * * Midnight on the 1st of each month`;
106
+ }
107
+ //# sourceMappingURL=cron.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/lib/cron.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface FoldManifest {
2
+ name?: string;
3
+ entrypoint?: string;
4
+ tenant_id?: string;
5
+ intent?: {
6
+ trigger?: string;
7
+ bindings?: string[];
8
+ };
9
+ }
10
+ export interface ManifestValidationError {
11
+ field: string;
12
+ message: string;
13
+ }
14
+ export interface ManifestResult {
15
+ manifest: FoldManifest | null;
16
+ errors: ManifestValidationError[];
17
+ warnings: string[];
18
+ }
19
+ /**
20
+ * Load and validate fold.json from current directory.
21
+ * Returns manifest (if valid), errors (blocking), and warnings (non-blocking).
22
+ */
23
+ export declare function loadManifest(dir?: string): ManifestResult;
24
+ /**
25
+ * Format validation errors for display.
26
+ */
27
+ export declare function formatManifestErrors(errors: ManifestValidationError[]): string;
28
+ /**
29
+ * Format warnings for display.
30
+ */
31
+ export declare function formatManifestWarnings(warnings: string[]): string;
@@ -0,0 +1,195 @@
1
+ // fold.json manifest validation
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ const KNOWN_FIELDS = ['name', 'entrypoint', 'tenant_id', 'intent'];
5
+ const KNOWN_INTENT_FIELDS = ['trigger', 'bindings'];
6
+ const VALID_TRIGGERS = ['http', 'cron', 'webhook', 'queue'];
7
+ const VALID_BINDINGS = ['kv', 'storage', 'db', 'queue', 'ai'];
8
+ function validateType(value, field, expected) {
9
+ const actual = Array.isArray(value) ? 'array' : typeof value;
10
+ if (actual !== expected) {
11
+ return `"${field}" must be a ${expected}, got ${actual}`;
12
+ }
13
+ return null;
14
+ }
15
+ /**
16
+ * Load and validate fold.json from current directory.
17
+ * Returns manifest (if valid), errors (blocking), and warnings (non-blocking).
18
+ */
19
+ export function loadManifest(dir) {
20
+ const manifestPath = resolve(dir ?? '.', 'fold.json');
21
+ const errors = [];
22
+ const warnings = [];
23
+ if (!existsSync(manifestPath)) {
24
+ return { manifest: null, errors: [], warnings: [] };
25
+ }
26
+ let raw;
27
+ try {
28
+ raw = readFileSync(manifestPath, 'utf-8');
29
+ }
30
+ catch (err) {
31
+ errors.push({ field: 'file', message: `Could not read fold.json: ${err}` });
32
+ return { manifest: null, errors, warnings };
33
+ }
34
+ let data;
35
+ try {
36
+ data = JSON.parse(raw);
37
+ }
38
+ catch (err) {
39
+ const parseErr = err;
40
+ errors.push({ field: 'json', message: `Invalid JSON: ${parseErr.message}` });
41
+ return { manifest: null, errors, warnings };
42
+ }
43
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
44
+ errors.push({ field: 'root', message: 'fold.json must be an object' });
45
+ return { manifest: null, errors, warnings };
46
+ }
47
+ const obj = data;
48
+ // Check for unknown top-level fields
49
+ for (const key of Object.keys(obj)) {
50
+ if (!KNOWN_FIELDS.includes(key)) {
51
+ warnings.push(`Unknown field "${key}" in fold.json (will be ignored)`);
52
+ }
53
+ }
54
+ // Validate name
55
+ if (obj.name !== undefined) {
56
+ const typeErr = validateType(obj.name, 'name', 'string');
57
+ if (typeErr) {
58
+ errors.push({ field: 'name', message: typeErr });
59
+ }
60
+ else if (typeof obj.name === 'string') {
61
+ if (obj.name.trim() === '') {
62
+ errors.push({ field: 'name', message: '"name" cannot be empty' });
63
+ }
64
+ else if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(obj.name)) {
65
+ errors.push({
66
+ field: 'name',
67
+ message: '"name" must be lowercase alphanumeric with hyphens (e.g., "my-function")',
68
+ });
69
+ }
70
+ }
71
+ }
72
+ // Validate entrypoint
73
+ if (obj.entrypoint !== undefined) {
74
+ const typeErr = validateType(obj.entrypoint, 'entrypoint', 'string');
75
+ if (typeErr) {
76
+ errors.push({ field: 'entrypoint', message: typeErr });
77
+ }
78
+ else if (typeof obj.entrypoint === 'string') {
79
+ if (obj.entrypoint.trim() === '') {
80
+ errors.push({ field: 'entrypoint', message: '"entrypoint" cannot be empty' });
81
+ }
82
+ else {
83
+ const entryPath = resolve(dir ?? '.', obj.entrypoint);
84
+ if (!existsSync(entryPath)) {
85
+ errors.push({
86
+ field: 'entrypoint',
87
+ message: `Entrypoint file not found: ${obj.entrypoint}`,
88
+ });
89
+ }
90
+ }
91
+ }
92
+ }
93
+ // Validate tenant_id
94
+ if (obj.tenant_id !== undefined) {
95
+ const typeErr = validateType(obj.tenant_id, 'tenant_id', 'string');
96
+ if (typeErr) {
97
+ errors.push({ field: 'tenant_id', message: typeErr });
98
+ }
99
+ else if (typeof obj.tenant_id === 'string' && obj.tenant_id.trim() === '') {
100
+ errors.push({ field: 'tenant_id', message: '"tenant_id" cannot be empty' });
101
+ }
102
+ }
103
+ // Validate intent
104
+ if (obj.intent !== undefined) {
105
+ const typeErr = validateType(obj.intent, 'intent', 'object');
106
+ if (typeErr) {
107
+ errors.push({ field: 'intent', message: typeErr });
108
+ }
109
+ else if (typeof obj.intent === 'object' && obj.intent !== null && !Array.isArray(obj.intent)) {
110
+ const intent = obj.intent;
111
+ // Check for unknown intent fields
112
+ for (const key of Object.keys(intent)) {
113
+ if (!KNOWN_INTENT_FIELDS.includes(key)) {
114
+ warnings.push(`Unknown field "intent.${key}" (will be ignored)`);
115
+ }
116
+ }
117
+ // Validate trigger
118
+ if (intent.trigger !== undefined) {
119
+ const triggerErr = validateType(intent.trigger, 'intent.trigger', 'string');
120
+ if (triggerErr) {
121
+ errors.push({ field: 'intent.trigger', message: triggerErr });
122
+ }
123
+ else if (typeof intent.trigger === 'string' && !VALID_TRIGGERS.includes(intent.trigger)) {
124
+ warnings.push(`Unknown trigger "${intent.trigger}" (valid: ${VALID_TRIGGERS.join(', ')})`);
125
+ }
126
+ }
127
+ // Validate bindings
128
+ if (intent.bindings !== undefined) {
129
+ const bindingsErr = validateType(intent.bindings, 'intent.bindings', 'array');
130
+ if (bindingsErr) {
131
+ errors.push({ field: 'intent.bindings', message: bindingsErr });
132
+ }
133
+ else if (Array.isArray(intent.bindings)) {
134
+ for (let i = 0; i < intent.bindings.length; i++) {
135
+ const b = intent.bindings[i];
136
+ if (typeof b !== 'string') {
137
+ errors.push({
138
+ field: `intent.bindings[${i}]`,
139
+ message: `Binding must be a string, got ${typeof b}`,
140
+ });
141
+ }
142
+ else if (!VALID_BINDINGS.includes(b)) {
143
+ warnings.push(`Unknown binding "${b}" (valid: ${VALID_BINDINGS.join(', ')})`);
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ if (errors.length > 0) {
151
+ return { manifest: null, errors, warnings };
152
+ }
153
+ // Build validated manifest
154
+ const manifest = {};
155
+ if (typeof obj.name === 'string')
156
+ manifest.name = obj.name;
157
+ if (typeof obj.entrypoint === 'string')
158
+ manifest.entrypoint = obj.entrypoint;
159
+ if (typeof obj.tenant_id === 'string')
160
+ manifest.tenant_id = obj.tenant_id;
161
+ if (typeof obj.intent === 'object' && obj.intent !== null) {
162
+ const intent = obj.intent;
163
+ manifest.intent = {};
164
+ if (typeof intent.trigger === 'string')
165
+ manifest.intent.trigger = intent.trigger;
166
+ if (Array.isArray(intent.bindings)) {
167
+ manifest.intent.bindings = intent.bindings.filter((b) => typeof b === 'string');
168
+ }
169
+ }
170
+ return { manifest, errors, warnings };
171
+ }
172
+ /**
173
+ * Format validation errors for display.
174
+ */
175
+ export function formatManifestErrors(errors) {
176
+ const lines = ['Invalid fold.json:', ''];
177
+ for (const err of errors) {
178
+ lines.push(` \x1b[31m✗\x1b[0m ${err.message}`);
179
+ }
180
+ lines.push('');
181
+ lines.push('Example fold.json:');
182
+ lines.push(' {');
183
+ lines.push(' "name": "my-function",');
184
+ lines.push(' "entrypoint": "function.ts",');
185
+ lines.push(' "intent": { "bindings": ["kv"] }');
186
+ lines.push(' }');
187
+ return lines.join('\n');
188
+ }
189
+ /**
190
+ * Format warnings for display.
191
+ */
192
+ export function formatManifestWarnings(warnings) {
193
+ return warnings.map((w) => `\x1b[33mWarning:\x1b[0m ${w}`).join('\n');
194
+ }
195
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/lib/manifest.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,30 @@
1
+ /**
2
+ * Prompt for yes/no confirmation. Returns true if user confirms.
3
+ * Defaults to 'no' if user just presses enter.
4
+ */
5
+ export declare function confirm(message: string): Promise<boolean>;
6
+ /**
7
+ * Prompt for a single line of text input.
8
+ * Returns the trimmed input, or defaultValue if the user presses Enter.
9
+ */
10
+ export declare function ask(message: string, defaultValue?: string): Promise<string>;
11
+ /**
12
+ * Prompt the user to select from a list of options using arrow keys.
13
+ * Returns the selected option value. Falls back to numbered list on non-TTY.
14
+ */
15
+ export declare function select<T extends string>(message: string, options: {
16
+ label: string;
17
+ value: T;
18
+ }[]): Promise<T>;
19
+ /**
20
+ * Prompt for toggling multiple options on/off. Returns selected values.
21
+ * Space to toggle, Enter to confirm.
22
+ */
23
+ export declare function multiSelect<T extends string>(message: string, options: {
24
+ label: string;
25
+ value: T;
26
+ default?: boolean;
27
+ }[]): Promise<T[]>;
1
28
  /**
2
29
  * Read a line of input with masked output (shows * for each character).
3
30
  * Handles backspace and Ctrl+C.