@finsys/core 4.3.0 → 4.5.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/dist/index.d.cts CHANGED
@@ -974,6 +974,11 @@ type CanonicalFieldValues = Partial<Record<CanonicalFieldName, CanonicalFieldVal
974
974
  * MUST be stable across re-extractions so the storage layer can
975
975
  * replace-in-place rather than accumulating duplicates. Conventions:
976
976
  * - For periodic data: encode the period (`'2026-Q1'`, `'2026-03'`)
977
+ * NOTE (SYS-3002): that is the multi-INSTANCE axis — one snapshot per
978
+ * instance. Do NOT encode a within-document period into the instance
979
+ * key; period-scoped values belong in `periods` (contractual 1-based
980
+ * positions). The two axes compose: instance = which document/snapshot,
981
+ * period = which declared position within it.
977
982
  * - For per-line data: encode the line id (`'msisdn-60123456789'`,
978
983
  * `'card-last4-1234'`)
979
984
  * - For natively single-instance adapters: use the empty string `''`
@@ -1014,6 +1019,62 @@ interface AdapterExtraction {
1014
1019
  * matching IhsFieldProvenance.origin semantics).
1015
1020
  */
1016
1021
  readonly confidence?: Partial<Record<CanonicalFieldName, number | null>>;
1022
+ /**
1023
+ * SYS-3002: per-period value sets for adapters whose category
1024
+ * declares a period axis (see `AdapterManifest.periods`). Each entry
1025
+ * carries the values for ONE contractual position; `position` is
1026
+ * 1-based — period1 is the first declared period, there is no
1027
+ * period0.
1028
+ *
1029
+ * An instance carrying `periods` uses them for period-scoped fields,
1030
+ * while the instance-level `values` above remains the home for
1031
+ * period-less (singleton / instance-scoped) fields. Instances of
1032
+ * single-period adapters (no `periods` on the manifest) omit this
1033
+ * entirely and keep everything in `values` — the existing flat path
1034
+ * is unchanged and remains the single-period path.
1035
+ *
1036
+ * Periods are scoped WITHIN this instance: this instance's period1
1037
+ * and another instance's period1 are unrelated data points.
1038
+ */
1039
+ readonly periods?: ReadonlyArray<PeriodValues>;
1040
+ }
1041
+ /**
1042
+ * SYS-3002: one period's value set within an AdapterExtraction
1043
+ * instance. Identity is `position` — the 1-based index into the
1044
+ * manifest's declared `periods` array — never the dates: declared
1045
+ * positions may overlap, nest, vary in length, or be staggered (e.g.
1046
+ * period1 = an annual table, periods 2–5 = the four quarters
1047
+ * overlapping it), so dates cannot identify a period and recency
1048
+ * ordering across positions is meaningless.
1049
+ */
1050
+ interface PeriodValues {
1051
+ /**
1052
+ * 1-based contractual position into the manifest's `periods`
1053
+ * declaration. MUST be >= 1 — period1 is the first declared period;
1054
+ * there is no period0. This IS the period's identity.
1055
+ */
1056
+ readonly position: number;
1057
+ /**
1058
+ * ISO-8601 date the period starts — display/temporal metadata only,
1059
+ * NEVER identity.
1060
+ */
1061
+ readonly start?: string;
1062
+ /**
1063
+ * ISO-8601 date the period ends — display/temporal metadata only,
1064
+ * NEVER identity.
1065
+ */
1066
+ readonly end?: string;
1067
+ /**
1068
+ * The canonical field values for this period, same shape as the
1069
+ * instance-level `values`.
1070
+ */
1071
+ readonly values: CanonicalFieldValues;
1072
+ /**
1073
+ * Optional per-field extraction confidence for this period's values,
1074
+ * same semantics as the instance-level `confidence` (0..1 keyed by
1075
+ * canonical field name; `null` marks a derived/computed value).
1076
+ */
1077
+ readonly confidence?: Partial<Record<CanonicalFieldName, number | null>>;
1017
1078
  }
