@ondc/automation-mock-runner 1.3.42 → 1.3.44

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.
@@ -1,4 +1,5 @@
1
1
  import { BaseCodeRunner } from "./runners/base-runner";
2
+ import { RunnerOptions } from "./runners/runner-factory";
2
3
  import { MockPlaygroundConfigType } from "./types/mock-config";
3
4
  import { Logger } from "./utils/logger";
4
5
  import { ExecutionResult } from "./types/execution-results";
@@ -7,6 +8,14 @@ export declare class MockRunner {
7
8
  private static sharedRunner;
8
9
  logger: Logger;
9
10
  private static getSharedRunner;
11
+ /**
12
+ * Initialize (or replace) the process-wide shared runner with explicit
13
+ * options. Call this once at service boot — before constructing any
14
+ * MockRunner — to configure the fetch allowlist and worker pool settings.
15
+ *
16
+ * If a shared runner already exists it is terminated and replaced.
17
+ */
18
+ static initSharedRunner(options?: RunnerOptions): BaseCodeRunner;
10
19
  constructor(config: MockPlaygroundConfigType, skipValidation?: boolean);
11
20
  getRunnerInstance(): BaseCodeRunner;
12
21
  getConfig(): {
@@ -69,9 +78,9 @@ export declare class MockRunner {
69
78
  success: boolean;
70
79
  errors?: import("zod/v4/core").$ZodIssue[];
71
80
  };
72
- runGeneratePayload(actionId: string, inputs?: any): Promise<ExecutionResult>;
81
+ runGeneratePayload(actionId: string, inputs?: any, extraSessionData?: Record<string, any>): Promise<ExecutionResult>;
73
82
  runGeneratePayloadWithSession(actionId: string, sessionData: any): Promise<ExecutionResult>;
74
- runValidatePayload(actionId: string, targetPayload: any): Promise<ExecutionResult>;
83
+ runValidatePayload(actionId: string, targetPayload: any, extraSessionData?: Record<string, any>): Promise<ExecutionResult>;
75
84
  runValidatePayloadWithSession(actionId: string, targetPayload: any, sessionData: any): Promise<ExecutionResult>;
76
85
  runMeetRequirements(actionId: string): Promise<ExecutionResult>;
77
86
  runMeetRequirementsWithSession(actionId: string, sessionData: any): Promise<ExecutionResult>;
@@ -81,5 +90,6 @@ export declare class MockRunner {
81
90
  static runGetSave(payload: any, expression: string): Promise<ExecutionResult>;
82
91
  static encodeBase64(input: string): string;
83
92
  static decodeBase64(encoded: string): string;
93
+ private static resolveBaseActionId;
84
94
  private static getIdFromSession;
85
95
  }
@@ -18,6 +18,27 @@ class MockRunner {
18
18
  }
19
19
  return MockRunner.sharedRunner;
20
20
  }
21
+ /**
22
+ * Initialize (or replace) the process-wide shared runner with explicit
23
+ * options. Call this once at service boot — before constructing any
24
+ * MockRunner — to configure the fetch allowlist and worker pool settings.
25
+ *
26
+ * If a shared runner already exists it is terminated and replaced.
27
+ */
28
+ static initSharedRunner(options = {}) {
29
+ const logger = logger_1.Logger.getInstance();
30
+ if (MockRunner.sharedRunner) {
31
+ logger.warn("Replacing existing shared runner");
32
+ try {
33
+ MockRunner.sharedRunner.terminate();
34
+ }
35
+ catch (e) {
36
+ logger.error("Failed to terminate previous shared runner", {}, e);
37
+ }
38
+ }
39
+ MockRunner.sharedRunner = runner_factory_1.RunnerFactory.createRunner(options, logger);
40
+ return MockRunner.sharedRunner;
41
+ }
21
42
  constructor(config, skipValidation = false) {
22
43
  this.logger = logger_1.Logger.getInstance();
23
44
  if (!skipValidation) {
@@ -55,23 +76,27 @@ class MockRunner {
55
76
  const res = (0, validateConfig_1.validateConfigWithErrors)(this.config);
56
77
  return res;
57
78
  }
58
- async runGeneratePayload(actionId, inputs = {}) {
79
+ async runGeneratePayload(actionId, inputs = {}, extraSessionData) {
59
80
  const executionId = this.logger.createExecutionContext(actionId);
60
81
  const startTime = Date.now();
61
82
  try {
83
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
62
84
  this.logger.logExecution(executionId, "Starting payload generation", {
63
85
  actionId,
64
86
  inputKeys: Object.keys(inputs),
65
87
  });
66
- const step = this.config.steps.find((s) => s.action_id === actionId);
88
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
67
89
  if (!step) {
68
90
  const availableActions = this.config.steps.map((s) => s.action_id);
69
91
  throw new errors_1.ActionNotFoundError(actionId, availableActions);
70
92
  }
71
- const index = this.config.steps.findIndex((s) => s.action_id === actionId);
93
+ const index = this.config.steps.findIndex((s) => s.action_id === baseActionId);
72
94
  // Deep clone to avoid mutations
73
95
  const defaultPayload = JSON.parse(JSON.stringify(step.mock.defaultPayload));
74
96
  const sessionData = await this.getSessionDataUpToStep(index);
97
+ if (extraSessionData) {
98
+ Object.assign(sessionData, extraSessionData);
99
+ }
75
100
  // Validate inputs against schema if provided
76
101
  if (step.mock.inputs?.jsonSchema && Object.keys(inputs).length > 0) {
77
102
  // TODO: Add JSON schema validation for inputs
@@ -132,16 +157,17 @@ class MockRunner {
132
157
  const executionId = this.logger.createExecutionContext(actionId);
133
158
  const startTime = Date.now();
134
159
  try {
160
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
135
161
  this.logger.logExecution(executionId, "Starting payload generation with session data", {
136
162
  actionId,
137
163
  sessionKeys: Object.keys(sessionData),
138
164
  });
139
- const step = this.config.steps.find((s) => s.action_id === actionId);
165
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
140
166
  if (!step) {
141
167
  const availableActions = this.config.steps.map((s) => s.action_id);
142
168
  throw new errors_1.ActionNotFoundError(actionId, availableActions);
143
169
  }
144
- const index = this.config.steps.findIndex((s) => s.action_id === actionId);
170
+ const index = this.config.steps.findIndex((s) => s.action_id === baseActionId);
145
171
  // Deep clone to avoid mutations
146
172
  const defaultPayload = JSON.parse(JSON.stringify(step.mock.defaultPayload));
147
173
  const context = this.generateContext(step.action_id, step.api, sessionData);
@@ -189,15 +215,19 @@ class MockRunner {
189
215
  };
190
216
  }
191
217
  }
192
- async runValidatePayload(actionId, targetPayload) {
218
+ async runValidatePayload(actionId, targetPayload, extraSessionData) {
193
219
  try {
194
- const step = this.config.steps.find((s) => s.action_id === actionId);
220
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
221
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
195
222
  if (!step) {
196
223
  throw new Error(`Action step with ID ${actionId} not found.`);
197
224
  }
198
- const index = this.config.steps.findIndex((s) => s.action_id === actionId);
225
+ const index = this.config.steps.findIndex((s) => s.action_id === baseActionId);
199
226
  const schema = (0, function_registry_1.getFunctionSchema)("validate");
200
227
  const sessionData = await this.getSessionDataUpToStep(index);
228
+ if (extraSessionData) {
229
+ Object.assign(sessionData, extraSessionData);
230
+ }
201
231
  const result = await this.getRunnerInstance().execute(MockRunner.decodeBase64(step.mock.validate), schema, [targetPayload, sessionData]);
202
232
  return result;
203
233
  }
@@ -217,7 +247,8 @@ class MockRunner {
217
247
  }
218
248
  async runValidatePayloadWithSession(actionId, targetPayload, sessionData) {
219
249
  try {
220
- const step = this.config.steps.find((s) => s.action_id === actionId);
250
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
251
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
221
252
  if (!step) {
222
253
  throw new Error(`Action step with ID ${actionId} not found.`);
223
254
  }
@@ -241,11 +272,12 @@ class MockRunner {
241
272
  }
242
273
  async runMeetRequirements(actionId) {
243
274
  try {
244
- const step = this.config.steps.find((s) => s.action_id === actionId);
275
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
276
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
245
277
  if (!step) {
246
278
  throw new Error(`Action step with ID ${actionId} not found.`);
247
279
  }
248
- const index = this.config.steps.findIndex((s) => s.action_id === actionId);
280
+ const index = this.config.steps.findIndex((s) => s.action_id === baseActionId);
249
281
  const schema = (0, function_registry_1.getFunctionSchema)("meetsRequirements");
250
282
  const sessionData = await this.getSessionDataUpToStep(index);
251
283
  const result = await this.getRunnerInstance().execute(MockRunner.decodeBase64(step.mock.requirements), schema, [sessionData]);
@@ -267,7 +299,8 @@ class MockRunner {
267
299
  }
268
300
  async runMeetRequirementsWithSession(actionId, sessionData) {
269
301
  try {
270
- const step = this.config.steps.find((s) => s.action_id === actionId);
302
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
303
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
271
304
  if (!step) {
272
305
  throw new Error(`Action step with ID ${actionId} not found.`);
273
306
  }
@@ -290,6 +323,7 @@ class MockRunner {
290
323
  }
291
324
  }
292
325
  getDefaultStep(api, actionId, formType) {
326
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
293
327
  if (formType === "dynamic_form" || formType === "html_form") {
294
328
  return {
295
329
  api: api,
@@ -386,7 +420,10 @@ class MockRunner {
386
420
  }
387
421
  generateContext(actionId, action, sessionData) {
388
422
  // Find the step configuration for this action
389
- const step = this.config.steps.find((s) => s.action_id === actionId);
423
+ // GENERATED#1#on_search_full_page_gcr
424
+ // get the last by splitting on # and taking the last part
425
+ const baseActionId = MockRunner.resolveBaseActionId(actionId);
426
+ const step = this.config.steps.find((s) => s.action_id === baseActionId);
390
427
  // Determine the message_id based on responseFor logic
391
428
  let messageId = (0, uuid_1.v4)();
392
429
  if (step?.responseFor) {
@@ -587,6 +624,9 @@ class MockRunner {
587
624
  const bytes = new Uint8Array([...binaryString].map((char) => char.charCodeAt(0)));
588
625
  return new TextDecoder().decode(bytes);
589
626
  }
627
+ static resolveBaseActionId(actionId) {
628
+ return actionId.split("#").slice(-1)[0];
629
+ }
590
630
  static getIdFromSession(sessionData, key) {
591
631
  if (sessionData === undefined) {
592
632
  return undefined;
@@ -11,6 +11,7 @@ const MockRunner_1 = require("./MockRunner");
11
11
  const uuid_1 = require("uuid");
12
12
  const terser_1 = require("terser");
13
13
  const validateConfig_1 = require("./utils/validateConfig");
14
+ const helpers_1 = require("./helpers");
14
15
  function createInitialMockConfig(domain, version, flowId) {
15
16
  return {
16
17
  meta: {
@@ -32,65 +33,9 @@ function createInitialMockConfig(domain, version, flowId) {
32
33
  steps: [],
33
34
  transaction_history: [],
34
35
  validationLib: "",
35
- helperLib: MockRunner_1.MockRunner.encodeBase64(defaultHelpers),
36
+ helperLib: MockRunner_1.MockRunner.encodeBase64(helpers_1.DEFAULT_HELPER_LIB),
36
37
  };
37
38
  }
38
- const defaultHelpers = `/*
39
- Custom helper functions available in all mock generation functions.
40
- these are appended below the generate function for each step.
41
- */
42
-
43
- const createFormURL = (domain,formId, sessionData) => {
44
- const baseURL = sessionData.mockBaseUrl;
45
- const transactionId = sessionData.transactionId[0];
46
- const sessionId = sessionData.sessionId;
47
- return \`\${baseURL}/forms/\${domain}/\${formId}/?transaction_id=\${transactionId}&session_id=\${sessionId}\`;
48
- }
49
-
50
- // Generates a UUID v4
51
- function uuidv4() {
52
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
53
- const r = Math.random() * 16 | 0;
54
- const v = c === 'x' ? r : (r & 0x3 | 0x8);
55
- return v.toString(16);
56
- });
57
- }
58
-
59
- // Generate a 6 digit string ID
60
- function generate6DigitId() {
61
- return Math.floor(100000 + Math.random() * 900000).toString();
62
- }
63
-
64
- // Returns the current ISO timestamp
65
- function currentTimestamp() {
66
- return new Date().toISOString();
67
- }
68
-
69
- // Converts ISO 8601 duration string to total seconds
70
- const isoDurToSec = (duration) => {
71
- const durRE = /P((\d+)Y)?((\d+)M)?((\d+)W)?((\d+)D)?T?((\d+)H)?((\d+)M)?((\d+)S)?/;
72
- const s = durRE.exec(duration);
73
- if (!s) return 0;
74
-
75
- return (Number(s?.[2]) || 0) * 31536000 +
76
- (Number(s?.[4]) || 0) * 2628288 +
77
- (Number(s?.[6]) || 0) * 604800 +
78
- (Number(s?.[8]) || 0) * 86400 +
79
- (Number(s?.[10]) || 0) * 3600 +
80
- (Number(s?.[12]) || 0) * 60 +
81
- (Number(s?.[14]) || 0);
82
- };
83
-
84
- const setCityFromInputs = (payload, inputs) => {
85
- if (!inputs) return "*";
86
- let version = payload.context.version || payload.context.core_version || "2.0.0";
87
- if (version.startsWith("1")) {
88
- payload.context.city = inputs.city_code ?? "*";
89
- } else {
90
- payload.context.location.city.code = inputs.city_code ?? "*";
91
- }
92
- }
93
- `;
94
39
  function convertToFlowConfig(config) {
95
40
  const flowConfig = {};
96
41
  flowConfig.id = config.meta.flowId;
@@ -172,13 +117,25 @@ function convertToFlowConfig(config) {
172
117
  if (step.mock.inputs !== undefined &&
173
118
  step.mock.inputs !== null &&
174
119
  Object.keys(step.mock.inputs).length > 0) {
175
- flowStep.input = [
176
- {
177
- name: step.mock.inputs.id,
178
- type: step.mock.inputs.id,
179
- schema: step.mock.inputs.jsonSchema,
180
- },
181
- ];
120
+ if (step.mock.inputs.id == "finvu_verification") {
121
+ flowStep.input = [
122
+ {
123
+ name: "finvu_verification",
124
+ label: "Complete Account Aggregator Verification",
125
+ type: "FINVU_REDIRECT",
126
+ payloadField: "$.context.aa_consent_verified",
127
+ },
128
+ ];
129
+ }
130
+ else {
131
+ flowStep.input = [
132
+ {
133
+ name: step.mock.inputs.id,
134
+ type: step.mock.inputs.id,
135
+ schema: step.mock.inputs.jsonSchema,
136
+ },
137
+ ];
138
+ }
182
139
  }
183
140
  if (step.mock.inputs?.oldInputs) {
184
141
  flowStep.input = step.mock.inputs.oldInputs;
@@ -26,7 +26,7 @@ exports.FUNCTION_REGISTRY = {
26
26
  description: "The generated payload object to be sent in the API request",
27
27
  },
28
28
  description: "Generates the mock payload for an API call",
29
- timeout: 35 * 1000,
29
+ timeout: 45 * 1000,
30
30
  defaultBody: ` return defaultPayload;`,
31
31
  template: (body) => `/**
32
32
  * Generates the mock payload for an API call in the transaction flow.
@@ -0,0 +1,13 @@
1
+ export function getSubscriberUrl(sessionData: any, type: any): any;
2
+ export function uuidv4(): string;
3
+ export function generate6DigitId(): string;
4
+ export function currentTimestamp(): string;
5
+ export function isoDurToSec(duration: any): number;
6
+ export function setCityFromInputs(payload: any, inputs: any): "*" | undefined;
7
+ export function createFormURL(domain: any, formId: any, sessionData: any): string;
8
+ export function generateConsentHandler(sessionData: any, { custId, templateName, consentDescription, redirectUrl, }: {
9
+ custId: any;
10
+ templateName?: string | undefined;
11
+ consentDescription?: string | undefined;
12
+ redirectUrl?: string | undefined;
13
+ }): Promise<any>;
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ /*
3
+ * Default helpers available to every `generate()` in a mock step.
4
+ *
5
+ * Authoring rules (enforced by how this file is consumed, not by tooling):
6
+ * 1. Use `function` declarations only. Arrow `const x = () => {}` stringifies
7
+ * as an expression — it won't hoist or concat cleanly when each function
8
+ * is `.toString()`-ed into the helper bundle.
9
+ * 2. No `require` / `import` inside function bodies. The VM sandbox has no
10
+ * module system. Only sandbox-whitelisted globals (Math, Date, JSON, …)
11
+ * and sibling helpers are in scope.
12
+ * 3. Cross-helper calls are fine — every function declaration lands in the
13
+ * same flat script after assembly, and declarations hoist.
14
+ * 4. Put docs INSIDE the function body (first statement). Leading comments
15
+ * above a declaration are dropped by `fn.toString()`, so they never
16
+ * reach the assembled bundle.
17
+ * 5. If the helper needs request-scope data, take `sessionData` as an
18
+ * explicit parameter. Free-variable references to `sessionData` do NOT
19
+ * resolve at runtime — helpers are declared at script scope, `sessionData`
20
+ * is only a parameter of `generate()`.
21
+ *
22
+ * The `module.exports = {...}` line at the bottom is only used by Node
23
+ * (index.ts and the Jest tests). `fn.toString()` never includes it, so it
24
+ * doesn't leak into the sandbox string.
25
+ */
26
+ function getSubscriberUrl(sessionData, type) {
27
+ // Resolve the BPP or BAP subscriber URL from session data.
28
+ // Usage: getSubscriberUrl(sessionData, "bpp")
29
+ if (type === "bpp") {
30
+ return sessionData.bppUri;
31
+ }
32
+ else {
33
+ return sessionData.bapUri;
34
+ }
35
+ }
36
+ function uuidv4() {
37
+ // Generates a UUID v4 (RFC 4122, random-based).
38
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
39
+ const r = (Math.random() * 16) | 0;
40
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
41
+ return v.toString(16);
42
+ });
43
+ }
44
+ function generate6DigitId() {
45
+ // Generate a 6-digit numeric string ID in [100000, 999999].
46
+ return Math.floor(100000 + Math.random() * 900000).toString();
47
+ }
48
+ function currentTimestamp() {
49
+ // Returns the current ISO-8601 UTC timestamp (e.g. "2026-04-23T12:34:56.789Z").
50
+ return new Date().toISOString();
51
+ }
52
+ function isoDurToSec(duration) {
53
+ /*
54
+ * Convert an ISO 8601 duration string (e.g. "PT1H30M", "P2DT3H") to total seconds.
55
+ * Returns 0 for unparseable input.
56
+ * Approximations used: 1 week = 7 days, 1 month ≈ 30.42 days (2628288 sec),
57
+ * 1 year = 365 days. Not calendar-exact.
58
+ */
59
+ const durRE = /P((\d+)Y)?((\d+)M)?((\d+)W)?((\d+)D)?T?((\d+)H)?((\d+)M)?((\d+)S)?/;
60
+ const s = durRE.exec(duration);
61
+ if (!s)
62
+ return 0;
63
+ return ((Number(s?.[2]) || 0) * 31536000 +
64
+ (Number(s?.[4]) || 0) * 2628288 +
65
+ (Number(s?.[6]) || 0) * 604800 +
66
+ (Number(s?.[8]) || 0) * 86400 +
67
+ (Number(s?.[10]) || 0) * 3600 +
68
+ (Number(s?.[12]) || 0) * 60 +
69
+ (Number(s?.[14]) || 0));
70
+ }
71
+ function setCityFromInputs(payload, inputs) {
72
+ /*
73
+ * Mutates `payload.context` in place to set the city code from `inputs.city_code`.
74
+ * Version-aware: ONDC v1.x uses flat `context.city`, v2.x uses nested
75
+ * `context.location.city.code`. Falls back to "*" when city_code is missing.
76
+ * No-op when `inputs` is falsy.
77
+ */
78
+ if (!inputs)
79
+ return "*";
80
+ const version = payload.context.version || payload.context.core_version || "2.0.0";
81
+ if (version.startsWith("1")) {
82
+ payload.context.city = inputs.city_code ?? "*";
83
+ }
84
+ else {
85
+ payload.context.location.city.code = inputs.city_code ?? "*";
86
+ }
87
+ }
88
+ function createFormURL(domain, formId, sessionData) {
89
+ /*
90
+ * Build a form submission URL from session data.
91
+ * Reads sessionData.mockBaseUrl, sessionData.transactionId[0], sessionData.sessionId.
92
+ * Returns: `${baseURL}/forms/${domain}/${formId}/?transaction_id=...&session_id=...`
93
+ */
94
+ const baseURL = sessionData.mockBaseUrl;
95
+ const transactionId = sessionData.transactionId[0];
96
+ const sessionId = sessionData.sessionId;
97
+ return `${baseURL}/forms/${domain}/${formId}/?transaction_id=${transactionId}&session_id=${sessionId}`;
98
+ }
99
+ async function generateConsentHandler(sessionData, { custId, templateName = "FINVUDEMO_TESTING", consentDescription = "Gold Loan Account Aggregator Consent", redirectUrl = "https://google.co.in", }) {
100
+ /*
101
+ * Generate a consent handler from the Finvu AA Service.
102
+ * Reads the service base URL from `sessionData.finvuUrl` — the installing
103
+ * service MUST include that origin in
104
+ * MockRunner.initSharedRunner({ allowedFetchBaseUrls: [...] })
105
+ * otherwise the sandboxed fetch will be blocked.
106
+ *
107
+ * Times out after 10s via AbortController.
108
+ *
109
+ * @param {Object} sessionData session data; sessionData.finvuUrl is required
110
+ * @param {Object} params
111
+ * @param {string} params.custId customer ID (required)
112
+ * @param {string} [params.templateName]
113
+ * @param {string} [params.consentDescription]
114
+ * @param {string} [params.redirectUrl]
115
+ * @returns {Promise<string>} consentHandler
116
+ */
117
+ if (!custId) {
118
+ throw new Error("custId is required");
119
+ }
120
+ const baseUrl = sessionData && sessionData.finvuUrl;
121
+ if (!baseUrl) {
122
+ throw new Error("sessionData.finvuUrl is required");
123
+ }
124
+ const url = `${baseUrl}/finvu-aa/consent/generate`;
125
+ const payload = {
126
+ custId,
127
+ templateName,
128
+ consentDescription,
129
+ redirectUrl,
130
+ };
131
+ console.log("Calling Finvu AA Service:", url);
132
+ console.log("Consent request payload:", payload);
133
+ const controller = new AbortController();
134
+ const timeout = setTimeout(() => controller.abort(), 10000);
135
+ try {
136
+ const res = await fetch(url, {
137
+ method: "POST",
138
+ headers: {
139
+ "Content-Type": "application/json",
140
+ },
141
+ body: JSON.stringify(payload),
142
+ signal: controller.signal,
143
+ });
144
+ if (!res.ok) {
145
+ const text = await res.text();
146
+ throw new Error(`Request failed: ${res.status} ${text}`);
147
+ }
148
+ const data = await res.json();
149
+ if (!data || !data.consentHandler) {
150
+ throw new Error("Invalid response: consentHandler missing");
151
+ }
152
+ return data.consentHandler;
153
+ }
154
+ catch (err) {
155
+ if (err && err.name === "AbortError") {
156
+ throw new Error("Request timed out after 10 seconds");
157
+ }
158
+ throw err;
159
+ }
160
+ finally {
161
+ clearTimeout(timeout);
162
+ }
163
+ }
164
+ module.exports = {
165
+ getSubscriberUrl,
166
+ uuidv4,
167
+ generate6DigitId,
168
+ currentTimestamp,
169
+ isoDurToSec,
170
+ setCityFromInputs,
171
+ createFormURL,
172
+ generateConsentHandler,
173
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Unit tests for the default helper functions + bundle integrity.
3
+ *
4
+ * Unit tests import the functions as a normal CJS module and call them.
5
+ * The bundle test loads DEFAULT_HELPER_LIB into a fresh vm context — this
6
+ * simulates how the string is actually used in the worker sandbox and
7
+ * catches any stringification / hoisting / free-variable regressions.
8
+ */
9
+ export {};