@scalemule/news-publication 0.0.49 → 0.0.51

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.
Files changed (39) hide show
  1. package/README.md +26 -0
  2. package/dist/{chunk-ZXH3O537.js → chunk-ABPJMDUG.js} +1 -1
  3. package/dist/{chunk-MBBPEFDA.js → chunk-AFJ6S5WJ.js} +1 -1
  4. package/dist/{chunk-2MEYHM7M.js → chunk-AMLVCZDP.js} +1 -1
  5. package/dist/{chunk-TTLM7YOH.js → chunk-QW3OZB22.js} +183 -11
  6. package/dist/index.js +3 -3
  7. package/dist/meet-forms.js +2 -2
  8. package/dist/meet-view.d.cts +1 -1
  9. package/dist/meet-view.d.ts +1 -1
  10. package/dist/meet-view.js +2 -2
  11. package/dist/pets-auth-server.cjs +59 -14
  12. package/dist/pets-auth-server.d.cts +7 -1
  13. package/dist/pets-auth-server.d.ts +7 -1
  14. package/dist/pets-auth-server.js +60 -17
  15. package/dist/pets-forms.cjs +8 -4
  16. package/dist/pets-forms.d.cts +4 -2
  17. package/dist/pets-forms.d.ts +4 -2
  18. package/dist/pets-forms.js +10 -6
  19. package/dist/pets-interactions.cjs +6 -5
  20. package/dist/pets-interactions.d.cts +5 -2
  21. package/dist/pets-interactions.d.ts +5 -2
  22. package/dist/pets-interactions.js +7 -6
  23. package/dist/pets-plugin.cjs +551 -0
  24. package/dist/pets-plugin.d.cts +50 -0
  25. package/dist/pets-plugin.d.ts +50 -0
  26. package/dist/pets-plugin.js +317 -0
  27. package/dist/pets-publication.cjs +230 -34
  28. package/dist/pets-publication.d.cts +7 -3
  29. package/dist/pets-publication.d.ts +7 -3
  30. package/dist/pets-publication.js +51 -27
  31. package/dist/pets-server.js +2 -2
  32. package/dist/pets-view.cjs +182 -9
  33. package/dist/pets-view.d.cts +3 -1
  34. package/dist/pets-view.d.ts +3 -1
  35. package/dist/pets-view.js +2 -2
  36. package/dist/pets.cjs +1 -1
  37. package/dist/pets.js +1 -1
  38. package/package.json +6 -1
  39. package/pets.css +215 -7
package/README.md CHANGED
@@ -273,3 +273,29 @@ Private recovery contact and broad community alert delivery are not implemented
273
273
  by these components. Notification controls default to disabled. The canonical
274
274
  application, collections, publication views and legitimate source content must
275
275
  be provisioned separately before launch.
276
+
277
+ ### Native pet plugin and shared sign-in
278
+
279
+ `pets-plugin` exports `PetAccountPage`, `PetSubmitPage`, `PetStoryPage` and
280
+ `PetBrowsePage`, with `publicationPetPaths` or `standalonePetPaths`. These are
281
+ server components: give them the publication’s `PetScope` resolved on the server
282
+ and its current reader token. Mount publication pages at `/pets/account`,
283
+ `/pets/submit`, `/pets/:id` and `/pets/browse/:kind`. `native` on the publication
284
+ section, references and calendar keeps resource links inside the publication.
285
+
286
+ Configure `createPawAuthHandler` with the host’s existing `sessionCookie`,
287
+ `callbackPath` and `accountPath`. An existing callback should dispatch to this
288
+ handler only when `openPawFlow(pawCookie(request, PAW_FLOW_COOKIE), state, key)`
289
+ validates. Otherwise preserve the publication’s normal authentication flow.
290
+ `GET resume?next=...` makes a top-level `prompt=none` attempt; protected pages
291
+ should call it only when the session is absent/invalid, `signin` is absent and
292
+ `PAW_SIGNED_OUT_COOKIE` is absent. Failed continuity returns `signin=required`
293
+ or `signin=retry`, preventing redirect loops. Explicit `POST start` opens the
294
+ normal sign-in. Honor and clear the sign-out marker in existing host login/logout
295
+ flows. All cookies remain host-only; do not embed the sign-in in an iframe.
296
+
297
+ The collection must explicitly set `shared_identity_provider` to its configured
298
+ OIDC provider. Auth resolves the verified provider subject; Knowledge authorizes
299
+ each accepted view and keeps ownership collection-scoped. Never correlate local
300
+ users by email or forward one application’s reader token/API key to another.
301
+ Provision and verify each RP before enabling sign-in or contribution flags.
@@ -1,4 +1,4 @@
1
- import { PET_UUID, petReferences, PET_SLUG } from './chunk-MBBPEFDA.js';
1
+ import { PET_UUID, petReferences, PET_SLUG } from './chunk-AFJ6S5WJ.js';
2
2
  import { buildClientContextHeaders } from '@scalemule/sdk';
