@zapier/zapier-sdk 0.13.6 → 0.13.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/api/client.d.ts.map +1 -1
  3. package/dist/api/client.js +5 -5
  4. package/dist/api/client.test.d.ts +2 -0
  5. package/dist/api/client.test.d.ts.map +1 -0
  6. package/dist/api/client.test.js +80 -0
  7. package/dist/api/index.d.ts +1 -0
  8. package/dist/api/index.d.ts.map +1 -1
  9. package/dist/api/index.js +3 -1
  10. package/dist/api/schemas.d.ts +20 -20
  11. package/dist/api/types.d.ts +2 -0
  12. package/dist/api/types.d.ts.map +1 -1
  13. package/dist/auth.d.ts +3 -0
  14. package/dist/auth.d.ts.map +1 -1
  15. package/dist/auth.test.d.ts +2 -0
  16. package/dist/auth.test.d.ts.map +1 -0
  17. package/dist/auth.test.js +102 -0
  18. package/dist/constants.d.ts +4 -4
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +4 -4
  21. package/dist/index.cjs +89 -21
  22. package/dist/index.d.mts +21 -1
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -0
  26. package/dist/index.mjs +88 -22
  27. package/dist/plugins/api/index.d.ts.map +1 -1
  28. package/dist/plugins/api/index.js +4 -1
  29. package/dist/plugins/eventEmission/index.d.ts +2 -0
  30. package/dist/plugins/eventEmission/index.d.ts.map +1 -1
  31. package/dist/plugins/eventEmission/index.js +35 -9
  32. package/dist/plugins/eventEmission/index.test.js +100 -0
  33. package/dist/schemas/Action.d.ts +2 -2
  34. package/dist/schemas/Auth.d.ts +4 -4
  35. package/dist/schemas/Field.d.ts +10 -10
  36. package/dist/sdk.test.js +121 -1
  37. package/dist/types/sdk.d.ts +3 -0
  38. package/dist/types/sdk.d.ts.map +1 -1
  39. package/dist/utils/url-utils.d.ts +19 -0
  40. package/dist/utils/url-utils.d.ts.map +1 -0
  41. package/dist/utils/url-utils.js +62 -0
  42. package/dist/utils/url-utils.test.d.ts +2 -0
  43. package/dist/utils/url-utils.test.d.ts.map +1 -0
  44. package/dist/utils/url-utils.test.js +103 -0
  45. package/package.json +8 -3
  46. package/src/api/auth.ts +0 -28
  47. package/src/api/client.ts +0 -491
  48. package/src/api/debug.test.ts +0 -76
  49. package/src/api/debug.ts +0 -154
  50. package/src/api/index.ts +0 -90
  51. package/src/api/polling.test.ts +0 -405
  52. package/src/api/polling.ts +0 -253
  53. package/src/api/schemas.ts +0 -465
  54. package/src/api/types.ts +0 -152
  55. package/src/auth.ts +0 -72
  56. package/src/constants.ts +0 -16
  57. package/src/index.ts +0 -111
  58. package/src/plugins/api/index.ts +0 -43
  59. package/src/plugins/apps/index.ts +0 -203
  60. package/src/plugins/apps/schemas.ts +0 -64
  61. package/src/plugins/eventEmission/builders.ts +0 -115
  62. package/src/plugins/eventEmission/index.test.ts +0 -169
  63. package/src/plugins/eventEmission/index.ts +0 -294
  64. package/src/plugins/eventEmission/transport.test.ts +0 -214
  65. package/src/plugins/eventEmission/transport.ts +0 -135
  66. package/src/plugins/eventEmission/types.ts +0 -58
  67. package/src/plugins/eventEmission/utils.ts +0 -121
  68. package/src/plugins/fetch/index.ts +0 -83
  69. package/src/plugins/fetch/schemas.ts +0 -37
  70. package/src/plugins/findFirstAuthentication/index.test.ts +0 -209
  71. package/src/plugins/findFirstAuthentication/index.ts +0 -68
  72. package/src/plugins/findFirstAuthentication/schemas.ts +0 -47
  73. package/src/plugins/findUniqueAuthentication/index.test.ts +0 -197
  74. package/src/plugins/findUniqueAuthentication/index.ts +0 -77
  75. package/src/plugins/findUniqueAuthentication/schemas.ts +0 -49
  76. package/src/plugins/getAction/index.test.ts +0 -239
  77. package/src/plugins/getAction/index.ts +0 -75
  78. package/src/plugins/getAction/schemas.ts +0 -41
  79. package/src/plugins/getApp/index.test.ts +0 -181
  80. package/src/plugins/getApp/index.ts +0 -60
  81. package/src/plugins/getApp/schemas.ts +0 -33
  82. package/src/plugins/getAuthentication/index.test.ts +0 -294
  83. package/src/plugins/getAuthentication/index.ts +0 -95
  84. package/src/plugins/getAuthentication/schemas.ts +0 -38
  85. package/src/plugins/getProfile/index.ts +0 -60
  86. package/src/plugins/getProfile/schemas.ts +0 -24
  87. package/src/plugins/listActions/index.test.ts +0 -526
  88. package/src/plugins/listActions/index.ts +0 -132
  89. package/src/plugins/listActions/schemas.ts +0 -55
  90. package/src/plugins/listApps/index.test.ts +0 -378
  91. package/src/plugins/listApps/index.ts +0 -159
  92. package/src/plugins/listApps/schemas.ts +0 -41
  93. package/src/plugins/listAuthentications/index.test.ts +0 -739
  94. package/src/plugins/listAuthentications/index.ts +0 -152
  95. package/src/plugins/listAuthentications/schemas.ts +0 -77
  96. package/src/plugins/listInputFieldChoices/index.test.ts +0 -653
  97. package/src/plugins/listInputFieldChoices/index.ts +0 -173
  98. package/src/plugins/listInputFieldChoices/schemas.ts +0 -125
  99. package/src/plugins/listInputFields/index.test.ts +0 -439
  100. package/src/plugins/listInputFields/index.ts +0 -294
  101. package/src/plugins/listInputFields/schemas.ts +0 -68
  102. package/src/plugins/manifest/index.test.ts +0 -776
  103. package/src/plugins/manifest/index.ts +0 -461
  104. package/src/plugins/manifest/schemas.ts +0 -60
  105. package/src/plugins/registry/index.ts +0 -160
  106. package/src/plugins/request/index.test.ts +0 -333
  107. package/src/plugins/request/index.ts +0 -105
  108. package/src/plugins/request/schemas.ts +0 -69
  109. package/src/plugins/runAction/index.test.ts +0 -388
  110. package/src/plugins/runAction/index.ts +0 -215
  111. package/src/plugins/runAction/schemas.ts +0 -60
  112. package/src/resolvers/actionKey.ts +0 -37
  113. package/src/resolvers/actionType.ts +0 -34
  114. package/src/resolvers/appKey.ts +0 -7
  115. package/src/resolvers/authenticationId.ts +0 -54
  116. package/src/resolvers/index.ts +0 -11
  117. package/src/resolvers/inputFieldKey.ts +0 -70
  118. package/src/resolvers/inputs.ts +0 -69
  119. package/src/schemas/Action.ts +0 -52
  120. package/src/schemas/App.ts +0 -45
  121. package/src/schemas/Auth.ts +0 -59
  122. package/src/schemas/Field.ts +0 -169
  123. package/src/schemas/Run.ts +0 -40
  124. package/src/schemas/UserProfile.ts +0 -60
  125. package/src/sdk.test.ts +0 -212
  126. package/src/sdk.ts +0 -178
  127. package/src/types/domain.test.ts +0 -50
  128. package/src/types/domain.ts +0 -66
  129. package/src/types/errors.ts +0 -278
  130. package/src/types/events.ts +0 -43
  131. package/src/types/functions.ts +0 -28
  132. package/src/types/optional-zapier-sdk-cli-login.d.ts +0 -37
  133. package/src/types/plugin.ts +0 -125
  134. package/src/types/properties.ts +0 -80
  135. package/src/types/sdk.ts +0 -111
  136. package/src/types/telemetry-events.ts +0 -85
  137. package/src/utils/array-utils.test.ts +0 -131
  138. package/src/utils/array-utils.ts +0 -41
  139. package/src/utils/domain-utils.test.ts +0 -433
  140. package/src/utils/domain-utils.ts +0 -267
  141. package/src/utils/file-utils.test.ts +0 -73
  142. package/src/utils/file-utils.ts +0 -94
  143. package/src/utils/function-utils.test.ts +0 -141
  144. package/src/utils/function-utils.ts +0 -245
  145. package/src/utils/pagination-utils.test.ts +0 -620
  146. package/src/utils/pagination-utils.ts +0 -242
  147. package/src/utils/schema-utils.ts +0 -207
  148. package/src/utils/string-utils.test.ts +0 -45
  149. package/src/utils/string-utils.ts +0 -54
  150. package/src/utils/validation.test.ts +0 -51
  151. package/src/utils/validation.ts +0 -44
  152. package/tsconfig.build.json +0 -18
  153. package/tsconfig.json +0 -20
  154. package/tsconfig.tsbuildinfo +0 -1
  155. package/tsup.config.ts +0 -23
