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.
Files changed (70) hide show
  1. package/README.md +4 -0
  2. package/dist/cjs/auth/index.d.ts +2 -2
  3. package/dist/cjs/bundle/index.d.ts +5 -1
  4. package/dist/cjs/bundle/index.js +46 -26
  5. package/dist/cjs/check/index.js +2 -2
  6. package/dist/cjs/cli.js +1 -1
  7. package/dist/cjs/dev/index.d.ts +5 -0
  8. package/dist/cjs/dev/index.js +47 -1
  9. package/dist/cjs/index.d.ts +2 -0
  10. package/dist/cjs/index.js +7 -1
  11. package/dist/cjs/integrations/client.d.ts +25 -0
  12. package/dist/cjs/integrations/client.js +21 -0
  13. package/dist/cjs/integrations/client.test-d.d.ts +1 -0
  14. package/dist/cjs/integrations/client.test-d.js +50 -0
  15. package/dist/cjs/integrations/index.d.ts +3 -0
  16. package/dist/cjs/integrations/index.js +6 -0
  17. package/dist/cjs/integrations/rules.d.ts +67 -0
  18. package/dist/cjs/integrations/rules.js +104 -0
  19. package/dist/cjs/integrations/rules.test.d.ts +1 -0
  20. package/dist/cjs/integrations/rules.test.js +86 -0
  21. package/dist/cjs/internal/sdkCall.d.ts +1 -0
  22. package/dist/cjs/internal/sdkCall.js +3 -1
  23. package/dist/cjs/runtime/index.d.ts +1 -0
  24. package/dist/cjs/runtime/index.js +3 -1
  25. package/dist/cjs/sourceRoots.d.ts +13 -0
  26. package/dist/cjs/sourceRoots.js +38 -1
  27. package/dist/cjs/sourceRoots.test.d.ts +1 -0
  28. package/dist/cjs/sourceRoots.test.js +30 -0
  29. package/dist/cjs/sync/lib.d.ts +9 -0
  30. package/dist/cjs/sync/lib.js +53 -0
  31. package/dist/cjs/sync/lib.test.js +119 -0
  32. package/dist/esm/auth/index.d.ts +2 -2
  33. package/dist/esm/bundle/index.d.ts +5 -1
  34. package/dist/esm/bundle/index.js +47 -28
  35. package/dist/esm/check/index.js +3 -3
  36. package/dist/esm/cli.js +1 -1
  37. package/dist/esm/dev/index.d.ts +5 -0
  38. package/dist/esm/dev/index.js +48 -3
  39. package/dist/esm/index.d.ts +2 -0
  40. package/dist/esm/index.js +1 -0
  41. package/dist/esm/integrations/client.d.ts +25 -0
  42. package/dist/esm/integrations/client.js +17 -0
  43. package/dist/esm/integrations/client.test-d.d.ts +1 -0
  44. package/dist/esm/integrations/client.test-d.js +48 -0
  45. package/dist/esm/integrations/index.d.ts +3 -0
  46. package/dist/esm/integrations/index.js +3 -0
  47. package/dist/esm/integrations/rules.d.ts +67 -0
  48. package/dist/esm/integrations/rules.js +98 -0
  49. package/dist/esm/integrations/rules.test.d.ts +1 -0
  50. package/dist/esm/integrations/rules.test.js +84 -0
  51. package/dist/esm/internal/sdkCall.d.ts +1 -0
  52. package/dist/esm/internal/sdkCall.js +2 -1
  53. package/dist/esm/runtime/index.d.ts +1 -0
  54. package/dist/esm/runtime/index.js +1 -0
  55. package/dist/esm/sourceRoots.d.ts +13 -0
  56. package/dist/esm/sourceRoots.js +35 -1
  57. package/dist/esm/sourceRoots.test.d.ts +1 -0
  58. package/dist/esm/sourceRoots.test.js +28 -0
  59. package/dist/esm/sync/lib.d.ts +9 -0
  60. package/dist/esm/sync/lib.js +52 -0
  61. package/dist/esm/sync/lib.test.js +120 -1
  62. package/package.json +10 -1
  63. package/dist/cjs/meta/index.d.ts +0 -14
  64. package/dist/cjs/meta/index.js +0 -12
  65. package/dist/cjs/notifications/index.d.ts +0 -25
  66. package/dist/cjs/notifications/index.js +0 -12
  67. package/dist/esm/meta/index.d.ts +0 -14
  68. package/dist/esm/meta/index.js +0 -8
  69. package/dist/esm/notifications/index.d.ts +0 -25
  70. package/dist/esm/notifications/index.js +0 -8
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ // Which `zite.config.json` entries `integrations.get` can name, and the fields
3
+ // each answers with. No imports, so the platform applies these same rules.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.gettableIntegrations = exports.isCredentialServiceType = exports.normalizeIntegrationServiceType = exports.NON_CREDENTIAL_SERVICE_TYPES = exports.CREDENTIAL_FIELDS = void 0;
6
+ const extras = (...labels) => [
7
+ "accessToken",
8
+ ...[...labels].sort(),
9
+ ];
10
+ const FIELDS_BY_TYPE = {
11
+ googleCalendar: extras(),
12
+ googleDrive: extras(),
13
+ gmail: extras(),
14
+ googleDocs: extras(),
15
+ hubspot: extras(),
16
+ salesforce: extras("instanceUrl"),
17
+ twilio: extras("authToken"),
18
+ slack: extras(),
19
+ linear: extras(),
20
+ openai: extras(),
21
+ googlesheets: extras(),
22
+ microsoftTeams: extras(),
23
+ onedrive: extras(),
24
+ outlook: extras(),
25
+ intercom: extras(),
26
+ mailchimp: extras("server"),
27
+ anthropic: extras(),
28
+ gemini: extras(),
29
+ stripe: extras(),
30
+ trello: extras("clientApiKey"),
31
+ notion: extras(),
32
+ facebookPages: extras(),
33
+ monday: extras(),
34
+ resend: extras(),
35
+ clickhouse: extras("url", "username"),
36
+ amplitude: extras("apiKey"),
37
+ elevenlabs: extras(),
38
+ brevo: extras(),
39
+ calendly: extras(),
40
+ asana: extras(),
41
+ xero: extras("tenantId"),
42
+ googleForms: extras(),
43
+ linkedin: extras("personUrn"),
44
+ github: extras(),
45
+ quickbooks: extras("realmId", "apiBaseUrl"),
46
+ firecrawl: extras(),
47
+ jira: extras("cloudId", "siteUrl"),
48
+ typeform: extras(),
49
+ apollo: extras(),
50
+ attio: extras(),
51
+ };
52
+ /** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
53
+ exports.CREDENTIAL_FIELDS = FIELDS_BY_TYPE;
54
+ /**
55
+ * Types the runtime never serves: those with a generated client (Airtable, email,
56
+ * the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
57
+ */
58
+ exports.NON_CREDENTIAL_SERVICE_TYPES = [
59
+ "airtable",
60
+ "databases",
61
+ "email",
62
+ "fillout",
63
+ "googleAnalytics",
64
+ "googlemaps",
65
+ ];
66
+ /** Spellings older configs, or an agent writing the entry's slug, put in `type`. */
67
+ const LEGACY_SERVICE_TYPES = {
68
+ googlecalendar: "googleCalendar",
69
+ "google-drive": "googleDrive",
70
+ "google-docs": "googleDocs",
71
+ "google-calendar": "googleCalendar",
72
+ "google-sheets": "googlesheets",
73
+ "google-analytics": "googleAnalytics",
74
+ "google-maps": "googlemaps",
75
+ "microsoft-teams": "microsoftTeams",
76
+ "one-drive": "onedrive",
77
+ };
78
+ // Own keys only: a name like `constructor` must not match Object.prototype.
79
+ const hasOwn = (record, key) => Object.prototype.hasOwnProperty.call(record, key);
80
+ const normalizeIntegrationServiceType = (type) => hasOwn(LEGACY_SERVICE_TYPES, type) ? LEGACY_SERVICE_TYPES[type] : type;
81
+ exports.normalizeIntegrationServiceType = normalizeIntegrationServiceType;
82
+ const isCredentialServiceType = (type) => hasOwn(FIELDS_BY_TYPE, type);
83
+ exports.isCredentialServiceType = isCredentialServiceType;
84
+ /**
85
+ * The entries a source dir can name, by name: its own, then the workspace's under
86
+ * keys it has not taken. An entry whose type the runtime would not serve is dropped.
87
+ */
88
+ const gettableIntegrations = (rootIntegrations, appIntegrations) => {
89
+ const own = appIntegrations ?? {};
90
+ const workspace = rootIntegrations ?? {};
91
+ const visible = [];
92
+ for (const [name, entry] of [
93
+ ...Object.entries(own),
94
+ ...Object.entries(workspace).filter(([name]) => !hasOwn(own, name)),
95
+ ]) {
96
+ if (typeof entry?.type !== "string")
97
+ continue;
98
+ const serviceType = (0, exports.normalizeIntegrationServiceType)(entry.type);
99
+ if ((0, exports.isCredentialServiceType)(serviceType))
100
+ visible.push({ name, serviceType });
101
+ }
102
+ return visible.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
103
+ };
104
+ exports.gettableIntegrations = gettableIntegrations;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const index_js_1 = require("../index.js");
5
+ (0, vitest_1.describe)("CREDENTIAL_FIELDS", () => {
6
+ (0, vitest_1.it)("answers accessToken, then the service's extras sorted", () => {
7
+ (0, vitest_1.expect)(index_js_1.CREDENTIAL_FIELDS.slack).toEqual(["accessToken"]);
8
+ (0, vitest_1.expect)(index_js_1.CREDENTIAL_FIELDS.salesforce).toEqual(["accessToken", "instanceUrl"]);
9
+ (0, vitest_1.expect)(index_js_1.CREDENTIAL_FIELDS.clickhouse).toEqual([
10
+ "accessToken",
11
+ "url",
12
+ "username",
13
+ ]);
14
+ (0, vitest_1.expect)(index_js_1.CREDENTIAL_FIELDS.quickbooks).toEqual([
15
+ "accessToken",
16
+ "apiBaseUrl",
17
+ "realmId",
18
+ ]);
19
+ (0, vitest_1.expect)(index_js_1.CREDENTIAL_FIELDS.jira).toEqual(["accessToken", "cloudId", "siteUrl"]);
20
+ });
21
+ (0, vitest_1.it)("has no type the runtime never serves", () => {
22
+ for (const type of index_js_1.NON_CREDENTIAL_SERVICE_TYPES) {
23
+ (0, vitest_1.expect)((0, index_js_1.isCredentialServiceType)(type)).toBe(false);
24
+ }
25
+ });
26
+ (0, vitest_1.it)("does not treat Object.prototype names as service types", () => {
27
+ (0, vitest_1.expect)((0, index_js_1.isCredentialServiceType)("toString")).toBe(false);
28
+ (0, vitest_1.expect)((0, index_js_1.normalizeIntegrationServiceType)("constructor")).toBe("constructor");
29
+ });
30
+ });
31
+ (0, vitest_1.describe)("normalizeIntegrationServiceType", () => {
32
+ vitest_1.it.each([
33
+ ["googlecalendar", "googleCalendar"],
34
+ ["google-drive", "googleDrive"],
35
+ ["google-sheets", "googlesheets"],
36
+ ["microsoft-teams", "microsoftTeams"],
37
+ ["one-drive", "onedrive"],
38
+ ])("maps %s to %s", (legacy, canonical) => {
39
+ (0, vitest_1.expect)((0, index_js_1.normalizeIntegrationServiceType)(legacy)).toBe(canonical);
40
+ (0, vitest_1.expect)((0, index_js_1.isCredentialServiceType)(canonical)).toBe(true);
41
+ });
42
+ (0, vitest_1.it)("leaves a canonical type alone", () => {
43
+ (0, vitest_1.expect)((0, index_js_1.normalizeIntegrationServiceType)("slack")).toBe("slack");
44
+ });
45
+ });
46
+ (0, vitest_1.describe)("gettableIntegrations", () => {
47
+ (0, vitest_1.it)("lists the app's entries, then the workspace's under untaken keys, by name", () => {
48
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ crm: { type: "salesforce" }, team: { type: "slack" } }, { billing: { type: "stripe" }, team: { type: "microsoftTeams" } })).toEqual([
49
+ { name: "billing", serviceType: "stripe" },
50
+ { name: "crm", serviceType: "salesforce" },
51
+ { name: "team", serviceType: "microsoftTeams" },
52
+ ]);
53
+ });
54
+ (0, vitest_1.it)("lets an app entry of a generated-client type shadow a workspace credential entry", () => {
55
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ mail: { type: "gmail" } }, { mail: { type: "email" } })).toEqual([]);
56
+ });
57
+ (0, vitest_1.it)("drops types the runtime never serves and entries without a type", () => {
58
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({
59
+ base: { type: "airtable" },
60
+ mail: { type: "email" },
61
+ db: { type: "databases" },
62
+ form: { type: "fillout" },
63
+ map: { type: "google-maps" },
64
+ ga: { type: "googleAnalytics" },
65
+ broken: {},
66
+ numeric: { type: 7 },
67
+ gone: undefined,
68
+ })).toEqual([]);
69
+ });
70
+ (0, vitest_1.it)("normalizes legacy type spellings", () => {
71
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ cal: { type: "google-calendar" } })).toEqual([
72
+ { name: "cal", serviceType: "googleCalendar" },
73
+ ]);
74
+ });
75
+ (0, vitest_1.it)("drops a type it does not know, as the runtime does", () => {
76
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ next: { type: "someNewService" } })).toEqual([]);
77
+ });
78
+ (0, vitest_1.it)("shadows by own keys only", () => {
79
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ constructor: { type: "slack" } }, {})).toEqual([
80
+ { name: "constructor", serviceType: "slack" },
81
+ ]);
82
+ });
83
+ (0, vitest_1.it)("works with no configs", () => {
84
+ (0, vitest_1.expect)((0, index_js_1.gettableIntegrations)(undefined)).toEqual([]);
85
+ });
86
+ });
@@ -1,2 +1,3 @@
1
1
  export type SdkCall = (integrationId: string, className: string, methodName: string, params?: unknown) => Promise<unknown>;
