@abyss-project/extract 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +32 -0
- package/.prettierrc +5 -0
- package/README.md +21 -2
- package/dist/api/extraction-plan-preset.api.d.ts +9 -0
- package/dist/api/extraction-plan-preset.api.js +36 -0
- package/dist/api/extraction-plan-preset.api.js.map +1 -0
- package/dist/api/extraction-plan-preset.api.test.d.ts +1 -0
- package/dist/api/extraction-plan-preset.api.test.js +51 -0
- package/dist/api/extraction-plan-preset.api.test.js.map +1 -0
- package/dist/api/extraction-settings.api.d.ts +4 -0
- package/dist/api/extraction-settings.api.js +22 -0
- package/dist/api/extraction-settings.api.js.map +1 -0
- package/dist/api/extraction.api.d.ts +76 -0
- package/dist/api/extraction.api.js +414 -0
- package/dist/api/extraction.api.js.map +1 -0
- package/dist/api/extraction.application.api.d.ts +4 -0
- package/dist/api/extraction.application.api.js +23 -0
- package/dist/api/extraction.application.api.js.map +1 -0
- package/dist/api/extraction.application.api.test.d.ts +1 -0
- package/dist/api/extraction.application.api.test.js +69 -0
- package/dist/api/extraction.application.api.test.js.map +1 -0
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.js +21 -0
- package/dist/api/index.js.map +1 -0
- package/dist/constants/extract.constants.d.ts +4 -0
- package/dist/constants/extract.constants.js +91 -0
- package/dist/constants/extract.constants.js.map +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +18 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +210 -0
- package/dist/index.js.map +1 -0
- package/dist/types/enum/api-error.enum.d.ts +31 -0
- package/dist/types/enum/api-error.enum.js +37 -0
- package/dist/types/enum/api-error.enum.js.map +1 -0
- package/dist/types/enum/combine-strategy.enum.d.ts +5 -0
- package/dist/types/enum/combine-strategy.enum.js +10 -0
- package/dist/types/enum/combine-strategy.enum.js.map +1 -0
- package/dist/types/enum/document-type.enum.d.ts +10 -0
- package/dist/types/enum/document-type.enum.js +15 -0
- package/dist/types/enum/document-type.enum.js.map +1 -0
- package/dist/types/enum/extract-bank.enum.d.ts +50 -0
- package/dist/types/enum/extract-bank.enum.js +327 -0
- package/dist/types/enum/extract-bank.enum.js.map +1 -0
- package/dist/types/enum/extract-field-format.enum.d.ts +7 -0
- package/dist/types/enum/extract-field-format.enum.js +12 -0
- package/dist/types/enum/extract-field-format.enum.js.map +1 -0
- package/dist/types/enum/extract-field-key.enum.d.ts +59 -0
- package/dist/types/enum/extract-field-key.enum.js +64 -0
- package/dist/types/enum/extract-field-key.enum.js.map +1 -0
- package/dist/types/enum/extraction-feedback-issue-type.enum.d.ts +8 -0
- package/dist/types/enum/extraction-feedback-issue-type.enum.js +13 -0
- package/dist/types/enum/extraction-feedback-issue-type.enum.js.map +1 -0
- package/dist/types/enum/extraction-step-status.enum.d.ts +6 -0
- package/dist/types/enum/extraction-step-status.enum.js +11 -0
- package/dist/types/enum/extraction-step-status.enum.js.map +1 -0
- package/dist/types/enum/extraction-warning.enum.d.ts +10 -0
- package/dist/types/enum/extraction-warning.enum.js +15 -0
- package/dist/types/enum/extraction-warning.enum.js.map +1 -0
- package/dist/types/enum/file-scan-status.enum.d.ts +1 -0
- package/dist/types/enum/file-scan-status.enum.js +3 -0
- package/dist/types/enum/file-scan-status.enum.js.map +1 -0
- package/dist/types/enum/index.d.ts +12 -0
- package/dist/types/enum/index.js +29 -0
- package/dist/types/enum/index.js.map +1 -0
- package/dist/types/enum/interpreter-kind.enum.d.ts +5 -0
- package/dist/types/enum/interpreter-kind.enum.js +10 -0
- package/dist/types/enum/interpreter-kind.enum.js.map +1 -0
- package/dist/types/enum/provider-kind.enum.d.ts +10 -0
- package/dist/types/enum/provider-kind.enum.js +16 -0
- package/dist/types/enum/provider-kind.enum.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/interface/api/index.d.ts +5 -0
- package/dist/types/interface/api/index.js +22 -0
- package/dist/types/interface/api/index.js.map +1 -0
- package/dist/types/interface/api/requests/extraction.request.d.ts +259 -0
- package/dist/types/interface/api/requests/extraction.request.js +3 -0
- package/dist/types/interface/api/requests/extraction.request.js.map +1 -0
- package/dist/types/interface/api/requests/index.d.ts +1 -0
- package/dist/types/interface/api/requests/index.js +18 -0
- package/dist/types/interface/api/requests/index.js.map +1 -0
- package/dist/types/interface/api/responses/extraction.response.d.ts +424 -0
- package/dist/types/interface/api/responses/extraction.response.js +3 -0
- package/dist/types/interface/api/responses/extraction.response.js.map +1 -0
- package/dist/types/interface/api/responses/index.d.ts +1 -0
- package/dist/types/interface/api/responses/index.js +18 -0
- package/dist/types/interface/api/responses/index.js.map +1 -0
- package/dist/types/interface/api/type-message/api-error.d.ts +6 -0
- package/dist/types/interface/api/type-message/api-error.js +3 -0
- package/dist/types/interface/api/type-message/api-error.js.map +1 -0
- package/dist/types/interface/api/type-message/base-paginate.d.ts +10 -0
- package/dist/types/interface/api/type-message/base-paginate.js +3 -0
- package/dist/types/interface/api/type-message/base-paginate.js.map +1 -0
- package/dist/types/interface/api/type-message/response.d.ts +5 -0
- package/dist/types/interface/api/type-message/response.js +3 -0
- package/dist/types/interface/api/type-message/response.js.map +1 -0
- package/dist/types/interface/index.d.ts +2 -0
- package/dist/types/interface/index.js +19 -0
- package/dist/types/interface/index.js.map +1 -0
- package/dist/types/interface/models/extraction-fetched-provenance.dto.test.d.ts +1 -0
- package/dist/types/interface/models/extraction-fetched-provenance.dto.test.js +165 -0
- package/dist/types/interface/models/extraction-fetched-provenance.dto.test.js.map +1 -0
- package/dist/types/interface/models/extraction-plan.dto.d.ts +192 -0
- package/dist/types/interface/models/extraction-plan.dto.js +13 -0
- package/dist/types/interface/models/extraction-plan.dto.js.map +1 -0
- package/dist/types/interface/models/extraction-plan.dto.test.d.ts +1 -0
- package/dist/types/interface/models/extraction-plan.dto.test.js +40 -0
- package/dist/types/interface/models/extraction-plan.dto.test.js.map +1 -0
- package/dist/types/interface/models/extraction-spatial-template.dto.d.ts +37 -0
- package/dist/types/interface/models/extraction-spatial-template.dto.js +3 -0
- package/dist/types/interface/models/extraction-spatial-template.dto.js.map +1 -0
- package/dist/types/interface/models/extraction-spatial-template.dto.test.d.ts +1 -0
- package/dist/types/interface/models/extraction-spatial-template.dto.test.js +32 -0
- package/dist/types/interface/models/extraction-spatial-template.dto.test.js.map +1 -0
- package/dist/types/interface/models/extraction.dto.d.ts +255 -0
- package/dist/types/interface/models/extraction.dto.js +28 -0
- package/dist/types/interface/models/extraction.dto.js.map +1 -0
- package/dist/types/interface/models/index.d.ts +3 -0
- package/dist/types/interface/models/index.js +20 -0
- package/dist/types/interface/models/index.js.map +1 -0
- package/dist/utils/enum.utils.d.ts +1 -0
- package/dist/utils/enum.utils.js +3 -0
- package/dist/utils/enum.utils.js.map +1 -0
- package/dist/utils/error.utils.d.ts +15 -0
- package/dist/utils/error.utils.js +25 -0
- package/dist/utils/error.utils.js.map +1 -0
- package/dist/utils/extraction-webhook.utils.d.ts +6 -0
- package/dist/utils/extraction-webhook.utils.js +17 -0
- package/dist/utils/extraction-webhook.utils.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +58 -4
- package/src/api/extraction-plan-preset.api.test.ts +24 -0
- package/src/api/extraction-plan-preset.api.ts +97 -0
- package/src/api/extraction-settings.api.ts +53 -0
- package/src/api/extraction.api.ts +1012 -0
- package/src/api/extraction.application.api.test.ts +55 -0
- package/src/api/extraction.application.api.ts +73 -0
- package/src/api/index.ts +4 -0
- package/src/constants/extract.constants.ts +109 -0
- package/src/constants/index.ts +1 -0
- package/src/index.ts +305 -0
- package/src/types/enum/api-error.enum.ts +33 -0
- package/src/types/enum/combine-strategy.enum.ts +7 -0
- package/src/types/enum/document-type.enum.ts +11 -0
- package/src/types/enum/extract-bank.enum.ts +363 -0
- package/src/types/enum/extract-field-format.enum.ts +16 -0
- package/src/types/enum/extract-field-key.enum.ts +77 -0
- package/src/types/enum/extraction-feedback-issue-type.enum.ts +10 -0
- package/src/types/enum/extraction-step-status.enum.ts +7 -0
- package/src/types/enum/extraction-warning.enum.ts +78 -0
- package/src/types/enum/file-scan-status.enum.ts +33 -0
- package/src/types/enum/index.ts +12 -0
- package/src/types/enum/interpreter-kind.enum.ts +7 -0
- package/src/types/enum/provider-kind.enum.ts +13 -0
- package/src/types/index.ts +2 -0
- package/src/types/interface/api/index.ts +5 -0
- package/src/types/interface/api/requests/extraction.request.ts +423 -0
- package/src/types/interface/api/requests/index.ts +1 -0
- package/src/types/interface/api/responses/extraction.response.ts +488 -0
- package/src/types/interface/api/responses/index.ts +1 -0
- package/src/types/interface/api/type-message/api-error.ts +7 -0
- package/src/types/interface/api/type-message/base-paginate.ts +11 -0
- package/src/types/interface/api/type-message/response.ts +6 -0
- package/src/types/interface/index.ts +2 -0
- package/src/types/interface/models/extraction-fetched-provenance.dto.test.ts +204 -0
- package/src/types/interface/models/extraction-plan.dto.test.ts +60 -0
- package/src/types/interface/models/extraction-plan.dto.ts +280 -0
- package/src/types/interface/models/extraction-spatial-template.dto.test.ts +48 -0
- package/src/types/interface/models/extraction-spatial-template.dto.ts +48 -0
- package/src/types/interface/models/extraction.dto.ts +399 -0
- package/src/types/interface/models/index.ts +3 -0
- package/src/types/tests/extract-bank-catalogue.spec.ts +74 -0
- package/src/utils/enum.utils.ts +1 -0
- package/src/utils/error.utils.ts +30 -0
- package/src/utils/extraction-webhook.utils.ts +30 -0
- package/src/utils/index.ts +3 -0
- package/tsconfig.check.json +15 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// ──────────────────────────────────────────────
|
|
2
|
+
// Extraction DTOs.
|
|
3
|
+
// Mirror server-side Sequelize models, dates serialized as ISO strings.
|
|
4
|
+
// ──────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
import { ExtractionWarningCode } from '../../../types/enum/extraction-warning.enum';
|
|
7
|
+
import { ExtractionFeedbackIssueType } from '../../../types/enum/extraction-feedback-issue-type.enum';
|
|
8
|
+
import { DocumentType } from '../../../types/enum/document-type.enum';
|
|
9
|
+
import { FileScanStatus } from '../../enum/file-scan-status.enum';
|
|
10
|
+
import type {
|
|
11
|
+
IFieldValue,
|
|
12
|
+
IExecutionManifest,
|
|
13
|
+
IGlobalConfidence,
|
|
14
|
+
IExecutionTrace,
|
|
15
|
+
} from './extraction-plan.dto';
|
|
16
|
+
|
|
17
|
+
// Re-export so consumers can import ExtractionFeedbackIssueType from the DTO barrel.
|
|
18
|
+
export { ExtractionFeedbackIssueType };
|
|
19
|
+
|
|
20
|
+
export type ExtractionMode = 'auto' | 'hint' | 'template';
|
|
21
|
+
export type ProcessingMode = 'sync' | 'queue';
|
|
22
|
+
export type ExtractionStatus = 'pending' | 'completed' | 'failed' | 'cached';
|
|
23
|
+
|
|
24
|
+
export type ExtractionFeedbackStatus = 'open' | 'triaged' | 'fixed' | 'closed';
|
|
25
|
+
|
|
26
|
+
export type ExtractionUsageEventType =
|
|
27
|
+
| 'extract.sync.success'
|
|
28
|
+
| 'extract.sync.cached'
|
|
29
|
+
| 'extract.sync.failed'
|
|
30
|
+
| 'extract.queue.enqueued'
|
|
31
|
+
| 'extract.queue.success'
|
|
32
|
+
| 'extract.queue.cached'
|
|
33
|
+
| 'extract.queue.failed'
|
|
34
|
+
| 'template.run.success'
|
|
35
|
+
| 'template.run.failed';
|
|
36
|
+
|
|
37
|
+
export interface IExtractionBankHint {
|
|
38
|
+
bank: string;
|
|
39
|
+
version?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface IExtractionTransaction {
|
|
43
|
+
date?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
amount?: number;
|
|
46
|
+
balance?: number;
|
|
47
|
+
valueDate?: string;
|
|
48
|
+
bookingDate?: string;
|
|
49
|
+
reference?: string;
|
|
50
|
+
[k: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IExtractionMetadata {
|
|
54
|
+
iban?: string;
|
|
55
|
+
bic?: string;
|
|
56
|
+
bank?: string;
|
|
57
|
+
accountHolder?: string;
|
|
58
|
+
periodStart?: string;
|
|
59
|
+
periodEnd?: string;
|
|
60
|
+
openingBalance?: number;
|
|
61
|
+
closingBalance?: number;
|
|
62
|
+
currency?: string;
|
|
63
|
+
[k: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Payslip (fiche de paie) metadata, extracted generically by FR labels — no
|
|
68
|
+
* per-employer template. Amounts are integer cents; `pasRatePct` is a percent
|
|
69
|
+
* (e.g. 3.6 for 3,6 %). `period` is a stable label (ISO month or a "du … au …"
|
|
70
|
+
* span). Every field is optional: a field is present only when confidently found.
|
|
71
|
+
*/
|
|
72
|
+
export interface IPayslipMetadata {
|
|
73
|
+
netCents?: number;
|
|
74
|
+
grossCents?: number;
|
|
75
|
+
netTaxableCents?: number;
|
|
76
|
+
pasRatePct?: number;
|
|
77
|
+
pasAmountCents?: number;
|
|
78
|
+
period?: string;
|
|
79
|
+
employer?: string;
|
|
80
|
+
currency?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface IExtractionFile {
|
|
84
|
+
id: string;
|
|
85
|
+
userId: string;
|
|
86
|
+
applicationId: string | null;
|
|
87
|
+
pdfHash: string;
|
|
88
|
+
pdfSizeBytes: number;
|
|
89
|
+
pdfMimeType: string;
|
|
90
|
+
pdfPageCount: number | null;
|
|
91
|
+
pdfFilename: string | null;
|
|
92
|
+
applicationFileId: string | null;
|
|
93
|
+
userExternalId: string | null;
|
|
94
|
+
userMetadata: Record<string, unknown> | null;
|
|
95
|
+
detectedBank: string | null;
|
|
96
|
+
detectedVersion: string | null;
|
|
97
|
+
detectedIban: string | null;
|
|
98
|
+
detectedBic: string | null;
|
|
99
|
+
detectedCurrency: string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Antivirus verdict mirrored from AbyssStorage for an ARCHIVE-OWNED file
|
|
102
|
+
* only (seeded at extractionFileService.upsert from the archive-upload
|
|
103
|
+
* response — see extraction-extract.service.ts#archivePdf — and updated by
|
|
104
|
+
* the SCAN_RESULT webhook, storage-webhook.service.ts#handleScanResult).
|
|
105
|
+
* Null for a by-reference file (AbyssExtract never requested that scan, so
|
|
106
|
+
* it never mirrors a verdict for it) and for rows created before this
|
|
107
|
+
* column existed. Storage-neutral (ADR-0038): purely informational — never
|
|
108
|
+
* redacted, never gates a read.
|
|
109
|
+
*/
|
|
110
|
+
scanStatus: FileScanStatus | null;
|
|
111
|
+
createdAt: string;
|
|
112
|
+
updatedAt: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Re-export ExtractionWarningCode so consumers can import it from the dto barrel.
|
|
116
|
+
export { ExtractionWarningCode };
|
|
117
|
+
|
|
118
|
+
export interface IExtractionWarning {
|
|
119
|
+
code: ExtractionWarningCode;
|
|
120
|
+
data?: {
|
|
121
|
+
/** Balance mismatch data (bank_statement). */
|
|
122
|
+
actualCents?: number;
|
|
123
|
+
expectedCents?: number;
|
|
124
|
+
currency?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Adapter-specific validation error/warning type string, e.g.
|
|
127
|
+
* `ACTIF_PASSIF_MISMATCH`, `TOTAL_MISMATCH`, `MRZ_INVALID`.
|
|
128
|
+
* Present when `code === ExtractionWarningCode.ADAPTER_VALIDATION_ERROR`.
|
|
129
|
+
*/
|
|
130
|
+
type?: string;
|
|
131
|
+
/** Human-readable explanation from the adapter's ValidationResult. */
|
|
132
|
+
message?: string;
|
|
133
|
+
/**
|
|
134
|
+
* The withheld field's name. Present for the per-field withdrawal codes
|
|
135
|
+
* (`FIELD_BELOW_PUBLISH_FLOOR`, `FIELD_FORMAT_ONLY_DATE` #575,
|
|
136
|
+
* `FIELD_MRZ_OUT_OF_DOMAIN` #614).
|
|
137
|
+
*/
|
|
138
|
+
fieldKey?: string;
|
|
139
|
+
/**
|
|
140
|
+
* The field's calibrated confidence at the time it was withheld. Present
|
|
141
|
+
* for the per-field withdrawal codes. Never the value itself.
|
|
142
|
+
*/
|
|
143
|
+
confidence?: number;
|
|
144
|
+
/**
|
|
145
|
+
* The publish floor the field missed. Present only for
|
|
146
|
+
* `FIELD_BELOW_PUBLISH_FLOOR` — neither a `FIELD_FORMAT_ONLY_DATE` nor a
|
|
147
|
+
* `FIELD_MRZ_OUT_OF_DOMAIN` withdrawal is a floor comparison, and their
|
|
148
|
+
* confidence can sit above the field's floor.
|
|
149
|
+
*/
|
|
150
|
+
floor?: number;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface IExtraction {
|
|
155
|
+
id: string;
|
|
156
|
+
fileId: string;
|
|
157
|
+
mode: ExtractionMode;
|
|
158
|
+
hintBank: string | null;
|
|
159
|
+
hintVersion: string | null;
|
|
160
|
+
templateId: string | null;
|
|
161
|
+
templateVersion: number | null;
|
|
162
|
+
status: ExtractionStatus;
|
|
163
|
+
strategyUsed: string | null;
|
|
164
|
+
confidence: number | null;
|
|
165
|
+
recordsCount: number | null;
|
|
166
|
+
balanceValidated: boolean | null;
|
|
167
|
+
durationMs: number | null;
|
|
168
|
+
error: string | null;
|
|
169
|
+
recordsJson: IExtractionTransaction[] | null;
|
|
170
|
+
metadataJson: IExtractionMetadata | null;
|
|
171
|
+
warningsJson: IExtractionWarning[] | null;
|
|
172
|
+
tags: string[] | null;
|
|
173
|
+
note: string | null;
|
|
174
|
+
shareToken: string | null;
|
|
175
|
+
shareExpiresAt: string | null;
|
|
176
|
+
documentType: string | null;
|
|
177
|
+
documentTypeConfidence: number | null;
|
|
178
|
+
/**
|
|
179
|
+
* Persisted per-field results. Widened (V2-P1, ADDITIVE) to the IFieldValue
|
|
180
|
+
* superset: value + confidence stay at the SAME path (old readers unaffected),
|
|
181
|
+
* and the plan path additionally surfaces chosen / sources / signals /
|
|
182
|
+
* agreement provenance. Legacy template/hints rows persist only value +
|
|
183
|
+
* confidence (still a valid IFieldValue subset on the wire).
|
|
184
|
+
*/
|
|
185
|
+
fieldsJson: Record<string, IFieldValue> | null;
|
|
186
|
+
improvementConsent: boolean;
|
|
187
|
+
usableForTraining: boolean;
|
|
188
|
+
supportTicketId: string | null;
|
|
189
|
+
/** AbyssExtract-owned training copy (extraction-training bucket). Purgeable. */
|
|
190
|
+
trainingFileId: string | null;
|
|
191
|
+
/** Whether the OCR layer was used for this extraction run. */
|
|
192
|
+
usedOcr: boolean;
|
|
193
|
+
/** Number of pages processed by the OCR layer. */
|
|
194
|
+
ocrPageCount: number;
|
|
195
|
+
/**
|
|
196
|
+
* Frozen execution manifest (resolved plan + per-pass impl/version) — the
|
|
197
|
+
* reproducible recipe. Present on plan-path rows; absent (null/undefined) on
|
|
198
|
+
* legacy template/hints rows. ADDITIVE, optional.
|
|
199
|
+
*/
|
|
200
|
+
executionManifest?: IExecutionManifest | null;
|
|
201
|
+
/**
|
|
202
|
+
* Auditable global confidence (stats + aggregation + per-pass contributions).
|
|
203
|
+
* Surfaced where available; optional/absent otherwise. ADDITIVE, optional.
|
|
204
|
+
*/
|
|
205
|
+
globalConfidence?: IGlobalConfidence | null;
|
|
206
|
+
/**
|
|
207
|
+
* Per-pass execution trace skeleton (timing/status/impl + lazy IO refs) — P1.
|
|
208
|
+
* Present on plan-path rows; absent on legacy paths. ADDITIVE, optional.
|
|
209
|
+
*/
|
|
210
|
+
executionTrace?: IExecutionTrace | null;
|
|
211
|
+
createdAt: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface IExtractionTemplate {
|
|
215
|
+
id: string;
|
|
216
|
+
/** Personal scope owner — null when the template is org/project-scoped. */
|
|
217
|
+
userId: string | null;
|
|
218
|
+
/** Owning organization — null for personal templates. */
|
|
219
|
+
organizationId: string | null;
|
|
220
|
+
/** Owning project — null for personal and org-wide templates. */
|
|
221
|
+
projectId: string | null;
|
|
222
|
+
/** Author inside an org/project scope — null for personal templates. */
|
|
223
|
+
createdByUserId: string | null;
|
|
224
|
+
name: string;
|
|
225
|
+
description: string | null;
|
|
226
|
+
/**
|
|
227
|
+
* Kind of document the template targets (DocumentType). Null when the
|
|
228
|
+
* template declares no type. Authoritative — spatial templates also embed
|
|
229
|
+
* `templateJson.documentType`, but this column is the source of truth.
|
|
230
|
+
*/
|
|
231
|
+
documentType: DocumentType | null;
|
|
232
|
+
isActive: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Stamped (fire-and-forget) whenever an extraction run resolves the
|
|
235
|
+
* template. Null until first use.
|
|
236
|
+
*/
|
|
237
|
+
lastUsedAt: string | null;
|
|
238
|
+
createdAt: string;
|
|
239
|
+
updatedAt: string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Spatial zone on a PDF page (PDF coords: origin bottom-left, points).
|
|
244
|
+
* Restricts regex matching to a specific rectangle.
|
|
245
|
+
*/
|
|
246
|
+
export interface IExtractionTemplateZone {
|
|
247
|
+
name: string;
|
|
248
|
+
page: number; // 1-indexed
|
|
249
|
+
x: number;
|
|
250
|
+
y: number;
|
|
251
|
+
w: number;
|
|
252
|
+
h: number;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Typed shape of the template DSL JSON stored in `templateJson`. Mirrors
|
|
257
|
+
* `TemplateDSL` server-side. UI editors should narrow `templateJson` to this
|
|
258
|
+
* shape via `templateJson as IExtractionTemplateDsl`.
|
|
259
|
+
*/
|
|
260
|
+
export interface IExtractionTemplateDsl {
|
|
261
|
+
regex_iban?: string;
|
|
262
|
+
regex_bic?: string;
|
|
263
|
+
period?: { regex: string };
|
|
264
|
+
balance?: { opening_regex?: string; closing_regex?: string };
|
|
265
|
+
transactions?: {
|
|
266
|
+
row_pattern: string;
|
|
267
|
+
date_format?: string;
|
|
268
|
+
amount_locale?: 'fr' | 'en';
|
|
269
|
+
sign_rule?: 'explicit' | 'keyword';
|
|
270
|
+
};
|
|
271
|
+
skip_patterns?: string[];
|
|
272
|
+
zones?: IExtractionTemplateZone[];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface IExtractionTemplateVersion {
|
|
276
|
+
id: string;
|
|
277
|
+
templateId: string;
|
|
278
|
+
version: number;
|
|
279
|
+
templateJson: Record<string, unknown>;
|
|
280
|
+
comment: string | null;
|
|
281
|
+
/**
|
|
282
|
+
* Witness (sample) PDF reference in the dedicated /rcb-witness bucket.
|
|
283
|
+
* Null when the version carries no witness. Retrieve a download URL via
|
|
284
|
+
* `sdk.extract.templates.getWitnessUrl`.
|
|
285
|
+
*/
|
|
286
|
+
witnessFileId: string | null;
|
|
287
|
+
/** Witness byte size (billed to the owner's storage pool). */
|
|
288
|
+
witnessSizeBytes: number | null;
|
|
289
|
+
/** Original witness filename. */
|
|
290
|
+
witnessFilename: string | null;
|
|
291
|
+
createdAt: string;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface IExtractionFeedback {
|
|
295
|
+
id: string;
|
|
296
|
+
extractionId: string;
|
|
297
|
+
userId: string;
|
|
298
|
+
issueType: ExtractionFeedbackIssueType;
|
|
299
|
+
fieldKey: string | null;
|
|
300
|
+
expectedValue: string | null;
|
|
301
|
+
description: string | null;
|
|
302
|
+
supportTicketId: string | null;
|
|
303
|
+
status: ExtractionFeedbackStatus;
|
|
304
|
+
createdAt: string;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export interface IExtractionWebhookDelivery {
|
|
308
|
+
id: string;
|
|
309
|
+
userId: string | null;
|
|
310
|
+
organizationId: string | null;
|
|
311
|
+
projectId: string | null;
|
|
312
|
+
createdByUserId: string | null;
|
|
313
|
+
webhookId: string | null;
|
|
314
|
+
jobId: string | null;
|
|
315
|
+
event: string;
|
|
316
|
+
url: string;
|
|
317
|
+
payloadJson: Record<string, unknown>;
|
|
318
|
+
attempts: number;
|
|
319
|
+
lastStatus: number | null;
|
|
320
|
+
lastError: string | null;
|
|
321
|
+
deliveredAt: string | null;
|
|
322
|
+
createdAt: string;
|
|
323
|
+
updatedAt: string;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Webhook event identifier. Values mirror the AbyssApplicationEvent extraction
|
|
327
|
+
// entries so a logger.log(applicationEvent: ...) and a webhook delivery
|
|
328
|
+
// can never drift.
|
|
329
|
+
export enum ExtractionWebhookEvent {
|
|
330
|
+
EXTRACT_COMPLETED = 'rcb.extract.completed',
|
|
331
|
+
EXTRACT_FAILED = 'rcb.extract.failed',
|
|
332
|
+
EXTRACT_LOW_CONFIDENCE = 'rcb.extract.low-confidence',
|
|
333
|
+
EXTRACT_BALANCE_KO = 'rcb.extract.balance-ko',
|
|
334
|
+
FILE_ARCHIVED = 'rcb.file.archived',
|
|
335
|
+
SHARE_MINTED = 'rcb.share.minted',
|
|
336
|
+
SHARE_REVOKED = 'rcb.share.revoked',
|
|
337
|
+
FEEDBACK_SUBMITTED = 'rcb.feedback.submitted',
|
|
338
|
+
JOB_FAILED = 'rcb.job.failed',
|
|
339
|
+
EXPORT_COMPLETED = 'rcb.export.completed',
|
|
340
|
+
EXPORT_FAILED = 'rcb.export.failed',
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export const EXTRACTION_WEBHOOK_EVENTS: ExtractionWebhookEvent[] =
|
|
344
|
+
Object.values(ExtractionWebhookEvent);
|
|
345
|
+
|
|
346
|
+
export interface IExtractionWebhook {
|
|
347
|
+
id: string;
|
|
348
|
+
userId: string | null;
|
|
349
|
+
organizationId: string | null;
|
|
350
|
+
projectId: string | null;
|
|
351
|
+
createdByUserId: string | null;
|
|
352
|
+
webhookUrl: string;
|
|
353
|
+
webhookSecret: string;
|
|
354
|
+
isEnabled: boolean;
|
|
355
|
+
name: string;
|
|
356
|
+
description: string;
|
|
357
|
+
scopes: ExtractionWebhookEvent[];
|
|
358
|
+
consecutiveFailures: number;
|
|
359
|
+
createdAt: string;
|
|
360
|
+
updatedAt: string;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export interface IExtractionBankVersion {
|
|
364
|
+
id: string;
|
|
365
|
+
bank: string;
|
|
366
|
+
version: string;
|
|
367
|
+
validFrom: string | null;
|
|
368
|
+
validTo: string | null;
|
|
369
|
+
detectorJson: Record<string, unknown>;
|
|
370
|
+
parserKind: string;
|
|
371
|
+
configJson: Record<string, unknown>;
|
|
372
|
+
isActive: boolean;
|
|
373
|
+
createdAt: string;
|
|
374
|
+
updatedAt: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ─── EXTRACTION SETTINGS (P4) ────────────────────────────────────────────────
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Scope discriminator for extraction settings.
|
|
381
|
+
* 'user' = personal scope; 'org' = organization scope.
|
|
382
|
+
*/
|
|
383
|
+
export enum ExtractionSettingsScopeKind {
|
|
384
|
+
USER = 'user',
|
|
385
|
+
ORG = 'org',
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Per-scope improvement-consent settings row. */
|
|
389
|
+
export interface IExtractionSettings {
|
|
390
|
+
id: string;
|
|
391
|
+
/** Set for personal scope. XOR with organizationId. */
|
|
392
|
+
userId: string | null;
|
|
393
|
+
/** Set for organization scope. XOR with userId. */
|
|
394
|
+
organizationId: string | null;
|
|
395
|
+
/** Factory default for per-extraction improvementConsent. OFF (false) by default. */
|
|
396
|
+
improvementDefault: boolean;
|
|
397
|
+
createdAt: string;
|
|
398
|
+
updatedAt: string;
|
|
399
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EXTRACT_BANK_CATALOGUE,
|
|
3
|
+
ExtractBankVersionId,
|
|
4
|
+
getExtractBankCatalogueEntry,
|
|
5
|
+
groupExtractCatalogueByBank,
|
|
6
|
+
} from '../enum/extract-bank.enum';
|
|
7
|
+
|
|
8
|
+
// Snapshot of the catalogue as shipped before the rename (id, bank, version, country, type).
|
|
9
|
+
const EXPECTED_ENTRIES: ReadonlyArray<readonly [string, string, string, string, string]> = [
|
|
10
|
+
['bnp-connexis-default', 'BNP Connexis', 'default', 'FR', 'business'],
|
|
11
|
+
['bnp-paribas-default', 'BNP Paribas', 'default', 'FR', 'retail'],
|
|
12
|
+
['societe-generale-default', 'Société Générale', 'default', 'FR', 'retail'],
|
|
13
|
+
['credit-agricole-default', 'Crédit Agricole', 'default', 'FR', 'retail'],
|
|
14
|
+
['lcl-default', 'LCL', 'default', 'FR', 'retail'],
|
|
15
|
+
['boursorama-default', 'Boursorama', 'default', 'FR', 'retail'],
|
|
16
|
+
['la-banque-postale-default', 'La Banque Postale', 'default', 'FR', 'retail'],
|
|
17
|
+
['caisse-epargne-default', "Caisse d'Épargne", 'default', 'FR', 'retail'],
|
|
18
|
+
['cic-ebics-default', 'CIC', 'ebics', 'FR', 'business'],
|
|
19
|
+
['cic-default', 'CIC', 'default', 'FR', 'retail'],
|
|
20
|
+
['credit-mutuel-default', 'Crédit Mutuel', 'default', 'FR', 'retail'],
|
|
21
|
+
['bred-default', 'BRED', 'default', 'FR', 'retail'],
|
|
22
|
+
['cdn-default', 'Crédit du Nord', 'default', 'FR', 'retail'],
|
|
23
|
+
['cde-net-default', 'CDE Net', 'default', 'FR', 'business'],
|
|
24
|
+
['delubac-default', 'Delubac', 'default', 'FR', 'business'],
|
|
25
|
+
['palatine-default', 'Palatine', 'default', 'FR', 'business'],
|
|
26
|
+
['natixis-default', 'Natixis', 'default', 'FR', 'corporate'],
|
|
27
|
+
['themis-default', 'Themis Banque', 'default', 'FR', 'business'],
|
|
28
|
+
['rothschild-default', 'Rothschild Martin Maurel', 'default', 'FR', 'corporate'],
|
|
29
|
+
['la-nef-v1', 'La Nef', 'v1', 'FR', 'retail'],
|
|
30
|
+
['la-nef-v2', 'La Nef', 'v2', 'FR', 'retail'],
|
|
31
|
+
['qonto-default', 'Qonto', 'default', 'FR', 'neobank'],
|
|
32
|
+
['shine-default', 'Shine', 'default', 'FR', 'neobank'],
|
|
33
|
+
['finom-default', 'Finom', 'default', 'EU', 'neobank'],
|
|
34
|
+
['tiime-default', 'Tiime', 'default', 'FR', 'neobank'],
|
|
35
|
+
['spendesk-default', 'Spendesk', 'default', 'FR', 'fintech'],
|
|
36
|
+
['swan-default', 'Swan', 'default', 'FR', 'fintech'],
|
|
37
|
+
['n26-default', 'N26', 'default', 'EU', 'neobank'],
|
|
38
|
+
['revolut-default', 'Revolut', 'default', 'EU', 'neobank'],
|
|
39
|
+
['wise-default', 'Wise', 'default', 'INTL', 'fintech'],
|
|
40
|
+
['paypal-default', 'PayPal', 'default', 'INTL', 'fintech'],
|
|
41
|
+
['airwallex-default', 'Airwallex', 'default', 'INTL', 'fintech'],
|
|
42
|
+
['viva-wallet-default', 'Viva Wallet', 'default', 'EU', 'fintech'],
|
|
43
|
+
['hsbc-default', 'HSBC', 'default', 'FR', 'retail'],
|
|
44
|
+
['hsbc-uk-default', 'HSBC UK', 'default', 'UK', 'retail'],
|
|
45
|
+
['ubs-default', 'UBS', 'default', 'CH', 'corporate'],
|
|
46
|
+
['caixa-default', 'Caixa', 'default', 'PT', 'retail'],
|
|
47
|
+
['jpmorgan-default', 'JPMorgan', 'default', 'US', 'corporate'],
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
describe('EXTRACT_BANK_CATALOGUE', () => {
|
|
51
|
+
it('holds the same entries as the catalogue it was renamed from', () => {
|
|
52
|
+
const actual = EXTRACT_BANK_CATALOGUE.map((e) => [e.id, e.bank, e.version, e.country, e.type]);
|
|
53
|
+
expect(actual).toEqual(EXPECTED_ENTRIES);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('references only ids declared in ExtractBankVersionId', () => {
|
|
57
|
+
const declared = new Set<string>(Object.values(ExtractBankVersionId));
|
|
58
|
+
for (const entry of EXTRACT_BANK_CATALOGUE) {
|
|
59
|
+
expect(declared.has(entry.id)).toBe(true);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('looks an entry up by id', () => {
|
|
64
|
+
expect(getExtractBankCatalogueEntry('qonto-default')?.bank).toBe('Qonto');
|
|
65
|
+
expect(getExtractBankCatalogueEntry('unknown')).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('groups every entry under its bank', () => {
|
|
69
|
+
const grouped = groupExtractCatalogueByBank();
|
|
70
|
+
const total = Array.from(grouped.values()).reduce((sum, list) => sum + list.length, 0);
|
|
71
|
+
expect(total).toBe(EXTRACT_BANK_CATALOGUE.length);
|
|
72
|
+
expect(grouped.get('La Nef')?.map((e) => e.version)).toEqual(['v1', 'v2']);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ValueOf<T> = T[keyof T];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Code, ErrorType } from '../types';
|
|
2
|
+
|
|
3
|
+
type ErrorParams = { code: Code; type: ErrorType; message?: string };
|
|
4
|
+
|
|
5
|
+
export class ServiceException extends Error {
|
|
6
|
+
private readonly code: Code;
|
|
7
|
+
|
|
8
|
+
private readonly type: ErrorType;
|
|
9
|
+
|
|
10
|
+
getCode(): Code {
|
|
11
|
+
return this.code;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getType(): ErrorType {
|
|
15
|
+
return this.type;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
constructor(params: ErrorParams) {
|
|
19
|
+
super(params.message);
|
|
20
|
+
this.code = params.code;
|
|
21
|
+
this.type = params.type;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const handleError = (error: Error | ErrorParams, _params?: ErrorParams): Error => {
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
return error;
|
|
28
|
+
}
|
|
29
|
+
return new ServiceException(error);
|
|
30
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// ──────────────────────────────────────────────
|
|
2
|
+
// Extraction webhook signature verification (server-side helper for receivers).
|
|
3
|
+
//
|
|
4
|
+
// The AbyssExtract queue signs every webhook delivery with HMAC-SHA256 of
|
|
5
|
+
// the raw JSON body using the secret provided at extract time. Receivers
|
|
6
|
+
// compare the x-rcb-signature header (format `sha256=<hex>`) against the
|
|
7
|
+
// same computation. Constant-time compare prevents timing attacks.
|
|
8
|
+
//
|
|
9
|
+
// Lazy-requires `crypto` so the SDK stays browser-compatible when this
|
|
10
|
+
// utility is never invoked (browsers won't receive webhooks anyway).
|
|
11
|
+
// ──────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export interface VerifyExtractionWebhookInput {
|
|
14
|
+
rawBody: string | Buffer;
|
|
15
|
+
signatureHeader: string | undefined;
|
|
16
|
+
secret: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function verifyExtractionWebhook(input: VerifyExtractionWebhookInput): boolean {
|
|
20
|
+
if (!input.signatureHeader || !input.secret) return false;
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
22
|
+
const crypto = require('crypto');
|
|
23
|
+
const provided = input.signatureHeader.replace(/^sha256=/, '');
|
|
24
|
+
const computed: string = crypto
|
|
25
|
+
.createHmac('sha256', input.secret)
|
|
26
|
+
.update(input.rawBody)
|
|
27
|
+
.digest('hex');
|
|
28
|
+
if (provided.length !== computed.length) return false;
|
|
29
|
+
return crypto.timingSafeEqual(Buffer.from(provided, 'hex'), Buffer.from(computed, 'hex'));
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Perimetre de VERIFICATION, distinct de celui du build.
|
|
3
|
+
//
|
|
4
|
+
// `tsconfig.json` exclut `src/**/*.spec.ts` parce qu'il sert a emettre `dist/`, ou une spec
|
|
5
|
+
// n'a rien a faire. Mais eslint s'appuie sur ce meme fichier via `parserOptions.project` :
|
|
6
|
+
// les cinq specs du paquet sortaient donc en « Parsing error: that TSConfig does not include
|
|
7
|
+
// this file », mesure du 2026-09-09, et n'etaient lintees par personne.
|
|
8
|
+
//
|
|
9
|
+
// Ce fichier sert uniquement a eslint. Il n'emet rien et ne change pas ce que `build` produit.
|
|
10
|
+
"extends": "./tsconfig.json",
|
|
11
|
+
"compilerOptions": {
|
|
12
|
+
"noEmit": true
|
|
13
|
+
},
|
|
14
|
+
"exclude": ["./dist/**/*"]
|
|
15
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"incremental": false,
|
|
4
|
+
"target": "es2021",
|
|
5
|
+
"lib": [
|
|
6
|
+
"dom",
|
|
7
|
+
"es2021"
|
|
8
|
+
],
|
|
9
|
+
"experimentalDecorators": true,
|
|
10
|
+
"emitDecoratorMetadata": true,
|
|
11
|
+
"module": "commonjs",
|
|
12
|
+
"rootDir": "src",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"allowJs": true,
|
|
16
|
+
"declaration": true,
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"outDir": "./dist",
|
|
19
|
+
"removeComments": true,
|
|
20
|
+
"allowSyntheticDefaultImports": true,
|
|
21
|
+
"esModuleInterop": true,
|
|
22
|
+
"forceConsistentCasingInFileNames": true,
|
|
23
|
+
"strict": true,
|
|
24
|
+
"strictNullChecks": true,
|
|
25
|
+
"strictFunctionTypes": true,
|
|
26
|
+
"strictPropertyInitialization": false,
|
|
27
|
+
"skipLibCheck": true
|
|
28
|
+
},
|
|
29
|
+
"include": [
|
|
30
|
+
"./src"
|
|
31
|
+
],
|
|
32
|
+
"exclude": [
|
|
33
|
+
"./dist/**/*",
|
|
34
|
+
"./src/**/*.spec.ts"
|
|
35
|
+
]
|
|
36
|
+
}
|