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