1018
1079
  /**
1019
1080
  * Allowed value shapes for canonical fields. Per-field type narrowing
@@ -1418,8 +1479,15 @@ interface AdapterManifest {
1418
1479
  * post-extraction. `produces` IS the override surface (a separate
1419
1480
  * list could only duplicate or contradict it); the host's
1420
1481
  * override endpoints gate on membership.
1482
+ * - `extraction-pipeline` — SYS-2998: declaration-only adapter whose
1483
+ * implementation IS the host application's own document-extraction
1484
+ * pipeline. No code is loaded and neither fetch() nor extract()
1485
+ * ever runs — the host's pipeline writes the canonical rows and
1486
+ * records the adapter runs itself; the manifest exists purely as
1487
+ * the declaration plane (produces, cardinality,
1488
+ * fieldAuthorizations) for data the host was already producing.
1421
1489
  */
1422
- readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation;
1490
+ readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation | ExtractionPipelineImplementation;
1423
1491
  /**
1424
1492
  * SYS-2502: explicit instance cardinality.
1425
1493
  *
@@ -1494,6 +1562,41 @@ interface AdapterManifest {
1494
1562
  * not producing the field.
1495
1563
  */
1496
1564
  readonly fieldAuthorizations?: Readonly<Partial<Record<CanonicalFieldName, FieldAuthorization>>>;
1565
+ /**
1566
+ * SYS-3002: ordered period declarations — the contract for the
1567
+ * period axis of this adapter's category.
1568
+ *
1569
+ * The period axis is ordered BY CONTRACT: `periodN` is a POSITIONAL
1570
+ * identifier into this array. Numbering is 1-BASED — period1 is the
1571
+ * FIRST declared period (array index 0); there is no period0.
1572
+ * Position is the period's IDENTITY: two extractions' period1 values
1573
+ * are comparable because they occupy the same contractual slot, not
1574
+ * because their dates match.
1575
+ *
1576
+ * Declared positions may overlap, nest, vary in length, or be
1577
+ * staggered — e.g. period1 = an annual table, periods 2–5 = the four
1578
+ * quarters overlapping it. The declaration makes no statement about
1579
+ * dates; each extraction-time period carries its own dated metadata
1580
+ * (see `PeriodValues.start`/`end`) for display and temporal
1581
+ * reasoning, never for identity. Periods are scoped WITHIN one
1582
+ * instance: one document's period1 and another document's period1
1583
+ * are unrelated data points.
1584
+ *
1585
+ * ABSENT means the single-period convention: the adapter's output
1586
+ * has exactly one implicit period, and instance-level `values` is
1587
+ * that period's value set. Single-period categories (bank
1588
+ * statements, EPF, payslips) never need to declare. Non-empty when
1589
+ * present — declaring zero periods would contradict the implicit
1590
+ * single-period convention, so the schema requires at least one
1591
+ * entry.
1592
+ *
1593
+ * The motivating consumer is financial statements — one document
1594
+ * carries period1 (its current fiscal year) plus period2 (its prior
1595
+ * comparative year) — but any implementation type may declare
1596
+ * periods: the axis is a property of the contract, not of how the
1597
+ * adapter is implemented.
1598
+ */
1599
+ readonly periods?: ReadonlyArray<PeriodDeclaration>;
1497
1600
  /**
1498
1601
  * Optional free-form notes — useful for partner-side documentation
1499
1602
  * (where to find the adapter's source, who owns it, what version of
@@ -1501,6 +1604,22 @@ interface AdapterManifest {
1501
1604
  */
1502
1605
  readonly notes?: string;
1503
1606
  }
