@broberg/sso 0.10.0 → 0.11.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 +31 -9
- package/dist/hono.cjs +26 -5
- package/dist/hono.cjs.map +1 -1
- package/dist/hono.d.cts +13 -0
- package/dist/hono.d.ts +13 -0
- package/dist/hono.js +26 -5
- package/dist/hono.js.map +1 -1
- package/package.json +1 -1
package/dist/hono.d.cts
CHANGED
|
@@ -447,6 +447,10 @@ declare function ssoRoutes(options?: SsoRoutesOptions): {
|
|
|
447
447
|
client: SsoClient;
|
|
448
448
|
config: SsoConfig;
|
|
449
449
|
getAccessToken: (c: Context) => Promise<string>;
|
|
450
|
+
refreshSessionProfile: (c: Context, profile: {
|
|
451
|
+
name: string | null;
|
|
452
|
+
picture: string | null;
|
|
453
|
+
}) => Promise<void>;
|
|
450
454
|
};
|
|
451
455
|
/** Why a login transaction could not be read back. Three states, three answers. */
|
|
452
456
|
type TransactionFailure = "absent" | "expired" | "unreadable";
|
|
@@ -456,6 +460,15 @@ declare function getSession(c: Context): SessionPayload | null;
|
|
|
456
460
|
interface AccountRoutesInput {
|
|
457
461
|
client: Pick<SsoClient, "getProfile" | "updateProfile" | "uploadAvatar" | "removeAvatar">;
|
|
458
462
|
getAccessToken(c: Context): Promise<string>;
|
|
463
|
+
/**
|
|
464
|
+
* F095.5 — re-sign the session cookie with the profile BID answered, so the
|
|
465
|
+
* user menu shows the new name and picture on the next page load. ssoRoutes
|
|
466
|
+
* provides it; optional so an older or hand-built input still works.
|
|
467
|
+
*/
|
|
468
|
+
refreshSessionProfile?(c: Context, profile: {
|
|
469
|
+
name: string | null;
|
|
470
|
+
picture: string | null;
|
|
471
|
+
}): Promise<void>;
|
|
459
472
|
}
|
|
460
473
|
/**
|
|
461
474
|
* The signed-in user's own name and picture, for the app's account page.
|
package/dist/hono.d.ts
CHANGED
|
@@ -447,6 +447,10 @@ declare function ssoRoutes(options?: SsoRoutesOptions): {
|
|
|
447
447
|
client: SsoClient;
|
|
448
448
|
config: SsoConfig;
|
|
449
449
|
getAccessToken: (c: Context) => Promise<string>;
|
|
450
|
+
refreshSessionProfile: (c: Context, profile: {
|
|
451
|
+
name: string | null;
|
|
452
|
+
picture: string | null;
|
|
453
|
+
}) => Promise<void>;
|
|
450
454
|
};
|
|
451
455
|
/** Why a login transaction could not be read back. Three states, three answers. */
|
|
452
456
|
type TransactionFailure = "absent" | "expired" | "unreadable";
|
|
@@ -456,6 +460,15 @@ declare function getSession(c: Context): SessionPayload | null;
|
|
|
456
460
|
interface AccountRoutesInput {
|
|
457
461
|
client: Pick<SsoClient, "getProfile" | "updateProfile" | "uploadAvatar" | "removeAvatar">;
|
|
458
462
|
getAccessToken(c: Context): Promise<string>;
|
|
463
|
+
/**
|
|
464
|
+
* F095.5 — re-sign the session cookie with the profile BID answered, so the
|
|
465
|
+
* user menu shows the new name and picture on the next page load. ssoRoutes
|
|
466
|
+
* provides it; optional so an older or hand-built input still works.
|
|
467
|
+
*/
|
|
468
|
+
refreshSessionProfile?(c: Context, profile: {
|
|
469
|
+
name: string | null;
|
|
470
|
+
picture: string | null;
|
|
471
|
+
}): Promise<void>;
|
|
459
472
|
}
|
|
460
473
|
/**
|
|
461
474
|
* The signed-in user's own name and picture, for the app's account page.
|
package/dist/hono.js
CHANGED
|
@@ -1046,7 +1046,24 @@ function ssoRoutes(options = {}) {
|
|
|
1046
1046
|
refreshing.delete(sid);
|
|
1047
1047
|
}
|
|
1048
1048
|
}
|
|
1049
|
-
|
|
1049
|
+
async function refreshSessionProfile(c, profile) {
|
|
1050
|
+
const live = await liveSession(c);
|
|
1051
|
+
if (!live) return;
|
|
1052
|
+
const next = { ...live };
|
|
1053
|
+
if (profile.name) next.name = profile.name;
|
|
1054
|
+
else delete next.name;
|
|
1055
|
+
if (profile.picture) next.picture = profile.picture;
|
|
1056
|
+
else delete next.picture;
|
|
1057
|
+
if (next.name === live.name && next.picture === live.picture) return;
|
|
1058
|
+
const left = live.exp - Math.floor(Date.now() / 1e3);
|
|
1059
|
+
if (left <= 0) return;
|
|
1060
|
+
c.header(
|
|
1061
|
+
"Set-Cookie",
|
|
1062
|
+
cookieHeader(config.cookieName, await signSession(next, config.cookieSecret), { maxAge: left, secure: isSecure(c) }),
|
|
1063
|
+
{ append: true }
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
return { app, attach, require: require2, client, config, getAccessToken, refreshSessionProfile };
|
|
1050
1067
|
}
|
|
1051
1068
|
async function parseTransaction(raw, secret) {
|
|
1052
1069
|
if (raw === void 0) return { ok: false, reason: "absent" };
|
|
@@ -1107,14 +1124,18 @@ function accountRoutes(sso) {
|
|
|
1107
1124
|
}
|
|
1108
1125
|
await next();
|
|
1109
1126
|
});
|
|
1110
|
-
|
|
1127
|
+
const answer = async (c, profile) => {
|
|
1128
|
+
if (sso.refreshSessionProfile) await sso.refreshSessionProfile(c, profile);
|
|
1129
|
+
return c.json(profile);
|
|
1130
|
+
};
|
|
1131
|
+
app.get("/profile", async (c) => answer(c, await client.getProfile(await sso.getAccessToken(c))));
|
|
1111
1132
|
app.post("/profile", async (c) => {
|
|
1112
1133
|
const token = await sso.getAccessToken(c);
|
|
1113
1134
|
const body = await c.req.json().catch(() => null);
|
|
1114
1135
|
if (typeof body?.name !== "string") {
|
|
1115
1136
|
return c.json({ error: "invalid_request", error_description: '"name" must be a string' }, 400);
|
|
1116
1137
|
}
|
|
1117
|
-
return c
|
|
1138
|
+
return answer(c, await client.updateProfile(token, body.name));
|
|
1118
1139
|
});
|
|
1119
1140
|
app.post("/profile/avatar", async (c) => {
|
|
1120
1141
|
const token = await sso.getAccessToken(c);
|
|
@@ -1128,9 +1149,9 @@ function accountRoutes(sso) {
|
|
|
1128
1149
|
}
|
|
1129
1150
|
const bytes = await readCapped(c, MAX_AVATAR_BYTES);
|
|
1130
1151
|
if (!bytes) return c.json({ error: "too_large", max_bytes: MAX_AVATAR_BYTES }, 413);
|
|
1131
|
-
return c
|
|
1152
|
+
return answer(c, await client.uploadAvatar(token, bytes, type));
|
|
1132
1153
|
});
|
|
1133
|
-
app.post("/profile/avatar/remove", async (c) => c
|
|
1154
|
+
app.post("/profile/avatar/remove", async (c) => answer(c, await client.removeAvatar(await sso.getAccessToken(c))));
|
|
1134
1155
|
app.onError((err, c) => {
|
|
1135
1156
|
c.header("Cache-Control", "no-store");
|
|
1136
1157
|
const e = err;
|