teak-sdk 1.0.80 → 1.0.82
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
CHANGED
|
@@ -14,7 +14,10 @@ const client = createTeakClient({
|
|
|
14
14
|
});
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Use the discovered endpoints and client ID for your OAuth surface.
|
|
17
|
+
Use the discovered endpoints and client ID for your OAuth surface. The WorkOS
|
|
18
|
+
Connect helpers (`createPkceChallenge`, `createConnectAuthorizeUrl`,
|
|
19
|
+
`requestConnectTokens`, `fetchConnectOwnerId`, `disconnectConnectGrant`) cover
|
|
20
|
+
PKCE sign-in, refresh, account binding and disconnect. Refresh
|
|
18
21
|
discovery after sign-in or refresh failures. Keep tokens in your platform's secure
|
|
19
22
|
storage; this package does not store credentials or open a browser.
|
|
20
23
|
|
package/dist/sdk.js
CHANGED
|
@@ -143,7 +143,7 @@ function discoverAuthServer(siteUrl, options = {}) {
|
|
|
143
143
|
if (metadata.issuer !== servers[0]) {
|
|
144
144
|
throw new Error("OAuth issuer mismatch");
|
|
145
145
|
}
|
|
146
|
-
if (clientDocument.primary !== "
|
|
146
|
+
if (clientDocument.primary !== "workos") {
|
|
147
147
|
throw new Error("Unknown OAuth provider");
|
|
148
148
|
}
|
|
149
149
|
if (!(Array.isArray(metadata.code_challenge_methods_supported) && metadata.code_challenge_methods_supported.includes("S256"))) {
|
|
@@ -155,18 +155,14 @@ function discoverAuthServer(siteUrl, options = {}) {
|
|
|
155
155
|
throw new Error("Missing OAuth client registration");
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
|
|
159
|
-
if (resource.resource !== expectedResource) {
|
|
158
|
+
if (resource.resource !== WORKOS_RESOURCES.mcp) {
|
|
160
159
|
throw new Error("OAuth resource mismatch");
|
|
161
160
|
}
|
|
162
161
|
return Object.freeze({
|
|
163
|
-
primary:
|
|
162
|
+
primary: "workos",
|
|
164
163
|
issuer: servers[0],
|
|
165
164
|
authorizationEndpoint: validateUrl(metadata.authorization_endpoint).href,
|
|
166
165
|
tokenEndpoint: validateUrl(metadata.token_endpoint).href,
|
|
167
|
-
...metadata.revocation_endpoint === undefined ? {} : {
|
|
168
|
-
revocationEndpoint: validateUrl(metadata.revocation_endpoint).href
|
|
169
|
-
},
|
|
170
166
|
resource: resource.resource,
|
|
171
167
|
clients: Object.freeze(Object.fromEntries(OAUTH_SURFACES.map((surface) => [surface, clients[surface]])))
|
|
172
168
|
});
|
|
@@ -183,6 +179,125 @@ function discoverAuthServer(siteUrl, options = {}) {
|
|
|
183
179
|
});
|
|
184
180
|
return pending;
|
|
185
181
|
}
|
|
182
|
+
// ../convex/client/workosConnect.ts
|
|
183
|
+
var WORKOS_CONNECT_SCOPE = "openid profile email offline_access";
|
|
184
|
+
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
185
|
+
var MAX_TOKEN_LIFETIME_SECONDS = 365 * 24 * 3600;
|
|
186
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
187
|
+
var base64Url = (bytes) => {
|
|
188
|
+
let binary = "";
|
|
189
|
+
for (const byte of bytes) {
|
|
190
|
+
binary += String.fromCharCode(byte);
|
|
191
|
+
}
|
|
192
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
|
|
193
|
+
};
|
|
194
|
+
var randomBase64Url = (byteLength) => base64Url(crypto.getRandomValues(new Uint8Array(byteLength)));
|
|
195
|
+
var createPkceChallenge = async (verifier) => base64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier))));
|
|
196
|
+
var apiResource = (auth) => new URL("/api", auth.resource).href;
|
|
197
|
+
var createConnectAuthorizeUrl = (auth, params) => {
|
|
198
|
+
const url = new URL(auth.authorizationEndpoint);
|
|
199
|
+
url.searchParams.set("response_type", "code");
|
|
200
|
+
url.searchParams.set("client_id", params.clientId);
|
|
201
|
+
url.searchParams.set("resource", apiResource(auth));
|
|
202
|
+
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
203
|
+
url.searchParams.set("code_challenge", params.codeChallenge);
|
|
204
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
205
|
+
url.searchParams.set("scope", WORKOS_CONNECT_SCOPE);
|
|
206
|
+
url.searchParams.set("state", params.state);
|
|
207
|
+
return url;
|
|
208
|
+
};
|
|
209
|
+
var send = (url, init, local) => fetch(validateOAuthUrl(url, local).href, {
|
|
210
|
+
...init,
|
|
211
|
+
credentials: "omit",
|
|
212
|
+
redirect: "error",
|
|
213
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
214
|
+
});
|
|
215
|
+
var readObject = async (response) => {
|
|
216
|
+
const text = await readResponseTextWithinLimit(response, MAX_RESPONSE_BYTES);
|
|
217
|
+
if (text === null) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const value = JSON.parse(text);
|
|
222
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
223
|
+
} catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var requestConnectTokens = async (auth, options) => {
|
|
228
|
+
const response = await send(auth.tokenEndpoint, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
231
|
+
body: new URLSearchParams({
|
|
232
|
+
...options.grant,
|
|
233
|
+
client_id: options.clientId,
|
|
234
|
+
resource: apiResource(auth)
|
|
235
|
+
})
|
|
236
|
+
}, options.local ?? false);
|
|
237
|
+
const payload = await readObject(response);
|
|
238
|
+
const { status } = response;
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
if (status !== 400 && status !== 401) {
|
|
241
|
+
return { ok: false, reason: "failed", status };
|
|
242
|
+
}
|
|
243
|
+
const refreshTokenRejected = options.grant.grant_type === "refresh_token" && (payload?.error === "invalid_grant" || payload?.error === "invalid_refresh_token" || payload?.code === "invalid_refresh_token");
|
|
244
|
+
if (refreshTokenRejected) {
|
|
245
|
+
return { ok: false, reason: "refresh_token_rejected", status };
|
|
246
|
+
}
|
|
247
|
+
const clientRejected = payload?.error === "invalid_client" || payload?.error === "unauthorized_client";
|
|
248
|
+
return {
|
|
249
|
+
ok: false,
|
|
250
|
+
reason: clientRejected ? "client_rejected" : "rejected",
|
|
251
|
+
status
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const expiresIn = payload?.expires_in;
|
|
255
|
+
const keepsRefreshToken = options.grant.grant_type === "refresh_token" && payload !== null && !("refresh_token" in payload);
|
|
256
|
+
const refreshToken = keepsRefreshToken ? options.grant.refresh_token : payload?.refresh_token;
|
|
257
|
+
if (typeof payload?.access_token !== "string" || !payload.access_token || typeof refreshToken !== "string" || !refreshToken || typeof expiresIn !== "number" || !Number.isSafeInteger(expiresIn) || expiresIn <= 0 || expiresIn > MAX_TOKEN_LIFETIME_SECONDS) {
|
|
258
|
+
return { ok: false, reason: "invalid_response", status };
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
ok: true,
|
|
262
|
+
tokens: {
|
|
263
|
+
accessToken: payload.access_token,
|
|
264
|
+
refreshToken,
|
|
265
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
266
|
+
expiresIn
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
var apiEndpoint = (apiUrl, path, local) => {
|
|
271
|
+
let base = validateOAuthUrl(apiUrl, local).href;
|
|
272
|
+
while (base.endsWith("/")) {
|
|
273
|
+
base = base.slice(0, -1);
|
|
274
|
+
}
|
|
275
|
+
return `${base.replace(/\/v1$/, "")}${path}`;
|
|
276
|
+
};
|
|
277
|
+
var disconnectConnectGrant = async (apiUrl, accessToken, options = {}) => {
|
|
278
|
+
const local = options.local ?? false;
|
|
279
|
+
const endpoint = apiEndpoint(apiUrl, "/v1/oauth/disconnect", local);
|
|
280
|
+
const disconnect = (token) => send(endpoint, { method: "POST", headers: { Authorization: `Bearer ${token}` } }, local);
|
|
281
|
+
let response = await disconnect(accessToken);
|
|
282
|
+
if (response.status === 401 && options.refreshAccessToken) {
|
|
283
|
+
const renewed = await options.refreshAccessToken();
|
|
284
|
+
if (renewed === null) {
|
|
285
|
+
return "refresh_rejected";
|
|
286
|
+
}
|
|
287
|
+
response = await disconnect(renewed);
|
|
288
|
+
}
|
|
289
|
+
return response.status === 204 ? "disconnected" : "unconfirmed";
|
|
290
|
+
};
|
|
291
|
+
var fetchConnectOwnerId = async (apiUrl, accessToken, options = {}) => {
|
|
292
|
+
const local = options.local ?? false;
|
|
293
|
+
const response = await send(apiEndpoint(apiUrl, "/v1/me", local), { headers: { Authorization: `Bearer ${accessToken}` } }, local);
|
|
294
|
+
if (!response.ok) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
const data = (await readObject(response))?.data;
|
|
298
|
+
const id = data && typeof data === "object" && "id" in data ? data.id : undefined;
|
|
299
|
+
return typeof id === "string" && id ? id : null;
|
|
300
|
+
};
|
|
186
301
|
// ../convex/shared/markdown.ts
|
|
187
302
|
var MARKDOWN_CONTENT_MAX_BYTES = 512 * 1024;
|
|
188
303
|
|
|
@@ -986,13 +1101,20 @@ export {
|
|
|
986
1101
|
CARD_TYPES2 as CARD_TYPES,
|
|
987
1102
|
ERROR_CODES,
|
|
988
1103
|
TeakApiError,
|
|
1104
|
+
WORKOS_CONNECT_SCOPE,
|
|
989
1105
|
buildCardsSearchParams,
|
|
1106
|
+
createConnectAuthorizeUrl,
|
|
1107
|
+
createPkceChallenge,
|
|
990
1108
|
createTeakClient,
|
|
1109
|
+
disconnectConnectGrant,
|
|
991
1110
|
discoverAuthServer,
|
|
1111
|
+
fetchConnectOwnerId,
|
|
992
1112
|
isCardType,
|
|
993
1113
|
isStringList,
|
|
994
1114
|
normalizeLimit,
|
|
995
1115
|
parseTags,
|
|
1116
|
+
randomBase64Url,
|
|
1117
|
+
requestConnectTokens,
|
|
996
1118
|
staticTokenProvider,
|
|
997
1119
|
validateOAuthUrl
|
|
998
1120
|
};
|
|
@@ -4,9 +4,8 @@ export interface AuthDiscovery {
|
|
|
4
4
|
readonly authorizationEndpoint: string;
|
|
5
5
|
readonly clients: Readonly<Record<OAuthSurface, string>>;
|
|
6
6
|
readonly issuer: string;
|
|
7
|
-
readonly primary: "
|
|
7
|
+
readonly primary: "workos";
|
|
8
8
|
readonly resource: string;
|
|
9
|
-
readonly revocationEndpoint?: string;
|
|
10
9
|
readonly tokenEndpoint: string;
|
|
11
10
|
}
|
|
12
11
|
export declare const validateOAuthUrl: (raw: unknown, local?: boolean) => URL;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { type AuthDiscovery, discoverAuthServer, type OAuthSurface, validateOAuthUrl, } from "./authDiscovery.js";
|
|
2
|
+
export { type ConnectTokenResult, type ConnectTokens, createConnectAuthorizeUrl, createPkceChallenge, disconnectConnectGrant, fetchConnectOwnerId, randomBase64Url, requestConnectTokens, WORKOS_CONNECT_SCOPE, } from "./workosConnect.js";
|
|
2
3
|
import { type CardType } from "../shared/constants.js";
|
|
3
4
|
import type { FileKind, FilePreviewFacts } from "../shared/fileFormats.js";
|
|
4
5
|
export type { CardType } from "../shared/constants.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type AuthDiscovery } from "./authDiscovery.js";
|
|
2
|
+
export declare const WORKOS_CONNECT_SCOPE = "openid profile email offline_access";
|
|
3
|
+
export declare const randomBase64Url: (byteLength: number) => string;
|
|
4
|
+
export declare const createPkceChallenge: (verifier: string) => Promise<string>;
|
|
5
|
+
export declare const createConnectAuthorizeUrl: (auth: AuthDiscovery, params: {
|
|
6
|
+
clientId: string;
|
|
7
|
+
codeChallenge: string;
|
|
8
|
+
redirectUri: string;
|
|
9
|
+
state: string;
|
|
10
|
+
}) => URL;
|
|
11
|
+
export interface ConnectTokens {
|
|
12
|
+
accessToken: string;
|
|
13
|
+
expiresAt: number;
|
|
14
|
+
expiresIn: number;
|
|
15
|
+
refreshToken: string;
|
|
16
|
+
}
|
|
17
|
+
export type ConnectTokenResult = {
|
|
18
|
+
ok: true;
|
|
19
|
+
tokens: ConnectTokens;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
reason: "refresh_token_rejected" | "client_rejected" | "rejected" | "failed" | "invalid_response";
|
|
23
|
+
status: number;
|
|
24
|
+
};
|
|
25
|
+
export declare const requestConnectTokens: (auth: AuthDiscovery, options: {
|
|
26
|
+
clientId: string;
|
|
27
|
+
grant: Record<string, string>;
|
|
28
|
+
local?: boolean;
|
|
29
|
+
}) => Promise<ConnectTokenResult>;
|
|
30
|
+
export declare const disconnectConnectGrant: (apiUrl: string, accessToken: string, options?: {
|
|
31
|
+
local?: boolean;
|
|
32
|
+
refreshAccessToken?: () => Promise<string | null>;
|
|
33
|
+
}) => Promise<"disconnected" | "unconfirmed" | "refresh_rejected">;
|
|
34
|
+
export declare const fetchConnectOwnerId: (apiUrl: string, accessToken: string, options?: {
|
|
35
|
+
local?: boolean;
|
|
36
|
+
}) => Promise<string | null>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare const SIGNUPS_PAUSED_MESSAGE = "New sign-ups are paused
|
|
1
|
+
export declare const SIGNUPS_PAUSED_MESSAGE = "New sign-ups are paused right now. Please try again later.";
|
|
2
|
+
export declare const ACCOUNT_CHANGES_PAUSED_MESSAGE = "Account changes are paused right now. Please try again later.";
|
|
2
3
|
export declare const cardTypes: readonly ["text", "link", "image", "video", "audio", "document", "palette", "quote"];
|
|
3
4
|
export type CardType = (typeof cardTypes)[number];
|
|
4
5
|
export declare const VISUAL_STYLE_TAXONOMY: readonly ["abstract", "cinematic", "dark", "illustrative", "minimal", "monochrome", "moody", "pastel", "photographic", "retro", "surreal", "vintage", "vibrant"];
|