@conduit-client/salesforce-lightning-service-worker 3.16.0-dev1 → 3.17.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/README.md CHANGED
@@ -30,26 +30,6 @@ const response = await client.fetch('/services/data/v65.0/sobjects/Account', {
30
30
  });
31
31
  ```
32
32
 
33
- ### 2. Service Worker (Advanced)
34
-
35
- The only difference compared to the default behavior is that all CSRF processing is offloaded to a service worker,
36
- enabling ConduitClient to make unmodified calls to `fetch`.
37
-
38
- #### Modern Bundlers (Vite, Webpack 5+)
39
-
40
- ```typescript
41
- import { ConduitClient } from '@conduit-client/salesforce-lightning-service-worker';
42
-
43
- // Register the built-in service worker
44
- await ConduitClient.registerServiceWorker(`/sw.js`);
45
- ```
46
-
47
- **Important Notes:**
48
-
49
- 1. **No Separate Files**: The built-in classic service worker eliminates the need to create and maintain separate service worker files
50
- 2. **Classic Registration**: Uses `type: 'classic'` for better browser compatibility and to avoid ES module security constraints
51
- 3. **Fallback Protection**: If service worker registration fails, the default behavior remains in place
52
-
53
33
  ## CSRF Protection Features
54
34
 
55
35
  This package provides automatic CSRF protection with the following features:
@@ -66,52 +46,6 @@ This package provides automatic CSRF protection with the following features:
66
46
  - **URL Protection**: Currently protects all Salesforce API endpoints under `/services`
67
47
  - **Intelligent Detection**: Only applies CSRF protection where needed
68
48
 
69
- ### Service Worker Integration
70
-
71
- - **Install Handler**: Skips waiting to activate immediately
72
- - **Activate Handler**: Claims all clients immediately
73
- - **Fetch Interception**: Intercepts and enhances requests with CSRF tokens
74
-
75
- ## Development
76
-
77
- ### Running the Development Server
78
-
79
- Use the `dev` script to run and debug the service worker code:
80
-
81
- ```bash
82
- npm run dev
83
- ```
84
-
85
- This will:
86
-
87
- 1. Build the service worker code
88
- 2. Start a development server on port 3000
89
- 3. Serve a test page with service worker registration
90
- 4. Automatically open your browser
91
-
92
- ### Development Features
93
-
94
- - **Live Service Worker Updates**: The development server includes automatic service worker update detection and page reloading when you make changes to the source code
95
- - **Test API Endpoint**: A dummy `/api/data` endpoint is configured to test fetch interception by the service worker
96
- - **Debug Console**: The test page includes buttons to check service worker status and test API calls
97
- - **TypeScript Transformation**: Service worker code is served as transformed TypeScript via Vite
98
-
99
- ### Development Workflow
100
-
101
- 1. Make changes to `src/index.ts` (service worker logic)
102
- 2. The page will automatically detect service worker updates and reload
103
- 3. Use the test page buttons to verify your changes:
104
- - **Check SW Status**: View service worker registration details
105
- - **Fetch API Data**: Test the `/api/data` endpoint through the service worker
106
- - **Clear Output**: Clear the debug console
107
-
108
- ### Development File Structure
109
-
110
- - `src/index.ts` - Main service worker code and registration utilities
111
- - `scripts/dev.ts` - Development server with API mock and service worker serving
112
- - `scripts/dev-service-worker.ts` - Entry point for the development service worker
113
- - `scripts/dev-test-page.html` - Test page for debugging service worker functionality
114
-
115
49
  ### Building for Production
116
50
 
117
51
  ```bash
package/dist/index.js CHANGED
@@ -321,119 +321,13 @@ function createFetchService(config) {
321
321
  ).service;
322
322
  }
323
323
  let clientFetch;
