@schematichq/schematic-react 1.5.0 → 1.6.0

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.
@@ -30,23 +30,38 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ BillingDataProvider: () => BillingDataProvider,
34
+ BillingProvider: () => BillingProvider,
35
+ DEFAULT_INVOICE_QUERY: () => DEFAULT_INVOICE_QUERY,
36
+ INVOICE_PAGE_SIZE: () => INVOICE_PAGE_SIZE,
37
+ InvoiceStatus: () => InvoiceStatus,
33
38
  RuleType: () => RuleType,
34
39
  Schematic: () => Schematic,
40
+ SchematicI18nContext: () => SchematicI18nContext,
41
+ SchematicI18nProvider: () => SchematicI18nProvider,
35
42
  SchematicProvider: () => SchematicProvider,
36
43
  TrialStatus: () => TrialStatus,
37
44
  UsagePeriod: () => UsagePeriod,
45
+ normalizeInvoiceQuery: () => normalizeInvoiceQuery2,
46
+ useBillingDataSource: () => useBillingDataSource,
47
+ useInvalidateBillingData: () => useInvalidateBillingData,
48
+ useInvoices: () => useInvoices,
38
49
  useSchematic: () => useSchematic,
39
50
  useSchematicContext: () => useSchematicContext,
40
51
  useSchematicCreditBalance: () => useSchematicCreditBalance,
41
52
  useSchematicEntitlement: () => useSchematicEntitlement,
42
53
  useSchematicEvents: () => useSchematicEvents,
43
54
  useSchematicFlag: () => useSchematicFlag,
55
+ useSchematicI18n: () => useSchematicI18n,
44
56
  useSchematicIsPending: () => useSchematicIsPending,
45
- useSchematicPlan: () => useSchematicPlan
57
+ useSchematicLocale: () => useSchematicLocale,
58
+ useSchematicPlan: () => useSchematicPlan,
59
+ useSchematicStrings: () => useSchematicStrings,
60
+ useSchematicTranslate: () => useSchematicTranslate
46
61
  });
47
62
  module.exports = __toCommonJS(index_exports);
48
63
 
49
- // node_modules/@schematichq/schematic-js/dist/schematic.esm.js
64
+ // node_modules/.pnpm/@schematichq+schematic-js@1.7.0/node_modules/@schematichq/schematic-js/dist/schematic.esm.js
50
65
  var __create2 = Object.create;
51
66
  var __defProp2 = Object.defineProperty;
52
67
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -60,6 +75,10 @@ var __commonJS = (cb, mod) => function __require() {
60
75
  throw mod = 0, e;
61
76
  }
62
77
  };
78
+ var __export2 = (target, all) => {
79
+ for (var name in all)
80
+ __defProp2(target, name, { get: all[name], enumerable: true });
81
+ };
63
82
  var __copyProps2 = (to, from, except, desc) => {
64
83
  if (from && typeof from === "object" || typeof from === "function") {
65
84
  for (let key of __getOwnPropNames2(from))
@@ -77,7 +96,7 @@ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__
77
96
  mod
78
97
  ));
