@ondc/automation-mock-runner 1.3.44 → 1.3.46

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.
@@ -35,6 +35,7 @@ export declare class MockRunner {
35
35
  bap_uri?: string | undefined;
36
36
  bpp_id?: string | undefined;
37
37
  bpp_uri?: string | undefined;
38
+ external_session_data?: Record<string, any> | undefined;
38
39
  };
39
40
  steps: {
40
41
  api: string;
@@ -29,6 +29,10 @@ function createInitialMockConfig(domain, version, flowId) {
29
29
  bap_uri: "https://bap.example.com",
30
30
  bpp_id: "bpp.example.com",
31
31
  bpp_uri: "https://bpp.example.com",
32
+ external_session_data: {
33
+ finvuUrl: "https://dev-automation.ondc.org/finvu",
34
+ mockBaseUrl: "https://dev-automation.ondc.org/mock",
35
+ },
32
36
  },
33
37
  steps: [],
34
38
  transaction_history: [],
@@ -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
+ `;
@@ -1,13 +1,83 @@
1
- export function getSubscriberUrl(sessionData: any, type: any): any;
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
+ */
2
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
+ */
3
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
+ */
4
26
  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;
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;
10
80
  templateName?: string | undefined;
11
81
  consentDescription?: string | undefined;
12
82
  redirectUrl?: string | undefined;
13
- }): Promise<any>;
83
+ }): Promise<string>;
@@ -2,30 +2,31 @@
2
2
  /*
3
3
  * Default helpers available to every `generate()` in a mock step.
4
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.
5
+ * Authoring rules:
6
+ * 1. Prefer `function` declarations they hoist, so cross-helper calls
7
+ * work regardless of order.
9
8
  * 2. No `require` / `import` inside function bodies. The VM sandbox has no
10
9
  * module system. Only sandbox-whitelisted globals (Math, Date, JSON, …)
11
10
  * 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
11
+ * 3. If the helper needs request-scope data, take `sessionData` as an
18
12
  * 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()`.
13
+ * resolve at runtime — helpers run at script scope, `sessionData` is
14
+ * only a parameter of `generate()`.
15
+ * 4. Document every helper with a leading JSDoc block (`@param`, `@returns`).
21
16
  *
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.
17
+ * The full file (minus the trailing `module.exports = {...}` block) is
18
+ * embedded verbatim into the sandbox bundle by
19
+ * `scripts/generate-helpers-source.js`, so JSDoc reaches end users unchanged.
20
+ * Re-run `npm run helpers:gen` after editing.
21
+ */
22
+ /**
23
+ * Resolve the BPP or BAP subscriber URL from session data.
24
+ *
25
+ * @param {Object} sessionData session data (reads `bppUri` or `bapUri`)
26
+ * @param {"bpp"|"bap"|string} type subscriber kind; anything other than "bpp" returns bapUri
27
+ * @returns {string} the subscriber URL
25
28
  */
26
29
  function getSubscriberUrl(sessionData, type) {
27
- // Resolve the BPP or BAP subscriber URL from session data.
28
- // Usage: getSubscriberUrl(sessionData, "bpp")
29
30
  if (type === "bpp") {
30
31
  return sessionData.bppUri;
31
32
  }
@@ -33,29 +34,44 @@ function getSubscriberUrl(sessionData, type) {
33
34
  return sessionData.bapUri;
34
35
  }
35
36
  }
37
+ /**
38
+ * Generate a UUID v4 (RFC 4122, random-based).
39
+ *
40
+ * @returns {string} a new UUID v4, e.g. "550e8400-e29b-41d4-a716-446655440000"
41
+ */
36
42
  function uuidv4() {
37
- // Generates a UUID v4 (RFC 4122, random-based).
38
43
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
39
44
  const r = (Math.random() * 16) | 0;
40
45
  const v = c === "x" ? r : (r & 0x3) | 0x8;
41
46
  return v.toString(16);
42
47
  });
43
48
  }
49
+ /**
50
+ * Generate a 6-digit numeric string ID in [100000, 999999].
51
+ *
52
+ * @returns {string} a zero-padded 6-digit numeric string
53
+ */
44
54
  function generate6DigitId() {
45
- // Generate a 6-digit numeric string ID in [100000, 999999].
46
55
  return Math.floor(100000 + Math.random() * 900000).toString();
47
56
  }
57
+ /**
58
+ * Get the current ISO-8601 UTC timestamp.
59
+ *
60
+ * @returns {string} e.g. "2026-04-23T12:34:56.789Z"
61
+ */
48
62
  function currentTimestamp() {
49
- // Returns the current ISO-8601 UTC timestamp (e.g. "2026-04-23T12:34:56.789Z").
50
63
  return new Date().toISOString();
51
64
  }