2
+ export declare const SDK_NOT_INITIALIZED_MESSAGE = "Zite SDK runtime not initialized. Endpoints must run inside the Zite worker.";
2
3
  export declare function getSdkCall(): SdkCall;
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SDK_NOT_INITIALIZED_MESSAGE = void 0;
3
4
  exports.getSdkCall = getSdkCall;
5
+ exports.SDK_NOT_INITIALIZED_MESSAGE = 'Zite SDK runtime not initialized. Endpoints must run inside the Zite worker.';
4
6
  function getSdkCall() {
5
7
  const fn = globalThis.__wrapSdkCall;
6
8
  if (!fn) {
7
- throw new Error('Zite SDK runtime not initialized. Endpoints must run inside the Zite worker.');
9
+ throw new Error(exports.SDK_NOT_INITIALIZED_MESSAGE);
8
10
  }
9
11
  return fn;
10
12
  }
@@ -332,5 +332,6 @@ export interface EmailClient {
332
332
  * app's connected email integration key.
333
333
  */
334
334
  export declare function createEmailClient(integrationId: string): EmailClient;
335
+ export { createIntegrationsClient, type Connected, type IntegrationsClient, type NeedsConnect, } from "../integrations/client.js";
335
336
  export { createCaller } from "../caller/index.js";
336
337
  export type { EndpointConfig } from "../caller/index.js";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createCaller = void 0;
3
+ exports.createCaller = exports.createIntegrationsClient = void 0;
4
4
  exports.createTableClient = createTableClient;
5
5
  exports.createSqlClient = createSqlClient;
6
6
  exports.createAuthClient = createAuthClient;
@@ -211,5 +211,7 @@ function createEmailClient(integrationId) {
211
211
  send: (params) => (0, sdkCall_js_1.getSdkCall)()(integrationId, "Email", "send", params),
212
212
  };
213
213
  }
