zitejs 0.9.125 → 0.9.127
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 +96 -5
- package/dist/cjs/backend/index.test.js +68 -0
- package/dist/cjs/bundle/index.d.ts +1 -1
- package/dist/cjs/bundle/index.js +6 -2
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/meta/index.d.ts +14 -0
- package/dist/cjs/meta/index.js +12 -0
- package/dist/cjs/notifications/index.d.ts +25 -0
- package/dist/cjs/notifications/index.js +12 -0
- package/dist/cjs/sourceRoots.d.ts +3 -3
- package/dist/cjs/sourceRoots.js +6 -6
- package/dist/cjs/sourceRoots.test.js +4 -4
- package/dist/cjs/sync/lib.js +1 -1
- package/dist/cjs/sync/lib.test.js +1 -1
- package/dist/esm/backend/index.d.ts +96 -5
- package/dist/esm/backend/index.test.js +69 -1
- package/dist/esm/bundle/index.d.ts +1 -1
- package/dist/esm/bundle/index.js +6 -2
- package/dist/esm/cli.js +1 -1
- package/dist/esm/meta/index.d.ts +14 -0
- package/dist/esm/meta/index.js +8 -0
- package/dist/esm/notifications/index.d.ts +25 -0
- package/dist/esm/notifications/index.js +8 -0
- package/dist/esm/sourceRoots.d.ts +3 -3
- package/dist/esm/sourceRoots.js +5 -5
- package/dist/esm/sourceRoots.test.js +4 -4
- package/dist/esm/sync/lib.js +1 -1
- package/dist/esm/sync/lib.test.js +1 -1
- package/package.json +1 -1
|
@@ -13,17 +13,100 @@ export type ZiteWebhook = {
|
|
|
13
13
|
export type ZiteTrigger = {
|
|
14
14
|
/**
|
|
15
15
|
* The connection's name in `zite.config.json`. Registered with the
|
|
16
|
-
* provider by `
|
|
17
|
-
* by `unsubscribe
|
|
16
|
+
* provider by the endpoint file's own `subscribe` export and taken down
|
|
17
|
+
* by its `unsubscribe` export, which the platform runs at publish and
|
|
18
|
+
* teardown.
|
|
18
19
|
*/
|
|
19
20
|
integration: string;
|
|
21
|
+
/** The sentence the editor shows for what fires this endpoint, e.g. "When a task is completed in Asana". */
|
|
22
|
+
label?: string;
|
|
20
23
|
paused?: boolean;
|
|
24
|
+
every?: never;
|
|
21
25
|
} | {
|
|
22
|
-
|
|
23
|
-
/** `<n>m` (1–59) or `<n>h` (1–23) */
|
|
26
|
+
/** `<n>m` (1–59) or `<n>h` (1–23). What makes the trigger a poll. */
|
|
24
27
|
every: string;
|
|
28
|
+
/** The connection the poll checks, if any, so the editor can name it. */
|
|
29
|
+
integration?: string;
|
|
30
|
+
/** The sentence the editor shows for this poll, e.g. "Every 10 minutes, new Stripe charges". */
|
|
31
|
+
label?: string;
|
|
25
32
|
paused?: boolean;
|
|
26
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* What a provider trigger's `subscribe` export receives. Write it as
|
|
36
|
+
* `export const subscribe = (async input => { ... }) satisfies ZiteTriggerSubscribe`
|
|
37
|
+
* so the input is typed and a wrong return shape is a typecheck error.
|
|
38
|
+
*/
|
|
39
|
+
export type ZiteTriggerSubscribeInput = {
|
|
40
|
+
/** Where the provider must deliver, token included. */
|
|
41
|
+
notificationUrl: string;
|
|
42
|
+
/** The connection's name, as the trigger names it. */
|
|
43
|
+
integration: string;
|
|
44
|
+
endpointId: string;
|
|
45
|
+
/** A fresh 64-char hex secret, for providers that let the caller choose the signing secret. */
|
|
46
|
+
secret: string;
|
|
47
|
+
/** Set on a re-subscribe, including a renewal. */
|
|
48
|
+
previous: {
|
|
49
|
+
externalId: string;
|
|
50
|
+
state: Record<string, unknown>;
|
|
51
|
+
} | null;
|
|
52
|
+
};
|
|
53
|
+
export type ZiteTriggerSubscribeResult = {
|
|
54
|
+
/** The provider's id for the registration; what `unsubscribe` receives. */
|
|
55
|
+
externalId: string;
|
|
56
|
+
/** The signing secret, if the provider issued one or accepted `input.secret`. */
|
|
57
|
+
secret?: string;
|
|
58
|
+
/** Anything `unsubscribe` needs later; handed back to it and to the next `subscribe`. */
|
|
59
|
+
state?: Record<string, unknown>;
|
|
60
|
+
/** The provider's starting change marker, for notifications that only say something changed. */
|
|
61
|
+
cursor?: string;
|
|
62
|
+
/** ISO time the provider says the registration lapses, read from its response. */
|
|
63
|
+
expiresAt?: string;
|
|
64
|
+
};
|
|
65
|
+
export type ZiteTriggerUnsubscribeInput = {
|
|
66
|
+
externalId: string;
|
|
67
|
+
state: Record<string, unknown>;
|
|
68
|
+
integration: string;
|
|
69
|
+
endpointId: string;
|
|
70
|
+
};
|
|
71
|
+
export type ZiteTriggerSubscribe = (input: ZiteTriggerSubscribeInput) => Promise<ZiteTriggerSubscribeResult> | ZiteTriggerSubscribeResult;
|
|
72
|
+
export type ZiteTriggerUnsubscribe = (input: ZiteTriggerUnsubscribeInput) => Promise<void> | void;
|
|
73
|
+
/**
|
|
74
|
+
* What a poll-triggered run receives as `input.__poll`. Only on a fire from
|
|
75
|
+
* the poll's schedule; a request call to the same endpoint carries none.
|
|
76
|
+
*/
|
|
77
|
+
export type ZitePollInput = {
|
|
78
|
+
/** What the previous successful run returned as `cursor`; null on the first run. */
|
|
79
|
+
cursor: string | null;
|
|
80
|
+
/** Ids earlier runs returned as `handled`, newest last. Skip these. */
|
|
81
|
+
seen: string[];
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* What a provider trigger's delivery carries as `input.__webhook`, beside the
|
|
85
|
+
* provider's own body. `cursor` and `seen` work as they do for a poll: for a
|
|
86
|
+
* provider whose notification only says that something changed, `subscribe`
|
|
87
|
+
* returns a starting `cursor` and each delivery returns the next one. A
|
|
88
|
+
* trigger that keeps a cursor gets one delivery at a time.
|
|
89
|
+
*/
|
|
90
|
+
export type ZiteTriggerDelivery = {
|
|
91
|
+
headers: Record<string, string>;
|
|
92
|
+
/** The provider's id for this delivery; redeliveries share it. */
|
|
93
|
+
deliveryId?: string;
|
|
94
|
+
provider?: string;
|
|
95
|
+
/** What `subscribe` or the previous successful delivery returned as `cursor`. */
|
|
96
|
+
cursor: string | null;
|
|
97
|
+
/** Ids earlier deliveries returned as `handled`, newest last. Skip these. */
|
|
98
|
+
seen: string[];
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* What a poll-triggered run, or a provider trigger's delivery, returns for
|
|
102
|
+
* the platform to keep: its new `cursor`, and the id of every item it acted
|
|
103
|
+
* on, so the next run's `seen` includes them even if the cursor hands them
|
|
104
|
+
* back.
|
|
105
|
+
*/
|
|
106
|
+
export type ZitePollResult = {
|
|
107
|
+
cursor?: string;
|
|
108
|
+
handled?: string[];
|
|
109
|
+
};
|
|
27
110
|
export interface ZiteRequestContext {
|
|
28
111
|
user: {
|
|
29
112
|
id: string;
|
|
@@ -116,7 +199,15 @@ export interface EndpointConfig<TInput = unknown, TOutput = unknown, TStream ext
|
|
|
116
199
|
*/
|
|
117
200
|
validatesInput?: boolean;
|
|
118
201
|
execute: (params: {
|
|
119
|
-
input:
|
|
202
|
+
input: TTrigger extends {
|
|
203
|
+
every: string;
|
|
204
|
+
} ? TInput & {
|
|
205
|
+
__poll?: ZitePollInput;
|
|
206
|
+
} : TTrigger extends {
|
|
207
|
+
integration: string;
|
|
208
|
+
} ? TInput & {
|
|
209
|
+
__webhook?: ZiteTriggerDelivery;
|
|
210
|
+
} : TInput;
|
|
120
211
|
context: TSchedule extends ZiteSchedule ? ZiteRequestContext | ZiteScheduledContext : TWebhook extends ZiteWebhook ? ZiteRequestContext | ZiteScheduledContext : TTrigger extends ZiteTrigger ? ZiteRequestContext | ZiteScheduledContext : ZiteRequestContext;
|
|
121
212
|
} & (TStream extends true ? {
|
|
122
213
|
stream: ZiteStreamInterface;
|
|
@@ -133,6 +133,74 @@ const requestContext = { user: { id: "u1", email: "a@b.c" } };
|
|
|
133
133
|
});
|
|
134
134
|
await (0, vitest_1.expect)(endpoint.execute({ input: undefined, context: requestContext })).rejects.toMatchObject({ code: "BAD_REQUEST" });
|
|
135
135
|
});
|
|
136
|
+
(0, vitest_1.it)("hands a poll its cursor and seen ids, typed", async () => {
|
|
137
|
+
const endpoint = (0, index_js_1.createEndpoint)({
|
|
138
|
+
inputSchema: zod_1.z.object({}),
|
|
139
|
+
trigger: { every: "5m", integration: "stripe" },
|
|
140
|
+
execute: async ({ input }) => {
|
|
141
|
+
const seen = new Set(input.__poll?.seen);
|
|
142
|
+
const items = ["a", "b"].filter((id) => !seen.has(id));
|
|
143
|
+
return { cursor: input.__poll?.cursor ?? "start", handled: items };
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
await (0, vitest_1.expect)(endpoint.execute({
|
|
147
|
+
input: { __poll: { cursor: "c1", seen: ["a"] } },
|
|
148
|
+
context: { user: null },
|
|
149
|
+
})).resolves.toEqual({ cursor: "c1", handled: ["b"] });
|
|
150
|
+
});
|
|
151
|
+
(0, vitest_1.it)("gives __poll only to poll triggers", () => {
|
|
152
|
+
(0, index_js_1.createEndpoint)({
|
|
153
|
+
inputSchema: zod_1.z.object({ action: zod_1.z.string() }),
|
|
154
|
+
trigger: { integration: "github" },
|
|
155
|
+
execute: async ({ input }) => {
|
|
156
|
+
// @ts-expect-error a provider trigger's input has no __poll
|
|
157
|
+
return input.__poll;
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
(0, vitest_1.it)("types a trigger's registration exports and checks what subscribe returns", async () => {
|
|
162
|
+
const subscribe = (async (input) => ({
|
|
163
|
+
externalId: `hook-for-${input.endpointId}`,
|
|
164
|
+
secret: input.secret,
|
|
165
|
+
state: { repo: "acme/api" },
|
|
166
|
+
}));
|
|
167
|
+
const unsubscribe = (async (input) => {
|
|
168
|
+
(0, vitest_1.expect)(input.state.repo).toBe("acme/api");
|
|
169
|
+
});
|
|
170
|
+
// @ts-expect-error subscribe has to return the provider's id
|
|
171
|
+
void (async () => ({ secret: "s" }));
|
|
172
|
+
const registered = await subscribe({
|
|
173
|
+
notificationUrl: "https://x",
|
|
174
|
+
integration: "github",
|
|
175
|
+
endpointId: "onPush",
|
|
176
|
+
secret: "abc",
|
|
177
|
+
previous: null,
|
|
178
|
+
});
|
|
179
|
+
(0, vitest_1.expect)(registered.externalId).toBe("hook-for-onPush");
|
|
180
|
+
await unsubscribe({
|
|
181
|
+
externalId: registered.externalId,
|
|
182
|
+
state: registered.state ?? {},
|
|
183
|
+
integration: "github",
|
|
184
|
+
endpointId: "onPush",
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
(0, vitest_1.it)("hands a provider trigger's delivery its cursor and seen ids, typed", async () => {
|
|
188
|
+
const endpoint = (0, index_js_1.createEndpoint)({
|
|
189
|
+
inputSchema: zod_1.z.object({}),
|
|
190
|
+
trigger: { integration: "googleCalendar" },
|
|
191
|
+
execute: async ({ input }) => {
|
|
192
|
+
const seen = new Set(input.__webhook?.seen);
|
|
193
|
+
const changed = ["e1", "e2"].filter((id) => !seen.has(id));
|
|
194
|
+
return { cursor: `${input.__webhook?.cursor}+1`, handled: changed };
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
await (0, vitest_1.expect)(endpoint.execute({
|
|
198
|
+
input: {
|
|
199
|
+
__webhook: { headers: {}, cursor: "sync1", seen: ["e1"] },
|
|
200
|
+
},
|
|
201
|
+
context: { user: null },
|
|
202
|
+
})).resolves.toEqual({ cursor: "sync1+1", handled: ["e2"] });
|
|
203
|
+
});
|
|
136
204
|
(0, vitest_1.it)("does not validate a webhook fire", async () => {
|
|
137
205
|
const endpoint = (0, index_js_1.createEndpoint)({
|
|
138
206
|
inputSchema: zod_1.z.object({ token: zod_1.z.string().min(10) }),
|
|
@@ -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 an app's src/api/*.ts endpoints (an automation's single src/
|
|
5
|
+
* Reads an app's src/api/*.ts endpoints (an automation's single src/index.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
|
*
|
package/dist/cjs/bundle/index.js
CHANGED
|
@@ -40,7 +40,7 @@ exports.runBundle = runBundle;
|
|
|
40
40
|
* `npx zitejs bundle` — Bundle endpoint files for cloudflare-lambda deployment.
|
|
41
41
|
*
|
|
42
42
|
* Replaces the legacy `scripts/bundle-endpoints.js` from zitejs-starter.
|
|
43
|
-
* Reads an app's src/api/*.ts endpoints (an automation's single src/
|
|
43
|
+
* Reads an app's src/api/*.ts endpoints (an automation's single src/index.ts), resolves SDK imports via .zite/backend.ts
|
|
44
44
|
* (monorepo) or src/__zite__/integrations.ts (legacy), and outputs bundled ESM
|
|
45
45
|
* code suitable for the cloudflare-lambda worker runtime.
|
|
46
46
|
*
|
|
@@ -420,7 +420,7 @@ async function bundleEndpointsImpl(baseDir, root, endpointNames) {
|
|
|
420
420
|
for (const name of endpointNames) {
|
|
421
421
|
if (root === 'automations' && name !== sourceRoots_js_1.AUTOMATION_ENDPOINT_NAME) {
|
|
422
422
|
endpointErrors[name] =
|
|
423
|
-
`An automation is one workflow, src/
|
|
423
|
+
`An automation is one workflow, src/index.ts, bundled as "${sourceRoots_js_1.AUTOMATION_ENDPOINT_NAME}"; there is no endpoint "${name}"`;
|
|
424
424
|
continue;
|
|
425
425
|
}
|
|
426
426
|
const entryFile = (0, sourceRoots_js_1.endpointEntryFile)(root, name);
|
|
@@ -592,6 +592,10 @@ ${bodySection}
|
|
|
592
592
|
},
|
|
593
593
|
minify: false,
|
|
594
594
|
logLevel: 'silent',
|
|
595
|
+
// A script that imports an endpoint file's named exports (a trigger's
|
|
596
|
+
// subscribe/unsubscribe) must not carry the endpoint along with them:
|
|
597
|
+
// unused, its `createEndpoint(...)` and everything `execute` imports go.
|
|
598
|
+
pure: ['createEndpoint'],
|
|
595
599
|
plugins: [plugin],
|
|
596
600
|
});
|
|
597
601
|
if (result.errors.length > 0) {
|
package/dist/cjs/cli.js
CHANGED
|
@@ -75,7 +75,7 @@ async function main() {
|
|
|
75
75
|
console.error(' dev Run sync then watch for changes (like npx convex dev)');
|
|
76
76
|
console.error(' generate Regenerate every app and automation .zite/ (monorepo)');
|
|
77
77
|
console.error(' check Run tsc --noEmit (and vite build where there is one) for every app and automation');
|
|
78
|
-
console.error(' bundle Bundle endpoints (src/api/*.ts, or an automation\'s src/
|
|
78
|
+
console.error(' bundle Bundle endpoints (src/api/*.ts, or an automation\'s src/index.ts) for cloudflare-lambda');
|
|
79
79
|
process.exit(1);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
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;
|
|
@@ -0,0 +1,12 @@
|
|
|
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;
|
|
@@ -0,0 +1,25 @@
|
|
|
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;
|
|
@@ -0,0 +1,12 @@
|
|
|
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;
|
|
@@ -18,12 +18,12 @@ 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
20
|
/**
|
|
21
|
-
* An automation is one workflow: its single endpoint is `src/
|
|
21
|
+
* An automation is one workflow: its single endpoint is `src/index.ts` and
|
|
22
22
|
* its name is fixed, so nothing about an automation is keyed on a file name
|
|
23
23
|
* the way an app's `src/api/<name>.ts` endpoints are.
|
|
24
24
|
*/
|
|
25
|
-
export declare const AUTOMATION_ENDPOINT_NAME = "
|
|
26
|
-
export declare const
|
|
25
|
+
export declare const AUTOMATION_ENDPOINT_NAME = "index";
|
|
26
|
+
export declare const AUTOMATION_ENTRY_FILE = "src/index.ts";
|
|
27
27
|
/** The root a source dir sits under, read from its parent directory. */
|
|
28
28
|
export declare function sourceRootOf(sourceDirPath: string): SourceRoot | undefined;
|
|
29
29
|
/** An endpoint's entry file, relative to the source dir. */
|
package/dist/cjs/sourceRoots.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.AUTOMATION_ENTRY_FILE = exports.AUTOMATION_ENDPOINT_NAME = exports.SOURCE_ROOTS = void 0;
|
|
4
4
|
exports.listSourceDirs = listSourceDirs;
|
|
5
5
|
exports.findSourceDir = findSourceDir;
|
|
6
6
|
exports.sourceRootOf = sourceRootOf;
|
|
@@ -35,12 +35,12 @@ function findSourceDir(name, cwd = ".") {
|
|
|
35
35
|
return listSourceDirs(cwd).find((d) => d.dir === name);
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
* An automation is one workflow: its single endpoint is `src/
|
|
38
|
+
* An automation is one workflow: its single endpoint is `src/index.ts` and
|
|
39
39
|
* its name is fixed, so nothing about an automation is keyed on a file name
|
|
40
40
|
* the way an app's `src/api/<name>.ts` endpoints are.
|
|
41
41
|
*/
|
|
42
|
-
exports.AUTOMATION_ENDPOINT_NAME = "
|
|
43
|
-
exports.
|
|
42
|
+
exports.AUTOMATION_ENDPOINT_NAME = "index";
|
|
43
|
+
exports.AUTOMATION_ENTRY_FILE = "src/index.ts";
|
|
44
44
|
/** The root a source dir sits under, read from its parent directory. */
|
|
45
45
|
function sourceRootOf(sourceDirPath) {
|
|
46
46
|
const parent = (0, path_1.basename)((0, path_1.dirname)((0, path_1.resolve)(sourceDirPath)));
|
|
@@ -51,13 +51,13 @@ function sourceRootOf(sourceDirPath) {
|
|
|
51
51
|
/** An endpoint's entry file, relative to the source dir. */
|
|
52
52
|
function endpointEntryFile(root, name) {
|
|
53
53
|
return root === "automations"
|
|
54
|
-
? exports.
|
|
54
|
+
? exports.AUTOMATION_ENTRY_FILE
|
|
55
55
|
: (0, path_1.join)("src", "api", `${name}.ts`);
|
|
56
56
|
}
|
|
57
57
|
/** Every endpoint name a source dir has on disk. */
|
|
58
58
|
function listEndpointNames(root, sourceDirPath) {
|
|
59
59
|
if (root === "automations") {
|
|
60
|
-
return (0, fs_1.existsSync)((0, path_1.join)(sourceDirPath, exports.
|
|
60
|
+
return (0, fs_1.existsSync)((0, path_1.join)(sourceDirPath, exports.AUTOMATION_ENTRY_FILE))
|
|
61
61
|
? [exports.AUTOMATION_ENDPOINT_NAME]
|
|
62
62
|
: [];
|
|
63
63
|
}
|
|
@@ -11,9 +11,9 @@ const sourceRoots_js_1 = require("./sourceRoots.js");
|
|
|
11
11
|
(0, vitest_1.expect)((0, sourceRoots_js_1.sourceRootOf)("/repo/automations/digest")).toBe("automations");
|
|
12
12
|
(0, vitest_1.expect)((0, sourceRoots_js_1.sourceRootOf)("/repo/packages/ui")).toBeUndefined();
|
|
13
13
|
});
|
|
14
|
-
(0, vitest_1.it)("an app's endpoints are src/api/<name>.ts; an automation's one endpoint is src/
|
|
14
|
+
(0, vitest_1.it)("an app's endpoints are src/api/<name>.ts; an automation's one endpoint is src/index.ts", () => {
|
|
15
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", "
|
|
16
|
+
(0, vitest_1.expect)((0, sourceRoots_js_1.endpointEntryFile)("automations", "index")).toBe("src/index.ts");
|
|
17
17
|
});
|
|
18
18
|
(0, vitest_1.it)("lists what is on disk under each layout", () => {
|
|
19
19
|
const repo = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), "zitejs-roots-"));
|
|
@@ -22,9 +22,9 @@ const sourceRoots_js_1 = require("./sourceRoots.js");
|
|
|
22
22
|
(0, fs_1.writeFileSync)((0, path_1.join)(repo, "apps/crm/src/api/apiTypes.d.ts"), "");
|
|
23
23
|
(0, fs_1.mkdirSync)((0, path_1.join)(repo, "automations/digest/src"), { recursive: true });
|
|
24
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/
|
|
25
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(repo, "automations/digest/src/index.ts"), "");
|
|
26
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(["
|
|
27
|
+
(0, vitest_1.expect)((0, sourceRoots_js_1.listEndpointNames)("automations", (0, path_1.join)(repo, "automations/digest"))).toEqual(["index"]);
|
|
28
28
|
(0, vitest_1.expect)((0, sourceRoots_js_1.listEndpointNames)("automations", (0, path_1.join)(repo, "automations/empty"))).toEqual([]);
|
|
29
29
|
});
|
|
30
30
|
});
|
package/dist/cjs/sync/lib.js
CHANGED
|
@@ -1426,7 +1426,7 @@ function generateIntegrationsIndex(entries, opts) {
|
|
|
1426
1426
|
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.",
|
|
1427
1427
|
"// zitejs/integrations — an integration's credentials by its zite.config.json entry name.",
|
|
1428
1428
|
"//",
|
|
1429
|
-
"// Usage in endpoints (src/api/*.ts) and automations (src/
|
|
1429
|
+
"// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):",
|
|
1430
1430
|
"// import { integrations } from 'zitejs/integrations';",
|
|
1431
1431
|
"//",
|
|
1432
1432
|
"// const crm = await integrations.get('<entry name>');",
|
|
@@ -465,7 +465,7 @@ const duplicateIdentifierErrorsIn = (source) => {
|
|
|
465
465
|
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.
|
|
466
466
|
// zitejs/integrations — an integration's credentials by its zite.config.json entry name.
|
|
467
467
|
//
|
|
468
|
-
// Usage in endpoints (src/api/*.ts) and automations (src/
|
|
468
|
+
// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):
|
|
469
469
|
// import { integrations } from 'zitejs/integrations';
|
|
470
470
|
//
|
|
471
471
|
// const crm = await integrations.get('<entry name>');
|
|
@@ -13,17 +13,100 @@ export type ZiteWebhook = {
|
|
|
13
13
|
export type ZiteTrigger = {
|
|
14
14
|
/**
|
|
15
15
|
* The connection's name in `zite.config.json`. Registered with the
|
|
16
|
-
* provider by `
|
|
17
|
-
* by `unsubscribe
|
|
16
|
+
* provider by the endpoint file's own `subscribe` export and taken down
|
|
17
|
+
* by its `unsubscribe` export, which the platform runs at publish and
|
|
18
|
+
* teardown.
|
|
18
19
|
*/
|
|
19
20
|
integration: string;
|
|
21
|
+
/** The sentence the editor shows for what fires this endpoint, e.g. "When a task is completed in Asana". */
|
|
22
|
+
label?: string;
|
|
20
23
|
paused?: boolean;
|
|
24
|
+
every?: never;
|
|
21
25
|
} | {
|
|
22
|
-
|
|
23
|
-
/** `<n>m` (1–59) or `<n>h` (1–23) */
|
|
26
|
+
/** `<n>m` (1–59) or `<n>h` (1–23). What makes the trigger a poll. */
|
|
24
27
|
every: string;
|
|
28
|
+
/** The connection the poll checks, if any, so the editor can name it. */
|
|
29
|
+
integration?: string;
|
|
30
|
+
/** The sentence the editor shows for this poll, e.g. "Every 10 minutes, new Stripe charges". */
|
|
31
|
+
label?: string;
|
|
25
32
|
paused?: boolean;
|
|
26
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* What a provider trigger's `subscribe` export receives. Write it as
|
|
36
|
+
* `export const subscribe = (async input => { ... }) satisfies ZiteTriggerSubscribe`
|
|
37
|
+
* so the input is typed and a wrong return shape is a typecheck error.
|
|
38
|
+
*/
|
|
39
|
+
export type ZiteTriggerSubscribeInput = {
|
|
40
|
+
/** Where the provider must deliver, token included. */
|
|
41
|
+
notificationUrl: string;
|
|
42
|
+
/** The connection's name, as the trigger names it. */
|
|
43
|
+
integration: string;
|
|
44
|
+
endpointId: string;
|
|
45
|
+
/** A fresh 64-char hex secret, for providers that let the caller choose the signing secret. */
|
|
46
|
+
secret: string;
|
|
47
|
+
/** Set on a re-subscribe, including a renewal. */
|
|
48
|
+
previous: {
|
|
49
|
+
externalId: string;
|
|
50
|
+
state: Record<string, unknown>;
|
|
51
|
+
} | null;
|
|
52
|
+
};
|
|
53
|
+
export type ZiteTriggerSubscribeResult = {
|
|
54
|
+
/** The provider's id for the registration; what `unsubscribe` receives. */
|
|
55
|
+
externalId: string;
|
|
56
|
+
/** The signing secret, if the provider issued one or accepted `input.secret`. */
|
|
57
|
+
secret?: string;
|
|
58
|
+
/** Anything `unsubscribe` needs later; handed back to it and to the next `subscribe`. */
|
|
59
|
+
state?: Record<string, unknown>;
|
|
60
|
+
/** The provider's starting change marker, for notifications that only say something changed. */
|
|
61
|
+
cursor?: string;
|
|
62
|
+
/** ISO time the provider says the registration lapses, read from its response. */
|
|
63
|
+
expiresAt?: string;
|
|
64
|
+
};
|
|
65
|
+
export type ZiteTriggerUnsubscribeInput = {
|
|
66
|
+
externalId: string;
|
|
67
|
+
state: Record<string, unknown>;
|
|
68
|
+
integration: string;
|
|
69
|
+
endpointId: string;
|
|
70
|
+
};
|
|
71
|
+
export type ZiteTriggerSubscribe = (input: ZiteTriggerSubscribeInput) => Promise<ZiteTriggerSubscribeResult> | ZiteTriggerSubscribeResult;
|
|
72
|
+
export type ZiteTriggerUnsubscribe = (input: ZiteTriggerUnsubscribeInput) => Promise<void> | void;
|
|
73
|
+
/**
|
|
74
|
+
* What a poll-triggered run receives as `input.__poll`. Only on a fire from
|
|
75
|
+
* the poll's schedule; a request call to the same endpoint carries none.
|
|
76
|
+
*/
|
|
77
|
+
export type ZitePollInput = {
|
|
78
|
+
/** What the previous successful run returned as `cursor`; null on the first run. */
|
|
79
|
+
cursor: string | null;
|
|
80
|
+
/** Ids earlier runs returned as `handled`, newest last. Skip these. */
|
|
81
|
+
seen: string[];
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* What a provider trigger's delivery carries as `input.__webhook`, beside the
|
|
85
|
+
* provider's own body. `cursor` and `seen` work as they do for a poll: for a
|
|
86
|
+
* provider whose notification only says that something changed, `subscribe`
|
|
87
|
+
* returns a starting `cursor` and each delivery returns the next one. A
|
|
88
|
+
* trigger that keeps a cursor gets one delivery at a time.
|
|
89
|
+
*/
|
|
90
|
+
export type ZiteTriggerDelivery = {
|
|
91
|
+
headers: Record<string, string>;
|
|
92
|
+
/** The provider's id for this delivery; redeliveries share it. */
|
|
93
|
+
deliveryId?: string;
|
|
94
|
+
provider?: string;
|
|
95
|
+
/** What `subscribe` or the previous successful delivery returned as `cursor`. */
|
|
96
|
+
cursor: string | null;
|
|
97
|
+
/** Ids earlier deliveries returned as `handled`, newest last. Skip these. */
|
|
98
|
+
seen: string[];
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* What a poll-triggered run, or a provider trigger's delivery, returns for
|
|
102
|
+
* the platform to keep: its new `cursor`, and the id of every item it acted
|
|
103
|
+
* on, so the next run's `seen` includes them even if the cursor hands them
|
|
104
|
+
* back.
|
|
105
|
+
*/
|
|
106
|
+
export type ZitePollResult = {
|
|
107
|
+
cursor?: string;
|
|
108
|
+
handled?: string[];
|
|
109
|
+
};
|
|
27
110
|
export interface ZiteRequestContext {
|
|
28
111
|
user: {
|
|
29
112
|
id: string;
|
|
@@ -116,7 +199,15 @@ export interface EndpointConfig<TInput = unknown, TOutput = unknown, TStream ext
|
|
|
116
199
|
*/
|
|
117
200
|
validatesInput?: boolean;
|
|
118
201
|
execute: (params: {
|
|
119
|
-
input:
|
|
202
|
+
input: TTrigger extends {
|
|
203
|
+
every: string;
|
|
204
|
+
} ? TInput & {
|
|
205
|
+
__poll?: ZitePollInput;
|
|
206
|
+
} : TTrigger extends {
|
|
207
|
+
integration: string;
|
|
208
|
+
} ? TInput & {
|
|
209
|
+
__webhook?: ZiteTriggerDelivery;
|
|
210
|
+
} : TInput;
|
|
120
211
|
context: TSchedule extends ZiteSchedule ? ZiteRequestContext | ZiteScheduledContext : TWebhook extends ZiteWebhook ? ZiteRequestContext | ZiteScheduledContext : TTrigger extends ZiteTrigger ? ZiteRequestContext | ZiteScheduledContext : ZiteRequestContext;
|
|
121
212
|
} & (TStream extends true ? {
|
|
122
213
|
stream: ZiteStreamInterface;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { createEndpoint, ZiteError } from "./index.js";
|
|
3
|
+
import { createEndpoint, ZiteError, } from "./index.js";
|
|
4
4
|
import { createTableClient } from "../runtime/index.js";
|
|
5
5
|
const requestContext = { user: { id: "u1", email: "a@b.c" } };
|
|
6
6
|
afterEach(() => {
|
|
@@ -131,6 +131,74 @@ describe("platform-triggered runs", () => {
|
|
|
131
131
|
});
|
|
132
132
|
await expect(endpoint.execute({ input: undefined, context: requestContext })).rejects.toMatchObject({ code: "BAD_REQUEST" });
|
|
133
133
|
});
|
|
134
|
+
it("hands a poll its cursor and seen ids, typed", async () => {
|
|
135
|
+
const endpoint = createEndpoint({
|
|
136
|
+
inputSchema: z.object({}),
|
|
137
|
+
trigger: { every: "5m", integration: "stripe" },
|
|
138
|
+
execute: async ({ input }) => {
|
|
139
|
+
const seen = new Set(input.__poll?.seen);
|
|
140
|
+
const items = ["a", "b"].filter((id) => !seen.has(id));
|
|
141
|
+
return { cursor: input.__poll?.cursor ?? "start", handled: items };
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
await expect(endpoint.execute({
|
|
145
|
+
input: { __poll: { cursor: "c1", seen: ["a"] } },
|
|
146
|
+
context: { user: null },
|
|
147
|
+
})).resolves.toEqual({ cursor: "c1", handled: ["b"] });
|
|
148
|
+
});
|
|
149
|
+
it("gives __poll only to poll triggers", () => {
|
|
150
|
+
createEndpoint({
|
|
151
|
+
inputSchema: z.object({ action: z.string() }),
|
|
152
|
+
trigger: { integration: "github" },
|
|
153
|
+
execute: async ({ input }) => {
|
|
154
|
+
// @ts-expect-error a provider trigger's input has no __poll
|
|
155
|
+
return input.__poll;
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
it("types a trigger's registration exports and checks what subscribe returns", async () => {
|
|
160
|
+
const subscribe = (async (input) => ({
|
|
161
|
+
externalId: `hook-for-${input.endpointId}`,
|
|
162
|
+
secret: input.secret,
|
|
163
|
+
state: { repo: "acme/api" },
|
|
164
|
+
}));
|
|
165
|
+
const unsubscribe = (async (input) => {
|
|
166
|
+
expect(input.state.repo).toBe("acme/api");
|
|
167
|
+
});
|
|
168
|
+
// @ts-expect-error subscribe has to return the provider's id
|
|
169
|
+
void (async () => ({ secret: "s" }));
|
|
170
|
+
const registered = await subscribe({
|
|
171
|
+
notificationUrl: "https://x",
|
|
172
|
+
integration: "github",
|
|
173
|
+
endpointId: "onPush",
|
|
174
|
+
secret: "abc",
|
|
175
|
+
previous: null,
|
|
176
|
+
});
|
|
177
|
+
expect(registered.externalId).toBe("hook-for-onPush");
|
|
178
|
+
await unsubscribe({
|
|
179
|
+
externalId: registered.externalId,
|
|
180
|
+
state: registered.state ?? {},
|
|
181
|
+
integration: "github",
|
|
182
|
+
endpointId: "onPush",
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
it("hands a provider trigger's delivery its cursor and seen ids, typed", async () => {
|
|
186
|
+
const endpoint = createEndpoint({
|
|
187
|
+
inputSchema: z.object({}),
|
|
188
|
+
trigger: { integration: "googleCalendar" },
|
|
189
|
+
execute: async ({ input }) => {
|
|
190
|
+
const seen = new Set(input.__webhook?.seen);
|
|
191
|
+
const changed = ["e1", "e2"].filter((id) => !seen.has(id));
|
|
192
|
+
return { cursor: `${input.__webhook?.cursor}+1`, handled: changed };
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
await expect(endpoint.execute({
|
|
196
|
+
input: {
|
|
197
|
+
__webhook: { headers: {}, cursor: "sync1", seen: ["e1"] },
|
|
198
|
+
},
|
|
199
|
+
context: { user: null },
|
|
200
|
+
})).resolves.toEqual({ cursor: "sync1+1", handled: ["e2"] });
|
|
201
|
+
});
|
|
134
202
|
it("does not validate a webhook fire", async () => {
|
|
135
203
|
const endpoint = createEndpoint({
|
|
136
204
|
inputSchema: z.object({ token: z.string().min(10) }),
|
|
@@ -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 an app's src/api/*.ts endpoints (an automation's single src/
|
|
5
|
+
* Reads an app's src/api/*.ts endpoints (an automation's single src/index.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
|
*
|
package/dist/esm/bundle/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `npx zitejs bundle` — Bundle endpoint files for cloudflare-lambda deployment.
|
|
3
3
|
*
|
|
4
4
|
* Replaces the legacy `scripts/bundle-endpoints.js` from zitejs-starter.
|
|
5
|
-
* Reads an app's src/api/*.ts endpoints (an automation's single src/
|
|
5
|
+
* Reads an app's src/api/*.ts endpoints (an automation's single src/index.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
|
*
|
|
@@ -382,7 +382,7 @@ async function bundleEndpointsImpl(baseDir, root, endpointNames) {
|
|
|
382
382
|
for (const name of endpointNames) {
|
|
383
383
|
if (root === 'automations' && name !== AUTOMATION_ENDPOINT_NAME) {
|
|
384
384
|
endpointErrors[name] =
|
|
385
|
-
`An automation is one workflow, src/
|
|
385
|
+
`An automation is one workflow, src/index.ts, bundled as "${AUTOMATION_ENDPOINT_NAME}"; there is no endpoint "${name}"`;
|
|
386
386
|
continue;
|
|
387
387
|
}
|
|
388
388
|
const entryFile = endpointEntryFile(root, name);
|
|
@@ -554,6 +554,10 @@ ${bodySection}
|
|
|
554
554
|
},
|
|
555
555
|
minify: false,
|
|
556
556
|
logLevel: 'silent',
|
|
557
|
+
// A script that imports an endpoint file's named exports (a trigger's
|
|
558
|
+
// subscribe/unsubscribe) must not carry the endpoint along with them:
|
|
559
|
+
// unused, its `createEndpoint(...)` and everything `execute` imports go.
|
|
560
|
+
pure: ['createEndpoint'],
|
|
557
561
|
plugins: [plugin],
|
|
558
562
|
});
|
|
559
563
|
if (result.errors.length > 0) {
|
package/dist/esm/cli.js
CHANGED
|
@@ -40,7 +40,7 @@ async function main() {
|
|
|
40
40
|
console.error(' dev Run sync then watch for changes (like npx convex dev)');
|
|
41
41
|
console.error(' generate Regenerate every app and automation .zite/ (monorepo)');
|
|
42
42
|
console.error(' check Run tsc --noEmit (and vite build where there is one) for every app and automation');
|
|
43
|
-
console.error(' bundle Bundle endpoints (src/api/*.ts, or an automation\'s src/
|
|
43
|
+
console.error(' bundle Bundle endpoints (src/api/*.ts, or an automation\'s src/index.ts) for cloudflare-lambda');
|
|
44
44
|
process.exit(1);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
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;
|
|
@@ -0,0 +1,25 @@
|
|
|
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;
|
|
@@ -0,0 +1,8 @@
|
|
|
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;
|
|
@@ -18,12 +18,12 @@ 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
20
|
/**
|
|
21
|
-
* An automation is one workflow: its single endpoint is `src/
|
|
21
|
+
* An automation is one workflow: its single endpoint is `src/index.ts` and
|
|
22
22
|
* its name is fixed, so nothing about an automation is keyed on a file name
|
|
23
23
|
* the way an app's `src/api/<name>.ts` endpoints are.
|
|
24
24
|
*/
|
|
25
|
-
export declare const AUTOMATION_ENDPOINT_NAME = "
|
|
26
|
-
export declare const
|
|
25
|
+
export declare const AUTOMATION_ENDPOINT_NAME = "index";
|
|
26
|
+
export declare const AUTOMATION_ENTRY_FILE = "src/index.ts";
|
|
27
27
|
/** The root a source dir sits under, read from its parent directory. */
|
|
28
28
|
export declare function sourceRootOf(sourceDirPath: string): SourceRoot | undefined;
|
|
29
29
|
/** An endpoint's entry file, relative to the source dir. */
|
package/dist/esm/sourceRoots.js
CHANGED
|
@@ -27,12 +27,12 @@ export function findSourceDir(name, cwd = ".") {
|
|
|
27
27
|
return listSourceDirs(cwd).find((d) => d.dir === name);
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* An automation is one workflow: its single endpoint is `src/
|
|
30
|
+
* An automation is one workflow: its single endpoint is `src/index.ts` and
|
|
31
31
|
* its name is fixed, so nothing about an automation is keyed on a file name
|
|
32
32
|
* the way an app's `src/api/<name>.ts` endpoints are.
|
|
33
33
|
*/
|
|
34
|
-
export const AUTOMATION_ENDPOINT_NAME = "
|
|
35
|
-
export const
|
|
34
|
+
export const AUTOMATION_ENDPOINT_NAME = "index";
|
|
35
|
+
export const AUTOMATION_ENTRY_FILE = "src/index.ts";
|
|
36
36
|
/** The root a source dir sits under, read from its parent directory. */
|
|
37
37
|
export function sourceRootOf(sourceDirPath) {
|
|
38
38
|
const parent = basename(dirname(resolve(sourceDirPath)));
|
|
@@ -43,13 +43,13 @@ export function sourceRootOf(sourceDirPath) {
|
|
|
43
43
|
/** An endpoint's entry file, relative to the source dir. */
|
|
44
44
|
export function endpointEntryFile(root, name) {
|
|
45
45
|
return root === "automations"
|
|
46
|
-
?
|
|
46
|
+
? AUTOMATION_ENTRY_FILE
|
|
47
47
|
: join("src", "api", `${name}.ts`);
|
|
48
48
|
}
|
|
49
49
|
/** Every endpoint name a source dir has on disk. */
|
|
50
50
|
export function listEndpointNames(root, sourceDirPath) {
|
|
51
51
|
if (root === "automations") {
|
|
52
|
-
return existsSync(join(sourceDirPath,
|
|
52
|
+
return existsSync(join(sourceDirPath, AUTOMATION_ENTRY_FILE))
|
|
53
53
|
? [AUTOMATION_ENDPOINT_NAME]
|
|
54
54
|
: [];
|
|
55
55
|
}
|
|
@@ -9,9 +9,9 @@ describe("source roots", () => {
|
|
|
9
9
|
expect(sourceRootOf("/repo/automations/digest")).toBe("automations");
|
|
10
10
|
expect(sourceRootOf("/repo/packages/ui")).toBeUndefined();
|
|
11
11
|
});
|
|
12
|
-
it("an app's endpoints are src/api/<name>.ts; an automation's one endpoint is src/
|
|
12
|
+
it("an app's endpoints are src/api/<name>.ts; an automation's one endpoint is src/index.ts", () => {
|
|
13
13
|
expect(endpointEntryFile("apps", "listItems")).toBe("src/api/listItems.ts");
|
|
14
|
-
expect(endpointEntryFile("automations", "
|
|
14
|
+
expect(endpointEntryFile("automations", "index")).toBe("src/index.ts");
|
|
15
15
|
});
|
|
16
16
|
it("lists what is on disk under each layout", () => {
|
|
17
17
|
const repo = mkdtempSync(join(tmpdir(), "zitejs-roots-"));
|
|
@@ -20,9 +20,9 @@ describe("source roots", () => {
|
|
|
20
20
|
writeFileSync(join(repo, "apps/crm/src/api/apiTypes.d.ts"), "");
|
|
21
21
|
mkdirSync(join(repo, "automations/digest/src"), { recursive: true });
|
|
22
22
|
mkdirSync(join(repo, "automations/empty/src"), { recursive: true });
|
|
23
|
-
writeFileSync(join(repo, "automations/digest/src/
|
|
23
|
+
writeFileSync(join(repo, "automations/digest/src/index.ts"), "");
|
|
24
24
|
expect(listEndpointNames("apps", join(repo, "apps/crm"))).toEqual(["listItems"]);
|
|
25
|
-
expect(listEndpointNames("automations", join(repo, "automations/digest"))).toEqual(["
|
|
25
|
+
expect(listEndpointNames("automations", join(repo, "automations/digest"))).toEqual(["index"]);
|
|
26
26
|
expect(listEndpointNames("automations", join(repo, "automations/empty"))).toEqual([]);
|
|
27
27
|
});
|
|
28
28
|
});
|
package/dist/esm/sync/lib.js
CHANGED
|
@@ -1411,7 +1411,7 @@ export function generateIntegrationsIndex(entries, opts) {
|
|
|
1411
1411
|
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.",
|
|
1412
1412
|
"// zitejs/integrations — an integration's credentials by its zite.config.json entry name.",
|
|
1413
1413
|
"//",
|
|
1414
|
-
"// Usage in endpoints (src/api/*.ts) and automations (src/
|
|
1414
|
+
"// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):",
|
|
1415
1415
|
"// import { integrations } from 'zitejs/integrations';",
|
|
1416
1416
|
"//",
|
|
1417
1417
|
"// const crm = await integrations.get('<entry name>');",
|
|
@@ -460,7 +460,7 @@ describe('generateIntegrationsIndex', () => {
|
|
|
460
460
|
"// Auto-generated by zitejs generate from zite.config.json. Do not edit manually.
|
|
461
461
|
// zitejs/integrations — an integration's credentials by its zite.config.json entry name.
|
|
462
462
|
//
|
|
463
|
-
// Usage in endpoints (src/api/*.ts) and automations (src/
|
|
463
|
+
// Usage in endpoints (src/api/*.ts) and automations (src/index.ts):
|
|
464
464
|
// import { integrations } from 'zitejs/integrations';
|
|
465
465
|
//
|
|
466
466
|
// const crm = await integrations.get('<entry name>');
|