@happyvertical/smrt-subscriptions 0.60.14 → 0.60.16

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 (54) hide show
  1. package/AGENTS.md +152 -0
  2. package/README.md +206 -0
  3. package/dist/billing/apply.d.ts +52 -0
  4. package/dist/billing/apply.d.ts.map +1 -0
  5. package/dist/billing/checkout-sessions.d.ts +99 -0
  6. package/dist/billing/checkout-sessions.d.ts.map +1 -0
  7. package/dist/billing/config.d.ts +64 -0
  8. package/dist/billing/config.d.ts.map +1 -0
  9. package/dist/billing/events.d.ts +49 -0
  10. package/dist/billing/events.d.ts.map +1 -0
  11. package/dist/billing/host.d.ts +3 -0
  12. package/dist/billing/host.d.ts.map +1 -0
  13. package/dist/billing/index.d.ts +4 -0
  14. package/dist/billing/index.d.ts.map +1 -0
  15. package/dist/billing/plans.d.ts +45 -0
  16. package/dist/billing/plans.d.ts.map +1 -0
  17. package/dist/billing/signing.d.ts +24 -0
  18. package/dist/billing/signing.d.ts.map +1 -0
  19. package/dist/billing/types.d.ts +265 -0
  20. package/dist/billing/types.d.ts.map +1 -0
  21. package/dist/collections/TenantUsageMetricCollection.d.ts.map +1 -1
  22. package/dist/index.d.ts +4 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3230 -1123
  25. package/dist/index.js.map +1 -1
  26. package/dist/manifest.json +314 -4
  27. package/dist/models/BillingCheckoutSession.d.ts +39 -0
  28. package/dist/models/BillingCheckoutSession.d.ts.map +1 -0
  29. package/dist/models/index.d.ts +1 -0
  30. package/dist/models/index.d.ts.map +1 -1
  31. package/dist/recipes.d.ts +1 -1
  32. package/dist/services/entitlement-changes.d.ts +115 -0
  33. package/dist/services/entitlement-changes.d.ts.map +1 -0
  34. package/dist/services/hosted-ai-spend.d.ts +182 -0
  35. package/dist/services/hosted-ai-spend.d.ts.map +1 -0
  36. package/dist/services/index.d.ts +3 -0
  37. package/dist/services/index.d.ts.map +1 -1
  38. package/dist/services/subscription-feature-source.d.ts +89 -0
  39. package/dist/services/subscription-feature-source.d.ts.map +1 -0
  40. package/dist/services/subscription-resolver.d.ts +34 -1
  41. package/dist/services/subscription-resolver.d.ts.map +1 -1
  42. package/dist/smrt-knowledge.json +103 -8
  43. package/dist/smrt-knowledge.okf.md +6 -2
  44. package/dist/vault-account/actions.d.ts +24 -0
  45. package/dist/vault-account/actions.d.ts.map +1 -0
  46. package/dist/vault-account/errors.d.ts +20 -0
  47. package/dist/vault-account/errors.d.ts.map +1 -0
  48. package/dist/vault-account/index.d.ts +5 -0
  49. package/dist/vault-account/index.d.ts.map +1 -0
  50. package/dist/vault-account/relay-admin-client.d.ts +10 -0
  51. package/dist/vault-account/relay-admin-client.d.ts.map +1 -0
  52. package/dist/vault-account/types.d.ts +115 -0
  53. package/dist/vault-account/types.d.ts.map +1 -0
  54. package/package.json +9 -6
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-subscriptions",
5
- "packageVersion": "0.60.14",
5
+ "packageVersion": "0.60.16",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-subscriptions:SubscriptionPlanCollection": {
8
8
  "name": "subscriptionplancollection",
@@ -1132,6 +1132,311 @@
1132
1132
  },
1133
1133
  "importPath": "@happyvertical/smrt-subscriptions"
1134
1134
  },
