@pymthouse/builder-sdk 0.1.0 → 0.3.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.
Files changed (77) hide show
  1. package/README.md +66 -0
  2. package/dist/{client-BroVFyIy.d.ts → client-BHfjDvIe.d.ts} +49 -1
  3. package/dist/{client-BhC1YhB1.d.cts → client-CvhJEhjV.d.cts} +49 -1
  4. package/dist/config.cjs +59 -3
  5. package/dist/config.cjs.map +1 -1
  6. package/dist/config.d.cts +8 -1
  7. package/dist/config.d.ts +8 -1
  8. package/dist/config.js +57 -4
  9. package/dist/config.js.map +1 -1
  10. package/dist/device-initiate.cjs +1 -1
  11. package/dist/device-initiate.cjs.map +1 -1
  12. package/dist/device-initiate.js +1 -1
  13. package/dist/device-initiate.js.map +1 -1
  14. package/dist/device.cjs +1 -1
  15. package/dist/device.cjs.map +1 -1
  16. package/dist/device.d.cts +1 -1
  17. package/dist/device.d.ts +1 -1
  18. package/dist/device.js +1 -1
  19. package/dist/device.js.map +1 -1
  20. package/dist/env.cjs +794 -36
  21. package/dist/env.cjs.map +1 -1
  22. package/dist/env.d.cts +2 -2
  23. package/dist/env.d.ts +2 -2
  24. package/dist/env.js +794 -36
  25. package/dist/env.js.map +1 -1
  26. package/dist/gateway/client/index.cjs +492 -0
  27. package/dist/gateway/client/index.cjs.map +1 -0
  28. package/dist/gateway/client/index.d.cts +63 -0
  29. package/dist/gateway/client/index.d.ts +63 -0
  30. package/dist/gateway/client/index.js +489 -0
  31. package/dist/gateway/client/index.js.map +1 -0
  32. package/dist/gateway/index.cjs +16 -0
  33. package/dist/gateway/index.cjs.map +1 -0
  34. package/dist/gateway/index.d.cts +52 -0
  35. package/dist/gateway/index.d.ts +52 -0
  36. package/dist/gateway/index.js +10 -0
  37. package/dist/gateway/index.js.map +1 -0
  38. package/dist/gateway/server/index.cjs +1248 -0
  39. package/dist/gateway/server/index.cjs.map +1 -0
  40. package/dist/gateway/server/index.d.cts +31 -0
  41. package/dist/gateway/server/index.d.ts +31 -0
  42. package/dist/gateway/server/index.js +1233 -0
  43. package/dist/gateway/server/index.js.map +1 -0
  44. package/dist/index.cjs +1075 -186
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.d.cts +6 -4
  47. package/dist/index.d.ts +6 -4
  48. package/dist/index.js +1042 -163
  49. package/dist/index.js.map +1 -1
  50. package/dist/ingest-B3Yi8Tb1.d.cts +271 -0
  51. package/dist/ingest-DoKJTWU9.d.ts +271 -0
  52. package/dist/plan-pricing.cjs +108 -0
  53. package/dist/plan-pricing.cjs.map +1 -0
  54. package/dist/plan-pricing.d.cts +15 -0
  55. package/dist/plan-pricing.d.ts +15 -0
  56. package/dist/plan-pricing.js +98 -0
  57. package/dist/plan-pricing.js.map +1 -0
  58. package/dist/signer/server.cjs +1366 -0
  59. package/dist/signer/server.cjs.map +1 -0
  60. package/dist/signer/server.d.cts +73 -0
  61. package/dist/signer/server.d.ts +73 -0
  62. package/dist/signer/server.js +1331 -0
  63. package/dist/signer/server.js.map +1 -0
  64. package/dist/tokens.d.cts +1 -1
  65. package/dist/tokens.d.ts +1 -1
  66. package/dist/types-_R1AwEZp.d.cts +343 -0
  67. package/dist/types-_R1AwEZp.d.ts +343 -0
  68. package/dist/verify.cjs +1 -1
  69. package/dist/verify.cjs.map +1 -1
  70. package/dist/verify.d.cts +1 -1
  71. package/dist/verify.d.ts +1 -1
  72. package/dist/verify.js +1 -1
  73. package/dist/verify.js.map +1 -1
  74. package/gateway/proto/lp_rpc.proto +542 -0
  75. package/package.json +42 -1
  76. package/dist/types-rKzVXvMu.d.cts +0 -196
  77. package/dist/types-rKzVXvMu.d.ts +0 -196
package/dist/index.cjs CHANGED
@@ -3,6 +3,830 @@
3
3
  var oauth4webapi = require('oauth4webapi');
4
4
  var crypto = require('crypto');
