@zapier/zapier-sdk 0.23.2 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -362,71 +362,136 @@ var appsPlugin = ({ sdk }) => {
362
362
  }
363
363
  };
364
364
  };
365
- var FetchUrlSchema = z.union([z.string(), z.instanceof(URL)]).describe("The URL to fetch");
365
+ var FetchUrlSchema = z.union([z.string(), z.instanceof(URL)]).describe(
366
+ "The full URL of the API endpoint to call (proxied through Zapier's Relay service)"
367
+ );
366
368
  var FetchInitSchema = z.object({
367
- method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).optional(),
368
- headers: z.record(z.string(), z.string()).optional(),
369
+ method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).optional().describe("HTTP method for the request (defaults to GET)"),
370
+ headers: z.record(z.string(), z.string()).optional().describe("HTTP headers to include in the request"),
369
371
  body: z.union([
370
372
  z.string(),
371
373
  z.instanceof(FormData),
372
374
  z.instanceof(URLSearchParams)
373
- ]).optional(),
375
+ ]).optional().describe(
376
+ "Request body \u2014 JSON strings are auto-detected and Content-Type is set accordingly"
377
+ ),
374
378
  authenticationId: AuthenticationIdPropertySchema.optional(),
375
379
  callbackUrl: z.string().optional().describe("URL to send async response to (makes request async)"),
376
380
  authenticationTemplate: z.string().optional().describe(
377
381
  "Optional JSON string authentication template to bypass Notary lookup"
378
382
  )
379
- }).optional().describe("Fetch options including authentication");
383
+ }).optional().describe(
384
+ "Request options including method, headers, body, and authentication"
385
+ );
386
+
387
+ // src/utils/id-utils.ts
388
+ function coerceToNumericId(fieldName, value) {
389
+ if (value === "") {
390
+ throw new ZapierValidationError(`The ${fieldName} cannot be empty`);
391
+ }
392
+ const numericValue = typeof value === "number" ? value : Number(value);
393
+ if (!Number.isFinite(numericValue)) {
394
+ throw new ZapierValidationError(
395
+ `The ${fieldName} "${value}" could not be converted to a number`
396
+ );
397
+ }
398
+ return numericValue;
399
+ }
380
400
 
381
401
  // src/plugins/fetch/index.ts
