@schematichq/schematic-js 1.5.0 → 1.7.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.
@@ -11,6 +11,10 @@ var __commonJS = (cb, mod) => function __require() {
11
11
  throw mod = 0, e;
12
12
  }
13
13
  };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
14
18
  var __copyProps = (to, from, except, desc) => {
15
19
  if (from && typeof from === "object" || typeof from === "function") {
16
20
  for (let key of __getOwnPropNames(from))
@@ -28,9 +32,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
32
  mod
29
33
  ));
30
34
 
31
- // node_modules/cross-fetch/dist/browser-polyfill.js
35
+ // node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js
32
36
  var require_browser_polyfill = __commonJS({
33
- "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
37
+ "node_modules/.pnpm/cross-fetch@4.1.0/node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
34
38
  (function(self2) {
35
39
  var irrelevant = (function(exports2) {
36
40
  var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
@@ -564,7 +568,7 @@ var require_browser_polyfill = __commonJS({
564
568
  }
565
569
  });
566
570
 
567
- // node_modules/uuid/dist/stringify.js
571
+ // node_modules/.pnpm/uuid@14.0.2/node_modules/uuid/dist/stringify.js
568
572
  var byteToHex = [];
569
573
  for (let i = 0; i < 256; ++i) {
570
574
  byteToHex.push((i + 256).toString(16).slice(1));
@@ -573,13 +577,13 @@ function unsafeStringify(arr, offset = 0) {
573
577
  return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
574
578
  }
575
579
 
576
- // node_modules/uuid/dist/rng.js
580
+ // node_modules/.pnpm/uuid@14.0.2/node_modules/uuid/dist/rng.js
577
581
  var rnds8 = new Uint8Array(16);
578
582
  function rng() {
579
583
  return crypto.getRandomValues(rnds8);
580
584
  }
581
585
 
582
- // node_modules/uuid/dist/v4.js
586
+ // node_modules/.pnpm/uuid@14.0.2/node_modules/uuid/dist/v4.js
583
587
  function v4(options, buf, offset) {
584
588
  if (!buf && !options && crypto.randomUUID) {
585
589
  return crypto.randomUUID();
@@ -627,6 +631,20 @@ function MetricPeriodMonthResetFromJSONTyped(json, ignoreDiscriminator) {
627
631
  return json;
628
632
  }
629
633
 
634
+ // src/types/api/models/WarningTier.ts
635
+ function WarningTierFromJSON(json) {
636
+ return WarningTierFromJSONTyped(json, false);
637
+ }
638
+ function WarningTierFromJSONTyped(json, ignoreDiscriminator) {
639
+ if (json == null) {
640
+ return json;
641
+ }
642
+ return {
643
+ key: json["key"],
644
+ value: json["value"]
645
+ };
646
+ }
647
+
630
648
  // src/types/api/models/MetricPeriod.ts
631
649
  function MetricPeriodFromJSON(json) {
632
650
  return MetricPeriodFromJSONTyped(json, false);
@@ -661,7 +679,8 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
661
679
  monthReset: json["month_reset"] == null ? void 0 : MetricPeriodMonthResetFromJSON(json["month_reset"]),
662
680
  softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
663
681
  usage: json["usage"] == null ? void 0 : json["usage"],
664
- valueType: EntitlementValueTypeFromJSON(json["value_type"])
682
+ valueType: EntitlementValueTypeFromJSON(json["value_type"]),
683
+ warningTiers: json["warning_tiers"] == null ? void 0 : json["warning_tiers"].map(WarningTierFromJSON)
665
684
  };
666
685
  }
667
686
 
@@ -1051,6 +1070,7 @@ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
1051
1070
  error: value["error"],
1052
1071
  flag_id: value["flagId"],
1053
1072
  flag_key: value["flagKey"],
1073
+ preflight: value["preflight"],
1054
1074
  reason: value["reason"],
1055
1075
  req_company: value["reqCompany"],
1056
1076
  req_user: value["reqUser"],
@@ -1172,7 +1192,590 @@ function contextString(context) {
1172
1192
  }
1173
1193
 
1174
1194
  // src/version.ts
1175
- var version = "1.5.0";
1195
+ var version = "1.7.0";
1196
+
1197
+ // src/billing/api/generated/models/index.ts
1198
+ var models_exports = {};
1199
+ __export(models_exports, {
1200
+ ApiErrorFromJSON: () => ApiErrorFromJSON,
1201
+ ApiErrorFromJSONTyped: () => ApiErrorFromJSONTyped,
1202
+ ApiErrorToJSON: () => ApiErrorToJSON,
1203
+ ApiErrorToJSONTyped: () => ApiErrorToJSONTyped,
1204
+ CompanyInvoiceResponseDataFromJSON: () => CompanyInvoiceResponseDataFromJSON,
1205
+ CompanyInvoiceResponseDataFromJSONTyped: () => CompanyInvoiceResponseDataFromJSONTyped,
1206
+ CompanyInvoiceResponseDataToJSON: () => CompanyInvoiceResponseDataToJSON,
1207
+ CompanyInvoiceResponseDataToJSONTyped: () => CompanyInvoiceResponseDataToJSONTyped,
1208
+ CompanyInvoicesResponseDataFromJSON: () => CompanyInvoicesResponseDataFromJSON,
1209
+ CompanyInvoicesResponseDataFromJSONTyped: () => CompanyInvoicesResponseDataFromJSONTyped,
1210
+ CompanyInvoicesResponseDataToJSON: () => CompanyInvoicesResponseDataToJSON,
1211
+ CompanyInvoicesResponseDataToJSONTyped: () => CompanyInvoicesResponseDataToJSONTyped,
1212
+ GetCompanyInvoicesParamsFromJSON: () => GetCompanyInvoicesParamsFromJSON,
1213
+ GetCompanyInvoicesParamsFromJSONTyped: () => GetCompanyInvoicesParamsFromJSONTyped,
1214
+ GetCompanyInvoicesParamsToJSON: () => GetCompanyInvoicesParamsToJSON,
1215
+ GetCompanyInvoicesParamsToJSONTyped: () => GetCompanyInvoicesParamsToJSONTyped,
1216
+ GetCompanyInvoicesResponseFromJSON: () => GetCompanyInvoicesResponseFromJSON,
1217
+ GetCompanyInvoicesResponseFromJSONTyped: () => GetCompanyInvoicesResponseFromJSONTyped,
1218
+ GetCompanyInvoicesResponseToJSON: () => GetCompanyInvoicesResponseToJSON,
1219
+ GetCompanyInvoicesResponseToJSONTyped: () => GetCompanyInvoicesResponseToJSONTyped,
1220
+ InvoiceStatus: () => InvoiceStatus,
1221
+ InvoiceStatusFromJSON: () => InvoiceStatusFromJSON,
1222
+ InvoiceStatusFromJSONTyped: () => InvoiceStatusFromJSONTyped,
1223
+ InvoiceStatusToJSON: () => InvoiceStatusToJSON,
1224
+ InvoiceStatusToJSONTyped: () => InvoiceStatusToJSONTyped,
1225
+ instanceOfApiError: () => instanceOfApiError,
1226
+ instanceOfCompanyInvoiceResponseData: () => instanceOfCompanyInvoiceResponseData,
1227
+ instanceOfCompanyInvoicesResponseData: () => instanceOfCompanyInvoicesResponseData,
1228
+ instanceOfGetCompanyInvoicesParams: () => instanceOfGetCompanyInvoicesParams,
1229
+ instanceOfGetCompanyInvoicesResponse: () => instanceOfGetCompanyInvoicesResponse,
1230
+ instanceOfInvoiceStatus: () => instanceOfInvoiceStatus
1231
+ });
1232
+
1233
+ // src/billing/api/generated/models/ApiError.ts
1234
+ function instanceOfApiError(value) {
1235
+ if (!("error" in value) || value["error"] === void 0) return false;
1236
+ return true;
1237
+ }
1238
+ function ApiErrorFromJSON(json) {
1239
+ return ApiErrorFromJSONTyped(json, false);
1240
+ }
1241
+ function ApiErrorFromJSONTyped(json, ignoreDiscriminator) {
1242
+ if (json == null) {
1243
+ return json;
1244
+ }
1245
+ return {
1246
+ error: json["error"]
1247
+ };
1248
+ }
1249
+ function ApiErrorToJSON(json) {
1250
+ return ApiErrorToJSONTyped(json, false);
1251
+ }
1252
+ function ApiErrorToJSONTyped(value, ignoreDiscriminator = false) {
1253
+ if (value == null) {
1254
+ return value;
1255
+ }
1256
+ return {
1257
+ error: value["error"]
1258
+ };
1259
+ }
1260
+
1261
+ // src/billing/api/generated/models/InvoiceStatus.ts
1262
+ var InvoiceStatus = {
1263
+ Draft: "draft",
1264
+ Open: "open",
1265
+ Paid: "paid",
1266
+ Uncollectible: "uncollectible",
1267
+ Void: "void"
1268
+ };
1269
+ function instanceOfInvoiceStatus(value) {
1270
+ for (const key in InvoiceStatus) {
1271
+ if (Object.prototype.hasOwnProperty.call(InvoiceStatus, key)) {
1272
+ if (InvoiceStatus[key] === value) {
1273
+ return true;
1274
+ }
1275
+ }
1276
+ }
1277
+ return false;
1278
+ }
1279
+ function InvoiceStatusFromJSON(json) {
1280
+ return InvoiceStatusFromJSONTyped(json, false);
1281
+ }
1282
+ function InvoiceStatusFromJSONTyped(json, ignoreDiscriminator) {
1283
+ return json;
1284
+ }
1285
+ function InvoiceStatusToJSON(value) {
1286
+ return value;
1287
+ }
1288
+ function InvoiceStatusToJSONTyped(value, ignoreDiscriminator) {
1289
+ return value;
1290
+ }
1291
+
1292
+ // src/billing/api/generated/models/CompanyInvoiceResponseData.ts
1293
+ function instanceOfCompanyInvoiceResponseData(value) {
1294
+ if (!("amountDue" in value) || value["amountDue"] === void 0) return false;
1295
+ if (!("createdAt" in value) || value["createdAt"] === void 0) return false;
1296
+ if (!("currency" in value) || value["currency"] === void 0) return false;
1297
+ if (!("id" in value) || value["id"] === void 0) return false;
1298
+ return true;
1299
+ }
1300
+ function CompanyInvoiceResponseDataFromJSON(json) {
1301
+ return CompanyInvoiceResponseDataFromJSONTyped(json, false);
1302
+ }
1303
+ function CompanyInvoiceResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1304
+ if (json == null) {
1305
+ return json;
1306
+ }
1307
+ return {
1308
+ amountDue: json["amount_due"],
1309
+ createdAt: new Date(json["created_at"]),
1310
+ currency: json["currency"],
1311
+ dueDate: json["due_date"] == null ? void 0 : new Date(json["due_date"]),
1312
+ id: json["id"],
1313
+ status: json["status"] == null ? void 0 : InvoiceStatusFromJSON(json["status"]),
1314
+ url: json["url"] == null ? void 0 : json["url"]
1315
+ };
1316
+ }
1317
+ function CompanyInvoiceResponseDataToJSON(json) {
1318
+ return CompanyInvoiceResponseDataToJSONTyped(json, false);
1319
+ }
1320
+ function CompanyInvoiceResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1321
+ if (value == null) {
1322
+ return value;
1323
+ }
1324
+ return {
1325
+ amount_due: value["amountDue"],
1326
+ created_at: value["createdAt"].toISOString(),
1327
+ currency: value["currency"],
1328
+ due_date: value["dueDate"] == null ? void 0 : value["dueDate"].toISOString(),
1329
+ id: value["id"],
1330
+ status: InvoiceStatusToJSON(value["status"]),
1331
+ url: value["url"]
1332
+ };
1333
+ }
1334
+
1335
+ // src/billing/api/generated/models/CompanyInvoicesResponseData.ts
1336
+ function instanceOfCompanyInvoicesResponseData(value) {
1337
+ if (!("count" in value) || value["count"] === void 0) return false;
1338
+ if (!("invoices" in value) || value["invoices"] === void 0) return false;
1339
+ return true;
1340
+ }
1341
+ function CompanyInvoicesResponseDataFromJSON(json) {
1342
+ return CompanyInvoicesResponseDataFromJSONTyped(json, false);
1343
+ }
1344
+ function CompanyInvoicesResponseDataFromJSONTyped(json, ignoreDiscriminator) {
1345
+ if (json == null) {
1346
+ return json;
1347
+ }
1348
+ return {
1349
+ count: json["count"],
1350
+ invoices: json["invoices"].map(
1351
+ CompanyInvoiceResponseDataFromJSON
1352
+ )
1353
+ };
1354
+ }
1355
+ function CompanyInvoicesResponseDataToJSON(json) {
1356
+ return CompanyInvoicesResponseDataToJSONTyped(json, false);
1357
+ }
1358
+ function CompanyInvoicesResponseDataToJSONTyped(value, ignoreDiscriminator = false) {
1359
+ if (value == null) {
1360
+ return value;
1361
+ }
1362
+ return {
1363
+ count: value["count"],
1364
+ invoices: value["invoices"].map(
1365
+ CompanyInvoiceResponseDataToJSON
1366
+ )
1367
+ };
1368
+ }
1369
+
1370
+ // src/billing/api/generated/models/GetCompanyInvoicesParams.ts
1371
+ function instanceOfGetCompanyInvoicesParams(value) {
1372
+ return true;
1373
+ }
1374
+ function GetCompanyInvoicesParamsFromJSON(json) {
1375
+ return GetCompanyInvoicesParamsFromJSONTyped(json, false);
1376
+ }
1377
+ function GetCompanyInvoicesParamsFromJSONTyped(json, ignoreDiscriminator) {
1378
+ if (json == null) {
1379
+ return json;
1380
+ }
1381
+ return {
1382
+ includePending: json["include_pending"] == null ? void 0 : json["include_pending"],
1383
+ limit: json["limit"] == null ? void 0 : json["limit"],
1384
+ offset: json["offset"] == null ? void 0 : json["offset"]
1385
+ };
1386
+ }
1387
+ function GetCompanyInvoicesParamsToJSON(json) {
1388
+ return GetCompanyInvoicesParamsToJSONTyped(json, false);
1389
+ }
1390
+ function GetCompanyInvoicesParamsToJSONTyped(value, ignoreDiscriminator = false) {
1391
+ if (value == null) {
1392
+ return value;
1393
+ }
1394
+ return {
1395
+ include_pending: value["includePending"],
1396
+ limit: value["limit"],
1397
+ offset: value["offset"]
1398
+ };
1399
+ }
1400
+
1401
+ // src/billing/api/generated/models/GetCompanyInvoicesResponse.ts
1402
+ function instanceOfGetCompanyInvoicesResponse(value) {
1403
+ if (!("data" in value) || value["data"] === void 0) return false;
1404
+ if (!("params" in value) || value["params"] === void 0) return false;
1405
+ return true;
1406
+ }
1407
+ function GetCompanyInvoicesResponseFromJSON(json) {
1408
+ return GetCompanyInvoicesResponseFromJSONTyped(json, false);
1409
+ }
1410
+ function GetCompanyInvoicesResponseFromJSONTyped(json, ignoreDiscriminator) {
1411
+ if (json == null) {
1412
+ return json;
1413
+ }
1414
+ return {
1415
+ data: CompanyInvoicesResponseDataFromJSON(json["data"]),
1416
+ params: GetCompanyInvoicesParamsFromJSON(json["params"])
1417
+ };
1418
+ }
1419
+ function GetCompanyInvoicesResponseToJSON(json) {
1420
+ return GetCompanyInvoicesResponseToJSONTyped(json, false);
1421
+ }
1422
+ function GetCompanyInvoicesResponseToJSONTyped(value, ignoreDiscriminator = false) {
1423
+ if (value == null) {
1424
+ return value;
1425
+ }
1426
+ return {
1427
+ data: CompanyInvoicesResponseDataToJSON(value["data"]),
1428
+ params: GetCompanyInvoicesParamsToJSON(value["params"])
1429
+ };
1430
+ }
1431
+
1432
+ // src/billing/contract/invoices.ts
1433
+ var DEFAULT_INVOICE_QUERY = {};
1434
+ function normalizeInvoiceQuery(query) {
1435
+ const { includePending, ...rest } = query;
1436
+ return includePending === true ? { ...rest, includePending: true } : rest;
1437
+ }
1438
+
1439
+ // src/billing/session.ts
1440
+ var SchematicApiError = class extends Error {
1441
+ constructor(status, path, body) {
1442
+ super(
1443
+ typeof body === "object" && body !== null && "error" in body ? String(body.error) : `Request to ${path} failed with status ${status}`
1444
+ );
1445
+ this.status = status;
1446
+ this.path = path;
1447
+ this.body = body;
1448
+ this.name = "SchematicApiError";
1449
+ }
1450
+ status;
1451
+ path;
1452
+ body;
1453
+ };
1454
+ var DEFAULT_API_URL = "https://api.schematichq.com";
1455
+ var TOKEN_CACHE_SIZE = 10;
1456
+ function sessionKey(session) {
1457
+ return JSON.stringify([session.company, session.user ?? null]);
1458
+ }
1459
+ var SchematicSession = class {
1460
+ _apiUrl;
1461
+ _headers;
1462
+ _fetch;
1463
+ _session;
1464
+ _tokens = /* @__PURE__ */ new Map();
1465
+ _resolving = /* @__PURE__ */ new Map();
1466
+ /**
1467
+ * Bumped when the session's identity changes, and only then — the object
1468
+ * itself is replaced on every render. Anything asking "is this still the
1469
+ * session I started under?" counts generations rather than comparing.
1470
+ */
1471
+ _generation = 0;
1472
+ _listeners = /* @__PURE__ */ new Set();
1473
+ constructor(options = {}) {
1474
+ this._session = options.session;
1475
+ this._apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
1476
+ this._headers = options.additionalHeaders ?? {};
1477
+ this._fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
1478
+ }
1479
+ get key() {
1480
+ return this._session === null || this._session === void 0 ? void 0 : sessionKey(this._session);
1481
+ }
1482
+ get status() {
1483
+ if (this._session === void 0) {
1484
+ return "pending";
1485
+ }
1486
+ return this._session === null ? "ended" : "active";
1487
+ }
1488
+ /** Only a statement that changes which pair is read counts as a change. */
1489
+ set(session) {
1490
+ if (session === void 0) {
1491
+ return;
1492
+ }
1493
+ const previous = this._session;
1494
+ this._session = session;
1495
+ if (session === null) {
1496
+ if (previous === null) {
1497
+ return;
1498
+ }
1499
+ this._tokens.clear();
1500
+ this._resolving.clear();
1501
+ this._generation += 1;
1502
+ this._emit({ type: "ended" });
1503
+ return;
1504
+ }
1505
+ if (previous !== null && previous !== void 0) {
1506
+ if (previous.company === session.company && (previous.user ?? null) === (session.user ?? null)) {
1507
+ return;
1508
+ }
1509
+ this._generation += 1;
1510
+ this._emit({ type: "changed" });
1511
+ return;
1512
+ }
1513
+ this._generation += 1;
1514
+ this._emit({ type: "started" });
1515
+ }
1516
+ onChange(listener) {
1517
+ this._listeners.add(listener);
1518
+ return () => {
1519
+ this._listeners.delete(listener);
1520
+ };
1521
+ }
1522
+ _emit(event) {
1523
+ for (const listener of this._listeners) {
1524
+ listener(event);
1525
+ }
1526
+ }
1527
+ _cached(key) {
1528
+ const cached = this._tokens.get(key);
1529
+ if (cached === void 0) {
1530
+ return void 0;
1531
+ }
1532
+ if (cached.expiresAt !== void 0 && cached.expiresAt.getTime() <= Date.now()) {
1533
+ this._tokens.delete(key);
1534
+ return void 0;
1535
+ }
1536
+ this._tokens.delete(key);
1537
+ this._tokens.set(key, cached);
1538
+ return cached;
1539
+ }
1540
+ _cache(key, resolved) {
1541
+ this._tokens.delete(key);
1542
+ this._tokens.set(key, resolved);
1543
+ while (this._tokens.size > TOKEN_CACHE_SIZE) {
1544
+ const oldest = this._tokens.keys().next();
1545
+ if (oldest.done === true) {
1546
+ break;
1547
+ }
1548
+ this._tokens.delete(oldest.value);
1549
+ }
1550
+ }
1551
+ /**
1552
+ * The credential for a session, minted if this one is not held. `force`
1553
+ * retires what is held first: the caller is a request the API has just
1554
+ * rejected.
1555
+ */
1556
+ resolveToken(session, force) {
1557
+ const { token } = session;
1558
+ if (typeof token === "string") {
1559
+ return Promise.resolve(token);
1560
+ }
1561
+ const key = sessionKey(session);
1562
+ if (!force) {
1563
+ const cached = this._cached(key);
1564
+ if (cached !== void 0) {
1565
+ return Promise.resolve(cached.token);
1566
+ }
1567
+ } else {
1568
+ this._tokens.delete(key);
1569
+ }
1570
+ const inflight = this._resolving.get(key);
1571
+ if (inflight !== void 0 && inflight.sessionGeneration === this._generation && (!force || inflight.forced)) {
1572
+ return inflight.promise;
1573
+ }
1574
+ const provider = token;
1575
+ const sessionGeneration = this._generation;
1576
+ const owns = () => this._resolving.get(key)?.promise === promise;
1577
+ const promise = Promise.resolve().then(() => provider()).then((result) => {
1578
+ const { resolved, stamped } = asResolvedToken(result, session);
1579
+ if (owns() && (this._generation === sessionGeneration || stamped)) {
1580
+ this._cache(key, resolved);
1581
+ }
1582
+ return resolved.token;
1583
+ }).finally(() => {
1584
+ if (owns()) {
1585
+ this._resolving.delete(key);
1586
+ }
1587
+ });
1588
+ this._resolving.set(key, { promise, forced: force, sessionGeneration });
1589
+ return promise;
1590
+ }
1591
+ /**
1592
+ * Sends a request under the active session's credential, refreshing once
1593
+ * and retrying if the API rejects it. Rejects rather than answering when
1594
+ * the session changes while the request is in flight: the rows would
1595
+ * otherwise come back as the answer to a question asked for another pair.
1596
+ */
1597
+ async request(path, options = {}) {
1598
+ const { method = "GET", body } = options;
1599
+ const send = async (credential2) => this._fetch(`${this._apiUrl}${path}`, {
1600
+ method,
1601
+ headers: {
1602
+ "Accept": "application/json",
1603
+ ...body === void 0 ? {} : { "Content-Type": "application/json" },
1604
+ ...this._headers,
1605
+ "X-Schematic-Api-Key": credential2
1606
+ },
1607
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
1608
+ });
1609
+ const session = this._session;
1610
+ if (session === null) {
1611
+ throw new Error("There is no session to read data for.");
1612
+ }
1613
+ if (session === void 0) {
1614
+ throw new Error("A session is required to read data.");
1615
+ }
1616
+ const provider = session.token;
1617
+ const generation = this._generation;
1618
+ const stillOurs = async (response2) => {
1619
+ if (this._generation === generation) {
1620
+ return;
1621
+ }
1622
+ if (response2 !== void 0) {
1623
+ await discardBody(response2);
1624
+ }
1625
+ throw new Error("The session changed while this request was in flight.");
1626
+ };
1627
+ const credential = await this.resolveToken(session, false);
1628
+ if (this._generation !== generation) {
1629
+ throw new Error("The session changed before this request was sent.");
1630
+ }
1631
+ let response = await send(credential);
1632
+ await stillOurs(response);
1633
+ if (response.status === 401 && typeof provider === "function" && this._generation === generation) {
1634
+ const status = response.status;
1635
+ const rejected = await readBody(response);
1636
+ let retried = false;
1637
+ const current = this._session;
1638
+ if (this._generation === generation && current !== null && current !== void 0) {
1639
+ const refreshed = await this.resolveToken(current, true);
1640
+ if (this._generation === generation) {
1641
+ response = await send(refreshed);
1642
+ await stillOurs(response);
1643
+ retried = true;
1644
+ }
1645
+ }
1646
+ if (!retried) {
1647
+ throw new SchematicApiError(status, path, rejected);
1648
+ }
1649
+ }
1650
+ const parsed = await readBody(response);
1651
+ await stillOurs();
1652
+ if (!response.ok) {
1653
+ throw new SchematicApiError(response.status, path, parsed);
1654
+ }
1655
+ return parsed;
1656
+ }
1657
+ };
1658
+ function asResolvedToken(result, session) {
1659
+ if (typeof result === "string") {
1660
+ return { resolved: { token: result }, stamped: false };
1661
+ }
1662
+ const token = result?.token;
1663
+ if (typeof token !== "string" || token === "") {
1664
+ throw new Error("The access token provider did not return a token.");
1665
+ }
1666
+ if (result.company !== void 0 && result.company !== session.company || result.user !== void 0 && session.user !== void 0 && result.user !== session.user) {
1667
+ throw new Error(
1668
+ "The access token provider returned a token for a different session."
1669
+ );
1670
+ }
1671
+ const stamped = result.company !== void 0 && (session.user === void 0 || result.user !== void 0);
1672
+ return { resolved: { token, expiresAt: asDate(result.expiresAt) }, stamped };
1673
+ }
1674
+ function asDate(value) {
1675
+ if (value === void 0 || value === null) {
1676
+ return void 0;
1677
+ }
1678
+ const date = value instanceof Date ? value : new Date(value);
1679
+ return Number.isNaN(date.getTime()) ? void 0 : date;
1680
+ }
1681
+ async function discardBody(response) {
1682
+ try {
1683
+ await response.body?.cancel();
1684
+ } catch {
1685
+ }
1686
+ }
1687
+ async function readBody(response) {
1688
+ const text = await response.text();
1689
+ if (text === "") {
1690
+ return null;
1691
+ }
1692
+ try {
1693
+ return JSON.parse(text);
1694
+ } catch {
1695
+ return text;
1696
+ }
1697
+ }
1698
+
1699
+ // src/billing/client.ts
1700
+ var INVOICE_PAGE_SIZE = 12;
1701
+ var INVOICE_MAX_PAGE_SIZE = 250;
1702
+ var SchematicBillingClient = class {
1703
+ /**
1704
+ * Public so a second client over the same surface can be constructed on
1705
+ * this one rather than minting tokens of its own.
1706
+ */
1707
+ session;
1708
+ constructor(options = {}) {
1709
+ this.session = options instanceof SchematicSession ? options : new SchematicSession(options);
1710
+ }
1711
+ get sessionKey() {
1712
+ return this.session.key;
1713
+ }
1714
+ get sessionStatus() {
1715
+ return this.session.status;
1716
+ }
1717
+ setSession(session) {
1718
+ this.session.set(session);
1719
+ }
1720
+ onSessionChange(listener) {
1721
+ return this.session.onChange(listener);
1722
+ }
1723
+ fetchInvoices(params) {
1724
+ const query = new URLSearchParams({
1725
+ limit: String(Math.min(params.limit, INVOICE_MAX_PAGE_SIZE)),
1726
+ offset: String(params.offset)
1727
+ });
1728
+ if (params.includePending !== void 0) {
1729
+ query.set("include_pending", String(params.includePending));
1730
+ }
1731
+ const path = `/company/invoices?${query}`;
1732
+ return this.session.request(path).then((body) => {
1733
+ if (body === null || typeof body !== "object" || !("data" in body)) {
1734
+ throw new Error(`Malformed response from ${path}`);
1735
+ }
1736
+ const data = body.data;
1737
+ if (data == null || data.invoices == null) {
1738
+ return { invoices: [], count: 0 };
1739
+ }
1740
+ const decoded = GetCompanyInvoicesResponseFromJSON(body).data;
1741
+ return { invoices: decoded.invoices, count: decoded.count };
1742
+ });
1743
+ }
1744
+ };
1745
+ async function fetchBillingData(client, options = {}) {
1746
+ const wanted = options.names ?? ["invoices"];
1747
+ const data = {};
1748
+ const invoices = options.invoices === void 0 ? void 0 : normalizeInvoiceQuery(options.invoices);
1749
+ if (invoices !== void 0) {
1750
+ data.params = { invoices };
1751
+ }
1752
+ data.sessionKey = client.sessionKey;
1753
+ await Promise.all(
1754
+ wanted.map(async (name) => {
1755
+ try {
1756
+ switch (name) {
1757
+ case "invoices": {
1758
+ const page = await client.fetchInvoices({
1759
+ ...invoices ?? {},
1760
+ limit: INVOICE_PAGE_SIZE,
1761
+ offset: 0
1762
+ });
1763
+ data.invoices = {
1764
+ invoices: page.invoices,
1765
+ count: page.count,
1766
+ // Two queries on the server: a count that outran the rows
1767
+ // would seed a page that pages nothing.
1768
+ hasMore: page.invoices.length > 0 && page.invoices.length < page.count
1769
+ };
1770
+ break;
1771
+ }
1772
+ }
1773
+ } catch {
1774
+ }
1775
+ })
1776
+ );
1777
+ return data;
1778
+ }
1176
1779
 
1177
1780
  // src/index.ts
1178
1781
  var anonymousIdKey = "schematicId";
@@ -1181,9 +1784,9 @@ var flagStateCacheMaxContexts = 10;
1181
1784
  var flagStateCacheDefaultMaxAgeMs = 7 * 24 * 60 * 60 * 1e3;
1182
1785
  var emptyCreditBalances = Object.freeze({});
1183
1786
  var Schematic = class {
1184
- additionalHeaders = {};
1787
+ _additionalHeaders = {};
1185
1788
  apiKey;
1186
- apiUrl = "https://api.schematichq.com";
1789
+ _apiUrl = "https://api.schematichq.com";
1187
1790
  conn = null;
1188
1791
  context = {};
1189
1792
  debugEnabled = false;
@@ -1263,7 +1866,7 @@ var Schematic = class {
1263
1866
  if (this.offlineEnabled) {
1264
1867
  this.setIsPending(false);
1265
1868
  }
1266
- this.additionalHeaders = {
1869
+ this._additionalHeaders = {
1267
1870
  "X-Schematic-Client-Version": `schematic-js@${version}`,
1268
1871
  ...options?.additionalHeaders ?? {}
1269
1872
  };
@@ -1279,7 +1882,7 @@ var Schematic = class {
1279
1882
  }
1280
1883
  this.hydrateFlagStateFromCache();
1281
1884
  if (options?.apiUrl !== void 0) {
1282
- this.apiUrl = options.apiUrl;
1885
+ this._apiUrl = options.apiUrl;
1283
1886
  }
1284
1887
  if (options?.eventUrl !== void 0) {
1285
1888
  this.eventUrl = options.eventUrl;
@@ -1344,6 +1947,12 @@ var Schematic = class {
1344
1947
  this.debug("Initialized with debug mode enabled");
1345
1948
  }
1346
1949
  }
1950
+ get apiUrl() {
1951
+ return this._apiUrl;
1952
+ }
1953
+ get additionalHeaders() {
1954
+ return { ...this._additionalHeaders };
1955
+ }
1347
1956
  /**
1348
1957
  * Resolve fallback value according to priority order:
1349
1958
  * 1. Callsite fallback value (if provided)
@@ -1429,11 +2038,11 @@ var Schematic = class {
1429
2038
  return resolvedFallbackResult.value;
1430
2039
  }
1431
2040
  if (!this.useWebSocket) {
1432
- const requestUrl = `${this.apiUrl}/flags/${key}/check`;
2041
+ const requestUrl = `${this._apiUrl}/flags/${key}/check`;
1433
2042
  return fetch(requestUrl, {
1434
2043
  method: "POST",
1435
2044
  headers: {
1436
- ...this.additionalHeaders ?? {},
2045
+ ...this._additionalHeaders ?? {},
1437
2046
  "Content-Type": "application/json;charset=UTF-8",
1438
2047
  "X-Schematic-Api-Key": this.apiKey
1439
2048
  },
@@ -1636,12 +2245,12 @@ var Schematic = class {
1636
2245
  this.debug(`checkFlags offline result: returning empty object`);
1637
2246
  return {};
1638
2247
  }
1639
- const requestUrl = `${this.apiUrl}/flags/check`;
2248
+ const requestUrl = `${this._apiUrl}/flags/check`;
1640
2249
  const requestBody = JSON.stringify(context);
1641
2250
  return fetch(requestUrl, {
1642
2251
  method: "POST",
1643
2252
  headers: {
1644
- ...this.additionalHeaders ?? {},
2253
+ ...this._additionalHeaders ?? {},
1645
2254
  "Content-Type": "application/json;charset=UTF-8",
1646
2255
  "X-Schematic-Api-Key": this.apiKey
1647
2256
  },
@@ -2188,7 +2797,7 @@ var Schematic = class {
2188
2797
  const response = await fetch(captureUrl, {
2189
2798
  method: "POST",
2190
2799
  headers: {
2191
- ...this.additionalHeaders ?? {},
2800
+ ...this._additionalHeaders ?? {},
2192
2801
  "Content-Type": "application/json;charset=UTF-8"
2193
2802
  },
2194
2803
  body: payload
@@ -2684,7 +3293,7 @@ var Schematic = class {
2684
3293
  }
2685
3294
  });
2686
3295
  this.currentWebSocket = socket;
2687
- const clientVersion = this.additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
3296
+ const clientVersion = this._additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
2688
3297
  const messagePayload = {
2689
3298
  apiKey: this.apiKey,
2690
3299
  clientVersion,
@@ -2922,11 +3531,23 @@ export {
2922
3531
  CheckFlagsResponseFromJSON,
2923
3532
  CheckPlanReturnFromJSON,
2924
3533
  CreditBalancesFromJSON,
3534
+ DEFAULT_INVOICE_QUERY,
2925
3535
  DatastreamCompanyPlanFromJSON,
2926
3536
  EventBodyFlagCheckToJSON,
3537
+ INVOICE_MAX_PAGE_SIZE,
3538
+ INVOICE_PAGE_SIZE,
3539
+ InvoiceStatus,
2927
3540
  RuleType,
2928
3541
  Schematic,
3542
+ SchematicApiError,
3543
+ SchematicBillingClient,
3544
+ SchematicSession,
3545
+ TOKEN_CACHE_SIZE,
2929
3546
  TrialStatus,
2930
- UsagePeriod
3547
+ UsagePeriod,
3548
+ models_exports as billingApi,
3549
+ fetchBillingData,
3550
+ normalizeInvoiceQuery,
3551
+ sessionKey
2931
3552
  };
2932
3553
  /* @preserve */