5
5
 
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+
16
+ // src/encoding.ts
17
+ function encodeClientSecretBasic(clientId, clientSecret) {
18
+ const raw = `${clientId}:${clientSecret}`;
19
+ const b64 = typeof Buffer !== "undefined" ? Buffer.from(raw, "utf8").toString("base64") : btoa(Array.from(new TextEncoder().encode(raw), (c) => String.fromCharCode(c)).join(""));
20
+ return `Basic ${b64}`;
21
+ }
22
+ var init_encoding = __esm({
23
+ "src/encoding.ts"() {
24
+ }
25
+ });
26
+
27
+ // src/errors.ts
28
+ function toPmtHouseError(error, fallbackMessage) {
29
+ if (error instanceof exports.PmtHouseError) {
30
+ return error;
31
+ }
32
+ if (error instanceof Error) {
33
+ return new exports.PmtHouseError(error.message || fallbackMessage, {
34
+ code: "unexpected_error",
35
+ status: 500
36
+ });
37
+ }
38
+ return new exports.PmtHouseError(fallbackMessage, {
39
+ code: "unexpected_error",
40
+ status: 500
41
+ });
42
+ }
43
+ exports.PmtHouseError = void 0;
44
+ var init_errors = __esm({
45
+ "src/errors.ts"() {
46
+ exports.PmtHouseError = class extends Error {
47
+ status;
48
+ code;
49
+ details;
50
+ constructor(message, {
51
+ status = 500,
52
+ code = "pymthouse_error",
53
+ details
54
+ } = {}) {
55
+ super(message);
56
+ this.name = "PmtHouseError";
57
+ this.status = status;
58
+ this.code = code;
59
+ this.details = details;
60
+ }
61
+ };
62
+ }
63
+ });
64
+
65
+ // src/string-utils.ts
66
+ function stripTrailingSlashes(value) {
67
+ let end = value.length;
68
+ while (end > 0 && (value.codePointAt(end - 1) ?? 0) === 47) {
69
+ end--;
70
+ }
71
+ return value.slice(0, end);
72
+ }
73
+ function endsWithIgnoreCase(value, suffix) {
74
+ if (suffix.length > value.length) {
75
+ return false;
76
+ }
77
+ const start = value.length - suffix.length;
78
+ for (let i = 0; i < suffix.length; i++) {
79
+ const a = value.codePointAt(start + i) ?? 0;
80
+ const b = suffix.codePointAt(i) ?? 0;
81
+ if (a !== b && (a | 32) !== (b | 32)) {
82
+ return false;
83
+ }
84
+ }
85
+ return true;
86
+ }
87
+ function stripSuffixIgnoreCase(value, suffix) {
88
+ return endsWithIgnoreCase(value, suffix) ? value.slice(0, value.length - suffix.length) : value;
89
+ }
90
+ function stripOidcPathSuffix(issuerUrl) {
91
+ let base = stripTrailingSlashes(issuerUrl.trim());
92
+ base = stripSuffixIgnoreCase(base, "/oidc");
93
+ return stripTrailingSlashes(base);
94
+ }
95
+ function stripIssuerOriginFromOidcUrl(issuerUrl) {
96
+ let base = stripTrailingSlashes(issuerUrl.trim());
97
+ base = stripSuffixIgnoreCase(base, "/api/v1/oidc");
98
+ base = stripSuffixIgnoreCase(base, "/oidc");
99
+ return stripTrailingSlashes(base);
100
+ }
101
+ var init_string_utils = __esm({
102
+ "src/string-utils.ts"() {
103
+ }
104
+ });
105
+ function authorizationServerToOidcDocument(as) {
106
+ const tokenEndpoint = as.token_endpoint;
107
+ const jwksUri = as.jwks_uri;
108
+ if (!tokenEndpoint || !jwksUri) {
109
+ throw new exports.PmtHouseError("OIDC discovery document is missing token_endpoint or jwks_uri", {
110
+ status: 500,
111
+ code: "oidc_discovery_invalid"
112
+ });
113
+ }
114
+ return {
115
+ issuer: as.issuer,
116
+ authorization_endpoint: as.authorization_endpoint ?? "",
117
+ token_endpoint: tokenEndpoint,
118
+ jwks_uri: jwksUri,
119
+ userinfo_endpoint: as.userinfo_endpoint,
120
+ device_authorization_endpoint: as.device_authorization_endpoint
121
+ };
122
+ }
123
+ function normalizedIssuerKey(issuerUrl) {
124
+ return stripTrailingSlashes(issuerUrl);
125
+ }
126
+ async function loadAuthorizationServer(issuerUrl, fetchImpl, options = {}) {
127
+ const key = normalizedIssuerKey(issuerUrl);
128
+ const now = Date.now();
129
+ const cached = discoveryCache.get(key);
130
+ if (!options.force && cached && now - cached.fetchedAt < CACHE_TTL_MS) {
131
+ return cached.as;
132
+ }
133
+ const issuerIdentifier = new URL(key);
134
+ const discoveryOpts = {
135
+ algorithm: "oidc",
136
+ [oauth4webapi.customFetch]: fetchImpl
137
+ };
138
+ if (options.allowInsecureHttp) {
139
+ discoveryOpts[oauth4webapi.allowInsecureRequests] = true;
140
+ }
141
+ let response;
142
+ try {
143
+ response = await oauth4webapi.discoveryRequest(issuerIdentifier, discoveryOpts);
144
+ } catch (e) {
145
+ throw mapDiscoveryNetworkError(e);
146
+ }
147
+ let as;
148
+ try {
149
+ as = await oauth4webapi.processDiscoveryResponse(issuerIdentifier, response);
150
+ } catch (e) {
151
+ throw mapOAuthDiscoveryError(e);
152
+ }
153
+ discoveryCache.set(key, { as, fetchedAt: now });
154
+ return as;
155
+ }
156
+ async function fetchDiscoveryDocument(issuerUrl, fetchImpl, options = {}) {
157
+ const as = await loadAuthorizationServer(issuerUrl, fetchImpl, options);
158
+ return authorizationServerToOidcDocument(as);
159
+ }
160
+ function clearDiscoveryCache(issuerUrl) {
161
+ if (!issuerUrl) {
162
+ discoveryCache.clear();
163
+ return;
164
+ }
165
+ discoveryCache.delete(normalizedIssuerKey(issuerUrl));
166
+ }
167
+ function mapOAuthDiscoveryError(error) {
168
+ if (error instanceof exports.PmtHouseError) {
169
+ return error;
170
+ }
171
+ if (error instanceof Error) {
172
+ return new exports.PmtHouseError(error.message, {
173
+ status: 500,
174
+ code: "oidc_discovery_invalid",
175
+ details: { cause: error.cause }
176
+ });
177
+ }
178
+ return new exports.PmtHouseError("OIDC discovery failed", {
179
+ status: 500,
180
+ code: "oidc_discovery_invalid"
181
+ });
182
+ }
183
+ function mapDiscoveryNetworkError(error) {
184
+ if (error instanceof exports.PmtHouseError) {
185
+ return error;
186
+ }
187
+ if (error instanceof Error) {
188
+ return new exports.PmtHouseError(`Failed to load OIDC discovery: ${error.message}`, {
189
+ status: 502,
190
+ code: "oidc_discovery_failed"
191
+ });
192
+ }
193
+ return new exports.PmtHouseError("Failed to load OIDC discovery", {
194
+ status: 502,
195
+ code: "oidc_discovery_failed"
196
+ });
197
+ }
198
+ var CACHE_TTL_MS, discoveryCache;
199
+ var init_discovery = __esm({
200
+ "src/discovery.ts"() {
201
+ init_errors();
202
+ init_string_utils();
203
+ CACHE_TTL_MS = 5 * 60 * 1e3;
204
+ discoveryCache = /* @__PURE__ */ new Map();
205
+ }
206
+ });
207
+
208
+ // src/signer/fetch-json.ts
209
+ function oauthFailureDescription(parsed, failureLabel, status) {
210
+ if (typeof parsed.error_description === "string") {
211
+ return parsed.error_description;
212
+ }
213
+ if (typeof parsed.error === "string") {
214
+ return parsed.error;
215
+ }
216
+ return `${failureLabel} (${status})`;
217
+ }
218
+ async function readJsonObjectFromResponse(response, options) {
219
+ const text = await response.text();
220
+ let parsed;
221
+ try {
222
+ parsed = text ? JSON.parse(text) : {};
223
+ } catch {
224
+ throw new exports.PmtHouseError(options.invalidJsonMessage, {
225
+ status: 502,
226
+ code: options.invalidJsonCode,
227
+ details: { status: response.status }
228
+ });
229
+ }
230
+ if (!response.ok) {
231
+ const description = oauthFailureDescription(parsed, options.failureLabel, response.status);
232
+ throw new exports.PmtHouseError(description, {
233
+ status: response.status,
234
+ code: typeof parsed.error === "string" ? parsed.error : options.defaultErrorCode,
235
+ details: parsed
236
+ });
237
+ }
238
+ return parsed;
239
+ }
240
+ var init_fetch_json = __esm({
241
+ "src/signer/fetch-json.ts"() {
242
+ init_errors();
243
+ }
244
+ });
245
+
246
+ // src/signer/handler-errors.ts
247
+ function signerHandlerErrorResponse(error) {
248
+ if (error instanceof exports.PmtHouseError) {
249
+ return new Response(
250
+ JSON.stringify({
251
+ error: error.code,
252
+ error_description: error.message,
253
+ details: error.details
254
+ }),
255
+ {
256
+ status: error.status,
257
+ headers: { "Content-Type": "application/json" }
258
+ }
259
+ );
260
+ }
261
+ const message = error instanceof Error ? error.message : "Internal error";
262
+ return new Response(JSON.stringify({ error: "internal_error", error_description: message }), {
263
+ status: 500,
264
+ headers: { "Content-Type": "application/json" }
265
+ });
266
+ }
267
+ var init_handler_errors = __esm({
268
+ "src/signer/handler-errors.ts"() {
269
+ init_errors();
270
+ }
271
+ });
272
+
273
+ // src/signer/json-fields.ts
274
+ function readStringField(body, key, errorCode, messagePrefix = "Response") {
275
+ const value = body[key];
276
+ if (typeof value !== "string" || !value.trim()) {
277
+ throw new exports.PmtHouseError(`${messagePrefix} missing ${key}`, {
278
+ status: 502,
279
+ code: errorCode
280
+ });
281
+ }
282
+ return value.trim();
283
+ }
284
+ function readExpiresIn(body, errorCode) {
285
+ const expiresIn = body.expires_in;
286
+ if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || expiresIn <= 0) {
287
+ throw new exports.PmtHouseError("Response missing expires_in", {
288
+ status: 502,
289
+ code: errorCode
290
+ });
291
+ }
292
+ return Math.floor(expiresIn);
293
+ }
294
+ var init_json_fields = __esm({
295
+ "src/signer/json-fields.ts"() {
296
+ init_errors();
297
+ }
298
+ });
299
+
300
+ // src/signer/mint-token.ts
301
+ function parseMintUserSignerTokenResponse(body, ttlRefreshRatio = DEFAULT_TTL_REFRESH_RATIO) {
302
+ const accessToken = readStringField(body, "access_token", TOKEN_RESPONSE_ERROR, "Token response");
303
+ const expiresIn = readExpiresIn(body, TOKEN_RESPONSE_ERROR);
304
+ const balanceUsdMicros = readStringField(
305
+ body,
306
+ "balanceUsdMicros",
307
+ TOKEN_RESPONSE_ERROR,
308
+ "Token response"
309
+ );
310
+ const lifetimeGrantedUsdMicros = readStringField(
311
+ body,
312
+ "lifetimeGrantedUsdMicros",
313
+ TOKEN_RESPONSE_ERROR,
314
+ "Token response"
315
+ );
316
+ const now = Date.now();
317
+ const expiresAt = now + expiresIn * 1e3;
318
+ const refreshAt = now + Math.floor(expiresIn * 1e3 * ttlRefreshRatio);
319
+ return {
320
+ jwt: accessToken,
321
+ expiresAt,
322
+ refreshAt,
323
+ balanceUsdMicros,
324
+ lifetimeGrantedUsdMicros
325
+ };
326
+ }
327
+ var LIVEPEER_REMOTE_SIGNER_AUDIENCE, DEFAULT_TTL_REFRESH_RATIO, TOKEN_RESPONSE_ERROR;
328
+ var init_mint_token = __esm({
329
+ "src/signer/mint-token.ts"() {
330
+ init_json_fields();
331
+ LIVEPEER_REMOTE_SIGNER_AUDIENCE = "livepeer-remote-signer";
332
+ DEFAULT_TTL_REFRESH_RATIO = 0.8;
333
+ TOKEN_RESPONSE_ERROR = "invalid_token_response";
334
+ }
335
+ });
336
+
337
+ // src/signer/device-exchange.ts
338
+ function extractSignerAccessTokenFromExchangeBody(body) {
339
+ const tokenObj = body.token;
340
+ if (tokenObj !== null && typeof tokenObj === "object" && !Array.isArray(tokenObj)) {
341
+ const nested = tokenObj;
342
+ for (const key of ["accessToken", "access_token"]) {
343
+ const value = nested[key];
344
+ if (typeof value === "string" && value.trim()) {
345
+ return value.trim();
346
+ }
347
+ }
348
+ }
349
+ for (const key of ["accessToken", "access_token"]) {
350
+ const value = body[key];
351
+ if (typeof value === "string" && value.trim()) {
352
+ return value.trim();
353
+ }
354
+ }
355
+ throw new exports.PmtHouseError("Device exchange response missing signer access token", {
356
+ status: 502,
357
+ code: "invalid_exchange_response"
358
+ });
359
+ }
360
+ function normalizeDeviceExchangeResponse(minted, options) {
361
+ const scope = minted.scope.trim() || "sign:job";
362
+ const body = {
363
+ access_token: minted.access_token,
364
+ token_type: "Bearer",
365
+ expires_in: minted.expires_in,
366
+ scope,
367
+ balanceUsdMicros: minted.balanceUsdMicros,
368
+ lifetimeGrantedUsdMicros: minted.lifetimeGrantedUsdMicros,
369
+ token: {
370
+ accessToken: minted.access_token,
371
+ access_token: minted.access_token,
372
+ expiresIn: minted.expires_in,
373
+ expires_in: minted.expires_in,
374
+ scope,
375
+ balanceUsdMicros: minted.balanceUsdMicros,
376
+ lifetimeGrantedUsdMicros: minted.lifetimeGrantedUsdMicros
377
+ }
378
+ };
379
+ const signerUrl = options?.signerUrl?.trim();
380
+ if (signerUrl) {
381
+ body.signerUrl = signerUrl;
382
+ }
383
+ return body;
384
+ }
385
+ async function mintSignerTokenFromDeviceToken(options) {
386
+ const fetchImpl = options.fetch ?? fetch;
387
+ const issuerUrl = stripTrailingSlashes(options.issuerUrl);
388
+ const as = await loadAuthorizationServer(issuerUrl, fetchImpl, {
389
+ allowInsecureHttp: options.allowInsecureHttp
390
+ });
391
+ const tokenEndpoint = as.token_endpoint;
392
+ if (!tokenEndpoint) {
393
+ throw new exports.PmtHouseError("OIDC discovery document is missing token_endpoint", {
394
+ status: 500,
395
+ code: "oidc_discovery_invalid"
396
+ });
397
+ }
398
+ const audience = options.audience?.trim() || LIVEPEER_REMOTE_SIGNER_AUDIENCE;
399
+ const params = new URLSearchParams({
400
+ grant_type: TOKEN_EXCHANGE_GRANT,
401
+ subject_token: options.deviceToken,
402
+ subject_token_type: SUBJECT_ACCESS_TOKEN_TYPE,
403
+ audience,
404
+ resource: audience
405
+ });
406
+ if (options.scope?.trim()) {
407
+ params.set("scope", options.scope.trim());
408
+ }
409
+ const response = await fetchImpl(tokenEndpoint, {
410
+ method: "POST",
411
+ headers: {
412
+ Authorization: encodeClientSecretBasic(options.m2mClientId, options.m2mClientSecret),
413
+ "Content-Type": "application/x-www-form-urlencoded",
414
+ Accept: "application/json"
415
+ },
416
+ body: params.toString(),
417
+ cache: "no-store"
418
+ });
419
+ const parsed = await readJsonObjectFromResponse(response, {
420
+ invalidJsonMessage: "Token endpoint returned invalid JSON",
421
+ invalidJsonCode: "invalid_token_response",
422
+ failureLabel: "Signer JWT exchange failed",
423
+ defaultErrorCode: "token_exchange_failed"
424
+ });
425
+ const cached = parseMintUserSignerTokenResponse(parsed);
426
+ return {
427
+ access_token: cached.jwt,
428
+ expires_in: readExpiresIn(parsed, EXCHANGE_RESPONSE_ERROR),
429
+ scope: readStringField(parsed, "scope", EXCHANGE_RESPONSE_ERROR),
430
+ balanceUsdMicros: cached.balanceUsdMicros,
431
+ lifetimeGrantedUsdMicros: cached.lifetimeGrantedUsdMicros
432
+ };
433
+ }
434
+ var TOKEN_EXCHANGE_GRANT, SUBJECT_ACCESS_TOKEN_TYPE, EXCHANGE_RESPONSE_ERROR;
435
+ var init_device_exchange = __esm({
436
+ "src/signer/device-exchange.ts"() {
437
+ init_discovery();
438
+ init_encoding();
439
+ init_errors();
440
+ init_string_utils();
441
+ init_fetch_json();
442
+ init_json_fields();
443
+ init_mint_token();
444
+ TOKEN_EXCHANGE_GRANT = "urn:ietf:params:oauth:grant-type:token-exchange";
445
+ SUBJECT_ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
446
+ EXCHANGE_RESPONSE_ERROR = "invalid_exchange_response";
447
+ }
448
+ });
449
+
450
+ // src/signer/api-key-exchange.ts
451
+ var api_key_exchange_exports = {};
452
+ __export(api_key_exchange_exports, {
453
+ createApiKeyExchangeHandler: () => createApiKeyExchangeHandler,
454
+ exchangeApiKeyForSigner: () => exchangeApiKeyForSigner,
455
+ mintSignerSessionFromApiKey: () => mintSignerSessionFromApiKey,
456
+ mintUserAccessTokenFromApiKey: () => mintUserAccessTokenFromApiKey,
457
+ parseApiKeyExchangeRequestBody: () => parseApiKeyExchangeRequestBody
458
+ });
459
+ async function parseApiKeyExchangeRequestBody(request) {
460
+ let body;
461
+ try {
462
+ body = await request.json();
463
+ } catch {
464
+ throw new exports.PmtHouseError("Request body must be JSON", {
465
+ status: 400,
466
+ code: "invalid_request"
467
+ });
468
+ }
469
+ if (body === null || typeof body !== "object" || Array.isArray(body)) {
470
+ throw new exports.PmtHouseError("Request body must be a JSON object", {
471
+ status: 400,
472
+ code: "invalid_request"
473
+ });
474
+ }
475
+ const record = body;
476
+ const apiKeyRaw = record.apiKey;
477
+ if (typeof apiKeyRaw !== "string" || !apiKeyRaw.trim()) {
478
+ throw new exports.PmtHouseError("Request body must include apiKey", {
479
+ status: 400,
480
+ code: "invalid_request"
481
+ });
482
+ }
483
+ const scope = typeof record.scope === "string" && record.scope.trim() ? record.scope.trim() : void 0;
484
+ const clientId = typeof record.clientId === "string" && record.clientId.trim() ? record.clientId.trim() : void 0;
485
+ return { apiKey: apiKeyRaw.trim(), scope, clientId };
486
+ }
487
+ async function mintUserAccessTokenFromApiKey(input) {
488
+ const fetchImpl = input.fetch ?? fetch;
489
+ const issuerOrigin = stripIssuerOriginFromOidcUrl(input.issuerUrl);
490
+ const url = `${issuerOrigin}/api/v1/apps/${encodeURIComponent(input.publicClientId)}/auth/api-key/token`;
491
+ const response = await fetchImpl(url, {
492
+ method: "POST",
493
+ headers: {
494
+ Authorization: `Bearer ${input.apiKey}`,
495
+ "Content-Type": "application/json",
496
+ Accept: "application/json"
497
+ },
498
+ body: JSON.stringify(input.scope ? { scope: input.scope } : {}),
499
+ cache: "no-store"
500
+ });
501
+ const parsed = await readJsonObjectFromResponse(response, {
502
+ invalidJsonMessage: "API key token exchange returned invalid JSON",
503
+ invalidJsonCode: "invalid_token_response",
504
+ failureLabel: "API key token exchange failed",
505
+ defaultErrorCode: "api_key_token_exchange_failed"
506
+ });
507
+ const accessToken = parsed.access_token;
508
+ if (typeof accessToken !== "string" || !accessToken.trim()) {
509
+ throw new exports.PmtHouseError("API key token exchange missing access_token", {
510
+ status: 502,
511
+ code: EXCHANGE_RESPONSE_ERROR2
512
+ });
513
+ }
514
+ const expiresIn = typeof parsed.expires_in === "number" && Number.isFinite(parsed.expires_in) ? parsed.expires_in : 900;
515
+ const scope = typeof parsed.scope === "string" && parsed.scope.trim() ? parsed.scope.trim() : input.scope?.trim() || "sign:job";
516
+ return {
517
+ access_token: accessToken.trim(),
518
+ expires_in: expiresIn,
519
+ scope
520
+ };
521
+ }
522
+ async function mintSignerSessionFromApiKey(input) {
523
+ const userToken = await mintUserAccessTokenFromApiKey({
524
+ issuerUrl: input.issuerUrl,
525
+ publicClientId: input.publicClientId,
526
+ apiKey: input.apiKey,
527
+ scope: input.scope,
528
+ fetch: input.fetch
529
+ });
530
+ return mintSignerTokenFromDeviceToken({
531
+ issuerUrl: input.issuerUrl,
532
+ m2mClientId: input.m2mClientId,
533
+ m2mClientSecret: input.m2mClientSecret,
534
+ deviceToken: userToken.access_token,
535
+ scope: userToken.scope,
536
+ audience: input.audience,
537
+ fetch: input.fetch,
538
+ allowInsecureHttp: input.allowInsecureHttp
539
+ });
540
+ }
541
+ async function exchangeApiKeyForSigner(options) {
542
+ const fetchImpl = options.fetch ?? fetch;
543
+ const url = `${stripTrailingSlashes(options.facadeUrl)}/api/pymthouse/keys/exchange`;
544
+ const body = { apiKey: options.apiKey };
545
+ if (options.scope?.trim()) {
546
+ body.scope = options.scope.trim();
547
+ }
548
+ if (options.clientId?.trim()) {
549
+ body.clientId = options.clientId.trim();
550
+ }
551
+ const response = await fetchImpl(url, {
552
+ method: "POST",
553
+ headers: {
554
+ "Content-Type": "application/json",
555
+ Accept: "application/json"
556
+ },
557
+ body: JSON.stringify(body),
558
+ cache: "no-store"
559
+ });
560
+ const parsed = await readJsonObjectFromResponse(response, {
561
+ invalidJsonMessage: "API key exchange returned invalid JSON",
562
+ invalidJsonCode: EXCHANGE_RESPONSE_ERROR2,
563
+ failureLabel: "API key exchange failed",
564
+ defaultErrorCode: "api_key_exchange_failed"
565
+ });
566
+ const accessToken = extractSignerAccessTokenFromExchangeBody(parsed);
567
+ const signerUrlRaw = parsed.signerUrl ?? parsed.signer_url;
568
+ const signerUrl = typeof signerUrlRaw === "string" && signerUrlRaw.trim() ? signerUrlRaw.trim() : void 0;
569
+ return normalizeDeviceExchangeResponse(
570
+ {
571
+ access_token: accessToken,
572
+ expires_in: typeof parsed.expires_in === "number" && Number.isFinite(parsed.expires_in) ? parsed.expires_in : 3600,
573
+ scope: typeof parsed.scope === "string" && parsed.scope.trim() ? parsed.scope.trim() : "sign:job",
574
+ balanceUsdMicros: typeof parsed.balanceUsdMicros === "string" ? parsed.balanceUsdMicros : "0",
575
+ lifetimeGrantedUsdMicros: typeof parsed.lifetimeGrantedUsdMicros === "string" ? parsed.lifetimeGrantedUsdMicros : "0"
576
+ },
577
+ { signerUrl }
578
+ );
579
+ }
580
+ function createApiKeyExchangeHandler(config) {
581
+ const publicClientId = config.publicClientId.trim();
582
+ return async function apiKeyExchangeHandler(request) {
583
+ try {
584
+ if (request.method !== "POST") {
585
+ return new Response(JSON.stringify({ error: "method_not_allowed" }), {
586
+ status: 405,
587
+ headers: { "Content-Type": "application/json" }
588
+ });
589
+ }
590
+ const parsed = await parseApiKeyExchangeRequestBody(request);
591
+ const effectiveClientId = parsed.clientId?.trim() || publicClientId;
592
+ if (effectiveClientId !== publicClientId) {
593
+ throw new exports.PmtHouseError("clientId does not match configured public client", {
594
+ status: 400,
595
+ code: "invalid_request"
596
+ });
597
+ }
598
+ const minted = await mintSignerSessionFromApiKey({
599
+ issuerUrl: config.issuerUrl,
600
+ publicClientId,
601
+ m2mClientId: config.m2mClientId,
602
+ m2mClientSecret: config.m2mClientSecret,
603
+ apiKey: parsed.apiKey,
604
+ scope: parsed.scope,
605
+ audience: config.audience,
606
+ fetch: config.fetch,
607
+ allowInsecureHttp: config.allowInsecureHttp
608
+ });
609
+ const signerUrlValue = typeof config.signerUrl === "string" && config.signerUrl.trim() ? config.signerUrl.trim() : void 0;
610
+ const body = normalizeDeviceExchangeResponse(minted, { signerUrl: signerUrlValue });
611
+ return new Response(JSON.stringify(body), {
612
+ status: 200,
613
+ headers: {
614
+ "Content-Type": "application/json",
615
+ "Cache-Control": "no-store"
616
+ }
617
+ });
618
+ } catch (error) {
619
+ return signerHandlerErrorResponse(error);
620
+ }
621
+ };
622
+ }
623
+ var EXCHANGE_RESPONSE_ERROR2;
624
+ var init_api_key_exchange = __esm({
625
+ "src/signer/api-key-exchange.ts"() {
626
+ init_string_utils();
627
+ init_errors();
628
+ init_fetch_json();
629
+ init_handler_errors();
630
+ init_device_exchange();
631
+ EXCHANGE_RESPONSE_ERROR2 = "invalid_exchange_response";
632
+ }
633
+ });
634
+
635
+ // src/plan-pricing.ts
636
+ var NETWORK_USD_PER_MICRO = 1e-6;
637
+ var RETAIL_RATE_DECIMALS = 9;
638
+ function trimFixedDecimalZeros(fixed) {
639
+ const dotIndex = fixed.indexOf(".");
640
+ if (dotIndex === -1) {
641
+ return fixed;
642
+ }
643
+ let end = fixed.length;
644
+ while (end > dotIndex + 1 && fixed[end - 1] === "0") {
645
+ end -= 1;
646
+ }
647
+ if (end === dotIndex + 1) {
648
+ end = dotIndex;
649
+ }
650
+ const trimmed = fixed.slice(0, end);
651
+ return trimmed.length > 0 ? trimmed : "0";
652
+ }
653
+ function defaultRetailRateUsd() {
654
+ return formatRetailRateUsd(NETWORK_USD_PER_MICRO);
655
+ }
656
+ function formatRetailRateUsd(value) {
657
+ if (!Number.isFinite(value) || value < 0) {
658
+ return defaultRetailRateUsd();
659
+ }
660
+ return trimFixedDecimalZeros(value.toFixed(RETAIL_RATE_DECIMALS));
661
+ }
662
+ function parseRetailRateUsd(raw) {
663
+ if (raw === null || raw === void 0) {
664
+ return null;
665
+ }
666
+ const trimmed = String(raw).trim();
667
+ if (!trimmed) {
668
+ return null;
669
+ }
670
+ const n = Number(trimmed);
671
+ if (!Number.isFinite(n) || n < 0) {
672
+ return null;
673
+ }
674
+ return formatRetailRateUsd(n);
675
+ }
676
+ function markupPercentToRetailRateUsd(markupPercent) {
677
+ const pct = Number.isFinite(markupPercent) ? Math.max(0, markupPercent) : 0;
678
+ return formatRetailRateUsd(NETWORK_USD_PER_MICRO * (1 + pct / 100));
679
+ }
680
+ function retailRateUsdToMarkupPercent(raw) {
681
+ const rate = parseRetailRateUsd(raw);
682
+ if (!rate) {
683
+ return "";
684
+ }
685
+ const n = Number(rate);
686
+ if (!Number.isFinite(n) || n <= NETWORK_USD_PER_MICRO) {
687
+ return n === NETWORK_USD_PER_MICRO ? "0" : "";
688
+ }
689
+ const pct = (n / NETWORK_USD_PER_MICRO - 1) * 100;
690
+ if (!Number.isFinite(pct) || pct <= 0) {
691
+ return "";
692
+ }
693
+ return pct % 1 === 0 ? String(Math.round(pct)) : pct.toFixed(1);
694
+ }
695
+ function retailRateUsdPerMillion(raw) {
696
+ const rate = parseRetailRateUsd(raw);
697
+ if (!rate) {
698
+ return "";
699
+ }
700
+ const perM = Number(rate) * 1e6;
701
+ if (!Number.isFinite(perM)) {
702
+ return "";
703
+ }
704
+ return perM.toFixed(2);
705
+ }
706
+ function parseMarkupPercentInput(raw) {
707
+ const trimmed = raw.trim();
708
+ if (!trimmed) {
709
+ return null;
710
+ }
711
+ const n = Number(trimmed);
712
+ if (!Number.isFinite(n) || n < 0) {
713
+ return null;
714
+ }
715
+ return n;
716
+ }
717
+ function applyRetailRateToNetworkMicros(networkFeeUsdMicros, retailRateUsd) {
718
+ const networkPerMicro = NETWORK_USD_PER_MICRO;
719
+ const retail = Number(retailRateUsd);
720
+ if (!Number.isFinite(retail) || retail <= 0) {
721
+ return networkFeeUsdMicros;
722
+ }
723
+ const ratio = retail / networkPerMicro;
724
+ if (!Number.isFinite(ratio) || ratio <= 0) {
725
+ return networkFeeUsdMicros;
726
+ }
727
+ return networkFeeUsdMicros * BigInt(Math.round(ratio * 1e6)) / 1000000n;
728
+ }
729
+
730
+ // src/ingest.ts
731
+ init_encoding();
732
+ init_errors();
733
+ init_string_utils();
734
+ function signerSnapshotToIngestPayload(input) {
735
+ return {
736
+ requestId: input.snapshot.requestId,
737
+ externalUserId: input.externalUserId,
738
+ networkFeeUsdMicros: input.snapshot.computedFeeUsdMicros.toString(),
739
+ feeWei: input.snapshot.computedFeeWei,
740
+ pixels: input.snapshot.pixels,
741
+ pipeline: input.snapshot.pipeline,
742
+ modelId: input.snapshot.modelId,
743
+ gatewayRequestId: input.gatewayRequestId,
744
+ ethUsdPrice: input.snapshot.ethUsdPrice,
745
+ ethUsdRoundId: input.snapshot.ethUsdRoundId,
746
+ ethUsdObservedAt: input.snapshot.ethUsdObservedAt
747
+ };
748
+ }
749
+ function ingestUrl(issuerUrl, publicClientId) {
750
+ const origin = new URL(stripTrailingSlashes(issuerUrl)).origin;
751
+ return `${origin}/api/v1/apps/${encodeURIComponent(publicClientId)}/usage/signed-tickets`;
752
+ }
753
+ async function readJsonResponse(response) {
754
+ const text = await response.text();
755
+ if (!text.trim()) {
756
+ return {};
757
+ }
758
+ try {
759
+ const parsed = JSON.parse(text);
760
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
761
+ } catch {
762
+ return {};
763
+ }
764
+ }
765
+ async function ingestSignedTicket(options) {
766
+ const fetchImpl = options.fetch ?? fetch;
767
+ const url = ingestUrl(options.issuerUrl, options.publicClientId);
768
+ const response = await fetchImpl(url, {
769
+ method: "POST",
770
+ headers: {
771
+ Authorization: encodeClientSecretBasic(options.m2mClientId, options.m2mClientSecret),
772
+ "Content-Type": "application/json",
773
+ Accept: "application/json"
774
+ },
775
+ body: JSON.stringify(options.ticket),
776
+ cache: "no-store"
777
+ });
778
+ const body = await readJsonResponse(response);
779
+ if (!response.ok) {
780
+ const message = typeof body.error === "string" ? body.error : `Signed-ticket ingest failed (${response.status})`;
781
+ throw new exports.PmtHouseError(message, {
782
+ status: response.status,
783
+ code: "ingest_failed",
784
+ details: body
785
+ });
786
+ }
787
+ return {
788
+ ingested: Boolean(body.ingested),
789
+ duplicate: Boolean(body.duplicate),
790
+ source: body.source === "openmeter" ? "openmeter" : "disabled"
791
+ };
792
+ }
793
+ async function ingestSignedTicketsBatch(options) {
794
+ const fetchImpl = options.fetch ?? fetch;
795
+ const url = ingestUrl(options.issuerUrl, options.publicClientId);
796
+ const response = await fetchImpl(url, {
797
+ method: "POST",
798
+ headers: {
799
+ Authorization: encodeClientSecretBasic(options.m2mClientId, options.m2mClientSecret),
800
+ "Content-Type": "application/json",
801
+ Accept: "application/json"
802
+ },
803
+ body: JSON.stringify({ tickets: options.tickets }),
804
+ cache: "no-store"
805
+ });
806
+ const body = await readJsonResponse(response);
807
+ if (!response.ok) {
808
+ const message = typeof body.error === "string" ? body.error : `Signed-ticket batch ingest failed (${response.status})`;
809
+ throw new exports.PmtHouseError(message, {
810
+ status: response.status,
811
+ code: "ingest_failed",
812
+ details: body
813
+ });
814
+ }
815
+ const rawResults = Array.isArray(body.results) ? body.results : [];
816
+ return {
817
+ results: rawResults.map((entry) => {
818
+ const row = entry ?? {};
819
+ return {
820
+ requestId: typeof row.requestId === "string" ? row.requestId : void 0,
821
+ ok: row.ok === true,
822
+ ingested: Boolean(row.ingested),
823
+ duplicate: Boolean(row.duplicate),
824
+ source: row.source === "openmeter" ? "openmeter" : "disabled"
825
+ };
826
+ })
827
+ };
828
+ }
829
+
6
830
  // src/usage.ts
