@zapier/zapier-sdk 0.5.2 → 0.6.1
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 +17 -0
- package/README.md +107 -83
- package/dist/index.cjs +320 -50
- package/dist/index.d.mts +409 -340
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.mjs +320 -50
- package/dist/plugins/api/index.js +1 -1
- package/dist/plugins/findFirstAuthentication/index.d.ts.map +1 -1
- package/dist/plugins/findFirstAuthentication/index.js +1 -0
- package/dist/plugins/findUniqueAuthentication/index.d.ts.map +1 -1
- package/dist/plugins/findUniqueAuthentication/index.js +1 -0
- package/dist/plugins/getAction/index.d.ts.map +1 -1
- package/dist/plugins/getAction/index.js +1 -0
- package/dist/plugins/getAction/index.test.js +1 -1
- package/dist/plugins/getApp/index.d.ts +6 -3
- package/dist/plugins/getApp/index.d.ts.map +1 -1
- package/dist/plugins/getApp/index.js +8 -18
- package/dist/plugins/getApp/index.test.js +2 -0
- package/dist/plugins/getAuthentication/index.d.ts.map +1 -1
- package/dist/plugins/getAuthentication/index.js +1 -0
- package/dist/plugins/getAuthentication/index.test.js +12 -1
- package/dist/plugins/getProfile/index.d.ts.map +1 -1
- package/dist/plugins/getProfile/index.js +1 -0
- package/dist/plugins/listActions/index.d.ts +5 -3
- package/dist/plugins/listActions/index.d.ts.map +1 -1
- package/dist/plugins/listActions/index.js +6 -6
- package/dist/plugins/listActions/index.test.js +26 -74
- package/dist/plugins/listActions/schemas.d.ts +4 -4
- package/dist/plugins/listApps/index.d.ts.map +1 -1
- package/dist/plugins/listApps/index.js +1 -0
- package/dist/plugins/listApps/schemas.d.ts +2 -2
- package/dist/plugins/listAuthentications/index.d.ts +4 -2
- package/dist/plugins/listAuthentications/index.d.ts.map +1 -1
- package/dist/plugins/listAuthentications/index.js +9 -12
- package/dist/plugins/listAuthentications/index.test.js +33 -40
- package/dist/plugins/listAuthentications/schemas.d.ts +4 -4
- package/dist/plugins/listInputFields/index.d.ts +3 -1
- package/dist/plugins/listInputFields/index.d.ts.map +1 -1
- package/dist/plugins/listInputFields/index.js +5 -5
- package/dist/plugins/listInputFields/index.test.js +10 -8
- package/dist/plugins/listInputFields/schemas.d.ts +4 -4
- package/dist/plugins/lockVersion/index.d.ts +24 -0
- package/dist/plugins/lockVersion/index.d.ts.map +1 -0
- package/dist/plugins/lockVersion/index.js +72 -0
- package/dist/plugins/lockVersion/index.test.d.ts +2 -0
- package/dist/plugins/lockVersion/index.test.d.ts.map +1 -0
- package/dist/plugins/lockVersion/index.test.js +129 -0
- package/dist/plugins/lockVersion/schemas.d.ts +10 -0
- package/dist/plugins/lockVersion/schemas.d.ts.map +1 -0
- package/dist/plugins/lockVersion/schemas.js +6 -0
- package/dist/plugins/manifest/index.d.ts +24 -0
- package/dist/plugins/manifest/index.d.ts.map +1 -0
- package/dist/plugins/manifest/index.js +119 -0
- package/dist/plugins/manifest/index.test.d.ts +2 -0
- package/dist/plugins/manifest/index.test.d.ts.map +1 -0
- package/dist/plugins/manifest/index.test.js +331 -0
- package/dist/plugins/manifest/schemas.d.ts +64 -0
- package/dist/plugins/manifest/schemas.d.ts.map +1 -0
- package/dist/plugins/manifest/schemas.js +25 -0
- package/dist/plugins/registry/index.d.ts +9 -1
- package/dist/plugins/registry/index.d.ts.map +1 -1
- package/dist/plugins/registry/index.js +68 -3
- package/dist/plugins/request/index.d.ts.map +1 -1
- package/dist/plugins/request/index.js +1 -0
- package/dist/plugins/request/index.test.js +6 -1
- package/dist/plugins/request/schemas.d.ts +4 -4
- package/dist/plugins/runAction/index.d.ts +2 -0
- package/dist/plugins/runAction/index.d.ts.map +1 -1
- package/dist/plugins/runAction/index.js +5 -5
- package/dist/plugins/runAction/index.test.js +9 -8
- package/dist/plugins/runAction/schemas.d.ts +4 -4
- package/dist/sdk.d.ts +3 -3
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +18 -7
- package/dist/sdk.test.js +1 -1
- package/dist/types/plugin.d.ts +10 -2
- package/dist/types/plugin.d.ts.map +1 -1
- package/dist/types/sdk.d.ts +13 -2
- package/dist/types/sdk.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +0 -2
- package/src/plugins/api/index.ts +1 -1
- package/src/plugins/findFirstAuthentication/index.ts +1 -0
- package/src/plugins/findUniqueAuthentication/index.ts +1 -0
- package/src/plugins/getAction/index.test.ts +1 -1
- package/src/plugins/getAction/index.ts +1 -0
- package/src/plugins/getApp/index.test.ts +2 -0
- package/src/plugins/getApp/index.ts +12 -24
- package/src/plugins/getAuthentication/index.test.ts +13 -3
- package/src/plugins/getAuthentication/index.ts +1 -0
- package/src/plugins/getProfile/index.ts +1 -0
- package/src/plugins/listActions/index.test.ts +30 -89
- package/src/plugins/listActions/index.ts +13 -9
- package/src/plugins/listApps/index.ts +1 -0
- package/src/plugins/listAuthentications/index.test.ts +38 -47
- package/src/plugins/listAuthentications/index.ts +21 -18
- package/src/plugins/listInputFields/index.test.ts +12 -9
- package/src/plugins/listInputFields/index.ts +10 -6
- package/src/plugins/lockVersion/index.test.ts +176 -0
- package/src/plugins/lockVersion/index.ts +112 -0
- package/src/plugins/lockVersion/schemas.ts +9 -0
- package/src/plugins/manifest/index.test.ts +438 -0
- package/src/plugins/manifest/index.ts +171 -0
- package/src/plugins/manifest/schemas.ts +53 -0
- package/src/plugins/registry/index.ts +89 -8
- package/src/plugins/request/index.test.ts +8 -4
- package/src/plugins/request/index.ts +1 -0
- package/src/plugins/runAction/index.test.ts +9 -8
- package/src/plugins/runAction/index.ts +13 -7
- package/src/sdk.test.ts +1 -1
- package/src/sdk.ts +22 -7
- package/src/types/plugin.ts +14 -2
- package/src/types/sdk.ts +15 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
ZapierAuthenticationError,
|
|
13
13
|
} from "../../types/errors";
|
|
14
14
|
import { createPaginatedFunction } from "../../utils/function-utils";
|
|
15
|
-
import
|
|
15
|
+
import { ManifestPluginProvides } from "../manifest";
|
|
16
|
+
import { GetVersionedImplementationId } from "../manifest/schemas";
|
|
16
17
|
|
|
17
18
|
export interface ListActionsPluginProvides {
|
|
18
19
|
listActions: (options?: ListActionsOptions) => Promise<{
|
|
@@ -31,20 +32,22 @@ export interface ListActionsPluginProvides {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export const listActionsPlugin: Plugin<
|
|
34
|
-
GetSdkType<
|
|
35
|
-
{
|
|
35
|
+
GetSdkType<ManifestPluginProvides>, // requires getApp in SDK
|
|
36
|
+
{
|
|
37
|
+
api: ApiClient;
|
|
38
|
+
getVersionedImplementationId: GetVersionedImplementationId;
|
|
39
|
+
}, // requires api and getVersionedImplementationId in context
|
|
36
40
|
ListActionsPluginProvides
|
|
37
|
-
> = ({
|
|
41
|
+
> = ({ context }) => {
|
|
38
42
|
const listActions = createPaginatedFunction(async function listActionsPage(
|
|
39
43
|
options: ListActionsOptions & { cursor?: string } & { pageSize: number },
|
|
40
44
|
): Promise<ListActionsPage> {
|
|
41
|
-
const { api } = context;
|
|
45
|
+
const { api, getVersionedImplementationId } = context;
|
|
42
46
|
|
|
43
47
|
// Use the getApp function from the SDK (dependency injection)
|
|
44
|
-
const
|
|
48
|
+
const selectedApi = await getVersionedImplementationId(options.appKey);
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
if (!implementationId) {
|
|
50
|
+
if (!selectedApi) {
|
|
48
51
|
throw new ZapierConfigurationError(
|
|
49
52
|
"No current_implementation_id found for app",
|
|
50
53
|
{ configType: "current_implementation_id" },
|
|
@@ -54,7 +57,7 @@ export const listActionsPlugin: Plugin<
|
|
|
54
57
|
const searchParams: Record<string, string> = {
|
|
55
58
|
global: "true",
|
|
56
59
|
public_only: "true",
|
|
57
|
-
selected_apis:
|
|
60
|
+
selected_apis: selectedApi,
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
const data = await api.get<{ results: Implementation[] }>(
|
|
@@ -110,6 +113,7 @@ export const listActionsPlugin: Plugin<
|
|
|
110
113
|
context: {
|
|
111
114
|
meta: {
|
|
112
115
|
listActions: {
|
|
116
|
+
categories: ["action"],
|
|
113
117
|
inputSchema: ListActionsSchema,
|
|
114
118
|
},
|
|
115
119
|
},
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import { listAuthenticationsPlugin } from "./index";
|
|
7
7
|
import { createSdk } from "../../sdk";
|
|
8
8
|
import type { ApiClient } from "../../api";
|
|
9
|
-
import type {
|
|
9
|
+
import type { AppItem } from "../../types/domain";
|
|
10
10
|
|
|
11
11
|
const mockAuthenticationsResponse = {
|
|
12
12
|
results: [
|
|
@@ -42,29 +42,18 @@ const mockAuthenticationsResponse = {
|
|
|
42
42
|
previous: null,
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
const mockSlackApp = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
api_docs_url: "https://slack.com/api-docs",
|
|
53
|
-
app_profile_url: "https://slack.com",
|
|
54
|
-
banner: "https://slack.com/banner.png",
|
|
55
|
-
categories: [],
|
|
56
|
-
canonical_id: "slack",
|
|
57
|
-
zap_usage_count: 100,
|
|
58
|
-
zap_usage_count_last_updated: "2021-01-01",
|
|
59
|
-
zap_usage_count_last_updated_by: "user1",
|
|
60
|
-
zap_usage_count_last_updated_by_id: 123,
|
|
61
|
-
current_implementation_id: "SlackCLIAPI@1.21.1",
|
|
62
|
-
} as Partial<App> as App,
|
|
45
|
+
const mockSlackApp: AppItem = {
|
|
46
|
+
title: "Slack",
|
|
47
|
+
key: "SlackCLIAPI",
|
|
48
|
+
current_implementation_id: "SlackCLIAPI@1.21.1",
|
|
49
|
+
version: "1.21.1",
|
|
50
|
+
description: "Team communication platform",
|
|
51
|
+
slug: "slack",
|
|
63
52
|
};
|
|
64
53
|
|
|
65
54
|
describe("listAuthentications plugin", () => {
|
|
66
55
|
let mockApiClient: ApiClient;
|
|
67
|
-
let
|
|
56
|
+
let mockGetVersionedImplementationId: any;
|
|
68
57
|
|
|
69
58
|
beforeEach(() => {
|
|
70
59
|
vi.clearAllMocks();
|
|
@@ -72,14 +61,34 @@ describe("listAuthentications plugin", () => {
|
|
|
72
61
|
get: vi.fn().mockResolvedValue(mockAuthenticationsResponse),
|
|
73
62
|
} as Partial<ApiClient> as ApiClient;
|
|
74
63
|
|
|
75
|
-
|
|
64
|
+
mockGetVersionedImplementationId = vi
|
|
65
|
+
.fn()
|
|
66
|
+
.mockResolvedValue("SlackCLIAPI@1.21.1");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const apiPlugin = () => ({
|
|
70
|
+
context: {
|
|
71
|
+
api: mockApiClient,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const manifestPlugin = () => ({
|
|
76
|
+
context: {
|
|
77
|
+
manifest: null,
|
|
78
|
+
getVersionedImplementationId: mockGetVersionedImplementationId,
|
|
79
|
+
getManifestEntry: () => ({
|
|
80
|
+
implementationName: "SlackCLIAPI",
|
|
81
|
+
version: "1.21.1",
|
|
82
|
+
}),
|
|
83
|
+
getImplementation: vi.fn().mockResolvedValue(mockSlackApp),
|
|
84
|
+
},
|
|
76
85
|
});
|
|
77
86
|
|
|
78
87
|
function createTestSdk() {
|
|
79
|
-
return createSdk(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
return createSdk()
|
|
89
|
+
.addPlugin(apiPlugin)
|
|
90
|
+
.addPlugin(manifestPlugin)
|
|
91
|
+
.addPlugin(listAuthenticationsPlugin);
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
describe("schema validation", () => {
|
|
@@ -129,7 +138,7 @@ describe("listAuthentications plugin", () => {
|
|
|
129
138
|
const sdk = createTestSdk();
|
|
130
139
|
expect(() => {
|
|
131
140
|
sdk.listAuthentications({
|
|
132
|
-
account_id: 123,
|
|
141
|
+
account_id: 123 as any,
|
|
133
142
|
});
|
|
134
143
|
}).toThrow(ZapierValidationError);
|
|
135
144
|
});
|
|
@@ -192,7 +201,7 @@ describe("listAuthentications plugin", () => {
|
|
|
192
201
|
describe("data mapping", () => {
|
|
193
202
|
it("should map is_stale to is_expired and marked_stale_at to expired_at", async () => {
|
|
194
203
|
const sdk = createTestSdk();
|
|
195
|
-
const result = await sdk.listAuthentications(
|
|
204
|
+
const result = await sdk.listAuthentications();
|
|
196
205
|
|
|
197
206
|
expect(result.data[0].is_expired).toBe("false");
|
|
198
207
|
expect(result.data[0].expired_at).toBe(null);
|
|
@@ -582,16 +591,7 @@ describe("listAuthentications plugin", () => {
|
|
|
582
591
|
|
|
583
592
|
describe("app key integration", () => {
|
|
584
593
|
it("should handle app without current_implementation_id", async () => {
|
|
585
|
-
|
|
586
|
-
data: {
|
|
587
|
-
id: 123,
|
|
588
|
-
key: "slack",
|
|
589
|
-
title: "Slack",
|
|
590
|
-
current_implementation_id: undefined,
|
|
591
|
-
} as Partial<App> as App,
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
mockGetApp.mockResolvedValue(appWithoutImplementation);
|
|
594
|
+
mockGetVersionedImplementationId.mockResolvedValue(null);
|
|
595
595
|
|
|
596
596
|
const sdk = createTestSdk();
|
|
597
597
|
await sdk.listAuthentications({ appKey: "slack" });
|
|
@@ -608,16 +608,7 @@ describe("listAuthentications plugin", () => {
|
|
|
608
608
|
});
|
|
609
609
|
|
|
610
610
|
it("should extract versionless API from versioned implementation ID", async () => {
|
|
611
|
-
|
|
612
|
-
data: {
|
|
613
|
-
id: 123,
|
|
614
|
-
key: "slack",
|
|
615
|
-
title: "Slack",
|
|
616
|
-
current_implementation_id: "SlackCLIAPI@2.1.3",
|
|
617
|
-
} as Partial<App> as App,
|
|
618
|
-
};
|
|
619
|
-
|
|
620
|
-
mockGetApp.mockResolvedValue(appWithVersionedApi);
|
|
611
|
+
mockGetVersionedImplementationId.mockResolvedValue("SlackCLIAPI@2.1.3");
|
|
621
612
|
|
|
622
613
|
const sdk = createTestSdk();
|
|
623
614
|
await sdk.listAuthentications({ appKey: "slack" });
|
|
@@ -7,13 +7,17 @@ import {
|
|
|
7
7
|
type ListAuthenticationsOptions,
|
|
8
8
|
type ListAuthenticationsPage,
|
|
9
9
|
} from "./schemas";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
normalizeAuthenticationItem,
|
|
12
|
+
splitVersionedKey,
|
|
13
|
+
} from "../../utils/domain-utils";
|
|
11
14
|
import { ZapierAuthenticationError } from "../../types/errors";
|
|
12
15
|
import {
|
|
13
16
|
createPaginatedFunction,
|
|
14
17
|
extractCursor,
|
|
15
18
|
} from "../../utils/function-utils";
|
|
16
|
-
import
|
|
19
|
+
import { GetVersionedImplementationId } from "../manifest/schemas";
|
|
20
|
+
import { ManifestPluginProvides } from "../manifest";
|
|
17
21
|
|
|
18
22
|
export interface ListAuthenticationsPluginProvides {
|
|
19
23
|
listAuthentications: (options?: ListAuthenticationsOptions) => Promise<{
|
|
@@ -32,33 +36,31 @@ export interface ListAuthenticationsPluginProvides {
|
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
export const listAuthenticationsPlugin: Plugin<
|
|
35
|
-
GetSdkType<
|
|
36
|
-
{
|
|
39
|
+
GetSdkType<ManifestPluginProvides>, // requires getApp in SDK
|
|
40
|
+
{
|
|
41
|
+
api: ApiClient;
|
|
42
|
+
getVersionedImplementationId: GetVersionedImplementationId;
|
|
43
|
+
}, // requires api in context
|
|
37
44
|
ListAuthenticationsPluginProvides
|
|
38
|
-
> = ({
|
|
45
|
+
> = ({ context }) => {
|
|
39
46
|
const listAuthentications = createPaginatedFunction(
|
|
40
47
|
async function listAuthenticationsPage(
|
|
41
48
|
options: ListAuthenticationsOptions & { cursor?: string } & {
|
|
42
49
|
pageSize: number;
|
|
43
50
|
},
|
|
44
51
|
): Promise<ListAuthenticationsPage> {
|
|
45
|
-
const { api } = context;
|
|
46
|
-
|
|
52
|
+
const { api, getVersionedImplementationId } = context;
|
|
47
53
|
// Build search parameters
|
|
48
54
|
const searchParams: Record<string, string> = {};
|
|
49
55
|
|
|
50
56
|
// Handle appKey filtering by getting the selected_api first
|
|
51
57
|
if (options.appKey) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Use versionless_selected_api to find auths across all app versions
|
|
59
|
-
// Extract the base name without the version (e.g., "SlackCLIAPI" from "SlackCLIAPI@1.21.1")
|
|
60
|
-
const versionlessApi = selectedApi.split("@")[0];
|
|
61
|
-
searchParams.versionless_selected_api = versionlessApi;
|
|
58
|
+
const implementationId = await getVersionedImplementationId(
|
|
59
|
+
options.appKey,
|
|
60
|
+
);
|
|
61
|
+
if (implementationId) {
|
|
62
|
+
const [versionlessSelectedApi] = splitVersionedKey(implementationId);
|
|
63
|
+
searchParams.versionless_selected_api = versionlessSelectedApi;
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -81,7 +83,7 @@ export const listAuthenticationsPlugin: Plugin<
|
|
|
81
83
|
// Convert cursor back to offset for the API
|
|
82
84
|
searchParams.offset = options.cursor;
|
|
83
85
|
}
|
|
84
|
-
|
|
86
|
+
console.log({ searchParams });
|
|
85
87
|
const data: AuthenticationsResponse = await api.get(
|
|
86
88
|
"/api/v4/authentications/",
|
|
87
89
|
{
|
|
@@ -128,6 +130,7 @@ export const listAuthenticationsPlugin: Plugin<
|
|
|
128
130
|
context: {
|
|
129
131
|
meta: {
|
|
130
132
|
listAuthentications: {
|
|
133
|
+
categories: ["authentication"],
|
|
131
134
|
inputSchema: ListAuthenticationsSchema,
|
|
132
135
|
},
|
|
133
136
|
},
|
|
@@ -47,7 +47,7 @@ const mockNeedsResponse: NeedsResponse = {
|
|
|
47
47
|
|
|
48
48
|
describe("listInputFields plugin", () => {
|
|
49
49
|
let mockApiClient: ApiClient;
|
|
50
|
-
let
|
|
50
|
+
let mockGetVersionedImplementationId: any;
|
|
51
51
|
|
|
52
52
|
beforeEach(() => {
|
|
53
53
|
vi.clearAllMocks();
|
|
@@ -55,15 +55,20 @@ describe("listInputFields plugin", () => {
|
|
|
55
55
|
post: vi.fn().mockResolvedValue(mockNeedsResponse),
|
|
56
56
|
} as Partial<ApiClient> as ApiClient;
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
mockGetVersionedImplementationId = vi
|
|
59
|
+
.fn()
|
|
60
|
+
.mockResolvedValue("SlackCLIAPI@1.21.1");
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
function createTestSdk() {
|
|
64
64
|
return createSdk(
|
|
65
|
-
{
|
|
66
|
-
{
|
|
65
|
+
{},
|
|
66
|
+
{},
|
|
67
|
+
{
|
|
68
|
+
api: mockApiClient,
|
|
69
|
+
meta: {},
|
|
70
|
+
getVersionedImplementationId: mockGetVersionedImplementationId,
|
|
71
|
+
},
|
|
67
72
|
).addPlugin(listInputFieldsPlugin as any);
|
|
68
73
|
}
|
|
69
74
|
|
|
@@ -303,9 +308,7 @@ describe("listInputFields plugin", () => {
|
|
|
303
308
|
|
|
304
309
|
describe("error handling", () => {
|
|
305
310
|
it("should throw ZapierConfigurationError when app has no current_implementation_id", async () => {
|
|
306
|
-
|
|
307
|
-
data: { current_implementation_id: undefined },
|
|
308
|
-
});
|
|
311
|
+
mockGetVersionedImplementationId.mockResolvedValue(null);
|
|
309
312
|
|
|
310
313
|
const sdk = createTestSdk();
|
|
311
314
|
await expect(
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { ZapierConfigurationError, ZapierApiError } from "../../types/errors";
|
|
11
11
|
import { createPaginatedFunction } from "../../utils/function-utils";
|
|
12
12
|
import type { GetAppPluginProvides } from "../getApp";
|
|
13
|
+
import { GetVersionedImplementationId } from "../manifest/schemas";
|
|
13
14
|
|
|
14
15
|
// Enums for input field transformation
|
|
15
16
|
enum InputFieldType {
|
|
@@ -125,9 +126,12 @@ export interface ListInputFieldsPluginProvides {
|
|
|
125
126
|
|
|
126
127
|
export const listInputFieldsPlugin: Plugin<
|
|
127
128
|
GetSdkType<GetAppPluginProvides>, // requires getApp in SDK
|
|
128
|
-
{
|
|
129
|
+
{
|
|
130
|
+
api: ApiClient;
|
|
131
|
+
getVersionedImplementationId: GetVersionedImplementationId;
|
|
132
|
+
}, // requires api and getVersionedImplementationId in context
|
|
129
133
|
ListInputFieldsPluginProvides
|
|
130
|
-
> = ({
|
|
134
|
+
> = ({ context }) => {
|
|
131
135
|
const listInputFields = createPaginatedFunction(
|
|
132
136
|
async function listInputFieldsPage(
|
|
133
137
|
options: ListInputFieldsOptions & { cursor?: string } & {
|
|
@@ -135,15 +139,14 @@ export const listInputFieldsPlugin: Plugin<
|
|
|
135
139
|
},
|
|
136
140
|
): Promise<ListInputFieldsPage> {
|
|
137
141
|
// Note: This function ignores pageSize and cursor since it's not actually paginated internally
|
|
138
|
-
const { api } = context;
|
|
142
|
+
const { api, getVersionedImplementationId } = context;
|
|
139
143
|
|
|
140
144
|
// Extract parameters
|
|
141
145
|
const { appKey, actionKey, actionType, authenticationId, inputs } =
|
|
142
146
|
options;
|
|
143
147
|
|
|
144
|
-
// Use the
|
|
145
|
-
const
|
|
146
|
-
const selectedApi = appData.data.current_implementation_id;
|
|
148
|
+
// Use the manifest plugin
|
|
149
|
+
const selectedApi = await getVersionedImplementationId(appKey);
|
|
147
150
|
|
|
148
151
|
if (!selectedApi) {
|
|
149
152
|
throw new ZapierConfigurationError(
|
|
@@ -196,6 +199,7 @@ export const listInputFieldsPlugin: Plugin<
|
|
|
196
199
|
context: {
|
|
197
200
|
meta: {
|
|
198
201
|
listInputFields: {
|
|
202
|
+
categories: ["action"],
|
|
199
203
|
inputSchema: ListInputFieldsSchema,
|
|
200
204
|
},
|
|
201
205
|
},
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { lockVersionPlugin } from "./index";
|
|
3
|
+
import { createSdk } from "../../sdk";
|
|
4
|
+
|
|
5
|
+
// Mock fs module
|
|
6
|
+
vi.mock("fs", () => ({
|
|
7
|
+
readFileSync: vi.fn(),
|
|
8
|
+
writeFileSync: vi.fn(),
|
|
9
|
+
existsSync: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
// Mock path module
|
|
13
|
+
vi.mock("path", () => ({
|
|
14
|
+
resolve: vi.fn((path) => `/resolved/${path}`),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
18
|
+
import { resolve } from "path";
|
|
19
|
+
import { apiPlugin } from "../api";
|
|
20
|
+
|
|
21
|
+
const mockReadFileSync = vi.mocked(readFileSync);
|
|
22
|
+
const mockWriteFileSync = vi.mocked(writeFileSync);
|
|
23
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
24
|
+
const mockResolve = vi.mocked(resolve);
|
|
25
|
+
|
|
26
|
+
describe("lockVersion plugin", () => {
|
|
27
|
+
let mockSdk: any;
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
vi.clearAllMocks();
|
|
31
|
+
|
|
32
|
+
mockSdk = {
|
|
33
|
+
listApps: vi.fn().mockReturnValue({
|
|
34
|
+
items: vi.fn().mockReturnValue(
|
|
35
|
+
[
|
|
36
|
+
{
|
|
37
|
+
title: "Gmail",
|
|
38
|
+
key: "GmailCLIAPI",
|
|
39
|
+
current_implementation_id: "GmailCLIAPI@2.1.0",
|
|
40
|
+
description: "Email service",
|
|
41
|
+
},
|
|
42
|
+
][Symbol.iterator](),
|
|
43
|
+
),
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const listAppsPlugin = () => ({
|
|
49
|
+
listApps: mockSdk.listApps,
|
|
50
|
+
context: {
|
|
51
|
+
meta: {
|
|
52
|
+
listApps: {
|
|
53
|
+
inputSchema: {} as any,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function createTestSdk() {
|
|
60
|
+
return createSdk()
|
|
61
|
+
.addPlugin(apiPlugin)
|
|
62
|
+
.addPlugin(listAppsPlugin)
|
|
63
|
+
.addPlugin(lockVersionPlugin);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
describe("version locking", () => {
|
|
67
|
+
it("should extract implementation name and version and write to file", async () => {
|
|
68
|
+
mockExistsSync.mockReturnValue(false);
|
|
69
|
+
mockResolve.mockReturnValue("/resolved/.zapierrc");
|
|
70
|
+
|
|
71
|
+
const sdk = createTestSdk();
|
|
72
|
+
const result = await sdk.lockVersion({ appKey: "gmail" });
|
|
73
|
+
|
|
74
|
+
expect((result.data as any).implementationName).toBe("GmailCLIAPI");
|
|
75
|
+
expect((result.data as any).version).toBe("2.1.0");
|
|
76
|
+
expect(result.data.current_implementation_id).toBe("GmailCLIAPI@2.1.0");
|
|
77
|
+
expect(result.configPath).toBe("/resolved/.zapierrc");
|
|
78
|
+
|
|
79
|
+
// Verify file was written
|
|
80
|
+
expect(mockWriteFileSync).toHaveBeenCalledWith(
|
|
81
|
+
"/resolved/.zapierrc",
|
|
82
|
+
JSON.stringify(
|
|
83
|
+
{
|
|
84
|
+
apps: {
|
|
85
|
+
gmail: {
|
|
86
|
+
implementationName: "GmailCLIAPI",
|
|
87
|
+
version: "2.1.0",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
null,
|
|
92
|
+
2,
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should update existing .zapierrc file", async () => {
|
|
98
|
+
const existingConfig = {
|
|
99
|
+
apps: {
|
|
100
|
+
slack: {
|
|
101
|
+
implementationName: "SlackCLIAPI",
|
|
102
|
+
version: "1.27.1",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
mockExistsSync.mockReturnValue(true);
|
|
108
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(existingConfig));
|
|
109
|
+
mockResolve.mockReturnValue("/resolved/.zapierrc");
|
|
110
|
+
|
|
111
|
+
const sdk = createTestSdk();
|
|
112
|
+
const result = await sdk.lockVersion({ appKey: "gmail" });
|
|
113
|
+
|
|
114
|
+
expect(mockReadFileSync).toHaveBeenCalledWith(
|
|
115
|
+
"/resolved/.zapierrc",
|
|
116
|
+
"utf8",
|
|
117
|
+
);
|
|
118
|
+
expect(result.configPath).toBe("/resolved/.zapierrc");
|
|
119
|
+
|
|
120
|
+
// Verify file was updated with both apps
|
|
121
|
+
expect(mockWriteFileSync).toHaveBeenCalledWith(
|
|
122
|
+
"/resolved/.zapierrc",
|
|
123
|
+
JSON.stringify(
|
|
124
|
+
{
|
|
125
|
+
apps: {
|
|
126
|
+
slack: {
|
|
127
|
+
implementationName: "SlackCLIAPI",
|
|
128
|
+
version: "1.27.1",
|
|
129
|
+
},
|
|
130
|
+
gmail: {
|
|
131
|
+
implementationName: "GmailCLIAPI",
|
|
132
|
+
version: "2.1.0",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
null,
|
|
137
|
+
2,
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should handle invalid implementation ID format", async () => {
|
|
143
|
+
mockSdk.listApps = vi.fn().mockReturnValue({
|
|
144
|
+
items: vi.fn().mockReturnValue(
|
|
145
|
+
[
|
|
146
|
+
{
|
|
147
|
+
title: "Invalid App",
|
|
148
|
+
key: "InvalidApp",
|
|
149
|
+
current_implementation_id: "InvalidFormat",
|
|
150
|
+
},
|
|
151
|
+
][Symbol.iterator](),
|
|
152
|
+
),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const sdk = createTestSdk();
|
|
156
|
+
|
|
157
|
+
await expect(sdk.lockVersion({ appKey: "invalid" })).rejects.toThrow(
|
|
158
|
+
"Invalid implementation ID format: InvalidFormat. Expected format: <implementationName>@<version>",
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should use custom config path when provided", async () => {
|
|
163
|
+
mockExistsSync.mockReturnValue(false);
|
|
164
|
+
mockResolve.mockReturnValue("/resolved/custom-config.json");
|
|
165
|
+
|
|
166
|
+
const sdk = createTestSdk();
|
|
167
|
+
const result = await sdk.lockVersion({
|
|
168
|
+
appKey: "gmail",
|
|
169
|
+
configPath: "custom-config.json",
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
expect(mockResolve).toHaveBeenCalledWith("custom-config.json");
|
|
173
|
+
expect(result.configPath).toBe("/resolved/custom-config.json");
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { Plugin, GetSdkType } from "../../types/plugin";
|
|
2
|
+
import { createFunction } from "../../utils/function-utils";
|
|
3
|
+
import { LockVersionSchema } from "./schemas";
|
|
4
|
+
import type { LockVersionOptions } from "./schemas";
|
|
5
|
+
import type { AppItem } from "../../types/domain";
|
|
6
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
7
|
+
import { resolve } from "path";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { ListAppsPluginProvides } from "../listApps";
|
|
10
|
+
|
|
11
|
+
export interface LockVersionPluginProvides {
|
|
12
|
+
lockVersion: (
|
|
13
|
+
options: LockVersionOptions & { configPath?: string },
|
|
14
|
+
) => Promise<{ data: AppItem; configPath: string }>;
|
|
15
|
+
context: {
|
|
16
|
+
meta: {
|
|
17
|
+
lockVersion: {
|
|
18
|
+
inputSchema: typeof LockVersionSchema;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const lockVersionPlugin: Plugin<
|
|
25
|
+
GetSdkType<ListAppsPluginProvides>, // requires getApp in SDK
|
|
26
|
+
{}, // requires manifest context
|
|
27
|
+
LockVersionPluginProvides
|
|
28
|
+
> = ({ sdk }) => {
|
|
29
|
+
const lockVersion = createFunction(
|
|
30
|
+
async function lockVersion(
|
|
31
|
+
options: LockVersionOptions & { configPath?: string },
|
|
32
|
+
) {
|
|
33
|
+
const { appKey, configPath = ".zapierrc" } = options;
|
|
34
|
+
const resolvedPath = resolve(configPath);
|
|
35
|
+
|
|
36
|
+
// Get the current app information
|
|
37
|
+
const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
|
|
38
|
+
const apps = [];
|
|
39
|
+
for await (const app of appsIterator) {
|
|
40
|
+
apps.push(app);
|
|
41
|
+
break; // Only need the first result
|
|
42
|
+
}
|
|
43
|
+
const app = apps[0];
|
|
44
|
+
|
|
45
|
+
// Extract implementation name and version from current_implementation_id
|
|
46
|
+
const currentImplementationId = app.current_implementation_id;
|
|
47
|
+
const [implementationName, version] = currentImplementationId.split("@");
|
|
48
|
+
|
|
49
|
+
if (!implementationName || !version) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Invalid implementation ID format: ${currentImplementationId}. Expected format: <implementationName>@<version>`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Read existing config or create new one
|
|
56
|
+
let config: { apps: Record<string, any> } = { apps: {} };
|
|
57
|
+
|
|
58
|
+
if (existsSync(resolvedPath)) {
|
|
59
|
+
try {
|
|
60
|
+
const configContent = readFileSync(resolvedPath, "utf8");
|
|
61
|
+
config = JSON.parse(configContent);
|
|
62
|
+
|
|
63
|
+
// Ensure apps property exists
|
|
64
|
+
if (!config.apps) {
|
|
65
|
+
config.apps = {};
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.warn(
|
|
69
|
+
`⚠️ Failed to parse existing config file, creating new one: ${error}`,
|
|
70
|
+
);
|
|
71
|
+
config = { apps: {} };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Update the apps section
|
|
76
|
+
config.apps[appKey] = {
|
|
77
|
+
implementationName,
|
|
78
|
+
version,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Write the updated config
|
|
82
|
+
writeFileSync(resolvedPath, JSON.stringify(config, null, 2));
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
data: {
|
|
86
|
+
...app,
|
|
87
|
+
implementationName,
|
|
88
|
+
version,
|
|
89
|
+
},
|
|
90
|
+
configPath: resolvedPath,
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
LockVersionSchema.extend({
|
|
94
|
+
configPath: z
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe("Path to .zapierrc file (defaults to '.zapierrc')"),
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
lockVersion,
|
|
103
|
+
context: {
|
|
104
|
+
meta: {
|
|
105
|
+
lockVersion: {
|
|
106
|
+
categories: ["utility"],
|
|
107
|
+
inputSchema: LockVersionSchema,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
};
|