@firela/api-types 0.0.0-canary.792fa5f1 → 0.0.0-canary.7b647d33

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.
@@ -660,6 +660,32 @@ export const $CreateTransactionDto = {
660
660
  required: ['date', 'narration', 'postings']
661
661
  } as const;
662
662
 
663
+ export const $CostDetailDto = {
664
+ type: 'object',
665
+ properties: {
666
+ number: {
667
+ type: 'string',
668
+ description: 'Per-unit cost basis (mirrors engine Cost.number)',
669
+ example: '240'
670
+ },
671
+ currency: {
672
+ type: 'string',
673
+ description: 'Cost currency',
674
+ example: 'USD'
675
+ },
676
+ date: {
677
+ type: 'string',
678
+ description: 'Lot acquisition date (ISO yyyy-mm-dd)',
679
+ example: '2024-01-15'
680
+ },
681
+ label: {
682
+ type: 'string',
683
+ description: 'Lot label',
684
+ example: 'lot-2024-01'
685
+ }
686
+ }
687
+ } as const;
688
+
663
689
  export const $PostingResponseDto = {
664
690
  type: 'object',
665
691
  properties: {
@@ -678,6 +704,15 @@ export const $PostingResponseDto = {
678
704
  type: 'string',
679
705
  description: 'Currency',
680
706
  example: 'USD'
707
+ },
708
+ cost: {
709
+ description:
710
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
711
+ allOf: [
712
+ {
713
+ $ref: '#/components/schemas/CostDetailDto'
714
+ }
715
+ ]
681
716
  }
682
717
  },
683
718
  required: ['account']
@@ -1051,6 +1086,15 @@ export const $PostingDetailDto = {
1051
1086
  description: 'Cost date',
1052
1087
  example: '2024-01-15'
1053
1088
  },
1089
+ cost: {
1090
+ description:
1091
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
1092
+ allOf: [
1093
+ {
1094
+ $ref: '#/components/schemas/CostDetailDto'
1095
+ }
1096
+ ]
1097
+ },
1054
1098
  priceAmount: {
1055
1099
  type: 'string',
1056
1100
  description: 'Price amount',
@@ -1811,7 +1855,8 @@ export const $ResolveResultDto = {
1811
1855
  },
1812
1856
  resolutionId: {
1813
1857
  type: 'string',
1814
- description: 'Resolution ID for undo'
1858
+ description:
1859
+ 'Resolution ID for undo. Absent when the resolver rejected the decision (review stayed PENDING).'
1815
1860
  },
1816
1861
  canUndo: {
1817
1862
  type: 'boolean',
@@ -1829,7 +1874,7 @@ export const $ResolveResultDto = {
1829
1874
  example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1830
1875
  }
1831
1876
  },
1832
- required: ['success', 'resolutionId', 'canUndo', 'undoDeadline']
1877
+ required: ['success']
1833
1878
  } as const;
1834
1879
 
1835
1880
  export const $UndoResultDto = {
@@ -4267,6 +4312,144 @@ export const $UpdatePropertyDto = {
4267
4312
  required: ['value']
4268
4313
  } as const;
4269
4314
 
4315
+ export const $CreateBeanEventDto = {
4316
+ type: 'object',
4317
+ properties: {
4318
+ date: {
4319
+ type: 'string',
4320
+ description: 'Life event date (ISO 8601)',
4321
+ example: '2024-03-15'
4322
+ },
4323
+ type: {
4324
+ type: 'string',
4325
+ description:
4326
+ 'Life event type (e.g., "employer", "location", "marital-status") — user-defined, no enum constraint at engine layer',
4327
+ example: 'employer'
4328
+ },
4329
+ description: {
4330
+ type: 'string',
4331
+ description:
4332
+ 'Life event description. Empty string is a VALID value (distinct from absence).',
4333
+ example: 'Acme Corp'
4334
+ },
4335
+ meta: {
4336
+ type: 'object',
4337
+ description:
4338
+ 'Product-side metadata (lives in BeanEvent.meta JSON, never in engine Event fields)',
4339
+ example: {
4340
+ note: 'Promotion'
4341
+ }
4342
+ }
4343
+ },
4344
+ required: ['date', 'type', 'description']
4345
+ } as const;
4346
+
4347
+ export const $EventResponseDto = {
4348
+ type: 'object',
4349
+ properties: {
4350
+ id: {
4351
+ type: 'string',
4352
+ description: 'Unique identifier',
4353
+ example: 'uuid-123-456'
4354
+ },
4355
+ userId: {
4356
+ type: 'string',
4357
+ description: 'User ID (owner of the life event)',
4358
+ example: 'user-123'
4359
+ },
4360
+ date: {
4361
+ type: 'string',
4362
+ description: 'Life event date (ISO 8601 format)',
4363
+ example: '2024-03-15',
4364
+ format: 'date'
4365
+ },
4366
+ type: {
4367
+ type: 'string',
4368
+ description:
4369
+ 'Life event type (user-defined, e.g., "employer", "location")',
4370
+ example: 'employer'
4371
+ },
4372
+ description: {
4373
+ type: 'string',
4374
+ description:
4375
+ 'Life event description. May be an empty string (a valid value distinct from absence).',
4376
+ example: 'Acme Corp'
4377
+ },
4378
+ meta: {
4379
+ type: 'object',
4380
+ description: 'Product-side metadata (free-form JSON)',
4381
+ example: {
4382
+ note: 'Promotion'
4383
+ }
4384
+ },
4385
+ createdAt: {
4386
+ format: 'date-time',
4387
+ type: 'string',
4388
+ description: 'Creation timestamp',
4389
+ example: '2024-03-15T10:00:00Z'
4390
+ },
4391
+ updatedAt: {
4392
+ format: 'date-time',
4393
+ type: 'string',
4394
+ description:
4395
+ 'Last update timestamp. Also emitted as the ETag response header for If-Match optimistic concurrency.',
4396
+ example: '2024-03-15T10:00:00Z'
4397
+ }
4398
+ },
4399
+ required: [
4400
+ 'id',
4401
+ 'userId',
4402
+ 'date',
4403
+ 'type',
4404
+ 'description',
4405
+ 'meta',
4406
+ 'createdAt',
4407
+ 'updatedAt'
4408
+ ]
4409
+ } as const;
4410
+
4411
+ export const $EventListResponseDto = {
4412
+ type: 'object',
4413
+ properties: {
4414
+ items: {
4415
+ description: 'List of life events',
4416
+ type: 'array',
4417
+ items: {
4418
+ $ref: '#/components/schemas/EventResponseDto'
4419
+ }
4420
+ },
4421
+ total: {
4422
+ type: 'number',
4423
+ description: 'Total number of life events matching the query',
4424
+ example: 42
4425
+ }
4426
+ },
4427
+ required: ['items', 'total']
4428
+ } as const;
4429
+
4430
+ export const $UpdateBeanEventDto = {
4431
+ type: 'object',
4432
+ properties: {
4433
+ date: {
4434
+ type: 'string',
4435
+ description: 'Life event date (ISO 8601)'
4436
+ },
4437
+ type: {
4438
+ type: 'string',
4439
+ description: 'Life event type (user-defined)'
4440
+ },
4441
+ description: {
4442
+ type: 'string',
4443
+ description:
4444
+ 'Life event description. Empty string is a VALID value (distinct from absence).'
4445
+ },
4446
+ meta: {
4447
+ type: 'object',
4448
+ description: 'Product-side metadata (free-form JSON)'
4449
+ }
4450
+ }
4451
+ } as const;
4452
+
4270
4453
  export const $FileImportDto = {
4271
4454
  type: 'object',
4272
4455
  properties: {
@@ -7029,6 +7212,111 @@ export const $PortfolioTrendsResponseDto = {
7029
7212
  required: ['series', 'summary', 'period', 'granularity', 'currency']
7030
7213
  } as const;
7031
7214
 
7215
+ export const $CashFlowPointDto = {
7216
+ type: 'object',
7217
+ properties: {
7218
+ month: {
7219
+ type: 'string',
7220
+ description: 'Month key (YYYY-MM)',
7221
+ example: '2024-03'
7222
+ },
7223
+ income: {
7224
+ type: 'string',
7225
+ description: 'Income in base currency (absolute, converted)',
7226
+ example: '10000.00'
7227
+ },
7228
+ expense: {
7229
+ type: 'string',
7230
+ description: 'Expense in base currency (absolute, converted)',
7231
+ example: '5000.00'
7232
+ },
7233
+ netSavings: {
7234
+ type: 'string',
7235
+ description: 'netSavings = income − expense (savings positive)',
7236
+ example: '5000.00'
7237
+ }
7238
+ },
7239
+ required: ['month', 'income', 'expense', 'netSavings']
7240
+ } as const;
7241
+
7242
+ export const $CashFlowTrendSummaryDto = {
7243
+ type: 'object',
7244
+ properties: {
7245
+ totalIncome: {
7246
+ type: 'string',
7247
+ description: 'Total income across the period',
7248
+ example: '60000.00'
7249
+ },
7250
+ totalExpense: {
7251
+ type: 'string',
7252
+ description: 'Total expense across the period',
7253
+ example: '30000.00'
7254
+ },
7255
+ totalNetSavings: {
7256
+ type: 'string',
7257
+ description: 'income − expense across the period',
7258
+ example: '30000.00'
7259
+ },
7260
+ averageMonthlyNetSavings: {
7261
+ type: 'string',
7262
+ description:
7263
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
7264
+ example: '5000.00'
7265
+ }
7266
+ },
7267
+ required: [
7268
+ 'totalIncome',
7269
+ 'totalExpense',
7270
+ 'totalNetSavings',
7271
+ 'averageMonthlyNetSavings'
7272
+ ]
7273
+ } as const;
7274
+
7275
+ export const $CashFlowTrendsResponseDto = {
7276
+ type: 'object',
7277
+ properties: {
7278
+ series: {
7279
+ description:
7280
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
7281
+ type: 'array',
7282
+ items: {
7283
+ $ref: '#/components/schemas/CashFlowPointDto'
7284
+ }
7285
+ },
7286
+ summary: {
7287
+ description: 'Period totals',
7288
+ allOf: [
7289
+ {
7290
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
7291
+ }
7292
+ ]
7293
+ },
7294
+ period: {
7295
+ type: 'string',
7296
+ description: 'Period requested',
7297
+ example: '6m'
7298
+ },
7299
+ granularity: {
7300
+ type: 'string',
7301
+ description: 'Data granularity (v1 returns month buckets)',
7302
+ example: 'month'
7303
+ },
7304
+ currency: {
7305
+ type: 'string',
7306
+ description: 'Base currency for converted values',
7307
+ example: 'CNY'
7308
+ },
7309
+ warnings: {
7310
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
7311
+ type: 'array',
7312
+ items: {
7313
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7314
+ }
7315
+ }
7316
+ },
7317
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
7318
+ } as const;
7319
+
7032
7320
  export const $GenerateSnapshotBody = {
7033
7321
  type: 'object',
7034
7322
  properties: {}
@@ -171,6 +171,18 @@ import type {
171
171
  PropertyControllerUpdateResponse,
172
172
  PropertyControllerDeleteData,
173
173
  PropertyControllerDeleteResponse,
174
+ EventControllerCreateData,
175
+ EventControllerCreateResponse,
176
+ EventControllerFindAllData,
177
+ EventControllerFindAllResponse,
178
+ EventControllerFindOneData,
179
+ EventControllerFindOneResponse,
180
+ EventControllerUpdateData,
181
+ EventControllerUpdateResponse,
182
+ EventControllerDeleteData,
183
+ EventControllerDeleteResponse,
184
+ EventControllerGetSliceData,
185
+ EventControllerGetSliceResponse,
174
186
  ExportControllerExportBeancountResponse,
175
187
  FileImportControllerImportFileData,
176
188
  FileImportControllerImportFileResponse,
@@ -234,6 +246,8 @@ import type {
234
246
  PriceControllerBulkCreateResponse,
235
247
  ReportingControllerGetPortfolioTrendsData,
236
248
  ReportingControllerGetPortfolioTrendsResponse,
249
+ ReportingControllerGetCashFlowTrendsData,
250
+ ReportingControllerGetCashFlowTrendsResponse,
237
251
  ReportingControllerGenerateSnapshotData,
238
252
  ReportingControllerGenerateSnapshotResponse,
239
253
  ReportingControllerBackfillSnapshotsData,
@@ -2460,6 +2474,181 @@ export class PropertiesService {
2460
2474
  }
2461
2475
  }
2462
2476
 
2477
+ export class LifeEventsService {
2478
+ /**
2479
+ * Create a new life event
2480
+ * Creates a new life event entry for the authenticated user. Returns ETag header carrying the row updatedAt.
2481
+ * @param data The data for the request.
2482
+ * @param data.region Region code for tenant context (decorative for life events)
2483
+ * @param data.requestBody
2484
+ * @returns EventResponseDto Life event created successfully
2485
+ * @throws ApiError
2486
+ */
2487
+ public static eventControllerCreate(
2488
+ data: EventControllerCreateData
2489
+ ): CancelablePromise<EventControllerCreateResponse> {
2490
+ return __request(OpenAPI, {
2491
+ method: 'POST',
2492
+ url: '/api/v1/{region}/bean/events',
2493
+ path: {
2494
+ region: data.region
2495
+ },
2496
+ body: data.requestBody,
2497
+ mediaType: 'application/json',
2498
+ errors: {
2499
+ 409: 'Life event already exists for this (userId, type, date) combination'
2500
+ }
2501
+ });
2502
+ }
2503
+
2504
+ /**
2505
+ * List user life events
2506
+ * Returns life events for the authenticated user with optional filtering by type, description search, and date range.
2507
+ * @param data The data for the request.
2508
+ * @param data.region Region code for tenant context (decorative for life events)
2509
+ * @param data.type Filter by life event type (exact match)
2510
+ * @param data.q Search term for description (case-insensitive partial match)
2511
+ * @param data.from Filter life events from this date (ISO 8601 format)
2512
+ * @param data.to Filter life events to this date (ISO 8601 format)
2513
+ * @param data.page Page number for pagination (default: 1)
2514
+ * @param data.limit Number of items per page (default: 20, max: 100)
2515
+ * @returns EventListResponseDto Life events retrieved successfully
2516
+ * @throws ApiError
2517
+ */
2518
+ public static eventControllerFindAll(
2519
+ data: EventControllerFindAllData
2520
+ ): CancelablePromise<EventControllerFindAllResponse> {
2521
+ return __request(OpenAPI, {
2522
+ method: 'GET',
2523
+ url: '/api/v1/{region}/bean/events',
2524
+ path: {
2525
+ region: data.region
2526
+ },
2527
+ query: {
2528
+ type: data.type,
2529
+ q: data.q,
2530
+ from: data.from,
2531
+ to: data.to,
2532
+ page: data.page,
2533
+ limit: data.limit
2534
+ }
2535
+ });
2536
+ }
2537
+
2538
+ /**
2539
+ * Get life event by ID
2540
+ * Returns a single life event by its ID. Returns ETag header.
2541
+ * @param data The data for the request.
2542
+ * @param data.id Life event ID
2543
+ * @param data.region Region code for tenant context (decorative for life events)
2544
+ * @returns EventResponseDto Life event retrieved successfully
2545
+ * @throws ApiError
2546
+ */
2547
+ public static eventControllerFindOne(
2548
+ data: EventControllerFindOneData
2549
+ ): CancelablePromise<EventControllerFindOneResponse> {
2550
+ return __request(OpenAPI, {
2551
+ method: 'GET',
2552
+ url: '/api/v1/{region}/bean/events/{id}',
2553
+ path: {
2554
+ id: data.id,
2555
+ region: data.region
2556
+ },
2557
+ errors: {
2558
+ 404: 'Life event not found'
2559
+ }
2560
+ });
2561
+ }
2562
+
2563
+ /**
2564
+ * Update a life event
2565
+ * Updates an existing life event. If If-Match header is provided, performs optimistic concurrency check; mismatched updatedAt returns 412.
2566
+ * @param data The data for the request.
2567
+ * @param data.id Life event ID
2568
+ * @param data.region Region code for tenant context (decorative for life events)
2569
+ * @param data.requestBody
2570
+ * @returns EventResponseDto Life event updated successfully
2571
+ * @throws ApiError
2572
+ */
2573
+ public static eventControllerUpdate(
2574
+ data: EventControllerUpdateData
2575
+ ): CancelablePromise<EventControllerUpdateResponse> {
2576
+ return __request(OpenAPI, {
2577
+ method: 'PUT',
2578
+ url: '/api/v1/{region}/bean/events/{id}',
2579
+ path: {
2580
+ id: data.id,
2581
+ region: data.region
2582
+ },
2583
+ body: data.requestBody,
2584
+ mediaType: 'application/json',
2585
+ errors: {
2586
+ 400: 'If-Match header is not a valid ISO 8601 date',
2587
+ 404: 'Life event not found',
2588
+ 409: 'Updated event conflicts with an existing (userId, type, date) combination',
2589
+ 412: 'If-Match precondition failed (updatedAt mismatch)'
2590
+ }
2591
+ });
2592
+ }
2593
+
2594
+ /**
2595
+ * Delete a life event
2596
+ * Deletes a life event entry (hard delete). Returns 204.
2597
+ * @param data The data for the request.
2598
+ * @param data.id Life event ID
2599
+ * @param data.region Region code for tenant context (decorative for life events)
2600
+ * @returns void Life event deleted successfully
2601
+ * @throws ApiError
2602
+ */
2603
+ public static eventControllerDelete(
2604
+ data: EventControllerDeleteData
2605
+ ): CancelablePromise<EventControllerDeleteResponse> {
2606
+ return __request(OpenAPI, {
2607
+ method: 'DELETE',
2608
+ url: '/api/v1/{region}/bean/events/{id}',
2609
+ path: {
2610
+ id: data.id,
2611
+ region: data.region
2612
+ },
2613
+ errors: {
2614
+ 404: 'Life event not found'
2615
+ }
2616
+ });
2617
+ }
2618
+
2619
+ /**
2620
+ * Slice time-series by a life event (Phase 79)
2621
+ * Returns aggregated time-series for postings matching accountPattern within the half-open date range of the given life event.
2622
+ * @param data The data for the request.
2623
+ * @param data.id Life event ID
2624
+ * @param data.accountPattern
2625
+ * @param data.granularity
2626
+ * @param data.region Region code for tenant context (decorative for life events)
2627
+ * @returns unknown Time-series sliced by the life event range
2628
+ * @throws ApiError
2629
+ */
2630
+ public static eventControllerGetSlice(
2631
+ data: EventControllerGetSliceData
2632
+ ): CancelablePromise<EventControllerGetSliceResponse> {
2633
+ return __request(OpenAPI, {
2634
+ method: 'GET',
2635
+ url: '/api/v1/{region}/bean/events/{id}/slice',
2636
+ path: {
2637
+ id: data.id,
2638
+ region: data.region
2639
+ },
2640
+ query: {
2641
+ accountPattern: data.accountPattern,
2642
+ granularity: data.granularity
2643
+ },
2644
+ errors: {
2645
+ 400: 'accountPattern query param is empty',
2646
+ 404: 'Life event not found'
2647
+ }
2648
+ });
2649
+ }
2650
+ }
2651
+
2463
2652
  export class BeanExportService {
2464
2653
  /**
2465
2654
  * Export Beancount ledger as ZIP
@@ -3341,6 +3530,42 @@ export class ReportingService {
3341
3530
  });
3342
3531
  }
3343
3532
 
3533
+ /**
3534
+ * Get cash-flow trends
3535
+ *
3536
+ * Monthly income / expense / netSavings over a fixed N-month window
3537
+ * (current month + N−1 prior). Missing months are zero-filled (flow metric).
3538
+ *
3539
+ * **Parameters:**
3540
+ * - `period`: 1m | 3m | 6m | 1y (default 6m)
3541
+ * - `granularity`: accepted for API symmetry; v1 returns month buckets
3542
+ *
3543
+ * @param data The data for the request.
3544
+ * @param data.region Region code for tenant context
3545
+ * @param data.period Time period
3546
+ * @param data.granularity Data granularity (accepted for API symmetry; v1 returns month buckets)
3547
+ * @returns CashFlowTrendsResponseDto Cash-flow trends retrieved successfully
3548
+ * @throws ApiError
3549
+ */
3550
+ public static reportingControllerGetCashFlowTrends(
3551
+ data: ReportingControllerGetCashFlowTrendsData
3552
+ ): CancelablePromise<ReportingControllerGetCashFlowTrendsResponse> {
3553
+ return __request(OpenAPI, {
3554
+ method: 'GET',
3555
+ url: '/api/v1/{region}/reporting/cash-flow/trends',
3556
+ path: {
3557
+ region: data.region
3558
+ },
3559
+ query: {
3560
+ period: data.period,
3561
+ granularity: data.granularity
3562
+ },
3563
+ errors: {
3564
+ 401: 'User not authenticated'
3565
+ }
3566
+ });
3567
+ }
3568
+
3344
3569
  /**
3345
3570
  * Generate portfolio snapshot
3346
3571
  *