@antelopejs/interface-dms-saas 0.3.0 → 0.4.1

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.
Files changed (73) hide show
  1. package/README.md +75 -66
  2. package/dist/billing.d.ts +2 -0
  3. package/dist/billing.js +2 -1
  4. package/dist/billing.js.map +1 -1
  5. package/dist/db/models/billingSettings.model.d.ts +1 -0
  6. package/dist/db/models/creditNotes.model.d.ts +2 -0
  7. package/dist/db/models/creditNotes.model.js +9 -0
  8. package/dist/db/models/creditNotes.model.js.map +1 -1
  9. package/dist/db/models/features.model.d.ts +1 -0
  10. package/dist/db/models/invoices.model.d.ts +1 -0
  11. package/dist/db/models/legalDocuments.model.d.ts +1 -0
  12. package/dist/db/models/planMigrations.model.d.ts +6 -2
  13. package/dist/db/models/planMigrations.model.js +25 -8
  14. package/dist/db/models/planMigrations.model.js.map +1 -1
  15. package/dist/db/models/plans.model.d.ts +1 -0
  16. package/dist/db/models/platformNotes.model.d.ts +1 -0
  17. package/dist/db/models/refunds.model.d.ts +1 -0
  18. package/dist/db/models/segments.model.d.ts +8 -2
  19. package/dist/db/models/segments.model.js +14 -3
  20. package/dist/db/models/segments.model.js.map +1 -1
  21. package/dist/db/models/stripeWebhookEvents.model.d.ts +1 -0
  22. package/dist/db/models/tenantBillingInfo.model.d.ts +1 -0
  23. package/dist/db/models/tenantBillingState.model.d.ts +4 -2
  24. package/dist/db/models/tenantBillingState.model.js +47 -5
  25. package/dist/db/models/tenantBillingState.model.js.map +1 -1
  26. package/dist/db/models/tenantSubscriptions.model.d.ts +2 -0
  27. package/dist/db/models/tenantSubscriptions.model.js +6 -0
  28. package/dist/db/models/tenantSubscriptions.model.js.map +1 -1
  29. package/dist/db/models/trialConsumptions.model.d.ts +1 -0
  30. package/dist/db/models/userSegments.model.d.ts +3 -1
  31. package/dist/db/models/userSegments.model.js +2 -2
  32. package/dist/db/models/userSegments.model.js.map +1 -1
  33. package/dist/db/tables/billingSettings.table.d.ts +2 -1
  34. package/dist/db/tables/billingSettings.table.js +5 -1
  35. package/dist/db/tables/billingSettings.table.js.map +1 -1
  36. package/dist/db/tables/features.table.js +2 -0
  37. package/dist/db/tables/features.table.js.map +1 -1
  38. package/dist/db/tables/invoices.table.d.ts +6 -0
  39. package/dist/db/tables/invoices.table.js +24 -0
  40. package/dist/db/tables/invoices.table.js.map +1 -1
  41. package/dist/db/tables/legalDocuments.table.d.ts +8 -0
  42. package/dist/db/tables/legalDocuments.table.js +10 -1
  43. package/dist/db/tables/legalDocuments.table.js.map +1 -1
  44. package/dist/db/tables/planMigrations.table.d.ts +19 -1
  45. package/dist/db/tables/planMigrations.table.js +60 -1
  46. package/dist/db/tables/planMigrations.table.js.map +1 -1
  47. package/dist/db/tables/plans.table.d.ts +1 -0
  48. package/dist/db/tables/plans.table.js +2 -1
  49. package/dist/db/tables/plans.table.js.map +1 -1
  50. package/dist/db/tables/segments.table.d.ts +6 -0
  51. package/dist/db/tables/segments.table.js +8 -0
  52. package/dist/db/tables/segments.table.js.map +1 -1
  53. package/dist/db/tables/tenantBillingState.table.d.ts +48 -1
  54. package/dist/db/tables/tenantBillingState.table.js +100 -1
  55. package/dist/db/tables/tenantBillingState.table.js.map +1 -1
  56. package/dist/db/tables/tenantSubscriptions.table.d.ts +2 -0
  57. package/dist/db/tables/tenantSubscriptions.table.js +9 -0
  58. package/dist/db/tables/tenantSubscriptions.table.js.map +1 -1
  59. package/dist/page-definitions.d.ts +1 -8
  60. package/dist/page-definitions.js +1 -27
  61. package/dist/page-definitions.js.map +1 -1
  62. package/dist/pages.d.ts +1 -2
  63. package/dist/pages.js +13 -11
  64. package/dist/pages.js.map +1 -1
  65. package/dist/plans.d.ts +1 -1
  66. package/dist/plans.js +12 -2
  67. package/dist/plans.js.map +1 -1
  68. package/docs/1.index.md +47 -0
  69. package/docs/2.billing.md +66 -0
  70. package/docs/3.lifecycle-and-usage.md +95 -0
  71. package/docs/4.pages-plans-data.md +64 -0
  72. package/docs/tsconfig.json +11 -0
  73. package/package.json +24 -11
package/README.md CHANGED
@@ -1,76 +1,85 @@
1
+ <div align="center">
2
+
1
3
  # @antelopejs/interface-dms-saas
