@pymthouse/builder-sdk 0.1.0 → 0.3.1
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/README.md +66 -0
- package/dist/{client-BroVFyIy.d.ts → client-BHfjDvIe.d.ts} +49 -1
- package/dist/{client-BhC1YhB1.d.cts → client-CvhJEhjV.d.cts} +49 -1
- package/dist/config.cjs +59 -3
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +8 -1
- package/dist/config.d.ts +8 -1
- package/dist/config.js +57 -4
- package/dist/config.js.map +1 -1
- package/dist/device-initiate.cjs +1 -1
- package/dist/device-initiate.cjs.map +1 -1
- package/dist/device-initiate.js +1 -1
- package/dist/device-initiate.js.map +1 -1
- package/dist/device.cjs +1 -1
- package/dist/device.cjs.map +1 -1
- package/dist/device.d.cts +1 -1
- package/dist/device.d.ts +1 -1
- package/dist/device.js +1 -1
- package/dist/device.js.map +1 -1
- package/dist/env.cjs +794 -36
- package/dist/env.cjs.map +1 -1
- package/dist/env.d.cts +2 -2
- package/dist/env.d.ts +2 -2
- package/dist/env.js +794 -36
- package/dist/env.js.map +1 -1
- package/dist/gateway/client/index.cjs +492 -0
- package/dist/gateway/client/index.cjs.map +1 -0
- package/dist/gateway/client/index.d.cts +63 -0
- package/dist/gateway/client/index.d.ts +63 -0
- package/dist/gateway/client/index.js +489 -0
- package/dist/gateway/client/index.js.map +1 -0
- package/dist/gateway/index.cjs +16 -0
- package/dist/gateway/index.cjs.map +1 -0
- package/dist/gateway/index.d.cts +52 -0
- package/dist/gateway/index.d.ts +52 -0
- package/dist/gateway/index.js +10 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/server/index.cjs +1248 -0
- package/dist/gateway/server/index.cjs.map +1 -0
- package/dist/gateway/server/index.d.cts +31 -0
- package/dist/gateway/server/index.d.ts +31 -0
- package/dist/gateway/server/index.js +1233 -0
- package/dist/gateway/server/index.js.map +1 -0
- package/dist/index.cjs +1075 -186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +1042 -163
- package/dist/index.js.map +1 -1
- package/dist/ingest-B3Yi8Tb1.d.cts +271 -0
- package/dist/ingest-DoKJTWU9.d.ts +271 -0
- package/dist/plan-pricing.cjs +108 -0
- package/dist/plan-pricing.cjs.map +1 -0
- package/dist/plan-pricing.d.cts +15 -0
- package/dist/plan-pricing.d.ts +15 -0
- package/dist/plan-pricing.js +98 -0
- package/dist/plan-pricing.js.map +1 -0
- package/dist/signer/server.cjs +1366 -0
- package/dist/signer/server.cjs.map +1 -0
- package/dist/signer/server.d.cts +73 -0
- package/dist/signer/server.d.ts +73 -0
- package/dist/signer/server.js +1331 -0
- package/dist/signer/server.js.map +1 -0
- package/dist/tokens.d.cts +1 -1
- package/dist/tokens.d.ts +1 -1
- package/dist/types-_R1AwEZp.d.cts +343 -0
- package/dist/types-_R1AwEZp.d.ts +343 -0
- package/dist/verify.cjs +1 -1
- package/dist/verify.cjs.map +1 -1
- package/dist/verify.d.cts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/gateway/proto/lp_rpc.proto +542 -0
- package/package.json +42 -1
- package/dist/types-rKzVXvMu.d.cts +0 -196
- 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:
|
|
127
|
-
ownerChargeUsdMicros:
|
|
128
|
-
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(
|
|
136
|
-
ownerChargeUsdMicros: (parseSafeBigInt(existing.ownerChargeUsdMicros) + parseSafeBigInt(
|
|
137
|
-
endUserBillableUsdMicros: (parseSafeBigInt(existing.endUserBillableUsdMicros) + parseSafeBigInt(
|
|
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/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
|
501
|
-
var
|
|
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",
|
|
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
|
-
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|