@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/env.cjs
CHANGED
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
var oauth4webapi = require('oauth4webapi');
|
|
4
4
|
require('crypto');
|
|
5
5
|
|
|
6
|
-
|
|
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
|
+
};
|
|
7
15
|
|
|
8
16
|
// src/encoding.ts
|
|
9
17
|
function encodeClientSecretBasic(clientId, clientSecret) {
|
|
@@ -11,35 +19,69 @@ function encodeClientSecretBasic(clientId, clientSecret) {
|
|
|
11
19
|
const b64 = typeof Buffer !== "undefined" ? Buffer.from(raw, "utf8").toString("base64") : btoa(Array.from(new TextEncoder().encode(raw), (c) => String.fromCharCode(c)).join(""));
|
|
12
20
|
return `Basic ${b64}`;
|
|
13
21
|
}
|
|
22
|
+
var init_encoding = __esm({
|
|
23
|
+
"src/encoding.ts"() {
|
|
24
|
+
}
|
|
25
|
+
});
|
|
14
26
|
|
|
15
27
|
// src/errors.ts
|
|
16
|
-
var PmtHouseError
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
var PmtHouseError;
|
|
29
|
+
var init_errors = __esm({
|
|
30
|
+
"src/errors.ts"() {
|
|
31
|
+
PmtHouseError = class extends Error {
|
|
32
|
+
status;
|
|
33
|
+
code;
|
|
34
|
+
details;
|
|
35
|
+
constructor(message, {
|
|
36
|
+
status = 500,
|
|
37
|
+
code = "pymthouse_error",
|
|
38
|
+
details
|
|
39
|
+
} = {}) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "PmtHouseError";
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.code = code;
|
|
44
|
+
this.details = details;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
30
47
|
}
|
|
31
|
-
};
|
|
48
|
+
});
|
|
32
49
|
|
|
33
50
|
// src/string-utils.ts
|
|
34
51
|
function stripTrailingSlashes(value) {
|
|
35
52
|
let end = value.length;
|
|
36
|
-
while (end > 0 && value.
|
|
53
|
+
while (end > 0 && (value.codePointAt(end - 1) ?? 0) === 47) {
|
|
37
54
|
end--;
|
|
38
55
|
}
|
|
39
56
|
return value.slice(0, end);
|
|
40
57
|
}
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
function endsWithIgnoreCase(value, suffix) {
|
|
59
|
+
if (suffix.length > value.length) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const start = value.length - suffix.length;
|
|
63
|
+
for (let i = 0; i < suffix.length; i++) {
|
|
64
|
+
const a = value.codePointAt(start + i) ?? 0;
|
|
65
|
+
const b = suffix.codePointAt(i) ?? 0;
|
|
66
|
+
if (a !== b && (a | 32) !== (b | 32)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
function stripSuffixIgnoreCase(value, suffix) {
|
|
73
|
+
return endsWithIgnoreCase(value, suffix) ? value.slice(0, value.length - suffix.length) : value;
|
|
74
|
+
}
|
|
75
|
+
function stripIssuerOriginFromOidcUrl(issuerUrl) {
|
|
76
|
+
let base = stripTrailingSlashes(issuerUrl.trim());
|
|
77
|
+
base = stripSuffixIgnoreCase(base, "/api/v1/oidc");
|
|
78
|
+
base = stripSuffixIgnoreCase(base, "/oidc");
|
|
79
|
+
return stripTrailingSlashes(base);
|
|
80
|
+
}
|
|
81
|
+
var init_string_utils = __esm({
|
|
82
|
+
"src/string-utils.ts"() {
|
|
83
|
+
}
|
|
84
|
+
});
|
|
43
85
|
function authorizationServerToOidcDocument(as) {
|
|
44
86
|
const tokenEndpoint = as.token_endpoint;
|
|
45
87
|
const jwksUri = as.jwks_uri;
|
|
@@ -58,8 +100,6 @@ function authorizationServerToOidcDocument(as) {
|
|
|
58
100
|
device_authorization_endpoint: as.device_authorization_endpoint
|
|
59
101
|
};
|
|
60
102
|
}
|
|
61
|
-
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
62
|
-
var discoveryCache = /* @__PURE__ */ new Map();
|
|
63
103
|
function normalizedIssuerKey(issuerUrl) {
|
|
64
104
|
return stripTrailingSlashes(issuerUrl);
|
|
65
105
|
}
|
|
@@ -124,6 +164,447 @@ function mapDiscoveryNetworkError(error) {
|
|
|
124
164
|
code: "oidc_discovery_failed"
|
|
125
165
|
});
|
|
126
166
|
}
|
|
167
|
+
var CACHE_TTL_MS, discoveryCache;
|
|
168
|
+
var init_discovery = __esm({
|
|
169
|
+
"src/discovery.ts"() {
|
|
170
|
+
init_errors();
|
|
171
|
+
init_string_utils();
|
|
172
|
+
CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
173
|
+
discoveryCache = /* @__PURE__ */ new Map();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// src/signer/fetch-json.ts
|
|
178
|
+
function oauthFailureDescription(parsed, failureLabel, status) {
|
|
179
|
+
if (typeof parsed.error_description === "string") {
|
|
180
|
+
return parsed.error_description;
|
|
181
|
+
}
|
|
182
|
+
if (typeof parsed.error === "string") {
|
|
183
|
+
return parsed.error;
|
|
184
|
+
}
|
|
185
|
+
return `${failureLabel} (${status})`;
|
|
186
|
+
}
|
|
187
|
+
async function readJsonObjectFromResponse(response, options) {
|
|
188
|
+
const text = await response.text();
|
|
189
|
+
let parsed;
|
|
190
|
+
try {
|
|
191
|
+
parsed = text ? JSON.parse(text) : {};
|
|
192
|
+
} catch {
|
|
193
|
+
throw new PmtHouseError(options.invalidJsonMessage, {
|
|
194
|
+
status: 502,
|
|
195
|
+
code: options.invalidJsonCode,
|
|
196
|
+
details: { status: response.status }
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (!response.ok) {
|
|
200
|
+
const description = oauthFailureDescription(parsed, options.failureLabel, response.status);
|
|
201
|
+
throw new PmtHouseError(description, {
|
|
202
|
+
status: response.status,
|
|
203
|
+
code: typeof parsed.error === "string" ? parsed.error : options.defaultErrorCode,
|
|
204
|
+
details: parsed
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return parsed;
|
|
208
|
+
}
|
|
209
|
+
var init_fetch_json = __esm({
|
|
210
|
+
"src/signer/fetch-json.ts"() {
|
|
211
|
+
init_errors();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// src/signer/handler-errors.ts
|
|
216
|
+
function signerHandlerErrorResponse(error) {
|
|
217
|
+
if (error instanceof PmtHouseError) {
|
|
218
|
+
return new Response(
|
|
219
|
+
JSON.stringify({
|
|
220
|
+
error: error.code,
|
|
221
|
+
error_description: error.message,
|
|
222
|
+
details: error.details
|
|
223
|
+
}),
|
|
224
|
+
{
|
|
225
|
+
status: error.status,
|
|
226
|
+
headers: { "Content-Type": "application/json" }
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
const message = error instanceof Error ? error.message : "Internal error";
|
|
231
|
+
return new Response(JSON.stringify({ error: "internal_error", error_description: message }), {
|
|
232
|
+
status: 500,
|
|
233
|
+
headers: { "Content-Type": "application/json" }
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
var init_handler_errors = __esm({
|
|
237
|
+
"src/signer/handler-errors.ts"() {
|
|
238
|
+
init_errors();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// src/signer/json-fields.ts
|
|
243
|
+
function readStringField(body, key, errorCode, messagePrefix = "Response") {
|
|
244
|
+
const value = body[key];
|
|
245
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
246
|
+
throw new PmtHouseError(`${messagePrefix} missing ${key}`, {
|
|
247
|
+
status: 502,
|
|
248
|
+
code: errorCode
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return value.trim();
|
|
252
|
+
}
|
|
253
|
+
function readExpiresIn(body, errorCode) {
|
|
254
|
+
const expiresIn = body.expires_in;
|
|
255
|
+
if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
256
|
+
throw new PmtHouseError("Response missing expires_in", {
|
|
257
|
+
status: 502,
|
|
258
|
+
code: errorCode
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
return Math.floor(expiresIn);
|
|
262
|
+
}
|
|
263
|
+
var init_json_fields = __esm({
|
|
264
|
+
"src/signer/json-fields.ts"() {
|
|
265
|
+
init_errors();
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// src/signer/mint-token.ts
|
|
270
|
+
function parseMintUserSignerTokenResponse(body, ttlRefreshRatio = DEFAULT_TTL_REFRESH_RATIO) {
|
|
271
|
+
const accessToken = readStringField(body, "access_token", TOKEN_RESPONSE_ERROR, "Token response");
|
|
272
|
+
const expiresIn = readExpiresIn(body, TOKEN_RESPONSE_ERROR);
|
|
273
|
+
const balanceUsdMicros = readStringField(
|
|
274
|
+
body,
|
|
275
|
+
"balanceUsdMicros",
|
|
276
|
+
TOKEN_RESPONSE_ERROR,
|
|
277
|
+
"Token response"
|
|
278
|
+
);
|
|
279
|
+
const lifetimeGrantedUsdMicros = readStringField(
|
|
280
|
+
body,
|
|
281
|
+
"lifetimeGrantedUsdMicros",
|
|
282
|
+
TOKEN_RESPONSE_ERROR,
|
|
283
|
+
"Token response"
|
|
284
|
+
);
|
|
285
|
+
const now = Date.now();
|
|
286
|
+
const expiresAt = now + expiresIn * 1e3;
|
|
287
|
+
const refreshAt = now + Math.floor(expiresIn * 1e3 * ttlRefreshRatio);
|
|
288
|
+
return {
|
|
289
|
+
jwt: accessToken,
|
|
290
|
+
expiresAt,
|
|
291
|
+
refreshAt,
|
|
292
|
+
balanceUsdMicros,
|
|
293
|
+
lifetimeGrantedUsdMicros
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
var LIVEPEER_REMOTE_SIGNER_AUDIENCE, DEFAULT_TTL_REFRESH_RATIO, TOKEN_RESPONSE_ERROR;
|
|
297
|
+
var init_mint_token = __esm({
|
|
298
|
+
"src/signer/mint-token.ts"() {
|
|
299
|
+
init_json_fields();
|
|
300
|
+
LIVEPEER_REMOTE_SIGNER_AUDIENCE = "livepeer-remote-signer";
|
|
301
|
+
DEFAULT_TTL_REFRESH_RATIO = 0.8;
|
|
302
|
+
TOKEN_RESPONSE_ERROR = "invalid_token_response";
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// src/signer/device-exchange.ts
|
|
307
|
+
function extractSignerAccessTokenFromExchangeBody(body) {
|
|
308
|
+
const tokenObj = body.token;
|
|
309
|
+
if (tokenObj !== null && typeof tokenObj === "object" && !Array.isArray(tokenObj)) {
|
|
310
|
+
const nested = tokenObj;
|
|
311
|
+
for (const key of ["accessToken", "access_token"]) {
|
|
312
|
+
const value = nested[key];
|
|
313
|
+
if (typeof value === "string" && value.trim()) {
|
|
314
|
+
return value.trim();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const key of ["accessToken", "access_token"]) {
|
|
319
|
+
const value = body[key];
|
|
320
|
+
if (typeof value === "string" && value.trim()) {
|
|
321
|
+
return value.trim();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
throw new PmtHouseError("Device exchange response missing signer access token", {
|
|
325
|
+
status: 502,
|
|
326
|
+
code: "invalid_exchange_response"
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function normalizeDeviceExchangeResponse(minted, options) {
|
|
330
|
+
const scope = minted.scope.trim() || "sign:job";
|
|
331
|
+
const body = {
|
|
332
|
+
access_token: minted.access_token,
|
|
333
|
+
token_type: "Bearer",
|
|
334
|
+
expires_in: minted.expires_in,
|
|
335
|
+
scope,
|
|
336
|
+
balanceUsdMicros: minted.balanceUsdMicros,
|
|
337
|
+
lifetimeGrantedUsdMicros: minted.lifetimeGrantedUsdMicros,
|
|
338
|
+
token: {
|
|
339
|
+
accessToken: minted.access_token,
|
|
340
|
+
access_token: minted.access_token,
|
|
341
|
+
expiresIn: minted.expires_in,
|
|
342
|
+
expires_in: minted.expires_in,
|
|
343
|
+
scope,
|
|
344
|
+
balanceUsdMicros: minted.balanceUsdMicros,
|
|
345
|
+
lifetimeGrantedUsdMicros: minted.lifetimeGrantedUsdMicros
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
const signerUrl = options?.signerUrl?.trim();
|
|
349
|
+
if (signerUrl) {
|
|
350
|
+
body.signerUrl = signerUrl;
|
|
351
|
+
}
|
|
352
|
+
return body;
|
|
353
|
+
}
|
|
354
|
+
async function mintSignerTokenFromDeviceToken(options) {
|
|
355
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
356
|
+
const issuerUrl = stripTrailingSlashes(options.issuerUrl);
|
|
357
|
+
const as = await loadAuthorizationServer(issuerUrl, fetchImpl, {
|
|
358
|
+
allowInsecureHttp: options.allowInsecureHttp
|
|
359
|
+
});
|
|
360
|
+
const tokenEndpoint = as.token_endpoint;
|
|
361
|
+
if (!tokenEndpoint) {
|
|
362
|
+
throw new PmtHouseError("OIDC discovery document is missing token_endpoint", {
|
|
363
|
+
status: 500,
|
|
364
|
+
code: "oidc_discovery_invalid"
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
const audience = options.audience?.trim() || LIVEPEER_REMOTE_SIGNER_AUDIENCE;
|
|
368
|
+
const params = new URLSearchParams({
|
|
369
|
+
grant_type: TOKEN_EXCHANGE_GRANT,
|
|
370
|
+
subject_token: options.deviceToken,
|
|
371
|
+
subject_token_type: SUBJECT_ACCESS_TOKEN_TYPE,
|
|
372
|
+
audience,
|
|
373
|
+
resource: audience
|
|
374
|
+
});
|
|
375
|
+
if (options.scope?.trim()) {
|
|
376
|
+
params.set("scope", options.scope.trim());
|
|
377
|
+
}
|
|
378
|
+
const response = await fetchImpl(tokenEndpoint, {
|
|
379
|
+
method: "POST",
|
|
380
|
+
headers: {
|
|
381
|
+
Authorization: encodeClientSecretBasic(options.m2mClientId, options.m2mClientSecret),
|
|
382
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
383
|
+
Accept: "application/json"
|
|
384
|
+
},
|
|
385
|
+
body: params.toString(),
|
|
386
|
+
cache: "no-store"
|
|
387
|
+
});
|
|
388
|
+
const parsed = await readJsonObjectFromResponse(response, {
|
|
389
|
+
invalidJsonMessage: "Token endpoint returned invalid JSON",
|
|
390
|
+
invalidJsonCode: "invalid_token_response",
|
|
391
|
+
failureLabel: "Signer JWT exchange failed",
|
|
392
|
+
defaultErrorCode: "token_exchange_failed"
|
|
393
|
+
});
|
|
394
|
+
const cached = parseMintUserSignerTokenResponse(parsed);
|
|
395
|
+
return {
|
|
396
|
+
access_token: cached.jwt,
|
|
397
|
+
expires_in: readExpiresIn(parsed, EXCHANGE_RESPONSE_ERROR),
|
|
398
|
+
scope: readStringField(parsed, "scope", EXCHANGE_RESPONSE_ERROR),
|
|
399
|
+
balanceUsdMicros: cached.balanceUsdMicros,
|
|
400
|
+
lifetimeGrantedUsdMicros: cached.lifetimeGrantedUsdMicros
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
var TOKEN_EXCHANGE_GRANT, SUBJECT_ACCESS_TOKEN_TYPE, EXCHANGE_RESPONSE_ERROR;
|
|
404
|
+
var init_device_exchange = __esm({
|
|
405
|
+
"src/signer/device-exchange.ts"() {
|
|
406
|
+
init_discovery();
|
|
407
|
+
init_encoding();
|
|
408
|
+
init_errors();
|
|
409
|
+
init_string_utils();
|
|
410
|
+
init_fetch_json();
|
|
411
|
+
init_json_fields();
|
|
412
|
+
init_mint_token();
|
|
413
|
+
TOKEN_EXCHANGE_GRANT = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
414
|
+
SUBJECT_ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
|
|
415
|
+
EXCHANGE_RESPONSE_ERROR = "invalid_exchange_response";
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// src/signer/api-key-exchange.ts
|
|
420
|
+
var api_key_exchange_exports = {};
|
|
421
|
+
__export(api_key_exchange_exports, {
|
|
422
|
+
createApiKeyExchangeHandler: () => createApiKeyExchangeHandler,
|
|
423
|
+
exchangeApiKeyForSigner: () => exchangeApiKeyForSigner,
|
|
424
|
+
mintSignerSessionFromApiKey: () => mintSignerSessionFromApiKey,
|
|
425
|
+
mintUserAccessTokenFromApiKey: () => mintUserAccessTokenFromApiKey,
|
|
426
|
+
parseApiKeyExchangeRequestBody: () => parseApiKeyExchangeRequestBody
|
|
427
|
+
});
|
|
428
|
+
async function parseApiKeyExchangeRequestBody(request) {
|
|
429
|
+
let body;
|
|
430
|
+
try {
|
|
431
|
+
body = await request.json();
|
|
432
|
+
} catch {
|
|
433
|
+
throw new PmtHouseError("Request body must be JSON", {
|
|
434
|
+
status: 400,
|
|
435
|
+
code: "invalid_request"
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
if (body === null || typeof body !== "object" || Array.isArray(body)) {
|
|
439
|
+
throw new PmtHouseError("Request body must be a JSON object", {
|
|
440
|
+
status: 400,
|
|
441
|
+
code: "invalid_request"
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
const record = body;
|
|
445
|
+
const apiKeyRaw = record.apiKey;
|
|
446
|
+
if (typeof apiKeyRaw !== "string" || !apiKeyRaw.trim()) {
|
|
447
|
+
throw new PmtHouseError("Request body must include apiKey", {
|
|
448
|
+
status: 400,
|
|
449
|
+
code: "invalid_request"
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
const scope = typeof record.scope === "string" && record.scope.trim() ? record.scope.trim() : void 0;
|
|
453
|
+
const clientId = typeof record.clientId === "string" && record.clientId.trim() ? record.clientId.trim() : void 0;
|
|
454
|
+
return { apiKey: apiKeyRaw.trim(), scope, clientId };
|
|
455
|
+
}
|
|
456
|
+
async function mintUserAccessTokenFromApiKey(input) {
|
|
457
|
+
const fetchImpl = input.fetch ?? fetch;
|
|
458
|
+
const issuerOrigin = stripIssuerOriginFromOidcUrl(input.issuerUrl);
|
|
459
|
+
const url = `${issuerOrigin}/api/v1/apps/${encodeURIComponent(input.publicClientId)}/auth/api-key/token`;
|
|
460
|
+
const response = await fetchImpl(url, {
|
|
461
|
+
method: "POST",
|
|
462
|
+
headers: {
|
|
463
|
+
Authorization: `Bearer ${input.apiKey}`,
|
|
464
|
+
"Content-Type": "application/json",
|
|
465
|
+
Accept: "application/json"
|
|
466
|
+
},
|
|
467
|
+
body: JSON.stringify(input.scope ? { scope: input.scope } : {}),
|
|
468
|
+
cache: "no-store"
|
|
469
|
+
});
|
|
470
|
+
const parsed = await readJsonObjectFromResponse(response, {
|
|
471
|
+
invalidJsonMessage: "API key token exchange returned invalid JSON",
|
|
472
|
+
invalidJsonCode: "invalid_token_response",
|
|
473
|
+
failureLabel: "API key token exchange failed",
|
|
474
|
+
defaultErrorCode: "api_key_token_exchange_failed"
|
|
475
|
+
});
|
|
476
|
+
const accessToken = parsed.access_token;
|
|
477
|
+
if (typeof accessToken !== "string" || !accessToken.trim()) {
|
|
478
|
+
throw new PmtHouseError("API key token exchange missing access_token", {
|
|
479
|
+
status: 502,
|
|
480
|
+
code: EXCHANGE_RESPONSE_ERROR2
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const expiresIn = typeof parsed.expires_in === "number" && Number.isFinite(parsed.expires_in) ? parsed.expires_in : 900;
|
|
484
|
+
const scope = typeof parsed.scope === "string" && parsed.scope.trim() ? parsed.scope.trim() : input.scope?.trim() || "sign:job";
|
|
485
|
+
return {
|
|
486
|
+
access_token: accessToken.trim(),
|
|
487
|
+
expires_in: expiresIn,
|
|
488
|
+
scope
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
async function mintSignerSessionFromApiKey(input) {
|
|
492
|
+
const userToken = await mintUserAccessTokenFromApiKey({
|
|
493
|
+
issuerUrl: input.issuerUrl,
|
|
494
|
+
publicClientId: input.publicClientId,
|
|
495
|
+
apiKey: input.apiKey,
|
|
496
|
+
scope: input.scope,
|
|
497
|
+
fetch: input.fetch
|
|
498
|
+
});
|
|
499
|
+
return mintSignerTokenFromDeviceToken({
|
|
500
|
+
issuerUrl: input.issuerUrl,
|
|
501
|
+
m2mClientId: input.m2mClientId,
|
|
502
|
+
m2mClientSecret: input.m2mClientSecret,
|
|
503
|
+
deviceToken: userToken.access_token,
|
|
504
|
+
scope: userToken.scope,
|
|
505
|
+
audience: input.audience,
|
|
506
|
+
fetch: input.fetch,
|
|
507
|
+
allowInsecureHttp: input.allowInsecureHttp
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
async function exchangeApiKeyForSigner(options) {
|
|
511
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
512
|
+
const url = `${stripTrailingSlashes(options.facadeUrl)}/api/pymthouse/keys/exchange`;
|
|
513
|
+
const body = { apiKey: options.apiKey };
|
|
514
|
+
if (options.scope?.trim()) {
|
|
515
|
+
body.scope = options.scope.trim();
|
|
516
|
+
}
|
|
517
|
+
if (options.clientId?.trim()) {
|
|
518
|
+
body.clientId = options.clientId.trim();
|
|
519
|
+
}
|
|
520
|
+
const response = await fetchImpl(url, {
|
|
521
|
+
method: "POST",
|
|
522
|
+
headers: {
|
|
523
|
+
"Content-Type": "application/json",
|
|
524
|
+
Accept: "application/json"
|
|
525
|
+
},
|
|
526
|
+
body: JSON.stringify(body),
|
|
527
|
+
cache: "no-store"
|
|
528
|
+
});
|
|
529
|
+
const parsed = await readJsonObjectFromResponse(response, {
|
|
530
|
+
invalidJsonMessage: "API key exchange returned invalid JSON",
|
|
531
|
+
invalidJsonCode: EXCHANGE_RESPONSE_ERROR2,
|
|
532
|
+
failureLabel: "API key exchange failed",
|
|
533
|
+
defaultErrorCode: "api_key_exchange_failed"
|
|
534
|
+
});
|
|
535
|
+
const accessToken = extractSignerAccessTokenFromExchangeBody(parsed);
|
|
536
|
+
const signerUrlRaw = parsed.signerUrl ?? parsed.signer_url;
|
|
537
|
+
const signerUrl = typeof signerUrlRaw === "string" && signerUrlRaw.trim() ? signerUrlRaw.trim() : void 0;
|
|
538
|
+
return normalizeDeviceExchangeResponse(
|
|
539
|
+
{
|
|
540
|
+
access_token: accessToken,
|
|
541
|
+
expires_in: typeof parsed.expires_in === "number" && Number.isFinite(parsed.expires_in) ? parsed.expires_in : 3600,
|
|
542
|
+
scope: typeof parsed.scope === "string" && parsed.scope.trim() ? parsed.scope.trim() : "sign:job",
|
|
543
|
+
balanceUsdMicros: typeof parsed.balanceUsdMicros === "string" ? parsed.balanceUsdMicros : "0",
|
|
544
|
+
lifetimeGrantedUsdMicros: typeof parsed.lifetimeGrantedUsdMicros === "string" ? parsed.lifetimeGrantedUsdMicros : "0"
|
|
545
|
+
},
|
|
546
|
+
{ signerUrl }
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
function createApiKeyExchangeHandler(config) {
|
|
550
|
+
const publicClientId = config.publicClientId.trim();
|
|
551
|
+
return async function apiKeyExchangeHandler(request) {
|
|
552
|
+
try {
|
|
553
|
+
if (request.method !== "POST") {
|
|
554
|
+
return new Response(JSON.stringify({ error: "method_not_allowed" }), {
|
|
555
|
+
status: 405,
|
|
556
|
+
headers: { "Content-Type": "application/json" }
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
const parsed = await parseApiKeyExchangeRequestBody(request);
|
|
560
|
+
const effectiveClientId = parsed.clientId?.trim() || publicClientId;
|
|
561
|
+
if (effectiveClientId !== publicClientId) {
|
|
562
|
+
throw new PmtHouseError("clientId does not match configured public client", {
|
|
563
|
+
status: 400,
|
|
564
|
+
code: "invalid_request"
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
const minted = await mintSignerSessionFromApiKey({
|
|
568
|
+
issuerUrl: config.issuerUrl,
|
|
569
|
+
publicClientId,
|
|
570
|
+
m2mClientId: config.m2mClientId,
|
|
571
|
+
m2mClientSecret: config.m2mClientSecret,
|
|
572
|
+
apiKey: parsed.apiKey,
|
|
573
|
+
scope: parsed.scope,
|
|
574
|
+
audience: config.audience,
|
|
575
|
+
fetch: config.fetch,
|
|
576
|
+
allowInsecureHttp: config.allowInsecureHttp
|
|
577
|
+
});
|
|
578
|
+
const signerUrlValue = typeof config.signerUrl === "string" && config.signerUrl.trim() ? config.signerUrl.trim() : void 0;
|
|
579
|
+
const body = normalizeDeviceExchangeResponse(minted, { signerUrl: signerUrlValue });
|
|
580
|
+
return new Response(JSON.stringify(body), {
|
|
581
|
+
status: 200,
|
|
582
|
+
headers: {
|
|
583
|
+
"Content-Type": "application/json",
|
|
584
|
+
"Cache-Control": "no-store"
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
} catch (error) {
|
|
588
|
+
return signerHandlerErrorResponse(error);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
var EXCHANGE_RESPONSE_ERROR2;
|
|
593
|
+
var init_api_key_exchange = __esm({
|
|
594
|
+
"src/signer/api-key-exchange.ts"() {
|
|
595
|
+
init_string_utils();
|
|
596
|
+
init_errors();
|
|
597
|
+
init_fetch_json();
|
|
598
|
+
init_handler_errors();
|
|
599
|
+
init_device_exchange();
|
|
600
|
+
EXCHANGE_RESPONSE_ERROR2 = "invalid_exchange_response";
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// src/client.ts
|
|
605
|
+
init_encoding();
|
|
606
|
+
init_discovery();
|
|
607
|
+
init_errors();
|
|
127
608
|
function parseAppManifestResponse(json) {
|
|
128
609
|
if (!json || typeof json !== "object" || Array.isArray(json)) {
|
|
129
610
|
return { capabilities: [], excludedCapabilities: [] };
|
|
@@ -141,6 +622,9 @@ function parseCapabilityArray(raw) {
|
|
|
141
622
|
);
|
|
142
623
|
}
|
|
143
624
|
|
|
625
|
+
// src/client.ts
|
|
626
|
+
init_string_utils();
|
|
627
|
+
|
|
144
628
|
// src/tokens.ts
|
|
145
629
|
var SIGNER_SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
146
630
|
var SIGNER_SESSION_EXPIRES_IN_SEC = Math.floor(SIGNER_SESSION_TTL_MS / 1e3);
|
|
@@ -234,24 +718,27 @@ function mergeUsageByPipelineModel(usagePipelineModels) {
|
|
|
234
718
|
const key = JSON.stringify([pipeline, modelId]);
|
|
235
719
|
const existing = byKey.get(key);
|
|
236
720
|
const rowCurrency = row.currency ?? "USD";
|
|
721
|
+
const networkFee = row.networkFeeUsdMicros ?? "0";
|
|
722
|
+
const ownerCharge = row.ownerChargeUsdMicros ?? "0";
|
|
723
|
+
const endUserBillable = row.endUserBillableUsdMicros ?? "0";
|
|
237
724
|
if (!existing) {
|
|
238
725
|
byKey.set(key, {
|
|
239
726
|
pipeline,
|
|
240
727
|
modelId,
|
|
241
728
|
requestCount: row.requestCount,
|
|
242
729
|
currency: rowCurrency,
|
|
243
|
-
networkFeeUsdMicros:
|
|
244
|
-
ownerChargeUsdMicros:
|
|
245
|
-
endUserBillableUsdMicros:
|
|
730
|
+
networkFeeUsdMicros: networkFee,
|
|
731
|
+
ownerChargeUsdMicros: ownerCharge,
|
|
732
|
+
endUserBillableUsdMicros: endUserBillable
|
|
246
733
|
});
|
|
247
734
|
continue;
|
|
248
735
|
}
|
|
249
736
|
byKey.set(key, {
|
|
250
737
|
...existing,
|
|
251
738
|
requestCount: existing.requestCount + row.requestCount,
|
|
252
|
-
networkFeeUsdMicros: (parseSafeBigInt(existing.networkFeeUsdMicros) + parseSafeBigInt(
|
|
253
|
-
ownerChargeUsdMicros: (parseSafeBigInt(existing.ownerChargeUsdMicros) + parseSafeBigInt(
|
|
254
|
-
endUserBillableUsdMicros: (parseSafeBigInt(existing.endUserBillableUsdMicros) + parseSafeBigInt(
|
|
739
|
+
networkFeeUsdMicros: (parseSafeBigInt(existing.networkFeeUsdMicros) + parseSafeBigInt(networkFee)).toString(),
|
|
740
|
+
ownerChargeUsdMicros: (parseSafeBigInt(existing.ownerChargeUsdMicros) + parseSafeBigInt(ownerCharge)).toString(),
|
|
741
|
+
endUserBillableUsdMicros: (parseSafeBigInt(existing.endUserBillableUsdMicros) + parseSafeBigInt(endUserBillable)).toString()
|
|
255
742
|
});
|
|
256
743
|
}
|
|
257
744
|
}
|
|
@@ -260,9 +747,10 @@ function mergeUsageByPipelineModel(usagePipelineModels) {
|
|
|
260
747
|
return a.pipeline.localeCompare(b.pipeline);
|
|
261
748
|
});
|
|
262
749
|
}
|
|
263
|
-
function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineModel) {
|
|
750
|
+
function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineModel, usageDaily) {
|
|
264
751
|
const summary = summarizeUsageFiatForExternalUser(usageByUser, externalUserId);
|
|
265
752
|
const pipelineModels = mergeUsageByPipelineModel(usagePipelineModel);
|
|
753
|
+
const dailyByPipeline = usageDaily?.byDailyPipeline ?? [];
|
|
266
754
|
return {
|
|
267
755
|
clientId: usageByUser.clientId,
|
|
268
756
|
period: usageByUser.period,
|
|
@@ -273,11 +761,15 @@ function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineMode
|
|
|
273
761
|
networkFeeUsdMicros: summary.networkFeeUsdMicros,
|
|
274
762
|
ownerChargeUsdMicros: summary.ownerChargeUsdMicros,
|
|
275
763
|
endUserBillableUsdMicros: summary.endUserBillableUsdMicros,
|
|
276
|
-
pipelineModels
|
|
764
|
+
pipelineModels,
|
|
765
|
+
dailyByPipeline
|
|
277
766
|
}
|
|
278
767
|
};
|
|
279
768
|
}
|
|
280
769
|
var DEFAULT_MAX_END_USER_IDS = 25;
|
|
770
|
+
|
|
771
|
+
// src/oauth-map.ts
|
|
772
|
+
init_errors();
|
|
281
773
|
var ACCEPTED_ISSUED_TOKEN_TYPES = /* @__PURE__ */ new Set([
|
|
282
774
|
"urn:ietf:params:oauth:token-type:access_token",
|
|
283
775
|
"urn:pmth:token-type:remote-signer-session"
|
|
@@ -370,9 +862,94 @@ function m2mClient(clientId) {
|
|
|
370
862
|
return { client_id: clientId };
|
|
371
863
|
}
|
|
372
864
|
|
|
865
|
+
// src/ingest.ts
|
|
866
|
+
init_encoding();
|
|
867
|
+
init_errors();
|
|
868
|
+
init_string_utils();
|
|
869
|
+
function ingestUrl(issuerUrl, publicClientId) {
|
|
870
|
+
const origin = new URL(stripTrailingSlashes(issuerUrl)).origin;
|
|
871
|
+
return `${origin}/api/v1/apps/${encodeURIComponent(publicClientId)}/usage/signed-tickets`;
|
|
872
|
+
}
|
|
873
|
+
async function readJsonResponse(response) {
|
|
874
|
+
const text = await response.text();
|
|
875
|
+
if (!text.trim()) {
|
|
876
|
+
return {};
|
|
877
|
+
}
|
|
878
|
+
try {
|
|
879
|
+
const parsed = JSON.parse(text);
|
|
880
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
881
|
+
} catch {
|
|
882
|
+
return {};
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
async function ingestSignedTicket(options) {
|
|
886
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
887
|
+
const url = ingestUrl(options.issuerUrl, options.publicClientId);
|
|
888
|
+
const response = await fetchImpl(url, {
|
|
889
|
+
method: "POST",
|
|
890
|
+
headers: {
|
|
891
|
+
Authorization: encodeClientSecretBasic(options.m2mClientId, options.m2mClientSecret),
|
|
892
|
+
"Content-Type": "application/json",
|
|
893
|
+
Accept: "application/json"
|
|
894
|
+
},
|
|
895
|
+
body: JSON.stringify(options.ticket),
|
|
896
|
+
cache: "no-store"
|
|
897
|
+
});
|
|
898
|
+
const body = await readJsonResponse(response);
|
|
899
|
+
if (!response.ok) {
|
|
900
|
+
const message = typeof body.error === "string" ? body.error : `Signed-ticket ingest failed (${response.status})`;
|
|
901
|
+
throw new PmtHouseError(message, {
|
|
902
|
+
status: response.status,
|
|
903
|
+
code: "ingest_failed",
|
|
904
|
+
details: body
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
return {
|
|
908
|
+
ingested: Boolean(body.ingested),
|
|
909
|
+
duplicate: Boolean(body.duplicate),
|
|
910
|
+
source: body.source === "openmeter" ? "openmeter" : "disabled"
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
async function ingestSignedTicketsBatch(options) {
|
|
914
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
915
|
+
const url = ingestUrl(options.issuerUrl, options.publicClientId);
|
|
916
|
+
const response = await fetchImpl(url, {
|
|
917
|
+
method: "POST",
|
|
918
|
+
headers: {
|
|
919
|
+
Authorization: encodeClientSecretBasic(options.m2mClientId, options.m2mClientSecret),
|
|
920
|
+
"Content-Type": "application/json",
|
|
921
|
+
Accept: "application/json"
|
|
922
|
+
},
|
|
923
|
+
body: JSON.stringify({ tickets: options.tickets }),
|
|
924
|
+
cache: "no-store"
|
|
925
|
+
});
|
|
926
|
+
const body = await readJsonResponse(response);
|
|
927
|
+
if (!response.ok) {
|
|
928
|
+
const message = typeof body.error === "string" ? body.error : `Signed-ticket batch ingest failed (${response.status})`;
|
|
929
|
+
throw new PmtHouseError(message, {
|
|
930
|
+
status: response.status,
|
|
931
|
+
code: "ingest_failed",
|
|
932
|
+
details: body
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
const rawResults = Array.isArray(body.results) ? body.results : [];
|
|
936
|
+
return {
|
|
937
|
+
results: rawResults.map((entry) => {
|
|
938
|
+
const row = entry ?? {};
|
|
939
|
+
return {
|
|
940
|
+
requestId: typeof row.requestId === "string" ? row.requestId : void 0,
|
|
941
|
+
ok: row.ok === true,
|
|
942
|
+
ingested: Boolean(row.ingested),
|
|
943
|
+
duplicate: Boolean(row.duplicate),
|
|
944
|
+
source: row.source === "openmeter" ? "openmeter" : "disabled"
|
|
945
|
+
};
|
|
946
|
+
})
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
|
|
373
950
|
// src/client.ts
|
|
374
|
-
var
|
|
375
|
-
var
|
|
951
|
+
var TOKEN_EXCHANGE_GRANT2 = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
952
|
+
var SUBJECT_ACCESS_TOKEN_TYPE2 = "urn:ietf:params:oauth:token-type:access_token";
|
|
376
953
|
var REQUESTED_ACCESS_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
|
|
377
954
|
var DEVICE_RESOURCE_PREFIX = "urn:pmth:device_code:";
|
|
378
955
|
function normalizeUserCode(value) {
|
|
@@ -499,6 +1076,50 @@ var PmtHouseClient = class {
|
|
|
499
1076
|
cache: "no-store"
|
|
500
1077
|
});
|
|
501
1078
|
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Exchange a long-lived dashboard API key (`pmth_*`) for a short-lived user JWT.
|
|
1081
|
+
*/
|
|
1082
|
+
async exchangeApiKeyForUserAccessToken(input) {
|
|
1083
|
+
const url = `${this.getAppsBaseUrl()}/auth/api-key/token`;
|
|
1084
|
+
return this.requestJson(url, {
|
|
1085
|
+
method: "POST",
|
|
1086
|
+
headers: {
|
|
1087
|
+
Authorization: `Bearer ${input.apiKey.trim()}`,
|
|
1088
|
+
"Content-Type": "application/json",
|
|
1089
|
+
Accept: "application/json"
|
|
1090
|
+
},
|
|
1091
|
+
body: JSON.stringify(input.scope ? { scope: input.scope } : {}),
|
|
1092
|
+
cache: "no-store"
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Exchange a dashboard API key for a signer session via a trusted facade (recommended)
|
|
1097
|
+
* or directly when M2M credentials are available on this client.
|
|
1098
|
+
*/
|
|
1099
|
+
async exchangeApiKeyForSignerSession(input) {
|
|
1100
|
+
if (input.facadeUrl?.trim()) {
|
|
1101
|
+
const { exchangeApiKeyForSigner: exchangeApiKeyForSigner2 } = await Promise.resolve().then(() => (init_api_key_exchange(), api_key_exchange_exports));
|
|
1102
|
+
const exchanged = await exchangeApiKeyForSigner2({
|
|
1103
|
+
facadeUrl: input.facadeUrl.trim(),
|
|
1104
|
+
apiKey: input.apiKey,
|
|
1105
|
+
scope: input.scope,
|
|
1106
|
+
clientId: this.publicClientId,
|
|
1107
|
+
fetch: this.fetchImpl
|
|
1108
|
+
});
|
|
1109
|
+
return {
|
|
1110
|
+
access_token: exchanged.access_token,
|
|
1111
|
+
token_type: exchanged.token_type,
|
|
1112
|
+
expires_in: exchanged.expires_in,
|
|
1113
|
+
scope: exchanged.scope,
|
|
1114
|
+
issued_token_type: "urn:ietf:params:oauth:token-type:access_token"
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
const userToken = await this.exchangeApiKeyForUserAccessToken({
|
|
1118
|
+
apiKey: input.apiKey,
|
|
1119
|
+
scope: input.scope
|
|
1120
|
+
});
|
|
1121
|
+
return this.exchangeForSignerSession({ userJwt: userToken.access_token });
|
|
1122
|
+
}
|
|
502
1123
|
async completeDeviceApproval(input) {
|
|
503
1124
|
const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {
|
|
504
1125
|
allowInsecureHttp: this.allowInsecureHttp
|
|
@@ -507,14 +1128,14 @@ var PmtHouseClient = class {
|
|
|
507
1128
|
const clientAuth = this.m2mClientAuth();
|
|
508
1129
|
const params = new URLSearchParams();
|
|
509
1130
|
params.set("subject_token", input.userJwt);
|
|
510
|
-
params.set("subject_token_type",
|
|
1131
|
+
params.set("subject_token_type", SUBJECT_ACCESS_TOKEN_TYPE2);
|
|
511
1132
|
params.set("resource", buildDeviceCodeResource(input.userCode));
|
|
512
1133
|
try {
|
|
513
1134
|
const response = await oauth4webapi.genericTokenEndpointRequest(
|
|
514
1135
|
as,
|
|
515
1136
|
client,
|
|
516
1137
|
clientAuth,
|
|
517
|
-
|
|
1138
|
+
TOKEN_EXCHANGE_GRANT2,
|
|
518
1139
|
params,
|
|
519
1140
|
this.tokenEndpointFetchOptions()
|
|
520
1141
|
);
|
|
@@ -562,7 +1183,7 @@ var PmtHouseClient = class {
|
|
|
562
1183
|
const clientAuth = this.m2mClientAuth();
|
|
563
1184
|
const params = new URLSearchParams();
|
|
564
1185
|
params.set("subject_token", input.userJwt);
|
|
565
|
-
params.set("subject_token_type",
|
|
1186
|
+
params.set("subject_token_type", SUBJECT_ACCESS_TOKEN_TYPE2);
|
|
566
1187
|
params.set("requested_token_type", REQUESTED_ACCESS_TOKEN_TYPE);
|
|
567
1188
|
const resourceCandidate = typeof input.resource === "string" && input.resource.trim() !== "" ? input.resource.trim() : this.issuerUrl;
|
|
568
1189
|
params.set("resource", stripTrailingSlashes(resourceCandidate));
|
|
@@ -571,7 +1192,7 @@ var PmtHouseClient = class {
|
|
|
571
1192
|
as,
|
|
572
1193
|
client,
|
|
573
1194
|
clientAuth,
|
|
574
|
-
|
|
1195
|
+
TOKEN_EXCHANGE_GRANT2,
|
|
575
1196
|
params,
|
|
576
1197
|
this.tokenEndpointFetchOptions()
|
|
577
1198
|
);
|
|
@@ -627,6 +1248,7 @@ var PmtHouseClient = class {
|
|
|
627
1248
|
if (input.groupBy) url.searchParams.set("groupBy", input.groupBy);
|
|
628
1249
|
if (input.userId) url.searchParams.set("userId", input.userId);
|
|
629
1250
|
if (input.gatewayRequestId) url.searchParams.set("gatewayRequestId", input.gatewayRequestId);
|
|
1251
|
+
if (input.includeRetail) url.searchParams.set("include", "retail");
|
|
630
1252
|
return this.requestJson(url.toString(), {
|
|
631
1253
|
method: "GET",
|
|
632
1254
|
headers: this.builderHeaders(),
|
|
@@ -636,6 +1258,129 @@ var PmtHouseClient = class {
|
|
|
636
1258
|
/**
|
|
637
1259
|
* Session-scoped usage for one `externalUserId`: user rollup plus merged pipeline/model breakdown.
|
|
638
1260
|
*/
|
|
1261
|
+
async ingestSignedTicket(ticket) {
|
|
1262
|
+
return ingestSignedTicket({
|
|
1263
|
+
issuerUrl: this.issuerUrl,
|
|
1264
|
+
publicClientId: this.publicClientId,
|
|
1265
|
+
m2mClientId: this.m2mClientId,
|
|
1266
|
+
m2mClientSecret: this.m2mClientSecret,
|
|
1267
|
+
ticket,
|
|
1268
|
+
fetch: this.fetchImpl
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
async ingestSignedTickets(tickets) {
|
|
1272
|
+
return ingestSignedTicketsBatch({
|
|
1273
|
+
issuerUrl: this.issuerUrl,
|
|
1274
|
+
publicClientId: this.publicClientId,
|
|
1275
|
+
m2mClientId: this.m2mClientId,
|
|
1276
|
+
m2mClientSecret: this.m2mClientSecret,
|
|
1277
|
+
tickets,
|
|
1278
|
+
fetch: this.fetchImpl
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
async getSignerRouting() {
|
|
1282
|
+
return this.requestJson(
|
|
1283
|
+
`${this.getAppsBaseUrl()}/signer/routing`,
|
|
1284
|
+
{
|
|
1285
|
+
method: "GET",
|
|
1286
|
+
headers: this.builderHeaders(),
|
|
1287
|
+
cache: "no-store"
|
|
1288
|
+
}
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
async listBillingProducts() {
|
|
1292
|
+
const url = `${this.getAppsBaseUrl()}/plans?apiVersion=2`;
|
|
1293
|
+
const body = await this.requestJson(
|
|
1294
|
+
url,
|
|
1295
|
+
{
|
|
1296
|
+
method: "GET",
|
|
1297
|
+
headers: this.builderHeaders(),
|
|
1298
|
+
cache: "no-store"
|
|
1299
|
+
}
|
|
1300
|
+
);
|
|
1301
|
+
return {
|
|
1302
|
+
apiVersion: body.apiVersion ?? 2,
|
|
1303
|
+
products: body.products ?? body.plans ?? []
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
async syncBillingProduct(planId) {
|
|
1307
|
+
return this.requestJson(
|
|
1308
|
+
`${this.getAppsBaseUrl()}/plans/${encodeURIComponent(planId)}/sync`,
|
|
1309
|
+
{
|
|
1310
|
+
method: "POST",
|
|
1311
|
+
headers: this.builderHeaders(),
|
|
1312
|
+
cache: "no-store"
|
|
1313
|
+
}
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
async getUsageBalance(externalUserId) {
|
|
1317
|
+
const url = new URL(`${this.getAppsBaseUrl()}/usage/balance`);
|
|
1318
|
+
url.searchParams.set("externalUserId", externalUserId);
|
|
1319
|
+
return this.requestJson(url.toString(), {
|
|
1320
|
+
method: "GET",
|
|
1321
|
+
headers: this.builderHeaders(),
|
|
1322
|
+
cache: "no-store"
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
async getUserAllowances(externalUserId) {
|
|
1326
|
+
return this.requestJson(
|
|
1327
|
+
`${this.getAppsBaseUrl()}/users/${encodeURIComponent(externalUserId)}/allowances`,
|
|
1328
|
+
{
|
|
1329
|
+
method: "GET",
|
|
1330
|
+
headers: this.builderHeaders(),
|
|
1331
|
+
cache: "no-store"
|
|
1332
|
+
}
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
async grantUserAllowance(externalUserId, input) {
|
|
1336
|
+
return this.requestJson(
|
|
1337
|
+
`${this.getAppsBaseUrl()}/users/${encodeURIComponent(externalUserId)}/allowances`,
|
|
1338
|
+
{
|
|
1339
|
+
method: "POST",
|
|
1340
|
+
headers: this.builderHeaders(),
|
|
1341
|
+
body: JSON.stringify(input),
|
|
1342
|
+
cache: "no-store"
|
|
1343
|
+
}
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* @deprecated Removed from PymtHouse — use {@link getUsageBalance} or {@link getUserAllowances}.
|
|
1348
|
+
*/
|
|
1349
|
+
async getUserCredits(externalUserId) {
|
|
1350
|
+
return this.getUsageBalance(externalUserId);
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* @deprecated Removed from PymtHouse — use {@link grantUserAllowance} (`POST .../allowances`).
|
|
1354
|
+
*/
|
|
1355
|
+
async grantUserCredits(externalUserId, input) {
|
|
1356
|
+
const result = await this.grantUserAllowance(externalUserId, {
|
|
1357
|
+
amountUsdMicros: input.amountUsdMicros,
|
|
1358
|
+
source: input.source ?? "manual",
|
|
1359
|
+
featureKey: input.featureKey
|
|
1360
|
+
});
|
|
1361
|
+
const flat = result;
|
|
1362
|
+
const nested = result.allowances;
|
|
1363
|
+
return {
|
|
1364
|
+
externalUserId: result.externalUserId,
|
|
1365
|
+
balanceUsdMicros: flat.balanceUsdMicros ?? nested?.balanceUsdMicros ?? "0",
|
|
1366
|
+
consumedUsdMicros: flat.consumedUsdMicros ?? nested?.consumedUsdMicros ?? "0",
|
|
1367
|
+
lifetimeGrantedUsdMicros: flat.lifetimeGrantedUsdMicros ?? nested?.lifetimeGrantedUsdMicros ?? "0",
|
|
1368
|
+
hasAccess: flat.hasAccess ?? nested?.hasAccess ?? false,
|
|
1369
|
+
remainingUsdMicros: flat.balanceUsdMicros ?? nested?.balanceUsdMicros,
|
|
1370
|
+
grantedUsdMicros: flat.grantedUsdMicros,
|
|
1371
|
+
featureKey: flat.featureKey
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
async getUserSubscription(externalUserId) {
|
|
1375
|
+
return this.requestJson(
|
|
1376
|
+
`${this.getAppsBaseUrl()}/users/${encodeURIComponent(externalUserId)}/subscription`,
|
|
1377
|
+
{
|
|
1378
|
+
method: "GET",
|
|
1379
|
+
headers: this.builderHeaders(),
|
|
1380
|
+
cache: "no-store"
|
|
1381
|
+
}
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
639
1384
|
async fetchUsageForExternalUser(input) {
|
|
640
1385
|
const usageByUser = await this.getUsage({
|
|
641
1386
|
startDate: input.startDate,
|
|
@@ -655,7 +1400,18 @@ var PmtHouseClient = class {
|
|
|
655
1400
|
})
|
|
656
1401
|
)
|
|
657
1402
|
);
|
|
658
|
-
|
|
1403
|
+
const usageDaily = await this.getUsage({
|
|
1404
|
+
startDate: input.startDate,
|
|
1405
|
+
endDate: input.endDate,
|
|
1406
|
+
groupBy: "daily_pipeline",
|
|
1407
|
+
userId: input.externalUserId
|
|
1408
|
+
});
|
|
1409
|
+
return buildMeScopeUsagePayload(
|
|
1410
|
+
usageByUser,
|
|
1411
|
+
input.externalUserId,
|
|
1412
|
+
usagePipelineModels,
|
|
1413
|
+
usageDaily
|
|
1414
|
+
);
|
|
659
1415
|
}
|
|
660
1416
|
async getAppManifest(opts) {
|
|
661
1417
|
const url = `${this.getAppsBaseUrl()}/manifest`;
|
|
@@ -846,6 +1602,8 @@ var PmtHouseClient = class {
|
|
|
846
1602
|
};
|
|
847
1603
|
|
|
848
1604
|
// src/env.ts
|
|
1605
|
+
init_errors();
|
|
1606
|
+
init_string_utils();
|
|
849
1607
|
function assertEnvModuleServerOnly() {
|
|
850
1608
|
if (typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined") {
|
|
851
1609
|
throw new Error(
|