@zapier/zapier-sdk 0.13.5 → 0.13.7
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/CHANGELOG.md +15 -0
- package/dist/api/schemas.d.ts +38 -38
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +170 -177
- package/dist/index.mjs +1 -1
- package/dist/plugins/fetch/schemas.d.ts +4 -4
- package/dist/plugins/getAction/schemas.d.ts +2 -2
- package/dist/plugins/listActions/schemas.d.ts +6 -6
- package/dist/plugins/listApps/schemas.d.ts +6 -6
- package/dist/plugins/listAuthentications/schemas.d.ts +4 -4
- package/dist/plugins/listInputFieldChoices/schemas.d.ts +8 -8
- package/dist/plugins/listInputFields/schemas.d.ts +8 -8
- package/dist/plugins/request/schemas.d.ts +8 -8
- package/dist/plugins/runAction/schemas.d.ts +8 -8
- package/dist/schemas/Action.d.ts +2 -2
- package/dist/schemas/App.d.ts +8 -8
- package/dist/types/sdk.d.ts +2 -8
- package/dist/types/sdk.d.ts.map +1 -1
- package/package.json +8 -3
- package/src/api/auth.ts +0 -28
- package/src/api/client.ts +0 -491
- package/src/api/debug.test.ts +0 -76
- package/src/api/debug.ts +0 -154
- package/src/api/index.ts +0 -90
- package/src/api/polling.test.ts +0 -405
- package/src/api/polling.ts +0 -253
- package/src/api/schemas.ts +0 -465
- package/src/api/types.ts +0 -152
- package/src/auth.ts +0 -72
- package/src/constants.ts +0 -16
- package/src/index.ts +0 -111
- package/src/plugins/api/index.ts +0 -43
- package/src/plugins/apps/index.ts +0 -203
- package/src/plugins/apps/schemas.ts +0 -64
- package/src/plugins/eventEmission/builders.ts +0 -115
- package/src/plugins/eventEmission/index.test.ts +0 -169
- package/src/plugins/eventEmission/index.ts +0 -294
- package/src/plugins/eventEmission/transport.test.ts +0 -214
- package/src/plugins/eventEmission/transport.ts +0 -135
- package/src/plugins/eventEmission/types.ts +0 -58
- package/src/plugins/eventEmission/utils.ts +0 -121
- package/src/plugins/fetch/index.ts +0 -83
- package/src/plugins/fetch/schemas.ts +0 -37
- package/src/plugins/findFirstAuthentication/index.test.ts +0 -209
- package/src/plugins/findFirstAuthentication/index.ts +0 -68
- package/src/plugins/findFirstAuthentication/schemas.ts +0 -47
- package/src/plugins/findUniqueAuthentication/index.test.ts +0 -197
- package/src/plugins/findUniqueAuthentication/index.ts +0 -77
- package/src/plugins/findUniqueAuthentication/schemas.ts +0 -49
- package/src/plugins/getAction/index.test.ts +0 -239
- package/src/plugins/getAction/index.ts +0 -75
- package/src/plugins/getAction/schemas.ts +0 -41
- package/src/plugins/getApp/index.test.ts +0 -181
- package/src/plugins/getApp/index.ts +0 -60
- package/src/plugins/getApp/schemas.ts +0 -33
- package/src/plugins/getAuthentication/index.test.ts +0 -294
- package/src/plugins/getAuthentication/index.ts +0 -95
- package/src/plugins/getAuthentication/schemas.ts +0 -38
- package/src/plugins/getProfile/index.ts +0 -60
- package/src/plugins/getProfile/schemas.ts +0 -24
- package/src/plugins/listActions/index.test.ts +0 -526
- package/src/plugins/listActions/index.ts +0 -132
- package/src/plugins/listActions/schemas.ts +0 -55
- package/src/plugins/listApps/index.test.ts +0 -378
- package/src/plugins/listApps/index.ts +0 -159
- package/src/plugins/listApps/schemas.ts +0 -41
- package/src/plugins/listAuthentications/index.test.ts +0 -739
- package/src/plugins/listAuthentications/index.ts +0 -152
- package/src/plugins/listAuthentications/schemas.ts +0 -77
- package/src/plugins/listInputFieldChoices/index.test.ts +0 -653
- package/src/plugins/listInputFieldChoices/index.ts +0 -173
- package/src/plugins/listInputFieldChoices/schemas.ts +0 -125
- package/src/plugins/listInputFields/index.test.ts +0 -439
- package/src/plugins/listInputFields/index.ts +0 -294
- package/src/plugins/listInputFields/schemas.ts +0 -68
- package/src/plugins/manifest/index.test.ts +0 -776
- package/src/plugins/manifest/index.ts +0 -461
- package/src/plugins/manifest/schemas.ts +0 -60
- package/src/plugins/registry/index.ts +0 -160
- package/src/plugins/request/index.test.ts +0 -333
- package/src/plugins/request/index.ts +0 -105
- package/src/plugins/request/schemas.ts +0 -69
- package/src/plugins/runAction/index.test.ts +0 -388
- package/src/plugins/runAction/index.ts +0 -215
- package/src/plugins/runAction/schemas.ts +0 -60
- package/src/resolvers/actionKey.ts +0 -37
- package/src/resolvers/actionType.ts +0 -34
- package/src/resolvers/appKey.ts +0 -7
- package/src/resolvers/authenticationId.ts +0 -54
- package/src/resolvers/index.ts +0 -11
- package/src/resolvers/inputFieldKey.ts +0 -70
- package/src/resolvers/inputs.ts +0 -69
- package/src/schemas/Action.ts +0 -52
- package/src/schemas/App.ts +0 -45
- package/src/schemas/Auth.ts +0 -59
- package/src/schemas/Field.ts +0 -169
- package/src/schemas/Run.ts +0 -40
- package/src/schemas/UserProfile.ts +0 -60
- package/src/sdk.test.ts +0 -212
- package/src/sdk.ts +0 -178
- package/src/types/domain.test.ts +0 -50
- package/src/types/domain.ts +0 -66
- package/src/types/errors.ts +0 -278
- package/src/types/events.ts +0 -43
- package/src/types/functions.ts +0 -28
- package/src/types/optional-zapier-sdk-cli-login.d.ts +0 -37
- package/src/types/plugin.ts +0 -125
- package/src/types/properties.ts +0 -80
- package/src/types/sdk.ts +0 -117
- package/src/types/telemetry-events.ts +0 -85
- package/src/utils/array-utils.test.ts +0 -131
- package/src/utils/array-utils.ts +0 -41
- package/src/utils/domain-utils.test.ts +0 -433
- package/src/utils/domain-utils.ts +0 -267
- package/src/utils/file-utils.test.ts +0 -73
- package/src/utils/file-utils.ts +0 -94
- package/src/utils/function-utils.test.ts +0 -141
- package/src/utils/function-utils.ts +0 -245
- package/src/utils/pagination-utils.test.ts +0 -620
- package/src/utils/pagination-utils.ts +0 -242
- package/src/utils/schema-utils.ts +0 -207
- package/src/utils/string-utils.test.ts +0 -45
- package/src/utils/string-utils.ts +0 -54
- package/src/utils/validation.test.ts +0 -51
- package/src/utils/validation.ts +0 -44
- package/tsconfig.build.json +0 -18
- package/tsconfig.json +0 -20
- package/tsconfig.tsbuildinfo +0 -1
- package/tsup.config.ts +0 -23
|
@@ -1,461 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile, resolve } from "../../utils/file-utils";
|
|
2
|
-
import type {
|
|
3
|
-
GetVersionedImplementationId,
|
|
4
|
-
Manifest,
|
|
5
|
-
ManifestEntry,
|
|
6
|
-
ManifestPluginOptionsSchema,
|
|
7
|
-
ResolveAppKeys,
|
|
8
|
-
} from "./schemas";
|
|
9
|
-
import { ManifestSchema, DEFAULT_CONFIG_PATH } from "./schemas";
|
|
10
|
-
import type { Plugin } from "../../types/plugin";
|
|
11
|
-
import type { z } from "zod";
|
|
12
|
-
import type { ApiClient } from "../../api";
|
|
13
|
-
import type { ImplementationsMetaResponse } from "../../api/types";
|
|
14
|
-
import {
|
|
15
|
-
normalizeImplementationMetaToAppItem,
|
|
16
|
-
splitVersionedKey,
|
|
17
|
-
isSnakeCasedSlug,
|
|
18
|
-
dashifySnakeCasedSlug,
|
|
19
|
-
toAppLocator,
|
|
20
|
-
type ResolvedAppLocator,
|
|
21
|
-
isResolvedAppLocator,
|
|
22
|
-
} from "../../utils/domain-utils";
|
|
23
|
-
import type { AppItem } from "../../types/domain";
|
|
24
|
-
import { extractCursor } from "../../utils/function-utils";
|
|
25
|
-
import { paginate } from "../../utils/pagination-utils";
|
|
26
|
-
import { toArrayFromAsync } from "../../utils/array-utils";
|
|
27
|
-
|
|
28
|
-
export type ManifestPluginOptions = z.infer<typeof ManifestPluginOptionsSchema>;
|
|
29
|
-
|
|
30
|
-
export interface UpdateManifestEntryOptions {
|
|
31
|
-
appKey: string;
|
|
32
|
-
entry: ManifestEntry;
|
|
33
|
-
configPath?: string;
|
|
34
|
-
skipWrite?: boolean;
|
|
35
|
-
manifest?: Manifest;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ManifestPluginProvides {
|
|
39
|
-
context: {
|
|
40
|
-
getVersionedImplementationId: GetVersionedImplementationId;
|
|
41
|
-
resolveAppKeys: ResolveAppKeys;
|
|
42
|
-
updateManifestEntry: (
|
|
43
|
-
options: UpdateManifestEntryOptions,
|
|
44
|
-
) => Promise<[string, ManifestEntry, Manifest]>;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Parse manifest content from a string
|
|
50
|
-
*/
|
|
51
|
-
function parseManifestContent(
|
|
52
|
-
content: string,
|
|
53
|
-
source: string,
|
|
54
|
-
): Manifest | null {
|
|
55
|
-
try {
|
|
56
|
-
const parsed = JSON.parse(content);
|
|
57
|
-
|
|
58
|
-
if (parsed?.apps && typeof parsed?.apps === "object") {
|
|
59
|
-
const result = ManifestSchema.safeParse(parsed);
|
|
60
|
-
if (result.success) {
|
|
61
|
-
return result.data;
|
|
62
|
-
}
|
|
63
|
-
console.warn(`⚠️ Invalid manifest format in ${source}: ${result.error}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return null;
|
|
67
|
-
} catch (error) {
|
|
68
|
-
console.warn(`⚠️ Failed to parse manifest from ${source}:`, error);
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Read manifest from a file path asynchronously
|
|
75
|
-
* Supports local files (Node.js) and browser environments (fallback to global filesystem)
|
|
76
|
-
*/
|
|
77
|
-
export async function readManifestFromFile(
|
|
78
|
-
filePath: string,
|
|
79
|
-
): Promise<Manifest | null> {
|
|
80
|
-
try {
|
|
81
|
-
// Resolve relative paths relative to current working directory
|
|
82
|
-
const resolvedPath = await resolve(filePath);
|
|
83
|
-
const content = await readFile(resolvedPath);
|
|
84
|
-
return parseManifestContent(content, resolvedPath);
|
|
85
|
-
} catch {
|
|
86
|
-
console.warn(`⚠️ Failed to read manifest from ${filePath}`);
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Write manifest to a file path asynchronously
|
|
93
|
-
* Supports local files (Node.js) and browser environments (fallback to global filesystem)
|
|
94
|
-
*/
|
|
95
|
-
async function writeManifestToFile(
|
|
96
|
-
manifest: Manifest,
|
|
97
|
-
filePath: string,
|
|
98
|
-
): Promise<void> {
|
|
99
|
-
const resolvedPath = await resolve(filePath);
|
|
100
|
-
await writeFile(resolvedPath, JSON.stringify(manifest, null, 2));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get the preferred key for storing an app in the manifest
|
|
105
|
-
* Extracted from plugin to make it easier to test
|
|
106
|
-
*/
|
|
107
|
-
export async function getPreferredManifestEntryKey({
|
|
108
|
-
appKey,
|
|
109
|
-
api,
|
|
110
|
-
}: {
|
|
111
|
-
appKey: string;
|
|
112
|
-
api: ApiClient;
|
|
113
|
-
}): Promise<string> {
|
|
114
|
-
const locator = toAppLocator(appKey);
|
|
115
|
-
|
|
116
|
-
// If we have a slug, prefer it
|
|
117
|
-
if (locator.slug) {
|
|
118
|
-
return locator.slug;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// If we have implementation name, look up the latest to get the slug
|
|
122
|
-
if (locator.implementationName) {
|
|
123
|
-
try {
|
|
124
|
-
// API call to get app metadata by implementation name using selected_apis parameter
|
|
125
|
-
const implementationsEnvelope: ImplementationsMetaResponse =
|
|
126
|
-
await api.get(`/api/v4/implementations-meta/lookup/`, {
|
|
127
|
-
searchParams: {
|
|
128
|
-
selected_apis: locator.implementationName,
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
implementationsEnvelope.results.length > 0 &&
|
|
134
|
-
implementationsEnvelope.results[0].slug
|
|
135
|
-
) {
|
|
136
|
-
return implementationsEnvelope.results[0].slug;
|
|
137
|
-
}
|
|
138
|
-
} catch {
|
|
139
|
-
// Fall back to implementation name if lookup fails
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return locator.implementationName;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Fall back to original key if we can't determine anything better
|
|
146
|
-
return locator.lookupAppKey;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function listAppsForSlugsPage({
|
|
150
|
-
slugs,
|
|
151
|
-
cursor,
|
|
152
|
-
api,
|
|
153
|
-
}: {
|
|
154
|
-
slugs: string[];
|
|
155
|
-
cursor?: string;
|
|
156
|
-
api: ApiClient;
|
|
157
|
-
}) {
|
|
158
|
-
const searchParams: Record<string, string> = {};
|
|
159
|
-
|
|
160
|
-
if (slugs.length > 0) {
|
|
161
|
-
searchParams.slugs = slugs.join(",");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (cursor) {
|
|
165
|
-
searchParams.offset = cursor;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const implementationsEnvelope: ImplementationsMetaResponse = await api.get(
|
|
169
|
-
"/api/v4/implementations-meta/lookup/",
|
|
170
|
-
{
|
|
171
|
-
searchParams,
|
|
172
|
-
},
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
data: implementationsEnvelope.results.map(
|
|
177
|
-
normalizeImplementationMetaToAppItem,
|
|
178
|
-
),
|
|
179
|
-
nextCursor: extractCursor(implementationsEnvelope),
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Find a manifest entry by any app key (implementation name, slug, etc.).
|
|
185
|
-
*/
|
|
186
|
-
export function findManifestEntry({
|
|
187
|
-
appKey,
|
|
188
|
-
manifest,
|
|
189
|
-
}: {
|
|
190
|
-
appKey: string;
|
|
191
|
-
manifest: Manifest;
|
|
192
|
-
}): [string, ManifestEntry] | null {
|
|
193
|
-
const [appKeyWithoutVersion] = splitVersionedKey(appKey);
|
|
194
|
-
|
|
195
|
-
// Direct match by key
|
|
196
|
-
if (manifest.apps[appKeyWithoutVersion]) {
|
|
197
|
-
return [appKeyWithoutVersion, manifest.apps[appKeyWithoutVersion]];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Handle snake-cased slugs (convert to dashed)
|
|
201
|
-
if (isSnakeCasedSlug(appKey)) {
|
|
202
|
-
const slug = dashifySnakeCasedSlug(appKey);
|
|
203
|
-
if (manifest.apps[slug]) {
|
|
204
|
-
return [slug, manifest.apps[slug]];
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Search by implementation name in manifest values
|
|
209
|
-
for (const [key, entry] of Object.entries(manifest.apps)) {
|
|
210
|
-
if (entry.implementationName === appKeyWithoutVersion) {
|
|
211
|
-
return [key, entry];
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// No match found
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Turn any app keys (slugs, implementation names, etc.) into app locators, which are objects that will be guaranteed to
|
|
221
|
-
* have implementation names. Note that this function will not actually guarantee that implementation names are valid!
|
|
222
|
-
* It will attempt to find the app key in the manifest, or if it's a slug, actually do an API call, or otherwise just
|
|
223
|
-
* assume it's an implementation name that will be used for an API call.
|
|
224
|
-
*/
|
|
225
|
-
async function resolveAppKeys({
|
|
226
|
-
appKeys,
|
|
227
|
-
api,
|
|
228
|
-
manifest,
|
|
229
|
-
}: {
|
|
230
|
-
appKeys: string[];
|
|
231
|
-
api: ApiClient;
|
|
232
|
-
manifest: Manifest;
|
|
233
|
-
}): Promise<ResolvedAppLocator[]> {
|
|
234
|
-
// Step 1: Convert all app keys to locators
|
|
235
|
-
const locators = appKeys.map(toAppLocator);
|
|
236
|
-
|
|
237
|
-
// Step 2: Map to resolved/unresolved via manifest
|
|
238
|
-
const locatorsWithManifest = locators.map((locator) => {
|
|
239
|
-
const manifestEntryResult = findManifestEntry({
|
|
240
|
-
appKey: locator.lookupAppKey,
|
|
241
|
-
manifest,
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
if (manifestEntryResult) {
|
|
245
|
-
const [, manifestEntry] = manifestEntryResult;
|
|
246
|
-
// Use manifest entry to resolve implementation name
|
|
247
|
-
const resolvedVersion = locator.version || manifestEntry.version;
|
|
248
|
-
|
|
249
|
-
const resolvedLocator: ResolvedAppLocator = {
|
|
250
|
-
...locator,
|
|
251
|
-
implementationName: manifestEntry.implementationName,
|
|
252
|
-
version: resolvedVersion,
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
return resolvedLocator;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// If these have an implementationName, they're already resolved.
|
|
259
|
-
return locator;
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// Step 3: Separate resolved from unresolved
|
|
263
|
-
const unresolvedLocators = locatorsWithManifest.filter(
|
|
264
|
-
(locator) => !isResolvedAppLocator(locator),
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
// Step 4: Resolve slugs via API
|
|
268
|
-
const slugsToResolve = unresolvedLocators
|
|
269
|
-
.map((locator) => locator.slug)
|
|
270
|
-
.filter((slug): slug is string => !!slug)
|
|
271
|
-
.filter((slug, index, array) => array.indexOf(slug) === index); // dedupe
|
|
272
|
-
|
|
273
|
-
if (slugsToResolve.length === 0) {
|
|
274
|
-
return locatorsWithManifest.filter(isResolvedAppLocator);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const iterator = paginate(listAppsForSlugsPage, {
|
|
278
|
-
slugs: slugsToResolve,
|
|
279
|
-
api,
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
const pages = await toArrayFromAsync(iterator);
|
|
283
|
-
const apps = pages.flatMap((page) => page.data);
|
|
284
|
-
|
|
285
|
-
const slugToAppData = new Map<string, AppItem>();
|
|
286
|
-
for (const app of apps) {
|
|
287
|
-
if (app.slug) {
|
|
288
|
-
slugToAppData.set(app.slug, app);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const slugResolvedLocators = locatorsWithManifest.map((locator) => {
|
|
293
|
-
if (isResolvedAppLocator(locator)) {
|
|
294
|
-
return locator;
|
|
295
|
-
}
|
|
296
|
-
if (locator.slug) {
|
|
297
|
-
const appData = slugToAppData.get(locator.slug);
|
|
298
|
-
if (appData) {
|
|
299
|
-
// After resolving from API, check if we have a manifest entry for this implementation name
|
|
300
|
-
const manifestEntryByImplementationName = findManifestEntry({
|
|
301
|
-
appKey: appData.key, // appData.key is the implementation name
|
|
302
|
-
manifest,
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
let version = locator.version;
|
|
306
|
-
if (!version) {
|
|
307
|
-
// Prefer manifest version if available, otherwise use API version
|
|
308
|
-
version = manifestEntryByImplementationName
|
|
309
|
-
? manifestEntryByImplementationName[1].version || appData.version
|
|
310
|
-
: appData.version;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
...locator,
|
|
315
|
-
implementationName: appData.key,
|
|
316
|
-
version,
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return locator;
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// Return all resolved locators.
|
|
324
|
-
return slugResolvedLocators.filter(isResolvedAppLocator);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export { DEFAULT_CONFIG_PATH } from "./schemas";
|
|
328
|
-
export type { ManifestEntry, Manifest } from "./schemas";
|
|
329
|
-
|
|
330
|
-
export const manifestPlugin: Plugin<
|
|
331
|
-
{}, // no SDK dependencies
|
|
332
|
-
{ api: ApiClient },
|
|
333
|
-
ManifestPluginProvides
|
|
334
|
-
> = (params) => {
|
|
335
|
-
const { context } = params;
|
|
336
|
-
const { api, options } = context;
|
|
337
|
-
const { manifestPath = DEFAULT_CONFIG_PATH, manifest } = options || {};
|
|
338
|
-
|
|
339
|
-
let resolvedManifest: Manifest | undefined | null;
|
|
340
|
-
|
|
341
|
-
async function resolveManifest(): Promise<Manifest | null> {
|
|
342
|
-
// If manifest is provided directly, use it
|
|
343
|
-
if (manifest) {
|
|
344
|
-
return manifest;
|
|
345
|
-
}
|
|
346
|
-
// If manifestPath is provided, load from file
|
|
347
|
-
if (manifestPath) {
|
|
348
|
-
return await readManifestFromFile(manifestPath);
|
|
349
|
-
}
|
|
350
|
-
return null;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const getResolvedManifest = async (): Promise<Manifest | null> => {
|
|
354
|
-
if (typeof resolvedManifest === "undefined") {
|
|
355
|
-
resolvedManifest = (await resolveManifest()) ?? null;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return resolvedManifest;
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
const getVersionedImplementationId = async (appKey: string) => {
|
|
362
|
-
const resolvedApps = await resolveAppKeys({
|
|
363
|
-
appKeys: [appKey],
|
|
364
|
-
api,
|
|
365
|
-
manifest: (await getResolvedManifest()) ?? { apps: {} },
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
const resolvedApp = resolvedApps[0];
|
|
369
|
-
if (!resolvedApp) return null;
|
|
370
|
-
|
|
371
|
-
return `${resolvedApp.implementationName}@${resolvedApp.version || "latest"}`;
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
const updateManifestEntry = async (
|
|
375
|
-
options: UpdateManifestEntryOptions,
|
|
376
|
-
): Promise<[string, ManifestEntry, Manifest]> => {
|
|
377
|
-
const {
|
|
378
|
-
appKey,
|
|
379
|
-
entry,
|
|
380
|
-
configPath = DEFAULT_CONFIG_PATH,
|
|
381
|
-
skipWrite = false,
|
|
382
|
-
manifest: inputManifest,
|
|
383
|
-
} = options;
|
|
384
|
-
|
|
385
|
-
// Use provided manifest or read from file
|
|
386
|
-
const manifest = inputManifest ||
|
|
387
|
-
(await readManifestFromFile(configPath)) || { apps: {} };
|
|
388
|
-
|
|
389
|
-
// Try to find existing entry by direct key first
|
|
390
|
-
let existingEntry = findManifestEntry({
|
|
391
|
-
appKey,
|
|
392
|
-
manifest,
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
// If not found directly, try to resolve the app key and search by implementation name
|
|
396
|
-
if (!existingEntry) {
|
|
397
|
-
try {
|
|
398
|
-
const resolvedApps = await resolveAppKeys({
|
|
399
|
-
appKeys: [appKey],
|
|
400
|
-
api,
|
|
401
|
-
manifest,
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
if (resolvedApps.length > 0) {
|
|
405
|
-
const resolvedImplementationName = resolvedApps[0].implementationName;
|
|
406
|
-
// Try to find entry using the resolved implementation name
|
|
407
|
-
existingEntry = findManifestEntry({
|
|
408
|
-
appKey: resolvedImplementationName,
|
|
409
|
-
manifest,
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
} catch {
|
|
413
|
-
// If resolution fails, continue with original logic
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
let manifestKey: string;
|
|
418
|
-
|
|
419
|
-
if (existingEntry) {
|
|
420
|
-
// Use existing key to maintain consistency with types files
|
|
421
|
-
manifestKey = existingEntry[0];
|
|
422
|
-
} else {
|
|
423
|
-
// Get preferred key for new entries
|
|
424
|
-
manifestKey = await getPreferredManifestEntryKey({
|
|
425
|
-
appKey,
|
|
426
|
-
api,
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const updatedManifest = {
|
|
431
|
-
...manifest,
|
|
432
|
-
apps: {
|
|
433
|
-
...manifest.apps,
|
|
434
|
-
[manifestKey]: entry,
|
|
435
|
-
},
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
// Conditionally write to file
|
|
439
|
-
if (!skipWrite) {
|
|
440
|
-
await writeManifestToFile(updatedManifest, configPath);
|
|
441
|
-
|
|
442
|
-
// Clear the cached manifest so it gets reloaded with the new data
|
|
443
|
-
resolvedManifest = undefined;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return [manifestKey, entry, updatedManifest];
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
return {
|
|
450
|
-
context: {
|
|
451
|
-
getVersionedImplementationId,
|
|
452
|
-
resolveAppKeys: async ({ appKeys }: { appKeys: string[] }) =>
|
|
453
|
-
resolveAppKeys({
|
|
454
|
-
appKeys,
|
|
455
|
-
api,
|
|
456
|
-
manifest: (await getResolvedManifest()) ?? { apps: {} },
|
|
457
|
-
}),
|
|
458
|
-
updateManifestEntry,
|
|
459
|
-
},
|
|
460
|
-
};
|
|
461
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { ResolvedAppLocator } from "../../utils/domain-utils";
|
|
3
|
-
import type { AppItem } from "../../types/domain";
|
|
4
|
-
|
|
5
|
-
export const DEFAULT_CONFIG_PATH = ".zapierrc" as const;
|
|
6
|
-
|
|
7
|
-
export type ManifestEntry = {
|
|
8
|
-
implementationName: string;
|
|
9
|
-
version?: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export type GetVersionedImplementationId = (
|
|
13
|
-
appKey: string,
|
|
14
|
-
) => Promise<string | null>;
|
|
15
|
-
|
|
16
|
-
export type GetImplementation = (appKey: string) => Promise<AppItem | null>;
|
|
17
|
-
|
|
18
|
-
export type Manifest = {
|
|
19
|
-
apps: Record<string, ManifestEntry>;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type ResolveAppKeys = ({
|
|
23
|
-
appKeys,
|
|
24
|
-
}: {
|
|
25
|
-
appKeys: string[];
|
|
26
|
-
}) => Promise<ResolvedAppLocator[]>;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Manifest schema for version locking
|
|
30
|
-
* Maps app keys to their locked version information
|
|
31
|
-
*/
|
|
32
|
-
export const ManifestSchema = z
|
|
33
|
-
.object({
|
|
34
|
-
apps: z.record(
|
|
35
|
-
z.string(),
|
|
36
|
-
z.object({
|
|
37
|
-
implementationName: z
|
|
38
|
-
.string()
|
|
39
|
-
.describe(
|
|
40
|
-
"Base implementation name without version (e.g., 'SlackCLIAPI')",
|
|
41
|
-
),
|
|
42
|
-
version: z.string().describe("Version string (e.g., '1.21.1')"),
|
|
43
|
-
}),
|
|
44
|
-
),
|
|
45
|
-
})
|
|
46
|
-
.describe("Manifest mapping app keys to version information");
|
|
47
|
-
|
|
48
|
-
export const ManifestPluginOptionsSchema = z.object({
|
|
49
|
-
manifestPath: z.string().optional().describe("Path to manifest file"),
|
|
50
|
-
manifest: z
|
|
51
|
-
.record(
|
|
52
|
-
z.string(),
|
|
53
|
-
z.object({
|
|
54
|
-
implementationName: z.string(),
|
|
55
|
-
version: z.string().optional(),
|
|
56
|
-
}),
|
|
57
|
-
)
|
|
58
|
-
.optional()
|
|
59
|
-
.describe("Direct manifest object"),
|
|
60
|
-
});
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from "../../types/plugin";
|
|
2
|
-
import type { FunctionRegistryEntry } from "../../types/sdk";
|
|
3
|
-
|
|
4
|
-
export interface RegisterPluginFunctionOptions {}
|
|
5
|
-
|
|
6
|
-
export interface RegistryPluginProvides {
|
|
7
|
-
getRegistry: (options?: { package?: string }) => {
|
|
8
|
-
functions: FunctionRegistryEntry[];
|
|
9
|
-
categories: {
|
|
10
|
-
key: string;
|
|
11
|
-
title: string;
|
|
12
|
-
titlePlural: string;
|
|
13
|
-
functions: string[];
|
|
14
|
-
}[];
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Registry plugin requires no context but collects SDK metadata
|
|
19
|
-
export const registryPlugin: Plugin<
|
|
20
|
-
{}, // accepts any SDK shape
|
|
21
|
-
{}, // requires no context
|
|
22
|
-
RegistryPluginProvides
|
|
23
|
-
> = ({ sdk, context }) => {
|
|
24
|
-
const metaKeys = Object.keys(context.meta || {});
|
|
25
|
-
|
|
26
|
-
const categoryDefinitions: Record<
|
|
27
|
-
string,
|
|
28
|
-
{ title: string; titlePlural?: string }
|
|
29
|
-
> = {
|
|
30
|
-
account: {
|
|
31
|
-
title: "Account",
|
|
32
|
-
},
|
|
33
|
-
app: {
|
|
34
|
-
title: "App",
|
|
35
|
-
titlePlural: "Apps",
|
|
36
|
-
},
|
|
37
|
-
authentication: {
|
|
38
|
-
title: "Authentication",
|
|
39
|
-
},
|
|
40
|
-
action: {
|
|
41
|
-
title: "Action",
|
|
42
|
-
},
|
|
43
|
-
http: {
|
|
44
|
-
title: "HTTP Request",
|
|
45
|
-
},
|
|
46
|
-
utility: {
|
|
47
|
-
title: "Utility",
|
|
48
|
-
titlePlural: "Utilities",
|
|
49
|
-
},
|
|
50
|
-
other: {
|
|
51
|
-
title: "Other",
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const functions = metaKeys
|
|
56
|
-
.filter((key) => {
|
|
57
|
-
const property = sdk[key as keyof typeof sdk];
|
|
58
|
-
if (typeof property === "function") {
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
const [rootKey] = key.split(".");
|
|
62
|
-
const rootProperty = sdk[rootKey as keyof typeof sdk];
|
|
63
|
-
if (typeof rootProperty === "object" && rootProperty !== null) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
})
|
|
68
|
-
.map((key) => {
|
|
69
|
-
const meta = context.meta[key];
|
|
70
|
-
return {
|
|
71
|
-
name: key,
|
|
72
|
-
type: meta.type,
|
|
73
|
-
itemType: meta.itemType,
|
|
74
|
-
returnType: meta.returnType,
|
|
75
|
-
inputSchema: meta.inputSchema,
|
|
76
|
-
inputParameters: meta.inputParameters,
|
|
77
|
-
outputSchema: meta.outputSchema,
|
|
78
|
-
categories: meta.categories || [],
|
|
79
|
-
resolvers: meta.resolvers,
|
|
80
|
-
packages: meta.packages,
|
|
81
|
-
};
|
|
82
|
-
})
|
|
83
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
84
|
-
|
|
85
|
-
const knownCategories = Object.keys(categoryDefinitions);
|
|
86
|
-
|
|
87
|
-
// Cache the entire registry result for each package
|
|
88
|
-
const registryCache = new Map<
|
|
89
|
-
string,
|
|
90
|
-
{ functions: FunctionRegistryEntry[]; categories: any[] }
|
|
91
|
-
>();
|
|
92
|
-
|
|
93
|
-
function getRegistry(options?: { package?: string }) {
|
|
94
|
-
const packageFilter = options?.package;
|
|
95
|
-
const cacheKey = packageFilter || "__all__";
|
|
96
|
-
|
|
97
|
-
// Return cached result if available
|
|
98
|
-
if (registryCache.has(cacheKey)) {
|
|
99
|
-
return registryCache.get(cacheKey)!;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Filter functions by package if specified
|
|
103
|
-
const filteredFunctions = packageFilter
|
|
104
|
-
? functions.filter(
|
|
105
|
-
(f) =>
|
|
106
|
-
// Include if packages is undefined (belongs to all packages) or includes the specified package
|
|
107
|
-
!f.packages || f.packages.includes(packageFilter),
|
|
108
|
-
)
|
|
109
|
-
: functions;
|
|
110
|
-
|
|
111
|
-
// Build categories with filtered functions
|
|
112
|
-
const filteredCategories = knownCategories
|
|
113
|
-
.sort((a, b) => {
|
|
114
|
-
// Keep "other" category last
|
|
115
|
-
if (a === "other") return 1;
|
|
116
|
-
if (b === "other") return -1;
|
|
117
|
-
// Alphabetize by title, not key
|
|
118
|
-
const titleA = categoryDefinitions[a].title;
|
|
119
|
-
const titleB = categoryDefinitions[b].title;
|
|
120
|
-
return titleA.localeCompare(titleB);
|
|
121
|
-
})
|
|
122
|
-
.map((categoryKey) => {
|
|
123
|
-
// Find the functions that are in this category and match the package filter
|
|
124
|
-
const categoryFunctions = filteredFunctions
|
|
125
|
-
.filter(
|
|
126
|
-
(f) =>
|
|
127
|
-
f.categories.includes(categoryKey) ||
|
|
128
|
-
// If the category is "other" and the function is not in any other category, include it
|
|
129
|
-
(categoryKey === "other" &&
|
|
130
|
-
!f.categories.some((c) => knownCategories.includes(c))),
|
|
131
|
-
)
|
|
132
|
-
.map((f) => f.name)
|
|
133
|
-
.sort(); // Alphabetize functions within each category
|
|
134
|
-
|
|
135
|
-
const definition = categoryDefinitions[categoryKey];
|
|
136
|
-
const title = definition.title;
|
|
137
|
-
return {
|
|
138
|
-
key: categoryKey,
|
|
139
|
-
title,
|
|
140
|
-
titlePlural: definition.titlePlural ?? `${title}s`,
|
|
141
|
-
functions: categoryFunctions,
|
|
142
|
-
};
|
|
143
|
-
})
|
|
144
|
-
.filter((category) => category.functions.length > 0); // Only include categories with functions
|
|
145
|
-
|
|
146
|
-
const result = {
|
|
147
|
-
functions: filteredFunctions,
|
|
148
|
-
categories: filteredCategories,
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
// Cache the result
|
|
152
|
-
registryCache.set(cacheKey, result);
|
|
153
|
-
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
getRegistry,
|
|
159
|
-
};
|
|
160
|
-
};
|