65
+ /**
66
+ * Convert an ISO 8601 duration string (e.g. "PT1H30M", "P2DT3H") to total seconds.
67
+ *
68
+ * Approximations used: 1 week = 7 days, 1 month ≈ 30.42 days (2628288 sec),
69
+ * 1 year = 365 days. Not calendar-exact.
70
+ *
71
+ * @param {string} duration ISO 8601 duration string
72
+ * @returns {number} total seconds; 0 when the input is unparseable
73
+ */
52
74
  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
75
  const durRE = /P((\d+)Y)?((\d+)M)?((\d+)W)?((\d+)D)?T?((\d+)H)?((\d+)M)?((\d+)S)?/;
60
76
  const s = durRE.exec(duration);
61
77
  if (!s)
@@ -68,13 +84,18 @@ function isoDurToSec(duration) {
68
84
  (Number(s?.[12]) || 0) * 60 +
69
85
  (Number(s?.[14]) || 0));
70
86
  }
87
+ /**
88
+ * Mutate `payload.context` in place to set the city code from `inputs.city_code`.
89
+ *
90
+ * Version-aware: ONDC v1.x uses flat `context.city`, v2.x uses nested
91
+ * `context.location.city.code`. Falls back to "*" when `city_code` is missing.
92
+ * No-op when `inputs` is falsy.
93
+ *
94
+ * @param {Object} payload payload with a `context` to mutate
95
+ * @param {Object|null|undefined} inputs object with optional `city_code`
96
+ * @returns {string|undefined} "*" when inputs is falsy; otherwise undefined
97
+ */
71
98
  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
99
  if (!inputs)
79
100
  return "*";
80
101
  const version = payload.context.version || payload.context.core_version || "2.0.0";
@@ -85,35 +106,41 @@ function setCityFromInputs(payload, inputs) {
85
106
  payload.context.location.city.code = inputs.city_code ?? "*";
86
107
  }
87
108
  }
109
+ /**
110
+ * Build a form submission URL from session data.
111
+ *
112
+ * @param {string} domain ONDC domain (e.g. "ONDC:RET10")
113
+ * @param {string} formId form identifier
114
+ * @param {Object} sessionData reads `mockBaseUrl`, `transactionId[0]`, `sessionId`
115
+ * @returns {string} `${baseURL}/forms/${domain}/${formId}/?transaction_id=...&session_id=...`
116
+ */
88
117
  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
118
  const baseURL = sessionData.mockBaseUrl;
95
119
  const transactionId = sessionData.transactionId[0];
96
120
  const sessionId = sessionData.sessionId;
97
121
  return `${baseURL}/forms/${domain}/${formId}/?transaction_id=${transactionId}&session_id=${sessionId}`;
98
122
  }
123
+ /**
124
+ * Generate a consent handler from the Finvu AA Service.
125
+ *
126
+ * Reads the service base URL from `sessionData.finvuUrl` — the installing
127
+ * service MUST include that origin in
128
+ * MockRunner.initSharedRunner({ allowedFetchBaseUrls: [...] })
129
+ * otherwise the sandboxed fetch will be blocked.
130
+ *
131
+ * Times out after 10s via AbortController.
132
+ *
133
+ * @param {Object} sessionData session data; `sessionData.finvuUrl` is required
134
+ * @param {Object} params
135
+ * @param {string} params.custId customer ID (required)
136
+ * @param {string} [params.templateName] defaults to "FINVUDEMO_TESTING"
137
+ * @param {string} [params.consentDescription] defaults to "Gold Loan Account Aggregator Consent"
138
+ * @param {string} [params.redirectUrl] defaults to "https://google.co.in"
139
+ * @returns {Promise<string>} the `consentHandler` returned by the AA service
140
+ * @throws {Error} when `custId` or `sessionData.finvuUrl` is missing, on non-OK
141
+ * response, on missing `consentHandler` in the body, or on 10s timeout
142
+ */
99
143
  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
144
  if (!custId) {
118
145
  throw new Error("custId is required");
119
146
  }
