@antelopejs/interface-dms-saas 0.5.1 → 0.6.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.
- package/README.md +5 -5
- package/dist/billing.d.ts +5 -0
- package/dist/billing.js +2 -1
- package/dist/billing.js.map +1 -1
- package/dist/db/models/plans.model.d.ts +3 -0
- package/dist/db/models/plans.model.js +22 -9
- package/dist/db/models/plans.model.js.map +1 -1
- package/dist/db/tables/plans.table.d.ts +10 -1
- package/dist/db/tables/plans.table.js +11 -2
- package/dist/db/tables/plans.table.js.map +1 -1
- package/dist/db/tables/tenantSubscriptions.table.d.ts +1 -0
- package/dist/db/tables/tenantSubscriptions.table.js +4 -0
- package/dist/db/tables/tenantSubscriptions.table.js.map +1 -1
- package/dist/invoice-line-items.d.ts +10 -6
- package/dist/invoice-line-items.js +4 -4
- package/dist/invoice-line-items.js.map +1 -1
- package/dist/plans.d.ts +1 -0
- package/dist/plans.js +7 -3
- package/dist/plans.js.map +1 -1
- package/dist/provisioning.d.ts +1 -1
- package/docs/2.billing.md +6 -0
- package/docs/3.lifecycle-and-usage.md +17 -9
- package/docs/4.pages-plans-data.md +3 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ types barrel. After direct subscription writes, call
|
|
|
44
44
|
[`RecomputeTenantBillingState`](./docs/2.billing.md#recomputetenantbillingstate)
|
|
45
45
|
to refresh derived billing and workspace directory state.
|
|
46
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).
|
|
47
|
+
A module may seed plans straight into the `db` plan table: it writes `name`, `description` and `borderLabel` with one value per locale through `localize("*")`, 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
48
|
|
|
49
49
|
## Compatibility
|
|
50
50
|
|
|
@@ -54,8 +54,8 @@ The implementation is `@antelopejs/dms-saas >=0.6.0`. The interface declares the
|
|
|
54
54
|
|
|
55
55
|
| Package | Range |
|
|
56
56
|
| --- | --- |
|
|
57
|
-
| `@antelopejs/interface-data-api` | `>=0.
|
|
58
|
-
| `@antelopejs/interface-dms` | `>=0.
|
|
57
|
+
| `@antelopejs/interface-data-api` | `>=0.4.0 <1.0.0` |
|
|
58
|
+
| `@antelopejs/interface-dms` | `>=0.9.0 <1.0.0` |
|
|
59
59
|
|
|
60
60
|
Peer dependencies:
|
|
61
61
|
|
|
@@ -64,8 +64,8 @@ Peer dependencies:
|
|
|
64
64
|
| Package | Range |
|
|
65
65
|
| --- | --- |
|
|
66
66
|
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` |
|
|
67
|
-
| `@antelopejs/interface-database` | `>=0.1.
|
|
68
|
-
| `@antelopejs/interface-database-decorators` | `>=0.1.
|
|
67
|
+
| `@antelopejs/interface-database` | `>=0.1.11 <1.0.0` |
|
|
68
|
+
| `@antelopejs/interface-database-decorators` | `>=0.1.10 <1.0.0` |
|
|
69
69
|
|
|
70
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
71
|
|
package/dist/billing.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ export interface ComplimentarySubscriptionState {
|
|
|
2
2
|
isComplimentary?: boolean | null;
|
|
3
3
|
}
|
|
4
4
|
export declare function isComplimentarySubscription(subscription: ComplimentarySubscriptionState | null | undefined): boolean;
|
|
5
|
+
export interface TenantBillingPeriod {
|
|
6
|
+
start: Date;
|
|
7
|
+
end: Date;
|
|
8
|
+
}
|
|
9
|
+
export declare const GetTenantBillingPeriod: (tenantId: string) => Promise<TenantBillingPeriod | null>;
|
|
5
10
|
export interface TenantCustomerBalanceScope {
|
|
6
11
|
tenantId: string;
|
|
7
12
|
userId: string;
|
package/dist/billing.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RecomputeTenantBillingState = exports.GetUpcomingInvoicePreview = exports.GetTenantCustomerBalance = void 0;
|
|
3
|
+
exports.RecomputeTenantBillingState = exports.GetUpcomingInvoicePreview = exports.GetTenantCustomerBalance = exports.GetTenantBillingPeriod = void 0;
|
|
4
4
|
exports.isComplimentarySubscription = isComplimentarySubscription;
|
|
5
5
|
const interface_core_1 = require("@antelopejs/interface-core");
|
|
6
6
|
function isComplimentarySubscription(subscription) {
|
|
7
7
|
return subscription?.isComplimentary === true;
|
|
8
8
|
}
|
|
9
|
+
exports.GetTenantBillingPeriod = (0, interface_core_1.InterfaceFunction)();
|
|
9
10
|
exports.GetTenantCustomerBalance = (0, interface_core_1.InterfaceFunction)();
|
|
10
11
|
exports.GetUpcomingInvoicePreview = (0, interface_core_1.InterfaceFunction)();
|
|
11
12
|
exports.RecomputeTenantBillingState = (0, interface_core_1.InterfaceFunction)();
|
package/dist/billing.js.map
CHANGED
|
@@ -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;
|
|
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;AAgBY,QAAA,sBAAsB,GACjC,IAAA,kCAAiB,GAEd,CAAC;AAwCO,QAAA,wBAAwB,GACnC,IAAA,kCAAiB,GAEd,CAAC;AAmIO,QAAA,yBAAyB,GACpC,IAAA,kCAAiB,GAEd,CAAC;AAQO,QAAA,2BAA2B,GACtC,IAAA,kCAAiB,GAAuC,CAAC"}
|
|
@@ -23,6 +23,9 @@ declare const PlanModel_base: {
|
|
|
23
23
|
validate(obj: unknown, options?: import("@antelopejs/interface-database-decorators").ValidateInputOptions): import("@antelopejs/interface-database-decorators").ValidationResult;
|
|
24
24
|
};
|
|
25
25
|
export declare class PlanModel extends PlanModel_base {
|
|
26
|
+
get(id: string): Promise<Plan | undefined>;
|
|
27
|
+
getBy(index: keyof Plan, ...keys: unknown[]): Promise<Plan[]>;
|
|
28
|
+
getAll(): Promise<Plan[]>;
|
|
26
29
|
findNotDeleted(): Promise<Plan[]>;
|
|
27
30
|
findActiveNotDeleted(): Promise<Plan[]>;
|
|
28
31
|
findPubliclyVisible(): Promise<Plan[]>;
|
|
@@ -4,22 +4,37 @@ exports.PlanModel = void 0;
|
|
|
4
4
|
const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
|
|
5
5
|
const plans_table_1 = require("../tables/plans.table");
|
|
6
6
|
const MAX_INHERITANCE_DEPTH = 10;
|
|
7
|
+
function inFallbackLocale(plan) {
|
|
8
|
+
return plan.localize(plans_table_1.PLAN_FALLBACK_LOCALE, plans_table_1.PLAN_LOCALIZED_FIELDS);
|
|
9
|
+
}
|
|
10
|
+
function readPlans(rows) {
|
|
11
|
+
return rows
|
|
12
|
+
.map((row) => PlanModel.fromDatabase(row))
|
|
13
|
+
.filter((row) => row !== undefined)
|
|
14
|
+
.map(inFallbackLocale);
|
|
15
|
+
}
|
|
7
16
|
class PlanModel extends (0, interface_database_decorators_1.BasicDataModel)(plans_table_1.Plan, plans_table_1.plansTableName) {
|
|
17
|
+
async get(id) {
|
|
18
|
+
const plan = await super.get(id);
|
|
19
|
+
return plan && inFallbackLocale(plan);
|
|
20
|
+
}
|
|
21
|
+
async getBy(index, ...keys) {
|
|
22
|
+
return (await super.getBy(index, ...keys)).map(inFallbackLocale);
|
|
23
|
+
}
|
|
24
|
+
async getAll() {
|
|
25
|
+
return (await super.getAll()).map(inFallbackLocale);
|
|
26
|
+
}
|
|
8
27
|
async findNotDeleted() {
|
|
9
28
|
const rows = await this.table
|
|
10
29
|
.filter((row) => row.key("isDeleted").eq(false))
|
|
11
30
|
.run();
|
|
12
|
-
return rows
|
|
13
|
-
.map((row) => PlanModel.fromDatabase(row))
|
|
14
|
-
.filter((row) => row !== undefined);
|
|
31
|
+
return readPlans(rows);
|
|
15
32
|
}
|
|
16
33
|
async findActiveNotDeleted() {
|
|
17
34
|
const rows = await this.table
|
|
18
35
|
.filter((row) => row.key("isDeleted").eq(false).and(row.key("isActive").eq(true)))
|
|
19
36
|
.run();
|
|
20
|
-
return rows
|
|
21
|
-
.map((row) => PlanModel.fromDatabase(row))
|
|
22
|
-
.filter((row) => row !== undefined);
|
|
37
|
+
return readPlans(rows);
|
|
23
38
|
}
|
|
24
39
|
async findPubliclyVisible() {
|
|
25
40
|
const rows = await this.table
|
|
@@ -29,9 +44,7 @@ class PlanModel extends (0, interface_database_decorators_1.BasicDataModel)(plan
|
|
|
29
44
|
.and(row.key("isActive").eq(true))
|
|
30
45
|
.and(row.key("isPublic").eq(true)))
|
|
31
46
|
.run();
|
|
32
|
-
return rows
|
|
33
|
-
.map((row) => PlanModel.fromDatabase(row))
|
|
34
|
-
.filter((row) => row !== undefined);
|
|
47
|
+
return readPlans(rows);
|
|
35
48
|
}
|
|
36
49
|
async resolveInheritanceChain(plan) {
|
|
37
50
|
const visited = new Set();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plans.model.js","sourceRoot":"","sources":["../../../src/db/models/plans.model.ts"],"names":[],"mappings":";;;AAAA,6FAA2E;AAC3E,
|
|
1
|
+
{"version":3,"file":"plans.model.js","sourceRoot":"","sources":["../../../src/db/models/plans.model.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Table } from "@antelopejs/interface-database-decorators";
|
|
2
2
|
export declare const plansTableName = "plans";
|
|
3
|
+
export declare const PLAN_FALLBACK_LOCALE = "en";
|
|
4
|
+
export type PlanLocalizedText = Record<string, string>;
|
|
3
5
|
export declare const PLAN_AUDIENCES: readonly ["any", "individual", "business"];
|
|
4
6
|
export type PlanAudience = (typeof PLAN_AUDIENCES)[number];
|
|
5
7
|
export declare const PLAN_INTERVALS: readonly ["month", "year"];
|
|
@@ -30,8 +32,14 @@ export interface PlanProviderRefs {
|
|
|
30
32
|
stripePriceId?: string;
|
|
31
33
|
stripeSyncedTerms?: PlanStripeSyncedTerms;
|
|
32
34
|
}
|
|
35
|
+
export declare const PLAN_LOCALIZED_FIELDS: Array<keyof Plan>;
|
|
33
36
|
export declare const PLAN_UNLIMITED = -1;
|
|
34
|
-
|
|
37
|
+
declare const Plan_base: import("@antelopejs/interface-database-decorators").TableClass<Table & {
|
|
38
|
+
localize<This extends {
|
|
39
|
+
constructor: any;
|
|
40
|
+
}>(this: This, locale: string, fields?: Array<keyof This>): This;
|
|
41
|
+
}, [], object>;
|
|
42
|
+
export declare class Plan extends Plan_base {
|
|
35
43
|
_id: string;
|
|
36
44
|
name: string;
|
|
37
45
|
slug: string;
|
|
@@ -56,3 +64,4 @@ export declare class Plan extends Table {
|
|
|
56
64
|
createdAt: Date;
|
|
57
65
|
updatedAt: Date;
|
|
58
66
|
}
|
|
67
|
+
export {};
|
|
@@ -9,15 +9,21 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Plan = exports.PLAN_UNLIMITED = exports.PLAN_BILLING_MODES = exports.PLAN_INTERVALS = exports.PLAN_AUDIENCES = exports.plansTableName = void 0;
|
|
12
|
+
exports.Plan = exports.PLAN_UNLIMITED = exports.PLAN_LOCALIZED_FIELDS = exports.PLAN_BILLING_MODES = exports.PLAN_INTERVALS = exports.PLAN_AUDIENCES = exports.PLAN_FALLBACK_LOCALE = exports.plansTableName = void 0;
|
|
13
13
|
const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
|
|
14
14
|
const constants_1 = require("@antelopejs/interface-dms/constants");
|
|
15
15
|
exports.plansTableName = "plans";
|
|
16
|
+
exports.PLAN_FALLBACK_LOCALE = "en";
|
|
16
17
|
exports.PLAN_AUDIENCES = ["any", "individual", "business"];
|
|
17
18
|
exports.PLAN_INTERVALS = ["month", "year"];
|
|
18
19
|
exports.PLAN_BILLING_MODES = ["flat", "seat"];
|
|
20
|
+
exports.PLAN_LOCALIZED_FIELDS = [
|
|
21
|
+
"name",
|
|
22
|
+
"description",
|
|
23
|
+
"borderLabel",
|
|
24
|
+
];
|
|
19
25
|
exports.PLAN_UNLIMITED = -1;
|
|
20
|
-
let Plan = class Plan extends interface_database_decorators_1.Table {
|
|
26
|
+
let Plan = class Plan extends interface_database_decorators_1.Table.with(interface_database_decorators_1.LocalizationModifier) {
|
|
21
27
|
};
|
|
22
28
|
exports.Plan = Plan;
|
|
23
29
|
__decorate([
|
|
@@ -25,6 +31,7 @@ __decorate([
|
|
|
25
31
|
__metadata("design:type", String)
|
|
26
32
|
], Plan.prototype, "_id", void 0);
|
|
27
33
|
__decorate([
|
|
34
|
+
(0, interface_database_decorators_1.Localized)({ fallbackLocale: exports.PLAN_FALLBACK_LOCALE }),
|
|
28
35
|
(0, interface_database_decorators_1.Field)("string"),
|
|
29
36
|
__metadata("design:type", String)
|
|
30
37
|
], Plan.prototype, "name", void 0);
|
|
@@ -34,6 +41,7 @@ __decorate([
|
|
|
34
41
|
__metadata("design:type", String)
|
|
35
42
|
], Plan.prototype, "slug", void 0);
|
|
36
43
|
__decorate([
|
|
44
|
+
(0, interface_database_decorators_1.Localized)({ fallbackLocale: exports.PLAN_FALLBACK_LOCALE }),
|
|
37
45
|
(0, interface_database_decorators_1.Field)("string"),
|
|
38
46
|
__metadata("design:type", String)
|
|
39
47
|
], Plan.prototype, "description", void 0);
|
|
@@ -93,6 +101,7 @@ __decorate([
|
|
|
93
101
|
__metadata("design:type", Object)
|
|
94
102
|
], Plan.prototype, "borderColor", void 0);
|
|
95
103
|
__decorate([
|
|
104
|
+
(0, interface_database_decorators_1.Localized)({ fallbackLocale: exports.PLAN_FALLBACK_LOCALE }),
|
|
96
105
|
(0, interface_database_decorators_1.Field)("string"),
|
|
97
106
|
__metadata("design:type", Object)
|
|
98
107
|
], Plan.prototype, "borderLabel", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plans.table.js","sourceRoot":"","sources":["../../../src/db/tables/plans.table.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"plans.table.js","sourceRoot":"","sources":["../../../src/db/tables/plans.table.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6FAUmD;AACnD,mEAAuE;AAE1D,QAAA,cAAc,GAAG,OAAO,CAAC;AAGzB,QAAA,oBAAoB,GAAG,IAAI,CAAC;AAK5B,QAAA,cAAc,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,CAAU,CAAC;AAG5D,QAAA,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,CAAU,CAAC;AAG5C,QAAA,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AA4C/C,QAAA,qBAAqB,GAAsB;IACtD,MAAM;IACN,aAAa;IACb,aAAa;CACd,CAAC;AAGW,QAAA,cAAc,GAAG,CAAC,CAAC,CAAC;AAW1B,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,qCAAK,CAAC,IAAI,CAAC,oDAAoB,CAAC;CAiFzD,CAAA;AAjFY,oBAAI;AAEP;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;iCACI;AAIZ;IAFP,IAAA,yCAAS,EAAC,EAAE,cAAc,EAAE,4BAAoB,EAAE,CAAC;IACnD,IAAA,qCAAK,EAAC,QAAQ,CAAC;;kCACK;AAIb;IAFP,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;kCACK;AAIb;IAFP,IAAA,yCAAS,EAAC,EAAE,cAAc,EAAE,4BAAoB,EAAE,CAAC;IACnD,IAAA,qCAAK,EAAC,QAAQ,CAAC;;yCACY;AAIpB;IAFP,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;sCACe;AAGvB;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;mCACM;AAGd;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;sCACS;AAGjB;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;sCACe;AAGvB;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;yCACqB;AAG7B;IADP,IAAA,qCAAK,EAAC,KAAK,CAAC;;sCACwB;AAG7B;IADP,IAAA,qCAAK,EAAC,CAAC,QAAQ,CAAC,CAAC;;yCACY;AAItB;IAFP,IAAA,qCAAK,EAAC,QAAQ,CAAC;IACf,IAAA,wCAAQ,EAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;;gDACa;AAGlC;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;uCACU;AAIlB;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;wCACW;AAInB;IAFP,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,SAAS,CAAC;;sCACS;AAGlB;IADP,IAAA,qCAAK,EAAC,KAAK,CAAC;;iDACiC;AAGtC;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;yCACmB;AAI3B;IAFP,IAAA,yCAAS,EAAC,EAAE,cAAc,EAAE,4BAAoB,EAAE,CAAC;IACnD,IAAA,qCAAK,EAAC,QAAQ,CAAC;;yCACmB;AAI3B;IAFP,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;mCACM;AAId;IAFP,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,SAAS,CAAC;;sCACS;AAGlB;IADP,IAAA,qCAAK,EAAC,SAAS,CAAC;;uCACU;AAInB;IAFP,IAAA,4CAAY,GAAE;IACd,IAAA,qCAAK,EAAC,MAAM,CAAC;8BACK,IAAI;uCAAC;AAIhB;IAFP,IAAA,0CAAU,GAAE;IACZ,IAAA,qCAAK,EAAC,MAAM,CAAC;8BACK,IAAI;uCAAC;eAhFb,IAAI;IADhB,IAAA,6CAAa,EAAC,sBAAc,EAAE,4BAAgB,CAAC;GACnC,IAAI,CAiFhB"}
|
|
@@ -42,6 +42,7 @@ export declare class TenantSubscription extends Table {
|
|
|
42
42
|
stripeCheckoutSessionId: string | null;
|
|
43
43
|
completedCheckoutSessionId: string | null;
|
|
44
44
|
cardFingerprint: string | null;
|
|
45
|
+
currentPeriodStart: Date | null;
|
|
45
46
|
currentPeriodEnd: Date | null;
|
|
46
47
|
pendingPlanId: string | null;
|
|
47
48
|
pendingPlanChangeAt: Date | null;
|
|
@@ -87,6 +87,10 @@ __decorate([
|
|
|
87
87
|
(0, interface_database_decorators_1.Field)("string"),
|
|
88
88
|
__metadata("design:type", Object)
|
|
89
89
|
], TenantSubscription.prototype, "cardFingerprint", void 0);
|
|
90
|
+
__decorate([
|
|
91
|
+
(0, interface_database_decorators_1.Field)("date"),
|
|
92
|
+
__metadata("design:type", Object)
|
|
93
|
+
], TenantSubscription.prototype, "currentPeriodStart", void 0);
|
|
90
94
|
__decorate([
|
|
91
95
|
(0, interface_database_decorators_1.Field)("date"),
|
|
92
96
|
__metadata("design:type", Object)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenantSubscriptions.table.js","sourceRoot":"","sources":["../../../src/db/tables/tenantSubscriptions.table.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,sEAA8E;AAC9E,6FAUmD;AACnD,mEAAyE;AACzE,sFAA4E;AAC5E,+CAAqC;AAGxB,QAAA,4BAA4B,GAAG,sBAAsB,CAAC;AAEtD,QAAA,4BAA4B,GAAG;IAC1C,iBAAiB;IACjB,QAAQ;IACR,UAAU;IACV,UAAU;IACV,WAAW;IACX,WAAW;CACH,CAAC;AAqDX,MAAM,eAAe,GAA6B,UAAU,CAAC;AAO7D,MAAM,oBAAqB,SAAQ,wCAAQ;IACzC,MAAM,CAAC,MAAyB,EAAE,KAAa;QAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO;QACxC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS;YAAE,OAAO;QACxC,IAAI,MAAM,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;CACF;AAoBY,QAAA,YAAY,GAAG,IAAA,kCAAqB,EAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;IACvE,8CAAsC,CACrC,MAAM,CAAC,WAA+B,EACtC,oBAAoB,EACpB,WAAqB,EACrB,EAAE,CACH,CAAC;AACJ,CAAC,CAAC,CAAC;AAII,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,qCAAK;
|
|
1
|
+
{"version":3,"file":"tenantSubscriptions.table.js","sourceRoot":"","sources":["../../../src/db/tables/tenantSubscriptions.table.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,17 +23,21 @@ export interface InvoiceLineItemsNotReady {
|
|
|
23
23
|
status: "not_ready";
|
|
24
24
|
reason: string;
|
|
25
25
|
}
|
|
26
|
-
export
|
|
27
|
-
status: "blocked";
|
|
28
|
-
reason: string;
|
|
29
|
-
}
|
|
30
|
-
export type InvoiceLineItemsResolution = InvoiceLineItemsReady | InvoiceLineItemsNotReady | InvoiceLineItemsBlocked;
|
|
26
|
+
export type InvoiceLineItemsResolution = InvoiceLineItemsReady | InvoiceLineItemsNotReady;
|
|
31
27
|
export type InvoiceLineItemsResolver = (context: InvoiceLineItemsContext) => Promise<InvoiceLineItem[] | InvoiceLineItemsResolution> | InvoiceLineItem[] | InvoiceLineItemsResolution;
|
|
32
28
|
export declare const INVALID_RESOLUTION_REASON = "invalid_resolution";
|
|
33
29
|
export declare function normalizeInvoiceLineItemsResolution(value: unknown): InvoiceLineItemsResolution;
|
|
30
|
+
export interface InvoiceUsageGap {
|
|
31
|
+
tenantId: string;
|
|
32
|
+
invoiceId: string;
|
|
33
|
+
periodStart: Date;
|
|
34
|
+
periodEnd: Date;
|
|
35
|
+
reasons: string[];
|
|
36
|
+
}
|
|
34
37
|
export interface InvoiceLineItemsProvider {
|
|
35
38
|
id: string;
|
|
36
39
|
resolve: InvoiceLineItemsResolver;
|
|
40
|
+
onUsageGap?: (gap: InvoiceUsageGap) => void;
|
|
37
41
|
}
|
|
38
42
|
export declare const LINE_KEY_SEPARATOR = ":";
|
|
39
43
|
export type SkippedLineItemReason = "already_invoiced" | "duplicate_key" | "zero_amount" | "invalid";
|
|
@@ -52,7 +56,7 @@ export interface InvoiceLineItemSelection {
|
|
|
52
56
|
export declare function buildInvoiceLineKey(providerId: string, key: string): string;
|
|
53
57
|
export declare function selectInvoiceLineItemsToCreate(providerId: string, items: readonly InvoiceLineItem[], alreadyInjectedKeys: ReadonlySet<string>): InvoiceLineItemSelection;
|
|
54
58
|
export declare namespace internal {
|
|
55
|
-
const RegisterInvoiceLineItemsProvider: RegisteringProxy<(providerId: string,
|
|
59
|
+
const RegisterInvoiceLineItemsProvider: RegisteringProxy<(providerId: string, provider: InvoiceLineItemsProvider) => void>;
|
|
56
60
|
}
|
|
57
61
|
export declare function RegisterInvoiceLineItemsProvider(provider: InvoiceLineItemsProvider): void;
|
|
58
62
|
export declare function UnregisterInvoiceLineItemsProvider(providerId: string): void;
|
|
@@ -14,9 +14,9 @@ function normalizeInvoiceLineItemsResolution(value) {
|
|
|
14
14
|
const candidate = value;
|
|
15
15
|
if (candidate?.status === "ready" && Array.isArray(candidate.lines))
|
|
16
16
|
return { status: "ready", lines: candidate.lines };
|
|
17
|
-
if (candidate?.status === "not_ready"
|
|
18
|
-
return { status:
|
|
19
|
-
return { status: "
|
|
17
|
+
if (candidate?.status === "not_ready")
|
|
18
|
+
return { status: "not_ready", reason: String(candidate.reason) };
|
|
19
|
+
return { status: "not_ready", reason: exports.INVALID_RESOLUTION_REASON };
|
|
20
20
|
}
|
|
21
21
|
exports.LINE_KEY_SEPARATOR = ":";
|
|
22
22
|
const MAX_LINE_KEY_LENGTH = 150;
|
|
@@ -87,7 +87,7 @@ function RegisterInvoiceLineItemsProvider(provider) {
|
|
|
87
87
|
if (provider.id.includes(exports.LINE_KEY_SEPARATOR)) {
|
|
88
88
|
throw new Error(`An invoice line items provider id cannot contain '${exports.LINE_KEY_SEPARATOR}' (got '${provider.id}').`);
|
|
89
89
|
}
|
|
90
|
-
internal.RegisterInvoiceLineItemsProvider.register(provider.id, provider
|
|
90
|
+
internal.RegisterInvoiceLineItemsProvider.register(provider.id, provider);
|
|
91
91
|
}
|
|
92
92
|
function UnregisterInvoiceLineItemsProvider(providerId) {
|
|
93
93
|
internal.RegisterInvoiceLineItemsProvider.unregister(providerId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoice-line-items.js","sourceRoot":"","sources":["../src/invoice-line-items.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"invoice-line-items.js","sourceRoot":"","sources":["../src/invoice-line-items.ts"],"names":[],"mappings":"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"}
|
package/dist/plans.d.ts
CHANGED
|
@@ -26,4 +26,5 @@ export declare function monthlyPrice(plan: Plan): number;
|
|
|
26
26
|
export declare function isDowngrade(current: Plan | null, target: Plan, seats?: number): boolean;
|
|
27
27
|
export declare const FEATURE_LOCALIZED_FIELDS: Array<keyof Feature>;
|
|
28
28
|
export declare function localizeFeature(feature: Feature, locale: string): Feature;
|
|
29
|
+
export declare function localizePlan(plan: Plan, locale: string): Plan;
|
|
29
30
|
export declare function buildTenantPlanCatalog(planModel: PlanModel, featureModel: FeatureModel, plans: Plan[], locale: string): Promise<TenantPlanCatalog>;
|
package/dist/plans.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.FEATURE_LOCALIZED_FIELDS = void 0;
|
|
|
4
4
|
exports.monthlyPrice = monthlyPrice;
|
|
5
5
|
exports.isDowngrade = isDowngrade;
|
|
6
6
|
exports.localizeFeature = localizeFeature;
|
|
7
|
+
exports.localizePlan = localizePlan;
|
|
7
8
|
exports.buildTenantPlanCatalog = buildTenantPlanCatalog;
|
|
8
9
|
const db_1 = require("./db");
|
|
9
10
|
const MONTHS_PER_INTERVAL = {
|
|
@@ -35,6 +36,9 @@ exports.FEATURE_LOCALIZED_FIELDS = [
|
|
|
35
36
|
function localizeFeature(feature, locale) {
|
|
36
37
|
return feature.localize(locale, exports.FEATURE_LOCALIZED_FIELDS);
|
|
37
38
|
}
|
|
39
|
+
function localizePlan(plan, locale) {
|
|
40
|
+
return plan.localize(locale, db_1.PLAN_LOCALIZED_FIELDS);
|
|
41
|
+
}
|
|
38
42
|
function toPlanFeature(feature) {
|
|
39
43
|
return {
|
|
40
44
|
featureId: feature._id,
|
|
@@ -46,7 +50,7 @@ function toPlanFeature(feature) {
|
|
|
46
50
|
order: feature.order ?? db_1.FEATURE_DEFAULT_ORDER,
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
|
-
async function toPlanView(planModel, plan, knownFeatureIds) {
|
|
53
|
+
async function toPlanView(planModel, plan, knownFeatureIds, locale) {
|
|
50
54
|
const resolved = await planModel.resolveInheritance(plan);
|
|
51
55
|
const featureValues = {};
|
|
52
56
|
for (const entry of resolved.features) {
|
|
@@ -56,7 +60,7 @@ async function toPlanView(planModel, plan, knownFeatureIds) {
|
|
|
56
60
|
}
|
|
57
61
|
return {
|
|
58
62
|
_id: plan._id,
|
|
59
|
-
name: plan.name,
|
|
63
|
+
name: localizePlan(plan, locale).name,
|
|
60
64
|
price: plan.price,
|
|
61
65
|
currency: plan.currency,
|
|
62
66
|
interval: plan.interval,
|
|
@@ -68,7 +72,7 @@ async function toPlanView(planModel, plan, knownFeatureIds) {
|
|
|
68
72
|
async function buildTenantPlanCatalog(planModel, featureModel, plans, locale) {
|
|
69
73
|
const features = await featureModel.getAll();
|
|
70
74
|
const knownFeatureIds = new Set(features.map((feature) => feature._id));
|
|
71
|
-
const views = await Promise.all(plans.map((plan) => toPlanView(planModel, plan, knownFeatureIds)));
|
|
75
|
+
const views = await Promise.all(plans.map((plan) => toPlanView(planModel, plan, knownFeatureIds, locale)));
|
|
72
76
|
return {
|
|
73
77
|
plans: views.sort((left, right) => left.order - right.order),
|
|
74
78
|
features: features
|
package/dist/plans.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plans.js","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":";;;AA6CA,oCAEC;AAsBD,kCAOC;AAmBD,0CAEC;
|
|
1
|
+
{"version":3,"file":"plans.js","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"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"}
|
package/dist/provisioning.d.ts
CHANGED
package/docs/2.billing.md
CHANGED
|
@@ -73,6 +73,12 @@ An available preview includes these fields. All amounts are integers in the mino
|
|
|
73
73
|
|
|
74
74
|
The preview calls usage providers with `isPreview: true` and can populate a tenant-level shared database cache. It never creates an invoice or charges quoted lines. Usage covers the running cycle so far, not its final total; display `computedAt`. A missing payment method does not itself prevent previewing. Cache lifetime, invalidation and Stripe read timeouts are [runtime configuration](/docs/modules/saas/extending#upcoming-invoice-preview).
|
|
75
75
|
|
|
76
|
+
## GetTenantBillingPeriod
|
|
77
|
+
|
|
78
|
+
`GetTenantBillingPeriod(tenantId: string): Promise<TenantBillingPeriod | null>` returns the tenant's current Stripe billing period as `{ start: Date, end: Date }`, half-open (`[start, end)`). It is clipped to the paid usage exactly as renewal invoices clip their usage window: a period opened before the paid usage started starts with it, and a guarded downgrade or a closed paid period ends it early. It is `null` for a free or complimentary tenant and for one whose period dms-saas has not recorded yet (`currentPeriodStart` is stored from the subscription webhooks).
|
|
79
|
+
|
|
80
|
+
This is a trusted read with no user scope or membership check; storage errors propagate. It does not call Stripe. Usage credits in dms-saas consumers may follow another cycle (Cloud resets its allowance on the UTC calendar month): use this period only where you mean the invoice's.
|
|
81
|
+
|
|
76
82
|
## RecomputeTenantBillingState
|
|
77
83
|
|
|
78
84
|
`RecomputeTenantBillingState(tenantId: string): Promise<void>` republishes the tenant's billing state and workspace directory fields, including plan, seats, MRR, renewal and owner, from current records. Call it after a seed or import finishes direct writes. Normal runtime billing operations already do this.
|
|
@@ -24,7 +24,7 @@ before implementing the contract below.
|
|
|
24
24
|
|
|
25
25
|
## Invoice line items
|
|
26
26
|
|
|
27
|
-
Import from `/invoice-line-items`. `RegisterInvoiceLineItemsProvider(provider: InvoiceLineItemsProvider): void` registers `{ id: string, resolve: InvoiceLineItemsResolver }`. `UnregisterInvoiceLineItemsProvider(providerId: string): void` removes it; unknown IDs are ignored. Register during `construct()` and unregister during `stop()`.
|
|
27
|
+
Import from `/invoice-line-items`. `RegisterInvoiceLineItemsProvider(provider: InvoiceLineItemsProvider): void` registers `{ id: string, resolve: InvoiceLineItemsResolver, onUsageGap?: (gap: InvoiceUsageGap) => void }`. `UnregisterInvoiceLineItemsProvider(providerId: string): void` removes it; unknown IDs are ignored. Register during `construct()` and unregister during `stop()`.
|
|
28
28
|
|
|
29
29
|
```ts [Contract]
|
|
30
30
|
interface InvoiceLineItemsContext {
|
|
@@ -47,8 +47,15 @@ interface InvoiceLineItem {
|
|
|
47
47
|
|
|
48
48
|
type InvoiceLineItemsResolution =
|
|
49
49
|
| { status: "ready"; lines: InvoiceLineItem[] }
|
|
50
|
-
| { status: "not_ready"; reason: string }
|
|
51
|
-
|
|
50
|
+
| { status: "not_ready"; reason: string };
|
|
51
|
+
|
|
52
|
+
interface InvoiceUsageGap {
|
|
53
|
+
tenantId: string;
|
|
54
|
+
invoiceId: string;
|
|
55
|
+
periodStart: Date;
|
|
56
|
+
periodEnd: Date;
|
|
57
|
+
reasons: string[];
|
|
58
|
+
}
|
|
52
59
|
|
|
53
60
|
type InvoiceLineItemsResolver = (
|
|
54
61
|
context: InvoiceLineItemsContext,
|
|
@@ -64,16 +71,17 @@ The runtime asks providers for `subscription_cycle` renewal invoices, not initia
|
|
|
64
71
|
|
|
65
72
|
Keep each line key stable. The runtime injects at most one line per invoice/provider/key across webhook replays and concurrent workers. Returning lines is not a guarantee that Stripe accepted the invoice items.
|
|
66
73
|
|
|
67
|
-
On a closing invoice the runtime first suspends the draft (`auto_advance=false`) and hands the injection to a durable task
|
|
74
|
+
On a closing invoice the runtime first suspends the draft (`auto_advance=false`) and hands the injection to a durable task. The invoice is always finalized: once every provider's lines are on it, or 48 hours after it was registered with the lines available:
|
|
68
75
|
|
|
69
76
|
| Resolver answer | Effect |
|
|
70
77
|
| --- | --- |
|
|
71
78
|
| An array, or `{ status: "ready", lines }` | The lines are injected; an empty array states an empty bill. |
|
|
72
|
-
| `{ status: "not_ready", reason }`, or a thrown error | The draft stays suspended and the provider is asked again later. |
|
|
73
|
-
|
|
|
74
|
-
|
|
79
|
+
| `{ status: "not_ready", reason }`, or a thrown error | The draft stays suspended and the provider is asked again later; past the deadline, the invoice is finalized without its lines. |
|
|
80
|
+
| Anything else | Treated as `not_ready` with reason `invalid_resolution` (`INVALID_RESOLUTION_REASON`); `normalizeInvoiceLineItemsResolution` applies that rule. |
|
|
81
|
+
|
|
82
|
+
An invoice finalized without some of its lines — a provider not ready at the deadline, invalid lines, Stripe refusing a line, or a draft changed outside dms-saas — never bills the missing usage: the gap favours the customer. The runtime logs it at error level (`invoice finalized with missing usage`) and calls `onUsageGap` on every provider the invoice was registered with, so the provider can raise an alert and its owner can fix the system. Each reason starts with a stable code (`provider_not_ready`, `managed_lines_unexpected_or_changed`, `before_finalize`, ...) followed by `:` and its detail.
|
|
75
83
|
|
|
76
|
-
`periodStart` is inclusive and `periodEnd` exclusive, so two adjacent cycle invoices cover disjoint windows. A preview covers the open cycle up to the request time; it is a quote of the next invoice, not an addition to it. A negative `amountCents` is a credit line.
|
|
84
|
+
`periodStart` is inclusive and `periodEnd` exclusive, so two adjacent cycle invoices cover disjoint windows. A preview covers the open cycle up to the request time; it is a quote of the next invoice, not an addition to it. A negative `amountCents` is a credit line.
|
|
77
85
|
|
|
78
86
|
A provider that may still be loading when an invoice is created is listed in the runtime's `invoiceLineRequiredProviders` option so the invoice waits for it. See the [runtime configuration](/docs/modules/saas/configuration).
|
|
79
87
|
|
|
@@ -149,7 +157,7 @@ Delivery is **at least once**. Deduplicate by `operationId`, durably link provis
|
|
|
149
157
|
|
|
150
158
|
## Registration and provisioning
|
|
151
159
|
|
|
152
|
-
`TenantBeingProvisionedPayload` from `/provisioning` has `tenantId: string`, `userId: string`, and optional `extras: Record<string, unknown>`. Use it with the DMS `Hook.TENANT_BEING_PROVISIONED` hook; the hook handler returns `Promise<undefined>`, not `Promise<void>`.
|
|
160
|
+
`TenantBeingProvisionedPayload` from `/provisioning` has `tenantId: string`, optional `userId: string`, and optional `extras: Record<string, unknown>`. Use it with the DMS `Hook.TENANT_BEING_PROVISIONED` hook; the hook handler returns `Promise<undefined>`, not `Promise<void>`. The runtime fires the hook through DMS `ProvisionTenant`, which registers the workspace's tenant-schema instance before any listener runs. DMS also fires it once for its `default` tenant, at its creation and without `userId`: write a tenant's default data in this hook, never in `start()` or `DATABASE_INITIALIZED`.
|
|
153
161
|
|
|
154
162
|
Listeners run serially inside provisioning, while the per-card lock is held, after workspace records exist but before registration returns. A throwing listener cancels registration and rolls back the runtime's tenant, subscription, Stripe customer and password-path account. Do not assume external side effects of your listener roll back automatically. Keep it to bounded persistence work rather than network provisioning; use durable `created` delivery for post-payment resources.
|
|
155
163
|
|
|
@@ -42,14 +42,15 @@ Import from `/plans`. These helpers do not charge customers or authorize access.
|
|
|
42
42
|
| `monthlyPrice(plan: Plan): number` | Returns the price as a monthly amount; yearly prices divide by 12 |
|
|
43
43
|
| `isDowngrade(current: Plan \| null, target: Plan, seats?: number): boolean` | Compares monthly cost, multiplying seat plans by at least one seat; seats default to 1. No current plan returns false; equal cost is not a downgrade |
|
|
44
44
|
| `localizeFeature(feature: Feature, locale: string): Feature` | Applies localization to `displayName`, `description`, `tooltip`, and `unit`, listed by exported `FEATURE_LOCALIZED_FIELDS`; missing translations fall back to the table locale (`en`) |
|
|
45
|
-
| `
|
|
45
|
+
| `localizePlan(plan: Plan, locale: string): Plan` | Applies localization to `name`, `description`, and `borderLabel`, listed by exported `PLAN_LOCALIZED_FIELDS`; missing translations fall back to `PLAN_FALLBACK_LOCALE` (`en`). `PlanModel` reads already return plans unlocked in that fallback locale |
|
|
46
|
+
| `buildTenantPlanCatalog(planModel: PlanModel, featureModel: FeatureModel, plans: Plan[], locale: string): Promise<TenantPlanCatalog>` | Reads features, resolves plan inheritance, excludes unknown feature IDs and sorts plans/features by order; plan names and feature labels are read in `locale`; model read failures reject |
|
|
46
47
|
|
|
47
48
|
`TenantPlanCatalog` has `plans: TenantPlanView[]` and `features: TenantPlanFeature[]`.
|
|
48
49
|
|
|
49
50
|
- `TenantPlanView`: `_id: string`, `name: string`, `price: number`, `currency: string`, `interval: PlanInterval` (`month` or `year`), `order: number`, `checkoutAvailable: boolean`, and `featureValues: Record<string, unknown>`. Checkout availability reflects a Stripe price reference, not an authorization decision.
|
|
50
51
|
- `TenantPlanFeature`: `featureId: string`, `displayName: string`, `tooltip: string | null`, `unit: string | null`, `valueType: FeatureValueType` (`boolean`, `number`, or `string`), `isDetailRow: boolean`, and `order: number`.
|
|
51
52
|
|
|
52
|
-
Keep caller-supplied plan/model scopes authorized. The catalogue builder does not filter an arbitrary plan list to what a user may buy. Write localized feature
|
|
53
|
+
Keep caller-supplied plan/model scopes authorized. The catalogue builder does not filter an arbitrary plan list to what a user may buy. Write localized plan and feature texts using the canonical model's `localize("*")` convention, one value per locale (`{ en: "Pro", fr: "Pro" }`), never `$` i18n keys; see the [feature integration guide](/docs/modules/saas/extending#plan-feature-labels-and-values).
|
|
53
54
|
|
|
54
55
|
## HiddenStringFilter
|
|
55
56
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-dms-saas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "AntelopeJS interface for the DMS SaaS module: billing, plans, registration, workspace pages and lifecycle extension points.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
@@ -70,13 +70,13 @@
|
|
|
70
70
|
"prepack": "pnpm run build"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@antelopejs/interface-data-api": ">=0.
|
|
74
|
-
"@antelopejs/interface-dms": ">=0.
|
|
73
|
+
"@antelopejs/interface-data-api": ">=0.4.0 <1.0.0",
|
|
74
|
+
"@antelopejs/interface-dms": ">=0.9.0 <1.0.0"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@antelopejs/interface-core": ">=0.2.4 <1.0.0",
|
|
78
|
-
"@antelopejs/interface-database": ">=0.1.
|
|
79
|
-
"@antelopejs/interface-database-decorators": ">=0.1.
|
|
78
|
+
"@antelopejs/interface-database": ">=0.1.11 <1.0.0",
|
|
79
|
+
"@antelopejs/interface-database-decorators": ">=0.1.10 <1.0.0",
|
|
80
80
|
"@types/node": "^24.0.0",
|
|
81
81
|
"knip": "^6.34.0",
|
|
82
82
|
"oxfmt": "^0.66.0",
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
91
|
"@antelopejs/interface-core": ">=0.2.4 <1.0.0",
|
|
92
|
-
"@antelopejs/interface-database": ">=0.1.
|
|
93
|
-
"@antelopejs/interface-database-decorators": ">=0.1.
|
|
92
|
+
"@antelopejs/interface-database": ">=0.1.11 <1.0.0",
|
|
93
|
+
"@antelopejs/interface-database-decorators": ">=0.1.10 <1.0.0"
|
|
94
94
|
},
|
|
95
95
|
"packageManager": "pnpm@10.2.0",
|
|
96
96
|
"antelopeJs": {}
|