79
98
  var require_browser_polyfill = __commonJS({
80
- "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
99
+ "node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
81
100
  (function(self2) {
82
101
  var irrelevant = (function(exports2) {
83
102
  var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
@@ -661,6 +680,18 @@ function MetricPeriodMonthResetFromJSON(json) {
661
680
  function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
662
681
  return json;
663
682
  }
683
+ function WarningTierFromJSON(json) {
684
+ return WarningTierFromJSONTyped(json, false);
685
+ }
686
+ function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
687
+ if (json == null) {
688
+ return json;
689
+ }
690
+ return {
691
+ key: json["key"],
692
+ value: json["value"]
693
+ };
694
+ }
664
695
  function MetricPeriodFromJSON(json) {
665
696
  return MetricPeriodFromJSONTyped(json, false);
666
697
  }
@@ -692,7 +723,8 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
692
723
  monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
693
724
  softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
694
725
  usage: json["usage"] == null ? void 0 : json["usage"],
695
- valueType: EntitlementValueTypeFromJSON(json["value_type"])
726
+ valueType: EntitlementValueTypeFromJSON(json["value_type"]),
727
+ warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
696
728
  };
697
729
  }
698
730
  function RuleTypeFromJSON(json) {
@@ -1062,6 +1094,7 @@ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
1062
1094
  error: value["error"],
1063
1095
  flag_id: value["flagId"],
1064
1096
  flag_key: value["flagKey"],
1097
+ preflight: value["preflight"],
1065
1098
  reason: value["reason"],
1066
1099
  req_company: value["reqCompany"],
1067
1100
  req_user: value["reqUser"],
@@ -1175,16 +1208,545 @@ function contextString(context) {
1175
1208
  }, {});
1176
1209
  return JSON.stringify(sortedContext);
1177
1210
  }
1178
- var version = "1.5.0";
1211
+ var version = "1.7.0";
1212
+ var models_exports = {};
1213
+ __export2(models_exports, {
1214
+ ApiErrorFromJSON: () => ApiErrorFromJSON,
1215
+ ApiErrorFromJSONTyped: () => ApiErrorFromJSONTyped,
1216
+ ApiErrorToJSON: () => ApiErrorToJSON,
1217
+ ApiErrorToJSONTyped: () => ApiErrorToJSONTyped,
1218
+ CompanyInvoiceResponseDataFromJSON: () => CompanyInvoiceResponseDataFromJSON,
1219
+ CompanyInvoiceResponseDataFromJSONTyped: () => CompanyInvoiceResponseDataFromJSONTyped,
1220
+ CompanyInvoiceResponseDataToJSON: () => CompanyInvoiceResponseDataToJSON,
1221
+ CompanyInvoiceResponseDataToJSONTyped: () => CompanyInvoiceResponseDataToJSONTyped,
1222
+ CompanyInvoicesResponseDataFromJSON: () => CompanyInvoicesResponseDataFromJSON,
1223
+ CompanyInvoicesResponseDataFromJSONTyped: () => CompanyInvoicesResponseDataFromJSONTyped,
1224
+ CompanyInvoicesResponseDataToJSON: () => CompanyInvoicesResponseDataToJSON,
1225
+ CompanyInvoicesResponseDataToJSONTyped: () => CompanyInvoicesResponseDataToJSONTyped,
1226
+ GetCompanyInvoicesParamsFromJSON: () => GetCompanyInvoicesParamsFromJSON,
1227
+ GetCompanyInvoicesParamsFromJSONTyped: () => GetCompanyInvoicesParamsFromJSONTyped,
1228
+ GetCompanyInvoicesParamsToJSON: () => GetCompanyInvoicesParamsToJSON,
1229
+ GetCompanyInvoicesParamsToJSONTyped: () => GetCompanyInvoicesParamsToJSONTyped,
1230
+ GetCompanyInvoicesResponseFromJSON: () => GetCompanyInvoicesResponseFromJSON,
1231
+ GetCompanyInvoicesResponseFromJSONTyped: () => GetCompanyInvoicesResponseFromJSONTyped,
1232
+ GetCompanyInvoicesResponseToJSON: () => GetCompanyInvoicesResponseToJSON,
1233
+ GetCompanyInvoicesResponseToJSONTyped: () => GetCompanyInvoicesResponseToJSONTyped,
1234
+ InvoiceStatus: () => InvoiceStatus,
1235
+ InvoiceStatusFromJSON: () => InvoiceStatusFromJSON,
1236
+ InvoiceStatusFromJSONTyped: () => InvoiceStatusFromJSONTyped,
1237
+ InvoiceStatusToJSON: () => InvoiceStatusToJSON,
1238
+ InvoiceStatusToJSONTyped: () => InvoiceStatusToJSONTyped,
1239
+ instanceOfApiError: () => instanceOfApiError,
1240
+ instanceOfCompanyInvoiceResponseData: () => instanceOfCompanyInvoiceResponseData,
1241
+ instanceOfCompanyInvoicesResponseData: () => instanceOfCompanyInvoicesResponseData,
1242
+ instanceOfGetCompanyInvoicesParams: () => instanceOfGetCompanyInvoicesParams,
1243
+ instanceOfGetCompanyInvoicesResponse: () => instanceOfGetCompanyInvoicesResponse,
1244
+ instanceOfInvoiceStatus: () => instanceOfInvoiceStatus
1245
+ });
1246
+ function instanceOfApiError(value) {
1247
+ if (!("error" in value) || value["error"] === void 0) return false;
1248
+ return true;
1249
+ }
1250
+ function ApiErrorFromJSON(json) {
1251
+ return ApiErrorFromJSONTyped(json, false);
1252
+ }
1253
+ function ApiErrorFromJSONTyped(json, ignoreDiscriminator) {
1254
+ if (json == null) {
1255
+ return json;
1256
+ }
1257
+ return {
1258
+ error: json["error"]
1259
+ };
1260
+ }
1261
+ function ApiErrorToJSON(json) {
1262
+ return ApiErrorToJSONTyped(json, false);
1263
+ }
1264
+ function ApiErrorToJSONTyped(value, ignoreDiscriminator = false) {
1265
+ if (value == null) {
1266
+ return value;
1267
+ }
1268
+ return {
1269
+ error: value["error"]
1270
+ };
1271
+ }
1272
+ var InvoiceStatus = {
1273
+ Draft: "draft",
1274
+ Open: "open",
1275
+ Paid: "paid",
1276
+ Uncollectible: "uncollectible",
1277
+ Void: "void"
1278
+ };
1279
+ function instanceOfInvoiceStatus(value) {
1280
+ for (const key in InvoiceStatus) {
1281
+ if (Object.prototype.hasOwnProperty.call(InvoiceStatus, key)) {
1282
+ if (InvoiceStatus[key] === value) {
1283
+ return true;
1284
+ }
1285
+ }
1286
+ }
1287
+ return false;
1288
+ }
1289
+ function InvoiceStatusFromJSON(json) {
1290
+ return InvoiceStatusFromJSONTyped(json, false);
1291
+ }
1292
+ function InvoiceStatusFromJSONTyped(json, ignoreDiscriminator) {
1293
+ return json;
1294
+ }
1295
+ function InvoiceStatusToJSON(value) {
1296
+ return value;
1297
+ }
1298
+ function InvoiceStatusToJSONTyped(value, ignoreDiscriminator) {
1299
+ return value;
1300
+ }
1301
+ function instanceOfCompanyInvoiceResponseData(value) {
1302
+ if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
1303
+ if (!("createdAt" in value) || value["createdAt"] === void 0) return false;
1304
+ if (!("currency" in value) || value["currency"] === void 0) return false;
1305
+ if (!("id" in value) || value["id"] === void 0) return false;
1306
+ return true;
1307
+ }
1308
+ function CompanyInvoiceResponseDataFromJSON(json) {
1309
+ return CompanyInvoiceResponseDataFromJSONTyped(json, false);
1310
+ }
1311
+ function CompanyInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1312
+ if (json == null) {
1313
+ return json;
1314
+ }
1315
+ return {
1316
+ amountDue: json["amount_due"],
1317
+ createdAt: new Date(json["created_at"]),
1318
+ currency: json["currency"],
1319
+ dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
1320
+ id: json["id"],
1321
+ status: json["status"] == null ? void 0 : InvoiceStatusFromJSON(json["status"]),
1322
+ url: json["url"] == null ? void 0 : json["url"]
1323
+ };
1324
+ }
1325
+ function CompanyInvoiceResponseDataToJSON(json) {
1326
+ return CompanyInvoiceResponseDataToJSONTyped(json, false);
1327
+ }
1328
+ function CompanyInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1329
+ if (value == null) {
1330
+ return value;
1331
+ }
1332
+ return {
1333
+ amount_due: value["amountDue"],
1334
+ created_at: value["createdAt"].toISOString(),
1335
+ currency: value["currency"],
1336
+ due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
1337
+ id: value["id"],
1338
+ status: InvoiceStatusToJSON(value["status"]),
1339
+ url: value["url"]
1340
+ };
1341
+ }
1342
+ function instanceOfCompanyInvoicesResponseData(value) {
1343
+ if (!("count" in value) || value["count"] === void 0) return false;
1344
+ if (!("invoices" in value) || value["invoices"] === void 0) return false;
1345
+ return true;
1346
+ }
1347
+ function CompanyInvoicesResponseDataFromJSON(json) {
1348
+ return CompanyInvoicesResponseDataFromJSONTyped(json, false);
1349
+ }
1350
+ function CompanyInvoicesResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1351
+ if (json == null) {
1352
+ return json;
1353
+ }
1354
+ return {
1355
+ count: json["count"],
1356
+ invoices: json["invoices"].map(
1357
+ CompanyInvoiceResponseDataFromJSON
1358
+ )
1359
+ };
1360
+ }
1361
+ function CompanyInvoicesResponseDataToJSON(json) {
1362
+ return CompanyInvoicesResponseDataToJSONTyped(json, false);
1363
+ }
1364
+ function CompanyInvoicesResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1365
+ if (value == null) {
1366
+ return value;
1367
+ }
1368
+ return {
1369
+ count: value["count"],
1370
+ invoices: value["invoices"].map(
1371
+ CompanyInvoiceResponseDataToJSON
1372
+ )
1373
+ };
1374
+ }
1375
+ function instanceOfGetCompanyInvoicesParams(value) {
1376
+ return true;
1377
+ }
1378
+ function GetCompanyInvoicesParamsFromJSON(json) {
1379
+ return GetCompanyInvoicesParamsFromJSONTyped(json, false);
1380
+ }
1381
+ function GetCompanyInvoicesParamsFromJSONTyped(json, ignoreDiscriminator) {
1382
+ if (json == null) {
1383
+ return json;
1384
+ }
1385
+ return {
1386
+ includePending: json["include_pending"] == null ? void 0 : json["include_pending"],
1387
+ limit: json["limit"] == null ? void 0 : json["limit"],
1388
+ offset: json["offset"] == null ? void 0 : json["offset"]
1389
+ };
1390
+ }
1391
+ function GetCompanyInvoicesParamsToJSON(json) {
1392
+ return GetCompanyInvoicesParamsToJSONTyped(json, false);
1393
+ }
1394
+ function GetCompanyInvoicesParamsToJSONTyped(value, ignoreDiscriminator = false) {
1395
+ if (value == null) {
1396
+ return value;
1397
+ }
1398
+ return {
1399
+ include_pending: value["includePending"],
1400
+ limit: value["limit"],
1401
+ offset: value["offset"]
1402
+ };
1403
+ }
1404
+ function instanceOfGetCompanyInvoicesResponse(value) {
1405
+ if (!("data" in value) || value["data"] === void 0) return false;
1406
+ if (!("params" in value) || value["params"] === void 0) return false;
1407
+ return true;
1408
+ }
1409
+ function GetCompanyInvoicesResponseFromJSON(json) {
1410
+ return GetCompanyInvoicesResponseFromJSONTyped(json, false);
1411
+ }
1412
+ function GetCompanyInvoicesResponseFromJSONTyped(json, ignoreDiscriminator) {
1413
+ if (json == null) {
1414
+ return json;
1415
+ }
1416
+ return {
1417
+ data: CompanyInvoicesResponseDataFromJSON(json["data"]),
1418
+ params: GetCompanyInvoicesParamsFromJSON(json["params"])
1419
+ };
1420
+ }
1421
+ function GetCompanyInvoicesResponseToJSON(json) {
1422
+ return GetCompanyInvoicesResponseToJSONTyped(json, false);
1423
+ }
1424
+ function GetCompanyInvoicesResponseToJSONTyped(value, ignoreDiscriminator = false) {
1425
+ if (value == null) {
1426
+ return value;
1427
+ }
1428
+ return {
1429
+ data: CompanyInvoicesResponseDataToJSON(value["data"]),
1430
+ params: GetCompanyInvoicesParamsToJSON(value["params"])
1431
+ };
1432
+ }
1433
+ var DEFAULT_INVOICE_QUERY = {};
1434
+ function normalizeInvoiceQuery(query) {
1435
+ const { includePending, ...rest } = query;
1436
+ return includePending === true ? { ...rest, includePending: true } : rest;
1437
+ }
1438
+ var SchematicApiError = class extends Error {
1439
+ constructor(status, path, body) {
1440
+ super(
1441
+ typeof body === "object" && body !== null && "error" in body ? String(body.error) : `Request to ${path} failed with status ${status}`
1442
+ );
1443
+ this.status = status;
1444
+ this.path = path;
1445
+ this.body = body;
1446
+ this.name = "SchematicApiError";
1447
+ }
1448
+ status;
1449
+ path;
1450
+ body;
1451
+ };
1452
+ var DEFAULT_API_URL = "https://api.schematichq.com";
1453
+ var TOKEN_CACHE_SIZE = 10;
1454
+ function sessionKey(session) {
1455
+ return JSON.stringify([session.company, session.user ?? null]);
1456
+ }
1457
+ var SchematicSession = class {
1458
+ _apiUrl;
1459
+ _headers;
1460
+ _fetch;
1461
+ _session;
1462
+ _tokens = /* @__PURE__ */ new Map();
1463
+ _resolving = /* @__PURE__ */ new Map();
1464
+ /**
1465
+ * Bumped when the session's identity changes, and only then — the object
1466
+ * itself is replaced on every render. Anything asking "is this still the
1467
+ * session I started under?" counts generations rather than comparing.
1468
+ */
1469
+ _generation = 0;
1470
+ _listeners = /* @__PURE__ */ new Set();
1471
+ constructor(options = {}) {
1472
+ this._session = options.session;
1473
+ this._apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
1474
+ this._headers = options.additionalHeaders ?? {};
1475
+ this._fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
1476
+ }
1477
+ get key() {
1478
+ return this._session === null || this._session === void 0 ? void 0 : sessionKey(this._session);
1479
+ }
1480
+ get status() {
1481
+ if (this._session === void 0) {
1482
+ return "pending";
1483
+ }
1484
+ return this._session === null ? "ended" : "active";
1485
+ }
1486
+ /** Only a statement that changes which pair is read counts as a change. */
1487
+ set(session) {
1488
+ if (session === void 0) {
1489
+ return;
1490
+ }
1491
+ const previous = this._session;
1492
+ this._session = session;
1493
+ if (session === null) {
1494
+ if (previous === null) {
1495
+ return;
1496
+ }
1497
+ this._tokens.clear();
1498
+ this._resolving.clear();
1499
+ this._generation += 1;
1500
+ this._emit({ type: "ended" });
1501
+ return;
1502
+ }
1503
+ if (previous !== null && previous !== void 0) {
1504
+ if (previous.company === session.company && (previous.user ?? null) === (session.user ?? null)) {
1505
+ return;
1506
+ }
1507
+ this._generation += 1;
1508
+ this._emit({ type: "changed" });
1509
+ return;
1510
+ }
1511
+ this._generation += 1;
1512
+ this._emit({ type: "started" });
1513
+ }
1514
+ onChange(listener) {
1515
+ this._listeners.add(listener);
1516
+ return () => {
1517
+ this._listeners.delete(listener);
1518
+ };
1519
+ }
1520
+ _emit(event) {
1521
+ for (const listener of this._listeners) {
1522
+ listener(event);
1523
+ }
1524
+ }
1525
+ _cached(key) {
1526
+ const cached = this._tokens.get(key);
1527
+ if (cached === void 0) {
1528
+ return void 0;
1529
+ }
1530
+ if (cached.expiresAt !== void 0 && cached.expiresAt.getTime() <= Date.now()) {
1531
+ this._tokens.delete(key);
1532
+ return void 0;
1533
+ }
1534
+ this._tokens.delete(key);
1535
+ this._tokens.set(key, cached);
1536
+ return cached;
1537
+ }
1538
+ _cache(key, resolved) {
1539
+ this._tokens.delete(key);
1540
+ this._tokens.set(key, resolved);
1541
+ while (this._tokens.size > TOKEN_CACHE_SIZE) {
1542
+ const oldest = this._tokens.keys().next();
1543
+ if (oldest.done === true) {
1544
+ break;
1545
+ }
1546
+ this._tokens.delete(oldest.value);
1547
+ }
1548
+ }
1549
+ /**
1550
+ * The credential for a session, minted if this one is not held. `force`
1551
+ * retires what is held first: the caller is a request the API has just
1552
+ * rejected.
1553
+ */
1554
+ resolveToken(session, force) {
1555
+ const { token } = session;
1556
+ if (typeof token === "string") {
1557
+ return Promise.resolve(token);
1558
+ }
1559
+ const key = sessionKey(session);
1560
+ if (!force) {
1561
+ const cached = this._cached(key);
1562
+ if (cached !== void 0) {
1563
+ return Promise.resolve(cached.token);
1564
+ }
1565
+ } else {
1566
+ this._tokens.delete(key);
1567
+ }
1568
+ const inflight = this._resolving.get(key);
1569
+ if (inflight !== void 0 && inflight.sessionGeneration === this._generation && (!force || inflight.forced)) {
1570
+ return inflight.promise;
1571
+ }
1572
+ const provider = token;
1573
+ const sessionGeneration = this._generation;
1574
+ const owns = () => this._resolving.get(key)?.promise === promise;
1575
+ const promise = Promise.resolve().then(() => provider()).then((result) => {
1576
+ const { resolved, stamped } = asResolvedToken(result, session);
1577
+ if (owns() && (this._generation === sessionGeneration || stamped)) {
1578
+ this._cache(key, resolved);
1579
+ }
1580
+ return resolved.token;
1581
+ }).finally(() => {
1582
+ if (owns()) {
1583
+ this._resolving.delete(key);
1584
+ }
1585
+ });
1586
+ this._resolving.set(key, { promise, forced: force, sessionGeneration });
1587
+ return promise;
1588
+ }
1589
+ /**
1590
+ * Sends a request under the active session's credential, refreshing once
1591
+ * and retrying if the API rejects it. Rejects rather than answering when
1592
+ * the session changes while the request is in flight: the rows would
1593
+ * otherwise come back as the answer to a question asked for another pair.
1594
+ */
1595
+ async request(path, options = {}) {
1596
+ const { method = "GET", body } = options;
1597
+ const send = async (credential2) => this._fetch(`${this._apiUrl}${path}`, {
1598
+ method,
1599
+ headers: {
1600
+ "Accept": "application/json",
1601
+ ...body === void 0 ? {} : { "Content-Type": "application/json" },
1602
+ ...this._headers,
1603
+ "X-Schematic-Api-Key": credential2
1604
+ },
1605
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
1606
+ });
1607
+ const session = this._session;
1608
+ if (session === null) {
1609
+ throw new Error("There is no session to read data for.");
1610
+ }
1611
+ if (session === void 0) {
1612
+ throw new Error("A session is required to read data.");
1613
+ }
1614
+ const provider = session.token;
1615
+ const generation = this._generation;
1616
+ const stillOurs = async (response2) => {
1617
+ if (this._generation === generation) {
1618
+ return;
1619
+ }
1620
+ if (response2 !== void 0) {
1621
+ await discardBody(response2);
1622
+ }
1623
+ throw new Error("The session changed while this request was in flight.");
1624
+ };
1625
+ const credential = await this.resolveToken(session, false);
1626
+ if (this._generation !== generation) {
1627
+ throw new Error("The session changed before this request was sent.");
1628
+ }
1629
+ let response = await send(credential);
1630
+ await stillOurs(response);
1631
+ if (response.status === 401 && typeof provider === "function" && this._generation === generation) {
1632
+ const status = response.status;
1633
+ const rejected = await readBody(response);
1634
+ let retried = false;
1635
+ const current = this._session;
1636
+ if (this._generation === generation && current !== null && current !== void 0) {
1637
+ const refreshed = await this.resolveToken(current, true);
1638
+ if (this._generation === generation) {
1639
+ response = await send(refreshed);
1640
+ await stillOurs(response);
1641
+ retried = true;
1642
+ }
1643
+ }
1644
+ if (!retried) {
1645
+ throw new SchematicApiError(status, path, rejected);
1646
+ }
1647
+ }
1648
+ const parsed = await readBody(response);
1649
+ await stillOurs();
1650
+ if (!response.ok) {
1651
+ throw new SchematicApiError(response.status, path, parsed);
1652
+ }
1653
+ return parsed;
1654
+ }
1655
+ };
1656
+ function asResolvedToken(result, session) {
1657
+ if (typeof result === "string") {
1658
+ return { resolved: { token: result }, stamped: false };
1659
+ }
1660
+ const token = result?.token;
1661
+ if (typeof token !== "string" || token === "") {
1662
+ throw new Error("The access token provider did not return a token.");
1663
+ }
1664
+ if (result.company !== void 0 && result.company !== session.company || result.user !== void 0 && session.user !== void 0 && result.user !== session.user) {
1665
+ throw new Error(
1666
+ "The access token provider returned a token for a different session."
1667
+ );
1668
+ }
1669
+ const stamped = result.company !== void 0 && (session.user === void 0 || result.user !== void 0);
1670
+ return { resolved: { token, expiresAt: asDate(result.expiresAt) }, stamped };
1671
+ }
1672
+ function asDate(value) {
1673
+ if (value === void 0 || value === null) {
1674
+ return void 0;
1675
+ }
1676
+ const date = value instanceof Date ? value : new Date(value);
1677
+ return Number.isNaN(date.getTime()) ? void 0 : date;
1678
+ }
1679
+ async function discardBody(response) {
1680
+ try {
1681
+ await response.body?.cancel();
1682
+ } catch {
1683
+ }
1684
+ }
1685
+ async function readBody(response) {
1686
+ const text = await response.text();
1687
+ if (text === "") {
1688
+ return null;
1689
+ }
1690
+ try {
1691
+ return JSON.parse(text);
1692
+ } catch {
1693
+ return text;
1694
+ }
1695
+ }
1696
+ var INVOICE_PAGE_SIZE = 12;
1697
+ var INVOICE_MAX_PAGE_SIZE = 250;
1698
+ var SchematicBillingClient = class {
1699
+ /**
1700
+ * Public so a second client over the same surface can be constructed on
1701
+ * this one rather than minting tokens of its own.
1702
+ */
1703
+ session;
1704
+ constructor(options = {}) {
1705
+ this.session = options instanceof SchematicSession ? options : new SchematicSession(options);
1706
+ }
1707
+ get sessionKey() {
1708
+ return this.session.key;
1709
+ }
1710
+ get sessionStatus() {
1711
+ return this.session.status;
1712
+ }
1713
+ setSession(session) {
1714
+ this.session.set(session);
1715
+ }
1716
+ onSessionChange(listener) {
1717
+ return this.session.onChange(listener);
1718
+ }
1719
+ fetchInvoices(params) {
1720
+ const query = new URLSearchParams({
1721
+ limit: String(Math.min(params.limit, INVOICE_MAX_PAGE_SIZE)),
1722
+ offset: String(params.offset)
1723
+ });
1724
+ if (params.includePending !== void 0) {
1725
+ query.set("include_pending", String(params.includePending));
1726
+ }
1727
+ const path = `/company/invoices?${query}`;
1728
+ return this.session.request(path).then((body) => {
1729
+ if (body === null || typeof body !== "object" || !("data" in body)) {
1730
+ throw new Error(`Malformed response from ${path}`);
1731
+ }
1732
+ const data = body.data;
1733
+ if (data == null || data.invoices == null) {
1734
+ return { invoices: [], count: 0 };
1735
+ }
1736
+ const decoded = GetCompanyInvoicesResponseFromJSON(body).data;
1737
+ return { invoices: decoded.invoices, count: decoded.count };
1738
+ });
1739
+ }
1740
+ };
1179
1741
  var anonymousIdKey = "schematicId";