1607
+ /**
1608
+ * SYS-3002: one declared period on the adapter's period axis. See
1609
+ * {@link AdapterManifest.periods} for the positional (1-based) identity
1610
+ * semantics — the entry's position in the `periods` array IS the
1611
+ * period's identity; the entry itself only labels the role.
1612
+ */
1613
+ interface PeriodDeclaration {
1614
+ /**
1615
+ * Human role label for the position, e.g. "Current fiscal year",
1616
+ * "Prior comparative year". Rendered in operator UIs; carries no
1617
+ * identity semantics.
1618
+ */
1619
+ readonly name: string;
1620
+ /** Optional longer description of what this position holds. */
1621
+ readonly description?: string;
1622
+ }
1504
1623
  /**
1505
1624
  * SYS-2503: one field's authorization gate. See
1506
1625
  * {@link AdapterManifest.fieldAuthorizations} for semantics.
@@ -1574,6 +1693,26 @@ interface FormIntakeFieldMapEntry {
1574
1693
  interface ManualOverrideImplementation {
1575
1694
  readonly type: "manual-override";
1576
1695
  }
1696
+ /**
1697
+ * SYS-2998: declaration-only implementation for adapters whose
1698
+ * implementation IS the host application's own extraction pipeline
1699
+ * (e.g. the FinXtract document-processing pipeline wrapped as
1700
+ * "finxtract-bank-statement-v1"). The host's pipeline code performs the
1701
+ * extraction, writes the canonical rows, and records the adapter runs —
1702
+ * this manifest is how that pipeline's output becomes declared,
1703
+ * provenance-carrying, per-field-gateable adapter data instead of
1704
+ * hand-wired writes. No code, no fetch(), no extract(); like
1705
+ * `manual-override`, the discriminator alone carries the meaning.
1706
+ *
1707
+ * Distinct from `form-intake` (whose runtime is the form submission
1708
+ * handler and which needs a fieldMap) and from `manual-override` (which
1709
+ * declares an override SURFACE): an extraction-pipeline manifest
1710
+ * declares the pipeline's produced fields verbatim — `produces` is the
1711
+ * contract, and the host validates the pipeline's writes against it.
1712
+ */
1713
+ interface ExtractionPipelineImplementation {
1714
+ readonly type: "extraction-pipeline";
1715
+ }
1577
1716
  interface FieldMapEntry {
1578
1717
  /**
1579
1718
  * JSONPath expression into the raw payload. E.g.
@@ -1601,4 +1740,4 @@ interface FieldMapEntry {
1601
1740
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1602
1741
  }
1603
1742
 
1604
- export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type CategorySpec, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, type FormIntakeFieldMapEntry, type FormIntakeImplementation, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_FIELD_ORIGINS, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldOrigin, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceRow, type InstanceValue, type ManualOverrideImplementation, type PageConfig, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, buildFileFieldTablesFromInstances, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByInstance, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsFieldOrigin, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
1743
+ export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type CategorySpec, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionPipelineImplementation, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, type FormIntakeFieldMapEntry, type FormIntakeImplementation, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_FIELD_ORIGINS, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldOrigin, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceRow, type InstanceValue, type ManualOverrideImplementation, type PageConfig, type PeriodDeclaration, type PeriodValues, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, buildFileFieldTablesFromInstances, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByInstance, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsFieldOrigin, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
package/dist/index.d.ts CHANGED
@@ -974,6 +974,11 @@ type CanonicalFieldValues = Partial<Record<CanonicalFieldName, CanonicalFieldVal
974
974
  * MUST be stable across re-extractions so the storage layer can
975
975
  * replace-in-place rather than accumulating duplicates. Conventions:
976
976
  * - For periodic data: encode the period (`'2026-Q1'`, `'2026-03'`)
977
+ * NOTE (SYS-3002): that is the multi-INSTANCE axis — one snapshot per
978
+ * instance. Do NOT encode a within-document period into the instance
979
+ * key; period-scoped values belong in `periods` (contractual 1-based
980
+ * positions). The two axes compose: instance = which document/snapshot,
981
+ * period = which declared position within it.
977
982
  * - For per-line data: encode the line id (`'msisdn-60123456789'`,
978
983
  * `'card-last4-1234'`)
979
984
  * - For natively single-instance adapters: use the empty string `''`
@@ -1014,6 +1019,62 @@ interface AdapterExtraction {
1014
1019
  * matching IhsFieldProvenance.origin semantics).
1015
1020
  */
1016
1021
  readonly confidence?: Partial<Record<CanonicalFieldName, number | null>>;
1022
+ /**
1023
+ * SYS-3002: per-period value sets for adapters whose category
1024
+ * declares a period axis (see `AdapterManifest.periods`). Each entry
1025
+ * carries the values for ONE contractual position; `position` is
1026
+ * 1-based — period1 is the first declared period, there is no
1027
+ * period0.
1028
+ *
1029
+ * An instance carrying `periods` uses them for period-scoped fields,
1030
+ * while the instance-level `values` above remains the home for
1031
+ * period-less (singleton / instance-scoped) fields. Instances of
1032
+ * single-period adapters (no `periods` on the manifest) omit this
1033
+ * entirely and keep everything in `values` — the existing flat path
1034
+ * is unchanged and remains the single-period path.
1035
+ *
1036
+ * Periods are scoped WITHIN this instance: this instance's period1
1037
+ * and another instance's period1 are unrelated data points.
1038
+ */
1039
+ readonly periods?: ReadonlyArray<PeriodValues>;
1040
+ }
1041
+ /**
1042
+ * SYS-3002: one period's value set within an AdapterExtraction
1043
+ * instance. Identity is `position` — the 1-based index into the
1044
+ * manifest's declared `periods` array — never the dates: declared
1045
+ * positions may overlap, nest, vary in length, or be staggered (e.g.
1046
+ * period1 = an annual table, periods 2–5 = the four quarters
1047
+ * overlapping it), so dates cannot identify a period and recency
1048
+ * ordering across positions is meaningless.
1049
+ */
1050
+ interface PeriodValues {
1051
+ /**
1052
+ * 1-based contractual position into the manifest's `periods`
1053
+ * declaration. MUST be >= 1 — period1 is the first declared period;
1054
+ * there is no period0. This IS the period's identity.
1055
+ */
1056
+ readonly position: number;
1057
+ /**
1058
+ * ISO-8601 date the period starts — display/temporal metadata only,
1059
+ * NEVER identity.
1060
+ */
1061
+ readonly start?: string;
1062
+ /**
1063
+ * ISO-8601 date the period ends — display/temporal metadata only,
1064
+ * NEVER identity.
1065
+ */
1066
+ readonly end?: string;
1067
+ /**
1068
+ * The canonical field values for this period, same shape as the
1069
+ * instance-level `values`.
1070
+ */
1071
+ readonly values: CanonicalFieldValues;
1072
+ /**
1073
+ * Optional per-field extraction confidence for this period's values,
1074
+ * same semantics as the instance-level `confidence` (0..1 keyed by
1075
+ * canonical field name; `null` marks a derived/computed value).
1076
+ */
1077
+ readonly confidence?: Partial<Record<CanonicalFieldName, number | null>>;
1017
1078
  }