2
4
 
3
- <div align="center">
4
- <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue?style=for-the-badge&labelColor=000000"></a>
5
- <a href="https://discord.gg/sjK28QHrA7"><img src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000" alt="Discord"></a>
6
- <a href="https://antelopejs.com"><img src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000" alt="Documentation"></a>
5
+ <a href="https://www.npmjs.com/package/@antelopejs/interface-dms-saas"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-dms-saas?style=for-the-badge&labelColor=000000&color=000000"></a>
6
+ <a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-dms-saas?style=for-the-badge&labelColor=000000&color=000000"></a>
7
+ <a href="https://discord.gg/sjK28QHrA7"><img alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
8
+ <a href="https://dms.antelopejs.com/docs/modules/saas/extending"><img alt="Documentation" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
9
+
10
+ The AntelopeJS interface to extend the DMS SaaS module: billing, plans, registration, workspace pages and lifecycle.
11
+
7
12
  </div>
8
13
 
9
- Public interfaces of the AntelopeJS DMS SaaS module.
14
+ ## What it does
10
15
 
11
- A module that extends `@antelopejs/dms-saas` depends on this package rather than
12
- on the runtime, and imports the extension points from it:
16
+ - Adds invoice line items, reads customer balances and previews the upcoming invoice.
17
+ - Builds plan projections and catalogues, and normalizes prices.
18
+ - Extends registration and the provisioning of a new workspace.
19
+ - Adds workspace settings categories and blocks to the tenant billing page.
20
+ - Listens to workspace lifecycle events and operator actions, and exposes the canonical SaaS tables and models (`/db`).
13
21
 
14
- | Subpath | Surface |
15
- | --- | --- |
16
- | `@antelopejs/interface-dms-saas` | every extension point except `db`: billing, data API, pages, plans, provisioning and registration flat, plus the `invoiceLineItems` and `workspaceLifecycle` namespaces |
17
- | `@antelopejs/interface-dms-saas/billing` | customer balance, upcoming invoice preview and complimentary subscription state |
18
- | `@antelopejs/interface-dms-saas/data-api` | hidden-value data API filters |
19
- | `@antelopejs/interface-dms-saas/db` | canonical SaaS tables and data models |
20
- | `@antelopejs/interface-dms-saas/hidden-filter` | the `HiddenStringFilter` decorator on its own |
21
- | `@antelopejs/interface-dms-saas/invoice-line-items` | provider registration, line item types, line key helpers |
22
- | `@antelopejs/interface-dms-saas/page-definitions` | page and module ids, slugs and descriptors |
23
- | `@antelopejs/interface-dms-saas/pages` | workspace settings category and tenant billing page extensions |
24
- | `@antelopejs/interface-dms-saas/plans` | plan projections, catalog builder, and price normalization |
25
- | `@antelopejs/interface-dms-saas/provisioning` | provisioning hook payload |
26
- | `@antelopejs/interface-dms-saas/registration` | public registration capture limits |
27
- | `@antelopejs/interface-dms-saas/workspace-lifecycle` | workspace lifecycle events and operator actions |
28
-
29
- Two of those surfaces reach the root entry as namespaces rather than flat
30
- re-exports, because each exposes an `internal` proxy namespace and two
31
- `internal` names cannot coexist in one barrel:
32
-
33
- ```ts
22
+ A module that extends [`@antelopejs/dms-saas`](https://www.npmjs.com/package/@antelopejs/dms-saas) depends on this package, never on the runtime.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pnpm add @antelopejs/interface-dms-saas
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ The root entry holds every extension point except `db`, with `invoiceLineItems` and `workspaceLifecycle` as namespaces:
33
+
34
+ ```ts docs-check
34
35
  import { invoiceLineItems, workspaceLifecycle } from "@antelopejs/interface-dms-saas";
35
36
 
