@yumiai/chat-widget 0.2.0 → 0.2.2
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/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/dist/ExcelCore-EAXQMKZT.js +10 -0
- package/dist/{ExcelViewer-3YLLYYIQ.js → ExcelViewer-OGWM52ZT.js} +2 -3
- package/dist/{ExcelViewer-3YLLYYIQ.js.map → ExcelViewer-OGWM52ZT.js.map} +1 -1
- package/dist/{GerberViewerA2UI-X5FWAD5M.js → GerberViewerA2UI-AORHOCF6.js} +2 -3
- package/dist/{GerberViewerA2UI-X5FWAD5M.js.map → GerberViewerA2UI-AORHOCF6.js.map} +1 -1
- package/dist/{GraphStatsLegend-D5bPeXB_.d.cts → GraphStatsLegend-CV0Y3-cP.d.cts} +39 -0
- package/dist/{GraphStatsLegend-D5bPeXB_.d.ts → GraphStatsLegend-CV0Y3-cP.d.ts} +39 -0
- package/dist/JsonRenderStandalone-L5ROJ6XP.js +17 -0
- package/dist/{KicadViewer-GV6ZC4AQ.js → KicadViewer-H6YY6WVC.js} +3 -4
- package/dist/{KicadViewer-GV6ZC4AQ.js.map → KicadViewer-H6YY6WVC.js.map} +1 -1
- package/dist/KicadViewerCore-XVJE2FTQ.js +10 -0
- package/dist/{PdfViewer-CHPDRK46.js → PdfViewer-GKVDDNCZ.js} +9 -10
- package/dist/{PdfViewer-CHPDRK46.js.map → PdfViewer-GKVDDNCZ.js.map} +1 -1
- package/dist/{PdfViewerCore-HJPEHSRA.js → PdfViewerCore-SUVXHXYO.js} +24 -11
- package/dist/PdfViewerCore-SUVXHXYO.js.map +1 -0
- package/dist/PowerPointCore-IZ4G6HEQ.js +10 -0
- package/dist/{PowerPointViewer-LQTO6UCU.js → PowerPointViewer-5R2KSWWJ.js} +2 -3
- package/dist/{PowerPointViewer-LQTO6UCU.js.map → PowerPointViewer-5R2KSWWJ.js.map} +1 -1
- package/dist/{StepViewerCore-7W3L3R4E.js → StepViewerCore-RORWXIRU.js} +2 -3
- package/dist/{StepViewerCore-7W3L3R4E.js.map → StepViewerCore-RORWXIRU.js.map} +1 -1
- package/dist/{ThreeViewerCore-N3QJD5QI.js → ThreeViewerCore-GTUZKD5V.js} +2 -3
- package/dist/{ThreeViewerCore-N3QJD5QI.js.map → ThreeViewerCore-GTUZKD5V.js.map} +1 -1
- package/dist/WordCore-QFG5HTYD.js +10 -0
- package/dist/{WordViewer-ZHCQMHOH.js → WordViewer-7XUQFS4A.js} +2 -3
- package/dist/{WordViewer-ZHCQMHOH.js.map → WordViewer-7XUQFS4A.js.map} +1 -1
- package/dist/{chunk-QLVPIM6R.js → chunk-3CNQONCV.js} +79 -1
- package/dist/chunk-3CNQONCV.js.map +1 -0
- package/dist/{chunk-2UC7YLVX.js → chunk-3LOSHCSH.js} +3 -3
- package/dist/chunk-5VUKEGFC.js +108 -0
- package/dist/chunk-5VUKEGFC.js.map +1 -0
- package/dist/chunk-AO4YUJQT.js +479 -0
- package/dist/chunk-AO4YUJQT.js.map +1 -0
- package/dist/{chunk-KQV7IKET.js → chunk-ASV4TISB.js} +2 -2
- package/dist/{chunk-CFKGNAJM.js → chunk-AT6VLLOO.js} +15 -15
- package/dist/{chunk-56WRZM3R.js → chunk-EYWNUJVZ.js} +3 -3
- package/dist/{chunk-K4KGNVL5.js → chunk-EZ46FGQ6.js} +3 -3
- package/dist/{chunk-GYXTSY22.js → chunk-KXPR6SRW.js} +4 -4
- package/dist/{chunk-7S67DOHQ.js → chunk-MTN6SUUQ.js} +2 -2
- package/dist/chunk-Q5PLT3AI.js +29 -0
- package/dist/chunk-Q5PLT3AI.js.map +1 -0
- package/dist/{chunk-PZXSASDY.js → chunk-R5LHMOAC.js} +3 -3
- package/dist/chunk-X67V7257.js +238 -0
- package/dist/chunk-X67V7257.js.map +1 -0
- package/dist/citationContext-CILHTO2Z.js +25 -0
- package/dist/components/JsonRender/standalone.cjs +56 -9753
- package/dist/components/JsonRender/standalone.cjs.map +1 -1
- package/dist/components/JsonRender/standalone.js +10 -11
- package/dist/components/JsonRender/standalone.js.map +1 -1
- package/dist/{gerber-2d-entry-OQ4SQRBY.js → gerber-2d-entry-HEFXQGBK.js} +5 -9
- package/dist/{gerber-2d-entry-OQ4SQRBY.js.map → gerber-2d-entry-HEFXQGBK.js.map} +1 -1
- package/dist/{gerber-3d-entry-DEHDBOO2.js → gerber-3d-entry-KVTONA37.js} +5 -9
- package/dist/{gerber-3d-entry-DEHDBOO2.js.map → gerber-3d-entry-KVTONA37.js.map} +1 -1
- package/dist/{gerber-simulation-entry-EBDX72XE.js → gerber-simulation-entry-GZ62QX5H.js} +5 -9
- package/dist/{gerber-simulation-entry-EBDX72XE.js.map → gerber-simulation-entry-GZ62QX5H.js.map} +1 -1
- package/dist/index.cjs +6690 -13472
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +776 -4
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +979 -26
- package/dist/index.d.ts +979 -26
- package/dist/index.js +4350 -1859
- package/dist/index.js.map +1 -1
- package/dist/provenance/index.cjs +78 -0
- package/dist/provenance/index.cjs.map +1 -1
- package/dist/provenance/index.d.cts +2 -2
- package/dist/provenance/index.d.ts +2 -2
- package/dist/provenance/index.js +2 -3
- package/dist/{resolveToArrayBuffer-AQIDZHSQ.js → resolveToArrayBuffer-PVSVIAII.js} +1 -3
- package/dist/{resolveToArrayBuffer-AQIDZHSQ.js.map → resolveToArrayBuffer-PVSVIAII.js.map} +1 -1
- package/dist/sseAdapter-LFXYGYC4.js +8 -0
- package/dist/sseAdapter-LFXYGYC4.js.map +1 -0
- package/package.json +4 -1
- package/dist/ExcelCore-DJOIVQMI.js +0 -11
- package/dist/JsonRenderStandalone-EIZM62JU.js +0 -18
- package/dist/KicadViewerCore-U7BWZHKJ.js +0 -11
- package/dist/PdfViewerCore-HJPEHSRA.js.map +0 -1
- package/dist/PowerPointCore-FPDR2BL4.js +0 -11
- package/dist/WordCore-JKSXK2XD.js +0 -11
- package/dist/chunk-7A4FY6FK.js +0 -10226
- package/dist/chunk-7A4FY6FK.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-QLVPIM6R.js.map +0 -1
- package/dist/chunk-VXJWGLZ7.js +0 -21
- package/dist/chunk-VXJWGLZ7.js.map +0 -1
- /package/dist/{ExcelCore-DJOIVQMI.js.map → ExcelCore-EAXQMKZT.js.map} +0 -0
- /package/dist/{JsonRenderStandalone-EIZM62JU.js.map → JsonRenderStandalone-L5ROJ6XP.js.map} +0 -0
- /package/dist/{KicadViewerCore-U7BWZHKJ.js.map → KicadViewerCore-XVJE2FTQ.js.map} +0 -0
- /package/dist/{PowerPointCore-FPDR2BL4.js.map → PowerPointCore-IZ4G6HEQ.js.map} +0 -0
- /package/dist/{WordCore-JKSXK2XD.js.map → WordCore-QFG5HTYD.js.map} +0 -0
- /package/dist/{chunk-2UC7YLVX.js.map → chunk-3LOSHCSH.js.map} +0 -0
- /package/dist/{chunk-KQV7IKET.js.map → chunk-ASV4TISB.js.map} +0 -0
- /package/dist/{chunk-CFKGNAJM.js.map → chunk-AT6VLLOO.js.map} +0 -0
- /package/dist/{chunk-56WRZM3R.js.map → chunk-EYWNUJVZ.js.map} +0 -0
- /package/dist/{chunk-K4KGNVL5.js.map → chunk-EZ46FGQ6.js.map} +0 -0
- /package/dist/{chunk-GYXTSY22.js.map → chunk-KXPR6SRW.js.map} +0 -0
- /package/dist/{chunk-7S67DOHQ.js.map → chunk-MTN6SUUQ.js.map} +0 -0
- /package/dist/{chunk-PZXSASDY.js.map → chunk-R5LHMOAC.js.map} +0 -0
- /package/dist/{chunk-7D4SUZUM.js.map → citationContext-CILHTO2Z.js.map} +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ingestCitationContext
|
|
3
|
+
} from "./chunk-X67V7257.js";
|
|
4
|
+
|
|
5
|
+
// src/provenance/rag/sseAdapter.ts
|
|
6
|
+
var IS_DEV = typeof import.meta !== "undefined" && Boolean(import.meta.env?.DEV);
|
|
7
|
+
function coerceToObject(input) {
|
|
8
|
+
if (input == null) return null;
|
|
9
|
+
if (typeof input === "string") {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(input);
|
|
12
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (typeof input === "object" && !Array.isArray(input)) {
|
|
18
|
+
return input;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function isString(v) {
|
|
23
|
+
return typeof v === "string";
|
|
24
|
+
}
|
|
25
|
+
function isFiniteNumber(v) {
|
|
26
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
27
|
+
}
|
|
28
|
+
var ALLOWED_FILE_TYPES = /* @__PURE__ */ new Set([
|
|
29
|
+
"markdown",
|
|
30
|
+
"text",
|
|
31
|
+
"code",
|
|
32
|
+
"pdf",
|
|
33
|
+
"word"
|
|
34
|
+
]);
|
|
35
|
+
function validateFile(raw) {
|
|
36
|
+
if (raw == null || typeof raw !== "object") return null;
|
|
37
|
+
const r = raw;
|
|
38
|
+
if (!isString(r.rid) || !r.rid) return null;
|
|
39
|
+
if (!isString(r.rid_short) || !r.rid_short) return null;
|
|
40
|
+
if (!isString(r.git_commit_hash) || !r.git_commit_hash) return null;
|
|
41
|
+
if (!isString(r.file_name) || !r.file_name) return null;
|
|
42
|
+
const file_type = ALLOWED_FILE_TYPES.has(
|
|
43
|
+
r.file_type
|
|
44
|
+
) ? r.file_type : "text";
|
|
45
|
+
if (!isFiniteNumber(r.total_chunks) || r.total_chunks < 0) return null;
|
|
46
|
+
const file_path = isString(r.file_path) ? r.file_path : "";
|
|
47
|
+
return {
|
|
48
|
+
rid: r.rid,
|
|
49
|
+
rid_short: r.rid_short,
|
|
50
|
+
git_commit_hash: r.git_commit_hash,
|
|
51
|
+
file_name: r.file_name,
|
|
52
|
+
file_path,
|
|
53
|
+
file_type,
|
|
54
|
+
total_chunks: r.total_chunks
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function validateFilesArray(obj) {
|
|
58
|
+
const rawFiles = obj.files;
|
|
59
|
+
if (!Array.isArray(rawFiles)) return null;
|
|
60
|
+
const files = [];
|
|
61
|
+
for (const raw of rawFiles) {
|
|
62
|
+
const f = validateFile(raw);
|
|
63
|
+
if (f) files.push(f);
|
|
64
|
+
}
|
|
65
|
+
return files;
|
|
66
|
+
}
|
|
67
|
+
function handleCitationContextNotification(payload) {
|
|
68
|
+
if (IS_DEV) {
|
|
69
|
+
const preview = typeof payload === "string" ? payload.slice(0, 120) : payload && typeof payload === "object" ? Object.keys(payload) : payload;
|
|
70
|
+
console.info("[jetp-084 v3] citation_context received", { preview });
|
|
71
|
+
}
|
|
72
|
+
const obj = coerceToObject(payload);
|
|
73
|
+
if (!obj) {
|
|
74
|
+
if (payload != null) {
|
|
75
|
+
console.warn("[jetp-084 v3] citation_context: unparseable payload", {
|
|
76
|
+
payloadType: typeof payload,
|
|
77
|
+
preview: typeof payload === "string" ? payload.slice(0, 64) : void 0
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if ("message_id" in obj) {
|
|
83
|
+
if (IS_DEV) {
|
|
84
|
+
console.warn(
|
|
85
|
+
"[jetp-084 v3] payload contains legacy `message_id` \u2014 ignored. Backend should emit v3 `{files: [...]}` only."
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const files = validateFilesArray(obj);
|
|
90
|
+
if (files === null) {
|
|
91
|
+
console.warn("[jetp-084 v3] citation_context: `files` missing or not array", {
|
|
92
|
+
keys: Object.keys(obj)
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (IS_DEV) {
|
|
97
|
+
console.info("[jetp-084 v3] citation_context ingested", {
|
|
98
|
+
file_count: files.length,
|
|
99
|
+
rid_shorts: files.map((f) => f.rid_short)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
ingestCitationContext(files);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
handleCitationContextNotification
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=chunk-5VUKEGFC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provenance/rag/sseAdapter.ts"],"sourcesContent":["/**\n * JETP-084 v3 (Phase 10, 2026-05-27) — SSE → citationContext adapter.\n *\n * v3 contract:\n * - Payload is `{\"files\": [...]}`. No `message_id` (the backend emits\n * the event from the *read* tool — decoupled from LLM message IDs).\n * - Each entry in `files` MUST include `rid`, `rid_short`,\n * `git_commit_hash`, `file_name`, `file_path`, `file_type`,\n * `total_chunks`.\n * - SSE handlers MUST NOT throw — a malformed event is logged and\n * dropped silently.\n *\n * v1 (standalone `citation_context` with `message_id`) and v2\n * (NodeNotification.ext embed) payloads are **rejected** with a warning;\n * `handleEmbeddedCitationContext` was deleted.\n *\n * Spec: `chat-widget/05_sidecar_cache.md` §5 (v3 ingest path),\n * `00_shared/01_protocol.md` §4 (v3 notification schema).\n */\n\nimport { ingestCitationContext } from './citationContext'\nimport type { CitationContextFile } from './types'\n\nconst IS_DEV: boolean =\n typeof import.meta !== 'undefined' &&\n Boolean((import.meta as { env?: { DEV?: boolean } }).env?.DEV)\n\ntype CitationContextPayloadInput =\n | string\n | Record<string, unknown>\n | null\n | undefined\n\nfunction coerceToObject(input: CitationContextPayloadInput): Record<string, unknown> | null {\n if (input == null) return null\n if (typeof input === 'string') {\n try {\n const parsed = JSON.parse(input)\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : null\n } catch {\n return null\n }\n }\n if (typeof input === 'object' && !Array.isArray(input)) {\n return input as Record<string, unknown>\n }\n return null\n}\n\nfunction isString(v: unknown): v is string {\n return typeof v === 'string'\n}\n\nfunction isFiniteNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v)\n}\n\nconst ALLOWED_FILE_TYPES: ReadonlySet<CitationContextFile['file_type']> = new Set([\n 'markdown',\n 'text',\n 'code',\n 'pdf',\n 'word',\n])\n\nfunction validateFile(raw: unknown): CitationContextFile | null {\n if (raw == null || typeof raw !== 'object') return null\n const r = raw as Record<string, unknown>\n\n if (!isString(r.rid) || !r.rid) return null\n if (!isString(r.rid_short) || !r.rid_short) return null\n if (!isString(r.git_commit_hash) || !r.git_commit_hash) return null\n if (!isString(r.file_name) || !r.file_name) return null\n\n const file_type: CitationContextFile['file_type'] = ALLOWED_FILE_TYPES.has(\n r.file_type as CitationContextFile['file_type'],\n )\n ? (r.file_type as CitationContextFile['file_type'])\n : 'text'\n\n if (!isFiniteNumber(r.total_chunks) || r.total_chunks < 0) return null\n\n // v3 adds `file_path` to the protocol; tolerate its absence so older\n // backends mid-roll-out don't break — fall back to empty string.\n const file_path = isString(r.file_path) ? r.file_path : ''\n\n return {\n rid: r.rid,\n rid_short: r.rid_short,\n git_commit_hash: r.git_commit_hash,\n file_name: r.file_name,\n file_path,\n file_type,\n total_chunks: r.total_chunks,\n }\n}\n\nfunction validateFilesArray(obj: Record<string, unknown>): CitationContextFile[] | null {\n const rawFiles = obj.files\n if (!Array.isArray(rawFiles)) return null\n const files: CitationContextFile[] = []\n for (const raw of rawFiles) {\n const f = validateFile(raw)\n if (f) files.push(f)\n }\n return files\n}\n\n/**\n * Entry point: feed any raw v3 `citation_context` notification payload.\n *\n * Accepts:\n * - the inner JSON object (from `JsonNotificationContent.content`)\n * - a JSON string (transport-serialized form)\n * - the `SSEMessage.content` field directly\n *\n * Returns `void` so call sites are trivially safe.\n */\nexport function handleCitationContextNotification(\n payload: CitationContextPayloadInput,\n): void {\n if (IS_DEV) {\n const preview =\n typeof payload === 'string'\n ? payload.slice(0, 120)\n : payload && typeof payload === 'object'\n ? Object.keys(payload as Record<string, unknown>)\n : payload\n // eslint-disable-next-line no-console\n console.info('[jetp-084 v3] citation_context received', { preview })\n }\n\n const obj = coerceToObject(payload)\n if (!obj) {\n if (payload != null) {\n // eslint-disable-next-line no-console\n console.warn('[jetp-084 v3] citation_context: unparseable payload', {\n payloadType: typeof payload,\n preview: typeof payload === 'string' ? payload.slice(0, 64) : undefined,\n })\n }\n return\n }\n\n if ('message_id' in obj) {\n // Legacy v1 payload — log and ignore the field. We still ingest the\n // files so a transitional backend doesn't completely break.\n if (IS_DEV) {\n // eslint-disable-next-line no-console\n console.warn(\n '[jetp-084 v3] payload contains legacy `message_id` — ignored. ' +\n 'Backend should emit v3 `{files: [...]}` only.',\n )\n }\n }\n\n const files = validateFilesArray(obj)\n if (files === null) {\n // eslint-disable-next-line no-console\n console.warn('[jetp-084 v3] citation_context: `files` missing or not array', {\n keys: Object.keys(obj),\n })\n return\n }\n\n if (IS_DEV) {\n // eslint-disable-next-line no-console\n console.info('[jetp-084 v3] citation_context ingested', {\n file_count: files.length,\n rid_shorts: files.map(f => f.rid_short),\n })\n }\n ingestCitationContext(files)\n}\n"],"mappings":";;;;;AAuBA,IAAM,SACJ,OAAO,gBAAgB,eACvB,QAAS,YAA4C,KAAK,GAAG;AAQ/D,SAAS,eAAe,OAAoE;AAC1F,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,aAAO,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,IAC/D,SACD;AAAA,IACN,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACtD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,SAAS,GAAyB;AACzC,SAAO,OAAO,MAAM;AACtB;AAEA,SAAS,eAAe,GAAyB;AAC/C,SAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC;AACnD;AAEA,IAAM,qBAAoE,oBAAI,IAAI;AAAA,EAChF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,aAAa,KAA0C;AAC9D,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACnD,QAAM,IAAI;AAEV,MAAI,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,EAAE,IAAK,QAAO;AACvC,MAAI,CAAC,SAAS,EAAE,SAAS,KAAK,CAAC,EAAE,UAAW,QAAO;AACnD,MAAI,CAAC,SAAS,EAAE,eAAe,KAAK,CAAC,EAAE,gBAAiB,QAAO;AAC/D,MAAI,CAAC,SAAS,EAAE,SAAS,KAAK,CAAC,EAAE,UAAW,QAAO;AAEnD,QAAM,YAA8C,mBAAmB;AAAA,IACrE,EAAE;AAAA,EACJ,IACK,EAAE,YACH;AAEJ,MAAI,CAAC,eAAe,EAAE,YAAY,KAAK,EAAE,eAAe,EAAG,QAAO;AAIlE,QAAM,YAAY,SAAS,EAAE,SAAS,IAAI,EAAE,YAAY;AAExD,SAAO;AAAA,IACL,KAAK,EAAE;AAAA,IACP,WAAW,EAAE;AAAA,IACb,iBAAiB,EAAE;AAAA,IACnB,WAAW,EAAE;AAAA,IACb;AAAA,IACA;AAAA,IACA,cAAc,EAAE;AAAA,EAClB;AACF;AAEA,SAAS,mBAAmB,KAA4D;AACtF,QAAM,WAAW,IAAI;AACrB,MAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG,QAAO;AACrC,QAAM,QAA+B,CAAC;AACtC,aAAW,OAAO,UAAU;AAC1B,UAAM,IAAI,aAAa,GAAG;AAC1B,QAAI,EAAG,OAAM,KAAK,CAAC;AAAA,EACrB;AACA,SAAO;AACT;AAYO,SAAS,kCACd,SACM;AACN,MAAI,QAAQ;AACV,UAAM,UACJ,OAAO,YAAY,WACf,QAAQ,MAAM,GAAG,GAAG,IACpB,WAAW,OAAO,YAAY,WAC5B,OAAO,KAAK,OAAkC,IAC9C;AAER,YAAQ,KAAK,2CAA2C,EAAE,QAAQ,CAAC;AAAA,EACrE;AAEA,QAAM,MAAM,eAAe,OAAO;AAClC,MAAI,CAAC,KAAK;AACR,QAAI,WAAW,MAAM;AAEnB,cAAQ,KAAK,uDAAuD;AAAA,QAClE,aAAa,OAAO;AAAA,QACpB,SAAS,OAAO,YAAY,WAAW,QAAQ,MAAM,GAAG,EAAE,IAAI;AAAA,MAChE,CAAC;AAAA,IACH;AACA;AAAA,EACF;AAEA,MAAI,gBAAgB,KAAK;AAGvB,QAAI,QAAQ;AAEV,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,mBAAmB,GAAG;AACpC,MAAI,UAAU,MAAM;AAElB,YAAQ,KAAK,gEAAgE;AAAA,MAC3E,MAAM,OAAO,KAAK,GAAG;AAAA,IACvB,CAAC;AACD;AAAA,EACF;AAEA,MAAI,QAAQ;AAEV,YAAQ,KAAK,2CAA2C;AAAA,MACtD,YAAY,MAAM;AAAA,MAClB,YAAY,MAAM,IAAI,OAAK,EAAE,SAAS;AAAA,IACxC,CAAC;AAAA,EACH;AACA,wBAAsB,KAAK;AAC7B;","names":[]}
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
// src/components/jetPaveGerberViewer/src/viewer-src/common/archiveExtractor.js
|
|
2
|
+
import { createExtractorFromData } from "node-unrar-js";
|
|
3
|
+
import wasmUrl from "node-unrar-js/esm/js/unrar.wasm?url";
|
|
4
|
+
function isGerberFile(fileName) {
|
|
5
|
+
const fileNameOnly = fileName.split(/[/\\]/).pop();
|
|
6
|
+
const fileNameUpper = fileNameOnly.toUpperCase();
|
|
7
|
+
if (fileNameUpper.includes("STATUS REPORT") || fileNameUpper.includes("NETLIST") || fileNameUpper.endsWith(".REP") || fileNameUpper.endsWith(".LOG") || fileNameUpper.endsWith(".CSV") || fileNameUpper.endsWith(".DRR") || fileNameUpper.endsWith(".EXTREP") || fileNameUpper.endsWith(".RUL") || fileNameUpper.endsWith(".LDP") || fileNameUpper.endsWith(".APR") || fileNameUpper.endsWith(".APR_LIB") || fileNameUpper.endsWith(".TGZ") || fileNameUpper.endsWith(".ZIP") || fileNameUpper.endsWith(".RAR")) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const specialSuffixes = ["_SST", "_PMT", "_SMT", "_TOP", "_SMB", "_PMB", "_SSB", "OUTLINE"];
|
|
11
|
+
for (const suffix of specialSuffixes) {
|
|
12
|
+
if (fileNameUpper.endsWith(suffix) || fileNameUpper.includes(suffix + ".")) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (/.*_INT\d+$/i.test(fileNameUpper) || /.*_INT\d+\./i.test(fileNameUpper)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
const validExtensions = [
|
|
20
|
+
".gtl",
|
|
21
|
+
".gbl",
|
|
22
|
+
".gts",
|
|
23
|
+
".gbs",
|
|
24
|
+
".gto",
|
|
25
|
+
".gbo",
|
|
26
|
+
".gtp",
|
|
27
|
+
".gbp",
|
|
28
|
+
".gm1",
|
|
29
|
+
".drl",
|
|
30
|
+
".gbr",
|
|
31
|
+
".gko",
|
|
32
|
+
".gdl",
|
|
33
|
+
".gdd",
|
|
34
|
+
".gm",
|
|
35
|
+
".gd1",
|
|
36
|
+
".gg1",
|
|
37
|
+
".gpb",
|
|
38
|
+
".gpt",
|
|
39
|
+
".txt",
|
|
40
|
+
".art",
|
|
41
|
+
".d",
|
|
42
|
+
".rou",
|
|
43
|
+
".pho",
|
|
44
|
+
// CAM350 等软件导出的扩展名
|
|
45
|
+
".bot",
|
|
46
|
+
".top",
|
|
47
|
+
".sob",
|
|
48
|
+
".sot",
|
|
49
|
+
".dri",
|
|
50
|
+
".ser",
|
|
51
|
+
".sst",
|
|
52
|
+
".ssb",
|
|
53
|
+
".smt",
|
|
54
|
+
".smb",
|
|
55
|
+
".pmt",
|
|
56
|
+
".pmb"
|
|
57
|
+
];
|
|
58
|
+
const fileExtension = "." + fileNameOnly.split(".").pop().toLowerCase();
|
|
59
|
+
return validExtensions.includes(fileExtension) || /^\.g\d+$/i.test(fileExtension) || /^\.gm\d+$/i.test(fileExtension) || /^\.gp\d+$/i.test(fileExtension) || // 支持 .gp1, .gp2, .gp3 等
|
|
60
|
+
/^\.tx\d+$/i.test(fileExtension) || // 支持 .tx1, .tx2, .tx3 等
|
|
61
|
+
/^\.int\d+$/i.test(fileExtension);
|
|
62
|
+
}
|
|
63
|
+
async function loadWasmBinary() {
|
|
64
|
+
try {
|
|
65
|
+
console.log("\u5C1D\u8BD5\u52A0\u8F7D WASM \u6587\u4EF6\uFF0CURL:", wasmUrl);
|
|
66
|
+
const response = await fetch(wasmUrl);
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new Error(`\u65E0\u6CD5\u52A0\u8F7D WASM \u6587\u4EF6: ${response.status} ${response.statusText}`);
|
|
69
|
+
}
|
|
70
|
+
const wasmBinary = await response.arrayBuffer();
|
|
71
|
+
console.log("\u6210\u529F\u52A0\u8F7D WASM \u6587\u4EF6\uFF0C\u5927\u5C0F:", wasmBinary.byteLength, "bytes");
|
|
72
|
+
return wasmBinary;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error("\u65E0\u6CD5\u52A0\u8F7D WASM \u6587\u4EF6:", error);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function extractRar(rarFile) {
|
|
79
|
+
console.log("[\u6027\u80FD] extractRar \u5F00\u59CB\uFF0C\u6587\u4EF6\u5927\u5C0F:", (rarFile.size / 1024).toFixed(2), "KB");
|
|
80
|
+
const startTime = performance.now();
|
|
81
|
+
const gerberFiles = [];
|
|
82
|
+
try {
|
|
83
|
+
console.log("[\u6027\u80FD] \u8BFB\u53D6 RAR \u6587\u4EF6\u4E3A ArrayBuffer...");
|
|
84
|
+
const startTimeBuffer = performance.now();
|
|
85
|
+
const arrayBuffer = await rarFile.arrayBuffer();
|
|
86
|
+
const data = new Uint8Array(arrayBuffer);
|
|
87
|
+
const endTimeBuffer = performance.now();
|
|
88
|
+
console.log(`[\u6027\u80FD] ArrayBuffer \u8BFB\u53D6\u5B8C\u6210\uFF0C\u8017\u65F6: ${(endTimeBuffer - startTimeBuffer).toFixed(2)}ms`);
|
|
89
|
+
console.log("[\u6027\u80FD] \u5F00\u59CB\u52A0\u8F7D WASM \u6587\u4EF6...");
|
|
90
|
+
const startTimeWasm = performance.now();
|
|
91
|
+
const wasmBinary = await loadWasmBinary();
|
|
92
|
+
const endTimeWasm = performance.now();
|
|
93
|
+
console.log(`[\u6027\u80FD] WASM \u6587\u4EF6\u52A0\u8F7D\u5B8C\u6210\uFF0C\u8017\u65F6: ${(endTimeWasm - startTimeWasm).toFixed(2)}ms`);
|
|
94
|
+
let extractor;
|
|
95
|
+
if (wasmBinary) {
|
|
96
|
+
console.log("\u4F7F\u7528\u63D0\u4F9B\u7684 WASM \u4E8C\u8FDB\u5236\u6587\u4EF6");
|
|
97
|
+
extractor = await createExtractorFromData({ data, wasmBinary });
|
|
98
|
+
} else {
|
|
99
|
+
console.log("\u5C1D\u8BD5\u4E0D\u4F7F\u7528 wasmBinary\uFF0C\u8BA9 node-unrar-js \u81EA\u52A8\u5904\u7406");
|
|
100
|
+
try {
|
|
101
|
+
extractor = await createExtractorFromData({ data });
|
|
102
|
+
} catch (noWasmError) {
|
|
103
|
+
console.error("\u4E0D\u4F7F\u7528 wasmBinary \u5931\u8D25:", noWasmError);
|
|
104
|
+
throw new Error("\u65E0\u6CD5\u521B\u5EFA RAR \u63D0\u53D6\u5668\u3002WASM \u6587\u4EF6\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 node-unrar-js \u7684\u914D\u7F6E\u3002");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const list = extractor.getFileList();
|
|
108
|
+
if (!list || !list.fileHeaders) {
|
|
109
|
+
console.error("RAR\u6587\u4EF6\u5217\u8868\u683C\u5F0F\u9519\u8BEF:", list);
|
|
110
|
+
throw new Error("\u65E0\u6CD5\u8BFB\u53D6RAR\u6587\u4EF6\u5217\u8868");
|
|
111
|
+
}
|
|
112
|
+
const gerberFileNames = [];
|
|
113
|
+
const pcbDocFiles = [];
|
|
114
|
+
console.log("\u5F00\u59CB\u626B\u63CF RAR \u5185\u5BB9...");
|
|
115
|
+
let fileCount = 0;
|
|
116
|
+
for (const fileHeader of list.fileHeaders) {
|
|
117
|
+
const fileName = fileHeader.name;
|
|
118
|
+
const isDir = fileHeader.flags.directory;
|
|
119
|
+
fileCount++;
|
|
120
|
+
const isValid = isGerberFile(fileName);
|
|
121
|
+
console.log(`[RAR\u626B\u63CF] \u6587\u4EF6: ${fileName}, \u76EE\u5F55: ${isDir}, \u6709\u6548Gerber: ${isValid}`);
|
|
122
|
+
if (fileName && !isDir) {
|
|
123
|
+
if (isValid) {
|
|
124
|
+
gerberFileNames.push(fileName);
|
|
125
|
+
} else if (fileName.toUpperCase().endsWith(".PCBDOC")) {
|
|
126
|
+
pcbDocFiles.push(fileName);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
console.log(`RAR \u626B\u63CF\u7ED3\u675F\uFF0C\u5171 ${fileCount} \u4E2A\u6761\u76EE\uFF0C\u627E\u5230 ${gerberFileNames.length} \u4E2A Gerber \u6587\u4EF6`);
|
|
131
|
+
if (gerberFileNames.length === 0) {
|
|
132
|
+
if (pcbDocFiles.length > 0) {
|
|
133
|
+
throw new Error(`\u672A\u627E\u5230 Gerber \u6587\u4EF6\uFF0C\u4F46\u53D1\u73B0\u4E86 PCB \u6E90\u6587\u4EF6 (${pcbDocFiles[0]})\u3002\u672C\u67E5\u770B\u5668\u4E0D\u652F\u6301\u76F4\u63A5\u8BFB\u53D6 .PCBDOC \u6587\u4EF6\uFF0C\u8BF7\u5148\u5728 EDA \u8F6F\u4EF6\u4E2D\u5BFC\u51FA\u4E3A Gerber \u6587\u4EF6\u3002`);
|
|
134
|
+
}
|
|
135
|
+
console.warn("RAR\u6587\u4EF6\u4E2D\u6CA1\u6709\u627E\u5230Gerber\u6587\u4EF6");
|
|
136
|
+
return gerberFiles;
|
|
137
|
+
}
|
|
138
|
+
const extracted = extractor.extract({ files: gerberFileNames });
|
|
139
|
+
for (const arcFile of extracted.files) {
|
|
140
|
+
const fileName = arcFile.fileHeader.name;
|
|
141
|
+
const content = arcFile.extraction;
|
|
142
|
+
if (content && content instanceof Uint8Array) {
|
|
143
|
+
const blob = new Blob([content], { type: "application/octet-stream" });
|
|
144
|
+
gerberFiles.push(new File([blob], fileName, { type: "application/octet-stream" }));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const endTime = performance.now();
|
|
148
|
+
const totalTime = endTime - startTime;
|
|
149
|
+
console.log(`[\u6027\u80FD] extractRar \u5B8C\u6210\uFF0C\u603B\u8017\u65F6: ${totalTime.toFixed(2)}ms\uFF0C\u63D0\u53D6\u6587\u4EF6\u6570: ${gerberFiles.length}`);
|
|
150
|
+
console.log(`\u4ECE RAR \u6587\u4EF6 ${rarFile.name} \u4E2D\u63D0\u53D6\u51FA ${gerberFiles.length} \u4E2A Gerber \u6587\u4EF6`);
|
|
151
|
+
return gerberFiles;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error("\u89E3\u6790RAR\u538B\u7F29\u5305\u5931\u8D25:", error);
|
|
154
|
+
console.error("\u9519\u8BEF\u8BE6\u60C5:", error.stack);
|
|
155
|
+
if (error.message.includes("\u672A\u627E\u5230 Gerber \u6587\u4EF6") || error.message.includes("\u65E0\u6CD5\u521B\u5EFA RAR \u63D0\u53D6\u5668")) {
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
throw new Error("\u65E0\u6CD5\u89E3\u6790RAR\u538B\u7F29\u5305\uFF0C\u8BF7\u786E\u8BA4\u6587\u4EF6\u662F\u5426\u635F\u574F: " + error.message);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/components/jetPaveGerberViewer/src/viewer-src/common/gerber-common.js
|
|
163
|
+
function parseUrlId() {
|
|
164
|
+
try {
|
|
165
|
+
const params = new URLSearchParams(window.location.search);
|
|
166
|
+
const idParam = params.get("id");
|
|
167
|
+
if (idParam) {
|
|
168
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u4ECE URL \u67E5\u8BE2\u53C2\u6570\u83B7\u53D6\u5230\u7684 ID (id=):", idParam);
|
|
169
|
+
return idParam;
|
|
170
|
+
}
|
|
171
|
+
const objectParam = params.get("object");
|
|
172
|
+
if (objectParam) {
|
|
173
|
+
const data = JSON.parse(objectParam);
|
|
174
|
+
if (data && data.id) {
|
|
175
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u4ECE URL \u67E5\u8BE2\u53C2\u6570\u83B7\u53D6\u5230\u7684 ID (object=):", data.id);
|
|
176
|
+
return data.id;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const pathname = window.location.pathname;
|
|
180
|
+
const pathParts = pathname.split("/").filter((part) => part && part !== "index.html");
|
|
181
|
+
for (const part of pathParts) {
|
|
182
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(part)) {
|
|
183
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u4ECE URL \u8DEF\u5F84\u83B7\u53D6\u5230\u7684 ID:", part);
|
|
184
|
+
return part;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error("[\u516C\u5171\u51FD\u6570] \u89E3\u6790 URL \u53C2\u6570\u5931\u8D25:", error);
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
function parseUrlFileUrl() {
|
|
193
|
+
try {
|
|
194
|
+
const params = new URLSearchParams(window.location.search);
|
|
195
|
+
const urlParam = params.get("url");
|
|
196
|
+
if (urlParam) {
|
|
197
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u4ECE URL \u67E5\u8BE2\u53C2\u6570\u83B7\u53D6\u5230\u7684\u6587\u4EF6\u94FE\u63A5 (url=):", urlParam);
|
|
198
|
+
return urlParam;
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error("[\u516C\u5171\u51FD\u6570] \u89E3\u6790 URL \u53C2\u6570\u5931\u8D25 (url):", error);
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
async function fetchFileById(id, handleFileSelection, showStatus) {
|
|
206
|
+
if (!id) {
|
|
207
|
+
console.warn("[\u516C\u5171\u51FD\u6570] ID \u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u6587\u4EF6\u83B7\u53D6");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const startTimeTotal = performance.now();
|
|
211
|
+
try {
|
|
212
|
+
showStatus("\u6B63\u5728\u4ECE\u670D\u52A1\u5668\u83B7\u53D6\u6587\u4EF6...", "loading");
|
|
213
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u5F00\u59CB\u83B7\u53D6\u6587\u4EF6\uFF0CID:", id);
|
|
214
|
+
const encodedId = encodeURIComponent(id);
|
|
215
|
+
const apiUrl = `https://x.jiepei.com/mfr/app/p-cBTo-gerber-task/${encodedId}/output-file-by-id`;
|
|
216
|
+
console.log("[\u6027\u80FD] \u53D1\u8D77\u7F51\u7EDC\u8BF7\u6C42:", apiUrl);
|
|
217
|
+
showStatus("\u6B63\u5728\u4ECE\u670D\u52A1\u5668\u83B7\u53D6\u6587\u4EF6\uFF08\u5982\u679C\u662F\u9996\u6B21\u8BBF\u95EE\u53EF\u80FD\u9700\u898110-15\u79D2\uFF09...", "loading");
|
|
218
|
+
const startTimeFetch = performance.now();
|
|
219
|
+
const response = await fetch(apiUrl);
|
|
220
|
+
const endTimeFetch = performance.now();
|
|
221
|
+
const fetchTime = (endTimeFetch - startTimeFetch) / 1e3;
|
|
222
|
+
console.log(`[\u6027\u80FD] \u670D\u52A1\u5668\u54CD\u5E94\u6536\u5230\uFF0C\u8017\u65F6: ${fetchTime.toFixed(2)}\u79D2, \u72B6\u6001: ${response.status}`);
|
|
223
|
+
if (!response.ok) {
|
|
224
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
225
|
+
}
|
|
226
|
+
const contentLength = response.headers.get("Content-Length");
|
|
227
|
+
if (contentLength) {
|
|
228
|
+
console.log("[\u6027\u80FD] \u6587\u4EF6\u5927\u5C0F:", (parseInt(contentLength) / 1024).toFixed(2), "KB");
|
|
229
|
+
}
|
|
230
|
+
console.log("[\u6027\u80FD] \u5F00\u59CB\u4E0B\u8F7D\u6587\u4EF6\u5185\u5BB9...");
|
|
231
|
+
showStatus("\u6B63\u5728\u4E0B\u8F7D\u6587\u4EF6...", "loading");
|
|
232
|
+
const startTimeBlob = performance.now();
|
|
233
|
+
let blob;
|
|
234
|
+
if (contentLength && response.body) {
|
|
235
|
+
const total = parseInt(contentLength);
|
|
236
|
+
let loaded = 0;
|
|
237
|
+
const chunks = [];
|
|
238
|
+
const reader = response.body.getReader();
|
|
239
|
+
const startDownloadTime = Date.now();
|
|
240
|
+
let lastUpdateTime = startDownloadTime;
|
|
241
|
+
while (true) {
|
|
242
|
+
const { done, value } = await reader.read();
|
|
243
|
+
if (done) break;
|
|
244
|
+
chunks.push(value);
|
|
245
|
+
loaded += value.length;
|
|
246
|
+
const now = Date.now();
|
|
247
|
+
if (now - lastUpdateTime > 500) {
|
|
248
|
+
const progress = (loaded / total * 100).toFixed(1);
|
|
249
|
+
const speed = (loaded / 1024 / ((now - startDownloadTime) / 1e3)).toFixed(1);
|
|
250
|
+
showStatus(`\u6B63\u5728\u4E0B\u8F7D\u6587\u4EF6 ${progress}% (${speed} KB/s)...`, "loading");
|
|
251
|
+
lastUpdateTime = now;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
blob = new Blob(chunks);
|
|
255
|
+
} else {
|
|
256
|
+
blob = await response.blob();
|
|
257
|
+
}
|
|
258
|
+
const endTimeBlob = performance.now();
|
|
259
|
+
const blobTime = (endTimeBlob - startTimeBlob) / 1e3;
|
|
260
|
+
const downloadSpeed = (blob.size / 1024 / blobTime).toFixed(1);
|
|
261
|
+
console.log(`[\u6027\u80FD] \u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u8017\u65F6: ${blobTime.toFixed(2)}\u79D2, \u5B9E\u9645\u5927\u5C0F: ${(blob.size / 1024).toFixed(2)}KB, \u5E73\u5747\u901F\u5EA6: ${downloadSpeed} KB/s`);
|
|
262
|
+
if (parseFloat(downloadSpeed) < 100) {
|
|
263
|
+
console.warn(`\u26A0\uFE0F [\u6027\u80FD\u8B66\u544A] \u4E0B\u8F7D\u901F\u5EA6\u8FC7\u6162\uFF08${downloadSpeed} KB/s\uFF09\uFF0C\u6B63\u5E38\u5E94\u8BE5 > 500 KB/s`);
|
|
264
|
+
console.warn(" \u53EF\u80FD\u539F\u56E0\uFF1A");
|
|
265
|
+
console.warn(" 1. \u670D\u52A1\u5668\u5E26\u5BBD\u4E0D\u8DB3");
|
|
266
|
+
console.warn(" 2. \u7F51\u7EDC\u8FDE\u63A5\u8D28\u91CF\u5DEE");
|
|
267
|
+
console.warn(" 3. \u670D\u52A1\u5668\u8D1F\u8F7D\u8FC7\u9AD8");
|
|
268
|
+
console.warn(" \u5EFA\u8BAE\uFF1A\u4F7F\u7528CDN\u52A0\u901F\u6587\u4EF6\u5206\u53D1");
|
|
269
|
+
}
|
|
270
|
+
showStatus("\u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u5F00\u59CB\u89E3\u6790...", "loading");
|
|
271
|
+
console.log("[\u6027\u80FD] \u5F00\u59CB\u8BC6\u522B\u6587\u4EF6\u7C7B\u578B...");
|
|
272
|
+
const startTimeIdentify = performance.now();
|
|
273
|
+
let fileName = "gerber.rar";
|
|
274
|
+
const disposition = response.headers.get("Content-Disposition");
|
|
275
|
+
if (disposition) {
|
|
276
|
+
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
|
|
277
|
+
const matches = filenameRegex.exec(disposition);
|
|
278
|
+
if (matches != null && matches[1]) {
|
|
279
|
+
fileName = matches[1].replace(/['"]/g, "");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
const headerBuffer = await blob.slice(0, 4).arrayBuffer();
|
|
284
|
+
const headerView = new Uint8Array(headerBuffer);
|
|
285
|
+
if (headerView[0] === 80 && headerView[1] === 75) {
|
|
286
|
+
if (!fileName.toLowerCase().endsWith(".zip")) {
|
|
287
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u68C0\u6D4B\u5230 ZIP \u9B54\u6570 (PK..)\uFF0C\u4FEE\u6B63\u6269\u5C55\u540D\u4E3A .zip");
|
|
288
|
+
fileName = fileName.replace(/\.[^/.]+$/, "") + ".zip";
|
|
289
|
+
if (!fileName.endsWith(".zip")) fileName += ".zip";
|
|
290
|
+
}
|
|
291
|
+
} else if (headerView[0] === 82 && headerView[1] === 97 && headerView[2] === 114 && headerView[3] === 33) {
|
|
292
|
+
if (!fileName.toLowerCase().endsWith(".rar")) {
|
|
293
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u68C0\u6D4B\u5230 RAR \u9B54\u6570 (Rar!)\uFF0C\u4FEE\u6B63\u6269\u5C55\u540D\u4E3A .rar");
|
|
294
|
+
fileName = fileName.replace(/\.[^/.]+$/, "") + ".rar";
|
|
295
|
+
if (!fileName.endsWith(".rar")) fileName += ".rar";
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} catch (e) {
|
|
299
|
+
console.warn("[\u516C\u5171\u51FD\u6570] \u6587\u4EF6\u7C7B\u578B\u68C0\u6D4B\u5931\u8D25:", e);
|
|
300
|
+
}
|
|
301
|
+
const endTimeIdentify = performance.now();
|
|
302
|
+
console.log(`[\u6027\u80FD] \u6587\u4EF6\u7C7B\u578B\u8BC6\u522B\u5B8C\u6210\uFF0C\u8017\u65F6: ${(endTimeIdentify - startTimeIdentify).toFixed(2)}ms, \u6587\u4EF6\u540D: ${fileName}`);
|
|
303
|
+
console.log("[\u6027\u80FD] \u521B\u5EFA File \u5BF9\u8C61...");
|
|
304
|
+
const startTimeFile = performance.now();
|
|
305
|
+
const file = new File([blob], fileName, { type: fileName.endsWith(".zip") ? "application/zip" : "application/x-rar-compressed" });
|
|
306
|
+
const endTimeFile = performance.now();
|
|
307
|
+
console.log(`[\u6027\u80FD] File \u5BF9\u8C61\u521B\u5EFA\u5B8C\u6210\uFF0C\u8017\u65F6: ${(endTimeFile - startTimeFile).toFixed(2)}ms`);
|
|
308
|
+
const endTimeTotal = performance.now();
|
|
309
|
+
const totalTimeBeforeHandle = (endTimeTotal - startTimeTotal) / 1e3;
|
|
310
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u6587\u4EF6\u83B7\u53D6\u6210\u529F\uFF0C\u5927\u5C0F:", (file.size / 1024).toFixed(2), "KB", "\u6587\u4EF6\u540D:", fileName);
|
|
311
|
+
console.log(`[\u6027\u80FD] ========== \u63A5\u53E3\u8C03\u7528\u5230File\u5BF9\u8C61\u521B\u5EFA\u603B\u8017\u65F6: ${totalTimeBeforeHandle.toFixed(2)}\u79D2 ==========`);
|
|
312
|
+
if (totalTimeBeforeHandle > 5) {
|
|
313
|
+
console.warn(`\u26A0\uFE0F [\u6027\u80FD\u5EFA\u8BAE] \u63A5\u53E3\u54CD\u5E94\u8F83\u6162\uFF08${totalTimeBeforeHandle.toFixed(1)}\u79D2\uFF09\uFF0C\u5EFA\u8BAE\u540E\u7AEF\u4F18\u5316\uFF1A`);
|
|
314
|
+
console.warn(" 1. \u9884\u5148\u751F\u6210\u6587\u4EF6\uFF0C\u800C\u4E0D\u662F\u5B9E\u65F6\u751F\u6210");
|
|
315
|
+
console.warn(" 2. \u4F7F\u7528CDN\u52A0\u901F\u6587\u4EF6\u5206\u53D1");
|
|
316
|
+
console.warn(" 3. \u542F\u7528\u6587\u4EF6\u538B\u7F29\u548C\u7F13\u5B58");
|
|
317
|
+
}
|
|
318
|
+
console.log("[\u6027\u80FD] \u5F00\u59CB\u8C03\u7528 handleFileSelection...");
|
|
319
|
+
const startTimeHandle = performance.now();
|
|
320
|
+
await handleFileSelection([file]);
|
|
321
|
+
const endTimeHandle = performance.now();
|
|
322
|
+
console.log(`[\u6027\u80FD] handleFileSelection \u5B8C\u6210\uFF0C\u8017\u65F6: ${(endTimeHandle - startTimeHandle).toFixed(2)}ms`);
|
|
323
|
+
const finalTime = performance.now();
|
|
324
|
+
const grandTotal = (finalTime - startTimeTotal) / 1e3;
|
|
325
|
+
console.log(`[\u6027\u80FD] ========== \u4ECE\u5F00\u59CB\u83B7\u53D6\u5230\u5904\u7406\u5B8C\u6210\u603B\u8017\u65F6: ${grandTotal.toFixed(2)}\u79D2 ==========`);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
const endTime = performance.now();
|
|
328
|
+
const errorTime = endTime - startTimeTotal;
|
|
329
|
+
console.error(`[\u516C\u5171\u51FD\u6570] \u83B7\u53D6\u6587\u4EF6\u5931\u8D25 (\u8017\u65F6: ${errorTime.toFixed(2)}ms):`, error);
|
|
330
|
+
showStatus(`\u83B7\u53D6\u6587\u4EF6\u5931\u8D25: ${error.message}`, "error");
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async function fetchFileByUrl(url, handleFileSelection, showStatus) {
|
|
334
|
+
if (!url) {
|
|
335
|
+
console.warn("[\u516C\u5171\u51FD\u6570] URL \u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u6587\u4EF6\u83B7\u53D6");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const startTimeTotal = performance.now();
|
|
339
|
+
try {
|
|
340
|
+
showStatus("\u6B63\u5728\u4ECE\u94FE\u63A5\u83B7\u53D6\u6587\u4EF6...", "loading");
|
|
341
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u5F00\u59CB\u83B7\u53D6\u6587\u4EF6\uFF0CURL:", url);
|
|
342
|
+
let proxyUrl = `https://x.jiepei.com/api/app/file-upload/temporary-url?oldOssUrl=${url}`;
|
|
343
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u83B7\u53D6\u4E34\u65F6\u94FE\u63A5:", proxyUrl);
|
|
344
|
+
let response = await fetch(proxyUrl);
|
|
345
|
+
if (!response.ok) {
|
|
346
|
+
if (response.status === 403 || response.status === 401) {
|
|
347
|
+
throw new Error(`HTTP error! status: ${response.status} (\u94FE\u63A5\u65E0\u6743\u9650\uFF0C\u8BF7\u4F7F\u7528\u5E26\u7B7E\u540D\u7684 URL \u6216\u6539\u7528 ?id=...)`);
|
|
348
|
+
}
|
|
349
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
350
|
+
}
|
|
351
|
+
let downloadUrl = url;
|
|
352
|
+
const contentType = response.headers.get("Content-Type") || "";
|
|
353
|
+
if (contentType.includes("application/json")) {
|
|
354
|
+
const data = await response.json();
|
|
355
|
+
const tempUrl = data?.url || data?.data || data?.result || data?.content || data?.temporaryUrl || data?.tempUrl;
|
|
356
|
+
if (!tempUrl || typeof tempUrl !== "string") {
|
|
357
|
+
throw new Error("\u4E34\u65F6\u94FE\u63A5\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38");
|
|
358
|
+
}
|
|
359
|
+
downloadUrl = tempUrl.trim();
|
|
360
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u4F7F\u7528\u4E34\u65F6\u94FE\u63A5\u4E0B\u8F7D\u6587\u4EF6:", downloadUrl);
|
|
361
|
+
response = await fetch(downloadUrl);
|
|
362
|
+
if (!response.ok) {
|
|
363
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
364
|
+
}
|
|
365
|
+
} else if (contentType.includes("text/plain")) {
|
|
366
|
+
const text = await response.text();
|
|
367
|
+
const tempUrl = text.trim();
|
|
368
|
+
if (!/^https?:\/\//i.test(tempUrl)) {
|
|
369
|
+
throw new Error("\u4E34\u65F6\u94FE\u63A5\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38");
|
|
370
|
+
}
|
|
371
|
+
downloadUrl = tempUrl;
|
|
372
|
+
console.log("[\u516C\u5171\u51FD\u6570] \u4F7F\u7528\u4E34\u65F6\u94FE\u63A5\u4E0B\u8F7D\u6587\u4EF6:", downloadUrl);
|
|
373
|
+
response = await fetch(downloadUrl);
|
|
374
|
+
if (!response.ok) {
|
|
375
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const contentLength = response.headers.get("Content-Length");
|
|
379
|
+
if (contentLength) {
|
|
380
|
+
console.log("[\u6027\u80FD] \u6587\u4EF6\u5927\u5C0F:", (parseInt(contentLength) / 1024).toFixed(2), "KB");
|
|
381
|
+
}
|
|
382
|
+
showStatus("\u6B63\u5728\u4E0B\u8F7D\u6587\u4EF6...", "loading");
|
|
383
|
+
const startTimeBlob = performance.now();
|
|
384
|
+
let blob;
|
|
385
|
+
if (contentLength && response.body) {
|
|
386
|
+
const total = parseInt(contentLength);
|
|
387
|
+
let loaded = 0;
|
|
388
|
+
const chunks = [];
|
|
389
|
+
const reader = response.body.getReader();
|
|
390
|
+
const startDownloadTime = Date.now();
|
|
391
|
+
let lastUpdateTime = startDownloadTime;
|
|
392
|
+
while (true) {
|
|
393
|
+
const { done, value } = await reader.read();
|
|
394
|
+
if (done) break;
|
|
395
|
+
chunks.push(value);
|
|
396
|
+
loaded += value.length;
|
|
397
|
+
const now = Date.now();
|
|
398
|
+
if (now - lastUpdateTime > 500) {
|
|
399
|
+
const progress = (loaded / total * 100).toFixed(1);
|
|
400
|
+
const speed = (loaded / 1024 / ((now - startDownloadTime) / 1e3)).toFixed(1);
|
|
401
|
+
showStatus(`\u6B63\u5728\u4E0B\u8F7D\u6587\u4EF6 ${progress}% (${speed} KB/s)...`, "loading");
|
|
402
|
+
lastUpdateTime = now;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
blob = new Blob(chunks);
|
|
406
|
+
} else {
|
|
407
|
+
blob = await response.blob();
|
|
408
|
+
}
|
|
409
|
+
const endTimeBlob = performance.now();
|
|
410
|
+
const blobTime = (endTimeBlob - startTimeBlob) / 1e3;
|
|
411
|
+
console.log(`[\u6027\u80FD] \u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u8017\u65F6: ${blobTime.toFixed(2)}\u79D2, \u5B9E\u9645\u5927\u5C0F: ${(blob.size / 1024).toFixed(2)}KB`);
|
|
412
|
+
showStatus("\u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210\uFF0C\u5F00\u59CB\u89E3\u6790...", "loading");
|
|
413
|
+
let fileName = "gerber.zip";
|
|
414
|
+
const disposition = response.headers.get("Content-Disposition");
|
|
415
|
+
if (disposition) {
|
|
416
|
+
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
|
|
417
|
+
const matches = filenameRegex.exec(disposition);
|
|
418
|
+
if (matches != null && matches[1]) {
|
|
419
|
+
fileName = matches[1].replace(/['"]/g, "");
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
try {
|
|
423
|
+
const urlObj = new URL(downloadUrl);
|
|
424
|
+
const base = urlObj.pathname.split("/").filter(Boolean).pop();
|
|
425
|
+
if (base) fileName = base;
|
|
426
|
+
} catch (e) {
|
|
427
|
+
console.warn("[\u516C\u5171\u51FD\u6570] URL \u89E3\u6790\u5931\u8D25\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u6587\u4EF6\u540D:", e);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
const headerBuffer = await blob.slice(0, 4).arrayBuffer();
|
|
432
|
+
const headerView = new Uint8Array(headerBuffer);
|
|
433
|
+
if (headerView[0] === 80 && headerView[1] === 75) {
|
|
434
|
+
if (!fileName.toLowerCase().endsWith(".zip")) {
|
|
435
|
+
fileName = fileName.replace(/\.[^/.]+$/, "") + ".zip";
|
|
436
|
+
if (!fileName.endsWith(".zip")) fileName += ".zip";
|
|
437
|
+
}
|
|
438
|
+
} else if (headerView[0] === 82 && headerView[1] === 97 && headerView[2] === 114 && headerView[3] === 33) {
|
|
439
|
+
if (!fileName.toLowerCase().endsWith(".rar")) {
|
|
440
|
+
fileName = fileName.replace(/\.[^/.]+$/, "") + ".rar";
|
|
441
|
+
if (!fileName.endsWith(".rar")) fileName += ".rar";
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
} catch (e) {
|
|
445
|
+
console.warn("[\u516C\u5171\u51FD\u6570] \u6587\u4EF6\u7C7B\u578B\u68C0\u6D4B\u5931\u8D25:", e);
|
|
446
|
+
}
|
|
447
|
+
const file = new File([blob], fileName, { type: fileName.endsWith(".zip") ? "application/zip" : "application/x-rar-compressed" });
|
|
448
|
+
await handleFileSelection([file]);
|
|
449
|
+
const finalTime = performance.now();
|
|
450
|
+
const totalTime = (finalTime - startTimeTotal) / 1e3;
|
|
451
|
+
console.log(`[\u6027\u80FD] ========== \u4ECE\u94FE\u63A5\u83B7\u53D6\u5230\u5904\u7406\u5B8C\u6210\u603B\u8017\u65F6: ${totalTime.toFixed(2)}\u79D2 ==========`);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
const endTime = performance.now();
|
|
454
|
+
const errorTime = endTime - startTimeTotal;
|
|
455
|
+
console.error(`[\u516C\u5171\u51FD\u6570] \u83B7\u53D6\u6587\u4EF6\u5931\u8D25 (\u8017\u65F6: ${errorTime.toFixed(2)}ms):`, error);
|
|
456
|
+
showStatus(`\u83B7\u53D6\u6587\u4EF6\u5931\u8D25: ${error.message}`, "error");
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function initUrlIdHandler(handleFileSelection, showStatus) {
|
|
460
|
+
const id = parseUrlId();
|
|
461
|
+
if (id) {
|
|
462
|
+
fetchFileById(id, handleFileSelection, showStatus);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const url = parseUrlFileUrl();
|
|
466
|
+
if (url) {
|
|
467
|
+
fetchFileByUrl(url, handleFileSelection, showStatus);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export {
|
|
472
|
+
extractRar,
|
|
473
|
+
parseUrlId,
|
|
474
|
+
parseUrlFileUrl,
|
|
475
|
+
fetchFileById,
|
|
476
|
+
fetchFileByUrl,
|
|
477
|
+
initUrlIdHandler
|
|
478
|
+
};
|
|
479
|
+
//# sourceMappingURL=chunk-AO4YUJQT.js.map
|