7
831
  function parseSafeBigInt(value, fallback = 0n) {
8
832
  try {
@@ -117,24 +941,27 @@ function mergeUsageByPipelineModel(usagePipelineModels) {
117
941
  const key = JSON.stringify([pipeline, modelId]);
118
942
  const existing = byKey.get(key);
119
943
  const rowCurrency = row.currency ?? "USD";
944
+ const networkFee = row.networkFeeUsdMicros ?? "0";
945
+ const ownerCharge = row.ownerChargeUsdMicros ?? "0";
946
+ const endUserBillable = row.endUserBillableUsdMicros ?? "0";
120
947
  if (!existing) {
121
948
  byKey.set(key, {
122
949
  pipeline,
123
950
  modelId,
124
951
  requestCount: row.requestCount,
125
952
  currency: rowCurrency,
126
- networkFeeUsdMicros: row.networkFeeUsdMicros,
127
- ownerChargeUsdMicros: row.ownerChargeUsdMicros,
128
- endUserBillableUsdMicros: row.endUserBillableUsdMicros
953
+ networkFeeUsdMicros: networkFee,
954
+ ownerChargeUsdMicros: ownerCharge,
955
+ endUserBillableUsdMicros: endUserBillable
129
956
  });
130
957
  continue;
131
958
  }
132
959
  byKey.set(key, {
133
960
  ...existing,
134
961
  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()
962
+ networkFeeUsdMicros: (parseSafeBigInt(existing.networkFeeUsdMicros) + parseSafeBigInt(networkFee)).toString(),
963
+ ownerChargeUsdMicros: (parseSafeBigInt(existing.ownerChargeUsdMicros) + parseSafeBigInt(ownerCharge)).toString(),
964
+ endUserBillableUsdMicros: (parseSafeBigInt(existing.endUserBillableUsdMicros) + parseSafeBigInt(endUserBillable)).toString()
138
965
  });
139
966
  }
140
967
  }
@@ -143,9 +970,10 @@ function mergeUsageByPipelineModel(usagePipelineModels) {
143
970
  return a.pipeline.localeCompare(b.pipeline);
144
971
  });