1018
1079
  /**
1019
1080
  * Allowed value shapes for canonical fields. Per-field type narrowing
@@ -1418,8 +1479,15 @@ interface AdapterManifest {
1418
1479
  * post-extraction. `produces` IS the override surface (a separate
1419
1480
  * list could only duplicate or contradict it); the host's
1420
1481
  * override endpoints gate on membership.
1482
+ * - `extraction-pipeline` — SYS-2998: declaration-only adapter whose
1483
+ * implementation IS the host application's own document-extraction
1484
+ * pipeline. No code is loaded and neither fetch() nor extract()
1485
+ * ever runs — the host's pipeline writes the canonical rows and
1486
+ * records the adapter runs itself; the manifest exists purely as
1487
+ * the declaration plane (produces, cardinality,
1488
+ * fieldAuthorizations) for data the host was already producing.
1421
1489
  */
1422
- readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation;
1490
+ readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation | ExtractionPipelineImplementation;
1423
1491
  /**
1424
1492
  * SYS-2502: explicit instance cardinality.
1425
1493
  *
@@ -1494,6 +1562,41 @@ interface AdapterManifest {
1494
1562
  * not producing the field.
1495
1563
  */
1496
1564
  readonly fieldAuthorizations?: Readonly<Partial<Record<CanonicalFieldName, FieldAuthorization>>>;
1565
+ /**
1566
+ * SYS-3002: ordered period declarations — the contract for the
1567
+ * period axis of this adapter's category.
1568
+ *
1569
+ * The period axis is ordered BY CONTRACT: `periodN` is a POSITIONAL
1570
+ * identifier into this array. Numbering is 1-BASED — period1 is the
1571
+ * FIRST declared period (array index 0); there is no period0.
1572
+ * Position is the period's IDENTITY: two extractions' period1 values
1573
+ * are comparable because they occupy the same contractual slot, not
1574
+ * because their dates match.
1575
+ *
1576
+ * Declared positions may overlap, nest, vary in length, or be
1577
+ * staggered — e.g. period1 = an annual table, periods 2–5 = the four
1578
+ * quarters overlapping it. The declaration makes no statement about
1579
+ * dates; each extraction-time period carries its own dated metadata
1580
+ * (see `PeriodValues.start`/`end`) for display and temporal
1581
+ * reasoning, never for identity. Periods are scoped WITHIN one
1582
+ * instance: one document's period1 and another document's period1
1583
+ * are unrelated data points.
1584
+ *
1585
+ * ABSENT means the single-period convention: the adapter's output
1586
+ * has exactly one implicit period, and instance-level `values` is
1587
+ * that period's value set. Single-period categories (bank
1588
+ * statements, EPF, payslips) never need to declare. Non-empty when
1589
+ * present — declaring zero periods would contradict the implicit
1590
+ * single-period convention, so the schema requires at least one
1591
+ * entry.
1592
+ *
1593
+ * The motivating consumer is financial statements — one document
1594
+ * carries period1 (its current fiscal year) plus period2 (its prior
1595
+ * comparative year) — but any implementation type may declare
1596
+ * periods: the axis is a property of the contract, not of how the
1597
+ * adapter is implemented.
1598
+ */
1599
+ readonly periods?: ReadonlyArray<PeriodDeclaration>;
1497
1600
  /**
1498
1601
  * Optional free-form notes — useful for partner-side documentation
1499
1602
  * (where to find the adapter's source, who owns it, what version of
@@ -1501,6 +1604,22 @@ interface AdapterManifest {
1501
1604
  */
1502
1605
  readonly notes?: string;
1503
1606
  }
