@zapier/kitcore 0.17.2 → 0.19.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,39 @@
1
1
  # @zapier/kitcore
2
2
 
3
+ ## 0.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1ec9410: Added `RetryHttpRequestOptions.onRetry` and exported `RetryHttpRequestAttempt` for observing retries scheduled by `retryHttpRequestPlugin`. The callback runs before the retry wait and receives the request, operation ID, failed attempt number, selected delay, and response or error. Promise results are not awaited, and thrown errors or rejected promises do not cancel the retry. When a response is present, read only its status and headers.
8
+
9
+ ### Patch Changes
10
+
11
+ - 1ec9410: `retryHttpRequestPlugin` now waits at least 100 milliseconds before retrying when generated backoff is capped by a zero or near-zero `maxDelayMilliseconds`. Use `maxAttempts: 1` to disable retries.
12
+
13
+ ## 0.18.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 2c8ea56: **Added `httpFetchPluginRef` (`kitcore/httpFetch`), the function
18
+ `dispatchHttpRequest` calls to reach the network.** Provide it and the default
19
+ dispatch stage calls that function instead of the ambient `fetch` — a
20
+ debug-wrapped fetch, a test double, a polyfill. Provide nothing and the stage
21
+ behaves as before.
22
+
23
+ ```ts
24
+ const httpFetch = defineProperty({
25
+ namespace: "kitcore",
26
+ name: "httpFetch",
27
+ value: myFetch,
28
+ });
29
+
30
+ // Or supply it by id, with no plugin of your own:
31
+ createSdk(root, { configuration: { [HTTP_FETCH_ID]: myFetch } });
32
+ ```
33
+
34
+ It is a value rather than a wrap, so the `dispatchHttpRequest` wrap slot stays
35
+ free for a host that replaces the stage outright.
36
+
3
37
  ## 0.17.2
4
38
 
5
39
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  CoreError: () => CoreError,
30
30
  CoreErrorCode: () => CoreErrorCode,
31
31
  CoreSignal: () => CoreSignal,
32
+ HTTP_FETCH_ID: () => HTTP_FETCH_ID,
32
33
  RETRY_HTTP_REQUEST_OPTIONS_ID: () => RETRY_HTTP_REQUEST_OPTIONS_ID,
33
34
  STABILITY_LEVELS: () => STABILITY_LEVELS,
34
35
  STABILITY_TITLES: () => STABILITY_TITLES,