145
972
  }
146
- function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineModel) {
973
+ function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineModel, usageDaily) {
147
974
  const summary = summarizeUsageFiatForExternalUser(usageByUser, externalUserId);
148
975
  const pipelineModels = mergeUsageByPipelineModel(usagePipelineModel);
976
+ const dailyByPipeline = usageDaily?.byDailyPipeline ?? [];
149
977
  return {
150
978
  clientId: usageByUser.clientId,
151
979
  period: usageByUser.period,
@@ -156,157 +984,17 @@ function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineMode
156
984
  networkFeeUsdMicros: summary.networkFeeUsdMicros,
157
985
  ownerChargeUsdMicros: summary.ownerChargeUsdMicros,
158
986
  endUserBillableUsdMicros: summary.endUserBillableUsdMicros,
159
- pipelineModels
987
+ pipelineModels,
988
+ dailyByPipeline
160
989
  }
161
990
  };
162
991
  }
163
992
  var DEFAULT_MAX_END_USER_IDS = 25;
164
993
 
165
- // src/encoding.ts
166
- function encodeClientSecretBasic(clientId, clientSecret) {
167
- const raw = `${clientId}:${clientSecret}`;
168
- const b64 = typeof Buffer !== "undefined" ? Buffer.from(raw, "utf8").toString("base64") : btoa(Array.from(new TextEncoder().encode(raw), (c) => String.fromCharCode(c)).join(""));
169
- return `Basic ${b64}`;
170
- }
171
-
172
- // src/errors.ts
173
- var PmtHouseError = class extends Error {
174
- status;
175
- code;
176
- details;
177
- constructor(message, {
178
- status = 500,
179
- code = "pymthouse_error",
180
- details
181
- } = {}) {
182
- super(message);
183
- this.name = "PmtHouseError";
184
- this.status = status;
185
- this.code = code;
186
- this.details = details;
187
- }
188
- };
189
- function toPmtHouseError(error, fallbackMessage) {
190
- if (error instanceof PmtHouseError) {
191
- return error;
192
- }
193
- if (error instanceof Error) {
194
- return new PmtHouseError(error.message || fallbackMessage, {
195
- code: "unexpected_error",
196
- status: 500
197
- });
198
- }
199
- return new PmtHouseError(fallbackMessage, {
200
- code: "unexpected_error",
201
- status: 500
202
- });
203
- }
204
-
205
- // src/string-utils.ts
206
- function stripTrailingSlashes(value) {
207
- let end = value.length;
208
- while (end > 0 && value.charCodeAt(end - 1) === 47) {
209
- end--;
210
- }
211
- return value.slice(0, end);
212
- }
213
-
214
- // src/discovery.ts
215
- function authorizationServerToOidcDocument(as) {
216
- const tokenEndpoint = as.token_endpoint;
217
- const jwksUri = as.jwks_uri;
218
- if (!tokenEndpoint || !jwksUri) {
219
- throw new PmtHouseError("OIDC discovery document is missing token_endpoint or jwks_uri", {
220
- status: 500,
221
- code: "oidc_discovery_invalid"
222
- });
223
- }
224
- return {
225
- issuer: as.issuer,
226
- authorization_endpoint: as.authorization_endpoint ?? "",
227
- token_endpoint: tokenEndpoint,
228
- jwks_uri: jwksUri,
229
- userinfo_endpoint: as.userinfo_endpoint,
230
- device_authorization_endpoint: as.device_authorization_endpoint
231
- };
232
- }
233
- var CACHE_TTL_MS = 5 * 60 * 1e3;
234
- var discoveryCache = /* @__PURE__ */ new Map();
235
- function normalizedIssuerKey(issuerUrl) {
236
- return stripTrailingSlashes(issuerUrl);
237
- }
238
- async function loadAuthorizationServer(issuerUrl, fetchImpl, options = {}) {
239
- const key = normalizedIssuerKey(issuerUrl);
240
- const now = Date.now();
241
- const cached = discoveryCache.get(key);
242
- if (!options.force && cached && now - cached.fetchedAt < CACHE_TTL_MS) {
243
- return cached.as;
244
- }
245
- const issuerIdentifier = new URL(key);
246
- const discoveryOpts = {
247
- algorithm: "oidc",
248
- [oauth4webapi.customFetch]: fetchImpl
249
- };
250
- if (options.allowInsecureHttp) {
251
- discoveryOpts[oauth4webapi.allowInsecureRequests] = true;
252
- }
253
- let response;
254
- try {
255
- response = await oauth4webapi.discoveryRequest(issuerIdentifier, discoveryOpts);
256
- } catch (e) {
257
- throw mapDiscoveryNetworkError(e);
258
- }
259
- let as;
260
- try {
261
- as = await oauth4webapi.processDiscoveryResponse(issuerIdentifier, response);
262
- } catch (e) {
263
- throw mapOAuthDiscoveryError(e);
264
- }
265
- discoveryCache.set(key, { as, fetchedAt: now });
266
- return as;
267
- }
268
- async function fetchDiscoveryDocument(issuerUrl, fetchImpl, options = {}) {
269
- const as = await loadAuthorizationServer(issuerUrl, fetchImpl, options);
270
- return authorizationServerToOidcDocument(as);
271
- }
272
- function clearDiscoveryCache(issuerUrl) {
273
- if (!issuerUrl) {
274
- discoveryCache.clear();
275
- return;
276
- }
277
- discoveryCache.delete(normalizedIssuerKey(issuerUrl));
278
- }
279
- function mapOAuthDiscoveryError(error) {
280
- if (error instanceof PmtHouseError) {
281
- return error;
282
- }
283
- if (error instanceof Error) {
284
- return new PmtHouseError(error.message, {
285
- status: 500,
286
- code: "oidc_discovery_invalid",
287
- details: { cause: error.cause }
288
- });
289
- }
290
- return new PmtHouseError("OIDC discovery failed", {
291
- status: 500,
292
- code: "oidc_discovery_invalid"
293
- });
294
- }
295
- function mapDiscoveryNetworkError(error) {
296
- if (error instanceof PmtHouseError) {
297
- return error;
298
- }
299
- if (error instanceof Error) {
300
- return new PmtHouseError(`Failed to load OIDC discovery: ${error.message}`, {
301
- status: 502,
302
- code: "oidc_discovery_failed"
303
- });
304
- }
305
- return new PmtHouseError("Failed to load OIDC discovery", {
306
- status: 502,
307
- code: "oidc_discovery_failed"
308
- });
309
- }
994
+ // src/client.ts
995
+ init_encoding();
996
+ init_discovery();
997
+ init_errors();
310
998
  function parseAppManifestResponse(json) {
311
999
  if (!json || typeof json !== "object" || Array.isArray(json)) {
312
1000
  return { capabilities: [], excludedCapabilities: [] };
@@ -344,6 +1032,9 @@ function computeManifestRevision(data) {
344
1032
  return crypto.createHash("sha256").update(JSON.stringify({ capabilities: caps, excludedCapabilities: excl })).digest("hex").slice(0, 24);
345
1033
  }
346
1034
 
1035
+ // src/client.ts
1036
+ init_string_utils();
1037
+
347
1038
  // src/tokens.ts
348
1039
  var SIGNER_SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
349
1040
  var SIGNER_SESSION_EXPIRES_IN_SEC = Math.floor(SIGNER_SESSION_TTL_MS / 1e3);
@@ -404,12 +1095,15 @@ function parseSignerSessionExchange(res) {
404
1095
  scope
405
1096
  };
406
1097
  }
1098
+
1099
+ // src/oauth-map.ts
1100
+ init_errors();
407
1101
  var ACCEPTED_ISSUED_TOKEN_TYPES = /* @__PURE__ */ new Set([
408
1102
  "urn:ietf:params:oauth:token-type:access_token",
409
1103
  "urn:pmth:token-type:remote-signer-session"
410
1104
  ]);
411
1105
  function mapOAuthError(error) {
412
- if (error instanceof PmtHouseError) {
1106
+ if (error instanceof exports.PmtHouseError) {
413
1107
  return error;
414
1108
  }
415
1109
  if (error instanceof oauth4webapi.ResponseBodyError) {
@@ -419,26 +1113,26 @@ function mapOAuthError(error) {
419
1113
  if (typeof cause.error_uri === "string") {
420
1114
  details.error_uri = cause.error_uri;
421
1115
  }
422
- return new PmtHouseError(description, {
1116
+ return new exports.PmtHouseError(description, {
423
1117
  status: error.status,
424
1118
  code: error.error,
425
1119
  details
426
1120
  });
427
1121
  }
428
1122
  if (error instanceof oauth4webapi.OperationProcessingError) {
429
- return new PmtHouseError(error.message, {
1123
+ return new exports.PmtHouseError(error.message, {
430
1124
  status: 502,
431
1125
  code: error.code ?? "oauth_processing_error",
432
1126
  details: { cause: error.cause }
433
1127
  });
434
1128
  }
435
1129
  if (error instanceof Error) {
436
- return new PmtHouseError(error.message, {
1130
+ return new exports.PmtHouseError(error.message, {
437
1131
  status: 500,
438
1132
  code: "unexpected_error"
439
1133
  });
440
1134
  }
441
- return new PmtHouseError("Unexpected error", {
1135
+ return new exports.PmtHouseError("Unexpected error", {
442
1136
  status: 500,
443
1137
  code: "unexpected_error"
444
1138
  });
@@ -446,7 +1140,7 @@ function mapOAuthError(error) {
446
1140
  function tokenEndpointResponseToExchange(tr) {
447
1141
  const issued = tr.issued_token_type;
448
1142
  if (typeof issued !== "string" || !ACCEPTED_ISSUED_TOKEN_TYPES.has(issued)) {
449
- throw new PmtHouseError("Token exchange returned an unexpected issued_token_type", {
1143
+ throw new exports.PmtHouseError("Token exchange returned an unexpected issued_token_type", {
450
1144
  status: 502,
451
1145
  code: "invalid_token_response",
452
1146
  details: { issued_token_type: issued }
@@ -454,7 +1148,7 @@ function tokenEndpointResponseToExchange(tr) {
454
1148
  }
455
1149
  const tt = tr.token_type;
456
1150
  if (typeof tt !== "string" || tt.toLowerCase() !== "bearer") {
457
- throw new PmtHouseError("Token endpoint returned a non-Bearer token_type", {
1151
+ throw new exports.PmtHouseError("Token endpoint returned a non-Bearer token_type", {
458
1152
  status: 502,
459
1153
  code: "invalid_token_response",
460
1154
  details: { token_type: tt }
@@ -462,7 +1156,7 @@ function tokenEndpointResponseToExchange(tr) {
462
1156
  }
463
1157
  const expiresIn = tr.expires_in;
464
1158
  if (typeof expiresIn !== "number") {
465
- throw new PmtHouseError("Token response missing expires_in", {
1159
+ throw new exports.PmtHouseError("Token response missing expires_in", {
466
1160
  status: 502,
467
1161
  code: "invalid_token_response"
468
1162
  });
@@ -479,7 +1173,7 @@ function tokenEndpointResponseToExchange(tr) {
479
1173
  function tokenEndpointResponseToClientCredentials(tr) {
480
1174
  const tt = tr.token_type;
481
1175
  if (typeof tt !== "string" || tt.toLowerCase() !== "bearer") {
482
- throw new PmtHouseError("Token endpoint returned a non-Bearer token_type", {
1176
+ throw new exports.PmtHouseError("Token endpoint returned a non-Bearer token_type", {
483
1177
  status: 502,
484
1178
  code: "invalid_token_response",
485
1179
  details: { token_type: tt }
@@ -497,8 +1191,8 @@ function m2mClient(clientId) {
497
1191
  }
498
1192
 
499
1193
  // src/client.ts
500
- var TOKEN_EXCHANGE_GRANT = "urn:ietf:params:oauth:grant-type:token-exchange";
501
- var SUBJECT_ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
1194
+ var TOKEN_EXCHANGE_GRANT2 = "urn:ietf:params:oauth:grant-type:token-exchange";
1195
+ var SUBJECT_ACCESS_TOKEN_TYPE2 = "urn:ietf:params:oauth:token-type:access_token";
502
1196
  var REQUESTED_ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
503
1197
  var DEVICE_RESOURCE_PREFIX = "urn:pmth:device_code:";
504
1198
  function normalizeUserCode(value) {
@@ -539,13 +1233,13 @@ var PmtHouseClient = class {
539
1233
  const issuer = searchParams.get("iss")?.trim() ?? "";
540
1234
  const targetLinkUri = searchParams.get("target_link_uri")?.trim() ?? "";
541
1235
  if (!issuer || !targetLinkUri) {
542
- throw new PmtHouseError("Missing iss or target_link_uri", {
1236
+ throw new exports.PmtHouseError("Missing iss or target_link_uri", {
543
1237
  status: 400,
544
1238
  code: "invalid_request"
545
1239
  });
546
1240
  }
547
1241
  if (!this.verifyIssuer(issuer)) {
548
- throw new PmtHouseError("Issuer mismatch for initiate login", {
1242
+ throw new exports.PmtHouseError("Issuer mismatch for initiate login", {
549
1243
  status: 400,
550
1244
  code: "invalid_issuer"
551
1245
  });
@@ -554,14 +1248,14 @@ var PmtHouseClient = class {
554
1248
  try {
555
1249
  targetUrl = new URL(targetLinkUri);
556
1250
  } catch {
557
- throw new PmtHouseError("target_link_uri is not a valid URL", {
1251
+ throw new exports.PmtHouseError("target_link_uri is not a valid URL", {
558
1252
  status: 400,
559
1253
  code: "invalid_target"
560
1254
  });
561
1255
  }
562
1256
  const issuerOrigin = new URL(this.issuerUrl).origin;
563
1257
  if (targetUrl.origin !== issuerOrigin || targetUrl.pathname !== "/oidc/device") {
564
- throw new PmtHouseError(
1258
+ throw new exports.PmtHouseError(
565
1259
  "target_link_uri does not point to the issuer device path",
566
1260
  {
567
1261
  status: 400,
@@ -572,7 +1266,7 @@ var PmtHouseClient = class {
572
1266
  const userCode = normalizeUserCode(targetUrl.searchParams.get("user_code") ?? "");
573
1267
  const clientId = targetUrl.searchParams.get("client_id")?.trim() ?? "";
574
1268
  if (!userCode || !clientId) {
575
- throw new PmtHouseError("target_link_uri is missing user_code or client_id", {
1269
+ throw new exports.PmtHouseError("target_link_uri is missing user_code or client_id", {
576
1270
  status: 400,
577
1271
  code: "invalid_target"
578
1272
  });
@@ -625,6 +1319,50 @@ var PmtHouseClient = class {
625
1319
  cache: "no-store"
626
1320
  });
627
1321
  }
1322
+ /**
1323
+ * Exchange a long-lived dashboard API key (`pmth_*`) for a short-lived user JWT.
1324
+ */
1325
+ async exchangeApiKeyForUserAccessToken(input) {
1326
+ const url = `${this.getAppsBaseUrl()}/auth/api-key/token`;
1327
+ return this.requestJson(url, {
1328
+ method: "POST",
1329
+ headers: {
1330
+ Authorization: `Bearer ${input.apiKey.trim()}`,
1331
+ "Content-Type": "application/json",
1332
+ Accept: "application/json"
1333
+ },
1334
+ body: JSON.stringify(input.scope ? { scope: input.scope } : {}),
1335
+ cache: "no-store"
1336
+ });
1337
+ }
1338
+ /**
1339
+ * Exchange a dashboard API key for a signer session via a trusted facade (recommended)
1340
+ * or directly when M2M credentials are available on this client.
1341
+ */
1342
+ async exchangeApiKeyForSignerSession(input) {
1343
+ if (input.facadeUrl?.trim()) {
1344
+ const { exchangeApiKeyForSigner: exchangeApiKeyForSigner2 } = await Promise.resolve().then(() => (init_api_key_exchange(), api_key_exchange_exports));
1345
+ const exchanged = await exchangeApiKeyForSigner2({
1346
+ facadeUrl: input.facadeUrl.trim(),
1347
+ apiKey: input.apiKey,
1348
+ scope: input.scope,
1349
+ clientId: this.publicClientId,
1350
+ fetch: this.fetchImpl
1351
+ });
1352
+ return {
1353
+ access_token: exchanged.access_token,
1354
+ token_type: exchanged.token_type,
1355
+ expires_in: exchanged.expires_in,
1356
+ scope: exchanged.scope,
1357
+ issued_token_type: "urn:ietf:params:oauth:token-type:access_token"
1358
+ };
1359
+ }
1360
+ const userToken = await this.exchangeApiKeyForUserAccessToken({
1361
+ apiKey: input.apiKey,
1362
+ scope: input.scope
1363
+ });
1364
+ return this.exchangeForSignerSession({ userJwt: userToken.access_token });
1365
+ }
628
1366
  async completeDeviceApproval(input) {
629
1367
  const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {
630
1368
  allowInsecureHttp: this.allowInsecureHttp
@@ -633,14 +1371,14 @@ var PmtHouseClient = class {
633
1371
  const clientAuth = this.m2mClientAuth();
634
1372
  const params = new URLSearchParams();
635
1373
  params.set("subject_token", input.userJwt);
636
- params.set("subject_token_type", SUBJECT_ACCESS_TOKEN_TYPE);
1374
+ params.set("subject_token_type", SUBJECT_ACCESS_TOKEN_TYPE2);
637
1375
  params.set("resource", buildDeviceCodeResource(input.userCode));
638
1376
  try {
639
1377
  const response = await oauth4webapi.genericTokenEndpointRequest(
640
1378
  as,
641
1379
  client,
642
1380
  clientAuth,
643
- TOKEN_EXCHANGE_GRANT,
1381
+ TOKEN_EXCHANGE_GRANT2,
644
1382
  params,
645
1383
  this.tokenEndpointFetchOptions()
646
1384
  );
@@ -688,7 +1426,7 @@ var PmtHouseClient = class {
688
1426
  const clientAuth = this.m2mClientAuth();
689
1427
  const params = new URLSearchParams();
690
1428
  params.set("subject_token", input.userJwt);
691
- params.set("subject_token_type", SUBJECT_ACCESS_TOKEN_TYPE);
1429
+ params.set("subject_token_type", SUBJECT_ACCESS_TOKEN_TYPE2);
692
1430
  params.set("requested_token_type", REQUESTED_ACCESS_TOKEN_TYPE);
693
1431
  const resourceCandidate = typeof input.resource === "string" && input.resource.trim() !== "" ? input.resource.trim() : this.issuerUrl;
694
1432
  params.set("resource", stripTrailingSlashes(resourceCandidate));
@@ -697,7 +1435,7 @@ var PmtHouseClient = class {
697
1435
  as,
698
1436
  client,
699
1437
  clientAuth,
700
- TOKEN_EXCHANGE_GRANT,
1438
+ TOKEN_EXCHANGE_GRANT2,
701
1439
  params,
702
1440
  this.tokenEndpointFetchOptions()
703
1441
  );
@@ -739,7 +1477,7 @@ var PmtHouseClient = class {
739
1477
  }
740
1478
  const machineToken = await this.issueMachineAccessToken("sign:job");
741
1479
  if (!machineToken.access_token) {
742
- throw new PmtHouseError("Client credentials flow did not return access_token", {
1480
+ throw new exports.PmtHouseError("Client credentials flow did not return access_token", {
743
1481
  status: 502,
744
1482
  code: "invalid_token_response"
745
1483
  });
@@ -753,6 +1491,7 @@ var PmtHouseClient = class {
753
1491
  if (input.groupBy) url.searchParams.set("groupBy", input.groupBy);
754
1492
  if (input.userId) url.searchParams.set("userId", input.userId);
755
1493
  if (input.gatewayRequestId) url.searchParams.set("gatewayRequestId", input.gatewayRequestId);
1494
+ if (input.includeRetail) url.searchParams.set("include", "retail");
756
1495
  return this.requestJson(url.toString(), {
757
1496
  method: "GET",
758
1497
  headers: this.builderHeaders(),
@@ -762,6 +1501,129 @@ var PmtHouseClient = class {
762
1501
  /**
763
1502
  * Session-scoped usage for one `externalUserId`: user rollup plus merged pipeline/model breakdown.
764
1503
  */
1504
+ async ingestSignedTicket(ticket) {
1505
+ return ingestSignedTicket({
1506
+ issuerUrl: this.issuerUrl,
1507
+ publicClientId: this.publicClientId,
1508
+ m2mClientId: this.m2mClientId,
1509
+ m2mClientSecret: this.m2mClientSecret,
1510
+ ticket,
1511
+ fetch: this.fetchImpl
1512
+ });
1513
+ }
1514
+ async ingestSignedTickets(tickets) {
1515
+ return ingestSignedTicketsBatch({
1516
+ issuerUrl: this.issuerUrl,
1517
+ publicClientId: this.publicClientId,
1518
+ m2mClientId: this.m2mClientId,
1519
+ m2mClientSecret: this.m2mClientSecret,
1520
+ tickets,
1521
+ fetch: this.fetchImpl
1522
+ });
1523
+ }
1524
+ async getSignerRouting() {
1525
+ return this.requestJson(
1526
+ `${this.getAppsBaseUrl()}/signer/routing`,
1527
+ {
1528
+ method: "GET",
1529
+ headers: this.builderHeaders(),
1530
+ cache: "no-store"
1531
+ }
1532
+ );
1533
+ }
1534
+ async listBillingProducts() {
1535
+ const url = `${this.getAppsBaseUrl()}/plans?apiVersion=2`;
1536
+ const body = await this.requestJson(
1537
+ url,
1538
+ {
1539
+ method: "GET",
1540
+ headers: this.builderHeaders(),
1541
+ cache: "no-store"
1542
+ }
1543
+ );
1544
+ return {
1545
+ apiVersion: body.apiVersion ?? 2,
1546
+ products: body.products ?? body.plans ?? []
1547
+ };
1548
+ }
1549
+ async syncBillingProduct(planId) {
1550
+ return this.requestJson(
1551
+ `${this.getAppsBaseUrl()}/plans/${encodeURIComponent(planId)}/sync`,
1552
+ {
1553
+ method: "POST",
1554
+ headers: this.builderHeaders(),
1555
+ cache: "no-store"
1556
+ }
1557
+ );
1558
+ }
1559
+ async getUsageBalance(externalUserId) {
1560
+ const url = new URL(`${this.getAppsBaseUrl()}/usage/balance`);
1561
+ url.searchParams.set("externalUserId", externalUserId);
1562
+ return this.requestJson(url.toString(), {
1563
+ method: "GET",
1564
+ headers: this.builderHeaders(),
1565
+ cache: "no-store"
1566
+ });
1567
+ }
1568
+ async getUserAllowances(externalUserId) {
1569
+ return this.requestJson(
1570
+ `${this.getAppsBaseUrl()}/users/${encodeURIComponent(externalUserId)}/allowances`,
1571
+ {
1572
+ method: "GET",
1573
+ headers: this.builderHeaders(),
1574
+ cache: "no-store"
1575
+ }
1576
+ );
1577
+ }
1578
+ async grantUserAllowance(externalUserId, input) {
1579
+ return this.requestJson(
1580
+ `${this.getAppsBaseUrl()}/users/${encodeURIComponent(externalUserId)}/allowances`,
1581
+ {
1582
+ method: "POST",
1583
+ headers: this.builderHeaders(),
1584
+ body: JSON.stringify(input),
1585
+ cache: "no-store"
1586
+ }
1587
+ );
1588
+ }
1589
+ /**
1590
+ * @deprecated Removed from PymtHouse — use {@link getUsageBalance} or {@link getUserAllowances}.
1591
+ */
1592
+ async getUserCredits(externalUserId) {
1593
+ return this.getUsageBalance(externalUserId);
1594
+ }
1595
+ /**
1596
+ * @deprecated Removed from PymtHouse — use {@link grantUserAllowance} (`POST .../allowances`).
1597
+ */
1598
+ async grantUserCredits(externalUserId, input) {
1599
+ const result = await this.grantUserAllowance(externalUserId, {
1600
+ amountUsdMicros: input.amountUsdMicros,
1601
+ source: input.source ?? "manual",
1602
+ featureKey: input.featureKey
1603
+ });
1604
+ const flat = result;
1605
+ const nested = result.allowances;
1606
+ return {
1607
+ externalUserId: result.externalUserId,
1608
+ balanceUsdMicros: flat.balanceUsdMicros ?? nested?.balanceUsdMicros ?? "0",
1609
+ consumedUsdMicros: flat.consumedUsdMicros ?? nested?.consumedUsdMicros ?? "0",
1610
+ lifetimeGrantedUsdMicros: flat.lifetimeGrantedUsdMicros ?? nested?.lifetimeGrantedUsdMicros ?? "0",
1611
+ hasAccess: flat.hasAccess ?? nested?.hasAccess ?? false,
1612
+ remainingUsdMicros: flat.balanceUsdMicros ?? nested?.balanceUsdMicros,
1613
+ grantedUsdMicros: flat.grantedUsdMicros,
1614
+ featureKey: flat.featureKey
1615
+ };
1616
+ }
1617
+ async getUserSubscription(externalUserId) {
1618
+ return this.requestJson(
1619
+ `${this.getAppsBaseUrl()}/users/${encodeURIComponent(externalUserId)}/subscription`,
1620
+ {
1621
+ method: "GET",
1622
+ headers: this.builderHeaders(),
1623
+ cache: "no-store"
1624
+ }
1625
+ );
1626
+ }
765
1627
  async fetchUsageForExternalUser(input) {
766
1628
  const usageByUser = await this.getUsage({
767
1629
  startDate: input.startDate,
@@ -781,7 +1643,18 @@ var PmtHouseClient = class {
781
1643
  })
782
1644
  )
783
1645
  );
784
- return buildMeScopeUsagePayload(usageByUser, input.externalUserId, usagePipelineModels);
1646
+ const usageDaily = await this.getUsage({
1647
+ startDate: input.startDate,
1648
+ endDate: input.endDate,
1649
+ groupBy: "daily_pipeline",
1650
+ userId: input.externalUserId
1651
+ });
1652
+ return buildMeScopeUsagePayload(
1653
+ usageByUser,
1654
+ input.externalUserId,
1655
+ usagePipelineModels,
1656
+ usageDaily
1657
+ );
785
1658
  }
786
1659
  async getAppManifest(opts) {
787
1660
  const url = `${this.getAppsBaseUrl()}/manifest`;
@@ -820,14 +1693,14 @@ var PmtHouseClient = class {
820
1693
  } else {
821
1694
  description = `Request failed (${response.status})`;
822
1695
  }
823
- throw new PmtHouseError(description, {
1696
+ throw new exports.PmtHouseError(description, {
824
1697
  status: response.status,
825
1698
  code: typeof details.error === "string" ? details.error : "pymthouse_http_error",
826
1699
  details
827
1700
  });
828
1701
  }
829
1702
  if (!looksJson || parsed === null) {
830
- throw new PmtHouseError("Expected JSON response from Builder manifest endpoint", {
1703
+ throw new exports.PmtHouseError("Expected JSON response from Builder manifest endpoint", {
831
1704
  status: 502,
832
1705
  code: "invalid_response",
833
1706
  details: { contentType: ct, preview: raw.slice(0, 200) }
@@ -860,7 +1733,7 @@ var PmtHouseClient = class {
860
1733
  */
861
1734
  async approveDeviceLogin(input) {
862
1735
  if (input.publicClientId && input.publicClientId !== this.publicClientId) {
863
- throw new PmtHouseError(
1736
+ throw new exports.PmtHouseError(
864
1737
  "publicClientId does not match configured public client id",
865
1738
  { status: 400, code: "invalid_client" }
866
1739
  );
@@ -929,14 +1802,14 @@ var PmtHouseClient = class {
929
1802
  } else {
930
1803
  description = `Request failed (${response.status})`;
931
1804
  }
932
- throw new PmtHouseError(description, {
1805
+ throw new exports.PmtHouseError(description, {
933
1806
  status: response.status,
934
1807
  code: typeof details.error === "string" ? details.error : "pymthouse_http_error",
935
1808
  details
936
1809
  });
937
1810
  }
938
1811
  if (!looksJson || parsed === null) {
939
- throw new PmtHouseError("Expected JSON response from Builder or Usage API", {
1812
+ throw new exports.PmtHouseError("Expected JSON response from Builder or Usage API", {
940
1813
  status: 502,
941
1814
  code: "invalid_response",
942
1815
  details: { contentType: ct, preview: raw.slice(0, 200) }
@@ -955,23 +1828,27 @@ var PmtHouseClient = class {
955
1828
  }
956
1829
  }
957
1830
  asError(error) {
958
- if (error instanceof PmtHouseError) {
1831
+ if (error instanceof exports.PmtHouseError) {
959
1832
  return error;
960
1833
  }
961
1834
  if (error instanceof Error) {
962
- return new PmtHouseError(error.message, {
1835
+ return new exports.PmtHouseError(error.message, {
963
1836
  code: "unexpected_error",
964
1837
  status: 500
965
1838
  });
966
1839
  }
967
- return new PmtHouseError("Unexpected error", {
1840
+ return new exports.PmtHouseError("Unexpected error", {
968
1841
  code: "unexpected_error",
969
1842
  status: 500
970
1843
  });
971
1844
  }
972
1845
  };
973
1846
 
1847
+ // src/index.ts
1848
+ init_errors();
1849
+
974
1850
  // src/config.ts
1851
+ init_string_utils();
975
1852
  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
1853
  function trimEnv(name) {
977
1854
  const value = process.env[name];
@@ -1010,22 +1887,25 @@ function isPymthouseConfigured() {
1010
1887
  return readPymthouseEnv() !== null;
1011
1888
  }
1012
1889
  function getBuilderApiV1BaseFromIssuerUrl(issuerUrl) {
1013
- const noTrail = stripTrailingSlashes(issuerUrl.trim());
1014
- return noTrail.replace(/\/oidc\/?$/i, "");
1890
+ return stripOidcPathSuffix(issuerUrl);
1015
1891
  }
1016
1892
  function getPymthouseIssuerOrigin(issuerUrl) {
1017
1893
  return new URL(stripTrailingSlashes(issuerUrl.trim())).origin;
1018
1894
  }
1019
1895
 
1896
+ // src/index.ts
1897
+ init_discovery();
1898
+
1020
1899
  exports.DEFAULT_MAX_END_USER_IDS = DEFAULT_MAX_END_USER_IDS;
1900
+ exports.NETWORK_USD_PER_MICRO = NETWORK_USD_PER_MICRO;
1021
1901
  exports.PYMTHOUSE_NOT_CONFIGURED_MESSAGE = PYMTHOUSE_NOT_CONFIGURED_MESSAGE;
1022
1902
  exports.PYMTHOUSE_SIGNER_SESSION_TTL_MS = PYMTHOUSE_SIGNER_SESSION_TTL_MS;
1023
1903
  exports.PmtHouseClient = PmtHouseClient;
1024
- exports.PmtHouseError = PmtHouseError;
1025
1904
  exports.SIGNER_SESSION_EXPIRES_IN_SEC = SIGNER_SESSION_EXPIRES_IN_SEC;
1026
1905
  exports.SIGNER_SESSION_TTL_MS = SIGNER_SESSION_TTL_MS;
1027
1906
  exports.SIGN_JOB_SCOPE = SIGN_JOB_SCOPE;
1028
1907
  exports.aggregateUsageByExternalUserId = aggregateUsageByExternalUserId;
1908
+ exports.applyRetailRateToNetworkMicros = applyRetailRateToNetworkMicros;
1029
1909
  exports.authorizationServerToOidcDocument = authorizationServerToOidcDocument;
1030
1910
  exports.buildDeviceCodeResource = buildDeviceCodeResource;
1031
1911
  exports.buildMeScopeUsagePayload = buildMeScopeUsagePayload;
@@ -1034,6 +1914,7 @@ exports.computeManifestRevision = computeManifestRevision;
1034
1914
  exports.computePymthouseExpiry = computePymthouseExpiry;
1035
1915
  exports.computeSignerSessionExpiry = computeSignerSessionExpiry;
1036
1916
  exports.decodeJwtExp = decodeJwtExp;
1917
+ exports.defaultRetailRateUsd = defaultRetailRateUsd;
1037
1918
  exports.fetchDiscoveryDocument = fetchDiscoveryDocument;
1038
1919
  exports.getBuilderApiV1BaseFromIssuerUrl = getBuilderApiV1BaseFromIssuerUrl;
1039
1920
  exports.getEndUserIdsForExternalUser = getEndUserIdsForExternalUser;
@@ -1042,17 +1923,25 @@ exports.getPymthouseIssuerUrlFromEnv = getPymthouseIssuerUrlFromEnv;
1042
1923
  exports.getPymthousePublicClientIdFromEnv = getPymthousePublicClientIdFromEnv;
1043
1924
  exports.getUsageRecordUserIdsForExternalUser = getUsageRecordUserIdsForExternalUser;
1044
1925
  exports.getUtcCalendarMonthIsoBounds = getUtcCalendarMonthIsoBounds;
1926
+ exports.ingestSignedTicket = ingestSignedTicket;
1927
+ exports.ingestSignedTicketsBatch = ingestSignedTicketsBatch;
1045
1928
  exports.isLikelyOidcJwt = isLikelyOidcJwt;
1046
1929
  exports.isOpaqueSignerSessionToken = isOpaqueSignerSessionToken;
1047
1930
  exports.isPymthouseConfigured = isPymthouseConfigured;
1048
1931
  exports.listUsageByPipelineModel = listUsageByPipelineModel;
1049
1932
  exports.loadAuthorizationServer = loadAuthorizationServer;
1933
+ exports.markupPercentToRetailRateUsd = markupPercentToRetailRateUsd;
1050
1934
  exports.mergeUsageByPipelineModel = mergeUsageByPipelineModel;
1051
1935
  exports.normalizeUserCode = normalizeUserCode;
1052
1936
  exports.parseAppManifestResponse = parseAppManifestResponse;
1937
+ exports.parseMarkupPercentInput = parseMarkupPercentInput;
1938
+ exports.parseRetailRateUsd = parseRetailRateUsd;
1053
1939
  exports.parseSignerSessionExchange = parseSignerSessionExchange;
1054
1940
  exports.parseUsageDateParam = parseUsageDateParam;
1055
1941
  exports.readPymthouseEnv = readPymthouseEnv;
1942
+ exports.retailRateUsdPerMillion = retailRateUsdPerMillion;
1943
+ exports.retailRateUsdToMarkupPercent = retailRateUsdToMarkupPercent;
1944
+ exports.signerSnapshotToIngestPayload = signerSnapshotToIngestPayload;
1056
1945
  exports.summarizeUsageFiatForExternalUser = summarizeUsageFiatForExternalUser;
1057
1946
  exports.summarizeUsageForExternalUser = summarizeUsageForExternalUser;
1058
1947
  exports.toPmtHouseError = toPmtHouseError;