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