zitejs 0.9.122 → 0.9.124
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.
- package/README.md +4 -0
- package/dist/cjs/auth/index.d.ts +2 -2
- package/dist/cjs/bundle/index.d.ts +5 -1
- package/dist/cjs/bundle/index.js +46 -26
- package/dist/cjs/check/index.js +2 -2
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/dev/index.d.ts +5 -0
- package/dist/cjs/dev/index.js +47 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/integrations/client.d.ts +25 -0
- package/dist/cjs/integrations/client.js +21 -0
- package/dist/cjs/integrations/client.test-d.d.ts +1 -0
- package/dist/cjs/integrations/client.test-d.js +50 -0
- package/dist/cjs/integrations/index.d.ts +3 -0
- package/dist/cjs/integrations/index.js +6 -0
- package/dist/cjs/integrations/rules.d.ts +67 -0
- package/dist/cjs/integrations/rules.js +104 -0
- package/dist/cjs/integrations/rules.test.d.ts +1 -0
- package/dist/cjs/integrations/rules.test.js +86 -0
- package/dist/cjs/internal/sdkCall.d.ts +1 -0
- package/dist/cjs/internal/sdkCall.js +3 -1
- package/dist/cjs/runtime/index.d.ts +1 -0
- package/dist/cjs/runtime/index.js +3 -1
- package/dist/cjs/sourceRoots.d.ts +13 -0
- package/dist/cjs/sourceRoots.js +38 -1
- package/dist/cjs/sourceRoots.test.d.ts +1 -0
- package/dist/cjs/sourceRoots.test.js +30 -0
- package/dist/cjs/sync/lib.d.ts +9 -0
- package/dist/cjs/sync/lib.js +53 -0
- package/dist/cjs/sync/lib.test.js +119 -0
- package/dist/esm/auth/index.d.ts +2 -2
- package/dist/esm/bundle/index.d.ts +5 -1
- package/dist/esm/bundle/index.js +47 -28
- package/dist/esm/check/index.js +3 -3
- package/dist/esm/cli.js +1 -1
- package/dist/esm/dev/index.d.ts +5 -0
- package/dist/esm/dev/index.js +48 -3
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/integrations/client.d.ts +25 -0
- package/dist/esm/integrations/client.js +17 -0
- package/dist/esm/integrations/client.test-d.d.ts +1 -0
- package/dist/esm/integrations/client.test-d.js +48 -0
- package/dist/esm/integrations/index.d.ts +3 -0
- package/dist/esm/integrations/index.js +3 -0
- package/dist/esm/integrations/rules.d.ts +67 -0
- package/dist/esm/integrations/rules.js +98 -0
- package/dist/esm/integrations/rules.test.d.ts +1 -0
- package/dist/esm/integrations/rules.test.js +84 -0
- package/dist/esm/internal/sdkCall.d.ts +1 -0
- package/dist/esm/internal/sdkCall.js +2 -1
- package/dist/esm/runtime/index.d.ts +1 -0
- package/dist/esm/runtime/index.js +1 -0
- package/dist/esm/sourceRoots.d.ts +13 -0
- package/dist/esm/sourceRoots.js +35 -1
- package/dist/esm/sourceRoots.test.d.ts +1 -0
- package/dist/esm/sourceRoots.test.js +28 -0
- package/dist/esm/sync/lib.d.ts +9 -0
- package/dist/esm/sync/lib.js +52 -0
- package/dist/esm/sync/lib.test.js +120 -1
- package/package.json +10 -1
- package/dist/cjs/meta/index.d.ts +0 -14
- package/dist/cjs/meta/index.js +0 -12
- package/dist/cjs/notifications/index.d.ts +0 -25
- package/dist/cjs/notifications/index.js +0 -12
- package/dist/esm/meta/index.d.ts +0 -14
- package/dist/esm/meta/index.js +0 -8
- package/dist/esm/notifications/index.d.ts +0 -25
- package/dist/esm/notifications/index.js +0 -8
package/dist/esm/bundle/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `npx zitejs bundle` — Bundle endpoint files for cloudflare-lambda deployment.
|
|
3
3
|
*
|
|
4
4
|
* Replaces the legacy `scripts/bundle-endpoints.js` from zitejs-starter.
|
|
5
|
-
* Reads
|
|
5
|
+
* Reads an app's src/api/*.ts endpoints (an automation's single src/workflow.ts), resolves SDK imports via .zite/backend.ts
|
|
6
6
|
* (monorepo) or src/__zite__/integrations.ts (legacy), and outputs bundled ESM
|
|
7
7
|
* code suitable for the cloudflare-lambda worker runtime.
|
|
8
8
|
*
|
|
@@ -24,7 +24,9 @@ import * as path from 'path';
|
|
|
24
24
|
import * as fs from 'fs';
|
|
25
25
|
import { parse } from '@babel/parser';
|
|
26
26
|
import { builtinModules } from 'node:module';
|
|
27
|
-
import {
|
|
27
|
+
import { INTEGRATIONS_CLASS_NAME, INTEGRATIONS_SDK_INTEGRATION_ID, } from '../integrations/client.js';
|
|
28
|
+
import { SDK_NOT_INITIALIZED_MESSAGE } from '../internal/sdkCall.js';
|
|
29
|
+
import { AUTOMATION_ENDPOINT_NAME, endpointEntryFile, findSourceDir, listEndpointNames, sourceRootOf, } from '../sourceRoots.js';
|
|
28
30
|
// workerd's `nodejs_compat` does not provide these. Left external they bundle
|
|
29
31
|
// fine and then kill the worker at load time with `No such module`; excluded,
|
|
30
32
|
// esbuild fails the one endpoint with a resolvable error instead. Pinned by
|
|
@@ -192,7 +194,7 @@ function getSdkImportSource(baseDir) {
|
|
|
192
194
|
return 'zite-integrations-backend-sdk';
|
|
193
195
|
}
|
|
194
196
|
/**
|
|
195
|
-
* `zitejs/db`, `zitejs/api
|
|
197
|
+
* `zitejs/db`, `zitejs/api` and `zitejs/email` are
|
|
196
198
|
* tsconfig aliases onto generated files, not real package subpaths — they are
|
|
197
199
|
* absent from the `exports` map. `zitejs/backend` IS a real subpath export, but
|
|
198
200
|
* it lands here too and `zitejs` is not in PREBUNDLED_LIBS, so nothing would
|
|
@@ -205,7 +207,19 @@ const unresolvedAlias = (specifier, expectedPath) => {
|
|
|
205
207
|
throw new Error(`Cannot resolve '${specifier}': expected generated file at ${expectedPath}. ` +
|
|
206
208
|
`Run \`npx zitejs generate\` before bundling.`);
|
|
207
209
|
};
|
|
208
|
-
|
|
210
|
+
const AUTH_SERVER_SHIM_PATH = 'zitejs-auth-server-shim';
|
|
211
|
+
const INTEGRATIONS_SHIM_PATH = 'zitejs-integrations-shim';
|
|
212
|
+
const VIRTUAL_MODULES = {
|
|
213
|
+
[AUTH_SERVER_SHIM_PATH]: 'export const ziteAuth = (config) => config;',
|
|
214
|
+
[INTEGRATIONS_SHIM_PATH]: `export const integrations = {
|
|
215
|
+
get(name) {
|
|
216
|
+
const sdkCall = globalThis.__wrapSdkCall;
|
|
217
|
+
if (!sdkCall) throw new Error(${JSON.stringify(SDK_NOT_INITIALIZED_MESSAGE)});
|
|
218
|
+
return sdkCall(${JSON.stringify(INTEGRATIONS_SDK_INTEGRATION_ID)}, ${JSON.stringify(INTEGRATIONS_CLASS_NAME)}, 'get', { name });
|
|
219
|
+
},
|
|
220
|
+
};`,
|
|
221
|
+
};
|
|
222
|
+
export function createAliasPlugin(opts) {
|
|
209
223
|
return {
|
|
210
224
|
name: 'zite-alias',
|
|
211
225
|
setup(build) {
|
|
@@ -256,14 +270,18 @@ function createAliasPlugin(opts) {
|
|
|
256
270
|
}
|
|
257
271
|
return unresolvedAlias('zitejs/api', `${opts.baseDir}/.zite/api.ts`);
|
|
258
272
|
});
|
|
259
|
-
//
|
|
273
|
+
// zitejs/integrations: the generated index (the integrations client plus
|
|
274
|
+
// any Airtable clients), else Airtable alone from an older generate, else
|
|
275
|
+
// this bundler's own client, whatever zitejs the project pins.
|
|
260
276
|
build.onResolve({ filter: /^zitejs\/integrations$/ }, () => {
|
|
261
277
|
if (opts.baseDir) {
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
278
|
+
for (const file of ['index.ts', 'airtable.ts']) {
|
|
279
|
+
const intPath = path.resolve(opts.baseDir, '.zite/integrations', file);
|
|
280
|
+
if (fs.existsSync(intPath))
|
|
281
|
+
return { path: intPath };
|
|
282
|
+
}
|
|
265
283
|
}
|
|
266
|
-
return
|
|
284
|
+
return { path: INTEGRATIONS_SHIM_PATH, namespace: 'zite-virtual' };
|
|
267
285
|
});
|
|
268
286
|
// Resolve zitejs/email to .zite/integrations/email.ts
|
|
269
287
|
build.onResolve({ filter: /^zitejs\/email$/ }, () => {
|
|
@@ -277,11 +295,11 @@ function createAliasPlugin(opts) {
|
|
|
277
295
|
// zitejs/auth/server is types + an identity wrapper — inline a shim so
|
|
278
296
|
// zite.auth.ts bundles without resolving the installed package.
|
|
279
297
|
build.onResolve({ filter: /^zitejs\/auth\/server$/ }, () => ({
|
|
280
|
-
path:
|
|
298
|
+
path: AUTH_SERVER_SHIM_PATH,
|
|
281
299
|
namespace: 'zite-virtual',
|
|
282
300
|
}));
|
|
283
|
-
build.onLoad({ filter: /.*/, namespace: 'zite-virtual' }, () => ({
|
|
284
|
-
contents:
|
|
301
|
+
build.onLoad({ filter: /.*/, namespace: 'zite-virtual' }, (args) => ({
|
|
302
|
+
contents: VIRTUAL_MODULES[args.path],
|
|
285
303
|
loader: 'js',
|
|
286
304
|
}));
|
|
287
305
|
// zitejs/runtime is NOT in PREBUNDLED_LIBS — it's a thin fetch()
|
|
@@ -297,7 +315,7 @@ function createAliasPlugin(opts) {
|
|
|
297
315
|
},
|
|
298
316
|
};
|
|
299
317
|
}
|
|
300
|
-
function generateEndpointWrapper(
|
|
318
|
+
function generateEndpointWrapper(entryImport, usedImports, sdkExportKinds, sdkSource) {
|
|
301
319
|
// Always import the prebundled runtime to ensure globalThis.__wrapSdkCall
|
|
302
320
|
// is available for createTableClient/createSqlClient from zitejs/runtime.
|
|
303
321
|
const runtimeInit = `import { __wrapSdkCall, initRuntime } from '@zite/endpoints-runtime-sdk';
|
|
@@ -308,14 +326,14 @@ initRuntime();`;
|
|
|
308
326
|
${runtimeInit}
|
|
309
327
|
import * as sdk from '${sdkSource}';
|
|
310
328
|
Object.assign(globalThis, sdk);
|
|
311
|
-
import endpoint from '
|
|
329
|
+
import endpoint from '${entryImport}';
|
|
312
330
|
globalThis.__endpoint = endpoint;
|
|
313
331
|
`;
|
|
314
332
|
}
|
|
315
333
|
if (usedImports.length === 0) {
|
|
316
334
|
return `
|
|
317
335
|
${runtimeInit}
|
|
318
|
-
import endpoint from '
|
|
336
|
+
import endpoint from '${entryImport}';
|
|
319
337
|
globalThis.__endpoint = endpoint;
|
|
320
338
|
`;
|
|
321
339
|
}
|
|
@@ -343,11 +361,11 @@ globalThis.__endpoint = endpoint;
|
|
|
343
361
|
${runtimeInit}
|
|
344
362
|
${importStatements.join('\n')}
|
|
345
363
|
${globalAssign}
|
|
346
|
-
import endpoint from '
|
|
364
|
+
import endpoint from '${entryImport}';
|
|
347
365
|
globalThis.__endpoint = endpoint;
|
|
348
366
|
`;
|
|
349
367
|
}
|
|
350
|
-
async function bundleEndpointsImpl(baseDir, endpointNames) {
|
|
368
|
+
async function bundleEndpointsImpl(baseDir, root, endpointNames) {
|
|
351
369
|
const bundledEndpoints = {};
|
|
352
370
|
const endpointErrors = {};
|
|
353
371
|
const aliasPlugin = createAliasPlugin({ baseDir });
|
|
@@ -362,14 +380,20 @@ async function bundleEndpointsImpl(baseDir, endpointNames) {
|
|
|
362
380
|
}
|
|
363
381
|
catch { }
|
|
364
382
|
for (const name of endpointNames) {
|
|
383
|
+
if (root === 'automations' && name !== AUTOMATION_ENDPOINT_NAME) {
|
|
384
|
+
endpointErrors[name] =
|
|
385
|
+
`An automation is one workflow, src/workflow.ts, bundled as "${AUTOMATION_ENDPOINT_NAME}"; there is no endpoint "${name}"`;
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
const entryFile = endpointEntryFile(root, name);
|
|
365
389
|
let usedImports = null;
|
|
366
390
|
try {
|
|
367
|
-
const
|
|
368
|
-
const endpointCode = fs.readFileSync(endpointPath, 'utf-8');
|
|
391
|
+
const endpointCode = fs.readFileSync(path.join(baseDir, entryFile), 'utf-8');
|
|
369
392
|
usedImports = getUsedSdkImports(endpointCode);
|
|
370
393
|
}
|
|
371
394
|
catch { }
|
|
372
|
-
|
|
395
|
+
// The wrapper resolves from `src/`, so the entry is imported relative to it.
|
|
396
|
+
const wrapperCode = generateEndpointWrapper('./' + path.relative('src', entryFile).replace(/\.ts$/, ''), usedImports, sdkExportKinds, sdkSource);
|
|
373
397
|
try {
|
|
374
398
|
const result = await esbuild.build({
|
|
375
399
|
...BASE_BUILD_OPTIONS,
|
|
@@ -592,18 +616,13 @@ export async function runBundle() {
|
|
|
592
616
|
// as missing.
|
|
593
617
|
const explicitNames = args.filter((a, i) => !a.startsWith('--') && !(appFlag !== -1 && i === appFlag + 1));
|
|
594
618
|
let endpointNames;
|
|
619
|
+
const root = sourceRootOf(baseDir) ?? 'apps';
|
|
595
620
|
if (explicitNames.length > 0) {
|
|
596
621
|
endpointNames = explicitNames;
|
|
597
622
|
}
|
|
598
623
|
else {
|
|
599
|
-
|
|
600
|
-
endpointNames = fs.existsSync(apiDir)
|
|
601
|
-
? fs
|
|
602
|
-
.readdirSync(apiDir)
|
|
603
|
-
.filter(f => f.endsWith('.ts'))
|
|
604
|
-
.map(f => f.replace('.ts', ''))
|
|
605
|
-
: [];
|
|
624
|
+
endpointNames = listEndpointNames(root, baseDir);
|
|
606
625
|
}
|
|
607
626
|
// Even with no endpoints, zite.auth.ts may still need bundling.
|
|
608
|
-
return bundleEndpointsImpl(baseDir, endpointNames);
|
|
627
|
+
return bundleEndpointsImpl(baseDir, root, endpointNames);
|
|
609
628
|
}
|
package/dist/esm/check/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from 'child_process';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import { listSourceDirs } from '../sourceRoots.js';
|
|
4
|
+
import { listEndpointNames, listSourceDirs } from '../sourceRoots.js';
|
|
5
5
|
/**
|
|
6
6
|
* An argument array, not a command string, so no shell is involved.
|
|
7
7
|
*
|
|
@@ -62,7 +62,7 @@ export async function runCheck() {
|
|
|
62
62
|
process.exit(1);
|
|
63
63
|
}
|
|
64
64
|
let allPassed = true;
|
|
65
|
-
for (const { dir: app, path: appPath } of appDirs) {
|
|
65
|
+
for (const { root, dir: app, path: appPath } of appDirs) {
|
|
66
66
|
console.log(`\n── ${appPath} ──`);
|
|
67
67
|
// Only tsconfig.app.json compiles anything. The app's tsconfig.json is a
|
|
68
68
|
// solution-style config — `"files": []` plus a reference — so
|
|
@@ -89,7 +89,7 @@ export async function runCheck() {
|
|
|
89
89
|
// Endpoints never reach vite — they are bundled separately for the lambda,
|
|
90
90
|
// against a different resolver. tsc and vite both pass on an endpoint whose
|
|
91
91
|
// `zitejs/*` alias has no generated file behind it; only the bundler knows.
|
|
92
|
-
if (
|
|
92
|
+
if (listEndpointNames(root, appPath).length > 0) {
|
|
93
93
|
process.stdout.write(' bundle endpoints ... ');
|
|
94
94
|
const bundle = run('npx', ['zitejs', 'bundle', '--app', app], '.');
|
|
95
95
|
const failures = bundle.ok ? bundleFailures(bundle.output) : [bundle.output];
|
package/dist/esm/cli.js
CHANGED
|
@@ -40,7 +40,7 @@ async function main() {
|
|
|
40
40
|
console.error(' dev Run sync then watch for changes (like npx convex dev)');
|
|
41
41
|
console.error(' generate Regenerate every app and automation .zite/ (monorepo)');
|
|
42
42
|
console.error(' check Run tsc --noEmit (and vite build where there is one) for every app and automation');
|
|
43
|
-
console.error(' bundle Bundle src/api/*.ts
|
|
43
|
+
console.error(' bundle Bundle endpoints (src/api/*.ts, or an automation\'s src/workflow.ts) for cloudflare-lambda');
|
|
44
44
|
process.exit(1);
|
|
45
45
|
}
|
|
46
46
|
}
|
package/dist/esm/dev/index.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the zitejs that `fromDir` resolves, nearest first up to the project root,
|
|
3
|
+
* has the integrations client: the CLI running generate can be newer than that pin.
|
|
4
|
+
*/
|
|
5
|
+
export declare function projectRuntimeHasIntegrationsClient(fromDir: string, projectRoot?: string): boolean;
|
|
1
6
|
export declare function runGenerate(): Promise<void>;
|
|
2
7
|
export declare function runDev(): Promise<void>;
|
package/dist/esm/dev/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { watch } from "fs";
|
|
2
2
|
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
3
|
+
import { dirname, join, resolve } from "path";
|
|
4
4
|
import { listSourceDirs } from "../sourceRoots.js";
|
|
5
5
|
import { runSync } from "../sync/index.js";
|
|
6
|
-
import { generateDbTs, generateApiTs, generateBackendWrapperTs, generateAirtableTs, findEmailIntegrationId, generateEmailSdk, } from "../sync/lib.js";
|
|
6
|
+
import { generateDbTs, generateApiTs, generateBackendWrapperTs, generateAirtableTs, findEmailIntegrationId, generateEmailSdk, generateIntegrationsIndex, } from "../sync/lib.js";
|
|
7
|
+
import { gettableIntegrations, } from "../integrations/rules.js";
|
|
7
8
|
const debounceTimers = new Map();
|
|
8
9
|
function debounce(key, fn, ms) {
|
|
9
10
|
const existing = debounceTimers.get(key);
|
|
@@ -35,6 +36,48 @@ const readJsonFile = (path) => {
|
|
|
35
36
|
function getEmailIntegrationId(appDir) {
|
|
36
37
|
return findEmailIntegrationId(readJsonFile(join(appDir.path, "zite.config.json")), readJsonFile("zite.config.json"));
|
|
37
38
|
}
|
|
39
|
+
// `{}` with no file; undefined when unreadable, so a failed read keeps the old file.
|
|
40
|
+
const readConfigIntegrations = (path) => {
|
|
41
|
+
if (!existsSync(path))
|
|
42
|
+
return {};
|
|
43
|
+
const config = readJsonFile(path);
|
|
44
|
+
if (typeof config !== "object" || config === null)
|
|
45
|
+
return undefined;
|
|
46
|
+
const { integrations } = config;
|
|
47
|
+
if (integrations == null)
|
|
48
|
+
return {};
|
|
49
|
+
return typeof integrations === "object" && !Array.isArray(integrations)
|
|
50
|
+
? integrations
|
|
51
|
+
: undefined;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Whether the zitejs that `fromDir` resolves, nearest first up to the project root,
|
|
55
|
+
* has the integrations client: the CLI running generate can be newer than that pin.
|
|
56
|
+
*/
|
|
57
|
+
export function projectRuntimeHasIntegrationsClient(fromDir, projectRoot = process.cwd()) {
|
|
58
|
+
const root = resolve(projectRoot);
|
|
59
|
+
for (let dir = resolve(fromDir);; dir = dirname(dir)) {
|
|
60
|
+
const pkg = readJsonFile(join(dir, "node_modules", "zitejs", "package.json"));
|
|
61
|
+
if (pkg)
|
|
62
|
+
return pkg.exports?.["./integrations"] !== undefined;
|
|
63
|
+
if (dir === root || dirname(dir) === dir)
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Runs after the Airtable step, so the index re-exports its clients when they exist.
|
|
68
|
+
function regenerateAppIntegrationsIndex(appDir) {
|
|
69
|
+
if (!projectRuntimeHasIntegrationsClient(appDir.path))
|
|
70
|
+
return;
|
|
71
|
+
const root = readConfigIntegrations("zite.config.json");
|
|
72
|
+
const own = readConfigIntegrations(join(appDir.path, "zite.config.json"));
|
|
73
|
+
if (!root || !own)
|
|
74
|
+
return;
|
|
75
|
+
const intDir = join(appDir.path, ".zite", "integrations");
|
|
76
|
+
mkdirSync(intDir, { recursive: true });
|
|
77
|
+
writeFileSync(join(intDir, "index.ts"), generateIntegrationsIndex(gettableIntegrations(root, own), {
|
|
78
|
+
reexportAirtable: existsSync(join(intDir, "airtable.ts")),
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
38
81
|
function getDeclaredEnvVarNames(appDir) {
|
|
39
82
|
try {
|
|
40
83
|
const configPath = join(appDir.path, "zite.config.json");
|
|
@@ -149,6 +192,7 @@ export async function runGenerate() {
|
|
|
149
192
|
regenerateAppApiTs(app);
|
|
150
193
|
regenerateAppTypedWrappers(app);
|
|
151
194
|
regenerateAppAirtableSdk(app);
|
|
195
|
+
regenerateAppIntegrationsIndex(app);
|
|
152
196
|
}
|
|
153
197
|
console.log("Done!");
|
|
154
198
|
}
|
|
@@ -169,6 +213,7 @@ export async function runDev() {
|
|
|
169
213
|
for (const app of appDirs) {
|
|
170
214
|
regenerateAppApiTs(app);
|
|
171
215
|
regenerateAppTypedWrappers(app);
|
|
216
|
+
regenerateAppIntegrationsIndex(app);
|
|
172
217
|
}
|
|
173
218
|
// 3. Watch each dir's src/api/ for endpoint changes
|
|
174
219
|
let watchingAny = false;
|
|
@@ -190,7 +235,7 @@ export async function runDev() {
|
|
|
190
235
|
});
|
|
191
236
|
}
|
|
192
237
|
if (!watchingAny) {
|
|
193
|
-
console.log("No apps
|
|
238
|
+
console.log("No apps with src/api/ found.");
|
|
194
239
|
}
|
|
195
240
|
// 4. Watch zite.schema.json for schema drift
|
|
196
241
|
if (existsSync("zite.schema.json")) {
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { Zite } from "./client/index.js";
|
|
2
2
|
export type { Record, RecordListOutput, RecordListOptions, FieldCreateInput, FieldUpdateInput, TableCreateInput, TableUpdateInput, DatabaseCreateInput, DatabaseListOutput, } from "./client/index.js";
|
|
3
3
|
export * from "./types/index.js";
|
|
4
|
+
export { CREDENTIAL_FIELDS, NON_CREDENTIAL_SERVICE_TYPES, gettableIntegrations, isCredentialServiceType, normalizeIntegrationServiceType, } from "./integrations/rules.js";
|
|
5
|
+
export type { ConfigIntegrations, CredentialServiceType, GettableIntegration, } from "./integrations/rules.js";
|
package/dist/esm/index.js
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const INTEGRATIONS_SDK_INTEGRATION_ID = "__connections__";
|
|
2
|
+
export declare const INTEGRATIONS_CLASS_NAME = "Connections";
|
|
3
|
+
/**
|
|
4
|
+
* `accessToken` is the service's primary credential (for Twilio the account SID).
|
|
5
|
+
* Call `get` where the value is used: a token refreshed mid-run is what the next call returns.
|
|
6
|
+
*/
|
|
7
|
+
export type Connected<Extra = {}> = {
|
|
8
|
+
status: "connected";
|
|
9
|
+
accessToken: string;
|
|
10
|
+
} & Extra;
|
|
11
|
+
/** No account behind the entry, or its token could not be refreshed. `connectUrl` is where a person fixes that. */
|
|
12
|
+
export type NeedsConnect = {
|
|
13
|
+
status: "missing" | "expired";
|
|
14
|
+
connectUrl: string;
|
|
15
|
+
};
|
|
16
|
+
export interface IntegrationsClient<ByName extends Record<string, unknown>> {
|
|
17
|
+
/** The credentials of the `zite.config.json` integration entry named `name`. */
|
|
18
|
+
get<Name extends keyof ByName & string>(name: Name): Promise<ByName[Name]>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `ByName` maps each entry name to its answer, e.g.
|
|
22
|
+
* `{ crm: Connected<{ instanceUrl: string }> | NeedsConnect }`; `zitejs generate`
|
|
23
|
+
* writes it per app into `.zite/integrations/index.ts`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createIntegrationsClient<ByName extends Record<string, unknown>>(): IntegrationsClient<ByName>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getSdkCall } from "../internal/sdkCall.js";
|
|
2
|
+
// The worker and runner answer this call under its original name; renaming the
|
|
3
|
+
// wire protocol would break every deployed bundle for no user-visible gain.
|
|
4
|
+
export const INTEGRATIONS_SDK_INTEGRATION_ID = "__connections__";
|
|
5
|
+
export const INTEGRATIONS_CLASS_NAME = "Connections";
|
|
6
|
+
/**
|
|
7
|
+
* `ByName` maps each entry name to its answer, e.g.
|
|
8
|
+
* `{ crm: Connected<{ instanceUrl: string }> | NeedsConnect }`; `zitejs generate`
|
|
9
|
+
* writes it per app into `.zite/integrations/index.ts`.
|
|
10
|
+
*/
|
|
11
|
+
export function createIntegrationsClient() {
|
|
12
|
+
return {
|
|
13
|
+
get(name) {
|
|
14
|
+
return getSdkCall()(INTEGRATIONS_SDK_INTEGRATION_ID, INTEGRATIONS_CLASS_NAME, "get", { name });
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, expectTypeOf } from "vitest";
|
|
2
|
+
import { createIntegrationsClient, } from "./client.js";
|
|
3
|
+
import { integrations as untyped } from "./index.js";
|
|
4
|
+
import { CREDENTIAL_FIELDS, isCredentialServiceType } from "../index.js";
|
|
5
|
+
describe("createIntegrationsClient", () => {
|
|
6
|
+
const client = createIntegrationsClient();
|
|
7
|
+
it("types each name's answer", () => {
|
|
8
|
+
expectTypeOf(client.get("crm")).resolves.toEqualTypeOf();
|
|
9
|
+
});
|
|
10
|
+
it("rejects a name the app cannot see", () => {
|
|
11
|
+
// @ts-expect-error not a visible entry
|
|
12
|
+
void client.get("nope");
|
|
13
|
+
});
|
|
14
|
+
// What `.zite/integrations/index.ts` emits when nothing is visible.
|
|
15
|
+
it("accepts an empty map, naming nothing", () => {
|
|
16
|
+
const none = createIntegrationsClient();
|
|
17
|
+
expectTypeOf().toEqualTypeOf();
|
|
18
|
+
});
|
|
19
|
+
it("narrows to the connected fields on status", async () => {
|
|
20
|
+
const crm = await client.get("crm");
|
|
21
|
+
if (crm.status === "connected") {
|
|
22
|
+
expectTypeOf(crm.instanceUrl).toEqualTypeOf();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
expectTypeOf(crm.connectUrl).toEqualTypeOf();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe("the untyped zitejs/integrations client", () => {
|
|
30
|
+
it("takes any name; only accessToken is certain", async () => {
|
|
31
|
+
const entry = await untyped.get("anything");
|
|
32
|
+
if (entry.status === "connected") {
|
|
33
|
+
expectTypeOf(entry.accessToken).toEqualTypeOf();
|
|
34
|
+
expectTypeOf(entry.instanceUrl).toEqualTypeOf();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe("CREDENTIAL_FIELDS", () => {
|
|
39
|
+
it("is keyed by service type, and a string narrows to one", () => {
|
|
40
|
+
expectTypeOf(CREDENTIAL_FIELDS.salesforce).toEqualTypeOf();
|
|
41
|
+
const type = "salesforce";
|
|
42
|
+
// @ts-expect-error a plain string is not a service type
|
|
43
|
+
void CREDENTIAL_FIELDS[type];
|
|
44
|
+
if (isCredentialServiceType(type)) {
|
|
45
|
+
expectTypeOf(CREDENTIAL_FIELDS[type]).toEqualTypeOf();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type Connected, type NeedsConnect } from "./client.js";
|
|
2
|
+
export type { Connected, NeedsConnect } from "./client.js";
|
|
3
|
+
export declare const integrations: import("./client.js").IntegrationsClient<Record<string, NeedsConnect | Connected<Partial<Record<string, string>>>>>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
declare const FIELDS_BY_TYPE: {
|
|
2
|
+
googleCalendar: readonly string[];
|
|
3
|
+
googleDrive: readonly string[];
|
|
4
|
+
gmail: readonly string[];
|
|
5
|
+
googleDocs: readonly string[];
|
|
6
|
+
hubspot: readonly string[];
|
|
7
|
+
salesforce: readonly string[];
|
|
8
|
+
twilio: readonly string[];
|
|
9
|
+
slack: readonly string[];
|
|
10
|
+
linear: readonly string[];
|
|
11
|
+
openai: readonly string[];
|
|
12
|
+
googlesheets: readonly string[];
|
|
13
|
+
microsoftTeams: readonly string[];
|
|
14
|
+
onedrive: readonly string[];
|
|
15
|
+
outlook: readonly string[];
|
|
16
|
+
intercom: readonly string[];
|
|
17
|
+
mailchimp: readonly string[];
|
|
18
|
+
anthropic: readonly string[];
|
|
19
|
+
gemini: readonly string[];
|
|
20
|
+
stripe: readonly string[];
|
|
21
|
+
trello: readonly string[];
|
|
22
|
+
notion: readonly string[];
|
|
23
|
+
facebookPages: readonly string[];
|
|
24
|
+
monday: readonly string[];
|
|
25
|
+
resend: readonly string[];
|
|
26
|
+
clickhouse: readonly string[];
|
|
27
|
+
amplitude: readonly string[];
|
|
28
|
+
elevenlabs: readonly string[];
|
|
29
|
+
brevo: readonly string[];
|
|
30
|
+
calendly: readonly string[];
|
|
31
|
+
asana: readonly string[];
|
|
32
|
+
xero: readonly string[];
|
|
33
|
+
googleForms: readonly string[];
|
|
34
|
+
linkedin: readonly string[];
|
|
35
|
+
github: readonly string[];
|
|
36
|
+
quickbooks: readonly string[];
|
|
37
|
+
firecrawl: readonly string[];
|
|
38
|
+
jira: readonly string[];
|
|
39
|
+
typeform: readonly string[];
|
|
40
|
+
apollo: readonly string[];
|
|
41
|
+
attio: readonly string[];
|
|
42
|
+
};
|
|
43
|
+
/** A service type `integrations.get` serves: one used through its npm package with a token. */
|
|
44
|
+
export type CredentialServiceType = keyof typeof FIELDS_BY_TYPE;
|
|
45
|
+
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
46
|
+
export declare const CREDENTIAL_FIELDS: Readonly<Record<CredentialServiceType, readonly string[]>>;
|
|
47
|
+
/**
|
|
48
|
+
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
49
|
+
* the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
|
|
50
|
+
*/
|
|
51
|
+
export declare const NON_CREDENTIAL_SERVICE_TYPES: readonly string[];
|
|
52
|
+
export declare const normalizeIntegrationServiceType: (type: string) => string;
|
|
53
|
+
export declare const isCredentialServiceType: (type: string) => type is CredentialServiceType;
|
|
54
|
+
/** One entry `integrations.get` can name from a source dir. */
|
|
55
|
+
export type GettableIntegration = {
|
|
56
|
+
name: string;
|
|
57
|
+
serviceType: CredentialServiceType;
|
|
58
|
+
};
|
|
59
|
+
export type ConfigIntegrations = Readonly<Record<string, {
|
|
60
|
+
type?: unknown;
|
|
61
|
+
} | undefined>>;
|
|
62
|
+
/**
|
|
63
|
+
* The entries a source dir can name, by name: its own, then the workspace's under
|
|
64
|
+
* keys it has not taken. An entry whose type the runtime would not serve is dropped.
|
|
65
|
+
*/
|
|
66
|
+
export declare const gettableIntegrations: (rootIntegrations: ConfigIntegrations | undefined, appIntegrations?: ConfigIntegrations) => GettableIntegration[];
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Which `zite.config.json` entries `integrations.get` can name, and the fields
|
|
2
|
+
// each answers with. No imports, so the platform applies these same rules.
|
|
3
|
+
const extras = (...labels) => [
|
|
4
|
+
"accessToken",
|
|
5
|
+
...[...labels].sort(),
|
|
6
|
+
];
|
|
7
|
+
const FIELDS_BY_TYPE = {
|
|
8
|
+
googleCalendar: extras(),
|
|
9
|
+
googleDrive: extras(),
|
|
10
|
+
gmail: extras(),
|
|
11
|
+
googleDocs: extras(),
|
|
12
|
+
hubspot: extras(),
|
|
13
|
+
salesforce: extras("instanceUrl"),
|
|
14
|
+
twilio: extras("authToken"),
|
|
15
|
+
slack: extras(),
|
|
16
|
+
linear: extras(),
|
|
17
|
+
openai: extras(),
|
|
18
|
+
googlesheets: extras(),
|
|
19
|
+
microsoftTeams: extras(),
|
|
20
|
+
onedrive: extras(),
|
|
21
|
+
outlook: extras(),
|
|
22
|
+
intercom: extras(),
|
|
23
|
+
mailchimp: extras("server"),
|
|
24
|
+
anthropic: extras(),
|
|
25
|
+
gemini: extras(),
|
|
26
|
+
stripe: extras(),
|
|
27
|
+
trello: extras("clientApiKey"),
|
|
28
|
+
notion: extras(),
|
|
29
|
+
facebookPages: extras(),
|
|
30
|
+
monday: extras(),
|
|
31
|
+
resend: extras(),
|
|
32
|
+
clickhouse: extras("url", "username"),
|
|
33
|
+
amplitude: extras("apiKey"),
|
|
34
|
+
elevenlabs: extras(),
|
|
35
|
+
brevo: extras(),
|
|
36
|
+
calendly: extras(),
|
|
37
|
+
asana: extras(),
|
|
38
|
+
xero: extras("tenantId"),
|
|
39
|
+
googleForms: extras(),
|
|
40
|
+
linkedin: extras("personUrn"),
|
|
41
|
+
github: extras(),
|
|
42
|
+
quickbooks: extras("realmId", "apiBaseUrl"),
|
|
43
|
+
firecrawl: extras(),
|
|
44
|
+
jira: extras("cloudId", "siteUrl"),
|
|
45
|
+
typeform: extras(),
|
|
46
|
+
apollo: extras(),
|
|
47
|
+
attio: extras(),
|
|
48
|
+
};
|
|
49
|
+
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
50
|
+
export const CREDENTIAL_FIELDS = FIELDS_BY_TYPE;
|
|
51
|
+
/**
|
|
52
|
+
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
53
|
+
* the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
|
|
54
|
+
*/
|
|
55
|
+
export const NON_CREDENTIAL_SERVICE_TYPES = [
|
|
56
|
+
"airtable",
|
|
57
|
+
"databases",
|
|
58
|
+
"email",
|
|
59
|
+
"fillout",
|
|
60
|
+
"googleAnalytics",
|
|
61
|
+
"googlemaps",
|
|
62
|
+
];
|
|
63
|
+
/** Spellings older configs, or an agent writing the entry's slug, put in `type`. */
|
|
64
|
+
const LEGACY_SERVICE_TYPES = {
|
|
65
|
+
googlecalendar: "googleCalendar",
|
|
66
|
+
"google-drive": "googleDrive",
|
|
67
|
+
"google-docs": "googleDocs",
|
|
68
|
+
"google-calendar": "googleCalendar",
|
|
69
|
+
"google-sheets": "googlesheets",
|
|
70
|
+
"google-analytics": "googleAnalytics",
|
|
71
|
+
"google-maps": "googlemaps",
|
|
72
|
+
"microsoft-teams": "microsoftTeams",
|
|
73
|
+
"one-drive": "onedrive",
|
|
74
|
+
};
|
|
75
|
+
// Own keys only: a name like `constructor` must not match Object.prototype.
|
|
76
|
+
const hasOwn = (record, key) => Object.prototype.hasOwnProperty.call(record, key);
|
|
77
|
+
export const normalizeIntegrationServiceType = (type) => hasOwn(LEGACY_SERVICE_TYPES, type) ? LEGACY_SERVICE_TYPES[type] : type;
|
|
78
|
+
export const isCredentialServiceType = (type) => hasOwn(FIELDS_BY_TYPE, type);
|
|
79
|
+
/**
|
|
80
|
+
* The entries a source dir can name, by name: its own, then the workspace's under
|
|
81
|
+
* keys it has not taken. An entry whose type the runtime would not serve is dropped.
|
|
82
|
+
*/
|
|
83
|
+
export const gettableIntegrations = (rootIntegrations, appIntegrations) => {
|
|
84
|
+
const own = appIntegrations ?? {};
|
|
85
|
+
const workspace = rootIntegrations ?? {};
|
|
86
|
+
const visible = [];
|
|
87
|
+
for (const [name, entry] of [
|
|
88
|
+
...Object.entries(own),
|
|
89
|
+
...Object.entries(workspace).filter(([name]) => !hasOwn(own, name)),
|
|
90
|
+
]) {
|
|
91
|
+
if (typeof entry?.type !== "string")
|
|
92
|
+
continue;
|
|
93
|
+
const serviceType = normalizeIntegrationServiceType(entry.type);
|
|
94
|
+
if (isCredentialServiceType(serviceType))
|
|
95
|
+
visible.push({ name, serviceType });
|
|
96
|
+
}
|
|
97
|
+
return visible.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
98
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|