@pymthouse/builder-sdk 0.0.8 → 0.1.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.
package/dist/index.cjs CHANGED
@@ -1,8 +1,31 @@
1
1
  'use strict';
2
2
 
3
3
  var oauth4webapi = require('oauth4webapi');
4
+ var crypto = require('crypto');
4
5
 
5
6
  // src/usage.ts
7
+ function parseSafeBigInt(value, fallback = 0n) {
8
+ try {
9
+ return BigInt(value);
10
+ } catch {
11
+ return fallback;
12
+ }
13
+ }
14
+ function getUtcCalendarMonthIsoBounds(now = /* @__PURE__ */ new Date()) {
15
+ const y = now.getUTCFullYear();
16
+ const m = now.getUTCMonth();
17
+ const start = new Date(Date.UTC(y, m, 1, 0, 0, 0, 0));
18
+ const end = new Date(Date.UTC(y, m + 1, 0, 23, 59, 59, 999));
19
+ return { startDate: start.toISOString(), endDate: end.toISOString() };
20
+ }
21
+ function parseUsageDateParam(raw) {
22
+ if (raw == null) return null;
23
+ const trimmed = raw.trim();
24
+ if (!trimmed) return null;
25
+ const t = Date.parse(trimmed);
26
+ if (Number.isNaN(t)) return null;
27
+ return trimmed;
28
+ }
6
29
  function aggregateUsageByExternalUserId(byUser, externalUserId) {
7
30
  const rows = byUser?.filter((row) => row.externalUserId === externalUserId) ?? [];
8
31
  if (rows.length === 0) {
@@ -15,7 +38,9 @@ function aggregateUsageByExternalUserId(byUser, externalUserId) {
15
38
  let feeWei = 0n;
16
39
  let requestCount = 0;
17
40
  for (const row of rows) {
18
- feeWei += BigInt(row.feeWei);
41
+ if (row.feeWei) {
42
+ feeWei += BigInt(row.feeWei);
43
+ }
19
44
  requestCount += row.requestCount;
20
45
  }
21
46
  return {
@@ -35,6 +60,107 @@ function listUsageByPipelineModel(usage) {
35
60
  return a.modelId.localeCompare(b.modelId);
36
61
  });
37
62
  }
63
+ function getEndUserIdsForExternalUser(usage, externalUserId) {
64
+ const userIds = /* @__PURE__ */ new Set();
65
+ for (const row of usage.byUser ?? []) {
66
+ if (row.externalUserId === externalUserId && row.endUserId !== "unknown") {
67
+ userIds.add(row.endUserId);
68
+ }
69
+ }
70
+ return [...userIds];
71
+ }
72
+ var getUsageRecordUserIdsForExternalUser = getEndUserIdsForExternalUser;
73
+ function summarizeUsageFiatForExternalUser(usageByUser, externalUserId) {
74
+ const rows = usageByUser.byUser ?? [];
75
+ let requestCount = 0;
76
+ let networkFeeUsdMicros = 0n;
77
+ let ownerChargeUsdMicros = 0n;
78
+ let endUserBillableUsdMicros = 0n;
79
+ let currency = "USD";
80
+ for (const row of rows) {
81
+ if (row.externalUserId !== externalUserId) continue;
82
+ requestCount += row.requestCount;
83
+ if (row.currency) currency = row.currency;
84
+ if (row.networkFeeUsdMicros) {
85
+ networkFeeUsdMicros += BigInt(row.networkFeeUsdMicros);
86
+ }
87
+ if (row.ownerChargeUsdMicros) {
88
+ ownerChargeUsdMicros += BigInt(row.ownerChargeUsdMicros);
89
+ }
90
+ if (row.endUserBillableUsdMicros) {
91
+ endUserBillableUsdMicros += BigInt(row.endUserBillableUsdMicros);
92
+ }
93
+ }
94
+ return {
95
+ externalUserId,
96
+ requestCount,
97
+ currency,
98
+ networkFeeUsdMicros: networkFeeUsdMicros.toString(),
99
+ ownerChargeUsdMicros: ownerChargeUsdMicros.toString(),
100
+ endUserBillableUsdMicros: endUserBillableUsdMicros.toString()
101
+ };
102
+ }
103
+ function mergeUsageByPipelineModel(usagePipelineModels) {
104
+ let responses;
105
+ if (Array.isArray(usagePipelineModels)) {
106
+ responses = usagePipelineModels;
107
+ } else if (usagePipelineModels) {
108
+ responses = [usagePipelineModels];
109
+ } else {
110
+ responses = [];
111
+ }
112
+ const byKey = /* @__PURE__ */ new Map();
113
+ for (const response of responses) {
114
+ for (const row of response.byPipelineModel ?? []) {
115
+ const { pipeline, modelId } = row;
116
+ if (!pipeline || !modelId) continue;
117
+ const key = JSON.stringify([pipeline, modelId]);
118
+ const existing = byKey.get(key);
119
+ const rowCurrency = row.currency ?? "USD";
120
+ if (!existing) {
121
+ byKey.set(key, {
122
+ pipeline,
123
+ modelId,
124
+ requestCount: row.requestCount,
125
+ currency: rowCurrency,
126
+ networkFeeUsdMicros: row.networkFeeUsdMicros,
127
+ ownerChargeUsdMicros: row.ownerChargeUsdMicros,
128
+ endUserBillableUsdMicros: row.endUserBillableUsdMicros
129
+ });
130
+ continue;
131
+ }
132
+ byKey.set(key, {
133
+ ...existing,
134
+ requestCount: existing.requestCount + row.requestCount,
135
+ networkFeeUsdMicros: (parseSafeBigInt(existing.networkFeeUsdMicros) + parseSafeBigInt(row.networkFeeUsdMicros)).toString(),
136
+ ownerChargeUsdMicros: (parseSafeBigInt(existing.ownerChargeUsdMicros) + parseSafeBigInt(row.ownerChargeUsdMicros)).toString(),
137
+ endUserBillableUsdMicros: (parseSafeBigInt(existing.endUserBillableUsdMicros) + parseSafeBigInt(row.endUserBillableUsdMicros)).toString()
138
+ });
139
+ }
140
+ }
141
+ return [...byKey.values()].sort((a, b) => {
142
+ if (a.pipeline === b.pipeline) return a.modelId.localeCompare(b.modelId);
143
+ return a.pipeline.localeCompare(b.pipeline);
144
+ });
145
+ }
146
+ function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineModel) {
147
+ const summary = summarizeUsageFiatForExternalUser(usageByUser, externalUserId);
148
+ const pipelineModels = mergeUsageByPipelineModel(usagePipelineModel);
149
+ return {
150
+ clientId: usageByUser.clientId,
151
+ period: usageByUser.period,
152
+ currentUser: {
153
+ externalUserId: summary.externalUserId,
154
+ requestCount: summary.requestCount,
155
+ currency: summary.currency,
156
+ networkFeeUsdMicros: summary.networkFeeUsdMicros,
157
+ ownerChargeUsdMicros: summary.ownerChargeUsdMicros,
158
+ endUserBillableUsdMicros: summary.endUserBillableUsdMicros,
159
+ pipelineModels
160
+ }
161
+ };
162
+ }
163
+ var DEFAULT_MAX_END_USER_IDS = 25;
38
164
 
39
165
  // src/encoding.ts
40
166
  function encodeClientSecretBasic(clientId, clientSecret) {
@@ -181,6 +307,103 @@ function mapDiscoveryNetworkError(error) {
181
307
  code: "oidc_discovery_failed"
182
308
  });
183
309
  }