@@ -226,7 +226,9 @@ describe("DEFAULT_HELPER_LIB bundle", () => {
226
226
  return sandbox;
227
227
  }
228
228
  it("does not leak `module.exports` or `require` into the bundle source", () => {
229
- expect(index_1.DEFAULT_HELPER_LIB).not.toMatch(/module\.exports/);
229
+ // Statement-level `module.exports = ...` (line-anchored) would throw
230
+ // ReferenceError in the sandbox. Mentions inside comments are harmless.
231
+ expect(index_1.DEFAULT_HELPER_LIB).not.toMatch(/^module\.exports\s*=/m);
230
232
  expect(index_1.DEFAULT_HELPER_LIB).not.toMatch(/\brequire\s*\(/);
231
233
  });
232
234
  it("declares every expected helper as a function", () => {
@@ -250,8 +252,14 @@ describe("DEFAULT_HELPER_LIB bundle", () => {
250
252
  it("preserves in-body docs so playground users see them", () => {
251
253
  // Guard against a future refactor silently dropping the in-body comments
252
254
  // the way the pre-refactor .toString() pattern did.
253
- expect(index_1.DEFAULT_HELPER_LIB).toContain("Generates a UUID v4");
255
+ expect(index_1.DEFAULT_HELPER_LIB).toContain("Generate a UUID v4");
254
256
  expect(index_1.DEFAULT_HELPER_LIB).toContain("ISO 8601 duration");
255
257
  expect(index_1.DEFAULT_HELPER_LIB).toContain("Finvu AA Service");
256
258
  });
259
+ it("preserves source fidelity (no bundler lowering / numeric packing)", () => {
260
+ // If a future build step reintroduces fn.toString() or otherwise lets a
261
+ // minifier touch the helper bodies, these canaries break.
262
+ expect(index_1.DEFAULT_HELPER_LIB).toContain("s?.[2]");
263
+ expect(index_1.DEFAULT_HELPER_LIB).toContain("100000 + Math.random() * 900000");
264
+ });
257
265
  });
@@ -1,47 +1,10 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.DEFAULT_HELPER_LIB = void 0;
37
- const defaultHelperFns = __importStar(require("./default-helpers"));
4
+ const default_helpers_source_1 = require("./default-helpers-source");
38
5
  const HEADER = `/*
39
6
  Custom helper functions available in all mock generate() functions.
40
- Assembled from src/lib/helpers/default-helpers.js — edit there.
7
+ Source: src/lib/helpers/default-helpers.js — edit there, then run
8
+ \`npm run helpers:gen\` to refresh.
41
9
  */`;
42
- exports.DEFAULT_HELPER_LIB = [
43
- HEADER,
44
- ...Object.values(defaultHelperFns)
45
- .filter((v) => typeof v === "function")
46
- .map((f) => f.toString()),
47
- ].join("\n\n");
10
+ exports.DEFAULT_HELPER_LIB = HEADER + "\n\n" + default_helpers_source_1.DEFAULT_HELPERS_RAW;
@@ -19,6 +19,7 @@ export declare const TransactionDataSchema: z.ZodObject<{
19
19
  bap_uri: z.ZodOptional<z.ZodString>;
20
20
  bpp_id: z.ZodOptional<z.ZodString>;
21
21
  bpp_uri: z.ZodOptional<z.ZodString>;
22
+ external_session_data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
22
23
  }, z.core.$strip>;
23
24
  export declare const MockConfigSchema: z.ZodObject<{
24
25
  generate: z.ZodBase64;
@@ -92,6 +93,7 @@ export declare const MockPlaygroundConfigSchema: z.ZodObject<{
92
93
  bap_uri: z.ZodOptional<z.ZodString>;
93
94
  bpp_id: z.ZodOptional<z.ZodString>;
94
95
  bpp_uri: z.ZodOptional<z.ZodString>;
96
+ external_session_data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
95
97
  }, z.core.$strip>;
96
98
  steps: z.ZodArray<z.ZodObject<{
97
99
  api: z.ZodString;
@@ -20,6 +20,7 @@ exports.TransactionDataSchema = zod_1.z.object({
20
20
  bap_uri: zod_1.z.string().min(1, "BAP URI is required").optional(),
21
21
  bpp_id: zod_1.z.string().min(1, "BPP ID is required").optional(),
22
22
  bpp_uri: zod_1.z.string().min(1, "BPP URI is required").optional(),
23
+ external_session_data: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
23
24
  });
24
25
  exports.MockConfigSchema = zod_1.z.object({
25
26
  generate: zod_1.z.base64(),
@@ -456,6 +456,10 @@ describe("configHelper", () => {
456
456
  bap_uri: "https://bap.example.com",
457
457
  bpp_id: "bpp.example.com",
458
458
  bpp_uri: "https://bpp.example.com",
459
+ external_session_data: {
460
+ finvuUrl: "https://dev-automation.ondc.org/finvu",
461
+ mockBaseUrl: "https://dev-automation.ondc.org/mock",
462
+ },
459
463
  });
460
464
  });
461
465
  it("should initialize empty arrays and strings", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ondc/automation-mock-runner",
3
- "version": "1.3.44",
3
+ "version": "1.3.46",
4
4
  "description": "A TypeScript library for ONDC automation mock runner",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,6 +11,8 @@
11
11
  "public"
12
12
  ],
13
13
  "scripts": {
14
+ "helpers:gen": "node scripts/generate-helpers-source.js",
15
+ "prebuild": "npm run helpers:gen",
14
16
  "build": "npm run clean && tsc",
15
17
  "build:watch": "tsc --watch",
16
18
  "start": "node dist/index.js",
@@ -18,6 +20,7 @@
18
20
  "clean": "rm -rf dist coverage browser-dist",
19
21
  "prepare": "npm run clean && npm run build",
20
22
  "prepublishOnly": "npm run test && npm run build",
23
+ "pretest": "npm run helpers:gen",
21
24
  "test": "jest",
22
25
  "test:watch": "jest --watch",
23
26
  "test:coverage": "jest --coverage",