1135
+ "@happyvertical/smrt-subscriptions:BillingCheckoutSession": {
1136
+ "name": "billingcheckoutsession",
1137
+ "className": "BillingCheckoutSession",
1138
+ "qualifiedName": "@happyvertical/smrt-subscriptions:BillingCheckoutSession",
1139
+ "collection": "billingcheckoutsessions",
1140
+ "description": "One Checkout session created by the billing host, recorded when the host creates it and required when the paid session completes, so signed metadata copied onto another integration's session is never…",
1141
+ "filePath": "/home/runner/work/smrt/smrt/packages/subscriptions/src/models/BillingCheckoutSession.ts",
1142
+ "packageName": "@happyvertical/smrt-subscriptions",
1143
+ "fields": {
1144
+ "sessionId": {
1145
+ "type": "text",
1146
+ "required": true,
1147
+ "default": "",
1148
+ "_meta": {
1149
+ "required": true
1150
+ }
1151
+ },
1152
+ "targetTenantId": {
1153
+ "type": "text",
1154
+ "required": false,
1155
+ "default": "",
1156
+ "description": "The tenant the host created the session for.",
1157
+ "_meta": {
1158
+ "description": "The tenant the host created the session for."
1159
+ }
1160
+ },
1161
+ "status": {
1162
+ "type": "text",
1163
+ "required": false,
1164
+ "default": "pending",
1165
+ "enum": [
1166
+ "pending",
1167
+ "completed",
1168
+ "needs_reconciliation",
1169
+ "dismissed"
1170
+ ]
1171
+ },
1172
+ "expiresAt": {
1173
+ "type": "datetime",
1174
+ "required": false
1175
+ },
1176
+ "completedAt": {
1177
+ "type": "datetime",
1178
+ "required": false
1179
+ },
1180
+ "reason": {
1181
+ "type": "text",
1182
+ "required": false,
1183
+ "default": ""
1184
+ },
1185
+ "detail": {
1186
+ "type": "text",
1187
+ "required": false,
1188
+ "default": "{}"
1189
+ }
1190
+ },
1191
+ "methods": {},
1192
+ "decoratorConfig": {
1193
+ "tableName": "_smrt_billing_checkout_sessions",
1194
+ "conflictColumns": [
1195
+ "session_id"
1196
+ ],
1197
+ "api": false,
1198
+ "cli": false,
1199
+ "mcp": false
1200
+ },
1201
+ "extends": "SmrtObject",
1202
+ "exportName": "BillingCheckoutSession",
1203
+ "collectionExportName": "BillingCheckoutSessionCollection",
1204
+ "validationRules": [
1205
+ {
1206
+ "field": "sessionId",
1207
+ "rule": "required",
1208
+ "fieldType": "text"
1209
+ }
1210
+ ],
1211
+ "schema": {
1212
+ "tableName": "_smrt_billing_checkout_sessions",
1213
+ "ddl": "CREATE TABLE IF NOT EXISTS \"_smrt_billing_checkout_sessions\" (\n \"_sync_origin_device_id\" TEXT,\n \"_sync_revision\" INTEGER,\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"session_id\" TEXT NOT NULL DEFAULT '',\n \"target_tenant_id\" TEXT DEFAULT '',\n \"status\" TEXT DEFAULT 'pending',\n \"expires_at\" TIMESTAMP,\n \"completed_at\" TIMESTAMP,\n \"reason\" TEXT DEFAULT '',\n \"detail\" TEXT DEFAULT '{}'\n);",
1214
+ "columns": {
1215
+ "_sync_origin_device_id": {
1216
+ "type": "TEXT"
1217
+ },
1218
+ "_sync_revision": {
1219
+ "type": "INTEGER"
1220
+ },
1221
+ "id": {
1222
+ "type": "UUID",
1223
+ "primaryKey": true,
1224
+ "referenceKind": "id",
1225
+ "notNull": true
1226
+ },
1227
+ "slug": {
1228
+ "type": "TEXT",
1229
+ "notNull": true
1230
+ },
1231
+ "context": {
1232
+ "type": "TEXT",
1233
+ "notNull": true,
1234
+ "default": ""
1235
+ },
1236
+ "created_at": {
1237
+ "type": "TIMESTAMP",
1238
+ "notNull": true,
1239
+ "default": "current_timestamp"
1240
+ },
1241
+ "updated_at": {
1242
+ "type": "TIMESTAMP",
1243
+ "notNull": true,
1244
+ "default": "current_timestamp"
1245
+ },
1246
+ "session_id": {
1247
+ "type": "TEXT",
1248
+ "notNull": true,
1249
+ "unique": false,
1250
+ "default": ""
1251
+ },
1252
+ "target_tenant_id": {
1253
+ "type": "TEXT",
1254
+ "notNull": false,
1255
+ "unique": false,
1256
+ "default": ""
1257
+ },
1258
+ "status": {
1259
+ "type": "TEXT",
1260
+ "notNull": false,
1261
+ "unique": false,
1262
+ "default": "pending"
1263
+ },
1264
+ "expires_at": {
1265
+ "type": "TIMESTAMP",
1266
+ "notNull": false,
1267
+ "unique": false
1268
+ },
1269
+ "completed_at": {
1270
+ "type": "TIMESTAMP",
1271
+ "notNull": false,
1272
+ "unique": false
1273
+ },
1274
+ "reason": {
1275
+ "type": "TEXT",
1276
+ "notNull": false,
1277
+ "unique": false,
1278
+ "default": ""
1279
+ },
1280
+ "detail": {
1281
+ "type": "TEXT",
1282
+ "notNull": false,
1283
+ "unique": false,
1284
+ "default": "{}"
1285
+ }
1286
+ },
1287
+ "indexes": [
1288
+ {
1289
+ "name": "_smrt_billing_checkout_sessions_session_id_idx",
1290
+ "columns": [
1291
+ "session_id"
1292
+ ],
1293
+ "unique": true
1294
+ },
1295
+ {
1296
+ "name": "_smrt_billing_checkout_sessions_slug_context_idx",
1297
+ "columns": [
1298
+ "slug",
1299
+ "context"
1300
+ ]
1301
+ },
1302
+ {
1303
+ "name": "_smrt_billing_checkout_sessions_created_at_idx",
1304
+ "columns": [
1305
+ "created_at"
1306
+ ]
1307
+ }
1308
+ ],
1309
+ "version": "c1924881"
1310
+ },
1311
+ "importPath": "@happyvertical/smrt-subscriptions"
1312
+ },
1313
+ "@happyvertical/smrt-subscriptions:BillingCheckoutSessionCollection": {
1314
+ "name": "billingcheckoutsessioncollection",
1315
+ "className": "BillingCheckoutSessionCollection",
1316
+ "qualifiedName": "@happyvertical/smrt-subscriptions:BillingCheckoutSessionCollection",
1317
+ "collection": "billingcheckoutsessions",
1318
+ "filePath": "/home/runner/work/smrt/smrt/packages/subscriptions/src/models/BillingCheckoutSession.ts",
1319
+ "packageName": "@happyvertical/smrt-subscriptions",
1320
+ "fields": {},
1321
+ "methods": {},
1322
+ "decoratorConfig": {
1323
+ "tableName": "_smrt_billing_checkout_sessions",
1324
+ "api": false,
1325
+ "mcp": false,
1326
+ "cli": false
1327
+ },
1328
+ "extends": "SmrtCollection",
1329
+ "extendsTypeArg": "BillingCheckoutSession",
1330
+ "exportName": "BillingCheckoutSessionCollection",
1331
+ "collectionExportName": "BillingCheckoutSessionCollectionCollection",
1332
+ "collectionOf": "@happyvertical/smrt-subscriptions:BillingCheckoutSession",
1333
+ "inheritedExposure": [
1334
+ "api",
1335
+ "mcp",
1336
+ "cli"
1337
+ ],
1338
+ "schema": {
1339
+ "tableName": "_smrt_billing_checkout_sessions",
1340
+ "ddl": "CREATE TABLE IF NOT EXISTS \"_smrt_billing_checkout_sessions\" (\n \"_sync_origin_device_id\" TEXT,\n \"_sync_revision\" INTEGER,\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"session_id\" TEXT NOT NULL DEFAULT '',\n \"target_tenant_id\" TEXT DEFAULT '',\n \"status\" TEXT DEFAULT 'pending',\n \"expires_at\" TIMESTAMP,\n \"completed_at\" TIMESTAMP,\n \"reason\" TEXT DEFAULT '',\n \"detail\" TEXT DEFAULT '{}'\n);",
1341
+ "columns": {
1342
+ "_sync_origin_device_id": {
1343
+ "type": "TEXT"
1344
+ },
1345
+ "_sync_revision": {
1346
+ "type": "INTEGER"
1347
+ },
1348
+ "id": {
1349
+ "type": "UUID",
1350
+ "primaryKey": true,
1351
+ "referenceKind": "id",
1352
+ "notNull": true
1353
+ },
1354
+ "slug": {
1355
+ "type": "TEXT",
1356
+ "notNull": true
1357
+ },
1358
+ "context": {
1359
+ "type": "TEXT",
1360
+ "notNull": true,
1361
+ "default": ""
1362
+ },
1363
+ "created_at": {
1364
+ "type": "TIMESTAMP",
1365
+ "notNull": true,
1366
+ "default": "current_timestamp"
1367
+ },
1368
+ "updated_at": {
1369
+ "type": "TIMESTAMP",
1370
+ "notNull": true,
1371
+ "default": "current_timestamp"
1372
+ },
1373
+ "session_id": {
1374
+ "type": "TEXT",
1375
+ "notNull": true,
1376
+ "unique": false,
1377
+ "default": ""
1378
+ },
1379
+ "target_tenant_id": {
1380
+ "type": "TEXT",
1381
+ "notNull": false,
1382
+ "unique": false,
1383
+ "default": ""
1384
+ },
1385
+ "status": {
1386
+ "type": "TEXT",
1387
+ "notNull": false,
1388
+ "unique": false,
1389
+ "default": "pending"
1390
+ },
1391
+ "expires_at": {
1392
+ "type": "TIMESTAMP",
1393
+ "notNull": false,
1394
+ "unique": false
1395
+ },
1396
+ "completed_at": {
1397
+ "type": "TIMESTAMP",
1398
+ "notNull": false,
1399
+ "unique": false
1400
+ },
1401
+ "reason": {
1402
+ "type": "TEXT",
1403
+ "notNull": false,
1404
+ "unique": false,
1405
+ "default": ""
1406
+ },
1407
+ "detail": {
1408
+ "type": "TEXT",
1409
+ "notNull": false,
1410
+ "unique": false,
1411
+ "default": "{}"
1412
+ }
1413
+ },
1414
+ "indexes": [
1415
+ {
1416
+ "name": "_smrt_billing_checkout_sessions_session_id_idx",
1417
+ "columns": [
1418
+ "session_id"
1419
+ ],
1420
+ "unique": true
1421
+ },
1422
+ {
1423
+ "name": "_smrt_billing_checkout_sessions_slug_context_idx",
1424
+ "columns": [
1425
+ "slug",
1426
+ "context"
1427
+ ]
1428
+ },
1429
+ {
1430
+ "name": "_smrt_billing_checkout_sessions_created_at_idx",
1431
+ "columns": [
1432
+ "created_at"
1433
+ ]
1434
+ }
1435
+ ],
1436
+ "version": "c1924881"
1437
+ },
1438
+ "importPath": "@happyvertical/smrt-subscriptions"
1439
+ },
1135
1440
  "@happyvertical/smrt-subscriptions:SubscriptionPlan": {
1136
1441
  "name": "subscriptionplan",
1137
1442
  "className": "SubscriptionPlan",
@@ -6894,24 +7199,29 @@
6894
7199
  "demo": {
6895
7200
  "mode": "server",
6896
7201
  "reasons": [
6897
- "Needs a server because its package does not build for a browser: core migrations (node:crypto, node:os); and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3626)."
7202
+ "Needs a server because its package does not build for a browser: core migrations (node:crypto, node:os); and its package depends on @happyvertical/smrt-profiles, @happyvertical/smrt-tenancy, @happyvertical/smrt-users, which do not build for a browser (#3617, #3624, #3626)."
6898
7203
  ]
6899
7204
  }
6900
7205
  }
