@zapier/zapier-sdk 0.15.1 → 0.15.3
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 +12 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.integration.test.d.ts +5 -0
- package/dist/api/client.integration.test.d.ts.map +1 -0
- package/dist/api/client.integration.test.js +318 -0
- package/dist/api/client.js +31 -1
- package/dist/index.cjs +401 -108
- package/dist/index.d.mts +360 -56
- package/dist/index.mjs +401 -108
- package/dist/plugins/fetch/schemas.d.ts +2 -2
- package/dist/plugins/getAction/schemas.d.ts +2 -2
- package/dist/plugins/getApp/index.test.js +17 -21
- package/dist/plugins/getInputFieldsSchema/schemas.d.ts +2 -2
- package/dist/plugins/listActions/index.test.js +25 -0
- package/dist/plugins/listActions/schemas.d.ts +6 -6
- package/dist/plugins/listApps/index.d.ts +1 -3
- package/dist/plugins/listApps/index.d.ts.map +1 -1
- package/dist/plugins/listApps/index.js +18 -44
- package/dist/plugins/listApps/index.test.js +89 -288
- package/dist/plugins/listApps/schemas.d.ts +19 -26
- package/dist/plugins/listApps/schemas.d.ts.map +1 -1
- package/dist/plugins/listApps/schemas.js +19 -18
- package/dist/plugins/listAuthentications/index.test.js +20 -0
- 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/manifest/index.d.ts +42 -3
- package/dist/plugins/manifest/index.d.ts.map +1 -1
- package/dist/plugins/manifest/index.js +68 -1
- package/dist/plugins/manifest/index.test.js +513 -1
- package/dist/plugins/manifest/schemas.d.ts +75 -2
- package/dist/plugins/manifest/schemas.d.ts.map +1 -1
- package/dist/plugins/manifest/schemas.js +27 -3
- package/dist/plugins/request/schemas.d.ts +4 -4
- package/dist/plugins/runAction/schemas.d.ts +8 -8
- package/dist/sdk.d.ts +24 -2
- package/dist/sdk.d.ts.map +1 -1
- package/dist/temporary-internal-core/handlers/listApps.d.ts +67 -0
- package/dist/temporary-internal-core/handlers/listApps.d.ts.map +1 -0
- package/dist/temporary-internal-core/handlers/listApps.js +121 -0
- package/dist/temporary-internal-core/handlers/listApps.test.d.ts +2 -0
- package/dist/temporary-internal-core/handlers/listApps.test.d.ts.map +1 -0
- package/dist/temporary-internal-core/handlers/listApps.test.js +328 -0
- package/dist/temporary-internal-core/index.d.ts +4 -0
- package/dist/temporary-internal-core/index.d.ts.map +1 -1
- package/dist/temporary-internal-core/index.js +5 -1
- package/dist/temporary-internal-core/schemas/apps/index.d.ts +582 -0
- package/dist/temporary-internal-core/schemas/apps/index.d.ts.map +1 -0
- package/dist/temporary-internal-core/schemas/apps/index.js +95 -0
- package/dist/temporary-internal-core/schemas/implementations/index.d.ts +511 -0
- package/dist/temporary-internal-core/schemas/implementations/index.d.ts.map +1 -0
- package/dist/temporary-internal-core/schemas/implementations/index.js +79 -0
- package/dist/temporary-internal-core/types/handler.d.ts +51 -0
- package/dist/temporary-internal-core/types/handler.d.ts.map +1 -0
- package/dist/temporary-internal-core/types/handler.js +8 -0
- package/dist/temporary-internal-core/types/index.d.ts +5 -0
- package/dist/temporary-internal-core/types/index.d.ts.map +1 -0
- package/dist/temporary-internal-core/types/index.js +4 -0
- package/dist/temporary-internal-core/utils/app-locators.d.ts +54 -0
- package/dist/temporary-internal-core/utils/app-locators.d.ts.map +1 -0
- package/dist/temporary-internal-core/utils/app-locators.js +83 -0
- package/dist/temporary-internal-core/utils/transformations.d.ts +18 -0
- package/dist/temporary-internal-core/utils/transformations.d.ts.map +1 -0
- package/dist/temporary-internal-core/utils/transformations.js +36 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GetVersionedImplementationId, Manifest, ManifestEntry, ManifestPluginOptionsSchema, ResolveAppKeys } from "./schemas";
|
|
1
|
+
import type { GetVersionedImplementationId, Manifest, ManifestEntry, ManifestPluginOptionsSchema, ResolveAppKeys, ActionEntry } from "./schemas";
|
|
2
2
|
import type { Plugin } from "../../types/plugin";
|
|
3
3
|
import type { z } from "zod";
|
|
4
4
|
import type { ApiClient } from "../../api";
|
|
@@ -10,11 +10,50 @@ export interface UpdateManifestEntryOptions {
|
|
|
10
10
|
skipWrite?: boolean;
|
|
11
11
|
manifest?: Manifest;
|
|
12
12
|
}
|
|
13
|
+
export interface UpdateManifestEntryResult {
|
|
14
|
+
key: string;
|
|
15
|
+
entry: ManifestEntry;
|
|
16
|
+
manifest: Manifest;
|
|
17
|
+
}
|
|
18
|
+
export interface AddActionEntryOptions {
|
|
19
|
+
name: string;
|
|
20
|
+
entry: ActionEntry;
|
|
21
|
+
configPath?: string;
|
|
22
|
+
skipWrite?: boolean;
|
|
23
|
+
manifest?: Manifest;
|
|
24
|
+
}
|
|
25
|
+
export interface AddActionEntryResult {
|
|
26
|
+
name: string;
|
|
27
|
+
entry: ActionEntry;
|
|
28
|
+
manifest: Manifest;
|
|
29
|
+
}
|
|
13
30
|
export interface ManifestPluginProvides {
|
|
14
31
|
context: {
|
|
15
32
|
getVersionedImplementationId: GetVersionedImplementationId;
|
|
16
33
|
resolveAppKeys: ResolveAppKeys;
|
|
17
|
-
updateManifestEntry: (options: UpdateManifestEntryOptions) => Promise<
|
|
34
|
+
updateManifestEntry: (options: UpdateManifestEntryOptions) => Promise<UpdateManifestEntryResult>;
|
|
35
|
+
addActionEntry: (options: AddActionEntryOptions) => Promise<AddActionEntryResult>;
|
|
36
|
+
findActionEntry: (options: {
|
|
37
|
+
name: string;
|
|
38
|
+
manifest: Manifest;
|
|
39
|
+
}) => ActionEntry | null;
|
|
40
|
+
listActionEntries: (options?: {
|
|
41
|
+
configPath?: string;
|
|
42
|
+
}) => Promise<Array<[string, ActionEntry]>>;
|
|
43
|
+
deleteActionEntry: (options: {
|
|
44
|
+
name: string;
|
|
45
|
+
configPath?: string;
|
|
46
|
+
skipWrite?: boolean;
|
|
47
|
+
}) => Promise<Manifest>;
|
|
48
|
+
hasActionEntry: (options: {
|
|
49
|
+
name: string;
|
|
50
|
+
manifest: Manifest;
|
|
51
|
+
}) => boolean;
|
|
52
|
+
findManifestEntry: (options: {
|
|
53
|
+
appKey: string;
|
|
54
|
+
manifest: Manifest;
|
|
55
|
+
}) => [string, ManifestEntry] | null;
|
|
56
|
+
readManifestFromFile: (filePath: string) => Promise<Manifest | null>;
|
|
18
57
|
};
|
|
19
58
|
}
|
|
20
59
|
/**
|
|
@@ -38,7 +77,7 @@ export declare function findManifestEntry({ appKey, manifest, }: {
|
|
|
38
77
|
manifest: Manifest;
|
|
39
78
|
}): [string, ManifestEntry] | null;
|
|
40
79
|
export { DEFAULT_CONFIG_PATH } from "./schemas";
|
|
41
|
-
export type { ManifestEntry, Manifest } from "./schemas";
|
|
80
|
+
export type { ManifestEntry, Manifest, ActionEntry } from "./schemas";
|
|
42
81
|
export declare const manifestPlugin: Plugin<{}, // no SDK dependencies
|
|
43
82
|
{
|
|
44
83
|
api: ApiClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/manifest/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,4BAA4B,EAC5B,QAAQ,EACR,aAAa,EACb,2BAA2B,EAC3B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/manifest/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -293,7 +293,67 @@ export const manifestPlugin = (params) => {
|
|
|
293
293
|
// Clear the cached manifest so it gets reloaded with the new data
|
|
294
294
|
resolvedManifest = undefined;
|
|
295
295
|
}
|
|
296
|
-
return
|
|
296
|
+
return {
|
|
297
|
+
key: manifestKey,
|
|
298
|
+
entry,
|
|
299
|
+
manifest: updatedManifest,
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
const addActionEntry = async (options) => {
|
|
303
|
+
const { name, entry, configPath = DEFAULT_CONFIG_PATH, skipWrite = false, manifest: inputManifest, } = options;
|
|
304
|
+
// Use provided manifest or read from file
|
|
305
|
+
const manifest = inputManifest ||
|
|
306
|
+
(await readManifestFromFile(configPath)) || { apps: {} };
|
|
307
|
+
// Ensure actions exists
|
|
308
|
+
const actions = manifest.actions || {};
|
|
309
|
+
// Validate uniqueness - if action with this name already exists, throw error
|
|
310
|
+
if (actions[name] && !skipWrite) {
|
|
311
|
+
throw new Error(`Action "${name}" already exists. Please choose a different name or remove the existing action first.`);
|
|
312
|
+
}
|
|
313
|
+
const updatedManifest = {
|
|
314
|
+
...manifest,
|
|
315
|
+
actions: {
|
|
316
|
+
...actions,
|
|
317
|
+
[name]: entry,
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
// Conditionally write to file
|
|
321
|
+
if (!skipWrite) {
|
|
322
|
+
await writeManifestToFile(updatedManifest, configPath);
|
|
323
|
+
// Clear the cached manifest so it gets reloaded with the new data
|
|
324
|
+
resolvedManifest = undefined;
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
name,
|
|
328
|
+
entry,
|
|
329
|
+
manifest: updatedManifest,
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
const findActionEntry = ({ name, manifest, }) => {
|
|
333
|
+
return manifest.actions?.[name] || null;
|
|
334
|
+
};
|
|
335
|
+
const listActionEntries = async ({ configPath = DEFAULT_CONFIG_PATH, } = {}) => {
|
|
336
|
+
const manifest = (await readManifestFromFile(configPath)) || { apps: {} };
|
|
337
|
+
return Object.entries(manifest.actions || {});
|
|
338
|
+
};
|
|
339
|
+
const deleteActionEntry = async ({ name, configPath = DEFAULT_CONFIG_PATH, skipWrite = false, }) => {
|
|
340
|
+
const manifest = (await readManifestFromFile(configPath)) || { apps: {} };
|
|
341
|
+
if (!manifest.actions?.[name]) {
|
|
342
|
+
throw new Error(`Action "${name}" does not exist.`);
|
|
343
|
+
}
|
|
344
|
+
const { [name]: removed, ...remainingActions } = manifest.actions;
|
|
345
|
+
const updatedManifest = {
|
|
346
|
+
...manifest,
|
|
347
|
+
actions: remainingActions,
|
|
348
|
+
};
|
|
349
|
+
if (!skipWrite) {
|
|
350
|
+
await writeManifestToFile(updatedManifest, configPath);
|
|
351
|
+
resolvedManifest = undefined;
|
|
352
|
+
}
|
|
353
|
+
return updatedManifest;
|
|
354
|
+
};
|
|
355
|
+
const hasActionEntry = ({ name, manifest, }) => {
|
|
356
|
+
return !!manifest.actions?.[name];
|
|
297
357
|
};
|
|
298
358
|
return {
|
|
299
359
|
context: {
|
|
@@ -304,6 +364,13 @@ export const manifestPlugin = (params) => {
|
|
|
304
364
|
manifest: (await getResolvedManifest()) ?? { apps: {} },
|
|
305
365
|
}),
|
|
306
366
|
updateManifestEntry,
|
|
367
|
+
addActionEntry,
|
|
368
|
+
findActionEntry,
|
|
369
|
+
listActionEntries,
|
|
370
|
+
deleteActionEntry,
|
|
371
|
+
hasActionEntry,
|
|
372
|
+
findManifestEntry,
|
|
373
|
+
readManifestFromFile,
|
|
307
374
|
},
|
|
308
375
|
};
|
|
309
376
|
};
|
|
@@ -379,7 +379,7 @@ describe("manifestPlugin", () => {
|
|
|
379
379
|
const sdk = createTestSdk();
|
|
380
380
|
const context = sdk.getContext();
|
|
381
381
|
// This should now find the existing "SlackCLIAPI" entry
|
|
382
|
-
const
|
|
382
|
+
const { key: manifestKey } = await context.updateManifestEntry({
|
|
383
383
|
appKey: "slack", // Input is slug
|
|
384
384
|
entry: { implementationName: "SlackCLIAPI", version: "1.30.0" },
|
|
385
385
|
});
|
|
@@ -615,4 +615,516 @@ describe("readManifestFromFile", () => {
|
|
|
615
615
|
expect(result).toBe("some-random-key");
|
|
616
616
|
});
|
|
617
617
|
});
|
|
618
|
+
describe("Action management", () => {
|
|
619
|
+
const mockManifest = {
|
|
620
|
+
apps: {
|
|
621
|
+
slack: {
|
|
622
|
+
implementationName: "SlackCLIAPI",
|
|
623
|
+
version: "1.21.1",
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
};
|
|
627
|
+
let mockApiClient;
|
|
628
|
+
beforeEach(() => {
|
|
629
|
+
vi.clearAllMocks();
|
|
630
|
+
vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
631
|
+
mockApiClient = {
|
|
632
|
+
get: vi.fn(),
|
|
633
|
+
};
|
|
634
|
+
});
|
|
635
|
+
afterEach(() => {
|
|
636
|
+
vi.restoreAllMocks();
|
|
637
|
+
});
|
|
638
|
+
const apiPlugin = () => ({
|
|
639
|
+
context: {
|
|
640
|
+
api: mockApiClient,
|
|
641
|
+
},
|
|
642
|
+
});
|
|
643
|
+
function createTestSdk(options = {}) {
|
|
644
|
+
return createSdk(options).addPlugin(apiPlugin).addPlugin(manifestPlugin);
|
|
645
|
+
}
|
|
646
|
+
describe("findActionEntry", () => {
|
|
647
|
+
it("should find an existing action by name", () => {
|
|
648
|
+
const manifest = {
|
|
649
|
+
apps: mockManifest.apps,
|
|
650
|
+
actions: {
|
|
651
|
+
"weekly-report": {
|
|
652
|
+
appKey: "slack",
|
|
653
|
+
actionKey: "post_message",
|
|
654
|
+
actionType: "write",
|
|
655
|
+
authenticationId: 123,
|
|
656
|
+
inputs: { channel: "#general" },
|
|
657
|
+
schema: {},
|
|
658
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
};
|
|
662
|
+
const sdk = createTestSdk({ manifest });
|
|
663
|
+
const context = sdk.getContext();
|
|
664
|
+
const action = context.findActionEntry({
|
|
665
|
+
name: "weekly-report",
|
|
666
|
+
manifest,
|
|
667
|
+
});
|
|
668
|
+
expect(action).toEqual({
|
|
669
|
+
appKey: "slack",
|
|
670
|
+
actionKey: "post_message",
|
|
671
|
+
actionType: "write",
|
|
672
|
+
authenticationId: 123,
|
|
673
|
+
inputs: { channel: "#general" },
|
|
674
|
+
schema: {},
|
|
675
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
it("should return null for non-existent action", () => {
|
|
679
|
+
const manifest = {
|
|
680
|
+
apps: mockManifest.apps,
|
|
681
|
+
actions: {},
|
|
682
|
+
};
|
|
683
|
+
const sdk = createTestSdk({ manifest });
|
|
684
|
+
const context = sdk.getContext();
|
|
685
|
+
const action = context.findActionEntry({
|
|
686
|
+
name: "non-existent",
|
|
687
|
+
manifest,
|
|
688
|
+
});
|
|
689
|
+
expect(action).toBeNull();
|
|
690
|
+
});
|
|
691
|
+
it("should return null when manifest has no actions section", () => {
|
|
692
|
+
const manifest = {
|
|
693
|
+
apps: mockManifest.apps,
|
|
694
|
+
};
|
|
695
|
+
const sdk = createTestSdk({ manifest });
|
|
696
|
+
const context = sdk.getContext();
|
|
697
|
+
const action = context.findActionEntry({
|
|
698
|
+
name: "any-action",
|
|
699
|
+
manifest,
|
|
700
|
+
});
|
|
701
|
+
expect(action).toBeNull();
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
describe("hasActionEntry", () => {
|
|
705
|
+
it("should return true for existing action", () => {
|
|
706
|
+
const manifest = {
|
|
707
|
+
apps: mockManifest.apps,
|
|
708
|
+
actions: {
|
|
709
|
+
"weekly-report": {
|
|
710
|
+
appKey: "slack",
|
|
711
|
+
actionKey: "post_message",
|
|
712
|
+
actionType: "write",
|
|
713
|
+
authenticationId: 123,
|
|
714
|
+
inputs: {},
|
|
715
|
+
schema: {},
|
|
716
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
};
|
|
720
|
+
const sdk = createTestSdk({ manifest });
|
|
721
|
+
const context = sdk.getContext();
|
|
722
|
+
const exists = context.hasActionEntry({
|
|
723
|
+
name: "weekly-report",
|
|
724
|
+
manifest,
|
|
725
|
+
});
|
|
726
|
+
expect(exists).toBe(true);
|
|
727
|
+
});
|
|
728
|
+
it("should return false for non-existent action", () => {
|
|
729
|
+
const manifest = {
|
|
730
|
+
apps: mockManifest.apps,
|
|
731
|
+
actions: {},
|
|
732
|
+
};
|
|
733
|
+
const sdk = createTestSdk({ manifest });
|
|
734
|
+
const context = sdk.getContext();
|
|
735
|
+
const exists = context.hasActionEntry({
|
|
736
|
+
name: "non-existent",
|
|
737
|
+
manifest,
|
|
738
|
+
});
|
|
739
|
+
expect(exists).toBe(false);
|
|
740
|
+
});
|
|
741
|
+
it("should return false when manifest has no actions section", () => {
|
|
742
|
+
const manifest = {
|
|
743
|
+
apps: mockManifest.apps,
|
|
744
|
+
};
|
|
745
|
+
const sdk = createTestSdk({ manifest });
|
|
746
|
+
const context = sdk.getContext();
|
|
747
|
+
const exists = context.hasActionEntry({ name: "any-action", manifest });
|
|
748
|
+
expect(exists).toBe(false);
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
describe("listActionEntries", () => {
|
|
752
|
+
it("should return all actions as [name, entry] tuples", async () => {
|
|
753
|
+
const mockManifestContent = JSON.stringify({
|
|
754
|
+
apps: mockManifest.apps,
|
|
755
|
+
actions: {
|
|
756
|
+
"weekly-report": {
|
|
757
|
+
appKey: "slack",
|
|
758
|
+
actionKey: "post_message",
|
|
759
|
+
actionType: "write",
|
|
760
|
+
authenticationId: 123,
|
|
761
|
+
inputs: { channel: "#general" },
|
|
762
|
+
schema: {},
|
|
763
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
764
|
+
},
|
|
765
|
+
"daily-summary": {
|
|
766
|
+
appKey: "slack",
|
|
767
|
+
actionKey: "post_message",
|
|
768
|
+
actionType: "write",
|
|
769
|
+
authenticationId: 123,
|
|
770
|
+
inputs: { channel: "#daily" },
|
|
771
|
+
schema: {},
|
|
772
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
773
|
+
},
|
|
774
|
+
},
|
|
775
|
+
});
|
|
776
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
777
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
778
|
+
const context = sdk.getContext();
|
|
779
|
+
const actions = await context.listActionEntries({
|
|
780
|
+
configPath: ".zapierrc",
|
|
781
|
+
});
|
|
782
|
+
expect(actions).toHaveLength(2);
|
|
783
|
+
expect(actions).toEqual([
|
|
784
|
+
[
|
|
785
|
+
"weekly-report",
|
|
786
|
+
{
|
|
787
|
+
appKey: "slack",
|
|
788
|
+
actionKey: "post_message",
|
|
789
|
+
actionType: "write",
|
|
790
|
+
authenticationId: 123,
|
|
791
|
+
inputs: { channel: "#general" },
|
|
792
|
+
schema: {},
|
|
793
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
794
|
+
},
|
|
795
|
+
],
|
|
796
|
+
[
|
|
797
|
+
"daily-summary",
|
|
798
|
+
{
|
|
799
|
+
appKey: "slack",
|
|
800
|
+
actionKey: "post_message",
|
|
801
|
+
actionType: "write",
|
|
802
|
+
authenticationId: 123,
|
|
803
|
+
inputs: { channel: "#daily" },
|
|
804
|
+
schema: {},
|
|
805
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
806
|
+
},
|
|
807
|
+
],
|
|
808
|
+
]);
|
|
809
|
+
});
|
|
810
|
+
it("should return empty array when no actions exist", async () => {
|
|
811
|
+
const mockManifestContent = JSON.stringify({
|
|
812
|
+
apps: mockManifest.apps,
|
|
813
|
+
});
|
|
814
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
815
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
816
|
+
const context = sdk.getContext();
|
|
817
|
+
const actions = await context.listActionEntries({
|
|
818
|
+
configPath: ".zapierrc",
|
|
819
|
+
});
|
|
820
|
+
expect(actions).toEqual([]);
|
|
821
|
+
});
|
|
822
|
+
it("should use default configPath when not provided", async () => {
|
|
823
|
+
const mockManifestContent = JSON.stringify({
|
|
824
|
+
apps: mockManifest.apps,
|
|
825
|
+
actions: {},
|
|
826
|
+
});
|
|
827
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
828
|
+
const sdk = createTestSdk();
|
|
829
|
+
const context = sdk.getContext();
|
|
830
|
+
await context.listActionEntries();
|
|
831
|
+
expect(mockResolve).toHaveBeenCalledWith(".zapierrc");
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
describe("addActionEntry", () => {
|
|
835
|
+
it("should successfully add a new action", async () => {
|
|
836
|
+
const mockManifestContent = JSON.stringify({
|
|
837
|
+
apps: mockManifest.apps,
|
|
838
|
+
});
|
|
839
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
840
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
841
|
+
const context = sdk.getContext();
|
|
842
|
+
const entry = {
|
|
843
|
+
appKey: "slack",
|
|
844
|
+
actionKey: "post_message",
|
|
845
|
+
actionType: "write",
|
|
846
|
+
authenticationId: 123,
|
|
847
|
+
inputs: { channel: "#general" },
|
|
848
|
+
schema: { type: "object" },
|
|
849
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
850
|
+
};
|
|
851
|
+
const { name, entry: returnedEntry, manifest: updatedManifest, } = await context.addActionEntry({
|
|
852
|
+
name: "weekly-report",
|
|
853
|
+
entry,
|
|
854
|
+
configPath: ".zapierrc",
|
|
855
|
+
});
|
|
856
|
+
expect(name).toBe("weekly-report");
|
|
857
|
+
expect(returnedEntry).toEqual(entry);
|
|
858
|
+
expect(updatedManifest.actions).toEqual({
|
|
859
|
+
"weekly-report": entry,
|
|
860
|
+
});
|
|
861
|
+
});
|
|
862
|
+
it("should throw error when action name already exists", async () => {
|
|
863
|
+
const mockManifestContent = JSON.stringify({
|
|
864
|
+
apps: mockManifest.apps,
|
|
865
|
+
actions: {
|
|
866
|
+
"weekly-report": {
|
|
867
|
+
appKey: "slack",
|
|
868
|
+
actionKey: "post_message",
|
|
869
|
+
actionType: "write",
|
|
870
|
+
authenticationId: 123,
|
|
871
|
+
inputs: {},
|
|
872
|
+
schema: {},
|
|
873
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
874
|
+
},
|
|
875
|
+
},
|
|
876
|
+
});
|
|
877
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
878
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
879
|
+
const context = sdk.getContext();
|
|
880
|
+
const entry = {
|
|
881
|
+
appKey: "slack",
|
|
882
|
+
actionKey: "post_message",
|
|
883
|
+
actionType: "write",
|
|
884
|
+
authenticationId: 123,
|
|
885
|
+
inputs: {},
|
|
886
|
+
schema: {},
|
|
887
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
888
|
+
};
|
|
889
|
+
await expect(context.addActionEntry({
|
|
890
|
+
name: "weekly-report",
|
|
891
|
+
entry,
|
|
892
|
+
configPath: ".zapierrc",
|
|
893
|
+
})).rejects.toThrow('Action "weekly-report" already exists. Please choose a different name or remove the existing action first.');
|
|
894
|
+
});
|
|
895
|
+
it("should allow duplicate name with skipWrite option", async () => {
|
|
896
|
+
const mockManifestContent = JSON.stringify({
|
|
897
|
+
apps: mockManifest.apps,
|
|
898
|
+
actions: {
|
|
899
|
+
"weekly-report": {
|
|
900
|
+
appKey: "slack",
|
|
901
|
+
actionKey: "post_message",
|
|
902
|
+
actionType: "write",
|
|
903
|
+
authenticationId: 123,
|
|
904
|
+
inputs: {},
|
|
905
|
+
schema: {},
|
|
906
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
});
|
|
910
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
911
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
912
|
+
const context = sdk.getContext();
|
|
913
|
+
const entry = {
|
|
914
|
+
appKey: "slack",
|
|
915
|
+
actionKey: "post_message",
|
|
916
|
+
actionType: "write",
|
|
917
|
+
authenticationId: 456,
|
|
918
|
+
inputs: {},
|
|
919
|
+
schema: {},
|
|
920
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
921
|
+
};
|
|
922
|
+
const { name, entry: returnedEntry } = await context.addActionEntry({
|
|
923
|
+
name: "weekly-report",
|
|
924
|
+
entry,
|
|
925
|
+
configPath: ".zapierrc",
|
|
926
|
+
skipWrite: true,
|
|
927
|
+
});
|
|
928
|
+
expect(name).toBe("weekly-report");
|
|
929
|
+
expect(returnedEntry).toEqual(entry);
|
|
930
|
+
});
|
|
931
|
+
it("should create actions section if it doesn't exist", async () => {
|
|
932
|
+
const mockManifestContent = JSON.stringify({
|
|
933
|
+
apps: mockManifest.apps,
|
|
934
|
+
});
|
|
935
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
936
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
937
|
+
const context = sdk.getContext();
|
|
938
|
+
const entry = {
|
|
939
|
+
appKey: "slack",
|
|
940
|
+
actionKey: "post_message",
|
|
941
|
+
actionType: "write",
|
|
942
|
+
authenticationId: 123,
|
|
943
|
+
inputs: {},
|
|
944
|
+
schema: {},
|
|
945
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
946
|
+
};
|
|
947
|
+
const { manifest: updatedManifest } = await context.addActionEntry({
|
|
948
|
+
name: "first-action",
|
|
949
|
+
entry,
|
|
950
|
+
configPath: ".zapierrc",
|
|
951
|
+
});
|
|
952
|
+
expect(updatedManifest.actions).toBeDefined();
|
|
953
|
+
expect(updatedManifest.actions).toEqual({
|
|
954
|
+
"first-action": entry,
|
|
955
|
+
});
|
|
956
|
+
});
|
|
957
|
+
});
|
|
958
|
+
describe("deleteActionEntry", () => {
|
|
959
|
+
it("should successfully delete an existing action", async () => {
|
|
960
|
+
const mockManifestContent = JSON.stringify({
|
|
961
|
+
apps: mockManifest.apps,
|
|
962
|
+
actions: {
|
|
963
|
+
"weekly-report": {
|
|
964
|
+
appKey: "slack",
|
|
965
|
+
actionKey: "post_message",
|
|
966
|
+
actionType: "write",
|
|
967
|
+
authenticationId: 123,
|
|
968
|
+
inputs: {},
|
|
969
|
+
schema: {},
|
|
970
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
971
|
+
},
|
|
972
|
+
"daily-summary": {
|
|
973
|
+
appKey: "slack",
|
|
974
|
+
actionKey: "post_message",
|
|
975
|
+
actionType: "write",
|
|
976
|
+
authenticationId: 123,
|
|
977
|
+
inputs: {},
|
|
978
|
+
schema: {},
|
|
979
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
});
|
|
983
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
984
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
985
|
+
const context = sdk.getContext();
|
|
986
|
+
const updatedManifest = await context.deleteActionEntry({
|
|
987
|
+
name: "weekly-report",
|
|
988
|
+
configPath: ".zapierrc",
|
|
989
|
+
});
|
|
990
|
+
expect(updatedManifest.actions).toEqual({
|
|
991
|
+
"daily-summary": {
|
|
992
|
+
appKey: "slack",
|
|
993
|
+
actionKey: "post_message",
|
|
994
|
+
actionType: "write",
|
|
995
|
+
authenticationId: 123,
|
|
996
|
+
inputs: {},
|
|
997
|
+
schema: {},
|
|
998
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
999
|
+
},
|
|
1000
|
+
});
|
|
1001
|
+
expect(updatedManifest.actions?.["weekly-report"]).toBeUndefined();
|
|
1002
|
+
});
|
|
1003
|
+
it("should throw error when action does not exist", async () => {
|
|
1004
|
+
const mockManifestContent = JSON.stringify({
|
|
1005
|
+
apps: mockManifest.apps,
|
|
1006
|
+
actions: {},
|
|
1007
|
+
});
|
|
1008
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
1009
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
1010
|
+
const context = sdk.getContext();
|
|
1011
|
+
await expect(context.deleteActionEntry({
|
|
1012
|
+
name: "non-existent",
|
|
1013
|
+
configPath: ".zapierrc",
|
|
1014
|
+
})).rejects.toThrow('Action "non-existent" does not exist.');
|
|
1015
|
+
});
|
|
1016
|
+
it("should work with skipWrite option", async () => {
|
|
1017
|
+
const mockManifestContent = JSON.stringify({
|
|
1018
|
+
apps: mockManifest.apps,
|
|
1019
|
+
actions: {
|
|
1020
|
+
"weekly-report": {
|
|
1021
|
+
appKey: "slack",
|
|
1022
|
+
actionKey: "post_message",
|
|
1023
|
+
actionType: "write",
|
|
1024
|
+
authenticationId: 123,
|
|
1025
|
+
inputs: {},
|
|
1026
|
+
schema: {},
|
|
1027
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
1028
|
+
},
|
|
1029
|
+
},
|
|
1030
|
+
});
|
|
1031
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
1032
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
1033
|
+
const context = sdk.getContext();
|
|
1034
|
+
const updatedManifest = await context.deleteActionEntry({
|
|
1035
|
+
name: "weekly-report",
|
|
1036
|
+
configPath: ".zapierrc",
|
|
1037
|
+
skipWrite: true,
|
|
1038
|
+
});
|
|
1039
|
+
expect(updatedManifest.actions).toEqual({});
|
|
1040
|
+
});
|
|
1041
|
+
it("should handle deleting the last action", async () => {
|
|
1042
|
+
const mockManifestContent = JSON.stringify({
|
|
1043
|
+
apps: mockManifest.apps,
|
|
1044
|
+
actions: {
|
|
1045
|
+
"only-action": {
|
|
1046
|
+
appKey: "slack",
|
|
1047
|
+
actionKey: "post_message",
|
|
1048
|
+
actionType: "write",
|
|
1049
|
+
authenticationId: 123,
|
|
1050
|
+
inputs: {},
|
|
1051
|
+
schema: {},
|
|
1052
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
1053
|
+
},
|
|
1054
|
+
},
|
|
1055
|
+
});
|
|
1056
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
1057
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
1058
|
+
const context = sdk.getContext();
|
|
1059
|
+
const updatedManifest = await context.deleteActionEntry({
|
|
1060
|
+
name: "only-action",
|
|
1061
|
+
configPath: ".zapierrc",
|
|
1062
|
+
});
|
|
1063
|
+
expect(updatedManifest.actions).toEqual({});
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
describe("action CRUD integration", () => {
|
|
1067
|
+
it("should support full CRUD workflow", async () => {
|
|
1068
|
+
const mockManifestContent = JSON.stringify({
|
|
1069
|
+
apps: mockManifest.apps,
|
|
1070
|
+
});
|
|
1071
|
+
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
1072
|
+
const sdk = createTestSdk({ manifestPath: ".zapierrc" });
|
|
1073
|
+
const context = sdk.getContext();
|
|
1074
|
+
// Create first action
|
|
1075
|
+
const entry1 = {
|
|
1076
|
+
appKey: "slack",
|
|
1077
|
+
actionKey: "post_message",
|
|
1078
|
+
actionType: "write",
|
|
1079
|
+
authenticationId: 123,
|
|
1080
|
+
inputs: { channel: "#general" },
|
|
1081
|
+
schema: {},
|
|
1082
|
+
createdAt: "2025-11-18T12:00:00.000Z",
|
|
1083
|
+
};
|
|
1084
|
+
const { manifest: manifest1 } = await context.addActionEntry({
|
|
1085
|
+
name: "action-1",
|
|
1086
|
+
entry: entry1,
|
|
1087
|
+
skipWrite: true,
|
|
1088
|
+
});
|
|
1089
|
+
// Create second action
|
|
1090
|
+
const entry2 = {
|
|
1091
|
+
appKey: "slack",
|
|
1092
|
+
actionKey: "post_message",
|
|
1093
|
+
actionType: "write",
|
|
1094
|
+
authenticationId: 123,
|
|
1095
|
+
inputs: { channel: "#daily" },
|
|
1096
|
+
schema: {},
|
|
1097
|
+
createdAt: "2025-11-18T13:00:00.000Z",
|
|
1098
|
+
};
|
|
1099
|
+
const { manifest: manifest2 } = await context.addActionEntry({
|
|
1100
|
+
name: "action-2",
|
|
1101
|
+
entry: entry2,
|
|
1102
|
+
manifest: manifest1,
|
|
1103
|
+
skipWrite: true,
|
|
1104
|
+
});
|
|
1105
|
+
// Verify both actions exist
|
|
1106
|
+
expect(context.hasActionEntry({ name: "action-1", manifest: manifest2 })).toBe(true);
|
|
1107
|
+
expect(context.hasActionEntry({ name: "action-2", manifest: manifest2 })).toBe(true);
|
|
1108
|
+
// Find action
|
|
1109
|
+
const foundAction = context.findActionEntry({
|
|
1110
|
+
name: "action-1",
|
|
1111
|
+
manifest: manifest2,
|
|
1112
|
+
});
|
|
1113
|
+
expect(foundAction).toEqual(entry1);
|
|
1114
|
+
// List actions
|
|
1115
|
+
mockReadFile.mockResolvedValue(JSON.stringify(manifest2));
|
|
1116
|
+
const actions = await context.listActionEntries({
|
|
1117
|
+
configPath: ".zapierrc",
|
|
1118
|
+
});
|
|
1119
|
+
expect(actions).toHaveLength(2);
|
|
1120
|
+
// Delete action
|
|
1121
|
+
const manifest3 = await context.deleteActionEntry({
|
|
1122
|
+
name: "action-1",
|
|
1123
|
+
skipWrite: true,
|
|
1124
|
+
});
|
|
1125
|
+
expect(context.hasActionEntry({ name: "action-1", manifest: manifest3 })).toBe(false);
|
|
1126
|
+
expect(context.hasActionEntry({ name: "action-2", manifest: manifest3 })).toBe(true);
|
|
1127
|
+
});
|
|
1128
|
+
});
|
|
1129
|
+
});
|
|
618
1130
|
});
|