1180
1742
  var flagStateCachePrefix = "schematicCache";
1181
1743
  var flagStateCacheMaxContexts = 10;
1182
1744
  var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
1183
1745
  var emptyCreditBalances = Object.freeze({});
1184
1746
  var Schematic = class {
1185
- additionalHeaders = {};
1747
+ _additionalHeaders = {};
1186
1748
  apiKey;
1187
- apiUrl = "https://api.schematichq.com";
1749
+ _apiUrl = "https://api.schematichq.com";
1188
1750
  conn = null;
1189
1751
  context = {};
1190
1752
  debugEnabled = false;
@@ -1264,7 +1826,7 @@ var Schematic = class {
1264
1826
  if (this.offlineEnabled) {
1265
1827
  this.setIsPending(false);
1266
1828
  }
1267
- this.additionalHeaders = {
1829
+ this._additionalHeaders = {
1268
1830
  "X-Schematic-Client-Version": `schematic-js@${version}`,
1269
1831
  ...options?.additionalHeaders ?? {}
1270
1832
  };
@@ -1280,7 +1842,7 @@ var Schematic = class {
1280
1842
  }
1281
1843
  this.hydrateFlagStateFromCache();
1282
1844
  if (options?.apiUrl !== void 0) {
1283
- this.apiUrl = options.apiUrl;
1845
+ this._apiUrl = options.apiUrl;
1284
1846
  }
1285
1847
  if (options?.eventUrl !== void 0) {
1286
1848
  this.eventUrl = options.eventUrl;
@@ -1345,6 +1907,12 @@ var Schematic = class {
1345
1907
  this.debug("Initialized with debug mode enabled");
1346
1908
  }
1347
1909
  }
1910
+ get apiUrl() {
1911
+ return this._apiUrl;
1912
+ }
1913
+ get additionalHeaders() {
1914
+ return { ...this._additionalHeaders };
1915
+ }
1348
1916
  /**
1349
1917
  * Resolve fallback value according to priority order:
1350
1918
  * 1. Callsite fallback value (if provided)
@@ -1430,11 +1998,11 @@ var Schematic = class {
1430
1998
  return resolvedFallbackResult.value;
1431
1999
  }
1432
2000
  if (!this.useWebSocket) {
1433
- const requestUrl = `${this.apiUrl}/flags/${key}/check`;
2001
+ const requestUrl = `${this._apiUrl}/flags/${key}/check`;
1434
2002
  return fetch(requestUrl, {
1435
2003
  method: "POST",
1436
2004
  headers: {
1437
- ...this.additionalHeaders ?? {},
2005
+ ...this._additionalHeaders ?? {},
1438
2006
  "Content-Type": "application/json;charset=UTF-8",
1439
2007
  "X-Schematic-Api-Key": this.apiKey
1440
2008
  },
@@ -1637,12 +2205,12 @@ var Schematic = class {
1637
2205
  this.debug(`checkFlags offline result: returning empty object`);
1638
2206
  return {};
1639
2207
  }
1640
- const requestUrl = `${this.apiUrl}/flags/check`;
2208
+ const requestUrl = `${this._apiUrl}/flags/check`;
1641
2209
  const requestBody = JSON.stringify(context);
1642
2210
  return fetch(requestUrl, {
1643
2211
  method: "POST",
1644
2212
  headers: {
1645
- ...this.additionalHeaders ?? {},
2213
+ ...this._additionalHeaders ?? {},
1646
2214
  "Content-Type": "application/json;charset=UTF-8",
1647
2215
  "X-Schematic-Api-Key": this.apiKey
1648
2216
  },
@@ -2189,7 +2757,7 @@ var Schematic = class {
2189
2757
  const response = await fetch(captureUrl, {
2190
2758
  method: "POST",
2191
2759
  headers: {
2192
- ...this.additionalHeaders ?? {},
2760
+ ...this._additionalHeaders ?? {},
2193
2761
  "Content-Type": "application/json;charset=UTF-8"
2194
2762
  },
2195
2763
  body: payload
@@ -2685,7 +3253,7 @@ var Schematic = class {
2685
3253
  }
2686
3254
  });
2687
3255
  this.currentWebSocket = socket;
2688
- const clientVersion = this.additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
3256
+ const clientVersion = this._additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
2689
3257
  const messagePayload = {
2690
3258
  apiKey: this.apiKey,
2691
3259
  clientVersion,
@@ -2919,23 +3487,853 @@ var notifyCreditBalanceListener = (listener, value) => {
2919
3487
  };
2920
3488
 
2921
3489
  // src/context/schematic.tsx
2922
- var import_react = __toESM(require("react"));
3490
+ var import_react5 = __toESM(require("react"));
3491
+
3492
+ // src/billing/contract/index.ts
3493
+ function normalizeInvoiceQuery2(query) {
3494
+ return normalizeInvoiceQuery(query).includePending === true ? { includePending: true } : {};
3495
+ }
3496
+
3497
+ // src/billing/store.ts
3498
+ var Resource = class {
3499
+ constructor(_fetcher, initial, _readiness = () => "ready") {
3500
+ this._fetcher = _fetcher;
3501
+ this._readiness = _readiness;
3502
+ this._loaded = initial !== void 0;
3503
+ this._snapshot = {
3504
+ data: initial,
3505
+ error: void 0,
3506
+ isPending: initial === void 0
3507
+ };
3508
+ }
3509
+ _fetcher;
3510
+ _readiness;
3511
+ _snapshot;
3512
+ _listeners = /* @__PURE__ */ new Set();
3513
+ _inflight;
3514
+ _extending;
3515
+ /** A refetch asked for mid-load; runs once that load lands. */
3516
+ _queued;
3517
+ _generation = 0;
3518
+ _loaded = false;
3519
+ get snapshot() {
3520
+ return this._snapshot;
3521
+ }
3522
+ get subscriberCount() {
3523
+ return this._listeners.size;
3524
+ }
3525
+ getSnapshot = () => this._snapshot;
3526
+ subscribe = (listener) => {
3527
+ this._listeners.add(listener);
3528
+ if (!this._loaded && this._inflight === void 0 && this._snapshot.error === void 0) {
3529
+ void this.load();
3530
+ }
3531
+ return () => {
3532
+ this._listeners.delete(listener);
3533
+ };
3534
+ };
3535
+ load() {
3536
+ if (this._inflight !== void 0) {
3537
+ return this._inflight;
3538
+ }
3539
+ const readiness = this._readiness();
3540
+ if (readiness !== "ready") {
3541
+ if (readiness === "never" && this._snapshot.isPending) {
3542
+ this._set({ ...this._snapshot, isPending: false });
3543
+ }
3544
+ return Promise.resolve();
3545
+ }
3546
+ const generation = ++this._generation;
3547
+ this._set({ ...this._snapshot, error: void 0, isPending: true });
3548
+ const run = Promise.resolve().then(() => this._fetcher()).then(
3549
+ (data) => {
3550
+ if (generation !== this._generation) return;
3551
+ this._loaded = true;
3552
+ this._set({ data, error: void 0, isPending: false });
3553
+ },
3554
+ (cause) => {
3555
+ if (generation !== this._generation) return;
3556
+ const error = cause instanceof Error ? cause : new Error(String(cause));
3557
+ this._set({ ...this._snapshot, error, isPending: false });
3558
+ }
3559
+ ).finally(() => {
3560
+ if (generation === this._generation) {
3561
+ this._inflight = void 0;
3562
+ }
3563
+ });
3564
+ this._inflight = run;
3565
+ return run;
3566
+ }
3567
+ /**
3568
+ * Reloads; `data` holds its current value until the response lands. Asked
3569
+ * for mid-load, it runs again after: that request was built before
3570
+ * whatever prompted this one. Refetches queued on one load share the
3571
+ * re-run; a reset, seed, or clear in the meantime supersedes it.
3572
+ */
3573
+ refetch() {
3574
+ if (this._inflight === void 0) {
3575
+ return this.load();
3576
+ }
3577
+ if (this._queued === void 0) {
3578
+ const generation = this._generation;
3579
+ const queued = this._inflight.then(() => {
3580
+ if (this._queued === queued) {
3581
+ this._queued = void 0;
3582
+ }
3583
+ if (generation !== this._generation) {
3584
+ return;
3585
+ }
3586
+ return this.load();
3587
+ });
3588
+ this._queued = queued;
3589
+ }
3590
+ return this._queued;
3591
+ }
3592
+ /**
3593
+ * Pages: `fetcher` receives the current data and returns what replaces it.
3594
+ * Never rejects — a caller that wants the failure reads `snapshot.error`,
3595
+ * and `data` keeps what was already fetched.
3596
+ *
3597
+ * A load already in flight wins: it is about to refresh the window this
3598
+ * would have appended to.
3599
+ */
3600
+ extend(fetcher) {
3601
+ const current = this._snapshot.data;
3602
+ if (current === void 0) {
3603
+ return Promise.resolve();
3604
+ }
3605
+ if (this._readiness() !== "ready") {
3606
+ return Promise.resolve();
3607
+ }
3608
+ if (this._extending !== void 0) {
3609
+ return this._extending;
3610
+ }
3611
+ if (this._inflight !== void 0) {
3612
+ return this._inflight;
3613
+ }
3614
+ const generation = ++this._generation;
3615
+ this._set({ ...this._snapshot, error: void 0, isPending: true });
3616
+ const run = Promise.resolve().then(() => fetcher(current)).then(
3617
+ (data) => {
3618
+ if (generation !== this._generation) return;
3619
+ this._set({ data, error: void 0, isPending: false });
3620
+ },
3621
+ (cause) => {
3622
+ if (generation !== this._generation) return;
3623
+ const error = cause instanceof Error ? cause : new Error(String(cause));
3624
+ this._set({ ...this._snapshot, error, isPending: false });
3625
+ }
3626
+ ).finally(() => {
3627
+ if (this._extending === run) {
3628
+ this._extending = void 0;
3629
+ }
3630
+ });
3631
+ this._extending = run;
3632
+ return run;
3633
+ }
3634
+ seed(data) {
3635
+ this._generation++;
3636
+ this._inflight = void 0;
3637
+ this._extending = void 0;
3638
+ this._queued = void 0;
3639
+ this._loaded = true;
3640
+ this._set({ data, error: void 0, isPending: false });
3641
+ }
3642
+ update(fn) {
3643
+ if (this._snapshot.data === void 0) return;
3644
+ this._generation++;
3645
+ this._inflight = void 0;
3646
+ this._extending = void 0;
3647
+ this._queued = void 0;
3648
+ this._set({ ...this._snapshot, data: fn(this._snapshot.data) });
3649
+ }
3650
+ /**
3651
+ * Forgets everything and stays empty — no data, no error, not pending.
3652
+ * What a resource holds when there is no session to hold it for: a session
3653
+ * ending is not a failure and must not surface as one.
3654
+ */
3655
+ clear() {
3656
+ this._generation++;
3657
+ this._inflight = void 0;
3658
+ this._extending = void 0;
3659
+ this._queued = void 0;
3660
+ this._loaded = false;
3661
+ this._set({ data: void 0, error: void 0, isPending: false });
3662
+ }
3663
+ /** Forgets everything; reloads immediately if anyone is subscribed. */
3664
+ reset() {
3665
+ this._generation++;
3666
+ this._inflight = void 0;
3667
+ this._extending = void 0;
3668
+ this._queued = void 0;
3669
+ this._loaded = false;
3670
+ const readiness = this._readiness();
3671
+ const willLoad = this._listeners.size > 0 && readiness === "ready";
3672
+ this._set({
3673
+ data: void 0,
3674
+ error: void 0,
3675
+ isPending: willLoad || readiness === "waiting"
3676
+ });
3677
+ if (willLoad) {
3678
+ void this.load();
3679
+ }
3680
+ }
3681
+ _set(next) {
3682
+ this._snapshot = next;
3683
+ for (const listener of this._listeners) {
3684
+ listener();
3685
+ }
3686
+ }
3687
+ };
3688
+ function hashKey(params) {
3689
+ return JSON.stringify(canonical(params));
3690
+ }
3691
+ function canonical(value) {
3692
+ if (Array.isArray(value)) {
3693
+ return value.map(canonical);
3694
+ }
3695
+ if (value instanceof Date) {
3696
+ const time = value.getTime();
3697
+ return Number.isNaN(time) ? "Invalid Date" : value.toISOString();
3698
+ }
3699
+ if (value !== null && typeof value === "object") {
3700
+ const out = {};
3701
+ for (const key of Object.keys(value).sort()) {
3702
+ const v = value[key];
3703
+ if (v !== void 0) {
3704
+ out[key] = canonical(v);
3705
+ }
3706
+ }
3707
+ return out;
3708
+ }
3709
+ return value ?? null;
3710
+ }
3711
+ var DEFAULT_EVICTION = { maxIdle: 4 };
3712
+ var KeyedResource = class {
3713
+ constructor(_fetcher, options = {}) {
3714
+ this._fetcher = _fetcher;
3715
+ this._readiness = options.readiness ?? (() => "ready");
3716
+ this._hash = options.hash ?? hashKey;
3717
+ this._eviction = {
3718
+ maxIdle: options.eviction?.maxIdle ?? DEFAULT_EVICTION.maxIdle
3719
+ };
3720
+ }
3721
+ _fetcher;
3722
+ _entries = /* @__PURE__ */ new Map();
3723
+ _hash;
3724
+ _eviction;
3725
+ _readiness;
3726
+ hash(params) {
3727
+ return this._hash(params);
3728
+ }
3729
+ get size() {
3730
+ return this._entries.size;
3731
+ }
3732
+ entries() {
3733
+ return Array.from(this._entries, ([key, e]) => ({ key, ...e }));
3734
+ }
3735
+ get(params) {
3736
+ const key = this._hash(params);
3737
+ const existing = this._entries.get(key);
3738
+ if (existing !== void 0) {
3739
+ this._entries.delete(key);
3740
+ this._entries.set(key, existing);
3741
+ return existing.resource;
3742
+ }
3743
+ const resource = new Resource(
3744
+ () => this._fetcher(params, resource.snapshot.data),
3745
+ void 0,
3746
+ this._readiness
3747
+ );
3748
+ this._entries.set(key, { params, resource });
3749
+ return resource;
3750
+ }
3751
+ has(params) {
3752
+ return this._entries.has(this._hash(params));
3753
+ }
3754
+ subscribe(params, listener) {
3755
+ const resource = this.get(params);
3756
+ const unsubscribe = resource.subscribe(listener);
3757
+ return () => {
3758
+ unsubscribe();
3759
+ this._evict();
3760
+ };
3761
+ }
3762
+ seed(params, data) {
3763
+ this.get(params).seed(data);
3764
+ }
3765
+ evict(params) {
3766
+ return this._entries.delete(this._hash(params));
3767
+ }
3768
+ resetAll() {
3769
+ for (const [key, { resource }] of Array.from(this._entries)) {
3770
+ if (resource.subscriberCount === 0) {
3771
+ this._entries.delete(key);
3772
+ } else {
3773
+ resource.reset();
3774
+ }
3775
+ }
3776
+ }
3777
+ resumeAll() {
3778
+ for (const { resource } of this._entries.values()) {
3779
+ if (resource.subscriberCount === 0) {
3780
+ continue;
3781
+ }
3782
+ const { data, error } = resource.snapshot;
3783
+ if (data === void 0 || error !== void 0) {
3784
+ void resource.load();
3785
+ }
3786
+ }
3787
+ }
3788
+ clearAll() {
3789
+ for (const [key, { resource }] of Array.from(this._entries)) {
3790
+ if (resource.subscriberCount === 0) {
3791
+ this._entries.delete(key);
3792
+ } else {
3793
+ resource.clear();
3794
+ }
3795
+ }
3796
+ }
3797
+ invalidateAll() {
3798
+ for (const { resource } of this._entries.values()) {
3799
+ if (resource.snapshot.data !== void 0) {
3800
+ void resource.refetch();
3801
+ }
3802
+ }
3803
+ }
3804
+ _evict() {
3805
+ const idle = Array.from(this._entries).filter(
3806
+ ([, e]) => e.resource.subscriberCount === 0
3807
+ );
3808
+ let excess = idle.length - this._eviction.maxIdle;
3809
+ for (const [key] of idle) {
3810
+ if (excess <= 0) break;
3811
+ this._entries.delete(key);
3812
+ excess -= 1;
3813
+ }
3814
+ }
3815
+ };
3816
+
3817
+ // src/billing/client.ts
3818
+ function claimOf(client) {
3819
+ return { status: client.sessionStatus, key: client.sessionKey };
3820
+ }
3821
+ function claimFrom(session) {
3822
+ if (session === void 0) {
3823
+ return void 0;
3824
+ }
3825
+ return session === null ? { status: "ended", key: void 0 } : { status: "active", key: sessionKey(session) };
3826
+ }
3827
+ function judgeSeed(seedKey, claim) {
3828
+ if (claim.status === "ended") {
3829
+ return "drop";
3830
+ }
3831
+ if (seedKey === void 0) {
3832
+ return "adopt";
3833
+ }
3834
+ if (claim.status === "pending") {
3835
+ return "hold";
3836
+ }
3837
+ return seedKey === claim.key ? "adopt" : "drop";
3838
+ }
3839
+ var READINESS = {
3840
+ pending: "waiting",
3841
+ active: "ready",
3842
+ ended: "never"
3843
+ };
3844
+ var BillingStore = class {
3845
+ constructor(_client, initialData = {}, options = {}) {
3846
+ this._client = _client;
3847
+ this._pageSize = options.pageSize ?? INVOICE_PAGE_SIZE;
3848
+ this.invoices = new KeyedResource(
3849
+ (query, current) => this._reloadWindow(
3850
+ query,
3851
+ Math.max(this._pageSize, current?.invoices.length ?? 0)
3852
+ ),
3853
+ // Waiting until connected; then a session still pending stays
3854
+ // pending, and one that has ended settles empty rather than recording
3855
+ // the client's refusal as an error.
3856
+ {
3857
+ readiness: () => this._connected ? READINESS[this._client.sessionStatus] : "waiting"
3858
+ }
3859
+ );
3860
+ if (initialData.invoices !== void 0) {
3861
+ this._held = {
3862
+ // Normalized the way the hook normalizes, or the caller asking for
3863
+ // it fetches the same page again.
3864
+ params: normalizeInvoiceQuery2(
3865
+ initialData.params?.invoices ?? DEFAULT_INVOICE_QUERY
3866
+ ),
3867
+ data: initialData.invoices,
3868
+ key: initialData.sessionKey
3869
+ };
3870
+ this._settleSeed(claimFrom(options.session) ?? claimOf(this._client));
3871
+ }
3872
+ }
3873
+ _client;
3874
+ invoices;
3875
+ _pageSize;
3876
+ _unsubscribe;
3877
+ _connected = false;
3878
+ _seeded = false;
3879
+ /** The session that prefetch was for, where it said. */
3880
+ _seedKey;
3881
+ /** A stamped prefetch waiting for a session to check it against. */
3882
+ _held;
3883
+ /**
3884
+ * Not done in the constructor: the provider arms it from an effect, and
3885
+ * React runs an effect, its cleanup, then the effect again under
3886
+ * StrictMode. A subscription made once at construction is torn down by
3887
+ * that cleanup and never comes back, leaving the store deaf to every
3888
+ * session change for the rest of the page.
3889
+ *
3890
+ * Also what opens the store: subscribers who arrived first have been
3891
+ * waiting, and this is the moment the session is known to be installed.
3892
+ */
3893
+ connect() {
3894
+ this._unsubscribe?.();
3895
+ const unsubscribe = this._client.onSessionChange?.((event) => {
3896
+ if (event.type === "ended") {
3897
+ this._held = void 0;
3898
+ this._seeded = false;
3899
+ this.clearAll();
3900
+ } else if (event.type === "changed") {
3901
+ this._held = void 0;
3902
+ this._seeded = false;
3903
+ this.resetAll();
3904
+ } else {
3905
+ this._onStarted();
3906
+ }
3907
+ });
3908
+ this._unsubscribe = unsubscribe;
3909
+ if (!this._connected) {
3910
+ this._connected = true;
3911
+ this._settleSeed(claimOf(this._client));
3912
+ this.resumeAll();
3913
+ }
3914
+ return () => {
3915
+ unsubscribe?.();
3916
+ if (this._unsubscribe === unsubscribe) {
3917
+ this._unsubscribe = void 0;
3918
+ }
3919
+ };
3920
+ }
3921
+ _onStarted() {
3922
+ const claim = claimOf(this._client);
3923
+ this._settleSeed(claim);
3924
+ if (this._seeded && judgeSeed(this._seedKey, claim) !== "adopt") {
3925
+ this._seeded = false;
3926
+ this.resetAll();
3927
+ return;
3928
+ }
3929
+ this._seeded = false;
3930
+ this.resumeAll();
3931
+ }
3932
+ /** Adopts, keeps holding, or drops the prefetch, by what `claim` says. */
3933
+ _settleSeed(claim) {
3934
+ const held = this._held;
3935
+ if (held === void 0) {
3936
+ return;
3937
+ }
3938
+ const verdict = judgeSeed(held.key, claim);
3939
+ if (verdict === "hold") {
3940
+ return;
3941
+ }
3942
+ this._held = void 0;
3943
+ if (verdict === "adopt") {
3944
+ this.invoices.seed(held.params, held.data);
3945
+ this._seedKey = held.key;
3946
+ this._seeded = true;
3947
+ }
3948
+ }
3949
+ resource(name) {
3950
+ return this[name];
3951
+ }
3952
+ /** Forgets every resource; subscribed ones reload, idle ones are dropped. */
3953
+ resetAll() {
3954
+ for (const name of RESOURCE_NAMES) {
3955
+ this[name].resetAll();
3956
+ }
3957
+ }
3958
+ /** Forgets every resource and leaves them empty; nothing reloads. */
3959
+ clearAll() {
3960
+ for (const name of RESOURCE_NAMES) {
3961
+ this[name].clearAll();
3962
+ }
3963
+ }
3964
+ /** Loads every resource that is subscribed and has nothing yet. */
3965
+ resumeAll() {
3966
+ for (const name of RESOURCE_NAMES) {
3967
+ this[name].resumeAll();
3968
+ }
3969
+ }
3970
+ /** Reloads every resource that has been loaded, keeping its current data. */
3971
+ invalidateAll() {
3972
+ for (const name of RESOURCE_NAMES) {
3973
+ this[name].invalidateAll();
3974
+ }
3975
+ }
3976
+ /**
3977
+ * Appends the next page to the invoices list for `query`, when there is
3978
+ * one. A failure records the error on the resource and keeps the rows
3979
+ * already fetched; the returned promise never rejects.
3980
+ */
3981
+ loadMoreInvoices(query = DEFAULT_INVOICE_QUERY) {
3982
+ const resource = this.invoices.get(normalizeInvoiceQuery2(query));
3983
+ if (resource.snapshot.data?.hasMore !== true) {
3984
+ return Promise.resolve();
3985
+ }
3986
+ return resource.extend(async (current) => {
3987
+ const page = await this._fetchInvoices(
3988
+ normalizeInvoiceQuery2(query),
3989
+ current.invoices.length,
3990
+ this._pageSize
3991
+ );
3992
+ const invoices = [...current.invoices, ...page.invoices];
3993
+ return {
3994
+ invoices,
3995
+ count: page.count,
3996
+ // From the count the page came back with, not the one the list was
3997
+ // built on: an invoice finalized between the two requests changes
3998
+ // what is left to load. An empty page ends the list whatever the
3999
+ // count says — the rows and the count are two queries, and a count
4000
+ // that outruns the rows would otherwise leave `hasMore` true for
4001
+ // good, with every further page fetching nothing.
4002
+ hasMore: page.invoices.length > 0 && invoices.length < page.count
4003
+ };
4004
+ });
4005
+ }
4006
+ dispose() {
4007
+ this._unsubscribe?.();
4008
+ }
4009
+ /**
4010
+ * Re-reads the window already loaded, in as many requests as the API's
4011
+ * page cap needs. A window paged past that cap still comes back whole:
4012
+ * asking for it in one request would be a 400, and asking for only the
4013
+ * first page would drop the rest.
4014
+ */
4015
+ async _reloadWindow(query, window2) {
4016
+ const invoices = [];
4017
+ let count = 0;
4018
+ while (invoices.length < window2) {
4019
+ const page = await this._fetchInvoices(
4020
+ query,
4021
+ invoices.length,
4022
+ Math.min(INVOICE_MAX_PAGE_SIZE, window2 - invoices.length)
4023
+ );
4024
+ count = page.count;
4025
+ invoices.push(...page.invoices);
4026
+ if (page.invoices.length === 0 || invoices.length >= count) {
4027
+ break;
4028
+ }
4029
+ }
4030
+ return {
4031
+ invoices,
4032
+ count,
4033
+ hasMore: invoices.length > 0 && invoices.length < count
4034
+ };
4035
+ }
4036
+ /**
4037
+ * Returns what the server said and nothing more: whether there is more to
4038
+ * load depends on the whole window, which only the caller assembling it
4039
+ * knows — `_reloadWindow` across its requests, and `loadMoreInvoices`
4040
+ * across the rows already loaded.
4041
+ */
4042
+ _fetchInvoices(query, offset, limit) {
4043
+ return this._client.fetchInvoices({ ...query, limit, offset });
4044
+ }
4045
+ };
4046
+ var RESOURCE_NAMES = ["invoices"];
4047
+
4048
+ // src/billing/context.tsx
4049
+ var import_react2 = require("react");
4050
+
4051
+ // src/i18n/context.tsx
4052
+ var import_react = require("react");
4053
+ var import_jsx_runtime = require("react/jsx-runtime");
4054
+ var EMPTY = Object.freeze({});
4055
+ var SchematicI18nContext = (0, import_react.createContext)(EMPTY);
4056
+ function SchematicI18nProvider({
4057
+ children,
4058
+ locale,
4059
+ onMissingString,
4060
+ strings,
4061
+ translate
4062
+ }) {
4063
+ const parent = (0, import_react.useContext)(SchematicI18nContext);
4064
+ const value = (0, import_react.useMemo)(
4065
+ () => ({
4066
+ locale: locale ?? parent.locale,
4067
+ translate: translate ?? parent.translate,
4068
+ strings: strings === void 0 ? parent.strings : { ...parent.strings, ...strings },
4069
+ onMissingString: onMissingString ?? parent.onMissingString
4070
+ }),
4071
+ [locale, onMissingString, parent, strings, translate]
4072
+ );
4073
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchematicI18nContext.Provider, { value, children });
4074
+ }
4075
+ function useSchematicI18n() {
4076
+ return (0, import_react.useContext)(SchematicI18nContext);
4077
+ }
4078
+ function useSchematicLocale() {
4079
+ return (0, import_react.useContext)(SchematicI18nContext).locale;
4080
+ }
4081
+ function useSchematicTranslate() {
4082
+ return (0, import_react.useContext)(SchematicI18nContext).translate;
4083
+ }
4084
+ function useSchematicStrings() {
4085
+ return (0, import_react.useContext)(SchematicI18nContext).strings;
4086
+ }
4087
+
4088
+ // src/billing/context.tsx
4089
+ var import_jsx_runtime2 = require("react/jsx-runtime");
4090
+ var BillingDataContext = (0, import_react2.createContext)(
4091
+ void 0
4092
+ );
4093
+ var MISSING_BILLING_SOURCE_MESSAGE = "Schematic billing hooks need a SchematicProvider with a session, billingClient, or initialData, or a BillingDataProvider.";
4094
+ var missingSourceError = new Error(MISSING_BILLING_SOURCE_MESSAGE);
4095
+ var missingHandle = {
4096
+ data: void 0,
4097
+ error: missingSourceError,
4098
+ isPending: false,
4099
+ refetch: () => {
4100
+ }
4101
+ };
4102
+ var missingBillingSource = {
4103
+ subscribe: () => () => {
4104
+ },
4105
+ handle: () => missingHandle,
4106
+ loadMoreInvoices: () => Promise.resolve(),
4107
+ invalidateAll: () => {
4108
+ }
4109
+ };
4110
+ function useBillingDataSource() {
4111
+ return (0, import_react2.useContext)(BillingDataContext) ?? missingBillingSource;
4112
+ }
4113
+ function BillingDataProvider({
4114
+ children,
4115
+ data,
4116
+ locale,
4117
+ onLoadMoreInvoices,
4118
+ onMissingString,
4119
+ onRefetch,
4120
+ status,
4121
+ strings,
4122
+ translate
4123
+ }) {
4124
+ const source = (0, import_react2.useMemo)(() => {
4125
+ const handles = /* @__PURE__ */ new Map();
4126
+ return {
4127
+ subscribe: () => () => {
4128
+ },
4129
+ handle: (name) => {
4130
+ const cached = handles.get(name);
4131
+ if (cached !== void 0) {
4132
+ return cached;
4133
+ }
4134
+ const value = data[name];
4135
+ const override = status?.[name];
4136
+ const handle = {
4137
+ data: value,
4138
+ error: override?.error,
4139
+ isPending: override?.isPending ?? value === void 0,
4140
+ refetch: () => onRefetch?.(name)
4141
+ };
4142
+ handles.set(name, handle);
4143
+ return handle;
4144
+ },
4145
+ loadMoreInvoices: (query) => {
4146
+ onLoadMoreInvoices?.(query);
4147
+ return Promise.resolve();
4148
+ },
4149
+ invalidateAll: () => {
4150
+ }
4151
+ };
4152
+ }, [data, onLoadMoreInvoices, onRefetch, status]);
4153
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BillingDataContext.Provider, { value: source, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
4154
+ SchematicI18nProvider,
4155
+ {
4156
+ locale,
4157
+ strings,
4158
+ translate,
4159
+ onMissingString,
4160
+ children
4161
+ }
4162
+ ) });
4163
+ }
4164
+
4165
+ // src/billing/hooks.ts
4166
+ var import_react3 = require("react");
4167
+ function useStableParams(params) {
4168
+ const key = hashKey(params);
4169
+ const ref = (0, import_react3.useRef)({ key, params });
4170
+ if (ref.current.key !== key) {
4171
+ ref.current = { key, params };
4172
+ }
4173
+ return ref.current.params;
4174
+ }
4175
+ function useBillingResource(name, params) {
4176
+ const source = useBillingDataSource();
4177
+ const subscribe = (0, import_react3.useCallback)(
4178
+ (listener) => source.subscribe(name, params, listener),
4179
+ [name, params, source]
4180
+ );
4181
+ const getSnapshot = (0, import_react3.useCallback)(
4182
+ () => source.handle(name, params),
4183
+ [name, params, source]
4184
+ );
4185
+ return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
4186
+ }
4187
+ function useInvoices(query = DEFAULT_INVOICE_QUERY) {
4188
+ const source = useBillingDataSource();
4189
+ const params = useStableParams(normalizeInvoiceQuery2(query));
4190
+ const handle = useBillingResource("invoices", params);
4191
+ const loadMore = (0, import_react3.useCallback)(
4192
+ () => source.loadMoreInvoices(params),
4193
+ [params, source]
4194
+ );
4195
+ return (0, import_react3.useMemo)(() => ({ ...handle, loadMore }), [handle, loadMore]);
4196
+ }
4197
+ function useInvalidateBillingData() {
4198
+ return useBillingDataSource().invalidateAll;
4199
+ }
4200
+
4201
+ // src/billing/provider.tsx
4202
+ var import_react4 = require("react");
4203
+ var import_jsx_runtime3 = require("react/jsx-runtime");
4204
+ var SESSION_REPLACED_MESSAGE = "BillingProvider is moving its billingClient from one session to another. A client holds one session: if another provider shares this client, each will keep installing its own and show the other's data. Give each provider its own client.";
4205
+ function BillingProvider({
4206
+ billingClient,
4207
+ children,
4208
+ initialData,
4209
+ locale,
4210
+ onMissingString,
4211
+ session,
4212
+ strings,
4213
+ translate
4214
+ }) {
4215
+ const initialRef = (0, import_react4.useRef)(initialData);
4216
+ const install = () => {
4217
+ billingClient?.setSession?.(session);
4218
+ };
4219
+ (0, import_react4.useEffect)(() => {
4220
+ const claim = billingClient?.sessionKey;
4221
+ if (claim !== void 0 && session !== null && session !== void 0 && claim !== sessionKey(session)) {
4222
+ console.warn(SESSION_REPLACED_MESSAGE);
4223
+ }
4224
+ }, []);
4225
+ (0, import_react4.useEffect)(install);
4226
+ const seedSpent = (0, import_react4.useRef)(false);
4227
+ const store = (0, import_react4.useMemo)(
4228
+ () => billingClient === void 0 ? void 0 : new BillingStore(
4229
+ billingClient,
4230
+ seedSpent.current ? void 0 : initialRef.current,
4231
+ {
4232
+ // What `install` is about to say, so a stamped prefetch is
4233
+ // judged now rather than after the effect.
4234
+ session
4235
+ }
4236
+ ),
4237
+ // `session` is read only when the store is built: the client learns
4238
+ // later sessions through `install`, and the store through the client.
4239
+ [billingClient]
4240
+ );
4241
+ (0, import_react4.useEffect)(() => {
4242
+ if (store !== void 0) {
4243
+ seedSpent.current = true;
4244
+ }
4245
+ }, [store]);
4246
+ (0, import_react4.useEffect)(() => store?.connect(), [store]);
4247
+ const source = (0, import_react4.useMemo)(() => {
4248
+ if (store === void 0) {
4249
+ return initialRef.current === void 0 ? void 0 : staticSource(initialRef.current);
4250
+ }
4251
+ const handles = /* @__PURE__ */ new WeakMap();
4252
+ const handle = (name, params) => {
4253
+ const resource = store.resource(name).get(params);
4254
+ const snapshot = resource.getSnapshot();
4255
+ const cached = handles.get(resource);
4256
+ if (cached !== void 0 && cached.snapshot === snapshot) {
4257
+ return cached.handle;
4258
+ }
4259
+ const next = {
4260
+ ...snapshot,
4261
+ refetch: () => void resource.refetch()
4262
+ };
4263
+ handles.set(resource, { snapshot, handle: next });
4264
+ return next;
4265
+ };
4266
+ return {
4267
+ subscribe: (name, params, listener) => store.resource(name).subscribe(params, listener),
4268
+ handle,
4269
+ loadMoreInvoices: (query) => store.loadMoreInvoices(query),
4270
+ invalidateAll: () => store.invalidateAll()
4271
+ };
4272
+ }, [store]);
4273
+ const localized = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4274
+ SchematicI18nProvider,
4275
+ {
4276
+ locale,
4277
+ strings,
4278
+ translate,
4279
+ onMissingString,
4280
+ children
4281
+ }
4282
+ );
4283
+ if (source === void 0) {
4284
+ return localized;
4285
+ }
4286
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BillingDataContext.Provider, { value: source, children: localized });
4287
+ }
4288
+ function staticSource(data) {
4289
+ const handles = /* @__PURE__ */ new Map();
4290
+ return {
4291
+ subscribe: () => () => {
4292
+ },
4293
+ handle: (name) => {
4294
+ const cached = handles.get(name);
4295
+ if (cached !== void 0) {
4296
+ return cached;
4297
+ }
4298
+ const value = data[name];
4299
+ const next = {
4300
+ data: value,
4301
+ error: void 0,
4302
+ isPending: value === void 0,
4303
+ refetch: () => {
4304
+ }
4305
+ };
4306
+ handles.set(name, next);
4307
+ return next;
4308
+ },
4309
+ loadMoreInvoices: () => Promise.resolve(),
4310
+ invalidateAll: () => {
4311
+ }
4312
+ };
4313
+ }
2923
4314
 
