@zapier/zapier-sdk 0.95.0 → 0.96.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @zapier/zapier-sdk
2
2
 
3
+ ## 0.96.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2726599: Added `createForm` (experimental) to create Zapier Forms from a title, optional description, and typed field list. Forms publish by default and return a shareable `hosted_url`; pass `draft: true` to save without publishing. A complete `document` can be supplied for layouts the field list cannot express.
8
+
3
9
  ## 0.95.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -63,6 +63,8 @@
63
63
  - [`waitForNewConnection`](#waitfornewconnection)
64
64
  - [HTTP Requests](#http-requests)
65
65
  - [`fetch`](#fetch)
66
+ - [Human Inputs (Experimental)](#human-inputs-experimental)
67
+ - [`createForm`](#createform--experimental)
66
68
  - [Tables](#tables)
67
69
  - [`createTable`](#createtable)
68
70
  - [`createTableFields`](#createtablefields)
@@ -2592,6 +2594,84 @@ Make authenticated HTTP requests to any API through Zapier. Pass a connectionId
2592
2594
  const result = await zapier.fetch("https://example.com", {});
2593
2595
  ```
2594
2596
 
2597
+ ### Human Inputs (Experimental)
2598
+
2599
+ > ℹ️ **Experimental.** Import from `"@zapier/zapier-sdk/experimental"` to use these methods. Methods and behavior may change.
2600
+
2601
+ #### `createForm` 🧪 _experimental_
2602
+
2603
+ Create a Zapier Form from a title and optional fields. Forms publish by default and return a shareable `hosted_url`; set `draft` to save without publishing.
2604
+
2605
+ **Parameters:**
2606
+
2607
+ | Name | Type | Required | Default | Possible Values | Description |
2608
+ | ------------------------- | ---------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2609
+ | `options` | `object` | ✅ | — | — | |
2610
+ | ​ ↳ `title` | `string` | ✅ | — | — | The title shown in the Forms UI and on the form. |
2611
+ | ​ ↳ `description` | `string` | ❌ | — | — | An optional description of the form. |
2612
+ | ​ ↳ `fields[]` | `object[]` | ❌ | — | — | Initial fields to add to the form. |
2613
+ | ​   ↳ `label` | `string` | ✅ | — | — | Human-readable label shown above the input. |
2614
+ | ​   ↳ `type` | `string` | ✅ | — | `short_text`, `long_text`, `email`, `number`, `yes_no`, `url`, `date`, `date_range`, `currency`, `phone_number`, `dropdown`, `integration_backed` | The type of field. |
2615
+ | ​   ↳ `required` | `boolean` | ❌ | — | — | Whether the field must be answered before the form can submit. |
2616
+ | ​   ↳ `disabled` | `boolean` | ❌ | — | — | When true, the field is rendered read-only — shown but not editable. A rendering hint only; it is not enforced during submission validation. |
2617
+ | ​   ↳ `variant` | `string` | ❌ | — | `checkbox`, `radio` | For `yes_no` fields: `checkbox` renders a single toggle, `radio` renders explicit yes/no buttons. Defaults to `checkbox`. |
2618
+ | ​   ↳ `multiUrl` | `boolean` | ❌ | — | — | For `url` fields: when true the field accepts a list of URLs, otherwise a single URL. Defaults to false. |
2619
+ | ​   ↳ `includeTime` | `boolean` | ❌ | — | — | For `date` and `date_range` fields: when true the picker also captures a time. Defaults to false. |
2620
+ | ​   ↳ `currencyFormat` | `string` | ❌ | — | — | For `currency` fields: ISO 4217 currency code (e.g. `usd`, `eur`). Controls the symbol shown in the form UI. |
2621
+ | ​   ↳ `decimals` | `literal` | ❌ | — | — | For `currency` fields: allowed decimal places. `0` for whole numbers, `2` for up to two decimal places. Defaults to `2`. |
2622
+ | ​   ↳ `defaultCountry` | `string` | ❌ | — | — | For `phone_number` fields: ISO 3166-1 alpha-2 code for the default selected country (e.g. `US`). Defaults to `US`. |
2623
+ | ​   ↳ `phoneNumberFormat` | `string` | ❌ | — | `national`, `international` | For `phone_number` fields: `national` omits the country-code prefix, `international` includes it. Defaults to `national`. |
2624
+ | ​   ↳ `acceptedCountries` | `array` | ❌ | — | — | For `phone_number` fields: restrict input to specific ISO 3166-1 alpha-2 country codes. Omit to allow all countries. |
2625
+ | ​   ↳ `options[]` | `object[]` | ❌ | — | — | For `dropdown` fields: the selectable options. At least one is required. |
2626
+ | ​     ↳ `value` | `string` | ✅ | — | — | The value submitted when this option is selected. |
2627
+ | ​     ↳ `label` | `string` | ✅ | — | — | Human-readable label shown to the user. |
2628
+ | ​   ↳ `multiSelect` | `boolean` | ❌ | — | — | For `dropdown` fields: when true the user may select multiple options. Defaults to false. |
2629
+ | ​   ↳ `dataSource` | `object` | ❌ | — | — | For `integration_backed` fields: where to fetch the field's options from at render time. |
2630
+ | ​     ↳ `app` | `string` | ✅ | — | — | Zapier app to pull options from. See `listApps` for the catalog. |
2631
+ | ​     ↳ `actionType` | `string` | ✅ | — | `read`, `read_bulk` | Whether the data source returns a single record (`read`) or a collection (`read_bulk`). |
2632
+ | ​     ↳ `resource` | `string` | ✅ | — | — | Resource name within the app — typically a trigger or search key from the app's definition. |
2633
+ | ​     ↳ `valueKey` | `string` | ❌ | — | — | Property on each returned record to use as the submitted option value. Defaults to `id`. |
2634
+ | ​     ↳ `labelKey` | `string` | ❌ | — | — | Property on each returned record to use as the displayed option label. Defaults to a sensible name field. |
2635
+ | ​ ↳ `draft` | `boolean` | ❌ | — | — | When true, save without publishing. Omit to publish immediately, making `hosted_url` live. |
2636
+ | ​ ↳ `confirmationTitle` | `string` | ❌ | — | — | Heading shown to the respondent after they submit. Omit to use the form renderer's default. |
2637
+ | ​ ↳ `confirmationMessage` | `string` | ❌ | — | — | Message shown to the respondent after they submit, below the confirmation title. Omit to use the form renderer's default. |
2638
+ | ​ ↳ `callbackUrl` | `string` | ❌ | — | — | Absolute http/https URL notified with the submission JSON each time the form is answered. |
2639
+ | ​ ↳ `consumerAuth` | `string` | ❌ | — | `none`, `zapier` | Who may open the published form. `none` (the default) leaves it public to anyone with the link; `zapier` requires the visitor to be signed in to Zapier on the form's owning account. |
2640
+ | ​ ↳ `document` | `object` | ❌ | — | — | Escape hatch: a complete form document tree, sent as-is. When supplied it replaces the document built from `fields`, and `title`, `description`, `confirmationTitle`, and `confirmationMessage` are ignored. Use only for structures the flat field list cannot express, such as approval decisions or multi-column row layout. |
2641
+ | ​   ↳ `id` | `string` | ✅ | — | — | |
2642
+ | ​   ↳ `type` | `string` | ✅ | — | `root` | |
2643
+ | ​   ↳ `attrs` | `object` | ✅ | — | — | |
2644
+ | ​     ↳ `schema_version` | `number` | ✅ | — | — | |
2645
+ | ​     ↳ `title` | `string` | ✅ | — | — | |
2646
+ | ​   ↳ `children` | `array` | ❌ | — | — | |
2647
+
2648
+ **Returns:** `Promise<FormItem>`
2649
+
2650
+ | Name | Type | Required | Possible Values | Description |
2651
+ | ----------------------- | --------- | -------- | --------------- | ----------- |
2652
+ | `data` | `object` | ✅ | — | |
2653
+ | ​ ↳ `id` | `string` | ✅ | — | |
2654
+ | ​ ↳ `title` | `string` | ✅ | — | |
2655
+ | ​ ↳ `description` | `string` | ❌ | — | |
2656
+ | ​ ↳ `hosted_url` | `string` | ✅ | — | |
2657
+ | ​ ↳ `submission_count` | `number` | ✅ | — | |
2658
+ | ​ ↳ `account_id` | `number` | ✅ | — | |
2659
+ | ​ ↳ `owner_id` | `string` | ✅ | — | |
2660
+ | ​ ↳ `created_at` | `string` | ✅ | — | |
2661
+ | ​ ↳ `updated_at` | `string` | ✅ | — | |
2662
+ | ​ ↳ `document` | `unknown` | ✅ | — | |
2663
+ | ​ ↳ `last_published_at` | `string` | ✅ | — | |
2664
+ | ​ ↳ `consumer_auth` | `unknown` | ✅ | — | |
2665
+ | ​ ↳ `callback_url` | `unknown` | ✅ | — | |
2666
+
2667
+ **Example:**
2668
+
2669
+ ```typescript
2670
+ const { data: form } = await zapier.createForm({
2671
+ title: "example-title",
2672
+ });
2673
+ ```
2674
+
2595
2675
  ### Tables
2596
2676
 
2597
2677
  #### `createTable`
@@ -1541,6 +1541,11 @@ function declareOptionalProperty(config) {
1541
1541
  // import binding is still typed `TValue | undefined` from the descriptor.
1542
1542
  };
1543
1543
  }
1544
+ function declareDefault({
1545
+ plugin
1546
+ }) {
1547
+ return { ...plugin, defaultSource: plugin };
1548
+ }
1544
1549
  function defineHook(config) {
1545
1550
  const deps = normalizeImports(config.imports);
1546
1551
  return {
@@ -4210,6 +4215,321 @@ function createCorePlugin(options) {
4210
4215
  }
4211
4216
  });
4212
4217
  }
4218
+ function describeUnclaimedConnection(connection) {
4219
+ const delimiterIndex = connection.indexOf(":");
4220
+ if (delimiterIndex === -1) {
4221
+ return 'no auth provider claimed this connection, and it carries no "scheme:" prefix';
4222
+ }
4223
+ return `no auth provider claimed the "${connection.slice(0, delimiterIndex)}" connection scheme`;
4224
+ }
4225
+ var authorizeHttpRequestPlugin = defineMethod({
4226
+ name: "authorizeHttpRequest",
4227
+ namespace: "kitcore",
4228
+ inputSchema: zod.z.custom(),
4229
+ skipInputValidation: true,
4230
+ run: async ({ input }) => {
4231
+ const { connection } = input.request;
4232
+ if (connection != null) {
4233
+ throw createCoreError({
4234
+ code: CoreErrorCode.Unknown,
4235
+ message: `authorizeHttpRequest: ${describeUnclaimedConnection(connection)}, so the request was not sent.`
4236
+ });
4237
+ }
4238
+ return input.request;
4239
+ }
4240
+ });
4241
+ function toFetchInput(request) {
4242
+ const init = { ...request };
4243
+ const { url } = request;
4244
+ delete init.url;
4245
+ delete init.connection;
4246
+ return { url, init };
4247
+ }
4248
+ var dispatchHttpRequestPlugin = defineMethod({
4249
+ name: "dispatchHttpRequest",
4250
+ namespace: "kitcore",
4251
+ inputSchema: zod.z.custom(),
4252
+ skipInputValidation: true,
4253
+ run: async ({ input }) => {
4254
+ const { url, init } = toFetchInput(input.request);
4255
+ return fetch(url, init);
4256
+ }
4257
+ });
4258
+ var prepareHttpRequestPlugin = defineMethod({
4259
+ name: "prepareHttpRequest",
4260
+ namespace: "kitcore",
4261
+ inputSchema: zod.z.custom(),
4262
+ skipInputValidation: true,
4263
+ run: async ({ input }) => input.request
4264
+ });
4265
+ var receiveHttpResponsePlugin = defineMethod({
4266
+ name: "receiveHttpResponse",
4267
+ namespace: "kitcore",
4268
+ inputSchema: zod.z.custom(),
4269
+ skipInputValidation: true,
4270
+ run: async ({ input }) => input.response
4271
+ });
4272
+ var attemptHttpRequestPlugin = defineMethod({
4273
+ name: "attemptHttpRequest",
4274
+ namespace: "kitcore",
4275
+ imports: [
4276
+ declareDefault({ plugin: prepareHttpRequestPlugin }),
4277
+ declareDefault({ plugin: authorizeHttpRequestPlugin }),
4278
+ declareDefault({ plugin: dispatchHttpRequestPlugin }),
4279
+ declareDefault({ plugin: receiveHttpResponsePlugin })
4280
+ ],
4281
+ inputSchema: zod.z.custom(),
4282
+ skipInputValidation: true,
4283
+ run: async ({ input, imports }) => {
4284
+ const { attempt } = input;
4285
+ const preparedRequest = await imports.prepareHttpRequest({
4286
+ request: input.request,
4287
+ attempt
4288
+ });
4289
+ const authorizedRequest = await imports.authorizeHttpRequest({
4290
+ request: preparedRequest,
4291
+ attempt
4292
+ });
4293
+ const response = await imports.dispatchHttpRequest({
4294
+ request: authorizedRequest,
4295
+ attempt
4296
+ });
4297
+ return imports.receiveHttpResponse({
4298
+ request: authorizedRequest,
4299
+ response,
4300
+ attempt
4301
+ });
4302
+ }
4303
+ });
4304
+ function isReplayableBody(body) {
4305
+ if (body == null || typeof body !== "object") return true;
4306
+ return typeof Blob !== "undefined" && body instanceof Blob || // File extends Blob
4307
+ typeof FormData !== "undefined" && body instanceof FormData || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || body instanceof ArrayBuffer || ArrayBuffer.isView(body);
4308
+ }
4309
+ function withStringUrl(request) {
4310
+ return typeof request.url === "string" ? request : { ...request, url: String(request.url) };
4311
+ }
4312
+ var initializeHttpRequestPlugin = defineMethod({
4313
+ name: "initializeHttpRequest",
4314
+ namespace: "kitcore",
4315
+ inputSchema: zod.z.custom(),
4316
+ skipInputValidation: true,
4317
+ run: async ({ input }) => {
4318
+ const request = withStringUrl(input.request);
4319
+ return {
4320
+ ...input.operation,
4321
+ request,
4322
+ replayable: isReplayableBody(request.body)
4323
+ };
4324
+ }
4325
+ });
4326
+ var RETRY_HTTP_REQUEST_OPTIONS_ID = "kitcore/retryHttpRequestOptions";
4327
+ var retryHttpRequestOptionsPluginRef = declareOptionalProperty({ id: RETRY_HTTP_REQUEST_OPTIONS_ID });
4328
+ var DEFAULT_MAX_ATTEMPTS = 3;
4329
+ var DEFAULT_MAX_DELAY_MILLISECONDS = 6e4;
4330
+ var DEFAULT_RETRY_STATUSES = [429, 500, 502, 503, 504];
4331
+ var DEFAULT_NON_IDEMPOTENT_RETRY_STATUSES = [429];
4332
+ var DEFAULT_IDEMPOTENT_METHODS = [
4333
+ "GET",
4334
+ "HEAD",
4335
+ "PUT",
4336
+ "DELETE",
4337
+ "OPTIONS",
4338
+ "TRACE"
4339
+ ];
4340
+ var BASE_BACKOFF_MILLISECONDS = 1e3;
4341
+ var JITTER_FACTOR = 0.5;
4342
+ function directedDelayMilliseconds(response) {
4343
+ const retryAfter = response.headers.get("retry-after");
4344
+ if (retryAfter) {
4345
+ const seconds = Number.parseInt(retryAfter, 10);
4346
+ if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1e3);
4347
+ const date = Date.parse(retryAfter);
4348
+ if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
4349
+ }
4350
+ const reset = response.headers.get("x-ratelimit-reset");
4351
+ if (reset) {
4352
+ const resetSeconds = Number.parseInt(reset, 10);
4353
+ if (!Number.isNaN(resetSeconds)) {
4354
+ return Math.max(0, resetSeconds * 1e3 - Date.now());
4355
+ }
4356
+ }
4357
+ return void 0;
4358
+ }
4359
+ function backoffMilliseconds(attemptNumber) {
4360
+ const base = BASE_BACKOFF_MILLISECONDS * 2 ** (attemptNumber - 1);
4361
+ return base + Math.random() * JITTER_FACTOR * base;
4362
+ }
4363
+ function abortReason(signal) {
4364
+ const reason = signal?.reason;
4365
+ return reason ?? new Error("The request was aborted.");
4366
+ }
4367
+ function sleep(milliseconds, signal) {
4368
+ return new Promise((resolve2, reject) => {
4369
+ const timer = setTimeout(finish, milliseconds);
4370
+ function finish() {
4371
+ clearTimeout(timer);
4372
+ signal?.removeEventListener("abort", cancel);
4373
+ resolve2();
4374
+ }
4375
+ function cancel() {
4376
+ clearTimeout(timer);
4377
+ reject(abortReason(signal));
4378
+ }
4379
+ if (signal?.aborted) return cancel();
4380
+ signal?.addEventListener("abort", cancel, { once: true });
4381
+ });
4382
+ }
4383
+ function isIdempotent(request, idempotentMethods) {
4384
+ const method = (request.method ?? "GET").toUpperCase();
4385
+ return idempotentMethods.includes(method);
4386
+ }
4387
+ defineHook({
4388
+ name: "retryHttpRequest",
4389
+ imports: [attemptHttpRequestPlugin, retryHttpRequestOptionsPluginRef],
4390
+ wrap: {
4391
+ attemptHttpRequest: async ({ input, imports, next }) => {
4392
+ const options = imports.retryHttpRequestOptions ?? {};
4393
+ const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
4394
+ const maxDelayMilliseconds = options.maxDelayMilliseconds ?? DEFAULT_MAX_DELAY_MILLISECONDS;
4395
+ const idempotentMethods = options.idempotentMethods ?? DEFAULT_IDEMPOTENT_METHODS;
4396
+ const statuses = isIdempotent(input.request, idempotentMethods) ? options.retryStatuses ?? DEFAULT_RETRY_STATUSES : options.nonIdempotentRetryStatuses ?? DEFAULT_NON_IDEMPOTENT_RETRY_STATUSES;
4397
+ for (let attemptNumber = 1; ; attemptNumber++) {
4398
+ const attempt = {
4399
+ ...input.attempt,
4400
+ attemptNumber,
4401
+ // Per-attempt scratch: a cross-stage handoff from a previous attempt
4402
+ // describes a request that is no longer in flight. `operation` rides
4403
+ // through unchanged, so the id and the caller's original request are
4404
+ // the same for every attempt.
4405
+ state: {}
4406
+ };
4407
+ let response;
4408
+ try {
4409
+ response = await next({ ...input, attempt });
4410
+ } catch (error) {
4411
+ if (!options.retryOnError || !canRetry(
4412
+ attemptNumber,
4413
+ maxAttempts,
4414
+ input.attempt.operation.replayable
4415
+ )) {
4416
+ throw error;
4417
+ }
4418
+ await sleep(
4419
+ Math.min(backoffMilliseconds(attemptNumber), maxDelayMilliseconds),
4420
+ attempt.signal
4421
+ );
4422
+ continue;
4423
+ }
4424
+ if (!statuses.includes(response.status) || !canRetry(
4425
+ attemptNumber,
4426
+ maxAttempts,
4427
+ input.attempt.operation.replayable
4428
+ )) {
4429
+ return response;
4430
+ }
4431
+ const directed = directedDelayMilliseconds(response);
4432
+ if (directed != null && directed > maxDelayMilliseconds)
4433
+ return response;
4434
+ const delay = Math.min(
4435
+ directed ?? backoffMilliseconds(attemptNumber),
4436
+ maxDelayMilliseconds
4437
+ );
4438
+ await response.body?.cancel().catch(() => {
4439
+ });
4440
+ await sleep(delay, attempt.signal);
4441
+ }
4442
+ }
4443
+ }
4444
+ });
4445
+ function canRetry(attemptNumber, maxAttempts, replayable) {
4446
+ return attemptNumber < maxAttempts && replayable;
4447
+ }
4448
+ function createOperationId() {
4449
+ return globalThis.crypto?.randomUUID?.() ?? `http-${Date.now()}`;
4450
+ }
4451
+ var sendHttpRequestPlugin = defineMethod({
4452
+ name: "sendHttpRequest",
4453
+ namespace: "kitcore",
4454
+ imports: [
4455
+ declareDefault({ plugin: initializeHttpRequestPlugin }),
4456
+ declareDefault({ plugin: attemptHttpRequestPlugin })
4457
+ ],
4458
+ inputSchema: zod.z.custom(),
4459
+ skipInputValidation: true,
4460
+ run: async ({ input, imports }) => {
4461
+ const start2 = {
4462
+ operationId: createOperationId(),
4463
+ signal: input.signal
4464
+ };
4465
+ const operation = await imports.initializeHttpRequest({
4466
+ request: input,
4467
+ operation: start2
4468
+ });
4469
+ return imports.attemptHttpRequest({
4470
+ request: operation.request,
4471
+ attempt: {
4472
+ attemptNumber: 1,
4473
+ operation,
4474
+ signal: operation.signal,
4475
+ state: {}
4476
+ }
4477
+ });
4478
+ }
4479
+ });
4480
+ defineMethod({
4481
+ name: "fetch",
4482
+ namespace: "kitcore",
4483
+ imports: [declareDefault({ plugin: sendHttpRequestPlugin })],
4484
+ positional: ["url", "init"],
4485
+ inputSchema: zod.z.custom(),
4486
+ skipInputValidation: true,
4487
+ run: ({ input, imports }) => {
4488
+ const { url, init } = input;
4489
+ return imports.sendHttpRequest({ url, ...init });
4490
+ }
4491
+ });
4492
+ var defaultConnectionSchemePlugin = defineMethod({
4493
+ name: "defaultConnectionScheme",
4494
+ namespace: "kitcore",
4495
+ inputSchema: zod.z.custom(),
4496
+ skipInputValidation: true,
4497
+ run: () => void 0
4498
+ });
4499
+ defineMethod({
4500
+ name: "normalizeConnection",
4501
+ namespace: "kitcore",
4502
+ imports: [declareDefault({ plugin: defaultConnectionSchemePlugin })],
4503
+ inputSchema: zod.z.custom(),
4504
+ skipInputValidation: true,
4505
+ run: ({ input, imports }) => {
4506
+ const { connection } = input;
4507
+ if (connection == null) {
4508
+ return void 0;
4509
+ }
4510
+ const delimiterIndex = connection.indexOf(":");
4511
+ if (delimiterIndex !== -1) {
4512
+ return {
4513
+ connection,
4514
+ scheme: connection.slice(0, delimiterIndex),
4515
+ value: connection.slice(delimiterIndex + 1)
4516
+ };
4517
+ }
4518
+ const scheme = imports.defaultConnectionScheme({ connection });
4519
+ return {
4520
+ connection,
4521
+ scheme,
4522
+ value: connection
4523
+ };
4524
+ }
4525
+ });
4526
+ defineMethod({
4527
+ name: "resolveConnection",
4528
+ namespace: "kitcore",
4529
+ inputSchema: zod.z.custom(),
4530
+ skipInputValidation: true,
4531
+ run: ({ input }) => input.connection
4532
+ });
4213
4533
 
4214
4534
  // src/constants.ts
4215
4535
  var ZAPIER_BASE_URL = globalThis.process?.env?.ZAPIER_BASE_URL || "https://zapier.com";
@@ -4914,9 +5234,9 @@ function createDebugFetch(options) {
4914
5234
  var MAX_CONSECUTIVE_ERRORS = 3;
4915
5235
  var BASE_ERROR_BACKOFF_MILLISECONDS = 1e3;
4916
5236
  var BASE_EXPONENTIAL_BACKOFF_MILLISECONDS = 1e3;
4917
- var JITTER_FACTOR = 0.5;
5237
+ var JITTER_FACTOR2 = 0.5;
4918
5238
  function calculateErrorBackoffMs(baseInterval, errorCount) {
4919
- const jitter = Math.random() * JITTER_FACTOR * baseInterval;
5239
+ const jitter = Math.random() * JITTER_FACTOR2 * baseInterval;
4920
5240
  const errorBackoff = Math.min(
4921
5241
  BASE_ERROR_BACKOFF_MILLISECONDS * (errorCount / 2),
4922
5242
  baseInterval * 2
@@ -4926,10 +5246,10 @@ function calculateErrorBackoffMs(baseInterval, errorCount) {
4926
5246
  }
4927
5247
  function calculateExponentialBackoffMs(attempt, baseDelayMs = BASE_EXPONENTIAL_BACKOFF_MILLISECONDS) {
4928
5248
  const baseDelay = baseDelayMs * Math.pow(2, attempt - 1);
4929
- const jitter = Math.random() * JITTER_FACTOR * baseDelay;
5249
+ const jitter = Math.random() * JITTER_FACTOR2 * baseDelay;
4930
5250
  return Math.floor(baseDelay + jitter);
4931
5251
  }
4932
- function sleep(ms, signal) {
5252
+ function sleep2(ms, signal) {
4933
5253
  if (!signal) {
4934
5254
  return new Promise((resolve2) => setTimeout(resolve2, ms));
4935
5255
  }
@@ -5141,7 +5461,7 @@ async function pollUntilComplete(options) {
5141
5461
  let attempts = 0;
5142
5462
  let errorCount = 0;
5143
5463
  if (initialDelay > 0) {
5144
- await sleep(initialDelay, signal);
5464
+ await sleep2(initialDelay, signal);
5145
5465
  if (signal?.aborted) throw makeAbortError();
5146
5466
  }
5147
5467
  while (true) {
@@ -5159,7 +5479,7 @@ async function pollUntilComplete(options) {
5159
5479
  const interval = getPollingInterval(elapsedTime);
5160
5480
  const waitTime = calculateErrorBackoffMs(interval, errorCount);
5161
5481
  const cappedWaitTime = maxPollingIntervalMs === void 0 ? waitTime : Math.min(waitTime, maxPollingIntervalMs);
5162
- await sleep(cappedWaitTime, signal);
5482
+ await sleep2(cappedWaitTime, signal);
5163
5483
  if (signal?.aborted) throw makeAbortError();
5164
5484
  }
5165
5485
  attempts++;
@@ -6194,7 +6514,7 @@ function parseDeprecationDate(value) {
6194
6514
  }
6195
6515
 
6196
6516
  // src/sdk-version.ts
6197
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.95.0" : void 0) || "unknown";
6517
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.96.0" : void 0) || "unknown";
6198
6518
 
6199
6519
  // src/utils/open-url.ts
6200
6520
  var nodePrefix = "node:";
@@ -6428,6 +6748,15 @@ var pathConfig = {
6428
6748
  "/code-substrate-workflows": {
6429
6749
  authHeader: "Authorization",
6430
6750
  pathPrefix: "/api/v0/sdk/code-substrate-workflows"
6751
+ },
6752
+ // e.g. /forms/v0/forms -> https://api.zapier.com/forms/v0/forms
6753
+ // The Forms API is registered on the Public API Gateway and has no sdkapi
6754
+ // proxy route, so it goes straight to the gateway. Its governance metadata
6755
+ // rewrites /forms/v0/... to the backend's /api/forms/v0/..., which is why no
6756
+ // pathPrefix is applied here.
6757
+ "/forms": {
6758
+ authHeader: "Authorization",
6759
+ subdomain: "api"
6431
6760
  }
6432
6761
  };
6433
6762
  var ZapierApiClient = class {
@@ -6490,7 +6819,7 @@ var ZapierApiClient = class {
6490
6819
  method: init?.method ?? "GET",
6491
6820
  rateLimit: rateLimitInfo
6492
6821
  });
6493
- await sleep(delayMs, init?.signal ?? void 0);
6822
+ await sleep2(delayMs, init?.signal ?? void 0);
6494
6823
  }
6495
6824
  };
6496
6825
  /**
@@ -6968,7 +7297,8 @@ var ZapierApiClient = class {
6968
7297
  const zapierBaseUrl = getZapierBaseUrl(this.options.baseUrl);
6969
7298
  if (zapierBaseUrl === this.options.baseUrl.replace(/\/$/, "")) {
6970
7299
  const originalBaseUrl = new URL(this.options.baseUrl);
6971
- const finalBaseUrl = `https://sdkapi.${originalBaseUrl.hostname}`;
7300
+ const subdomain = routingMatch?.config.subdomain ?? "sdkapi";
7301
+ const finalBaseUrl = `https://${subdomain}.${originalBaseUrl.hostname}`;
6972
7302
  const url2 = new URL(finalPath, finalBaseUrl);
6973
7303
  return buildResult(url2);
6974
7304
  }
@@ -8373,7 +8703,7 @@ function buildAbortHandle({
8373
8703
  return combineAbortSignals({ handles });
8374
8704
  }
8375
8705
  var FetchInitSdkValidationSchema = zod.z.looseObject(FetchInitZapierFieldsSchema.shape).optional();
8376
- var fetchPlugin = defineMethod({
8706
+ var fetchPlugin2 = defineMethod({
8377
8707
  name: "fetch",
8378
8708
  imports: [coreOptionsPluginRef, connectionsPluginRef, apiPluginRef],
8379
8709
  output: "raw",
@@ -10705,7 +11035,7 @@ function createAppsProxy(imports) {
10705
11035
  }
10706
11036
  var appsPlugin = defineProperty({
10707
11037
  name: "apps",
10708
- imports: [fetchPlugin, runActionPlugin],
11038
+ imports: [fetchPlugin2, runActionPlugin],
10709
11039
  // Build the proxy once from the imported methods (stable callables).
10710
11040
  setup: ({ imports }) => (
10711
11041
  // Cast: ZapierSdkApps is augmented by user-generated .d.ts files to give
@@ -12059,7 +12389,7 @@ var RelayFetchSchema = RelayRequestSchema;
12059
12389
  // src/plugins/request/index.ts
12060
12390
  var requestPlugin = defineMethod({
12061
12391
  name: "request",
12062
- imports: [fetchPlugin, coreOptionsPluginRef],
12392
+ imports: [fetchPlugin2, coreOptionsPluginRef],
12063
12393
  output: "raw",
12064
12394
  inputSchema: RelayRequestSchema,
12065
12395
  skipInputValidation: true,
@@ -13884,7 +14214,7 @@ async function drainRunner({
13884
14214
  `[zapier-sdk] Retrying drain for inbox ${inboxId} (attempt ${errorAttempts}, retry in ${delay}ms)${httpPart}: ${errorMessage(error)}`
13885
14215
  );
13886
14216
  }
13887
- await sleep(delay, signal);
14217
+ await sleep2(delay, signal);
13888
14218
  if (signal.aborted) return { kind: "aborted" };
13889
14219
  drainRequest.request();
13890
14220
  continue;
@@ -13951,7 +14281,7 @@ async function sseLoop({
13951
14281
  }
13952
14282
  attempt = 0;
13953
14283
  if (signal.aborted) return;
13954
- await sleep(safetyDrainMs, signal);
14284
+ await sleep2(safetyDrainMs, signal);
13955
14285
  continue;
13956
14286
  }
13957
14287
  if (connected) attempt = 0;
@@ -13971,7 +14301,7 @@ async function sseLoop({
13971
14301
  `[zapier-sdk] Reconnecting real-time wake-ups for inbox ${inboxId} (attempt ${attempt}, retry in ${delay}ms)${httpPart}: ${errorMsg}`
13972
14302
  );
13973
14303
  }
13974
- await sleep(delay, signal);
14304
+ await sleep2(delay, signal);
13975
14305
  }
13976
14306
  }
13977
14307
  async function safetyTimerLoop({
@@ -13980,7 +14310,7 @@ async function safetyTimerLoop({
13980
14310
  signal
13981
14311
  }) {
13982
14312
  while (!signal.aborted) {
13983
- await sleep(safetyDrainMs, signal);
14313
+ await sleep2(safetyDrainMs, signal);
13984
14314
  if (signal.aborted) return;
13985
14315
  drainRequest.request();
13986
14316
  }
@@ -15862,7 +16192,7 @@ var zapierSdkPlugin = definePlugin({
15862
16192
  createActionRunPlugin,
15863
16193
  getActionRunPlugin,
15864
16194
  runActionPlugin,
15865
- fetchPlugin,
16195
+ fetchPlugin2,
15866
16196
  requestPlugin,
15867
16197
  appsPlugin,
15868
16198
  // Triggers. `list*` plugins are exported before their `get*` / mutation
@@ -15946,7 +16276,7 @@ async function batch(tasks, options = {}) {
15946
16276
  try {
15947
16277
  let result;
15948
16278
  if (taskTimeoutMs !== void 0) {
15949
- const timeoutPromise = sleep(taskTimeoutMs).then(() => {
16279
+ const timeoutPromise = sleep2(taskTimeoutMs).then(() => {
15950
16280
  throw new ZapierTimeoutError(
15951
16281
  `Task timed out after ${taskTimeoutMs}ms`
15952
16282
  );
@@ -15961,7 +16291,7 @@ async function batch(tasks, options = {}) {
15961
16291
  const isTimeout = isZapierTimeoutError(error);
15962
16292
  if (retry && !isTimeout && newErrorCount < MAX_CONSECUTIVE_ERRORS) {
15963
16293
  const waitTime = calculateErrorBackoffMs(1e3, newErrorCount);
15964
- await sleep(waitTime);
16294
+ await sleep2(waitTime);
15965
16295
  taskQueue.push({
15966
16296
  index,
15967
16297
  task,
@@ -15984,7 +16314,7 @@ async function batch(tasks, options = {}) {
15984
16314
  if (!taskState) break;
15985
16315
  await executeTask(taskState);
15986
16316
  if (taskQueue.length > 0 && batchDelay > 0) {
15987
- await sleep(batchDelay);
16317
+ await sleep2(batchDelay);
15988
16318
  }
15989
16319
  }
15990
16320
  }
@@ -15993,7 +16323,7 @@ async function batch(tasks, options = {}) {
15993
16323
  for (let i = 0; i < workerCount; i++) {
15994
16324
  workers.push(worker());
15995
16325
  if (i < workerCount - 1 && batchDelay > 0) {
15996
- await sleep(batchDelay / 10);
16326
+ await sleep2(batchDelay / 10);
15997
16327
  }
15998
16328
  }
15999
16329
  await Promise.all(workers);
@@ -16228,7 +16558,7 @@ exports.eventEmissionHookPlugin = eventEmissionHookPlugin;
16228
16558
  exports.eventEmissionPlugin = eventEmissionPlugin;
16229
16559
  exports.eventEmissionPluginRef = eventEmissionPluginRef;
16230
16560
  exports.extractErrorDetail = extractErrorDetail;
16231
- exports.fetchPlugin = fetchPlugin;
16561
+ exports.fetchPlugin = fetchPlugin2;
16232
16562
  exports.findFirstConnectionPlugin = findFirstConnectionPlugin;
16233
16563
  exports.findManifestEntry = findManifestEntry;
16234
16564
  exports.findUniqueConnectionPlugin = findUniqueConnectionPlugin;