382
- var fetchPlugin = ({ sdk, context }) => {
402
+ function transformUrlToRelayPath(url) {
403
+ const targetUrl = new URL(url);
404
+ return `/relay/${targetUrl.host}${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
405
+ }
406
+ function normalizeHeaders(optionsHeaders) {
407
+ const headers = {};
408
+ if (!optionsHeaders) {
409
+ return headers;
410
+ }
411
+ const headerEntries = optionsHeaders instanceof Headers ? Array.from(optionsHeaders.entries()) : Array.isArray(optionsHeaders) ? optionsHeaders : Object.entries(optionsHeaders);
412
+ for (const [key, value] of headerEntries) {
413
+ headers[key] = value;
414
+ }
415
+ return headers;
416
+ }
417
+ var fetchPlugin = ({ context }) => {
383
418
  return {
384
419
  fetch: async function fetch2(url, init) {
420
+ const { api } = context;
385
421
  const startTime = Date.now();
422
+ const isNested = init?._telemetry?.isNested === true;
386
423
  try {
387
424
  const {
388
425
  authenticationId,
389
426
  callbackUrl,
390
427
  authenticationTemplate,
428
+ _telemetry,
391
429
  ...fetchInit
392
430
  } = init || {};
393
- const result = await sdk.request({
394
- url: url.toString(),
395
- method: fetchInit.method,
431
+ const relayPath = transformUrlToRelayPath(url);
432
+ const headers = normalizeHeaders(
433
+ fetchInit.headers
434
+ );
435
+ const hasContentType = Object.keys(headers).some(
436
+ (k) => k.toLowerCase() === "content-type"
437
+ );
438
+ if (fetchInit.body && !hasContentType) {
439
+ const bodyStr = typeof fetchInit.body === "string" ? fetchInit.body : JSON.stringify(fetchInit.body);
440
+ const trimmed = bodyStr.trimStart();
441
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
442
+ headers["Content-Type"] = "application/json; charset=utf-8";
443
+ }
444
+ }
445
+ if (authenticationId) {
446
+ headers["X-Relay-Authentication-Id"] = coerceToNumericId(
447
+ "authenticationId",
448
+ authenticationId
449
+ ).toString();
450
+ }
451
+ if (callbackUrl) {
452
+ headers["X-Relay-Callback-Url"] = callbackUrl;
453
+ }
454
+ if (authenticationTemplate) {
455
+ headers["X-Authentication-Template"] = authenticationTemplate;
456
+ }
457
+ const result = await api.fetch(relayPath, {
458
+ method: fetchInit.method ?? "GET",
396
459
  body: fetchInit.body,
397
- headers: fetchInit.headers,
398
- authenticationId,
399
- callbackUrl,
400
- authenticationTemplate,
401
- _telemetry: { isNested: true }
402
- });
403
- context.eventEmission.emitMethodCalled({
404
- method_name: "fetch",
405
- execution_duration_ms: Date.now() - startTime,
406
- success_flag: true,
407
- error_message: null,
408
- error_type: null,
409
- argument_count: init ? 2 : 1,
410
- is_paginated: false
460
+ headers,
461
+ authRequired: true
411
462
  });
463
+ if (!isNested) {
464
+ context.eventEmission.emitMethodCalled({
465
+ method_name: "fetch",
466
+ execution_duration_ms: Date.now() - startTime,
467
+ success_flag: true,
468
+ error_message: null,
469
+ error_type: null,
470
+ argument_count: init ? 2 : 1,
471
+ is_paginated: false
472
+ });
473
+ }
412
474
  return result;
413
475
  } catch (error) {
414
- context.eventEmission.emitMethodCalled({
415
- method_name: "fetch",
416
- execution_duration_ms: Date.now() - startTime,
417
- success_flag: false,
418
- error_message: error instanceof Error ? error.message : String(error),
419
- error_type: error instanceof Error ? error.constructor.name : "Unknown",
420
- argument_count: init ? 2 : 1,
421
- is_paginated: false
422
- });
476
+ if (!isNested) {
477
+ context.eventEmission.emitMethodCalled({
478
+ method_name: "fetch",
479
+ execution_duration_ms: Date.now() - startTime,
480
+ success_flag: false,
481
+ error_message: error instanceof Error ? error.message : String(error),
482
+ error_type: error instanceof Error ? error.constructor.name : "Unknown",
483
+ argument_count: init ? 2 : 1,
484
+ is_paginated: false
485
+ });
486
+ }
423
487
  throw error;
424
488
  }
425
489
  },
426
490
  context: {
427
491
  meta: {
428
492
  fetch: {
429
- packages: ["sdk"],
493
+ description: "Make authenticated HTTP requests to any API through Zapier's Relay service. Pass an authenticationId to automatically inject the user's stored credentials (OAuth tokens, API keys, etc.) into the outgoing request. Mirrors the native fetch(url, init?) signature with additional Zapier-specific options.",
494
+ packages: ["sdk", "cli", "mcp"],
430
495
  categories: ["http"],
431
496
  returnType: "Response",
432
497
  inputParameters: [
@@ -1805,20 +1870,6 @@ var RootFieldItemSchema = z.union([
1805
1870
  FieldsetItemSchema
1806
1871
  ]);
1807
1872
 
1808
- // src/utils/id-utils.ts
1809
- function coerceToNumericId(fieldName, value) {
1810
- if (value === "") {
1811
- throw new ZapierValidationError(`The ${fieldName} cannot be empty`);
1812
- }
1813
- const numericValue = typeof value === "number" ? value : Number(value);
1814
- if (!Number.isFinite(numericValue)) {
1815
- throw new ZapierValidationError(
1816
- `The ${fieldName} "${value}" could not be converted to a number`
1817
- );
1818
- }
1819
- return numericValue;
1820
- }
1821
-
1822
1873
  // src/services/implementations.ts
1823
1874
  async function fetchImplementationNeeds({
1824
1875
  api,
@@ -2801,64 +2852,41 @@ var RelayRequestSchema = z.object({
2801
2852
  z.instanceof(Headers),
2802
2853
  z.array(z.tuple([z.string(), z.string()]))
2803
2854
  ]).optional().describe("Request headers")
2804
- }).extend({
2805
- relayBaseUrl: z.string().optional().describe("Base URL for Relay service")
2806
2855
  }).merge(TelemetryMarkerSchema).describe("Make authenticated HTTP requests through Zapier's Relay service");
2807
2856
  var RelayFetchSchema = RelayRequestSchema;
2808
2857
 
2809
- // src/plugins/request/index.ts
2810
- function transformUrlToRelayPath(url) {
2811
- const targetUrl = new URL(url);
2812
- const relayPath = `/relay/${targetUrl.host}${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
2813
- return relayPath;
2858
+ // src/utils/logging.ts
2859
+ var loggedDeprecations = /* @__PURE__ */ new Set();
2860
+ function logDeprecation(message) {
2861
+ if (loggedDeprecations.has(message)) return;
2862
+ loggedDeprecations.add(message);
2863
+ console.warn(`[zapier-sdk] Deprecation: ${message}`);
2864
+ }
2865
+ function resetDeprecationWarnings() {
2866
+ loggedDeprecations.clear();
2814
2867
  }
2815
- var requestPlugin = ({ context }) => {
2868
+
2869
+ // src/plugins/request/index.ts
2870
+ var requestPlugin = ({ sdk, context }) => {
2816
2871
  async function request(options) {
2817
- const { api } = context;
2872
+ logDeprecation("request() is deprecated. Use fetch() instead.");
2818
2873
  const {
2819
2874
  url,
2820
- method = "GET",
2875
+ method,
2821
2876
  body,
2822
- headers: optionsHeaders,
2877
+ headers,
2823
2878
  authenticationId,
2824
2879
  callbackUrl,
2825
2880
  authenticationTemplate
2826
2881
  } = options;
2827
- const relayPath = transformUrlToRelayPath(url);
2828
- const headers = {};
2829
- if (optionsHeaders) {
2830
- const headerEntries = optionsHeaders instanceof Headers ? Array.from(optionsHeaders.entries()) : Array.isArray(optionsHeaders) ? optionsHeaders : Object.entries(optionsHeaders);
2831
- for (const [key, value] of headerEntries) {
2832
- headers[key] = value;
2833
- }
2834
- }
2835
- const hasContentType = Object.keys(headers).some(
2836
- (k) => k.toLowerCase() === "content-type"
2837
- );
2838
- if (body && !hasContentType) {
2839
- const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
2840
- const trimmed = bodyStr.trimStart();
2841
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2842
- headers["Content-Type"] = "application/json; charset=utf-8";
2843
- }
2844
- }
2845
- if (authenticationId) {
2846
- headers["X-Relay-Authentication-Id"] = coerceToNumericId(
2847
- "authenticationId",
2848
- authenticationId
2849
- ).toString();
2850
- }
2851
- if (callbackUrl) {
2852
- headers["X-Relay-Callback-Url"] = callbackUrl;
2853
- }
2854
- if (authenticationTemplate) {
2855
- headers["X-Authentication-Template"] = authenticationTemplate;
2856
- }
2857
- return await api.fetch(relayPath, {
2882
+ return sdk.fetch(url, {
2858
2883
  method,
2859
2884
  body,
2860
2885
  headers,
2861
- authRequired: true
2886
+ authenticationId,
2887
+ callbackUrl,
2888
+ authenticationTemplate,
2889
+ _telemetry: { isNested: true }
2862
2890
  });
2863
2891
  }
2864
2892
  const requestDefinition = createFunction(
@@ -2874,7 +2902,8 @@ var requestPlugin = ({ context }) => {
2874
2902
  context: {
2875
2903
  meta: {
2876
2904
  request: {
2877
- categories: ["http"],
2905
+ packages: ["cli", "mcp"],
2906
+ categories: ["http", "deprecated"],
2878
2907
  returnType: "Response",
2879
2908
  inputSchema: RelayRequestSchema
2880
2909
  }
@@ -3747,17 +3776,6 @@ function isCredentialsFunction(credentials) {
3747
3776
  return typeof credentials === "function";
3748
3777
  }
3749
3778
 
3750
- // src/utils/logging.ts
3751
- var loggedDeprecations = /* @__PURE__ */ new Set();
3752
- function logDeprecation(message) {
3753
- if (loggedDeprecations.has(message)) return;
3754
- loggedDeprecations.add(message);
3755
- console.warn(`[zapier-sdk] Deprecation: ${message}`);
3756
- }
3757
- function resetDeprecationWarnings() {
3758
- loggedDeprecations.clear();
3759
- }
3760
-
3761
3779
  // src/utils/url-utils.ts
3762
3780
  function getZapierBaseUrl(baseUrl) {
3763
3781
  if (!baseUrl) {
@@ -4615,6 +4633,7 @@ var registryPlugin = ({ sdk, context }) => {
4615
4633
  const meta = context.meta[key];
4616
4634
  return {
4617
4635
  name: key,
4636
+ description: meta.description,
4618
4637
  type: meta.type,
4619
4638
  itemType: meta.itemType,
4620
4639
  returnType: meta.returnType,
@@ -5075,7 +5094,7 @@ function getCpuTime() {
5075
5094
 
5076
5095
  // package.json
5077
5096
  var package_default = {
5078
- version: "0.23.2"};
5097
+ version: "0.24.0"};
5079
5098
 
5080
5099
  // src/plugins/eventEmission/builders.ts
5081
5100
  function createBaseEvent(context = {}) {
@@ -5529,7 +5548,7 @@ function createSdk(options = {}, initialSdk = {}, initialContext = { meta: {} })
5529
5548
  };
5530
5549
  }
5531
5550
  function createZapierSdkWithoutRegistry(options = {}) {
5532
- return createSdk(options).addPlugin(eventEmissionPlugin).addPlugin(apiPlugin).addPlugin(manifestPlugin).addPlugin(listAppsPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listInputFieldsPlugin).addPlugin(getInputFieldsSchemaPlugin).addPlugin(listInputFieldChoicesPlugin).addPlugin(runActionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(listClientCredentialsPlugin).addPlugin(createClientCredentialsPlugin).addPlugin(deleteClientCredentialsPlugin).addPlugin(requestPlugin).addPlugin(fetchPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin);
5551
+ return createSdk(options).addPlugin(eventEmissionPlugin).addPlugin(apiPlugin).addPlugin(manifestPlugin).addPlugin(listAppsPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listInputFieldsPlugin).addPlugin(getInputFieldsSchemaPlugin).addPlugin(listInputFieldChoicesPlugin).addPlugin(runActionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(listClientCredentialsPlugin).addPlugin(createClientCredentialsPlugin).addPlugin(deleteClientCredentialsPlugin).addPlugin(fetchPlugin).addPlugin(requestPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin);
5533
5552
  }
5534
5553
  function createZapierSdk(options = {}) {
5535
5554
  return createZapierSdkWithoutRegistry(options).addPlugin(registryPlugin);
@@ -1,5 +1,5 @@
1
- import type { Plugin, GetSdkType } from "../../types/plugin";
2
- import type { RequestPluginProvides } from "../request";
1
+ import type { Plugin } from "../../types/plugin";
2
+ import type { ApiClient } from "../../api";
3
3
  import type { z } from "zod";
4
4
  import type { EventEmissionContext } from "../eventEmission";
5
5
  export interface FetchPluginProvides {
@@ -7,10 +7,14 @@ export interface FetchPluginProvides {
7
7
  authenticationId?: string | number;
8
8
  callbackUrl?: string;
9
9
  authenticationTemplate?: string;
10
+ _telemetry?: {
11
+ isNested?: boolean;
12
+ };
10
13
  }) => Promise<Response>;
11
14
  context: {
12
15
  meta: {
13
16
  fetch: {
17
+ description: string;
14
18
  packages: string[];
15
19
  categories: string[];
16
20
  returnType: string;
@@ -23,10 +27,14 @@ export interface FetchPluginProvides {
23
27
  };
24
28
  }
25
29
  /**
26
- * Direct plugin function - takes options + sdk + context in one object
30
+ * Fetch plugin the primary way to make authenticated HTTP requests through Zapier's Relay service.
31
+ * Mirrors the native fetch(url, init?) signature with additional Zapier-specific options.
27
32
  */
28
- export declare const fetchPlugin: Plugin<GetSdkType<RequestPluginProvides>, // requires request in SDK
29
- EventEmissionContext, // requires eventEmission context for telemetry
33
+ export declare const fetchPlugin: Plugin<{}, // no SDK dependencies
34
+ // no SDK dependencies
35
+ {
36
+ api: ApiClient;
37
+ } & EventEmissionContext, // requires api + eventEmission in context
30
38
  FetchPluginProvides>;
31
39
  export type ZapierFetchInitOptions = RequestInit & {
32
40
  authenticationId?: string | number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/fetch/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,CACL,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,CAAC,EAAE,WAAW,GAAG;QACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACnC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,sBAAsB,CAAC,EAAE,MAAM,CAAC;KACjC,KACE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM,EAAE,CAAC;gBACnB,UAAU,EAAE,MAAM,EAAE,CAAC;gBACrB,UAAU,EAAE,MAAM,CAAC;gBACnB,eAAe,EAAE,KAAK,CAAC;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAA;iBAAE,CAAC,CAAC;aAC/D,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAC9B,UAAU,CAAC,qBAAqB,CAAC,EAAE,0BAA0B;AAC7D,oBAAoB,EAAE,+CAA+C;AACrE,mBAAmB,CA2EpB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG;IACjD,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/fetch/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAoC7D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,CACL,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,CAAC,EAAE,WAAW,GAAG;QACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACnC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC,UAAU,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KACrC,KACE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,KAAK,EAAE;gBACL,WAAW,EAAE,MAAM,CAAC;gBACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;gBACnB,UAAU,EAAE,MAAM,EAAE,CAAC;gBACrB,UAAU,EAAE,MAAM,CAAC;gBACnB,eAAe,EAAE,KAAK,CAAC;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAA;iBAAE,CAAC,CAAC;aAC/D,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAC9B,EAAE,EAAE,sBAAsB;AAC1B,AADI,sBAAsB;AAC1B;IAAE,GAAG,EAAE,SAAS,CAAA;CAAE,GAAG,oBAAoB,EAAE,0CAA0C;AACrF,mBAAmB,CAsHpB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG;IACjD,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC"}
@@ -1,54 +1,106 @@
1
1
  import { FetchUrlSchema, FetchInitSchema } from "./schemas";
2
+ import { coerceToNumericId } from "../../utils/id-utils";
2
3
  /**
3
- * Direct plugin function - takes options + sdk + context in one object
4
+ * Transforms full URLs into Relay format: /relay/{domain}/{path}
4
5
  */
5
- export const fetchPlugin = ({ sdk, context }) => {
6
- // Return flat structure - fetch goes directly to SDK
6
+ function transformUrlToRelayPath(url) {
7
+ const targetUrl = new URL(url);
8
+ return `/relay/${targetUrl.host}${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
9
+ }
10
+ /**
11
+ * Normalizes various header formats into a plain Record<string, string>.
12
+ */
13
+ function normalizeHeaders(optionsHeaders) {
14
+ const headers = {};
15
+ if (!optionsHeaders) {
16
+ return headers;
17
+ }
18
+ const headerEntries = optionsHeaders instanceof Headers
19
+ ? Array.from(optionsHeaders.entries())
20
+ : Array.isArray(optionsHeaders)
21
+ ? optionsHeaders
22
+ : Object.entries(optionsHeaders);
23
+ for (const [key, value] of headerEntries) {
24
+ headers[key] = value;
25
+ }
26
+ return headers;
27
+ }
28
+ /**
29
+ * Fetch plugin — the primary way to make authenticated HTTP requests through Zapier's Relay service.
30
+ * Mirrors the native fetch(url, init?) signature with additional Zapier-specific options.
31
+ */
32
+ export const fetchPlugin = ({ context }) => {
7
33
  return {
8
34
  fetch: async function fetch(url, init) {
35
+ const { api } = context;
9
36
  const startTime = Date.now();
37
+ const isNested = init?._telemetry?.isNested === true;
10
38
  try {
11
- const { authenticationId, callbackUrl, authenticationTemplate, ...fetchInit } = init || {};
12
- const result = await sdk.request({
13
- url: url.toString(),
14
- method: fetchInit.method,
39
+ const { authenticationId, callbackUrl, authenticationTemplate, _telemetry, ...fetchInit } = init || {};
40
+ const relayPath = transformUrlToRelayPath(url);
41
+ const headers = normalizeHeaders(fetchInit.headers);
42
+ // Auto-set Content-Type for JSON bodies if not already specified
43
+ const hasContentType = Object.keys(headers).some((k) => k.toLowerCase() === "content-type");
44
+ if (fetchInit.body && !hasContentType) {
45
+ const bodyStr = typeof fetchInit.body === "string"
46
+ ? fetchInit.body
47
+ : JSON.stringify(fetchInit.body);
48
+ const trimmed = bodyStr.trimStart();
49
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
50
+ headers["Content-Type"] = "application/json; charset=utf-8";
51
+ }
52
+ }
53
+ if (authenticationId) {
54
+ headers["X-Relay-Authentication-Id"] = coerceToNumericId("authenticationId", authenticationId).toString();
55
+ }
56
+ if (callbackUrl) {
57
+ headers["X-Relay-Callback-Url"] = callbackUrl;
58
+ }
59
+ if (authenticationTemplate) {
60
+ headers["X-Authentication-Template"] = authenticationTemplate;
61
+ }
62
+ const result = await api.fetch(relayPath, {
63
+ method: fetchInit.method ?? "GET",
15
64
  body: fetchInit.body,
16
- headers: fetchInit.headers,
17
- authenticationId,
18
- callbackUrl,
19
- authenticationTemplate,
20
- _telemetry: { isNested: true },
21
- });
22
- // Emit success telemetry
23
- context.eventEmission.emitMethodCalled({
24
- method_name: "fetch",
25
- execution_duration_ms: Date.now() - startTime,
26
- success_flag: true,
27
- error_message: null,
28
- error_type: null,
29
- argument_count: init ? 2 : 1,
30
- is_paginated: false,
65
+ headers,
66
+ authRequired: true,
31
67
  });
68
+ if (!isNested) {
69
+ context.eventEmission.emitMethodCalled({
70
+ method_name: "fetch",
71
+ execution_duration_ms: Date.now() - startTime,
72
+ success_flag: true,
73
+ error_message: null,
74
+ error_type: null,
75
+ argument_count: init ? 2 : 1,
76
+ is_paginated: false,
77
+ });
78
+ }
32
79
  return result;
33
80
  }
34
81
  catch (error) {
35
- // Emit failure telemetry
36
- context.eventEmission.emitMethodCalled({
37
- method_name: "fetch",
38
- execution_duration_ms: Date.now() - startTime,
39
- success_flag: false,
40
- error_message: error instanceof Error ? error.message : String(error),
41
- error_type: error instanceof Error ? error.constructor.name : "Unknown",
42
- argument_count: init ? 2 : 1,
43
- is_paginated: false,
44
- });
82
+ if (!isNested) {
83
+ context.eventEmission.emitMethodCalled({
84
+ method_name: "fetch",
85
+ execution_duration_ms: Date.now() - startTime,
86
+ success_flag: false,
87
+ error_message: error instanceof Error ? error.message : String(error),
88
+ error_type: error instanceof Error ? error.constructor.name : "Unknown",
89
+ argument_count: init ? 2 : 1,
90
+ is_paginated: false,
91
+ });
92
+ }
45
93
  throw error;
46
94
  }
47
95
  },
48
96
  context: {
49
97
  meta: {
50
98
  fetch: {
51
- packages: ["sdk"],
99
+ description: "Make authenticated HTTP requests to any API through Zapier's Relay service. " +
100
+ "Pass an authenticationId to automatically inject the user's stored credentials " +
101
+ "(OAuth tokens, API keys, etc.) into the outgoing request. " +
102
+ "Mirrors the native fetch(url, init?) signature with additional Zapier-specific options.",
103
+ packages: ["sdk", "cli", "mcp"],
52
104
  categories: ["http"],
53
105
  returnType: "Response",
54
106
  inputParameters: [
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/plugins/fetch/index.test.ts"],"names":[],"mappings":""}