310
+ function parseAppManifestResponse(json) {
311
+ if (!json || typeof json !== "object" || Array.isArray(json)) {
312
+ return { capabilities: [], excludedCapabilities: [] };
313
+ }
314
+ const record = json;
315
+ const capabilities = parseCapabilityArray(record.capabilities);
316
+ const excludedCapabilities = parseCapabilityArray(record.excludedCapabilities);
317
+ const manifestVersion = typeof record.manifestVersion === "string" && record.manifestVersion.trim() ? record.manifestVersion.trim() : void 0;
318
+ return { capabilities, excludedCapabilities, manifestVersion };
319
+ }
320
+ function parseCapabilityArray(raw) {
321
+ if (!Array.isArray(raw)) return [];
322
+ return raw.filter(
323
+ (c) => !!c && typeof c === "object" && typeof c.pipeline === "string" && typeof c.modelId === "string"
324
+ );
325
+ }
326
+ function sortedCaps(caps) {
327
+ return [...caps].sort((a, b) => {
328
+ const p = a.pipeline.localeCompare(b.pipeline);
329
+ return p === 0 ? a.modelId.localeCompare(b.modelId) : p;
330
+ });
331
+ }
332
+ function computeManifestRevision(data) {
333
+ if (data == null) {
334
+ return "unavailable";
335
+ }
336
+ if (data.manifestVersion?.trim()) {
337
+ return data.manifestVersion.trim();
338
+ }
339
+ const caps = sortedCaps(data.capabilities ?? []);
340
+ const excl = sortedCaps(data.excludedCapabilities ?? []);
341
+ if (caps.length === 0 && excl.length === 0) {
342
+ return "empty";
343
+ }
344
+ return crypto.createHash("sha256").update(JSON.stringify({ capabilities: caps, excludedCapabilities: excl })).digest("hex").slice(0, 24);
345
+ }
346
+
347
+ // src/tokens.ts
348
+ var SIGNER_SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
349
+ var SIGNER_SESSION_EXPIRES_IN_SEC = Math.floor(SIGNER_SESSION_TTL_MS / 1e3);
350
+ var SIGN_JOB_SCOPE = "sign:job";
351
+ var PYMTHOUSE_SIGNER_SESSION_TTL_MS = SIGNER_SESSION_TTL_MS;
352
+ function computeSignerSessionExpiry(input) {
353
+ const createdAt = input instanceof Date ? input : new Date(input);
354
+ return new Date(createdAt.getTime() + SIGNER_SESSION_TTL_MS);
355
+ }
356
+ var computePymthouseExpiry = computeSignerSessionExpiry;
357
+ function isLikelyOidcJwt(rawToken) {
358
+ const t = rawToken.trim();
359
+ return t.startsWith("eyJ") && t.split(".").length >= 3;
360
+ }
361
+ function isOpaqueSignerSessionToken(rawToken) {
362
+ const t = rawToken.trim();
363
+ return t.length > 0 && !isLikelyOidcJwt(t);
364
+ }
365
+ function base64UrlPayloadToUtf8(payloadB64) {
366
+ const normalized = payloadB64.replaceAll("-", "+").replaceAll("_", "/");
367
+ const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
368
+ if (typeof Buffer !== "undefined") {
369
+ return Buffer.from(padded, "base64").toString("utf8");
370
+ }
371
+ return atob(padded);
372
+ }
373
+ function decodeJwtExp(rawToken) {
374
+ try {
375
+ const parts = rawToken.split(".");
376
+ if (parts.length < 2) return null;
377
+ const payloadJson = base64UrlPayloadToUtf8(parts[1]);
378
+ const payload = JSON.parse(payloadJson);
379
+ if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp)) return null;
380
+ const expMs = Math.floor(payload.exp * 1e3);
381
+ if (expMs <= 0) return null;
382
+ return new Date(expMs);
383
+ } catch {
384
+ return null;
385
+ }
386
+ }
387
+ function parseSignerSessionExchange(res) {
388
+ const accessToken = typeof res.access_token === "string" ? res.access_token.trim() : "";
389
+ if (!accessToken) {
390
+ throw new Error("PymtHouse signer session exchange returned no access_token");
391
+ }
392
+ if (isLikelyOidcJwt(accessToken)) {
393
+ throw new Error(
394
+ "PymtHouse signer session exchange returned a JWT; expected opaque signer session token"
395
+ );
396
+ }
397
+ const tokenType = typeof res.token_type === "string" && res.token_type.trim() ? res.token_type.trim() : "Bearer";
398
+ const expiresIn = typeof res.expires_in === "number" && Number.isFinite(res.expires_in) && res.expires_in > 0 ? Math.floor(res.expires_in) : SIGNER_SESSION_EXPIRES_IN_SEC;
399
+ const scope = typeof res.scope === "string" && res.scope.trim() ? res.scope.trim() : SIGN_JOB_SCOPE;
400
+ return {
401
+ accessToken,
402
+ tokenType,
403
+ expiresIn,
404
+ scope
405
+ };
406
+ }
184
407
  var ACCEPTED_ISSUED_TOKEN_TYPES = /* @__PURE__ */ new Set([
185
408
  "urn:ietf:params:oauth:token-type:access_token",
186
409
  "urn:pmth:token-type:remote-signer-session"
@@ -536,6 +759,126 @@ var PmtHouseClient = class {
536
759
  cache: "no-store"
537
760
  });
538
761
  }