@@ -1,242 +0,0 @@
1
- const offsetCursorMarker = "$$offset$$";
2
-
3
- type TPageOptions<TOptions> = TOptions extends undefined
4
- ? { cursor?: string; maxItems?: number; pageSize?: number }
5
- : TOptions & { cursor?: string; maxItems?: number; pageSize?: number };
6
-
7
- function splitOffsetCursor(cursor?: string): [number, string | undefined] {
8
- if (!cursor) {
9
- return [0, cursor];
10
- }
11
-
12
- try {
13
- const parsedCursor = JSON.parse(cursor);
14
- if (!Array.isArray(parsedCursor)) {
15
- return [0, cursor];
16
- }
17
-
18
- const [marker, offset, currentCursor] = parsedCursor;
19
-
20
- if (marker !== offsetCursorMarker) {
21
- return [0, cursor];
22
- }
23
-
24
- if (typeof offset !== "number") {
25
- return [0, cursor];
26
- }
27
-
28
- return [offset, currentCursor];
29
- } catch {
30
- return [0, cursor];
31
- }
32
- }
33
-
34
- function createOffsetCursor(
35
- offset: number,
36
- currentCursor: string | undefined,
37
- ): string {
38
- return JSON.stringify([offsetCursorMarker, offset, currentCursor]);
39
- }
40
-
41
- export function createPrefixedCursor(
42
- prefix: string,
43
- cursor: string | undefined,
44
- ): string {
45
- if (!cursor) {
46
- return `${prefix}::`;
47
- }
48
- return `${prefix}::${cursor}`;
49
- }
50
-
51
- export function splitPrefixedCursor(
52
- cursor: string | undefined,
53
- prefixes?: string[],
54
- ): [string | undefined, string | undefined] {
55
- if (!cursor) {
56
- return [undefined, undefined];
57
- }
58
-
59
- const [prefix, ...rest] = cursor.split("::");
60
-
61
- if (prefixes && !prefixes.includes(prefix)) {
62
- return [undefined, cursor];
63
- }
64
-
65
- cursor = rest.join("::");
66
-
67
- if (!cursor) {
68
- return [prefix, undefined];
69
- }
70
-
71
- return [prefix, cursor];
72
- }
73
-
74
- /**
75
- * Utility for paginating through API endpoints that return cursor-based pages
76
- *
77
- * @param pageFunction - Function that fetches a single page with {data, nextCursor} structure
78
- * @param pageOptions - Options to pass to the page function (cursor will be managed automatically)
79
- * @returns Async iterator that yields pages
80
- */
81
- export async function* paginateMaxItems<
82
- TOptions,
83
- TPage extends { data: any[]; nextCursor?: string },
84
- >(
85
- pageFunction: (
86
- options: TOptions & {
87
- cursor?: string;
88
- maxItems?: number;
89
- pageSize?: number;
90
- },
91
- ) => Promise<TPage>,
92
- pageOptions?: TPageOptions<TOptions>,
93
- ): AsyncIterableIterator<TPage> {
94
- let cursor = pageOptions?.cursor;
95
- let totalItemsYielded = 0;
96
- const maxItems = pageOptions?.maxItems;
97
- const pageSize = pageOptions?.pageSize;
98
-
99
- do {
100
- const options = {
101
- ...(pageOptions || {}),
102
- cursor,
103
- pageSize:
104
- maxItems !== undefined && pageSize !== undefined
105
- ? Math.min(pageSize, maxItems)
106
- : pageSize,
107
- } as TOptions & { cursor?: string; maxItems?: number; pageSize?: number };
108
-
109
- const page = await pageFunction(options);
110
-
111
- if (maxItems !== undefined) {
112
- const remainingItems = maxItems - totalItemsYielded;
113
- if (page.data.length >= remainingItems) {
114
- const yieldedPage = {
115
- ...page,
116
- data: page.data.slice(0, remainingItems),
117
- nextCursor: undefined,
118
- };
119
- yield yieldedPage;
120
- break;
121
- }
122
- }
123
-
124
- yield page;
125
- totalItemsYielded += page.data.length;
126
-
127
- cursor = page.nextCursor;
128
- } while (cursor);
129
- }
130
-
131
- export async function* paginateBuffered<
132
- TOptions,
133
- TPage extends { data: any[]; nextCursor?: string },
134
- >(
135
- pageFunction: (
136
- options: TOptions & {
137
- cursor?: string;
138
- maxItems?: number;
139
- pageSize?: number;
140
- },
141
- ) => Promise<TPage>,
142
- pageOptions?: TPageOptions<TOptions>,
143
- ): AsyncIterableIterator<TPage> {
144
- const pageSize = pageOptions?.pageSize;
145
- const [cursorOffset, currentCursor] = splitOffsetCursor(pageOptions?.cursor);
146
- const options = {
147
- ...(pageOptions || {}),
148
- cursor: currentCursor,
149
- } as TPageOptions<TOptions>;
150
- const iterator = paginateMaxItems(pageFunction, options);
151
- let bufferedPages: TPage[] = [];
152
- let isFirstPage = true;
153
- let cursor: string | undefined;
154
- for await (let page of iterator) {
155
- if (isFirstPage) {
156
- isFirstPage = false;
157
- if (cursorOffset) {
158
- page = {
159
- ...page,
160
- data: page.data.slice(cursorOffset),
161
- };
162
- }
163
- }
164
- if (!pageSize) {
165
- yield page;
166
- cursor = page.nextCursor;
167
- continue;
168
- }
169
-
170
- const bufferedLength = bufferedPages.reduce(
171
- (acc, page) => acc + page.data.length,
172
- 0,
173
- );
174
-
175
- // If we don't have enough to fill a page, buffer this page.
176
- if (bufferedLength + page.data.length < pageSize) {
177
- bufferedPages.push(page);
178
- cursor = page.nextCursor;
179
- continue;
180
- }
181
-
182
- // Let's yield a page from our buffered pages.
183
- const bufferedItems = bufferedPages.map((p) => p.data).flat();
184
- const allItems = [...bufferedItems, ...page.data];
185
- const pageItems = allItems.slice(0, pageSize);
186
- const remainingItems = allItems.slice(pageItems.length);
187
-
188
- // No extra items to buffer, so we can just yield a normal page with a cursor to the next one.
189
- if (remainingItems.length === 0) {
190
- yield {
191
- ...page,
192
- data: pageItems,
193
- nextCursor: page.nextCursor,
194
- };
195
- bufferedPages = [];
196
- cursor = page.nextCursor;
197
- continue;
198
- }
199
-
200
- // Yield our items with a cursor to offset into this page.
201
- yield {
202
- ...page,
203
- data: pageItems,
204
- nextCursor: createOffsetCursor(
205
- page.data.length - remainingItems.length,
206
- cursor,
207
- ),
208
- };
209
-
210
- while (remainingItems.length > pageSize) {
211
- const pageItems = remainingItems.splice(0, pageSize);
212
- yield {
213
- ...page,
214
- data: pageItems,
215
- nextCursor: createOffsetCursor(
216
- page.data.length - remainingItems.length,
217
- cursor,
218
- ),
219
- };
220
- }
221
-
222
- bufferedPages = [
223
- {
224
- ...page,
225
- data: remainingItems,
226
- },
227
- ];
228
-
229
- cursor = page.nextCursor;
230
- }
231
-
232
- if (bufferedPages.length > 0) {
233
- const lastBufferedPage = bufferedPages.slice(-1)[0];
234
- const bufferedItems = bufferedPages.map((p) => p.data).flat();
235
- yield {
236
- ...lastBufferedPage,
237
- data: bufferedItems,
238
- };
239
- }
240
- }
241
-
242
- export const paginate = paginateBuffered;
@@ -1,207 +0,0 @@
1
- import { z } from "zod";
2
- import type { ZapierSdk } from "../types/sdk";
3
- import type { InputFieldItem } from "../schemas/Field";
4
-
5
- // ============================================================================
6
- // Format Metadata Types
7
- // ============================================================================
8
-
9
- export interface FormattedItem {
10
- title: string;
11
- id?: string;
12
- key?: string;
13
- keys?: string[];
14
- description?: string;
15
- data?: unknown; // Optional: if provided, CLI will use formatJsonOutput instead of details
16
- details: Array<{
17
- text: string;
18
- style: "normal" | "dim" | "accent" | "warning" | "success";
19
- }>;
20
- }
21
-
22
- export interface FormatMetadata<TItem = unknown> {
23
- format: (item: TItem) => FormattedItem;
24
- }
25
-
26
- // Helper function to add format metadata to schemas
27
- export function withFormatter<T extends z.ZodType>(
28
- schema: T,
29
- formatMeta: FormatMetadata<z.infer<T>>,
30
- ): T {
31
- // Store format metadata on the schema definition
32
- Object.assign(schema._def, {
33
- formatMeta: formatMeta,
34
- });
35
- return schema as T & {
36
- _def: T["_def"] & { formatMeta: FormatMetadata<z.infer<T>> };
37
- };
38
- }
39
-
40
- // Helper function to get output schema from an input schema
41
- export function getOutputSchema(inputSchema: z.ZodType): z.ZodType | undefined {
42
- return (inputSchema._def as { outputSchema?: z.ZodType }).outputSchema;
43
- }
44
-
45
- // Helper function to link input schemas to output schemas
46
- export function withOutputSchema<T extends z.ZodType>(
47
- inputSchema: T,
48
- outputSchema: z.ZodType,
49
- ): T & {
50
- _def: T["_def"] & { outputSchema: z.ZodType };
51
- } {
52
- // Store output schema reference on the input schema
53
- Object.assign(inputSchema._def, {
54
- outputSchema,
55
- });
56
- return inputSchema as T & {
57
- _def: T["_def"] & { outputSchema: z.ZodType };
58
- };
59
- }
60
-
61
- // ============================================================================
62
- // Resolution Metadata Types
63
- // ============================================================================
64
-
65
- export interface PromptConfig {
66
- type: "list";
67
- name: string;
68
- message: string;
69
- choices: Array<{
70
- name: string;
71
- value: unknown;
72
- }>;
73
- }
74
-
75
- export interface Resolver {
76
- type: string;
77
- depends?: readonly string[] | string[]; // Parameters this resolver depends on
78
- }
79
-
80
- export interface StaticResolver extends Resolver {
81
- type: "static";
82
- inputType?: "text" | "password" | "email";
83
- placeholder?: string;
84
- }
85
-
86
- export interface DynamicResolver<
87
- TItem = unknown,
88
- TParams = Record<string, unknown>,
89
- > extends Resolver {
90
- type: "dynamic";
91
- fetch: (sdk: ZapierSdk, resolvedParams: TParams) => Promise<TItem[]>; // Function to fetch data using SDK
92
- prompt: (items: TItem[], params: TParams) => PromptConfig;
93
- }
94
-
95
- export interface FieldsResolver<TParams = Record<string, unknown>>
96
- extends Resolver {
97
- type: "fields";
98
- fetch: (sdk: ZapierSdk, resolvedParams: TParams) => Promise<InputFieldItem[]>; // Function to fetch fields using SDK
99
- }
100
-
101
- export type ResolverMetadata<
102
- TItem = unknown,
103
- TParams = Record<string, unknown>,
104
- > = StaticResolver | DynamicResolver<TItem, TParams> | FieldsResolver<TParams>;
105
-
106
- // Wrapper interface for resolver metadata to allow future extensibility
107
- export interface ResolverConfig<
108
- TItem = unknown,
109
- TParams = Record<string, unknown>,
110
- > {
111
- resolver: ResolverMetadata<TItem, TParams>;
112
- // Future metadata types can be added here:
113
- // validation?: ValidationMetadata;
114
- // display?: DisplayMetadata;
115
- }
116
-
117
- // Helper function to add resolver metadata to schemas
118
- export function withResolver<
119
- T extends z.ZodType,
120
- TItem = unknown,
121
- TParams = Record<string, unknown>,
122
- >(schema: T, config: ResolverConfig<TItem, TParams>): T {
123
- // Store resolver metadata on the schema definition
124
- (
125
- schema._def as { resolverMeta?: ResolverConfig<TItem, TParams> }
126
- ).resolverMeta = config;
127
- return schema;
128
- }
129
-
130
- // ============================================================================
131
- // Schema Description Utilities
132
- // ============================================================================
133
-
134
- export function getSchemaDescription(schema: z.ZodSchema): string | undefined {
135
- return schema.description;
136
- }
137
-
138
- export function getFieldDescriptions(
139
- schema: z.ZodObject<z.ZodRawShape>,
140
- ): Record<string, string> {
141
- const descriptions: Record<string, string> = {};
142
- const shape = schema.shape;
143
-
144
- for (const [key, fieldSchema] of Object.entries(shape)) {
145
- if (fieldSchema instanceof z.ZodType && fieldSchema.description) {
146
- descriptions[key] = fieldSchema.description;
147
- }
148
- }
149
-
150
- return descriptions;
151
- }
152
-
153
- // ============================================================================
154
- // Positional Parameter Metadata
155
- // ============================================================================
156
-
157
- export interface PositionalMetadata {
158
- positionalMeta: {
159
- positional: true;
160
- };
161
- }
162
-
163
- // Helper function to mark a parameter as positional for CLI
164
- export function withPositional<T extends z.ZodType>(
165
- schema: T,
166
- ): T & {
167
- _def: T["_def"] & PositionalMetadata;
168
- } {
169
- // Store positional metadata on the schema definition
170
- Object.assign(schema._def, {
171
- positionalMeta: { positional: true },
172
- } satisfies PositionalMetadata);
173
- return schema as T & {
174
- _def: T["_def"] & PositionalMetadata;
175
- };
176
- }
177
-
178
- function schemaHasPositionalMeta<T extends z.ZodType>(
179
- schema: T,
180
- ): schema is T & {
181
- _def: T["_def"] & PositionalMetadata;
182
- } {
183
- return "positionalMeta" in schema._def;
184
- }
185
-
186
- // Helper function to check if a parameter should be positional
187
- export function isPositional(schema: z.ZodType): boolean {
188
- // Check the current schema first
189
- if (
190
- schemaHasPositionalMeta(schema) &&
191
- schema._def.positionalMeta?.positional
192
- ) {
193
- return true;
194
- }
195
-
196
- // If this is a ZodOptional, check the inner type
197
- if (schema instanceof z.ZodOptional) {
198
- return isPositional(schema._def.innerType);
199
- }
200
-
201
- // If this is a ZodDefault, check the inner type
202
- if (schema instanceof z.ZodDefault) {
203
- return isPositional(schema._def.innerType);
204
- }
205
-
206
- return false;
207
- }
@@ -1,45 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { toTitleCase } from "./string-utils";
3
-
4
- describe("toTitleCase", () => {
5
- it("converts snake_case to title case", () => {
6
- expect(toTitleCase("first_name")).toBe("First Name");
7
- expect(toTitleCase("sender_settings")).toBe("Sender Settings");
8
- expect(toTitleCase("api_key_config")).toBe("Api Key Config");
9
- });
10
-
11
- it("converts camelCase to title case", () => {
12
- expect(toTitleCase("firstName")).toBe("First Name");
13
- expect(toTitleCase("senderSettings")).toBe("Sender Settings");
14
- expect(toTitleCase("apiKeyConfig")).toBe("Api Key Config");
15
- });
16
-
17
- it("converts kebab-case to title case", () => {
18
- expect(toTitleCase("first-name")).toBe("First Name");
19
- expect(toTitleCase("sender-settings")).toBe("Sender Settings");
20
- expect(toTitleCase("api-key-config")).toBe("Api Key Config");
21
- });
22
-
23
- it("handles mixed formats", () => {
24
- expect(toTitleCase("first_name-value")).toBe("First Name Value");
25
- expect(toTitleCase("sender_settings-config")).toBe(
26
- "Sender Settings Config",
27
- );
28
- });
29
-
30
- it("handles single words", () => {
31
- expect(toTitleCase("name")).toBe("Name");
32
- expect(toTitleCase("settings")).toBe("Settings");
33
- });
34
-
35
- it("handles multiple spaces and trims", () => {
36
- expect(toTitleCase(" first name ")).toBe("First Name");
37
- expect(toTitleCase("sender__settings")).toBe("Sender Settings");
38
- });
39
-
40
- it("handles empty and edge cases", () => {
41
- expect(toTitleCase("")).toBe("");
42
- expect(toTitleCase("a")).toBe("A");
43
- expect(toTitleCase("_")).toBe("");
44
- });
45
- });
@@ -1,54 +0,0 @@
1
- /**
2
- * String utility functions for the Zapier SDK
3
- */
4
-
5
- /**
6
- * Converts a string to title case, handling various input formats:
7
- * - camelCase: "firstName" → "First Name"
8
- * - snake_case: "first_name" → "First Name"
9
- * - kebab-case: "first-name" → "First Name"
10
- * - mixed formats: "first_name-value" → "First Name Value"
11
- */
12
- export function toTitleCase(input: string): string {
13
- return (
14
- input
15
- // insert a space before capital letters (handles camelCase)
16
- .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
17
- // replace delimiters (underscore, dash, multiple spaces) with single space
18
- .replace(/[_\-]+/g, " ")
19
- .replace(/\s+/g, " ")
20
- .trim()
21
- // split and capitalize each word
22
- .split(" ")
23
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
24
- .join(" ")
25
- );
26
- }
27
-
28
- /**
29
- * Converts a string to snake_case, handling various input formats:
30
- * - camelCase: "firstName" → "first_name"
31
- * - kebab-case: "first-name" → "first_name"
32
- * - title case: "First Name" → "first_name"
33
- * - mixed formats: "first-Name Value" → "first_name_value"
34
- * - starts with number: "123abc" → "_123abc"
35
- */
36
- export function toSnakeCase(input: string): string {
37
- let result = input
38
- // insert underscore before capital letters (handles camelCase)
39
- .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
40
- // replace spaces and dashes with underscores
41
- .replace(/[\s\-]+/g, "_")
42
- // replace multiple underscores with single underscore
43
- .replace(/_+/g, "_")
44
- // remove leading/trailing underscores and convert to lowercase
45
- .replace(/^_|_$/g, "")
46
- .toLowerCase();
47
-
48
- // If the result starts with a number, prefix with underscore
49
- if (/^[0-9]/.test(result)) {
50
- result = "_" + result;
51
- }
52
-
53
- return result;
54
- }
@@ -1,51 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { z } from "zod";
3
- import { createValidator } from "./validation";
4
- import { ZapierValidationError } from "../types/errors";
5
-
6
- describe("validation utilities", () => {
7
- describe("createValidator", () => {
8
- it("should validate valid input", () => {
9
- const schema = z.object({
10
- name: z.string(),
11
- age: z.number(),
12
- });
13
- const validator = createValidator(schema);
14
-
15
- const result = validator({ name: "John", age: 30 });
16
- expect(result).toEqual({ name: "John", age: 30 });
17
- });
18
-
19
- it("should throw ZapierValidationError for invalid input", () => {
20
- const schema = z.object({
21
- name: z.string(),
22
- age: z.number(),
23
- });
24
- const validator = createValidator(schema);
25
-
26
- expect(() => {
27
- validator({ name: "John", age: "not-a-number" });
28
- }).toThrow(ZapierValidationError);
29
- });
30
-
31
- it("should include helpful error messages", () => {
32
- const schema = z.object({
33
- name: z.string(),
34
- age: z.number().min(0),
35
- });
36
- const validator = createValidator(schema);
37
-
38
- try {
39
- validator({ name: 123, age: -5 });
40
- } catch (error) {
41
- expect(error).toBeInstanceOf(ZapierValidationError);
42
- expect((error as ZapierValidationError).message).toContain("name:");
43
- expect((error as ZapierValidationError).message).toContain("age:");
44
- expect(
45
- ((error as ZapierValidationError).details as { zodErrors: unknown })
46
- ?.zodErrors,
47
- ).toBeDefined();
48
- }
49
- });
50
- });
51
- });
@@ -1,44 +0,0 @@
1
- import type { z } from "zod";
2
- import { ZapierValidationError } from "../types/errors";
3
-
4
- /**
5
- * Throws clean ZapierValidationError on validation failures
6
- */
7
- const validate = <TSchema extends z.ZodSchema>(
8
- schema: TSchema,
9
- input: unknown,
10
- ) => {
11
- const result = schema.safeParse(input);
12
-
13
- if (!result.success) {
14
- // Format Zod errors into a clean, user-friendly message
15
- const errorMessages = result.error.errors.map((error) => {
16
- const path = error.path.length > 0 ? error.path.join(".") : "input";
17
- return `${path}: ${error.message}`;
18
- });
19
-
20
- const message = `Validation failed:\n ${errorMessages.join("\n ")}`;
21
-
22
- throw new ZapierValidationError(message, {
23
- details: {
24
- zodErrors: result.error.errors,
25
- input,
26
- },
27
- });
28
- }
29
-
30
- return result.data;
31
- };
32
-
33
- export function createValidator<TSchema extends z.ZodSchema>(schema: TSchema) {
34
- return function validateFn(input: unknown): z.infer<TSchema> {
35
- return validate(schema, input);
36
- };
37
- }
38
-
39
- export const validateOptions = <TOptions, TSchemaOptions extends TOptions>(
40
- schema: z.ZodSchema<TSchemaOptions>,
41
- options: TOptions,
42
- ) => {
43
- return validate(schema, options);
44
- };
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ES2020",
5
- "declaration": true,
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "noUnusedLocals": true,
10
- "noUnusedParameters": true,
11
- "esModuleInterop": true,
12
- "skipLibCheck": true,
13
- "forceConsistentCasingInFileNames": true,
14
- "moduleResolution": "bundler"
15
- },
16
- "include": ["src/**/*"],
17
- "exclude": ["dist", "node_modules", "src/**/*.test.ts", "src/**/*.spec.ts"]
18
- }
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ES2020",
5
- "declaration": true,
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "noUnusedLocals": true,
10
- "noUnusedParameters": true,
11
- "esModuleInterop": true,
12
- "skipLibCheck": true,
13
- "forceConsistentCasingInFileNames": true,
14
- "moduleResolution": "bundler",
15
- "composite": true,
16
- "declarationMap": true
17
- },
18
- "include": ["src/**/*"],
19
- "exclude": ["dist", "node_modules"]
20
- }