@scalemule/news-publication 0.0.47 → 0.0.49

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 (73) hide show
  1. package/README.md +28 -0
  2. package/dist/{chunk-GB36YM56.js → chunk-2MEYHM7M.js} +11 -1
  3. package/dist/chunk-4JRWZXAP.js +62 -0
  4. package/dist/chunk-MBBPEFDA.js +124 -0
  5. package/dist/chunk-TTLM7YOH.js +444 -0
  6. package/dist/chunk-ZXH3O537.js +251 -0
  7. package/dist/community-maps-view.d.cts +3 -3
  8. package/dist/community-maps-view.d.ts +3 -3
  9. package/dist/cookie-consent-banner.d.cts +2 -2
  10. package/dist/cookie-consent-banner.d.ts +2 -2
  11. package/dist/cookie-settings-view.d.cts +2 -2
  12. package/dist/cookie-settings-view.d.ts +2 -2
  13. package/dist/index.cjs +74 -3
  14. package/dist/index.d.cts +12 -4
  15. package/dist/index.d.ts +12 -4
  16. package/dist/index.js +49 -6
  17. package/dist/marketplace-forms.d.cts +3 -3
  18. package/dist/marketplace-forms.d.ts +3 -3
  19. package/dist/marketplace-view.d.cts +5 -5
  20. package/dist/marketplace-view.d.ts +5 -5
  21. package/dist/{meet-RWmfj3I3.d.cts → meet-BWpxY20X.d.ts} +5 -0
  22. package/dist/{meet-RWmfj3I3.d.ts → meet-CO9Unz5M.d.cts} +5 -0
  23. package/dist/meet-forms.d.cts +7 -6
  24. package/dist/meet-forms.d.ts +7 -6
  25. package/dist/meet-forms.js +2 -1
  26. package/dist/meet-view.cjs +22 -2
  27. package/dist/meet-view.d.cts +7 -5
  28. package/dist/meet-view.d.ts +7 -5
  29. package/dist/meet-view.js +21 -4
  30. package/dist/network-bar.d.cts +2 -2
  31. package/dist/network-bar.d.ts +2 -2
  32. package/dist/network-copyright.d.cts +2 -2
  33. package/dist/network-copyright.d.ts +2 -2
  34. package/dist/pets-auth-server.cjs +212 -0
  35. package/dist/pets-auth-server.d.cts +17 -0
  36. package/dist/pets-auth-server.d.ts +17 -0
  37. package/dist/pets-auth-server.js +155 -0
  38. package/dist/pets-forms.cjs +762 -0
  39. package/dist/pets-forms.d.cts +26 -0
  40. package/dist/pets-forms.d.ts +26 -0
  41. package/dist/pets-forms.js +712 -0
  42. package/dist/pets-interactions.cjs +332 -0
  43. package/dist/pets-interactions.d.cts +20 -0
  44. package/dist/pets-interactions.d.ts +20 -0
  45. package/dist/pets-interactions.js +319 -0
  46. package/dist/pets-publication.cjs +818 -0
  47. package/dist/pets-publication.d.cts +36 -0
  48. package/dist/pets-publication.d.ts +36 -0
  49. package/dist/pets-publication.js +177 -0
  50. package/dist/pets-server.cjs +289 -0
  51. package/dist/pets-server.d.cts +42 -0
  52. package/dist/pets-server.d.ts +42 -0
  53. package/dist/pets-server.js +2 -0
  54. package/dist/pets-view.cjs +541 -0
  55. package/dist/pets-view.d.cts +56 -0
  56. package/dist/pets-view.d.ts +56 -0
  57. package/dist/pets-view.js +4 -0
  58. package/dist/pets.cjs +138 -0
  59. package/dist/pets.d.cts +127 -0
  60. package/dist/pets.d.ts +127 -0
  61. package/dist/pets.js +1 -0
  62. package/dist/sponsorship-view.d.cts +2 -2
  63. package/dist/sponsorship-view.d.ts +2 -2
  64. package/dist/sponsorship-view.js +2 -62
  65. package/dist/story-review.d.cts +6 -6
  66. package/dist/story-review.d.ts +6 -6
  67. package/dist/theme-toggle.d.cts +2 -2
  68. package/dist/theme-toggle.d.ts +2 -2
  69. package/dist/verified-card.d.cts +3 -3
  70. package/dist/verified-card.d.ts +3 -3
  71. package/package.json +40 -3
  72. package/pets.css +538 -0
  73. package/tokens/broadsheet.css +46 -0