214
+ var client_js_1 = require("../integrations/client.js");
215
+ Object.defineProperty(exports, "createIntegrationsClient", { enumerable: true, get: function () { return client_js_1.createIntegrationsClient; } });
214
216
  var index_js_1 = require("../caller/index.js");
215
217
  Object.defineProperty(exports, "createCaller", { enumerable: true, get: function () { return index_js_1.createCaller; } });
@@ -17,3 +17,16 @@ export interface SourceDir {
17
17
  export declare function listSourceDirs(cwd?: string): SourceDir[];
18
18
  /** The source dir with this bare name, under whichever root holds it. */
19
19
  export declare function findSourceDir(name: string, cwd?: string): SourceDir | undefined;
20
+ /**
21
+ * An automation is one workflow: its single endpoint is `src/workflow.ts` and
22
+ * its name is fixed, so nothing about an automation is keyed on a file name
23
+ * the way an app's `src/api/<name>.ts` endpoints are.
24
+ */
25
+ export declare const AUTOMATION_ENDPOINT_NAME = "workflow";
26
+ export declare const AUTOMATION_WORKFLOW_FILE = "src/workflow.ts";
27
+ /** The root a source dir sits under, read from its parent directory. */
28
+ export declare function sourceRootOf(sourceDirPath: string): SourceRoot | undefined;
29
+ /** An endpoint's entry file, relative to the source dir. */
30
+ export declare function endpointEntryFile(root: SourceRoot, name: string): string;
31
+ /** Every endpoint name a source dir has on disk. */
32
+ export declare function listEndpointNames(root: SourceRoot, sourceDirPath: string): string[];
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SOURCE_ROOTS = void 0;
3
+ exports.AUTOMATION_WORKFLOW_FILE = exports.AUTOMATION_ENDPOINT_NAME = exports.SOURCE_ROOTS = void 0;
4
4
  exports.listSourceDirs = listSourceDirs;
5
5
  exports.findSourceDir = findSourceDir;
6
+ exports.sourceRootOf = sourceRootOf;
7
+ exports.endpointEntryFile = endpointEntryFile;
8
+ exports.listEndpointNames = listEndpointNames;
6
9
  const fs_1 = require("fs");
7
10
  const path_1 = require("path");
8
11
  /**
@@ -31,3 +34,37 @@ function listSourceDirs(cwd = ".") {
31
34
  function findSourceDir(name, cwd = ".") {
32
35
  return listSourceDirs(cwd).find((d) => d.dir === name);
33
36
  }
37
+ /**
38
+ * An automation is one workflow: its single endpoint is `src/workflow.ts` and
39
+ * its name is fixed, so nothing about an automation is keyed on a file name
40
+ * the way an app's `src/api/<name>.ts` endpoints are.
41
+ */
42
+ exports.AUTOMATION_ENDPOINT_NAME = "workflow";
43
+ exports.AUTOMATION_WORKFLOW_FILE = "src/workflow.ts";
44
+ /** The root a source dir sits under, read from its parent directory. */
45
+ function sourceRootOf(sourceDirPath) {
46
+ const parent = (0, path_1.basename)((0, path_1.dirname)((0, path_1.resolve)(sourceDirPath)));
47
+ return exports.SOURCE_ROOTS.includes(parent)
48
+ ? parent
49
+ : undefined;
50
+ }
51
+ /** An endpoint's entry file, relative to the source dir. */
52
+ function endpointEntryFile(root, name) {
53
+ return root === "automations"
54
+ ? exports.AUTOMATION_WORKFLOW_FILE
55
+ : (0, path_1.join)("src", "api", `${name}.ts`);
56
+ }
57
+ /** Every endpoint name a source dir has on disk. */
58
+ function listEndpointNames(root, sourceDirPath) {
59
+ if (root === "automations") {
60
+ return (0, fs_1.existsSync)((0, path_1.join)(sourceDirPath, exports.AUTOMATION_WORKFLOW_FILE))
61
+ ? [exports.AUTOMATION_ENDPOINT_NAME]
62
+ : [];
63
+ }
64
+ const apiDir = (0, path_1.join)(sourceDirPath, "src", "api");
65
+ return (0, fs_1.existsSync)(apiDir)
66
+ ? (0, fs_1.readdirSync)(apiDir)
67
+ .filter((f) => f.endsWith(".ts") && !f.endsWith(".d.ts"))
68
+ .map((f) => f.replace(/\.ts$/, ""))
69
+ : [];
70
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const os_1 = require("os");
5
+ const path_1 = require("path");
6
+ const vitest_1 = require("vitest");
7
+ const sourceRoots_js_1 = require("./sourceRoots.js");
8
+ (0, vitest_1.describe)("source roots", () => {
9
+ (0, vitest_1.it)("reads the root from the source dir's parent", () => {
10
+ (0, vitest_1.expect)((0, sourceRoots_js_1.sourceRootOf)("/repo/apps/crm")).toBe("apps");
11
+ (0, vitest_1.expect)((0, sourceRoots_js_1.sourceRootOf)("/repo/automations/digest")).toBe("automations");
12
+ (0, vitest_1.expect)((0, sourceRoots_js_1.sourceRootOf)("/repo/packages/ui")).toBeUndefined();
13
+ });
14
+ (0, vitest_1.it)("an app's endpoints are src/api/<name>.ts; an automation's one endpoint is src/workflow.ts", () => {
15
+ (0, vitest_1.expect)((0, sourceRoots_js_1.endpointEntryFile)("apps", "listItems")).toBe("src/api/listItems.ts");
16
+ (0, vitest_1.expect)((0, sourceRoots_js_1.endpointEntryFile)("automations", "workflow")).toBe("src/workflow.ts");
17
+ });
18
+ (0, vitest_1.it)("lists what is on disk under each layout", () => {
19
+ const repo = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), "zitejs-roots-"));
20
+ (0, fs_1.mkdirSync)((0, path_1.join)(repo, "apps/crm/src/api"), { recursive: true });
21
+ (0, fs_1.writeFileSync)((0, path_1.join)(repo, "apps/crm/src/api/listItems.ts"), "");
22
+ (0, fs_1.writeFileSync)((0, path_1.join)(repo, "apps/crm/src/api/apiTypes.d.ts"), "");
23
+ (0, fs_1.mkdirSync)((0, path_1.join)(repo, "automations/digest/src"), { recursive: true });
24
+ (0, fs_1.mkdirSync)((0, path_1.join)(repo, "automations/empty/src"), { recursive: true });
25
+ (0, fs_1.writeFileSync)((0, path_1.join)(repo, "automations/digest/src/workflow.ts"), "");
26
+ (0, vitest_1.expect)((0, sourceRoots_js_1.listEndpointNames)("apps", (0, path_1.join)(repo, "apps/crm"))).toEqual(["listItems"]);
27
+ (0, vitest_1.expect)((0, sourceRoots_js_1.listEndpointNames)("automations", (0, path_1.join)(repo, "automations/digest"))).toEqual(["workflow"]);
28
+ (0, vitest_1.expect)((0, sourceRoots_js_1.listEndpointNames)("automations", (0, path_1.join)(repo, "automations/empty"))).toEqual([]);
29
+ });
30
+ });
@@ -1,6 +1,7 @@
1
1
  import type { PublicFieldDefinition } from "../types/fields.js";
