@happyvertical/smrt-subscriptions 0.57.9 → 0.57.10
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/AGENTS.md +21 -0
- package/README.md +112 -3
- package/dist/chunks/SubscriptionPlanCollection-CqlYYtPg.js +229 -0
- package/dist/chunks/SubscriptionPlanCollection-CqlYYtPg.js.map +1 -0
- package/dist/chunks/SubscriptionPlanVersionCollection-CV0QPmp0.js +193 -0
- package/dist/chunks/SubscriptionPlanVersionCollection-CV0QPmp0.js.map +1 -0
- package/dist/chunks/plan-terms-BoeXvDhs.js +219 -0
- package/dist/chunks/plan-terms-BoeXvDhs.js.map +1 -0
- package/dist/chunks/plan-versioning-Bp0NqTJf.js +142 -0
- package/dist/chunks/plan-versioning-Bp0NqTJf.js.map +1 -0
- package/dist/chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/collections/SubscriptionPlanVersionCollection.d.ts +33 -0
- package/dist/collections/SubscriptionPlanVersionCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +1 -0
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +181 -349
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1114 -328
- package/dist/migrations/planVersions.d.ts +16 -0
- package/dist/migrations/planVersions.d.ts.map +1 -0
- package/dist/models/SubscriptionPlan.d.ts +39 -3
- package/dist/models/SubscriptionPlan.d.ts.map +1 -1
- package/dist/models/SubscriptionPlanVersion.d.ts +51 -0
- package/dist/models/SubscriptionPlanVersion.d.ts.map +1 -0
- package/dist/models/TenantSubscription.d.ts +49 -1
- package/dist/models/TenantSubscription.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/plan-terms.d.ts +26 -0
- package/dist/plan-terms.d.ts.map +1 -0
- package/dist/plan-versioning.d.ts +45 -0
- package/dist/plan-versioning.d.ts.map +1 -0
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/subscription-resolver.d.ts +26 -0
- package/dist/services/subscription-resolver.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +547 -7
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-subscriptions",
|
|
6
|
-
"packageVersion": "0.57.
|
|
6
|
+
"packageVersion": "0.57.10",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "230888d57f42ed4f6743c05d2272779cdcf47599eedab5b4a2e52aa7b5b8bbfa",
|
|
11
|
+
"packageJson": "f23eb15869858c996cfce6d5a3338844f9e434141c9bd5688a83d73f7ee3a6f2",
|
|
12
|
+
"agents": "8d03287e49f241cfe3f1dac0a3bd32ffc51d67709c1e2af93e0368cd0cadaf02"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
15
15
|
".",
|
|
@@ -162,6 +162,95 @@
|
|
|
162
162
|
"tags": [],
|
|
163
163
|
"risks": []
|
|
164
164
|
},
|
|
165
|
+
{
|
|
166
|
+
"name": "SubscriptionPlanVersionCollection",
|
|
167
|
+
"qualifiedName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersionCollection",
|
|
168
|
+
"collection": "subscriptionplanversions",
|
|
169
|
+
"description": "Effective-dated plan versions (#4032).",
|
|
170
|
+
"tableName": "_smrt_subscription_plan_versions",
|
|
171
|
+
"packageName": "@happyvertical/smrt-subscriptions",
|
|
172
|
+
"extends": "SmrtCollection",
|
|
173
|
+
"fields": [],
|
|
174
|
+
"relationships": [],
|
|
175
|
+
"methods": [
|
|
176
|
+
"findInForce",
|
|
177
|
+
"findLatest",
|
|
178
|
+
"findVisibleById",
|
|
179
|
+
"listForPlan"
|
|
180
|
+
],
|
|
181
|
+
"methodSignatures": [
|
|
182
|
+
{
|
|
183
|
+
"name": "findInForce",
|
|
184
|
+
"async": true,
|
|
185
|
+
"params": [
|
|
186
|
+
"planId: string",
|
|
187
|
+
"at: Date"
|
|
188
|
+
],
|
|
189
|
+
"returns": "Promise<SubscriptionPlanVersion | null>"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "findLatest",
|
|
193
|
+
"async": true,
|
|
194
|
+
"params": [
|
|
195
|
+
"planId: string",
|
|
196
|
+
"tenantId?: string | null"
|
|
197
|
+
],
|
|
198
|
+
"returns": "Promise<SubscriptionPlanVersion | null>"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "findVisibleById",
|
|
202
|
+
"async": true,
|
|
203
|
+
"params": [
|
|
204
|
+
"id: string"
|
|
205
|
+
],
|
|
206
|
+
"returns": "Promise<SubscriptionPlanVersion | null>"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"name": "listForPlan",
|
|
210
|
+
"async": true,
|
|
211
|
+
"params": [
|
|
212
|
+
"planId: string"
|
|
213
|
+
],
|
|
214
|
+
"returns": "Promise<SubscriptionPlanVersion[]>"
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"surfaces": [],
|
|
218
|
+
"withheldSurfaces": [
|
|
219
|
+
{
|
|
220
|
+
"kind": "api",
|
|
221
|
+
"operation": "findInForce",
|
|
222
|
+
"code": "not-included",
|
|
223
|
+
"reason": "not listed in api.include",
|
|
224
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersionCollection"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"kind": "api",
|
|
228
|
+
"operation": "findLatest",
|
|
229
|
+
"code": "not-included",
|
|
230
|
+
"reason": "not listed in api.include",
|
|
231
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersionCollection"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"kind": "api",
|
|
235
|
+
"operation": "findVisibleById",
|
|
236
|
+
"code": "not-included",
|
|
237
|
+
"reason": "not listed in api.include",
|
|
238
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersionCollection"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"kind": "api",
|
|
242
|
+
"operation": "listForPlan",
|
|
243
|
+
"code": "not-included",
|
|
244
|
+
"reason": "not listed in api.include",
|
|
245
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersionCollection"
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
"relationshipFeatures": [
|
|
249
|
+
"uuidColumns"
|
|
250
|
+
],
|
|
251
|
+
"tags": [],
|
|
252
|
+
"risks": []
|
|
253
|
+
},
|
|
165
254
|
{
|
|
166
255
|
"name": "TenantSubscriptionCollection",
|
|
167
256
|
"qualifiedName": "@happyvertical/smrt-subscriptions:TenantSubscriptionCollection",
|
|
@@ -527,8 +616,12 @@
|
|
|
527
616
|
"getFeatureGrants",
|
|
528
617
|
"getFeatureKeys",
|
|
529
618
|
"getMetadata",
|
|
619
|
+
"getTerms",
|
|
530
620
|
"getThresholds",
|
|
621
|
+
"getVersionInForce",
|
|
531
622
|
"isActive",
|
|
623
|
+
"publishTerms",
|
|
624
|
+
"save",
|
|
532
625
|
"setFeatureGrants",
|
|
533
626
|
"setMetadata",
|
|
534
627
|
"setThresholds"
|
|
@@ -546,14 +639,42 @@
|
|
|
546
639
|
"name": "getMetadata",
|
|
547
640
|
"returns": "JsonObject"
|
|
548
641
|
},
|
|
642
|
+
{
|
|
643
|
+
"name": "getTerms",
|
|
644
|
+
"returns": "PlanTerms"
|
|
645
|
+
},
|
|
549
646
|
{
|
|
550
647
|
"name": "getThresholds",
|
|
551
648
|
"returns": "PlanThreshold[]"
|
|
552
649
|
},
|
|
650
|
+
{
|
|
651
|
+
"name": "getVersionInForce",
|
|
652
|
+
"async": true,
|
|
653
|
+
"params": [
|
|
654
|
+
"at?: any"
|
|
655
|
+
],
|
|
656
|
+
"returns": "Promise<SubscriptionPlanVersion | null>"
|
|
657
|
+
},
|
|
553
658
|
{
|
|
554
659
|
"name": "isActive",
|
|
555
660
|
"returns": "boolean"
|
|
556
661
|
},
|
|
662
|
+
{
|
|
663
|
+
"name": "publishTerms",
|
|
664
|
+
"async": true,
|
|
665
|
+
"params": [
|
|
666
|
+
"options?: object"
|
|
667
|
+
],
|
|
668
|
+
"returns": "Promise<SubscriptionPlanVersion>"
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
"name": "save",
|
|
672
|
+
"async": true,
|
|
673
|
+
"params": [
|
|
674
|
+
"options?: SmrtSaveOptions"
|
|
675
|
+
],
|
|
676
|
+
"returns": "Promise<this>"
|
|
677
|
+
},
|
|
557
678
|
{
|
|
558
679
|
"name": "setFeatureGrants",
|
|
559
680
|
"params": [
|
|
@@ -654,6 +775,24 @@
|
|
|
654
775
|
"operation": "isActive",
|
|
655
776
|
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
656
777
|
},
|
|
778
|
+
{
|
|
779
|
+
"kind": "cli",
|
|
780
|
+
"name": "subscriptionplan_getTerms",
|
|
781
|
+
"operation": "getTerms",
|
|
782
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
"kind": "cli",
|
|
786
|
+
"name": "subscriptionplan_publishTerms",
|
|
787
|
+
"operation": "publishTerms",
|
|
788
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"kind": "cli",
|
|
792
|
+
"name": "subscriptionplan_getVersionInForce",
|
|
793
|
+
"operation": "getVersionInForce",
|
|
794
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
795
|
+
},
|
|
657
796
|
{
|
|
658
797
|
"kind": "cli",
|
|
659
798
|
"name": "subscriptionplan_getFeatureGrants",
|
|
@@ -731,6 +870,13 @@
|
|
|
731
870
|
"reason": "not listed in api.include",
|
|
732
871
|
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
733
872
|
},
|
|
873
|
+
{
|
|
874
|
+
"kind": "api",
|
|
875
|
+
"operation": "getTerms",
|
|
876
|
+
"code": "not-included",
|
|
877
|
+
"reason": "not listed in api.include",
|
|
878
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
879
|
+
},
|
|
734
880
|
{
|
|
735
881
|
"kind": "api",
|
|
736
882
|
"operation": "getThresholds",
|
|
@@ -738,6 +884,13 @@
|
|
|
738
884
|
"reason": "not listed in api.include",
|
|
739
885
|
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
740
886
|
},
|
|
887
|
+
{
|
|
888
|
+
"kind": "api",
|
|
889
|
+
"operation": "getVersionInForce",
|
|
890
|
+
"code": "not-included",
|
|
891
|
+
"reason": "not listed in api.include",
|
|
892
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
893
|
+
},
|
|
741
894
|
{
|
|
742
895
|
"kind": "api",
|
|
743
896
|
"operation": "isActive",
|
|
@@ -745,6 +898,20 @@
|
|
|
745
898
|
"reason": "not listed in api.include",
|
|
746
899
|
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
747
900
|
},
|
|
901
|
+
{
|
|
902
|
+
"kind": "api",
|
|
903
|
+
"operation": "publishTerms",
|
|
904
|
+
"code": "not-included",
|
|
905
|
+
"reason": "not listed in api.include",
|
|
906
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
"kind": "api",
|
|
910
|
+
"operation": "save",
|
|
911
|
+
"code": "lifecycle-method",
|
|
912
|
+
"reason": "`save` is a framework lifecycle method, not a distinct operation",
|
|
913
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
914
|
+
},
|
|
748
915
|
{
|
|
749
916
|
"kind": "api",
|
|
750
917
|
"operation": "setFeatureGrants",
|
|
@@ -773,6 +940,253 @@
|
|
|
773
940
|
"tags": [],
|
|
774
941
|
"risks": []
|
|
775
942
|
},
|
|
943
|
+
{
|
|
944
|
+
"name": "SubscriptionPlanVersion",
|
|
945
|
+
"qualifiedName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion",
|
|
946
|
+
"displayLabelField": "name",
|
|
947
|
+
"collection": "subscriptionplanversions",
|
|
948
|
+
"description": "An immutable, effective-dated snapshot of a plan's terms (#4032).",
|
|
949
|
+
"tableName": "_smrt_subscription_plan_versions",
|
|
950
|
+
"packageName": "@happyvertical/smrt-subscriptions",
|
|
951
|
+
"extends": "SmrtObject",
|
|
952
|
+
"fields": [
|
|
953
|
+
{
|
|
954
|
+
"name": "tenantId",
|
|
955
|
+
"type": "text",
|
|
956
|
+
"required": false,
|
|
957
|
+
"columnType": "UUID"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
"name": "planId",
|
|
961
|
+
"type": "foreignKey",
|
|
962
|
+
"required": false,
|
|
963
|
+
"related": "SubscriptionPlan",
|
|
964
|
+
"columnType": "UUID"
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
"name": "planKey",
|
|
968
|
+
"type": "text",
|
|
969
|
+
"required": false,
|
|
970
|
+
"columnType": "TEXT",
|
|
971
|
+
"default": ""
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
"name": "version",
|
|
975
|
+
"type": "integer",
|
|
976
|
+
"required": false,
|
|
977
|
+
"columnType": "INTEGER",
|
|
978
|
+
"default": 0
|
|
979
|
+
},
|
|
980
|
+
{
|
|
981
|
+
"name": "effectiveFrom",
|
|
982
|
+
"type": "datetime",
|
|
983
|
+
"required": false,
|
|
984
|
+
"columnType": "TIMESTAMP"
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
"name": "name",
|
|
988
|
+
"type": "text",
|
|
989
|
+
"required": false,
|
|
990
|
+
"columnType": "TEXT",
|
|
991
|
+
"default": ""
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
"name": "status",
|
|
995
|
+
"type": "text",
|
|
996
|
+
"required": false,
|
|
997
|
+
"columnType": "TEXT",
|
|
998
|
+
"default": "active"
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
"name": "priceAmount",
|
|
1002
|
+
"type": "integer",
|
|
1003
|
+
"required": false,
|
|
1004
|
+
"columnType": "INTEGER",
|
|
1005
|
+
"default": 0
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
"name": "currency",
|
|
1009
|
+
"type": "text",
|
|
1010
|
+
"required": false,
|
|
1011
|
+
"columnType": "TEXT",
|
|
1012
|
+
"default": "USD"
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
"name": "billingInterval",
|
|
1016
|
+
"type": "text",
|
|
1017
|
+
"required": false,
|
|
1018
|
+
"columnType": "TEXT",
|
|
1019
|
+
"default": "month"
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
"name": "pricingMode",
|
|
1023
|
+
"type": "text",
|
|
1024
|
+
"required": false,
|
|
1025
|
+
"columnType": "TEXT",
|
|
1026
|
+
"default": "fixed"
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
"name": "minimumAmount",
|
|
1030
|
+
"type": "integer",
|
|
1031
|
+
"required": false,
|
|
1032
|
+
"columnType": "INTEGER",
|
|
1033
|
+
"default": 0
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
"name": "suggestedAmount",
|
|
1037
|
+
"type": "integer",
|
|
1038
|
+
"required": false,
|
|
1039
|
+
"columnType": "INTEGER",
|
|
1040
|
+
"default": 0
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
"name": "features",
|
|
1044
|
+
"type": "text",
|
|
1045
|
+
"required": false,
|
|
1046
|
+
"columnType": "TEXT",
|
|
1047
|
+
"default": "[]"
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
"name": "thresholds",
|
|
1051
|
+
"type": "text",
|
|
1052
|
+
"required": false,
|
|
1053
|
+
"columnType": "TEXT",
|
|
1054
|
+
"default": "[]"
|
|
1055
|
+
}
|
|
1056
|
+
],
|
|
1057
|
+
"relationships": [
|
|
1058
|
+
{
|
|
1059
|
+
"name": "planId",
|
|
1060
|
+
"type": "foreignKey",
|
|
1061
|
+
"required": false,
|
|
1062
|
+
"related": "SubscriptionPlan",
|
|
1063
|
+
"columnType": "UUID"
|
|
1064
|
+
}
|
|
1065
|
+
],
|
|
1066
|
+
"methods": [
|
|
1067
|
+
"getFeatureGrants",
|
|
1068
|
+
"getFeatureKeys",
|
|
1069
|
+
"getTerms",
|
|
1070
|
+
"getThresholds",
|
|
1071
|
+
"isActive"
|
|
1072
|
+
],
|
|
1073
|
+
"methodSignatures": [
|
|
1074
|
+
{
|
|
1075
|
+
"name": "getFeatureGrants",
|
|
1076
|
+
"returns": "PlanFeatureGrant[]"
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
"name": "getFeatureKeys",
|
|
1080
|
+
"returns": "string[]"
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
"name": "getTerms",
|
|
1084
|
+
"returns": "PlanTerms"
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
"name": "getThresholds",
|
|
1088
|
+
"returns": "PlanThreshold[]"
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
"name": "isActive",
|
|
1092
|
+
"returns": "boolean"
|
|
1093
|
+
}
|
|
1094
|
+
],
|
|
1095
|
+
"tenant": {
|
|
1096
|
+
"scoped": true,
|
|
1097
|
+
"mode": "optional",
|
|
1098
|
+
"field": "tenantId"
|
|
1099
|
+
},
|
|
1100
|
+
"conflictColumns": [
|
|
1101
|
+
"plan_id",
|
|
1102
|
+
"version"
|
|
1103
|
+
],
|
|
1104
|
+
"surfaces": [
|
|
1105
|
+
{
|
|
1106
|
+
"kind": "api",
|
|
1107
|
+
"name": "subscriptionplanversions.list",
|
|
1108
|
+
"operation": "list",
|
|
1109
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion",
|
|
1110
|
+
"path": "/subscriptionplanversions",
|
|
1111
|
+
"method": "GET"
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
"kind": "api",
|
|
1115
|
+
"name": "subscriptionplanversions.get",
|
|
1116
|
+
"operation": "get",
|
|
1117
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion",
|
|
1118
|
+
"path": "/subscriptionplanversions/[id]",
|
|
1119
|
+
"method": "GET"
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
"kind": "cli",
|
|
1123
|
+
"name": "subscriptionplanversion_list",
|
|
1124
|
+
"operation": "list",
|
|
1125
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
"kind": "cli",
|
|
1129
|
+
"name": "subscriptionplanversion_get",
|
|
1130
|
+
"operation": "get",
|
|
1131
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"kind": "mcp",
|
|
1135
|
+
"name": "subscriptionplanversion_list",
|
|
1136
|
+
"operation": "list",
|
|
1137
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
"kind": "mcp",
|
|
1141
|
+
"name": "subscriptionplanversion_get",
|
|
1142
|
+
"operation": "get",
|
|
1143
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1144
|
+
}
|
|
1145
|
+
],
|
|
1146
|
+
"withheldSurfaces": [
|
|
1147
|
+
{
|
|
1148
|
+
"kind": "api",
|
|
1149
|
+
"operation": "getFeatureGrants",
|
|
1150
|
+
"code": "not-included",
|
|
1151
|
+
"reason": "not listed in api.include",
|
|
1152
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1153
|
+
},
|
|
1154
|
+
{
|
|
1155
|
+
"kind": "api",
|
|
1156
|
+
"operation": "getFeatureKeys",
|
|
1157
|
+
"code": "not-included",
|
|
1158
|
+
"reason": "not listed in api.include",
|
|
1159
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
"kind": "api",
|
|
1163
|
+
"operation": "getTerms",
|
|
1164
|
+
"code": "not-included",
|
|
1165
|
+
"reason": "not listed in api.include",
|
|
1166
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
"kind": "api",
|
|
1170
|
+
"operation": "getThresholds",
|
|
1171
|
+
"code": "not-included",
|
|
1172
|
+
"reason": "not listed in api.include",
|
|
1173
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1174
|
+
},
|
|
1175
|
+
{
|
|
1176
|
+
"kind": "api",
|
|
1177
|
+
"operation": "isActive",
|
|
1178
|
+
"code": "not-included",
|
|
1179
|
+
"reason": "not listed in api.include",
|
|
1180
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
1181
|
+
}
|
|
1182
|
+
],
|
|
1183
|
+
"relationshipFeatures": [
|
|
1184
|
+
"foreignKey",
|
|
1185
|
+
"uuidColumns"
|
|
1186
|
+
],
|
|
1187
|
+
"tags": [],
|
|
1188
|
+
"risks": []
|
|
1189
|
+
},
|
|
776
1190
|
{
|
|
777
1191
|
"name": "TenantSubscription",
|
|
778
1192
|
"qualifiedName": "@happyvertical/smrt-subscriptions:TenantSubscription",
|
|
@@ -858,6 +1272,39 @@
|
|
|
858
1272
|
"required": false,
|
|
859
1273
|
"columnType": "INTEGER"
|
|
860
1274
|
},
|
|
1275
|
+
{
|
|
1276
|
+
"name": "planVersionId",
|
|
1277
|
+
"type": "foreignKey",
|
|
1278
|
+
"required": false,
|
|
1279
|
+
"related": "SubscriptionPlanVersion",
|
|
1280
|
+
"columnType": "UUID"
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
"name": "planVersionPinnedAt",
|
|
1284
|
+
"type": "datetime",
|
|
1285
|
+
"required": false,
|
|
1286
|
+
"columnType": "TIMESTAMP"
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
"name": "planVersionPinReason",
|
|
1290
|
+
"type": "text",
|
|
1291
|
+
"required": false,
|
|
1292
|
+
"columnType": "TEXT"
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
"name": "planVersionPinNote",
|
|
1296
|
+
"type": "text",
|
|
1297
|
+
"required": false,
|
|
1298
|
+
"columnType": "TEXT",
|
|
1299
|
+
"default": ""
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
"name": "retainsPaidPeriod",
|
|
1303
|
+
"type": "boolean",
|
|
1304
|
+
"required": false,
|
|
1305
|
+
"columnType": "BOOLEAN",
|
|
1306
|
+
"default": false
|
|
1307
|
+
},
|
|
861
1308
|
{
|
|
862
1309
|
"name": "externalProvider",
|
|
863
1310
|
"type": "text",
|
|
@@ -900,12 +1347,20 @@
|
|
|
900
1347
|
"required": false,
|
|
901
1348
|
"related": "SubscriptionPlan",
|
|
902
1349
|
"columnType": "UUID"
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
"name": "planVersionId",
|
|
1353
|
+
"type": "foreignKey",
|
|
1354
|
+
"required": false,
|
|
1355
|
+
"related": "SubscriptionPlanVersion",
|
|
1356
|
+
"columnType": "UUID"
|
|
903
1357
|
}
|
|
904
1358
|
],
|
|
905
1359
|
"methods": [
|
|
906
1360
|
"getMetadata",
|
|
907
1361
|
"getSubscriber",
|
|
908
1362
|
"isEntitled",
|
|
1363
|
+
"replacePlanVersion",
|
|
909
1364
|
"setMetadata"
|
|
910
1365
|
],
|
|
911
1366
|
"methodSignatures": [
|
|
@@ -924,6 +1379,14 @@
|
|
|
924
1379
|
],
|
|
925
1380
|
"returns": "boolean"
|
|
926
1381
|
},
|
|
1382
|
+
{
|
|
1383
|
+
"name": "replacePlanVersion",
|
|
1384
|
+
"async": true,
|
|
1385
|
+
"params": [
|
|
1386
|
+
"options: any"
|
|
1387
|
+
],
|
|
1388
|
+
"returns": "Promise<this>"
|
|
1389
|
+
},
|
|
927
1390
|
{
|
|
928
1391
|
"name": "setMetadata",
|
|
929
1392
|
"params": [
|
|
@@ -1005,6 +1468,12 @@
|
|
|
1005
1468
|
"operation": "delete",
|
|
1006
1469
|
"objectName": "@happyvertical/smrt-subscriptions:TenantSubscription"
|
|
1007
1470
|
},
|
|
1471
|
+
{
|
|
1472
|
+
"kind": "cli",
|
|
1473
|
+
"name": "tenantsubscription_replacePlanVersion",
|
|
1474
|
+
"operation": "replacePlanVersion",
|
|
1475
|
+
"objectName": "@happyvertical/smrt-subscriptions:TenantSubscription"
|
|
1476
|
+
},
|
|
1008
1477
|
{
|
|
1009
1478
|
"kind": "cli",
|
|
1010
1479
|
"name": "tenantsubscription_isEntitled",
|
|
@@ -1064,6 +1533,13 @@
|
|
|
1064
1533
|
"reason": "not listed in api.include",
|
|
1065
1534
|
"objectName": "@happyvertical/smrt-subscriptions:TenantSubscription"
|
|
1066
1535
|
},
|
|
1536
|
+
{
|
|
1537
|
+
"kind": "api",
|
|
1538
|
+
"operation": "replacePlanVersion",
|
|
1539
|
+
"code": "not-included",
|
|
1540
|
+
"reason": "not listed in api.include",
|
|
1541
|
+
"objectName": "@happyvertical/smrt-subscriptions:TenantSubscription"
|
|
1542
|
+
},
|
|
1067
1543
|
{
|
|
1068
1544
|
"kind": "api",
|
|
1069
1545
|
"operation": "setMetadata",
|
|
@@ -3031,6 +3507,24 @@
|
|
|
3031
3507
|
"operation": "isActive",
|
|
3032
3508
|
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
3033
3509
|
},
|
|
3510
|
+
{
|
|
3511
|
+
"kind": "cli",
|
|
3512
|
+
"name": "subscriptionplan_getTerms",
|
|
3513
|
+
"operation": "getTerms",
|
|
3514
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
3515
|
+
},
|
|
3516
|
+
{
|
|
3517
|
+
"kind": "cli",
|
|
3518
|
+
"name": "subscriptionplan_publishTerms",
|
|
3519
|
+
"operation": "publishTerms",
|
|
3520
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
3521
|
+
},
|
|
3522
|
+
{
|
|
3523
|
+
"kind": "cli",
|
|
3524
|
+
"name": "subscriptionplan_getVersionInForce",
|
|
3525
|
+
"operation": "getVersionInForce",
|
|
3526
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
3527
|
+
},
|
|
3034
3528
|
{
|
|
3035
3529
|
"kind": "cli",
|
|
3036
3530
|
"name": "subscriptionplan_getFeatureGrants",
|
|
@@ -3085,6 +3579,46 @@
|
|
|
3085
3579
|
"operation": "get",
|
|
3086
3580
|
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlan"
|
|
3087
3581
|
},
|
|
3582
|
+
{
|
|
3583
|
+
"kind": "api",
|
|
3584
|
+
"name": "subscriptionplanversions.list",
|
|
3585
|
+
"operation": "list",
|
|
3586
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion",
|
|
3587
|
+
"path": "/subscriptionplanversions",
|
|
3588
|
+
"method": "GET"
|
|
3589
|
+
},
|
|
3590
|
+
{
|
|
3591
|
+
"kind": "api",
|
|
3592
|
+
"name": "subscriptionplanversions.get",
|
|
3593
|
+
"operation": "get",
|
|
3594
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion",
|
|
3595
|
+
"path": "/subscriptionplanversions/[id]",
|
|
3596
|
+
"method": "GET"
|
|
3597
|
+
},
|
|
3598
|
+
{
|
|
3599
|
+
"kind": "cli",
|
|
3600
|
+
"name": "subscriptionplanversion_list",
|
|
3601
|
+
"operation": "list",
|
|
3602
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
3603
|
+
},
|
|
3604
|
+
{
|
|
3605
|
+
"kind": "cli",
|
|
3606
|
+
"name": "subscriptionplanversion_get",
|
|
3607
|
+
"operation": "get",
|
|
3608
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
3609
|
+
},
|
|
3610
|
+
{
|
|
3611
|
+
"kind": "mcp",
|
|
3612
|
+
"name": "subscriptionplanversion_list",
|
|
3613
|
+
"operation": "list",
|
|
3614
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
3615
|
+
},
|
|
3616
|
+
{
|
|
3617
|
+
"kind": "mcp",
|
|
3618
|
+
"name": "subscriptionplanversion_get",
|
|
3619
|
+
"operation": "get",
|
|
3620
|
+
"objectName": "@happyvertical/smrt-subscriptions:SubscriptionPlanVersion"
|
|
3621
|
+
},
|
|
3088
3622
|
{
|
|
3089
3623
|
"kind": "api",
|
|
3090
3624
|
"name": "tenantsubscriptions.list",
|
|
@@ -3147,6 +3681,12 @@
|
|
|
3147
3681
|
"operation": "delete",
|
|
3148
3682
|
"objectName": "@happyvertical/smrt-subscriptions:TenantSubscription"
|
|
3149
3683
|
},
|
|
3684
|
+
{
|
|
3685
|
+
"kind": "cli",
|
|
3686
|
+
"name": "tenantsubscription_replacePlanVersion",
|
|
3687
|
+
"operation": "replacePlanVersion",
|
|
3688
|
+
"objectName": "@happyvertical/smrt-subscriptions:TenantSubscription"
|
|
3689
|
+
},
|
|
3150
3690
|
{
|
|
3151
3691
|
"kind": "cli",
|
|
3152
3692
|
"name": "tenantsubscription_isEntitled",
|
|
@@ -3640,14 +4180,14 @@
|
|
|
3640
4180
|
],
|
|
3641
4181
|
"prompts": [],
|
|
3642
4182
|
"relationshipsV2": {
|
|
3643
|
-
"foreignKeyFields":
|
|
4183
|
+
"foreignKeyFields": 15,
|
|
3644
4184
|
"crossPackageRefFields": 6,
|
|
3645
4185
|
"junctionCollections": 0,
|
|
3646
4186
|
"hierarchicalObjects": 0,
|
|
3647
4187
|
"polymorphicAssociations": 0,
|
|
3648
|
-
"uuidColumns":
|
|
4188
|
+
"uuidColumns": 88
|
|
3649
4189
|
},
|
|
3650
|
-
"agentDoc": "# @happyvertical/smrt-subscriptions\n\nTenant subscriptions, plan features, immutable/idempotent usage evidence,\neffective-dated client pricing, scoped spending policies, and entitlement\nresolution for SMRT applications.\n\n## Validation\n\n```bash\npnpm --filter @happyvertical/smrt-subscriptions test\npnpm --filter @happyvertical/smrt-subscriptions test:postgres\npnpm --filter @happyvertical/smrt-subscriptions typecheck\npnpm --filter @happyvertical/smrt-subscriptions build\n```\n\n`test:postgres` is the lane that holds the money-column line — SQLite's type\naffinity stores a REAL in an INTEGER column without complaint, so a money field\nthat reverted to DECIMAL passes every SQLite suite.\n\n## Money\n\n- **Money is integer minor units** (cents) — `$19.99` is `1999`.\n `SubscriptionPlan.priceAmount`, `ClientCharge.amount`, `RetailCharge.amount`,\n `CreditGrant.amount`,\n `BillingAdjustment.amount` and `SpendingPolicy.limitAmount` all initialize\n `= 0`, never `= 0.0`: the integer literal is what maps them to INTEGER\n columns (BIGINT on fresh PostgreSQL/DuckDB databases; #2401, #2373). `ClientCharge.quantity` and `TenantUsageMetric.quantity` are\n the opposite case — metered quantities are genuinely fractional and stay\n DECIMAL.\n- **`PricingRule.terms` are minor units *per unit of usage*, and stay\n fractional.** A per-token rate is routinely a fraction of a cent, so an\n integer `unitPrice` would truncate it to zero. `calculateAmount()` rounds the\n computed result to a whole minor unit — that is the single boundary in the\n package where a rate meets money, and it is what lets `evaluateSpending()`\n compare charge sums against `limitAmount` exactly.\n- **`adjust()` rejects a fractional amount.** Negative amounts are legitimate\n (a credit); fractional ones almost always mean the caller passed major units.\n- **Billing rejects immediate JSON write-back.** The JSON adapter's default\n `writeStrategy: 'immediate'` and DuckDB with that write-back strategy export\n files before transaction commit, while adapter rollback restores only the\n database transaction. `CommercialUsageService` therefore fails before setup\n on those configurations. PostgreSQL, SQLite, ordinary DuckDB, and explicit\n non-immediate write strategies remain supported. When supplying an already\n resolved database handle, also pass `billingStorage` so this capability\n decision is explicit rather than inferred from private adapter state.\n- **Embedded sourced adjustments serialize per database.** SQLite, DuckDB, and\n supported non-immediate JSON handles multiplex local writes; the complete\n deterministic adjustment flow, including recovery reads, runs under one\n database-scoped lock. Every supported embedded adjustment transaction,\n sourced or unsourced, also holds the core embedded write queue for its full\n lifetime; transaction-bound model saves re-enter that hold so adjustments\n cannot absorb, roll back, or deadlock with unrelated ordinary writes.\n- **UI formats by dividing, never by `toFixed`.** `PlanPicker` and\n `CommercialOverview` scale back to major units using the currency's own\n minor-unit exponent, so zero-decimal currencies (JPY, KRW) are not divided.\n- **Migrating an existing database**: `preflightSubscriptionsMoneyMinorUnits(db)`\n reports which columns still hold major units and which rows would be rounded\n or exceed JavaScript's safe-integer range; `migrateSubscriptionsMoneyToMinorUnits(db)` converts them\n (idempotent via `_smrt_backfills`). On SQLite the values are rescaled but the\n declared type needs the table-rebuild path (#2370). Existing\n `PricingRule.terms` are **not** migrated automatically — only the operator\n knows which keys in a given rule are prices rather than quantities or ratios.\n- **Range and existing deployments**: fresh PostgreSQL/DuckDB INTEGER columns\n are BIGINT, and hydration rejects values outside JavaScript's safe-integer\n range. Existing PostgreSQL `int4` columns require the explicit widening in #2424.\n\n## Reseller billing (#3059)\n\n- Billing ownership is consumed from `smrt-tenancy`'s\n `BillingRelationshipService` (`BillingRelationshipReader`); never re-derive\n parentage or owners here.\n- `ClientCharge` stays one row per usage event (`usage_event_id` unique) and\n `tenantId` is always the payer. That uniqueness is the double-billing guard\n across owner changes; do not widen its conflict key. The retail leg lives in\n `RetailCharge` (also one per event), written in the same transaction.\n- Price-book rules are `PricingRule` rows with `priceBookId`; `price()` must\n keep ignoring them, and `rateUsage()` only trusts rules whose tenant owns the\n book.\n- Delegated `SpendingPolicy` rows (`setByTenantId`) are guarded in\n `validateBeforeSave` and a `beforeDelete` hook, by id and by conflict key;\n `CreditGrant` applies the same parent-only rule to delegated balances.\n `PriceBookAssignmentCollection` is deliberately not a root export.\n- `ResellerBillingService` authorizes first, then writes in a system context\n (parent writes land on child-owned rows). The wholesale leg is authorized by\n the book's publisher and may never be published by the payer; whether a\n publisher is a legitimate provider for the reseller is a host obligation\n (the model records no upstream seller). Relationship reads precede\n authorization and stay under smrt-tenancy's own read rules. The only\n cross-tenant read in evaluation is the bounded `wholesale`-basis sum.\n- `balance` policies take their limit from `CreditGrant`s; `limitAmount` must\n be 0, and currency and period are fixed once saved (the ledger is scoped to\n them). Auto top-up is a host hook only — no payment provider calls. The\n evaluator re-reads credit after the hook returns (grant or not) and hands\n it `currentShortfall()`, so a hook that charges asynchronously can see a\n concurrent top-up (smrt-commerce's `autoTopUpHook()`, #3139).\n\n## Notes\n\n- Keep Stripe-specific fields as provider binding metadata. Runtime Stripe API\n calls belong in the HappyVertical SDK accounting provider.\n- Thresholds are evaluated from tenant usage metrics and optional AI usage\n summaries. Resolve multiple thresholds with the batch usage path where\n available; do not bypass tenant context in application code.\n- Use `SubscriptionResolver.create()` or an explicitly injected\n `SubscriptionResolver` once per request when resolving entitlements multiple\n times. Load and pass `EntitlementResolutionContext` to avoid re-reading the\n current subscription and plan.\n- Subscription UI components should stay provider-neutral and receive actions\n from the host app.\n",
|
|
4190
|
+
"agentDoc": "# @happyvertical/smrt-subscriptions\n\nTenant subscriptions, plan features, immutable/idempotent usage evidence,\neffective-dated client pricing, scoped spending policies, and entitlement\nresolution for SMRT applications.\n\n## Validation\n\n```bash\npnpm --filter @happyvertical/smrt-subscriptions test\npnpm --filter @happyvertical/smrt-subscriptions test:postgres\npnpm --filter @happyvertical/smrt-subscriptions typecheck\npnpm --filter @happyvertical/smrt-subscriptions build\n```\n\n`test:postgres` is the lane that holds the money-column line — SQLite's type\naffinity stores a REAL in an INTEGER column without complaint, so a money field\nthat reverted to DECIMAL passes every SQLite suite.\n\n## Money\n\n- **Money is integer minor units** (cents) — `$19.99` is `1999`.\n `SubscriptionPlan.priceAmount`, `ClientCharge.amount`, `RetailCharge.amount`,\n `CreditGrant.amount`,\n `BillingAdjustment.amount` and `SpendingPolicy.limitAmount` all initialize\n `= 0`, never `= 0.0`: the integer literal is what maps them to INTEGER\n columns (BIGINT on fresh PostgreSQL/DuckDB databases; #2401, #2373). `ClientCharge.quantity` and `TenantUsageMetric.quantity` are\n the opposite case — metered quantities are genuinely fractional and stay\n DECIMAL.\n- **`PricingRule.terms` are minor units *per unit of usage*, and stay\n fractional.** A per-token rate is routinely a fraction of a cent, so an\n integer `unitPrice` would truncate it to zero. `calculateAmount()` rounds the\n computed result to a whole minor unit — that is the single boundary in the\n package where a rate meets money, and it is what lets `evaluateSpending()`\n compare charge sums against `limitAmount` exactly.\n- **`adjust()` rejects a fractional amount.** Negative amounts are legitimate\n (a credit); fractional ones almost always mean the caller passed major units.\n- **Billing rejects immediate JSON write-back.** The JSON adapter's default\n `writeStrategy: 'immediate'` and DuckDB with that write-back strategy export\n files before transaction commit, while adapter rollback restores only the\n database transaction. `CommercialUsageService` therefore fails before setup\n on those configurations. PostgreSQL, SQLite, ordinary DuckDB, and explicit\n non-immediate write strategies remain supported. When supplying an already\n resolved database handle, also pass `billingStorage` so this capability\n decision is explicit rather than inferred from private adapter state.\n- **Embedded sourced adjustments serialize per database.** SQLite, DuckDB, and\n supported non-immediate JSON handles multiplex local writes; the complete\n deterministic adjustment flow, including recovery reads, runs under one\n database-scoped lock. Every supported embedded adjustment transaction,\n sourced or unsourced, also holds the core embedded write queue for its full\n lifetime; transaction-bound model saves re-enter that hold so adjustments\n cannot absorb, roll back, or deadlock with unrelated ordinary writes.\n- **UI formats by dividing, never by `toFixed`.** `PlanPicker` and\n `CommercialOverview` scale back to major units using the currency's own\n minor-unit exponent, so zero-decimal currencies (JPY, KRW) are not divided.\n- **Migrating an existing database**: `preflightSubscriptionsMoneyMinorUnits(db)`\n reports which columns still hold major units and which rows would be rounded\n or exceed JavaScript's safe-integer range; `migrateSubscriptionsMoneyToMinorUnits(db)` converts them\n (idempotent via `_smrt_backfills`). On SQLite the values are rescaled but the\n declared type needs the table-rebuild path (#2370). Existing\n `PricingRule.terms` are **not** migrated automatically — only the operator\n knows which keys in a given rule are prices rather than quantities or ratios.\n- **Range and existing deployments**: fresh PostgreSQL/DuckDB INTEGER columns\n are BIGINT, and hydration rejects values outside JavaScript's safe-integer\n range. Existing PostgreSQL `int4` columns require the explicit widening in #2424.\n\n## Plan versions (#4032)\n\n- `SubscriptionPlan.save()` publishes the next immutable\n `SubscriptionPlanVersion` when its terms (`PLAN_TERM_FIELDS`) change; the\n logic lives in `src/plan-versioning.ts`. Versions are append-only,\n contiguous, and monotonic in `effectiveFrom`.\n- `TenantSubscription.validateBeforeSave()` maintains `planVersionId` via\n `pinSubscriptionPlanVersion()`: pin at period start, re-pin when\n `currentPeriodStart` moves, and refuse in-period changes that are not an\n `isEntitlementUpgrade()` unless `replacePlanVersion({ policy: 'authorized',\n reason })`. Never relax this to \"latest version wins\": a paid period must\n not lose entitlements.\n- The resolver reads the pinned version; a missing or inactive pinned version\n fails closed. Only unpinned rows on plans without versions fall back to the\n live plan. `migrateSubscriptionPlanVersions(db)` backfills both.\n- Renewal means the new `currentPeriodStart` is at or after the stored\n `currentPeriodEnd`; creation and renewal pin the boundary's version, and a\n caller-named other version needs an authorized replacement.\n- `canceled` subscriptions entitle until `currentPeriodEnd` only with\n `retainsPaidPeriod`, derived on save from an entitled pre-cancel row.\n\n## Reseller billing (#3059)\n\n- Billing ownership is consumed from `smrt-tenancy`'s\n `BillingRelationshipService` (`BillingRelationshipReader`); never re-derive\n parentage or owners here.\n- `ClientCharge` stays one row per usage event (`usage_event_id` unique) and\n `tenantId` is always the payer. That uniqueness is the double-billing guard\n across owner changes; do not widen its conflict key. The retail leg lives in\n `RetailCharge` (also one per event), written in the same transaction.\n- Price-book rules are `PricingRule` rows with `priceBookId`; `price()` must\n keep ignoring them, and `rateUsage()` only trusts rules whose tenant owns the\n book.\n- Delegated `SpendingPolicy` rows (`setByTenantId`) are guarded in\n `validateBeforeSave` and a `beforeDelete` hook, by id and by conflict key;\n `CreditGrant` applies the same parent-only rule to delegated balances.\n `PriceBookAssignmentCollection` is deliberately not a root export.\n- `ResellerBillingService` authorizes first, then writes in a system context\n (parent writes land on child-owned rows). The wholesale leg is authorized by\n the book's publisher and may never be published by the payer; whether a\n publisher is a legitimate provider for the reseller is a host obligation\n (the model records no upstream seller). Relationship reads precede\n authorization and stay under smrt-tenancy's own read rules. The only\n cross-tenant read in evaluation is the bounded `wholesale`-basis sum.\n- `balance` policies take their limit from `CreditGrant`s; `limitAmount` must\n be 0, and currency and period are fixed once saved (the ledger is scoped to\n them). Auto top-up is a host hook only — no payment provider calls. The\n evaluator re-reads credit after the hook returns (grant or not) and hands\n it `currentShortfall()`, so a hook that charges asynchronously can see a\n concurrent top-up (smrt-commerce's `autoTopUpHook()`, #3139).\n\n## Notes\n\n- Keep Stripe-specific fields as provider binding metadata. Runtime Stripe API\n calls belong in the HappyVertical SDK accounting provider.\n- Thresholds are evaluated from tenant usage metrics and optional AI usage\n summaries. Resolve multiple thresholds with the batch usage path where\n available; do not bypass tenant context in application code.\n- Use `SubscriptionResolver.create()` or an explicitly injected\n `SubscriptionResolver` once per request when resolving entitlements multiple\n times. Load and pass `EntitlementResolutionContext` to avoid re-reading the\n current subscription and plan.\n- Subscription UI components should stay provider-neutral and receive actions\n from the host app.\n",
|
|
3651
4191
|
"browser": {
|
|
3652
4192
|
"status": "server-only",
|
|
3653
4193
|
"issues": [
|