@amigo-ai/platform-sdk 0.11.0 → 0.11.2
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/dist/core/device-code.js +60 -11
- package/dist/core/device-code.js.map +1 -1
- package/dist/index.cjs +75 -14
- package/dist/index.cjs.map +3 -3
- package/dist/index.mjs +75 -14
- package/dist/index.mjs.map +3 -3
- package/dist/types/core/device-code.d.ts +2 -0
- package/dist/types/core/device-code.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3115,9 +3115,10 @@ async function requestDeviceCode(baseUrl, params, fetchFn) {
|
|
|
3115
3115
|
}
|
|
3116
3116
|
return await res.json();
|
|
3117
3117
|
}
|
|
3118
|
-
async function pollDeviceCode(baseUrl, deviceCode, scope, fetchFn) {
|
|
3118
|
+
async function pollDeviceCode(baseUrl, deviceCode, scope, workspaceId2, fetchFn) {
|
|
3119
3119
|
const body = new URLSearchParams({ grant_type: "device_code", device_code: deviceCode });
|
|
3120
3120
|
if (scope) body.set("scope", scope);
|
|
3121
|
+
if (workspaceId2) body.set("workspace_id", workspaceId2);
|
|
3121
3122
|
const res = await identityPost(baseUrl, "/token", body, fetchFn);
|
|
3122
3123
|
if (res.status === 300)
|
|
3123
3124
|
return { type: "multi_workspace", data: await res.json() };
|
|
@@ -3193,6 +3194,64 @@ function toAuthResult(token, workspaceIdOverride) {
|
|
|
3193
3194
|
scope: token.scope
|
|
3194
3195
|
};
|
|
3195
3196
|
}
|
|
3197
|
+
async function fetchWorkspaces(baseUrl, accessToken, fetchFn) {
|
|
3198
|
+
for (const path of ["/self/profile", "/self"]) {
|
|
3199
|
+
const res = await fetchFn(`${baseUrl}${path}`, {
|
|
3200
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
3201
|
+
});
|
|
3202
|
+
if (res.ok) {
|
|
3203
|
+
const data = await res.json();
|
|
3204
|
+
return (data.workspaces ?? []).map((ws) => ({
|
|
3205
|
+
workspace_id: ws.workspace_id,
|
|
3206
|
+
role: ws.role,
|
|
3207
|
+
name: ws.name
|
|
3208
|
+
}));
|
|
3209
|
+
}
|
|
3210
|
+
if (res.status !== 404) {
|
|
3211
|
+
throw new AmigoError(`Failed to fetch workspaces (${res.status})`, { statusCode: res.status });
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
return [];
|
|
3215
|
+
}
|
|
3216
|
+
async function resolveWorkspaceFromBootstrap(baseUrl, token, options, fetchFn) {
|
|
3217
|
+
if (!token.refresh_token) {
|
|
3218
|
+
throw new AmigoError("Bootstrap token missing refresh_token", { errorCode: "server_error" });
|
|
3219
|
+
}
|
|
3220
|
+
const workspaces = await fetchWorkspaces(baseUrl, token.access_token, fetchFn);
|
|
3221
|
+
if (workspaces.length === 0) {
|
|
3222
|
+
throw new AmigoError(
|
|
3223
|
+
"No workspace memberships found. Create a workspace or request an invitation.",
|
|
3224
|
+
{ errorCode: "no_workspaces" }
|
|
3225
|
+
);
|
|
3226
|
+
}
|
|
3227
|
+
if (workspaces.length === 1 && workspaces[0]) {
|
|
3228
|
+
const scoped2 = await doRefreshToken(
|
|
3229
|
+
baseUrl,
|
|
3230
|
+
{ refreshToken: token.refresh_token, workspaceId: workspaces[0].workspace_id, scope: options.scope },
|
|
3231
|
+
fetchFn
|
|
3232
|
+
);
|
|
3233
|
+
return toAuthResult(scoped2, workspaces[0].workspace_id);
|
|
3234
|
+
}
|
|
3235
|
+
const workspaceId2 = await options.onWorkspaceRequired(workspaces);
|
|
3236
|
+
const scoped = await doRefreshToken(
|
|
3237
|
+
baseUrl,
|
|
3238
|
+
{ refreshToken: token.refresh_token, workspaceId: workspaceId2, scope: options.scope },
|
|
3239
|
+
fetchFn
|
|
3240
|
+
);
|
|
3241
|
+
return toAuthResult(scoped, workspaceId2);
|
|
3242
|
+
}
|
|
3243
|
+
async function resolveWorkspaceFromMulti(baseUrl, multi, options, fetchFn) {
|
|
3244
|
+
if (!multi.refresh_token) {
|
|
3245
|
+
throw new AmigoError("Multi-workspace response missing refresh_token", { errorCode: "server_error" });
|
|
3246
|
+
}
|
|
3247
|
+
const workspaceId2 = await options.onWorkspaceRequired(multi.workspaces);
|
|
3248
|
+
const scoped = await doRefreshToken(
|
|
3249
|
+
baseUrl,
|
|
3250
|
+
{ refreshToken: multi.refresh_token, workspaceId: workspaceId2, scope: options.scope },
|
|
3251
|
+
fetchFn
|
|
3252
|
+
);
|
|
3253
|
+
return toAuthResult(scoped, workspaceId2);
|
|
3254
|
+
}
|
|
3196
3255
|
async function loginWithDeviceCode(options) {
|
|
3197
3256
|
const baseUrl = (options.identityBaseUrl ?? DEFAULT_IDENTITY_URL).replace(/\/+$/, "");
|
|
3198
3257
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
@@ -3210,7 +3269,7 @@ async function loginWithDeviceCode(options) {
|
|
|
3210
3269
|
if (options.signal?.aborted) throw new LoginCancelledError();
|
|
3211
3270
|
options.onStatus?.("polling");
|
|
3212
3271
|
try {
|
|
3213
|
-
const result = await pollDeviceCode(baseUrl, issuance.device_code, options.scope, fetchFn);
|
|
3272
|
+
const result = await pollDeviceCode(baseUrl, issuance.device_code, options.scope, options.workspaceId, fetchFn);
|
|
3214
3273
|
if (result.type === "pending") {
|
|
3215
3274
|
options.onStatus?.("authorization_pending");
|
|
3216
3275
|
continue;
|
|
@@ -3222,20 +3281,22 @@ async function loginWithDeviceCode(options) {
|
|
|
3222
3281
|
}
|
|
3223
3282
|
options.onStatus?.("approved");
|
|
3224
3283
|
if (result.type === "token") {
|
|
3284
|
+
const claims = decodeJwtPayload(result.data.access_token);
|
|
3285
|
+
const isBootstrap = claims?.workspace_bootstrap || !claims?.workspace_id;
|
|
3286
|
+
if (isBootstrap && result.data.refresh_token) {
|
|
3287
|
+
if (options.workspaceId) {
|
|
3288
|
+
const scoped = await doRefreshToken(
|
|
3289
|
+
baseUrl,
|
|
3290
|
+
{ refreshToken: result.data.refresh_token, workspaceId: options.workspaceId, scope: options.scope },
|
|
3291
|
+
fetchFn
|
|
3292
|
+
);
|
|
3293
|
+
return toAuthResult(scoped, options.workspaceId);
|
|
3294
|
+
}
|
|
3295
|
+
return await resolveWorkspaceFromBootstrap(baseUrl, result.data, options, fetchFn);
|
|
3296
|
+
}
|
|
3225
3297
|
return toAuthResult(result.data);
|
|
3226
3298
|
}
|
|
3227
|
-
|
|
3228
|
-
if (!result.data.refresh_token) {
|
|
3229
|
-
throw new AmigoError("Multi-workspace response missing refresh_token", {
|
|
3230
|
-
errorCode: "server_error"
|
|
3231
|
-
});
|
|
3232
|
-
}
|
|
3233
|
-
const tokenResponse = await doRefreshToken(
|
|
3234
|
-
baseUrl,
|
|
3235
|
-
{ refreshToken: result.data.refresh_token, workspaceId: workspaceId2, scope: options.scope },
|
|
3236
|
-
fetchFn
|
|
3237
|
-
);
|
|
3238
|
-
return toAuthResult(tokenResponse, workspaceId2);
|
|
3299
|
+
return await resolveWorkspaceFromMulti(baseUrl, result.data, options, fetchFn);
|
|
3239
3300
|
} catch (err) {
|
|
3240
3301
|
if (err instanceof AmigoError && err.errorCode === "expired_token") {
|
|
3241
3302
|
options.onStatus?.("expired");
|