3
3
 
4
4
  var PetRequestError = class extends Error {
@@ -60,7 +60,7 @@ function petReferences(metadata) {
60
60
  });
61
61
  }
62
62
  function resolvePetCommunity(areas, selected, preference, publicationDefault) {
63
- if (selected === "") return void 0;
63
+ if (selected === "" || selected === void 0 && preference === "all") return void 0;
64
64
  for (const candidate of [selected, preference, publicationDefault]) {
65
65
  const found = areas.find(
66
66
  (area) => area.id === candidate || area.slug === candidate
@@ -1,4 +1,4 @@
1
- import { preparePawWalk } from './chunk-MBBPEFDA.js';
1
+ import { preparePawWalk } from './chunk-AFJ6S5WJ.js';
2
2
 
3
3
  // src/meet.ts
4
4
  var MEET_ACTIVITIES = [
@@ -1,5 +1,5 @@
1
1
  import { SponsorAcknowledgment } from './chunk-4JRWZXAP.js';
2
- import { PET_SAFETY, safePetLink, adoptionAvailability } from './chunk-MBBPEFDA.js';
2
+ import { PET_SAFETY, safePetLink, adoptionAvailability } from './chunk-AFJ6S5WJ.js';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  function PawMark({ size = 36 }) {
@@ -30,6 +30,181 @@ function PawMark({ size = 36 }) {
30
30
  }
31
31
  );
32
32
  }
33
+ function PawNeighborhoodIllustration() {
34
+ return /* @__PURE__ */ jsxs(
35
+ "svg",
36
+ {
37
+ className: "paw-neighborhood-art",
38
+ viewBox: "0 0 520 460",
39
+ fill: "none",
40
+ "aria-hidden": "true",
41
+ children: [
42
+ /* @__PURE__ */ jsx(
43
+ "path",
44
+ {
45
+ d: "M42 233C42 111 124 29 257 29c134 0 220 102 220 218v153H42V233Z",
46
+ fill: "var(--paw-art-sky)"
47
+ }
48
+ ),
49
+ /* @__PURE__ */ jsx("circle", { cx: "366", cy: "112", r: "44", fill: "var(--paw-sun)" }),
50
+ /* @__PURE__ */ jsx(
51
+ "path",
52
+ {
53
+ d: "M42 262c93-99 132-19 203-52 91-43 145-27 232 52v138H42V262Z",
54
+ fill: "var(--paw-art-hill)"
55
+ }
56
+ ),
57
+ /* @__PURE__ */ jsx(
58
+ "path",
59
+ {
60
+ d: "M42 331c89-59 161-27 216-3 81 36 145-47 219-21v93H42v-69Z",
61
+ fill: "var(--paw-art-ground)"
62
+ }
63
+ ),
64
+ /* @__PURE__ */ jsx(
65
+ "path",
66
+ {
67
+ d: "M310 239c34-18 68-21 103-14M311 249c34-18 68-21 103-14",
68
+ stroke: "var(--paw-art-line)",
69
+ strokeWidth: "2",
70
+ strokeLinecap: "round",
71
+ opacity: ".45"
72
+ }
73
+ ),
74
+ /* @__PURE__ */ jsx(
75
+ "path",
76
+ {
77
+ d: "M90 190v75m29-85v75m-44-46h61m-57 31c14-15 32-15 51-7",
78
+ stroke: "var(--paw-art-line)",
79
+ strokeWidth: "3",
80
+ strokeLinecap: "round",
81
+ opacity: ".45"
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsx(
85
+ "path",
86
+ {
87
+ d: "M167 341c-29-24-33-67-5-88 16-12 44-6 59 17l27 47c15 26 36 38 58 44H167v-20Z",
88
+ fill: "var(--paw-terracotta)"
89
+ }
90
+ ),
91
+ /* @__PURE__ */ jsx(
92
+ "path",
93
+ {
94
+ d: "M173 340c-17-9-39-15-54-31-14-16-13-27-11-38",
95
+ stroke: "var(--paw-terracotta)",
96
+ strokeWidth: "17",
97
+ strokeLinecap: "round"
98
+ }
99
+ ),
100
+ /* @__PURE__ */ jsx(
101
+ "path",
102
+ {
103
+ d: "M229 283c26-17 39-43 31-67-8-25-35-34-57-18-23 17-13 49 1 68",
104
+ fill: "var(--paw-terracotta)"
105
+ }
106
+ ),
107
+ /* @__PURE__ */ jsx(
108
+ "path",
109
+ {
110
+ d: "M251 224l34 5c14 2 13 23 0 28l-36 13",
111
+ fill: "var(--paw-terracotta)"
112
+ }
113
+ ),
114
+ /* @__PURE__ */ jsx(
115
+ "path",
116
+ {
117
+ d: "M206 203c-15 1-31 13-29 33 1 11 6 18 15 17 13-1 21-18 25-37",
118
+ fill: "var(--paw-art-line)"
119
+ }
120
+ ),
121
+ /* @__PURE__ */ jsx(
122
+ "path",
123
+ {
124
+ d: "M231 285l-10 67c-1 7 9 11 28 11M264 280l2 70c0 10 10 13 25 13",
125
+ stroke: "var(--paw-terracotta)",
126
+ strokeWidth: "19",
127
+ strokeLinecap: "round"
128
+ }
129
+ ),
130
+ /* @__PURE__ */ jsx(
131
+ "path",
132
+ {
133
+ d: "M215 273l38-7",
134
+ stroke: "var(--paw-art-line)",
135
+ strokeWidth: "9",
136
+ strokeLinecap: "round"
137
+ }
138
+ ),
139
+ /* @__PURE__ */ jsx("circle", { cx: "248", cy: "223", r: "3.5", fill: "var(--paw-art-line)" }),
140
+ /* @__PURE__ */ jsx("path", { d: "M283 229h9c1 8-3 13-9 13", fill: "var(--paw-art-line)" }),
141
+ /* @__PURE__ */ jsx(
142
+ "path",
143
+ {
144
+ d: "M292 348c-9-46 1-79 33-79 33 0 47 37 48 77l-1 17h-80v-15Z",
145
+ fill: "var(--paw-art-cat)"
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx("path", { d: "M303 277l-6-43 26 20 23-22 2 48", fill: "var(--paw-art-cat)" }),
149
+ /* @__PURE__ */ jsx(
150
+ "path",
151
+ {
152
+ d: "M365 351c27-4 45-15 41-39-2-11-15-16-24-10",
153
+ stroke: "var(--paw-art-cat)",
154
+ strokeWidth: "12",
155
+ strokeLinecap: "round"
156
+ }
157
+ ),
158
+ /* @__PURE__ */ jsx(
159
+ "path",
160
+ {
161
+ d: "M316 277h3m17-2h3m-13 10 3 2-3 3m-21-5-15-3m16 9-17 2m54-10 16-5m-14 13 15 1",
162
+ stroke: "var(--paw-art-line)",
163
+ strokeWidth: "2.5",
164
+ strokeLinecap: "round"
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsx(
168
+ "path",
169
+ {
170
+ d: "M145 378h245",
171
+ stroke: "var(--paw-art-line)",
172
+ strokeWidth: "2",
173
+ strokeLinecap: "round",
174
+ opacity: ".3"
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsx("circle", { cx: "99", cy: "365", r: "16", fill: "var(--paw-sun)" }),
178
+ /* @__PURE__ */ jsx(
179
+ "path",
180
+ {
181
+ d: "M93 351c16 8 18 18 12 28",
182
+ stroke: "var(--paw-art-line)",
183
+ strokeWidth: "2"
184
+ }
185
+ ),
186
+ /* @__PURE__ */ jsx(
187
+ "path",
188
+ {
189
+ d: "M426 352v-43m0 22c-14-1-20-10-20-20 15 2 21 11 20 20m0-9c0-15 6-25 20-28 2 13-6 24-20 28",
190
+ stroke: "var(--paw-art-line)",
191
+ strokeWidth: "3",
192
+ strokeLinecap: "round"
193
+ }
194
+ ),
195
+ /* @__PURE__ */ jsx(
196
+ "path",
197
+ {
198
+ d: "m406 153 8-6 8 6m-234-33 8-6 8 6",
199
+ stroke: "var(--paw-art-line)",
200
+ strokeWidth: "2.5",
201
+ strokeLinecap: "round"
202
+ }
203
+ )
204
+ ]
205
+ }
206
+ );
207
+ }
33
208
  function Photo({
34
209
  resource,
35
210
  mediaUrl,
@@ -301,22 +476,19 @@ function PetsSection({
301
476
  }
302
477
  ) : /* @__PURE__ */ jsxs("section", { className: "paw-welcome", children: [
303
478
  /* @__PURE__ */ jsxs("div", { children: [
479
+ /* @__PURE__ */ jsx("p", { className: "paw-eyebrow", children: "Life is better together" }),
304
480
  /* @__PURE__ */ jsxs("h1", { children: [
305
- "Every pet has a story.",
481
+ "Every pet.",
306
482
  /* @__PURE__ */ jsx("br", {}),
307
- "Let\u2019s meet yours."
483
+ /* @__PURE__ */ jsx("em", { children: "A local story." })
308
484
  ] }),
309
485
  /* @__PURE__ */ jsx("p", { children: "A place for familiar faces, happy reunions and the everyday joy of life with pets." }),
310
486
  contributeUrl && /* @__PURE__ */ jsx("a", { className: "paw-button", href: safePetLink(contributeUrl), children: "Submit for Paw of the Week" }),
311
487
  /* @__PURE__ */ jsx("small", { children: "Free to enter. Thoughtfully selected by local editors." })
312
488
  ] }),
313
- /* @__PURE__ */ jsxs("div", { className: "paw-emblem", children: [
314
- /* @__PURE__ */ jsx(PawMark, { size: 180 }),
315
- /* @__PURE__ */ jsxs("span", { children: [
316
- "Good neighbors.",
317
- /* @__PURE__ */ jsx("br", {}),
318
- "Great companions."
319
- ] })
489
+ /* @__PURE__ */ jsxs("div", { className: "paw-illustration", children: [
490
+ /* @__PURE__ */ jsx(PawNeighborhoodIllustration, {}),
491
+ /* @__PURE__ */ jsx("p", { children: "Good neighbors. Great companions." })
320
492
  ] })
321
493
  ] }),
322
494
  !unavailable && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -441,4 +613,4 @@ function PetsSection({
441
613
  ] });
442
614
  }
443
615
 
444
- export { AdoptionListingCard, LostPetNotice, PawMark, PawOfTheWeekCard, PetCelebrationCard, PetEventCard, PetFriendlyPlaceCard, PetProfileCard, PetsSection, SponsorAcknowledgment2 as SponsorAcknowledgment };
616
+ export { AdoptionListingCard, LostPetNotice, PawMark, PawNeighborhoodIllustration, PawOfTheWeekCard, PetCelebrationCard, PetEventCard, PetFriendlyPlaceCard, PetProfileCard, PetsSection, SponsorAcknowledgment2 as SponsorAcknowledgment };
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
+ export { NetworkCopyrightNotice } from './chunk-WAC6ATNP.js';
1
2
  export { CURATED_COMMUNITY_CARDS, VerifiedCardComponent, VerifiedCardSection, getArticleCards, isSafeActionUrl } from './chunk-FMCHQI7K.js';
3
+ export { MEET_ACTIVITIES, activityLabel, canHostMeetup, isAdult, prepareMeetup, screenMessage } from './chunk-AMLVCZDP.js';
2
4
  export { CookieConsentBanner } from './chunk-GOWOYMSG.js';
3
5
  export { CookieSettingsView } from './chunk-UL2Q3N26.js';
4
6
  export { THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, ThemeToggle, applyTheme, clearTheme, getStoredTheme, getSystemTheme, resolveEffectiveTheme, setTheme, subscribeTheme, themeInitScript } from './chunk-NQD3M7ZY.js';
5
7
  export { LocalNetworkBar } from './chunk-2XSW7JZS.js';
6
- export { NetworkCopyrightNotice } from './chunk-WAC6ATNP.js';
7
8
  import { localPublications } from './chunk-JV76ZEIA.js';
8
9
  export { COOKIE_CATEGORIES, COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, COOKIE_CONSENT_MAX_AGE_SECONDS, DEFAULT_CONSENT_HUB_URL, DEFAULT_PREFERENCES_ACCEPTED, DEFAULT_PREFERENCES_REJECTED, EDITORIAL_PRINCIPLES, EU_EEA_UK_COUNTRIES, NETWORK_CONSENT_STORAGE_KEY, NETWORK_PARENT, acceptAllCookies, checkUrlConsentBridge, clearCookieConsent, communityPublications, decorateNetworkUrl, findPublicationByHost, findPublicationBySlug, getCookieConsent, getNetworkPublicationUrl, hasConsented, isCategoryAllowed, isGeoConsentRequired, listedPublications, localPublications, queryNetworkConsentHub, recordConsentToCompliance, rejectOptionalCookies, setCookieConsent, setNetworkConsentHub } from './chunk-JV76ZEIA.js';
9
10
  export { communityMapEmbeds } from './chunk-IMYBSG7J.js';
@@ -11,9 +12,8 @@ export { formatArtworkCaption, parseDocumentBlocks, renderArticleBlocksToHtml, s
11
12
  import { definePublication } from './chunk-57YVL6BD.js';
12
13
  export { BROADSHEET_THEME, FEATURE_NAMES, LAYOUT_COOKIE, acceptRemoteRecord, acceptSnapshot, definePublication, featureEnabled, parseSnapshot, publicationFromSnapshot, publicationRecord, resolveLayout, snapshotFromRecord, syncPublication } from './chunk-57YVL6BD.js';
13
14
  export { CLASSIFIED_CATEGORIES, JOB_EMPLOYMENT_TYPES, categoryLabel, classifiedPath, classifiedSearchPath, clipChars, dealDollars, dealGoPath, dealsFeedPath, employmentLabel, isClassifiedCategory, isEmploymentType, jobEmployerBody, jobOpeningBody, jobPostingBody, prepareClassified, prepareJobPost, publicJobPath, publicJobsPath } from './chunk-C7ZPLH2K.js';
14
- export { MEET_ACTIVITIES, activityLabel, canHostMeetup, isAdult, prepareMeetup, screenMessage } from './chunk-2MEYHM7M.js';
15
15
  export { SPONSORSHIP_OFFERINGS, SPONSORSHIP_POLICY, placementAvailable, safeSponsorUrl } from './chunk-66GI2IX6.js';
16
- import './chunk-MBBPEFDA.js';
16
+ import './chunk-AFJ6S5WJ.js';
17
17
  import { jsxs, jsx } from 'react/jsx-runtime';
18
18
 
19
19
  // src/editorial.ts
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { MEET_ACTIVITIES } from './chunk-2MEYHM7M.js';
3
- import './chunk-MBBPEFDA.js';
2
+ import { MEET_ACTIVITIES } from './chunk-AMLVCZDP.js';
3
+ import './chunk-AFJ6S5WJ.js';
4
4
  import { useState } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
 
@@ -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: "other" | "walk" | "coffee" | "hike" | "pickleball" | "tennis" | "soccer" | "bike" | "dogs" | "books" | "games" | "kids" | "volunteer";
21
+ value: "walk" | "other" | "coffee" | "hike" | "pickleball" | "tennis" | "soccer" | "bike" | "dogs" | "books" | "games" | "kids" | "volunteer";
22
22
  label: string;
23
23
  }[];
24
24
 
@@ -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: "other" | "walk" | "coffee" | "hike" | "pickleball" | "tennis" | "soccer" | "bike" | "dogs" | "books" | "games" | "kids" | "volunteer";
21
+ value: "walk" | "other" | "coffee" | "hike" | "pickleball" | "tennis" | "soccer" | "bike" | "dogs" | "books" | "games" | "kids" | "volunteer";
22
22
  label: string;
23
23
  }[];
24
24
 
package/dist/meet-view.js CHANGED
@@ -1,5 +1,5 @@
1
- import { MEET_ACTIVITIES, activityLabel } from './chunk-2MEYHM7M.js';
2
- import { PET_SAFETY } from './chunk-MBBPEFDA.js';
1
+ import { MEET_ACTIVITIES, activityLabel } from './chunk-AMLVCZDP.js';
2
+ import { PET_SAFETY } from './chunk-AFJ6S5WJ.js';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  function MeetBoard({ region, meetups }) {
@@ -56,10 +56,13 @@ async function petRequest(scope, path, init = {}, fetcher = fetch) {
56
56
 
57
57
  // src/pets-auth-server.ts
58
58
  var PAW_SESSION_COOKIE = "__Host-paw-reader";
59
- var FLOW = "__Host-paw-signin";
59
+ var PAW_FLOW_COOKIE = "__Host-paw-signin";
60
+ var PAW_SIGNED_OUT_COOKIE = "__Host-paw-signed-out";
61
+ var FLOW = PAW_FLOW_COOKIE;
60
62
  var attrs = "Path=/; HttpOnly; Secure; SameSite=Lax";
61
63
  function pawCookie(request, name = PAW_SESSION_COOKIE) {
62
- return request.headers.get("cookie")?.split(";").map((v) => v.trim()).find((v) => v.startsWith(name + "="))?.slice(name.length + 1);
64
+ const values = (request.headers.get("cookie") || "").split(";").map((v) => v.trim()).filter((v) => v.startsWith(name + "="));
65
+ return values.length === 1 ? values[0].slice(name.length + 1) : void 0;
63
66
  }
64
67
  function digest(value) {
65
68
  return crypto.createHash("sha256").update(value).digest("hex");
@@ -108,6 +111,15 @@ function createPawAuthHandler(options) {
108
111
  const scope = await options.resolve(request), origin = new URL(scope.origin).origin;
109
112
  if (!origin.startsWith("https://") || !scope.apiKey)
110
113
  return json({ error: "Sign-in is not configured." }, 503);
114
+ const account = returnPath(options.accountPath || "/account");
115
+ const sessionCookie = options.sessionCookie || PAW_SESSION_COOKIE;
116
+ if (!/^[A-Za-z0-9_-]{1,100}$/.test(sessionCookie))
117
+ throw new Error("Invalid cookie name");
118
+ const retryPath = (path, reason) => {
119
+ const target = new URL(returnPath(path), origin);
120
+ target.searchParams.set("signin", reason);
121
+ return target.pathname + target.search;
122
+ };
111
123
  const redirect = (path) => new Response(null, {
112
124
  status: 303,
113
125
  headers: {
@@ -115,33 +127,60 @@ function createPawAuthHandler(options) {
115
127
  location: origin + returnPath(path)
116
128
  }
117
129
  });
118
- if (action === "start" && request.method === "POST") {
119
- if (request.headers.get("origin") !== origin)
130
+ const resuming = action === "resume" && request.method === "GET";
131
+ if (resuming || action === "start" && request.method === "POST") {
132
+ if (!resuming && request.headers.get("origin") !== origin || resuming && (request.headers.has("sec-fetch-mode") && request.headers.get("sec-fetch-mode") !== "navigate" || request.headers.has("sec-fetch-dest") && request.headers.get("sec-fetch-dest") !== "document"))
120
133
  return json({ error: "Sign in from this website." }, 403);
121
- const callback = origin + "/api/paw-auth/callback";
134
+ const next = returnPath(
135
+ new URL(request.url).searchParams.get("next") || account
136
+ );
137
+ if (resuming && pawCookie(request, PAW_SIGNED_OUT_COOKIE))
138
+ return redirect(retryPath(next, "required"));
139
+ const callback = origin + returnPath(options.callbackPath || "/api/paw-auth/callback");
122
140
  const result = await petRequest(
123
141
  scope,
124
- "/v1/auth/oauth/ledvery/authorize?" + new URLSearchParams({ redirect_uri: callback }),
142
+ "/v1/auth/oauth/ledvery/authorize?" + new URLSearchParams({
143
+ redirect_uri: callback,
144
+ ...resuming ? { prompt: "none" } : {}
145
+ }),
125
146
  {},
126
147
  options.fetch
127
148
  );
128
149
  const url = new URL(result.url);
129
- if (url.origin !== new URL(options.issuerOrigin).origin || url.pathname !== "/authorize" || url.username || url.password || url.searchParams.get("state") !== result.state || url.searchParams.get("redirect_uri") !== callback || url.searchParams.get("code_challenge_method") !== "S256" || !url.searchParams.get("code_challenge"))
150
+ if (url.protocol !== "https:" || url.origin !== new URL(options.issuerOrigin).origin || url.pathname !== "/authorize" || url.username || url.password || url.searchParams.get("state") !== result.state || url.searchParams.get("redirect_uri") !== callback || url.searchParams.get("code_challenge_method") !== "S256" || !url.searchParams.get("code_challenge"))
130
151
  throw new Error("Invalid authorization response");
131
- const response = json({ url: url.href });
152
+ const response = resuming ? new Response(null, {
153
+ status: 303,
154
+ headers: { ...petPrivateHeaders, location: url.href }
155
+ }) : json({ url: url.href });
156
+ if (!resuming)
157
+ response.headers.append(
158
+ "set-cookie",
159
+ `${PAW_SIGNED_OUT_COOKIE}=; ${attrs}; Max-Age=0`
160
+ );
132
161
  response.headers.append(
133
162
  "set-cookie",
134
- `${FLOW}=${sealPawFlow(result.state, returnPath(new URL(request.url).searchParams.get("next")), scope.apiKey)}; ${attrs}; Max-Age=600`
163
+ `${FLOW}=${sealPawFlow(result.state, next, scope.apiKey)}; ${attrs}; Max-Age=600`
135
164
  );
136
165
  return response;
137
166
  }
138
167
  if (action === "callback" && request.method === "GET") {
139
168
  const query = new URL(request.url).searchParams, code = query.get("code"), state = query.get("state");
140
169
  const next = openPawFlow(pawCookie(request, FLOW), state, scope.apiKey);
141
- const response = redirect(next || "/account?signin=retry");
170
+ const response = redirect(next || retryPath(account, "retry"));
142
171
  response.headers.append("set-cookie", `${FLOW}=; ${attrs}; Max-Age=0`);
143
- if (!next || !code || code.length > 4096 || query.has("error"))
172
+ if (!next || !code || code.length > 4096 || query.has("error")) {
173
+ response.headers.set(
174
+ "location",
175
+ origin + retryPath(
176
+ next || account,
177
+ ["login_required", "consent_required"].includes(
178
+ query.get("error") || ""
179
+ ) ? "required" : "retry"
180
+ )
181
+ );
144
182
  return response;
183
+ }
145
184
  try {
146
185
  const session = await petRequest(
147
186
  scope,
@@ -162,11 +201,11 @@ function createPawAuthHandler(options) {
162
201
  throw new Error("Verified reader required");
163
202
  response.headers.append(
164
203
  "set-cookie",
165
- `${PAW_SESSION_COOKIE}=${session.session_token}; ${attrs}; Expires=${new Date(expiry).toUTCString()}`
204
+ `${sessionCookie}=${session.session_token}; ${attrs}; Expires=${new Date(expiry).toUTCString()}`
166
205
  );
167
206
  return response;
168
207
  } catch {
169
- response.headers.set("location", origin + "/account?signin=retry");
208
+ response.headers.set("location", origin + retryPath(next, "retry"));
170
209
  return response;
171
210
  }
172
211
  }
@@ -191,7 +230,11 @@ function createPawAuthHandler(options) {
191
230
  const response = json({ authenticated: false });
192
231
  response.headers.append(
193
232
  "set-cookie",
194
- `${PAW_SESSION_COOKIE}=; ${attrs}; Max-Age=0`
233
+ `${sessionCookie}=; ${attrs}; Max-Age=0`
234
+ );
235
+ response.headers.append(
236
+ "set-cookie",
237
+ `${PAW_SIGNED_OUT_COOKIE}=1; ${attrs}; Max-Age=2592000`
195
238
  );
196
239
  return response;
197
240
  }
@@ -205,7 +248,9 @@ function createPawAuthHandler(options) {
205
248
  };
206
249
  }
207
250
 
251
+ exports.PAW_FLOW_COOKIE = PAW_FLOW_COOKIE;
208
252
  exports.PAW_SESSION_COOKIE = PAW_SESSION_COOKIE;
253
+ exports.PAW_SIGNED_OUT_COOKIE = PAW_SIGNED_OUT_COOKIE;
209
254
  exports.createPawAuthHandler = createPawAuthHandler;
210
255
  exports.openPawFlow = openPawFlow;
211
256
  exports.pawCookie = pawCookie;
@@ -4,6 +4,8 @@ import './sponsorships-CtnBe3S8.cjs';
4
4
  import './pets.cjs';
5
5
 
6
6
  declare const PAW_SESSION_COOKIE = "__Host-paw-reader";
7
+ declare const PAW_FLOW_COOKIE = "__Host-paw-signin";
8
+ declare const PAW_SIGNED_OUT_COOKIE = "__Host-paw-signed-out";
7
9
  declare function pawCookie(request: Request, name?: string): string | undefined;
8
10
  declare function sealPawFlow(state: string, next: string, key: string, now?: number): string;
9
11
  declare function openPawFlow(raw: string | undefined, state: string | null, key: string, now?: number): string | null;
@@ -11,7 +13,11 @@ declare function createPawAuthHandler(options: {
11
13
  resolve(request: Request): Promise<PetScope>;
12
14
  enabled: boolean;
13
15
  issuerOrigin: string;
16
+ /** Reuse the publication’s existing host-only reader cookie and registered callback. */
17
+ sessionCookie?: string;
18
+ callbackPath?: string;
19
+ accountPath?: string;
14
20
  fetch?: typeof fetch;
15
21
  }): (request: Request, action: string) => Promise<Response>;
16
22
 
17
- export { PAW_SESSION_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };
23
+ export { PAW_FLOW_COOKIE, PAW_SESSION_COOKIE, PAW_SIGNED_OUT_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };
@@ -4,6 +4,8 @@ import './sponsorships-CtnBe3S8.js';
4
4
  import './pets.js';
5
5
 
6
6
  declare const PAW_SESSION_COOKIE = "__Host-paw-reader";
7
+ declare const PAW_FLOW_COOKIE = "__Host-paw-signin";
8
+ declare const PAW_SIGNED_OUT_COOKIE = "__Host-paw-signed-out";
7
9
  declare function pawCookie(request: Request, name?: string): string | undefined;
8
10
  declare function sealPawFlow(state: string, next: string, key: string, now?: number): string;
9
11
  declare function openPawFlow(raw: string | undefined, state: string | null, key: string, now?: number): string | null;
@@ -11,7 +13,11 @@ declare function createPawAuthHandler(options: {
11
13
  resolve(request: Request): Promise<PetScope>;
12
14
  enabled: boolean;
13
15
  issuerOrigin: string;
16
+ /** Reuse the publication’s existing host-only reader cookie and registered callback. */
17
+ sessionCookie?: string;
18
+ callbackPath?: string;
19
+ accountPath?: string;
14
20
  fetch?: typeof fetch;
15
21
  }): (request: Request, action: string) => Promise<Response>;
16
22
 
17
- export { PAW_SESSION_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };
23
+ export { PAW_FLOW_COOKIE, PAW_SESSION_COOKIE, PAW_SIGNED_OUT_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };