@classytic/primitives 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,34 @@
3
3
  Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
4
4
  adhering to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## [0.7.2] - 2026-05-30
7
+
8
+ ### Added — `BankTransaction` per-account routing + pending lifecycle fields
9
+
10
+ Three additive optional fields on `BankTransaction` (`/bank-transaction`):
11
+
12
+ - **`sourceAccountId?: string`** — the vendor-side account this row belongs to
13
+ (Plaid `account_id`, Xero `BankAccount.AccountID`). Sync feeds return
14
+ transactions spanning multiple accounts in one batch; this lets consumers
15
+ route each row to the right account per-transaction (multi-account sync)
16
+ instead of forcing the whole batch onto one account. Statement formats
17
+ (single-account files) leave it undefined — the account lives on
18
+ `BankStatement.account`.
19
+ - **`pending?: boolean`** — the entry hasn't posted/cleared yet (real-time
20
+ feeds like Plaid `pending: true`; statement formats leave it undefined).
21
+ Consumers must treat pending rows as provisional — don't reconcile/post
22
+ them as final.
23
+ - **`supersedesExternalId?: string`** — set on a POSTED row that replaces an
24
+ earlier PENDING one, carrying the pending row's `externalId` (Plaid
25
+ `pending_transaction_id`). Pending and posted rows have different
26
+ `externalId`s, so consumers MUST use this back-pointer to drop/replace the
27
+ superseded pending row on ingest — otherwise both persist as duplicates.
28
+
29
+ Backward-compatible (both optional). Closes a fidelity gap where Plaid's
30
+ pending state was dropped at the canonical boundary, so downstream consumers
31
+ (`@classytic/fin-io` Plaid mapper, `@classytic/revenue` import) couldn't
32
+ distinguish provisional rows or dedupe pending→posted.
33
+
6
34
  ## [0.7.1] - 2026-05-26
7
35
 
8
36
  ### Added — workflow + scheduling + composition primitives
@@ -96,6 +96,41 @@ interface BankTransaction {
96
96
  balanceAfter?: Money;
97
97
  /** Format-specific entry-type code (`'DEBIT'`, `'CREDIT'`, `'CHECK'`, …). */
98
98
  type?: string;
99
+ /**
100
+ * Vendor-side identifier of the account this row belongs to — Plaid
101
+ * `account_id`, Xero `BankAccount.AccountID`. Sync feeds return transactions
102
+ * spanning MULTIPLE accounts in one batch, so this lets a consumer route
103
+ * each row to the right destination account per-transaction (multi-account
104
+ * sync) instead of forcing the whole batch onto one account.
105
+ *
106
+ * Statement formats (OFX / CAMT.053 / MT940 / CSV / IIF) are single-account
107
+ * files — they carry the account on `BankStatement.account` and leave this
108
+ * `undefined`. Distinct from any consumer-side account id (e.g. the host's
109
+ * own `bankAccountId` used in the import unique index).
110
+ */
111
+ sourceAccountId?: string;
112
+ /**
113
+ * The entry has not yet posted / cleared — the bank may still change its
114
+ * amount, description, or drop it entirely. Real-time feeds populate this
115
+ * (Plaid `pending: true`); statement formats (OFX / CAMT.053 / MT940 / CSV)
116
+ * only ever carry settled rows and leave it `undefined`.
117
+ *
118
+ * Consumers MUST treat `pending: true` rows as provisional — do not
119
+ * reconcile or post them as final, and expect a superseding posted row to
120
+ * arrive later (linked via `supersedesExternalId`).
121
+ */
122
+ pending?: boolean;
123
+ /**
124
+ * Set on a POSTED row that replaces an earlier PENDING one: the
125
+ * `externalId` of the pending row this entry supersedes (Plaid
126
+ * `pending_transaction_id`).
127
+ *
128
+ * The pending and posted rows carry DIFFERENT `externalId`s, so dedup on
129
+ * `externalId` alone can't collapse them — consumers MUST use this
130
+ * back-pointer to drop / replace the superseded pending row on ingest, or
131
+ * both versions persist as duplicates.
132
+ */
133
+ supersedesExternalId?: string;
99
134
  /**
100
135
  * Format-specific raw record. Pass-through for audit / debugging.
101
136
  * Consumers MUST NOT rely on this — schema may change between fin-io
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/primitives",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Framework-agnostic TypeScript primitives shared across Classytic packages — Money, events, pagination, tenant config, and other building blocks.",
5
5
  "author": "Classytic",
6
6
  "license": "MIT",