zitejs 0.10.0-start.6 → 0.10.0-start.8
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/backend/index.d.ts +115 -3
- package/dist/cjs/backend/index.test.js +58 -0
- package/dist/cjs/integrations/rules.d.ts +13 -0
- package/dist/cjs/integrations/rules.js +29 -0
- package/dist/cjs/integrations/rules.test.js +1 -0
- package/dist/cjs/sync/lib.js +10 -13
- package/dist/cjs/vite/index.js +8 -3
- package/dist/cjs/vite/index.test.js +10 -2
- package/dist/esm/backend/index.d.ts +115 -3
- package/dist/esm/backend/index.test.js +58 -0
- package/dist/esm/integrations/rules.d.ts +13 -0
- package/dist/esm/integrations/rules.js +29 -0
- package/dist/esm/integrations/rules.test.js +1 -0
- package/dist/esm/start/airtable/arrayFields.d.ts +10 -0
- package/dist/esm/start/airtable/arrayFields.js +30 -0
- package/dist/esm/start/airtable/dispatch.d.ts +54 -0
- package/dist/esm/start/airtable/dispatch.js +465 -0
- package/dist/esm/start/airtable/formulas.d.ts +69 -0
- package/dist/esm/start/airtable/formulas.js +235 -0
- package/dist/esm/start/airtable/index.d.ts +11 -0
- package/dist/esm/start/airtable/index.js +70 -0
- package/dist/esm/start/authHooks.d.ts +7 -0
- package/dist/esm/start/authHooks.js +10 -0
- package/dist/esm/start/authHooksModule.d.ts +1 -0
- package/dist/esm/start/authHooksModule.js +3 -0
- package/dist/esm/start/clientErrorMessage.test.d.ts +1 -0
- package/dist/esm/start/clientErrorMessage.test.js +105 -0
- package/dist/esm/start/data/baseRunner.d.ts +92 -0
- package/dist/esm/start/data/baseRunner.js +83 -0
- package/dist/esm/start/data/dispatch.d.ts +16 -0
- package/dist/esm/start/data/dispatch.js +198 -0
- package/dist/esm/start/data/index.d.ts +18 -0
- package/dist/esm/start/data/index.js +76 -0
- package/dist/esm/start/data/sqlNameMappings.d.ts +58 -0
- package/dist/esm/start/data/sqlNameMappings.js +92 -0
- package/dist/esm/start/data/transformations.d.ts +128 -0
- package/dist/esm/start/data/transformations.js +318 -0
- package/dist/esm/start/data/types.d.ts +91 -0
- package/dist/esm/start/data/types.js +14 -0
- package/dist/esm/start/describe.d.ts +17 -1
- package/dist/esm/start/describe.js +27 -5
- package/dist/esm/start/errors.d.ts +46 -0
- package/dist/esm/start/errors.js +99 -0
- package/dist/esm/start/errors.test.d.ts +1 -0
- package/dist/esm/start/errors.test.js +23 -0
- package/dist/esm/start/index.d.ts +3 -19
- package/dist/esm/start/index.js +28 -36
- package/dist/esm/start/instance.d.ts +1 -2
- package/dist/esm/start/instance.js +11 -4
- package/dist/esm/start/previewClaim.d.ts +10 -0
- package/dist/esm/start/previewClaim.js +32 -0
- package/dist/esm/start/redactSecrets.d.ts +7 -0
- package/dist/esm/start/redactSecrets.js +131 -0
- package/dist/esm/start/redactSecrets.test.d.ts +1 -0
- package/dist/esm/start/redactSecrets.test.js +151 -0
- package/dist/esm/start/router.d.ts +6 -3
- package/dist/esm/start/router.js +47 -7
- package/dist/esm/start/runLog.d.ts +7 -4
- package/dist/esm/start/runLog.js +64 -6
- package/dist/esm/start/server.d.ts +7 -3
- package/dist/esm/start/server.js +124 -22
- package/dist/esm/start/types.d.ts +68 -3
- package/dist/esm/start/version.d.ts +1 -0
- package/dist/esm/start/version.js +2 -0
- package/dist/esm/start/vite.js +33 -4
- package/dist/esm/start/workflowRun.js +2 -1
- package/dist/esm/sync/lib.js +10 -13
- package/dist/esm/vite/index.js +8 -3
- package/dist/esm/vite/index.test.js +10 -2
- package/package.json +16 -8
|
@@ -6,6 +6,8 @@ const requestContext = { user: { id: "u1", email: "a@b.c", roles: [] } };
|
|
|
6
6
|
// Direct execute() calls need the step surface the runtime always provides.
|
|
7
7
|
const stepStub = {
|
|
8
8
|
run: async (_name, fn) => await fn(),
|
|
9
|
+
sleep: async () => { },
|
|
10
|
+
sleepUntil: async () => { },
|
|
9
11
|
};
|
|
10
12
|
afterEach(() => {
|
|
11
13
|
vi.unstubAllGlobals();
|
|
@@ -205,6 +207,62 @@ describe("platform-triggered runs", () => {
|
|
|
205
207
|
return params.trigger;
|
|
206
208
|
},
|
|
207
209
|
});
|
|
210
|
+
createEndpoint({
|
|
211
|
+
trigger: { table: "orders", on: ["updated"], fields: ["status"] },
|
|
212
|
+
execute: async ({ input, trigger }) => {
|
|
213
|
+
// @ts-expect-error a database change has no cursor API
|
|
214
|
+
trigger?.advance("x");
|
|
215
|
+
const status = input.record?.status;
|
|
216
|
+
return { status, changed: input.changedFields, at: input.event };
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
createEndpoint({
|
|
220
|
+
// @ts-expect-error a database trigger names its table, not a connection
|
|
221
|
+
trigger: { table: "orders", on: ["created"], integration: "x" },
|
|
222
|
+
execute: async () => 1,
|
|
223
|
+
});
|
|
224
|
+
createEndpoint({
|
|
225
|
+
trigger: { form: "Intake form", on: ["submitted"] },
|
|
226
|
+
execute: async ({ input, trigger }) => {
|
|
227
|
+
// @ts-expect-error a form submission has no cursor API
|
|
228
|
+
trigger?.advance("x");
|
|
229
|
+
return {
|
|
230
|
+
email: input.answers.Email,
|
|
231
|
+
workEmail: input.answersById["wWorkEmail"],
|
|
232
|
+
id: input.submissionId,
|
|
233
|
+
};
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
createEndpoint({
|
|
237
|
+
// @ts-expect-error a form trigger watches submissions only
|
|
238
|
+
trigger: { form: "Intake form", on: ["updated"] },
|
|
239
|
+
execute: async () => 1,
|
|
240
|
+
});
|
|
241
|
+
createEndpoint({
|
|
242
|
+
// @ts-expect-error only created, updated and deleted
|
|
243
|
+
trigger: { table: "orders", on: ["archived"] },
|
|
244
|
+
execute: async () => 1,
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
it("hands a database trigger its change without parsing it against the input schema", async () => {
|
|
248
|
+
const endpoint = createEndpoint({
|
|
249
|
+
inputSchema: z.object({ orderId: z.string() }),
|
|
250
|
+
trigger: { table: "orders", on: ["created"] },
|
|
251
|
+
execute: async ({ input }) => input.recordId,
|
|
252
|
+
});
|
|
253
|
+
await expect(endpoint.execute({
|
|
254
|
+
step: stepStub,
|
|
255
|
+
input: {
|
|
256
|
+
event: "created",
|
|
257
|
+
table: "orders",
|
|
258
|
+
recordId: "rec_1",
|
|
259
|
+
record: { id: "rec_1" },
|
|
260
|
+
previous: null,
|
|
261
|
+
changedFields: [],
|
|
262
|
+
},
|
|
263
|
+
context: { user: null },
|
|
264
|
+
trigger: { headers: {}, deliveryId: "db:e1:rec_1" },
|
|
265
|
+
})).resolves.toBe("rec_1");
|
|
208
266
|
});
|
|
209
267
|
it("types a trigger's registration exports and checks what subscribe returns", async () => {
|
|
210
268
|
const subscribe = (async (input) => ({
|
|
@@ -38,11 +38,24 @@ declare const FIELDS_BY_TYPE: {
|
|
|
38
38
|
jira: readonly string[];
|
|
39
39
|
typeform: readonly string[];
|
|
40
40
|
apollo: readonly string[];
|
|
41
|
+
clay: readonly string[];
|
|
41
42
|
attio: readonly string[];
|
|
42
43
|
granola: readonly string[];
|
|
44
|
+
clickup: readonly string[];
|
|
43
45
|
dropbox: readonly string[];
|
|
46
|
+
zendesk: readonly string[];
|
|
47
|
+
smartsheet: readonly string[];
|
|
44
48
|
amazonS3: readonly string[];
|
|
45
49
|
snowflake: readonly string[];
|
|
50
|
+
databricks: readonly string[];
|
|
51
|
+
confluence: readonly string[];
|
|
52
|
+
pipedrive: readonly string[];
|
|
53
|
+
shopify: readonly string[];
|
|
54
|
+
sharepoint: readonly string[];
|
|
55
|
+
excel: readonly string[];
|
|
56
|
+
x: readonly string[];
|
|
57
|
+
zoomMeetings: readonly string[];
|
|
58
|
+
smartsuite: readonly string[];
|
|
46
59
|
};
|
|
47
60
|
/** A service type `integrations.get` serves: one used through its npm package with a token. */
|
|
48
61
|
export type CredentialServiceType = keyof typeof FIELDS_BY_TYPE;
|
|
@@ -44,15 +44,43 @@ const FIELDS_BY_TYPE = {
|
|
|
44
44
|
jira: extras("cloudId", "siteUrl"),
|
|
45
45
|
typeform: extras(),
|
|
46
46
|
apollo: extras(),
|
|
47
|
+
clay: extras(),
|
|
47
48
|
attio: extras(),
|
|
48
49
|
granola: extras(),
|
|
50
|
+
clickup: extras(),
|
|
49
51
|
dropbox: extras(),
|
|
52
|
+
// Every path is https://{subdomain}.zendesk.com/api/v2/..., and a token is
|
|
53
|
+
// only valid on the account it was issued for, so the subdomain travels with
|
|
54
|
+
// it rather than being configured per app.
|
|
55
|
+
zendesk: extras("subdomain"),
|
|
56
|
+
// Smartsheet's US, EU, AU and Gov regions are separate, and a token is only
|
|
57
|
+
// valid on its own region's host, so the host travels with it.
|
|
58
|
+
smartsheet: extras("apiBaseUrl"),
|
|
50
59
|
// The IAM key alone reaches nothing: every call needs the region and the
|
|
51
60
|
// bucket, and S3-compatible providers need the endpoint too.
|
|
52
61
|
amazonS3: extras("keyId", "region", "bucket", "endpoint", "pathPrefix"),
|
|
53
62
|
// The SQL API lives on each account's own host, and the token is pinned to
|
|
54
63
|
// one role; the warehouse is optional and falls back to the user's default.
|
|
55
64
|
snowflake: extras("accountUrl", "role", "warehouse"),
|
|
65
|
+
// A statement is addressed by workspace host and SQL warehouse, and the token
|
|
66
|
+
// derives neither.
|
|
67
|
+
databricks: extras("host", "warehouseId"),
|
|
68
|
+
// Cloud Confluence is addressed through api.atlassian.com by cloud id, the
|
|
69
|
+
// same as Jira; the site URL is only for links a human will click.
|
|
70
|
+
confluence: extras("cloudId", "siteUrl"),
|
|
71
|
+
// OAuth returns a per-company api_domain alongside the token, so there is no
|
|
72
|
+
// one host to call.
|
|
73
|
+
pipedrive: extras("apiBaseUrl"),
|
|
74
|
+
// Shopify has no global API host: every call goes to the store's own domain
|
|
75
|
+
// under a pinned API version. The storefront pair is the shopper-facing API,
|
|
76
|
+
// which installs predating those scopes do not have.
|
|
77
|
+
shopify: extras("shopDomain", "apiBaseUrl", "storefrontApiUrl", "storefrontAccessToken"),
|
|
78
|
+
sharepoint: extras(),
|
|
79
|
+
excel: extras(),
|
|
80
|
+
x: extras(),
|
|
81
|
+
zoomMeetings: extras(),
|
|
82
|
+
// Every request names the workspace in an Account-Id header beside the key.
|
|
83
|
+
smartsuite: extras("workspaceId"),
|
|
56
84
|
};
|
|
57
85
|
/** Per service type: `accessToken`, then its extra labels sorted (Salesforce `instanceUrl`). */
|
|
58
86
|
export const CREDENTIAL_FIELDS = FIELDS_BY_TYPE;
|
|
@@ -65,6 +93,7 @@ export const OPTIONAL_CREDENTIAL_FIELDS = {
|
|
|
65
93
|
// Only S3-compatible providers set an endpoint, and a prefix is opt-in.
|
|
66
94
|
amazonS3: ["endpoint", "pathPrefix"],
|
|
67
95
|
snowflake: ["warehouse"],
|
|
96
|
+
shopify: ["storefrontApiUrl", "storefrontAccessToken"],
|
|
68
97
|
};
|
|
69
98
|
/**
|
|
70
99
|
* Types the runtime never serves: those with a generated client (Airtable, email,
|
|
@@ -16,6 +16,7 @@ describe("CREDENTIAL_FIELDS", () => {
|
|
|
16
16
|
]);
|
|
17
17
|
expect(CREDENTIAL_FIELDS.jira).toEqual(["accessToken", "cloudId", "siteUrl"]);
|
|
18
18
|
expect(CREDENTIAL_FIELDS.granola).toEqual(["accessToken"]);
|
|
19
|
+
expect(CREDENTIAL_FIELDS.smartsheet).toEqual(["accessToken", "apiBaseUrl"]);
|
|
19
20
|
});
|
|
20
21
|
it("has no type the runtime never serves", () => {
|
|
21
22
|
for (const type of NON_CREDENTIAL_SERVICE_TYPES) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type AirtableFieldShape = {
|
|
2
|
+
type: string;
|
|
3
|
+
options?: unknown;
|
|
4
|
+
};
|
|
5
|
+
export declare const isArrayValuedAirtableField: (field: AirtableFieldShape) => boolean;
|
|
6
|
+
export declare const airtableEqualsFormula: ({ field, fieldName, value, }: {
|
|
7
|
+
field: AirtableFieldShape;
|
|
8
|
+
fieldName: string;
|
|
9
|
+
value: string;
|
|
10
|
+
}) => string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const ARRAY_VALUED_AIRTABLE_FIELD_TYPES = new Set([
|
|
3
|
+
'multipleLookupValues',
|
|
4
|
+
'multipleSelects',
|
|
5
|
+
'multipleRecordLinks',
|
|
6
|
+
'multipleCollaborators',
|
|
7
|
+
'multipleAttachments',
|
|
8
|
+
]);
|
|
9
|
+
const resultTypeOptionsSchema = z.object({
|
|
10
|
+
result: z.object({ type: z.string().optional() }).optional(),
|
|
11
|
+
});
|
|
12
|
+
export const isArrayValuedAirtableField = (field) => {
|
|
13
|
+
if (field.type === 'formula' || field.type === 'rollup') {
|
|
14
|
+
const resultType = resultTypeOptionsSchema.safeParse(field.options).data
|
|
15
|
+
?.result?.type;
|
|
16
|
+
return resultType
|
|
17
|
+
? ARRAY_VALUED_AIRTABLE_FIELD_TYPES.has(resultType)
|
|
18
|
+
: false;
|
|
19
|
+
}
|
|
20
|
+
return ARRAY_VALUED_AIRTABLE_FIELD_TYPES.has(field.type);
|
|
21
|
+
};
|
|
22
|
+
const ELEMENT_SEPARATOR = ', ';
|
|
23
|
+
export const airtableEqualsFormula = ({ field, fieldName, value, }) => {
|
|
24
|
+
if (!isArrayValuedAirtableField(field)) {
|
|
25
|
+
return `${fieldName}=${value}`;
|
|
26
|
+
}
|
|
27
|
+
const needle = `"${ELEMENT_SEPARATOR}" & ${value} & "${ELEMENT_SEPARATOR}"`;
|
|
28
|
+
const haystack = `"${ELEMENT_SEPARATOR}" & ARRAYJOIN(${fieldName}) & "${ELEMENT_SEPARATOR}"`;
|
|
29
|
+
return `SEARCH(${needle}, ${haystack}) != ""`;
|
|
30
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** As `@fillout/zite`'s `IntegrationFieldMappingType`, from zite.lock. */
|
|
2
|
+
export type AirtableFieldMapping = {
|
|
3
|
+
mapping: {
|
|
4
|
+
sdkName: string;
|
|
5
|
+
};
|
|
6
|
+
fieldType?: string;
|
|
7
|
+
fieldName?: string;
|
|
8
|
+
fieldOptions?: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
export type AirtableFieldMappings = Record<string, AirtableFieldMapping>;
|
|
11
|
+
export type AirtableNameMappings = {
|
|
12
|
+
bases: Record<string, {
|
|
13
|
+
mapping: {
|
|
14
|
+
sdkName: string;
|
|
15
|
+
};
|
|
16
|
+
tables: Record<string, {
|
|
17
|
+
mapping: {
|
|
18
|
+
sdkName: string;
|
|
19
|
+
};
|
|
20
|
+
primaryFieldId?: string;
|
|
21
|
+
fields: AirtableFieldMappings;
|
|
22
|
+
}>;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
/** An app's Airtable integration as its build declares it. */
|
|
26
|
+
export type AirtableSettings = {
|
|
27
|
+
baseId: string;
|
|
28
|
+
nameMappings: AirtableNameMappings | null;
|
|
29
|
+
};
|
|
30
|
+
/** Answers one Airtable request; the platform puts the connection's token on it. */
|
|
31
|
+
export type AirtableFetch = (path: string, init: {
|
|
32
|
+
method: string;
|
|
33
|
+
body?: unknown;
|
|
34
|
+
}) => Promise<Response>;
|
|
35
|
+
export type AirtableContext = {
|
|
36
|
+
settings: AirtableSettings;
|
|
37
|
+
fetch: AirtableFetch;
|
|
38
|
+
/** One request's reads, so the same read twice in a request goes to Airtable once. */
|
|
39
|
+
reads?: Map<string, Promise<unknown>>;
|
|
40
|
+
sleep?: (ms: number) => Promise<void>;
|
|
41
|
+
};
|
|
42
|
+
/** The npm SDK's error, whose shape apps (and the goldens) see: not an `Error`. */
|
|
43
|
+
export declare class AirtableError {
|
|
44
|
+
error: string;
|
|
45
|
+
message: string;
|
|
46
|
+
statusCode: number;
|
|
47
|
+
constructor(error: string, message: string, statusCode: number);
|
|
48
|
+
toString(): string;
|
|
49
|
+
}
|
|
50
|
+
export declare function airtableRecordToSdkNames(record: Record<string, any> | undefined, fieldMappings: AirtableFieldMappings | undefined): Record<string, any> | undefined;
|
|
51
|
+
/** A Duration cell (seconds) as HH:mm:ss, keeping seconds and fractions (ZIT-3889). */
|
|
52
|
+
export declare function formatAirtableDuration(durationSeconds: number): string;
|
|
53
|
+
/** One Airtable table call, as classic's dispatch runs it. */
|
|
54
|
+
export declare function executeAirtableCall(context: AirtableContext, methodName: string, params: any): Promise<any>;
|