SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
1 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%

Connector test context + dry-run script + worker skeleton

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 21 days ago (Sep 11, 2026) parent 5b9a906

7 changed files +698 −2

added apps/worker/package.json +26 −0
@@ -0,0 +1,26 @@
1 +{
2 + "name": "@dci/worker",
3 + "version": "0.1.0",
4 + "private": true,
5 + "type": "module",
6 + "scripts": {
7 + "typecheck": "tsc --noEmit",
8 + "test": "vitest run --passWithNoTests",
9 + "dev": "node ../../node_modules/tsx/dist/cli.mjs src/main.ts",
10 + "start": "node ../../node_modules/tsx/dist/cli.mjs src/main.ts",
11 + "scheduler": "node ../../node_modules/tsx/dist/cli.mjs src/scheduler.ts",
12 + "cli": "node ../../node_modules/tsx/dist/cli.mjs src/cli.ts"
13 + },
14 + "dependencies": {
15 + "@aws-sdk/client-s3": "^3.700.0",
16 + "@dci/connectors": "workspace:*",
17 + "@dci/core": "workspace:*",
18 + "@dci/db": "workspace:*",
19 + "bullmq": "^5.56.0",
20 + "cheerio": "^1.1.0",
21 + "ioredis": "^5.6.0",
22 + "yaml": "^2.8.0",
23 + "zod": "^4.1.0"
24 + },
25 + "devDependencies": { "@types/node": "^24.0.0", "typescript": "^5.9.3", "vitest": "^3.2.0" }
26 +}
added apps/worker/tsconfig.json +1 −0
@@ -0,0 +1 @@
1 +{ "extends": "../../tsconfig.base.json", "compilerOptions": { "noEmit": true, "types": ["node"], "lib": ["ES2023", "DOM"] }, "include": ["src"] }
modified package.json +9 −2
@@ -2,10 +2,12 @@
2 2 "name": "datacenterindex",
3 3 "version": "0.1.0",
4 4 "private": true,
5 − "description": "DataCenterIndex.io — the global index of data center infrastructure: facilities, campuses, operators, cloud regions, markets, projects, power and connectivity, built on a homemade connector and crawling platform.",
5 + "description": "DataCenterIndex.io \u2014 the global index of data center infrastructure: facilities, campuses, operators, cloud regions, markets, projects, power and connectivity, built on a homemade connector and crawling platform.",
6 6 "type": "module",
7 7 "packageManager": "pnpm@11.1.2",
8 − "engines": { "node": ">=22.15" },
8 + "engines": {
9 + "node": ">=22.15"
10 + },
9 11 "scripts": {
10 12 "typecheck": "pnpm -r --parallel run typecheck",
11 13 "test": "pnpm -r run test",
@@ -22,5 +24,10 @@
22 24 "tsx": "^4.20.0",
23 25 "typescript": "^5.9.3",
24 26 "vitest": "^3.2.0"
27 + },
28 + "dependencies": {
29 + "@dci/connectors": "workspace:*",
30 + "@dci/core": "workspace:*",
31 + "@dci/db": "workspace:*"
25 32 }
26 33 }
modified packages/connectors/src/index.ts +1 −0
@@ -8,3 +8,4 @@ export * from "./extract.js";
8 8 export * from "./classify.js";
9 9 export * from "./registry.js";
10 10 export * from "./generic.js";
11 +export * from "./testing.js";
added packages/connectors/src/testing.ts +58 −0
@@ -0,0 +1,58 @@
1 +import type { Provenance } from "@dci/core";
2 +import { contentFingerprint } from "@dci/core";
3 +import type { ConnectorContext, FetchOptions, RawDocument } from "./types.js";
4 +import type { ConnectorConfig } from "./config.js";
5 +import { fetchWithEscalation, BROWSER_UA } from "./fetchers.js";
6 +import { isAllowedByRobots } from "./robots.js";
7 +import { acquire, configureHost } from "./ratelimit.js";
8 +import type { FetchLevel } from "@dci/core";
9 +
10 +/**
11 + * Minimal in-memory ConnectorContext for dry runs / tests / connector authoring.
12 + * Applies robots, rate limits and escalation exactly like the production runtime, but persists nothing.
13 + */
14 +export function createTestContext(cfg: ConnectorConfig, opts: { verbose?: boolean; sourceId?: string } = {}): ConnectorContext & { fetched: RawDocument[]; credits: number } {
15 + const state = new Map<string, unknown>();
16 + const hashes = new Map<string, string>();
17 + const host = cfg.domain.replace(/^https?:\/\//, "").split("/")[0]!;
18 + configureHost(host, cfg.fetch.rpm, cfg.fetch.concurrency);
19 + const fetched: RawDocument[] = [];
20 + const ctx = {
21 + connectorId: cfg.id,
22 + sourceId: opts.sourceId ?? `src_${cfg.id}`,
23 + runId: `run_test_${Date.now().toString(36)}`,
24 + fetched,
25 + credits: 0,
26 + dryRun: true,
27 + env: process.env,
28 + now: () => new Date().toISOString(),
29 + log(level: "debug" | "info" | "warn" | "error", msg: string, extra?: Record<string, unknown>) {
30 + if (level === "debug" && !opts.verbose) return;
31 + console.error(`[${cfg.id}] ${level.toUpperCase()} ${msg}${extra ? " " + JSON.stringify(extra) : ""}`);
32 + },
33 + async getState<T>(key: string): Promise<T | null> { return (state.get(key) as T) ?? null; },
34 + async setState(key: string, value: unknown) { state.set(key, value); },
35 + async isKnownUnchanged(url: string, hash: string) { return hashes.get(url) === hash; },
36 + provenance(url: string, extra: Partial<Provenance> = {}): Provenance {
37 + const now = new Date().toISOString();
38 + return { sourceId: ctx.sourceId, connectorId: cfg.id, url, firstObserved: now, lastObserved: now, retrievedAt: now, confidence: cfg.kind === "operator" || cfg.kind === "government" || cfg.kind === "filing" || cfg.kind === "utility" || cfg.kind === "cloud_provider" || cfg.kind === "registry" ? "high" : "moderate", extractorVersion: cfg.parserVersion, ...extra };
39 + },
40 + async fetch(url: string, o: FetchOptions = {}): Promise<RawDocument> {
41 + if (cfg.fetch.respectRobots) {
42 + const r = await isAllowedByRobots(url).catch(() => ({ allowed: true, crawlDelay: null as number | null }));
43 + if (!r.allowed) { ctx.log("warn", `robots.txt disallows ${url}`); return { url, finalUrl: url, fetchedAt: new Date().toISOString(), status: 0, contentType: null, body: Buffer.alloc(0), text: "", headers: {}, etag: null, lastModified: null, notModified: false, fetcher: "direct", level: 1, durationMs: 0, credits: 0, error: { code: "robots_disallow", message: "disallowed by robots.txt" } }; }
44 + }
45 + const release = await acquire(new URL(url).hostname);
46 + try {
47 + const level = Math.max(o.level ?? 1, cfg.fetch.level) as FetchLevel;
48 + const doc = await fetchWithEscalation(url, { ...o, level, maxLevel: cfg.fetch.maxLevel as FetchLevel, renderJs: o.renderJs ?? cfg.fetch.renderJs, country: o.country ?? cfg.fetch.country, waitForSelector: o.waitForSelector ?? cfg.fetch.waitForSelector, timeoutMs: o.timeoutMs ?? cfg.fetch.timeoutMs, maxBytes: o.maxBytes ?? cfg.fetch.maxBytes, accept: o.accept ?? cfg.fetch.accept, headers: { ...(cfg.fetch.userAgent === "browser" ? { "user-agent": BROWSER_UA } : {}), ...(cfg.fetch.headers ?? {}), ...(o.headers ?? {}) } });
49 + ctx.credits += doc.credits;
50 + if (!doc.error && doc.body.length) hashes.set(url, contentFingerprint(doc.text, doc.contentType));
51 + fetched.push(doc);
52 + ctx.log("debug", `fetch ${url} → ${doc.error?.code ?? doc.status} via ${doc.fetcher} L${doc.level} ${doc.durationMs}ms ${doc.body.length}b`);
53 + return doc;
54 + } finally { release(); }
55 + },
56 + };
57 + return ctx;
58 +}
modified pnpm-lock.yaml +540 −0
@@ -7,6 +7,16 @@ settings:
7 7 importers:
8 8
9 9 .:
10 + dependencies:
11 + '@dci/connectors':
12 + specifier: workspace:*
13 + version: link:packages/connectors
14 + '@dci/core':
15 + specifier: workspace:*
16 + version: link:packages/core
17 + '@dci/db':
18 + specifier: workspace:*
19 + version: link:packages/db
10 20 devDependencies:
11 21 '@types/node':
12 22 specifier: ^24.0.0
@@ -21,6 +31,46 @@ importers:
21 31 specifier: ^3.2.0
22 32 version: 3.2.7(@types/node@24.13.4)(tsx@4.23.13)(yaml@2.9.0)
23 33
34 + apps/worker:
35 + dependencies:
36 + '@aws-sdk/client-s3':
37 + specifier: ^3.700.0
38 + version: 3.1129.0
39 + '@dci/connectors':
40 + specifier: workspace:*
41 + version: link:../../packages/connectors
42 + '@dci/core':
43 + specifier: workspace:*
44 + version: link:../../packages/core
45 + '@dci/db':
46 + specifier: workspace:*
47 + version: link:../../packages/db
48 + bullmq:
49 + specifier: ^5.56.0
50 + version: 5.81.4
51 + cheerio:
52 + specifier: ^1.1.0
53 + version: 1.2.0
54 + ioredis:
55 + specifier: ^5.6.0
56 + version: 5.11.1
57 + yaml:
58 + specifier: ^2.8.0
59 + version: 2.9.0
60 + zod:
61 + specifier: ^4.1.0
62 + version: 4.6.1
63 + devDependencies:
64 + '@types/node':
65 + specifier: ^24.0.0
66 + version: 24.13.4
67 + typescript:
68 + specifier: ^5.9.3
69 + version: 5.9.3
70 + vitest:
71 + specifier: ^3.2.0
72 + version: 3.2.7(@types/node@24.13.4)(tsx@4.23.13)(yaml@2.9.0)
73 +
24 74 packages/connectors:
25 75 dependencies:
26 76 '@dci/core':
@@ -101,6 +151,78 @@ importers:
101 151
102 152 packages:
103 153
154 + '@aws-sdk/checksums@3.1001.0':
155 + resolution: {integrity: sha512-6uTniZc87q+B5eXouGTl+7Tmc482rEeCcvxpsvREP8EfF0gvloRZ41UOA9sbSJlyy8TbqIBXb3kKfKarEArUQA==}
156 + engines: {node: '>=20.0.0'}
157 +
158 + '@aws-sdk/client-s3@3.1129.0':
159 + resolution: {integrity: sha512-TwbRTrAGwtFFUQ/jozsj9Jyjy+UjIsfSKaNs/tQfggIWFbk1Mim+IWjZ//IOz97Wc5Q/z/6G4cb5znYUXHKxHg==}
160 + engines: {node: '>=20.0.0'}
161 +
162 + '@aws-sdk/core@3.978.0':
163 + resolution: {integrity: sha512-2yX9LUmxPklVjSGTb8dfnWRJSiFQ3TeH2nn7G1mdKHTfnabzF0+gfrS8rYfLWmZrQ8A3mEcxMJjRc51dL5KWaA==}
164 + engines: {node: '>=20.0.0'}
165 +
166 + '@aws-sdk/credential-provider-env@3.972.71':
167 + resolution: {integrity: sha512-JN+JHruYZw3GUZB8YGAlDk4wTDPOEAEEdEzj5nS0xodWR4smzHsN7PnK2j6IeOsDIj2aqua5DSbhXl9Gtf90FQ==}
168 + engines: {node: '>=20.0.0'}
169 +
170 + '@aws-sdk/credential-provider-http@3.972.73':
171 + resolution: {integrity: sha512-uyYYnJOnlis8uQzaYGPd7N1JoioCoNpXgnkXYixsWJXHXgXyYi8WXJSDfofxJeWfQIGWLe2Nwyq60Uc7MZdVOg==}
172 + engines: {node: '>=20.0.0'}
173 +
174 + '@aws-sdk/credential-provider-ini@3.973.16':
175 + resolution: {integrity: sha512-i++ly+0Uxa+u3ebSSyr0S/3CFhFJDxCXT3+Zj+mW2bXenEx5bKGCdTIKFu39SgXBNhWDjex/8cXUx9MUTMCrTw==}
176 + engines: {node: '>=20.0.0'}
177 +
178 + '@aws-sdk/credential-provider-login@3.972.78':
179 + resolution: {integrity: sha512-eUtswnXu0+Ii9ieRK+0L7aPFV3Z/dnW2VntJzjBP9xs8s+8p5nBNuymIXtXwZ+5r5+XJP3e32nMkuZ/r0HozEA==}
180 + engines: {node: '>=20.0.0'}
181 +
182 + '@aws-sdk/credential-provider-node@3.972.83':
183 + resolution: {integrity: sha512-jdso7ejzfRnatxMUZK4S/U6KbaDPCvfIV4XL+IQAPFDBt5rj5Fq595euqlK8Le4lNCMFR9oUpt+1l0aMgaayOQ==}
184 + engines: {node: '>=20.0.0'}
185 +
186 + '@aws-sdk/credential-provider-process@3.972.71':
187 + resolution: {integrity: sha512-lYmXJa4gvq4xN1lrT5NiP5vIYYKcGWAdj8y+8o6dlcateB5eF3Dn8DtmjjHKfMBrTPAMr2pebIiX/UOj8c1/UA==}
188 + engines: {node: '>=20.0.0'}
189 +
190 + '@aws-sdk/credential-provider-sso@3.973.15':
191 + resolution: {integrity: sha512-6Jhcf4v0pSFdjk1EW2kvzuEBKD+UZ2uNcHUIglKKLndD20YhvkL2kdmDOV5/j4mYuWWwe/a1FQ1aomU86/Cg5Q==}
192 + engines: {node: '>=20.0.0'}
193 +
194 + '@aws-sdk/credential-provider-web-identity@3.972.77':
195 + resolution: {integrity: sha512-uylIQSUWpfLuH2LovxEEfwzJGM/SabLOfLMg6YXu/E8jJEKUdpdILCVCQCdFvHyu/7dLJOHPMfrSwduxO56NkQ==}
196 + engines: {node: '>=20.0.0'}
197 +
198 + '@aws-sdk/middleware-sdk-s3@3.972.76':
199 + resolution: {integrity: sha512-NfnTkVUTBKTBuBgqaapFK9r3YdkKt1b2oRvgLzZq91bwNKh6ZS0S7sEcheguttREaL4iyfs/xQnqD7Z7AsWSsA==}
200 + engines: {node: '>=20.0.0'}
201 +
202 + '@aws-sdk/nested-clients@3.997.45':
203 + resolution: {integrity: sha512-mooq9Q+jLa18VoM7HouczmslZU60iiB0aKc/Ztnq/luIL1ud0z4DnYprLR/ZO1gp331S9tJctM1HZr7u6YKBXQ==}
204 + engines: {node: '>=20.0.0'}
205 +
206 + '@aws-sdk/signature-v4-multi-region@3.996.46':
207 + resolution: {integrity: sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==}
208 + engines: {node: '>=20.0.0'}
209 +
210 + '@aws-sdk/token-providers@3.1129.0':
211 + resolution: {integrity: sha512-Sbl3rpzQdsG4ZK2zh0JWUYyZPKKorJlVOddA2T0DVbKJFrsW8J6wgnslxxUH04+WaBMr4A1HzJZvZX0xUvkniA==}
212 + engines: {node: '>=20.0.0'}
213 +
214 + '@aws-sdk/types@3.974.5':
215 + resolution: {integrity: sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==}
216 + engines: {node: '>=20.0.0'}
217 +
218 + '@aws-sdk/xml-builder@3.972.40':
219 + resolution: {integrity: sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==}
220 + engines: {node: '>=20.0.0'}
221 +
222 + '@aws/lambda-invoke-store@0.3.0':
223 + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==}
224 + engines: {node: '>=18.0.0'}
225 +
104 226 '@clickhouse/client@1.23.1':
105 227 resolution: {integrity: sha512-vs3/Zc1dHvT171btW5nMoPsPCJ6QVJ5pp7obxzO5sjqwFx/jjz9wwCAqcFOdc2DhprugDBaVn+4dVY8hG3A9nw==}
106 228 engines: {node: '>=20'}
@@ -560,9 +682,42 @@ packages:
560 682 cpu: [x64]
561 683 os: [win32]
562 684
685 + '@ioredis/commands@1.10.0':
686 + resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==}
687 +
563 688 '@jridgewell/sourcemap-codec@1.6.0':
564 689 resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
565 690
691 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4':
692 + resolution: {integrity: sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==}
693 + cpu: [arm64]
694 + os: [darwin]
695 +
696 + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4':
697 + resolution: {integrity: sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==}
698 + cpu: [x64]
699 + os: [darwin]
700 +
701 + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4':
702 + resolution: {integrity: sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==}
703 + cpu: [arm64]
704 + os: [linux]
705 +
706 + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4':
707 + resolution: {integrity: sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==}
708 + cpu: [arm]
709 + os: [linux]
710 +
711 + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4':
712 + resolution: {integrity: sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==}
713 + cpu: [x64]
714 + os: [linux]
715 +
716 + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4':
717 + resolution: {integrity: sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==}
718 + cpu: [x64]
719 + os: [win32]
720 +
566 721 '@napi-rs/lzma-linux-x64-gnu@1.5.1':
567 722 resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==}
568 723 engines: {node: ^22.20 || ^24.12 || >=25}
@@ -711,6 +866,30 @@ packages:
711 866 cpu: [x64]
712 867 os: [win32]
713 868
869 + '@smithy/core@3.33.3':
870 + resolution: {integrity: sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg==}
871 + engines: {node: '>=18.0.0'}
872 +
873 + '@smithy/credential-provider-imds@4.5.2':
874 + resolution: {integrity: sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==}
875 + engines: {node: '>=18.0.0'}
876 +
877 + '@smithy/fetch-http-handler@5.8.0':
878 + resolution: {integrity: sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==}
879 + engines: {node: '>=18.0.0'}
880 +
881 + '@smithy/node-http-handler@4.12.1':
882 + resolution: {integrity: sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==}
883 + engines: {node: '>=18.0.0'}
884 +
885 + '@smithy/signature-v4@5.7.3':
886 + resolution: {integrity: sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==}
887 + engines: {node: '>=18.0.0'}
888 +
889 + '@smithy/types@4.18.0':
890 + resolution: {integrity: sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==}
891 + engines: {node: '>=18.0.0'}
892 +
714 893 '@types/chai@5.2.3':
715 894 resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
716 895
@@ -762,9 +941,21 @@ packages:
762 941 boolbase@1.0.0:
763 942 resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
764 943
944 + bowser@2.14.1:
945 + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==}
946 +
765 947 buffer-from@1.1.2:
766 948 resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
767 949
950 + bullmq@5.81.4:
951 + resolution: {integrity: sha512-n+WHSzz20KooBGoJyASre6oJNz/p5f1IJRRN2ibD+NWPQaNpNQmDrwYuPO+bsXrQeM1MQzUxXGbdjmyOFKP2xQ==}
952 + engines: {node: '>=12.22.0'}
953 + peerDependencies:
954 + redis: '>=5.0.0'
955 + peerDependenciesMeta:
956 + redis:
957 + optional: true
958 +
768 959 cac@6.7.14:
769 960 resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
770 961 engines: {node: '>=8'}
@@ -784,6 +975,15 @@ packages:
784 975 resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==}
785 976 engines: {node: '>=20.18.1'}
786 977
978 + cluster-key-slot@1.1.1:
979 + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==}
980 + engines: {node: '>=0.10.0'}
981 +
982 + cron-parser@4.9.0:
983 + resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
984 + engines: {node: '>=12.0.0'}
985 + deprecated: v4 is no longer maintained, upgrade to v5
986 +
787 987 css-select@5.2.2:
788 988 resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
789 989
@@ -804,6 +1004,14 @@ packages:
804 1004 resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
805 1005 engines: {node: '>=6'}
806 1006
1007 + denque@2.1.0:
1008 + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
1009 + engines: {node: '>=0.10'}
1010 +
1011 + detect-libc@2.1.2:
1012 + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
1013 + engines: {node: '>=8'}
1014 +
807 1015 dom-serializer@2.0.0:
808 1016 resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
809 1017
@@ -984,6 +1192,10 @@ packages:
984 1192 resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
985 1193 engines: {node: '>=0.10.0'}
986 1194
1195 + ioredis@5.11.1:
1196 + resolution: {integrity: sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==}
1197 + engines: {node: '>=12.22.0'}
1198 +
987 1199 is-unsafe@2.0.2:
988 1200 resolution: {integrity: sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==}
989 1201
@@ -993,17 +1205,35 @@ packages:
993 1205 loupe@3.2.1:
994 1206 resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
995 1207
1208 + luxon@3.7.2:
1209 + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==}
1210 + engines: {node: '>=12'}
1211 +
996 1212 magic-string@0.30.21:
997 1213 resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
998 1214
999 1215 ms@2.1.3:
1000 1216 resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1001 1217
1218 + msgpackr-extract@3.0.4:
1219 + resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==}
1220 + hasBin: true
1221 +
1222 + msgpackr@2.0.5:
1223 + resolution: {integrity: sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA==}
1224 +
1002 1225 nanoid@3.3.18:
1003 1226 resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==}
1004 1227 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1005 1228 hasBin: true
1006 1229
1230 + node-abort-controller@3.1.1:
1231 + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
1232 +
1233 + node-gyp-build-optional-packages@5.2.2:
1234 + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
1235 + hasBin: true
1236 +
1007 1237 nth-check@2.1.1:
1008 1238 resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
1009 1239
@@ -1042,6 +1272,14 @@ packages:
1042 1272 resolution: {integrity: sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==}
1043 1273 engines: {node: '>=12'}
1044 1274
1275 + redis-errors@1.2.0:
1276 + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
1277 + engines: {node: '>=4'}
1278 +
1279 + redis-parser@3.0.0:
1280 + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
1281 + engines: {node: '>=4'}
1282 +
1045 1283 resolve-pkg-maps@1.0.0:
1046 1284 resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
1047 1285
@@ -1053,6 +1291,11 @@ packages:
1053 1291 safer-buffer@2.1.2:
1054 1292 resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
1055 1293
1294 + semver@7.8.5:
1295 + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
1296 + engines: {node: '>=10'}
1297 + hasBin: true
1298 +
1056 1299 siginfo@2.0.0:
1057 1300 resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
1058 1301
@@ -1070,6 +1313,9 @@ packages:
1070 1313 stackback@0.0.2:
1071 1314 resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
1072 1315
1316 + standard-as-callback@2.1.0:
1317 + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
1318 +
1073 1319 std-env@3.10.0:
1074 1320 resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
1075 1321
@@ -1101,6 +1347,9 @@ packages:
1101 1347 resolution: {integrity: sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==}
1102 1348 engines: {node: '>=14.0.0'}
1103 1349
1350 + tslib@2.8.1:
1351 + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1352 +
1104 1353 tsx@4.23.13:
1105 1354 resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==}
1106 1355 engines: {node: '>=18.0.0'}
@@ -1228,6 +1477,171 @@ packages:
1228 1477
1229 1478 snapshots:
1230 1479
1480 + '@aws-sdk/checksums@3.1001.0':
1481 + dependencies:
1482 + '@aws-sdk/core': 3.978.0
1483 + '@aws-sdk/types': 3.974.5
1484 + '@smithy/core': 3.33.3
1485 + '@smithy/types': 4.18.0
1486 + tslib: 2.8.1
1487 +
1488 + '@aws-sdk/client-s3@3.1129.0':
1489 + dependencies:
1490 + '@aws-sdk/checksums': 3.1001.0
1491 + '@aws-sdk/core': 3.978.0
1492 + '@aws-sdk/credential-provider-node': 3.972.83
1493 + '@aws-sdk/middleware-sdk-s3': 3.972.76
1494 + '@aws-sdk/signature-v4-multi-region': 3.996.46
1495 + '@aws-sdk/types': 3.974.5
1496 + '@smithy/core': 3.33.3
1497 + '@smithy/fetch-http-handler': 5.8.0
1498 + '@smithy/node-http-handler': 4.12.1
1499 + '@smithy/types': 4.18.0
1500 + tslib: 2.8.1
1501 +
1502 + '@aws-sdk/core@3.978.0':
1503 + dependencies:
1504 + '@aws-sdk/types': 3.974.5
1505 + '@aws-sdk/xml-builder': 3.972.40
1506 + '@aws/lambda-invoke-store': 0.3.0
1507 + '@smithy/core': 3.33.3
1508 + '@smithy/signature-v4': 5.7.3
1509 + '@smithy/types': 4.18.0
1510 + bowser: 2.14.1
1511 + tslib: 2.8.1
1512 +
1513 + '@aws-sdk/credential-provider-env@3.972.71':
1514 + dependencies:
1515 + '@aws-sdk/core': 3.978.0
1516 + '@aws-sdk/types': 3.974.5
1517 + '@smithy/core': 3.33.3
1518 + '@smithy/types': 4.18.0
1519 + tslib: 2.8.1
1520 +
1521 + '@aws-sdk/credential-provider-http@3.972.73':
1522 + dependencies:
1523 + '@aws-sdk/core': 3.978.0
1524 + '@aws-sdk/types': 3.974.5
1525 + '@smithy/core': 3.33.3
1526 + '@smithy/fetch-http-handler': 5.8.0
1527 + '@smithy/node-http-handler': 4.12.1
1528 + '@smithy/types': 4.18.0
1529 + tslib: 2.8.1
1530 +
1531 + '@aws-sdk/credential-provider-ini@3.973.16':
1532 + dependencies:
1533 + '@aws-sdk/core': 3.978.0
1534 + '@aws-sdk/credential-provider-env': 3.972.71
1535 + '@aws-sdk/credential-provider-http': 3.972.73
1536 + '@aws-sdk/credential-provider-login': 3.972.78
1537 + '@aws-sdk/credential-provider-process': 3.972.71
1538 + '@aws-sdk/credential-provider-sso': 3.973.15
1539 + '@aws-sdk/credential-provider-web-identity': 3.972.77
1540 + '@aws-sdk/nested-clients': 3.997.45
1541 + '@aws-sdk/types': 3.974.5
1542 + '@smithy/core': 3.33.3
1543 + '@smithy/credential-provider-imds': 4.5.2
1544 + '@smithy/types': 4.18.0
1545 + tslib: 2.8.1
1546 +
1547 + '@aws-sdk/credential-provider-login@3.972.78':
1548 + dependencies:
1549 + '@aws-sdk/core': 3.978.0
1550 + '@aws-sdk/nested-clients': 3.997.45
1551 + '@aws-sdk/types': 3.974.5
1552 + '@smithy/core': 3.33.3
1553 + '@smithy/types': 4.18.0
1554 + tslib: 2.8.1
1555 +
1556 + '@aws-sdk/credential-provider-node@3.972.83':
1557 + dependencies:
1558 + '@aws-sdk/credential-provider-env': 3.972.71
1559 + '@aws-sdk/credential-provider-http': 3.972.73
1560 + '@aws-sdk/credential-provider-ini': 3.973.16
1561 + '@aws-sdk/credential-provider-process': 3.972.71
1562 + '@aws-sdk/credential-provider-sso': 3.973.15
1563 + '@aws-sdk/credential-provider-web-identity': 3.972.77
1564 + '@aws-sdk/types': 3.974.5
1565 + '@smithy/core': 3.33.3
1566 + '@smithy/credential-provider-imds': 4.5.2
1567 + '@smithy/types': 4.18.0
1568 + tslib: 2.8.1
1569 +
1570 + '@aws-sdk/credential-provider-process@3.972.71':
1571 + dependencies:
1572 + '@aws-sdk/core': 3.978.0
1573 + '@aws-sdk/types': 3.974.5
1574 + '@smithy/core': 3.33.3
1575 + '@smithy/types': 4.18.0
1576 + tslib: 2.8.1
1577 +
1578 + '@aws-sdk/credential-provider-sso@3.973.15':
1579 + dependencies:
1580 + '@aws-sdk/core': 3.978.0
1581 + '@aws-sdk/nested-clients': 3.997.45
1582 + '@aws-sdk/token-providers': 3.1129.0
1583 + '@aws-sdk/types': 3.974.5
1584 + '@smithy/core': 3.33.3
1585 + '@smithy/types': 4.18.0
1586 + tslib: 2.8.1
1587 +
1588 + '@aws-sdk/credential-provider-web-identity@3.972.77':
1589 + dependencies:
1590 + '@aws-sdk/core': 3.978.0
1591 + '@aws-sdk/nested-clients': 3.997.45
1592 + '@aws-sdk/types': 3.974.5
1593 + '@smithy/core': 3.33.3
1594 + '@smithy/types': 4.18.0
1595 + tslib: 2.8.1
1596 +
1597 + '@aws-sdk/middleware-sdk-s3@3.972.76':
1598 + dependencies:
1599 + '@aws-sdk/core': 3.978.0
1600 + '@aws-sdk/signature-v4-multi-region': 3.996.46
1601 + '@aws-sdk/types': 3.974.5
1602 + '@smithy/core': 3.33.3
1603 + '@smithy/types': 4.18.0
1604 + tslib: 2.8.1
1605 +
1606 + '@aws-sdk/nested-clients@3.997.45':
1607 + dependencies:
1608 + '@aws-sdk/core': 3.978.0
1609 + '@aws-sdk/signature-v4-multi-region': 3.996.46
1610 + '@aws-sdk/types': 3.974.5
1611 + '@smithy/core': 3.33.3
1612 + '@smithy/fetch-http-handler': 5.8.0
1613 + '@smithy/node-http-handler': 4.12.1
1614 + '@smithy/types': 4.18.0
1615 + tslib: 2.8.1
1616 +
1617 + '@aws-sdk/signature-v4-multi-region@3.996.46':
1618 + dependencies:
1619 + '@aws-sdk/types': 3.974.5
1620 + '@smithy/signature-v4': 5.7.3
1621 + '@smithy/types': 4.18.0
1622 + tslib: 2.8.1
1623 +
1624 + '@aws-sdk/token-providers@3.1129.0':
1625 + dependencies:
1626 + '@aws-sdk/core': 3.978.0
1627 + '@aws-sdk/nested-clients': 3.997.45
1628 + '@aws-sdk/types': 3.974.5
1629 + '@smithy/core': 3.33.3
1630 + '@smithy/types': 4.18.0
1631 + tslib: 2.8.1
1632 +
1633 + '@aws-sdk/types@3.974.5':
1634 + dependencies:
1635 + '@smithy/types': 4.18.0
1636 + tslib: 2.8.1
1637 +
1638 + '@aws-sdk/xml-builder@3.972.40':
1639 + dependencies:
1640 + '@smithy/types': 4.18.0
1641 + tslib: 2.8.1
1642 +
1643 + '@aws/lambda-invoke-store@0.3.0': {}
1644 +
1231 1645 '@clickhouse/client@1.23.1': {}
1232 1646
1233 1647 '@drizzle-team/brocli@0.10.2': {}
@@ -1464,8 +1878,28 @@ snapshots:
1464 1878 '@esbuild/win32-x64@0.28.2':
1465 1879 optional: true
1466 1880
1881 + '@ioredis/commands@1.10.0': {}
1882 +
1467 1883 '@jridgewell/sourcemap-codec@1.6.0': {}
1468 1884
1885 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4':
1886 + optional: true
1887 +
1888 + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4':
1889 + optional: true
1890 +
1891 + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4':
1892 + optional: true
1893 +
1894 + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4':
1895 + optional: true
1896 +
1897 + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4':
1898 + optional: true
1899 +
1900 + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4':
1901 + optional: true
1902 +
1469 1903 '@napi-rs/lzma-linux-x64-gnu@1.5.1':
1470 1904 optional: true
1471 1905
@@ -1546,6 +1980,39 @@ snapshots:
1546 1980 '@rollup/rollup-win32-x64-msvc@4.63.1':
1547 1981 optional: true
1548 1982
1983 + '@smithy/core@3.33.3':
1984 + dependencies:
1985 + '@smithy/types': 4.18.0
1986 + tslib: 2.8.1
1987 +
1988 + '@smithy/credential-provider-imds@4.5.2':
1989 + dependencies:
1990 + '@smithy/core': 3.33.3
1991 + '@smithy/types': 4.18.0
1992 + tslib: 2.8.1
1993 +
1994 + '@smithy/fetch-http-handler@5.8.0':
1995 + dependencies:
1996 + '@smithy/core': 3.33.3
1997 + '@smithy/types': 4.18.0
1998 + tslib: 2.8.1
1999 +
2000 + '@smithy/node-http-handler@4.12.1':
2001 + dependencies:
2002 + '@smithy/core': 3.33.3
2003 + '@smithy/types': 4.18.0
2004 + tslib: 2.8.1
2005 +
2006 + '@smithy/signature-v4@5.7.3':
2007 + dependencies:
2008 + '@smithy/core': 3.33.3
2009 + '@smithy/types': 4.18.0
2010 + tslib: 2.8.1
2011 +
2012 + '@smithy/types@4.18.0':
2013 + dependencies:
2014 + tslib: 2.8.1
2015 +
1549 2016 '@types/chai@5.2.3':
1550 2017 dependencies:
1551 2018 '@types/deep-eql': 4.0.2
@@ -1607,8 +2074,21 @@ snapshots:
1607 2074
1608 2075 boolbase@1.0.0: {}
1609 2076
2077 + bowser@2.14.1: {}
2078 +
1610 2079 buffer-from@1.1.2: {}
1611 2080
2081 + bullmq@5.81.4:
2082 + dependencies:
2083 + cron-parser: 4.9.0
2084 + ioredis: 5.11.1
2085 + msgpackr: 2.0.5
2086 + node-abort-controller: 3.1.1
2087 + semver: 7.8.5
2088 + tslib: 2.8.1
2089 + transitivePeerDependencies:
2090 + - supports-color
2091 +
1612 2092 cac@6.7.14: {}
1613 2093
1614 2094 chai@5.3.3:
@@ -1644,6 +2124,12 @@ snapshots:
1644 2124 undici: 7.29.1
1645 2125 whatwg-mimetype: 4.0.0
1646 2126
2127 + cluster-key-slot@1.1.1: {}
2128 +
2129 + cron-parser@4.9.0:
2130 + dependencies:
2131 + luxon: 3.7.2
2132 +
1647 2133 css-select@5.2.2:
1648 2134 dependencies:
1649 2135 boolbase: 1.0.0
@@ -1660,6 +2146,11 @@ snapshots:
1660 2146
1661 2147 deep-eql@5.0.2: {}
1662 2148
2149 + denque@2.1.0: {}
2150 +
2151 + detect-libc@2.1.2:
2152 + optional: true
2153 +
1663 2154 dom-serializer@2.0.0:
1664 2155 dependencies:
1665 2156 domelementtype: 2.3.0
@@ -1827,20 +2318,57 @@ snapshots:
1827 2318 dependencies:
1828 2319 safer-buffer: 2.1.2
1829 2320
2321 + ioredis@5.11.1:
2322 + dependencies:
2323 + '@ioredis/commands': 1.10.0
2324 + cluster-key-slot: 1.1.1
2325 + debug: 4.4.3
2326 + denque: 2.1.0
2327 + redis-errors: 1.2.0
2328 + redis-parser: 3.0.0
2329 + standard-as-callback: 2.1.0
2330 + transitivePeerDependencies:
2331 + - supports-color
2332 +
1830 2333 is-unsafe@2.0.2: {}
1831 2334
1832 2335 js-tokens@9.0.1: {}
1833 2336
1834 2337 loupe@3.2.1: {}
1835 2338
2339 + luxon@3.7.2: {}
2340 +
1836 2341 magic-string@0.30.21:
1837 2342 dependencies:
1838 2343 '@jridgewell/sourcemap-codec': 1.6.0
1839 2344
1840 2345 ms@2.1.3: {}
1841 2346
2347 + msgpackr-extract@3.0.4:
2348 + dependencies:
2349 + node-gyp-build-optional-packages: 5.2.2
2350 + optionalDependencies:
2351 + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.4
2352 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.4
2353 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.4
2354 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.4
2355 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.4
2356 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4
2357 + optional: true
2358 +
2359 + msgpackr@2.0.5:
2360 + optionalDependencies:
2361 + msgpackr-extract: 3.0.4
2362 +
1842 2363 nanoid@3.3.18: {}
1843 2364
2365 + node-abort-controller@3.1.1: {}
2366 +
2367 + node-gyp-build-optional-packages@5.2.2:
2368 + dependencies:
2369 + detect-libc: 2.1.2
2370 + optional: true
2371 +
1844 2372 nth-check@2.1.1:
1845 2373 dependencies:
1846 2374 boolbase: 1.0.0
@@ -1876,6 +2404,12 @@ snapshots:
1876 2404
1877 2405 postgres@3.4.9: {}
1878 2406
2407 + redis-errors@1.2.0: {}
2408 +
2409 + redis-parser@3.0.0:
2410 + dependencies:
2411 + redis-errors: 1.2.0
2412 +
1879 2413 resolve-pkg-maps@1.0.0: {}
1880 2414
1881 2415 rollup@4.63.1:
@@ -1912,6 +2446,8 @@ snapshots:
1912 2446
1913 2447 safer-buffer@2.1.2: {}
1914 2448
2449 + semver@7.8.5: {}
2450 +
1915 2451 siginfo@2.0.0: {}
1916 2452
1917 2453 source-map-js@1.2.1: {}
@@ -1925,6 +2461,8 @@ snapshots:
1925 2461
1926 2462 stackback@0.0.2: {}
1927 2463
2464 + standard-as-callback@2.1.0: {}
2465 +
1928 2466 std-env@3.10.0: {}
1929 2467
1930 2468 strip-literal@3.1.0:
@@ -1950,6 +2488,8 @@ snapshots:
1950 2488
1951 2489 tinyspy@4.0.6: {}
1952 2490
2491 + tslib@2.8.1: {}
2492 +
1953 2493 tsx@4.23.13:
1954 2494 dependencies:
1955 2495 esbuild: 0.28.2
added scripts/try-connector.ts +63 −0
@@ -0,0 +1,63 @@
1 +/**
2 + * Dry-run a connector against LIVE sources without persisting anything.
3 + * pnpm tsx scripts/try-connector.ts config/connectors/<id>.yaml [--limit 5] [--url <single url>] [--verbose] [--json out.json]
4 + * Registers every apps/worker/src/connectors/<group>/index.ts (export function register()) found on disk.
5 + */
6 +import { readFileSync, readdirSync, existsSync } from "node:fs";
7 +import { join, resolve } from "node:path";
8 +import { parseConnectorConfig, GenericConnector, getImplementation, createTestContext, type Connector, type DiscoveredUrl } from "@dci/connectors";
9 +
10 +const args = process.argv.slice(2);
11 +const file = args.find((a) => !a.startsWith("--"));
12 +if (!file) { console.error("usage: try-connector.ts <config.yaml> [--limit N] [--url U] [--verbose] [--json out]"); process.exit(2); }
13 +const opt = (k: string) => { const i = args.indexOf(`--${k}`); return i >= 0 ? args[i + 1] : undefined; };
14 +const limit = Number(opt("limit") ?? 5);
15 +const only = opt("url");
16 +const verbose = args.includes("--verbose");
17 +const jsonOut = opt("json");
18 +
19 +async function registerAll() {
20 + const dir = resolve("apps/worker/src/connectors");
21 + if (!existsSync(dir)) return;
22 + for (const g of readdirSync(dir, { withFileTypes: true })) {
23 + if (!g.isDirectory()) continue;
24 + const idx = join(dir, g.name, "index.ts");
25 + if (!existsSync(idx)) continue;
26 + const mod = (await import(idx)) as { register?: () => void };
27 + mod.register?.();
28 + }
29 +}
30 +
31 +async function main() {
32 + await registerAll();
33 + const cfg = parseConnectorConfig(readFileSync(file!, "utf8"), file);
34 + const impl = cfg.implementation ? getImplementation(cfg.implementation) : undefined;
35 + if (cfg.implementation && !impl) throw new Error(`implementation "${cfg.implementation}" not registered`);
36 + const connector: Connector = impl ? impl(cfg) : new GenericConnector(cfg);
37 + const ctx = createTestContext(cfg, { verbose });
38 + const t0 = Date.now();
39 + let urls: DiscoveredUrl[] = only ? [{ url: only, group: "manual", priority: 100 }] : await connector.discover(ctx);
40 + console.error(`discovered ${urls.length} urls in ${Date.now() - t0}ms`);
41 + const groups = new Map<string, number>();
42 + for (const u of urls) groups.set(u.group, (groups.get(u.group) ?? 0) + 1);
43 + console.error(`groups: ${[...groups.entries()].map(([g, n]) => `${g}=${n}`).join(", ")}`);
44 + urls = urls.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0)).slice(0, limit);
45 + const all: unknown[] = [];
46 + let totalValid = 0, totalRejected = 0;
47 + for (const u of urls) {
48 + const doc = await connector.fetch(ctx, u);
49 + if (doc.error) { console.error(`✗ ${u.url} → ${doc.error.code}: ${doc.error.message}`); continue; }
50 + const recs = await connector.extract(ctx, doc);
51 + const ents = await connector.normalize(ctx, recs);
52 + const report = await connector.validate(ctx, ents);
53 + totalValid += report.valid; totalRejected += report.rejected;
54 + console.error(`✓ ${u.url} [${doc.fetcher} L${doc.level} ${doc.status} ${doc.durationMs}ms] → ${recs.length} records, ${ents.length} entities, ${report.valid} valid, ${report.rejected} rejected${(doc.meta?.pageType as string | undefined) ? " · " + doc.meta!.pageType : ""}`);
55 + for (const i of report.issues) console.error(` ${i.level === "error" ? "ERR " : "warn"} ${i.key} ${i.field ?? ""}: ${i.message}`);
56 + for (const e of ents.slice(0, 3)) console.log(JSON.stringify(e, null, verbose ? 1 : 0).slice(0, verbose ? 4000 : 700));
57 + all.push(...ents);
58 + }
59 + console.error(`\nTOTAL entities=${all.length} valid=${totalValid} rejected=${totalRejected} credits=${ctx.credits} fetched=${ctx.fetched.length}`);
60 + if (jsonOut) { const { writeFileSync } = await import("node:fs"); writeFileSync(jsonOut, JSON.stringify(all, null, 1)); console.error(`wrote ${jsonOut}`); }
61 + process.exit(totalRejected > 0 && totalValid === 0 ? 1 : 0);
62 +}
63 +main().catch((e) => { console.error(e); process.exit(1); });
64