@superatomai/sdk-node 0.0.32 → 0.0.33-dsp

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.
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+
3
+ // src/userResponse/scripts/script-bootstrap.ts
4
+ var import_url = require("url");
5
+
6
+ // src/userResponse/scripts/script-ipc.ts
7
+ function encodeMessage(msg) {
8
+ return JSON.stringify(msg) + "\n";
9
+ }
10
+ var LineOverflowError = class extends Error {
11
+ constructor(buffered, limit) {
12
+ super(`IPC message exceeded ${limit} bytes without a newline (${buffered} buffered) \u2014 aborting to avoid unbounded memory.`);
13
+ this.buffered = buffered;
14
+ this.limit = limit;
15
+ this.name = "LineOverflowError";
16
+ }
17
+ };
18
+ var DEFAULT_MAX_IPC_BYTES = (() => {
19
+ const envVal = Number(process.env.SCRIPT_MAX_IPC_BYTES);
20
+ return Number.isFinite(envVal) && envVal > 0 ? Math.floor(envVal) : 64 * 1024 * 1024;
21
+ })();
22
+ var LineSplitter = class {
23
+ constructor(maxBytes = DEFAULT_MAX_IPC_BYTES) {
24
+ this.maxBytes = maxBytes;
25
+ this.buffer = "";
26
+ }
27
+ push(chunk) {
28
+ this.buffer += chunk;
29
+ const lines = [];
30
+ let idx;
31
+ while ((idx = this.buffer.indexOf("\n")) !== -1) {
32
+ const line = this.buffer.slice(0, idx);
33
+ this.buffer = this.buffer.slice(idx + 1);
34
+ if (line.length > 0) lines.push(line);
35
+ }
36
+ if (this.buffer.length > this.maxBytes) {
37
+ const buffered = this.buffer.length;
38
+ this.buffer = "";
39
+ throw new LineOverflowError(buffered, this.maxBytes);
40
+ }
41
+ return lines;
42
+ }
43
+ /** Flush any remaining partial data (useful on stream close) */
44
+ flush() {
45
+ if (this.buffer.length === 0) return null;
46
+ const rest = this.buffer;
47
+ this.buffer = "";
48
+ return rest;
49
+ }
50
+ };
51
+
52
+ // src/userResponse/scripts/script-bootstrap.ts
53
+ var SCRIPT_ARG = process.argv[2];
54
+ if (!SCRIPT_ARG) {
55
+ sendError("Bootstrap was invoked without a script path.", "compile");
56
+ process.exit(1);
57
+ }
58
+ var BRIDGE_URL = process.env.SCRIPT_BRIDGE_URL;
59
+ var executedQueries = [];
60
+ var PREVIEW_MAX_ROWS = 10;
61
+ var PREVIEW_MAX_CHARS = 200;
62
+ var QUERY_ROW_CAP = 250;
63
+ function previewRows(data) {
64
+ return data.slice(0, PREVIEW_MAX_ROWS).map((row) => {
65
+ if (!row || typeof row !== "object") return row;
66
+ const out = {};
67
+ for (const [k, v] of Object.entries(row)) {
68
+ out[k] = typeof v === "string" && v.length > PREVIEW_MAX_CHARS ? v.slice(0, PREVIEW_MAX_CHARS) + "\u2026" : v;
69
+ }
70
+ return out;
71
+ });
72
+ }
73
+ var initResolve = null;
74
+ var initPromise = new Promise((resolve) => {
75
+ initResolve = resolve;
76
+ });
77
+ function buildCtx(init) {
78
+ return {
79
+ now: init.now,
80
+ async query(toolId, sql) {
81
+ if (!BRIDGE_URL) throw new Error("SCRIPT_BRIDGE_URL is not set \u2014 script bridge server is not running");
82
+ const startedAt = Date.now();
83
+ send({ type: "stream", chunk: `
84
+ \u{1F4DD} **Querying ${toolId}:**
85
+ \`\`\`sql
86
+ ${sql}
87
+ \`\`\`
88
+
89
+ ` });
90
+ send({ type: "stream", chunk: `__QUERY_TIMER_START_Executing query__` });
91
+ const res = await fetch(`${BRIDGE_URL}/query`, {
92
+ method: "POST",
93
+ headers: { "content-type": "application/json" },
94
+ body: JSON.stringify({ toolId, sql, limit: QUERY_ROW_CAP })
95
+ });
96
+ const json = await res.json();
97
+ const executionTimeMs = Date.now() - startedAt;
98
+ send({ type: "stream", chunk: `__QUERY_TIMER_DONE_${(executionTimeMs / 1e3).toFixed(1)}__
99
+
100
+ ` });
101
+ if (!res.ok || !json.success) {
102
+ const errMsg = json.error || `Bridge query failed (${res.status})`;
103
+ send({ type: "stream", chunk: `\u274C **Query failed on ${toolId}:** ${errMsg}
104
+
105
+ ` });
106
+ throw new Error(errMsg);
107
+ }
108
+ if (json.metadata?.truncated) {
109
+ const total = json.metadata.totalCount ?? "more";
110
+ const hasGroupBy = /\bGROUP\s+BY\b/i.test(sql);
111
+ if (hasGroupBy) {
112
+ send({ type: "stream", chunk: `\u2139\uFE0F Only the top ${QUERY_ROW_CAP} of ${total} grouped rows are returned (query is already aggregated via GROUP BY) \u2014 expected for a top-N request.
113
+
114
+ ` });
115
+ } else {
116
+ const msg = `ctx.query truncated the result of this query to ${QUERY_ROW_CAP} rows (it matched ${total}). Do NOT compute over raw rows \u2014 AGGREGATE IN SQL (GROUP BY / mode() / mode(...) FILTER (WHERE \u2026) / COUNT(...) FILTER (\u2026) / CASE) so the query returns the final, already-reduced rows, then have getData return those.`;
117
+ send({ type: "stream", chunk: `\u274C **Result truncated on ${toolId}:** ${msg}
118
+
119
+ ` });
120
+ throw new Error(msg);
121
+ }
122
+ }
123
+ const data = json.data ?? [];
124
+ const count = json.count ?? data.length;
125
+ send({ type: "stream", chunk: `\u2705 **${count} rows from ${toolId}**
126
+
127
+ ` });
128
+ if (data.length > 0) {
129
+ send({ type: "stream", chunk: `<DataTable>${JSON.stringify(previewRows(data))}</DataTable>
130
+
131
+ ` });
132
+ }
133
+ executedQueries.push({
134
+ sourceId: toolId,
135
+ sourceName: toolId,
136
+ // enriched by runner after result arrives
137
+ sql,
138
+ data,
139
+ count,
140
+ executionTimeMs
141
+ });
142
+ return { data, count };
143
+ },
144
+ /**
145
+ * Call a tool with structured params (typically a direct tool whose
146
+ * fn(params) does not expect a SQL string). Returns whatever the tool
147
+ * returned — shape is up to the tool.
148
+ *
149
+ * Use this when you need a pre-built business-logic tool (e.g.,
150
+ * "Calculate Shelf Life") that takes structured input rather than SQL.
151
+ * For SQL source tools, keep using ctx.query.
152
+ *
153
+ * runTool results do NOT auto-flow into executedQueries. If you want
154
+ * the result visualised, register it via ctx.emit() after extracting
155
+ * the array you want to chart.
156
+ */
157
+ async runTool(toolId, params = {}) {
158
+ if (!BRIDGE_URL) throw new Error("SCRIPT_BRIDGE_URL is not set \u2014 script bridge server is not running");
159
+ const res = await fetch(`${BRIDGE_URL}/run-tool`, {
160
+ method: "POST",
161
+ headers: { "content-type": "application/json" },
162
+ body: JSON.stringify({ toolId, params })
163
+ });
164
+ const json = await res.json();
165
+ if (!res.ok || !json.success) throw new Error(json.error || `Bridge run-tool failed (${res.status})`);
166
+ return json.result;
167
+ },
168
+ /**
169
+ * Register a computed dataset. Flows into executedQueries alongside
170
+ * real SQL query results so component generation can render post-SQL
171
+ * transforms (weighted averages, clustering, joins) as charts.
172
+ */
173
+ emit(name, rows, meta) {
174
+ executedQueries.push({
175
+ sourceId: `computed:${name}`,
176
+ sourceName: meta?.description || name,
177
+ sql: `-- computed dataset: ${name}`,
178
+ data: Array.isArray(rows) ? rows : [],
179
+ count: Array.isArray(rows) ? rows.length : 0,
180
+ executionTimeMs: 0,
181
+ virtual: true
182
+ });
183
+ },
184
+ /**
185
+ * Forward a short progress message to the parent's StreamBuffer so the UI
186
+ * continues to see per-script feedback during execution.
187
+ */
188
+ log(chunk) {
189
+ send({ type: "stream", chunk });
190
+ }
191
+ };
192
+ }
193
+ function send(msg) {
194
+ return process.stdout.write(encodeMessage(msg));
195
+ }
196
+ function sendError(message, phase, stack) {
197
+ send({ type: "error", message, stack, phase });
198
+ }
199
+ var splitter = new LineSplitter();
200
+ process.stdin.setEncoding("utf-8");
201
+ process.stdin.on("data", (chunk) => {
202
+ let lines;
203
+ try {
204
+ lines = splitter.push(chunk);
205
+ } catch (err) {
206
+ const msg = err instanceof Error ? err.message : String(err);
207
+ sendError(msg, "runtime");
208
+ process.exit(1);
209
+ }
210
+ for (const line of lines) {
211
+ let msg;
212
+ try {
213
+ msg = JSON.parse(line);
214
+ } catch {
215
+ continue;
216
+ }
217
+ handleMessage(msg);
218
+ }
219
+ });
220
+ function handleMessage(msg) {
221
+ switch (msg.type) {
222
+ case "init": {
223
+ if (initResolve) {
224
+ const now = new Date(msg.now || (/* @__PURE__ */ new Date()).toISOString());
225
+ const params = restoreParamTypes(msg.params || {}, msg.paramSchema);
226
+ initResolve({ params, now });
227
+ initResolve = null;
228
+ }
229
+ break;
230
+ }
231
+ }
232
+ }
233
+ (async () => {
234
+ let getData;
235
+ try {
236
+ const mod = await import((0, import_url.pathToFileURL)(SCRIPT_ARG).href);
237
+ getData = mod.getData ?? (typeof mod.default === "function" ? mod.default : mod.default?.getData);
238
+ if (typeof getData !== "function") {
239
+ throw new Error(
240
+ `Script at ${SCRIPT_ARG} does not export getData \u2014 expected \`export async function getData(ctx, params)\``
241
+ );
242
+ }
243
+ } catch (err) {
244
+ const e = err;
245
+ sendError(e.message || String(err), "compile", e.stack);
246
+ process.exit(1);
247
+ return;
248
+ }
249
+ const init = await initPromise;
250
+ const ctx = buildCtx(init);
251
+ const startedAt = Date.now();
252
+ try {
253
+ const raw = await getData(ctx, init.params);
254
+ const executionTimeMs = Date.now() - startedAt;
255
+ const data = normalizeResultData(raw);
256
+ const count = typeof raw?.count === "number" ? raw.count : data.length;
257
+ const sampleRows = data.slice(0, 5);
258
+ const result = {
259
+ type: "result",
260
+ data,
261
+ count,
262
+ executedQueries,
263
+ executionTimeMs,
264
+ sampleRows
265
+ };
266
+ const flushed = send(result);
267
+ if (flushed) {
268
+ process.exit(0);
269
+ } else {
270
+ process.stdout.once("drain", () => process.exit(0));
271
+ }
272
+ } catch (err) {
273
+ const e = err;
274
+ sendError(e.message || String(err), "runtime", e.stack);
275
+ process.exit(1);
276
+ }
277
+ })();
278
+ function normalizeResultData(raw) {
279
+ if (!raw) return [];
280
+ if (Array.isArray(raw)) return raw;
281
+ if (Array.isArray(raw.data)) return raw.data;
282
+ if (raw.data && typeof raw.data === "object") return [raw.data];
283
+ return [];
284
+ }
285
+ function restoreParamTypes(params, schema) {
286
+ if (!schema) return params;
287
+ const out = { ...params };
288
+ for (const [name, type] of Object.entries(schema)) {
289
+ const v = out[name];
290
+ if (v === void 0 || v === null) continue;
291
+ if (type === "date" && typeof v === "string") {
292
+ const d = new Date(v);
293
+ if (!isNaN(d.getTime())) out[name] = d;
294
+ } else if (type === "date_range" && typeof v === "object") {
295
+ const from = v.from;
296
+ const to = v.to;
297
+ out[name] = {
298
+ from: typeof from === "string" ? new Date(from) : from,
299
+ to: typeof to === "string" ? new Date(to) : to
300
+ };
301
+ }
302
+ }
303
+ return out;
304
+ }
305
+ //# sourceMappingURL=script-bootstrap.js.map
@@ -0,0 +1,303 @@
1
+ // src/userResponse/scripts/script-bootstrap.ts
2
+ import { pathToFileURL } from "url";
3
+
4
+ // src/userResponse/scripts/script-ipc.ts
5
+ function encodeMessage(msg) {
6
+ return JSON.stringify(msg) + "\n";
7
+ }
8
+ var LineOverflowError = class extends Error {
9
+ constructor(buffered, limit) {
10
+ super(`IPC message exceeded ${limit} bytes without a newline (${buffered} buffered) \u2014 aborting to avoid unbounded memory.`);
11
+ this.buffered = buffered;
12
+ this.limit = limit;
13
+ this.name = "LineOverflowError";
14
+ }
15
+ };
16
+ var DEFAULT_MAX_IPC_BYTES = (() => {
17
+ const envVal = Number(process.env.SCRIPT_MAX_IPC_BYTES);
18
+ return Number.isFinite(envVal) && envVal > 0 ? Math.floor(envVal) : 64 * 1024 * 1024;
19
+ })();
20
+ var LineSplitter = class {
21
+ constructor(maxBytes = DEFAULT_MAX_IPC_BYTES) {
22
+ this.maxBytes = maxBytes;
23
+ this.buffer = "";
24
+ }
25
+ push(chunk) {
26
+ this.buffer += chunk;
27
+ const lines = [];
28
+ let idx;
29
+ while ((idx = this.buffer.indexOf("\n")) !== -1) {
30
+ const line = this.buffer.slice(0, idx);
31
+ this.buffer = this.buffer.slice(idx + 1);
32
+ if (line.length > 0) lines.push(line);
33
+ }
34
+ if (this.buffer.length > this.maxBytes) {
35
+ const buffered = this.buffer.length;
36
+ this.buffer = "";
37
+ throw new LineOverflowError(buffered, this.maxBytes);
38
+ }
39
+ return lines;
40
+ }
41
+ /** Flush any remaining partial data (useful on stream close) */
42
+ flush() {
43
+ if (this.buffer.length === 0) return null;
44
+ const rest = this.buffer;
45
+ this.buffer = "";
46
+ return rest;
47
+ }
48
+ };
49
+
50
+ // src/userResponse/scripts/script-bootstrap.ts
51
+ var SCRIPT_ARG = process.argv[2];
52
+ if (!SCRIPT_ARG) {
53
+ sendError("Bootstrap was invoked without a script path.", "compile");
54
+ process.exit(1);
55
+ }
56
+ var BRIDGE_URL = process.env.SCRIPT_BRIDGE_URL;
57
+ var executedQueries = [];
58
+ var PREVIEW_MAX_ROWS = 10;
59
+ var PREVIEW_MAX_CHARS = 200;
60
+ var QUERY_ROW_CAP = 250;
61
+ function previewRows(data) {
62
+ return data.slice(0, PREVIEW_MAX_ROWS).map((row) => {
63
+ if (!row || typeof row !== "object") return row;
64
+ const out = {};
65
+ for (const [k, v] of Object.entries(row)) {
66
+ out[k] = typeof v === "string" && v.length > PREVIEW_MAX_CHARS ? v.slice(0, PREVIEW_MAX_CHARS) + "\u2026" : v;
67
+ }
68
+ return out;
69
+ });
70
+ }
71
+ var initResolve = null;
72
+ var initPromise = new Promise((resolve) => {
73
+ initResolve = resolve;
74
+ });
75
+ function buildCtx(init) {
76
+ return {
77
+ now: init.now,
78
+ async query(toolId, sql) {
79
+ if (!BRIDGE_URL) throw new Error("SCRIPT_BRIDGE_URL is not set \u2014 script bridge server is not running");
80
+ const startedAt = Date.now();
81
+ send({ type: "stream", chunk: `
82
+ \u{1F4DD} **Querying ${toolId}:**
83
+ \`\`\`sql
84
+ ${sql}
85
+ \`\`\`
86
+
87
+ ` });
88
+ send({ type: "stream", chunk: `__QUERY_TIMER_START_Executing query__` });
89
+ const res = await fetch(`${BRIDGE_URL}/query`, {
90
+ method: "POST",
91
+ headers: { "content-type": "application/json" },
92
+ body: JSON.stringify({ toolId, sql, limit: QUERY_ROW_CAP })
93
+ });
94
+ const json = await res.json();
95
+ const executionTimeMs = Date.now() - startedAt;
96
+ send({ type: "stream", chunk: `__QUERY_TIMER_DONE_${(executionTimeMs / 1e3).toFixed(1)}__
97
+
98
+ ` });
99
+ if (!res.ok || !json.success) {
100
+ const errMsg = json.error || `Bridge query failed (${res.status})`;
101
+ send({ type: "stream", chunk: `\u274C **Query failed on ${toolId}:** ${errMsg}
102
+
103
+ ` });
104
+ throw new Error(errMsg);
105
+ }
106
+ if (json.metadata?.truncated) {
107
+ const total = json.metadata.totalCount ?? "more";
108
+ const hasGroupBy = /\bGROUP\s+BY\b/i.test(sql);
109
+ if (hasGroupBy) {
110
+ send({ type: "stream", chunk: `\u2139\uFE0F Only the top ${QUERY_ROW_CAP} of ${total} grouped rows are returned (query is already aggregated via GROUP BY) \u2014 expected for a top-N request.
111
+
112
+ ` });
113
+ } else {
114
+ const msg = `ctx.query truncated the result of this query to ${QUERY_ROW_CAP} rows (it matched ${total}). Do NOT compute over raw rows \u2014 AGGREGATE IN SQL (GROUP BY / mode() / mode(...) FILTER (WHERE \u2026) / COUNT(...) FILTER (\u2026) / CASE) so the query returns the final, already-reduced rows, then have getData return those.`;
115
+ send({ type: "stream", chunk: `\u274C **Result truncated on ${toolId}:** ${msg}
116
+
117
+ ` });
118
+ throw new Error(msg);
119
+ }
120
+ }
121
+ const data = json.data ?? [];
122
+ const count = json.count ?? data.length;
123
+ send({ type: "stream", chunk: `\u2705 **${count} rows from ${toolId}**
124
+
125
+ ` });
126
+ if (data.length > 0) {
127
+ send({ type: "stream", chunk: `<DataTable>${JSON.stringify(previewRows(data))}</DataTable>
128
+
129
+ ` });
130
+ }
131
+ executedQueries.push({
132
+ sourceId: toolId,
133
+ sourceName: toolId,
134
+ // enriched by runner after result arrives
135
+ sql,
136
+ data,
137
+ count,
138
+ executionTimeMs
139
+ });
140
+ return { data, count };
141
+ },
142
+ /**
143
+ * Call a tool with structured params (typically a direct tool whose
144
+ * fn(params) does not expect a SQL string). Returns whatever the tool
145
+ * returned — shape is up to the tool.
146
+ *
147
+ * Use this when you need a pre-built business-logic tool (e.g.,
148
+ * "Calculate Shelf Life") that takes structured input rather than SQL.
149
+ * For SQL source tools, keep using ctx.query.
150
+ *
151
+ * runTool results do NOT auto-flow into executedQueries. If you want
152
+ * the result visualised, register it via ctx.emit() after extracting
153
+ * the array you want to chart.
154
+ */
155
+ async runTool(toolId, params = {}) {
156
+ if (!BRIDGE_URL) throw new Error("SCRIPT_BRIDGE_URL is not set \u2014 script bridge server is not running");
157
+ const res = await fetch(`${BRIDGE_URL}/run-tool`, {
158
+ method: "POST",
159
+ headers: { "content-type": "application/json" },
160
+ body: JSON.stringify({ toolId, params })
161
+ });
162
+ const json = await res.json();
163
+ if (!res.ok || !json.success) throw new Error(json.error || `Bridge run-tool failed (${res.status})`);
164
+ return json.result;
165
+ },
166
+ /**
167
+ * Register a computed dataset. Flows into executedQueries alongside
168
+ * real SQL query results so component generation can render post-SQL
169
+ * transforms (weighted averages, clustering, joins) as charts.
170
+ */
171
+ emit(name, rows, meta) {
172
+ executedQueries.push({
173
+ sourceId: `computed:${name}`,
174
+ sourceName: meta?.description || name,
175
+ sql: `-- computed dataset: ${name}`,
176
+ data: Array.isArray(rows) ? rows : [],
177
+ count: Array.isArray(rows) ? rows.length : 0,
178
+ executionTimeMs: 0,
179
+ virtual: true
180
+ });
181
+ },
182
+ /**
183
+ * Forward a short progress message to the parent's StreamBuffer so the UI
184
+ * continues to see per-script feedback during execution.
185
+ */
186
+ log(chunk) {
187
+ send({ type: "stream", chunk });
188
+ }
189
+ };
190
+ }
191
+ function send(msg) {
192
+ return process.stdout.write(encodeMessage(msg));
193
+ }
194
+ function sendError(message, phase, stack) {
195
+ send({ type: "error", message, stack, phase });
196
+ }
197
+ var splitter = new LineSplitter();
198
+ process.stdin.setEncoding("utf-8");
199
+ process.stdin.on("data", (chunk) => {
200
+ let lines;
201
+ try {
202
+ lines = splitter.push(chunk);
203
+ } catch (err) {
204
+ const msg = err instanceof Error ? err.message : String(err);
205
+ sendError(msg, "runtime");
206
+ process.exit(1);
207
+ }
208
+ for (const line of lines) {
209
+ let msg;
210
+ try {
211
+ msg = JSON.parse(line);
212
+ } catch {
213
+ continue;
214
+ }
215
+ handleMessage(msg);
216
+ }
217
+ });
218
+ function handleMessage(msg) {
219
+ switch (msg.type) {
220
+ case "init": {
221
+ if (initResolve) {
222
+ const now = new Date(msg.now || (/* @__PURE__ */ new Date()).toISOString());
223
+ const params = restoreParamTypes(msg.params || {}, msg.paramSchema);
224
+ initResolve({ params, now });
225
+ initResolve = null;
226
+ }
227
+ break;
228
+ }
229
+ }
230
+ }
231
+ (async () => {
232
+ let getData;
233
+ try {
234
+ const mod = await import(pathToFileURL(SCRIPT_ARG).href);
235
+ getData = mod.getData ?? (typeof mod.default === "function" ? mod.default : mod.default?.getData);
236
+ if (typeof getData !== "function") {
237
+ throw new Error(
238
+ `Script at ${SCRIPT_ARG} does not export getData \u2014 expected \`export async function getData(ctx, params)\``
239
+ );
240
+ }
241
+ } catch (err) {
242
+ const e = err;
243
+ sendError(e.message || String(err), "compile", e.stack);
244
+ process.exit(1);
245
+ return;
246
+ }
247
+ const init = await initPromise;
248
+ const ctx = buildCtx(init);
249
+ const startedAt = Date.now();
250
+ try {
251
+ const raw = await getData(ctx, init.params);
252
+ const executionTimeMs = Date.now() - startedAt;
253
+ const data = normalizeResultData(raw);
254
+ const count = typeof raw?.count === "number" ? raw.count : data.length;
255
+ const sampleRows = data.slice(0, 5);
256
+ const result = {
257
+ type: "result",
258
+ data,
259
+ count,
260
+ executedQueries,
261
+ executionTimeMs,
262
+ sampleRows
263
+ };
264
+ const flushed = send(result);
265
+ if (flushed) {
266
+ process.exit(0);
267
+ } else {
268
+ process.stdout.once("drain", () => process.exit(0));
269
+ }
270
+ } catch (err) {
271
+ const e = err;
272
+ sendError(e.message || String(err), "runtime", e.stack);
273
+ process.exit(1);
274
+ }
275
+ })();
276
+ function normalizeResultData(raw) {
277
+ if (!raw) return [];
278
+ if (Array.isArray(raw)) return raw;
279
+ if (Array.isArray(raw.data)) return raw.data;
280
+ if (raw.data && typeof raw.data === "object") return [raw.data];
281
+ return [];
282
+ }
283
+ function restoreParamTypes(params, schema) {
284
+ if (!schema) return params;
285
+ const out = { ...params };
286
+ for (const [name, type] of Object.entries(schema)) {
287
+ const v = out[name];
288
+ if (v === void 0 || v === null) continue;
289
+ if (type === "date" && typeof v === "string") {
290
+ const d = new Date(v);
291
+ if (!isNaN(d.getTime())) out[name] = d;
292
+ } else if (type === "date_range" && typeof v === "object") {
293
+ const from = v.from;
294
+ const to = v.to;
295
+ out[name] = {
296
+ from: typeof from === "string" ? new Date(from) : from,
297
+ to: typeof to === "string" ? new Date(to) : to
298
+ };
299
+ }
300
+ }
301
+ return out;
302
+ }
303
+ //# sourceMappingURL=script-bootstrap.mjs.map