1607
+ /**
1608
+ * SYS-3002: one declared period on the adapter's period axis. See
1609
+ * {@link AdapterManifest.periods} for the positional (1-based) identity
1610
+ * semantics — the entry's position in the `periods` array IS the
1611
+ * period's identity; the entry itself only labels the role.
1612
+ */
1613
+ interface PeriodDeclaration {
1614
+ /**
1615
+ * Human role label for the position, e.g. "Current fiscal year",
1616
+ * "Prior comparative year". Rendered in operator UIs; carries no
1617
+ * identity semantics.
1618
+ */
1619
+ readonly name: string;
1620
+ /** Optional longer description of what this position holds. */
1621
+ readonly description?: string;
1622
+ }
1504
1623
  /**
1505
1624
  * SYS-2503: one field's authorization gate. See
1506
1625
  * {@link AdapterManifest.fieldAuthorizations} for semantics.
@@ -1574,6 +1693,26 @@ interface FormIntakeFieldMapEntry {
1574
1693
  interface ManualOverrideImplementation {
1575
1694
  readonly type: "manual-override";
1576
1695
  }
1696
+ /**
1697
+ * SYS-2998: declaration-only implementation for adapters whose
1698
+ * implementation IS the host application's own extraction pipeline
1699
+ * (e.g. the FinXtract document-processing pipeline wrapped as
1700
+ * "finxtract-bank-statement-v1"). The host's pipeline code performs the
1701
+ * extraction, writes the canonical rows, and records the adapter runs —
1702
+ * this manifest is how that pipeline's output becomes declared,
1703
+ * provenance-carrying, per-field-gateable adapter data instead of
1704
+ * hand-wired writes. No code, no fetch(), no extract(); like
1705
+ * `manual-override`, the discriminator alone carries the meaning.
1706
+ *
1707
+ * Distinct from `form-intake` (whose runtime is the form submission
1708
+ * handler and which needs a fieldMap) and from `manual-override` (which
1709
+ * declares an override SURFACE): an extraction-pipeline manifest
1710
+ * declares the pipeline's produced fields verbatim — `produces` is the
1711
+ * contract, and the host validates the pipeline's writes against it.
1712
+ */
1713
+ interface ExtractionPipelineImplementation {
1714
+ readonly type: "extraction-pipeline";
1715
+ }
1577
1716
  interface FieldMapEntry {
1578
1717
  /**
1579
1718
  * JSONPath expression into the raw payload. E.g.
@@ -1601,4 +1740,4 @@ interface FieldMapEntry {
1601
1740
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1602
1741
  }
1603
1742
 
1604
- export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type CategorySpec, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, type FormIntakeFieldMapEntry, type FormIntakeImplementation, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_FIELD_ORIGINS, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldOrigin, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceRow, type InstanceValue, type ManualOverrideImplementation, type PageConfig, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, buildFileFieldTablesFromInstances, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByInstance, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsFieldOrigin, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
1743
+ export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type CategorySpec, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionPipelineImplementation, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, type FormIntakeFieldMapEntry, type FormIntakeImplementation, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_FIELD_ORIGINS, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldOrigin, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceRow, type InstanceValue, type ManualOverrideImplementation, type PageConfig, type PeriodDeclaration, type PeriodValues, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, buildFileFieldTablesFromInstances, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByInstance, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsFieldOrigin, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
package/dist/index.js CHANGED
@@ -10596,6 +10596,260 @@ var adapter_categories_default = {
10596
10596
  description: "Agreement between the inferred home anchor and the applicant's registered residential address. 1 = same premises, 0 = different state (summary instance only)."
10597
10597
  }
10598
10598
  ]
10599
+ },
10600
+ {
10601
+ id: "ic",
10602
+ displayName: "Identity Document (IC / Passport)",
10603
+ description: "Identity fields extracted from a Malaysian IC (MyKad) or passport document. Produced by the host's document-extraction pipeline; one instance per identity document.",
10604
+ canonicalTable: "ihs_alt_data_ic",
10605
+ fields: [
10606
+ {
10607
+ name: "icName",
10608
+ type: "string",
10609
+ description: "Full name as printed on the identity document."
10610
+ },
10611
+ {
10612
+ name: "icNumber",
10613
+ type: "string",
10614
+ description: "IC (MyKad) number, or passport number for passport documents."
10615
+ },
10616
+ {
10617
+ name: "icAddress",
10618
+ type: "string",
10619
+ description: "Registered address as printed on the document."
10620
+ },
10621
+ {
10622
+ name: "icGender",
10623
+ type: "string",
10624
+ description: "Gender as stated on the document."
10625
+ },
10626
+ {
10627
+ name: "icReligion",
10628
+ type: "string",
10629
+ description: "Religion as stated on the document (MyKad-only; absent on passports)."
10630
+ },
10631
+ {
10632
+ name: "icDateOfBirth",
10633
+ type: "string",
10634
+ description: "Date of birth as stated on the document."
10635
+ },
10636
+ {
10637
+ name: "icPlaceOfBirth",
10638
+ type: "string",
10639
+ description: "Place of birth as stated on the document."
10640
+ },
10641
+ {
10642
+ name: "icNationality",
10643
+ type: "string",
10644
+ description: "Nationality as stated on the document."
10645
+ },
10646
+ {
10647
+ name: "icRace",
10648
+ type: "string",
10649
+ description: "Race as stated on the document (MyKad-only; absent on passports)."
10650
+ }
10651
+ ]
10652
+ },
10653
+ {
10654
+ id: "finxtract-bank-statement",
10655
+ displayName: "Bank Statement (Document Extraction)",
10656
+ description: "Fields extracted from an uploaded bank-statement document by the host's extraction pipeline. One instance per statement document; each statement covers a single month. Distinct from the partner-API 'bank-statement' category: same real-world domain, different source and different canonical vocabulary.",
10657
+ canonicalTable: "ihsbankstatement",
10658
+ fields: [
10659
+ {
10660
+ name: "bankName",
10661
+ type: "string",
10662
+ description: "Issuing bank's name as printed on the statement."
10663
+ },
10664
+ {
10665
+ name: "accountHolderName",
10666
+ type: "string",
10667
+ description: "Account holder's name as printed on the statement."
10668
+ },
10669
+ {
10670
+ name: "accountNumber",
10671
+ type: "string",
10672
+ description: "Bank account number as printed on the statement."
10673
+ },
10674
+ {
10675
+ name: "statementDate",
10676
+ type: "string",
10677
+ description: "Statement date, normalized to ISO YYYY-MM-DD."
10678
+ },
10679
+ {
10680
+ name: "openingBalance",
10681
+ type: "number",
10682
+ unit: "MYR",
10683
+ description: "Opening balance for the statement period."
10684
+ },
10685
+ {
10686
+ name: "bankBalance",
10687
+ type: "number",
10688
+ unit: "MYR",
10689
+ description: "Closing balance for the statement period."
10690
+ },
10691
+ {
10692
+ name: "totalCredits",
10693
+ type: "number",
10694
+ unit: "MYR",
10695
+ description: "Sum of credit transactions in the statement period."
10696
+ },
10697
+ {
10698
+ name: "totalDebits",
10699
+ type: "number",
10700
+ unit: "MYR",
10701
+ description: "Sum of debit transactions in the statement period."
10702
+ }
10703
+ ]
10704
+ },
10705
+ {
10706
+ id: "finxtract-epf",
10707
+ displayName: "EPF Statement (Document Extraction)",
10708
+ description: "Fields extracted from an uploaded EPF (KWSP) statement document by the host's extraction pipeline. One instance per statement document. Field names carry the 'epf' prefix \u2014 the same prefix-namespaced vocabulary the host's flat read path and the eval engine already use, which also keeps canonical names globally unique across categories.",
10709
+ canonicalTable: "ihsepfstatement",
10710
+ fields: [
10711
+ {
10712
+ name: "epfAccountHolderName",
10713
+ type: "string",
10714
+ description: "Member's name as printed on the statement."
10715
+ },
10716
+ {
10717
+ name: "epfAccountHolderAddress",
10718
+ type: "string",
10719
+ description: "Member's address as printed on the statement."
10720
+ },
10721
+ {
10722
+ name: "epfStatementYear",
10723
+ type: "string",
10724
+ description: "The contribution year the statement covers."
10725
+ },
10726
+ {
10727
+ name: "epfKwspMemberNumber",
10728
+ type: "string",
10729
+ description: "KWSP membership number."
10730
+ },
10731
+ {
10732
+ name: "epfIcNumber",
10733
+ type: "string",
10734
+ description: "Member's IC number as printed on the statement."
10735
+ },
10736
+ {
10737
+ name: "epfEmployerNumber",
10738
+ type: "string",
10739
+ description: "Employer's KWSP reference number."
10740
+ },
10741
+ {
10742
+ name: "epfDateOfStatement",
10743
+ type: "string",
10744
+ description: "Statement issue date, normalized to ISO YYYY-MM-DD."
10745
+ },
10746
+ {
10747
+ name: "epfTotalContribution",
10748
+ type: "number",
10749
+ unit: "MYR",
10750
+ description: "Cumulative EPF balance as at the statement date."
10751
+ },
10752
+ {
10753
+ name: "epfTotalCurrentContribution",
10754
+ type: "number",
10755
+ unit: "MYR",
10756
+ description: "Contributions made within the statement's coverage year."
10757
+ }
10758
+ ]
10759
+ },
10760
+ {
10761
+ id: "finxtract-payslip",
10762
+ displayName: "Payslip (Document Extraction)",
10763
+ description: "Fields extracted from an uploaded payslip document by the host's extraction pipeline. One instance per payslip document; each payslip covers a single pay period. Field names carry the 'payslip' prefix \u2014 the same prefix-namespaced vocabulary the host's flat read path and the eval engine already use, which also keeps canonical names globally unique across categories.",
10764
+ canonicalTable: "ihspayslip",
10765
+ fields: [
10766
+ {
10767
+ name: "payslipEmployerName",
10768
+ type: "string",
10769
+ description: "Employer's name as printed on the payslip."
10770
+ },
10771
+ {
10772
+ name: "payslipEmployeeName",
10773
+ type: "string",
10774
+ description: "Employee's name as printed on the payslip."
10775
+ },
10776
+ {
10777
+ name: "payslipPayPeriod",
10778
+ type: "string",
10779
+ description: "The pay period the payslip covers, as printed."
10780
+ },
10781
+ {
10782
+ name: "payslipPayDate",
10783
+ type: "string",
10784
+ description: "Payment date, as printed."
10785
+ },
10786
+ {
10787
+ name: "payslipBasicPay",
10788
+ type: "number",
10789
+ unit: "MYR",
10790
+ description: "Basic salary for the period."
10791
+ },
10792
+ {
10793
+ name: "payslipGrossPay",
10794
+ type: "number",
10795
+ unit: "MYR",
10796
+ description: "Gross pay for the period."
10797
+ },
10798
+ {
10799
+ name: "payslipFixedAllowances",
10800
+ type: "number",
10801
+ unit: "MYR",
10802
+ description: "Fixed allowances for the period."
10803
+ },
10804
+ {
10805
+ name: "payslipVariableIncome",
10806
+ type: "number",
10807
+ unit: "MYR",
10808
+ description: "Variable income (overtime, commission, bonus) for the period."
10809
+ },
10810
+ {
10811
+ name: "payslipDeduction",
10812
+ type: "number",
10813
+ unit: "MYR",
10814
+ description: "Total statutory deductions for the period."
10815
+ },
10816
+ {
10817
+ name: "payslipOtherDeduction",
10818
+ type: "number",
10819
+ unit: "MYR",
10820
+ description: "Other (non-statutory) deductions for the period."
10821
+ },
10822
+ {
10823
+ name: "payslipEmployeeEpfContribution",
10824
+ type: "number",
10825
+ unit: "MYR",
10826
+ description: "Employee EPF contribution for the period."
10827
+ },
10828
+ {
10829
+ name: "payslipEmployeeSocsoContribution",
10830
+ type: "number",
10831
+ unit: "MYR",
10832
+ description: "Employee SOCSO contribution for the period."
10833
+ },
10834
+ {
10835
+ name: "payslipEmployeeEisContribution",
10836
+ type: "number",
10837
+ unit: "MYR",
10838
+ description: "Employee EIS contribution for the period."
10839
+ },
10840
+ {
10841
+ name: "payslipEmployeeTax",
10842
+ type: "number",
10843
+ unit: "MYR",
10844
+ description: "Employee income-tax (PCB) deduction for the period."
10845
+ },
10846
+ {
10847
+ name: "payslipNetPay",
10848
+ type: "number",
10849
+ unit: "MYR",
10850
+ description: "Net pay for the period."
10851
+ }
10852
+ ]
10599
10853
  }
10600
10854
  ]
10601
10855
  };
@@ -10634,9 +10888,9 @@ function buildCategoryRegistry(raw) {
10634
10888
  if (typeof cat.description !== "string" || cat.description.length === 0) {
10635
10889
  throw new Error(`adapter category data: ${where} needs a non-empty description`);
10636
10890
  }
10637
- if (typeof cat.canonicalTable !== "string" || !/^ihs_alt_data_/.test(cat.canonicalTable)) {
10891
+ if (typeof cat.canonicalTable !== "string" || !/^ihs[a-z0-9_]*$/.test(cat.canonicalTable)) {
10638
10892
  throw new Error(
10639
- `adapter category data: ${where} canonicalTable must start with "ihs_alt_data_" (got "${cat.canonicalTable}")`
10893
+ `adapter category data: ${where} canonicalTable must be an "ihs"-prefixed table identifier (got "${cat.canonicalTable}")`
10640
10894
  );
10641
10895
  }
10642
10896
  if (tables.has(cat.canonicalTable)) {