@superdurable/connectors-sdk 0.1.0 → 0.2.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 +27 -3
- package/dist/{chunk-2NBM7P4T.js → chunk-32YJXBE4.js} +1 -1
- package/dist/chunk-466BPS3M.js +336 -0
- package/dist/{chunk-IVJLNZVL.js → chunk-BG65RPGH.js} +70 -15
- package/dist/{chunk-SOXYPIMO.js → chunk-BQGYGCOQ.js} +35 -73
- package/dist/chunk-IHG6ADQG.js +44 -0
- package/dist/chunk-NQQJS6OC.js +316 -0
- package/dist/{chunk-KD5DYYSU.js → chunk-QDMBAWXD.js} +1 -1
- package/dist/connectormock/index.d.ts +3 -2
- package/dist/connectormock/index.js +5 -3
- package/dist/credentials-JqG97kJ5.d.ts +102 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +19 -291
- package/dist/oauthtoken/index.d.ts +36 -2
- package/dist/oauthtoken/index.js +326 -5
- package/dist/{operation-Ca8rfacf.d.ts → operation-CASLOg86.d.ts} +2 -1
- package/dist/projectconfig/index.d.ts +2 -1
- package/dist/projectconfig/index.js +5 -3
- package/dist/providerhttp/index.d.ts +21 -4
- package/dist/providerhttp/index.js +3 -1
- package/dist/query-CeUaW9xU.d.ts +42 -0
- package/dist/singledispatch/index.d.ts +2 -1
- package/dist/singledispatch/index.js +2 -1
- package/dist/textgen/index.d.ts +15 -0
- package/dist/textgen/index.js +628 -0
- package/dist/textgen/openaichat/index.d.ts +44 -0
- package/dist/textgen/openaichat/index.js +232 -0
- package/dist/textgen/textgentest/index.d.ts +106 -0
- package/dist/textgen/textgentest/index.js +537 -0
- package/dist/{credentials-vrvW0d4j.d.ts → types-D6De3sry.d.ts} +1 -100
- package/dist/wire_format-stEVruMs.d.ts +190 -0
- package/package.json +14 -2
package/dist/oauthtoken/index.js
CHANGED
|
@@ -1,14 +1,316 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SecretString
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-QDMBAWXD.js";
|
|
4
|
+
import "../chunk-BQGYGCOQ.js";
|
|
4
5
|
import {
|
|
5
6
|
ReauthorizationRequiredError
|
|
6
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-IHG6ADQG.js";
|
|
7
8
|
|
|
8
9
|
// src/oauthtoken/index.ts
|
|
9
10
|
import { createPrivateKey, sign } from "crypto";
|
|
11
|
+
|
|
12
|
+
// src/oauthtoken/manifest_refresh.ts
|
|
13
|
+
var ManifestCredentialRefreshDriver = class {
|
|
14
|
+
#providerName;
|
|
15
|
+
#auth;
|
|
16
|
+
#credentialFields;
|
|
17
|
+
#settings;
|
|
18
|
+
#fetch;
|
|
19
|
+
#now;
|
|
20
|
+
/** Bind validated auth data, pinned settings, a caller-owned transport, and a clock. */
|
|
21
|
+
constructor(options) {
|
|
22
|
+
if (!options?.providerName || !options.auth || !options.credentialFields) throw new TypeError("manifest refresh configuration is required");
|
|
23
|
+
this.#providerName = options.providerName;
|
|
24
|
+
this.#auth = options.auth;
|
|
25
|
+
this.#credentialFields = options.credentialFields;
|
|
26
|
+
this.#settings = options.settings ?? {};
|
|
27
|
+
this.#fetch = options.fetch ?? fetch;
|
|
28
|
+
this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
29
|
+
}
|
|
30
|
+
/** Check declared access fields against the host's single credential expiry. */
|
|
31
|
+
refreshRequired(state) {
|
|
32
|
+
const grants = this.#grants(this.#selectedMethod(state.credentials));
|
|
33
|
+
if (!grants.length) return false;
|
|
34
|
+
const accessFields = grants.flatMap((grant) => grant.mappings.filter((mapping) => mapping.source === "access_token").map((mapping) => manifestText(mapping.credential)));
|
|
35
|
+
const hasAccessToken = accessFields.length > 0 && accessFields.every((name) => Boolean(this.#credentialValue(state.credentials, name)));
|
|
36
|
+
return isRefreshRequired(hasAccessToken, state.expiresAt, state.now, "keep");
|
|
37
|
+
}
|
|
38
|
+
/** Send each active grant and return one complete credential with the earliest expiry. */
|
|
39
|
+
async refresh(state, signal) {
|
|
40
|
+
let credentials = state.credentials;
|
|
41
|
+
const method = this.#selectedMethod(credentials);
|
|
42
|
+
const grants = this.#grants(method);
|
|
43
|
+
if (!grants.length) throw new ReauthorizationRequiredError();
|
|
44
|
+
for (const grant of grants) this.#validateGrant(grant);
|
|
45
|
+
const expiries = [];
|
|
46
|
+
for (const grant of grants) {
|
|
47
|
+
if (grant.refreshField && !this.#credentialValue(credentials, grant.refreshField)) continue;
|
|
48
|
+
const token = await this.#exchange(grant, credentials, method, signal);
|
|
49
|
+
const requiredScopes = this.#scopes(grant.scopes).filter((scope) => grant.kind !== "refresh" || scope !== "offline_access");
|
|
50
|
+
if (grants.length > 1 ? !hasExactScopes(token.scope, requiredScopes) : token.scope !== "" && !hasAllScopes(token.scope, requiredScopes)) throw new ReauthorizationRequiredError();
|
|
51
|
+
const updates = {};
|
|
52
|
+
for (const mapping of grant.mappings) {
|
|
53
|
+
const destination = manifestText(mapping.credential);
|
|
54
|
+
const value = token.mappedCredentialValue(manifestText(mapping.source));
|
|
55
|
+
if (value === void 0 || value === "" && destination === grant.refreshField) continue;
|
|
56
|
+
const property = this.#credentialFields[destination];
|
|
57
|
+
if (!property) throw new TypeError("manifest credential field is not mapped");
|
|
58
|
+
updates[property] = this.#isSecret(method, destination) ? new SecretString(value) : value;
|
|
59
|
+
}
|
|
60
|
+
for (const copy of grant.copies) {
|
|
61
|
+
const destination = manifestText(copy.credential);
|
|
62
|
+
const property = this.#credentialFields[destination];
|
|
63
|
+
if (!property) throw new TypeError("manifest credential field is not mapped");
|
|
64
|
+
const value = this.#credentialValue(credentials, manifestText(copy.fromCredential));
|
|
65
|
+
updates[property] = this.#isSecret(method, destination) ? new SecretString(value) : value;
|
|
66
|
+
}
|
|
67
|
+
credentials = { ...credentials, ...updates };
|
|
68
|
+
const lifetime = token.expiresInMs > 0 ? token.expiresInMs : parseDurationMs(grant.missingExpiry);
|
|
69
|
+
expiries.push(lifetime > 0 ? this.#now().getTime() + lifetime : 0);
|
|
70
|
+
}
|
|
71
|
+
if (!expiries.length) throw new ReauthorizationRequiredError();
|
|
72
|
+
return { credentials, expiresAt: new Date(Math.min(...expiries)) };
|
|
73
|
+
}
|
|
74
|
+
#selectedMethod(credentials) {
|
|
75
|
+
const methods = manifestList(this.#auth.methods);
|
|
76
|
+
if (!methods.length) return this.#auth;
|
|
77
|
+
const selected = manifestText(credentials.authMethodId);
|
|
78
|
+
if (!selected && methods.length > 1) throw new ReauthorizationRequiredError();
|
|
79
|
+
const method = methods.map(manifestObject).find((item) => item.id === (selected || manifestText(this.#auth.defaultMethod)));
|
|
80
|
+
if (!method) throw new ReauthorizationRequiredError();
|
|
81
|
+
return method;
|
|
82
|
+
}
|
|
83
|
+
#grants(method) {
|
|
84
|
+
if (method.oauth2) {
|
|
85
|
+
const oauth = manifestObject(method.oauth2);
|
|
86
|
+
const refresh = method.oauth2 && manifestObject(oauth.refresh);
|
|
87
|
+
let declared = manifestList(refresh?.grants).map(manifestObject);
|
|
88
|
+
if (!declared.length) {
|
|
89
|
+
const mapped = manifestList(oauth.credentialMappings).map(manifestObject).find((mapping) => mapping.source === "refresh_token");
|
|
90
|
+
if (!mapped) return [];
|
|
91
|
+
declared = [{ refreshTokenCredential: mapped.credential, credentialMappings: oauth.credentialMappings }];
|
|
92
|
+
}
|
|
93
|
+
return declared.map((declaration) => ({
|
|
94
|
+
kind: "refresh",
|
|
95
|
+
endpoint: oauth.tokenEndpoint,
|
|
96
|
+
authentication: oauth.tokenEndpointAuthMethod ?? "client_secret_post",
|
|
97
|
+
encoding: manifestText(oauth.tokenRequestEncoding) || "form",
|
|
98
|
+
clientID: manifestText(oauth.clientIDCredential),
|
|
99
|
+
clientSecret: manifestText(oauth.clientSecretCredential),
|
|
100
|
+
refreshField: manifestText(declaration.refreshTokenCredential),
|
|
101
|
+
keyCredential: "",
|
|
102
|
+
assertion: {},
|
|
103
|
+
mappings: manifestList(declaration.credentialMappings).map(manifestObject),
|
|
104
|
+
copies: [],
|
|
105
|
+
scopes: declaration.grantedScopes === "userScopes" ? oauth.userScopes : oauth.scopes,
|
|
106
|
+
requestScopes: [],
|
|
107
|
+
terminalCodes: strings(refresh?.terminalErrorCodes, ["invalid_grant"]),
|
|
108
|
+
acceptedTokenTypes: strings(declaration.acceptedTokenTypes ?? refresh?.acceptedTokenTypes, ["Bearer"]),
|
|
109
|
+
acceptsMissingTokenType: refresh?.acceptsMissingTokenType === true,
|
|
110
|
+
missingExpiry: missingExpiryLifetime(refresh?.missingExpiry),
|
|
111
|
+
additionalParameters: stringRecord(refresh?.additionalParameters)
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
if (method.clientCredentials) {
|
|
115
|
+
const client = manifestObject(method.clientCredentials);
|
|
116
|
+
return [{
|
|
117
|
+
kind: "client_credentials",
|
|
118
|
+
endpoint: client.tokenEndpoint,
|
|
119
|
+
authentication: client.tokenEndpointAuthMethod ?? "client_secret_post",
|
|
120
|
+
encoding: manifestText(client.tokenRequestEncoding) || "form",
|
|
121
|
+
clientID: manifestText(client.clientIDCredential),
|
|
122
|
+
clientSecret: manifestText(client.clientSecretCredential),
|
|
123
|
+
refreshField: "",
|
|
124
|
+
keyCredential: "",
|
|
125
|
+
assertion: {},
|
|
126
|
+
mappings: manifestList(client.credentialMappings).map(manifestObject),
|
|
127
|
+
copies: [],
|
|
128
|
+
scopes: client.scopes,
|
|
129
|
+
requestScopes: client.scopes,
|
|
130
|
+
terminalCodes: strings(client.terminalErrorCodes, ["invalid_client"]),
|
|
131
|
+
acceptedTokenTypes: strings(client.acceptedTokenTypes, ["Bearer"]),
|
|
132
|
+
acceptsMissingTokenType: client.acceptsMissingTokenType === true,
|
|
133
|
+
missingExpiry: missingExpiryLifetime(client.missingExpiry),
|
|
134
|
+
additionalParameters: stringRecord(client.additionalParameters)
|
|
135
|
+
}];
|
|
136
|
+
}
|
|
137
|
+
const serviceAccount = manifestObject(method.serviceAccount);
|
|
138
|
+
if (!serviceAccount.jwtBearer) return [];
|
|
139
|
+
const bearer = manifestObject(serviceAccount.jwtBearer);
|
|
140
|
+
return [{
|
|
141
|
+
kind: "jwt_bearer",
|
|
142
|
+
endpoint: bearer.tokenEndpoint,
|
|
143
|
+
authentication: "",
|
|
144
|
+
encoding: "form",
|
|
145
|
+
clientID: "",
|
|
146
|
+
clientSecret: "",
|
|
147
|
+
refreshField: "",
|
|
148
|
+
keyCredential: manifestText(bearer.keyCredential),
|
|
149
|
+
assertion: bearer,
|
|
150
|
+
mappings: manifestList(bearer.credentialMappings).map(manifestObject),
|
|
151
|
+
copies: manifestList(bearer.credentialCopies).map(manifestObject),
|
|
152
|
+
scopes: bearer.scopes,
|
|
153
|
+
requestScopes: [],
|
|
154
|
+
terminalCodes: strings(bearer.terminalErrorCodes, ["invalid_grant"]),
|
|
155
|
+
acceptedTokenTypes: strings(bearer.acceptedTokenTypes, ["Bearer"]),
|
|
156
|
+
acceptsMissingTokenType: bearer.acceptsMissingTokenType === true,
|
|
157
|
+
missingExpiry: missingExpiryLifetime(bearer.missingExpiry),
|
|
158
|
+
additionalParameters: {}
|
|
159
|
+
}];
|
|
160
|
+
}
|
|
161
|
+
async #exchange(grant, credentials, method, signal) {
|
|
162
|
+
let key = {};
|
|
163
|
+
if (grant.kind === "jwt_bearer") {
|
|
164
|
+
try {
|
|
165
|
+
key = manifestObject(JSON.parse(this.#credentialValue(credentials, grant.keyCredential)));
|
|
166
|
+
} catch {
|
|
167
|
+
throw new ReauthorizationRequiredError();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const endpoint = new TokenEndpoint({
|
|
171
|
+
providerName: this.#providerName,
|
|
172
|
+
url: this.#resolveSource(grant.endpoint, credentials, key),
|
|
173
|
+
terminalErrorCodes: grant.terminalCodes,
|
|
174
|
+
acceptedTokenTypes: grant.acceptedTokenTypes,
|
|
175
|
+
acceptsMissingTokenType: grant.acceptsMissingTokenType,
|
|
176
|
+
acceptsMissingExpiresIn: true,
|
|
177
|
+
usesJSONRequestBody: grant.encoding === "json",
|
|
178
|
+
additionalRequestParameters: grant.additionalParameters,
|
|
179
|
+
credentialMappingPaths: grant.mappings.map((mapping) => manifestText(mapping.source)),
|
|
180
|
+
fetch: this.#fetch
|
|
181
|
+
});
|
|
182
|
+
if (grant.kind === "jwt_bearer") {
|
|
183
|
+
const assertion = grant.assertion;
|
|
184
|
+
const lifetimeMs = parseDurationMs(manifestText(assertion.lifetime));
|
|
185
|
+
let signed;
|
|
186
|
+
try {
|
|
187
|
+
signed = signJWTBearerAssertion({
|
|
188
|
+
issuer: this.#resolveSource(assertion.issuer, credentials, key),
|
|
189
|
+
audience: this.#resolveSource(assertion.audience, credentials, key),
|
|
190
|
+
...assertion.subject ? { subject: this.#resolveSource(assertion.subject, credentials, key) } : {},
|
|
191
|
+
scope: this.#scopes(assertion.scopes).join(" "),
|
|
192
|
+
issuedAt: this.#now(),
|
|
193
|
+
lifetimeMs
|
|
194
|
+
}, parseRSAPrivateKeyPEM(this.#resolveSource(assertion.privateKey, credentials, key)));
|
|
195
|
+
} catch {
|
|
196
|
+
throw new ReauthorizationRequiredError();
|
|
197
|
+
}
|
|
198
|
+
return await endpoint.exchangeJWTBearerAssertion(signed, signal);
|
|
199
|
+
}
|
|
200
|
+
const secret = this.#credentialValue(credentials, grant.clientSecret);
|
|
201
|
+
if (!secret && this.#isRequired(method, grant.clientSecret)) throw new ReauthorizationRequiredError();
|
|
202
|
+
const authenticationMethod = secret || grant.kind === "client_credentials" ? this.#resolveSource(grant.authentication, credentials, key) : "none";
|
|
203
|
+
const client = { id: this.#credentialValue(credentials, grant.clientID), secret: new SecretString(secret), authenticationMethod };
|
|
204
|
+
if (grant.kind === "refresh") {
|
|
205
|
+
return endpoint.exchangeRefreshToken(client, new SecretString(this.#credentialValue(credentials, grant.refreshField)), signal);
|
|
206
|
+
}
|
|
207
|
+
return endpoint.exchangeClientCredentials(client, this.#scopes(grant.requestScopes), signal);
|
|
208
|
+
}
|
|
209
|
+
#credentialValue(credentials, name) {
|
|
210
|
+
const property = this.#credentialFields[name];
|
|
211
|
+
if (!property) return "";
|
|
212
|
+
const value = credentials[property];
|
|
213
|
+
return value instanceof SecretString ? value.reveal() : typeof value === "string" ? value : "";
|
|
214
|
+
}
|
|
215
|
+
#isSecret(method, name) {
|
|
216
|
+
return manifestList(method.fields).map(manifestObject).some((field) => field.name === name && field.type === "secretString");
|
|
217
|
+
}
|
|
218
|
+
#isRequired(method, name) {
|
|
219
|
+
const field = manifestList(method.fields).map(manifestObject).find((candidate) => candidate.name === name);
|
|
220
|
+
return field ? field.required === true : true;
|
|
221
|
+
}
|
|
222
|
+
#validateGrant(grant) {
|
|
223
|
+
for (const mapping of grant.mappings) {
|
|
224
|
+
if (!manifestText(mapping.source) || !this.#credentialFields[manifestText(mapping.credential)])
|
|
225
|
+
throw new TypeError("manifest credential field is not mapped");
|
|
226
|
+
}
|
|
227
|
+
for (const copy of grant.copies) {
|
|
228
|
+
if (!this.#credentialFields[manifestText(copy.credential)] || !this.#credentialFields[manifestText(copy.fromCredential)])
|
|
229
|
+
throw new TypeError("manifest credential field is not mapped");
|
|
230
|
+
}
|
|
231
|
+
parseDurationMs(grant.missingExpiry);
|
|
232
|
+
if (grant.kind === "jwt_bearer") parseDurationMs(manifestText(grant.assertion.lifetime));
|
|
233
|
+
}
|
|
234
|
+
#scopes(source) {
|
|
235
|
+
if (Array.isArray(source)) return source.filter((value) => typeof value === "string");
|
|
236
|
+
const fromSetting = manifestObject(source).fromSetting;
|
|
237
|
+
return typeof fromSetting === "string" ? (this.#settings[fromSetting] ?? "").split(/\s+/).filter(Boolean) : [];
|
|
238
|
+
}
|
|
239
|
+
#resolveSource(source, credentials, key) {
|
|
240
|
+
if (typeof source === "string") return source;
|
|
241
|
+
const valueSource = manifestObject(source);
|
|
242
|
+
if (typeof valueSource.value === "string") return valueSource.value;
|
|
243
|
+
if (typeof valueSource.template === "string") return valueSource.template.replace(/\{([^{}]+)\}/g, (_, name) => pathEscape(this.#credentialFields[name] ? this.#credentialValue(credentials, name) : this.#settings[name] ?? ""));
|
|
244
|
+
let value = "";
|
|
245
|
+
if (typeof valueSource.fromCredential === "string") value = this.#credentialValue(credentials, valueSource.fromCredential);
|
|
246
|
+
else if (typeof valueSource.fromSetting === "string") value = this.#settings[valueSource.fromSetting] ?? "";
|
|
247
|
+
else if (typeof valueSource.fromKey === "string") value = manifestText(key[valueSource.fromKey]);
|
|
248
|
+
else throw new ReauthorizationRequiredError();
|
|
249
|
+
if (valueSource.values) {
|
|
250
|
+
const translated = manifestObject(valueSource.values)[value];
|
|
251
|
+
if (typeof translated !== "string") throw new ReauthorizationRequiredError();
|
|
252
|
+
return translated;
|
|
253
|
+
}
|
|
254
|
+
if (!value) throw new ReauthorizationRequiredError();
|
|
255
|
+
return value;
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
function manifestObject(value) {
|
|
259
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
260
|
+
}
|
|
261
|
+
function manifestList(value) {
|
|
262
|
+
return Array.isArray(value) ? value : [];
|
|
263
|
+
}
|
|
264
|
+
function manifestText(value) {
|
|
265
|
+
return typeof value === "string" ? value : "";
|
|
266
|
+
}
|
|
267
|
+
function strings(value, fallback) {
|
|
268
|
+
const found = manifestList(value).filter((item) => typeof item === "string");
|
|
269
|
+
return found.length ? found : fallback;
|
|
270
|
+
}
|
|
271
|
+
function stringRecord(value) {
|
|
272
|
+
return Object.fromEntries(Object.entries(manifestObject(value)).filter((entry) => typeof entry[1] === "string"));
|
|
273
|
+
}
|
|
274
|
+
function missingExpiryLifetime(value) {
|
|
275
|
+
return manifestText(manifestObject(value).lifetime);
|
|
276
|
+
}
|
|
277
|
+
function pathEscape(value) {
|
|
278
|
+
return encodeURIComponent(value).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%(?:2B|26|3D|3A|40|24)/g, (escaped) => ({ "%2B": "+", "%26": "&", "%3D": "=", "%3A": ":", "%40": "@", "%24": "$" })[escaped] ?? escaped);
|
|
279
|
+
}
|
|
280
|
+
function hasExactScopes(returnedScopes, requiredScopes) {
|
|
281
|
+
const granted = new Set(returnedScopes.split(/[\s,]+/).filter(Boolean));
|
|
282
|
+
const required = new Set(requiredScopes);
|
|
283
|
+
return granted.size === required.size && [...required].every((scope) => granted.has(scope));
|
|
284
|
+
}
|
|
285
|
+
function parseDurationMs(value) {
|
|
286
|
+
if (!value) return 0;
|
|
287
|
+
const parts = value.matchAll(/(\d+(?:\.\d+)?)(ns|us|µs|μs|ms|s|m|h)/g);
|
|
288
|
+
const milliseconds = {
|
|
289
|
+
ns: 1e-6,
|
|
290
|
+
us: 1e-3,
|
|
291
|
+
"\xB5s": 1e-3,
|
|
292
|
+
"\u03BCs": 1e-3,
|
|
293
|
+
ms: 1,
|
|
294
|
+
s: 1e3,
|
|
295
|
+
m: 6e4,
|
|
296
|
+
h: 36e5
|
|
297
|
+
};
|
|
298
|
+
let duration = 0;
|
|
299
|
+
let position = 0;
|
|
300
|
+
for (const part of parts) {
|
|
301
|
+
if (part.index !== position) throw new TypeError("manifest grant duration is invalid");
|
|
302
|
+
duration += Number(part[1]) * milliseconds[part[2]];
|
|
303
|
+
position += part[0].length;
|
|
304
|
+
}
|
|
305
|
+
if (position !== value.length || duration <= 0 || !Number.isFinite(duration) || duration > Number.MAX_SAFE_INTEGER)
|
|
306
|
+
throw new TypeError("manifest grant duration is invalid");
|
|
307
|
+
return duration;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/oauthtoken/index.ts
|
|
10
311
|
var RefreshSkewMs = 3e5;
|
|
11
312
|
var TokenResponse = class {
|
|
313
|
+
#mappedCredentialFields;
|
|
12
314
|
/** Replacement access token. */
|
|
13
315
|
accessToken;
|
|
14
316
|
/** Rotated refresh token, empty when the provider retained it. */
|
|
@@ -32,11 +334,16 @@ var TokenResponse = class {
|
|
|
32
334
|
this.scope = fields.scope;
|
|
33
335
|
this.tokenType = fields.tokenType;
|
|
34
336
|
this.retainedFields = fields.retainedFields;
|
|
337
|
+
this.#mappedCredentialFields = fields.mappedCredentialFields ?? {};
|
|
35
338
|
}
|
|
36
339
|
/** Keep the previous refresh token when no rotated value was returned. */
|
|
37
340
|
nextRefreshToken(prior) {
|
|
38
341
|
return this.refreshToken.reveal() ? this.refreshToken : prior;
|
|
39
342
|
}
|
|
343
|
+
/** Reveal only one declared credential mapping at the provider boundary. */
|
|
344
|
+
mappedCredentialValue(path) {
|
|
345
|
+
return this.#mappedCredentialFields[path]?.reveal();
|
|
346
|
+
}
|
|
40
347
|
};
|
|
41
348
|
var TokenEndpoint = class {
|
|
42
349
|
#options;
|
|
@@ -136,13 +443,26 @@ var TokenEndpoint = class {
|
|
|
136
443
|
if (typeof accessToken !== "string" || !accessToken || !hasAcceptedExpiry || !hasAcceptedType) throw new Error(`${options.providerName} token response omitted required fields`);
|
|
137
444
|
const retainedFields = {};
|
|
138
445
|
for (const field of options.retainedResponseFields ?? []) if (Object.hasOwn(decoded, field)) retainedFields[field] = decoded[field];
|
|
446
|
+
const mappedCredentialFields = {};
|
|
447
|
+
for (const path of options.credentialMappingPaths ?? []) {
|
|
448
|
+
const value = responsePathValue(decoded, path);
|
|
449
|
+
if (value !== void 0) mappedCredentialFields[path] = new SecretString(value);
|
|
450
|
+
}
|
|
139
451
|
const refreshToken = typeof decoded.refresh_token === "string" ? decoded.refresh_token : "";
|
|
140
452
|
const refreshTokenExpiry = typeof decoded.refresh_token_expires_in === "number" && decoded.refresh_token_expires_in > 0 ? decoded.refresh_token_expires_in : 0;
|
|
141
|
-
return new TokenResponse({ accessToken: new SecretString(accessToken), refreshToken: new SecretString(refreshToken), expiresInMs: (expiresIn ?? 0) * 1e3, refreshTokenExpiresInMs: refreshTokenExpiry * 1e3, scope: typeof decoded.scope === "string" ? decoded.scope : "", tokenType: typeof tokenType === "string" ? tokenType : "", retainedFields });
|
|
453
|
+
return new TokenResponse({ accessToken: new SecretString(accessToken), refreshToken: new SecretString(refreshToken), expiresInMs: (expiresIn ?? 0) * 1e3, refreshTokenExpiresInMs: refreshTokenExpiry * 1e3, scope: typeof decoded.scope === "string" ? decoded.scope : "", tokenType: typeof tokenType === "string" ? tokenType : "", retainedFields, mappedCredentialFields });
|
|
142
454
|
}
|
|
143
455
|
};
|
|
144
456
|
var grantParameters = /* @__PURE__ */ new Set(["grant_type", "refresh_token", "client_id", "client_secret", "assertion", "client_assertion", "client_assertion_type"]);
|
|
145
457
|
var standardResponseFields = /* @__PURE__ */ new Set(["access_token", "refresh_token", "expires_in", "refresh_token_expires_in", "scope", "token_type", "error", "error_description", "error_uri", "id_token"]);
|
|
458
|
+
function responsePathValue(response, path) {
|
|
459
|
+
let value = response;
|
|
460
|
+
for (const member of path.split(".")) {
|
|
461
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !Object.hasOwn(value, member)) return void 0;
|
|
462
|
+
value = value[member];
|
|
463
|
+
}
|
|
464
|
+
return typeof value === "string" ? value : void 0;
|
|
465
|
+
}
|
|
146
466
|
function validateEndpointURL(value, allowsPlainHTTP, providerName) {
|
|
147
467
|
let parsed;
|
|
148
468
|
try {
|
|
@@ -194,7 +514,7 @@ function hasAllScopes(returnedScope, requiredScopes) {
|
|
|
194
514
|
const granted = new Set(returnedScope.split(/[ ,]+/).filter(Boolean));
|
|
195
515
|
return requiredScopes.every((scope) => granted.has(scope));
|
|
196
516
|
}
|
|
197
|
-
function
|
|
517
|
+
function hasExactScopes2(returnedScope, requiredScopes) {
|
|
198
518
|
const granted = new Set(returnedScope.split(/[ ,]+/).filter(Boolean));
|
|
199
519
|
return granted.size === new Set(requiredScopes).size && hasAllScopes(returnedScope, requiredScopes);
|
|
200
520
|
}
|
|
@@ -222,12 +542,13 @@ function signJWTBearerAssertion(assertion, privateKey) {
|
|
|
222
542
|
return new SecretString(`${unsigned}.${signature}`);
|
|
223
543
|
}
|
|
224
544
|
export {
|
|
545
|
+
ManifestCredentialRefreshDriver,
|
|
225
546
|
RefreshSkewMs,
|
|
226
547
|
TokenEndpoint,
|
|
227
548
|
TokenResponse,
|
|
228
549
|
forcedRefreshFloorMs,
|
|
229
550
|
hasAllScopes,
|
|
230
|
-
hasExactScopes,
|
|
551
|
+
hasExactScopes2 as hasExactScopes,
|
|
231
552
|
isRefreshRequired,
|
|
232
553
|
isRefreshRequiredWithIssueTime,
|
|
233
554
|
parseRSAPrivateKeyPEM,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as Call } from './credentials-JqG97kJ5.js';
|
|
2
|
+
import { O as OperationRef, e as BranchDefinition, J as RetryPolicy, M as MutationAttempt, Q as QueryAttempt } from './types-D6De3sry.js';
|
|
2
3
|
|
|
3
4
|
/** Execute options owned by one operation; durations are milliseconds. */
|
|
4
5
|
interface StepDefaults {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { inspect } from 'node:util';
|
|
3
3
|
import { S3Client } from '@aws-sdk/client-s3';
|
|
4
|
-
import {
|
|
4
|
+
import { c as CredentialProvider$1, C as Call, R as RefreshingCredentialProvider$1, h as RejectedCredentialRefreshingProvider, d as CredentialRefreshDriver } from '../credentials-JqG97kJ5.js';
|
|
5
|
+
import '../types-D6De3sry.js';
|
|
5
6
|
import '@superdurable/dex';
|
|
6
7
|
|
|
7
8
|
/** Current secret-free project configuration schema shared with Dex Web. */
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OperationRefSchema
|
|
3
|
+
} from "../chunk-BQGYGCOQ.js";
|
|
1
4
|
import {
|
|
2
5
|
BodyTooLargeError,
|
|
3
6
|
isLocalStorageHost,
|
|
4
7
|
isPrivateBrokerHost,
|
|
5
8
|
readBoundedBody
|
|
6
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-BG65RPGH.js";
|
|
7
10
|
import {
|
|
8
|
-
OperationRefSchema,
|
|
9
11
|
ReauthorizationRequiredError
|
|
10
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-IHG6ADQG.js";
|
|
11
13
|
|
|
12
14
|
// src/projectconfig/model.ts
|
|
13
15
|
import { z } from "zod";
|
|
@@ -19,11 +19,24 @@ declare class AddressRefusal extends Error {
|
|
|
19
19
|
/** Sanitized transport failure with positive evidence about dispatch. */
|
|
20
20
|
declare class ProviderTransportError extends Error {
|
|
21
21
|
readonly isProvablyNotSent: boolean;
|
|
22
|
-
/** True only when
|
|
22
|
+
/** True only when the request failed before a usable connection could send HTTP bytes. */
|
|
23
23
|
constructor(isProvablyNotSent: boolean);
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/** Provider emitted no response byte within the configured stall timeout. */
|
|
26
|
+
declare class ProviderStalledError extends Error {
|
|
27
|
+
/** Construct a sanitized no-byte timeout failure. */
|
|
28
|
+
constructor();
|
|
29
|
+
}
|
|
30
|
+
/** Public HTTPS, owned private HTTP, or caller-owned unrestricted transport. */
|
|
31
|
+
type AddressPolicy = 'publicHTTPS' | 'privateNetworkHTTP' | 'unrestricted';
|
|
32
|
+
/** Caller-owned transport for a provider exchange; implementations must not replay redirects.
|
|
33
|
+
* A client may return a complete body without calling onResponseChunk. If it calls the callback,
|
|
34
|
+
* it must feed every received chunk in order before returning and honor false by stopping the response.
|
|
35
|
+
*/
|
|
36
|
+
interface ProviderHTTPClient {
|
|
37
|
+
/** Send one request and return its bounded response. */
|
|
38
|
+
send(request: ProviderRequest): Promise<ProviderResponse>;
|
|
39
|
+
}
|
|
27
40
|
/** One bounded provider request; response bodies and URL values never enter errors. */
|
|
28
41
|
interface ProviderRequest {
|
|
29
42
|
/** Absolute provider URL. */ url: string;
|
|
@@ -31,9 +44,13 @@ interface ProviderRequest {
|
|
|
31
44
|
/** Request headers, including provider credentials when needed. */ headers?: Record<string, string>;
|
|
32
45
|
/** Caller-encoded request body. */ body?: Uint8Array;
|
|
33
46
|
/** Maximum response body size in bytes. */ maxResponseBytes: number;
|
|
47
|
+
/** Optional separate prefix limit for non-2xx error bodies. */ maxErrorResponseBytes?: number;
|
|
48
|
+
/** Classify a non-2xx status even when its diagnostic body fails to read. */ ignoreErrorBodyReadFailure?: boolean;
|
|
34
49
|
/** Network policy checked against all resolved addresses. */ addressPolicy: AddressPolicy;
|
|
35
50
|
/** Request deadline in milliseconds. */ timeoutMs?: number;
|
|
36
51
|
/** Caller cancellation. */ signal?: AbortSignal;
|
|
52
|
+
/** Observe chunks in arrival order; returning false stops a completed event stream. */ onResponseChunk?: (chunk: Uint8Array, status: number, headers: http.IncomingHttpHeaders) => boolean | void;
|
|
53
|
+
/** Abort a response when no byte arrives for this many milliseconds. */ stallTimeoutMs?: number;
|
|
37
54
|
}
|
|
38
55
|
/** Bounded response; redirects remain visible as 3xx responses. */
|
|
39
56
|
interface ProviderResponse {
|
|
@@ -54,4 +71,4 @@ declare function readErrorTokens(body: Uint8Array, pointers: readonly string[]):
|
|
|
54
71
|
/** Send once using pinned, policy-checked DNS results and no redirect replay. */
|
|
55
72
|
declare function sendProviderRequest(request: ProviderRequest): Promise<ProviderResponse>;
|
|
56
73
|
|
|
57
|
-
export { type AddressPolicy, AddressRefusal, BodyTooLargeError, MaxErrorBodyBytes, MaxRetryAfterDelayMs, type ProviderRequest, type ProviderResponse, ProviderTransportError, isHeaderSafeCredential, parseRetryAfter, readBoundedBody, readErrorTokens, sendProviderRequest, validateBaseURL };
|
|
74
|
+
export { type AddressPolicy, AddressRefusal, BodyTooLargeError, MaxErrorBodyBytes, MaxRetryAfterDelayMs, type ProviderHTTPClient, type ProviderRequest, type ProviderResponse, ProviderStalledError, ProviderTransportError, isHeaderSafeCredential, parseRetryAfter, readBoundedBody, readErrorTokens, sendProviderRequest, validateBaseURL };
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
BodyTooLargeError,
|
|
4
4
|
MaxErrorBodyBytes,
|
|
5
5
|
MaxRetryAfterDelayMs,
|
|
6
|
+
ProviderStalledError,
|
|
6
7
|
ProviderTransportError,
|
|
7
8
|
isHeaderSafeCredential,
|
|
8
9
|
parseRetryAfter,
|
|
@@ -10,12 +11,13 @@ import {
|
|
|
10
11
|
readErrorTokens,
|
|
11
12
|
sendProviderRequest,
|
|
12
13
|
validateBaseURL
|
|
13
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-BG65RPGH.js";
|
|
14
15
|
export {
|
|
15
16
|
AddressRefusal,
|
|
16
17
|
BodyTooLargeError,
|
|
17
18
|
MaxErrorBodyBytes,
|
|
18
19
|
MaxRetryAfterDelayMs,
|
|
20
|
+
ProviderStalledError,
|
|
19
21
|
ProviderTransportError,
|
|
20
22
|
isHeaderSafeCredential,
|
|
21
23
|
parseRetryAfter,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { C as Call, S as SecretString } from './credentials-JqG97kJ5.js';
|
|
2
|
+
import { ProviderHTTPClient } from './providerhttp/index.js';
|
|
3
|
+
import { Q as QueryAttempt } from './types-D6De3sry.js';
|
|
4
|
+
import { b as Query, Q as QueryDefinition } from './operation-CASLOg86.js';
|
|
5
|
+
import { T as TextGenerationRequest, q as TextGenerationResponse, W as WireFormat } from './wire_format-stEVruMs.js';
|
|
6
|
+
|
|
7
|
+
/** Configuration for one generateText Query; durations are milliseconds. */
|
|
8
|
+
interface TextGenerationQueryConfig {
|
|
9
|
+
/** Generated connector operation definition and sync Step defaults. */ definition: QueryDefinition;
|
|
10
|
+
/** Provider-specific adapter. */ wireFormat: WireFormat;
|
|
11
|
+
/** Validated provider base URL. */ baseURL: string;
|
|
12
|
+
/** Default model; blank requires a request model. */ connectionModel?: string;
|
|
13
|
+
/** HTTP exchange deadline. */ requestTimeoutMs: number;
|
|
14
|
+
/** Optional caller-owned HTTP transport, as with Go's HTTPClient. It must not replay redirects. */ httpClient?: ProviderHTTPClient;
|
|
15
|
+
/** Resolve private credential once per validated attempt. */ resolveCredential: (call: Call) => string | SecretString | Promise<string | SecretString>;
|
|
16
|
+
/** Maximum complete body or event stream bytes. */ maxResponseBytes: number;
|
|
17
|
+
/** Maximum one SSE event bytes; required for streaming. */ maxStreamEventBytes?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Shared provider-neutral text generation Query; concurrent invocations own isolated state.
|
|
20
|
+
*
|
|
21
|
+
* Each invocation resolves the model, validates portable fields in order, applies model rules,
|
|
22
|
+
* resolves one credential, encodes the request, dispatches once, and classifies the response.
|
|
23
|
+
* Validation or configuration failure in the first five stages selects defect with zero requests.
|
|
24
|
+
* A silent request records a nil Dex heartbeat every five seconds, clearing a caller checkpoint.
|
|
25
|
+
* Stream text can include retried, blocked, or invalid attempts; only the final Result is authoritative.
|
|
26
|
+
* Sync Execute durability prevents a long local attempt from dispatching the billed call again.
|
|
27
|
+
* Structured numbers are bounded to 256 literal characters and exponent magnitude 400.
|
|
28
|
+
*/
|
|
29
|
+
declare class TextGenerationQuery implements Query<TextGenerationRequest, TextGenerationResponse> {
|
|
30
|
+
#private;
|
|
31
|
+
/** Validate configuration before a provider request can be made. */
|
|
32
|
+
constructor(config: TextGenerationQueryConfig);
|
|
33
|
+
/** Return the connector's generateText definition. */ definition(): QueryDefinition;
|
|
34
|
+
/** Return optional request features declared by the provider. */ requestFeatures(): Readonly<WireFormat['features']>;
|
|
35
|
+
/** Return the provider model ID rule. */ modelIDRule(): WireFormat['modelIDRule'];
|
|
36
|
+
/** Validate in fixed order, dispatch once, and classify a branch or safe retry without exposing secrets. */
|
|
37
|
+
invoke(call: Call, request: TextGenerationRequest): Promise<QueryAttempt<TextGenerationResponse>>;
|
|
38
|
+
}
|
|
39
|
+
/** Construct a generateText Query, rejecting invalid definitions, wire formats, models, timeouts, and size limits before dispatch. */
|
|
40
|
+
declare function newTextGenerationQuery(config: TextGenerationQueryConfig): TextGenerationQuery;
|
|
41
|
+
|
|
42
|
+
export { TextGenerationQuery as T, type TextGenerationQueryConfig as a, newTextGenerationQuery as n };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { C as
|
|
2
|
+
import { C as CallID } from '../types-D6De3sry.js';
|
|
3
|
+
import { C as Call } from '../credentials-JqG97kJ5.js';
|
|
3
4
|
import '@superdurable/dex';
|
|
4
5
|
|
|
5
6
|
/** The current attempt has no permission to send another provider write. */
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { T as TextGenerationRequest } from '../wire_format-stEVruMs.js';
|
|
2
|
+
export { B as BlockedBranchID, C as CredentialHeader, D as DecodedResponse, a as DefectBranchID, E as EncodeRequestInput, b as EncodedRequest, c as ErrorOutcome, d as ErrorRule, F as FinishReason, G as GeneratedBranchID, I as InvalidResponseBranchID, M as Message, e as MessageRole, f as ModelIDRule, g as ModelRequestRules, P as ProviderRejectedBranchID, h as ProviderReportedError, R as ReasoningEffort, i as RequestFeatures, j as ResponsePart, S as ServerSentEvent, k as StreamDecodeState, l as StructuredOutput, m as StructuredOutputMode, n as StructuredOutputRules, o as TemperaturePolicy, p as TextGenerationOperationID, q as TextGenerationResponse, r as TruncatedBranchID, U as Usage, W as WireFormat, s as blockedOutcome, t as classifyError, u as invalidResponseOutcome, v as providerRejectedOutcome, w as quotaExhaustedOutcome, x as resolveModel, y as retryOutcome, z as temperatureAccepted, A as temperatureNotAccepted, H as temperatureRange, J as textGenerationBranchDefinitions, K as validateModelID, L as validatePortableRequest, N as validateStructuredOutputRules, O as validateWireFormat } from '../wire_format-stEVruMs.js';
|
|
3
|
+
export { T as TextGenerationQuery, a as TextGenerationQueryConfig, n as newTextGenerationQuery } from '../query-CeUaW9xU.js';
|
|
4
|
+
import '../types-D6De3sry.js';
|
|
5
|
+
import 'zod';
|
|
6
|
+
import '../credentials-JqG97kJ5.js';
|
|
7
|
+
import '@superdurable/dex';
|
|
8
|
+
import '../providerhttp/index.js';
|
|
9
|
+
import 'node:http';
|
|
10
|
+
import '../operation-CASLOg86.js';
|
|
11
|
+
|
|
12
|
+
/** Remove whitespace and one JSON Markdown fence, then validate the original schema. */
|
|
13
|
+
declare function extractStructuredAnswer(request: TextGenerationRequest, generatedText: string): string;
|
|
14
|
+
|
|
15
|
+
export { TextGenerationRequest, extractStructuredAnswer };
|