6901
7206
  ],
6902
7207
  "smrtDependencies": [
6903
7208
  "@happyvertical/smrt-core",
6904
- "@happyvertical/smrt-tenancy"
7209
+ "@happyvertical/smrt-features",
7210
+ "@happyvertical/smrt-tenancy",
7211
+ "@happyvertical/smrt-users"
6905
7212
  ],
6906
7213
  "browser": {
6907
7214
  "status": "server-only",
6908
7215
  "issues": [
7216
+ "#3617",
6909
7217
  "#3624",
6910
7218
  "#3626"
6911
7219
  ],
6912
7220
  "reason": "core migrations (node:crypto, node:os)",
6913
7221
  "via": [
6914
- "@happyvertical/smrt-tenancy"
7222
+ "@happyvertical/smrt-profiles",
7223
+ "@happyvertical/smrt-tenancy",
7224
+ "@happyvertical/smrt-users"
6915
7225
  ]
6916
7226
  },
6917
7227
  "stampsConstructors": true
@@ -0,0 +1,39 @@
1
+ import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
+ /**
3
+ * Where a Checkout session the billing host created stands (#4814).
4
+ *
5
+ * - `pending`: created by the host, not yet completed.
6
+ * - `completed`: the paid session was linked to its tenant (single use).
7
+ * - `needs_reconciliation`: a paid session whose record was missing, expired
8
+ * or did not match. It is not linked; an operator links it on purpose with
9
+ * `BillingHost.reconcileCheckout()`.
10
+ */
11
+ export type BillingCheckoutSessionStatus = 'pending' | 'completed' | 'needs_reconciliation' | 'dismissed';
12
+ /**
13
+ * One Checkout session created by the billing host, recorded when the host
14
+ * creates it and required when the paid session completes, so signed
15
+ * metadata copied onto another integration's session is never trusted.
16
+ * `sessionId` is the provider's unguessable, unique id and doubles as the
17
+ * single-use nonce.
18
+ *
19
+ * A system table managed through `createBillingHost()`, like
20
+ * `_smrt_price_book_assignments`; it has no generated API surface. It is a
21
+ * root export because the published manifest advertises it. `tenantId` is the
22
+ * tenant the host created the session for (`''` on a row opened for a session
23
+ * the host never recorded).
24
+ */
25
+ export declare class BillingCheckoutSession extends SmrtObject {
26
+ sessionId: string;
27
+ targetTenantId: string;
28
+ status: BillingCheckoutSessionStatus;
29
+ expiresAt: Date;
30
+ completedAt: Date | null;
31
+ /** Why the row needs reconciliation (a code, never provider text). */
32
+ reason: string;
33
+ /** JSON ids needed to reconcile: event, subscription, customer, plan. */
34
+ detail: string;
35
+ }
36
+ export declare class BillingCheckoutSessionCollection extends SmrtCollection<BillingCheckoutSession> {
37
+ static readonly _itemClass: typeof BillingCheckoutSession;
38
+ }
39
+ //# sourceMappingURL=BillingCheckoutSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BillingCheckoutSession.d.ts","sourceRoot":"","sources":["../../src/models/BillingCheckoutSession.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,MAAM,4BAA4B,GACpC,SAAS,GACT,WAAW,GACX,sBAAsB,GACtB,WAAW,CAAC;AAEhB;;;;;;;;;;;;GAYG;AACH,qBAOa,sBAAuB,SAAQ,UAAU;IAEpD,SAAS,EAAE,MAAM,CAAM;IAEvB,cAAc,EAAE,MAAM,CAAM;IAC5B,MAAM,EAAE,4BAA4B,CAAa;IACjD,SAAS,EAAE,IAAI,CAAe;IAC9B,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;IAChC,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAM;IACpB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAQ;CACvB;AAED,qBAAa,gCAAiC,SAAQ,cAAc,CAAC,sBAAsB,CAAC;IAC1F,MAAM,CAAC,QAAQ,CAAC,UAAU,gCAA0B;CACrD"}
@@ -1,3 +1,4 @@
1
+ export { BillingCheckoutSession } from './BillingCheckoutSession.js';
1
2
  export type { PricingStrategy, SpendingBasis, SpendingPeriod, SpendingPolicyBehavior, } from './commercial.js';
