zitejs 0.9.128 → 0.9.130
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/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/integrations/client.d.ts +6 -3
- package/dist/cjs/integrations/client.js +4 -4
- package/dist/cjs/integrations/client.test-d.js +8 -9
- package/dist/cjs/integrations/index.d.ts +2 -2
- package/dist/cjs/integrations/rules.d.ts +8 -0
- package/dist/cjs/integrations/rules.js +16 -3
- package/dist/cjs/integrations/rules.test.js +14 -5
- package/dist/cjs/sync/lib.js +9 -4
- package/dist/cjs/sync/lib.test.js +33 -14
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/integrations/client.d.ts +6 -3
- package/dist/esm/integrations/client.js +4 -4
- package/dist/esm/integrations/client.test-d.js +8 -9
- package/dist/esm/integrations/index.d.ts +2 -2
- package/dist/esm/integrations/index.js +1 -1
- package/dist/esm/integrations/rules.d.ts +8 -0
- package/dist/esm/integrations/rules.js +15 -2
- package/dist/esm/integrations/rules.test.js +14 -5
- package/dist/esm/sync/lib.js +10 -5
- package/dist/esm/sync/lib.test.js +33 -14
- package/package.json +1 -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/cjs/index.d.ts
CHANGED
|
@@ -1,5 +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";
|
|
4
|
+
export { CREDENTIAL_FIELDS, NON_CREDENTIAL_SERVICE_TYPES, OPTIONAL_CREDENTIAL_FIELDS, gettableIntegrations, isCredentialServiceType, normalizeIntegrationServiceType, } from "./integrations/rules.js";
|
|
5
5
|
export type { ConfigIntegrations, CredentialServiceType, GettableIntegration, } from "./integrations/rules.js";
|
package/dist/cjs/index.js
CHANGED
|
@@ -14,13 +14,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.normalizeIntegrationServiceType = exports.isCredentialServiceType = exports.gettableIntegrations = exports.NON_CREDENTIAL_SERVICE_TYPES = exports.CREDENTIAL_FIELDS = exports.Zite = void 0;
|
|
17
|
+
exports.normalizeIntegrationServiceType = exports.isCredentialServiceType = exports.gettableIntegrations = exports.OPTIONAL_CREDENTIAL_FIELDS = exports.NON_CREDENTIAL_SERVICE_TYPES = exports.CREDENTIAL_FIELDS = exports.Zite = void 0;
|
|
18
18
|
var index_js_1 = require("./client/index.js");
|
|
19
19
|
Object.defineProperty(exports, "Zite", { enumerable: true, get: function () { return index_js_1.Zite; } });
|
|
20
20
|
__exportStar(require("./types/index.js"), exports);
|
|
21
21
|
var rules_js_1 = require("./integrations/rules.js");
|
|
22
22
|
Object.defineProperty(exports, "CREDENTIAL_FIELDS", { enumerable: true, get: function () { return rules_js_1.CREDENTIAL_FIELDS; } });
|
|
23
23
|
Object.defineProperty(exports, "NON_CREDENTIAL_SERVICE_TYPES", { enumerable: true, get: function () { return rules_js_1.NON_CREDENTIAL_SERVICE_TYPES; } });
|
|
24
|
+
Object.defineProperty(exports, "OPTIONAL_CREDENTIAL_FIELDS", { enumerable: true, get: function () { return rules_js_1.OPTIONAL_CREDENTIAL_FIELDS; } });
|
|
24
25
|
Object.defineProperty(exports, "gettableIntegrations", { enumerable: true, get: function () { return rules_js_1.gettableIntegrations; } });
|
|
25
26
|
Object.defineProperty(exports, "isCredentialServiceType", { enumerable: true, get: function () { return rules_js_1.isCredentialServiceType; } });
|
|
26
27
|
Object.defineProperty(exports, "normalizeIntegrationServiceType", { enumerable: true, get: function () { return rules_js_1.normalizeIntegrationServiceType; } });
|
|
@@ -3,12 +3,14 @@ export declare const INTEGRATIONS_CLASS_NAME = "Connections";
|
|
|
3
3
|
/**
|
|
4
4
|
* `accessToken` is the service's primary credential (for Twilio the account SID).
|
|
5
5
|
* Call `get` where the value is used: a token refreshed mid-run is what the next call returns.
|
|
6
|
+
* For a workspace connection that isn't connected, `get` throws a `ZiteError`
|
|
7
|
+
* whose `userFacingMessage` is safe to show visitors.
|
|
6
8
|
*/
|
|
7
9
|
export type Connected<Extra = {}> = {
|
|
8
10
|
status: "connected";
|
|
9
11
|
accessToken: string;
|
|
10
12
|
} & Extra;
|
|
11
|
-
/**
|
|
13
|
+
/** A per-user entry the signed-in user hasn't connected, or whose token expired: send them to `connectUrl`. */
|
|
12
14
|
export type NeedsConnect = {
|
|
13
15
|
status: "missing" | "expired";
|
|
14
16
|
connectUrl: string;
|
|
@@ -19,7 +21,8 @@ export interface IntegrationsClient<ByName extends Record<string, unknown>> {
|
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* `ByName` maps each entry name to its answer, e.g.
|
|
22
|
-
* `{ crm: Connected<{ instanceUrl: string }
|
|
23
|
-
* writes it per
|
|
24
|
+
* `{ crm: Connected<{ instanceUrl: string }>; inbox: Connected | NeedsConnect }`
|
|
25
|
+
* (only per-user entries can need connecting); `zitejs generate` writes it per
|
|
26
|
+
* app into `.zite/integrations/index.ts`.
|
|
24
27
|
*/
|
|
25
28
|
export declare function createIntegrationsClient<ByName extends Record<string, unknown>>(): IntegrationsClient<ByName>;
|
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.INTEGRATIONS_CLASS_NAME = exports.INTEGRATIONS_SDK_INTEGRATION_ID = void 0;
|
|
4
4
|
exports.createIntegrationsClient = createIntegrationsClient;
|
|
5
5
|
const sdkCall_js_1 = require("../internal/sdkCall.js");
|
|
6
|
-
// The
|
|
7
|
-
// wire protocol would break every deployed bundle for no user-visible gain.
|
|
6
|
+
// The platform id the worker answers `get` under, as `__pdf__` is for PDFs.
|
|
8
7
|
exports.INTEGRATIONS_SDK_INTEGRATION_ID = "__connections__";
|
|
9
8
|
exports.INTEGRATIONS_CLASS_NAME = "Connections";
|
|
10
9
|
/**
|
|
11
10
|
* `ByName` maps each entry name to its answer, e.g.
|
|
12
|
-
* `{ crm: Connected<{ instanceUrl: string }
|
|
13
|
-
* writes it per
|
|
11
|
+
* `{ crm: Connected<{ instanceUrl: string }>; inbox: Connected | NeedsConnect }`
|
|
12
|
+
* (only per-user entries can need connecting); `zitejs generate` writes it per
|
|
13
|
+
* app into `.zite/integrations/index.ts`.
|
|
14
14
|
*/
|
|
15
15
|
function createIntegrationsClient() {
|
|
16
16
|
return {
|
|
@@ -8,6 +8,7 @@ const index_js_2 = require("../index.js");
|
|
|
8
8
|
const client = (0, client_js_1.createIntegrationsClient)();
|
|
9
9
|
(0, vitest_1.it)("types each name's answer", () => {
|
|
10
10
|
(0, vitest_1.expectTypeOf)(client.get("crm")).resolves.toEqualTypeOf();
|
|
11
|
+
(0, vitest_1.expectTypeOf)(client.get("inbox")).resolves.toEqualTypeOf();
|
|
11
12
|
});
|
|
12
13
|
(0, vitest_1.it)("rejects a name the app cannot see", () => {
|
|
13
14
|
// @ts-expect-error not a visible entry
|
|
@@ -18,23 +19,21 @@ const index_js_2 = require("../index.js");
|
|
|
18
19
|
const none = (0, client_js_1.createIntegrationsClient)();
|
|
19
20
|
(0, vitest_1.expectTypeOf)().toEqualTypeOf();
|
|
20
21
|
});
|
|
21
|
-
(0, vitest_1.it)("narrows to the connected fields on status", async () => {
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
(0, vitest_1.expectTypeOf)(
|
|
22
|
+
(0, vitest_1.it)("narrows a per-user entry to the connected fields on status", async () => {
|
|
23
|
+
const inbox = await client.get("inbox");
|
|
24
|
+
if (inbox.status === "connected") {
|
|
25
|
+
(0, vitest_1.expectTypeOf)(inbox.accessToken).toEqualTypeOf();
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
|
-
(0, vitest_1.expectTypeOf)(
|
|
28
|
+
(0, vitest_1.expectTypeOf)(inbox.connectUrl).toEqualTypeOf();
|
|
28
29
|
}
|
|
29
30
|
});
|
|
30
31
|
});
|
|
31
32
|
(0, vitest_1.describe)("the untyped zitejs/integrations client", () => {
|
|
32
33
|
(0, vitest_1.it)("takes any name; only accessToken is certain", async () => {
|
|
33
34
|
const entry = await index_js_1.integrations.get("anything");
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
(0, vitest_1.expectTypeOf)(entry.instanceUrl).toEqualTypeOf();
|
|
37
|
-
}
|
|
35
|
+
(0, vitest_1.expectTypeOf)(entry.accessToken).toEqualTypeOf();
|
|
36
|
+
(0, vitest_1.expectTypeOf)(entry.instanceUrl).toEqualTypeOf();
|
|
38
37
|
});
|
|
39
38
|
});
|
|
40
39
|
(0, vitest_1.describe)("CREDENTIAL_FIELDS", () => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type Connected
|
|
1
|
+
import { type Connected } from "./client.js";
|
|
2
2
|
export type { Connected, NeedsConnect } from "./client.js";
|
|
3
|
-
export declare const integrations: import("./client.js").IntegrationsClient<Record<string,
|
|
3
|
+
export declare const integrations: import("./client.js").IntegrationsClient<Record<string, Connected<Partial<Record<string, string>>>>>;
|
|
@@ -45,6 +45,11 @@ declare const FIELDS_BY_TYPE: {
|
|
|
45
45
|
export type CredentialServiceType = keyof typeof FIELDS_BY_TYPE;
|
|
46
46
|
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
47
47
|
export declare const CREDENTIAL_FIELDS: Readonly<Record<CredentialServiceType, readonly string[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* Extras the platform omits when the account doesn't have them: a Jira site
|
|
50
|
+
* connected before its URL was stored, a Trello key the deployment never set.
|
|
51
|
+
*/
|
|
52
|
+
export declare const OPTIONAL_CREDENTIAL_FIELDS: Readonly<Partial<Record<CredentialServiceType, readonly string[]>>>;
|
|
48
53
|
/**
|
|
49
54
|
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
50
55
|
* the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
|
|
@@ -56,9 +61,12 @@ export declare const isCredentialServiceType: (type: string) => type is Credenti
|
|
|
56
61
|
export type GettableIntegration = {
|
|
57
62
|
name: string;
|
|
58
63
|
serviceType: CredentialServiceType;
|
|
64
|
+
/** Each signed-in user connects their own account, so `get` can answer that they haven't. */
|
|
65
|
+
perUser: boolean;
|
|
59
66
|
};
|
|
60
67
|
export type ConfigIntegrations = Readonly<Record<string, {
|
|
61
68
|
type?: unknown;
|
|
69
|
+
connectionMode?: unknown;
|
|
62
70
|
} | undefined>>;
|
|
63
71
|
/**
|
|
64
72
|
* The entries a source dir can name, by name: its own, then the workspace's under
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Which `zite.config.json` entries `integrations.get` can name, and the fields
|
|
3
3
|
// each answers with. No imports, so the platform applies these same rules.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.gettableIntegrations = exports.isCredentialServiceType = exports.normalizeIntegrationServiceType = exports.NON_CREDENTIAL_SERVICE_TYPES = exports.CREDENTIAL_FIELDS = void 0;
|
|
5
|
+
exports.gettableIntegrations = exports.isCredentialServiceType = exports.normalizeIntegrationServiceType = exports.NON_CREDENTIAL_SERVICE_TYPES = exports.OPTIONAL_CREDENTIAL_FIELDS = exports.CREDENTIAL_FIELDS = void 0;
|
|
6
6
|
const extras = (...labels) => [
|
|
7
7
|
"accessToken",
|
|
8
8
|
...[...labels].sort(),
|
|
@@ -52,6 +52,14 @@ const FIELDS_BY_TYPE = {
|
|
|
52
52
|
};
|
|
53
53
|
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
54
54
|
exports.CREDENTIAL_FIELDS = FIELDS_BY_TYPE;
|
|
55
|
+
/**
|
|
56
|
+
* Extras the platform omits when the account doesn't have them: a Jira site
|
|
57
|
+
* connected before its URL was stored, a Trello key the deployment never set.
|
|
58
|
+
*/
|
|
59
|
+
exports.OPTIONAL_CREDENTIAL_FIELDS = {
|
|
60
|
+
jira: ["siteUrl"],
|
|
61
|
+
trello: ["clientApiKey"],
|
|
62
|
+
};
|
|
55
63
|
/**
|
|
56
64
|
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
57
65
|
* the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
|
|
@@ -97,8 +105,13 @@ const gettableIntegrations = (rootIntegrations, appIntegrations) => {
|
|
|
97
105
|
if (typeof entry?.type !== "string")
|
|
98
106
|
continue;
|
|
99
107
|
const serviceType = (0, exports.normalizeIntegrationServiceType)(entry.type);
|
|
100
|
-
if ((0, exports.isCredentialServiceType)(serviceType))
|
|
101
|
-
visible.push({
|
|
108
|
+
if ((0, exports.isCredentialServiceType)(serviceType)) {
|
|
109
|
+
visible.push({
|
|
110
|
+
name,
|
|
111
|
+
serviceType,
|
|
112
|
+
perUser: entry.connectionMode === "app-user",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
102
115
|
}
|
|
103
116
|
return visible.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
104
117
|
};
|
|
@@ -47,9 +47,9 @@ const index_js_1 = require("../index.js");
|
|
|
47
47
|
(0, vitest_1.describe)("gettableIntegrations", () => {
|
|
48
48
|
(0, vitest_1.it)("lists the app's entries, then the workspace's under untaken keys, by name", () => {
|
|
49
49
|
(0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ crm: { type: "salesforce" }, team: { type: "slack" } }, { billing: { type: "stripe" }, team: { type: "microsoftTeams" } })).toEqual([
|
|
50
|
-
{ name: "billing", serviceType: "stripe" },
|
|
51
|
-
{ name: "crm", serviceType: "salesforce" },
|
|
52
|
-
{ name: "team", serviceType: "microsoftTeams" },
|
|
50
|
+
{ name: "billing", serviceType: "stripe", perUser: false },
|
|
51
|
+
{ name: "crm", serviceType: "salesforce", perUser: false },
|
|
52
|
+
{ name: "team", serviceType: "microsoftTeams", perUser: false },
|
|
53
53
|
]);
|
|
54
54
|
});
|
|
55
55
|
(0, vitest_1.it)("lets an app entry of a generated-client type shadow a workspace credential entry", () => {
|
|
@@ -70,7 +70,7 @@ const index_js_1 = require("../index.js");
|
|
|
70
70
|
});
|
|
71
71
|
(0, vitest_1.it)("normalizes legacy type spellings", () => {
|
|
72
72
|
(0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ cal: { type: "google-calendar" } })).toEqual([
|
|
73
|
-
{ name: "cal", serviceType: "googleCalendar" },
|
|
73
|
+
{ name: "cal", serviceType: "googleCalendar", perUser: false },
|
|
74
74
|
]);
|
|
75
75
|
});
|
|
76
76
|
(0, vitest_1.it)("drops a type it does not know, as the runtime does", () => {
|
|
@@ -78,7 +78,16 @@ const index_js_1 = require("../index.js");
|
|
|
78
78
|
});
|
|
79
79
|
(0, vitest_1.it)("shadows by own keys only", () => {
|
|
80
80
|
(0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({ constructor: { type: "slack" } }, {})).toEqual([
|
|
81
|
-
{ name: "constructor", serviceType: "slack" },
|
|
81
|
+
{ name: "constructor", serviceType: "slack", perUser: false },
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
(0, vitest_1.it)("marks an entry each signed-in user connects for themselves", () => {
|
|
85
|
+
(0, vitest_1.expect)((0, index_js_1.gettableIntegrations)({
|
|
86
|
+
inbox: { type: "gmail", connectionMode: "app-user" },
|
|
87
|
+
support: { type: "gmail" },
|
|
88
|
+
})).toEqual([
|
|
89
|
+
{ name: "inbox", serviceType: "gmail", perUser: true },
|
|
90
|
+
{ name: "support", serviceType: "gmail", perUser: false },
|
|
82
91
|
]);
|
|
83
92
|
});
|
|
84
93
|
(0, vitest_1.it)("works with no configs", () => {
|
package/dist/cjs/sync/lib.js
CHANGED
|
@@ -1406,9 +1406,12 @@ function generateEmailSdk(integrationId) {
|
|
|
1406
1406
|
}
|
|
1407
1407
|
const connectedTypeFor = (serviceType) => {
|
|
1408
1408
|
const extraLabels = rules_js_1.CREDENTIAL_FIELDS[serviceType].slice(1);
|
|
1409
|
+
const optional = rules_js_1.OPTIONAL_CREDENTIAL_FIELDS[serviceType] ?? [];
|
|
1409
1410
|
return extraLabels.length === 0
|
|
1410
1411
|
? "Connected"
|
|
1411
|
-
: `Connected<{ ${extraLabels
|
|
1412
|
+
: `Connected<{ ${extraLabels
|
|
1413
|
+
.map((label) => `${label}${optional.includes(label) ? "?" : ""}: string`)
|
|
1414
|
+
.join("; ")} }>`;
|
|
1412
1415
|
};
|
|
1413
1416
|
/**
|
|
1414
1417
|
* `.zite/integrations/index.ts`: `zitejs/integrations` for one source dir. The
|
|
@@ -1424,7 +1427,7 @@ function generateIntegrationsIndex(entries, opts) {
|
|
|
1424
1427
|
? ["export type IntegrationByName = {};"]
|
|
1425
1428
|
: [
|
|
1426
1429
|
"export type IntegrationByName = {",
|
|
1427
|
-
...sorted.map(({ name, serviceType }) => ` ${tsSingleQuoted(name)}: ${connectedTypeFor(serviceType)} | NeedsConnect;`),
|
|
1430
|
+
...sorted.map(({ name, serviceType, perUser }) => ` ${tsSingleQuoted(name)}: ${connectedTypeFor(serviceType)}${perUser ? " | NeedsConnect" : ""};`),
|
|
1428
1431
|
"};",
|
|
1429
1432
|
];
|
|
1430
1433
|
return [
|
|
@@ -1434,8 +1437,10 @@ function generateIntegrationsIndex(entries, opts) {
|
|
|
1434
1437
|
"// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):",
|
|
1435
1438
|
"// import { integrations } from 'zitejs/integrations';",
|
|
1436
1439
|
"//",
|
|
1437
|
-
"// const
|
|
1438
|
-
"//
|
|
1440
|
+
"// const { accessToken } = await integrations.get('<entry name>');",
|
|
1441
|
+
"//",
|
|
1442
|
+
"// A workspace connection that isn't connected throws a ZiteError. A per-user",
|
|
1443
|
+
"// entry answers `missing`/`expired` with a connectUrl for the signed-in user.",
|
|
1439
1444
|
"//",
|
|
1440
1445
|
"// Call get where the value is used, not once at module scope: a token refreshed",
|
|
1441
1446
|
"// mid-run is what the next call returns.",
|
|
@@ -467,8 +467,9 @@ const duplicateIdentifierErrorsIn = (source) => {
|
|
|
467
467
|
};
|
|
468
468
|
(0, vitest_1.it)('emits the client typed by name', () => {
|
|
469
469
|
(0, vitest_1.expect)((0, lib_js_1.generateIntegrationsIndex)([
|
|
470
|
-
{ name: 'team', serviceType: 'slack' },
|
|
471
|
-
{ name: 'crm', serviceType: 'salesforce' },
|
|
470
|
+
{ name: 'team', serviceType: 'slack', perUser: false },
|
|
471
|
+
{ name: 'crm', serviceType: 'salesforce', perUser: false },
|
|
472
|
+
{ name: 'inbox', serviceType: 'gmail', perUser: true },
|
|
472
473
|
], { reexportAirtable: false })).toMatchInlineSnapshot(`
|
|
473
474
|
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.
|
|
474
475
|
// zitejs/integrations — an integration's credentials by its zite.config.json entry name.
|
|
@@ -476,8 +477,10 @@ const duplicateIdentifierErrorsIn = (source) => {
|
|
|
476
477
|
// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):
|
|
477
478
|
// import { integrations } from 'zitejs/integrations';
|
|
478
479
|
//
|
|
479
|
-
// const
|
|
480
|
-
//
|
|
480
|
+
// const { accessToken } = await integrations.get('<entry name>');
|
|
481
|
+
//
|
|
482
|
+
// A workspace connection that isn't connected throws a ZiteError. A per-user
|
|
483
|
+
// entry answers \`missing\`/\`expired\` with a connectUrl for the signed-in user.
|
|
481
484
|
//
|
|
482
485
|
// Call get where the value is used, not once at module scope: a token refreshed
|
|
483
486
|
// mid-run is what the next call returns.
|
|
@@ -487,32 +490,48 @@ const duplicateIdentifierErrorsIn = (source) => {
|
|
|
487
490
|
|
|
488
491
|
export type { Connected, NeedsConnect };
|
|
489
492
|
|
|
490
|
-
export type IntegrationName = 'crm' | 'team';
|
|
493
|
+
export type IntegrationName = 'crm' | 'inbox' | 'team';
|
|
491
494
|
|
|
492
495
|
export type IntegrationByName = {
|
|
493
|
-
'crm': Connected<{ instanceUrl: string }
|
|
494
|
-
'
|
|
496
|
+
'crm': Connected<{ instanceUrl: string }>;
|
|
497
|
+
'inbox': Connected | NeedsConnect;
|
|
498
|
+
'team': Connected;
|
|
495
499
|
};
|
|
496
500
|
|
|
497
501
|
export const integrations = createIntegrationsClient<IntegrationByName>();
|
|
498
502
|
"
|
|
499
503
|
`);
|
|
500
504
|
});
|
|
505
|
+
// The platform leaves these out for some accounts, so the type can't promise them.
|
|
506
|
+
(0, vitest_1.it)('marks an extra the platform may omit as optional', () => {
|
|
507
|
+
const generated = (0, lib_js_1.generateIntegrationsIndex)([{ name: 'tickets', serviceType: 'jira', perUser: false }], { reexportAirtable: false });
|
|
508
|
+
(0, vitest_1.expect)(generated).toContain("'tickets': Connected<{ cloudId: string; siteUrl?: string }>;");
|
|
509
|
+
(0, vitest_1.expect)(typeErrorsIn(generated, `import { integrations } from 'zitejs/integrations';
|
|
510
|
+
const jira = await integrations.get('tickets');
|
|
511
|
+
const cloudId: string = jira.cloudId;
|
|
512
|
+
const siteUrl: string = jira.siteUrl;
|
|
513
|
+
`)).toEqual([
|
|
514
|
+
vitest_1.expect.stringContaining("Type 'string | undefined' is not assignable"),
|
|
515
|
+
]);
|
|
516
|
+
});
|
|
517
|
+
// A workspace entry is used as is; only a per-user one makes code check first.
|
|
501
518
|
(0, vitest_1.it)('types get per name in app code', () => {
|
|
502
519
|
const generated = (0, lib_js_1.generateIntegrationsIndex)([
|
|
503
|
-
{ name: 'crm', serviceType: 'salesforce' },
|
|
504
|
-
{ name: 'warehouse', serviceType: 'clickhouse' },
|
|
520
|
+
{ name: 'crm', serviceType: 'salesforce', perUser: false },
|
|
521
|
+
{ name: 'warehouse', serviceType: 'clickhouse', perUser: false },
|
|
522
|
+
{ name: 'inbox', serviceType: 'gmail', perUser: true },
|
|
505
523
|
], { reexportAirtable: false });
|
|
506
524
|
(0, vitest_1.expect)(typeErrorsIn(generated, [
|
|
507
525
|
"import { integrations } from 'zitejs/integrations';",
|
|
508
526
|
'export const run = async () => {',
|
|
509
527
|
" const crm = await integrations.get('crm');",
|
|
510
|
-
" if (crm.status === 'connected') return crm.instanceUrl + crm.accessToken;",
|
|
511
528
|
" const warehouse = await integrations.get('warehouse');",
|
|
512
|
-
"
|
|
513
|
-
'
|
|
529
|
+
" const inbox = await integrations.get('inbox');",
|
|
530
|
+
" if (inbox.status !== 'connected') return inbox.connectUrl;",
|
|
531
|
+
' return crm.instanceUrl + warehouse.url + inbox.accessToken;',
|
|
514
532
|
'};',
|
|
515
533
|
].join('\n'))).toEqual([]);
|
|
534
|
+
(0, vitest_1.expect)(typeErrorsIn(generated, "import { integrations } from 'zitejs/integrations';\nexport const f = async () => (await integrations.get('inbox')).accessToken;")).toHaveLength(1);
|
|
516
535
|
(0, vitest_1.expect)(typeErrorsIn(generated, "import { integrations } from 'zitejs/integrations';\nvoid integrations.get('nope');")).toHaveLength(1);
|
|
517
536
|
});
|
|
518
537
|
(0, vitest_1.it)('compiles with nothing visible, naming nothing', () => {
|
|
@@ -528,13 +547,13 @@ const duplicateIdentifierErrorsIn = (source) => {
|
|
|
528
547
|
['a newline', 'crm\nprod'],
|
|
529
548
|
['a trailing backslash', 'crm\\'],
|
|
530
549
|
])('emits parseable TypeScript for a name with %s', (_what, name) => {
|
|
531
|
-
(0, vitest_1.expect)(syntaxErrorsIn((0, lib_js_1.generateIntegrationsIndex)([{ name, serviceType: 'slack' }], {
|
|
550
|
+
(0, vitest_1.expect)(syntaxErrorsIn((0, lib_js_1.generateIntegrationsIndex)([{ name, serviceType: 'slack', perUser: false }], {
|
|
532
551
|
reexportAirtable: false,
|
|
533
552
|
}))).toEqual([]);
|
|
534
553
|
});
|
|
535
554
|
// One module for everything integration: the Airtable clients keep resolving.
|
|
536
555
|
(0, vitest_1.it)('re-exports the generated Airtable clients beside the integrations client', () => {
|
|
537
|
-
const generated = (0, lib_js_1.generateIntegrationsIndex)([{ name: 'team', serviceType: 'slack' }], { reexportAirtable: true });
|
|
556
|
+
const generated = (0, lib_js_1.generateIntegrationsIndex)([{ name: 'team', serviceType: 'slack', perUser: false }], { reexportAirtable: true });
|
|
538
557
|
(0, vitest_1.expect)(generated).toContain("export * from './airtable';");
|
|
539
558
|
(0, vitest_1.expect)(typeErrorsIn(generated, [
|
|
540
559
|
"import { Customers, integrations } from 'zitejs/integrations';",
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,5 +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";
|
|
4
|
+
export { CREDENTIAL_FIELDS, NON_CREDENTIAL_SERVICE_TYPES, OPTIONAL_CREDENTIAL_FIELDS, gettableIntegrations, isCredentialServiceType, normalizeIntegrationServiceType, } from "./integrations/rules.js";
|
|
5
5
|
export type { ConfigIntegrations, CredentialServiceType, GettableIntegration, } from "./integrations/rules.js";
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { Zite } from "./client/index.js";
|
|
2
2
|
export * from "./types/index.js";
|
|
3
|
-
export { CREDENTIAL_FIELDS, NON_CREDENTIAL_SERVICE_TYPES, gettableIntegrations, isCredentialServiceType, normalizeIntegrationServiceType, } from "./integrations/rules.js";
|
|
3
|
+
export { CREDENTIAL_FIELDS, NON_CREDENTIAL_SERVICE_TYPES, OPTIONAL_CREDENTIAL_FIELDS, gettableIntegrations, isCredentialServiceType, normalizeIntegrationServiceType, } from "./integrations/rules.js";
|
|
@@ -3,12 +3,14 @@ export declare const INTEGRATIONS_CLASS_NAME = "Connections";
|
|
|
3
3
|
/**
|
|
4
4
|
* `accessToken` is the service's primary credential (for Twilio the account SID).
|
|
5
5
|
* Call `get` where the value is used: a token refreshed mid-run is what the next call returns.
|
|
6
|
+
* For a workspace connection that isn't connected, `get` throws a `ZiteError`
|
|
7
|
+
* whose `userFacingMessage` is safe to show visitors.
|
|
6
8
|
*/
|
|
7
9
|
export type Connected<Extra = {}> = {
|
|
8
10
|
status: "connected";
|
|
9
11
|
accessToken: string;
|
|
10
12
|
} & Extra;
|
|
11
|
-
/**
|
|
13
|
+
/** A per-user entry the signed-in user hasn't connected, or whose token expired: send them to `connectUrl`. */
|
|
12
14
|
export type NeedsConnect = {
|
|
13
15
|
status: "missing" | "expired";
|
|
14
16
|
connectUrl: string;
|
|
@@ -19,7 +21,8 @@ export interface IntegrationsClient<ByName extends Record<string, unknown>> {
|
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* `ByName` maps each entry name to its answer, e.g.
|
|
22
|
-
* `{ crm: Connected<{ instanceUrl: string }
|
|
23
|
-
* writes it per
|
|
24
|
+
* `{ crm: Connected<{ instanceUrl: string }>; inbox: Connected | NeedsConnect }`
|
|
25
|
+
* (only per-user entries can need connecting); `zitejs generate` writes it per
|
|
26
|
+
* app into `.zite/integrations/index.ts`.
|
|
24
27
|
*/
|
|
25
28
|
export declare function createIntegrationsClient<ByName extends Record<string, unknown>>(): IntegrationsClient<ByName>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { getSdkCall } from "../internal/sdkCall.js";
|
|
2
|
-
// The
|
|
3
|
-
// wire protocol would break every deployed bundle for no user-visible gain.
|
|
2
|
+
// The platform id the worker answers `get` under, as `__pdf__` is for PDFs.
|
|
4
3
|
export const INTEGRATIONS_SDK_INTEGRATION_ID = "__connections__";
|
|
5
4
|
export const INTEGRATIONS_CLASS_NAME = "Connections";
|
|
6
5
|
/**
|
|
7
6
|
* `ByName` maps each entry name to its answer, e.g.
|
|
8
|
-
* `{ crm: Connected<{ instanceUrl: string }
|
|
9
|
-
* writes it per
|
|
7
|
+
* `{ crm: Connected<{ instanceUrl: string }>; inbox: Connected | NeedsConnect }`
|
|
8
|
+
* (only per-user entries can need connecting); `zitejs generate` writes it per
|
|
9
|
+
* app into `.zite/integrations/index.ts`.
|
|
10
10
|
*/
|
|
11
11
|
export function createIntegrationsClient() {
|
|
12
12
|
return {
|
|
@@ -6,6 +6,7 @@ describe("createIntegrationsClient", () => {
|
|
|
6
6
|
const client = createIntegrationsClient();
|
|
7
7
|
it("types each name's answer", () => {
|
|
8
8
|
expectTypeOf(client.get("crm")).resolves.toEqualTypeOf();
|
|
9
|
+
expectTypeOf(client.get("inbox")).resolves.toEqualTypeOf();
|
|
9
10
|
});
|
|
10
11
|
it("rejects a name the app cannot see", () => {
|
|
11
12
|
// @ts-expect-error not a visible entry
|
|
@@ -16,23 +17,21 @@ describe("createIntegrationsClient", () => {
|
|
|
16
17
|
const none = createIntegrationsClient();
|
|
17
18
|
expectTypeOf().toEqualTypeOf();
|
|
18
19
|
});
|
|
19
|
-
it("narrows to the connected fields on status", async () => {
|
|
20
|
-
const
|
|
21
|
-
if (
|
|
22
|
-
expectTypeOf(
|
|
20
|
+
it("narrows a per-user entry to the connected fields on status", async () => {
|
|
21
|
+
const inbox = await client.get("inbox");
|
|
22
|
+
if (inbox.status === "connected") {
|
|
23
|
+
expectTypeOf(inbox.accessToken).toEqualTypeOf();
|
|
23
24
|
}
|
|
24
25
|
else {
|
|
25
|
-
expectTypeOf(
|
|
26
|
+
expectTypeOf(inbox.connectUrl).toEqualTypeOf();
|
|
26
27
|
}
|
|
27
28
|
});
|
|
28
29
|
});
|
|
29
30
|
describe("the untyped zitejs/integrations client", () => {
|
|
30
31
|
it("takes any name; only accessToken is certain", async () => {
|
|
31
32
|
const entry = await untyped.get("anything");
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
expectTypeOf(entry.instanceUrl).toEqualTypeOf();
|
|
35
|
-
}
|
|
33
|
+
expectTypeOf(entry.accessToken).toEqualTypeOf();
|
|
34
|
+
expectTypeOf(entry.instanceUrl).toEqualTypeOf();
|
|
36
35
|
});
|
|
37
36
|
});
|
|
38
37
|
describe("CREDENTIAL_FIELDS", () => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type Connected
|
|
1
|
+
import { type Connected } from "./client.js";
|
|
2
2
|
export type { Connected, NeedsConnect } from "./client.js";
|
|
3
|
-
export declare const integrations: import("./client.js").IntegrationsClient<Record<string,
|
|
3
|
+
export declare const integrations: import("./client.js").IntegrationsClient<Record<string, Connected<Partial<Record<string, string>>>>>;
|
|
@@ -45,6 +45,11 @@ declare const FIELDS_BY_TYPE: {
|
|
|
45
45
|
export type CredentialServiceType = keyof typeof FIELDS_BY_TYPE;
|
|
46
46
|
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
47
47
|
export declare const CREDENTIAL_FIELDS: Readonly<Record<CredentialServiceType, readonly string[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* Extras the platform omits when the account doesn't have them: a Jira site
|
|
50
|
+
* connected before its URL was stored, a Trello key the deployment never set.
|
|
51
|
+
*/
|
|
52
|
+
export declare const OPTIONAL_CREDENTIAL_FIELDS: Readonly<Partial<Record<CredentialServiceType, readonly string[]>>>;
|
|
48
53
|
/**
|
|
49
54
|
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
50
55
|
* the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
|
|
@@ -56,9 +61,12 @@ export declare const isCredentialServiceType: (type: string) => type is Credenti
|
|
|
56
61
|
export type GettableIntegration = {
|
|
57
62
|
name: string;
|
|
58
63
|
serviceType: CredentialServiceType;
|
|
64
|
+
/** Each signed-in user connects their own account, so `get` can answer that they haven't. */
|
|
65
|
+
perUser: boolean;
|
|
59
66
|
};
|
|
60
67
|
export type ConfigIntegrations = Readonly<Record<string, {
|
|
61
68
|
type?: unknown;
|
|
69
|
+
connectionMode?: unknown;
|
|
62
70
|
} | undefined>>;
|
|
63
71
|
/**
|
|
64
72
|
* The entries a source dir can name, by name: its own, then the workspace's under
|
|
@@ -49,6 +49,14 @@ const FIELDS_BY_TYPE = {
|
|
|
49
49
|
};
|
|
50
50
|
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
51
51
|
export const CREDENTIAL_FIELDS = FIELDS_BY_TYPE;
|
|
52
|
+
/**
|
|
53
|
+
* Extras the platform omits when the account doesn't have them: a Jira site
|
|
54
|
+
* connected before its URL was stored, a Trello key the deployment never set.
|
|
55
|
+
*/
|
|
56
|
+
export const OPTIONAL_CREDENTIAL_FIELDS = {
|
|
57
|
+
jira: ["siteUrl"],
|
|
58
|
+
trello: ["clientApiKey"],
|
|
59
|
+
};
|
|
52
60
|
/**
|
|
53
61
|
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
54
62
|
* the project database, Fillout) and those whose key is a frontend value (Maps, Analytics).
|
|
@@ -92,8 +100,13 @@ export const gettableIntegrations = (rootIntegrations, appIntegrations) => {
|
|
|
92
100
|
if (typeof entry?.type !== "string")
|
|
93
101
|
continue;
|
|
94
102
|
const serviceType = normalizeIntegrationServiceType(entry.type);
|
|
95
|
-
if (isCredentialServiceType(serviceType))
|
|
96
|
-
visible.push({
|
|
103
|
+
if (isCredentialServiceType(serviceType)) {
|
|
104
|
+
visible.push({
|
|
105
|
+
name,
|
|
106
|
+
serviceType,
|
|
107
|
+
perUser: entry.connectionMode === "app-user",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
97
110
|
}
|
|
98
111
|
return visible.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
99
112
|
};
|
|
@@ -45,9 +45,9 @@ describe("normalizeIntegrationServiceType", () => {
|
|
|
45
45
|
describe("gettableIntegrations", () => {
|
|
46
46
|
it("lists the app's entries, then the workspace's under untaken keys, by name", () => {
|
|
47
47
|
expect(gettableIntegrations({ crm: { type: "salesforce" }, team: { type: "slack" } }, { billing: { type: "stripe" }, team: { type: "microsoftTeams" } })).toEqual([
|
|
48
|
-
{ name: "billing", serviceType: "stripe" },
|
|
49
|
-
{ name: "crm", serviceType: "salesforce" },
|
|
50
|
-
{ name: "team", serviceType: "microsoftTeams" },
|
|
48
|
+
{ name: "billing", serviceType: "stripe", perUser: false },
|
|
49
|
+
{ name: "crm", serviceType: "salesforce", perUser: false },
|
|
50
|
+
{ name: "team", serviceType: "microsoftTeams", perUser: false },
|
|
51
51
|
]);
|
|
52
52
|
});
|
|
53
53
|
it("lets an app entry of a generated-client type shadow a workspace credential entry", () => {
|
|
@@ -68,7 +68,7 @@ describe("gettableIntegrations", () => {
|
|
|
68
68
|
});
|
|
69
69
|
it("normalizes legacy type spellings", () => {
|
|
70
70
|
expect(gettableIntegrations({ cal: { type: "google-calendar" } })).toEqual([
|
|
71
|
-
{ name: "cal", serviceType: "googleCalendar" },
|
|
71
|
+
{ name: "cal", serviceType: "googleCalendar", perUser: false },
|
|
72
72
|
]);
|
|
73
73
|
});
|
|
74
74
|
it("drops a type it does not know, as the runtime does", () => {
|
|
@@ -76,7 +76,16 @@ describe("gettableIntegrations", () => {
|
|
|
76
76
|
});
|
|
77
77
|
it("shadows by own keys only", () => {
|
|
78
78
|
expect(gettableIntegrations({ constructor: { type: "slack" } }, {})).toEqual([
|
|
79
|
-
{ name: "constructor", serviceType: "slack" },
|
|
79
|
+
{ name: "constructor", serviceType: "slack", perUser: false },
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
it("marks an entry each signed-in user connects for themselves", () => {
|
|
83
|
+
expect(gettableIntegrations({
|
|
84
|
+
inbox: { type: "gmail", connectionMode: "app-user" },
|
|
85
|
+
support: { type: "gmail" },
|
|
86
|
+
})).toEqual([
|
|
87
|
+
{ name: "inbox", serviceType: "gmail", perUser: true },
|
|
88
|
+
{ name: "support", serviceType: "gmail", perUser: false },
|
|
80
89
|
]);
|
|
81
90
|
});
|
|
82
91
|
it("works with no configs", () => {
|
package/dist/esm/sync/lib.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parse } from "@babel/parser";
|
|
2
2
|
import { allocateSchemaNames, describeRenames, keepValidSdkName, normalizeSchemaNames, SdkNameAllocator, toCamelCase, toPascalCase, toSdkName, } from "./sdkNames.js";
|
|
3
|
-
import { CREDENTIAL_FIELDS, } from "../integrations/rules.js";
|
|
3
|
+
import { CREDENTIAL_FIELDS, OPTIONAL_CREDENTIAL_FIELDS, } from "../integrations/rules.js";
|
|
4
4
|
const AUTH_USERS_TABLE_ID = "zite_user";
|
|
5
5
|
/**
|
|
6
6
|
* What a field's value looks like when a record is READ back.
|
|
@@ -1391,9 +1391,12 @@ export function generateEmailSdk(integrationId) {
|
|
|
1391
1391
|
}
|
|
1392
1392
|
const connectedTypeFor = (serviceType) => {
|
|
1393
1393
|
const extraLabels = CREDENTIAL_FIELDS[serviceType].slice(1);
|
|
1394
|
+
const optional = OPTIONAL_CREDENTIAL_FIELDS[serviceType] ?? [];
|
|
1394
1395
|
return extraLabels.length === 0
|
|
1395
1396
|
? "Connected"
|
|
1396
|
-
: `Connected<{ ${extraLabels
|
|
1397
|
+
: `Connected<{ ${extraLabels
|
|
1398
|
+
.map((label) => `${label}${optional.includes(label) ? "?" : ""}: string`)
|
|
1399
|
+
.join("; ")} }>`;
|
|
1397
1400
|
};
|
|
1398
1401
|
/**
|
|
1399
1402
|
* `.zite/integrations/index.ts`: `zitejs/integrations` for one source dir. The
|
|
@@ -1409,7 +1412,7 @@ export function generateIntegrationsIndex(entries, opts) {
|
|
|
1409
1412
|
? ["export type IntegrationByName = {};"]
|
|
1410
1413
|
: [
|
|
1411
1414
|
"export type IntegrationByName = {",
|
|
1412
|
-
...sorted.map(({ name, serviceType }) => ` ${tsSingleQuoted(name)}: ${connectedTypeFor(serviceType)} | NeedsConnect;`),
|
|
1415
|
+
...sorted.map(({ name, serviceType, perUser }) => ` ${tsSingleQuoted(name)}: ${connectedTypeFor(serviceType)}${perUser ? " | NeedsConnect" : ""};`),
|
|
1413
1416
|
"};",
|
|
1414
1417
|
];
|
|
1415
1418
|
return [
|
|
@@ -1419,8 +1422,10 @@ export function generateIntegrationsIndex(entries, opts) {
|
|
|
1419
1422
|
"// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):",
|
|
1420
1423
|
"// import { integrations } from 'zitejs/integrations';",
|
|
1421
1424
|
"//",
|
|
1422
|
-
"// const
|
|
1423
|
-
"//
|
|
1425
|
+
"// const { accessToken } = await integrations.get('<entry name>');",
|
|
1426
|
+
"//",
|
|
1427
|
+
"// A workspace connection that isn't connected throws a ZiteError. A per-user",
|
|
1428
|
+
"// entry answers `missing`/`expired` with a connectUrl for the signed-in user.",
|
|
1424
1429
|
"//",
|
|
1425
1430
|
"// Call get where the value is used, not once at module scope: a token refreshed",
|
|
1426
1431
|
"// mid-run is what the next call returns.",
|
|
@@ -462,8 +462,9 @@ describe('generateIntegrationsIndex', () => {
|
|
|
462
462
|
};
|
|
463
463
|
it('emits the client typed by name', () => {
|
|
464
464
|
expect(generateIntegrationsIndex([
|
|
465
|
-
{ name: 'team', serviceType: 'slack' },
|
|
466
|
-
{ name: 'crm', serviceType: 'salesforce' },
|
|
465
|
+
{ name: 'team', serviceType: 'slack', perUser: false },
|
|
466
|
+
{ name: 'crm', serviceType: 'salesforce', perUser: false },
|
|
467
|
+
{ name: 'inbox', serviceType: 'gmail', perUser: true },
|
|
467
468
|
], { reexportAirtable: false })).toMatchInlineSnapshot(`
|
|
468
469
|
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.
|
|
469
470
|
// zitejs/integrations — an integration's credentials by its zite.config.json entry name.
|
|
@@ -471,8 +472,10 @@ describe('generateIntegrationsIndex', () => {
|
|
|
471
472
|
// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):
|
|
472
473
|
// import { integrations } from 'zitejs/integrations';
|
|
473
474
|
//
|
|
474
|
-
// const
|
|
475
|
-
//
|
|
475
|
+
// const { accessToken } = await integrations.get('<entry name>');
|
|
476
|
+
//
|
|
477
|
+
// A workspace connection that isn't connected throws a ZiteError. A per-user
|
|
478
|
+
// entry answers \`missing\`/\`expired\` with a connectUrl for the signed-in user.
|
|
476
479
|
//
|
|
477
480
|
// Call get where the value is used, not once at module scope: a token refreshed
|
|
478
481
|
// mid-run is what the next call returns.
|
|
@@ -482,32 +485,48 @@ describe('generateIntegrationsIndex', () => {
|
|
|
482
485
|
|
|
483
486
|
export type { Connected, NeedsConnect };
|
|
484
487
|
|
|
485
|
-
export type IntegrationName = 'crm' | 'team';
|
|
488
|
+
export type IntegrationName = 'crm' | 'inbox' | 'team';
|
|
486
489
|
|
|
487
490
|
export type IntegrationByName = {
|
|
488
|
-
'crm': Connected<{ instanceUrl: string }
|
|
489
|
-
'
|
|
491
|
+
'crm': Connected<{ instanceUrl: string }>;
|
|
492
|
+
'inbox': Connected | NeedsConnect;
|
|
493
|
+
'team': Connected;
|
|
490
494
|
};
|
|
491
495
|
|
|
492
496
|
export const integrations = createIntegrationsClient<IntegrationByName>();
|
|
493
497
|
"
|
|
494
498
|
`);
|
|
495
499
|
});
|
|
500
|
+
// The platform leaves these out for some accounts, so the type can't promise them.
|
|
501
|
+
it('marks an extra the platform may omit as optional', () => {
|
|
502
|
+
const generated = generateIntegrationsIndex([{ name: 'tickets', serviceType: 'jira', perUser: false }], { reexportAirtable: false });
|
|
503
|
+
expect(generated).toContain("'tickets': Connected<{ cloudId: string; siteUrl?: string }>;");
|
|
504
|
+
expect(typeErrorsIn(generated, `import { integrations } from 'zitejs/integrations';
|
|
505
|
+
const jira = await integrations.get('tickets');
|
|
506
|
+
const cloudId: string = jira.cloudId;
|
|
507
|
+
const siteUrl: string = jira.siteUrl;
|
|
508
|
+
`)).toEqual([
|
|
509
|
+
expect.stringContaining("Type 'string | undefined' is not assignable"),
|
|
510
|
+
]);
|
|
511
|
+
});
|
|
512
|
+
// A workspace entry is used as is; only a per-user one makes code check first.
|
|
496
513
|
it('types get per name in app code', () => {
|
|
497
514
|
const generated = generateIntegrationsIndex([
|
|
498
|
-
{ name: 'crm', serviceType: 'salesforce' },
|
|
499
|
-
{ name: 'warehouse', serviceType: 'clickhouse' },
|
|
515
|
+
{ name: 'crm', serviceType: 'salesforce', perUser: false },
|
|
516
|
+
{ name: 'warehouse', serviceType: 'clickhouse', perUser: false },
|
|
517
|
+
{ name: 'inbox', serviceType: 'gmail', perUser: true },
|
|
500
518
|
], { reexportAirtable: false });
|
|
501
519
|
expect(typeErrorsIn(generated, [
|
|
502
520
|
"import { integrations } from 'zitejs/integrations';",
|
|
503
521
|
'export const run = async () => {',
|
|
504
522
|
" const crm = await integrations.get('crm');",
|
|
505
|
-
" if (crm.status === 'connected') return crm.instanceUrl + crm.accessToken;",
|
|
506
523
|
" const warehouse = await integrations.get('warehouse');",
|
|
507
|
-
"
|
|
508
|
-
'
|
|
524
|
+
" const inbox = await integrations.get('inbox');",
|
|
525
|
+
" if (inbox.status !== 'connected') return inbox.connectUrl;",
|
|
526
|
+
' return crm.instanceUrl + warehouse.url + inbox.accessToken;',
|
|
509
527
|
'};',
|
|
510
528
|
].join('\n'))).toEqual([]);
|
|
529
|
+
expect(typeErrorsIn(generated, "import { integrations } from 'zitejs/integrations';\nexport const f = async () => (await integrations.get('inbox')).accessToken;")).toHaveLength(1);
|
|
511
530
|
expect(typeErrorsIn(generated, "import { integrations } from 'zitejs/integrations';\nvoid integrations.get('nope');")).toHaveLength(1);
|
|
512
531
|
});
|
|
513
532
|
it('compiles with nothing visible, naming nothing', () => {
|
|
@@ -523,13 +542,13 @@ describe('generateIntegrationsIndex', () => {
|
|
|
523
542
|
['a newline', 'crm\nprod'],
|
|
524
543
|
['a trailing backslash', 'crm\\'],
|
|
525
544
|
])('emits parseable TypeScript for a name with %s', (_what, name) => {
|
|
526
|
-
expect(syntaxErrorsIn(generateIntegrationsIndex([{ name, serviceType: 'slack' }], {
|
|
545
|
+
expect(syntaxErrorsIn(generateIntegrationsIndex([{ name, serviceType: 'slack', perUser: false }], {
|
|
527
546
|
reexportAirtable: false,
|
|
528
547
|
}))).toEqual([]);
|
|
529
548
|
});
|
|
530
549
|
// One module for everything integration: the Airtable clients keep resolving.
|
|
531
550
|
it('re-exports the generated Airtable clients beside the integrations client', () => {
|
|
532
|
-
const generated = generateIntegrationsIndex([{ name: 'team', serviceType: 'slack' }], { reexportAirtable: true });
|
|
551
|
+
const generated = generateIntegrationsIndex([{ name: 'team', serviceType: 'slack', perUser: false }], { reexportAirtable: true });
|
|
533
552
|
expect(generated).toContain("export * from './airtable';");
|
|
534
553
|
expect(typeErrorsIn(generated, [
|
|
535
554
|
"import { Customers, integrations } from 'zitejs/integrations';",
|
package/package.json
CHANGED
package/dist/cjs/meta/index.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type ZiteProjectUser = {
|
|
2
|
-
uuid: string;
|
|
3
|
-
firstName: string | null;
|
|
4
|
-
lastName: string | null;
|
|
5
|
-
email: string;
|
|
6
|
-
profilePictureUrl: string | null;
|
|
7
|
-
};
|
|
8
|
-
export type MetaListUsersResult = {
|
|
9
|
-
users: ZiteProjectUser[];
|
|
10
|
-
};
|
|
11
|
-
export declare class ZiteMeta {
|
|
12
|
-
static listUsers(): Promise<MetaListUsersResult>;
|
|
13
|
-
}
|
|
14
|
-
export declare const Meta: typeof ZiteMeta;
|
package/dist/cjs/meta/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Meta = exports.ZiteMeta = void 0;
|
|
4
|
-
const sdkCall_js_1 = require("../internal/sdkCall.js");
|
|
5
|
-
const META_SDK_INTEGRATION_ID = '__meta__';
|
|
6
|
-
class ZiteMeta {
|
|
7
|
-
static listUsers() {
|
|
8
|
-
return (0, sdkCall_js_1.getSdkCall)()(META_SDK_INTEGRATION_ID, 'ZiteMeta', 'listUsers', {});
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
exports.ZiteMeta = ZiteMeta;
|
|
12
|
-
exports.Meta = ZiteMeta;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface NotificationLink {
|
|
2
|
-
path?: string;
|
|
3
|
-
params?: Record<string, string>;
|
|
4
|
-
}
|
|
5
|
-
export type NotificationsCreateParams = {
|
|
6
|
-
recipients: string[];
|
|
7
|
-
title: string;
|
|
8
|
-
body?: string;
|
|
9
|
-
link?: NotificationLink;
|
|
10
|
-
path?: string;
|
|
11
|
-
params?: Record<string, string>;
|
|
12
|
-
payload?: Record<string, unknown>;
|
|
13
|
-
idempotencyKey?: string;
|
|
14
|
-
};
|
|
15
|
-
export type NotificationsCreateResult = {
|
|
16
|
-
created: number;
|
|
17
|
-
} | {
|
|
18
|
-
created: 0;
|
|
19
|
-
preview: true;
|
|
20
|
-
wouldCreate: number;
|
|
21
|
-
};
|
|
22
|
-
export declare class ZiteNotifications {
|
|
23
|
-
static create(params: NotificationsCreateParams): Promise<NotificationsCreateResult>;
|
|
24
|
-
}
|
|
25
|
-
export declare const Notifications: typeof ZiteNotifications;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Notifications = exports.ZiteNotifications = void 0;
|
|
4
|
-
const sdkCall_js_1 = require("../internal/sdkCall.js");
|
|
5
|
-
const NOTIFICATIONS_SDK_INTEGRATION_ID = '__notifications__';
|
|
6
|
-
class ZiteNotifications {
|
|
7
|
-
static create(params) {
|
|
8
|
-
return (0, sdkCall_js_1.getSdkCall)()(NOTIFICATIONS_SDK_INTEGRATION_ID, 'ZiteNotifications', 'create', params);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
exports.ZiteNotifications = ZiteNotifications;
|
|
12
|
-
exports.Notifications = ZiteNotifications;
|
package/dist/esm/meta/index.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type ZiteProjectUser = {
|
|
2
|
-
uuid: string;
|
|
3
|
-
firstName: string | null;
|
|
4
|
-
lastName: string | null;
|
|
5
|
-
email: string;
|
|
6
|
-
profilePictureUrl: string | null;
|
|
7
|
-
};
|
|
8
|
-
export type MetaListUsersResult = {
|
|
9
|
-
users: ZiteProjectUser[];
|
|
10
|
-
};
|
|
11
|
-
export declare class ZiteMeta {
|
|
12
|
-
static listUsers(): Promise<MetaListUsersResult>;
|
|
13
|
-
}
|
|
14
|
-
export declare const Meta: typeof ZiteMeta;
|
package/dist/esm/meta/index.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface NotificationLink {
|
|
2
|
-
path?: string;
|
|
3
|
-
params?: Record<string, string>;
|
|
4
|
-
}
|
|
5
|
-
export type NotificationsCreateParams = {
|
|
6
|
-
recipients: string[];
|
|
7
|
-
title: string;
|
|
8
|
-
body?: string;
|
|
9
|
-
link?: NotificationLink;
|
|
10
|
-
path?: string;
|
|
11
|
-
params?: Record<string, string>;
|
|
12
|
-
payload?: Record<string, unknown>;
|
|
13
|
-
idempotencyKey?: string;
|
|
14
|
-
};
|
|
15
|
-
export type NotificationsCreateResult = {
|
|
16
|
-
created: number;
|
|
17
|
-
} | {
|
|
18
|
-
created: 0;
|
|
19
|
-
preview: true;
|
|
20
|
-
wouldCreate: number;
|
|
21
|
-
};
|
|
22
|
-
export declare class ZiteNotifications {
|
|
23
|
-
static create(params: NotificationsCreateParams): Promise<NotificationsCreateResult>;
|
|
24
|
-
}
|
|
25
|
-
export declare const Notifications: typeof ZiteNotifications;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { getSdkCall } from '../internal/sdkCall.js';
|
|
2
|
-
const NOTIFICATIONS_SDK_INTEGRATION_ID = '__notifications__';
|
|
3
|
-
export class ZiteNotifications {
|
|
4
|
-
static create(params) {
|
|
5
|
-
return getSdkCall()(NOTIFICATIONS_SDK_INTEGRATION_ID, 'ZiteNotifications', 'create', params);
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
export const Notifications = ZiteNotifications;
|