36
- invoiceLineItems.RegisterInvoiceLineItemsProvider(/* … */);
37
+ export const usageKey = invoiceLineItems.buildInvoiceLineKey("example.compute", "minutes");
38
+ export const isProvisioningCommitted = workspaceLifecycle.IsWorkspaceProvisioningCommitted;
37
39
  ```
38
40
 
39
- Their own subpaths stay the direct route to the same symbols. `./db` is the one
40
- surface the root entry leaves out: importing it registers the SaaS tables, and a
41
- consumer that only wants types should not pay for that.
42
-
43
- Subpaths resolve through the `exports` map only, so consumers must compile with
44
- `moduleResolution` set to `bundler`, `node16` or `nodenext`; the legacy `node`
45
- (node10) mode is not supported.
46
-
47
- This package is released on its own workflow and must be published before the
48
- runtime module: `@antelopejs/dms-saas` depends on it through
49
- `>=<interface version> <0.<minor + 1>.0`, a range that only resolves once this
50
- package is released. The runtime implements this interface, so it caps the range
51
- below the next minor: a breaking minor of this package never reaches an older
52
- dms-saas.
53
-
54
- ## Writing plans
55
-
56
- A module may seed plans straight into the `db` plan table. It leaves
57
- `Plan.paymentProviderRefs` empty on creation and never rewrites it: dms-saas
58
- links every plan billed through Stripe to a matching Stripe product and price,
59
- at startup and whenever the plan is offered or billed, and records what it
60
- synced in `paymentProviderRefs.stripeSyncedTerms`. See
61
- [Plans and Stripe](../dms-saas/README.md#plans-and-stripe).
62
-
63
- ## Upgrading
64
-
65
- ### Rows written by earlier builds
66
-
67
- The data contract no longer tolerates rows that predate the current fields:
68
- `TenantSubscription.isComplimentary` is a required boolean and
69
- `isComplimentarySubscription` only returns `true` for `isComplimentary: true`,
70
- `InvoiceModel.getAllInvoices` only matches `documentType: "invoice"`,
71
- `WebhookResult` no longer includes `failed`, `TenantSubscription.paidUsagePeriods`
72
- is a required array that alone decides billable usage, and `revision` is
73
- required on `TenantSubscription`, `Segment`, `UserSegment`, `PlanMigration` and
74
- `StripeWebhookEvent`, whose revision-fenced writes refuse a row without one.
75
- Fix such rows before upgrading, as described in the
76
- [`@antelopejs/dms-saas` upgrade notes](../dms-saas/README.md#upgrading).
41
+ Use the [entry-point reference](./docs/1.index.md#entry-points) for supported
42
+ subpaths. Importing `/db` registers SaaS tables; it is not a side-effect-free
43
+ types barrel. After direct subscription writes, call
44
+ [`RecomputeTenantBillingState`](./docs/2.billing.md#recomputetenantbillingstate)
45
+ to refresh derived billing and workspace directory state.
46
+
47
+ A module may seed plans straight into the `db` plan table: it leaves `Plan.paymentProviderRefs` empty and never rewrites it, since dms-saas links every billed plan to Stripe itself. See [Plans and Stripe](https://dms.antelopejs.com/docs/modules/saas/stripe#plans-and-stripe).
48
+
49
+ ## Compatibility
50
+
51
+ The implementation is `@antelopejs/dms-saas >=0.6.0`. The interface declares these dependencies:
52
+
53
+ <!-- docs-compat: ./package.json#dependencies -->
54
+
55
+ | Package | Range |
56
+ | --- | --- |
57
+ | `@antelopejs/interface-data-api` | `>=0.2.2 <1.0.0` |
58
+ | `@antelopejs/interface-dms` | `>=0.7.2 <1.0.0` |
59
+
60
+ Peer dependencies:
61
+
62
+ <!-- docs-compat: ./package.json#peerDependencies -->
63
+
64
+ | Package | Range |
65
+ | --- | --- |
66
+ | `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` |
67
+ | `@antelopejs/interface-database` | `>=0.1.10 <1.0.0` |
68
+ | `@antelopejs/interface-database-decorators` | `>=0.1.9 <1.0.0` |
69
+
70
+ Subpaths resolve through the `exports` map only: compile consumers with `moduleResolution` set to `bundler`, `node16` or `nodenext`. Upgrade this package together with `@antelopejs/dms-saas`; the [upgrade notes](https://dms.antelopejs.com/docs/modules/saas/faq#upgrading) cover the tenant billing page anchors and the rows written by earlier builds.
71
+
72
+ ## Documentation
73
+
74
+ - [Consumer reference](./docs/1.index.md): billing, usage, lifecycle, pages, plans and database boundaries
75
+ - [Extending the SaaS module](https://dms.antelopejs.com/docs/modules/saas/extending): every extension point with examples
76
+ - [Stripe](https://dms.antelopejs.com/docs/modules/saas/stripe)
77
+ - [SaaS module guide](https://dms.antelopejs.com/docs/modules/saas)
78
+
79
+ ## Contributing
80
+
81
+ This package lives in the [`AntelopeJS/dms-saas`](https://github.com/AntelopeJS/dms-saas) pnpm workspace, next to the module that implements it. Read [CONTRIBUTING.md](https://github.com/AntelopeJS/dms-saas/blob/main/CONTRIBUTING.md) and the [repository README](https://github.com/AntelopeJS/dms-saas#contributing) for the development commands. Release this package on its own workflow before the module that implements it.
82
+
83
+ ## License
84
+
85
+ [Apache-2.0](./LICENSE)
package/dist/billing.d.ts CHANGED
@@ -32,6 +32,7 @@ export interface UpcomingInvoiceLine {
32
32
  periodEnd: string;
33
33
  isProration: boolean;
34
34
  usageLineKey: string | null;
35
+ productId: string | null;
35
36
  }
36
37
  export interface UpcomingInvoiceTax {
37
38
  amountMinorUnits: number;
@@ -78,3 +79,4 @@ export interface UnavailableUpcomingInvoicePreview {
78
79
  }
79
80
  export type UpcomingInvoicePreview = AvailableUpcomingInvoicePreview | AbsentUpcomingInvoicePreview | UnavailableUpcomingInvoicePreview;
80
81
  export declare const GetUpcomingInvoicePreview: (scope: TenantCustomerBalanceScope) => Promise<UpcomingInvoicePreview>;
82
+ export declare const RecomputeTenantBillingState: (tenantId: string) => Promise<void>;
package/dist/billing.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GetUpcomingInvoicePreview = exports.GetTenantCustomerBalance = void 0;
3
+ exports.RecomputeTenantBillingState = exports.GetUpcomingInvoicePreview = exports.GetTenantCustomerBalance = void 0;
4
4
  exports.isComplimentarySubscription = isComplimentarySubscription;
5
5
  const interface_core_1 = require("@antelopejs/interface-core");
6
6
  function isComplimentarySubscription(subscription) {
@@ -8,4 +8,5 @@ function isComplimentarySubscription(subscription) {
8
8
  }
9
9
  exports.GetTenantCustomerBalance = (0, interface_core_1.InterfaceFunction)();
10
10
  exports.GetUpcomingInvoicePreview = (0, interface_core_1.InterfaceFunction)();
11
+ exports.RecomputeTenantBillingState = (0, interface_core_1.InterfaceFunction)();
11
12
  //# sourceMappingURL=billing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":";;;AAQA,kEAIC;AAZD,+DAA+D;AAQ/D,SAAgB,2BAA2B,CACzC,YAA+D;IAE/D,OAAO,YAAY,EAAE,eAAe,KAAK,IAAI,CAAC;AAChD,CAAC;AAwCY,QAAA,wBAAwB,GACnC,IAAA,kCAAiB,GAEd,CAAC;AAiIO,QAAA,yBAAyB,GACpC,IAAA,kCAAiB,GAEd,CAAC"}
1
+ {"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":";;;AAQA,kEAIC;AAZD,+DAA+D;AAQ/D,SAAgB,2BAA2B,CACzC,YAA+D;IAE/D,OAAO,YAAY,EAAE,eAAe,KAAK,IAAI,CAAC;AAChD,CAAC;AAwCY,QAAA,wBAAwB,GACnC,IAAA,kCAAiB,GAEd,CAAC;AAmIO,QAAA,yBAAyB,GACpC,IAAA,kCAAiB,GAEd,CAAC;AAQO,QAAA,2BAA2B,GACtC,IAAA,kCAAiB,GAAuC,CAAC"}
@@ -12,6 +12,7 @@ declare const BillingSettingsModel_base: {
12
12
  delete(id: string): Promise<number>;
13
13
  };
14
14
  readonly schemaName: string;
15
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<BillingSettings>;
15
16
  fromPlainData(obj: any): BillingSettings;
16
17
  fromDatabase(obj: any): BillingSettings | undefined;
17
18
  toDatabase(obj: any): Record<string, any>;
@@ -13,6 +13,7 @@ declare const CreditNoteModel_base: {
13
13
  delete(id: string): Promise<number>;
14
14
  };
15
15
  readonly schemaName: string;
16
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<CreditNote>;
16
17
  fromPlainData(obj: any): CreditNote;
17
18
  fromDatabase(obj: any): CreditNote | undefined;
18
19
  toDatabase(obj: any): Record<string, any>;
@@ -20,6 +21,7 @@ declare const CreditNoteModel_base: {
20
21
  };
21
22
  export declare class CreditNoteModel extends CreditNoteModel_base {
22
23
  updateUnlessVoided(id: string, patch: DeepPartial<CreditNote>): Promise<boolean>;
24
+ findByInvoice(invoiceId: string): Promise<CreditNote[]>;
23
25
  findOneByStripeCreditNote(stripeCreditNoteId: string): Promise<CreditNote | undefined>;
24
26
  }
25
27
  export {};
@@ -13,6 +13,15 @@ class CreditNoteModel extends (0, interface_database_decorators_1.BasicDataModel
13
13
  .run();
14
14
  return (0, update_result_1.hasSelectedRow)(result);
15
15
  }
16
+ async findByInvoice(invoiceId) {
17
+ const rows = await this.table
18
+ .getAll(invoiceId, "invoiceId")
19
+ .orderBy("issuedAt")
20
+ .run();
21
+ return rows
22
+ .map((row) => CreditNoteModel.fromDatabase(row))
23
+ .filter((row) => row !== undefined);
24
+ }
16
25
  async findOneByStripeCreditNote(stripeCreditNoteId) {
17
26
  const row = await this.table
18
27
  .getAll(stripeCreditNoteId, "stripeCreditNoteId")
@@ -1 +1 @@
1
- {"version":3,"file":"creditNotes.model.js","sourceRoot":"","sources":["../../../src/db/models/creditNotes.model.ts"],"names":[],"mappings":";;;AACA,6FAA2E;AAC3E,mEAA+E;AAC/E,mDAAiD;AAGjD,MAAa,eAAgB,SAAQ,IAAA,8CAAc,EACjD,8BAAU,EACV,wCAAoB,CACrB;IAEC,KAAK,CAAC,kBAAkB,CACtB,EAAU,EACV,KAA8B;QAE9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK;aAC5B,MAAM,CAAC,EAAE,CAAC;aACV,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;aAC7C,MAAM,CAAC,KAAK,CAAC;aACb,GAAG,EAAE,CAAC;QACT,OAAO,IAAA,8BAAc,EAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC7B,kBAA0B;QAE1B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK;aACzB,MAAM,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;aAChD,GAAG,CAAC,CAAC,CAAC;aACN,OAAO,CAAC,SAAS,CAAC;aAClB,GAAG,EAAE,CAAC;QACT,OAAO,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7D,CAAC;CACF;AA3BD,0CA2BC"}
1
+ {"version":3,"file":"creditNotes.model.js","sourceRoot":"","sources":["../../../src/db/models/creditNotes.model.ts"],"names":[],"mappings":";;;AACA,6FAA2E;AAC3E,mEAA+E;AAC/E,mDAAiD;AAGjD,MAAa,eAAgB,SAAQ,IAAA,8CAAc,EACjD,8BAAU,EACV,wCAAoB,CACrB;IAEC,KAAK,CAAC,kBAAkB,CACtB,EAAU,EACV,KAA8B;QAE9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK;aAC5B,MAAM,CAAC,EAAE,CAAC;aACV,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;aAC7C,MAAM,CAAC,KAAK,CAAC;aACb,GAAG,EAAE,CAAC;QACT,OAAO,IAAA,8BAAc,EAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAGD,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK;aAC1B,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC;aAC9B,OAAO,CAAC,UAAU,CAAC;aACnB,GAAG,EAAE,CAAC;QACT,OAAO,IAAI;aACR,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;aAC/C,MAAM,CAAC,CAAC,GAAG,EAAqB,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC7B,kBAA0B;QAE1B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK;aACzB,MAAM,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;aAChD,GAAG,CAAC,CAAC,CAAC;aACN,OAAO,CAAC,SAAS,CAAC;aAClB,GAAG,EAAE,CAAC;QACT,OAAO,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7D,CAAC;CACF;AAtCD,0CAsCC"}
@@ -12,6 +12,7 @@ declare const FeatureModel_base: {
12
12
  delete(id: string): Promise<number>;
13
13
  };
14
14
  readonly schemaName: string;
15
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<Feature>;
15
16
  fromPlainData(obj: any): Feature;
16
17
  fromDatabase(obj: any): Feature | undefined;
17
18
  toDatabase(obj: any): Record<string, any>;
@@ -13,6 +13,7 @@ declare const InvoiceModel_base: {
13
13
  delete(id: string): Promise<number>;
14
14
  };
15
15
  readonly schemaName: string;
16
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<Invoice>;
16
17
  fromPlainData(obj: any): Invoice;
17
18
  fromDatabase(obj: any): Invoice | undefined;
18
19
  toDatabase(obj: any): Record<string, any>;
@@ -12,6 +12,7 @@ declare const LegalDocumentsModel_base: {
12
12
  delete(id: string): Promise<number>;
13
13
  };
14
14
  readonly schemaName: string;
15
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<LegalDocuments>;
15
16
  fromPlainData(obj: any): LegalDocuments;
16
17
  fromDatabase(obj: any): LegalDocuments | undefined;
17
18
  toDatabase(obj: any): Record<string, any>;
@@ -1,5 +1,5 @@
1
1
  import { type DeepPartial, type ValidateOptions } from "@antelopejs/interface-database-decorators";
2
- import { PlanMigration, type PlanMigrationSnapshot } from "../tables/planMigrations.table";
2
+ import { PlanMigration, type PlanMigrationSnapshot, type PlanMigrationStage } from "../tables/planMigrations.table";
3
3
  declare const PlanMigrationModel_base: {
4
4
  new (database: import("@antelopejs/interface-database").SchemaInstance<any>): {
5
5
  readonly table: import("@antelopejs/interface-database").Table<PlanMigration>;
@@ -13,6 +13,7 @@ declare const PlanMigrationModel_base: {
13
13
  delete(id: string): Promise<number>;
14
14
  };
15
15
  readonly schemaName: string;
16
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<PlanMigration>;
16
17
  fromPlainData(obj: any): PlanMigration;
17
18
  fromDatabase(obj: any): PlanMigration | undefined;
18
19
  toDatabase(obj: any): Record<string, any>;
@@ -23,8 +24,11 @@ export declare class PlanMigrationModel extends PlanMigrationModel_base {
23
24
  beginJob(job: PlanMigration, snapshot: PlanMigrationSnapshot): Promise<boolean>;
24
25
  checkpoint(job: PlanMigration, patch: Partial<PlanMigration>): Promise<void>;
25
26
  markInterrupted(job: PlanMigration): Promise<boolean>;
27
+ updateSettled(job: PlanMigration, patch: Partial<PlanMigration>): Promise<boolean>;
28
+ reopen(job: PlanMigration): Promise<boolean>;
26
29
  private persist;
27
30
  findResumable(): Promise<PlanMigration[]>;
28
- existsPendingOrRunningForPlan(fromPlanId: string): Promise<boolean>;
31
+ existsUnsettledForPlan(fromPlanId: string): Promise<boolean>;
32
+ findByStage(stage: PlanMigrationStage): Promise<PlanMigration[]>;
29
33
  }
30
34
  export {};
@@ -10,6 +10,7 @@ class PlanMigrationModel extends (0, interface_database_decorators_1.BasicDataMo
10
10
  ...row,
11
11
  revision: (0, node_crypto_1.randomUUID)(),
12
12
  tenantOutcomes: [],
13
+ stage: (0, planMigrations_table_1.planMigrationStageOf)(row.status ?? "pending"),
13
14
  });
14
15
  return super.insert(Array.isArray(rows) ? rows.map(initialize) : initialize(rows), options);
15
16
  }
@@ -32,22 +33,35 @@ class PlanMigrationModel extends (0, interface_database_decorators_1.BasicDataMo
32
33
  return false;
33
34
  return this.persist(job, { status: "reconciliation_required" });
34
35
  }
36
+ async updateSettled(job, patch) {
37
+ if ((0, planMigrations_table_1.isPlanMigrationExecuting)(job.status))
38
+ return false;
39
+ return this.persist(job, patch);
40
+ }
41
+ async reopen(job) {
42
+ if ((0, planMigrations_table_1.isPlanMigrationExecuting)(job.status))
43
+ return false;
44
+ return this.persist(job, { status: "running", completedAt: null });
45
+ }
35
46
  async persist(job, patch) {
36
47
  const nextRevision = (0, node_crypto_1.randomUUID)();
48
+ const written = patch.status
49
+ ? { ...patch, stage: (0, planMigrations_table_1.planMigrationStageOf)(patch.status) }
50
+ : patch;
37
51
  const outcome = await this.table
38
52
  .atomicMutation(job._id, {
39
53
  type: "update",
40
54
  revisionField: "revision",
41
55
  expectedRevision: job.revision,
42
56
  nextRevision,
43
- patch,
57
+ patch: written,
44
58
  })
45
59
  .run();
46
60
  if (outcome === "unknown")
47
61
  throw new Error("Migration acknowledgement unknown; reconciliation required");
48
62
  if (outcome !== "applied")
49
63
  return false;
50
- Object.assign(job, patch, { revision: nextRevision });
64
+ Object.assign(job, written, { revision: nextRevision });
51
65
  return true;
52
66
  }
53
67
  async findResumable() {
@@ -58,18 +72,21 @@ class PlanMigrationModel extends (0, interface_database_decorators_1.BasicDataMo
58
72
  .map((row) => PlanMigrationModel.fromDatabase(row))
59
73
  .filter((row) => row !== undefined);
60
74
  }
61
- async existsPendingOrRunningForPlan(fromPlanId) {
75
+ async existsUnsettledForPlan(fromPlanId) {
62
76
  const count = await this.table
63
77
  .getAll(fromPlanId, "fromPlanId")
64
- .filter((row) => row
65
- .key("status")
66
- .eq("pending")
67
- .or(row.key("status").eq("running"))
68
- .or(row.key("status").eq("reconciliation_required")))
78
+ .filter((row) => row.key("stage").ne("done"))
69
79
  .count()
70
80
  .run();
71
81
  return count > 0;
72
82
  }
83
+ async findByStage(stage) {
84
+ const rows = await this.table.getAll(stage, "stage").run();
85
+ return rows
86
+ .map((row) => PlanMigrationModel.fromDatabase(row))
87
+ .filter((row) => row !== undefined)
88
+ .sort((left, right) => right.createdAt.getTime() - left.createdAt.getTime());
89
+ }
73
90
  }
74
91
  exports.PlanMigrationModel = PlanMigrationModel;
75
92
  //# sourceMappingURL=planMigrations.model.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"planMigrations.model.js","sourceRoot":"","sources":["../../../src/db/models/planMigrations.model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"planMigrations.model.js","sourceRoot":"","sources":["../../../src/db/models/planMigrations.model.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,7 @@ declare const PlanModel_base: {
16
16
  delete(id: string): Promise<number>;
17
17
  };
18
18
  readonly schemaName: string;
19
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<Plan>;
19
20
  fromPlainData(obj: any): Plan;
20
21
  fromDatabase(obj: any): Plan | undefined;
21
22
  toDatabase(obj: any): Record<string, any>;
@@ -22,6 +22,7 @@ declare const PlatformNoteModel_base: {
22
22
  delete(id: string): Promise<number>;
23
23
  };
24
24
  readonly schemaName: string;
25
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<PlatformNote>;
25
26
  fromPlainData(obj: any): PlatformNote;
26
27
  fromDatabase(obj: any): PlatformNote | undefined;
27
28
  toDatabase(obj: any): Record<string, any>;
@@ -12,6 +12,7 @@ declare const RefundModel_base: {
12
12
  delete(id: string): Promise<number>;
13
13
  };
14
14
  readonly schemaName: string;
15
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<Refund>;
15
16
  fromPlainData(obj: any): Refund;
16
17
  fromDatabase(obj: any): Refund | undefined;
17
18
  toDatabase(obj: any): Record<string, any>;
@@ -1,5 +1,10 @@
1
1
  import { type DeepPartial, type ValidateOptions } from "@antelopejs/interface-database-decorators";
2
- import { Segment } from "../tables/segments.table";
2
+ import { Segment, type SegmentCountPoint } from "../tables/segments.table";
3
+ export declare const SEGMENT_COUNT_HISTORY_DAYS = 30;
4
+ export interface SegmentEvaluationStats {
5
+ durationMs?: number;
6
+ }
7
+ export declare function appendSegmentCountPoint(history: readonly SegmentCountPoint[], count: number, evaluatedAt: Date): SegmentCountPoint[];
3
8
  declare const SegmentModel_base: {
4
9
  new (database: import("@antelopejs/interface-database").SchemaInstance<any>): {
5
10
  readonly table: import("@antelopejs/interface-database").Table<Segment>;
@@ -13,6 +18,7 @@ declare const SegmentModel_base: {
13
18
  delete(id: string): Promise<number>;
14
19
  };
15
20
  readonly schemaName: string;
21
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<Segment>;
16
22
  fromPlainData(obj: any): Segment;
17
23
  fromDatabase(obj: any): Segment | undefined;
18
24
  toDatabase(obj: any): Record<string, any>;
@@ -22,7 +28,7 @@ export declare class SegmentModel extends SegmentModel_base {
22
28
  update(id: string, patch: DeepPartial<Segment>, options?: ValidateOptions): Promise<number>;
23
29
  update(patch: DeepPartial<Segment>, options?: ValidateOptions): Promise<number>;
24
30
  private updateRevision;
25
- publishMemberships(segment: Segment, generation: string, count: number, evaluatedAt: Date): Promise<boolean>;
31
+ publishMemberships(segment: Segment, generation: string, count: number, evaluatedAt: Date, stats?: SegmentEvaluationStats): Promise<boolean>;
26
32
  getMany(ids: readonly string[]): Promise<Segment[]>;
27
33
  }
28
34
  export {};
@@ -1,9 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SegmentModel = void 0;
3
+ exports.SegmentModel = exports.SEGMENT_COUNT_HISTORY_DAYS = void 0;
4
+ exports.appendSegmentCountPoint = appendSegmentCountPoint;
4
5
  const node_crypto_1 = require("node:crypto");
5
6
  const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
6
7
  const segments_table_1 = require("../tables/segments.table");
8
+ exports.SEGMENT_COUNT_HISTORY_DAYS = 30;
9
+ const ISO_DAY_LENGTH = 10;
10
+ function appendSegmentCountPoint(history, count, evaluatedAt) {
11
+ const day = evaluatedAt.toISOString().slice(0, ISO_DAY_LENGTH);
12
+ const kept = history.filter((point) => point.day !== day);
13
+ return [...kept, { day, count }]
14
+ .sort((a, b) => a.day.localeCompare(b.day))
15
+ .slice(-exports.SEGMENT_COUNT_HISTORY_DAYS);
16
+ }
7
17
  class SegmentModel extends (0, interface_database_decorators_1.BasicDataModel)(segments_table_1.Segment, segments_table_1.segmentsTableName) {
8
18
  async update(idOrPatch, patchOrOptions, options) {
9
19
  const id = typeof idOrPatch === "string" ? idOrPatch : idOrPatch._id;
@@ -39,7 +49,7 @@ class SegmentModel extends (0, interface_database_decorators_1.BasicDataModel)(s
39
49
  throw new Error(`Segment edit ${outcome}; reload before retry`);
40
50
  return 1;
41
51
  }
42
- async publishMemberships(segment, generation, count, evaluatedAt) {
52
+ async publishMemberships(segment, generation, count, evaluatedAt, stats = {}) {
43
53
  const outcome = await this.table
44
54
  .atomicMutation(segment._id, {
45
55
  type: "update",
@@ -50,7 +60,8 @@ class SegmentModel extends (0, interface_database_decorators_1.BasicDataModel)(s
50
60
  membershipGeneration: generation,
51
61
  estimatedCount: count,
52
62
  lastEvaluatedAt: evaluatedAt,
53
- updatedAt: evaluatedAt,
63
+ lastEvaluationMs: stats.durationMs ?? null,
64
+ countHistory: appendSegmentCountPoint(segment.countHistory, count, evaluatedAt),
54
65
  },
55
66
  })
56
67
  .run();
@@ -1 +1 @@
1
- {"version":3,"file":"segments.model.js","sourceRoot":"","sources":["../../../src/db/models/segments.model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"segments.model.js","sourceRoot":"","sources":["../../../src/db/models/segments.model.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,7 @@ declare const StripeWebhookEventModel_base: {
13
13
  delete(id: string): Promise<number>;
14
14
  };
15
15
  readonly schemaName: string;
16
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<StripeWebhookEvent>;
16
17
  fromPlainData(obj: any): StripeWebhookEvent;
17
18
  fromDatabase(obj: any): StripeWebhookEvent | undefined;
18
19
  toDatabase(obj: any): Record<string, any>;
@@ -12,6 +12,7 @@ declare const TenantBillingInfoModel_base: {
12
12
  delete(id: string): Promise<number>;
13
13
  };
14
14
  readonly schemaName: string;
15
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<TenantBillingInfo>;
15
16
  fromPlainData(obj: any): TenantBillingInfo;
16
17
  fromDatabase(obj: any): TenantBillingInfo | undefined;
17
18
  toDatabase(obj: any): Record<string, any>;
@@ -1,4 +1,4 @@
1
- import { type BillingState, TenantBillingState } from "../tables/tenantBillingState.table";
1
+ import { type BillingState, TenantBillingState, type WorkspaceDirectoryFields } from "../tables/tenantBillingState.table";
2
2
  declare const TenantBillingStateModel_base: {
3
3
  new (database: import("@antelopejs/interface-database").SchemaInstance<any>): {
4
4
  readonly table: import("@antelopejs/interface-database").Table<TenantBillingState>;
@@ -12,6 +12,7 @@ declare const TenantBillingStateModel_base: {
12
12
  delete(id: string): Promise<number>;
13
13
  };
14
14
  readonly schemaName: string;
15
+ readonly tableClass: import("@antelopejs/interface-database-decorators").Constructible<TenantBillingState>;
15
16
  fromPlainData(obj: any): TenantBillingState;
16
17
  fromDatabase(obj: any): TenantBillingState | undefined;
17
18
  toDatabase(obj: any): Record<string, any>;
@@ -19,9 +20,10 @@ declare const TenantBillingStateModel_base: {
19
20
  };
20
21
  export declare class TenantBillingStateModel extends TenantBillingStateModel_base {
21
22
  findByTenant(tenantId: string): Promise<TenantBillingState | undefined>;
22
- upsertForTenant(tenantId: string, billingState: BillingState, existing: TenantBillingState | undefined): Promise<boolean>;
23
+ upsertForTenant(tenantId: string, billingState: BillingState, existing: TenantBillingState | undefined, directory: WorkspaceDirectoryFields): Promise<boolean>;
23
24
  private publish;
24
25
  private insertPublication;
26
+ findByPlan(planId: string): Promise<TenantBillingState[]>;
25
27
  countByState(billingState: BillingState): Promise<number>;
26
28
  deleteForTenant(tenantId: string): Promise<void>;
27
29
  }
@@ -5,20 +5,53 @@ const node_crypto_1 = require("node:crypto");
5
5
  const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
6
6
  const tenantBillingState_table_1 = require("../tables/tenantBillingState.table");
7
7
  const DELETE_ATTEMPTS = 3;
8
+ const DELETED_WORKSPACE_DIRECTORY = {
9
+ planId: null,
10
+ planName: null,
11
+ planInterval: null,
12
+ planBillingMode: null,
13
+ planUnitAmountMinor: null,
14
+ currency: null,
15
+ seats: 0,
16
+ members: 0,
17
+ pendingPlanId: null,
18
+ isComplimentary: false,
19
+ mrrMinor: 0,
20
+ previousMrrMinor: 0,
21
+ reportingMrr: 0,
22
+ renewalKind: null,
23
+ renewsAt: null,
24
+ stateSince: null,
25
+ ownerStatus: "none",
26
+ ownerNeverJoined: false,
27
+ ownerName: null,
28
+ ownerEmail: null,
29
+ };
8
30
  class TenantBillingStateModel extends (0, interface_database_decorators_1.BasicDataModel)(tenantBillingState_table_1.TenantBillingState, tenantBillingState_table_1.tenantBillingStateTableName) {
9
31
  async findByTenant(tenantId) {
10
32
  return this.get(tenantId);
11
33
  }
12
- async upsertForTenant(tenantId, billingState, existing) {
34
+ async upsertForTenant(tenantId, billingState, existing, directory) {
13
35
  if (existing?.deletedAt)
14
36
  return true;
15
- return this.publish(tenantId, existing, billingState, null);
37
+ return this.publish(tenantId, existing, billingState, null, directory);
16
38
  }
17
- async publish(tenantId, existing, billingState, deletedAt) {
39
+ async publish(tenantId, existing, billingState, deletedAt, directory) {
18
40
  const revision = (0, node_crypto_1.randomUUID)();
19
- const patch = { tenantId, billingState, updatedAt: new Date(), deletedAt };
41
+ const patch = {
42
+ ...directory,
43
+ tenantId,
44
+ billingState,
45
+ updatedAt: new Date(),
46
+ deletedAt,
47
+ };
20
48
  if (!existing)
21
- return this.insertPublication({ _id: tenantId, ...patch, revision });
49
+ return this.insertPublication({
50
+ ...DELETED_WORKSPACE_DIRECTORY,
51
+ _id: tenantId,
52
+ ...patch,
53
+ revision,
54
+ });
22
55
  const outcome = await this.table
23
56
  .atomicMutation(tenantId, {
24
57
  type: "update",
@@ -47,6 +80,15 @@ class TenantBillingStateModel extends (0, interface_database_decorators_1.BasicD
47
80
  throw new Error("Billing publication was not persisted");
48
81
  return current.revision === row.revision;
49
82
  }
83
+ async findByPlan(planId) {
84
+ const rows = await this.table
85
+ .getAll(planId, "planId")
86
+ .filter((row) => row.key("deletedAt").eq(null))
87
+ .run();
88
+ return rows
89
+ .map((row) => TenantBillingStateModel.fromDatabase(row))
90
+ .filter((row) => row !== undefined);
91
+ }
50
92
  async countByState(billingState) {
51
93
  return this.table
52
94
  .getAll(billingState, "billingState")