2
3
  export { BillingAdjustment, BillingAdjustmentCollection, ClientCharge, ClientChargeCollection, PricingRule, PricingRuleCollection, SpendingPolicy, SpendingPolicyCollection, } from './commercial.js';
3
4
  export type { PriceBookKind } from './reseller.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,YAAY,EACZ,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,YAAY,EACV,eAAe,EACf,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,YAAY,EACZ,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/recipes.d.ts CHANGED
@@ -29,7 +29,7 @@ export declare class SubscriptionPlansRecipe extends SmrtRecipe {
29
29
  icon: string;
30
30
  description: string;
31
31
  };
32
- static models: (typeof SubscriptionPlanVersion | typeof TenantSubscription | typeof SubscriptionPlan | typeof ClientCharge)[];
32
+ static models: (typeof SubscriptionPlan | typeof SubscriptionPlanVersion | typeof TenantSubscription | typeof ClientCharge)[];
33
33
  static nav: ({
34
34
  label: string;
35
35
  model: typeof SubscriptionPlan;
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Entitlement change hook (#4759).
3
+ *
4
+ * A plan change arrives through the host's billing webhook (Stripe in
5
+ * smrt-saas-starter, #4667): the host writes the new `TenantSubscription`
6
+ * state. Code that must react to a feature key being gained or lost (hosted
7
+ * inference provisioning, #4759) registers a listener here; the host wraps
8
+ * its webhook write in {@link trackEntitlementChange}, which snapshots the
9
+ * tenant's feature grants before and after and notifies listeners with the
10
+ * difference.
11
+ *
12
+ * Listeners run after the write has been applied (and committed, when the
13
+ * host's write commits inside `apply`). A listener failure never undoes the
14
+ * write: it is collected in the outcome's `failures` so the host can log it,
15
+ * alert, or retry the reaction (listeners are expected to be idempotent;
16
+ * hosted provisioning is, through `runOnce()`). This package stays free of
17
+ * any listener's dependencies: listeners satisfy the structural
18
+ * {@link EntitlementChangeListener} type.
19
+ */
20
+ import type { PlanFeatureGrant } from '../types.js';
21
+ import type { SubscriptionResolver } from './subscription-resolver.js';
22
+ /** A tenant's entitled grants at one moment. */
23
+ export interface EntitlementSnapshot {
24
+ planId: string | null;
25
+ planKey: string | null;
26
+ /** Enabled feature keys, sorted. */
27
+ featureKeys: string[];
28
+ /** Enabled grants (with their `metadata`), sorted by key. */
29
+ grants: PlanFeatureGrant[];
30
+ }
31
+ /** The difference between two snapshots of one tenant. */
32
+ export interface EntitlementChange {
33
+ tenantId: string;
34
+ /** Keys granted after but not before. */
35
+ gained: string[];
36
+ /** Keys granted before but not after. */
37
+ lost: string[];
38
+ /**
39
+ * Keys granted both before and after whose grant `metadata` changed (a
40
+ * plan's budget for `inference.hosted`, for instance).
41
+ */
42
+ changed: string[];
43
+ before: EntitlementSnapshot;
44
+ after: EntitlementSnapshot;
45
+ }
46
+ /** Reacts to an {@link EntitlementChange}; may be async. */
47
+ export type EntitlementChangeListener = (change: EntitlementChange) => void | Promise<void>;
48
+ /** One listener that threw. */
49
+ export interface EntitlementChangeFailure {
50
+ error: unknown;
51
+ }
52
+ /** What {@link notifyEntitlementChange} reports. */
53
+ export interface EntitlementChangeOutcome {
54
+ change: EntitlementChange;
55
+ /** Listeners that threw, in registration order. Empty when all succeeded. */
56
+ failures: EntitlementChangeFailure[];
57
+ }
58
+ /** `Symbol.for()` key of the process-wide listener set. */
59
+ export declare const ENTITLEMENT_CHANGE_LISTENERS_SLOT_KEY = "@happyvertical/smrt-subscriptions:entitlement-change-listeners";
60
+ /**
61
+ * Register a process-wide listener. Returns a function that unregisters it.
62
+ * Registering the same function twice keeps one registration.
63
+ */
64
+ export declare function registerEntitlementChangeListener(listener: EntitlementChangeListener): () => void;
65
+ /** The registered listeners, in registration order. */
66
+ export declare function getEntitlementChangeListeners(): EntitlementChangeListener[];
67
+ /** An empty snapshot: no entitled subscription. */
68
+ export declare function emptyEntitlementSnapshot(): EntitlementSnapshot;
69
+ /**
70
+ * Snapshot the tenant's entitled grants through `resolver` (no usage
71
+ * meters are read). Missing subscription tables read as no plan, like
72
+ * `SubscriptionFeatureSource`; every other error propagates.
73
+ */
74
+ export declare function snapshotEntitlements(resolver: Pick<SubscriptionResolver, 'resolveFeatureGrants'>, tenantId: string, options?: {
75
+ now?: Date;
76
+ }): Promise<EntitlementSnapshot>;
77
+ /** Compute the {@link EntitlementChange} between two snapshots. */
78
+ export declare function diffEntitlements(tenantId: string, before: EntitlementSnapshot, after: EntitlementSnapshot): EntitlementChange;
79
+ /** True when the change gains, loses or changes at least one key. */
80
+ export declare function hasEntitlementChange(change: EntitlementChange): boolean;
81
+ /**
82
+ * Notify `listeners` (default: the registered ones) of `change`, one after
83
+ * another. A change with nothing gained, lost or changed notifies nobody.
84
+ * Never throws for a listener: failures are returned.
85
+ */
86
+ export declare function notifyEntitlementChange(change: EntitlementChange, options?: {
87
+ listeners?: readonly EntitlementChangeListener[];
88
+ }): Promise<EntitlementChangeOutcome>;
89
+ /** Options for {@link trackEntitlementChange}. */
90
+ export interface TrackEntitlementChangeOptions {
91
+ tenantId: string;
92
+ /** Resolver used for both snapshots (build one per webhook delivery). */
93
+ resolver: Pick<SubscriptionResolver, 'resolveFeatureGrants'>;
94
+ /** Listeners to notify instead of the registered ones. */
95
+ listeners?: readonly EntitlementChangeListener[];
96
+ /** Clock for both snapshots; defaults to the current time at each. */
97
+ now?: () => Date;
98
+ }
99
+ /**
100
+ * Snapshot the tenant's grants, run `apply` (the webhook's subscription
101
+ * write), snapshot again, and notify listeners of the difference. `apply`'s
102
+ * error propagates and notifies nobody. Listener failures are returned in
103
+ * `failures`, never thrown.
104
+ *
105
+ * ```ts
106
+ * const { failures } = await trackEntitlementChange(
107
+ * { tenantId, resolver: await SubscriptionResolver.create({ db }) },
108
+ * () => applyStripeSubscriptionUpdate(event),
109
+ * );
110
+ * ```
111
+ */
112
+ export declare function trackEntitlementChange<T>(options: TrackEntitlementChangeOptions, apply: () => Promise<T>): Promise<EntitlementChangeOutcome & {
113
+ result: T;
114
+ }>;
115
+ //# sourceMappingURL=entitlement-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlement-changes.d.ts","sourceRoot":"","sources":["../../src/services/entitlement-changes.ts"],"names":[],"mappings":"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"}