2924
4315
  // src/version.ts
2925
- var version2 = "1.5.0";
4316
+ var version2 = "1.6.0";
2926
4317
 
2927
4318
  // src/context/schematic.tsx
2928
- var import_jsx_runtime = require("react/jsx-runtime");
2929
- var SchematicContext = (0, import_react.createContext)(
4319
+ var import_jsx_runtime4 = require("react/jsx-runtime");
4320
+ var SchematicContext = (0, import_react5.createContext)(
2930
4321
  null
2931
4322
  );
2932
4323
  var SchematicProvider = ({
4324
+ session,
4325
+ billingClient,
2933
4326
  children,
2934
4327
  client: providedClient,
4328
+ initialData,
4329
+ locale,
4330
+ onMissingString,
2935
4331
  publishableKey,
4332
+ strings,
4333
+ translate,
2936
4334
  ...clientOpts
2937
4335
  }) => {
2938
- const initialOptsRef = (0, import_react.useRef)({
4336
+ const initialOptsRef = (0, import_react5.useRef)({
2939
4337
  publishableKey,
2940
4338
  useWebSocket: true,
2941
4339
  additionalHeaders: {
@@ -2943,7 +4341,7 @@ var SchematicProvider = ({
2943
4341
  },
2944
4342
  ...clientOpts
2945
4343
  });
2946
- const client = (0, import_react.useMemo)(() => {
4344
+ const client = (0, import_react5.useMemo)(() => {
2947
4345
  if (providedClient) {
2948
4346
  return providedClient;
2949
4347
  }
@@ -2951,7 +4349,7 @@ var SchematicProvider = ({
2951
4349
  ...initialOptsRef.current
2952
4350
  });
2953
4351
  }, [providedClient]);
2954
- (0, import_react.useEffect)(() => {
4352
+ (0, import_react5.useEffect)(() => {
2955
4353
  return () => {
2956
4354
  if (!providedClient) {
2957
4355
  client.cleanup().catch((error) => {
@@ -2960,16 +4358,46 @@ var SchematicProvider = ({
2960
4358
  }
2961
4359
  };
2962
4360
  }, [client, providedClient]);
2963
- const contextValue = (0, import_react.useMemo)(
4361
+ const contextValue = (0, import_react5.useMemo)(
2964
4362
  () => ({
2965
4363
  client
2966
4364
  }),
2967
4365
  [client]
2968
4366
  );
2969
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchematicContext.Provider, { value: contextValue, children });
4367
+ const { apiUrl, additionalHeaders } = initialOptsRef.current;
4368
+ const providedApiUrl = providedClient?.apiUrl;
4369
+ const resolvedBillingClient = (0, import_react5.useMemo)(
4370
+ () => billingClient ?? new SchematicBillingClient({
4371
+ session,
4372
+ apiUrl: apiUrl ?? providedApiUrl,
4373
+ // Read as they stand when a client is built: headers do not change
4374
+ // where the token goes, so they are no reason to build one.
4375
+ additionalHeaders: {
4376
+ ...providedClient?.additionalHeaders,
4377
+ ...additionalHeaders
4378
+ }
4379
+ }),
4380
+ // `session` is deliberately absent: `BillingProvider` forwards it through
4381
+ // `setSession`, so a token change resets the billing resources without
4382
+ // rebuilding the client.
4383
+ [additionalHeaders, apiUrl, billingClient, providedApiUrl]
4384
+ );
4385
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SchematicContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4386
+ BillingProvider,
4387
+ {
4388
+ billingClient: resolvedBillingClient,
4389
+ initialData,
4390
+ locale,
4391
+ session,
4392
+ strings,
4393
+ translate,
4394
+ onMissingString,
4395
+ children
4396
+ }
4397
+ ) });
2970
4398
  };
2971
4399
  var useSchematic = () => {
2972
- const context = import_react.default.useContext(SchematicContext);
4400
+ const context = import_react5.default.useContext(SchematicContext);
2973
4401
  if (context === null) {
2974
4402
  throw new Error("useSchematic must be used within a SchematicProvider");
2975
4403
  }
@@ -2977,11 +4405,11 @@ var useSchematic = () => {
2977
4405
  };
2978
4406
 
2979
4407
  // src/hooks/schematic.ts
2980
- var import_react2 = require("react");
4408
+ var import_react6 = require("react");
2981
4409
  var useSchematicClient = (opts) => {
2982
4410
  const schematic = useSchematic();
2983
4411
  const { client } = opts ?? {};
2984
- return (0, import_react2.useMemo)(() => {
4412
+ return (0, import_react6.useMemo)(() => {
2985
4413
  if (client) {
2986
4414
  return client;
2987
4415
  }
@@ -2990,7 +4418,7 @@ var useSchematicClient = (opts) => {
2990
4418
  };
2991
4419
  var useSchematicContext = (opts) => {
2992
4420
  const client = useSchematicClient(opts);
2993
- return (0, import_react2.useMemo)(
4421
+ return (0, import_react6.useMemo)(
2994
4422
  () => ({
2995
4423
  setContext: client.setContext.bind(client)
2996
4424
  }),
@@ -2999,33 +4427,33 @@ var useSchematicContext = (opts) => {
2999
4427
  };
3000
4428
  var useSchematicEvents = (opts) => {
3001
4429
  const client = useSchematicClient(opts);
3002
- const track = (0, import_react2.useCallback)(
4430
+ const track = (0, import_react6.useCallback)(
3003
4431
  (...args) => client.track(...args),
3004
4432
  [client]
3005
4433
  );
3006
- const identify = (0, import_react2.useCallback)(
4434
+ const identify = (0, import_react6.useCallback)(
3007
4435
  (...args) => client.identify(...args),
3008
4436
  [client]
3009
4437
  );
3010
- return (0, import_react2.useMemo)(() => ({ track, identify }), [track, identify]);
4438
+ return (0, import_react6.useMemo)(() => ({ track, identify }), [track, identify]);
3011
4439
  };
3012
4440
  var useSchematicFlag = (key, opts) => {
3013
4441
  const client = useSchematicClient(opts);
3014
4442
  const fallback = opts?.fallback ?? false;
3015
- const subscribe = (0, import_react2.useCallback)(
4443
+ const subscribe = (0, import_react6.useCallback)(
3016
4444
  (callback) => client.addFlagValueListener(key, callback),
3017
4445
  [client, key]
3018
4446
  );
3019
- const getSnapshot = (0, import_react2.useCallback)(() => {
4447
+ const getSnapshot = (0, import_react6.useCallback)(() => {
3020
4448
  const value = client.getFlagValue(key);
3021
4449
  return typeof value === "undefined" ? fallback : value;
3022
4450
  }, [client, key, fallback]);
3023
- return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => fallback);
4451
+ return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => fallback);
3024
4452
  };
3025
4453
  var useSchematicEntitlement = (key, opts) => {
3026
4454
  const client = useSchematicClient(opts);
3027
4455
  const fallback = opts?.fallback ?? false;
3028
- const fallbackCheck = (0, import_react2.useMemo)(
4456
+ const fallbackCheck = (0, import_react6.useMemo)(
3029
4457
  () => ({
3030
4458
  flag: key,
3031
4459
  reason: "Fallback",
@@ -3033,20 +4461,20 @@ var useSchematicEntitlement = (key, opts) => {
3033
4461
  }),
3034
4462
  [key, fallback]
3035
4463
  );
3036
- const subscribe = (0, import_react2.useCallback)(
4464
+ const subscribe = (0, import_react6.useCallback)(
3037
4465
  (callback) => client.addFlagCheckListener(key, callback),
3038
4466
  [client, key]
3039
4467
  );
3040
- const getSnapshot = (0, import_react2.useCallback)(() => {
4468
+ const getSnapshot = (0, import_react6.useCallback)(() => {
3041
4469
  const check = client.getFlagCheck(key);
3042
4470
  return check ?? fallbackCheck;
3043
4471
  }, [client, key, fallbackCheck]);
3044
- return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackCheck);
4472
+ return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackCheck);
3045
4473
  };
3046
4474
  var useSchematicPlan = (opts) => {
3047
4475
  const client = useSchematicClient(opts);
3048
4476
  const fallback = opts?.fallback;
3049
- const fallbackPlan = (0, import_react2.useMemo)(
4477
+ const fallbackPlan = (0, import_react6.useMemo)(
3050
4478
  () => fallback,
3051
4479
  [
3052
4480
  fallback?.id,
@@ -3055,37 +4483,37 @@ var useSchematicPlan = (opts) => {
3055
4483
  fallback?.trialStatus
3056
4484
  ]
3057
4485
  );
3058
- const subscribe = (0, import_react2.useCallback)(
4486
+ const subscribe = (0, import_react6.useCallback)(
3059
4487
  (callback) => client.addPlanListener(callback),
3060
4488
  [client]
3061
4489
  );
3062
- const getSnapshot = (0, import_react2.useCallback)(() => {
4490
+ const getSnapshot = (0, import_react6.useCallback)(() => {
3063
4491
  const plan = client.getPlan();
3064
4492
  return plan ?? fallbackPlan;
3065
4493
  }, [client, fallbackPlan]);
3066
- return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackPlan);
4494
+ return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => fallbackPlan);
3067
4495
  };
3068
4496
  var useSchematicCreditBalance = (creditId, opts) => {
3069
4497
  const client = useSchematicClient(opts);
3070
- const subscribe = (0, import_react2.useCallback)(
4498
+ const subscribe = (0, import_react6.useCallback)(
3071
4499
  (callback) => client.addCreditBalanceListener(callback),
3072
4500
  [client]
3073
4501
  );
3074
- const getSnapshot = (0, import_react2.useCallback)(
3075
- () => client.getCreditBalance(creditId),
4502
+ const getSnapshot = (0, import_react6.useCallback)(
4503
+ () => creditId === void 0 ? void 0 : client.getCreditBalance(creditId),
3076
4504
  [client, creditId]
3077
4505
  );
3078
- const balance = (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
3079
- const isPendingSubscribe = (0, import_react2.useCallback)(
4506
+ const balance = (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
4507
+ const isPendingSubscribe = (0, import_react6.useCallback)(
3080
4508
  (callback) => client.addIsPendingListener(callback),
3081
4509
  [client]
3082
4510
  );
3083
- const isPending = (0, import_react2.useSyncExternalStore)(
4511
+ const isPending = (0, import_react6.useSyncExternalStore)(
3084
4512
  isPendingSubscribe,
3085
4513
  () => client.getIsPending(),
3086
4514
  () => true
3087
4515
  );
3088
- return (0, import_react2.useMemo)(
4516
+ return (0, import_react6.useMemo)(
3089
4517
  () => ({
3090
4518
  balance: balance?.settled ?? 0,
3091
4519
  isLoading: balance === void 0 && isPending
@@ -3095,12 +4523,12 @@ var useSchematicCreditBalance = (creditId, opts) => {
3095
4523
  };
3096
4524
  var useSchematicIsPending = (opts) => {
3097
4525
  const client = useSchematicClient(opts);
3098
- const subscribe = (0, import_react2.useCallback)(
4526
+ const subscribe = (0, import_react6.useCallback)(
3099
4527
  (callback) => client.addIsPendingListener(callback),
3100
4528
  [client]
3101
4529
  );
3102
- const getSnapshot = (0, import_react2.useCallback)(() => client.getIsPending(), [client]);
3103
- return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => true);
4530
+ const getSnapshot = (0, import_react6.useCallback)(() => client.getIsPending(), [client]);
4531
+ return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, () => true);
3104
4532
  };
3105
4533
  /*! Bundled license information:
3106
4534