@yejiming/dsh-data-agent 0.0.12 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +97 -16
- package/README.md +97 -16
- package/conformance/dsh-ecosystem/baseline.json +59 -0
- package/conformance/dsh-ecosystem/dependencies.json +41 -0
- package/conformance/dsh-ecosystem/fixtures/host-degraded.fixture.json +12 -0
- package/conformance/dsh-ecosystem/fixtures/host-eligible.fixture.json +13 -0
- package/conformance/dsh-ecosystem/fixtures/host-rejected.fixture.json +12 -0
- package/conformance/dsh-ecosystem/fixtures/profiles/native-only/package.json +8 -0
- package/conformance/dsh-ecosystem/fixtures/profiles/native-plus-adapter/package.json +9 -0
- package/conformance/dsh-ecosystem/inventory.json +100 -0
- package/conformance/dsh-ecosystem/restrictions.json +20 -0
- package/cordis.patch.yml +6 -3
- package/dsh-plugin.json +72 -0
- package/lib/catalog-DEJqOXRo.js +1944 -0
- package/lib/catalog-identity-CVftmvQL.js +96 -0
- package/lib/client.js +3465 -138
- package/lib/client.js.map +1 -1
- package/lib/command-CzzSPmag.js +1719 -0
- package/lib/command.js +2 -2
- package/lib/{connections-5sfdEDsG.js → connections-CFXOZTHZ.js} +964 -68
- package/lib/ecosystem.js +19 -0
- package/lib/index.js +392 -34
- package/lib/routes.js +260 -8
- package/lib/{tool-DgL0fBfj.js → tool-DNkywSph.js} +367 -168
- package/lib/tool.js +1 -1
- package/lib/types/catalog-adapters.d.ts +52 -0
- package/lib/types/catalog-ai.d.ts +49 -0
- package/lib/types/catalog-command.d.ts +28 -0
- package/lib/types/catalog-identity.d.ts +23 -0
- package/lib/types/catalog-storage.d.ts +265 -0
- package/lib/types/catalog-tools.d.ts +5 -0
- package/lib/types/catalog-tui.d.ts +18 -0
- package/lib/types/catalog-types.d.ts +1376 -0
- package/lib/types/catalog.d.ts +59 -0
- package/lib/types/client/CatalogPanel.d.ts +15 -0
- package/lib/types/client/DataAgentWorkbench.d.ts +1 -2
- package/lib/types/client/QueryResultTable.d.ts +13 -0
- package/lib/types/client/catalog-client.d.ts +57 -0
- package/lib/types/client/locales.d.ts +290 -0
- package/lib/types/client/persistence.d.ts +3 -1
- package/lib/types/client/query-export.d.ts +11 -0
- package/lib/types/client-discovery.d.ts +3 -4
- package/lib/types/clients.d.ts +14 -8
- package/lib/types/command.d.ts +16 -5
- package/lib/types/connections.d.ts +42 -4
- package/lib/types/database-types.d.ts +23 -0
- package/lib/types/defaults.d.ts +26 -0
- package/lib/types/ecosystem.d.ts +13 -0
- package/lib/types/index.d.ts +58 -15
- package/lib/types/query.d.ts +13 -11
- package/lib/types/sql.d.ts +9 -1
- package/lib/types/storage.d.ts +11 -1
- package/lib/types/structured-read.d.ts +2 -2
- package/lib/types/structured.d.ts +1 -1
- package/lib/types/tool.d.ts +5 -5
- package/lib/types/tui-connection-form.d.ts +21 -12
- package/package.json +30 -4
- package/preset/data-agent/agent.cordis.yml +13 -2
- package/lib/command-DuCpwVbl.js +0 -875
- package/lib/defaults-DP4RyRh1.js +0 -21
package/lib/routes.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as isDatabaseType, b as DATABASE_TYPES, d as DEFAULT_CONNECT_TIMEOUT_MS, f as DEFAULT_MAX_QUERY_CHARS, h as DEFAULT_QUERY_TIMEOUT_MS, p as DEFAULT_MAX_RESULT_CHARS } from "./connections-CFXOZTHZ.js";
|
|
2
|
+
import { d as catalogSearchRequestSchema, h as semanticDefinitionSchema, l as catalogScopeSchema, t as CatalogVersionConflictError } from "./catalog-DEJqOXRo.js";
|
|
2
3
|
import { resolve } from "node:path";
|
|
3
4
|
import z from "schemastery";
|
|
5
|
+
import { z as z$1 } from "zod";
|
|
4
6
|
//#region src/routes.ts
|
|
5
7
|
const name = "data-agent-routes";
|
|
6
8
|
/** Headless profiles activate this row without waiting forever for webServer. */
|
|
@@ -20,12 +22,13 @@ function validateConnectBody(value, cwd = process.cwd()) {
|
|
|
20
22
|
const candidate = value;
|
|
21
23
|
const sessionId = requireString(candidate.sessionId, "sessionId");
|
|
22
24
|
const type = candidate.type;
|
|
23
|
-
if (!isDatabaseType(type)) throw new Error(
|
|
25
|
+
if (!isDatabaseType(type)) throw new Error(`type 必须是受支持的数据库类型:${DATABASE_TYPES.join("、")}`);
|
|
24
26
|
const database = requireString(candidate.database, "database");
|
|
25
27
|
const password = optionalString(candidate.password, "password");
|
|
26
28
|
const passwordRef = optionalString(candidate.passwordRef, "passwordRef");
|
|
27
29
|
if (password !== void 0 && passwordRef !== void 0) throw new Error("password 与 passwordRef 不能同时提供");
|
|
28
30
|
const readonly = optionalBoolean(candidate.readonly, "readonly");
|
|
31
|
+
const secure = optionalBoolean(candidate.secure, "secure");
|
|
29
32
|
const profileId = optionalString(candidate.profileId, "profileId");
|
|
30
33
|
const profileName = optionalString(candidate.name, "name");
|
|
31
34
|
const request = {
|
|
@@ -34,6 +37,7 @@ function validateConnectBody(value, cwd = process.cwd()) {
|
|
|
34
37
|
database: type === "sqlite" ? resolve(cwd, database) : database
|
|
35
38
|
};
|
|
36
39
|
if (readonly !== void 0) request.readonly = readonly;
|
|
40
|
+
if (type === "clickhouse" && secure !== void 0) request.secure = secure;
|
|
37
41
|
if (profileId !== void 0) request.profileId = profileId;
|
|
38
42
|
if (profileName !== void 0) request.name = profileName;
|
|
39
43
|
if (type === "sqlite") return request;
|
|
@@ -50,7 +54,13 @@ function validateConnectBody(value, cwd = process.cwd()) {
|
|
|
50
54
|
}
|
|
51
55
|
/** Register Web routes only when both the webserver and shared service exist. */
|
|
52
56
|
function apply(ctx, _config) {
|
|
53
|
-
ctx.inject([
|
|
57
|
+
ctx.inject([
|
|
58
|
+
"webServer",
|
|
59
|
+
"dataAgentConnections",
|
|
60
|
+
"dataAgentCatalog",
|
|
61
|
+
"dataAgentCatalogScanner",
|
|
62
|
+
"dataAgentCatalogReview"
|
|
63
|
+
], (scope) => {
|
|
54
64
|
scope.effect(() => {
|
|
55
65
|
const dispose = scope.webServer.register({
|
|
56
66
|
kind: "prefix",
|
|
@@ -133,13 +143,181 @@ function apply(ctx, _config) {
|
|
|
133
143
|
const sql = requireString(body.sql, "sql");
|
|
134
144
|
writeJson(200, {
|
|
135
145
|
ok: true,
|
|
136
|
-
result: await scope.dataAgentConnections.
|
|
146
|
+
result: await scope.dataAgentConnections.executeInteractive(sessionId, sql, signal)
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (req.method === "GET" && routePathIs(segments, "catalog", "sources")) {
|
|
151
|
+
assertOnlySearchParams(url.searchParams, []);
|
|
152
|
+
writeJson(200, {
|
|
153
|
+
ok: true,
|
|
154
|
+
sources: scope.dataAgentCatalog.listSources()
|
|
155
|
+
});
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (req.method === "GET" && routePathIs(segments, "catalog", "status")) {
|
|
159
|
+
assertOnlySearchParams(url.searchParams, ["sourceId"]);
|
|
160
|
+
const sourceId = requireBoundedString(url.searchParams.get("sourceId"), "sourceId");
|
|
161
|
+
writeJson(200, {
|
|
162
|
+
ok: true,
|
|
163
|
+
status: scope.dataAgentCatalog.status(sourceId) ?? null
|
|
164
|
+
});
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (req.method === "GET" && routePathIs(segments, "catalog", "runs")) {
|
|
168
|
+
assertOnlySearchParams(url.searchParams, ["sourceId", "limit"]);
|
|
169
|
+
const sourceId = requireBoundedString(url.searchParams.get("sourceId"), "sourceId");
|
|
170
|
+
const limit = optionalPositiveInteger(url.searchParams.get("limit"), "limit", 200);
|
|
171
|
+
writeJson(200, {
|
|
172
|
+
ok: true,
|
|
173
|
+
runs: scope.dataAgentCatalog.listRuns(sourceId, limit)
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (req.method === "POST" && routePathIs(segments, "catalog", "scan")) {
|
|
178
|
+
const body = catalogScanBodySchema.parse(await readJson(req));
|
|
179
|
+
if (body.sourceId !== void 0) {
|
|
180
|
+
if (scope.dataAgentConnections.get(body.sessionId)?.profileId !== body.sourceId) throw new Error("sourceId does not match the session connection");
|
|
181
|
+
}
|
|
182
|
+
writeJson(202, {
|
|
183
|
+
ok: true,
|
|
184
|
+
run: await scope.dataAgentCatalogScanner.start({
|
|
185
|
+
sessionId: body.sessionId,
|
|
186
|
+
scope: body.scope
|
|
187
|
+
})
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (req.method === "POST" && routePathIs(segments, "catalog", "cancel")) {
|
|
192
|
+
const body = catalogCancelBodySchema.parse(await readJson(req));
|
|
193
|
+
writeJson(200, {
|
|
194
|
+
ok: true,
|
|
195
|
+
run: await scope.dataAgentCatalogScanner.cancel(body.sourceId, body.runId)
|
|
196
|
+
});
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (req.method === "GET" && routePathIs(segments, "catalog", "search")) {
|
|
200
|
+
assertOnlySearchParams(url.searchParams, [
|
|
201
|
+
"sourceId",
|
|
202
|
+
"query",
|
|
203
|
+
"schema",
|
|
204
|
+
"assetKinds",
|
|
205
|
+
"semanticKinds",
|
|
206
|
+
"assetStatuses",
|
|
207
|
+
"semanticStatuses",
|
|
208
|
+
"includeInferred",
|
|
209
|
+
"cursor",
|
|
210
|
+
"pageSize"
|
|
211
|
+
]);
|
|
212
|
+
const sourceId = requireBoundedString(url.searchParams.get("sourceId"), "sourceId");
|
|
213
|
+
const query = requireBoundedString(url.searchParams.get("query"), "query", 512);
|
|
214
|
+
const pageSize = optionalPositiveInteger(url.searchParams.get("pageSize"), "pageSize", 200);
|
|
215
|
+
const includeInferred = optionalBooleanQuery(url.searchParams.get("includeInferred"), "includeInferred");
|
|
216
|
+
const request = catalogSearchRequestSchema.parse({
|
|
217
|
+
query,
|
|
218
|
+
filters: {
|
|
219
|
+
sourceId,
|
|
220
|
+
...url.searchParams.get("schema") !== null ? { schema: url.searchParams.get("schema") } : {},
|
|
221
|
+
...csvParam(url.searchParams, "assetKinds") !== void 0 ? { assetKinds: csvParam(url.searchParams, "assetKinds") } : {},
|
|
222
|
+
...csvParam(url.searchParams, "semanticKinds") !== void 0 ? { semanticKinds: csvParam(url.searchParams, "semanticKinds") } : {},
|
|
223
|
+
...csvParam(url.searchParams, "assetStatuses") !== void 0 ? { assetStatuses: csvParam(url.searchParams, "assetStatuses") } : {},
|
|
224
|
+
...csvParam(url.searchParams, "semanticStatuses") !== void 0 ? { semanticStatuses: csvParam(url.searchParams, "semanticStatuses") } : {},
|
|
225
|
+
includeInferred: includeInferred ?? false
|
|
226
|
+
},
|
|
227
|
+
...url.searchParams.get("cursor") !== null ? { cursor: url.searchParams.get("cursor") } : {},
|
|
228
|
+
...pageSize !== void 0 ? { pageSize } : {}
|
|
229
|
+
});
|
|
230
|
+
writeJson(200, {
|
|
231
|
+
ok: true,
|
|
232
|
+
page: await scope.dataAgentCatalog.search(request)
|
|
233
|
+
});
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (req.method === "GET" && segments.length === 3 && segments[0] === "catalog" && segments[1] === "assets") {
|
|
237
|
+
assertOnlySearchParams(url.searchParams, [
|
|
238
|
+
"sourceId",
|
|
239
|
+
"cursor",
|
|
240
|
+
"pageSize"
|
|
241
|
+
]);
|
|
242
|
+
const sourceId = requireBoundedString(url.searchParams.get("sourceId"), "sourceId");
|
|
243
|
+
const assetId = requireBoundedString(segments[2], "assetId");
|
|
244
|
+
const pageSize = optionalPositiveInteger(url.searchParams.get("pageSize"), "pageSize", 200);
|
|
245
|
+
const cursor = optionalBoundedString(url.searchParams.get("cursor"), "cursor", 512);
|
|
246
|
+
writeJson(200, {
|
|
247
|
+
ok: true,
|
|
248
|
+
detail: scope.dataAgentCatalog.getAsset(sourceId, assetId, cursor, pageSize)
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (req.method === "GET" && routePathIs(segments, "catalog", "diff")) {
|
|
253
|
+
assertOnlySearchParams(url.searchParams, [
|
|
254
|
+
"sourceId",
|
|
255
|
+
"from",
|
|
256
|
+
"to",
|
|
257
|
+
"cursor",
|
|
258
|
+
"pageSize"
|
|
259
|
+
]);
|
|
260
|
+
const sourceId = requireBoundedString(url.searchParams.get("sourceId"), "sourceId");
|
|
261
|
+
const fromRunId = optionalBoundedString(url.searchParams.get("from"), "from", 256);
|
|
262
|
+
const toRunId = optionalBoundedString(url.searchParams.get("to"), "to", 256);
|
|
263
|
+
if (fromRunId === void 0 !== (toRunId === void 0)) throw new Error("from and to must be supplied together");
|
|
264
|
+
const cursor = optionalBoundedString(url.searchParams.get("cursor"), "cursor", 512);
|
|
265
|
+
const pageSize = optionalPositiveInteger(url.searchParams.get("pageSize"), "pageSize", 200);
|
|
266
|
+
writeJson(200, {
|
|
267
|
+
ok: true,
|
|
268
|
+
diff: scope.dataAgentCatalog.diff(sourceId, fromRunId, toRunId, cursor, pageSize)
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (req.method === "GET" && segments.length === 3 && segments[0] === "catalog" && segments[1] === "semantics") {
|
|
273
|
+
assertOnlySearchParams(url.searchParams, ["sourceId", "version"]);
|
|
274
|
+
const sourceId = requireBoundedString(url.searchParams.get("sourceId"), "sourceId");
|
|
275
|
+
const semanticId = requireBoundedString(segments[2], "semanticId");
|
|
276
|
+
const version = optionalPositiveInteger(url.searchParams.get("version"), "version", Number.MAX_SAFE_INTEGER);
|
|
277
|
+
writeJson(200, {
|
|
278
|
+
ok: true,
|
|
279
|
+
semantic: scope.dataAgentCatalog.getSemantic(sourceId, semanticId, version)
|
|
280
|
+
});
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (req.method === "POST" && routePathIs(segments, "catalog", "semantics")) {
|
|
284
|
+
const body = catalogSemanticSaveBodySchema.parse(await readJson(req));
|
|
285
|
+
writeJson(200, {
|
|
286
|
+
ok: true,
|
|
287
|
+
semantic: await scope.dataAgentCatalogReview.saveCandidate(body.sourceId, body.definition, body.semanticId, body.expectedVersion)
|
|
288
|
+
});
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (req.method === "POST" && segments.length === 4 && segments[0] === "catalog" && segments[1] === "semantics" && segments[3] === "verify") {
|
|
292
|
+
const body = catalogSemanticVerifyBodySchema.parse(await readJson(req));
|
|
293
|
+
writeJson(200, {
|
|
294
|
+
ok: true,
|
|
295
|
+
semantic: await scope.dataAgentCatalogReview.verify(body.sourceId, requireBoundedString(segments[2], "semanticId"), body.expectedVersion, body.definition)
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (req.method === "POST" && segments.length === 4 && segments[0] === "catalog" && segments[1] === "semantics" && segments[3] === "retire") {
|
|
300
|
+
const body = catalogSemanticRetireBodySchema.parse(await readJson(req));
|
|
301
|
+
writeJson(200, {
|
|
302
|
+
ok: true,
|
|
303
|
+
semantic: await scope.dataAgentCatalogReview.retire(body.sourceId, requireBoundedString(segments[2], "semanticId"), body.expectedVersion, body.revisionNote)
|
|
304
|
+
});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (req.method === "POST" && segments.length === 4 && segments[0] === "catalog" && segments[1] === "semantics" && segments[3] === "dismiss") {
|
|
308
|
+
const body = catalogSemanticDismissBodySchema.parse(await readJson(req));
|
|
309
|
+
writeJson(200, {
|
|
310
|
+
ok: true,
|
|
311
|
+
semantic: await scope.dataAgentCatalogReview.dismissMeaning(body.sourceId, requireBoundedString(segments[2], "semanticId"), body.expectedVersion)
|
|
137
312
|
});
|
|
138
313
|
return;
|
|
139
314
|
}
|
|
140
315
|
writeJson(404, { error: "unknown data-agent route" });
|
|
141
316
|
} catch (error) {
|
|
142
|
-
writeJson(
|
|
317
|
+
writeJson(error instanceof CatalogVersionConflictError ? 409 : 400, {
|
|
318
|
+
error: sanitizeCatalogRouteError(error instanceof Error ? error.message : String(error)),
|
|
319
|
+
...error instanceof CatalogVersionConflictError ? { current: error.current } : {}
|
|
320
|
+
});
|
|
143
321
|
}
|
|
144
322
|
}
|
|
145
323
|
});
|
|
@@ -152,9 +330,47 @@ function apply(ctx, _config) {
|
|
|
152
330
|
function routeIs(segments, expected) {
|
|
153
331
|
return segments.length === 1 && segments[0] === expected;
|
|
154
332
|
}
|
|
333
|
+
function routePathIs(segments, ...expected) {
|
|
334
|
+
return segments.length === expected.length && segments.every((value, index) => value === expected[index]);
|
|
335
|
+
}
|
|
336
|
+
const catalogScanBodySchema = z$1.strictObject({
|
|
337
|
+
sessionId: z$1.string().min(1).max(256),
|
|
338
|
+
sourceId: z$1.string().min(1).max(256).optional(),
|
|
339
|
+
scope: catalogScopeSchema
|
|
340
|
+
});
|
|
341
|
+
const catalogCancelBodySchema = z$1.strictObject({
|
|
342
|
+
sourceId: z$1.string().min(1).max(256),
|
|
343
|
+
runId: z$1.string().min(1).max(256).optional()
|
|
344
|
+
});
|
|
345
|
+
const catalogSemanticSaveBodySchema = z$1.strictObject({
|
|
346
|
+
sourceId: z$1.string().min(1).max(256),
|
|
347
|
+
semanticId: z$1.string().min(1).max(256).optional(),
|
|
348
|
+
expectedVersion: z$1.number().int().nonnegative().optional(),
|
|
349
|
+
definition: semanticDefinitionSchema
|
|
350
|
+
});
|
|
351
|
+
const catalogSemanticVerifyBodySchema = z$1.strictObject({
|
|
352
|
+
sourceId: z$1.string().min(1).max(256),
|
|
353
|
+
expectedVersion: z$1.number().int().positive(),
|
|
354
|
+
definition: semanticDefinitionSchema
|
|
355
|
+
});
|
|
356
|
+
const catalogSemanticRetireBodySchema = z$1.strictObject({
|
|
357
|
+
sourceId: z$1.string().min(1).max(256),
|
|
358
|
+
expectedVersion: z$1.number().int().positive(),
|
|
359
|
+
revisionNote: z$1.string().trim().min(1).max(4096)
|
|
360
|
+
});
|
|
361
|
+
const catalogSemanticDismissBodySchema = z$1.strictObject({
|
|
362
|
+
sourceId: z$1.string().min(1).max(256),
|
|
363
|
+
expectedVersion: z$1.number().int().positive()
|
|
364
|
+
});
|
|
155
365
|
async function readJson(req) {
|
|
156
366
|
const chunks = [];
|
|
157
|
-
|
|
367
|
+
let size = 0;
|
|
368
|
+
for await (const chunk of req) {
|
|
369
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
370
|
+
size += buffer.byteLength;
|
|
371
|
+
if (size > 1048576) throw new Error("JSON request body exceeds 1 MiB");
|
|
372
|
+
chunks.push(buffer);
|
|
373
|
+
}
|
|
158
374
|
const raw = Buffer.concat(chunks).toString("utf8");
|
|
159
375
|
return raw.length === 0 ? {} : JSON.parse(raw);
|
|
160
376
|
}
|
|
@@ -177,8 +393,44 @@ function optionalBoolean(value, label) {
|
|
|
177
393
|
if (typeof value !== "boolean") throw new Error(`${label} 必须是布尔值`);
|
|
178
394
|
return value;
|
|
179
395
|
}
|
|
180
|
-
function
|
|
181
|
-
|
|
396
|
+
function requireBoundedString(value, label, max = 256) {
|
|
397
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.length > max) throw new Error(`${label} must be a non-empty string of at most ${max} characters`);
|
|
398
|
+
return value;
|
|
399
|
+
}
|
|
400
|
+
function optionalBoundedString(value, label, max) {
|
|
401
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
402
|
+
return requireBoundedString(value, label, max);
|
|
403
|
+
}
|
|
404
|
+
function optionalPositiveInteger(value, label, max) {
|
|
405
|
+
if (value === null || value === "") return void 0;
|
|
406
|
+
const number = Number(value);
|
|
407
|
+
if (!Number.isInteger(number) || number < 1 || number > max) throw new Error(`${label} must be an integer between 1 and ${max}`);
|
|
408
|
+
return number;
|
|
409
|
+
}
|
|
410
|
+
function optionalBooleanQuery(value, label) {
|
|
411
|
+
if (value === null || value === "") return void 0;
|
|
412
|
+
if (value === "true") return true;
|
|
413
|
+
if (value === "false") return false;
|
|
414
|
+
throw new Error(`${label} must be true or false`);
|
|
415
|
+
}
|
|
416
|
+
function csvParam(search, name) {
|
|
417
|
+
const value = search.get(name);
|
|
418
|
+
if (value === null || value === "") return void 0;
|
|
419
|
+
const items = value.split(",");
|
|
420
|
+
if (items.some((item) => item.length === 0 || item.length > 64) || items.length > 32) throw new Error(`${name} is invalid`);
|
|
421
|
+
return items;
|
|
422
|
+
}
|
|
423
|
+
function assertOnlySearchParams(search, allowed) {
|
|
424
|
+
const accepted = new Set(allowed);
|
|
425
|
+
const seen = /* @__PURE__ */ new Set();
|
|
426
|
+
for (const key of search.keys()) {
|
|
427
|
+
if (!accepted.has(key)) throw new Error(`Unknown query parameter: ${key}`);
|
|
428
|
+
if (seen.has(key)) throw new Error(`Duplicate query parameter: ${key}`);
|
|
429
|
+
seen.add(key);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function sanitizeCatalogRouteError(message) {
|
|
433
|
+
return message.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, " ").replace(/(?:\/[^\s/:]+){3,}/g, "[PATH]").slice(0, 4096);
|
|
182
434
|
}
|
|
183
435
|
//#endregion
|
|
184
436
|
export { Config, DATA_AGENT_PATH, apply, inject, name, validateConnectBody };
|