762
+ /**
763
+ * Session-scoped usage for one `externalUserId`: user rollup plus merged pipeline/model breakdown.
764
+ */
765
+ async fetchUsageForExternalUser(input) {
766
+ const usageByUser = await this.getUsage({
767
+ startDate: input.startDate,
768
+ endDate: input.endDate,
769
+ groupBy: "user"
770
+ });
771
+ const userIds = getEndUserIdsForExternalUser(usageByUser, input.externalUserId);
772
+ const cap = input.maxEndUserIds ?? DEFAULT_MAX_END_USER_IDS;
773
+ const cappedUserIds = userIds.slice(0, cap);
774
+ const usagePipelineModels = await Promise.all(
775
+ cappedUserIds.map(
776
+ (userId) => this.getUsage({
777
+ startDate: input.startDate,
778
+ endDate: input.endDate,
779
+ groupBy: "pipeline_model",
780
+ userId
781
+ })
782
+ )
783
+ );
784
+ return buildMeScopeUsagePayload(usageByUser, input.externalUserId, usagePipelineModels);
785
+ }
786
+ async getAppManifest(opts) {
787
+ const url = `${this.getAppsBaseUrl()}/manifest`;
788
+ const headers = {
789
+ ...this.builderHeadersRecord()
790
+ };
791
+ if (opts?.ifNoneMatch) {
792
+ headers["If-None-Match"] = opts.ifNoneMatch;
793
+ }
794
+ this.logger?.debug?.("PmtHouse request", { method: "GET", url });
795
+ const response = await this.fetchImpl(url, {
796
+ method: "GET",
797
+ headers,
798
+ signal: opts?.signal,
799
+ cache: "no-store"
800
+ });
801
+ const etag = response.headers.get("etag")?.trim() ?? null;
802
+ if (response.status === 304) {
803
+ return {
804
+ manifest: null,
805
+ etag: etag ?? opts?.ifNoneMatch ?? null,
806
+ notModified: true
807
+ };
808
+ }
809
+ const raw = await response.text();
810
+ const ct = response.headers.get("content-type") ?? "";
811
+ const looksJson = ct.includes("application/json") || ct.includes("json");
812
+ const parsed = raw && looksJson ? this.safeParseJson(raw) : null;
813
+ if (!response.ok) {
814
+ const details = parsed ?? {};
815
+ let description;
816
+ if (typeof details.error_description === "string") {
817
+ description = details.error_description;
818
+ } else if (typeof details.error === "string") {
819
+ description = details.error;
820
+ } else {
821
+ description = `Request failed (${response.status})`;
822
+ }
823
+ throw new PmtHouseError(description, {
824
+ status: response.status,
825
+ code: typeof details.error === "string" ? details.error : "pymthouse_http_error",
826
+ details
827
+ });
828
+ }
829
+ if (!looksJson || parsed === null) {
830
+ throw new PmtHouseError("Expected JSON response from Builder manifest endpoint", {
831
+ status: 502,
832
+ code: "invalid_response",
833
+ details: { contentType: ct, preview: raw.slice(0, 200) }
834
+ });
835
+ }
836
+ return {
837
+ manifest: parseAppManifestResponse(parsed),
838
+ etag,
839
+ notModified: false
840
+ };
841
+ }
842
+ /**
843
+ * Upsert an external user, mint a short-lived JWT, and exchange for an opaque signer session.
844
+ */
845
+ async mintSignerSessionForExternalUser(input) {
846
+ await this.upsertAppUser({
847
+ externalUserId: input.externalUserId,
848
+ email: input.email,
849
+ status: "active"
850
+ });
851
+ const exchange = await this.mintUserSignerSessionToken({
852
+ externalUserId: input.externalUserId,
853
+ scope: input.scope ?? SIGN_JOB_SCOPE,
854
+ resource: this.issuerUrl
855
+ });
856
+ return parseSignerSessionExchange(exchange);
857
+ }
858
+ /**
859
+ * Approve a pending RFC 8628 device code for an external user (Option B).
860
+ */
861
+ async approveDeviceLogin(input) {
862
+ if (input.publicClientId && input.publicClientId !== this.publicClientId) {
863
+ throw new PmtHouseError(
864
+ "publicClientId does not match configured public client id",
865
+ { status: 400, code: "invalid_client" }
866
+ );
867
+ }
868
+ await this.upsertAppUser({
869
+ externalUserId: input.externalUserId,
870
+ email: input.email,
871
+ status: "active"
872
+ });
873
+ const userToken = await this.mintUserAccessToken({
874
+ externalUserId: input.externalUserId,
875
+ scope: SIGN_JOB_SCOPE
876
+ });
877
+ await this.completeDeviceApproval({
878
+ userJwt: userToken.access_token,
879
+ userCode: input.userCode
880
+ });
881
+ }
539
882
  tokenEndpointFetchOptions() {
540
883
  const o = {
541
884
  [oauth4webapi.customFetch]: this.fetchImpl
@@ -552,6 +895,9 @@ var PmtHouseClient = class {
552
895
  return new URL(this.issuerUrl).origin;
553
896
  }
554
897
  builderHeaders() {
898
+ return this.builderHeadersRecord();
899
+ }
900
+ builderHeadersRecord() {
555
901
  return {
556
902
  Authorization: encodeClientSecretBasic(this.m2mClientId, this.m2mClientSecret),
557
903
  "Content-Type": "application/json",
@@ -575,7 +921,14 @@ var PmtHouseClient = class {
575
921
  const parsed = raw && looksJson ? this.safeParseJson(raw) : raw ? null : null;
576
922
  if (!response.ok) {
577
923
  const details = parsed ?? {};
578
- const description = typeof details.error_description === "string" ? details.error_description : typeof details.error === "string" ? details.error : `Request failed (${response.status})`;
924
+ let description;
925
+ if (typeof details.error_description === "string") {
926
+ description = details.error_description;
927
+ } else if (typeof details.error === "string") {
928
+ description = details.error;
929
+ } else {
930
+ description = `Request failed (${response.status})`;
931
+ }
579
932
  throw new PmtHouseError(description, {
580
933
  status: response.status,
581
934
  code: typeof details.error === "string" ? details.error : "pymthouse_http_error",
@@ -618,67 +971,89 @@ var PmtHouseClient = class {
618
971
  }
619
972
  };
620
973
 
621
- // src/env.ts
622
- function assertEnvModuleServerOnly() {
623
- if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined") {
624
- throw new Error(
625
- "@pymthouse/builder-sdk/env is server-only: do not import createPmtHouseClientFromEnv or getPymthouseBaseUrl in client-side code. Use a Route Handler, Server Action, or other server/runtime; keep M2M credentials out of the browser bundle."
626
- );
974
+ // src/config.ts
975
+ var PYMTHOUSE_NOT_CONFIGURED_MESSAGE = "PymtHouse is not configured. Set PYMTHOUSE_ISSUER_URL, PYMTHOUSE_PUBLIC_CLIENT_ID, PYMTHOUSE_M2M_CLIENT_ID, and PYMTHOUSE_M2M_CLIENT_SECRET, then restart.";
976
+ function trimEnv(name) {
977
+ const value = process.env[name];
978
+ if (!value) return null;
979
+ const trimmed = value.trim();
980
+ return trimmed || null;
981
+ }
982
+ function readPymthouseEnv() {
983
+ const issuerUrl = trimEnv("PYMTHOUSE_ISSUER_URL");
984
+ const publicClientId = trimEnv("PYMTHOUSE_PUBLIC_CLIENT_ID");
985
+ const m2mClientId = trimEnv("PYMTHOUSE_M2M_CLIENT_ID");
986
+ const m2mClientSecret = trimEnv("PYMTHOUSE_M2M_CLIENT_SECRET");
987
+ if (!issuerUrl || !publicClientId || !m2mClientId || !m2mClientSecret) {
988
+ return null;
627
989
  }
990
+ return {
991
+ issuerUrl: stripTrailingSlashes(issuerUrl),
992
+ publicClientId,
993
+ m2mClientId,
994
+ m2mClientSecret
995
+ };
628
996
  }
629
- assertEnvModuleServerOnly();
630
- var cachedClient = null;
631
- function requiredEnv(name) {
632
- const value = process.env[name];
633
- if (value && value.trim()) {
634
- return value.trim();
997
+ function getPymthouseIssuerUrlFromEnv() {
998
+ const raw = trimEnv("PYMTHOUSE_ISSUER_URL");
999
+ if (!raw) return null;
1000
+ try {
1001
+ return stripTrailingSlashes(new URL(raw).href);
1002
+ } catch {
1003
+ return null;
635
1004
  }
636
- throw new PmtHouseError(`Missing required environment variable: ${name}`, {
637
- status: 500,
638
- code: "missing_env"
639
- });
640
1005
  }
641
- function getPymthouseBaseUrl() {
642
- const issuerUrl = requiredEnv("PYMTHOUSE_ISSUER_URL");
643
- return new URL(stripTrailingSlashes(issuerUrl)).origin;
644
- }
645
- function createPmtHouseClientFromEnv() {
646
- if (cachedClient) {
647
- return cachedClient;
648
- }
649
- const issuerUrl = requiredEnv("PYMTHOUSE_ISSUER_URL");
650
- cachedClient = new PmtHouseClient({
651
- issuerUrl,
652
- publicClientId: requiredEnv("PYMTHOUSE_PUBLIC_CLIENT_ID"),
653
- m2mClientId: requiredEnv("PYMTHOUSE_M2M_CLIENT_ID"),
654
- m2mClientSecret: requiredEnv("PYMTHOUSE_M2M_CLIENT_SECRET"),
655
- allowInsecureHttp: issuerUrl.startsWith("http:"),
656
- logger: {
657
- debug: (message, details) => {
658
- if (process.env.NODE_ENV !== "production") {
659
- console.debug(`[pymthouse] ${message}`, details ?? {});
660
- }
661
- },
662
- warn: (message, details) => {
663
- console.warn(`[pymthouse] ${message}`, details ?? {});
664
- }
665
- }
666
- });
667
- return cachedClient;
1006
+ function getPymthousePublicClientIdFromEnv() {
1007
+ return trimEnv("PYMTHOUSE_PUBLIC_CLIENT_ID");
1008
+ }
1009
+ function isPymthouseConfigured() {
1010
+ return readPymthouseEnv() !== null;
1011
+ }
1012
+ function getBuilderApiV1BaseFromIssuerUrl(issuerUrl) {
1013
+ const noTrail = stripTrailingSlashes(issuerUrl.trim());
1014
+ return noTrail.replace(/\/oidc\/?$/i, "");
1015
+ }
1016
+ function getPymthouseIssuerOrigin(issuerUrl) {
1017
+ return new URL(stripTrailingSlashes(issuerUrl.trim())).origin;
668
1018
  }
669
1019
 
1020
+ exports.DEFAULT_MAX_END_USER_IDS = DEFAULT_MAX_END_USER_IDS;
1021
+ exports.PYMTHOUSE_NOT_CONFIGURED_MESSAGE = PYMTHOUSE_NOT_CONFIGURED_MESSAGE;
1022
+ exports.PYMTHOUSE_SIGNER_SESSION_TTL_MS = PYMTHOUSE_SIGNER_SESSION_TTL_MS;
670
1023
  exports.PmtHouseClient = PmtHouseClient;
671
1024
  exports.PmtHouseError = PmtHouseError;
1025
+ exports.SIGNER_SESSION_EXPIRES_IN_SEC = SIGNER_SESSION_EXPIRES_IN_SEC;
1026
+ exports.SIGNER_SESSION_TTL_MS = SIGNER_SESSION_TTL_MS;
1027
+ exports.SIGN_JOB_SCOPE = SIGN_JOB_SCOPE;
672
1028
  exports.aggregateUsageByExternalUserId = aggregateUsageByExternalUserId;
673
1029
  exports.authorizationServerToOidcDocument = authorizationServerToOidcDocument;
674
1030
  exports.buildDeviceCodeResource = buildDeviceCodeResource;
1031
+ exports.buildMeScopeUsagePayload = buildMeScopeUsagePayload;
675
1032
  exports.clearDiscoveryCache = clearDiscoveryCache;
676
- exports.createPmtHouseClientFromEnv = createPmtHouseClientFromEnv;
1033
+ exports.computeManifestRevision = computeManifestRevision;
1034
+ exports.computePymthouseExpiry = computePymthouseExpiry;
1035
+ exports.computeSignerSessionExpiry = computeSignerSessionExpiry;
1036
+ exports.decodeJwtExp = decodeJwtExp;
677
1037
  exports.fetchDiscoveryDocument = fetchDiscoveryDocument;
678
- exports.getPymthouseBaseUrl = getPymthouseBaseUrl;
1038
+ exports.getBuilderApiV1BaseFromIssuerUrl = getBuilderApiV1BaseFromIssuerUrl;
1039
+ exports.getEndUserIdsForExternalUser = getEndUserIdsForExternalUser;
1040
+ exports.getPymthouseIssuerOrigin = getPymthouseIssuerOrigin;
1041
+ exports.getPymthouseIssuerUrlFromEnv = getPymthouseIssuerUrlFromEnv;
1042
+ exports.getPymthousePublicClientIdFromEnv = getPymthousePublicClientIdFromEnv;
1043
+ exports.getUsageRecordUserIdsForExternalUser = getUsageRecordUserIdsForExternalUser;
1044
+ exports.getUtcCalendarMonthIsoBounds = getUtcCalendarMonthIsoBounds;
1045
+ exports.isLikelyOidcJwt = isLikelyOidcJwt;
1046
+ exports.isOpaqueSignerSessionToken = isOpaqueSignerSessionToken;
1047
+ exports.isPymthouseConfigured = isPymthouseConfigured;
679
1048
  exports.listUsageByPipelineModel = listUsageByPipelineModel;
680
1049
  exports.loadAuthorizationServer = loadAuthorizationServer;
1050
+ exports.mergeUsageByPipelineModel = mergeUsageByPipelineModel;
681
1051
  exports.normalizeUserCode = normalizeUserCode;
1052
+ exports.parseAppManifestResponse = parseAppManifestResponse;
1053
+ exports.parseSignerSessionExchange = parseSignerSessionExchange;
1054
+ exports.parseUsageDateParam = parseUsageDateParam;
1055
+ exports.readPymthouseEnv = readPymthouseEnv;
1056
+ exports.summarizeUsageFiatForExternalUser = summarizeUsageFiatForExternalUser;
682
1057
  exports.summarizeUsageForExternalUser = summarizeUsageForExternalUser;
683
1058
  exports.toPmtHouseError = toPmtHouseError;
684
1059
  //# sourceMappingURL=index.cjs.map