@ondc/automation-mock-runner 1.3.43 → 1.3.45

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>;
@@ -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,7 +76,7 @@ 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 {
@@ -73,6 +94,9 @@ class MockRunner {
73
94
  // Deep clone to avoid mutations
74
95
  const defaultPayload = JSON.parse(JSON.stringify(step.mock.defaultPayload));
75
96
  const sessionData = await this.getSessionDataUpToStep(index);
97
+ if (extraSessionData) {
98
+ Object.assign(sessionData, extraSessionData);
99
+ }
76
100
  // Validate inputs against schema if provided
77
101
  if (step.mock.inputs?.jsonSchema && Object.keys(inputs).length > 0) {
78
102
  // TODO: Add JSON schema validation for inputs
@@ -191,7 +215,7 @@ class MockRunner {
191
215
  };
192
216
  }
193
217
  }
194
- async runValidatePayload(actionId, targetPayload) {
218
+ async runValidatePayload(actionId, targetPayload, extraSessionData) {
195
219
  try {
196
220
  const baseActionId = MockRunner.resolveBaseActionId(actionId);
197
221
  const step = this.config.steps.find((s) => s.action_id === baseActionId);
@@ -201,6 +225,9 @@ class MockRunner {
201
225
  const index = this.config.steps.findIndex((s) => s.action_id === baseActionId);
202
226
  const schema = (0, function_registry_1.getFunctionSchema)("validate");
203
227
  const sessionData = await this.getSessionDataUpToStep(index);
228
+ if (extraSessionData) {
229
+ Object.assign(sessionData, extraSessionData);
230
+ }
204
231
  const result = await this.getRunnerInstance().execute(MockRunner.decodeBase64(step.mock.validate), schema, [targetPayload, sessionData]);
205
232
  return result;
206
233
  }
@@ -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 @@
1
+ export declare const DEFAULT_HELPERS_RAW = "\n/*\n * Default helpers available to every `generate()` in a mock step.\n *\n * Authoring rules:\n * 1. Prefer `function` declarations \u2014 they hoist, so cross-helper calls\n * work regardless of order.\n * 2. No `require` / `import` inside function bodies. The VM sandbox has no\n * module system. Only sandbox-whitelisted globals (Math, Date, JSON, \u2026)\n * and sibling helpers are in scope.\n * 3. If the helper needs request-scope data, take `sessionData` as an\n * explicit parameter. Free-variable references to `sessionData` do NOT\n * resolve at runtime \u2014 helpers run at script scope, `sessionData` is\n * only a parameter of `generate()`.\n * 4. Document every helper with a leading JSDoc block (`@param`, `@returns`).\n *\n * The full file (minus the trailing `module.exports = {...}` block) is\n * embedded verbatim into the sandbox bundle by\n * `scripts/generate-helpers-source.js`, so JSDoc reaches end users unchanged.\n * Re-run `npm run helpers:gen` after editing.\n */\n\n/**\n * Resolve the BPP or BAP subscriber URL from session data.\n *\n * @param {Object} sessionData session data (reads `bppUri` or `bapUri`)\n * @param {\"bpp\"|\"bap\"|string} type subscriber kind; anything other than \"bpp\" returns bapUri\n * @returns {string} the subscriber URL\n */\nfunction getSubscriberUrl(sessionData, type) {\n\tif (type === \"bpp\") {\n\t\treturn sessionData.bppUri;\n\t} else {\n\t\treturn sessionData.bapUri;\n\t}\n}\n\n/**\n * Generate a UUID v4 (RFC 4122, random-based).\n *\n * @returns {string} a new UUID v4, e.g. \"550e8400-e29b-41d4-a716-446655440000\"\n */\nfunction uuidv4() {\n\treturn \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n\t\tconst r = (Math.random() * 16) | 0;\n\t\tconst v = c === \"x\" ? r : (r & 0x3) | 0x8;\n\t\treturn v.toString(16);\n\t});\n}\n\n/**\n * Generate a 6-digit numeric string ID in [100000, 999999].\n *\n * @returns {string} a zero-padded 6-digit numeric string\n */\nfunction generate6DigitId() {\n\treturn Math.floor(100000 + Math.random() * 900000).toString();\n}\n\n/**\n * Get the current ISO-8601 UTC timestamp.\n *\n * @returns {string} e.g. \"2026-04-23T12:34:56.789Z\"\n */\nfunction currentTimestamp() {\n\treturn new Date().toISOString();\n}\n\n/**\n * Convert an ISO 8601 duration string (e.g. \"PT1H30M\", \"P2DT3H\") to total seconds.\n *\n * Approximations used: 1 week = 7 days, 1 month \u2248 30.42 days (2628288 sec),\n * 1 year = 365 days. Not calendar-exact.\n *\n * @param {string} duration ISO 8601 duration string\n * @returns {number} total seconds; 0 when the input is unparseable\n */\nfunction isoDurToSec(duration) {\n\tconst durRE =\n\t\t/P((\\d+)Y)?((\\d+)M)?((\\d+)W)?((\\d+)D)?T?((\\d+)H)?((\\d+)M)?((\\d+)S)?/;\n\tconst s = durRE.exec(duration);\n\tif (!s) return 0;\n\n\treturn (\n\t\t(Number(s?.[2]) || 0) * 31536000 +\n\t\t(Number(s?.[4]) || 0) * 2628288 +\n\t\t(Number(s?.[6]) || 0) * 604800 +\n\t\t(Number(s?.[8]) || 0) * 86400 +\n\t\t(Number(s?.[10]) || 0) * 3600 +\n\t\t(Number(s?.[12]) || 0) * 60 +\n\t\t(Number(s?.[14]) || 0)\n\t);\n}\n\n/**\n * Mutate `payload.context` in place to set the city code from `inputs.city_code`.\n *\n * Version-aware: ONDC v1.x uses flat `context.city`, v2.x uses nested\n * `context.location.city.code`. Falls back to \"*\" when `city_code` is missing.\n * No-op when `inputs` is falsy.\n *\n * @param {Object} payload payload with a `context` to mutate\n * @param {Object|null|undefined} inputs object with optional `city_code`\n * @returns {string|undefined} \"*\" when inputs is falsy; otherwise undefined\n */\nfunction setCityFromInputs(payload, inputs) {\n\tif (!inputs) return \"*\";\n\tconst version =\n\t\tpayload.context.version || payload.context.core_version || \"2.0.0\";\n\tif (version.startsWith(\"1\")) {\n\t\tpayload.context.city = inputs.city_code ?? \"*\";\n\t} else {\n\t\tpayload.context.location.city.code = inputs.city_code ?? \"*\";\n\t}\n}\n\n/**\n * Build a form submission URL from session data.\n *\n * @param {string} domain ONDC domain (e.g. \"ONDC:RET10\")\n * @param {string} formId form identifier\n * @param {Object} sessionData reads `mockBaseUrl`, `transactionId[0]`, `sessionId`\n * @returns {string} `${baseURL}/forms/${domain}/${formId}/?transaction_id=...&session_id=...`\n */\nfunction createFormURL(domain, formId, sessionData) {\n\tconst baseURL = sessionData.mockBaseUrl;\n\tconst transactionId = sessionData.transactionId[0];\n\tconst sessionId = sessionData.sessionId;\n\treturn `${baseURL}/forms/${domain}/${formId}/?transaction_id=${transactionId}&session_id=${sessionId}`;\n}\n\n/**\n * Generate a consent handler from the Finvu AA Service.\n *\n * Reads the service base URL from `sessionData.finvuUrl` \u2014 the installing\n * service MUST include that origin in\n * MockRunner.initSharedRunner({ allowedFetchBaseUrls: [...] })\n * otherwise the sandboxed fetch will be blocked.\n *\n * Times out after 10s via AbortController.\n *\n * @param {Object} sessionData session data; `sessionData.finvuUrl` is required\n * @param {Object} params\n * @param {string} params.custId customer ID (required)\n * @param {string} [params.templateName] defaults to \"FINVUDEMO_TESTING\"\n * @param {string} [params.consentDescription] defaults to \"Gold Loan Account Aggregator Consent\"\n * @param {string} [params.redirectUrl] defaults to \"https://google.co.in\"\n * @returns {Promise<string>} the `consentHandler` returned by the AA service\n * @throws {Error} when `custId` or `sessionData.finvuUrl` is missing, on non-OK\n * response, on missing `consentHandler` in the body, or on 10s timeout\n */\nasync function generateConsentHandler(\n\tsessionData,\n\t{\n\t\tcustId,\n\t\ttemplateName = \"FINVUDEMO_TESTING\",\n\t\tconsentDescription = \"Gold Loan Account Aggregator Consent\",\n\t\tredirectUrl = \"https://google.co.in\",\n\t},\n) {\n\tif (!custId) {\n\t\tthrow new Error(\"custId is required\");\n\t}\n\tconst baseUrl = sessionData && sessionData.finvuUrl;\n\tif (!baseUrl) {\n\t\tthrow new Error(\"sessionData.finvuUrl is required\");\n\t}\n\n\tconst url = `${baseUrl}/finvu-aa/consent/generate`;\n\n\tconst payload = {\n\t\tcustId,\n\t\ttemplateName,\n\t\tconsentDescription,\n\t\tredirectUrl,\n\t};\n\n\tconsole.log(\"Calling Finvu AA Service:\", url);\n\tconsole.log(\"Consent request payload:\", payload);\n\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), 10000);\n\n\ttry {\n\t\tconst res = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(payload),\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tif (!res.ok) {\n\t\t\tconst text = await res.text();\n\t\t\tthrow new Error(`Request failed: ${res.status} ${text}`);\n\t\t}\n\n\t\tconst data = await res.json();\n\n\t\tif (!data || !data.consentHandler) {\n\t\t\tthrow new Error(\"Invalid response: consentHandler missing\");\n\t\t}\n\n\t\treturn data.consentHandler;\n\t} catch (err) {\n\t\tif (err && err.name === \"AbortError\") {\n\t\t\tthrow new Error(\"Request timed out after 10 seconds\");\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\n";
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_HELPERS_RAW = void 0;
4
+ // AUTO-GENERATED by scripts/generate-helpers-source.js. Do not edit.
5
+ // Source: src/lib/helpers/default-helpers.js
6
+ /* eslint-disable */
7
+ exports.DEFAULT_HELPERS_RAW = `
8
+ /*
9
+ * Default helpers available to every \`generate()\` in a mock step.
10
+ *
11
+ * Authoring rules:
12
+ * 1. Prefer \`function\` declarations — they hoist, so cross-helper calls
13
+ * work regardless of order.
14
+ * 2. No \`require\` / \`import\` inside function bodies. The VM sandbox has no
15
+ * module system. Only sandbox-whitelisted globals (Math, Date, JSON, …)
16
+ * and sibling helpers are in scope.
17
+ * 3. 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 run at script scope, \`sessionData\` is
20
+ * only a parameter of \`generate()\`.
21
+ * 4. Document every helper with a leading JSDoc block (\`@param\`, \`@returns\`).
22
+ *
23
+ * The full file (minus the trailing \`module.exports = {...}\` block) is
24
+ * embedded verbatim into the sandbox bundle by
25
+ * \`scripts/generate-helpers-source.js\`, so JSDoc reaches end users unchanged.
26
+ * Re-run \`npm run helpers:gen\` after editing.
27
+ */
28
+
29
+ /**
30
+ * Resolve the BPP or BAP subscriber URL from session data.
31
+ *
32
+ * @param {Object} sessionData session data (reads \`bppUri\` or \`bapUri\`)
33
+ * @param {"bpp"|"bap"|string} type subscriber kind; anything other than "bpp" returns bapUri
34
+ * @returns {string} the subscriber URL
35
+ */
36
+ function getSubscriberUrl(sessionData, type) {
37
+ if (type === "bpp") {
38
+ return sessionData.bppUri;
39
+ } else {
40
+ return sessionData.bapUri;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Generate a UUID v4 (RFC 4122, random-based).
46
+ *
47
+ * @returns {string} a new UUID v4, e.g. "550e8400-e29b-41d4-a716-446655440000"
48
+ */
49
+ function uuidv4() {
50
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
51
+ const r = (Math.random() * 16) | 0;
52
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
53
+ return v.toString(16);
54
+ });
55
+ }
56
+
57
+ /**
58
+ * Generate a 6-digit numeric string ID in [100000, 999999].
59
+ *
60
+ * @returns {string} a zero-padded 6-digit numeric string
61
+ */
62
+ function generate6DigitId() {
63
+ return Math.floor(100000 + Math.random() * 900000).toString();
64
+ }
65
+
66
+ /**
67
+ * Get the current ISO-8601 UTC timestamp.
68
+ *
69
+ * @returns {string} e.g. "2026-04-23T12:34:56.789Z"
70
+ */
71
+ function currentTimestamp() {
72
+ return new Date().toISOString();
73
+ }
74
+
75
+ /**
76
+ * Convert an ISO 8601 duration string (e.g. "PT1H30M", "P2DT3H") to total seconds.
77
+ *
78
+ * Approximations used: 1 week = 7 days, 1 month ≈ 30.42 days (2628288 sec),
79
+ * 1 year = 365 days. Not calendar-exact.
80
+ *
81
+ * @param {string} duration ISO 8601 duration string
82
+ * @returns {number} total seconds; 0 when the input is unparseable
83
+ */
84
+ function isoDurToSec(duration) {
85
+ const durRE =
86
+ /P((\\d+)Y)?((\\d+)M)?((\\d+)W)?((\\d+)D)?T?((\\d+)H)?((\\d+)M)?((\\d+)S)?/;
87
+ const s = durRE.exec(duration);
88
+ if (!s) return 0;
89
+
90
+ return (
91
+ (Number(s?.[2]) || 0) * 31536000 +
92
+ (Number(s?.[4]) || 0) * 2628288 +
93
+ (Number(s?.[6]) || 0) * 604800 +
94
+ (Number(s?.[8]) || 0) * 86400 +
95
+ (Number(s?.[10]) || 0) * 3600 +
96
+ (Number(s?.[12]) || 0) * 60 +
97
+ (Number(s?.[14]) || 0)
98
+ );
99
+ }
100
+
101
+ /**
102
+ * Mutate \`payload.context\` in place to set the city code from \`inputs.city_code\`.
103
+ *
104
+ * Version-aware: ONDC v1.x uses flat \`context.city\`, v2.x uses nested
105
+ * \`context.location.city.code\`. Falls back to "*" when \`city_code\` is missing.
106
+ * No-op when \`inputs\` is falsy.
107
+ *
108
+ * @param {Object} payload payload with a \`context\` to mutate
109
+ * @param {Object|null|undefined} inputs object with optional \`city_code\`
110
+ * @returns {string|undefined} "*" when inputs is falsy; otherwise undefined
111
+ */
112
+ function setCityFromInputs(payload, inputs) {
113
+ if (!inputs) return "*";
114
+ const version =
115
+ payload.context.version || payload.context.core_version || "2.0.0";
116
+ if (version.startsWith("1")) {
117
+ payload.context.city = inputs.city_code ?? "*";
118
+ } else {
119
+ payload.context.location.city.code = inputs.city_code ?? "*";
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Build a form submission URL from session data.
125
+ *
126
+ * @param {string} domain ONDC domain (e.g. "ONDC:RET10")
127
+ * @param {string} formId form identifier
128
+ * @param {Object} sessionData reads \`mockBaseUrl\`, \`transactionId[0]\`, \`sessionId\`
129
+ * @returns {string} \`\${baseURL}/forms/\${domain}/\${formId}/?transaction_id=...&session_id=...\`
130
+ */
131
+ function createFormURL(domain, formId, sessionData) {
132
+ const baseURL = sessionData.mockBaseUrl;
133
+ const transactionId = sessionData.transactionId[0];
134
+ const sessionId = sessionData.sessionId;
135
+ return \`\${baseURL}/forms/\${domain}/\${formId}/?transaction_id=\${transactionId}&session_id=\${sessionId}\`;
136
+ }
137
+
138
+ /**
139
+ * Generate a consent handler from the Finvu AA Service.
140
+ *
141
+ * Reads the service base URL from \`sessionData.finvuUrl\` — the installing
142
+ * service MUST include that origin in
143
+ * MockRunner.initSharedRunner({ allowedFetchBaseUrls: [...] })
144
+ * otherwise the sandboxed fetch will be blocked.
145
+ *
146
+ * Times out after 10s via AbortController.
147
+ *
148
+ * @param {Object} sessionData session data; \`sessionData.finvuUrl\` is required
149
+ * @param {Object} params
150
+ * @param {string} params.custId customer ID (required)
151
+ * @param {string} [params.templateName] defaults to "FINVUDEMO_TESTING"
152
+ * @param {string} [params.consentDescription] defaults to "Gold Loan Account Aggregator Consent"
153
+ * @param {string} [params.redirectUrl] defaults to "https://google.co.in"
154
+ * @returns {Promise<string>} the \`consentHandler\` returned by the AA service
155
+ * @throws {Error} when \`custId\` or \`sessionData.finvuUrl\` is missing, on non-OK
156
+ * response, on missing \`consentHandler\` in the body, or on 10s timeout
157
+ */
158
+ async function generateConsentHandler(
159
+ sessionData,
160
+ {
161
+ custId,
162
+ templateName = "FINVUDEMO_TESTING",
163
+ consentDescription = "Gold Loan Account Aggregator Consent",
164
+ redirectUrl = "https://google.co.in",
165
+ },
166
+ ) {
167
+ if (!custId) {
168
+ throw new Error("custId is required");
169
+ }
170
+ const baseUrl = sessionData && sessionData.finvuUrl;
171
+ if (!baseUrl) {
172
+ throw new Error("sessionData.finvuUrl is required");
173
+ }
174
+
175
+ const url = \`\${baseUrl}/finvu-aa/consent/generate\`;
176
+
177
+ const payload = {
178
+ custId,
179
+ templateName,
180
+ consentDescription,
181
+ redirectUrl,
182
+ };
183
+
184
+ console.log("Calling Finvu AA Service:", url);
185
+ console.log("Consent request payload:", payload);
186
+
187
+ const controller = new AbortController();
188
+ const timeout = setTimeout(() => controller.abort(), 10000);
189
+
190
+ try {
191
+ const res = await fetch(url, {
192
+ method: "POST",
193
+ headers: {
194
+ "Content-Type": "application/json",
195
+ },
196
+ body: JSON.stringify(payload),
197
+ signal: controller.signal,
198
+ });
199
+
200
+ if (!res.ok) {
201
+ const text = await res.text();
202
+ throw new Error(\`Request failed: \${res.status} \${text}\`);
203
+ }
204
+
205
+ const data = await res.json();
206
+
207
+ if (!data || !data.consentHandler) {
208
+ throw new Error("Invalid response: consentHandler missing");
209
+ }
210
+
211
+ return data.consentHandler;
212
+ } catch (err) {
213
+ if (err && err.name === "AbortError") {
214
+ throw new Error("Request timed out after 10 seconds");
215
+ }
216
+ throw err;
217
+ } finally {
218
+ clearTimeout(timeout);
219
+ }
220
+ }
221
+ `;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Resolve the BPP or BAP subscriber URL from session data.
3
+ *
4
+ * @param {Object} sessionData session data (reads `bppUri` or `bapUri`)
5
+ * @param {"bpp"|"bap"|string} type subscriber kind; anything other than "bpp" returns bapUri
6
+ * @returns {string} the subscriber URL
7
+ */
8
+ export function getSubscriberUrl(sessionData: Object, type: "bpp" | "bap" | string): string;
9
+ /**
10
+ * Generate a UUID v4 (RFC 4122, random-based).
11
+ *
12
+ * @returns {string} a new UUID v4, e.g. "550e8400-e29b-41d4-a716-446655440000"
13
+ */
14
+ export function uuidv4(): string;
15
+ /**
16
+ * Generate a 6-digit numeric string ID in [100000, 999999].
17
+ *
18
+ * @returns {string} a zero-padded 6-digit numeric string
19
+ */
20
+ export function generate6DigitId(): string;
21
+ /**
22
+ * Get the current ISO-8601 UTC timestamp.
23
+ *
24
+ * @returns {string} e.g. "2026-04-23T12:34:56.789Z"
25
+ */
26
+ export function currentTimestamp(): string;
27
+ /**
28
+ * Convert an ISO 8601 duration string (e.g. "PT1H30M", "P2DT3H") to total seconds.
29
+ *
30
+ * Approximations used: 1 week = 7 days, 1 month ≈ 30.42 days (2628288 sec),
31
+ * 1 year = 365 days. Not calendar-exact.
32
+ *
33
+ * @param {string} duration ISO 8601 duration string
34
+ * @returns {number} total seconds; 0 when the input is unparseable
35
+ */
36
+ export function isoDurToSec(duration: string): number;
37
+ /**
38
+ * Mutate `payload.context` in place to set the city code from `inputs.city_code`.
39
+ *
40
+ * Version-aware: ONDC v1.x uses flat `context.city`, v2.x uses nested
41
+ * `context.location.city.code`. Falls back to "*" when `city_code` is missing.
42
+ * No-op when `inputs` is falsy.
43
+ *
44
+ * @param {Object} payload payload with a `context` to mutate
45
+ * @param {Object|null|undefined} inputs object with optional `city_code`
46
+ * @returns {string|undefined} "*" when inputs is falsy; otherwise undefined
47
+ */
48
+ export function setCityFromInputs(payload: Object, inputs: Object | null | undefined): string | undefined;
49
+ /**
50
+ * Build a form submission URL from session data.
51
+ *
52
+ * @param {string} domain ONDC domain (e.g. "ONDC:RET10")
53
+ * @param {string} formId form identifier
54
+ * @param {Object} sessionData reads `mockBaseUrl`, `transactionId[0]`, `sessionId`
55
+ * @returns {string} `${baseURL}/forms/${domain}/${formId}/?transaction_id=...&session_id=...`
56
+ */
57
+ export function createFormURL(domain: string, formId: string, sessionData: Object): string;
58
+ /**
59
+ * Generate a consent handler from the Finvu AA Service.
60
+ *
61
+ * Reads the service base URL from `sessionData.finvuUrl` — the installing
62
+ * service MUST include that origin in
63
+ * MockRunner.initSharedRunner({ allowedFetchBaseUrls: [...] })
64
+ * otherwise the sandboxed fetch will be blocked.
65
+ *
66
+ * Times out after 10s via AbortController.
67
+ *
68
+ * @param {Object} sessionData session data; `sessionData.finvuUrl` is required
69
+ * @param {Object} params
70
+ * @param {string} params.custId customer ID (required)
71
+ * @param {string} [params.templateName] defaults to "FINVUDEMO_TESTING"
72
+ * @param {string} [params.consentDescription] defaults to "Gold Loan Account Aggregator Consent"
73
+ * @param {string} [params.redirectUrl] defaults to "https://google.co.in"
74
+ * @returns {Promise<string>} the `consentHandler` returned by the AA service
75
+ * @throws {Error} when `custId` or `sessionData.finvuUrl` is missing, on non-OK
76
+ * response, on missing `consentHandler` in the body, or on 10s timeout
77
+ */
78
+ export function generateConsentHandler(sessionData: Object, { custId, templateName, consentDescription, redirectUrl, }: {
79
+ custId: string;
80
+ templateName?: string | undefined;
81
+ consentDescription?: string | undefined;
82
+ redirectUrl?: string | undefined;
83
+ }): Promise<string>;