@@ -0,0 +1,212 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('crypto');
4
+ var sdk = require('@scalemule/sdk');
5
+
6
+ // src/pets-auth-server.ts
7
+
8
+ // src/pets.ts
9
+ var PET_SLUG = /^[a-z0-9][a-z0-9-]{0,190}$/;
10
+
11
+ // src/pets-server.ts
12
+ var PetRequestError = class extends Error {
13
+ constructor(status, message) {
14
+ super(message);
15
+ this.status = status;
16
+ }
17
+ status;
18
+ };
19
+ var petPrivateHeaders = {
20
+ "cache-control": "private, no-store",
21
+ "x-robots-tag": "noindex, nofollow",
22
+ "referrer-policy": "no-referrer",
23
+ "x-content-type-options": "nosniff"
24
+ };
25
+ function config(scope) {
26
+ const url = new URL(scope.gatewayUrl);
27
+ if (!scope.apiKey || !PET_SLUG.test(scope.collectionSlug) || url.username || url.password || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1"].includes(url.hostname)))
28
+ throw new PetRequestError(503, "The pet community is not available yet.");
29
+ return url.origin;
30
+ }
31
+ async function petRequest(scope, path, init = {}, fetcher = fetch) {
32
+ const gateway = config(scope);
33
+ if (!path.startsWith("/v1/") || path.includes("..") || /[\\\r\n]/.test(path))
34
+ throw new Error("Invalid platform path");
35
+ const response = await fetcher(gateway + path, {
36
+ method: init.method || "GET",
37
+ headers: {
38
+ ...sdk.buildClientContextHeaders(scope.clientContext),
39
+ "x-api-key": scope.apiKey,
40
+ "content-type": "application/json",
41
+ ...scope.accessToken ? { authorization: `Bearer ${scope.accessToken}` } : {}
42
+ },
43
+ body: init.body === void 0 ? void 0 : JSON.stringify(init.body),
44
+ cache: "no-store",
45
+ redirect: "error",
46
+ signal: AbortSignal.timeout(15e3)
47
+ });
48
+ if (!response.ok)
49
+ throw new PetRequestError(
50
+ response.status,
51
+ response.status === 401 ? "Please sign in to continue." : response.status === 404 ? "This pet resource is not available." : response.status === 409 ? "This contribution changed. Reload before saving." : response.status === 429 ? "Please wait before trying again." : "We couldn\u2019t complete that request. Please try again."
52
+ );
53
+ const json = await response.json();
54
+ return json?.data ?? json;
55
+ }
56
+
57
+ // src/pets-auth-server.ts
58
+ var PAW_SESSION_COOKIE = "__Host-paw-reader";
59
+ var FLOW = "__Host-paw-signin";
60
+ var attrs = "Path=/; HttpOnly; Secure; SameSite=Lax";
61
+ 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);
63
+ }
64
+ function digest(value) {
65
+ return crypto.createHash("sha256").update(value).digest("hex");
66
+ }
67
+ function returnPath(value) {
68
+ return typeof value === "string" && value.startsWith("/") && !value.startsWith("//") && value.length <= 500 && !/[\\\r\n]/.test(value) ? value : "/account";
69
+ }
70
+ function sealPawFlow(state, next, key, now = Date.now()) {
71
+ const payload = Buffer.from(
72
+ JSON.stringify({
73
+ state: digest(state),
74
+ next: returnPath(next),
75
+ expires: now + 6e5
76
+ })
77
+ ).toString("base64url");
78
+ return payload + "." + crypto.createHmac("sha256", key).update("paw-signin:v1:" + payload).digest("hex");
79
+ }
80
+ function openPawFlow(raw, state, key, now = Date.now()) {
81
+ if (!key || !raw || raw.length > 2048 || !state || state.length > 2048)
82
+ return null;
83
+ const [payload, signature, extra] = raw.split(".");
84
+ if (!payload || extra || !/^[a-f0-9]{64}$/.test(signature || "")) return null;
85
+ if (!crypto.timingSafeEqual(
86
+ Buffer.from(signature, "hex"),
87
+ crypto.createHmac("sha256", key).update("paw-signin:v1:" + payload).digest()
88
+ ))
89
+ return null;
90
+ try {
91
+ const flow = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
92
+ if (!Number.isFinite(flow.expires) || flow.expires <= now || !/^[a-f0-9]{64}$/.test(flow.state) || !crypto.timingSafeEqual(
93
+ Buffer.from(flow.state, "hex"),
94
+ Buffer.from(digest(state), "hex")
95
+ ))
96
+ return null;
97
+ return returnPath(flow.next);
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ function createPawAuthHandler(options) {
103
+ return async (request, action) => {
104
+ const json = (body, status = 200) => Response.json(body, { status, headers: petPrivateHeaders });
105
+ try {
106
+ if (!options.enabled)
107
+ return json({ error: "Community sign-in is not available yet." }, 503);
108
+ const scope = await options.resolve(request), origin = new URL(scope.origin).origin;
109
+ if (!origin.startsWith("https://") || !scope.apiKey)
110
+ return json({ error: "Sign-in is not configured." }, 503);
111
+ const redirect = (path) => new Response(null, {
112
+ status: 303,
113
+ headers: {
114
+ ...petPrivateHeaders,
115
+ location: origin + returnPath(path)
116
+ }
117
+ });
118
+ if (action === "start" && request.method === "POST") {
119
+ if (request.headers.get("origin") !== origin)
120
+ return json({ error: "Sign in from this website." }, 403);
121
+ const callback = origin + "/api/paw-auth/callback";
122
+ const result = await petRequest(
123
+ scope,
124
+ "/v1/auth/oauth/ledvery/authorize?" + new URLSearchParams({ redirect_uri: callback }),
125
+ {},
126
+ options.fetch
127
+ );
128
+ 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"))
130
+ throw new Error("Invalid authorization response");
131
+ const response = json({ url: url.href });
132
+ response.headers.append(
133
+ "set-cookie",
134
+ `${FLOW}=${sealPawFlow(result.state, returnPath(new URL(request.url).searchParams.get("next")), scope.apiKey)}; ${attrs}; Max-Age=600`
135
+ );
136
+ return response;
137
+ }
138
+ if (action === "callback" && request.method === "GET") {
139
+ const query = new URL(request.url).searchParams, code = query.get("code"), state = query.get("state");
140
+ const next = openPawFlow(pawCookie(request, FLOW), state, scope.apiKey);
141
+ const response = redirect(next || "/account?signin=retry");
142
+ response.headers.append("set-cookie", `${FLOW}=; ${attrs}; Max-Age=0`);
143
+ if (!next || !code || code.length > 4096 || query.has("error"))
144
+ return response;
145
+ try {
146
+ const session = await petRequest(
147
+ scope,
148
+ "/v1/auth/oauth/ledvery/callback?" + new URLSearchParams({ code, state }),
149
+ {},
150
+ options.fetch
151
+ );
152
+ const expiry = Date.parse(session.expires_at);
153
+ if (!session.session_token || !/^[A-Za-z0-9._~-]{1,2048}$/.test(session.session_token) || !Number.isFinite(expiry) || expiry <= Date.now())
154
+ throw new Error("Invalid session");
155
+ const me = await petRequest(
156
+ { ...scope, accessToken: session.session_token },
157
+ "/v1/auth/me",
158
+ {},
159
+ options.fetch
160
+ );
161
+ if (!me.id || !me.email_verified)
162
+ throw new Error("Verified reader required");
163
+ response.headers.append(
164
+ "set-cookie",
165
+ `${PAW_SESSION_COOKIE}=${session.session_token}; ${attrs}; Expires=${new Date(expiry).toUTCString()}`
166
+ );
167
+ return response;
168
+ } catch {
169
+ response.headers.set("location", origin + "/account?signin=retry");
170
+ return response;
171
+ }
172
+ }
173
+ if (action === "session" && request.method === "GET") {
174
+ if (!scope.accessToken) return json({ authenticated: false });
175
+ const me = await petRequest(scope, "/v1/auth/me", {}, options.fetch);
176
+ return json({
177
+ authenticated: Boolean(me.id && me.email_verified),
178
+ name: me.full_name || "Neighbor"
179
+ });
180
+ }
181
+ if (action === "logout" && request.method === "POST") {
182
+ if (request.headers.get("origin") !== origin)
183
+ return json({ error: "Continue from this website." }, 403);
184
+ if (scope.accessToken)
185
+ await petRequest(
186
+ scope,
187
+ "/v1/auth/logout",
188
+ { method: "POST", body: { session_token: scope.accessToken } },
189
+ options.fetch
190
+ );
191
+ const response = json({ authenticated: false });
192
+ response.headers.append(
193
+ "set-cookie",
194
+ `${PAW_SESSION_COOKIE}=; ${attrs}; Max-Age=0`
195
+ );
196
+ return response;
197
+ }
198
+ return json({ error: "Route not found" }, 404);
199
+ } catch {
200
+ return json(
201
+ { error: "Sign-in is temporarily unavailable. Please try again." },
202
+ 503
203
+ );
204
+ }
205
+ };
206
+ }
207
+
208
+ exports.PAW_SESSION_COOKIE = PAW_SESSION_COOKIE;
209
+ exports.createPawAuthHandler = createPawAuthHandler;
210
+ exports.openPawFlow = openPawFlow;
211
+ exports.pawCookie = pawCookie;
212
+ exports.sealPawFlow = sealPawFlow;
@@ -0,0 +1,17 @@
1
+ import { PetScope } from './pets-server.cjs';
2
+ import '@scalemule/sdk';
3
+ import './sponsorships-CtnBe3S8.cjs';
4
+ import './pets.cjs';
5
+
6
+ declare const PAW_SESSION_COOKIE = "__Host-paw-reader";
7
+ declare function pawCookie(request: Request, name?: string): string | undefined;
8
+ declare function sealPawFlow(state: string, next: string, key: string, now?: number): string;
9
+ declare function openPawFlow(raw: string | undefined, state: string | null, key: string, now?: number): string | null;
10
+ declare function createPawAuthHandler(options: {
11
+ resolve(request: Request): Promise<PetScope>;
12
+ enabled: boolean;
13
+ issuerOrigin: string;
14
+ fetch?: typeof fetch;
15
+ }): (request: Request, action: string) => Promise<Response>;
16
+
17
+ export { PAW_SESSION_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };
@@ -0,0 +1,17 @@
1
+ import { PetScope } from './pets-server.js';
2
+ import '@scalemule/sdk';
3
+ import './sponsorships-CtnBe3S8.js';
4
+ import './pets.js';
5
+
6
+ declare const PAW_SESSION_COOKIE = "__Host-paw-reader";
7
+ declare function pawCookie(request: Request, name?: string): string | undefined;
8
+ declare function sealPawFlow(state: string, next: string, key: string, now?: number): string;
9
+ declare function openPawFlow(raw: string | undefined, state: string | null, key: string, now?: number): string | null;
10
+ declare function createPawAuthHandler(options: {
11
+ resolve(request: Request): Promise<PetScope>;
12
+ enabled: boolean;
13
+ issuerOrigin: string;
14
+ fetch?: typeof fetch;
15
+ }): (request: Request, action: string) => Promise<Response>;
16
+
17
+ export { PAW_SESSION_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };
@@ -0,0 +1,155 @@
1
+ import { petPrivateHeaders, petRequest } from './chunk-ZXH3O537.js';
2
+ import './chunk-MBBPEFDA.js';
3
+ import { createHmac, timingSafeEqual, createHash } from 'crypto';
4
+
5
+ var PAW_SESSION_COOKIE = "__Host-paw-reader";
6
+ var FLOW = "__Host-paw-signin";
7
+ var attrs = "Path=/; HttpOnly; Secure; SameSite=Lax";
8
+ function pawCookie(request, name = PAW_SESSION_COOKIE) {
9
+ return request.headers.get("cookie")?.split(";").map((v) => v.trim()).find((v) => v.startsWith(name + "="))?.slice(name.length + 1);
10
+ }
11
+ function digest(value) {
12
+ return createHash("sha256").update(value).digest("hex");
13
+ }
14
+ function returnPath(value) {
15
+ return typeof value === "string" && value.startsWith("/") && !value.startsWith("//") && value.length <= 500 && !/[\\\r\n]/.test(value) ? value : "/account";
16
+ }
17
+ function sealPawFlow(state, next, key, now = Date.now()) {
18
+ const payload = Buffer.from(
19
+ JSON.stringify({
20
+ state: digest(state),
21
+ next: returnPath(next),
22
+ expires: now + 6e5
23
+ })
24
+ ).toString("base64url");
25
+ return payload + "." + createHmac("sha256", key).update("paw-signin:v1:" + payload).digest("hex");
26
+ }
27
+ function openPawFlow(raw, state, key, now = Date.now()) {
28
+ if (!key || !raw || raw.length > 2048 || !state || state.length > 2048)
29
+ return null;
30
+ const [payload, signature, extra] = raw.split(".");
31
+ if (!payload || extra || !/^[a-f0-9]{64}$/.test(signature || "")) return null;
32
+ if (!timingSafeEqual(
33
+ Buffer.from(signature, "hex"),
34
+ createHmac("sha256", key).update("paw-signin:v1:" + payload).digest()
35
+ ))
36
+ return null;
37
+ try {
38
+ const flow = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
39
+ if (!Number.isFinite(flow.expires) || flow.expires <= now || !/^[a-f0-9]{64}$/.test(flow.state) || !timingSafeEqual(
40
+ Buffer.from(flow.state, "hex"),
41
+ Buffer.from(digest(state), "hex")
42
+ ))
43
+ return null;
44
+ return returnPath(flow.next);
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ function createPawAuthHandler(options) {
50
+ return async (request, action) => {
51
+ const json = (body, status = 200) => Response.json(body, { status, headers: petPrivateHeaders });
52
+ try {
53
+ if (!options.enabled)
54
+ return json({ error: "Community sign-in is not available yet." }, 503);
55
+ const scope = await options.resolve(request), origin = new URL(scope.origin).origin;
56
+ if (!origin.startsWith("https://") || !scope.apiKey)
57
+ return json({ error: "Sign-in is not configured." }, 503);
58
+ const redirect = (path) => new Response(null, {
59
+ status: 303,
60
+ headers: {
61
+ ...petPrivateHeaders,
62
+ location: origin + returnPath(path)
63
+ }
64
+ });
65
+ if (action === "start" && request.method === "POST") {
66
+ if (request.headers.get("origin") !== origin)
67
+ return json({ error: "Sign in from this website." }, 403);
68
+ const callback = origin + "/api/paw-auth/callback";
69
+ const result = await petRequest(
70
+ scope,
71
+ "/v1/auth/oauth/ledvery/authorize?" + new URLSearchParams({ redirect_uri: callback }),
72
+ {},
73
+ options.fetch
74
+ );
75
+ const url = new URL(result.url);
76
+ 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"))
77
+ throw new Error("Invalid authorization response");
78
+ const response = json({ url: url.href });
79
+ response.headers.append(
80
+ "set-cookie",
81
+ `${FLOW}=${sealPawFlow(result.state, returnPath(new URL(request.url).searchParams.get("next")), scope.apiKey)}; ${attrs}; Max-Age=600`
82
+ );
83
+ return response;
84
+ }
85
+ if (action === "callback" && request.method === "GET") {
86
+ const query = new URL(request.url).searchParams, code = query.get("code"), state = query.get("state");
87
+ const next = openPawFlow(pawCookie(request, FLOW), state, scope.apiKey);
88
+ const response = redirect(next || "/account?signin=retry");
89
+ response.headers.append("set-cookie", `${FLOW}=; ${attrs}; Max-Age=0`);
90
+ if (!next || !code || code.length > 4096 || query.has("error"))
91
+ return response;
92
+ try {
93
+ const session = await petRequest(
94
+ scope,
95
+ "/v1/auth/oauth/ledvery/callback?" + new URLSearchParams({ code, state }),
96
+ {},
97
+ options.fetch
98
+ );
99
+ const expiry = Date.parse(session.expires_at);
100
+ if (!session.session_token || !/^[A-Za-z0-9._~-]{1,2048}$/.test(session.session_token) || !Number.isFinite(expiry) || expiry <= Date.now())
101
+ throw new Error("Invalid session");
102
+ const me = await petRequest(
103
+ { ...scope, accessToken: session.session_token },
104
+ "/v1/auth/me",
105
+ {},
106
+ options.fetch
107
+ );
108
+ if (!me.id || !me.email_verified)
109
+ throw new Error("Verified reader required");
110
+ response.headers.append(
111
+ "set-cookie",
112
+ `${PAW_SESSION_COOKIE}=${session.session_token}; ${attrs}; Expires=${new Date(expiry).toUTCString()}`
113
+ );
114
+ return response;
115
+ } catch {
116
+ response.headers.set("location", origin + "/account?signin=retry");
117
+ return response;
118
+ }
119
+ }
120
+ if (action === "session" && request.method === "GET") {
121
+ if (!scope.accessToken) return json({ authenticated: false });
122
+ const me = await petRequest(scope, "/v1/auth/me", {}, options.fetch);
123
+ return json({
124
+ authenticated: Boolean(me.id && me.email_verified),
125
+ name: me.full_name || "Neighbor"
126
+ });
127
+ }
128
+ if (action === "logout" && request.method === "POST") {
129
+ if (request.headers.get("origin") !== origin)
130
+ return json({ error: "Continue from this website." }, 403);
131
+ if (scope.accessToken)
132
+ await petRequest(
133
+ scope,
134
+ "/v1/auth/logout",
135
+ { method: "POST", body: { session_token: scope.accessToken } },
136
+ options.fetch
137
+ );
138
+ const response = json({ authenticated: false });
139
+ response.headers.append(
140
+ "set-cookie",
141
+ `${PAW_SESSION_COOKIE}=; ${attrs}; Max-Age=0`
142
+ );
143
+ return response;
144
+ }
145
+ return json({ error: "Route not found" }, 404);
146
+ } catch {
147
+ return json(
148
+ { error: "Sign-in is temporarily unavailable. Please try again." },
149
+ 503
150
+ );
151
+ }
152
+ };
153
+ }
154
+
155
+ export { PAW_SESSION_COOKIE, createPawAuthHandler, openPawFlow, pawCookie, sealPawFlow };