@primocaredentgroup/dental-digital-intake-shared 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,585 @@
1
+ /** Union di stringa allineate al Convex component (validators). Solo contratto tipi — nessuna logica. */
2
+ type AcquisitionOrigin = "clinic_intraoral" | "lab_bench_scan" | "unknown";
3
+ type HostApp = "primoupcore" | "primolabcore" | "standalone";
4
+ type AcquisitionStatus = "draft" | "waiting_files" | "uploaded" | "parsing" | "needs_review" | "classified" | "linked" | "validated" | "ready_for_next_step" | "archived" | "failed";
5
+ type SourceVendor = "3shape" | "itero" | "carestream" | "sirona" | "exocad" | "unknown";
6
+ type ReviewStatus = "not_required" | "needs_review" | "in_review" | "reviewed" | "rejected";
7
+ type ValidationProfile = "clinic_intraoral_default" | "lab_bench_scan_default" | "generic_default";
8
+ type ReadinessLabel = "ready_for_lab" | "ready_for_cad" | "ready_for_next_step";
9
+ type ScanFileFormat = "stl" | "ply" | "obj" | "dcm" | "xml" | "json" | "png" | "jpg" | "pdf" | "txt" | "unknown";
10
+ type ScanFileRole = "upper_arch" | "lower_arch" | "bite" | "scanbody" | "abutment" | "model" | "impression" | "dicom_volume" | "project_file" | "preview" | "document" | "unknown";
11
+ type ClassificationSource = "auto" | "manual" | "unknown";
12
+ type ExtractionStatus = "not_started" | "extracting" | "completed" | "failed";
13
+
14
+ type LinkedEntity = {
15
+ patientId?: string;
16
+ prescriptionId?: string;
17
+ labWorkOrderId?: string;
18
+ customerId?: string;
19
+ externalCaseId?: string;
20
+ };
21
+ /** Esito validazione persistito dal backend (forma JSON). */
22
+ type ValidationResult = {
23
+ isValid: boolean;
24
+ blockingIssues: string[];
25
+ warnings: string[];
26
+ checkedAt: number;
27
+ checkedBy?: string;
28
+ profileUsed: ValidationProfile;
29
+ readinessLabel: ReadinessLabel;
30
+ };
31
+ /** Riga lista dashboard / card. */
32
+ type AcquisitionListRow = {
33
+ _id: string;
34
+ title: string;
35
+ status: AcquisitionStatus;
36
+ origin: AcquisitionOrigin;
37
+ hostApp: HostApp;
38
+ sourceVendor: SourceVendor;
39
+ vendorConfidence: number;
40
+ validationProfile?: ValidationProfile;
41
+ validationResult?: ValidationResult | null;
42
+ };
43
+ /** File scan (lista UI). */
44
+ type ScanFileListItem = {
45
+ _id: string;
46
+ originalName: string;
47
+ format: ScanFileFormat | string;
48
+ role: ScanFileRole | string;
49
+ sizeBytes: number;
50
+ storageId?: string;
51
+ extractedFromZip?: boolean;
52
+ extractedPath?: string;
53
+ };
54
+
55
+ /**
56
+ * Borsa riferimenti esterni vendor-agnostic (persistita su `digitalAcquisitions` e nel manifest).
57
+ * Solo valori sicuri come JSON Convex — niente `Date`, `undefined`, prototipi custom.
58
+ */
59
+ type ExternalReferenceJsonValue = string | number | boolean | null | ExternalReferenceJsonValue[] | ExternalReferencesMap;
60
+ type ExternalReferencesMap = {
61
+ readonly [key: string]: ExternalReferenceJsonValue;
62
+ };
63
+ /** Merge superficiale: le chiavi in `patch` sovrascrivono quelle in `base`. */
64
+ declare function mergeExternalReferences(base: ExternalReferencesMap | undefined, patch: ExternalReferencesMap): ExternalReferencesMap;
65
+
66
+ /**
67
+ * Parser Exocad strutturato per pacchetti ZIP di progetto.
68
+ *
69
+ * Obiettivo: dato l'insieme dei file estratti da uno ZIP Exocad, ricostruire
70
+ * informazioni cliniche/protesiche e soprattutto la **componentistica implantare**.
71
+ *
72
+ * Regole chiave (vedi prompt di riferimento):
73
+ * - `.constructionInfo` è la fonte principale per la componentistica implantare.
74
+ * - `.dentalProject` da solo NON basta a capire se il caso è implantare.
75
+ * - `.modelInfo` arricchisce con librerie analoghi / modello.
76
+ * - `.dentalCAD` è fallback: solo estrazione stringhe ASCII/UTF-8.
77
+ * - Mai inventare SKU commerciali: l'interpretazione del codice geometria è `inferred`.
78
+ *
79
+ * Tutto case-insensitive, robusto a path Windows (`\\`) e Unix (`/`), e funziona
80
+ * anche se alcuni file mancano.
81
+ */
82
+ type ExocadConfidence = "high" | "medium" | "low" | "inferred";
83
+ /** Valore con livello di confidenza (usato per le interpretazioni dei codici). */
84
+ type ExocadInferredValue = {
85
+ value: string;
86
+ confidence: ExocadConfidence;
87
+ };
88
+ type ExocadParsedGeometry = {
89
+ baseType?: ExocadInferredValue;
90
+ diameterOrPlatform?: ExocadInferredValue;
91
+ abutmentHeight?: ExocadInferredValue;
92
+ };
93
+ type ExocadImplantComponent = {
94
+ tooth?: string;
95
+ manufacturer?: string;
96
+ platform?: string;
97
+ connection?: string;
98
+ component?: string;
99
+ libraryName?: string;
100
+ libraryPath?: string;
101
+ geometryFile?: string;
102
+ geometryCode?: string;
103
+ parsedGeometry?: ExocadParsedGeometry;
104
+ sourceFiles: string[];
105
+ confidence: ExocadConfidence;
106
+ };
107
+ type ExocadRestorationItem = {
108
+ tooth: string;
109
+ type?: string;
110
+ material?: string;
111
+ materialCode?: string;
112
+ shade?: string;
113
+ preparationType?: string;
114
+ implantType?: string;
115
+ scanAbutmentScan?: boolean;
116
+ mesialConnector?: boolean;
117
+ };
118
+ type ExocadStlEntry = {
119
+ fileName: string;
120
+ role: string;
121
+ };
122
+ type ExocadCaseInfo = {
123
+ patientName: string | null;
124
+ practiceName: string | null;
125
+ practiceId: string | null;
126
+ projectDate: string | null;
127
+ exocadVersion: string | null;
128
+ };
129
+ type ExocadModelInfo = {
130
+ hasModelBase: boolean;
131
+ hasGingiva: boolean;
132
+ hasWaxup: boolean;
133
+ analogLibrary: string | null;
134
+ analogManufacturer: string | null;
135
+ modelWorkflow: string | null;
136
+ };
137
+ type ExocadFilesIndex = {
138
+ dentalProject: string[];
139
+ constructionInfo: string[];
140
+ modelInfo: string[];
141
+ dentalCAD: string[];
142
+ stl: string[];
143
+ };
144
+ type ExocadSummary = {
145
+ case: ExocadCaseInfo;
146
+ restoration: {
147
+ teeth: string[];
148
+ items: ExocadRestorationItem[];
149
+ span: string | null;
150
+ isBridge: boolean;
151
+ };
152
+ implantComponents: ExocadImplantComponent[];
153
+ model: ExocadModelInfo;
154
+ files: ExocadFilesIndex;
155
+ /** Caso implantare se constructionInfo contiene geometria/scan abutment impianto. */
156
+ isImplantCase: boolean;
157
+ warnings: string[];
158
+ };
159
+ /** File estratto dal pacchetto (path + byte). */
160
+ type ExocadFileEntry = {
161
+ /** Path normalizzato all'interno dello ZIP (slash). */
162
+ path: string;
163
+ data: Uint8Array;
164
+ };
165
+ type ExocadFileKind = "dentalProject" | "constructionInfo" | "modelInfo" | "dentalCAD" | "stl" | "other";
166
+ type ClassifiedFile$1 = {
167
+ path: string;
168
+ baseName: string;
169
+ ext: string;
170
+ kind: ExocadFileKind;
171
+ data: Uint8Array;
172
+ };
173
+ /** Estensione → kind Exocad. */
174
+ declare function classifyExocadFile(path: string): ExocadFileKind;
175
+ /** Indicizza i file rilevanti del pacchetto Exocad. */
176
+ declare function detectExocadFiles(entries: ExocadFileEntry[]): {
177
+ classified: ClassifiedFile$1[];
178
+ files: ExocadFilesIndex;
179
+ };
180
+ /** True se nel pacchetto esiste almeno un file Exocad riconoscibile. */
181
+ declare function isExocadPackage(entries: ExocadFileEntry[]): boolean;
182
+ declare function parseDentalProject(text: string): {
183
+ case: ExocadCaseInfo;
184
+ items: ExocadRestorationItem[];
185
+ };
186
+ /**
187
+ * Interpretazione best-effort (NON definitiva) di un codice geometria tipo
188
+ * `Base_Mini41-D48-AH46`. Tutti i valori sono marcati `inferred`.
189
+ */
190
+ declare function inferGeometryCode(code: string): ExocadParsedGeometry | undefined;
191
+ declare function parseConstructionInfo(text: string, sourceFile: string): {
192
+ components: ExocadImplantComponent[];
193
+ isImplantCase: boolean;
194
+ };
195
+ declare function parseModelInfo(text: string): Partial<ExocadModelInfo>;
196
+ /** Estrae sequenze stampabili (ASCII/UTF-8) leggibili da un binario. */
197
+ declare function extractStringsFromDentalCAD(data: Uint8Array, minLength?: number): string[];
198
+ /** Trova keyword di interesse nelle stringhe estratte dal `.dentalCAD`. */
199
+ declare function findDentalCadKeywords(strings: string[]): string[];
200
+ declare function inferStlRole(fileName: string): string;
201
+ /** Unisce componenti duplicati mantenendo la confidenza più alta e i sourceFiles. */
202
+ declare function normalizeImplantComponents(components: ExocadImplantComponent[]): ExocadImplantComponent[];
203
+ /** Costruisce il riassunto Exocad completo dai file estratti dello ZIP. */
204
+ declare function buildExocadSummary(entries: ExocadFileEntry[]): ExocadSummary | undefined;
205
+
206
+ /**
207
+ * Parser 3Shape Dental System / Dental Designer per pacchetti ZIP esportati.
208
+ *
209
+ * Obiettivo: estrarre dati ordine, restauro, materiale e — quando presente —
210
+ * la **componentistica implantare**, in modo robusto e best-effort.
211
+ *
212
+ * Priorità fonti:
213
+ * 1. XML principale ordine
214
+ * 2. PrintableOrderForm.html
215
+ * 3. Materials.xml
216
+ * 4. External models/<AbutmentKitID>/
217
+ * 5. CAD/*.dcm
218
+ * 6. Scans/**.dcm
219
+ * 7. *.3ml solo se leggibili (spesso ZIP cifrati: saltati senza bloccare)
220
+ *
221
+ * Regole: case-insensitive, path Windows/Unix, mai inventare SKU commerciali,
222
+ * non convertire ToothNumber interno se esiste già il dente FDI nell'ordine.
223
+ */
224
+ type ThreeShapeConfidence = "high" | "medium" | "low" | "inferred";
225
+ type ThreeShapeImplantComponent = {
226
+ name: string;
227
+ fileName: string;
228
+ type: "analog" | "analog_socket" | "scanbody" | "link/tibase_candidate" | "screw_or_transmucosal_component_candidate" | "manufacturer_component_candidate" | "unknown";
229
+ sourcePath: string;
230
+ confidence: ThreeShapeConfidence;
231
+ };
232
+ type ThreeShapeCase = {
233
+ patientName: string | null;
234
+ orderId: string | null;
235
+ customer: string | null;
236
+ operator: string | null;
237
+ createdAt: string | null;
238
+ groupFolder: string | null;
239
+ software: string;
240
+ softwareVersion: string | null;
241
+ processStatus: string | null;
242
+ scanSource: string | null;
243
+ };
244
+ type ThreeShapeRestoration = {
245
+ teeth: number[];
246
+ internalToothNumbers: number[];
247
+ name: string | null;
248
+ type: string | null;
249
+ toothElementTypeID: string | null;
250
+ cacheToothTypeClass: string | null;
251
+ materialId: string | null;
252
+ materialName: string | null;
253
+ materialFamily: string | null;
254
+ shaderMaterial: string | null;
255
+ shade: string | null;
256
+ isImplantCase: boolean;
257
+ isScrewRetained: boolean;
258
+ };
259
+ type ThreeShapeImplant = {
260
+ isImplantCase: boolean;
261
+ manufacturer: string | null;
262
+ connection: string | null;
263
+ connectionId: string | null;
264
+ implantSystemId: string | null;
265
+ abutmentKitId: string | null;
266
+ components: ThreeShapeImplantComponent[];
267
+ };
268
+ type ThreeShapeFilesIndex = {
269
+ mainXml: string[];
270
+ materialsXml: string[];
271
+ printableOrderForms: string[];
272
+ cadDcm: string[];
273
+ externalModels: string[];
274
+ scans: string[];
275
+ encrypted3ml: string[];
276
+ };
277
+ type ThreeShapeSummary = {
278
+ source: "3Shape";
279
+ case: ThreeShapeCase;
280
+ restoration: ThreeShapeRestoration;
281
+ implant: ThreeShapeImplant;
282
+ files: ThreeShapeFilesIndex;
283
+ warnings: string[];
284
+ };
285
+ type ThreeShapeFileEntry = {
286
+ /** Path normalizzato all'interno dello ZIP (slash). */
287
+ path: string;
288
+ data: Uint8Array;
289
+ };
290
+ type ThreeShapeFileKind = "mainXml" | "materialsXml" | "printableOrderForm" | "cadDcm" | "externalModel" | "scan" | "threeMl" | "other";
291
+ type ClassifiedFile = {
292
+ path: string;
293
+ baseName: string;
294
+ ext: string;
295
+ kind: ThreeShapeFileKind;
296
+ data: Uint8Array;
297
+ };
298
+ /** Estrae sequenze stampabili (ASCII) da un binario (best-effort). */
299
+ declare function extractReadableStringsFromBinary(data: Uint8Array, minLength?: number): string[];
300
+ declare function classifyThreeShapeFile(path: string): ThreeShapeFileKind;
301
+ declare function detectThreeShapeFiles(entries: ThreeShapeFileEntry[]): {
302
+ classified: ClassifiedFile[];
303
+ files: ThreeShapeFilesIndex;
304
+ };
305
+ /** Heuristica: il pacchetto sembra un export 3Shape? */
306
+ declare function isThreeShapePackage(entries: ThreeShapeFileEntry[]): boolean;
307
+ declare function normalizeRestorationType(text: string): {
308
+ type: string | null;
309
+ isImplantCase: boolean;
310
+ isScrewRetained: boolean;
311
+ };
312
+ declare function inferManufacturerFromIdsAndNames(value: string): {
313
+ manufacturer: string | null;
314
+ connection: string | null;
315
+ };
316
+ declare function normalizeImplantComponent(fileName: string, sourcePath: string, confidence?: ThreeShapeConfidence): ThreeShapeImplantComponent;
317
+ declare function parseExternalModels(classified: ClassifiedFile[]): {
318
+ components: ThreeShapeImplantComponent[];
319
+ abutmentKitId: string | null;
320
+ };
321
+ declare function parseMaterialsXml(xml: string): Record<string, {
322
+ name?: string;
323
+ family?: string;
324
+ shader?: string;
325
+ }>;
326
+ type ThreeShapeMainOrderResult = {
327
+ case: Partial<ThreeShapeCase>;
328
+ restoration: Partial<ThreeShapeRestoration>;
329
+ implantIds: {
330
+ abutmentKitId: string | null;
331
+ connectionId: string | null;
332
+ implantSystemId: string | null;
333
+ };
334
+ hasImplantLists: boolean;
335
+ };
336
+ declare function parseMainOrderXml(xml: string): ThreeShapeMainOrderResult;
337
+ type ThreeShapePrintableResult = {
338
+ teeth: number[];
339
+ patientName: string | null;
340
+ orderId: string | null;
341
+ customer: string | null;
342
+ operator: string | null;
343
+ shade: string | null;
344
+ };
345
+ declare function parsePrintableOrderForm(html: string): ThreeShapePrintableResult;
346
+ /** Cerca keyword di tipo restauro/impianto nelle stringhe leggibili di un .dcm. */
347
+ declare function parseCadDcm(data: Uint8Array): {
348
+ restorationType: string | null;
349
+ keywords: string[];
350
+ };
351
+ declare function parseScans(classified: ClassifiedFile[]): string[];
352
+ /** Parser completo: dai file estratti dello ZIP a `ThreeShapeSummary`. */
353
+ declare function buildThreeShapeSummary(entries: ThreeShapeFileEntry[]): ThreeShapeSummary | undefined;
354
+
355
+ /**
356
+ * Estrazione euristica di metadati da sidecar progetto CAD (Exocad e simili).
357
+ * Funziona su testo/XML in browser e Convex action senza dipendenze XML esterne.
358
+ */
359
+
360
+ type CadRestorationEntry = {
361
+ toothNumbers: number[];
362
+ material?: string;
363
+ shade?: string;
364
+ reconstructionType?: string;
365
+ meshFileName?: string;
366
+ /** Tipo preparazione (Crown, Pontic, Antagonist, …) — Exocad `<PreparationType>`. */
367
+ preparationType?: string;
368
+ /** Tipo impianto (es. WithoutAbutment) — Exocad `<ImplantType>`. */
369
+ implantType?: string;
370
+ /** Presenza scan abutment — Exocad `<ScanAbutmentScan>`. */
371
+ scanAbutmentScan?: boolean;
372
+ /** Connettore mesiale (indica ponte) — Exocad `<MesialConnector>`. */
373
+ mesialConnector?: boolean;
374
+ };
375
+ /** Metadati estratti da un singolo sidecar CAD (es. `.constructionInfo`, `.dentalProject`). */
376
+ type CadSourceFileMetadata = {
377
+ sourceFile: string;
378
+ source: "exocad" | "unknown";
379
+ projectName?: string;
380
+ projectDirectory?: string;
381
+ materials: string[];
382
+ shades: string[];
383
+ toothNumbers: number[];
384
+ reconstructions: CadRestorationEntry[];
385
+ parseWarnings: string[];
386
+ };
387
+ type CadProjectMetadata = {
388
+ source: "exocad" | "unknown";
389
+ sourceFiles: string[];
390
+ /** Dettaglio per file sorgente (presente dopo merge / upload con parser aggiornato). */
391
+ bySourceFile?: CadSourceFileMetadata[];
392
+ projectName?: string;
393
+ projectDirectory?: string;
394
+ materials: string[];
395
+ shades: string[];
396
+ toothNumbers: number[];
397
+ reconstructions: CadRestorationEntry[];
398
+ parseWarnings: string[];
399
+ /** Riassunto Exocad strutturato (case, restoration, componentistica implantare). */
400
+ exocad?: ExocadSummary;
401
+ /** Riassunto 3Shape strutturato (ordine, restauro, componentistica implantare). */
402
+ threeShape?: ThreeShapeSummary;
403
+ };
404
+ type CadProjectParseResult = CadProjectMetadata & {
405
+ /** Singolo file da cui è stato estratto questo frammento. */
406
+ sourceFile: string;
407
+ };
408
+ declare function isCadSidecarFileName(fileName: string): boolean;
409
+ /** Analizza un sidecar CAD; `null` se il file non è un candidato o non è testo/XML utile. */
410
+ declare function parseCadSidecarBytes(fileName: string, data: Uint8Array): CadProjectParseResult | null;
411
+ declare function mergeCadProjectParseResults(parts: CadProjectParseResult[]): CadProjectMetadata | undefined;
412
+ declare function collectCadMetadataFromZipEntries(entries: Array<{
413
+ safePath: string;
414
+ data: Uint8Array;
415
+ }>): CadProjectMetadata | undefined;
416
+
417
+ /**
418
+ * Forma del manifest normalizzato esposto da `getManifest` (snapshot JSON).
419
+ * Allineare al payload Convex senza importare il data model generato.
420
+ */
421
+ type NormalizedManifest = {
422
+ acquisitionId: string;
423
+ acquisitionSummary: {
424
+ title: string;
425
+ status: AcquisitionStatus;
426
+ reviewStatus: ReviewStatus;
427
+ origin: AcquisitionOrigin;
428
+ hostApp: HostApp;
429
+ updatedAt: number;
430
+ extractionStatus?: ExtractionStatus;
431
+ extractionError?: string;
432
+ originalPackageName?: string;
433
+ originalPackageSizeBytes?: number;
434
+ originalPackageContentType?: string;
435
+ };
436
+ origin: AcquisitionOrigin;
437
+ hostApp: HostApp;
438
+ sourceVendor: SourceVendor;
439
+ vendorConfidence: number;
440
+ linkedEntity: LinkedEntity;
441
+ files: Array<{
442
+ fileId: string;
443
+ originalName: string;
444
+ format: ScanFileFormat;
445
+ role: ScanFileRole;
446
+ sizeBytes: number;
447
+ classificationSource: ClassificationSource;
448
+ }>;
449
+ summary: {
450
+ totalFiles: number;
451
+ meshFiles: number;
452
+ dicomFiles: number;
453
+ projectFiles: number;
454
+ previewFiles: number;
455
+ documentFiles: number;
456
+ unknownFiles: number;
457
+ };
458
+ warnings: string[];
459
+ readiness: {
460
+ canValidate: boolean;
461
+ missingRequirements: string[];
462
+ };
463
+ validation: {
464
+ profile: ValidationProfile;
465
+ result: ValidationResult | null | undefined;
466
+ readinessLabel: ReadinessLabel;
467
+ blockingIssues: string[];
468
+ warnings: string[];
469
+ canMarkReady: boolean;
470
+ nextStepSemanticLabel?: ReadinessLabel;
471
+ };
472
+ /** Riferimenti esterni consolidati (stesso contenuto campo acquisizione, esposto nel manifest). */
473
+ externalReferences?: ExternalReferencesMap;
474
+ /** Metadati CAD estratti da file progetto nel pacchetto (materiale, denti, tipo lavorazione). */
475
+ cadProject?: CadProjectMetadata;
476
+ };
477
+
478
+ /**
479
+ * Contratti ingestion / adapter dental-digital-intake (allineamento TypeScript dominio Convex).
480
+ */
481
+
482
+ type IngestionAdapterType = "manual_upload" | "zip_upload" | "three_shape_web_service" | "itero_cloud" | "unknown";
483
+ type AdapterConnectionStatus = "disconnected" | "connecting" | "connected" | "error";
484
+ type AdapterSyncStatus = "idle" | "syncing" | "success" | "failed";
485
+ type ProviderCredentialType = "oauth_token_encrypted_placeholder" | "api_key_encrypted_placeholder" | "none" | "mock_opaque";
486
+ type ProviderCapability = "import_cases" | "download_files" | "push_notifications" | "polling" | "metadata_sync";
487
+ type ProviderCapabilityMap = Partial<Record<ProviderCapability, boolean>>;
488
+ /** Credenziali: mai segreti in chiaro nel DB; `encryptedPayloadEnc` sarà ciphertext in futuro. */
489
+ type ProviderCredentialEnvelope = {
490
+ type: ProviderCredentialType;
491
+ encryptedPayloadEnc?: string;
492
+ lastRotatedAt?: number;
493
+ };
494
+ type ManifestFileProjection = NormalizedManifest["files"][number];
495
+ /**
496
+ * Manifest parziale dall’adapter: il core convex consolida su acquisition + persistManifest.
497
+ */
498
+ type PartialNormalizedManifest = {
499
+ acquisitionSummary?: Partial<{
500
+ title: string;
501
+ status: AcquisitionStatus;
502
+ reviewStatus: ReviewStatus;
503
+ origin: AcquisitionOrigin;
504
+ hostApp: HostApp;
505
+ updatedAt: number;
506
+ extractionStatus: ExtractionStatus;
507
+ extractionError: string;
508
+ originalPackageName: string;
509
+ originalPackageSizeBytes: number;
510
+ }>;
511
+ origin?: AcquisitionOrigin;
512
+ hostApp?: HostApp;
513
+ sourceVendor?: SourceVendor;
514
+ vendorConfidence?: number;
515
+ linkedEntity?: Partial<LinkedEntity>;
516
+ files?: Partial<Pick<ManifestFileProjection, "originalName" | "format" | "role" | "sizeBytes" | "classificationSource">>[];
517
+ warnings?: string[];
518
+ };
519
+ type MockScanFileSuggestion = {
520
+ originalName: string;
521
+ originalPath: string;
522
+ extension: string;
523
+ sizeBytes: number;
524
+ };
525
+ type RemoteCaseSummary = {
526
+ externalCaseId: string;
527
+ patientDisplayName?: string;
528
+ prescriptionRef?: string;
529
+ scanDateEpoch?: number;
530
+ vendorHint: SourceVendor | string;
531
+ /** Metadati opachi da liste remote/cache (nested JSON-safe). */
532
+ metadata?: ExternalReferencesMap;
533
+ };
534
+ type AdapterExecutionResult = {
535
+ ok: boolean;
536
+ message?: string;
537
+ partialNormalizedManifest?: PartialNormalizedManifest;
538
+ linkedEntityHints?: Partial<LinkedEntity>;
539
+ warnings: string[];
540
+ suggestedMockScanFiles?: MockScanFileSuggestion[];
541
+ externalReferencesHints?: ExternalReferencesMap;
542
+ };
543
+
544
+ declare const MAX_ZIP_ENTRIES = 200;
545
+ declare const MAX_FILE_BYTES: number;
546
+ declare const MAX_TOTAL_EXTRACTED_BYTES: number;
547
+ /**
548
+ * Dimensione massima del file ZIP **compresso** accettata dall’action di estrazione server.
549
+ * Le Convex action hanno ~64 MB di heap.
550
+ */
551
+ declare const MAX_ZIP_PACKAGE_BYTES: number;
552
+ declare function zipPackageTooLargeMessage(sizeBytes: number): string;
553
+ type SafeZipSuccess = {
554
+ ok: true;
555
+ entries: Array<{
556
+ safePath: string;
557
+ extension: string;
558
+ data: Uint8Array;
559
+ }>;
560
+ warnings: string[];
561
+ };
562
+ type SafeZipFailure = {
563
+ ok: false;
564
+ fatal: string;
565
+ warnings: string[];
566
+ };
567
+ type SafeZipResult = SafeZipSuccess | SafeZipFailure;
568
+ /** Normalizza il path ZIP e blocca path traversal / assoluti. */
569
+ declare function sanitizeZipEntryPath(entryPath: string): string | null;
570
+ type SafeZipEntry = SafeZipSuccess["entries"][number];
571
+ /**
572
+ * Best-effort: espande i contenitori 3Shape `.3ml` (di fatto ZIP, spesso cifrati).
573
+ *
574
+ * Per ogni `.3ml` prova ad aprirlo come ZIP: se ci riesce estrae i file interni utili
575
+ * (mesh/anteprime/metadati in whitelist) aggiungendoli con path `contenitore.3ml/inner`,
576
+ * così eventuali STL/PLY/OBJ diventano visualizzabili. I `.3ml` cifrati o non-ZIP
577
+ * vengono saltati con un warning, senza bloccare il flusso. Espande **un solo livello**.
578
+ */
579
+ declare function expandThreeShape3mlEntries(entries: SafeZipEntry[]): {
580
+ entries: SafeZipEntry[];
581
+ warnings: string[];
582
+ };
583
+ declare function extractZipSafely(buffer: Uint8Array): SafeZipResult;
584
+
585
+ export { type AcquisitionListRow, type AcquisitionOrigin, type AcquisitionStatus, type AdapterConnectionStatus, type AdapterExecutionResult, type AdapterSyncStatus, type CadProjectMetadata, type CadRestorationEntry, type CadSourceFileMetadata, type ClassificationSource, type ExocadCaseInfo, type ExocadConfidence, type ExocadFileEntry, type ExocadFilesIndex, type ExocadImplantComponent, type ExocadInferredValue, type ExocadModelInfo, type ExocadParsedGeometry, type ExocadRestorationItem, type ExocadStlEntry, type ExocadSummary, type ExternalReferenceJsonValue, type ExternalReferencesMap, type ExtractionStatus, type HostApp, type IngestionAdapterType, type LinkedEntity, MAX_FILE_BYTES, MAX_TOTAL_EXTRACTED_BYTES, MAX_ZIP_ENTRIES, MAX_ZIP_PACKAGE_BYTES, type MockScanFileSuggestion, type NormalizedManifest, type PartialNormalizedManifest, type ProviderCapability, type ProviderCapabilityMap, type ProviderCredentialEnvelope, type ProviderCredentialType, type ReadinessLabel, type RemoteCaseSummary, type ReviewStatus, type SafeZipEntry, type SafeZipFailure, type SafeZipResult, type SafeZipSuccess, type ScanFileFormat, type ScanFileListItem, type ScanFileRole, type SourceVendor, type ThreeShapeCase, type ThreeShapeConfidence, type ThreeShapeFileEntry, type ThreeShapeFilesIndex, type ThreeShapeImplant, type ThreeShapeImplantComponent, type ThreeShapeMainOrderResult, type ThreeShapePrintableResult, type ThreeShapeRestoration, type ThreeShapeSummary, type ValidationProfile, type ValidationResult, buildExocadSummary, buildThreeShapeSummary, classifyExocadFile, classifyThreeShapeFile, collectCadMetadataFromZipEntries, detectExocadFiles, detectThreeShapeFiles, expandThreeShape3mlEntries, extractReadableStringsFromBinary, extractStringsFromDentalCAD, extractZipSafely, findDentalCadKeywords, inferGeometryCode, inferManufacturerFromIdsAndNames, inferStlRole, isCadSidecarFileName, isExocadPackage, isThreeShapePackage, mergeCadProjectParseResults, mergeExternalReferences, normalizeImplantComponent, normalizeImplantComponents, normalizeRestorationType, parseCadDcm, parseCadSidecarBytes, parseConstructionInfo, parseDentalProject, parseExternalModels, parseMainOrderXml, parseMaterialsXml, parseModelInfo, parsePrintableOrderForm, parseScans, sanitizeZipEntryPath, zipPackageTooLargeMessage };