@luca-financial/luca-schema 2.3.4 → 3.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/CHANGELOG.md +19 -0
- package/README.md +21 -9
- package/dist/esm/index.d.ts +20 -0
- package/dist/esm/index.js +31 -2
- package/dist/esm/lucaValidator.js +159 -3
- package/dist/esm/schemas/account.json +1 -0
- package/dist/esm/schemas/category.json +1 -0
- package/dist/esm/schemas/lucaSchema.json +2 -1
- package/dist/esm/schemas/recurringTransaction.json +1 -0
- package/dist/esm/schemas/recurringTransactionEvent.json +2 -1
- package/dist/esm/schemas/statement.json +1 -0
- package/dist/esm/schemas/transaction.json +6 -0
- package/dist/esm/schemas/transactionSplit.json +6 -0
- package/dist/index.d.ts +20 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.0.0] - 2026-02-13
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Enforce strict unknown-field validation across schemas via `unevaluatedProperties: false`.
|
|
13
|
+
- Add date normalization helpers and expose date-specific validation metadata from validator APIs.
|
|
14
|
+
- Expand validator exports for date utilities and schema date-field path discovery.
|
|
15
|
+
- Remove `counterparty` from transaction schema/examples and align fixtures/docs.
|
|
16
|
+
- Update example and test data to match strict schema behavior.
|
|
17
|
+
|
|
18
|
+
### Breaking
|
|
19
|
+
|
|
20
|
+
- Payloads containing undeclared properties now fail validation.
|
|
21
|
+
- `counterparty` is no longer accepted on transactions.
|
|
22
|
+
|
|
23
|
+
### Notes
|
|
24
|
+
|
|
25
|
+
- During this transition, test fixtures derive `schemaVersion` from package version to keep LucaLedger and LucaSchema on a synchronized `3.x` baseline. Contract-specific schema versioning and enforcement will be addressed in a follow-up cross-repo migration pass.
|
|
26
|
+
|
|
8
27
|
## [2.3.4] - 2026-02-06
|
|
9
28
|
|
|
10
29
|
### Changed
|
package/README.md
CHANGED
|
@@ -84,9 +84,10 @@ const transaction = {
|
|
|
84
84
|
authorizedAt: string | null;
|
|
85
85
|
postedAt: string | null;
|
|
86
86
|
currency: string | null;
|
|
87
|
-
amount: number;
|
|
87
|
+
amount: number; // integer minor units
|
|
88
88
|
date: string;
|
|
89
89
|
description: string;
|
|
90
|
+
memo: string | null;
|
|
90
91
|
aggregationServiceId: string | null;
|
|
91
92
|
transactionState:
|
|
92
93
|
| 'PLANNED'
|
|
@@ -115,7 +116,7 @@ const recurringTransaction = {
|
|
|
115
116
|
id: string;
|
|
116
117
|
accountId: string;
|
|
117
118
|
categoryId: string | null;
|
|
118
|
-
amount: number;
|
|
119
|
+
amount: number; // integer minor units
|
|
119
120
|
description: string;
|
|
120
121
|
frequency: 'DAY' | 'WEEK' | 'MONTH' | 'YEAR';
|
|
121
122
|
interval: number;
|
|
@@ -176,10 +177,10 @@ const statement = {
|
|
|
176
177
|
accountId: string;
|
|
177
178
|
startDate: string;
|
|
178
179
|
endDate: string;
|
|
179
|
-
startingBalance: number;
|
|
180
|
-
endingBalance: number;
|
|
181
|
-
totalCharges: number;
|
|
182
|
-
totalPayments: number;
|
|
180
|
+
startingBalance: number; // integer minor units
|
|
181
|
+
endingBalance: number; // integer minor units
|
|
182
|
+
totalCharges: number; // integer minor units
|
|
183
|
+
totalPayments: number; // integer minor units
|
|
183
184
|
isLocked: boolean;
|
|
184
185
|
createdAt: string;
|
|
185
186
|
updatedAt: string | null;
|
|
@@ -196,9 +197,10 @@ Validates splits within a transaction.
|
|
|
196
197
|
const transactionSplit = {
|
|
197
198
|
id: string;
|
|
198
199
|
transactionId: string;
|
|
199
|
-
amount: number;
|
|
200
|
+
amount: number; // integer minor units
|
|
200
201
|
categoryId: string | null;
|
|
201
202
|
description: string | null;
|
|
203
|
+
memo: string | null;
|
|
202
204
|
createdAt: string;
|
|
203
205
|
updatedAt: string | null;
|
|
204
206
|
deletedAt?: string | null;
|
|
@@ -231,6 +233,10 @@ This module exports helper utilities to inspect schemas and validate data:
|
|
|
231
233
|
import {
|
|
232
234
|
validate,
|
|
233
235
|
validateCollection,
|
|
236
|
+
normalizeDateString,
|
|
237
|
+
isDateStringFixable,
|
|
238
|
+
getDateFieldPaths,
|
|
239
|
+
getDateFieldPathsByCollection,
|
|
234
240
|
getValidFields,
|
|
235
241
|
getRequiredFields,
|
|
236
242
|
stripInvalidFields,
|
|
@@ -240,8 +246,12 @@ import {
|
|
|
240
246
|
} from '@luca-financial/luca-schema';
|
|
241
247
|
```
|
|
242
248
|
|
|
243
|
-
- `validate(schemaKey, data)` → `{ valid: boolean, errors: AjvError[] }`
|
|
244
|
-
- `validateCollection(schemaKey, array)` → `{ valid: boolean, errors: [{ index, entity, errors }] }`
|
|
249
|
+
- `validate(schemaKey, data)` → `{ valid: boolean, errors: AjvError[], metadata: { dateFormatIssues, hasFixableDateFormatIssues } }`
|
|
250
|
+
- `validateCollection(schemaKey, array)` → `{ valid: boolean, errors: [{ index, entity, errors, metadata }], metadata: { hasFixableDateFormatIssues } }`
|
|
251
|
+
- `normalizeDateString(value)` → normalized `YYYY-MM-DD` for unambiguous date strings (`YYYY-MM-DD` or `YYYY/MM/DD`), else `null`
|
|
252
|
+
- `isDateStringFixable(value)` → `true` only for unambiguous slash date strings that can be safely normalized
|
|
253
|
+
- `getDateFieldPaths(schemaKey)` → `string[]` of `format: date` fields for a schema key
|
|
254
|
+
- `getDateFieldPathsByCollection()` → `{ accounts, categories, statements, recurringTransactions, recurringTransactionEvents, transactions, transactionSplits }`
|
|
245
255
|
- `getValidFields(schemaKey)` → `Set<string>` of all fields (includes common fields when applicable)
|
|
246
256
|
- `getRequiredFields(schemaKey)` → `Set<string>` of required fields (includes common required fields)
|
|
247
257
|
- `stripInvalidFields(schemaKey, data)` → new object with only schema-defined keys
|
|
@@ -249,6 +259,8 @@ import {
|
|
|
249
259
|
- `enums` → enum definitions (including `LucaSchemas` keys)
|
|
250
260
|
- `LucaSchemas` → names for schema keys (e.g., `LucaSchemas.TRANSACTION`)
|
|
251
261
|
|
|
262
|
+
All entity schemas and the top-level `lucaSchema` reject unknown properties.
|
|
263
|
+
|
|
252
264
|
## Development
|
|
253
265
|
|
|
254
266
|
```bash
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -534,6 +534,7 @@ export type Transaction = Common5 & {
|
|
|
534
534
|
currency?: Currency;
|
|
535
535
|
amount: Amount1;
|
|
536
536
|
description: Description2;
|
|
537
|
+
memo?: Memo;
|
|
537
538
|
categoryId?: CategoryID1;
|
|
538
539
|
statementId?: StatementID;
|
|
539
540
|
aggregationServiceId?: AggregationServiceID1;
|
|
@@ -600,6 +601,10 @@ export type Amount1 = number;
|
|
|
600
601
|
* Description of the transaction
|
|
601
602
|
*/
|
|
602
603
|
export type Description2 = string;
|
|
604
|
+
/**
|
|
605
|
+
* Optional memo for the transaction.
|
|
606
|
+
*/
|
|
607
|
+
export type Memo = string | null;
|
|
603
608
|
/**
|
|
604
609
|
* Category UUID for this transaction
|
|
605
610
|
*/
|
|
@@ -620,6 +625,7 @@ export type TransactionSplit = Common6 & {
|
|
|
620
625
|
amount: Amount2;
|
|
621
626
|
categoryId: CategoryID2;
|
|
622
627
|
description?: Description3;
|
|
628
|
+
memo?: Memo1;
|
|
623
629
|
};
|
|
624
630
|
/**
|
|
625
631
|
* UUID for the item
|
|
@@ -657,6 +663,10 @@ export type CategoryID2 = string | null;
|
|
|
657
663
|
* Optional description for the split.
|
|
658
664
|
*/
|
|
659
665
|
export type Description3 = string | null;
|
|
666
|
+
/**
|
|
667
|
+
* Optional memo for this split line.
|
|
668
|
+
*/
|
|
669
|
+
export type Memo1 = string | null;
|
|
660
670
|
|
|
661
671
|
/**
|
|
662
672
|
* Schema for the luca ledger
|
|
@@ -1001,6 +1011,7 @@ export type Transaction = Common & {
|
|
|
1001
1011
|
currency?: Currency;
|
|
1002
1012
|
amount: Amount;
|
|
1003
1013
|
description: Description;
|
|
1014
|
+
memo?: Memo;
|
|
1004
1015
|
categoryId?: CategoryID;
|
|
1005
1016
|
statementId?: StatementID;
|
|
1006
1017
|
aggregationServiceId?: AggregationServiceID;
|
|
@@ -1067,6 +1078,10 @@ export type Amount = number;
|
|
|
1067
1078
|
* Description of the transaction
|
|
1068
1079
|
*/
|
|
1069
1080
|
export type Description = string;
|
|
1081
|
+
/**
|
|
1082
|
+
* Optional memo for the transaction.
|
|
1083
|
+
*/
|
|
1084
|
+
export type Memo = string | null;
|
|
1070
1085
|
/**
|
|
1071
1086
|
* Category UUID for this transaction
|
|
1072
1087
|
*/
|
|
@@ -1099,6 +1114,7 @@ export type TransactionSplit = Common & {
|
|
|
1099
1114
|
amount: Amount;
|
|
1100
1115
|
categoryId: CategoryID;
|
|
1101
1116
|
description?: Description;
|
|
1117
|
+
memo?: Memo;
|
|
1102
1118
|
};
|
|
1103
1119
|
/**
|
|
1104
1120
|
* UUID for the item
|
|
@@ -1136,6 +1152,10 @@ export type CategoryID = string | null;
|
|
|
1136
1152
|
* Optional description for the split.
|
|
1137
1153
|
*/
|
|
1138
1154
|
export type Description = string | null;
|
|
1155
|
+
/**
|
|
1156
|
+
* Optional memo for this split line.
|
|
1157
|
+
*/
|
|
1158
|
+
export type Memo = string | null;
|
|
1139
1159
|
|
|
1140
1160
|
/**
|
|
1141
1161
|
* Common properties for all schemas
|
package/dist/esm/index.js
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
account,
|
|
3
|
+
category,
|
|
4
|
+
common,
|
|
5
|
+
enums as enumsSchema,
|
|
6
|
+
lucaSchema as lucaSchemaJson,
|
|
7
|
+
recurringTransaction,
|
|
8
|
+
recurringTransactionEvent,
|
|
9
|
+
statement,
|
|
10
|
+
transaction,
|
|
11
|
+
transactionSplit
|
|
12
|
+
} from './schemas/index.js';
|
|
2
13
|
import { enums, LucaSchemas } from './enums.js';
|
|
3
14
|
import {
|
|
15
|
+
getDateFieldPaths,
|
|
16
|
+
getDateFieldPathsByCollection,
|
|
4
17
|
getRequiredFields,
|
|
5
18
|
getValidFields,
|
|
6
19
|
stripInvalidFields,
|
|
7
20
|
validate,
|
|
8
21
|
validateCollection
|
|
9
22
|
} from './lucaValidator.js';
|
|
23
|
+
import { isDateStringFixable, normalizeDateString } from './dateUtils.js';
|
|
10
24
|
|
|
11
|
-
const schemas = {
|
|
25
|
+
const schemas = {
|
|
26
|
+
account,
|
|
27
|
+
category,
|
|
28
|
+
common,
|
|
29
|
+
lucaSchema: lucaSchemaJson,
|
|
30
|
+
statement,
|
|
31
|
+
recurringTransaction,
|
|
32
|
+
recurringTransactionEvent,
|
|
33
|
+
transaction,
|
|
34
|
+
transactionSplit,
|
|
35
|
+
enums: enumsSchema
|
|
36
|
+
};
|
|
12
37
|
|
|
13
38
|
export const accountSchema = schemas.account;
|
|
14
39
|
export const categorySchema = schemas.category;
|
|
@@ -26,6 +51,10 @@ export {
|
|
|
26
51
|
schemas,
|
|
27
52
|
validate,
|
|
28
53
|
validateCollection,
|
|
54
|
+
normalizeDateString,
|
|
55
|
+
isDateStringFixable,
|
|
56
|
+
getDateFieldPaths,
|
|
57
|
+
getDateFieldPathsByCollection,
|
|
29
58
|
getValidFields,
|
|
30
59
|
getRequiredFields,
|
|
31
60
|
stripInvalidFields
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
2
2
|
import addFormats from 'ajv-formats';
|
|
3
|
+
import { isDateStringFixable, normalizeDateString } from './dateUtils.js';
|
|
3
4
|
import accountSchemaJson from './schemas/account.json' with { type: 'json' };
|
|
4
5
|
import categorySchemaJson from './schemas/category.json' with { type: 'json' };
|
|
5
6
|
import commonSchemaJson from './schemas/common.json' with { type: 'json' };
|
|
@@ -27,6 +28,7 @@ const supportSchemas = [commonSchemaJson, enumsSchemaJson];
|
|
|
27
28
|
let sharedAjv;
|
|
28
29
|
const validFieldsCache = new Map();
|
|
29
30
|
const requiredFieldsCache = new Map();
|
|
31
|
+
const dateFieldPathsCache = new Map();
|
|
30
32
|
|
|
31
33
|
function getValidator() {
|
|
32
34
|
if (sharedAjv) return sharedAjv;
|
|
@@ -89,11 +91,111 @@ function isPlainObject(value) {
|
|
|
89
91
|
return proto === Object.prototype || proto === null;
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
function decodePointerToken(token) {
|
|
95
|
+
return token.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getValueAtInstancePath(data, instancePath) {
|
|
99
|
+
if (!instancePath) return data;
|
|
100
|
+
if (typeof instancePath !== 'string' || !instancePath.startsWith('/')) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const tokens = instancePath
|
|
105
|
+
.slice(1)
|
|
106
|
+
.split('/')
|
|
107
|
+
.filter(token => token.length > 0)
|
|
108
|
+
.map(decodePointerToken);
|
|
109
|
+
|
|
110
|
+
let current = data;
|
|
111
|
+
for (const token of tokens) {
|
|
112
|
+
if (current === null || current === undefined) return undefined;
|
|
113
|
+
if (Array.isArray(current)) {
|
|
114
|
+
const index = Number.parseInt(token, 10);
|
|
115
|
+
if (!Number.isInteger(index) || index < 0 || index >= current.length) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
current = current[index];
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (typeof current !== 'object') return undefined;
|
|
122
|
+
current = current[token];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return current;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createDateFormatIssue(error, data) {
|
|
129
|
+
const instancePath =
|
|
130
|
+
typeof error?.instancePath === 'string' ? error.instancePath : '';
|
|
131
|
+
const value = getValueAtInstancePath(data, instancePath);
|
|
132
|
+
const normalizedValue = normalizeDateString(value);
|
|
133
|
+
const fixable = isDateStringFixable(value);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
instancePath,
|
|
137
|
+
schemaPath: typeof error?.schemaPath === 'string' ? error.schemaPath : '',
|
|
138
|
+
keyword: 'format',
|
|
139
|
+
format: 'date',
|
|
140
|
+
value,
|
|
141
|
+
fixable,
|
|
142
|
+
normalizedValue: fixable ? normalizedValue : null
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function buildValidationMetadata(errors, data) {
|
|
147
|
+
const dateFormatIssues = [];
|
|
148
|
+
for (const error of errors) {
|
|
149
|
+
if (error?.keyword !== 'format') continue;
|
|
150
|
+
if (error?.params?.format !== 'date') continue;
|
|
151
|
+
dateFormatIssues.push(createDateFormatIssue(error, data));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
dateFormatIssues,
|
|
156
|
+
hasFixableDateFormatIssues: dateFormatIssues.some(issue => issue.fixable)
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function collectDatePathsFromSchemaFragment(schemaFragment, prefix = '') {
|
|
161
|
+
if (!schemaFragment || typeof schemaFragment !== 'object') return [];
|
|
162
|
+
|
|
163
|
+
const paths = [];
|
|
164
|
+
const properties = isPlainObject(schemaFragment.properties)
|
|
165
|
+
? schemaFragment.properties
|
|
166
|
+
: {};
|
|
167
|
+
|
|
168
|
+
for (const [fieldName, fieldSchema] of Object.entries(properties)) {
|
|
169
|
+
const path = prefix ? `${prefix}.${fieldName}` : fieldName;
|
|
170
|
+
if (!fieldSchema || typeof fieldSchema !== 'object') continue;
|
|
171
|
+
|
|
172
|
+
if (fieldSchema.format === 'date') {
|
|
173
|
+
paths.push(path);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
paths.push(...collectDatePathsFromSchemaFragment(fieldSchema, path));
|
|
177
|
+
|
|
178
|
+
if (fieldSchema.items && typeof fieldSchema.items === 'object') {
|
|
179
|
+
const itemPath = `${path}[]`;
|
|
180
|
+
paths.push(
|
|
181
|
+
...collectDatePathsFromSchemaFragment(fieldSchema.items, itemPath)
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return paths;
|
|
187
|
+
}
|
|
188
|
+
|
|
92
189
|
export function validate(schemaKey, data) {
|
|
93
190
|
const ajv = getValidator();
|
|
94
191
|
const schema = getSchema(schemaKey);
|
|
95
192
|
const isValid = ajv.validate(schema, data);
|
|
96
|
-
|
|
193
|
+
const errors = ajv.errors ?? [];
|
|
194
|
+
return {
|
|
195
|
+
valid: isValid,
|
|
196
|
+
errors,
|
|
197
|
+
metadata: buildValidationMetadata(errors, data)
|
|
198
|
+
};
|
|
97
199
|
}
|
|
98
200
|
|
|
99
201
|
/**
|
|
@@ -130,6 +232,50 @@ export function getRequiredFields(schemaKey) {
|
|
|
130
232
|
return fields;
|
|
131
233
|
}
|
|
132
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Returns cached date-format field paths for a schema key.
|
|
237
|
+
* Paths are dot-delimited and include [] for array item traversal.
|
|
238
|
+
* @param {string} schemaKey
|
|
239
|
+
* @returns {Array<string>}
|
|
240
|
+
*/
|
|
241
|
+
export function getDateFieldPaths(schemaKey) {
|
|
242
|
+
if (dateFieldPathsCache.has(schemaKey)) {
|
|
243
|
+
return dateFieldPathsCache.get(schemaKey);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const schema = getSchema(schemaKey);
|
|
247
|
+
const paths = collectDatePathsFromSchemaFragment({
|
|
248
|
+
properties: getSchemaProperties(schema)
|
|
249
|
+
});
|
|
250
|
+
const deduped = [...new Set(paths)];
|
|
251
|
+
dateFieldPathsCache.set(schemaKey, deduped);
|
|
252
|
+
return deduped;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Returns date-format field paths keyed by collection name.
|
|
257
|
+
* @returns {{
|
|
258
|
+
* accounts: Array<string>,
|
|
259
|
+
* categories: Array<string>,
|
|
260
|
+
* statements: Array<string>,
|
|
261
|
+
* recurringTransactions: Array<string>,
|
|
262
|
+
* recurringTransactionEvents: Array<string>,
|
|
263
|
+
* transactions: Array<string>,
|
|
264
|
+
* transactionSplits: Array<string>
|
|
265
|
+
* }}
|
|
266
|
+
*/
|
|
267
|
+
export function getDateFieldPathsByCollection() {
|
|
268
|
+
return {
|
|
269
|
+
accounts: getDateFieldPaths('account'),
|
|
270
|
+
categories: getDateFieldPaths('category'),
|
|
271
|
+
statements: getDateFieldPaths('statement'),
|
|
272
|
+
recurringTransactions: getDateFieldPaths('recurringTransaction'),
|
|
273
|
+
recurringTransactionEvents: getDateFieldPaths('recurringTransactionEvent'),
|
|
274
|
+
transactions: getDateFieldPaths('transaction'),
|
|
275
|
+
transactionSplits: getDateFieldPaths('transactionSplit')
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
133
279
|
/**
|
|
134
280
|
* Returns a new object containing only fields defined in the schema.
|
|
135
281
|
* @param {string} schemaKey
|
|
@@ -167,15 +313,25 @@ export function validateCollection(schemaKey, arrayOfEntities) {
|
|
|
167
313
|
arrayOfEntities.forEach((entity, index) => {
|
|
168
314
|
const isValid = validateFn(entity);
|
|
169
315
|
if (!isValid) {
|
|
316
|
+
const entityErrors = validateFn.errors ?? [];
|
|
170
317
|
errors.push({
|
|
171
318
|
index,
|
|
172
319
|
entity,
|
|
173
|
-
errors:
|
|
320
|
+
errors: entityErrors,
|
|
321
|
+
metadata: buildValidationMetadata(entityErrors, entity)
|
|
174
322
|
});
|
|
175
323
|
}
|
|
176
324
|
});
|
|
177
325
|
|
|
178
|
-
return {
|
|
326
|
+
return {
|
|
327
|
+
valid: errors.length === 0,
|
|
328
|
+
errors,
|
|
329
|
+
metadata: {
|
|
330
|
+
hasFixableDateFormatIssues: errors.some(
|
|
331
|
+
entityError => entityError.metadata.hasFixableDateFormatIssues
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
};
|
|
179
335
|
}
|
|
180
336
|
|
|
181
337
|
export { schemas };
|
|
@@ -34,5 +34,6 @@
|
|
|
34
34
|
"description": "The identifier of the parent category, if any. Null if the category is top-level. Parents must be top-level (no deeper than two levels; enforced outside JSON Schema)."
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
|
+
"unevaluatedProperties": false,
|
|
37
38
|
"required": ["slug", "name", "parentId"]
|
|
38
39
|
}
|
|
@@ -52,6 +52,11 @@
|
|
|
52
52
|
"minLength": 1,
|
|
53
53
|
"description": "Description of the transaction"
|
|
54
54
|
},
|
|
55
|
+
"memo": {
|
|
56
|
+
"type": ["string", "null"],
|
|
57
|
+
"title": "Memo",
|
|
58
|
+
"description": "Optional memo for the transaction."
|
|
59
|
+
},
|
|
55
60
|
"categoryId": {
|
|
56
61
|
"type": ["string", "null"],
|
|
57
62
|
"title": "Category ID",
|
|
@@ -78,5 +83,6 @@
|
|
|
78
83
|
"description": "The current state of the transaction."
|
|
79
84
|
}
|
|
80
85
|
},
|
|
86
|
+
"unevaluatedProperties": false,
|
|
81
87
|
"required": ["accountId", "date", "amount", "description", "transactionState"]
|
|
82
88
|
}
|
|
@@ -33,7 +33,13 @@
|
|
|
33
33
|
"type": ["string", "null"],
|
|
34
34
|
"title": "Description",
|
|
35
35
|
"description": "Optional description for the split."
|
|
36
|
+
},
|
|
37
|
+
"memo": {
|
|
38
|
+
"type": ["string", "null"],
|
|
39
|
+
"title": "Memo",
|
|
40
|
+
"description": "Optional memo for this split line."
|
|
36
41
|
}
|
|
37
42
|
},
|
|
43
|
+
"unevaluatedProperties": false,
|
|
38
44
|
"required": ["transactionId", "amount", "categoryId"]
|
|
39
45
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -534,6 +534,7 @@ export type Transaction = Common5 & {
|
|
|
534
534
|
currency?: Currency;
|
|
535
535
|
amount: Amount1;
|
|
536
536
|
description: Description2;
|
|
537
|
+
memo?: Memo;
|
|
537
538
|
categoryId?: CategoryID1;
|
|
538
539
|
statementId?: StatementID;
|
|
539
540
|
aggregationServiceId?: AggregationServiceID1;
|
|
@@ -600,6 +601,10 @@ export type Amount1 = number;
|
|
|
600
601
|
* Description of the transaction
|
|
601
602
|
*/
|
|
602
603
|
export type Description2 = string;
|
|
604
|
+
/**
|
|
605
|
+
* Optional memo for the transaction.
|
|
606
|
+
*/
|
|
607
|
+
export type Memo = string | null;
|
|
603
608
|
/**
|
|
604
609
|
* Category UUID for this transaction
|
|
605
610
|
*/
|
|
@@ -620,6 +625,7 @@ export type TransactionSplit = Common6 & {
|
|
|
620
625
|
amount: Amount2;
|
|
621
626
|
categoryId: CategoryID2;
|
|
622
627
|
description?: Description3;
|
|
628
|
+
memo?: Memo1;
|
|
623
629
|
};
|
|
624
630
|
/**
|
|
625
631
|
* UUID for the item
|
|
@@ -657,6 +663,10 @@ export type CategoryID2 = string | null;
|
|
|
657
663
|
* Optional description for the split.
|
|
658
664
|
*/
|
|
659
665
|
export type Description3 = string | null;
|
|
666
|
+
/**
|
|
667
|
+
* Optional memo for this split line.
|
|
668
|
+
*/
|
|
669
|
+
export type Memo1 = string | null;
|
|
660
670
|
|
|
661
671
|
/**
|
|
662
672
|
* Schema for the luca ledger
|
|
@@ -1001,6 +1011,7 @@ export type Transaction = Common & {
|
|
|
1001
1011
|
currency?: Currency;
|
|
1002
1012
|
amount: Amount;
|
|
1003
1013
|
description: Description;
|
|
1014
|
+
memo?: Memo;
|
|
1004
1015
|
categoryId?: CategoryID;
|
|
1005
1016
|
statementId?: StatementID;
|
|
1006
1017
|
aggregationServiceId?: AggregationServiceID;
|
|
@@ -1067,6 +1078,10 @@ export type Amount = number;
|
|
|
1067
1078
|
* Description of the transaction
|
|
1068
1079
|
*/
|
|
1069
1080
|
export type Description = string;
|
|
1081
|
+
/**
|
|
1082
|
+
* Optional memo for the transaction.
|
|
1083
|
+
*/
|
|
1084
|
+
export type Memo = string | null;
|
|
1070
1085
|
/**
|
|
1071
1086
|
* Category UUID for this transaction
|
|
1072
1087
|
*/
|
|
@@ -1099,6 +1114,7 @@ export type TransactionSplit = Common & {
|
|
|
1099
1114
|
amount: Amount;
|
|
1100
1115
|
categoryId: CategoryID;
|
|
1101
1116
|
description?: Description;
|
|
1117
|
+
memo?: Memo;
|
|
1102
1118
|
};
|
|
1103
1119
|
/**
|
|
1104
1120
|
* UUID for the item
|
|
@@ -1136,6 +1152,10 @@ export type CategoryID = string | null;
|
|
|
1136
1152
|
* Optional description for the split.
|
|
1137
1153
|
*/
|
|
1138
1154
|
export type Description = string | null;
|
|
1155
|
+
/**
|
|
1156
|
+
* Optional memo for this split line.
|
|
1157
|
+
*/
|
|
1158
|
+
export type Memo = string | null;
|
|
1139
1159
|
|
|
1140
1160
|
/**
|
|
1141
1161
|
* Common properties for all schemas
|