@scalemule/news-publication 0.0.76 → 0.0.77
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/meet-view.d.cts +1 -1
- package/dist/meet-view.d.ts +1 -1
- package/dist/reader-sso-client.cjs +55 -7
- package/dist/reader-sso-client.d.cts +4 -1
- package/dist/reader-sso-client.d.ts +4 -1
- package/dist/reader-sso-client.js +53 -8
- package/dist/reader-sso.cjs +4 -4
- package/dist/reader-sso.js +4 -4
- package/package.json +4 -2
package/dist/meet-view.d.cts
CHANGED
|
@@ -18,7 +18,7 @@ declare function MeetupDetail({ meetup, joined }: {
|
|
|
18
18
|
joined: boolean;
|
|
19
19
|
}): React.JSX.Element;
|
|
20
20
|
declare function activityChoices(): {
|
|
21
|
-
value: "
|
|
21
|
+
value: "walk" | "other" | "games" | "coffee" | "hike" | "pickleball" | "tennis" | "soccer" | "bike" | "dogs" | "books" | "kids" | "volunteer";
|
|
22
22
|
label: string;
|
|
23
23
|
}[];
|
|
24
24
|
|
package/dist/meet-view.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ declare function MeetupDetail({ meetup, joined }: {
|
|
|
18
18
|
joined: boolean;
|
|
19
19
|
}): React.JSX.Element;
|
|
20
20
|
declare function activityChoices(): {
|
|
21
|
-
value: "
|
|
21
|
+
value: "walk" | "other" | "games" | "coffee" | "hike" | "pickleball" | "tennis" | "soccer" | "bike" | "dogs" | "books" | "kids" | "volunteer";
|
|
22
22
|
label: string;
|
|
23
23
|
}[];
|
|
24
24
|
|
|
@@ -150,19 +150,64 @@ function greetingText(profile, now = /* @__PURE__ */ new Date(), fallback = "Wel
|
|
|
150
150
|
if (!name) return fallback;
|
|
151
151
|
return `${greetingWord(localHour(now, profile.time_zone, profile.locale))}, ${name}`;
|
|
152
152
|
}
|
|
153
|
+
var READER_GREETING_POLL_MS = 3e4;
|
|
154
|
+
var READER_GREETING_TIMEOUT_MS = 8e3;
|
|
155
|
+
var READER_IDENTITY_CHANGED_EVENT = "scalemule:reader-identity-changed";
|
|
153
156
|
function ReaderGreeting({ endpoint = "/api/news/session", className, fallback = "Welcome back", as: Tag = "span" }) {
|
|
154
157
|
const [text, setText] = react.useState(null);
|
|
155
158
|
react.useEffect(() => {
|
|
156
159
|
let alive = true;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
let generation = 0;
|
|
161
|
+
let authenticated = false;
|
|
162
|
+
let controller;
|
|
163
|
+
let deadline;
|
|
164
|
+
const refresh = (clear = false) => {
|
|
165
|
+
if (!alive) return;
|
|
166
|
+
if (clear) {
|
|
167
|
+
authenticated = false;
|
|
168
|
+
setText(null);
|
|
169
|
+
}
|
|
170
|
+
const current = ++generation;
|
|
171
|
+
controller?.abort();
|
|
172
|
+
if (deadline !== void 0) window.clearTimeout(deadline);
|
|
173
|
+
if (document.visibilityState === "hidden") return;
|
|
174
|
+
const request = new AbortController();
|
|
175
|
+
controller = request;
|
|
176
|
+
const timeout = window.setTimeout(() => {
|
|
177
|
+
if (!alive || current !== generation) return;
|
|
178
|
+
generation++;
|
|
179
|
+
authenticated = false;
|
|
180
|
+
setText(null);
|
|
181
|
+
request.abort();
|
|
182
|
+
}, READER_GREETING_TIMEOUT_MS);
|
|
183
|
+
deadline = timeout;
|
|
184
|
+
fetch(endpoint, { credentials: "same-origin", cache: "no-store", signal: request.signal }).then((response) => response.ok ? response.json() : null).then((summary) => {
|
|
185
|
+
if (!alive || current !== generation) return;
|
|
186
|
+
authenticated = summary?.authenticated === true;
|
|
187
|
+
setText(authenticated && summary ? greetingText(summary, /* @__PURE__ */ new Date(), fallback) : null);
|
|
188
|
+
}).catch(() => {
|
|
189
|
+
if (!alive || current !== generation) return;
|
|
190
|
+
authenticated = false;
|
|
191
|
+
setText(null);
|
|
192
|
+
}).finally(() => window.clearTimeout(timeout));
|
|
193
|
+
};
|
|
194
|
+
const recheck = () => refresh(true);
|
|
195
|
+
const timer = window.setInterval(() => {
|
|
196
|
+
if (authenticated) refresh();
|
|
197
|
+
}, READER_GREETING_POLL_MS);
|
|
198
|
+
window.addEventListener("focus", recheck);
|
|
199
|
+
document.addEventListener("visibilitychange", recheck);
|
|
200
|
+
document.addEventListener(READER_IDENTITY_CHANGED_EVENT, recheck);
|
|
201
|
+
refresh(true);
|
|
163
202
|
return () => {
|
|
164
203
|
alive = false;
|
|
165
|
-
|
|
204
|
+
generation++;
|
|
205
|
+
controller?.abort();
|
|
206
|
+
if (deadline !== void 0) window.clearTimeout(deadline);
|
|
207
|
+
window.clearInterval(timer);
|
|
208
|
+
window.removeEventListener("focus", recheck);
|
|
209
|
+
document.removeEventListener("visibilitychange", recheck);
|
|
210
|
+
document.removeEventListener(READER_IDENTITY_CHANGED_EVENT, recheck);
|
|
166
211
|
};
|
|
167
212
|
}, [endpoint, fallback]);
|
|
168
213
|
if (text === null) return null;
|
|
@@ -350,6 +395,9 @@ exports.AccountLinkForm = AccountLinkForm;
|
|
|
350
395
|
exports.AccountSwitchPrompt = AccountSwitchPrompt;
|
|
351
396
|
exports.LEDVERY_BUTTON_LABELS = LEDVERY_BUTTON_LABELS;
|
|
352
397
|
exports.LedveryButton = LedveryButton;
|
|
398
|
+
exports.READER_GREETING_POLL_MS = READER_GREETING_POLL_MS;
|
|
399
|
+
exports.READER_GREETING_TIMEOUT_MS = READER_GREETING_TIMEOUT_MS;
|
|
400
|
+
exports.READER_IDENTITY_CHANGED_EVENT = READER_IDENTITY_CHANGED_EVENT;
|
|
353
401
|
exports.READER_SSO_ATTEMPT_WINDOW_MS = READER_SSO_ATTEMPT_WINDOW_MS;
|
|
354
402
|
exports.READER_SSO_BOT_PATTERN = READER_SSO_BOT_PATTERN;
|
|
355
403
|
exports.READER_SSO_PRIVATE_PATHS = READER_SSO_PRIVATE_PATHS;
|
|
@@ -64,6 +64,9 @@ type SessionSummaryResponse = {
|
|
|
64
64
|
locale?: string;
|
|
65
65
|
time_zone?: string;
|
|
66
66
|
};
|
|
67
|
+
declare const READER_GREETING_POLL_MS = 30000;
|
|
68
|
+
declare const READER_GREETING_TIMEOUT_MS = 8000;
|
|
69
|
+
declare const READER_IDENTITY_CHANGED_EVENT = "scalemule:reader-identity-changed";
|
|
67
70
|
declare function ReaderGreeting({ endpoint, className, fallback, as: Tag }: {
|
|
68
71
|
endpoint?: string;
|
|
69
72
|
className?: string;
|
|
@@ -128,4 +131,4 @@ declare function AccountSwitchPrompt({ currentName, pendingName, endpoint, class
|
|
|
128
131
|
onDone?: (result: SwitchResult) => void;
|
|
129
132
|
}): React.JSX.Element;
|
|
130
133
|
|
|
131
|
-
export { AccountLinkForm, AccountSwitchPrompt, type GreetingProfile, LEDVERY_BUTTON_LABELS, LedveryButton, type LinkResult, READER_SSO_ATTEMPT_WINDOW_MS, READER_SSO_BOT_PATTERN, READER_SSO_PRIVATE_PATHS, ReaderGreeting, ReaderSsoBoot, type ReaderSsoClassNames, type ReaderSsoProvider, type SessionSummaryResponse, type SilentSignInDecision, type SilentSignInEnvironment, type SwitchChoice, type SwitchResult, firstName, greetingText, greetingWord, isFormField, localHour, silentSignInDecision, silentSignInUrl };
|
|
134
|
+
export { AccountLinkForm, AccountSwitchPrompt, type GreetingProfile, LEDVERY_BUTTON_LABELS, LedveryButton, type LinkResult, READER_GREETING_POLL_MS, READER_GREETING_TIMEOUT_MS, READER_IDENTITY_CHANGED_EVENT, READER_SSO_ATTEMPT_WINDOW_MS, READER_SSO_BOT_PATTERN, READER_SSO_PRIVATE_PATHS, ReaderGreeting, ReaderSsoBoot, type ReaderSsoClassNames, type ReaderSsoProvider, type SessionSummaryResponse, type SilentSignInDecision, type SilentSignInEnvironment, type SwitchChoice, type SwitchResult, firstName, greetingText, greetingWord, isFormField, localHour, silentSignInDecision, silentSignInUrl };
|
|
@@ -64,6 +64,9 @@ type SessionSummaryResponse = {
|
|
|
64
64
|
locale?: string;
|
|
65
65
|
time_zone?: string;
|
|
66
66
|
};
|
|
67
|
+
declare const READER_GREETING_POLL_MS = 30000;
|
|
68
|
+
declare const READER_GREETING_TIMEOUT_MS = 8000;
|
|
69
|
+
declare const READER_IDENTITY_CHANGED_EVENT = "scalemule:reader-identity-changed";
|
|
67
70
|
declare function ReaderGreeting({ endpoint, className, fallback, as: Tag }: {
|
|
68
71
|
endpoint?: string;
|
|
69
72
|
className?: string;
|
|
@@ -128,4 +131,4 @@ declare function AccountSwitchPrompt({ currentName, pendingName, endpoint, class
|
|
|
128
131
|
onDone?: (result: SwitchResult) => void;
|
|
129
132
|
}): React.JSX.Element;
|
|
130
133
|
|
|
131
|
-
export { AccountLinkForm, AccountSwitchPrompt, type GreetingProfile, LEDVERY_BUTTON_LABELS, LedveryButton, type LinkResult, READER_SSO_ATTEMPT_WINDOW_MS, READER_SSO_BOT_PATTERN, READER_SSO_PRIVATE_PATHS, ReaderGreeting, ReaderSsoBoot, type ReaderSsoClassNames, type ReaderSsoProvider, type SessionSummaryResponse, type SilentSignInDecision, type SilentSignInEnvironment, type SwitchChoice, type SwitchResult, firstName, greetingText, greetingWord, isFormField, localHour, silentSignInDecision, silentSignInUrl };
|
|
134
|
+
export { AccountLinkForm, AccountSwitchPrompt, type GreetingProfile, LEDVERY_BUTTON_LABELS, LedveryButton, type LinkResult, READER_GREETING_POLL_MS, READER_GREETING_TIMEOUT_MS, READER_IDENTITY_CHANGED_EVENT, READER_SSO_ATTEMPT_WINDOW_MS, READER_SSO_BOT_PATTERN, READER_SSO_PRIVATE_PATHS, ReaderGreeting, ReaderSsoBoot, type ReaderSsoClassNames, type ReaderSsoProvider, type SessionSummaryResponse, type SilentSignInDecision, type SilentSignInEnvironment, type SwitchChoice, type SwitchResult, firstName, greetingText, greetingWord, isFormField, localHour, silentSignInDecision, silentSignInUrl };
|
|
@@ -148,19 +148,64 @@ function greetingText(profile, now = /* @__PURE__ */ new Date(), fallback = "Wel
|
|
|
148
148
|
if (!name) return fallback;
|
|
149
149
|
return `${greetingWord(localHour(now, profile.time_zone, profile.locale))}, ${name}`;
|
|
150
150
|
}
|
|
151
|
+
var READER_GREETING_POLL_MS = 3e4;
|
|
152
|
+
var READER_GREETING_TIMEOUT_MS = 8e3;
|
|
153
|
+
var READER_IDENTITY_CHANGED_EVENT = "scalemule:reader-identity-changed";
|
|
151
154
|
function ReaderGreeting({ endpoint = "/api/news/session", className, fallback = "Welcome back", as: Tag = "span" }) {
|
|
152
155
|
const [text, setText] = useState(null);
|
|
153
156
|
useEffect(() => {
|
|
154
157
|
let alive = true;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
let generation = 0;
|
|
159
|
+
let authenticated = false;
|
|
160
|
+
let controller;
|
|
161
|
+
let deadline;
|
|
162
|
+
const refresh = (clear = false) => {
|
|
163
|
+
if (!alive) return;
|
|
164
|
+
if (clear) {
|
|
165
|
+
authenticated = false;
|
|
166
|
+
setText(null);
|
|
167
|
+
}
|
|
168
|
+
const current = ++generation;
|
|
169
|
+
controller?.abort();
|
|
170
|
+
if (deadline !== void 0) window.clearTimeout(deadline);
|
|
171
|
+
if (document.visibilityState === "hidden") return;
|
|
172
|
+
const request = new AbortController();
|
|
173
|
+
controller = request;
|
|
174
|
+
const timeout = window.setTimeout(() => {
|
|
175
|
+
if (!alive || current !== generation) return;
|
|
176
|
+
generation++;
|
|
177
|
+
authenticated = false;
|
|
178
|
+
setText(null);
|
|
179
|
+
request.abort();
|
|
180
|
+
}, READER_GREETING_TIMEOUT_MS);
|
|
181
|
+
deadline = timeout;
|
|
182
|
+
fetch(endpoint, { credentials: "same-origin", cache: "no-store", signal: request.signal }).then((response) => response.ok ? response.json() : null).then((summary) => {
|
|
183
|
+
if (!alive || current !== generation) return;
|
|
184
|
+
authenticated = summary?.authenticated === true;
|
|
185
|
+
setText(authenticated && summary ? greetingText(summary, /* @__PURE__ */ new Date(), fallback) : null);
|
|
186
|
+
}).catch(() => {
|
|
187
|
+
if (!alive || current !== generation) return;
|
|
188
|
+
authenticated = false;
|
|
189
|
+
setText(null);
|
|
190
|
+
}).finally(() => window.clearTimeout(timeout));
|
|
191
|
+
};
|
|
192
|
+
const recheck = () => refresh(true);
|
|
193
|
+
const timer = window.setInterval(() => {
|
|
194
|
+
if (authenticated) refresh();
|
|
195
|
+
}, READER_GREETING_POLL_MS);
|
|
196
|
+
window.addEventListener("focus", recheck);
|
|
197
|
+
document.addEventListener("visibilitychange", recheck);
|
|
198
|
+
document.addEventListener(READER_IDENTITY_CHANGED_EVENT, recheck);
|
|
199
|
+
refresh(true);
|
|
161
200
|
return () => {
|
|
162
201
|
alive = false;
|
|
163
|
-
|
|
202
|
+
generation++;
|
|
203
|
+
controller?.abort();
|
|
204
|
+
if (deadline !== void 0) window.clearTimeout(deadline);
|
|
205
|
+
window.clearInterval(timer);
|
|
206
|
+
window.removeEventListener("focus", recheck);
|
|
207
|
+
document.removeEventListener("visibilitychange", recheck);
|
|
208
|
+
document.removeEventListener(READER_IDENTITY_CHANGED_EVENT, recheck);
|
|
164
209
|
};
|
|
165
210
|
}, [endpoint, fallback]);
|
|
166
211
|
if (text === null) return null;
|
|
@@ -344,4 +389,4 @@ function AccountSwitchPrompt({
|
|
|
344
389
|
] });
|
|
345
390
|
}
|
|
346
391
|
|
|
347
|
-
export { AccountLinkForm, AccountSwitchPrompt, LEDVERY_BUTTON_LABELS, LedveryButton, READER_SSO_ATTEMPT_WINDOW_MS, READER_SSO_BOT_PATTERN, READER_SSO_PRIVATE_PATHS, ReaderGreeting, ReaderSsoBoot, firstName, greetingText, greetingWord, isFormField, localHour, silentSignInDecision, silentSignInUrl };
|
|
392
|
+
export { AccountLinkForm, AccountSwitchPrompt, LEDVERY_BUTTON_LABELS, LedveryButton, READER_GREETING_POLL_MS, READER_GREETING_TIMEOUT_MS, READER_IDENTITY_CHANGED_EVENT, READER_SSO_ATTEMPT_WINDOW_MS, READER_SSO_BOT_PATTERN, READER_SSO_PRIVATE_PATHS, ReaderGreeting, ReaderSsoBoot, firstName, greetingText, greetingWord, isFormField, localHour, silentSignInDecision, silentSignInUrl };
|
package/dist/reader-sso.cjs
CHANGED
|
@@ -195,7 +195,7 @@ async function startSignIn(config, input) {
|
|
|
195
195
|
}
|
|
196
196
|
const staleSession = [];
|
|
197
197
|
if (input.cookies(c.names.session)) {
|
|
198
|
-
const current = await currentUser(c, input.cookies(c.names.session));
|
|
198
|
+
const current = await currentUser(c, input.cookies(c.names.session), mode === "silent" ? "passive" : "active");
|
|
199
199
|
if (current && current.email_verified) {
|
|
200
200
|
if (mode === "silent" && (!current.needsSsoUpgrade || keepsLocal(input.cookies(c.names.ssoChecked), input.cookies(c.names.session)))) return { ok: false, status: 204, error: "", reason: "session", redirect, cookies: [] };
|
|
201
201
|
} else {
|
|
@@ -237,9 +237,9 @@ async function startSignIn(config, input) {
|
|
|
237
237
|
return { ok: false, status: 503, error: "Ledvery sign-in is temporarily unavailable. Please try again shortly or use your existing reader account.", reason: "unavailable", redirect, cookies: [] };
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
|
-
async function currentUser(c, token) {
|
|
240
|
+
async function currentUser(c, token, activity = "active") {
|
|
241
241
|
if (!token || !SESSION_TOKEN.test(token)) return null;
|
|
242
|
-
const response = await c.request("/v1/auth/me", { method: "GET", token });
|
|
242
|
+
const response = await c.request(activity === "passive" ? "/v1/auth/me?passive=true" : "/v1/auth/me", { method: "GET", token });
|
|
243
243
|
if (failed(response)) return null;
|
|
244
244
|
const me = payload(response);
|
|
245
245
|
if (typeof me.id !== "string" || !me.id) return null;
|
|
@@ -468,7 +468,7 @@ async function signOut(config, input) {
|
|
|
468
468
|
}
|
|
469
469
|
async function sessionSummary(config, cookies) {
|
|
470
470
|
const c = resolve(config);
|
|
471
|
-
const user = await currentUser(c, cookies(c.names.session));
|
|
471
|
+
const user = await currentUser(c, cookies(c.names.session), "passive");
|
|
472
472
|
if (!user || !user.email_verified) return { authenticated: false };
|
|
473
473
|
return { authenticated: true, full_name: user.full_name, locale: user.locale, time_zone: user.time_zone, ...user.needsSsoUpgrade && !keepsLocal(cookies(c.names.ssoChecked), cookies(c.names.session)) ? { session_upgrade_required: true } : {} };
|
|
474
474
|
}
|
package/dist/reader-sso.js
CHANGED
|
@@ -180,7 +180,7 @@ async function startSignIn(config, input) {
|
|
|
180
180
|
}
|
|
181
181
|
const staleSession = [];
|
|
182
182
|
if (input.cookies(c.names.session)) {
|
|
183
|
-
const current = await currentUser(c, input.cookies(c.names.session));
|
|
183
|
+
const current = await currentUser(c, input.cookies(c.names.session), mode === "silent" ? "passive" : "active");
|
|
184
184
|
if (current && current.email_verified) {
|
|
185
185
|
if (mode === "silent" && (!current.needsSsoUpgrade || keepsLocal(input.cookies(c.names.ssoChecked), input.cookies(c.names.session)))) return { ok: false, status: 204, error: "", reason: "session", redirect, cookies: [] };
|
|
186
186
|
} else {
|
|
@@ -222,9 +222,9 @@ async function startSignIn(config, input) {
|
|
|
222
222
|
return { ok: false, status: 503, error: "Ledvery sign-in is temporarily unavailable. Please try again shortly or use your existing reader account.", reason: "unavailable", redirect, cookies: [] };
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
async function currentUser(c, token) {
|
|
225
|
+
async function currentUser(c, token, activity = "active") {
|
|
226
226
|
if (!token || !SESSION_TOKEN.test(token)) return null;
|
|
227
|
-
const response = await c.request("/v1/auth/me", { method: "GET", token });
|
|
227
|
+
const response = await c.request(activity === "passive" ? "/v1/auth/me?passive=true" : "/v1/auth/me", { method: "GET", token });
|
|
228
228
|
if (failed(response)) return null;
|
|
229
229
|
const me = payload(response);
|
|
230
230
|
if (typeof me.id !== "string" || !me.id) return null;
|
|
@@ -453,7 +453,7 @@ async function signOut(config, input) {
|
|
|
453
453
|
}
|
|
454
454
|
async function sessionSummary(config, cookies) {
|
|
455
455
|
const c = resolve(config);
|
|
456
|
-
const user = await currentUser(c, cookies(c.names.session));
|
|
456
|
+
const user = await currentUser(c, cookies(c.names.session), "passive");
|
|
457
457
|
if (!user || !user.email_verified) return { authenticated: false };
|
|
458
458
|
return { authenticated: true, full_name: user.full_name, locale: user.locale, time_zone: user.time_zone, ...user.needsSsoUpgrade && !keepsLocal(cookies(c.names.ssoChecked), cookies(c.names.session)) ? { session_upgrade_required: true } : {} };
|
|
459
459
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/news-publication",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.77",
|
|
4
4
|
"description": "Shared server framework for ScaleMule local news publications. Walnut Creek Times is the broadsheet default; each paper supplies its own identity and feature flags.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"bin": {
|
|
6
|
+
"bin": {
|
|
7
|
+
"scalemule-article": "./bin/scalemule-article.mjs"
|
|
8
|
+
},
|
|
7
9
|
"main": "./dist/index.cjs",
|
|
8
10
|
"module": "./dist/index.js",
|
|
9
11
|
"types": "./dist/index.d.ts",
|