@@ -89,6 +90,7 @@ __export(index_exports, {
89
90
  getRegistry: () => getRegistry,
90
91
  getRegistryPlugin: () => getRegistryPlugin,
91
92
  getSchemaDescription: () => getSchemaDescription,
93
+ httpFetchPluginRef: () => httpFetchPluginRef,
92
94
  initializeHttpRequestPlugin: () => initializeHttpRequestPlugin,
93
95
  isCoreCancelledSignal: () => isCoreCancelledSignal,
94
96
  isCoreError: () => isCoreError,
@@ -773,6 +775,11 @@ function toIterable(source) {
773
775
  return { [Symbol.asyncIterator]: () => source[Symbol.asyncIterator]() };
774
776
  }
775
777
 
778
+ // src/utils/promise-utils.ts
779
+ function isPromiseLike(value) {
780
+ return value !== null && typeof value === "object" && typeof value.then === "function";
781
+ }
782
+
776
783
  // src/utils/validation.ts
777
784
  var parseOrThrow = (schema, input, { adaptError } = {}) => {
778
785
  const result = schema.safeParse(input);
@@ -1239,7 +1246,7 @@ function createRawFunction(coreFn, options) {
1239
1246
  try {
1240
1247
  const parsed = schema ? validateOptions(schema, input, { adaptError }) : input;
1241
1248
  const result = coreFn(parsed, context);
1242
- if (result !== null && typeof result === "object" && typeof result.then === "function") {
1249
+ if (isPromiseLike(result)) {
1243
1250
  return result.then(
1244
1251
  (value) => {
1245
1252
  fireEnd();
@@ -2571,9 +2578,6 @@ function applyListOutputPolicy(page, policy) {
2571
2578
  var FRAMEWORK_CONFIGURATION_IDS = /* @__PURE__ */ new Set([
2572
2579
  CORE_OPTIONS_ID
2573
2580
  ]);
2574
- function isPromiseLike(value) {
2575
- return value !== null && typeof value === "object" && typeof value.then === "function";
2576
- }
2577
2581
  function normalizeOutput(output) {
2578
2582
  if (output === void 0) return { type: "raw" };
2579
2583
  if (typeof output === "string") return { type: output };
@@ -4944,6 +4948,8 @@ var authorizeHttpRequestPlugin = defineMethod({
4944
4948
 
4945
4949
  // src/transport/dispatch-http-request.ts
4946
4950
  var import_zod7 = require("zod");
4951
+ var HTTP_FETCH_ID = "kitcore/httpFetch";
4952
+ var httpFetchPluginRef = declareOptionalProperty({ id: HTTP_FETCH_ID });
4947
4953
  function toFetchInput(request) {
4948
4954
  const init = { ...request };
4949
4955
  const { url } = request;
@@ -4954,11 +4960,12 @@ function toFetchInput(request) {
4954
4960
  var dispatchHttpRequestPlugin = defineMethod({
4955
4961
  name: "dispatchHttpRequest",
4956
4962
  namespace: "kitcore",
4963
+ imports: [httpFetchPluginRef],
4957
4964
  inputSchema: import_zod7.z.custom(),
4958
4965
  skipInputValidation: true,
4959
- run: async ({ input }) => {
4966
+ run: async ({ input, imports }) => {
4960
4967
  const { url, init } = toFetchInput(input.request);
4961
- return fetch(url, init);
4968
+ return (imports.httpFetch ?? fetch)(url, init);
4962
4969
  }
4963
4970
  });
4964
4971
 
@@ -5057,6 +5064,7 @@ var DEFAULT_IDEMPOTENT_METHODS = [
5057
5064
  "TRACE"
5058
5065
  ];
5059
5066
  var BASE_BACKOFF_MILLISECONDS = 1e3;
5067
+ var MIN_BACKOFF_MILLISECONDS = 100;
5060
5068
  var JITTER_FACTOR = 0.5;
5061
5069
  var EPOCH_THRESHOLD_SECONDS = 1e9;
5062
5070
  function directedDelayMilliseconds(response) {
@@ -5081,6 +5089,12 @@ function backoffMilliseconds(attemptNumber) {
5081
5089
  const base = BASE_BACKOFF_MILLISECONDS * 2 ** (attemptNumber - 1);
5082
5090
  return base + Math.random() * JITTER_FACTOR * base;
5083
5091
  }
5092
+ function clampBackoffMilliseconds(attemptNumber, maxDelayMilliseconds) {
5093
+ return Math.max(
5094
+ Math.min(backoffMilliseconds(attemptNumber), maxDelayMilliseconds),
5095
+ MIN_BACKOFF_MILLISECONDS
5096
+ );
5097
+ }
5084
5098
  function abortReason(signal) {
5085
5099
  const reason = signal?.reason;
5086
5100
  return reason ?? new Error("The request was aborted.");
@@ -5115,6 +5129,20 @@ var retryHttpRequestPlugin = defineHook({
5115
5129
  const maxDelayMilliseconds = options.maxDelayMilliseconds ?? DEFAULT_MAX_DELAY_MILLISECONDS;
5116
5130
  const idempotentMethods = options.idempotentMethods ?? DEFAULT_IDEMPOTENT_METHODS;
5117
5131
  const statuses = isIdempotent(input.request, idempotentMethods) ? options.retryStatuses ?? DEFAULT_RETRY_STATUSES : options.nonIdempotentRetryStatuses ?? DEFAULT_NON_IDEMPOTENT_RETRY_STATUSES;
5132
+ const notifyRetry = (notice) => {
5133
+ try {
5134
+ const observed = options.onRetry?.({
5135
+ ...notice,
5136
+ request: input.attempt.operation.request,
5137
+ operationId: input.attempt.operation.operationId
5138
+ });
5139
+ if (isPromiseLike(observed)) {
5140
+ void observed.then(void 0, () => {
5141
+ });
5142
+ }
5143
+ } catch {
5144
+ }
5145
+ };
5118
5146
  for (let attemptNumber = 1; ; attemptNumber++) {
5119
5147
  const attempt = {
5120
5148
  ...input.attempt,
@@ -5136,10 +5164,16 @@ var retryHttpRequestPlugin = defineHook({
5136
5164
  )) {
5137
5165
  throw error;
5138
5166
  }
5139
- await sleep(
5140
- Math.min(backoffMilliseconds(attemptNumber), maxDelayMilliseconds),
5141
- attempt.signal
5167
+ const errorDelay = clampBackoffMilliseconds(
5168
+ attemptNumber,
5169
+ maxDelayMilliseconds
5142
5170
  );
5171
+ notifyRetry({
5172
+ attemptNumber,
5173
+ delayMilliseconds: errorDelay,
5174
+ error
5175
+ });
5176
+ await sleep(errorDelay, attempt.signal);
5143
5177
  continue;
5144
5178
  }
5145
5179
  if (!statuses.includes(response.status) || !canRetry(
@@ -5152,10 +5186,8 @@ var retryHttpRequestPlugin = defineHook({
5152
5186
  const directed = directedDelayMilliseconds(response);
5153
5187
  if (directed != null && directed > maxDelayMilliseconds)
5154
5188
  return response;
5155
- const delay = Math.min(
5156
- directed ?? backoffMilliseconds(attemptNumber),
5157
- maxDelayMilliseconds
5158
- );
5189
+ const delay = directed ?? clampBackoffMilliseconds(attemptNumber, maxDelayMilliseconds);
5190
+ notifyRetry({ attemptNumber, delayMilliseconds: delay, response });
5159
5191
  await response.body?.cancel().catch(() => {
5160
5192
  });
5161
5193
  await sleep(delay, attempt.signal);
@@ -5311,6 +5343,7 @@ var resolveConnectionPlugin = defineMethod({
5311
5343
  CoreError,
5312
5344
  CoreErrorCode,
5313
5345
  CoreSignal,
5346
+ HTTP_FETCH_ID,
5314
5347
  RETRY_HTTP_REQUEST_OPTIONS_ID,
5315
5348
  STABILITY_LEVELS,
5316
5349
  STABILITY_TITLES,
@@ -5371,6 +5404,7 @@ var resolveConnectionPlugin = defineMethod({
5371
5404
  getRegistry,
5372
5405
  getRegistryPlugin,
5373
5406
  getSchemaDescription,
5407
+ httpFetchPluginRef,
5374
5408
  initializeHttpRequestPlugin,
5375
5409
  isCoreCancelledSignal,
5376
5410
  isCoreError,