@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/env.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { genericTokenEndpointRequest, processGenericTokenEndpointResponse, clientCredentialsGrantRequest, processClientCredentialsResponse, customFetch, allowInsecureRequests, discoveryRequest, processDiscoveryResponse, ResponseBodyError, OperationProcessingError } from 'oauth4webapi';
|
|
2
|
+
import 'crypto';
|
|
2
3
|
|
|
3
4
|
// src/client.ts
|
|
4
5
|
|
|
@@ -121,6 +122,160 @@ function mapDiscoveryNetworkError(error) {
|
|
|
121
122
|
code: "oidc_discovery_failed"
|
|
122
123
|
});
|
|
123
124
|
}
|
|
125
|
+
function parseAppManifestResponse(json) {
|
|
126
|
+
if (!json || typeof json !== "object" || Array.isArray(json)) {
|
|
127
|
+
return { capabilities: [], excludedCapabilities: [] };
|
|
128
|
+
}
|
|
129
|
+
const record = json;
|
|
130
|
+
const capabilities = parseCapabilityArray(record.capabilities);
|
|
131
|
+
const excludedCapabilities = parseCapabilityArray(record.excludedCapabilities);
|
|
132
|
+
const manifestVersion = typeof record.manifestVersion === "string" && record.manifestVersion.trim() ? record.manifestVersion.trim() : void 0;
|
|
133
|
+
return { capabilities, excludedCapabilities, manifestVersion };
|
|
134
|
+
}
|
|
135
|
+
function parseCapabilityArray(raw) {
|
|
136
|
+
if (!Array.isArray(raw)) return [];
|
|
137
|
+
return raw.filter(
|
|
138
|
+
(c) => !!c && typeof c === "object" && typeof c.pipeline === "string" && typeof c.modelId === "string"
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/tokens.ts
|
|
143
|
+
var SIGNER_SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
144
|
+
var SIGNER_SESSION_EXPIRES_IN_SEC = Math.floor(SIGNER_SESSION_TTL_MS / 1e3);
|
|
145
|
+
var SIGN_JOB_SCOPE = "sign:job";
|
|
146
|
+
function isLikelyOidcJwt(rawToken) {
|
|
147
|
+
const t = rawToken.trim();
|
|
148
|
+
return t.startsWith("eyJ") && t.split(".").length >= 3;
|
|
149
|
+
}
|
|
150
|
+
function parseSignerSessionExchange(res) {
|
|
151
|
+
const accessToken = typeof res.access_token === "string" ? res.access_token.trim() : "";
|
|
152
|
+
if (!accessToken) {
|
|
153
|
+
throw new Error("PymtHouse signer session exchange returned no access_token");
|
|
154
|
+
}
|
|
155
|
+
if (isLikelyOidcJwt(accessToken)) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
"PymtHouse signer session exchange returned a JWT; expected opaque signer session token"
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
const tokenType = typeof res.token_type === "string" && res.token_type.trim() ? res.token_type.trim() : "Bearer";
|
|
161
|
+
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;
|
|
162
|
+
const scope = typeof res.scope === "string" && res.scope.trim() ? res.scope.trim() : SIGN_JOB_SCOPE;
|
|
163
|
+
return {
|
|
164
|
+
accessToken,
|
|
165
|
+
tokenType,
|
|
166
|
+
expiresIn,
|
|
167
|
+
scope
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/usage.ts
|
|
172
|
+
function parseSafeBigInt(value, fallback = 0n) {
|
|
173
|
+
try {
|
|
174
|
+
return BigInt(value);
|
|
175
|
+
} catch {
|
|
176
|
+
return fallback;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function getEndUserIdsForExternalUser(usage, externalUserId) {
|
|
180
|
+
const userIds = /* @__PURE__ */ new Set();
|
|
181
|
+
for (const row of usage.byUser ?? []) {
|
|
182
|
+
if (row.externalUserId === externalUserId && row.endUserId !== "unknown") {
|
|
183
|
+
userIds.add(row.endUserId);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return [...userIds];
|
|
187
|
+
}
|
|
188
|
+
function summarizeUsageFiatForExternalUser(usageByUser, externalUserId) {
|
|
189
|
+
const rows = usageByUser.byUser ?? [];
|
|
190
|
+
let requestCount = 0;
|
|
191
|
+
let networkFeeUsdMicros = 0n;
|
|
192
|
+
let ownerChargeUsdMicros = 0n;
|
|
193
|
+
let endUserBillableUsdMicros = 0n;
|
|
194
|
+
let currency = "USD";
|
|
195
|
+
for (const row of rows) {
|
|
196
|
+
if (row.externalUserId !== externalUserId) continue;
|
|
197
|
+
requestCount += row.requestCount;
|
|
198
|
+
if (row.currency) currency = row.currency;
|
|
199
|
+
if (row.networkFeeUsdMicros) {
|
|
200
|
+
networkFeeUsdMicros += BigInt(row.networkFeeUsdMicros);
|
|
201
|
+
}
|
|
202
|
+
if (row.ownerChargeUsdMicros) {
|
|
203
|
+
ownerChargeUsdMicros += BigInt(row.ownerChargeUsdMicros);
|
|
204
|
+
}
|
|
205
|
+
if (row.endUserBillableUsdMicros) {
|
|
206
|
+
endUserBillableUsdMicros += BigInt(row.endUserBillableUsdMicros);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
externalUserId,
|
|
211
|
+
requestCount,
|
|
212
|
+
currency,
|
|
213
|
+
networkFeeUsdMicros: networkFeeUsdMicros.toString(),
|
|
214
|
+
ownerChargeUsdMicros: ownerChargeUsdMicros.toString(),
|
|
215
|
+
endUserBillableUsdMicros: endUserBillableUsdMicros.toString()
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function mergeUsageByPipelineModel(usagePipelineModels) {
|
|
219
|
+
let responses;
|
|
220
|
+
if (Array.isArray(usagePipelineModels)) {
|
|
221
|
+
responses = usagePipelineModels;
|
|
222
|
+
} else if (usagePipelineModels) {
|
|
223
|
+
responses = [usagePipelineModels];
|
|
224
|
+
} else {
|
|
225
|
+
responses = [];
|
|
226
|
+
}
|
|
227
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
228
|
+
for (const response of responses) {
|
|
229
|
+
for (const row of response.byPipelineModel ?? []) {
|
|
230
|
+
const { pipeline, modelId } = row;
|
|
231
|
+
if (!pipeline || !modelId) continue;
|
|
232
|
+
const key = JSON.stringify([pipeline, modelId]);
|
|
233
|
+
const existing = byKey.get(key);
|
|
234
|
+
const rowCurrency = row.currency ?? "USD";
|
|
235
|
+
if (!existing) {
|
|
236
|
+
byKey.set(key, {
|
|
237
|
+
pipeline,
|
|
238
|
+
modelId,
|
|
239
|
+
requestCount: row.requestCount,
|
|
240
|
+
currency: rowCurrency,
|
|
241
|
+
networkFeeUsdMicros: row.networkFeeUsdMicros,
|
|
242
|
+
ownerChargeUsdMicros: row.ownerChargeUsdMicros,
|
|
243
|
+
endUserBillableUsdMicros: row.endUserBillableUsdMicros
|
|
244
|
+
});
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
byKey.set(key, {
|
|
248
|
+
...existing,
|
|
249
|
+
requestCount: existing.requestCount + row.requestCount,
|
|
250
|
+
networkFeeUsdMicros: (parseSafeBigInt(existing.networkFeeUsdMicros) + parseSafeBigInt(row.networkFeeUsdMicros)).toString(),
|
|
251
|
+
ownerChargeUsdMicros: (parseSafeBigInt(existing.ownerChargeUsdMicros) + parseSafeBigInt(row.ownerChargeUsdMicros)).toString(),
|
|
252
|
+
endUserBillableUsdMicros: (parseSafeBigInt(existing.endUserBillableUsdMicros) + parseSafeBigInt(row.endUserBillableUsdMicros)).toString()
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return [...byKey.values()].sort((a, b) => {
|
|
257
|
+
if (a.pipeline === b.pipeline) return a.modelId.localeCompare(b.modelId);
|
|
258
|
+
return a.pipeline.localeCompare(b.pipeline);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function buildMeScopeUsagePayload(usageByUser, externalUserId, usagePipelineModel) {
|
|
262
|
+
const summary = summarizeUsageFiatForExternalUser(usageByUser, externalUserId);
|
|
263
|
+
const pipelineModels = mergeUsageByPipelineModel(usagePipelineModel);
|
|
264
|
+
return {
|
|
265
|
+
clientId: usageByUser.clientId,
|
|
266
|
+
period: usageByUser.period,
|
|
267
|
+
currentUser: {
|
|
268
|
+
externalUserId: summary.externalUserId,
|
|
269
|
+
requestCount: summary.requestCount,
|
|
270
|
+
currency: summary.currency,
|
|
271
|
+
networkFeeUsdMicros: summary.networkFeeUsdMicros,
|
|
272
|
+
ownerChargeUsdMicros: summary.ownerChargeUsdMicros,
|
|
273
|
+
endUserBillableUsdMicros: summary.endUserBillableUsdMicros,
|
|
274
|
+
pipelineModels
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
var DEFAULT_MAX_END_USER_IDS = 25;
|
|
124
279
|
var ACCEPTED_ISSUED_TOKEN_TYPES = /* @__PURE__ */ new Set([
|
|
125
280
|
"urn:ietf:params:oauth:token-type:access_token",
|
|
126
281
|
"urn:pmth:token-type:remote-signer-session"
|
|
@@ -476,6 +631,126 @@ var PmtHouseClient = class {
|
|
|
476
631
|
cache: "no-store"
|
|
477
632
|
});
|
|
478
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Session-scoped usage for one `externalUserId`: user rollup plus merged pipeline/model breakdown.
|
|
636
|
+
*/
|
|
637
|
+
async fetchUsageForExternalUser(input) {
|
|
638
|
+
const usageByUser = await this.getUsage({
|
|
639
|
+
startDate: input.startDate,
|
|
640
|
+
endDate: input.endDate,
|
|
641
|
+
groupBy: "user"
|
|
642
|
+
});
|
|
643
|
+
const userIds = getEndUserIdsForExternalUser(usageByUser, input.externalUserId);
|
|
644
|
+
const cap = input.maxEndUserIds ?? DEFAULT_MAX_END_USER_IDS;
|
|
645
|
+
const cappedUserIds = userIds.slice(0, cap);
|
|
646
|
+
const usagePipelineModels = await Promise.all(
|
|
647
|
+
cappedUserIds.map(
|
|
648
|
+
(userId) => this.getUsage({
|
|
649
|
+
startDate: input.startDate,
|
|
650
|
+
endDate: input.endDate,
|
|
651
|
+
groupBy: "pipeline_model",
|
|
652
|
+
userId
|
|
653
|
+
})
|
|
654
|
+
)
|
|
655
|
+
);
|
|
656
|
+
return buildMeScopeUsagePayload(usageByUser, input.externalUserId, usagePipelineModels);
|
|
657
|
+
}
|
|
658
|
+
async getAppManifest(opts) {
|
|
659
|
+
const url = `${this.getAppsBaseUrl()}/manifest`;
|
|
660
|
+
const headers = {
|
|
661
|
+
...this.builderHeadersRecord()
|
|
662
|
+
};
|
|
663
|
+
if (opts?.ifNoneMatch) {
|
|
664
|
+
headers["If-None-Match"] = opts.ifNoneMatch;
|
|
665
|
+
}
|
|
666
|
+
this.logger?.debug?.("PmtHouse request", { method: "GET", url });
|
|
667
|
+
const response = await this.fetchImpl(url, {
|
|
668
|
+
method: "GET",
|
|
669
|
+
headers,
|
|
670
|
+
signal: opts?.signal,
|
|
671
|
+
cache: "no-store"
|
|
672
|
+
});
|
|
673
|
+
const etag = response.headers.get("etag")?.trim() ?? null;
|
|
674
|
+
if (response.status === 304) {
|
|
675
|
+
return {
|
|
676
|
+
manifest: null,
|
|
677
|
+
etag: etag ?? opts?.ifNoneMatch ?? null,
|
|
678
|
+
notModified: true
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
const raw = await response.text();
|
|
682
|
+
const ct = response.headers.get("content-type") ?? "";
|
|
683
|
+
const looksJson = ct.includes("application/json") || ct.includes("json");
|
|
684
|
+
const parsed = raw && looksJson ? this.safeParseJson(raw) : null;
|
|
685
|
+
if (!response.ok) {
|
|
686
|
+
const details = parsed ?? {};
|
|
687
|
+
let description;
|
|
688
|
+
if (typeof details.error_description === "string") {
|
|
689
|
+
description = details.error_description;
|
|
690
|
+
} else if (typeof details.error === "string") {
|
|
691
|
+
description = details.error;
|
|
692
|
+
} else {
|
|
693
|
+
description = `Request failed (${response.status})`;
|
|
694
|
+
}
|
|
695
|
+
throw new PmtHouseError(description, {
|
|
696
|
+
status: response.status,
|
|
697
|
+
code: typeof details.error === "string" ? details.error : "pymthouse_http_error",
|
|
698
|
+
details
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
if (!looksJson || parsed === null) {
|
|
702
|
+
throw new PmtHouseError("Expected JSON response from Builder manifest endpoint", {
|
|
703
|
+
status: 502,
|
|
704
|
+
code: "invalid_response",
|
|
705
|
+
details: { contentType: ct, preview: raw.slice(0, 200) }
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
return {
|
|
709
|
+
manifest: parseAppManifestResponse(parsed),
|
|
710
|
+
etag,
|
|
711
|
+
notModified: false
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Upsert an external user, mint a short-lived JWT, and exchange for an opaque signer session.
|
|
716
|
+
*/
|
|
717
|
+
async mintSignerSessionForExternalUser(input) {
|
|
718
|
+
await this.upsertAppUser({
|
|
719
|
+
externalUserId: input.externalUserId,
|
|
720
|
+
email: input.email,
|
|
721
|
+
status: "active"
|
|
722
|
+
});
|
|
723
|
+
const exchange = await this.mintUserSignerSessionToken({
|
|
724
|
+
externalUserId: input.externalUserId,
|
|
725
|
+
scope: input.scope ?? SIGN_JOB_SCOPE,
|
|
726
|
+
resource: this.issuerUrl
|
|
727
|
+
});
|
|
728
|
+
return parseSignerSessionExchange(exchange);
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Approve a pending RFC 8628 device code for an external user (Option B).
|
|
732
|
+
*/
|
|
733
|
+
async approveDeviceLogin(input) {
|
|
734
|
+
if (input.publicClientId && input.publicClientId !== this.publicClientId) {
|
|
735
|
+
throw new PmtHouseError(
|
|
736
|
+
"publicClientId does not match configured public client id",
|
|
737
|
+
{ status: 400, code: "invalid_client" }
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
await this.upsertAppUser({
|
|
741
|
+
externalUserId: input.externalUserId,
|
|
742
|
+
email: input.email,
|
|
743
|
+
status: "active"
|
|
744
|
+
});
|
|
745
|
+
const userToken = await this.mintUserAccessToken({
|
|
746
|
+
externalUserId: input.externalUserId,
|
|
747
|
+
scope: SIGN_JOB_SCOPE
|
|
748
|
+
});
|
|
749
|
+
await this.completeDeviceApproval({
|
|
750
|
+
userJwt: userToken.access_token,
|
|
751
|
+
userCode: input.userCode
|
|
752
|
+
});
|
|
753
|
+
}
|
|
479
754
|
tokenEndpointFetchOptions() {
|
|
480
755
|
const o = {
|
|
481
756
|
[customFetch]: this.fetchImpl
|
|
@@ -492,6 +767,9 @@ var PmtHouseClient = class {
|
|
|
492
767
|
return new URL(this.issuerUrl).origin;
|
|
493
768
|
}
|
|
494
769
|
builderHeaders() {
|
|
770
|
+
return this.builderHeadersRecord();
|
|
771
|
+
}
|
|
772
|
+
builderHeadersRecord() {
|
|
495
773
|
return {
|
|
496
774
|
Authorization: encodeClientSecretBasic(this.m2mClientId, this.m2mClientSecret),
|
|
497
775
|
"Content-Type": "application/json",
|
|
@@ -515,7 +793,14 @@ var PmtHouseClient = class {
|
|
|
515
793
|
const parsed = raw && looksJson ? this.safeParseJson(raw) : raw ? null : null;
|
|
516
794
|
if (!response.ok) {
|
|
517
795
|
const details = parsed ?? {};
|
|
518
|
-
|
|
796
|
+
let description;
|
|
797
|
+
if (typeof details.error_description === "string") {
|
|
798
|
+
description = details.error_description;
|
|
799
|
+
} else if (typeof details.error === "string") {
|
|
800
|
+
description = details.error;
|
|
801
|
+
} else {
|
|
802
|
+
description = `Request failed (${response.status})`;
|
|
803
|
+
}
|
|
519
804
|
throw new PmtHouseError(description, {
|
|
520
805
|
status: response.status,
|
|
521
806
|
code: typeof details.error === "string" ? details.error : "pymthouse_http_error",
|
package/dist/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encoding.ts","../src/errors.ts","../src/string-utils.ts","../src/discovery.ts","../src/oauth-map.ts","../src/client.ts","../src/env.ts"],"names":["customFetch","allowInsecureRequests"],"mappings":"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","file":"env.js","sourcesContent":["/**\n * Base64url-safe Basic auth encoding for `client_id:client_secret` (UTF-8).\n * Works in Node, Edge, and Workers without assuming `Buffer`.\n */\nexport function encodeClientSecretBasic(clientId: string, clientSecret: string): string {\n const raw = `${clientId}:${clientSecret}`;\n const b64 =\n typeof Buffer !== \"undefined\"\n ? Buffer.from(raw, \"utf8\").toString(\"base64\")\n : btoa(Array.from(new TextEncoder().encode(raw), (c) => String.fromCharCode(c)).join(\"\"));\n return `Basic ${b64}`;\n}\n","export class PmtHouseError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n {\n status = 500,\n code = \"pymthouse_error\",\n details,\n }: {\n status?: number;\n code?: string;\n details?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"PmtHouseError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toPmtHouseError(\n error: unknown,\n fallbackMessage: string,\n): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message || fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n}\n","/** Removes trailing `/` without regex (linear time). */\nexport function stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) {\n end--;\n }\n return value.slice(0, end);\n}\n","import {\n allowInsecureRequests,\n customFetch,\n discoveryRequest,\n processDiscoveryResponse,\n type AuthorizationServer,\n} from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\nimport type { FetchLike, OidcDiscoveryDocument } from \"./types.js\";\n\nexport function authorizationServerToOidcDocument(as: AuthorizationServer): OidcDiscoveryDocument {\n const tokenEndpoint = as.token_endpoint;\n const jwksUri = as.jwks_uri;\n if (!tokenEndpoint || !jwksUri) {\n throw new PmtHouseError(\"OIDC discovery document is missing token_endpoint or jwks_uri\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n }\n return {\n issuer: as.issuer,\n authorization_endpoint: as.authorization_endpoint ?? \"\",\n token_endpoint: tokenEndpoint,\n jwks_uri: jwksUri,\n userinfo_endpoint: as.userinfo_endpoint,\n device_authorization_endpoint: as.device_authorization_endpoint,\n };\n}\n\nconst CACHE_TTL_MS = 5 * 60 * 1000;\n\ntype CacheEntry = {\n as: AuthorizationServer;\n fetchedAt: number;\n};\n\nconst discoveryCache = new Map<string, CacheEntry>();\n\nfunction normalizedIssuerKey(issuerUrl: string): string {\n return stripTrailingSlashes(issuerUrl);\n}\n\nexport interface LoadAuthorizationServerOptions {\n force?: boolean;\n allowInsecureHttp?: boolean;\n}\n\n/**\n * Loads OIDC discovery metadata via oauth4webapi (RFC 8414 / OIDC Discovery), with a 5-minute cache.\n */\nexport async function loadAuthorizationServer(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<AuthorizationServer> {\n const key = normalizedIssuerKey(issuerUrl);\n const now = Date.now();\n const cached = discoveryCache.get(key);\n\n if (!options.force && cached && now - cached.fetchedAt < CACHE_TTL_MS) {\n return cached.as;\n }\n\n const issuerIdentifier = new URL(key);\n const discoveryOpts: Parameters<typeof discoveryRequest>[1] = {\n algorithm: \"oidc\",\n [customFetch]: fetchImpl,\n };\n if (options.allowInsecureHttp) {\n discoveryOpts[allowInsecureRequests] = true;\n }\n\n let response: Response;\n try {\n response = await discoveryRequest(issuerIdentifier, discoveryOpts);\n } catch (e) {\n throw mapDiscoveryNetworkError(e);\n }\n\n let as: AuthorizationServer;\n try {\n as = await processDiscoveryResponse(issuerIdentifier, response);\n } catch (e) {\n throw mapOAuthDiscoveryError(e);\n }\n\n discoveryCache.set(key, { as, fetchedAt: now });\n return as;\n}\n\nexport async function fetchDiscoveryDocument(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<OidcDiscoveryDocument> {\n const as = await loadAuthorizationServer(issuerUrl, fetchImpl, options);\n return authorizationServerToOidcDocument(as);\n}\n\nexport function clearDiscoveryCache(issuerUrl?: string): void {\n if (!issuerUrl) {\n discoveryCache.clear();\n return;\n }\n discoveryCache.delete(normalizedIssuerKey(issuerUrl));\n}\n\nfunction mapOAuthDiscoveryError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"oidc_discovery_invalid\",\n details: { cause: error.cause },\n });\n }\n return new PmtHouseError(\"OIDC discovery failed\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n}\n\nfunction mapDiscoveryNetworkError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(`Failed to load OIDC discovery: ${error.message}`, {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n }\n return new PmtHouseError(\"Failed to load OIDC discovery\", {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n}\n","import { type Client, OperationProcessingError, ResponseBodyError } from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport type { ClientCredentialsTokenResponse, TokenExchangeResponse } from \"./types.js\";\n\nconst ACCEPTED_ISSUED_TOKEN_TYPES = new Set([\n \"urn:ietf:params:oauth:token-type:access_token\",\n \"urn:pmth:token-type:remote-signer-session\",\n]);\n\nexport function mapOAuthError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof ResponseBodyError) {\n const cause = error.cause as Record<string, unknown>;\n const description =\n typeof error.error_description === \"string\"\n ? error.error_description\n : error.message;\n const details: Record<string, unknown> = { ...cause };\n if (typeof cause.error_uri === \"string\") {\n details.error_uri = cause.error_uri;\n }\n return new PmtHouseError(description, {\n status: error.status,\n code: error.error,\n details,\n });\n }\n\n if (error instanceof OperationProcessingError) {\n return new PmtHouseError(error.message, {\n status: 502,\n code: error.code ?? \"oauth_processing_error\",\n details: { cause: error.cause },\n });\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"unexpected_error\",\n });\n }\n\n return new PmtHouseError(\"Unexpected error\", {\n status: 500,\n code: \"unexpected_error\",\n });\n}\n\nexport function tokenEndpointResponseToExchange(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): TokenExchangeResponse {\n const issued = tr.issued_token_type;\n if (typeof issued !== \"string\" || !ACCEPTED_ISSUED_TOKEN_TYPES.has(issued)) {\n throw new PmtHouseError(\"Token exchange returned an unexpected issued_token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { issued_token_type: issued },\n });\n }\n\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n const expiresIn = tr.expires_in;\n if (typeof expiresIn !== \"number\") {\n throw new PmtHouseError(\"Token response missing expires_in\", {\n status: 502,\n code: \"invalid_token_response\",\n });\n }\n\n const scope = typeof tr.scope === \"string\" ? tr.scope : \"\";\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: expiresIn,\n scope,\n issued_token_type: issued,\n };\n}\n\nexport function tokenEndpointResponseToClientCredentials(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): ClientCredentialsTokenResponse {\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: tr.expires_in,\n scope: typeof tr.scope === \"string\" ? tr.scope : undefined,\n };\n}\n\nexport function m2mClient(clientId: string): Client {\n return { client_id: clientId };\n}\n","import {\n allowInsecureRequests,\n clientCredentialsGrantRequest,\n customFetch,\n genericTokenEndpointRequest,\n processClientCredentialsResponse,\n processGenericTokenEndpointResponse,\n type ClientAuth,\n type ClientCredentialsGrantRequestOptions,\n type TokenEndpointRequestOptions,\n} from \"oauth4webapi\";\nimport { encodeClientSecretBasic } from \"./encoding.js\";\nimport { loadAuthorizationServer, authorizationServerToOidcDocument } from \"./discovery.js\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\nimport {\n mapOAuthError,\n m2mClient,\n tokenEndpointResponseToClientCredentials,\n tokenEndpointResponseToExchange,\n} from \"./oauth-map.js\";\nimport type {\n AppUserRecord,\n ClientCredentialsTokenResponse,\n DeviceApprovalInput,\n FetchLike,\n GetDiscoveryOptions,\n MintUserSignerSessionTokenInput,\n MintUserAccessTokenInput,\n MintUserAccessTokenResponse,\n OidcDiscoveryDocument,\n ParsedDeviceApprovalRedirect,\n PmtHouseClientOptions,\n TokenExchangeResponse,\n UpsertAppUserInput,\n UsageApiResponse,\n UsageQueryInput,\n} from \"./types.js\";\n\nconst TOKEN_EXCHANGE_GRANT = \"urn:ietf:params:oauth:grant-type:token-exchange\";\nconst SUBJECT_ACCESS_TOKEN_TYPE = \"urn:ietf:params:oauth:token-type:access_token\";\nconst REQUESTED_ACCESS_TOKEN_TYPE = \"urn:ietf:params:oauth:token-type:access_token\";\n\nconst DEVICE_RESOURCE_PREFIX = \"urn:pmth:device_code:\";\n\n/**\n * Normalize RFC 8628 user codes for comparison and resource URIs (uppercase, strip separators).\n */\nexport function normalizeUserCode(value: string): string {\n return value\n .replace(/[a-z]/g, (char) => char.toUpperCase())\n .replace(/\\W/g, \"\");\n}\n\n/**\n * RFC 8707 resource indicator for NaaP Option B device approval (`urn:pmth:device_code:<normalized>`).\n */\nexport function buildDeviceCodeResource(userCode: string): string {\n return `${DEVICE_RESOURCE_PREFIX}${normalizeUserCode(userCode)}`;\n}\n\nexport class PmtHouseClient {\n private readonly issuerUrl: string;\n private readonly publicClientId: string;\n private readonly m2mClientId: string;\n private readonly m2mClientSecret: string;\n private readonly fetchImpl: FetchLike;\n private readonly logger?: PmtHouseClientOptions[\"logger\"];\n private readonly allowInsecureHttp: boolean;\n\n constructor(options: PmtHouseClientOptions) {\n this.issuerUrl = stripTrailingSlashes(options.issuerUrl);\n this.publicClientId = options.publicClientId;\n this.m2mClientId = options.m2mClientId;\n this.m2mClientSecret = options.m2mClientSecret;\n this.fetchImpl = options.fetch ?? fetch;\n this.logger = options.logger;\n this.allowInsecureHttp = options.allowInsecureHttp ?? false;\n }\n\n async getDiscovery(options: GetDiscoveryOptions = {}): Promise<OidcDiscoveryDocument> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n force: options.force,\n allowInsecureHttp: this.allowInsecureHttp,\n });\n return authorizationServerToOidcDocument(as);\n }\n\n verifyIssuer(iss: string): boolean {\n const candidate = stripTrailingSlashes(iss.trim());\n return candidate === this.issuerUrl;\n }\n\n parseDeviceApprovalRedirect(\n searchParams: URLSearchParams,\n ): ParsedDeviceApprovalRedirect {\n const issuer = searchParams.get(\"iss\")?.trim() ?? \"\";\n const targetLinkUri = searchParams.get(\"target_link_uri\")?.trim() ?? \"\";\n\n if (!issuer || !targetLinkUri) {\n throw new PmtHouseError(\"Missing iss or target_link_uri\", {\n status: 400,\n code: \"invalid_request\",\n });\n }\n\n if (!this.verifyIssuer(issuer)) {\n throw new PmtHouseError(\"Issuer mismatch for initiate login\", {\n status: 400,\n code: \"invalid_issuer\",\n });\n }\n\n let targetUrl: URL;\n try {\n targetUrl = new URL(targetLinkUri);\n } catch {\n throw new PmtHouseError(\"target_link_uri is not a valid URL\", {\n status: 400,\n code: \"invalid_target\",\n });\n }\n\n const issuerOrigin = new URL(this.issuerUrl).origin;\n if (targetUrl.origin !== issuerOrigin || targetUrl.pathname !== \"/oidc/device\") {\n throw new PmtHouseError(\n \"target_link_uri does not point to the issuer device path\",\n {\n status: 400,\n code: \"invalid_target\",\n },\n );\n }\n\n const userCode = normalizeUserCode(targetUrl.searchParams.get(\"user_code\") ?? \"\");\n const clientId = targetUrl.searchParams.get(\"client_id\")?.trim() ?? \"\";\n\n if (!userCode || !clientId) {\n throw new PmtHouseError(\"target_link_uri is missing user_code or client_id\", {\n status: 400,\n code: \"invalid_target\",\n });\n }\n\n return {\n issuer,\n targetLinkUri,\n userCode,\n clientId,\n };\n }\n\n async listAppUsers(): Promise<{ users: AppUserRecord[] }> {\n const url = `${this.getAppsBaseUrl()}/users`;\n return this.requestJson<{ users: AppUserRecord[] }>(url, {\n method: \"GET\",\n headers: this.builderHeaders(),\n cache: \"no-store\",\n });\n }\n\n async upsertAppUser(input: UpsertAppUserInput): Promise<AppUserRecord> {\n const payload: Record<string, unknown> = {\n externalUserId: input.externalUserId,\n };\n if (input.email) payload.email = input.email;\n if (input.status) payload.status = input.status;\n\n const url = `${this.getAppsBaseUrl()}/users`;\n return this.requestJson<AppUserRecord>(url, {\n method: \"POST\",\n headers: this.builderHeaders(),\n body: JSON.stringify(payload),\n cache: \"no-store\",\n });\n }\n\n async deleteAppUser(params: { externalUserId: string }): Promise<{ success: boolean }> {\n const url = new URL(`${this.getAppsBaseUrl()}/users`);\n url.searchParams.set(\"externalUserId\", params.externalUserId);\n return this.requestJson<{ success: boolean }>(url.toString(), {\n method: \"DELETE\",\n headers: this.builderHeaders(),\n cache: \"no-store\",\n });\n }\n\n async mintUserAccessToken(\n input: MintUserAccessTokenInput,\n ): Promise<MintUserAccessTokenResponse> {\n const url = `${this.getAppsBaseUrl()}/users/${encodeURIComponent(input.externalUserId)}/token`;\n const body = input.scope ? { scope: input.scope } : {};\n\n return this.requestJson<MintUserAccessTokenResponse>(url, {\n method: \"POST\",\n headers: this.builderHeaders(),\n body: JSON.stringify(body),\n cache: \"no-store\",\n });\n }\n\n async completeDeviceApproval(\n input: DeviceApprovalInput,\n ): Promise<TokenExchangeResponse> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n allowInsecureHttp: this.allowInsecureHttp,\n });\n const client = m2mClient(this.m2mClientId);\n const clientAuth = this.m2mClientAuth();\n const params = new URLSearchParams();\n params.set(\"subject_token\", input.userJwt);\n params.set(\"subject_token_type\", SUBJECT_ACCESS_TOKEN_TYPE);\n params.set(\"resource\", buildDeviceCodeResource(input.userCode));\n\n try {\n const response = await genericTokenEndpointRequest(\n as,\n client,\n clientAuth,\n TOKEN_EXCHANGE_GRANT,\n params,\n this.tokenEndpointFetchOptions(),\n );\n const tr = await processGenericTokenEndpointResponse(\n as,\n client,\n response,\n );\n return tokenEndpointResponseToExchange(tr);\n } catch (e) {\n throw mapOAuthError(e);\n }\n }\n\n async issueMachineAccessToken(\n scope = \"sign:job\",\n ): Promise<ClientCredentialsTokenResponse> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n allowInsecureHttp: this.allowInsecureHttp,\n });\n const client = m2mClient(this.m2mClientId);\n const clientAuth = this.m2mClientAuth();\n const params = new URLSearchParams();\n params.set(\"scope\", scope);\n\n try {\n const response = await clientCredentialsGrantRequest(\n as,\n client,\n clientAuth,\n params,\n this.tokenEndpointFetchOptions(),\n );\n const tr = await processClientCredentialsResponse(\n as,\n client,\n response,\n );\n return tokenEndpointResponseToClientCredentials(tr);\n } catch (e) {\n throw mapOAuthError(e);\n }\n }\n\n async exchangeForSignerSession(input: {\n userJwt: string;\n resource?: string;\n }): Promise<TokenExchangeResponse> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n allowInsecureHttp: this.allowInsecureHttp,\n });\n const client = m2mClient(this.m2mClientId);\n const clientAuth = this.m2mClientAuth();\n const params = new URLSearchParams();\n params.set(\"subject_token\", input.userJwt);\n params.set(\"subject_token_type\", SUBJECT_ACCESS_TOKEN_TYPE);\n params.set(\"requested_token_type\", REQUESTED_ACCESS_TOKEN_TYPE);\n const resourceCandidate =\n typeof input.resource === \"string\" && input.resource.trim() !== \"\"\n ? input.resource.trim()\n : this.issuerUrl;\n params.set(\"resource\", stripTrailingSlashes(resourceCandidate));\n\n try {\n const response = await genericTokenEndpointRequest(\n as,\n client,\n clientAuth,\n TOKEN_EXCHANGE_GRANT,\n params,\n this.tokenEndpointFetchOptions(),\n );\n const tr = await processGenericTokenEndpointResponse(\n as,\n client,\n response,\n );\n return tokenEndpointResponseToExchange(tr);\n } catch (e) {\n throw mapOAuthError(e);\n }\n }\n\n /**\n * Mint a short-lived per-user JWT with the Builder API, then exchange it for\n * a long-lived opaque signer session token at the PymtHouse OIDC token endpoint.\n */\n async mintUserSignerSessionToken(\n input: MintUserSignerSessionTokenInput,\n ): Promise<TokenExchangeResponse> {\n const userToken = await this.mintUserAccessToken({\n externalUserId: input.externalUserId,\n scope: input.scope ?? \"sign:job\",\n });\n\n return this.exchangeForSignerSession({\n userJwt: userToken.access_token,\n resource: input.resource,\n });\n }\n\n async createSignerSessionToken(params: {\n userJwt?: string;\n }): Promise<TokenExchangeResponse> {\n if (params.userJwt) {\n try {\n return await this.exchangeForSignerSession({ userJwt: params.userJwt });\n } catch (error) {\n const err = this.asError(error);\n this.logger?.warn?.(\"User JWT exchange failed, falling back to machine exchange\", {\n code: err.code,\n status: err.status,\n });\n }\n }\n\n const machineToken = await this.issueMachineAccessToken(\"sign:job\");\n if (!machineToken.access_token) {\n throw new PmtHouseError(\"Client credentials flow did not return access_token\", {\n status: 502,\n code: \"invalid_token_response\",\n });\n }\n\n return this.exchangeForSignerSession({ userJwt: machineToken.access_token });\n }\n\n async getUsage(input: UsageQueryInput = {}): Promise<UsageApiResponse> {\n const url = new URL(`${this.getAppsBaseUrl()}/usage`);\n if (input.startDate) url.searchParams.set(\"startDate\", input.startDate);\n if (input.endDate) url.searchParams.set(\"endDate\", input.endDate);\n if (input.groupBy) url.searchParams.set(\"groupBy\", input.groupBy);\n if (input.userId) url.searchParams.set(\"userId\", input.userId);\n if (input.gatewayRequestId) url.searchParams.set(\"gatewayRequestId\", input.gatewayRequestId);\n\n return this.requestJson<UsageApiResponse>(url.toString(), {\n method: \"GET\",\n headers: this.builderHeaders(),\n cache: \"no-store\",\n });\n }\n\n private tokenEndpointFetchOptions():\n | ClientCredentialsGrantRequestOptions\n | TokenEndpointRequestOptions {\n const o: ClientCredentialsGrantRequestOptions = {\n [customFetch]: this.fetchImpl,\n };\n if (this.allowInsecureHttp) {\n o[allowInsecureRequests] = true;\n }\n return o;\n }\n\n private getAppsBaseUrl(): string {\n return `${this.getIssuerOrigin()}/api/v1/apps/${encodeURIComponent(this.publicClientId)}`;\n }\n\n private getIssuerOrigin(): string {\n return new URL(this.issuerUrl).origin;\n }\n\n private builderHeaders(): HeadersInit {\n return {\n Authorization: encodeClientSecretBasic(this.m2mClientId, this.m2mClientSecret),\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n }\n\n private m2mClientAuth(): ClientAuth {\n return (_as, _client, _body, headers) => {\n headers.set(\"Authorization\", encodeClientSecretBasic(this.m2mClientId, this.m2mClientSecret));\n };\n }\n\n private async requestJson<T>(url: string, init: RequestInit): Promise<T> {\n this.logger?.debug?.(\"PmtHouse request\", {\n method: init.method ?? \"GET\",\n url,\n });\n\n const response = await this.fetchImpl(url, init);\n const raw = await response.text();\n const ct = response.headers.get(\"content-type\") ?? \"\";\n const looksJson = ct.includes(\"application/json\") || ct.includes(\"json\");\n const parsed = raw && looksJson ? this.safeParseJson(raw) : raw ? null : null;\n\n if (!response.ok) {\n const details = (parsed ?? {}) as Record<string, unknown>;\n const description =\n typeof details.error_description === \"string\"\n ? details.error_description\n : typeof details.error === \"string\"\n ? details.error\n : `Request failed (${response.status})`;\n\n throw new PmtHouseError(description, {\n status: response.status,\n code:\n typeof details.error === \"string\"\n ? details.error\n : \"pymthouse_http_error\",\n details,\n });\n }\n\n if (!looksJson || parsed === null) {\n throw new PmtHouseError(\"Expected JSON response from Builder or Usage API\", {\n status: 502,\n code: \"invalid_response\",\n details: { contentType: ct, preview: raw.slice(0, 200) },\n });\n }\n\n if (!parsed) {\n return {} as T;\n }\n\n return parsed as T;\n }\n\n private safeParseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n }\n\n private asError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(\"Unexpected error\", {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n}\n","import { PmtHouseClient } from \"./client.js\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\n\n/**\n * Fail fast if this module is bundled for the browser. M2M secrets must never\n * ship to clients; Next.js users can also re-export behind `import \"server-only\"`\n * for build-time enforcement (see README).\n */\nfunction assertEnvModuleServerOnly(): void {\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as { window?: unknown }).window !== \"undefined\"\n ) {\n throw new Error(\n \"@pymthouse/builder-sdk/env is server-only: do not import createPmtHouseClientFromEnv or getPymthouseBaseUrl in client-side code. Use a Route Handler, Server Action, or other server/runtime; keep M2M credentials out of the browser bundle.\",\n );\n }\n}\n\nassertEnvModuleServerOnly();\n\nlet cachedClient: PmtHouseClient | null = null;\n\nfunction requiredEnv(name: string): string {\n const value = process.env[name];\n if (value && value.trim()) {\n return value.trim();\n }\n\n throw new PmtHouseError(`Missing required environment variable: ${name}`, {\n status: 500,\n code: \"missing_env\",\n });\n}\n\n/**\n * Site origin for the PymtHouse deployment (e.g. https://pymthouse.com), derived\n * from `PYMTHOUSE_ISSUER_URL`.\n */\nexport function getPymthouseBaseUrl(): string {\n const issuerUrl = requiredEnv(\"PYMTHOUSE_ISSUER_URL\");\n return new URL(stripTrailingSlashes(issuerUrl)).origin;\n}\n\n/**\n * Singleton `PmtHouseClient` from `PYMTHOUSE_*` environment variables (server-side).\n */\nexport function createPmtHouseClientFromEnv(): PmtHouseClient {\n if (cachedClient) {\n return cachedClient;\n }\n\n const issuerUrl = requiredEnv(\"PYMTHOUSE_ISSUER_URL\");\n\n cachedClient = new PmtHouseClient({\n issuerUrl,\n publicClientId: requiredEnv(\"PYMTHOUSE_PUBLIC_CLIENT_ID\"),\n m2mClientId: requiredEnv(\"PYMTHOUSE_M2M_CLIENT_ID\"),\n m2mClientSecret: requiredEnv(\"PYMTHOUSE_M2M_CLIENT_SECRET\"),\n allowInsecureHttp: issuerUrl.startsWith(\"http:\"),\n logger: {\n debug: (message, details) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.debug(`[pymthouse] ${message}`, details ?? {});\n }\n },\n warn: (message, details) => {\n console.warn(`[pymthouse] ${message}`, details ?? {});\n },\n },\n });\n\n return cachedClient;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/encoding.ts","../src/errors.ts","../src/string-utils.ts","../src/discovery.ts","../src/manifest.ts","../src/tokens.ts","../src/usage.ts","../src/oauth-map.ts","../src/client.ts","../src/env.ts"],"names":["customFetch","allowInsecureRequests"],"mappings":"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","file":"env.js","sourcesContent":["/**\n * Base64url-safe Basic auth encoding for `client_id:client_secret` (UTF-8).\n * Works in Node, Edge, and Workers without assuming `Buffer`.\n */\nexport function encodeClientSecretBasic(clientId: string, clientSecret: string): string {\n const raw = `${clientId}:${clientSecret}`;\n const b64 =\n typeof Buffer !== \"undefined\"\n ? Buffer.from(raw, \"utf8\").toString(\"base64\")\n : btoa(Array.from(new TextEncoder().encode(raw), (c) => String.fromCharCode(c)).join(\"\"));\n return `Basic ${b64}`;\n}\n","export class PmtHouseError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n {\n status = 500,\n code = \"pymthouse_error\",\n details,\n }: {\n status?: number;\n code?: string;\n details?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"PmtHouseError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toPmtHouseError(\n error: unknown,\n fallbackMessage: string,\n): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message || fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n}\n","/** Removes trailing `/` without regex (linear time). */\nexport function stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) {\n end--;\n }\n return value.slice(0, end);\n}\n","import {\n allowInsecureRequests,\n customFetch,\n discoveryRequest,\n processDiscoveryResponse,\n type AuthorizationServer,\n} from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\nimport type { FetchLike, OidcDiscoveryDocument } from \"./types.js\";\n\nexport function authorizationServerToOidcDocument(as: AuthorizationServer): OidcDiscoveryDocument {\n const tokenEndpoint = as.token_endpoint;\n const jwksUri = as.jwks_uri;\n if (!tokenEndpoint || !jwksUri) {\n throw new PmtHouseError(\"OIDC discovery document is missing token_endpoint or jwks_uri\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n }\n return {\n issuer: as.issuer,\n authorization_endpoint: as.authorization_endpoint ?? \"\",\n token_endpoint: tokenEndpoint,\n jwks_uri: jwksUri,\n userinfo_endpoint: as.userinfo_endpoint,\n device_authorization_endpoint: as.device_authorization_endpoint,\n };\n}\n\nconst CACHE_TTL_MS = 5 * 60 * 1000;\n\ntype CacheEntry = {\n as: AuthorizationServer;\n fetchedAt: number;\n};\n\nconst discoveryCache = new Map<string, CacheEntry>();\n\nfunction normalizedIssuerKey(issuerUrl: string): string {\n return stripTrailingSlashes(issuerUrl);\n}\n\nexport interface LoadAuthorizationServerOptions {\n force?: boolean;\n allowInsecureHttp?: boolean;\n}\n\n/**\n * Loads OIDC discovery metadata via oauth4webapi (RFC 8414 / OIDC Discovery), with a 5-minute cache.\n */\nexport async function loadAuthorizationServer(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<AuthorizationServer> {\n const key = normalizedIssuerKey(issuerUrl);\n const now = Date.now();\n const cached = discoveryCache.get(key);\n\n if (!options.force && cached && now - cached.fetchedAt < CACHE_TTL_MS) {\n return cached.as;\n }\n\n const issuerIdentifier = new URL(key);\n const discoveryOpts: Parameters<typeof discoveryRequest>[1] = {\n algorithm: \"oidc\",\n [customFetch]: fetchImpl,\n };\n if (options.allowInsecureHttp) {\n discoveryOpts[allowInsecureRequests] = true;\n }\n\n let response: Response;\n try {\n response = await discoveryRequest(issuerIdentifier, discoveryOpts);\n } catch (e) {\n throw mapDiscoveryNetworkError(e);\n }\n\n let as: AuthorizationServer;\n try {\n as = await processDiscoveryResponse(issuerIdentifier, response);\n } catch (e) {\n throw mapOAuthDiscoveryError(e);\n }\n\n discoveryCache.set(key, { as, fetchedAt: now });\n return as;\n}\n\nexport async function fetchDiscoveryDocument(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<OidcDiscoveryDocument> {\n const as = await loadAuthorizationServer(issuerUrl, fetchImpl, options);\n return authorizationServerToOidcDocument(as);\n}\n\nexport function clearDiscoveryCache(issuerUrl?: string): void {\n if (!issuerUrl) {\n discoveryCache.clear();\n return;\n }\n discoveryCache.delete(normalizedIssuerKey(issuerUrl));\n}\n\nfunction mapOAuthDiscoveryError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"oidc_discovery_invalid\",\n details: { cause: error.cause },\n });\n }\n return new PmtHouseError(\"OIDC discovery failed\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n}\n\nfunction mapDiscoveryNetworkError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(`Failed to load OIDC discovery: ${error.message}`, {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n }\n return new PmtHouseError(\"Failed to load OIDC discovery\", {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n}\n","import { createHash } from \"node:crypto\";\n\nimport type { AppManifestCapability, AppManifestResponse } from \"./types.js\";\n\nexport function parseAppManifestResponse(json: unknown): AppManifestResponse {\n if (!json || typeof json !== \"object\" || Array.isArray(json)) {\n return { capabilities: [], excludedCapabilities: [] };\n }\n const record = json as Record<string, unknown>;\n const capabilities = parseCapabilityArray(record.capabilities);\n const excludedCapabilities = parseCapabilityArray(record.excludedCapabilities);\n const manifestVersion =\n typeof record.manifestVersion === \"string\" && record.manifestVersion.trim()\n ? record.manifestVersion.trim()\n : undefined;\n return { capabilities, excludedCapabilities, manifestVersion };\n}\n\nfunction parseCapabilityArray(raw: unknown): AppManifestCapability[] {\n if (!Array.isArray(raw)) return [];\n return raw.filter(\n (c): c is AppManifestCapability =>\n !!c &&\n typeof c === \"object\" &&\n typeof (c as { pipeline?: unknown }).pipeline === \"string\" &&\n typeof (c as { modelId?: unknown }).modelId === \"string\",\n );\n}\n\nfunction sortedCaps(caps: AppManifestCapability[]): AppManifestCapability[] {\n return [...caps].sort((a, b) => {\n const p = a.pipeline.localeCompare(b.pipeline);\n return p === 0 ? a.modelId.localeCompare(b.modelId) : p;\n });\n}\n\nexport function computeManifestRevision(\n data: Pick<\n AppManifestResponse,\n \"capabilities\" | \"excludedCapabilities\" | \"manifestVersion\"\n > | null,\n): string {\n if (data == null) {\n return \"unavailable\";\n }\n if (data.manifestVersion?.trim()) {\n return data.manifestVersion.trim();\n }\n const caps = sortedCaps(data.capabilities ?? []);\n const excl = sortedCaps(data.excludedCapabilities ?? []);\n if (caps.length === 0 && excl.length === 0) {\n return \"empty\";\n }\n return createHash(\"sha256\")\n .update(JSON.stringify({ capabilities: caps, excludedCapabilities: excl }))\n .digest(\"hex\")\n .slice(0, 24);\n}\n","import type { TokenExchangeResponse } from \"./types.js\";\n\n/**\n * Matches PymtHouse `gateway-token-exchange.ts` opaque signer session TTL (~90 days).\n *\n * Any change here must stay in sync with the upstream PymtHouse value.\n */\nexport const SIGNER_SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1000;\n\nexport const SIGNER_SESSION_EXPIRES_IN_SEC = Math.floor(SIGNER_SESSION_TTL_MS / 1000);\n\n/** Default end-user scope for Builder-minted user tokens and signer sessions. */\nexport const SIGN_JOB_SCOPE = \"sign:job\";\n\n/** @deprecated Use {@link SIGNER_SESSION_TTL_MS}. */\nexport const PYMTHOUSE_SIGNER_SESSION_TTL_MS = SIGNER_SESSION_TTL_MS;\n\nexport interface SignerSessionToken {\n accessToken: string;\n tokenType: string;\n expiresIn: number;\n scope: string;\n}\n\n/**\n * Compute the implied expiry for an opaque signer session key whose creation\n * timestamp is known but whose token body carries no expiry of its own.\n */\nexport function computeSignerSessionExpiry(input: Date | string): Date {\n const createdAt = input instanceof Date ? input : new Date(input);\n return new Date(createdAt.getTime() + SIGNER_SESSION_TTL_MS);\n}\n\n/** @deprecated Use {@link computeSignerSessionExpiry}. */\nexport const computePymthouseExpiry = computeSignerSessionExpiry;\n\n/**\n * Cheap shape check — true for inputs that look like a 3-segment JWT.\n * Does NOT validate the signature; callers must not use this for trust.\n */\nexport function isLikelyOidcJwt(rawToken: string): boolean {\n const t = rawToken.trim();\n return t.startsWith(\"eyJ\") && t.split(\".\").length >= 3;\n}\n\n/** True when the token is an opaque signer session (not a JWT). */\nexport function isOpaqueSignerSessionToken(rawToken: string): boolean {\n const t = rawToken.trim();\n return t.length > 0 && !isLikelyOidcJwt(t);\n}\n\nfunction base64UrlPayloadToUtf8(payloadB64: string): string {\n const normalized = payloadB64.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, \"=\");\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(padded, \"base64\").toString(\"utf8\");\n }\n return atob(padded);\n}\n\n/**\n * Best-effort `exp` extraction from a JWT payload. Returns null on any\n * parse error, missing/invalid `exp`, or non-finite numeric value.\n *\n * Security note: the JWT is not verified. Use only for UX-level expiry\n * display or soft-cleanup of unusable keys, never for authorization.\n */\nexport function decodeJwtExp(rawToken: string): Date | null {\n try {\n const parts = rawToken.split(\".\");\n if (parts.length < 2) return null;\n const payloadJson = base64UrlPayloadToUtf8(parts[1]);\n const payload = JSON.parse(payloadJson) as { exp?: number };\n if (typeof payload.exp !== \"number\" || !Number.isFinite(payload.exp)) return null;\n const expMs = Math.floor(payload.exp * 1000);\n if (expMs <= 0) return null;\n return new Date(expMs);\n } catch {\n return null;\n }\n}\n\n/**\n * Normalize an RFC 8693 token exchange response into a signer session token.\n * Validates that the access token is opaque (not a JWT).\n */\nexport function parseSignerSessionExchange(res: TokenExchangeResponse): SignerSessionToken {\n const accessToken = typeof res.access_token === \"string\" ? res.access_token.trim() : \"\";\n if (!accessToken) {\n throw new Error(\"PymtHouse signer session exchange returned no access_token\");\n }\n if (isLikelyOidcJwt(accessToken)) {\n throw new Error(\n \"PymtHouse signer session exchange returned a JWT; expected opaque signer session token\",\n );\n }\n\n const tokenType =\n typeof res.token_type === \"string\" && res.token_type.trim()\n ? res.token_type.trim()\n : \"Bearer\";\n const expiresIn =\n typeof res.expires_in === \"number\" &&\n Number.isFinite(res.expires_in) &&\n res.expires_in > 0\n ? Math.floor(res.expires_in)\n : SIGNER_SESSION_EXPIRES_IN_SEC;\n const scope =\n typeof res.scope === \"string\" && res.scope.trim() ? res.scope.trim() : SIGN_JOB_SCOPE;\n\n return {\n accessToken,\n tokenType,\n expiresIn,\n scope,\n };\n}\n","import type {\n UsageApiResponse,\n UsageByPipelineModelFiatRow,\n UsageByUserRow,\n UsageForExternalUser,\n MeScopeUsagePayload,\n} from \"./types.js\";\n\nfunction parseSafeBigInt(value: string | number | bigint, fallback = 0n): bigint {\n try {\n return BigInt(value);\n } catch {\n return fallback;\n }\n}\n\n/** ISO bounds for the current calendar month in UTC (billing-friendly window). */\nexport function getUtcCalendarMonthIsoBounds(now: Date = new Date()): {\n startDate: string;\n endDate: string;\n} {\n const y = now.getUTCFullYear();\n const m = now.getUTCMonth();\n const start = new Date(Date.UTC(y, m, 1, 0, 0, 0, 0));\n const end = new Date(Date.UTC(y, m + 1, 0, 23, 59, 59, 999));\n return { startDate: start.toISOString(), endDate: end.toISOString() };\n}\n\n/**\n * Parse a single date query value. Accepts ISO strings understood by `Date.parse`.\n * Returns `null` when missing, empty, or invalid.\n */\nexport function parseUsageDateParam(raw: string | null): string | null {\n if (raw == null) return null;\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const t = Date.parse(trimmed);\n if (Number.isNaN(t)) return null;\n return trimmed;\n}\n\n/**\n * Sum all `byUser` buckets whose `externalUserId` matches the provider user.\n *\n * PymtHouse may emit multiple rows for the same external user during transitions\n * (e.g. legacy internal ids vs external id on `usage_records.user_id`).\n */\nexport function aggregateUsageByExternalUserId(\n byUser: UsageByUserRow[] | undefined,\n externalUserId: string,\n): UsageForExternalUser {\n const rows = byUser?.filter((row) => row.externalUserId === externalUserId) ?? [];\n if (rows.length === 0) {\n return {\n externalUserId,\n requestCount: 0,\n feeWei: \"0\",\n };\n }\n\n let feeWei = 0n;\n let requestCount = 0;\n for (const row of rows) {\n if (row.feeWei) {\n feeWei += BigInt(row.feeWei);\n }\n requestCount += row.requestCount;\n }\n\n return {\n externalUserId,\n requestCount,\n feeWei: feeWei.toString(),\n };\n}\n\n/**\n * Convenience over {@link aggregateUsageByExternalUserId} using a full Usage API response.\n */\nexport function summarizeUsageForExternalUser(\n usage: UsageApiResponse,\n externalUserId: string,\n): UsageForExternalUser {\n return aggregateUsageByExternalUserId(usage.byUser, externalUserId);\n}\n\n/**\n * Returns `byPipelineModel` rows from a Usage API response, sorted by `pipeline` then `modelId`.\n */\nexport function listUsageByPipelineModel(usage: UsageApiResponse) {\n const rows = usage.byPipelineModel ?? [];\n return [...rows].sort((a, b) => {\n const p = a.pipeline.localeCompare(b.pipeline);\n if (p !== 0) return p;\n return a.modelId.localeCompare(b.modelId);\n });\n}\n\n/** Map `externalUserId` to internal `endUserId` values for follow-up pipeline_model queries. */\nexport function getEndUserIdsForExternalUser(\n usage: UsageApiResponse,\n externalUserId: string,\n): string[] {\n const userIds = new Set<string>();\n for (const row of usage.byUser ?? []) {\n if (row.externalUserId === externalUserId && row.endUserId !== \"unknown\") {\n userIds.add(row.endUserId);\n }\n }\n return [...userIds];\n}\n\n/** @deprecated Use {@link getEndUserIdsForExternalUser}. */\nexport const getUsageRecordUserIdsForExternalUser = getEndUserIdsForExternalUser;\n\nexport interface UsageFiatSummary {\n externalUserId: string;\n requestCount: number;\n currency: string;\n networkFeeUsdMicros: string;\n ownerChargeUsdMicros: string;\n endUserBillableUsdMicros: string;\n}\n\n/** Sum fiat usage fields across duplicate `byUser` buckets for one external user. */\nexport function summarizeUsageFiatForExternalUser(\n usageByUser: UsageApiResponse,\n externalUserId: string,\n): UsageFiatSummary {\n const rows = usageByUser.byUser ?? [];\n let requestCount = 0;\n let networkFeeUsdMicros = 0n;\n let ownerChargeUsdMicros = 0n;\n let endUserBillableUsdMicros = 0n;\n let currency = \"USD\";\n\n for (const row of rows) {\n if (row.externalUserId !== externalUserId) continue;\n requestCount += row.requestCount;\n if (row.currency) currency = row.currency;\n if (row.networkFeeUsdMicros) {\n networkFeeUsdMicros += BigInt(row.networkFeeUsdMicros);\n }\n if (row.ownerChargeUsdMicros) {\n ownerChargeUsdMicros += BigInt(row.ownerChargeUsdMicros);\n }\n if (row.endUserBillableUsdMicros) {\n endUserBillableUsdMicros += BigInt(row.endUserBillableUsdMicros);\n }\n }\n\n return {\n externalUserId,\n requestCount,\n currency,\n networkFeeUsdMicros: networkFeeUsdMicros.toString(),\n ownerChargeUsdMicros: ownerChargeUsdMicros.toString(),\n endUserBillableUsdMicros: endUserBillableUsdMicros.toString(),\n };\n}\n\n/** Merge and sort pipeline/model rows from multiple Usage API responses. */\nexport function mergeUsageByPipelineModel(\n usagePipelineModels: UsageApiResponse | UsageApiResponse[] | undefined,\n): UsageByPipelineModelFiatRow[] {\n let responses: UsageApiResponse[];\n if (Array.isArray(usagePipelineModels)) {\n responses = usagePipelineModels;\n } else if (usagePipelineModels) {\n responses = [usagePipelineModels];\n } else {\n responses = [];\n }\n const byKey = new Map<string, UsageByPipelineModelFiatRow>();\n\n for (const response of responses) {\n for (const row of response.byPipelineModel ?? []) {\n const { pipeline, modelId } = row;\n if (!pipeline || !modelId) continue;\n const key = JSON.stringify([pipeline, modelId]);\n const existing = byKey.get(key);\n const rowCurrency = row.currency ?? \"USD\";\n\n if (!existing) {\n byKey.set(key, {\n pipeline,\n modelId,\n requestCount: row.requestCount,\n currency: rowCurrency,\n networkFeeUsdMicros: row.networkFeeUsdMicros,\n ownerChargeUsdMicros: row.ownerChargeUsdMicros,\n endUserBillableUsdMicros: row.endUserBillableUsdMicros,\n });\n continue;\n }\n byKey.set(key, {\n ...existing,\n requestCount: existing.requestCount + row.requestCount,\n networkFeeUsdMicros: (\n parseSafeBigInt(existing.networkFeeUsdMicros) +\n parseSafeBigInt(row.networkFeeUsdMicros)\n ).toString(),\n ownerChargeUsdMicros: (\n parseSafeBigInt(existing.ownerChargeUsdMicros) +\n parseSafeBigInt(row.ownerChargeUsdMicros)\n ).toString(),\n endUserBillableUsdMicros: (\n parseSafeBigInt(existing.endUserBillableUsdMicros) +\n parseSafeBigInt(row.endUserBillableUsdMicros)\n ).toString(),\n });\n }\n }\n\n return [...byKey.values()].sort((a, b) => {\n if (a.pipeline === b.pipeline) return a.modelId.localeCompare(b.modelId);\n return a.pipeline.localeCompare(b.pipeline);\n });\n}\n\n/** Build the session-scoped `scope=me` usage payload for integrator BFFs. */\nexport function buildMeScopeUsagePayload(\n usageByUser: UsageApiResponse,\n externalUserId: string,\n usagePipelineModel?: UsageApiResponse | UsageApiResponse[],\n): MeScopeUsagePayload {\n const summary = summarizeUsageFiatForExternalUser(usageByUser, externalUserId);\n const pipelineModels = mergeUsageByPipelineModel(usagePipelineModel);\n return {\n clientId: usageByUser.clientId,\n period: usageByUser.period,\n currentUser: {\n externalUserId: summary.externalUserId,\n requestCount: summary.requestCount,\n currency: summary.currency,\n networkFeeUsdMicros: summary.networkFeeUsdMicros,\n ownerChargeUsdMicros: summary.ownerChargeUsdMicros,\n endUserBillableUsdMicros: summary.endUserBillableUsdMicros,\n pipelineModels,\n },\n };\n}\n\n/** Default cap for parallel pipeline_model fetches per external user (matches NaaP BFF). */\nexport const DEFAULT_MAX_END_USER_IDS = 25;\n","import { type Client, OperationProcessingError, ResponseBodyError } from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport type { ClientCredentialsTokenResponse, TokenExchangeResponse } from \"./types.js\";\n\nconst ACCEPTED_ISSUED_TOKEN_TYPES = new Set([\n \"urn:ietf:params:oauth:token-type:access_token\",\n \"urn:pmth:token-type:remote-signer-session\",\n]);\n\nexport function mapOAuthError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof ResponseBodyError) {\n const cause = error.cause as Record<string, unknown>;\n const description =\n typeof error.error_description === \"string\"\n ? error.error_description\n : error.message;\n const details: Record<string, unknown> = { ...cause };\n if (typeof cause.error_uri === \"string\") {\n details.error_uri = cause.error_uri;\n }\n return new PmtHouseError(description, {\n status: error.status,\n code: error.error,\n details,\n });\n }\n\n if (error instanceof OperationProcessingError) {\n return new PmtHouseError(error.message, {\n status: 502,\n code: error.code ?? \"oauth_processing_error\",\n details: { cause: error.cause },\n });\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"unexpected_error\",\n });\n }\n\n return new PmtHouseError(\"Unexpected error\", {\n status: 500,\n code: \"unexpected_error\",\n });\n}\n\nexport function tokenEndpointResponseToExchange(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): TokenExchangeResponse {\n const issued = tr.issued_token_type;\n if (typeof issued !== \"string\" || !ACCEPTED_ISSUED_TOKEN_TYPES.has(issued)) {\n throw new PmtHouseError(\"Token exchange returned an unexpected issued_token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { issued_token_type: issued },\n });\n }\n\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n const expiresIn = tr.expires_in;\n if (typeof expiresIn !== \"number\") {\n throw new PmtHouseError(\"Token response missing expires_in\", {\n status: 502,\n code: \"invalid_token_response\",\n });\n }\n\n const scope = typeof tr.scope === \"string\" ? tr.scope : \"\";\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: expiresIn,\n scope,\n issued_token_type: issued,\n };\n}\n\nexport function tokenEndpointResponseToClientCredentials(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): ClientCredentialsTokenResponse {\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: tr.expires_in,\n scope: typeof tr.scope === \"string\" ? tr.scope : undefined,\n };\n}\n\nexport function m2mClient(clientId: string): Client {\n return { client_id: clientId };\n}\n","import {\n allowInsecureRequests,\n clientCredentialsGrantRequest,\n customFetch,\n genericTokenEndpointRequest,\n processClientCredentialsResponse,\n processGenericTokenEndpointResponse,\n type ClientAuth,\n type ClientCredentialsGrantRequestOptions,\n type TokenEndpointRequestOptions,\n} from \"oauth4webapi\";\nimport { encodeClientSecretBasic } from \"./encoding.js\";\nimport { loadAuthorizationServer, authorizationServerToOidcDocument } from \"./discovery.js\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { parseAppManifestResponse } from \"./manifest.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\nimport { SIGN_JOB_SCOPE, parseSignerSessionExchange } from \"./tokens.js\";\nimport type { SignerSessionToken } from \"./tokens.js\";\nimport {\n buildMeScopeUsagePayload,\n DEFAULT_MAX_END_USER_IDS,\n getEndUserIdsForExternalUser,\n} from \"./usage.js\";\nimport {\n mapOAuthError,\n m2mClient,\n tokenEndpointResponseToClientCredentials,\n tokenEndpointResponseToExchange,\n} from \"./oauth-map.js\";\nimport type {\n AppUserRecord,\n ApproveDeviceLoginInput,\n ClientCredentialsTokenResponse,\n DeviceApprovalInput,\n FetchLike,\n GetAppManifestResult,\n GetDiscoveryOptions,\n MeScopeUsagePayload,\n MintSignerSessionForExternalUserInput,\n MintUserSignerSessionTokenInput,\n MintUserAccessTokenInput,\n MintUserAccessTokenResponse,\n OidcDiscoveryDocument,\n ParsedDeviceApprovalRedirect,\n PmtHouseClientOptions,\n TokenExchangeResponse,\n UpsertAppUserInput,\n UsageApiResponse,\n UsageQueryInput,\n} from \"./types.js\";\n\nconst TOKEN_EXCHANGE_GRANT = \"urn:ietf:params:oauth:grant-type:token-exchange\";\nconst SUBJECT_ACCESS_TOKEN_TYPE = \"urn:ietf:params:oauth:token-type:access_token\";\nconst REQUESTED_ACCESS_TOKEN_TYPE = \"urn:ietf:params:oauth:token-type:access_token\";\n\nconst DEVICE_RESOURCE_PREFIX = \"urn:pmth:device_code:\";\n\n/**\n * Normalize RFC 8628 user codes for comparison and resource URIs (uppercase, strip separators).\n */\nexport function normalizeUserCode(value: string): string {\n return value\n .replace(/[a-z]/g, (char) => char.toUpperCase())\n .replace(/\\W/g, \"\");\n}\n\n/**\n * RFC 8707 resource indicator for NaaP Option B device approval (`urn:pmth:device_code:<normalized>`).\n */\nexport function buildDeviceCodeResource(userCode: string): string {\n return `${DEVICE_RESOURCE_PREFIX}${normalizeUserCode(userCode)}`;\n}\n\nexport class PmtHouseClient {\n private readonly issuerUrl: string;\n private readonly publicClientId: string;\n private readonly m2mClientId: string;\n private readonly m2mClientSecret: string;\n private readonly fetchImpl: FetchLike;\n private readonly logger?: PmtHouseClientOptions[\"logger\"];\n private readonly allowInsecureHttp: boolean;\n\n constructor(options: PmtHouseClientOptions) {\n this.issuerUrl = stripTrailingSlashes(options.issuerUrl);\n this.publicClientId = options.publicClientId;\n this.m2mClientId = options.m2mClientId;\n this.m2mClientSecret = options.m2mClientSecret;\n this.fetchImpl = options.fetch ?? fetch;\n this.logger = options.logger;\n this.allowInsecureHttp = options.allowInsecureHttp ?? false;\n }\n\n async getDiscovery(options: GetDiscoveryOptions = {}): Promise<OidcDiscoveryDocument> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n force: options.force,\n allowInsecureHttp: this.allowInsecureHttp,\n });\n return authorizationServerToOidcDocument(as);\n }\n\n verifyIssuer(iss: string): boolean {\n const candidate = stripTrailingSlashes(iss.trim());\n return candidate === this.issuerUrl;\n }\n\n parseDeviceApprovalRedirect(\n searchParams: URLSearchParams,\n ): ParsedDeviceApprovalRedirect {\n const issuer = searchParams.get(\"iss\")?.trim() ?? \"\";\n const targetLinkUri = searchParams.get(\"target_link_uri\")?.trim() ?? \"\";\n\n if (!issuer || !targetLinkUri) {\n throw new PmtHouseError(\"Missing iss or target_link_uri\", {\n status: 400,\n code: \"invalid_request\",\n });\n }\n\n if (!this.verifyIssuer(issuer)) {\n throw new PmtHouseError(\"Issuer mismatch for initiate login\", {\n status: 400,\n code: \"invalid_issuer\",\n });\n }\n\n let targetUrl: URL;\n try {\n targetUrl = new URL(targetLinkUri);\n } catch {\n throw new PmtHouseError(\"target_link_uri is not a valid URL\", {\n status: 400,\n code: \"invalid_target\",\n });\n }\n\n const issuerOrigin = new URL(this.issuerUrl).origin;\n if (targetUrl.origin !== issuerOrigin || targetUrl.pathname !== \"/oidc/device\") {\n throw new PmtHouseError(\n \"target_link_uri does not point to the issuer device path\",\n {\n status: 400,\n code: \"invalid_target\",\n },\n );\n }\n\n const userCode = normalizeUserCode(targetUrl.searchParams.get(\"user_code\") ?? \"\");\n const clientId = targetUrl.searchParams.get(\"client_id\")?.trim() ?? \"\";\n\n if (!userCode || !clientId) {\n throw new PmtHouseError(\"target_link_uri is missing user_code or client_id\", {\n status: 400,\n code: \"invalid_target\",\n });\n }\n\n return {\n issuer,\n targetLinkUri,\n userCode,\n clientId,\n };\n }\n\n async listAppUsers(): Promise<{ users: AppUserRecord[] }> {\n const url = `${this.getAppsBaseUrl()}/users`;\n return this.requestJson<{ users: AppUserRecord[] }>(url, {\n method: \"GET\",\n headers: this.builderHeaders(),\n cache: \"no-store\",\n });\n }\n\n async upsertAppUser(input: UpsertAppUserInput): Promise<AppUserRecord> {\n const payload: Record<string, unknown> = {\n externalUserId: input.externalUserId,\n };\n if (input.email) payload.email = input.email;\n if (input.status) payload.status = input.status;\n\n const url = `${this.getAppsBaseUrl()}/users`;\n return this.requestJson<AppUserRecord>(url, {\n method: \"POST\",\n headers: this.builderHeaders(),\n body: JSON.stringify(payload),\n cache: \"no-store\",\n });\n }\n\n async deleteAppUser(params: { externalUserId: string }): Promise<{ success: boolean }> {\n const url = new URL(`${this.getAppsBaseUrl()}/users`);\n url.searchParams.set(\"externalUserId\", params.externalUserId);\n return this.requestJson<{ success: boolean }>(url.toString(), {\n method: \"DELETE\",\n headers: this.builderHeaders(),\n cache: \"no-store\",\n });\n }\n\n async mintUserAccessToken(\n input: MintUserAccessTokenInput,\n ): Promise<MintUserAccessTokenResponse> {\n const url = `${this.getAppsBaseUrl()}/users/${encodeURIComponent(input.externalUserId)}/token`;\n const body = input.scope ? { scope: input.scope } : {};\n\n return this.requestJson<MintUserAccessTokenResponse>(url, {\n method: \"POST\",\n headers: this.builderHeaders(),\n body: JSON.stringify(body),\n cache: \"no-store\",\n });\n }\n\n async completeDeviceApproval(\n input: DeviceApprovalInput,\n ): Promise<TokenExchangeResponse> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n allowInsecureHttp: this.allowInsecureHttp,\n });\n const client = m2mClient(this.m2mClientId);\n const clientAuth = this.m2mClientAuth();\n const params = new URLSearchParams();\n params.set(\"subject_token\", input.userJwt);\n params.set(\"subject_token_type\", SUBJECT_ACCESS_TOKEN_TYPE);\n params.set(\"resource\", buildDeviceCodeResource(input.userCode));\n\n try {\n const response = await genericTokenEndpointRequest(\n as,\n client,\n clientAuth,\n TOKEN_EXCHANGE_GRANT,\n params,\n this.tokenEndpointFetchOptions(),\n );\n const tr = await processGenericTokenEndpointResponse(\n as,\n client,\n response,\n );\n return tokenEndpointResponseToExchange(tr);\n } catch (e) {\n throw mapOAuthError(e);\n }\n }\n\n async issueMachineAccessToken(\n scope = \"sign:job\",\n ): Promise<ClientCredentialsTokenResponse> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n allowInsecureHttp: this.allowInsecureHttp,\n });\n const client = m2mClient(this.m2mClientId);\n const clientAuth = this.m2mClientAuth();\n const params = new URLSearchParams();\n params.set(\"scope\", scope);\n\n try {\n const response = await clientCredentialsGrantRequest(\n as,\n client,\n clientAuth,\n params,\n this.tokenEndpointFetchOptions(),\n );\n const tr = await processClientCredentialsResponse(\n as,\n client,\n response,\n );\n return tokenEndpointResponseToClientCredentials(tr);\n } catch (e) {\n throw mapOAuthError(e);\n }\n }\n\n async exchangeForSignerSession(input: {\n userJwt: string;\n resource?: string;\n }): Promise<TokenExchangeResponse> {\n const as = await loadAuthorizationServer(this.issuerUrl, this.fetchImpl, {\n allowInsecureHttp: this.allowInsecureHttp,\n });\n const client = m2mClient(this.m2mClientId);\n const clientAuth = this.m2mClientAuth();\n const params = new URLSearchParams();\n params.set(\"subject_token\", input.userJwt);\n params.set(\"subject_token_type\", SUBJECT_ACCESS_TOKEN_TYPE);\n params.set(\"requested_token_type\", REQUESTED_ACCESS_TOKEN_TYPE);\n const resourceCandidate =\n typeof input.resource === \"string\" && input.resource.trim() !== \"\"\n ? input.resource.trim()\n : this.issuerUrl;\n params.set(\"resource\", stripTrailingSlashes(resourceCandidate));\n\n try {\n const response = await genericTokenEndpointRequest(\n as,\n client,\n clientAuth,\n TOKEN_EXCHANGE_GRANT,\n params,\n this.tokenEndpointFetchOptions(),\n );\n const tr = await processGenericTokenEndpointResponse(\n as,\n client,\n response,\n );\n return tokenEndpointResponseToExchange(tr);\n } catch (e) {\n throw mapOAuthError(e);\n }\n }\n\n /**\n * Mint a short-lived per-user JWT with the Builder API, then exchange it for\n * a long-lived opaque signer session token at the PymtHouse OIDC token endpoint.\n */\n async mintUserSignerSessionToken(\n input: MintUserSignerSessionTokenInput,\n ): Promise<TokenExchangeResponse> {\n const userToken = await this.mintUserAccessToken({\n externalUserId: input.externalUserId,\n scope: input.scope ?? \"sign:job\",\n });\n\n return this.exchangeForSignerSession({\n userJwt: userToken.access_token,\n resource: input.resource,\n });\n }\n\n async createSignerSessionToken(params: {\n userJwt?: string;\n }): Promise<TokenExchangeResponse> {\n if (params.userJwt) {\n try {\n return await this.exchangeForSignerSession({ userJwt: params.userJwt });\n } catch (error) {\n const err = this.asError(error);\n this.logger?.warn?.(\"User JWT exchange failed, falling back to machine exchange\", {\n code: err.code,\n status: err.status,\n });\n }\n }\n\n const machineToken = await this.issueMachineAccessToken(\"sign:job\");\n if (!machineToken.access_token) {\n throw new PmtHouseError(\"Client credentials flow did not return access_token\", {\n status: 502,\n code: \"invalid_token_response\",\n });\n }\n\n return this.exchangeForSignerSession({ userJwt: machineToken.access_token });\n }\n\n async getUsage(input: UsageQueryInput = {}): Promise<UsageApiResponse> {\n const url = new URL(`${this.getAppsBaseUrl()}/usage`);\n if (input.startDate) url.searchParams.set(\"startDate\", input.startDate);\n if (input.endDate) url.searchParams.set(\"endDate\", input.endDate);\n if (input.groupBy) url.searchParams.set(\"groupBy\", input.groupBy);\n if (input.userId) url.searchParams.set(\"userId\", input.userId);\n if (input.gatewayRequestId) url.searchParams.set(\"gatewayRequestId\", input.gatewayRequestId);\n\n return this.requestJson<UsageApiResponse>(url.toString(), {\n method: \"GET\",\n headers: this.builderHeaders(),\n cache: \"no-store\",\n });\n }\n\n /**\n * Session-scoped usage for one `externalUserId`: user rollup plus merged pipeline/model breakdown.\n */\n async fetchUsageForExternalUser(input: {\n externalUserId: string;\n startDate: string;\n endDate: string;\n maxEndUserIds?: number;\n }): Promise<MeScopeUsagePayload> {\n const usageByUser = await this.getUsage({\n startDate: input.startDate,\n endDate: input.endDate,\n groupBy: \"user\",\n });\n const userIds = getEndUserIdsForExternalUser(usageByUser, input.externalUserId);\n const cap = input.maxEndUserIds ?? DEFAULT_MAX_END_USER_IDS;\n const cappedUserIds = userIds.slice(0, cap);\n const usagePipelineModels = await Promise.all(\n cappedUserIds.map((userId) =>\n this.getUsage({\n startDate: input.startDate,\n endDate: input.endDate,\n groupBy: \"pipeline_model\",\n userId,\n }),\n ),\n );\n return buildMeScopeUsagePayload(usageByUser, input.externalUserId, usagePipelineModels);\n }\n\n async getAppManifest(opts?: {\n ifNoneMatch?: string;\n signal?: AbortSignal;\n }): Promise<GetAppManifestResult> {\n const url = `${this.getAppsBaseUrl()}/manifest`;\n const headers: Record<string, string> = {\n ...this.builderHeadersRecord(),\n };\n if (opts?.ifNoneMatch) {\n headers[\"If-None-Match\"] = opts.ifNoneMatch;\n }\n\n this.logger?.debug?.(\"PmtHouse request\", { method: \"GET\", url });\n\n const response = await this.fetchImpl(url, {\n method: \"GET\",\n headers,\n signal: opts?.signal,\n cache: \"no-store\",\n });\n\n const etag = response.headers.get(\"etag\")?.trim() ?? null;\n\n if (response.status === 304) {\n return {\n manifest: null,\n etag: etag ?? opts?.ifNoneMatch ?? null,\n notModified: true,\n };\n }\n\n const raw = await response.text();\n const ct = response.headers.get(\"content-type\") ?? \"\";\n const looksJson = ct.includes(\"application/json\") || ct.includes(\"json\");\n const parsed = raw && looksJson ? this.safeParseJson(raw) : null;\n\n if (!response.ok) {\n const details = (parsed ?? {}) as Record<string, unknown>;\n let description: string;\n if (typeof details.error_description === \"string\") {\n description = details.error_description;\n } else if (typeof details.error === \"string\") {\n description = details.error;\n } else {\n description = `Request failed (${response.status})`;\n }\n throw new PmtHouseError(description, {\n status: response.status,\n code: typeof details.error === \"string\" ? details.error : \"pymthouse_http_error\",\n details,\n });\n }\n\n if (!looksJson || parsed === null) {\n throw new PmtHouseError(\"Expected JSON response from Builder manifest endpoint\", {\n status: 502,\n code: \"invalid_response\",\n details: { contentType: ct, preview: raw.slice(0, 200) },\n });\n }\n\n return {\n manifest: parseAppManifestResponse(parsed),\n etag,\n notModified: false,\n };\n }\n\n /**\n * Upsert an external user, mint a short-lived JWT, and exchange for an opaque signer session.\n */\n async mintSignerSessionForExternalUser(\n input: MintSignerSessionForExternalUserInput,\n ): Promise<SignerSessionToken> {\n await this.upsertAppUser({\n externalUserId: input.externalUserId,\n email: input.email,\n status: \"active\",\n });\n const exchange = await this.mintUserSignerSessionToken({\n externalUserId: input.externalUserId,\n scope: input.scope ?? SIGN_JOB_SCOPE,\n resource: this.issuerUrl,\n });\n return parseSignerSessionExchange(exchange);\n }\n\n /**\n * Approve a pending RFC 8628 device code for an external user (Option B).\n */\n async approveDeviceLogin(input: ApproveDeviceLoginInput): Promise<void> {\n if (input.publicClientId && input.publicClientId !== this.publicClientId) {\n throw new PmtHouseError(\n \"publicClientId does not match configured public client id\",\n { status: 400, code: \"invalid_client\" },\n );\n }\n\n await this.upsertAppUser({\n externalUserId: input.externalUserId,\n email: input.email,\n status: \"active\",\n });\n const userToken = await this.mintUserAccessToken({\n externalUserId: input.externalUserId,\n scope: SIGN_JOB_SCOPE,\n });\n await this.completeDeviceApproval({\n userJwt: userToken.access_token,\n userCode: input.userCode,\n });\n }\n\n private tokenEndpointFetchOptions():\n | ClientCredentialsGrantRequestOptions\n | TokenEndpointRequestOptions {\n const o: ClientCredentialsGrantRequestOptions = {\n [customFetch]: this.fetchImpl,\n };\n if (this.allowInsecureHttp) {\n o[allowInsecureRequests] = true;\n }\n return o;\n }\n\n private getAppsBaseUrl(): string {\n return `${this.getIssuerOrigin()}/api/v1/apps/${encodeURIComponent(this.publicClientId)}`;\n }\n\n private getIssuerOrigin(): string {\n return new URL(this.issuerUrl).origin;\n }\n\n private builderHeaders(): HeadersInit {\n return this.builderHeadersRecord();\n }\n\n private builderHeadersRecord(): Record<string, string> {\n return {\n Authorization: encodeClientSecretBasic(this.m2mClientId, this.m2mClientSecret),\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n }\n\n private m2mClientAuth(): ClientAuth {\n return (_as, _client, _body, headers) => {\n headers.set(\"Authorization\", encodeClientSecretBasic(this.m2mClientId, this.m2mClientSecret));\n };\n }\n\n private async requestJson<T>(url: string, init: RequestInit): Promise<T> {\n this.logger?.debug?.(\"PmtHouse request\", {\n method: init.method ?? \"GET\",\n url,\n });\n\n const response = await this.fetchImpl(url, init);\n const raw = await response.text();\n const ct = response.headers.get(\"content-type\") ?? \"\";\n const looksJson = ct.includes(\"application/json\") || ct.includes(\"json\");\n const parsed = raw && looksJson ? this.safeParseJson(raw) : raw ? null : null;\n\n if (!response.ok) {\n const details = (parsed ?? {}) as Record<string, unknown>;\n let description: string;\n if (typeof details.error_description === \"string\") {\n description = details.error_description;\n } else if (typeof details.error === \"string\") {\n description = details.error;\n } else {\n description = `Request failed (${response.status})`;\n }\n\n throw new PmtHouseError(description, {\n status: response.status,\n code:\n typeof details.error === \"string\"\n ? details.error\n : \"pymthouse_http_error\",\n details,\n });\n }\n\n if (!looksJson || parsed === null) {\n throw new PmtHouseError(\"Expected JSON response from Builder or Usage API\", {\n status: 502,\n code: \"invalid_response\",\n details: { contentType: ct, preview: raw.slice(0, 200) },\n });\n }\n\n if (!parsed) {\n return {} as T;\n }\n\n return parsed as T;\n }\n\n private safeParseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n }\n\n private asError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(\"Unexpected error\", {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n}\n","import { PmtHouseClient } from \"./client.js\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\n\n/**\n * Fail fast if this module is bundled for the browser. M2M secrets must never\n * ship to clients; Next.js users can also re-export behind `import \"server-only\"`\n * for build-time enforcement (see README).\n */\nfunction assertEnvModuleServerOnly(): void {\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as { window?: unknown }).window !== \"undefined\"\n ) {\n throw new Error(\n \"@pymthouse/builder-sdk/env is server-only: do not import createPmtHouseClientFromEnv or getPymthouseBaseUrl in client-side code. Use a Route Handler, Server Action, or other server/runtime; keep M2M credentials out of the browser bundle.\",\n );\n }\n}\n\nassertEnvModuleServerOnly();\n\nlet cachedClient: PmtHouseClient | null = null;\n\nfunction requiredEnv(name: string): string {\n const value = process.env[name];\n if (value && value.trim()) {\n return value.trim();\n }\n\n throw new PmtHouseError(`Missing required environment variable: ${name}`, {\n status: 500,\n code: \"missing_env\",\n });\n}\n\n/**\n * Site origin for the PymtHouse deployment (e.g. https://pymthouse.com), derived\n * from `PYMTHOUSE_ISSUER_URL`.\n */\nexport function getPymthouseBaseUrl(): string {\n const issuerUrl = requiredEnv(\"PYMTHOUSE_ISSUER_URL\");\n return new URL(stripTrailingSlashes(issuerUrl)).origin;\n}\n\n/**\n * Singleton `PmtHouseClient` from `PYMTHOUSE_*` environment variables (server-side).\n */\nexport function createPmtHouseClientFromEnv(): PmtHouseClient {\n if (cachedClient) {\n return cachedClient;\n }\n\n const issuerUrl = requiredEnv(\"PYMTHOUSE_ISSUER_URL\");\n\n cachedClient = new PmtHouseClient({\n issuerUrl,\n publicClientId: requiredEnv(\"PYMTHOUSE_PUBLIC_CLIENT_ID\"),\n m2mClientId: requiredEnv(\"PYMTHOUSE_M2M_CLIENT_ID\"),\n m2mClientSecret: requiredEnv(\"PYMTHOUSE_M2M_CLIENT_SECRET\"),\n allowInsecureHttp: issuerUrl.startsWith(\"http:\"),\n logger: {\n debug: (message, details) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.debug(`[pymthouse] ${message}`, details ?? {});\n }\n },\n warn: (message, details) => {\n console.warn(`[pymthouse] ${message}`, details ?? {});\n },\n },\n });\n\n return cachedClient;\n}\n"]}
|