zitejs 0.9.13 → 0.9.15

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.
@@ -0,0 +1,476 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runBundle = runBundle;
37
+ /**
38
+ * `npx zitejs bundle` — Bundle endpoint files for cloudflare-lambda deployment.
39
+ *
40
+ * Replaces the legacy `scripts/bundle-endpoints.js` from zitejs-starter.
41
+ * Reads endpoints from src/api/*.ts, resolves SDK imports via .zite/backend.ts
42
+ * (monorepo) or src/__zite__/integrations.ts (legacy), and outputs bundled ESM
43
+ * code suitable for the cloudflare-lambda worker runtime.
44
+ *
45
+ * Usage:
46
+ * npx zitejs bundle # bundle all endpoints
47
+ * npx zitejs bundle --app admin-panel # bundle endpoints for a specific app
48
+ * npx zitejs bundle --script <path> # bundle a one-off script
49
+ *
50
+ * Output: JSON to stdout
51
+ * { bundledEndpoints: Record<string, string>, endpointErrors?: Record<string, string> }
52
+ * or for --script: { bundledCode: string } or { error: string }
53
+ *
54
+ * Dependencies (add to zitejs package.json):
55
+ * "esbuild": "^0.25.0"
56
+ * "@babel/parser": "^7.26.0"
57
+ */
58
+ const esbuild = __importStar(require("esbuild"));
59
+ const path = __importStar(require("path"));
60
+ const fs = __importStar(require("fs"));
61
+ const parser_1 = require("@babel/parser");
62
+ const _NODE_BUILTIN_NAMES = [
63
+ 'http', 'https', 'http2', 'stream', 'buffer', 'util', 'events', 'crypto',
64
+ 'path', 'fs', 'url', 'querystring', 'zlib', 'net', 'tls', 'os', 'assert',
65
+ 'process', 'child_process', 'cluster', 'dgram', 'dns', 'inspector', 'module',
66
+ 'perf_hooks', 'readline', 'repl', 'string_decoder', 'timers', 'tty', 'v8',
67
+ 'vm', 'worker_threads', 'async_hooks', 'trace_events', 'punycode',
68
+ ];
69
+ const NODE_BUILTINS = _NODE_BUILTIN_NAMES.flatMap(m => [m, `node:${m}`]);
70
+ const PREBUNDLED_LIBS = {
71
+ '@zite/endpoints-runtime-sdk': '__zite-runtime__.js',
72
+ 'zod': '__zod__.js',
73
+ 'openai': '__openai__.js',
74
+ '@anthropic-ai/sdk': '__anthropic__.js',
75
+ 'stripe': '__stripe__.js',
76
+ 'airtable': '__airtable__.js',
77
+ '@notionhq/client': '__notion__.js',
78
+ '@slack/web-api': '__slack__.js',
79
+ 'googleapis': '__googleapis__.js',
80
+ '@mailchimp/mailchimp_marketing': '__mailchimp__.js',
81
+ '@hubspot/api-client': '__hubspot__.js',
82
+ 'jsforce': '__jsforce__.js',
83
+ '@linear/sdk': '__linear__.js',
84
+ '@microsoft/microsoft-graph-client': '__microsoft-graph__.js',
85
+ 'twilio': '__twilio__.js',
86
+ 'intercom-client': '__intercom__.js',
87
+ '@google/generative-ai': '__gemini__.js',
88
+ };
89
+ const BASE_BUILD_OPTIONS = {
90
+ bundle: true,
91
+ write: false,
92
+ format: 'esm',
93
+ platform: 'neutral',
94
+ target: 'es2022',
95
+ treeShaking: true,
96
+ external: NODE_BUILTINS,
97
+ mainFields: ['module', 'main'],
98
+ conditions: ['worker', 'browser', 'import', 'default'],
99
+ };
100
+ function getUsedSdkImports(endpointCode) {
101
+ try {
102
+ const ast = (0, parser_1.parse)(endpointCode, {
103
+ sourceType: 'module',
104
+ plugins: ['typescript'],
105
+ });
106
+ const usedImports = new Set();
107
+ const sdkSources = [
108
+ 'zite-integrations-backend-sdk',
109
+ 'zitejs/backend',
110
+ 'zitejs/backend/base',
111
+ ];
112
+ for (const node of ast.program.body) {
113
+ if (node.type === 'ImportDeclaration' &&
114
+ sdkSources.includes(node.source.value)) {
115
+ if (node.importKind === 'type')
116
+ continue;
117
+ for (const spec of node.specifiers) {
118
+ if (spec.type === 'ImportSpecifier') {
119
+ if (spec.importKind === 'type')
120
+ continue;
121
+ const importedName = spec.imported.type === 'Identifier'
122
+ ? spec.imported.name
123
+ : spec.imported.value;
124
+ usedImports.add(importedName);
125
+ }
126
+ else if (spec.type === 'ImportNamespaceSpecifier') {
127
+ return null;
128
+ }
129
+ }
130
+ }
131
+ }
132
+ return Array.from(usedImports);
133
+ }
134
+ catch {
135
+ return null;
136
+ }
137
+ }
138
+ function getSdkExportKinds(sdkCode) {
139
+ try {
140
+ const ast = (0, parser_1.parse)(sdkCode, {
141
+ sourceType: 'module',
142
+ plugins: ['typescript'],
143
+ });
144
+ const typeExports = new Set();
145
+ const valueExports = new Set();
146
+ for (const node of ast.program.body) {
147
+ if (node.type === 'ExportNamedDeclaration') {
148
+ if (node.declaration?.type === 'TSTypeAliasDeclaration') {
149
+ typeExports.add(node.declaration.id.name);
150
+ }
151
+ else if (node.declaration?.type === 'TSInterfaceDeclaration') {
152
+ typeExports.add(node.declaration.id.name);
153
+ }
154
+ else if (node.declaration?.type === 'ClassDeclaration' && node.declaration.id) {
155
+ valueExports.add(node.declaration.id.name);
156
+ }
157
+ else if (node.declaration?.type === 'FunctionDeclaration' && node.declaration.id) {
158
+ valueExports.add(node.declaration.id.name);
159
+ }
160
+ else if (node.declaration?.type === 'VariableDeclaration') {
161
+ for (const decl of node.declaration.declarations) {
162
+ if (decl.id.type === 'Identifier') {
163
+ valueExports.add(decl.id.name);
164
+ }
165
+ }
166
+ }
167
+ else if (node.specifiers && node.specifiers.length > 0) {
168
+ for (const spec of node.specifiers) {
169
+ if (spec.type === 'ExportSpecifier') {
170
+ const name = spec.exported.type === 'Identifier'
171
+ ? spec.exported.name
172
+ : spec.exported.value;
173
+ if (spec.exportKind === 'type') {
174
+ typeExports.add(name);
175
+ }
176
+ else {
177
+ valueExports.add(name);
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return { typeExports, valueExports };
185
+ }
186
+ catch {
187
+ return null;
188
+ }
189
+ }
190
+ /**
191
+ * Resolve the backend SDK file path. Tries monorepo layout first
192
+ * (.zite/backend.ts), falls back to legacy (__zite__/integrations.ts).
193
+ */
194
+ function findSdkPath(baseDir) {
195
+ const monorepoPath = path.resolve(baseDir, '.zite/backend.ts');
196
+ if (fs.existsSync(monorepoPath))
197
+ return monorepoPath;
198
+ const legacyPath = path.resolve(baseDir, 'src/__zite__/integrations.ts');
199
+ if (fs.existsSync(legacyPath))
200
+ return legacyPath;
201
+ return null;
202
+ }
203
+ /**
204
+ * Determine which import source the endpoint uses for the SDK.
205
+ * Returns the source string so we can generate the correct wrapper.
206
+ */
207
+ function getSdkImportSource(baseDir) {
208
+ if (fs.existsSync(path.resolve(baseDir, '.zite/backend.ts'))) {
209
+ return 'zitejs/backend';
210
+ }
211
+ return 'zite-integrations-backend-sdk';
212
+ }
213
+ function createAliasPlugin(opts) {
214
+ return {
215
+ name: 'zite-alias',
216
+ setup(build) {
217
+ const sdkSources = [
218
+ /^zite-integrations-backend-sdk$/,
219
+ /^zitejs\/backend$/,
220
+ /^zitejs\/backend\/base$/,
221
+ ];
222
+ for (const filter of sdkSources) {
223
+ build.onResolve({ filter }, () => {
224
+ if (opts.sdkPath)
225
+ return { path: path.resolve(opts.sdkPath) };
226
+ if (opts.baseDir) {
227
+ const sdkPath = findSdkPath(opts.baseDir);
228
+ if (sdkPath)
229
+ return { path: sdkPath };
230
+ }
231
+ return { path: 'zitejs/backend', external: true };
232
+ });
233
+ }
234
+ // Resolve zitejs/db to .zite/db.ts
235
+ build.onResolve({ filter: /^zitejs\/db$/ }, () => {
236
+ if (opts.baseDir) {
237
+ const dbPath = path.resolve(opts.baseDir, '.zite/db.ts');
238
+ if (fs.existsSync(dbPath))
239
+ return { path: dbPath };
240
+ }
241
+ return { path: 'zitejs/db', external: true };
242
+ });
243
+ // Resolve zitejs/runtime
244
+ build.onResolve({ filter: /^zitejs\/runtime$/ }, () => {
245
+ return { path: 'zitejs/runtime', external: true };
246
+ });
247
+ for (const [pkgName, modulePath] of Object.entries(PREBUNDLED_LIBS)) {
248
+ const escapedName = pkgName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
249
+ const filter = new RegExp(`^${escapedName}$`);
250
+ build.onResolve({ filter }, () => ({
251
+ path: `./${modulePath}`,
252
+ external: true,
253
+ }));
254
+ }
255
+ },
256
+ };
257
+ }
258
+ function generateEndpointWrapper(endpointName, usedImports, sdkExportKinds, sdkSource) {
259
+ if (usedImports === null) {
260
+ return `
261
+ import * as sdk from '${sdkSource}';
262
+ Object.assign(globalThis, sdk);
263
+ import endpoint from './api/${endpointName}';
264
+ globalThis.__endpoint = endpoint;
265
+ `;
266
+ }
267
+ if (usedImports.length === 0) {
268
+ return `
269
+ import endpoint from './api/${endpointName}';
270
+ globalThis.__endpoint = endpoint;
271
+ `;
272
+ }
273
+ const typeImports = [];
274
+ const valueImports = [];
275
+ for (const name of usedImports) {
276
+ if (sdkExportKinds?.typeExports.has(name)) {
277
+ typeImports.push(name);
278
+ }
279
+ else {
280
+ valueImports.push(name);
281
+ }
282
+ }
283
+ const importStatements = [];
284
+ if (typeImports.length > 0) {
285
+ importStatements.push(`import type { ${typeImports.join(', ')} } from '${sdkSource}';`);
286
+ }
287
+ if (valueImports.length > 0) {
288
+ importStatements.push(`import { ${valueImports.join(', ')} } from '${sdkSource}';`);
289
+ }
290
+ const globalAssign = valueImports.length > 0
291
+ ? `Object.assign(globalThis, { ${valueImports.join(', ')} });`
292
+ : '';
293
+ return `
294
+ ${importStatements.join('\n')}
295
+ ${globalAssign}
296
+ import endpoint from './api/${endpointName}';
297
+ globalThis.__endpoint = endpoint;
298
+ `;
299
+ }
300
+ async function bundleEndpointsImpl(baseDir, endpointNames) {
301
+ const bundledEndpoints = {};
302
+ const endpointErrors = {};
303
+ const aliasPlugin = createAliasPlugin({ baseDir });
304
+ const sdkSource = getSdkImportSource(baseDir);
305
+ let sdkExportKinds = null;
306
+ try {
307
+ const sdkPath = findSdkPath(baseDir);
308
+ if (sdkPath) {
309
+ const sdkCode = fs.readFileSync(sdkPath, 'utf-8');
310
+ sdkExportKinds = getSdkExportKinds(sdkCode);
311
+ }
312
+ }
313
+ catch { }
314
+ for (const name of endpointNames) {
315
+ let usedImports = null;
316
+ try {
317
+ const endpointPath = path.join(baseDir, 'src', 'api', `${name}.ts`);
318
+ const endpointCode = fs.readFileSync(endpointPath, 'utf-8');
319
+ usedImports = getUsedSdkImports(endpointCode);
320
+ }
321
+ catch { }
322
+ const wrapperCode = generateEndpointWrapper(name, usedImports, sdkExportKinds, sdkSource);
323
+ try {
324
+ const result = await esbuild.build({
325
+ ...BASE_BUILD_OPTIONS,
326
+ stdin: {
327
+ contents: wrapperCode,
328
+ resolveDir: `${baseDir}/src`,
329
+ loader: 'ts',
330
+ },
331
+ logLevel: 'warning',
332
+ plugins: [aliasPlugin],
333
+ });
334
+ if (result.warnings && result.warnings.length > 0) {
335
+ const msgs = result.warnings.map(w => `${w.location?.file || 'unknown'}:${w.location?.line || '?'} - ${w.text}`);
336
+ endpointErrors[name] = `Warnings: ${msgs.join('; ')}`;
337
+ }
338
+ if (result.outputFiles && result.outputFiles.length > 0) {
339
+ bundledEndpoints[name] = result.outputFiles[0].text;
340
+ }
341
+ else {
342
+ endpointErrors[name] = 'No output generated';
343
+ }
344
+ }
345
+ catch (err) {
346
+ const e = err;
347
+ if (e.errors && Array.isArray(e.errors)) {
348
+ const msgs = e.errors.map(er => {
349
+ const loc = er.location
350
+ ? `${er.location.file || 'unknown'}:${er.location.line || '?'}:${er.location.column || '?'}`
351
+ : 'unknown';
352
+ return `${loc} - ${er.text}`;
353
+ });
354
+ endpointErrors[name] = msgs.join('\n');
355
+ }
356
+ else {
357
+ endpointErrors[name] = e.message || String(err);
358
+ }
359
+ }
360
+ }
361
+ console.log(JSON.stringify({
362
+ bundledEndpoints,
363
+ endpointErrors: Object.keys(endpointErrors).length > 0 ? endpointErrors : undefined,
364
+ }));
365
+ }
366
+ async function bundleOneOffScriptImpl(scriptPath, sdkPath) {
367
+ const rawScript = fs.readFileSync(scriptPath, 'utf-8');
368
+ const plugin = createAliasPlugin({ sdkPath });
369
+ let importSection = '';
370
+ let bodySection = rawScript;
371
+ try {
372
+ const ast = (0, parser_1.parse)(rawScript, {
373
+ sourceType: 'module',
374
+ plugins: ['typescript'],
375
+ allowReturnOutsideFunction: true,
376
+ });
377
+ let lastImportEnd = 0;
378
+ for (const node of ast.program.body) {
379
+ if (node.type === 'ImportDeclaration' && node.end) {
380
+ lastImportEnd = node.end;
381
+ }
382
+ }
383
+ if (lastImportEnd > 0) {
384
+ importSection = rawScript.slice(0, lastImportEnd);
385
+ bodySection = rawScript.slice(lastImportEnd);
386
+ }
387
+ }
388
+ catch { }
389
+ const wrappedScript = `${importSection}
390
+ export async function execute() {
391
+ ${bodySection}
392
+ }`;
393
+ try {
394
+ const result = await esbuild.build({
395
+ ...BASE_BUILD_OPTIONS,
396
+ stdin: {
397
+ contents: wrappedScript,
398
+ loader: 'ts',
399
+ resolveDir: process.cwd(),
400
+ },
401
+ minify: false,
402
+ logLevel: 'silent',
403
+ plugins: [plugin],
404
+ });
405
+ if (result.errors.length > 0) {
406
+ console.log(JSON.stringify({ error: result.errors.map(e => e.text).join('\n') }));
407
+ process.exit(1);
408
+ }
409
+ if (!result.outputFiles || result.outputFiles.length === 0) {
410
+ console.log(JSON.stringify({ error: 'esbuild produced no output' }));
411
+ process.exit(1);
412
+ }
413
+ const esbuildOutput = result.outputFiles[0].text;
414
+ console.log(JSON.stringify({
415
+ bundledCode: `${esbuildOutput}\nglobalThis.__endpoint = { execute };\n`,
416
+ }));
417
+ }
418
+ catch (err) {
419
+ const e = err;
420
+ if (e.errors && Array.isArray(e.errors)) {
421
+ const msgs = e.errors.map(er => {
422
+ const loc = er.location
423
+ ? `${er.location.file || 'unknown'}:${er.location.line || '?'}`
424
+ : 'unknown';
425
+ return `${loc} - ${er.text}`;
426
+ });
427
+ console.log(JSON.stringify({ error: msgs.join('\n') }));
428
+ }
429
+ else {
430
+ console.log(JSON.stringify({ error: e.message || String(err) }));
431
+ }
432
+ process.exit(1);
433
+ }
434
+ }
435
+ async function runBundle() {
436
+ const args = process.argv.slice(3); // skip 'node', 'zitejs', 'bundle'
437
+ const scriptFlagIndex = args.indexOf('--script');
438
+ if (scriptFlagIndex !== -1) {
439
+ const scriptPath = args[scriptFlagIndex + 1];
440
+ if (!scriptPath) {
441
+ console.log(JSON.stringify({ error: 'Usage: zitejs bundle --script <path> [--sdk <path>]' }));
442
+ process.exit(1);
443
+ }
444
+ const sdkFlagIndex = args.indexOf('--sdk');
445
+ const sdkPath = sdkFlagIndex !== -1 ? args[sdkFlagIndex + 1] : undefined;
446
+ return bundleOneOffScriptImpl(scriptPath, sdkPath);
447
+ }
448
+ // Endpoint mode: find all endpoints and bundle them
449
+ const appFlag = args.indexOf('--app');
450
+ let baseDir = process.cwd();
451
+ if (appFlag !== -1 && args[appFlag + 1]) {
452
+ baseDir = path.resolve(baseDir, 'apps', args[appFlag + 1]);
453
+ }
454
+ // If explicit endpoint names passed, use those; otherwise find all
455
+ const explicitNames = args.filter(a => !a.startsWith('--'));
456
+ let endpointNames;
457
+ if (explicitNames.length > 0) {
458
+ endpointNames = explicitNames;
459
+ }
460
+ else {
461
+ const apiDir = path.join(baseDir, 'src', 'api');
462
+ if (!fs.existsSync(apiDir)) {
463
+ console.log(JSON.stringify({ bundledEndpoints: {} }));
464
+ return;
465
+ }
466
+ endpointNames = fs
467
+ .readdirSync(apiDir)
468
+ .filter(f => f.endsWith('.ts'))
469
+ .map(f => f.replace('.ts', ''));
470
+ }
471
+ if (endpointNames.length === 0) {
472
+ console.log(JSON.stringify({ bundledEndpoints: {} }));
473
+ return;
474
+ }
475
+ return bundleEndpointsImpl(baseDir, endpointNames);
476
+ }
@@ -11,19 +11,36 @@ function getRunnerUrl() {
11
11
  const env = (0, env_js_1.getEnv)('ZITE_ENV', 'VITE_ZITE_ENV') ?? 'production';
12
12
  return (0, env_js_1.getEnv)('ZITE_RUNNER_URL', 'VITE_ZITE_RUNNER_URL') ?? ENVIRONMENTS[env] ?? ENVIRONMENTS.production;
13
13
  }
14
- function getToken() {
15
- return (0, env_js_1.getEnv)('ZITE_DB_TOKEN', 'VITE_ZITE_DB_TOKEN') ?? '';
14
+ /**
15
+ * Get the user's usage token for endpoint auth.
16
+ * In internal mode: injected by app-runtime as window._ziteUsageToken
17
+ * In external mode: stored in localStorage by the auth flow
18
+ */
19
+ function getUsageToken() {
20
+ if (typeof window !== 'undefined') {
21
+ const win = window;
22
+ if (typeof win._ziteUsageToken === 'string')
23
+ return win._ziteUsageToken;
24
+ }
25
+ // Fallback to stored auth token (external mode)
26
+ if (typeof localStorage !== 'undefined') {
27
+ const stored = localStorage.getItem('zite.auth.token');
28
+ if (stored)
29
+ return stored;
30
+ }
31
+ return '';
16
32
  }
17
33
  function createCaller(endpoint, name, flowId) {
18
34
  return async (input) => {
19
35
  const appId = flowId ?? (0, env_js_1.getEnv)('ZITE_FLOW_ID', 'VITE_ZITE_FLOW_ID') ?? '';
36
+ const token = getUsageToken();
20
37
  const res = await fetch(getRunnerUrl() + '/public/' + appId + '/api/' + name, {
21
38
  method: 'POST',
22
39
  headers: {
23
- Authorization: `Bearer ${getToken()}`,
40
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
24
41
  'Content-Type': 'application/json',
25
42
  },
26
- body: JSON.stringify({ ...input, mode: 'preview', usageToken: getToken() }),
43
+ body: JSON.stringify({ ...input, mode: 'preview', usageToken: token }),
27
44
  });
28
45
  if (!res.ok) {
29
46
  const text = await res.text().catch(() => '');
package/dist/cjs/cli.js CHANGED
@@ -55,15 +55,21 @@ async function main() {
55
55
  await runCheck();
56
56
  break;
57
57
  }
58
+ case 'bundle': {
59
+ const { runBundle } = await Promise.resolve().then(() => __importStar(require('./bundle/index.js')));
60
+ await runBundle();
61
+ break;
62
+ }
58
63
  default:
59
64
  console.error(command
60
65
  ? `Unknown command: ${command}`
61
- : 'Usage: zitejs <sync|dev|check>');
66
+ : 'Usage: zitejs <sync|dev|check|bundle>');
62
67
  console.error('');
63
68
  console.error('Commands:');
64
69
  console.error(' sync Generate .zite/db.ts and .zite/api.ts from your database schema');
65
70
  console.error(' dev Run sync then watch for changes (like npx convex dev)');
66
71
  console.error(' check Run tsc --noEmit and vite build for all apps');
72
+ console.error(' bundle Bundle src/api/*.ts endpoints for cloudflare-lambda');
67
73
  process.exit(1);
68
74
  }
69
75
  }
@@ -0,0 +1 @@
1
+ export declare function runBundle(): Promise<void>;
@@ -0,0 +1,440 @@
1
+ /**
2
+ * `npx zitejs bundle` — Bundle endpoint files for cloudflare-lambda deployment.
3
+ *
4
+ * Replaces the legacy `scripts/bundle-endpoints.js` from zitejs-starter.
5
+ * Reads endpoints from src/api/*.ts, resolves SDK imports via .zite/backend.ts
6
+ * (monorepo) or src/__zite__/integrations.ts (legacy), and outputs bundled ESM
7
+ * code suitable for the cloudflare-lambda worker runtime.
8
+ *
9
+ * Usage:
10
+ * npx zitejs bundle # bundle all endpoints
11
+ * npx zitejs bundle --app admin-panel # bundle endpoints for a specific app
12
+ * npx zitejs bundle --script <path> # bundle a one-off script
13
+ *
14
+ * Output: JSON to stdout
15
+ * { bundledEndpoints: Record<string, string>, endpointErrors?: Record<string, string> }
16
+ * or for --script: { bundledCode: string } or { error: string }
17
+ *
18
+ * Dependencies (add to zitejs package.json):
19
+ * "esbuild": "^0.25.0"
20
+ * "@babel/parser": "^7.26.0"
21
+ */
22
+ import * as esbuild from 'esbuild';
23
+ import * as path from 'path';
24
+ import * as fs from 'fs';
25
+ import { parse } from '@babel/parser';
26
+ const _NODE_BUILTIN_NAMES = [
27
+ 'http', 'https', 'http2', 'stream', 'buffer', 'util', 'events', 'crypto',
28
+ 'path', 'fs', 'url', 'querystring', 'zlib', 'net', 'tls', 'os', 'assert',
29
+ 'process', 'child_process', 'cluster', 'dgram', 'dns', 'inspector', 'module',
30
+ 'perf_hooks', 'readline', 'repl', 'string_decoder', 'timers', 'tty', 'v8',
31
+ 'vm', 'worker_threads', 'async_hooks', 'trace_events', 'punycode',
32
+ ];
33
+ const NODE_BUILTINS = _NODE_BUILTIN_NAMES.flatMap(m => [m, `node:${m}`]);
34
+ const PREBUNDLED_LIBS = {
35
+ '@zite/endpoints-runtime-sdk': '__zite-runtime__.js',
36
+ 'zod': '__zod__.js',
37
+ 'openai': '__openai__.js',
38
+ '@anthropic-ai/sdk': '__anthropic__.js',
39
+ 'stripe': '__stripe__.js',
40
+ 'airtable': '__airtable__.js',
41
+ '@notionhq/client': '__notion__.js',
42
+ '@slack/web-api': '__slack__.js',
43
+ 'googleapis': '__googleapis__.js',
44
+ '@mailchimp/mailchimp_marketing': '__mailchimp__.js',
45
+ '@hubspot/api-client': '__hubspot__.js',
46
+ 'jsforce': '__jsforce__.js',
47
+ '@linear/sdk': '__linear__.js',
48
+ '@microsoft/microsoft-graph-client': '__microsoft-graph__.js',
49
+ 'twilio': '__twilio__.js',
50
+ 'intercom-client': '__intercom__.js',
51
+ '@google/generative-ai': '__gemini__.js',
52
+ };
53
+ const BASE_BUILD_OPTIONS = {
54
+ bundle: true,
55
+ write: false,
56
+ format: 'esm',
57
+ platform: 'neutral',
58
+ target: 'es2022',
59
+ treeShaking: true,
60
+ external: NODE_BUILTINS,
61
+ mainFields: ['module', 'main'],
62
+ conditions: ['worker', 'browser', 'import', 'default'],
63
+ };
64
+ function getUsedSdkImports(endpointCode) {
65
+ try {
66
+ const ast = parse(endpointCode, {
67
+ sourceType: 'module',
68
+ plugins: ['typescript'],
69
+ });
70
+ const usedImports = new Set();
71
+ const sdkSources = [
72
+ 'zite-integrations-backend-sdk',
73
+ 'zitejs/backend',
74
+ 'zitejs/backend/base',
75
+ ];
76
+ for (const node of ast.program.body) {
77
+ if (node.type === 'ImportDeclaration' &&
78
+ sdkSources.includes(node.source.value)) {
79
+ if (node.importKind === 'type')
80
+ continue;
81
+ for (const spec of node.specifiers) {
82
+ if (spec.type === 'ImportSpecifier') {
83
+ if (spec.importKind === 'type')
84
+ continue;
85
+ const importedName = spec.imported.type === 'Identifier'
86
+ ? spec.imported.name
87
+ : spec.imported.value;
88
+ usedImports.add(importedName);
89
+ }
90
+ else if (spec.type === 'ImportNamespaceSpecifier') {
91
+ return null;
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return Array.from(usedImports);
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ function getSdkExportKinds(sdkCode) {
103
+ try {
104
+ const ast = parse(sdkCode, {
105
+ sourceType: 'module',
106
+ plugins: ['typescript'],
107
+ });
108
+ const typeExports = new Set();
109
+ const valueExports = new Set();
110
+ for (const node of ast.program.body) {
111
+ if (node.type === 'ExportNamedDeclaration') {
112
+ if (node.declaration?.type === 'TSTypeAliasDeclaration') {
113
+ typeExports.add(node.declaration.id.name);
114
+ }
115
+ else if (node.declaration?.type === 'TSInterfaceDeclaration') {
116
+ typeExports.add(node.declaration.id.name);
117
+ }
118
+ else if (node.declaration?.type === 'ClassDeclaration' && node.declaration.id) {
119
+ valueExports.add(node.declaration.id.name);
120
+ }
121
+ else if (node.declaration?.type === 'FunctionDeclaration' && node.declaration.id) {
122
+ valueExports.add(node.declaration.id.name);
123
+ }
124
+ else if (node.declaration?.type === 'VariableDeclaration') {
125
+ for (const decl of node.declaration.declarations) {
126
+ if (decl.id.type === 'Identifier') {
127
+ valueExports.add(decl.id.name);
128
+ }
129
+ }
130
+ }
131
+ else if (node.specifiers && node.specifiers.length > 0) {
132
+ for (const spec of node.specifiers) {
133
+ if (spec.type === 'ExportSpecifier') {
134
+ const name = spec.exported.type === 'Identifier'
135
+ ? spec.exported.name
136
+ : spec.exported.value;
137
+ if (spec.exportKind === 'type') {
138
+ typeExports.add(name);
139
+ }
140
+ else {
141
+ valueExports.add(name);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ return { typeExports, valueExports };
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ /**
155
+ * Resolve the backend SDK file path. Tries monorepo layout first
156
+ * (.zite/backend.ts), falls back to legacy (__zite__/integrations.ts).
157
+ */
158
+ function findSdkPath(baseDir) {
159
+ const monorepoPath = path.resolve(baseDir, '.zite/backend.ts');
160
+ if (fs.existsSync(monorepoPath))
161
+ return monorepoPath;
162
+ const legacyPath = path.resolve(baseDir, 'src/__zite__/integrations.ts');
163
+ if (fs.existsSync(legacyPath))
164
+ return legacyPath;
165
+ return null;
166
+ }
167
+ /**
168
+ * Determine which import source the endpoint uses for the SDK.
169
+ * Returns the source string so we can generate the correct wrapper.
170
+ */
171
+ function getSdkImportSource(baseDir) {
172
+ if (fs.existsSync(path.resolve(baseDir, '.zite/backend.ts'))) {
173
+ return 'zitejs/backend';
174
+ }
175
+ return 'zite-integrations-backend-sdk';
176
+ }
177
+ function createAliasPlugin(opts) {
178
+ return {
179
+ name: 'zite-alias',
180
+ setup(build) {
181
+ const sdkSources = [
182
+ /^zite-integrations-backend-sdk$/,
183
+ /^zitejs\/backend$/,
184
+ /^zitejs\/backend\/base$/,
185
+ ];
186
+ for (const filter of sdkSources) {
187
+ build.onResolve({ filter }, () => {
188
+ if (opts.sdkPath)
189
+ return { path: path.resolve(opts.sdkPath) };
190
+ if (opts.baseDir) {
191
+ const sdkPath = findSdkPath(opts.baseDir);
192
+ if (sdkPath)
193
+ return { path: sdkPath };
194
+ }
195
+ return { path: 'zitejs/backend', external: true };
196
+ });
197
+ }
198
+ // Resolve zitejs/db to .zite/db.ts
199
+ build.onResolve({ filter: /^zitejs\/db$/ }, () => {
200
+ if (opts.baseDir) {
201
+ const dbPath = path.resolve(opts.baseDir, '.zite/db.ts');
202
+ if (fs.existsSync(dbPath))
203
+ return { path: dbPath };
204
+ }
205
+ return { path: 'zitejs/db', external: true };
206
+ });
207
+ // Resolve zitejs/runtime
208
+ build.onResolve({ filter: /^zitejs\/runtime$/ }, () => {
209
+ return { path: 'zitejs/runtime', external: true };
210
+ });
211
+ for (const [pkgName, modulePath] of Object.entries(PREBUNDLED_LIBS)) {
212
+ const escapedName = pkgName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
213
+ const filter = new RegExp(`^${escapedName}$`);
214
+ build.onResolve({ filter }, () => ({
215
+ path: `./${modulePath}`,
216
+ external: true,
217
+ }));
218
+ }
219
+ },
220
+ };
221
+ }
222
+ function generateEndpointWrapper(endpointName, usedImports, sdkExportKinds, sdkSource) {
223
+ if (usedImports === null) {
224
+ return `
225
+ import * as sdk from '${sdkSource}';
226
+ Object.assign(globalThis, sdk);
227
+ import endpoint from './api/${endpointName}';
228
+ globalThis.__endpoint = endpoint;
229
+ `;
230
+ }
231
+ if (usedImports.length === 0) {
232
+ return `
233
+ import endpoint from './api/${endpointName}';
234
+ globalThis.__endpoint = endpoint;
235
+ `;
236
+ }
237
+ const typeImports = [];
238
+ const valueImports = [];
239
+ for (const name of usedImports) {
240
+ if (sdkExportKinds?.typeExports.has(name)) {
241
+ typeImports.push(name);
242
+ }
243
+ else {
244
+ valueImports.push(name);
245
+ }
246
+ }
247
+ const importStatements = [];
248
+ if (typeImports.length > 0) {
249
+ importStatements.push(`import type { ${typeImports.join(', ')} } from '${sdkSource}';`);
250
+ }
251
+ if (valueImports.length > 0) {
252
+ importStatements.push(`import { ${valueImports.join(', ')} } from '${sdkSource}';`);
253
+ }
254
+ const globalAssign = valueImports.length > 0
255
+ ? `Object.assign(globalThis, { ${valueImports.join(', ')} });`
256
+ : '';
257
+ return `
258
+ ${importStatements.join('\n')}
259
+ ${globalAssign}
260
+ import endpoint from './api/${endpointName}';
261
+ globalThis.__endpoint = endpoint;
262
+ `;
263
+ }
264
+ async function bundleEndpointsImpl(baseDir, endpointNames) {
265
+ const bundledEndpoints = {};
266
+ const endpointErrors = {};
267
+ const aliasPlugin = createAliasPlugin({ baseDir });
268
+ const sdkSource = getSdkImportSource(baseDir);
269
+ let sdkExportKinds = null;
270
+ try {
271
+ const sdkPath = findSdkPath(baseDir);
272
+ if (sdkPath) {
273
+ const sdkCode = fs.readFileSync(sdkPath, 'utf-8');
274
+ sdkExportKinds = getSdkExportKinds(sdkCode);
275
+ }
276
+ }
277
+ catch { }
278
+ for (const name of endpointNames) {
279
+ let usedImports = null;
280
+ try {
281
+ const endpointPath = path.join(baseDir, 'src', 'api', `${name}.ts`);
282
+ const endpointCode = fs.readFileSync(endpointPath, 'utf-8');
283
+ usedImports = getUsedSdkImports(endpointCode);
284
+ }
285
+ catch { }
286
+ const wrapperCode = generateEndpointWrapper(name, usedImports, sdkExportKinds, sdkSource);
287
+ try {
288
+ const result = await esbuild.build({
289
+ ...BASE_BUILD_OPTIONS,
290
+ stdin: {
291
+ contents: wrapperCode,
292
+ resolveDir: `${baseDir}/src`,
293
+ loader: 'ts',
294
+ },
295
+ logLevel: 'warning',
296
+ plugins: [aliasPlugin],
297
+ });
298
+ if (result.warnings && result.warnings.length > 0) {
299
+ const msgs = result.warnings.map(w => `${w.location?.file || 'unknown'}:${w.location?.line || '?'} - ${w.text}`);
300
+ endpointErrors[name] = `Warnings: ${msgs.join('; ')}`;
301
+ }
302
+ if (result.outputFiles && result.outputFiles.length > 0) {
303
+ bundledEndpoints[name] = result.outputFiles[0].text;
304
+ }
305
+ else {
306
+ endpointErrors[name] = 'No output generated';
307
+ }
308
+ }
309
+ catch (err) {
310
+ const e = err;
311
+ if (e.errors && Array.isArray(e.errors)) {
312
+ const msgs = e.errors.map(er => {
313
+ const loc = er.location
314
+ ? `${er.location.file || 'unknown'}:${er.location.line || '?'}:${er.location.column || '?'}`
315
+ : 'unknown';
316
+ return `${loc} - ${er.text}`;
317
+ });
318
+ endpointErrors[name] = msgs.join('\n');
319
+ }
320
+ else {
321
+ endpointErrors[name] = e.message || String(err);
322
+ }
323
+ }
324
+ }
325
+ console.log(JSON.stringify({
326
+ bundledEndpoints,
327
+ endpointErrors: Object.keys(endpointErrors).length > 0 ? endpointErrors : undefined,
328
+ }));
329
+ }
330
+ async function bundleOneOffScriptImpl(scriptPath, sdkPath) {
331
+ const rawScript = fs.readFileSync(scriptPath, 'utf-8');
332
+ const plugin = createAliasPlugin({ sdkPath });
333
+ let importSection = '';
334
+ let bodySection = rawScript;
335
+ try {
336
+ const ast = parse(rawScript, {
337
+ sourceType: 'module',
338
+ plugins: ['typescript'],
339
+ allowReturnOutsideFunction: true,
340
+ });
341
+ let lastImportEnd = 0;
342
+ for (const node of ast.program.body) {
343
+ if (node.type === 'ImportDeclaration' && node.end) {
344
+ lastImportEnd = node.end;
345
+ }
346
+ }
347
+ if (lastImportEnd > 0) {
348
+ importSection = rawScript.slice(0, lastImportEnd);
349
+ bodySection = rawScript.slice(lastImportEnd);
350
+ }
351
+ }
352
+ catch { }
353
+ const wrappedScript = `${importSection}
354
+ export async function execute() {
355
+ ${bodySection}
356
+ }`;
357
+ try {
358
+ const result = await esbuild.build({
359
+ ...BASE_BUILD_OPTIONS,
360
+ stdin: {
361
+ contents: wrappedScript,
362
+ loader: 'ts',
363
+ resolveDir: process.cwd(),
364
+ },
365
+ minify: false,
366
+ logLevel: 'silent',
367
+ plugins: [plugin],
368
+ });
369
+ if (result.errors.length > 0) {
370
+ console.log(JSON.stringify({ error: result.errors.map(e => e.text).join('\n') }));
371
+ process.exit(1);
372
+ }
373
+ if (!result.outputFiles || result.outputFiles.length === 0) {
374
+ console.log(JSON.stringify({ error: 'esbuild produced no output' }));
375
+ process.exit(1);
376
+ }
377
+ const esbuildOutput = result.outputFiles[0].text;
378
+ console.log(JSON.stringify({
379
+ bundledCode: `${esbuildOutput}\nglobalThis.__endpoint = { execute };\n`,
380
+ }));
381
+ }
382
+ catch (err) {
383
+ const e = err;
384
+ if (e.errors && Array.isArray(e.errors)) {
385
+ const msgs = e.errors.map(er => {
386
+ const loc = er.location
387
+ ? `${er.location.file || 'unknown'}:${er.location.line || '?'}`
388
+ : 'unknown';
389
+ return `${loc} - ${er.text}`;
390
+ });
391
+ console.log(JSON.stringify({ error: msgs.join('\n') }));
392
+ }
393
+ else {
394
+ console.log(JSON.stringify({ error: e.message || String(err) }));
395
+ }
396
+ process.exit(1);
397
+ }
398
+ }
399
+ export async function runBundle() {
400
+ const args = process.argv.slice(3); // skip 'node', 'zitejs', 'bundle'
401
+ const scriptFlagIndex = args.indexOf('--script');
402
+ if (scriptFlagIndex !== -1) {
403
+ const scriptPath = args[scriptFlagIndex + 1];
404
+ if (!scriptPath) {
405
+ console.log(JSON.stringify({ error: 'Usage: zitejs bundle --script <path> [--sdk <path>]' }));
406
+ process.exit(1);
407
+ }
408
+ const sdkFlagIndex = args.indexOf('--sdk');
409
+ const sdkPath = sdkFlagIndex !== -1 ? args[sdkFlagIndex + 1] : undefined;
410
+ return bundleOneOffScriptImpl(scriptPath, sdkPath);
411
+ }
412
+ // Endpoint mode: find all endpoints and bundle them
413
+ const appFlag = args.indexOf('--app');
414
+ let baseDir = process.cwd();
415
+ if (appFlag !== -1 && args[appFlag + 1]) {
416
+ baseDir = path.resolve(baseDir, 'apps', args[appFlag + 1]);
417
+ }
418
+ // If explicit endpoint names passed, use those; otherwise find all
419
+ const explicitNames = args.filter(a => !a.startsWith('--'));
420
+ let endpointNames;
421
+ if (explicitNames.length > 0) {
422
+ endpointNames = explicitNames;
423
+ }
424
+ else {
425
+ const apiDir = path.join(baseDir, 'src', 'api');
426
+ if (!fs.existsSync(apiDir)) {
427
+ console.log(JSON.stringify({ bundledEndpoints: {} }));
428
+ return;
429
+ }
430
+ endpointNames = fs
431
+ .readdirSync(apiDir)
432
+ .filter(f => f.endsWith('.ts'))
433
+ .map(f => f.replace('.ts', ''));
434
+ }
435
+ if (endpointNames.length === 0) {
436
+ console.log(JSON.stringify({ bundledEndpoints: {} }));
437
+ return;
438
+ }
439
+ return bundleEndpointsImpl(baseDir, endpointNames);
440
+ }
@@ -8,19 +8,36 @@ function getRunnerUrl() {
8
8
  const env = getEnv('ZITE_ENV', 'VITE_ZITE_ENV') ?? 'production';
9
9
  return getEnv('ZITE_RUNNER_URL', 'VITE_ZITE_RUNNER_URL') ?? ENVIRONMENTS[env] ?? ENVIRONMENTS.production;
10
10
  }
11
- function getToken() {
12
- return getEnv('ZITE_DB_TOKEN', 'VITE_ZITE_DB_TOKEN') ?? '';
11
+ /**
12
+ * Get the user's usage token for endpoint auth.
13
+ * In internal mode: injected by app-runtime as window._ziteUsageToken
14
+ * In external mode: stored in localStorage by the auth flow
15
+ */
16
+ function getUsageToken() {
17
+ if (typeof window !== 'undefined') {
18
+ const win = window;
19
+ if (typeof win._ziteUsageToken === 'string')
20
+ return win._ziteUsageToken;
21
+ }
22
+ // Fallback to stored auth token (external mode)
23
+ if (typeof localStorage !== 'undefined') {
24
+ const stored = localStorage.getItem('zite.auth.token');
25
+ if (stored)
26
+ return stored;
27
+ }
28
+ return '';
13
29
  }
14
30
  export function createCaller(endpoint, name, flowId) {
15
31
  return async (input) => {
16
32
  const appId = flowId ?? getEnv('ZITE_FLOW_ID', 'VITE_ZITE_FLOW_ID') ?? '';
33
+ const token = getUsageToken();
17
34
  const res = await fetch(getRunnerUrl() + '/public/' + appId + '/api/' + name, {
18
35
  method: 'POST',
19
36
  headers: {
20
- Authorization: `Bearer ${getToken()}`,
37
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
21
38
  'Content-Type': 'application/json',
22
39
  },
23
- body: JSON.stringify({ ...input, mode: 'preview', usageToken: getToken() }),
40
+ body: JSON.stringify({ ...input, mode: 'preview', usageToken: token }),
24
41
  });
25
42
  if (!res.ok) {
26
43
  const text = await res.text().catch(() => '');
package/dist/esm/cli.js CHANGED
@@ -20,15 +20,21 @@ async function main() {
20
20
  await runCheck();
21
21
  break;
22
22
  }
23
+ case 'bundle': {
24
+ const { runBundle } = await import('./bundle/index.js');
25
+ await runBundle();
26
+ break;
27
+ }
23
28
  default:
24
29
  console.error(command
25
30
  ? `Unknown command: ${command}`
26
- : 'Usage: zitejs <sync|dev|check>');
31
+ : 'Usage: zitejs <sync|dev|check|bundle>');
27
32
  console.error('');
28
33
  console.error('Commands:');
29
34
  console.error(' sync Generate .zite/db.ts and .zite/api.ts from your database schema');
30
35
  console.error(' dev Run sync then watch for changes (like npx convex dev)');
31
36
  console.error(' check Run tsc --noEmit and vite build for all apps');
37
+ console.error(' bundle Bundle src/api/*.ts endpoints for cloudflare-lambda');
32
38
  process.exit(1);
33
39
  }
34
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zitejs",
3
- "version": "0.9.13",
3
+ "version": "0.9.15",
4
4
  "description": "The Zite framework — build apps on Zite Database",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/runtime/index.js",
@@ -111,6 +111,8 @@
111
111
  "url": "https://github.com/zite/zitejs"
112
112
  },
113
113
  "dependencies": {
114
- "dotenv": "^17.4.2"
114
+ "@babel/parser": "^7.29.7",
115
+ "dotenv": "^17.4.2",
116
+ "esbuild": "^0.28.0"
115
117
  }
116
118
  }