2
2
  import type { Database } from "../types/tables.js";
3
3
  import { type SdkNameRename } from "./sdkNames.js";
4
+ import { type GettableIntegration } from "../integrations/rules.js";
4
5
  export type ZiteSchemaField = {
5
6
  id: string;
6
7
  sdkName: string;
@@ -96,3 +97,11 @@ export declare function findEmailIntegrationId(appConfig: unknown, workspaceConf
96
97
  * connected integration's key.
97
98
  */
98
99
  export declare function generateEmailSdk(integrationId: string): string;
100
+ /**
101
+ * `.zite/integrations/index.ts`: `zitejs/integrations` for one source dir. The
102
+ * `integrations` client typed by what the dir can see, plus the generated
103
+ * Airtable clients when it has them.
104
+ */
105
+ export declare function generateIntegrationsIndex(entries: GettableIntegration[], opts: {
106
+ reexportAirtable: boolean;
107
+ }): string;
@@ -9,8 +9,10 @@ exports.generateAirtableTs = generateAirtableTs;
9
9
  exports.generateBackendWrapperTs = generateBackendWrapperTs;
10
10
  exports.findEmailIntegrationId = findEmailIntegrationId;
11
11
  exports.generateEmailSdk = generateEmailSdk;
12
+ exports.generateIntegrationsIndex = generateIntegrationsIndex;
12
13
  const parser_1 = require("@babel/parser");
13
14
  const sdkNames_js_1 = require("./sdkNames.js");
15
+ const rules_js_1 = require("../integrations/rules.js");
14
16
  const AUTH_USERS_TABLE_ID = "zite_user";
15
17
  /**
16
18
  * What a field's value looks like when a record is READ back.
@@ -1397,3 +1399,54 @@ function generateEmailSdk(integrationId) {
1397
1399
  "",
1398
1400
  ].join("\n");
1399
1401
  }
1402
+ const connectedTypeFor = (serviceType) => {
1403
+ const extraLabels = rules_js_1.CREDENTIAL_FIELDS[serviceType].slice(1);
1404
+ return extraLabels.length === 0
1405
+ ? "Connected"
1406
+ : `Connected<{ ${extraLabels.map((label) => `${label}: string`).join("; ")} }>`;
1407
+ };
1408
+ /**
1409
+ * `.zite/integrations/index.ts`: `zitejs/integrations` for one source dir. The
1410
+ * `integrations` client typed by what the dir can see, plus the generated
1411
+ * Airtable clients when it has them.
1412
+ */
1413
+ function generateIntegrationsIndex(entries, opts) {
1414
+ const sorted = [...entries].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
1415
+ const nameUnion = sorted.length === 0
1416
+ ? "never"
1417
+ : sorted.map(({ name }) => tsSingleQuoted(name)).join(" | ");
1418
+ const byName = sorted.length === 0
1419
+ ? ["export type IntegrationByName = {};"]
1420
+ : [
1421
+ "export type IntegrationByName = {",
1422
+ ...sorted.map(({ name, serviceType }) => ` ${tsSingleQuoted(name)}: ${connectedTypeFor(serviceType)} | NeedsConnect;`),
1423
+ "};",
1424
+ ];
1425
+ return [
1426
+ "// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.",
1427
+ "// zitejs/integrations — an integration's credentials by its zite.config.json entry name.",
1428
+ "//",
1429
+ "// Usage in endpoints (src/api/*.ts) and automations (src/workflow.ts):",
1430
+ "// import { integrations } from 'zitejs/integrations';",
1431
+ "//",
1432
+ "// const crm = await integrations.get('<entry name>');",
1433
+ "// if (crm.status !== 'connected') { /* crm.connectUrl is where a person reconnects */ }",
1434
+ "//",
1435
+ "// Call get where the value is used, not once at module scope: a token refreshed",
1436
+ "// mid-run is what the next call returns.",
1437
+ "",
1438
+ // Not 'zitejs/integrations': apps alias that specifier to this very file.
1439
+ "import { createIntegrationsClient } from 'zitejs/runtime';",
1440
+ "import type { Connected, NeedsConnect } from 'zitejs/runtime';",
1441
+ "",
1442
+ ...(opts.reexportAirtable ? ["export * from './airtable';", ""] : []),
1443
+ "export type { Connected, NeedsConnect };",
1444
+ "",
1445
+ `export type IntegrationName = ${nameUnion};`,
1446
+ "",
1447
+ ...byName,
1448
+ "",
1449
+ "export const integrations = createIntegrationsClient<IntegrationByName>();",
1450
+ "",
1451
+ ].join("\n");
1452
+ }
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const vitest_1 = require("vitest");
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
+ const path_1 = require("path");
8
9
  const lib_js_1 = require("./lib.js");
9
10
  /**
10
11
  * Syntax errors in the emitted source. `.zite/db.ts` sits at the repo root and
@@ -418,3 +419,121 @@ const duplicateIdentifierErrorsIn = (source) => {
418
419
  (0, vitest_1.expect)((0, lib_js_1.findEmailIntegrationId)(undefined, undefined)).toBeUndefined();
419
420
  });
420
421
  });
422
+ (0, vitest_1.describe)('generateIntegrationsIndex', () => {
423
+ // Not import.meta: this file also compiles to CommonJS. Vitest runs from the repo root.
424
+ const runtimePath = (0, path_1.resolve)('src/runtime/index.ts');
425
+ /** Type errors in `usage` compiled beside the generated file, `zitejs/runtime` mapped to this source. */
426
+ const typeErrorsIn = (generated, usage, airtable) => {
427
+ const files = {
428
+ '/app/.zite/integrations/index.ts': generated,
429
+ ...(airtable ? { '/app/.zite/integrations/airtable.ts': airtable } : {}),
430
+ '/app/src/usage.ts': usage,
431
+ };
432
+ const options = {
433
+ strict: true,
434
+ noEmit: true,
435
+ target: typescript_1.default.ScriptTarget.ES2022,
436
+ module: typescript_1.default.ModuleKind.ESNext,
437
+ moduleResolution: typescript_1.default.ModuleResolutionKind.Bundler,
438
+ skipLibCheck: true,
439
+ baseUrl: '/app',
440
+ paths: {
441
+ 'zitejs/runtime': [runtimePath],
442
+ 'zitejs/integrations': ['/app/.zite/integrations/index.ts'],
443
+ },
444
+ };
445
+ const host = typescript_1.default.createCompilerHost(options);
446
+ const { getSourceFile, fileExists, readFile, directoryExists } = host;
447
+ host.fileExists = f => f in files || fileExists(f);
448
+ host.directoryExists = d => Object.keys(files).some(f => f.startsWith(`${d}/`)) ||
449
+ (directoryExists?.(d) ?? false);
450
+ host.readFile = f => files[f] ?? readFile(f);
451
+ host.getSourceFile = (f, lang, ...rest) => f in files
452
+ ? typescript_1.default.createSourceFile(f, files[f], lang)
453
+ : getSourceFile(f, lang, ...rest);
454
+ const program = typescript_1.default.createProgram(Object.keys(files), options, host);
455
+ return typescript_1.default
456
+ .getPreEmitDiagnostics(program)
457
+ .filter(d => d.file?.fileName.startsWith('/app/'))
458
+ .map(d => typescript_1.default.flattenDiagnosticMessageText(d.messageText, ' '));
459
+ };
460
+ (0, vitest_1.it)('emits the client typed by name', () => {
461
+ (0, vitest_1.expect)((0, lib_js_1.generateIntegrationsIndex)([
462
+ { name: 'team', serviceType: 'slack' },
463
+ { name: 'crm', serviceType: 'salesforce' },
464
+ ], { reexportAirtable: false })).toMatchInlineSnapshot(`
465
+ "// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.
466
+ // zitejs/integrations — an integration's credentials by its zite.config.json entry name.
467
+ //
468
+ // Usage in endpoints (src/api/*.ts) and automations (src/workflow.ts):
469
+ // import { integrations } from 'zitejs/integrations';
470
+ //
471
+ // const crm = await integrations.get('<entry name>');
472
+ // if (crm.status !== 'connected') { /* crm.connectUrl is where a person reconnects */ }
473
+ //
474
+ // Call get where the value is used, not once at module scope: a token refreshed
475
+ // mid-run is what the next call returns.
476
+
477
+ import { createIntegrationsClient } from 'zitejs/runtime';
478
+ import type { Connected, NeedsConnect } from 'zitejs/runtime';
479
+
480
+ export type { Connected, NeedsConnect };
481
+
482
+ export type IntegrationName = 'crm' | 'team';
483
+
484
+ export type IntegrationByName = {
485
+ 'crm': Connected<{ instanceUrl: string }> | NeedsConnect;
486
+ 'team': Connected | NeedsConnect;
487
+ };
488
+
489
+ export const integrations = createIntegrationsClient<IntegrationByName>();
490
+ "
491
+ `);
492
+ });
493
+ (0, vitest_1.it)('types get per name in app code', () => {
494
+ const generated = (0, lib_js_1.generateIntegrationsIndex)([
495
+ { name: 'crm', serviceType: 'salesforce' },
496
+ { name: 'warehouse', serviceType: 'clickhouse' },
497
+ ], { reexportAirtable: false });
498
+ (0, vitest_1.expect)(typeErrorsIn(generated, [
499
+ "import { integrations } from 'zitejs/integrations';",
500
+ 'export const run = async () => {',
501
+ " const crm = await integrations.get('crm');",
502
+ " if (crm.status === 'connected') return crm.instanceUrl + crm.accessToken;",
503
+ " const warehouse = await integrations.get('warehouse');",
504
+ " if (warehouse.status === 'connected') return warehouse.url + warehouse.username;",
505
+ ' return crm.connectUrl;',
506
+ '};',
507
+ ].join('\n'))).toEqual([]);
508
+ (0, vitest_1.expect)(typeErrorsIn(generated, "import { integrations } from 'zitejs/integrations';\nvoid integrations.get('nope');")).toHaveLength(1);
509
+ });
510
+ (0, vitest_1.it)('compiles with nothing visible, naming nothing', () => {
511
+ const generated = (0, lib_js_1.generateIntegrationsIndex)([], {
512
+ reexportAirtable: false,
513
+ });
514
+ (0, vitest_1.expect)(generated).toContain('export type IntegrationName = never;');
515
+ (0, vitest_1.expect)(typeErrorsIn(generated, "import { integrations, type IntegrationName } from 'zitejs/integrations';\nexport const f = (n: IntegrationName) => n;\nexport const g = integrations;")).toEqual([]);
516
+ });
517
+ vitest_1.it.each([
518
+ ['a double quote', 'crm"prod'],
519
+ ['a single quote', "crm'prod"],
520
+ ['a newline', 'crm\nprod'],
521
+ ['a trailing backslash', 'crm\\'],
522
+ ])('emits parseable TypeScript for a name with %s', (_what, name) => {
523
+ (0, vitest_1.expect)(syntaxErrorsIn((0, lib_js_1.generateIntegrationsIndex)([{ name, serviceType: 'slack' }], {
524
+ reexportAirtable: false,
525
+ }))).toEqual([]);
526
+ });
527
+ // One module for everything integration: the Airtable clients keep resolving.
528
+ (0, vitest_1.it)('re-exports the generated Airtable clients beside the integrations client', () => {
529
+ const generated = (0, lib_js_1.generateIntegrationsIndex)([{ name: 'team', serviceType: 'slack' }], { reexportAirtable: true });
530
+ (0, vitest_1.expect)(generated).toContain("export * from './airtable';");
531
+ (0, vitest_1.expect)(typeErrorsIn(generated, [
532
+ "import { Customers, integrations } from 'zitejs/integrations';",
533
+ 'export const run = async () => {',
534
+ ' await Customers.findMany();',
535
+ " return integrations.get('team');",
536
+ '};',
537
+ ].join('\n'), 'export const Customers = { findMany: async () => [] };')).toEqual([]);
538
+ });
539
+ });
@@ -67,7 +67,7 @@ export declare const signIn: {
67
67
  }, FetchOptions["throw"] extends true ? true : false>>;