324
- let serviceWorkerLoading = false;
325
- let pendingRequests = [];
326
- let instance;
327
- class ConduitClient {
328
- /**
329
- * Makes an HTTP request
330
- *
331
- * @param input - The URL, Request object, or relative path to request
332
- * @param init - Optional request configuration that will be merged with defaults
333
- * @returns Promise that resolves to the Response object
334
- */
335
- fetch(input, init = {}) {
336
- if (serviceWorkerLoading) {
337
- return new Promise((resolve) => {
338
- pendingRequests.push({ input, init, resolve });
339
- });
340
- }
341
- return Promise.resolve(clientFetch(input, init));
342
- }
343
- /**
344
- * Configures global settings for all ConduitClient instances.
345
- * This will recreate the internal fetch service with the new configuration.
346
- *
347
- * @param config - Configuration options for CSRF handling and other features
348
- */
349
- static initialize(config) {
350
- if (instance) {
351
- throw new Error("ConduitClient.initialize can only be called once");
352
- }
353
- instance = new ConduitClient();
354
- if (config.serviceWorkerUrl) {
355
- return registerServiceWorker(config);
356
- } else {
357
- clientFetch = createFetchService(config);
358
- return Promise.resolve();
359
- }
360
- }
361
- /**
362
- * Factory method to create a new ConduitClient instance
363
- *
364
- * @returns A new ConduitClient instance
365
- */
366
- static instance() {
367
- if (!instance) {
368
- throw new Error("ConduitClient.initialize must be called first");
369
- }
370
- return instance;
324
+ function buildFetchService(config) {
325
+ if (!clientFetch) {
326
+ clientFetch = createFetchService(config);
371
327
  }
372
- }
373
- async function registerServiceWorker(config) {
374
- if ("serviceWorker" in navigator) {
375
- try {
376
- serviceWorkerLoading = true;
377
- const registration = await navigator.serviceWorker.register(config.serviceWorkerUrl, {
378
- type: "classic"
379
- });
380
- clientFetch = fetch;
381
- console.log("[Conduit Client] Service registration succeeded:", registration);
382
- if (registration.active) {
383
- await postConfigToServiceWorker(registration.active, config);
384
- } else if (registration.waiting || registration.installing) {
385
- const serviceWorker = registration.waiting || registration.installing;
386
- await waitForServiceWorkerActive(serviceWorker);
387
- if (registration.active) {
388
- await postConfigToServiceWorker(registration.active, config);
389
- }
390
- }
391
- } catch (error) {
392
- console.log(
393
- "[Conduit Client] Service Worker registration failed (using decorated `fetch`):",
394
- error
395
- );
396
- } finally {
397
- processQueuedRequests();
398
- }
399
- } else {
400
- console.log("[Conduit Client] Service Worker not supported (using decorated `fetch`):");
401
- }
402
- }
403
- async function postConfigToServiceWorker(serviceWorker, config) {
404
- try {
405
- const { serviceWorkerUrl: _, ...configData } = config;
406
- serviceWorker.postMessage({
407
- type: "fetch-config",
408
- config: configData
409
- });
410
- } catch (error) {
411
- console.warn("[Conduit Client] Failed to post config to service worker:", error);
412
- }
413
- }
414
- function waitForServiceWorkerActive(serviceWorker) {
415
- return new Promise((resolve) => {
416
- if (serviceWorker.state === "activated") {
417
- resolve();
418
- return;
419
- }
420
- function handleStateChange() {
421
- if (serviceWorker.state === "activated") {
422
- serviceWorker.removeEventListener("statechange", handleStateChange);
423
- resolve();
424
- }
425
- }
426
- serviceWorker.addEventListener("statechange", handleStateChange);
427
- });
428
- }
429
- function processQueuedRequests() {
430
- serviceWorkerLoading = false;
431
- pendingRequests.forEach(({ input, init, resolve }) => {
432
- resolve(clientFetch(input, init));
433
- });
434
- pendingRequests = [];
328
+ return clientFetch;
435
329
  }
436
330
  export {
437
- ConduitClient
331
+ buildFetchService as default
438
332
  };
439
333
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../utils/dist/index.js","../../services/fetch-network/dist/v1/index.js","../../services/retry/dist/v1/index.js","../src/csrf/header.interceptor.ts","../src/csrf/retry.interceptor.ts","../src/csrf/retry.policy.ts","../src/csrf/token-manager.ts","../src/fetch.ts","../src/index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2022, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nfunction bfs(start, predicate, getChildren) {\n const queue = [...start];\n const visited = /* @__PURE__ */ new Set([...start]);\n const matches2 = /* @__PURE__ */ new Set();\n while (queue.length) {\n const curr = queue.shift();\n if (predicate(curr)) {\n matches2.add(curr);\n }\n const children = getChildren(curr);\n for (const child of children) {\n if (!visited.has(child)) {\n visited.add(child);\n queue.push(child);\n }\n }\n }\n return matches2;\n}\nfunction lineFormatter(position, message, filePath) {\n return `${message} (${filePath}:${position.line}:${position.column})`;\n}\nclass DefaultFileParserLogger {\n constructor(services, filePath) {\n this.services = services;\n this.filePath = filePath;\n }\n trace(position, message) {\n this.services.logger.trace(this.format(position, message));\n }\n debug(position, message) {\n this.services.logger.debug(this.format(position, message));\n }\n info(position, message) {\n this.services.logger.info(this.format(position, message));\n }\n warn(position, message) {\n this.services.logger.warn(this.format(position, message));\n }\n error(position, message) {\n this.services.logger.error(this.format(position, message));\n }\n format(position, message) {\n return lineFormatter(position, message, this.filePath);\n }\n}\nfunction matches(test, s) {\n if (test === void 0) {\n return false;\n } else if (typeof test === \"string\") {\n return s === test;\n } else if (test instanceof RegExp) {\n return test.test(s);\n } else if (typeof test === \"function\") {\n return test(s);\n }\n return test.some((m) => matches(m, s));\n}\nfunction includes(incexc, s) {\n if (matches(incexc.exclude, s)) {\n return false;\n }\n if (matches(incexc.include, s)) {\n return true;\n }\n if (incexc.include) {\n return false;\n }\n return true;\n}\nconst { create, freeze, keys, entries } = Object;\nconst { hasOwnProperty } = Object.prototype;\nconst { isArray } = Array;\nconst { push, indexOf, slice } = Array.prototype;\nconst { stringify, parse } = JSON;\nconst WeakSetConstructor = WeakSet;\nconst LogLevelMap = {\n TRACE: 4,\n DEBUG: 3,\n INFO: 2,\n WARN: 1,\n ERROR: 0\n};\nclass ConsoleLogger {\n constructor(level = \"WARN\", printer = console.log, formatter = (level2, message) => `${level2}: ${message}`) {\n this.level = level;\n this.printer = printer;\n this.formatter = formatter;\n this.messages = [];\n }\n trace(message) {\n this.log(\"TRACE\", message);\n }\n debug(message) {\n this.log(\"DEBUG\", message);\n }\n info(message) {\n this.log(\"INFO\", message);\n }\n warn(message) {\n this.log(\"WARN\", message);\n }\n error(message) {\n this.log(\"ERROR\", message);\n }\n log(level, message) {\n if (LogLevelMap[level] > LogLevelMap[this.level]) {\n return;\n }\n this.printer(this.formatter(level, message));\n }\n}\nfunction loggerService(level, printer, formatter) {\n return new ConsoleLogger(level, printer, formatter);\n}\nclass Ok {\n constructor(value) {\n this.value = value;\n }\n isOk() {\n return true;\n }\n isErr() {\n return !this.isOk();\n }\n}\nclass Err {\n constructor(error) {\n this.error = error;\n }\n isOk() {\n return false;\n }\n isErr() {\n return !this.isOk();\n }\n}\nconst ok = (value) => new Ok(value);\nconst err = (err2) => new Err(err2);\nclass DataNotFoundError extends Error {\n constructor(message) {\n super(message);\n this.name = \"DataNotFoundError\";\n }\n}\nclass DataIncompleteError extends Error {\n constructor(message, partialData) {\n super(message);\n this.partialData = partialData;\n this.name = \"DataIncompleteError\";\n }\n}\nfunction isDataNotFoundError(error) {\n return error instanceof DataNotFoundError || error.name === \"DataNotFoundError\";\n}\nfunction isDataIncompleteError(error) {\n return error instanceof DataIncompleteError || error.name === \"DataIncompleteError\";\n}\nfunction isCacheHitOrError(value) {\n if (value.isErr() && (isDataIncompleteError(value.error) || isDataNotFoundError(value.error))) {\n return false;\n }\n return true;\n}\nfunction isCacheMiss(value) {\n return !isCacheHitOrError(value);\n}\nfunction isResult(value) {\n return value !== null && value !== void 0 && typeof value === \"object\" && \"isOk\" in value && \"isErr\" in value && typeof value.isOk === \"function\" && typeof value.isErr === \"function\" && (value.isOk() === true && value.isErr() === false && \"value\" in value || value.isOk() === false && value.isErr() === true && \"error\" in value);\n}\nfunction setOverlaps(setA, setB) {\n for (const element of setA) {\n if (setB.has(element)) {\n return true;\n }\n }\n return false;\n}\nfunction setDifference(setA, setB) {\n const differenceSet = /* @__PURE__ */ new Set();\n for (const element of setA) {\n if (!setB.has(element)) {\n differenceSet.add(element);\n }\n }\n return differenceSet;\n}\nfunction addAllToSet(targetSet, sourceSet) {\n for (const element of sourceSet) {\n targetSet.add(element);\n }\n}\nconst toTypeScriptSafeIdentifier = (s) => s.length >= 1 ? s[0].replace(/[^$_\\p{ID_Start}]/u, \"_\") + s.slice(1).replace(/[^$\\u200c\\u200d\\p{ID_Continue}]/gu, \"_\") : \"\";\nfunction toPascalCase(camelCase) {\n return camelCase.length >= 1 ? camelCase.charAt(0).toUpperCase() + camelCase.slice(1) : \"\";\n}\nfunction isSubscribable(obj) {\n return typeof obj === \"object\" && obj !== null && \"subscribe\" in obj && typeof obj.subscribe === \"function\" && \"refresh\" in obj && typeof obj.refresh === \"function\";\n}\nfunction isSubscribableResult(x) {\n if (!isResult(x)) {\n return false;\n }\n return isSubscribable(x.isOk() ? x.value : x.error);\n}\nfunction buildSubscribableResult(result, subscribe, refresh) {\n if (result.isOk()) {\n return ok({ data: result.value, subscribe, refresh });\n } else {\n return err({ failure: result.error, subscribe, refresh });\n }\n}\nfunction resolvedPromiseLike(result) {\n if (isPromiseLike(result)) {\n return result.then((nextResult) => nextResult);\n }\n return {\n then: (onFulfilled, _onRejected) => {\n try {\n return resolvedPromiseLike(onFulfilled(result));\n } catch (e) {\n if (onFulfilled === void 0) {\n return resolvedPromiseLike(result);\n }\n return rejectedPromiseLike(e);\n }\n }\n };\n}\nfunction rejectedPromiseLike(reason) {\n if (isPromiseLike(reason)) {\n return reason.then((nextResult) => nextResult);\n }\n return {\n then: (_onFulfilled, onRejected) => {\n if (typeof onRejected === \"function\") {\n try {\n return resolvedPromiseLike(onRejected(reason));\n } catch (e) {\n return rejectedPromiseLike(e);\n }\n }\n return rejectedPromiseLike(reason);\n }\n };\n}\nfunction isPromiseLike(x) {\n return typeof (x == null ? void 0 : x.then) === \"function\";\n}\nfunction racesync(values) {\n for (const value of values) {\n let settled = void 0;\n if (isPromiseLike(value)) {\n value.then(\n (_) => {\n settled = value;\n },\n (_) => {\n settled = value;\n }\n );\n } else {\n settled = resolvedPromiseLike(value);\n }\n if (settled !== void 0) {\n return settled;\n }\n }\n return Promise.race(values);\n}\nfunction withResolvers() {\n let resolve, reject;\n const promise = new Promise((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve, reject };\n}\nfunction deepEquals(x, y) {\n if (x === void 0) {\n return y === void 0;\n } else if (x === null) {\n return y === null;\n } else if (y === null) {\n return x === null;\n } else if (isArray(x)) {\n if (!isArray(y) || x.length !== y.length) {\n return false;\n }\n for (let i = 0; i < x.length; ++i) {\n if (!deepEquals(x[i], y[i])) {\n return false;\n }\n }\n return true;\n } else if (typeof x === \"object\") {\n if (typeof y !== \"object\") {\n return false;\n }\n const xkeys = Object.keys(x);\n const ykeys = Object.keys(y);\n if (xkeys.length !== ykeys.length) {\n return false;\n }\n for (let i = 0; i < xkeys.length; ++i) {\n const key = xkeys[i];\n if (!deepEquals(x[key], y[key])) {\n return false;\n }\n }\n return true;\n }\n return x === y;\n}\nfunction stableJSONStringify(node) {\n if (node && node.toJSON && typeof node.toJSON === \"function\") {\n node = node.toJSON();\n }\n if (node === void 0) {\n return;\n }\n if (typeof node === \"number\") {\n return isFinite(node) ? \"\" + node : \"null\";\n }\n if (typeof node !== \"object\") {\n return stringify(node);\n }\n let i;\n let out;\n if (isArray(node)) {\n out = \"[\";\n for (i = 0; i < node.length; i++) {\n if (i) {\n out += \",\";\n }\n out += stableJSONStringify(node[i]) || \"null\";\n }\n return out + \"]\";\n }\n if (node === null) {\n return \"null\";\n }\n const objKeys = keys(node).sort();\n out = \"\";\n for (i = 0; i < objKeys.length; i++) {\n const key = objKeys[i];\n const value = stableJSONStringify(node[key]);\n if (!value) {\n continue;\n }\n if (out) {\n out += \",\";\n }\n out += stringify(key) + \":\" + value;\n }\n return \"{\" + out + \"}\";\n}\nfunction toError(x) {\n if (x instanceof Error) {\n return x;\n }\n return new Error(typeof x === \"string\" ? x : JSON.stringify(x));\n}\nfunction deepCopy(x) {\n const stringified = stringify(x);\n return stringified ? parse(stringified) : void 0;\n}\nfunction readableStreamToAsyncIterable(stream) {\n if (stream.locked) {\n return err(new Error(\"ReadableStream is already locked\"));\n }\n if (Symbol.asyncIterator in stream) {\n return ok(stream);\n }\n const reader = stream.getReader();\n return ok({\n [Symbol.asyncIterator]: () => ({\n next: async () => {\n try {\n const result = await reader.read();\n if (result.done) {\n try {\n reader.releaseLock();\n } catch {\n }\n return { done: true, value: void 0 };\n }\n return {\n done: false,\n value: result.value\n };\n } catch (e) {\n try {\n reader.releaseLock();\n } catch {\n }\n throw e;\n }\n },\n return: async (value) => {\n try {\n await reader.cancel();\n } catch {\n }\n try {\n reader.releaseLock();\n } catch {\n }\n return { done: true, value };\n },\n throw: async (exception) => {\n try {\n await reader.cancel();\n } catch {\n }\n try {\n reader.releaseLock();\n } catch {\n }\n throw exception;\n }\n })\n });\n}\nfunction satisfies(provided, requested) {\n const providedN = provided.split(\".\").map((s) => parseInt(s));\n const requestedN = requested.split(\".\").map((s) => parseInt(s));\n return providedN[0] === requestedN[0] && providedN[1] >= requestedN[1];\n}\nfunction stringIsVersion(s) {\n const versionParts = s.split(\".\");\n return (versionParts.length === 2 || versionParts.length === 3) && versionParts.every((part) => part.match(/^\\d+$/));\n}\nvar HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {\n HttpStatusCode2[HttpStatusCode2[\"Ok\"] = 200] = \"Ok\";\n HttpStatusCode2[HttpStatusCode2[\"Created\"] = 201] = \"Created\";\n HttpStatusCode2[HttpStatusCode2[\"NoContent\"] = 204] = \"NoContent\";\n HttpStatusCode2[HttpStatusCode2[\"NotModified\"] = 304] = \"NotModified\";\n HttpStatusCode2[HttpStatusCode2[\"BadRequest\"] = 400] = \"BadRequest\";\n HttpStatusCode2[HttpStatusCode2[\"Unauthorized\"] = 401] = \"Unauthorized\";\n HttpStatusCode2[HttpStatusCode2[\"Forbidden\"] = 403] = \"Forbidden\";\n HttpStatusCode2[HttpStatusCode2[\"NotFound\"] = 404] = \"NotFound\";\n HttpStatusCode2[HttpStatusCode2[\"ServerError\"] = 500] = \"ServerError\";\n HttpStatusCode2[HttpStatusCode2[\"GatewayTimeout\"] = 504] = \"GatewayTimeout\";\n return HttpStatusCode2;\n})(HttpStatusCode || {});\nfunction getFetchResponseFromAuraError(err2) {\n if (err2.data !== void 0 && err2.data.statusCode !== void 0) {\n let data = {};\n data = err2.data;\n if (err2.id !== void 0) {\n data.id = err2.id;\n }\n return new FetchResponse(data.statusCode, data);\n }\n return new FetchResponse(500, {\n error: err2.message\n });\n}\nasync function coerceResponseToFetchResponse(response) {\n const { status } = response;\n const responseHeaders = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n let responseBody = null;\n if (status !== 204) {\n const contentType = responseHeaders[\"content-type\"];\n responseBody = contentType && contentType.startsWith(\"application/json\") ? await response.json() : await response.text();\n }\n return new FetchResponse(status, responseBody, responseHeaders);\n}\nfunction getStatusText(status) {\n switch (status) {\n case 200:\n return \"OK\";\n case 201:\n return \"Created\";\n case 304:\n return \"Not Modified\";\n case 400:\n return \"Bad Request\";\n case 404:\n return \"Not Found\";\n case 500:\n return \"Server Error\";\n default:\n return `Unexpected HTTP Status Code: ${status}`;\n }\n}\nclass FetchResponse extends Error {\n constructor(status, body, headers) {\n super();\n this.status = status;\n this.body = body;\n this.headers = headers || {};\n this.ok = status >= 200 && this.status <= 299;\n this.statusText = getStatusText(status);\n }\n}\nconst deeplyFrozen = new WeakSetConstructor();\nfunction deepFreeze(value) {\n if (typeof value !== \"object\" || value === null || deeplyFrozen.has(value)) {\n return;\n }\n deeplyFrozen.add(value);\n if (isArray(value)) {\n for (let i = 0, len = value.length; i < len; i += 1) {\n deepFreeze(value[i]);\n }\n } else {\n const keys$1 = keys(value);\n for (let i = 0, len = keys$1.length; i < len; i += 1) {\n deepFreeze(value[keys$1[i]]);\n }\n }\n freeze(value);\n}\nfunction isScalar(value) {\n return typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\" || value === null || value === void 0;\n}\nfunction isScalarObject(value) {\n return Object.values(value).every((value2) => isScalar(value2));\n}\nfunction isScalarArray(value) {\n return value.every((item) => isScalar(item));\n}\nfunction encodeQueryParam(paramName, value, explode) {\n switch (typeof value) {\n case \"string\":\n return [`${paramName}=${encodeURIComponent(value)}`];\n case \"number\":\n case \"boolean\":\n return [`${paramName}=${value}`];\n case \"object\":\n if (value === null) {\n return [];\n }\n if (isArray(value)) {\n if (!isScalarArray(value)) {\n throw new Error(`Unsupported non-scalar array type for ${paramName}`);\n }\n if (explode) {\n return value.map(\n (item) => `${paramName}=${item ? encodeURIComponent(item) : item}`\n );\n }\n return [\n `${paramName}=${value.map((item) => item ? encodeURIComponent(item) : item).join(\",\")}`\n ];\n }\n if (!isScalarObject(value)) {\n throw new Error(`Unsupported non-scalar object type for ${paramName}`);\n }\n if (explode) {\n return entries(value).map(\n ([key, value2]) => `${key}=${value2 ? encodeURIComponent(value2) : value2}`\n );\n }\n return [\n `${paramName}=${entries(value).flat().map((item) => item ? encodeURIComponent(item) : item).join(\",\")}`\n ];\n default:\n return [];\n }\n}\nclass InternalError extends Error {\n constructor(data) {\n super();\n this.data = data;\n this.type = \"internal\";\n }\n}\nclass UserVisibleError extends Error {\n constructor(data) {\n super();\n this.data = data;\n this.type = \"user-visible\";\n }\n}\nfunction isUserVisibleError(error) {\n return error instanceof Error && \"type\" in error && error.type === \"user-visible\";\n}\nfunction logError(error) {\n if (isUserVisibleError(error)) {\n return;\n }\n console.error(\"OneStore Command threw an error that we did not expect\", error);\n}\nfunction applyDecorators(baseCommand, decorators, options) {\n if (!decorators || decorators.length === 0) {\n return baseCommand;\n }\n return decorators.reduce((command, decorator) => decorator(command, options), baseCommand);\n}\nexport {\n isArray as ArrayIsArray,\n indexOf as ArrayPrototypeIndexOf,\n push as ArrayPrototypePush,\n slice as ArrayPrototypeSlice,\n ConsoleLogger,\n DataIncompleteError,\n DataNotFoundError,\n DefaultFileParserLogger,\n Err,\n FetchResponse,\n HttpStatusCode,\n InternalError,\n parse as JSONParse,\n stringify as JSONStringify,\n LogLevelMap,\n create as ObjectCreate,\n entries as ObjectEntries,\n freeze as ObjectFreeze,\n keys as ObjectKeys,\n hasOwnProperty as ObjectPrototypeHasOwnProperty,\n Ok,\n UserVisibleError,\n WeakSetConstructor,\n addAllToSet,\n applyDecorators,\n bfs,\n buildSubscribableResult,\n coerceResponseToFetchResponse,\n deepCopy,\n deepEquals,\n deepFreeze,\n encodeQueryParam,\n err,\n getFetchResponseFromAuraError,\n includes,\n isCacheHitOrError,\n isCacheMiss,\n isDataIncompleteError,\n isDataNotFoundError,\n isPromiseLike,\n isResult,\n isSubscribable,\n isSubscribableResult,\n isUserVisibleError,\n lineFormatter,\n logError,\n loggerService,\n ok,\n racesync,\n readableStreamToAsyncIterable,\n rejectedPromiseLike,\n resolvedPromiseLike,\n satisfies,\n setDifference,\n setOverlaps,\n stableJSONStringify,\n stringIsVersion,\n toError,\n toPascalCase,\n toTypeScriptSafeIdentifier,\n withResolvers\n};\n//# sourceMappingURL=index.js.map\n","/*!\n * Copyright (c) 2022, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nimport { resolvedPromiseLike } from \"@conduit-client/utils\";\nfunction buildServiceDescriptor(interceptors = {\n request: [],\n retry: void 0,\n response: [],\n finally: []\n}, retryService) {\n return {\n type: \"fetch\",\n version: \"1.0\",\n service: function(...args) {\n var _a;\n const context = (_a = interceptors.createContext) == null ? void 0 : _a.call(interceptors);\n const {\n request: requestInterceptors = [],\n retry: retryInterceptor = void 0,\n response: responseInterceptors = [],\n finally: finallyInterceptors = []\n } = interceptors;\n const pending = requestInterceptors.reduce(\n (previousPromise, interceptor) => previousPromise.then((args2) => interceptor(args2, context)),\n resolvedPromiseLike(args)\n );\n return Promise.resolve(pending).then((args2) => {\n if (retryInterceptor) {\n return retryInterceptor(args2, retryService, context);\n } else {\n if (retryService) {\n return retryService.applyRetry(() => fetch(...args2));\n }\n return fetch(...args2);\n }\n }).then((response) => {\n return responseInterceptors.reduce(\n (previousPromise, interceptor) => previousPromise.then((response2) => interceptor(response2, context)),\n resolvedPromiseLike(response)\n );\n }).finally(() => {\n if (finallyInterceptors.length > 0) {\n return finallyInterceptors.reduce(\n (previousPromise, interceptor) => previousPromise.then(() => interceptor(context)),\n Promise.resolve()\n );\n }\n });\n }\n };\n}\nlet textEncoder;\nfunction getTextEncoder() {\n if (!textEncoder) {\n if (typeof TextEncoder === \"undefined\") {\n throw new Error(\n \"TextEncoder is not available in this environment. Request body compression requires TextEncoder support.\"\n );\n }\n textEncoder = new TextEncoder();\n }\n return textEncoder;\n}\nfunction buildCompressionInterceptor(config) {\n const threshold = config.threshold ?? 1024;\n return async (args) => {\n const [resource, options = {}] = args;\n if (!options.body || typeof options.body !== \"string\") {\n return resolvedPromiseLike(args);\n }\n if (typeof CompressionStream === \"undefined\") {\n return resolvedPromiseLike(args);\n }\n const headers = new Headers(options.headers);\n if (headers.has(\"Content-Encoding\")) {\n return resolvedPromiseLike(args);\n }\n const encodedBody = getTextEncoder().encode(options.body);\n if (encodedBody.byteLength < threshold) {\n return resolvedPromiseLike(args);\n }\n try {\n const stream = new Blob([encodedBody]).stream().pipeThrough(new CompressionStream(config.algorithm));\n const compressedBody = await new Response(stream).blob();\n headers.set(\"Content-Encoding\", config.algorithm);\n headers.delete(\"Content-Length\");\n const compressedOptions = {\n ...options,\n body: compressedBody,\n headers\n };\n return resolvedPromiseLike([resource, compressedOptions]);\n } catch {\n return resolvedPromiseLike(args);\n }\n };\n}\nfunction setHeader(headerName, headerValue, [resource, options = {}], {\n throwOnExisting = false,\n errorMessage = `Unexpected ${headerName} header encountered`\n} = {}) {\n let hasHeaderBeenSet = false;\n if (resource instanceof Request && !(options == null ? void 0 : options.headers)) {\n if (throwOnExisting && resource.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n resource.headers.set(headerName, headerValue);\n hasHeaderBeenSet = true;\n }\n if ((options == null ? void 0 : options.headers) instanceof Headers) {\n if (throwOnExisting && options.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n options.headers.set(headerName, headerValue);\n } else {\n if (throwOnExisting && (options == null ? void 0 : options.headers) && Reflect.has(options.headers, headerName)) {\n throw new Error(errorMessage);\n }\n if (!hasHeaderBeenSet) {\n options.headers = {\n ...options == null ? void 0 : options.headers,\n [headerName]: headerValue\n };\n }\n }\n return [resource, options];\n}\nconst UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE = \"Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor\";\nfunction setHeaderAuthorization({ token }, fetchParams) {\n const authorizationValue = `Bearer ${token}`;\n return setHeader(\"Authorization\", authorizationValue, fetchParams, {\n throwOnExisting: true,\n errorMessage: UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE\n });\n}\nfunction buildJwtRequestHeaderInterceptor(jwtManager, jwtRequestModifier = (_e, fetchArgs) => fetchArgs) {\n return (args) => {\n return resolvedPromiseLike(jwtManager.getJwt()).then((token) => {\n const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);\n return token.extraInfo ? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization) : fetchArgsWithRequestHeaderAuthorization;\n });\n };\n}\nclass AbortError extends Error {\n constructor(message = \"This operation was aborted\") {\n super(message);\n this.name = \"AbortError\";\n }\n}\nfunction buildMockFetchService(initialResponses = []) {\n let responses = [...initialResponses];\n const networkAdapter = (...args) => {\n var _a;\n const [_, fetchOptions = {}] = args;\n networkAdapter.requests.push(args);\n if ((_a = fetchOptions.signal) == null ? void 0 : _a.aborted) {\n return Promise.reject(new AbortError());\n }\n const result = responses.shift();\n if (result === void 0) {\n throw new Error(\"No more mock responses queued\");\n }\n networkAdapter.availableResponses = responses.length;\n networkAdapter.responsesUsed++;\n if (result instanceof Error) {\n return Promise.reject(result);\n }\n const delay = result.delay || 0;\n return new Promise((resolve, reject) => {\n let abortHandler = null;\n if (fetchOptions.signal) {\n abortHandler = () => {\n reject(new AbortError());\n };\n fetchOptions.signal.addEventListener(\"abort\", abortHandler);\n }\n const completeRequest = () => {\n var _a2;\n if (abortHandler && fetchOptions.signal) {\n fetchOptions.signal.removeEventListener(\"abort\", abortHandler);\n }\n if ((_a2 = fetchOptions.signal) == null ? void 0 : _a2.aborted) {\n reject(new AbortError());\n return;\n }\n resolve({\n ok: result.ok !== void 0 ? result.ok : true,\n statusText: result.statusText !== void 0 ? result.statusText : \"ok\",\n status: result.status !== void 0 ? result.status : 200,\n json: () => Promise.resolve(result.body)\n });\n };\n if (delay > 0) {\n setTimeout(completeRequest, delay);\n } else {\n setTimeout(completeRequest, 0);\n }\n });\n };\n networkAdapter.requests = [];\n networkAdapter.availableResponses = responses.length;\n networkAdapter.queueResponses = (newResponses) => {\n responses = responses.concat(newResponses);\n networkAdapter.availableResponses = responses.length;\n };\n networkAdapter.fetch = (args) => networkAdapter(args);\n networkAdapter.reset = () => {\n networkAdapter.requests = [];\n responses = [];\n networkAdapter.availableResponses = 0;\n networkAdapter.responsesUsed = 0;\n };\n networkAdapter.responsesUsed = 0;\n return {\n type: \"fetch\",\n version: \"1.0\",\n service: networkAdapter\n };\n}\nexport {\n buildCompressionInterceptor,\n buildJwtRequestHeaderInterceptor,\n buildMockFetchService,\n buildServiceDescriptor,\n setHeader,\n setHeaderAuthorization\n};\n//# sourceMappingURL=index.js.map\n","/*!\n * Copyright (c) 2022, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nclass RetryService {\n constructor(defaultRetryPolicy) {\n this.defaultRetryPolicy = defaultRetryPolicy;\n }\n applyRetry(operation, retryPolicyOverride) {\n return this.retry(operation, retryPolicyOverride || this.defaultRetryPolicy);\n }\n async retry(operation, policy) {\n const startTime = Date.now();\n let attempt = 0;\n let result = await operation();\n let context = {\n attempt,\n totalElapsedMs: Date.now() - startTime,\n lastResult: result\n };\n while (await policy.shouldRetry(result, context)) {\n const delay = await policy.calculateDelay(result, context);\n await this.delay(delay);\n if (policy.prepareRetry) {\n await policy.prepareRetry(result, context);\n }\n attempt++;\n result = await operation();\n context = {\n attempt,\n totalElapsedMs: Date.now() - startTime,\n lastResult: result\n };\n }\n return result;\n }\n delay(ms) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n }\n}\nclass RetryPolicy {\n}\nclass ComposedRetryPolicy extends RetryPolicy {\n constructor(policies) {\n super();\n this.policies = policies;\n }\n /**\n * Returns true if any of the composed policies want to retry.\n *\n * Uses OR logic: if ANY policy returns true, this returns true.\n * Policies are checked in order and evaluation short-circuits on the first match.\n */\n async shouldRetry(result, context) {\n for (const policy of this.policies) {\n if (await policy.shouldRetry(result, context)) {\n return true;\n }\n }\n return false;\n }\n /**\n * Returns the delay from the first policy that wants to retry.\n *\n * If multiple policies want to retry, only the FIRST policy's delay is used.\n * Policy order in the constructor array determines priority.\n * If no policy wants to retry, returns 0.\n *\n * @example\n * ```typescript\n * // If both PolicyA (1000ms) and PolicyB (5000ms) want to retry:\n * const composed = new ComposedRetryPolicy([policyA, policyB]);\n * composed.calculateDelay(result, context); // Returns 1000ms (PolicyA wins)\n * ```\n */\n async calculateDelay(result, context) {\n for (const policy of this.policies) {\n if (await policy.shouldRetry(result, context)) {\n return policy.calculateDelay(result, context);\n }\n }\n return 0;\n }\n /**\n * Calls prepareRetry on policies that both:\n * 1. Implement the prepareRetry hook, AND\n * 2. Returned true from shouldRetry for this result\n *\n * This allows only the matching policies to perform preparation work (e.g., token refresh).\n * All matching prepareRetry calls run in parallel for efficiency.\n *\n * **Important**: prepareRetry only runs on policies that matched shouldRetry. This ensures\n * you don't perform unnecessary work or side effects for unrelated retry conditions.\n *\n * **Note**: If multiple policies match and have prepareRetry, ensure they don't have\n * conflicting side effects since they run in parallel.\n *\n * @example\n * ```typescript\n * // Status 401 occurs\n * const composed = new ComposedRetryPolicy([\n * authPolicy, // shouldRetry(401) → true, has prepareRetry\n * throttlePolicy, // shouldRetry(401) → false, has prepareRetry\n * ]);\n *\n * await composed.prepareRetry(result, context);\n * // → Only authPolicy.prepareRetry() runs (because it matched)\n * // → throttlePolicy.prepareRetry() does NOT run (didn't match)\n * ```\n */\n async prepareRetry(result, context) {\n const matchingPolicies = [];\n for (const policy of this.policies) {\n if (policy.prepareRetry !== void 0 && await policy.shouldRetry(result, context)) {\n matchingPolicies.push(policy);\n }\n }\n if (matchingPolicies.length > 0) {\n await Promise.all(\n matchingPolicies.map((policy) => policy.prepareRetry(result, context))\n );\n }\n }\n /**\n * Returns all composed policies.\n * Useful for accessing or configuring individual policies after composition.\n */\n getPolicies() {\n return this.policies;\n }\n /**\n * Helper to get a specific policy by type.\n * Useful for calling policy-specific methods after composition.\n *\n * @example\n * ```typescript\n * const csrfPolicy = composedPolicy.getPolicyByType(CsrfTokenRetryPolicy);\n * csrfPolicy?.setRequestContext(mutableRequest);\n * ```\n */\n getPolicyByType(policyType) {\n return this.policies.find((policy) => policy instanceof policyType);\n }\n}\nfunction buildServiceDescriptor(defaultRetryPolicy) {\n return {\n version: \"1.0\",\n service: new RetryService(defaultRetryPolicy),\n type: \"retry\"\n };\n}\nexport {\n ComposedRetryPolicy,\n RetryPolicy,\n RetryService,\n buildServiceDescriptor\n};\n//# sourceMappingURL=index.js.map\n","import { setHeader } from '@conduit-client/service-fetch-network/v1';\nimport { resolvedPromiseLike } from '@conduit-client/utils';\nimport type { CsrfTokenManager } from './token-manager';\nimport type { FetchParameters, RequestInterceptor } from '@conduit-client/service-fetch-network/v1';\n\nconst HEADER = 'X-CSRF-Token';\n\nexport interface HeaderInterceptorConfig {\n protectedUrls?: string[];\n}\n\n/**\n * Builds a configured interceptor for applying CSRF header to requests\n *\n * @param csrfTokenManager\n * @param config\n */\nexport function buildInterceptor(\n csrfTokenManager: CsrfTokenManager,\n config: HeaderInterceptorConfig = {}\n): RequestInterceptor {\n const { protectedUrls = [] } = config;\n\n return async (fetchArgs: FetchParameters) => {\n const [input, init] = fetchArgs;\n const request = new Request(input, init);\n\n // Only add CSRF token for mutating operations on protected URLs that don't already have one\n if (\n isProtectedMethod(request.method) &&\n isProtectedUrl(protectedUrls, request.url) &&\n !request.headers.has(HEADER)\n ) {\n const token = await csrfTokenManager.getToken();\n // eslint-disable-next-line no-param-reassign\n fetchArgs = setHeader(HEADER, token, fetchArgs);\n }\n\n return resolvedPromiseLike(fetchArgs);\n };\n}\n\n/**\n * Determines if the HTTP method requires CSRF protection.\n * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.\n *\n * @param method - The HTTP method to check\n * @returns true if the method requires CSRF protection\n */\nfunction isProtectedMethod(method: string): boolean {\n const normalizedMethod = method.toLowerCase();\n return (\n normalizedMethod === 'post' ||\n normalizedMethod === 'put' ||\n normalizedMethod === 'patch' ||\n normalizedMethod === 'delete'\n );\n}\n\n/**\n * Determines if the URL is for a path that requires CSRF protection.\n * Currently, protects all Salesforce API endpoints under '/services'.\n *\n * @param protectedUrls - Substrings that identify protected URLs\n * @param urlString - The full URL to check\n * @returns true if the URL requires CSRF protection\n * @note This could be made configurable in the future to support custom protected paths\n */\nfunction isProtectedUrl(protectedUrls: string[], urlString: string) {\n const url = new URL(urlString);\n\n // Agentforce Vibes IDE has a `absproxy/PORT/` path prefix for the Salesforce server\n return protectedUrls.some((protectedUrl) => url.pathname.includes(protectedUrl));\n}\n","import { type RetryService } from '@conduit-client/service-retry/v1';\nimport { buildInterceptor as buildHeaderInterceptor } from './header.interceptor';\nimport type { HeaderInterceptorConfig } from './header.interceptor';\nimport type { CsrfTokenManager } from './token-manager';\nimport type { FetchParameters } from '@conduit-client/service-fetch-network/v1';\n\nexport interface RetryInterceptorConfig extends HeaderInterceptorConfig {}\n\nexport function buildInterceptor(\n csrfTokenManager: CsrfTokenManager,\n config: RetryInterceptorConfig = {}\n) {\n const headerInterceptor = buildHeaderInterceptor(csrfTokenManager, config);\n\n /**\n * Makes request that has a CSRF header applied via an interceptor\n *\n * @param fetchArgs\n */\n async function makeRequest(fetchArgs: FetchParameters) {\n const args = await headerInterceptor(fetchArgs);\n return fetch(...args);\n }\n\n return (fetchArgs: FetchParameters, retryService?: RetryService<Response>) => {\n // simply make request if no service is provided\n if (!retryService) {\n return makeRequest(fetchArgs);\n }\n\n // run service with operation that makes the request\n return retryService.applyRetry(async () => {\n return makeRequest(fetchArgs);\n });\n };\n}\n","import { RetryPolicy, type RetryContext } from '@conduit-client/service-retry/v1';\nimport type { CsrfTokenManager } from './token-manager';\n\n/**\n * Retry policy that handles CSRF token expiration errors.\n *\n * When a request fails with a CSRF token error this policy will:\n * 1. Detect the error condition in shouldRetry\n * 2. Refresh the CSRF token in prepareRetry hook\n * 3. Retry the request once (maxRetries = 1)\n *\n */\nexport class CsrfTokenRetryPolicy extends RetryPolicy<Response> {\n constructor(private csrfTokenManager: CsrfTokenManager) {\n // @ts-ignore\n super(csrfTokenManager);\n }\n\n /**\n * Determines if a failed request should be retried due to CSRF token issues.\n */\n async shouldRetry(result: Response, context: RetryContext<Response>): Promise<boolean> {\n // Only retry once\n if (context.attempt >= 1) {\n return false;\n }\n\n // Only retry on 400 status\n if (result.status !== 400) {\n return false;\n }\n\n // Check if this is a CSRF error by examining the response body\n // This avoids retrying all 400s (validation errors, bad requests, etc.)\n // eslint-disable-next-line no-return-await\n return await isCsrfError(result);\n }\n\n /**\n * CSRF token refresh should happen immediately with no delay.\n */\n async calculateDelay(_result: Response, _context: RetryContext<Response>): Promise<number> {\n return 0; // No delay - retry immediately after token refresh\n }\n\n /**\n * Called by retry service before each retry attempt.\n *\n * @param _result - The failed response that triggered the retry (unused, already validated)\n * @param _context - Current retry context (unused but part of interface)\n */\n override async prepareRetry(\n _result: Response,\n _context: RetryContext<Response>\n ): Promise<void> {\n // Refresh the CSRF token (we already know this is a CSRF error from shouldRetry)\n await this.csrfTokenManager.refreshToken();\n }\n}\n\n/**\n * Helper to check if a response indicates a CSRF token error.\n *\n * @param response - The response to check\n * @returns true if the response indicates a CSRF token error (INVALID_ACCESS_TOKEN)\n */\nexport async function isCsrfError(response: Response): Promise<boolean> {\n try {\n // clone response to read body without consuming the original stream\n const body = await response.clone().json();\n\n // check for Salesforce's specific invalid token error code\n return body[0]?.errorCode === 'INVALID_ACCESS_TOKEN';\n } catch {\n // If we can't parse the body (network error, non-JSON response, etc.),\n // assume it's not a CSRF error\n return false;\n }\n}\n","/**\n * Manages CSRF token fetching and caching for secure requests.\n * Implements a singleton pattern to ensure consistent token management across the application.\n */\nclass CsrfTokenManager {\n private tokenPromise: Promise<string>;\n\n constructor(\n private endpoint: string,\n private cacheName?: string\n ) {\n this.tokenPromise = this.obtainToken();\n }\n\n /**\n * Returns the current token value as a Promise.\n * Lazy-loads the token on first call (from cache or by fetching).\n */\n async getToken(): Promise<string> {\n return this.tokenPromise;\n }\n\n /**\n * Obtains and returns a new token value as a promise.\n * This will clear the cached token and fetch a fresh one.\n */\n async refreshToken(): Promise<string | undefined> {\n // remove the invalid token from cache\n await this.withCache((cache) => cache.delete(this.endpoint));\n\n // start obtaining a new token\n this.tokenPromise = this.obtainToken();\n\n return this.tokenPromise;\n }\n\n /**\n * Obtains a CSRF token, using cache when available or fetching a new one.\n *\n * @returns Promise that resolves to the CSRF token string\n */\n private async obtainToken(): Promise<string> {\n // try to get cached token response first\n let response = await this.withCache((cache) => cache.match(this.endpoint));\n\n let cacheMiss = false;\n if (!response) {\n // no cached response available, fetch a new token\n response = await fetch(this.endpoint, { method: 'get' });\n cacheMiss = true;\n }\n\n // extract token from response (clone to avoid consuming original stream)\n const csrfToken: string = (await response.clone().json()).csrfToken;\n\n if (cacheMiss) {\n // cache the response for future use\n await this.withCache((cache) => cache.put(this.endpoint, response));\n }\n\n return csrfToken;\n }\n\n /**\n * Provides a safe way to interact with the Cache API with fallback for unsupported environments.\n *\n * @param callback - Function that receives the cache instance and returns a promise\n * @returns The result of the callback, or undefined if caches API is not available\n */\n private async withCache<T>(callback: (cache: Cache) => Promise<T>): Promise<T | undefined> {\n // Defend against the cache API not being available (e.g., in some test environments)\n if (this.cacheName && caches) {\n const cache = await caches.open(this.cacheName);\n return callback(cache);\n } else {\n return undefined;\n }\n }\n}\n\nexport { CsrfTokenManager };\n","import { buildServiceDescriptor as buildFetchServiceDescriptor } from '@conduit-client/service-fetch-network/v1';\nimport { buildServiceDescriptor as buildRetryServiceDescriptor } from '@conduit-client/service-retry/v1';\nimport { buildInterceptor as buildRetryInterceptor } from './csrf/retry.interceptor';\nimport { CsrfTokenRetryPolicy } from './csrf/retry.policy';\nimport { CsrfTokenManager } from './csrf/token-manager';\nimport type { RetryInterceptorConfig } from './csrf/retry.interceptor';\nimport type { FetchService } from '@conduit-client/service-fetch-network/v1';\n\ninterface CsrfConfig extends RetryInterceptorConfig {\n endpoint: string;\n cacheName: string;\n}\n\nexport interface FetchConfig {\n csrf: CsrfConfig;\n}\n\n/**\n * Creates an enhanced fetch function with automatic CSRF token handling.\n * The returned function automatically adds CSRF tokens to protected requests\n * and handles token refresh when tokens become invalid.\n *\n * @param config - Optional configuration for CSRF handling\n * @returns An enhanced fetch function that handles CSRF protection\n */\nexport function createFetchService(config: FetchConfig): FetchService {\n const csrfConfig = config.csrf;\n const csrfTokenManager = new CsrfTokenManager(csrfConfig.endpoint, csrfConfig.cacheName);\n\n return buildFetchServiceDescriptor(\n { retry: buildRetryInterceptor(csrfTokenManager, csrfConfig) },\n buildRetryServiceDescriptor(new CsrfTokenRetryPolicy(csrfTokenManager)).service\n ).service;\n}\n","import { createFetchService } from './fetch';\nimport type { FetchConfig } from './fetch';\nimport type { FetchService } from '@conduit-client/service-fetch-network/v1';\n\ntype ConduitClientConfig = {\n serviceWorkerUrl?: string;\n} & FetchConfig;\n\ntype QueuedRequest = {\n input: string | URL | Request;\n init?: RequestInit;\n resolve: (response: Response | PromiseLike<Response>) => void;\n};\n\n/**\n * The fetch function used by the client. Defaults to enhanced fetch for CSRF protection.\n * Will be switched to native fetch when CSRF-based service worker is successfully registered.\n */\nlet clientFetch: FetchService;\n\n/**\n * When a service worker is to be used, we need to hold off on all fetches until the worker is\n * loaded. That way the logic provided by the worker is applied.\n */\nlet serviceWorkerLoading = false;\nlet pendingRequests: QueuedRequest[] = [];\n\nlet instance: ConduitClient;\n\n/**\n * A client for making HTTP requests with CSRF protection. By default, protection is provided by\n * wrapping the native `fetch` API with functionality that will apply a CSRF token to appropriate\n * requests. This includes functionality to detect expired tokens, triggering a token refresh and\n * retry of the request.\n *\n * Optionally, CSRF protection can be offloaded to a service worker by making the appropriate calls\n * to `registerServiceWorker` and `defineServiceWorker`\n */\nexport class ConduitClient {\n /**\n * Makes an HTTP request\n *\n * @param input - The URL, Request object, or relative path to request\n * @param init - Optional request configuration that will be merged with defaults\n * @returns Promise that resolves to the Response object\n */\n fetch(input: string | URL | Request, init: RequestInit = {}): Promise<Response> {\n // queue any fetches until service worker is loaded\n if (serviceWorkerLoading) {\n return new Promise<Response>((resolve) => {\n pendingRequests.push({ input, init, resolve });\n });\n }\n\n return Promise.resolve(clientFetch(input, init));\n }\n\n /**\n * Configures global settings for all ConduitClient instances.\n * This will recreate the internal fetch service with the new configuration.\n *\n * @param config - Configuration options for CSRF handling and other features\n */\n static initialize(config: ConduitClientConfig) {\n if (instance) {\n throw new Error('ConduitClient.initialize can only be called once');\n }\n\n instance = new ConduitClient();\n\n if (config.serviceWorkerUrl) {\n return registerServiceWorker(config);\n } else {\n clientFetch = createFetchService(config);\n return Promise.resolve();\n }\n }\n\n /**\n * Factory method to create a new ConduitClient instance\n *\n * @returns A new ConduitClient instance\n */\n static instance() {\n if (!instance) {\n throw new Error('ConduitClient.initialize must be called first');\n }\n return instance;\n }\n}\n\n/**\n * Registers a service worker for enhanced CSRF protection and caching.\n * When successfully registered, the client will switch to using native fetch\n * as the service worker will handle CSRF protection.\n *\n * @param config\n */\nasync function registerServiceWorker(config: ConduitClientConfig) {\n // check if service workers are supported in this environment\n if ('serviceWorker' in navigator) {\n try {\n serviceWorkerLoading = true;\n\n // register service worker URL - classic due to security restraints with `module`\n // Chrome: won't include cookies, thus 302 to authenticate request\n // Firefox: not supported at all\n const registration = await navigator.serviceWorker.register(config.serviceWorkerUrl!, {\n type: 'classic',\n });\n\n clientFetch = fetch;\n\n // eslint-disable-next-line no-console\n console.log('[Conduit Client] Service registration succeeded:', registration);\n\n // Post configuration to the active service worker\n if (registration.active) {\n await postConfigToServiceWorker(registration.active, config);\n } else if (registration.waiting || registration.installing) {\n // Wait for service worker to become active, then post config\n const serviceWorker = registration.waiting || registration.installing;\n await waitForServiceWorkerActive(serviceWorker!);\n if (registration.active) {\n await postConfigToServiceWorker(registration.active, config);\n }\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.log(\n '[Conduit Client] Service Worker registration failed (using decorated `fetch`):',\n error\n );\n } finally {\n // with client finalized, process all queued requests\n processQueuedRequests();\n }\n } else {\n // eslint-disable-next-line no-console\n console.log('[Conduit Client] Service Worker not supported (using decorated `fetch`):');\n }\n}\n\n/**\n * Posts configuration data to the active service worker\n *\n * @param serviceWorker - The active service worker to send config to\n * @param config - The configuration to send\n */\nasync function postConfigToServiceWorker(\n serviceWorker: ServiceWorker,\n config: ConduitClientConfig\n): Promise<void> {\n try {\n // Prepare config data to send (exclude serviceWorkerUrl since it's not needed in the worker)\n const { serviceWorkerUrl: _, ...configData } = config;\n\n serviceWorker.postMessage({\n type: 'fetch-config',\n config: configData,\n });\n } catch (error) {\n console.warn('[Conduit Client] Failed to post config to service worker:', error);\n }\n}\n\n/**\n * Waits for a service worker to become active\n *\n * @param serviceWorker - The service worker to wait for\n * @returns Promise that resolves when the worker becomes active\n */\nfunction waitForServiceWorkerActive(serviceWorker: ServiceWorker): Promise<void> {\n return new Promise((resolve) => {\n if (serviceWorker.state === 'activated') {\n resolve();\n return;\n }\n\n function handleStateChange() {\n if (serviceWorker.state === 'activated') {\n serviceWorker.removeEventListener('statechange', handleStateChange);\n resolve();\n }\n }\n\n serviceWorker.addEventListener('statechange', handleStateChange);\n });\n}\n\n/**\n * Complete the queued requests\n */\nfunction processQueuedRequests() {\n // stop queuing\n serviceWorkerLoading = false;\n\n // complete requests\n pendingRequests.forEach(({ input, init, resolve }) => {\n resolve(clientFetch(input, init));\n });\n pendingRequests = [];\n}\n"],"names":["buildServiceDescriptor","buildInterceptor","buildHeaderInterceptor","buildFetchServiceDescriptor","buildRetryInterceptor","buildRetryServiceDescriptor"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../utils/dist/index.js","../../services/fetch-network/dist/v1/index.js","../../services/retry/dist/v1/index.js","../src/csrf/header.interceptor.ts","../src/csrf/retry.interceptor.ts","../src/csrf/retry.policy.ts","../src/csrf/token-manager.ts","../src/fetch.ts","../src/index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2022, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nfunction bfs(start, predicate, getChildren) {\n const queue = [...start];\n const visited = /* @__PURE__ */ new Set([...start]);\n const matches2 = /* @__PURE__ */ new Set();\n while (queue.length) {\n const curr = queue.shift();\n if (predicate(curr)) {\n matches2.add(curr);\n }\n const children = getChildren(curr);\n for (const child of children) {\n if (!visited.has(child)) {\n visited.add(child);\n queue.push(child);\n }\n }\n }\n return matches2;\n}\nfunction lineFormatter(position, message, filePath) {\n return `${message} (${filePath}:${position.line}:${position.column})`;\n}\nclass DefaultFileParserLogger {\n constructor(services, filePath) {\n this.services = services;\n this.filePath = filePath;\n }\n trace(position, message) {\n this.services.logger.trace(this.format(position, message));\n }\n debug(position, message) {\n this.services.logger.debug(this.format(position, message));\n }\n info(position, message) {\n this.services.logger.info(this.format(position, message));\n }\n warn(position, message) {\n this.services.logger.warn(this.format(position, message));\n }\n error(position, message) {\n this.services.logger.error(this.format(position, message));\n }\n format(position, message) {\n return lineFormatter(position, message, this.filePath);\n }\n}\nfunction matches(test, s) {\n if (test === void 0) {\n return false;\n } else if (typeof test === \"string\") {\n return s === test;\n } else if (test instanceof RegExp) {\n return test.test(s);\n } else if (typeof test === \"function\") {\n return test(s);\n }\n return test.some((m) => matches(m, s));\n}\nfunction includes(incexc, s) {\n if (matches(incexc.exclude, s)) {\n return false;\n }\n if (matches(incexc.include, s)) {\n return true;\n }\n if (incexc.include) {\n return false;\n }\n return true;\n}\nconst { create, freeze, keys, entries } = Object;\nconst { hasOwnProperty } = Object.prototype;\nconst { isArray } = Array;\nconst { push, indexOf, slice } = Array.prototype;\nconst { stringify, parse } = JSON;\nconst WeakSetConstructor = WeakSet;\nconst LogLevelMap = {\n TRACE: 4,\n DEBUG: 3,\n INFO: 2,\n WARN: 1,\n ERROR: 0\n};\nclass ConsoleLogger {\n constructor(level = \"WARN\", printer = console.log, formatter = (level2, message) => `${level2}: ${message}`) {\n this.level = level;\n this.printer = printer;\n this.formatter = formatter;\n this.messages = [];\n }\n trace(message) {\n this.log(\"TRACE\", message);\n }\n debug(message) {\n this.log(\"DEBUG\", message);\n }\n info(message) {\n this.log(\"INFO\", message);\n }\n warn(message) {\n this.log(\"WARN\", message);\n }\n error(message) {\n this.log(\"ERROR\", message);\n }\n log(level, message) {\n if (LogLevelMap[level] > LogLevelMap[this.level]) {\n return;\n }\n this.printer(this.formatter(level, message));\n }\n}\nfunction loggerService(level, printer, formatter) {\n return new ConsoleLogger(level, printer, formatter);\n}\nclass Ok {\n constructor(value) {\n this.value = value;\n }\n isOk() {\n return true;\n }\n isErr() {\n return !this.isOk();\n }\n}\nclass Err {\n constructor(error) {\n this.error = error;\n }\n isOk() {\n return false;\n }\n isErr() {\n return !this.isOk();\n }\n}\nconst ok = (value) => new Ok(value);\nconst err = (err2) => new Err(err2);\nclass DataNotFoundError extends Error {\n constructor(message) {\n super(message);\n this.name = \"DataNotFoundError\";\n }\n}\nclass DataIncompleteError extends Error {\n constructor(message, partialData) {\n super(message);\n this.partialData = partialData;\n this.name = \"DataIncompleteError\";\n }\n}\nfunction isDataNotFoundError(error) {\n return error instanceof DataNotFoundError || error.name === \"DataNotFoundError\";\n}\nfunction isDataIncompleteError(error) {\n return error instanceof DataIncompleteError || error.name === \"DataIncompleteError\";\n}\nfunction isCacheHitOrError(value) {\n if (value.isErr() && (isDataIncompleteError(value.error) || isDataNotFoundError(value.error))) {\n return false;\n }\n return true;\n}\nfunction isCacheMiss(value) {\n return !isCacheHitOrError(value);\n}\nfunction isResult(value) {\n return value !== null && value !== void 0 && typeof value === \"object\" && \"isOk\" in value && \"isErr\" in value && typeof value.isOk === \"function\" && typeof value.isErr === \"function\" && (value.isOk() === true && value.isErr() === false && \"value\" in value || value.isOk() === false && value.isErr() === true && \"error\" in value);\n}\nfunction setOverlaps(setA, setB) {\n for (const element of setA) {\n if (setB.has(element)) {\n return true;\n }\n }\n return false;\n}\nfunction setDifference(setA, setB) {\n const differenceSet = /* @__PURE__ */ new Set();\n for (const element of setA) {\n if (!setB.has(element)) {\n differenceSet.add(element);\n }\n }\n return differenceSet;\n}\nfunction addAllToSet(targetSet, sourceSet) {\n for (const element of sourceSet) {\n targetSet.add(element);\n }\n}\nconst toTypeScriptSafeIdentifier = (s) => s.length >= 1 ? s[0].replace(/[^$_\\p{ID_Start}]/u, \"_\") + s.slice(1).replace(/[^$\\u200c\\u200d\\p{ID_Continue}]/gu, \"_\") : \"\";\nfunction capitalizeFirst(s) {\n return s.length >= 1 ? s.charAt(0).toUpperCase() + s.slice(1) : \"\";\n}\nfunction isSubscribable(obj) {\n return typeof obj === \"object\" && obj !== null && \"subscribe\" in obj && typeof obj.subscribe === \"function\" && \"refresh\" in obj && typeof obj.refresh === \"function\";\n}\nfunction isSubscribableResult(x) {\n if (!isResult(x)) {\n return false;\n }\n return isSubscribable(x.isOk() ? x.value : x.error);\n}\nfunction buildSubscribableResult(result, subscribe, refresh) {\n if (result.isOk()) {\n return ok({ data: result.value, subscribe, refresh });\n } else {\n return err({ failure: result.error, subscribe, refresh });\n }\n}\nfunction resolvedPromiseLike(result) {\n if (isPromiseLike(result)) {\n return result.then((nextResult) => nextResult);\n }\n return {\n then: (onFulfilled, _onRejected) => {\n try {\n return resolvedPromiseLike(onFulfilled(result));\n } catch (e) {\n if (onFulfilled === void 0) {\n return resolvedPromiseLike(result);\n }\n return rejectedPromiseLike(e);\n }\n }\n };\n}\nfunction rejectedPromiseLike(reason) {\n if (isPromiseLike(reason)) {\n return reason.then((nextResult) => nextResult);\n }\n return {\n then: (_onFulfilled, onRejected) => {\n if (typeof onRejected === \"function\") {\n try {\n return resolvedPromiseLike(onRejected(reason));\n } catch (e) {\n return rejectedPromiseLike(e);\n }\n }\n return rejectedPromiseLike(reason);\n }\n };\n}\nfunction isPromiseLike(x) {\n return typeof (x == null ? void 0 : x.then) === \"function\";\n}\nfunction racesync(values) {\n for (const value of values) {\n let settled = void 0;\n if (isPromiseLike(value)) {\n value.then(\n (_) => {\n settled = value;\n },\n (_) => {\n settled = value;\n }\n );\n } else {\n settled = resolvedPromiseLike(value);\n }\n if (settled !== void 0) {\n return settled;\n }\n }\n return Promise.race(values);\n}\nfunction withResolvers() {\n let resolve, reject;\n const promise = new Promise((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve, reject };\n}\nfunction deepEquals(x, y) {\n if (x === void 0) {\n return y === void 0;\n } else if (x === null) {\n return y === null;\n } else if (y === null) {\n return x === null;\n } else if (isArray(x)) {\n if (!isArray(y) || x.length !== y.length) {\n return false;\n }\n for (let i = 0; i < x.length; ++i) {\n if (!deepEquals(x[i], y[i])) {\n return false;\n }\n }\n return true;\n } else if (typeof x === \"object\") {\n if (typeof y !== \"object\") {\n return false;\n }\n const xkeys = Object.keys(x);\n const ykeys = Object.keys(y);\n if (xkeys.length !== ykeys.length) {\n return false;\n }\n for (let i = 0; i < xkeys.length; ++i) {\n const key = xkeys[i];\n if (!deepEquals(x[key], y[key])) {\n return false;\n }\n }\n return true;\n }\n return x === y;\n}\nfunction stableJSONStringify(node) {\n if (node && node.toJSON && typeof node.toJSON === \"function\") {\n node = node.toJSON();\n }\n if (node === void 0) {\n return;\n }\n if (typeof node === \"number\") {\n return isFinite(node) ? \"\" + node : \"null\";\n }\n if (typeof node !== \"object\") {\n return stringify(node);\n }\n let i;\n let out;\n if (isArray(node)) {\n out = \"[\";\n for (i = 0; i < node.length; i++) {\n if (i) {\n out += \",\";\n }\n out += stableJSONStringify(node[i]) || \"null\";\n }\n return out + \"]\";\n }\n if (node === null) {\n return \"null\";\n }\n const objKeys = keys(node).sort();\n out = \"\";\n for (i = 0; i < objKeys.length; i++) {\n const key = objKeys[i];\n const value = stableJSONStringify(node[key]);\n if (!value) {\n continue;\n }\n if (out) {\n out += \",\";\n }\n out += stringify(key) + \":\" + value;\n }\n return \"{\" + out + \"}\";\n}\nfunction toError(x) {\n if (x instanceof Error) {\n return x;\n }\n return new Error(typeof x === \"string\" ? x : JSON.stringify(x));\n}\nfunction deepCopy(x) {\n const stringified = stringify(x);\n return stringified ? parse(stringified) : void 0;\n}\nfunction readableStreamToAsyncIterable(stream) {\n if (stream.locked) {\n return err(new Error(\"ReadableStream is already locked\"));\n }\n if (Symbol.asyncIterator in stream) {\n return ok(stream);\n }\n const reader = stream.getReader();\n return ok({\n [Symbol.asyncIterator]: () => ({\n next: async () => {\n try {\n const result = await reader.read();\n if (result.done) {\n try {\n reader.releaseLock();\n } catch {\n }\n return { done: true, value: void 0 };\n }\n return {\n done: false,\n value: result.value\n };\n } catch (e) {\n try {\n reader.releaseLock();\n } catch {\n }\n throw e;\n }\n },\n return: async (value) => {\n try {\n await reader.cancel();\n } catch {\n }\n try {\n reader.releaseLock();\n } catch {\n }\n return { done: true, value };\n },\n throw: async (exception) => {\n try {\n await reader.cancel();\n } catch {\n }\n try {\n reader.releaseLock();\n } catch {\n }\n throw exception;\n }\n })\n });\n}\nfunction satisfies(provided, requested) {\n const providedN = provided.split(\".\").map((s) => parseInt(s));\n const requestedN = requested.split(\".\").map((s) => parseInt(s));\n return providedN[0] === requestedN[0] && providedN[1] >= requestedN[1];\n}\nfunction stringIsVersion(s) {\n const versionParts = s.split(\".\");\n return (versionParts.length === 2 || versionParts.length === 3) && versionParts.every((part) => part.match(/^\\d+$/));\n}\nvar HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {\n HttpStatusCode2[HttpStatusCode2[\"Ok\"] = 200] = \"Ok\";\n HttpStatusCode2[HttpStatusCode2[\"Created\"] = 201] = \"Created\";\n HttpStatusCode2[HttpStatusCode2[\"NoContent\"] = 204] = \"NoContent\";\n HttpStatusCode2[HttpStatusCode2[\"NotModified\"] = 304] = \"NotModified\";\n HttpStatusCode2[HttpStatusCode2[\"BadRequest\"] = 400] = \"BadRequest\";\n HttpStatusCode2[HttpStatusCode2[\"Unauthorized\"] = 401] = \"Unauthorized\";\n HttpStatusCode2[HttpStatusCode2[\"Forbidden\"] = 403] = \"Forbidden\";\n HttpStatusCode2[HttpStatusCode2[\"NotFound\"] = 404] = \"NotFound\";\n HttpStatusCode2[HttpStatusCode2[\"ServerError\"] = 500] = \"ServerError\";\n HttpStatusCode2[HttpStatusCode2[\"GatewayTimeout\"] = 504] = \"GatewayTimeout\";\n return HttpStatusCode2;\n})(HttpStatusCode || {});\nfunction getFetchResponseFromAuraError(err2) {\n if (err2.data !== void 0 && err2.data.statusCode !== void 0) {\n let data = {};\n data = err2.data;\n if (err2.id !== void 0) {\n data.id = err2.id;\n }\n return new FetchResponse(data.statusCode, data);\n }\n return new FetchResponse(500, {\n error: err2.message\n });\n}\nasync function coerceResponseToFetchResponse(response) {\n const { status } = response;\n const responseHeaders = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n let responseBody = null;\n if (status !== 204) {\n const contentType = responseHeaders[\"content-type\"];\n responseBody = contentType && contentType.startsWith(\"application/json\") ? await response.json() : await response.text();\n }\n return new FetchResponse(status, responseBody, responseHeaders);\n}\nfunction getStatusText(status) {\n switch (status) {\n case 200:\n return \"OK\";\n case 201:\n return \"Created\";\n case 304:\n return \"Not Modified\";\n case 400:\n return \"Bad Request\";\n case 404:\n return \"Not Found\";\n case 500:\n return \"Server Error\";\n default:\n return `Unexpected HTTP Status Code: ${status}`;\n }\n}\nclass FetchResponse extends Error {\n constructor(status, body, headers) {\n super();\n this.status = status;\n this.body = body;\n this.headers = headers || {};\n this.ok = status >= 200 && this.status <= 299;\n this.statusText = getStatusText(status);\n }\n}\nconst deeplyFrozen = new WeakSetConstructor();\nfunction deepFreeze(value) {\n if (typeof value !== \"object\" || value === null || deeplyFrozen.has(value)) {\n return;\n }\n deeplyFrozen.add(value);\n if (isArray(value)) {\n for (let i = 0, len = value.length; i < len; i += 1) {\n deepFreeze(value[i]);\n }\n } else {\n const keys$1 = keys(value);\n for (let i = 0, len = keys$1.length; i < len; i += 1) {\n deepFreeze(value[keys$1[i]]);\n }\n }\n freeze(value);\n}\nfunction isScalar(value) {\n return typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\" || value === null || value === void 0;\n}\nfunction isScalarObject(value) {\n return Object.values(value).every((value2) => isScalar(value2));\n}\nfunction isScalarArray(value) {\n return value.every((item) => isScalar(item));\n}\nfunction encodeQueryParam(paramName, value, explode) {\n switch (typeof value) {\n case \"string\":\n return [`${paramName}=${encodeURIComponent(value)}`];\n case \"number\":\n case \"boolean\":\n return [`${paramName}=${value}`];\n case \"object\":\n if (value === null) {\n return [];\n }\n if (isArray(value)) {\n if (!isScalarArray(value)) {\n throw new Error(`Unsupported non-scalar array type for ${paramName}`);\n }\n if (explode) {\n return value.map(\n (item) => `${paramName}=${item ? encodeURIComponent(item) : item}`\n );\n }\n return [\n `${paramName}=${value.map((item) => item ? encodeURIComponent(item) : item).join(\",\")}`\n ];\n }\n if (!isScalarObject(value)) {\n throw new Error(`Unsupported non-scalar object type for ${paramName}`);\n }\n if (explode) {\n return entries(value).map(\n ([key, value2]) => `${key}=${value2 ? encodeURIComponent(value2) : value2}`\n );\n }\n return [\n `${paramName}=${entries(value).flat().map((item) => item ? encodeURIComponent(item) : item).join(\",\")}`\n ];\n default:\n return [];\n }\n}\nclass InternalError extends Error {\n constructor(data) {\n super();\n this.data = data;\n this.type = \"internal\";\n }\n}\nclass UserVisibleError extends Error {\n constructor(data) {\n super();\n this.data = data;\n this.type = \"user-visible\";\n }\n}\nfunction isUserVisibleError(error) {\n return error instanceof Error && \"type\" in error && error.type === \"user-visible\";\n}\nfunction logError(error) {\n if (isUserVisibleError(error)) {\n return;\n }\n console.error(\"OneStore Command threw an error that we did not expect\", error);\n}\nfunction applyDecorators(baseCommand, decorators, options) {\n if (!decorators || decorators.length === 0) {\n return baseCommand;\n }\n return decorators.reduce((command, decorator) => decorator(command, options), baseCommand);\n}\nexport {\n isArray as ArrayIsArray,\n indexOf as ArrayPrototypeIndexOf,\n push as ArrayPrototypePush,\n slice as ArrayPrototypeSlice,\n ConsoleLogger,\n DataIncompleteError,\n DataNotFoundError,\n DefaultFileParserLogger,\n Err,\n FetchResponse,\n HttpStatusCode,\n InternalError,\n parse as JSONParse,\n stringify as JSONStringify,\n LogLevelMap,\n create as ObjectCreate,\n entries as ObjectEntries,\n freeze as ObjectFreeze,\n keys as ObjectKeys,\n hasOwnProperty as ObjectPrototypeHasOwnProperty,\n Ok,\n UserVisibleError,\n WeakSetConstructor,\n addAllToSet,\n applyDecorators,\n bfs,\n buildSubscribableResult,\n capitalizeFirst,\n coerceResponseToFetchResponse,\n deepCopy,\n deepEquals,\n deepFreeze,\n encodeQueryParam,\n err,\n getFetchResponseFromAuraError,\n includes,\n isCacheHitOrError,\n isCacheMiss,\n isDataIncompleteError,\n isDataNotFoundError,\n isPromiseLike,\n isResult,\n isSubscribable,\n isSubscribableResult,\n isUserVisibleError,\n lineFormatter,\n logError,\n loggerService,\n ok,\n racesync,\n readableStreamToAsyncIterable,\n rejectedPromiseLike,\n resolvedPromiseLike,\n satisfies,\n setDifference,\n setOverlaps,\n stableJSONStringify,\n stringIsVersion,\n toError,\n toTypeScriptSafeIdentifier,\n withResolvers\n};\n//# sourceMappingURL=index.js.map\n","/*!\n * Copyright (c) 2022, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nimport { resolvedPromiseLike } from \"@conduit-client/utils\";\nfunction buildServiceDescriptor(interceptors = {\n request: [],\n retry: void 0,\n response: [],\n finally: []\n}, retryService) {\n return {\n type: \"fetch\",\n version: \"1.0\",\n service: function(...args) {\n var _a;\n const context = (_a = interceptors.createContext) == null ? void 0 : _a.call(interceptors);\n const {\n request: requestInterceptors = [],\n retry: retryInterceptor = void 0,\n response: responseInterceptors = [],\n finally: finallyInterceptors = []\n } = interceptors;\n const pending = requestInterceptors.reduce(\n (previousPromise, interceptor) => previousPromise.then((args2) => interceptor(args2, context)),\n resolvedPromiseLike(args)\n );\n return Promise.resolve(pending).then((args2) => {\n if (retryInterceptor) {\n return retryInterceptor(args2, retryService, context);\n } else {\n if (retryService) {\n return retryService.applyRetry(() => fetch(...args2));\n }\n return fetch(...args2);\n }\n }).then((response) => {\n return responseInterceptors.reduce(\n (previousPromise, interceptor) => previousPromise.then((response2) => interceptor(response2, context)),\n resolvedPromiseLike(response)\n );\n }).finally(() => {\n if (finallyInterceptors.length > 0) {\n return finallyInterceptors.reduce(\n (previousPromise, interceptor) => previousPromise.then(() => interceptor(context)),\n Promise.resolve()\n );\n }\n });\n }\n };\n}\nlet textEncoder;\nfunction getTextEncoder() {\n if (!textEncoder) {\n if (typeof TextEncoder === \"undefined\") {\n throw new Error(\n \"TextEncoder is not available in this environment. Request body compression requires TextEncoder support.\"\n );\n }\n textEncoder = new TextEncoder();\n }\n return textEncoder;\n}\nfunction buildCompressionInterceptor(config) {\n const threshold = config.threshold ?? 1024;\n return async (args) => {\n const [resource, options = {}] = args;\n if (!options.body || typeof options.body !== \"string\") {\n return resolvedPromiseLike(args);\n }\n if (typeof CompressionStream === \"undefined\") {\n return resolvedPromiseLike(args);\n }\n const headers = new Headers(options.headers);\n if (headers.has(\"Content-Encoding\")) {\n return resolvedPromiseLike(args);\n }\n const encodedBody = getTextEncoder().encode(options.body);\n if (encodedBody.byteLength < threshold) {\n return resolvedPromiseLike(args);\n }\n try {\n const stream = new Blob([encodedBody]).stream().pipeThrough(new CompressionStream(config.algorithm));\n const compressedBody = await new Response(stream).blob();\n headers.set(\"Content-Encoding\", config.algorithm);\n headers.delete(\"Content-Length\");\n const compressedOptions = {\n ...options,\n body: compressedBody,\n headers\n };\n return resolvedPromiseLike([resource, compressedOptions]);\n } catch {\n return resolvedPromiseLike(args);\n }\n };\n}\nfunction setHeader(headerName, headerValue, [resource, options = {}], {\n throwOnExisting = false,\n errorMessage = `Unexpected ${headerName} header encountered`\n} = {}) {\n let hasHeaderBeenSet = false;\n if (resource instanceof Request && !(options == null ? void 0 : options.headers)) {\n if (throwOnExisting && resource.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n resource.headers.set(headerName, headerValue);\n hasHeaderBeenSet = true;\n }\n if ((options == null ? void 0 : options.headers) instanceof Headers) {\n if (throwOnExisting && options.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n options.headers.set(headerName, headerValue);\n } else {\n if (throwOnExisting && (options == null ? void 0 : options.headers) && Reflect.has(options.headers, headerName)) {\n throw new Error(errorMessage);\n }\n if (!hasHeaderBeenSet) {\n options.headers = {\n ...options == null ? void 0 : options.headers,\n [headerName]: headerValue\n };\n }\n }\n return [resource, options];\n}\nconst UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE = \"Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor\";\nfunction setHeaderAuthorization({ token }, fetchParams) {\n const authorizationValue = `Bearer ${token}`;\n return setHeader(\"Authorization\", authorizationValue, fetchParams, {\n throwOnExisting: true,\n errorMessage: UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE\n });\n}\nfunction buildJwtRequestHeaderInterceptor(jwtManager, jwtRequestModifier = (_e, fetchArgs) => fetchArgs) {\n return (args) => {\n return resolvedPromiseLike(jwtManager.getJwt()).then((token) => {\n const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);\n return token.extraInfo ? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization) : fetchArgsWithRequestHeaderAuthorization;\n });\n };\n}\nclass AbortError extends Error {\n constructor(message = \"This operation was aborted\") {\n super(message);\n this.name = \"AbortError\";\n }\n}\nfunction buildMockFetchService(initialResponses = []) {\n let responses = [...initialResponses];\n const networkAdapter = (...args) => {\n var _a;\n const [_, fetchOptions = {}] = args;\n networkAdapter.requests.push(args);\n if ((_a = fetchOptions.signal) == null ? void 0 : _a.aborted) {\n return Promise.reject(new AbortError());\n }\n const result = responses.shift();\n if (result === void 0) {\n throw new Error(\"No more mock responses queued\");\n }\n networkAdapter.availableResponses = responses.length;\n networkAdapter.responsesUsed++;\n if (result instanceof Error) {\n return Promise.reject(result);\n }\n const delay = result.delay || 0;\n return new Promise((resolve, reject) => {\n let abortHandler = null;\n if (fetchOptions.signal) {\n abortHandler = () => {\n reject(new AbortError());\n };\n fetchOptions.signal.addEventListener(\"abort\", abortHandler);\n }\n const completeRequest = () => {\n var _a2;\n if (abortHandler && fetchOptions.signal) {\n fetchOptions.signal.removeEventListener(\"abort\", abortHandler);\n }\n if ((_a2 = fetchOptions.signal) == null ? void 0 : _a2.aborted) {\n reject(new AbortError());\n return;\n }\n resolve({\n ok: result.ok !== void 0 ? result.ok : true,\n statusText: result.statusText !== void 0 ? result.statusText : \"ok\",\n status: result.status !== void 0 ? result.status : 200,\n json: () => Promise.resolve(result.body)\n });\n };\n if (delay > 0) {\n setTimeout(completeRequest, delay);\n } else {\n setTimeout(completeRequest, 0);\n }\n });\n };\n networkAdapter.requests = [];\n networkAdapter.availableResponses = responses.length;\n networkAdapter.queueResponses = (newResponses) => {\n responses = responses.concat(newResponses);\n networkAdapter.availableResponses = responses.length;\n };\n networkAdapter.fetch = (args) => networkAdapter(args);\n networkAdapter.reset = () => {\n networkAdapter.requests = [];\n responses = [];\n networkAdapter.availableResponses = 0;\n networkAdapter.responsesUsed = 0;\n };\n networkAdapter.responsesUsed = 0;\n return {\n type: \"fetch\",\n version: \"1.0\",\n service: networkAdapter\n };\n}\nexport {\n buildCompressionInterceptor,\n buildJwtRequestHeaderInterceptor,\n buildMockFetchService,\n buildServiceDescriptor,\n setHeader,\n setHeaderAuthorization\n};\n//# sourceMappingURL=index.js.map\n","/*!\n * Copyright (c) 2022, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\nclass RetryService {\n constructor(defaultRetryPolicy) {\n this.defaultRetryPolicy = defaultRetryPolicy;\n }\n applyRetry(operation, retryPolicyOverride) {\n return this.retry(operation, retryPolicyOverride || this.defaultRetryPolicy);\n }\n async retry(operation, policy) {\n const startTime = Date.now();\n let attempt = 0;\n let result = await operation();\n let context = {\n attempt,\n totalElapsedMs: Date.now() - startTime,\n lastResult: result\n };\n while (await policy.shouldRetry(result, context)) {\n const delay = await policy.calculateDelay(result, context);\n await this.delay(delay);\n if (policy.prepareRetry) {\n await policy.prepareRetry(result, context);\n }\n attempt++;\n result = await operation();\n context = {\n attempt,\n totalElapsedMs: Date.now() - startTime,\n lastResult: result\n };\n }\n return result;\n }\n delay(ms) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n }\n}\nclass RetryPolicy {\n}\nclass ComposedRetryPolicy extends RetryPolicy {\n constructor(policies) {\n super();\n this.policies = policies;\n }\n /**\n * Returns true if any of the composed policies want to retry.\n *\n * Uses OR logic: if ANY policy returns true, this returns true.\n * Policies are checked in order and evaluation short-circuits on the first match.\n */\n async shouldRetry(result, context) {\n for (const policy of this.policies) {\n if (await policy.shouldRetry(result, context)) {\n return true;\n }\n }\n return false;\n }\n /**\n * Returns the delay from the first policy that wants to retry.\n *\n * If multiple policies want to retry, only the FIRST policy's delay is used.\n * Policy order in the constructor array determines priority.\n * If no policy wants to retry, returns 0.\n *\n * @example\n * ```typescript\n * // If both PolicyA (1000ms) and PolicyB (5000ms) want to retry:\n * const composed = new ComposedRetryPolicy([policyA, policyB]);\n * composed.calculateDelay(result, context); // Returns 1000ms (PolicyA wins)\n * ```\n */\n async calculateDelay(result, context) {\n for (const policy of this.policies) {\n if (await policy.shouldRetry(result, context)) {\n return policy.calculateDelay(result, context);\n }\n }\n return 0;\n }\n /**\n * Calls prepareRetry on policies that both:\n * 1. Implement the prepareRetry hook, AND\n * 2. Returned true from shouldRetry for this result\n *\n * This allows only the matching policies to perform preparation work (e.g., token refresh).\n * All matching prepareRetry calls run in parallel for efficiency.\n *\n * **Important**: prepareRetry only runs on policies that matched shouldRetry. This ensures\n * you don't perform unnecessary work or side effects for unrelated retry conditions.\n *\n * **Note**: If multiple policies match and have prepareRetry, ensure they don't have\n * conflicting side effects since they run in parallel.\n *\n * @example\n * ```typescript\n * // Status 401 occurs\n * const composed = new ComposedRetryPolicy([\n * authPolicy, // shouldRetry(401) → true, has prepareRetry\n * throttlePolicy, // shouldRetry(401) → false, has prepareRetry\n * ]);\n *\n * await composed.prepareRetry(result, context);\n * // → Only authPolicy.prepareRetry() runs (because it matched)\n * // → throttlePolicy.prepareRetry() does NOT run (didn't match)\n * ```\n */\n async prepareRetry(result, context) {\n const matchingPolicies = [];\n for (const policy of this.policies) {\n if (policy.prepareRetry !== void 0 && await policy.shouldRetry(result, context)) {\n matchingPolicies.push(policy);\n }\n }\n if (matchingPolicies.length > 0) {\n await Promise.all(\n matchingPolicies.map((policy) => policy.prepareRetry(result, context))\n );\n }\n }\n /**\n * Returns all composed policies.\n * Useful for accessing or configuring individual policies after composition.\n */\n getPolicies() {\n return this.policies;\n }\n /**\n * Helper to get a specific policy by type.\n * Useful for calling policy-specific methods after composition.\n *\n * @example\n * ```typescript\n * const csrfPolicy = composedPolicy.getPolicyByType(CsrfTokenRetryPolicy);\n * csrfPolicy?.setRequestContext(mutableRequest);\n * ```\n */\n getPolicyByType(policyType) {\n return this.policies.find((policy) => policy instanceof policyType);\n }\n}\nfunction buildServiceDescriptor(defaultRetryPolicy) {\n return {\n version: \"1.0\",\n service: new RetryService(defaultRetryPolicy),\n type: \"retry\"\n };\n}\nexport {\n ComposedRetryPolicy,\n RetryPolicy,\n RetryService,\n buildServiceDescriptor\n};\n//# sourceMappingURL=index.js.map\n","import { setHeader } from '@conduit-client/service-fetch-network/v1';\nimport { resolvedPromiseLike } from '@conduit-client/utils';\nimport type { CsrfTokenManager } from './token-manager';\nimport type { FetchParameters, RequestInterceptor } from '@conduit-client/service-fetch-network/v1';\n\nconst HEADER = 'X-CSRF-Token';\n\nexport interface HeaderInterceptorConfig {\n protectedUrls?: string[];\n}\n\n/**\n * Builds a configured interceptor for applying CSRF header to requests\n *\n * @param csrfTokenManager\n * @param config\n */\nexport function buildInterceptor(\n csrfTokenManager: CsrfTokenManager,\n config: HeaderInterceptorConfig = {}\n): RequestInterceptor {\n const { protectedUrls = [] } = config;\n\n return async (fetchArgs: FetchParameters) => {\n const [input, init] = fetchArgs;\n const request = new Request(input, init);\n\n // Only add CSRF token for mutating operations on protected URLs that don't already have one\n if (\n isProtectedMethod(request.method) &&\n isProtectedUrl(protectedUrls, request.url) &&\n !request.headers.has(HEADER)\n ) {\n const token = await csrfTokenManager.getToken();\n // eslint-disable-next-line no-param-reassign\n fetchArgs = setHeader(HEADER, token, fetchArgs);\n }\n\n return resolvedPromiseLike(fetchArgs);\n };\n}\n\n/**\n * Determines if the HTTP method requires CSRF protection.\n * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.\n *\n * @param method - The HTTP method to check\n * @returns true if the method requires CSRF protection\n */\nfunction isProtectedMethod(method: string): boolean {\n const normalizedMethod = method.toLowerCase();\n return (\n normalizedMethod === 'post' ||\n normalizedMethod === 'put' ||\n normalizedMethod === 'patch' ||\n normalizedMethod === 'delete'\n );\n}\n\n/**\n * Determines if the URL is for a path that requires CSRF protection.\n * Currently, protects all Salesforce API endpoints under '/services'.\n *\n * @param protectedUrls - Substrings that identify protected URLs\n * @param urlString - The full URL to check\n * @returns true if the URL requires CSRF protection\n * @note This could be made configurable in the future to support custom protected paths\n */\nfunction isProtectedUrl(protectedUrls: string[], urlString: string) {\n const url = new URL(urlString);\n\n // Agentforce Vibes IDE has a `absproxy/PORT/` path prefix for the Salesforce server\n return protectedUrls.some((protectedUrl) => url.pathname.includes(protectedUrl));\n}\n","import { type RetryService } from '@conduit-client/service-retry/v1';\nimport { buildInterceptor as buildHeaderInterceptor } from './header.interceptor';\nimport type { HeaderInterceptorConfig } from './header.interceptor';\nimport type { CsrfTokenManager } from './token-manager';\nimport type { FetchParameters } from '@conduit-client/service-fetch-network/v1';\n\nexport interface RetryInterceptorConfig extends HeaderInterceptorConfig {}\n\nexport function buildInterceptor(\n csrfTokenManager: CsrfTokenManager,\n config: RetryInterceptorConfig = {}\n) {\n const headerInterceptor = buildHeaderInterceptor(csrfTokenManager, config);\n\n /**\n * Makes request that has a CSRF header applied via an interceptor\n *\n * @param fetchArgs\n */\n async function makeRequest(fetchArgs: FetchParameters) {\n const args = await headerInterceptor(fetchArgs);\n return fetch(...args);\n }\n\n return (fetchArgs: FetchParameters, retryService?: RetryService<Response>) => {\n // simply make request if no service is provided\n if (!retryService) {\n return makeRequest(fetchArgs);\n }\n\n // run service with operation that makes the request\n return retryService.applyRetry(async () => {\n return makeRequest(fetchArgs);\n });\n };\n}\n","import { RetryPolicy, type RetryContext } from '@conduit-client/service-retry/v1';\nimport type { CsrfTokenManager } from './token-manager';\n\n/**\n * Retry policy that handles CSRF token expiration errors.\n *\n * When a request fails with a CSRF token error this policy will:\n * 1. Detect the error condition in shouldRetry\n * 2. Refresh the CSRF token in prepareRetry hook\n * 3. Retry the request once (maxRetries = 1)\n *\n */\nexport class CsrfTokenRetryPolicy extends RetryPolicy<Response> {\n constructor(private csrfTokenManager: CsrfTokenManager) {\n // @ts-ignore\n super(csrfTokenManager);\n }\n\n /**\n * Determines if a failed request should be retried due to CSRF token issues.\n */\n async shouldRetry(result: Response, context: RetryContext<Response>): Promise<boolean> {\n // Only retry once\n if (context.attempt >= 1) {\n return false;\n }\n\n // Only retry on 400 status\n if (result.status !== 400) {\n return false;\n }\n\n // Check if this is a CSRF error by examining the response body\n // This avoids retrying all 400s (validation errors, bad requests, etc.)\n // eslint-disable-next-line no-return-await\n return await isCsrfError(result);\n }\n\n /**\n * CSRF token refresh should happen immediately with no delay.\n */\n async calculateDelay(_result: Response, _context: RetryContext<Response>): Promise<number> {\n return 0; // No delay - retry immediately after token refresh\n }\n\n /**\n * Called by retry service before each retry attempt.\n *\n * @param _result - The failed response that triggered the retry (unused, already validated)\n * @param _context - Current retry context (unused but part of interface)\n */\n override async prepareRetry(\n _result: Response,\n _context: RetryContext<Response>\n ): Promise<void> {\n // Refresh the CSRF token (we already know this is a CSRF error from shouldRetry)\n await this.csrfTokenManager.refreshToken();\n }\n}\n\n/**\n * Helper to check if a response indicates a CSRF token error.\n *\n * @param response - The response to check\n * @returns true if the response indicates a CSRF token error (INVALID_ACCESS_TOKEN)\n */\nexport async function isCsrfError(response: Response): Promise<boolean> {\n try {\n // clone response to read body without consuming the original stream\n const body = await response.clone().json();\n\n // check for Salesforce's specific invalid token error code\n return body[0]?.errorCode === 'INVALID_ACCESS_TOKEN';\n } catch {\n // If we can't parse the body (network error, non-JSON response, etc.),\n // assume it's not a CSRF error\n return false;\n }\n}\n","/**\n * Manages CSRF token fetching and caching for secure requests.\n * Implements a singleton pattern to ensure consistent token management across the application.\n */\nclass CsrfTokenManager {\n private tokenPromise: Promise<string>;\n\n constructor(\n private endpoint: string,\n private cacheName?: string\n ) {\n this.tokenPromise = this.obtainToken();\n }\n\n /**\n * Returns the current token value as a Promise.\n * Lazy-loads the token on first call (from cache or by fetching).\n */\n async getToken(): Promise<string> {\n return this.tokenPromise;\n }\n\n /**\n * Obtains and returns a new token value as a promise.\n * This will clear the cached token and fetch a fresh one.\n */\n async refreshToken(): Promise<string | undefined> {\n // remove the invalid token from cache\n await this.withCache((cache) => cache.delete(this.endpoint));\n\n // start obtaining a new token\n this.tokenPromise = this.obtainToken();\n\n return this.tokenPromise;\n }\n\n /**\n * Obtains a CSRF token, using cache when available or fetching a new one.\n *\n * @returns Promise that resolves to the CSRF token string\n */\n private async obtainToken(): Promise<string> {\n // try to get cached token response first\n let response = await this.withCache((cache) => cache.match(this.endpoint));\n\n let cacheMiss = false;\n if (!response) {\n // no cached response available, fetch a new token\n response = await fetch(this.endpoint, { method: 'get' });\n cacheMiss = true;\n }\n\n // extract token from response (clone to avoid consuming original stream)\n const csrfToken: string = (await response.clone().json()).csrfToken;\n\n if (cacheMiss) {\n // cache the response for future use\n await this.withCache((cache) => cache.put(this.endpoint, response));\n }\n\n return csrfToken;\n }\n\n /**\n * Provides a safe way to interact with the Cache API with fallback for unsupported environments.\n *\n * @param callback - Function that receives the cache instance and returns a promise\n * @returns The result of the callback, or undefined if caches API is not available\n */\n private async withCache<T>(callback: (cache: Cache) => Promise<T>): Promise<T | undefined> {\n // Defend against the cache API not being available (e.g., in some test environments)\n if (this.cacheName && caches) {\n const cache = await caches.open(this.cacheName);\n return callback(cache);\n } else {\n return undefined;\n }\n }\n}\n\nexport { CsrfTokenManager };\n","import { buildServiceDescriptor as buildFetchServiceDescriptor } from '@conduit-client/service-fetch-network/v1';\nimport { buildServiceDescriptor as buildRetryServiceDescriptor } from '@conduit-client/service-retry/v1';\nimport { buildInterceptor as buildRetryInterceptor } from './csrf/retry.interceptor';\nimport { CsrfTokenRetryPolicy } from './csrf/retry.policy';\nimport { CsrfTokenManager } from './csrf/token-manager';\nimport type { RetryInterceptorConfig } from './csrf/retry.interceptor';\nimport type { FetchService } from '@conduit-client/service-fetch-network/v1';\n\ninterface CsrfConfig extends RetryInterceptorConfig {\n endpoint: string;\n cacheName: string;\n}\n\nexport interface FetchConfig {\n csrf: CsrfConfig;\n}\n\n/**\n * Creates an enhanced fetch function with automatic CSRF token handling.\n * The returned function automatically adds CSRF tokens to protected requests\n * and handles token refresh when tokens become invalid.\n *\n * @param config - Optional configuration for CSRF handling\n * @returns An enhanced fetch function that handles CSRF protection\n */\nexport function createFetchService(config: FetchConfig): FetchService {\n const csrfConfig = config.csrf;\n const csrfTokenManager = new CsrfTokenManager(csrfConfig.endpoint, csrfConfig.cacheName);\n\n return buildFetchServiceDescriptor(\n { retry: buildRetryInterceptor(csrfTokenManager, csrfConfig) },\n buildRetryServiceDescriptor(new CsrfTokenRetryPolicy(csrfTokenManager)).service\n ).service;\n}\n","import { createFetchService } from './fetch';\nimport type { FetchConfig } from './fetch';\nimport type { FetchService } from '@conduit-client/service-fetch-network/v1';\n\n/**\n * The fetch function used by the client. Defaults to enhanced fetch for CSRF protection.\n */\nlet clientFetch: FetchService;\n\nexport default function buildFetchService(config: FetchConfig) {\n if (!clientFetch) {\n clientFetch = createFetchService(config);\n }\n return clientFetch;\n}\n"],"names":["buildServiceDescriptor","buildInterceptor","buildHeaderInterceptor","buildFetchServiceDescriptor","buildRetryInterceptor","buildRetryServiceDescriptor"],"mappings":"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"}
@@ -1,37 +1,3 @@
1
1
  import type { FetchConfig } from './fetch';
2
- type ConduitClientConfig = {
3
- serviceWorkerUrl?: string;
4
- } & FetchConfig;
5
- /**
6
- * A client for making HTTP requests with CSRF protection. By default, protection is provided by
7
- * wrapping the native `fetch` API with functionality that will apply a CSRF token to appropriate
8
- * requests. This includes functionality to detect expired tokens, triggering a token refresh and
9
- * retry of the request.
10
- *
11
- * Optionally, CSRF protection can be offloaded to a service worker by making the appropriate calls
12
- * to `registerServiceWorker` and `defineServiceWorker`
13
- */
14
- export declare class ConduitClient {
15
- /**
16
- * Makes an HTTP request
17
- *
18
- * @param input - The URL, Request object, or relative path to request
19
- * @param init - Optional request configuration that will be merged with defaults
20
- * @returns Promise that resolves to the Response object
21
- */
22
- fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
23
- /**
24
- * Configures global settings for all ConduitClient instances.
25
- * This will recreate the internal fetch service with the new configuration.
26
- *
27
- * @param config - Configuration options for CSRF handling and other features
28
- */
29
- static initialize(config: ConduitClientConfig): Promise<void>;
30
- /**
31
- * Factory method to create a new ConduitClient instance
32
- *
33
- * @returns A new ConduitClient instance
34
- */
35
- static instance(): ConduitClient;
36
- }
37
- export {};
2
+ import type { FetchService } from '@conduit-client/service-fetch-network/v1';
3
+ export default function buildFetchService(config: FetchConfig): FetchService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduit-client/salesforce-lightning-service-worker",
3
- "version": "3.16.0-dev1",
3
+ "version": "3.17.0",
4
4
  "private": false,
5
5
  "description": "Service worker for accessing Salesforce data",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  "dist/"
24
24
  ],
25
25
  "scripts": {
26
- "build": "vite build && vite build --config vite.sw.config.js && tsc --build --emitDeclarationOnly",
26
+ "build": "vite build && tsc --build --emitDeclarationOnly",
27
27
  "clean": "rm -rf dist",
28
28
  "dev": "npm run build && tsx scripts/dev.ts",
29
29
  "test": "vitest run",
@@ -32,8 +32,8 @@
32
32
  "watch": "npm run build --watch"
33
33
  },
34
34
  "dependencies": {
35
- "@conduit-client/service-fetch-network": "3.16.0-dev1",
36
- "@conduit-client/utils": "3.16.0-dev1",
35
+ "@conduit-client/service-fetch-network": "3.17.0",
36
+ "@conduit-client/utils": "3.17.0",
37
37
  "vite": "6.3.5"
38
38
  },
39
39
  "volta": {
package/dist/sw.js DELETED
@@ -1,268 +0,0 @@
1
- /*!
2
- * Copyright (c) 2022, Salesforce, Inc.,
3
- * All rights reserved.
4
- * For full license text, see the LICENSE.txt file
5
- */
6
- function o(t) {
7
- return p(t) ? t.then((e) => e) : {
8
- then: (e, n) => {
9
- try {
10
- return o(e(t));
11
- } catch (r) {
12
- return e === void 0 ? o(t) : d(r);
13
- }
14
- }
15
- };
16
- }
17
- function d(t) {
18
- return p(t) ? t.then((e) => e) : {
19
- then: (e, n) => {
20
- if (typeof n == "function")
21
- try {
22
- return o(n(t));
23
- } catch (r) {
24
- return d(r);
25
- }
26
- return d(t);
27
- }
28
- };
29
- }
30
- function p(t) {
31
- return typeof (t == null ? void 0 : t.then) == "function";
32
- }
33
- /*!
34
- * Copyright (c) 2022, Salesforce, Inc.,
35
- * All rights reserved.
36
- * For full license text, see the LICENSE.txt file
37
- */
38
- function m(t = {
39
- request: [],
40
- retry: void 0,
41
- response: [],
42
- finally: []
43
- }, e) {
44
- return {
45
- type: "fetch",
46
- version: "1.0",
47
- service: function(...n) {
48
- var r;
49
- const s = (r = t.createContext) == null ? void 0 : r.call(t), {
50
- request: i = [],
51
- retry: a = void 0,
52
- response: l = [],
53
- finally: y = []
54
- } = t, k = i.reduce(
55
- (c, h) => c.then((f) => h(f, s)),
56
- o(n)
57
- );
58
- return Promise.resolve(k).then((c) => a ? a(c, e, s) : e ? e.applyRetry(() => fetch(...c)) : fetch(...c)).then((c) => l.reduce(
59
- (h, f) => h.then((R) => f(R, s)),
60
- o(c)
61
- )).finally(() => {
62
- if (y.length > 0)
63
- return y.reduce(
64
- (c, h) => c.then(() => h(s)),
65
- Promise.resolve()
66
- );
67
- });
68
- }
69
- };
70
- }
71
- function T(t, e, [n, r = {}], {
72
- throwOnExisting: s = !1,
73
- errorMessage: i = `Unexpected ${t} header encountered`
74
- } = {}) {
75
- let a = !1;
76
- if (n instanceof Request && !(r != null && r.headers)) {
77
- if (s && n.headers.has(t))
78
- throw new Error(i);
79
- n.headers.set(t, e), a = !0;
80
- }
81
- if ((r == null ? void 0 : r.headers) instanceof Headers) {
82
- if (s && r.headers.has(t))
83
- throw new Error(i);
84
- r.headers.set(t, e);
85
- } else {
86
- if (s && (r != null && r.headers) && Reflect.has(r.headers, t))
87
- throw new Error(i);
88
- a || (r.headers = {
89
- ...r == null ? void 0 : r.headers,
90
- [t]: e
91
- });
92
- }
93
- return [n, r];
94
- }
95
- /*!
96
- * Copyright (c) 2022, Salesforce, Inc.,
97
- * All rights reserved.
98
- * For full license text, see the LICENSE.txt file
99
- */
100
- class P {
101
- constructor(e) {
102
- this.defaultRetryPolicy = e;
103
- }
104
- applyRetry(e, n) {
105
- return this.retry(e, n || this.defaultRetryPolicy);
106
- }
107
- async retry(e, n) {
108
- const r = Date.now();
109
- let s = 0, i = await e(), a = {
110
- attempt: s,
111
- totalElapsedMs: Date.now() - r,
112
- lastResult: i
113
- };
114
- for (; await n.shouldRetry(i, a); ) {
115
- const l = await n.calculateDelay(i, a);
116
- await this.delay(l), n.prepareRetry && await n.prepareRetry(i, a), s++, i = await e(), a = {
117
- attempt: s,
118
- totalElapsedMs: Date.now() - r,
119
- lastResult: i
120
- };
121
- }
122
- return i;
123
- }
124
- delay(e) {
125
- return new Promise((n) => {
126
- setTimeout(n, e);
127
- });
128
- }
129
- }
130
- class C {
131
- }
132
- function E(t) {
133
- return {
134
- version: "1.0",
135
- service: new P(t),
136
- type: "retry"
137
- };
138
- }
139
- const w = "X-CSRF-Token";
140
- function L(t, e = {}) {
141
- const { protectedUrls: n = [] } = e;
142
- return async (r) => {
143
- const [s, i] = r, a = new Request(s, i);
144
- if (b(a.method) && D(n, a.url) && !a.headers.has(w)) {
145
- const l = await t.getToken();
146
- r = T(w, l, r);
147
- }
148
- return o(r);
149
- };
150
- }
151
- function b(t) {
152
- const e = t.toLowerCase();
153
- return e === "post" || e === "put" || e === "patch" || e === "delete";
154
- }
155
- function D(t, e) {
156
- const n = new URL(e);
157
- return t.some((r) => n.pathname.includes(r));
158
- }
159
- function I(t, e = {}) {
160
- const n = L(t, e);
161
- async function r(s) {
162
- const i = await n(s);
163
- return fetch(...i);
164
- }
165
- return (s, i) => i ? i.applyRetry(async () => r(s)) : r(s);
166
- }
167
- class _ extends C {
168
- constructor(e) {
169
- super(e), this.csrfTokenManager = e;
170
- }
171
- /**
172
- * Determines if a failed request should be retried due to CSRF token issues.
173
- */
174
- async shouldRetry(e, n) {
175
- return n.attempt >= 1 || e.status !== 400 ? !1 : await q(e);
176
- }
177
- /**
178
- * CSRF token refresh should happen immediately with no delay.
179
- */
180
- async calculateDelay(e, n) {
181
- return 0;
182
- }
183
- /**
184
- * Called by retry service before each retry attempt.
185
- *
186
- * @param _result - The failed response that triggered the retry (unused, already validated)
187
- * @param _context - Current retry context (unused but part of interface)
188
- */
189
- async prepareRetry(e, n) {
190
- await this.csrfTokenManager.refreshToken();
191
- }
192
- }
193
- async function q(t) {
194
- var e;
195
- try {
196
- return ((e = (await t.clone().json())[0]) == null ? void 0 : e.errorCode) === "INVALID_ACCESS_TOKEN";
197
- } catch {
198
- return !1;
199
- }
200
- }
201
- class M {
202
- constructor(e, n) {
203
- this.endpoint = e, this.cacheName = n, this.tokenPromise = this.obtainToken();
204
- }
205
- /**
206
- * Returns the current token value as a Promise.
207
- * Lazy-loads the token on first call (from cache or by fetching).
208
- */
209
- async getToken() {
210
- return this.tokenPromise;
211
- }
212
- /**
213
- * Obtains and returns a new token value as a promise.
214
- * This will clear the cached token and fetch a fresh one.
215
- */
216
- async refreshToken() {
217
- return await this.withCache((e) => e.delete(this.endpoint)), this.tokenPromise = this.obtainToken(), this.tokenPromise;
218
- }
219
- /**
220
- * Obtains a CSRF token, using cache when available or fetching a new one.
221
- *
222
- * @returns Promise that resolves to the CSRF token string
223
- */
224
- async obtainToken() {
225
- let e = await this.withCache((s) => s.match(this.endpoint)), n = !1;
226
- e || (e = await fetch(this.endpoint, { method: "get" }), n = !0);
227
- const r = (await e.clone().json()).csrfToken;
228
- return n && await this.withCache((s) => s.put(this.endpoint, e)), r;
229
- }
230
- /**
231
- * Provides a safe way to interact with the Cache API with fallback for unsupported environments.
232
- *
233
- * @param callback - Function that receives the cache instance and returns a promise
234
- * @returns The result of the callback, or undefined if caches API is not available
235
- */
236
- async withCache(e) {
237
- if (this.cacheName && caches) {
238
- const n = await caches.open(this.cacheName);
239
- return e(n);
240
- } else
241
- return;
242
- }
243
- }
244
- function S(t) {
245
- const e = t.csrf, n = new M(e.endpoint, e.cacheName);
246
- return m(
247
- { retry: I(n, e) },
248
- E(new _(n)).service
249
- ).service;
250
- }
251
- const u = self;
252
- let v;
253
- u.addEventListener("install", (t) => {
254
- t.waitUntil(u.skipWaiting());
255
- });
256
- u.addEventListener("activate", (t) => {
257
- t.waitUntil(u.clients.claim());
258
- });
259
- u.addEventListener("message", (t) => {
260
- var e;
261
- if (((e = t.data) == null ? void 0 : e.type) === "fetch-config") {
262
- const n = t.data.config;
263
- v = S(n);
264
- }
265
- });
266
- u.addEventListener("fetch", (t) => {
267
- t.respondWith(v(t.request));
268
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};