@scalemule/news-publication 0.0.77 → 0.0.78
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.
|
@@ -4,6 +4,46 @@
|
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
7
|
+
// src/reader-sso-scheduler.ts
|
|
8
|
+
function mountReaderSsoScheduler({ document: doc, timers, eligible, attempt, idleDelayMs }) {
|
|
9
|
+
let active = true;
|
|
10
|
+
let attempted = false;
|
|
11
|
+
let idle;
|
|
12
|
+
let delay;
|
|
13
|
+
const cancelPending = () => {
|
|
14
|
+
if (idle !== void 0) timers.cancelIdleCallback?.(idle);
|
|
15
|
+
if (delay !== void 0) timers.clearTimeout(delay);
|
|
16
|
+
idle = delay = void 0;
|
|
17
|
+
};
|
|
18
|
+
const run = () => {
|
|
19
|
+
delay = void 0;
|
|
20
|
+
if (!active || attempted || !eligible()) return;
|
|
21
|
+
attempted = true;
|
|
22
|
+
attempt();
|
|
23
|
+
};
|
|
24
|
+
const defer = () => {
|
|
25
|
+
idle = void 0;
|
|
26
|
+
if (active && !attempted) delay = timers.setTimeout(run, idleDelayMs);
|
|
27
|
+
};
|
|
28
|
+
const schedule = () => {
|
|
29
|
+
if (!active || attempted) return;
|
|
30
|
+
cancelPending();
|
|
31
|
+
if (doc.readyState === "loading" || !eligible()) return;
|
|
32
|
+
if (timers.requestIdleCallback) idle = timers.requestIdleCallback(defer, { timeout: 4e3 });
|
|
33
|
+
else defer();
|
|
34
|
+
};
|
|
35
|
+
doc.addEventListener("DOMContentLoaded", schedule);
|
|
36
|
+
doc.addEventListener("visibilitychange", schedule);
|
|
37
|
+
doc.addEventListener("prerenderingchange", schedule);
|
|
38
|
+
schedule();
|
|
39
|
+
return () => {
|
|
40
|
+
active = false;
|
|
41
|
+
cancelPending();
|
|
42
|
+
doc.removeEventListener("DOMContentLoaded", schedule);
|
|
43
|
+
doc.removeEventListener("visibilitychange", schedule);
|
|
44
|
+
doc.removeEventListener("prerenderingchange", schedule);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
7
47
|
var READER_SSO_BOT_PATTERN = /bot|crawl|spider|headless|lighthouse|pagespeed|preview|slurp|facebookexternalhit|embedly|python|curl|wget|phantom|puppeteer|playwright|selenium|prerender/i;
|
|
8
48
|
var READER_SSO_PRIVATE_PATHS = [
|
|
9
49
|
/^\/account(\/|$)/,
|
|
@@ -95,30 +135,18 @@ function ReaderSsoBoot({ enabled = true, hasSession: hasSessionCookie, suppresse
|
|
|
95
135
|
}, [enabled, hasSessionCookie, staleCookie, sessionPath]);
|
|
96
136
|
const hasSession = hasSessionCookie && !staleCookie;
|
|
97
137
|
react.useEffect(() => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (typeof w.requestIdleCallback === "function") idle = w.requestIdleCallback(() => {
|
|
111
|
-
idle = window.setTimeout(go, idleDelayMs);
|
|
112
|
-
}, { timeout: 4e3 });
|
|
113
|
-
else idle = window.setTimeout(go, idleDelayMs);
|
|
114
|
-
};
|
|
115
|
-
if (document.readyState === "complete") whenIdle();
|
|
116
|
-
else window.addEventListener("load", whenIdle, { once: true });
|
|
117
|
-
return () => {
|
|
118
|
-
cancelled = true;
|
|
119
|
-
window.removeEventListener("load", whenIdle);
|
|
120
|
-
if (idle !== void 0) window.clearTimeout(idle);
|
|
121
|
-
};
|
|
138
|
+
const flags = { enabled, hasSession, suppressed, privatePaths };
|
|
139
|
+
return mountReaderSsoScheduler({
|
|
140
|
+
document,
|
|
141
|
+
timers: window,
|
|
142
|
+
idleDelayMs,
|
|
143
|
+
eligible: () => silentSignInDecision(browserEnvironment(flags)).attempt === true,
|
|
144
|
+
attempt: () => {
|
|
145
|
+
const env = browserEnvironment(flags);
|
|
146
|
+
writeAttempt(env.now);
|
|
147
|
+
window.location.assign(silentSignInUrl(startPath, env.pathname, env.search));
|
|
148
|
+
}
|
|
149
|
+
});
|
|
122
150
|
}, [enabled, hasSession, suppressed, startPath, privatePaths, idleDelayMs]);
|
|
123
151
|
return null;
|
|
124
152
|
}
|
|
@@ -32,7 +32,7 @@ declare function silentSignInDecision(env: SilentSignInEnvironment): SilentSignI
|
|
|
32
32
|
declare function silentSignInUrl(startPath: string, pathname: string, search: string): string;
|
|
33
33
|
declare function isFormField(element: Element | null): boolean;
|
|
34
34
|
/**
|
|
35
|
-
* Renders nothing. Once per page load, after
|
|
35
|
+
* Renders nothing. Once per page load, after the DOM is usable and an idle period, performs a
|
|
36
36
|
* top-level navigation to the silent sign-in start route when nothing argues
|
|
37
37
|
* against it. The server sets the negative-cache cookie on every silent negative,
|
|
38
38
|
* so this can never loop.
|
|
@@ -32,7 +32,7 @@ declare function silentSignInDecision(env: SilentSignInEnvironment): SilentSignI
|
|
|
32
32
|
declare function silentSignInUrl(startPath: string, pathname: string, search: string): string;
|
|
33
33
|
declare function isFormField(element: Element | null): boolean;
|
|
34
34
|
/**
|
|
35
|
-
* Renders nothing. Once per page load, after
|
|
35
|
+
* Renders nothing. Once per page load, after the DOM is usable and an idle period, performs a
|
|
36
36
|
* top-level navigation to the silent sign-in start route when nothing argues
|
|
37
37
|
* against it. The server sets the negative-cache cookie on every silent negative,
|
|
38
38
|
* so this can never loop.
|
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
import { useState, useEffect, useId } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
|
+
// src/reader-sso-scheduler.ts
|
|
6
|
+
function mountReaderSsoScheduler({ document: doc, timers, eligible, attempt, idleDelayMs }) {
|
|
7
|
+
let active = true;
|
|
8
|
+
let attempted = false;
|
|
9
|
+
let idle;
|
|
10
|
+
let delay;
|
|
11
|
+
const cancelPending = () => {
|
|
12
|
+
if (idle !== void 0) timers.cancelIdleCallback?.(idle);
|
|
13
|
+
if (delay !== void 0) timers.clearTimeout(delay);
|
|
14
|
+
idle = delay = void 0;
|
|
15
|
+
};
|
|
16
|
+
const run = () => {
|
|
17
|
+
delay = void 0;
|
|
18
|
+
if (!active || attempted || !eligible()) return;
|
|
19
|
+
attempted = true;
|
|
20
|
+
attempt();
|
|
21
|
+
};
|
|
22
|
+
const defer = () => {
|
|
23
|
+
idle = void 0;
|
|
24
|
+
if (active && !attempted) delay = timers.setTimeout(run, idleDelayMs);
|
|
25
|
+
};
|
|
26
|
+
const schedule = () => {
|
|
27
|
+
if (!active || attempted) return;
|
|
28
|
+
cancelPending();
|
|
29
|
+
if (doc.readyState === "loading" || !eligible()) return;
|
|
30
|
+
if (timers.requestIdleCallback) idle = timers.requestIdleCallback(defer, { timeout: 4e3 });
|
|
31
|
+
else defer();
|
|
32
|
+
};
|
|
33
|
+
doc.addEventListener("DOMContentLoaded", schedule);
|
|
34
|
+
doc.addEventListener("visibilitychange", schedule);
|
|
35
|
+
doc.addEventListener("prerenderingchange", schedule);
|
|
36
|
+
schedule();
|
|
37
|
+
return () => {
|
|
38
|
+
active = false;
|
|
39
|
+
cancelPending();
|
|
40
|
+
doc.removeEventListener("DOMContentLoaded", schedule);
|
|
41
|
+
doc.removeEventListener("visibilitychange", schedule);
|
|
42
|
+
doc.removeEventListener("prerenderingchange", schedule);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
5
45
|
var READER_SSO_BOT_PATTERN = /bot|crawl|spider|headless|lighthouse|pagespeed|preview|slurp|facebookexternalhit|embedly|python|curl|wget|phantom|puppeteer|playwright|selenium|prerender/i;
|
|
6
46
|
var READER_SSO_PRIVATE_PATHS = [
|
|
7
47
|
/^\/account(\/|$)/,
|
|
@@ -93,30 +133,18 @@ function ReaderSsoBoot({ enabled = true, hasSession: hasSessionCookie, suppresse
|
|
|
93
133
|
}, [enabled, hasSessionCookie, staleCookie, sessionPath]);
|
|
94
134
|
const hasSession = hasSessionCookie && !staleCookie;
|
|
95
135
|
useEffect(() => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (typeof w.requestIdleCallback === "function") idle = w.requestIdleCallback(() => {
|
|
109
|
-
idle = window.setTimeout(go, idleDelayMs);
|
|
110
|
-
}, { timeout: 4e3 });
|
|
111
|
-
else idle = window.setTimeout(go, idleDelayMs);
|
|
112
|
-
};
|
|
113
|
-
if (document.readyState === "complete") whenIdle();
|
|
114
|
-
else window.addEventListener("load", whenIdle, { once: true });
|
|
115
|
-
return () => {
|
|
116
|
-
cancelled = true;
|
|
117
|
-
window.removeEventListener("load", whenIdle);
|
|
118
|
-
if (idle !== void 0) window.clearTimeout(idle);
|
|
119
|
-
};
|
|
136
|
+
const flags = { enabled, hasSession, suppressed, privatePaths };
|
|
137
|
+
return mountReaderSsoScheduler({
|
|
138
|
+
document,
|
|
139
|
+
timers: window,
|
|
140
|
+
idleDelayMs,
|
|
141
|
+
eligible: () => silentSignInDecision(browserEnvironment(flags)).attempt === true,
|
|
142
|
+
attempt: () => {
|
|
143
|
+
const env = browserEnvironment(flags);
|
|
144
|
+
writeAttempt(env.now);
|
|
145
|
+
window.location.assign(silentSignInUrl(startPath, env.pathname, env.search));
|
|
146
|
+
}
|
|
147
|
+
});
|
|
120
148
|
}, [enabled, hasSession, suppressed, startPath, privatePaths, idleDelayMs]);
|
|
121
149
|
return null;
|
|
122
150
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/news-publication",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.78",
|
|
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
6
|
"bin": {
|