68
68
  } & {
69
69
  social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
70
- provider: (string & {}) | "linear" | "huggingface" | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
70
+ provider: "salesforce" | "slack" | "linear" | "notion" | "linkedin" | "github" | (string & {}) | "huggingface" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "zoom" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
71
71
  callbackURL?: string | undefined;
72
72
  newUserCallbackURL?: string | undefined;
73
73
  errorCallbackURL?: string | undefined;
@@ -91,7 +91,7 @@ export declare const signIn: {
91
91
  loginHint?: string | undefined;
92
92
  additionalData?: Record<string, any> | undefined;
93
93
  }> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth/react").Prettify<{
94
- provider: (string & {}) | "linear" | "huggingface" | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
94
+ provider: "salesforce" | "slack" | "linear" | "notion" | "linkedin" | "github" | (string & {}) | "huggingface" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "zoom" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat";
95
95
  callbackURL?: string | undefined;
96
96
  newUserCallbackURL?: string | undefined;
97
97
  errorCallbackURL?: string | undefined;
@@ -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 endpoints from src/api/*.ts, resolves SDK imports via .zite/backend.ts
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
  *
@@ -22,4 +22,8 @@
22
22
  import * as esbuild from 'esbuild';
23
23
  export declare const UNSUPPORTED_IN_WORKERD: Set<string>;
24
24
  export declare const BASE_BUILD_OPTIONS: esbuild.BuildOptions;
25
+ export declare function createAliasPlugin(opts: {
26
+ baseDir?: string;
27
+ sdkPath?: string;
28
+ }): esbuild.Plugin;
25
29
  export declare function runBundle(): Promise<void>;