@pymthouse/builder-sdk 0.4.1-rc.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/env.cjs +4 -13
- package/dist/env.cjs.map +1 -1
- package/dist/env.js +4 -13
- package/dist/env.js.map +1 -1
- package/dist/{index-B0ryx942.d.cts → index-D5wdxNYy.d.cts} +1 -1
- package/dist/{index-CvV5syf_.d.ts → index-DFJ6qcK0.d.ts} +1 -1
- package/dist/index.cjs +4 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -13
- package/dist/index.js.map +1 -1
- package/dist/{proxy-JrT6raU_.d.cts → proxy-0wa8QZIU.d.cts} +16 -2
- package/dist/{proxy-U32DFNuj.d.ts → proxy-KrA1vEmh.d.ts} +16 -2
- package/dist/signer/server.cjs +89 -72
- package/dist/signer/server.cjs.map +1 -1
- package/dist/signer/server.d.cts +2 -2
- package/dist/signer/server.d.ts +2 -2
- package/dist/signer/server.js +89 -72
- package/dist/signer/server.js.map +1 -1
- package/dist/signer/webhook/adapters/api-key.cjs +1 -1
- package/dist/signer/webhook/adapters/api-key.cjs.map +1 -1
- package/dist/signer/webhook/adapters/api-key.d.cts +1 -1
- package/dist/signer/webhook/adapters/api-key.d.ts +1 -1
- package/dist/signer/webhook/adapters/api-key.js +1 -1
- package/dist/signer/webhook/adapters/api-key.js.map +1 -1
- package/dist/signer/webhook/adapters/composite.cjs +1 -1
- package/dist/signer/webhook/adapters/composite.cjs.map +1 -1
- package/dist/signer/webhook/adapters/composite.d.cts +1 -1
- package/dist/signer/webhook/adapters/composite.d.ts +1 -1
- package/dist/signer/webhook/adapters/composite.js +1 -1
- package/dist/signer/webhook/adapters/composite.js.map +1 -1
- package/dist/signer/webhook/adapters/oidc.cjs +6 -3
- package/dist/signer/webhook/adapters/oidc.cjs.map +1 -1
- package/dist/signer/webhook/adapters/oidc.d.cts +2 -2
- package/dist/signer/webhook/adapters/oidc.d.ts +2 -2
- package/dist/signer/webhook/adapters/oidc.js +6 -3
- package/dist/signer/webhook/adapters/oidc.js.map +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.cjs +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.cjs.map +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.d.cts +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.d.ts +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.js +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.js.map +1 -1
- package/dist/signer/webhook.cjs +7 -71
- package/dist/signer/webhook.cjs.map +1 -1
- package/dist/signer/webhook.d.cts +5 -14
- package/dist/signer/webhook.d.ts +5 -14
- package/dist/signer/webhook.js +8 -70
- package/dist/signer/webhook.js.map +1 -1
- package/dist/{verifier-B-WFDMz6.d.cts → verifier-Be9WAjFF.d.cts} +3 -2
- package/dist/{verifier-B-WFDMz6.d.ts → verifier-Be9WAjFF.d.ts} +3 -2
- package/package.json +2 -8
- package/dist/signer/webhook/adapters/oauth1.cjs +0 -18
- package/dist/signer/webhook/adapters/oauth1.cjs.map +0 -1
- package/dist/signer/webhook/adapters/oauth1.d.cts +0 -19
- package/dist/signer/webhook/adapters/oauth1.d.ts +0 -19
- package/dist/signer/webhook/adapters/oauth1.js +0 -16
- package/dist/signer/webhook/adapters/oauth1.js.map +0 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { F as FetchLike } from './types-BORaHW_x.cjs';
|
|
2
2
|
|
|
3
3
|
type SignerDmzGate = "http" | "cli";
|
|
4
|
+
interface M2MClientCredentials {
|
|
5
|
+
m2mClientId: string;
|
|
6
|
+
m2mClientSecret: string;
|
|
7
|
+
}
|
|
4
8
|
interface DirectSignerProxyConfig {
|
|
5
9
|
pymthouseIssuerUrl: string;
|
|
6
10
|
/** Public Builder app client id (`app_…`); used for cache keys and JWT `client_id`. */
|
|
@@ -10,6 +14,16 @@ interface DirectSignerProxyConfig {
|
|
|
10
14
|
remoteSignerUrl: string | URL;
|
|
11
15
|
fetch?: FetchLike;
|
|
12
16
|
allowInsecureHttp?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Multi-tenant: resolve the M2M credentials used to mint signer JWTs for a
|
|
19
|
+
* given `publicClientId`. The PymtHouse issuer binds the minted JWT's
|
|
20
|
+
* `client_id` to the developer app linked to these M2M credentials, so each
|
|
21
|
+
* tenant's `publicClientId` (from {@link DirectSignerProxyConfig.resolvePublicClientId})
|
|
22
|
+
* must map to the M2M credentials whose app uses it. The token manager
|
|
23
|
+
* validates that the minted `client_id` matches the requested `publicClientId`.
|
|
24
|
+
* Defaults to `pymthouseM2MClientId` / `pymthouseM2MClientSecret`.
|
|
25
|
+
*/
|
|
26
|
+
resolveM2MCredentials?: (publicClientId: string) => M2MClientCredentials | Promise<M2MClientCredentials>;
|
|
13
27
|
/**
|
|
14
28
|
* When set, incoming request paths matching this prefix are rewritten to the remote signer base.
|
|
15
29
|
* Example: `/api/signer/proxy` → remote `/generate-live-payment` when the suffix is empty.
|
|
@@ -53,7 +67,7 @@ interface MintUserSignerTokenResponse {
|
|
|
53
67
|
lifetimeGrantedUsdMicros: string;
|
|
54
68
|
}
|
|
55
69
|
interface SignerTokenManagerOptions {
|
|
56
|
-
mint: (externalUserId: string) => Promise<CachedSignerToken>;
|
|
70
|
+
mint: (publicClientId: string, externalUserId: string) => Promise<CachedSignerToken>;
|
|
57
71
|
/** Fraction of TTL after which a proactive refresh runs. Defaults to `0.8`. */
|
|
58
72
|
ttlRefreshRatio?: number;
|
|
59
73
|
fetch?: FetchLike;
|
|
@@ -231,4 +245,4 @@ declare function probeSignerHttpReachability(options: ProbeSignerHttpReachabilit
|
|
|
231
245
|
ethAddress?: string;
|
|
232
246
|
}>;
|
|
233
247
|
|
|
234
|
-
export { type ApiKeyExchangeHandlerConfig as A,
|
|
248
|
+
export { type ApiKeyExchangeHandlerConfig as A, readSignerUpstreamBody as B, type CachedSignerToken as C, type DeviceExchangeHandlerConfig as D, type ExchangeDeviceTokenForSignerOptions as E, type ForwardDirectSignerRequestOptions as F, resolveSignerBaseUrl as G, stripSignerUsageFromResponse as H, type MintUserSignerTokenOptions as M, type ProbeSignerHttpReachabilityOptions as P, type SignerUsageSnapshot as S, type SignerTokenManagerOptions as a, type SignerJwtIdentity as b, type DeviceExchangeHandlerConfigRemote as c, type DeviceExchangeResponse as d, type MintSignerTokenFromDeviceTokenOptions as e, type DeviceExchangeMintResult as f, type DeviceExchangeRequestBody as g, type ExchangeApiKeyForSignerOptions as h, type ApiKeyExchangeMintResult as i, type ApiKeyExchangeRequestBody as j, type DirectSignerProxyConfig as k, type DeviceExchangeMintContext as l, type DirectSignerBeforeSignContext as m, type DirectSignerBeforeSignResult as n, type ForwardToSignerOptions as o, type ForwardToSignerResult as p, type M2MClientCredentials as q, type MintUserSignerTokenResponse as r, type SignerDmzGate as s, forwardToSigner as t, getCachedDmzBearerToken as u, normalizeSignerBaseUrl as v, parseSignerUsageSnapshot as w, pickConflictingNumberAliases as x, pickConflictingStringAliases as y, probeSignerHttpReachability as z };
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { F as FetchLike } from './types-BORaHW_x.js';
|
|
2
2
|
|
|
3
3
|
type SignerDmzGate = "http" | "cli";
|
|
4
|
+
interface M2MClientCredentials {
|
|
5
|
+
m2mClientId: string;
|
|
6
|
+
m2mClientSecret: string;
|
|
7
|
+
}
|
|
4
8
|
interface DirectSignerProxyConfig {
|
|
5
9
|
pymthouseIssuerUrl: string;
|
|
6
10
|
/** Public Builder app client id (`app_…`); used for cache keys and JWT `client_id`. */
|
|
@@ -10,6 +14,16 @@ interface DirectSignerProxyConfig {
|
|
|
10
14
|
remoteSignerUrl: string | URL;
|
|
11
15
|
fetch?: FetchLike;
|
|
12
16
|
allowInsecureHttp?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Multi-tenant: resolve the M2M credentials used to mint signer JWTs for a
|
|
19
|
+
* given `publicClientId`. The PymtHouse issuer binds the minted JWT's
|
|
20
|
+
* `client_id` to the developer app linked to these M2M credentials, so each
|
|
21
|
+
* tenant's `publicClientId` (from {@link DirectSignerProxyConfig.resolvePublicClientId})
|
|
22
|
+
* must map to the M2M credentials whose app uses it. The token manager
|
|
23
|
+
* validates that the minted `client_id` matches the requested `publicClientId`.
|
|
24
|
+
* Defaults to `pymthouseM2MClientId` / `pymthouseM2MClientSecret`.
|
|
25
|
+
*/
|
|
26
|
+
resolveM2MCredentials?: (publicClientId: string) => M2MClientCredentials | Promise<M2MClientCredentials>;
|
|
13
27
|
/**
|
|
14
28
|
* When set, incoming request paths matching this prefix are rewritten to the remote signer base.
|
|
15
29
|
* Example: `/api/signer/proxy` → remote `/generate-live-payment` when the suffix is empty.
|
|
@@ -53,7 +67,7 @@ interface MintUserSignerTokenResponse {
|
|
|
53
67
|
lifetimeGrantedUsdMicros: string;
|
|
54
68
|
}
|
|
55
69
|
interface SignerTokenManagerOptions {
|
|
56
|
-
mint: (externalUserId: string) => Promise<CachedSignerToken>;
|
|
70
|
+
mint: (publicClientId: string, externalUserId: string) => Promise<CachedSignerToken>;
|
|
57
71
|
/** Fraction of TTL after which a proactive refresh runs. Defaults to `0.8`. */
|
|
58
72
|
ttlRefreshRatio?: number;
|
|
59
73
|
fetch?: FetchLike;
|
|
@@ -231,4 +245,4 @@ declare function probeSignerHttpReachability(options: ProbeSignerHttpReachabilit
|
|
|
231
245
|
ethAddress?: string;
|
|
232
246
|
}>;
|
|
233
247
|
|
|
234
|
-
export { type ApiKeyExchangeHandlerConfig as A,
|
|
248
|
+
export { type ApiKeyExchangeHandlerConfig as A, readSignerUpstreamBody as B, type CachedSignerToken as C, type DeviceExchangeHandlerConfig as D, type ExchangeDeviceTokenForSignerOptions as E, type ForwardDirectSignerRequestOptions as F, resolveSignerBaseUrl as G, stripSignerUsageFromResponse as H, type MintUserSignerTokenOptions as M, type ProbeSignerHttpReachabilityOptions as P, type SignerUsageSnapshot as S, type SignerTokenManagerOptions as a, type SignerJwtIdentity as b, type DeviceExchangeHandlerConfigRemote as c, type DeviceExchangeResponse as d, type MintSignerTokenFromDeviceTokenOptions as e, type DeviceExchangeMintResult as f, type DeviceExchangeRequestBody as g, type ExchangeApiKeyForSignerOptions as h, type ApiKeyExchangeMintResult as i, type ApiKeyExchangeRequestBody as j, type DirectSignerProxyConfig as k, type DeviceExchangeMintContext as l, type DirectSignerBeforeSignContext as m, type DirectSignerBeforeSignResult as n, type ForwardToSignerOptions as o, type ForwardToSignerResult as p, type M2MClientCredentials as q, type MintUserSignerTokenResponse as r, type SignerDmzGate as s, forwardToSigner as t, getCachedDmzBearerToken as u, normalizeSignerBaseUrl as v, parseSignerUsageSnapshot as w, pickConflictingNumberAliases as x, pickConflictingStringAliases as y, probeSignerHttpReachability as z };
|
package/dist/signer/server.cjs
CHANGED
|
@@ -21,14 +21,8 @@ var PmtHouseError = class extends Error {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
// src/signer/handler-errors.ts
|
|
24
|
-
function isPmtHouseError(error) {
|
|
25
|
-
if (error instanceof PmtHouseError) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
return error instanceof Error && typeof error.status === "number" && typeof error.code === "string";
|
|
29
|
-
}
|
|
30
24
|
function signerHandlerErrorResponse(error) {
|
|
31
|
-
if (
|
|
25
|
+
if (error instanceof PmtHouseError) {
|
|
32
26
|
return new Response(
|
|
33
27
|
JSON.stringify({
|
|
34
28
|
error: error.code,
|
|
@@ -48,62 +42,6 @@ function signerHandlerErrorResponse(error) {
|
|
|
48
42
|
});
|
|
49
43
|
}
|
|
50
44
|
|
|
51
|
-
// src/signer/token-manager.ts
|
|
52
|
-
function cacheKey(clientId, externalUserId) {
|
|
53
|
-
return `${clientId}\0${externalUserId}`;
|
|
54
|
-
}
|
|
55
|
-
function createSignerTokenManager(options) {
|
|
56
|
-
const ttlRefreshRatio = options.ttlRefreshRatio ?? 0.8;
|
|
57
|
-
const cache = /* @__PURE__ */ new Map();
|
|
58
|
-
const inflight = /* @__PURE__ */ new Map();
|
|
59
|
-
function isUsable(entry, now, forceRefresh) {
|
|
60
|
-
if (forceRefresh) return false;
|
|
61
|
-
if (now >= entry.expiresAt) return false;
|
|
62
|
-
if (now >= entry.refreshAt) return false;
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
async function refresh(publicClientId, externalUserId) {
|
|
66
|
-
const key = cacheKey(publicClientId, externalUserId);
|
|
67
|
-
const existing = inflight.get(key);
|
|
68
|
-
if (existing) {
|
|
69
|
-
return existing;
|
|
70
|
-
}
|
|
71
|
-
const promise = options.mint(externalUserId).then((token) => {
|
|
72
|
-
const normalized = {
|
|
73
|
-
...token,
|
|
74
|
-
refreshAt: token.refreshAt || Date.now() + Math.floor((token.expiresAt - Date.now()) * ttlRefreshRatio)
|
|
75
|
-
};
|
|
76
|
-
cache.set(key, normalized);
|
|
77
|
-
inflight.delete(key);
|
|
78
|
-
return normalized;
|
|
79
|
-
}).catch((error) => {
|
|
80
|
-
inflight.delete(key);
|
|
81
|
-
throw error;
|
|
82
|
-
});
|
|
83
|
-
inflight.set(key, promise);
|
|
84
|
-
return promise;
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
peek(publicClientId, externalUserId) {
|
|
88
|
-
return cache.get(cacheKey(publicClientId, externalUserId));
|
|
89
|
-
},
|
|
90
|
-
invalidate(publicClientId, externalUserId) {
|
|
91
|
-
const key = cacheKey(publicClientId, externalUserId);
|
|
92
|
-
cache.delete(key);
|
|
93
|
-
inflight.delete(key);
|
|
94
|
-
},
|
|
95
|
-
async getToken(publicClientId, externalUserId, getOptions = {}) {
|
|
96
|
-
const now = Date.now();
|
|
97
|
-
const key = cacheKey(publicClientId, externalUserId);
|
|
98
|
-
const cached = cache.get(key);
|
|
99
|
-
if (cached && isUsable(cached, now, getOptions.forceRefresh === true)) {
|
|
100
|
-
return cached;
|
|
101
|
-
}
|
|
102
|
-
return refresh(publicClientId, externalUserId);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
45
|
// src/signer/forward.ts
|
|
108
46
|
function base64UrlPayloadToUtf8(payloadB64) {
|
|
109
47
|
const normalized = payloadB64.replaceAll("-", "+").replaceAll("_", "/");
|
|
@@ -217,6 +155,70 @@ async function forwardDirectSignerRequest(options) {
|
|
|
217
155
|
return fetchImpl(target, init);
|
|
218
156
|
}
|
|
219
157
|
|
|
158
|
+
// src/signer/token-manager.ts
|
|
159
|
+
function cacheKey(clientId, externalUserId) {
|
|
160
|
+
return `${clientId}\0${externalUserId}`;
|
|
161
|
+
}
|
|
162
|
+
function createSignerTokenManager(options) {
|
|
163
|
+
const ttlRefreshRatio = options.ttlRefreshRatio ?? 0.8;
|
|
164
|
+
const cache = /* @__PURE__ */ new Map();
|
|
165
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
166
|
+
function isUsable(entry, now, forceRefresh) {
|
|
167
|
+
if (forceRefresh) return false;
|
|
168
|
+
if (now >= entry.expiresAt) return false;
|
|
169
|
+
if (now >= entry.refreshAt) return false;
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
async function refresh(publicClientId, externalUserId) {
|
|
173
|
+
const key = cacheKey(publicClientId, externalUserId);
|
|
174
|
+
const existing = inflight.get(key);
|
|
175
|
+
if (existing) {
|
|
176
|
+
return existing;
|
|
177
|
+
}
|
|
178
|
+
const promise = options.mint(publicClientId, externalUserId).then((token) => {
|
|
179
|
+
const identity = identityFromJwtPayload(decodeJwtPayload(token.jwt));
|
|
180
|
+
if (identity.clientId !== publicClientId) {
|
|
181
|
+
throw new PmtHouseError("minted JWT client_id does not match public client id", {
|
|
182
|
+
status: 500,
|
|
183
|
+
code: "invalid_client_id",
|
|
184
|
+
details: { expected: publicClientId, actual: identity.clientId }
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const normalized = {
|
|
188
|
+
...token,
|
|
189
|
+
refreshAt: token.refreshAt || Date.now() + Math.floor((token.expiresAt - Date.now()) * ttlRefreshRatio)
|
|
190
|
+
};
|
|
191
|
+
cache.set(key, normalized);
|
|
192
|
+
inflight.delete(key);
|
|
193
|
+
return normalized;
|
|
194
|
+
}).catch((error) => {
|
|
195
|
+
inflight.delete(key);
|
|
196
|
+
throw error;
|
|
197
|
+
});
|
|
198
|
+
inflight.set(key, promise);
|
|
199
|
+
return promise;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
peek(publicClientId, externalUserId) {
|
|
203
|
+
return cache.get(cacheKey(publicClientId, externalUserId));
|
|
204
|
+
},
|
|
205
|
+
invalidate(publicClientId, externalUserId) {
|
|
206
|
+
const key = cacheKey(publicClientId, externalUserId);
|
|
207
|
+
cache.delete(key);
|
|
208
|
+
inflight.delete(key);
|
|
209
|
+
},
|
|
210
|
+
async getToken(publicClientId, externalUserId, getOptions = {}) {
|
|
211
|
+
const now = Date.now();
|
|
212
|
+
const key = cacheKey(publicClientId, externalUserId);
|
|
213
|
+
const cached = cache.get(key);
|
|
214
|
+
if (cached && isUsable(cached, now, getOptions.forceRefresh === true)) {
|
|
215
|
+
return cached;
|
|
216
|
+
}
|
|
217
|
+
return refresh(publicClientId, externalUserId);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
220
222
|
// src/string-utils.ts
|
|
221
223
|
function stripTrailingSlashes(value) {
|
|
222
224
|
let end = value.length;
|
|
@@ -543,7 +545,7 @@ async function mintSignerTokenFromDeviceToken(options) {
|
|
|
543
545
|
code: "oidc_discovery_invalid"
|
|
544
546
|
});
|
|
545
547
|
}
|
|
546
|
-
const audience = options.audience?.trim() ||
|
|
548
|
+
const audience = options.audience?.trim() || LIVEPEER_REMOTE_SIGNER_AUDIENCE;
|
|
547
549
|
const params = new URLSearchParams({
|
|
548
550
|
grant_type: TOKEN_EXCHANGE_GRANT,
|
|
549
551
|
subject_token: options.deviceToken,
|
|
@@ -1157,15 +1159,30 @@ function toResponse(result) {
|
|
|
1157
1159
|
});
|
|
1158
1160
|
}
|
|
1159
1161
|
function createDirectSignerProxyHandler(config) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1162
|
+
async function resolveM2MCredentials(publicClientId) {
|
|
1163
|
+
if (config.resolveM2MCredentials) {
|
|
1164
|
+
return config.resolveM2MCredentials(publicClientId);
|
|
1165
|
+
}
|
|
1166
|
+
return {
|
|
1163
1167
|
m2mClientId: config.pymthouseM2MClientId,
|
|
1164
|
-
m2mClientSecret: config.pymthouseM2MClientSecret
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1168
|
+
m2mClientSecret: config.pymthouseM2MClientSecret
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
const tokenManager = createSignerTokenManager({
|
|
1172
|
+
// `publicClientId` selects the M2M credentials so the minted JWT's
|
|
1173
|
+
// `client_id` matches the cache partition key. The token manager rejects any
|
|
1174
|
+
// minted token whose `client_id` diverges from `publicClientId`.
|
|
1175
|
+
mint: async (publicClientId, externalUserId) => {
|
|
1176
|
+
const { m2mClientId, m2mClientSecret } = await resolveM2MCredentials(publicClientId);
|
|
1177
|
+
return mintUserSignerToken({
|
|
1178
|
+
issuerUrl: config.pymthouseIssuerUrl,
|
|
1179
|
+
m2mClientId,
|
|
1180
|
+
m2mClientSecret,
|
|
1181
|
+
externalUserId,
|
|
1182
|
+
fetch: config.fetch,
|
|
1183
|
+
allowInsecureHttp: config.allowInsecureHttp
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1169
1186
|
});
|
|
1170
1187
|
async function runBeforeSign(token, externalUserId, request) {
|
|
1171
1188
|
if (!config.beforeSign) {
|