@scalemule/news-publication 0.0.61 → 0.0.62

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 (41) hide show
  1. package/dist/chunk-3QU6BJVF.js +540 -0
  2. package/dist/chunk-4WVAT5M2.js +213 -0
  3. package/dist/chunk-6SBK3D3B.js +347 -0
  4. package/dist/chunk-CHF3YPDV.js +314 -0
  5. package/dist/chunk-FHRO2Z3F.js +174 -0
  6. package/dist/chunk-SKG5C3MS.js +379 -0
  7. package/dist/index.cjs +1 -0
  8. package/dist/index.js +3 -2
  9. package/dist/meet-view.d.cts +1 -1
  10. package/dist/meet-view.d.ts +1 -1
  11. package/dist/pets-plugin.js +4 -347
  12. package/dist/toys-forms.cjs +609 -0
  13. package/dist/toys-forms.d.cts +35 -0
  14. package/dist/toys-forms.d.ts +35 -0
  15. package/dist/toys-forms.js +4 -0
  16. package/dist/toys-interactions.cjs +594 -0
  17. package/dist/toys-interactions.d.cts +54 -0
  18. package/dist/toys-interactions.d.ts +54 -0
  19. package/dist/toys-interactions.js +520 -0
  20. package/dist/toys-plugin.cjs +713 -0
  21. package/dist/toys-plugin.d.cts +88 -0
  22. package/dist/toys-plugin.d.ts +88 -0
  23. package/dist/toys-plugin.js +10 -0
  24. package/dist/toys-publication.cjs +437 -0
  25. package/dist/toys-publication.d.cts +26 -0
  26. package/dist/toys-publication.d.ts +26 -0
  27. package/dist/toys-publication.js +72 -0
  28. package/dist/toys-server.cjs +275 -0
  29. package/dist/toys-server.d.cts +28 -0
  30. package/dist/toys-server.d.ts +28 -0
  31. package/dist/toys-server.js +4 -0
  32. package/dist/toys-view.cjs +420 -0
  33. package/dist/toys-view.d.cts +55 -0
  34. package/dist/toys-view.d.ts +55 -0
  35. package/dist/toys-view.js +2 -0
  36. package/dist/toys.cjs +196 -0
  37. package/dist/toys.d.cts +278 -0
  38. package/dist/toys.d.ts +278 -0
  39. package/dist/toys.js +1 -0
  40. package/package.json +40 -3
  41. package/toys.css +823 -0
@@ -0,0 +1,213 @@
1
+ import { TOY_UUID, TOY_SLUG } from './chunk-FHRO2Z3F.js';
2
+ import { petPrivateHeaders, petRequest, PetRequestError } from './chunk-ABPJMDUG.js';
3
+ import { buildClientContextHeaders } from '@scalemule/sdk';
4
+
5
+ var toyPrivateHeaders = petPrivateHeaders;
6
+ var toyRequest = petRequest;
7
+ var TOY_COMMUNITY_COOKIE = "__Host-toy-community";
8
+ function toyCollectionRequest(scope, suffix = "") {
9
+ return petRequest(scope, `/v1/knowledge/community-maps/collections/${scope.collectionSlug}/toys${suffix}`);
10
+ }
11
+ async function bounded(request, max) {
12
+ if (Number(request.headers.get("content-length")) > max) throw new PetRequestError(413, "The submission is too large.");
13
+ const reader = request.body?.getReader();
14
+ if (!reader) return new Uint8Array();
15
+ const parts = [];
16
+ let size = 0;
17
+ try {
18
+ for (; ; ) {
19
+ const { done, value } = await reader.read();
20
+ if (done) break;
21
+ size += value.length;
22
+ if (size > max) {
23
+ await reader.cancel();
24
+ throw new PetRequestError(413, "The submission is too large.");
25
+ }
26
+ parts.push(value);
27
+ }
28
+ } finally {
29
+ reader.releaseLock();
30
+ }
31
+ return Buffer.concat(parts);
32
+ }
33
+ function gatewayOrigin(scope) {
34
+ const url = new URL(scope.gatewayUrl);
35
+ if (!scope.apiKey || !TOY_SLUG.test(scope.collectionSlug) || url.username || url.password || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1"].includes(url.hostname)))
36
+ throw new PetRequestError(503, "The toy exchange is not available yet.");
37
+ return url.origin;
38
+ }
39
+ var LIST_FILTERS = ["area_id", "category", "age_range", "condition", "exchange_type", "availability", "q", "owner", "after", "limit"];
40
+ function route(method, path, url) {
41
+ const [a, b, c, d] = path;
42
+ const id = (v) => Boolean(v && TOY_UUID.test(v));
43
+ const base = "/toys";
44
+ if (method === "GET") {
45
+ if (!path.length) {
46
+ const q = new URLSearchParams();
47
+ for (const key of LIST_FILTERS) {
48
+ const value = url.searchParams.get(key);
49
+ if (value) q.set(key, value);
50
+ }
51
+ return { method, endpoint: base + (q.size ? "?" + q : ""), auth: false, write: false };
52
+ }
53
+ if (path.length === 1 && a === "policy") return { method, endpoint: base + "/policy", auth: false, write: false };
54
+ if (path.length === 1 && a === "locations") {
55
+ const area = url.searchParams.get("area_id");
56
+ return { method, endpoint: base + "/locations" + (area && TOY_UUID.test(area) ? "?area_id=" + area : ""), auth: false, write: false };
57
+ }
58
+ if (path.length === 2 && a === "profiles" && id(b)) return { method, endpoint: `${base}/profiles/${b}`, auth: false, write: false };
59
+ if (path.length === 3 && a === "profiles" && id(b) && c === "block") return { method, endpoint: `${base}/profiles/${b}/block`, auth: true, write: false };
60
+ if (path.length === 1 && a === "member") return { method, endpoint: base + "/member", auth: true, write: false };
61
+ if (path.length === 1 && a === "mine") {
62
+ const after = url.searchParams.get("after");
63
+ return { method, endpoint: base + "/mine" + (after && TOY_UUID.test(after) ? "?after=" + after : ""), auth: true, write: false };
64
+ }
65
+ if (path.length === 2 && a === "mine" && id(b)) return { method, endpoint: `${base}/mine/${b}`, auth: true, write: false };
66
+ if (path.length === 1 && a === "requests") return { method, endpoint: base + "/requests", auth: true, write: false };
67
+ if (path.length === 2 && a === "requests" && id(b)) return { method, endpoint: `${base}/requests/${b}`, auth: true, write: false };
68
+ if (path.length === 1 && id(a)) return { method, endpoint: `${base}/${a}`, auth: false, write: false };
69
+ if (path.length === 3 && id(a) && b === "media" && id(c)) return { method, endpoint: `${base}/${a}/media/${c}`, auth: false, write: false, kind: "media" };
70
+ if (path.length === 4 && a === "submissions" && id(b) && c === "media" && id(d)) return { method, endpoint: `/submissions/${b}/media/${d}`, auth: true, write: false, kind: "media" };
71
+ return null;
72
+ }
73
+ if (method === "POST") {
74
+ if (!path.length) return { method, endpoint: base, auth: true, write: true };
75
+ if (path.length === 1 && a === "phone") return { method, endpoint: "", auth: true, write: true, kind: "phone" };
76
+ if (path.length === 3 && a === "submissions" && id(b) && c === "media") return { method, endpoint: `/submissions/${b}/media`, auth: true, write: true, kind: "upload" };
77
+ if (path.length === 2 && a === "locations" && b === "suggestions") return { method, endpoint: base + "/locations/suggestions", auth: true, write: true };
78
+ if (path.length === 3 && a === "profiles" && id(b) && c === "reports") return { method, endpoint: `${base}/profiles/${b}/reports`, auth: true, write: true };
79
+ if (path.length === 2 && id(a) && ["requests", "reports"].includes(b)) return { method, endpoint: `${base}/${a}/${b}`, auth: true, write: true };
80
+ if (a === "requests" && id(b)) {
81
+ const action = path.slice(2).join("/");
82
+ if (["decision", "cancel", "complete", "messages", "appointment", "appointment/confirm", "appointment/cancel", "feedback", "reports"].includes(action))
83
+ return { method, endpoint: `${base}/requests/${b}/${action}`, auth: true, write: true };
84
+ }
85
+ return null;
86
+ }
87
+ if (method === "PUT") {
88
+ if (path.length === 1 && a === "member") return { method, endpoint: base + "/member", auth: true, write: true };
89
+ if (path.length === 3 && a === "profiles" && id(b) && c === "block") return { method, endpoint: `${base}/profiles/${b}/block`, auth: true, write: true };
90
+ if (path.length === 1 && id(a)) return { method, endpoint: `${base}/${a}`, auth: true, write: true };
91
+ return null;
92
+ }
93
+ if (method === "DELETE") {
94
+ if (path.length === 1 && a === "member") return { method, endpoint: base + "/member", auth: true, write: true };
95
+ if (path.length === 1 && id(a)) return { method, endpoint: `${base}/${a}`, auth: true, write: true };
96
+ return null;
97
+ }
98
+ return null;
99
+ }
100
+ async function phone(scope, body, fetcher) {
101
+ const number = typeof body.phone === "string" ? body.phone.replace(/[^\d+]/g, "") : "";
102
+ if (!/^\+?\d{10,15}$/.test(number)) throw new PetRequestError(400, "Enter a mobile number with country code, like +1 925 555 0100.");
103
+ if (body.action === "send") {
104
+ await petRequest(scope, "/v1/auth/phone/send-otp", { method: "POST", body: { phone: number, purpose: "verify_phone" } }, fetcher);
105
+ return { sent: true };
106
+ }
107
+ if (body.action === "verify") {
108
+ if (!/^\d{4,8}$/.test(body.code || "")) throw new PetRequestError(400, "Enter the code from the text message.");
109
+ await petRequest(scope, "/v1/auth/phone/verify-otp", { method: "POST", body: { phone: number, code: body.code } }, fetcher);
110
+ return { verified: true };
111
+ }
112
+ throw new PetRequestError(400, "Choose send or verify.");
113
+ }
114
+ function createPublicationToysHandler(options) {
115
+ const fetcher = options.fetch || fetch;
116
+ return async function handler(request, path) {
117
+ const json = (data, status = 200) => Response.json(data, { status, headers: petPrivateHeaders });
118
+ try {
119
+ const scope = await options.resolve(request);
120
+ const gateway = gatewayOrigin(scope);
121
+ const url = new URL(request.url);
122
+ if (path.some((segment) => segment.includes("..") || /[\\\r\n]/.test(segment))) return json({ error: "Route not found" }, 404);
123
+ const matched = route(request.method, path, url);
124
+ if (!matched) return json({ error: "Route not found" }, 404);
125
+ if (matched.write && (!scope.writesEnabled || request.headers.get("origin") !== new URL(scope.origin).origin))
126
+ return json({ error: "Continue from the exchange's official website." }, 403);
127
+ if (matched.auth && !scope.accessToken) return json({ error: "Sign in to continue." }, 401);
128
+ const root = `/v1/knowledge/community-maps/collections/${scope.collectionSlug}`;
129
+ if (matched.kind === "phone") {
130
+ let body2;
131
+ try {
132
+ body2 = JSON.parse(new TextDecoder().decode(await bounded(request, 2048)));
133
+ } catch (error) {
134
+ if (error instanceof PetRequestError) throw error;
135
+ throw new PetRequestError(400, "Check the phone details.");
136
+ }
137
+ return json({ data: await phone(scope, body2, fetcher) });
138
+ }
139
+ let endpoint = root + matched.endpoint;
140
+ if (matched.kind === "media" || matched.kind === "upload") {
141
+ const sourceQuery = url.searchParams;
142
+ const imageQuery = new URLSearchParams();
143
+ if (["640", "1280"].includes(sourceQuery.get("width") || "")) imageQuery.set("width", sourceQuery.get("width"));
144
+ if (["jpeg", "webp"].includes(sourceQuery.get("format") || "")) imageQuery.set("format", sourceQuery.get("format"));
145
+ if (matched.kind === "media" && imageQuery.size) endpoint += "?" + imageQuery;
146
+ let body2;
147
+ const type = request.headers.get("content-type") || "";
148
+ if (matched.kind === "upload") {
149
+ if (!type.startsWith("multipart/form-data;")) throw new PetRequestError(415, "Choose a photograph.");
150
+ body2 = await bounded(request, 9 * 1024 * 1024);
151
+ }
152
+ const response = await fetcher(gateway + endpoint, {
153
+ method: request.method,
154
+ headers: {
155
+ ...buildClientContextHeaders(scope.clientContext),
156
+ "x-api-key": scope.apiKey,
157
+ ...scope.accessToken ? { authorization: `Bearer ${scope.accessToken}` } : {},
158
+ ...matched.kind === "upload" ? { "content-type": type } : {}
159
+ },
160
+ body: body2,
161
+ cache: "no-store",
162
+ redirect: "error",
163
+ signal: AbortSignal.timeout(45e3)
164
+ });
165
+ if (!response.ok) {
166
+ await response.body?.cancel();
167
+ return json({ error: "The photograph is unavailable. Check its size and try again." }, response.status >= 500 ? 503 : response.status);
168
+ }
169
+ if (matched.kind === "upload") return json(await response.json());
170
+ const imageType = response.headers.get("content-type")?.split(";")[0] || "";
171
+ if (!["image/png", "image/jpeg", "image/webp"].includes(imageType)) {
172
+ await response.body?.cancel();
173
+ return json({ error: "Photograph unavailable" }, 404);
174
+ }
175
+ return new Response(response.body, { headers: { ...petPrivateHeaders, "content-type": imageType } });
176
+ }
177
+ let body;
178
+ if (matched.write) {
179
+ if (!request.headers.get("content-type")?.startsWith("application/json")) throw new PetRequestError(415, "Use the ToyRound form.");
180
+ try {
181
+ body = JSON.parse(new TextDecoder().decode(await bounded(request, 32768)));
182
+ } catch (error) {
183
+ if (error instanceof PetRequestError) throw error;
184
+ throw new PetRequestError(400, "Check the form fields.");
185
+ }
186
+ }
187
+ return json({ data: await petRequest(scope, endpoint, { method: request.method, body }, fetcher) });
188
+ } catch (error) {
189
+ const status = error instanceof PetRequestError ? error.status : 503;
190
+ const message = error instanceof PetRequestError ? error.message : "ToyRound is temporarily unavailable.";
191
+ return json({ error: message, code: status === 403 && message.includes("_REQUIRED") ? message : void 0 }, status);
192
+ }
193
+ };
194
+ }
195
+ function createToyCommunityHandler(options) {
196
+ return async function handler(request) {
197
+ try {
198
+ const scope = await options.resolve(request);
199
+ if (request.method !== "POST" || request.headers.get("origin") !== new URL(scope.origin).origin) return new Response(null, { status: 403 });
200
+ const { area_id } = JSON.parse(new TextDecoder().decode(await bounded(request, 256)));
201
+ if (area_id !== null && !TOY_UUID.test(String(area_id))) return new Response(null, { status: 400 });
202
+ if (area_id !== null) {
203
+ const policy = await petRequest({ ...scope, accessToken: void 0 }, `/v1/knowledge/community-maps/collections/${scope.collectionSlug}/toys/policy`, {}, options.fetch || fetch);
204
+ if (!policy.all_areas.some((a) => a.id === area_id)) return new Response(null, { status: 400 });
205
+ }
206
+ return Response.json({ saved: true }, { headers: { ...petPrivateHeaders, "set-cookie": `${TOY_COMMUNITY_COOKIE}=${area_id || "all"}; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=31536000` } });
207
+ } catch {
208
+ return Response.json({ error: "Community preference unavailable" }, { status: 503, headers: petPrivateHeaders });
209
+ }
210
+ };
211
+ }
212
+
213
+ export { TOY_COMMUNITY_COOKIE, createPublicationToysHandler, createToyCommunityHandler, toyCollectionRequest, toyPrivateHeaders, toyRequest };
@@ -0,0 +1,347 @@
1
+ import { LostPetNotice, PetCelebrationCard, AdoptionListingCard, PetEventCard, PetProfileCard, PawMark } from './chunk-7HXSQY4T.js';
2
+ import { petRequest } from './chunk-ABPJMDUG.js';
3
+ import { PET_UUID, safePetLink, PET_SAFETY, resolvePetCommunity } from './chunk-AFJ6S5WJ.js';
4
+ import { PetSignIn, PetOwnerActions, PetSubmissionForm } from '@scalemule/news-publication/pets-forms';
5
+ import { PetPreferencesForm, PetResourceActions, PetSignOut } from '@scalemule/news-publication/pets-interactions';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+
8
+ var publicationPetPaths = {
9
+ home: "/pets",
10
+ account: "/pets/account",
11
+ submit: "/pets/submit",
12
+ resource: "/pets",
13
+ browse: "/pets/browse"
14
+ };
15
+ var standalonePetPaths = {
16
+ home: "/",
17
+ account: "/account",
18
+ submit: "/submit",
19
+ resource: "/pets",
20
+ browse: "/browse"
21
+ };
22
+ function petCollectionRequest(scope, suffix = "") {
23
+ return petRequest(
24
+ scope,
25
+ `/v1/knowledge/community-maps/collections/${scope.collectionSlug}${suffix}`
26
+ );
27
+ }
28
+ async function petReaderAuthenticated(scope) {
29
+ if (!scope.accessToken) return false;
30
+ try {
31
+ const me = await petRequest(
32
+ scope,
33
+ "/v1/auth/me"
34
+ );
35
+ return Boolean(me.id && me.email_verified);
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+ function Shell({
41
+ paths,
42
+ children,
43
+ signedIn
44
+ }) {
45
+ return /* @__PURE__ */ jsxs("div", { className: "paw", children: [
46
+ /* @__PURE__ */ jsxs("header", { className: "paw-page-heading", children: [
47
+ /* @__PURE__ */ jsxs("a", { className: "paw-brand", href: paths.home, children: [
48
+ /* @__PURE__ */ jsx(PawMark, {}),
49
+ "Bay Area Paw"
50
+ ] }),
51
+ /* @__PURE__ */ jsxs("div", { className: "paw-form-actions", children: [
52
+ /* @__PURE__ */ jsx("a", { href: paths.account, children: "My pets" }),
53
+ signedIn && /* @__PURE__ */ jsx(PetSignOut, { returnTo: paths.home })
54
+ ] })
55
+ ] }),
56
+ children,
57
+ /* @__PURE__ */ jsxs("footer", { className: "paw-footer paw-page-footer", children: [
58
+ /* @__PURE__ */ jsxs("a", { href: paths.home, className: "paw-brand", children: [
59
+ /* @__PURE__ */ jsx(PawMark, { size: 28 }),
60
+ "Bay Area Paw"
61
+ ] }),
62
+ /* @__PURE__ */ jsx("p", { children: "Happier pets. Closer communities." }),
63
+ /* @__PURE__ */ jsx("a", { href: paths.home, children: "Back to your community" })
64
+ ] })
65
+ ] });
66
+ }
67
+ function LoadError({
68
+ error,
69
+ retry,
70
+ account
71
+ }) {
72
+ const status = error && typeof error === "object" && "status" in error ? error.status : void 0;
73
+ if (status === 401 || status === 403)
74
+ return /* @__PURE__ */ jsxs("div", { className: "paw-load-error", role: "status", children: [
75
+ /* @__PURE__ */ jsx("h2", { children: "Reconnect your community account." }),
76
+ /* @__PURE__ */ jsx("p", { children: "Your network sign-in gives you access to your pets across participating publications." }),
77
+ /* @__PURE__ */ jsx(PetSignIn, { returnTo: retry })
78
+ ] });
79
+ return /* @__PURE__ */ jsxs("div", { className: "paw-load-error", role: "status", children: [
80
+ /* @__PURE__ */ jsx("h2", { children: "We couldn\u2019t open your pet community." }),
81
+ /* @__PURE__ */ jsx("p", { children: status === 429 ? "There have been several requests in a short time. Wait a moment, then try again." : "The connection is temporarily unavailable. Try loading this page again to continue." }),
82
+ /* @__PURE__ */ jsxs("div", { className: "paw-form-actions", children: [
83
+ /* @__PURE__ */ jsx("a", { className: "paw-button", href: retry, children: "Try again" }),
84
+ retry !== account && /* @__PURE__ */ jsx("a", { className: "paw-text-link", href: account, children: "Back to My pets" })
85
+ ] })
86
+ ] });
87
+ }
88
+ async function PetAccountPage({
89
+ scope,
90
+ signedIn,
91
+ paths = publicationPetPaths,
92
+ after,
93
+ signInEnabled = true
94
+ }) {
95
+ let body;
96
+ if (!signedIn)
97
+ body = signInEnabled ? /* @__PURE__ */ jsx(PetSignIn, { returnTo: paths.account }) : /* @__PURE__ */ jsx("p", { children: "Community sign-in is being prepared. Public browsing is open." });
98
+ else
99
+ try {
100
+ const [own, preferences, collection] = await Promise.all([
101
+ petCollectionRequest(
102
+ scope,
103
+ "/pets/mine" + (after && PET_UUID.test(after) ? "?after=" + after : "")
104
+ ),
105
+ petCollectionRequest(scope, "/pets/preferences"),
106
+ petCollectionRequest(scope)
107
+ ]);
108
+ body = /* @__PURE__ */ jsxs(Fragment, { children: [
109
+ /* @__PURE__ */ jsx("p", { className: "paw-intro", children: "A home for their stories, wherever you read your local news." }),
110
+ !own.items.length && /* @__PURE__ */ jsx("p", { children: "Your pet\u2019s story starts here. Create a private profile or share a contribution with the community." }),
111
+ own.items.map((resource) => /* @__PURE__ */ jsxs("article", { className: "paw-account-row", children: [
112
+ /* @__PURE__ */ jsx("h2", { children: resource.content.name }),
113
+ /* @__PURE__ */ jsx("p", { children: resource.visibility === "private" ? "Private \u2014 only you" : resource.status === "published" ? "Editorially published; visibility follows its scheduled dates" : resource.status.replaceAll("_", " ") }),
114
+ resource.review_note && /* @__PURE__ */ jsxs("p", { children: [
115
+ "Editorial note: ",
116
+ resource.review_note
117
+ ] }),
118
+ /* @__PURE__ */ jsx(PetOwnerActions, { resource, submitUrl: paths.submit })
119
+ ] }, resource.id)),
120
+ own.next_cursor && /* @__PURE__ */ jsx("a", { href: paths.account + "?after=" + own.next_cursor, children: "More contributions" }),
121
+ /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("a", { className: "paw-button", href: paths.submit, children: "Add a pet or story" }) }),
122
+ /* @__PURE__ */ jsx(
123
+ PetPreferencesForm,
124
+ {
125
+ record: preferences,
126
+ communities: preferences.communities || collection.areas
127
+ }
128
+ )
129
+ ] });
130
+ } catch (error) {
131
+ body = /* @__PURE__ */ jsx(
132
+ LoadError,
133
+ {
134
+ error,
135
+ retry: paths.account,
136
+ account: paths.account
137
+ }
138
+ );
139
+ }
140
+ return /* @__PURE__ */ jsx(Shell, { paths, signedIn, children: /* @__PURE__ */ jsxs("section", { className: "paw-story", children: [
141
+ /* @__PURE__ */ jsx("p", { className: "paw-eyebrow", children: "Your community account" }),
142
+ /* @__PURE__ */ jsx("h1", { children: "A home for your pets." }),
143
+ body
144
+ ] }) });
145
+ }
146
+ async function PetSubmitPage({
147
+ scope,
148
+ signedIn,
149
+ paths = publicationPetPaths,
150
+ edit,
151
+ community,
152
+ submissionsEnabled = true
153
+ }) {
154
+ let form;
155
+ const next = paths.submit + "?" + new URLSearchParams({
156
+ ...edit ? { edit } : {},
157
+ ...community ? { community } : {}
158
+ });
159
+ if (!submissionsEnabled)
160
+ form = /* @__PURE__ */ jsxs("section", { className: "paw-form", children: [
161
+ /* @__PURE__ */ jsx("h1", { children: "We\u2019re getting ready to meet your pets." }),
162
+ /* @__PURE__ */ jsx("p", { children: "Contributions will open when our local review team and photo-sharing experience are ready." })
163
+ ] });
164
+ else if (!signedIn)
165
+ form = /* @__PURE__ */ jsxs("section", { className: "paw-form", children: [
166
+ /* @__PURE__ */ jsxs("h1", { children: [
167
+ "A familiar sign-in.",
168
+ /* @__PURE__ */ jsx("br", {}),
169
+ "A new place to belong."
170
+ ] }),
171
+ /* @__PURE__ */ jsx(PetSignIn, { returnTo: next })
172
+ ] });
173
+ else
174
+ try {
175
+ const [collection, own, initial, preferences] = await Promise.all([
176
+ petCollectionRequest(scope),
177
+ petCollectionRequest(scope, "/pets/mine"),
178
+ edit && PET_UUID.test(edit) ? petCollectionRequest(scope, "/pets/mine/" + edit) : void 0,
179
+ edit ? petCollectionRequest(scope, "/pets/preferences") : void 0
180
+ ]);
181
+ const currentHome = preferences?.communities?.find(
182
+ (a) => a.id === initial?.area_id
183
+ );
184
+ const editCommunities = currentHome && !collection.areas.some((a) => a.id === currentHome.id) ? [...collection.areas, currentHome] : collection.areas;
185
+ form = edit && !initial ? /* @__PURE__ */ jsx("p", { children: "This contribution is unavailable. Open it from My pets." }) : /* @__PURE__ */ jsx(
186
+ PetSubmissionForm,
187
+ {
188
+ communities: editCommunities,
189
+ policy: collection.submission_policy,
190
+ profiles: own.items.filter((p) => p.kind === "profile"),
191
+ initial,
192
+ defaultCommunity: collection.areas.find((a) => a.slug === community)?.id,
193
+ accountUrl: paths.account
194
+ }
195
+ );
196
+ } catch (error) {
197
+ form = /* @__PURE__ */ jsxs("section", { className: "paw-form", children: [
198
+ /* @__PURE__ */ jsx("h1", { children: "Let\u2019s meet your pet." }),
199
+ /* @__PURE__ */ jsx(LoadError, { error, retry: next, account: paths.account })
200
+ ] });
201
+ }
202
+ return /* @__PURE__ */ jsx(Shell, { paths, children: form });
203
+ }
204
+ function PetStoryPage({
205
+ resource,
206
+ communities,
207
+ signedIn,
208
+ paths = publicationPetPaths,
209
+ canonicalOrigin
210
+ }) {
211
+ const c = resource.content, photoUrl = (photo) => `/api/pets/${resource.id}/media/${photo}`, source = c.source && safePetLink(c.source.official_url);
212
+ return /* @__PURE__ */ jsx(Shell, { paths, children: /* @__PURE__ */ jsxs(
213
+ "article",
214
+ {
215
+ className: `paw-story${c.category === "memorial" ? " paw-memorial" : ""}`,
216
+ children: [
217
+ /* @__PURE__ */ jsx("p", { className: "paw-context", children: communities.find((a) => a.id === resource.area_id)?.name }),
218
+ /* @__PURE__ */ jsxs("h1", { children: [
219
+ c.category === "memorial" ? "Remembering " : "Meet ",
220
+ c.name,
221
+ "."
222
+ ] }),
223
+ resource.media.map((photo, index) => /* @__PURE__ */ jsxs("figure", { children: [
224
+ /* @__PURE__ */ jsxs("picture", { children: [
225
+ /* @__PURE__ */ jsx(
226
+ "source",
227
+ {
228
+ type: "image/webp",
229
+ srcSet: `${photoUrl(photo.id)}?width=640&format=webp 640w, ${photoUrl(photo.id)}?width=1280&format=webp 1280w`,
230
+ sizes: "(max-width: 850px) 100vw, 800px"
231
+ }
232
+ ),
233
+ /* @__PURE__ */ jsx(
234
+ "img",
235
+ {
236
+ src: `${photoUrl(photo.id)}?width=1280&format=jpeg`,
237
+ alt: photo.caption || c.name,
238
+ width: 1200,
239
+ height: 900,
240
+ loading: index ? "lazy" : "eager"
241
+ }
242
+ )
243
+ ] }),
244
+ /* @__PURE__ */ jsx("figcaption", { children: photo.attribution })
245
+ ] }, photo.id)),
246
+ /* @__PURE__ */ jsx("p", { children: c.story }),
247
+ c.personality && /* @__PURE__ */ jsx("p", { children: c.personality }),
248
+ c.activities.length > 0 && /* @__PURE__ */ jsxs("p", { children: [
249
+ "Favorite things: ",
250
+ c.activities.join(", "),
251
+ "."
252
+ ] }),
253
+ c.attribution && /* @__PURE__ */ jsxs("p", { className: "paw-credit", children: [
254
+ "Shared by ",
255
+ c.attribution
256
+ ] }),
257
+ ["lost", "found"].includes(resource.kind) && /* @__PURE__ */ jsxs("aside", { className: "paw-safety", children: [
258
+ /* @__PURE__ */ jsx("p", { children: resource.reunited_at ? "Reported reunited." : "A community report." }),
259
+ /* @__PURE__ */ jsx("p", { children: PET_SAFETY.recovery }),
260
+ /* @__PURE__ */ jsx("p", { children: "Private recovery contact is not available yet. Do not post contact details in public." })
261
+ ] }),
262
+ source && /* @__PURE__ */ jsxs("a", { href: source, rel: "noopener noreferrer", children: [
263
+ "Visit ",
264
+ c.source.organization,
265
+ " for current information"
266
+ ] }),
267
+ /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("a", { href: canonicalOrigin + "/pets/" + resource.id, children: "Permanent link to this story" }) }),
268
+ /* @__PURE__ */ jsx(
269
+ PetResourceActions,
270
+ {
271
+ resource,
272
+ signedIn,
273
+ accountUrl: paths.account
274
+ }
275
+ ),
276
+ /* @__PURE__ */ jsx("a", { href: paths.home, children: "More community pets" })
277
+ ]
278
+ }
279
+ ) });
280
+ }
281
+ var petBrowseLabels = {
282
+ neighbors: "Friends around the corner",
283
+ profile: "Meet our pets",
284
+ photo: "The community photo board",
285
+ lost_found: "Let\u2019s help them get home.",
286
+ celebration: "Little milestones. Lasting memories.",
287
+ adoption: "A new chapter starts with hello.",
288
+ event: "Good things to get together for."
289
+ };
290
+ async function PetBrowsePage({
291
+ scope,
292
+ kind,
293
+ query,
294
+ paths = publicationPetPaths
295
+ }) {
296
+ let body;
297
+ try {
298
+ const collection = await petCollectionRequest(scope), chosen = resolvePetCommunity(collection.areas, query.community);
299
+ const filter = new URLSearchParams({ kind });
300
+ if (chosen) filter.set("area_id", chosen.id);
301
+ for (const key of ["after", "species", "category"])
302
+ if (query[key]) filter.set(key, query[key]);
303
+ const result = await petCollectionRequest(scope, "/pets?" + filter);
304
+ const Card = kind === "lost_found" ? LostPetNotice : kind === "celebration" ? PetCelebrationCard : kind === "adoption" ? AdoptionListingCard : kind === "event" ? PetEventCard : PetProfileCard;
305
+ const next = new URLSearchParams(
306
+ Object.entries(query).filter(
307
+ (e) => typeof e[1] === "string"
308
+ )
309
+ );
310
+ if (result.next_cursor) next.set("after", result.next_cursor);
311
+ body = /* @__PURE__ */ jsxs(Fragment, { children: [
312
+ /* @__PURE__ */ jsxs("form", { className: "paw-filters", method: "get", children: [
313
+ /* @__PURE__ */ jsxs("label", { children: [
314
+ "Community",
315
+ /* @__PURE__ */ jsxs("select", { name: "community", defaultValue: chosen?.slug || "", children: [
316
+ /* @__PURE__ */ jsx("option", { value: "", children: "All local communities" }),
317
+ collection.areas.map((a) => /* @__PURE__ */ jsx("option", { value: a.slug, children: a.name }, a.id))
318
+ ] })
319
+ ] }),
320
+ /* @__PURE__ */ jsxs("label", { children: [
321
+ "Species",
322
+ /* @__PURE__ */ jsx("input", { name: "species", maxLength: 50, defaultValue: query.species })
323
+ ] }),
324
+ /* @__PURE__ */ jsx("button", { children: "Browse" })
325
+ ] }),
326
+ result.items.length ? /* @__PURE__ */ jsx("div", { className: "paw-gallery", children: result.items.map((r) => /* @__PURE__ */ jsx(
327
+ Card,
328
+ {
329
+ resource: r,
330
+ community: collection.areas.find((a) => a.id === r.area_id)?.name || "Our community",
331
+ href: paths.resource + "/" + r.id,
332
+ mediaUrl: (id, media) => `/api/pets/${id}/media/${media}`
333
+ },
334
+ r.id
335
+ )) }) : /* @__PURE__ */ jsx("p", { className: "paw-empty", children: "No reviewed public contributions match these filters." }),
336
+ result.next_cursor && /* @__PURE__ */ jsx("a", { className: "paw-button", href: "?" + next, children: "Next page" })
337
+ ] });
338
+ } catch {
339
+ body = /* @__PURE__ */ jsx("p", { role: "status", children: "The community board is temporarily unavailable. Please try again shortly." });
340
+ }
341
+ return /* @__PURE__ */ jsx(Shell, { paths, children: /* @__PURE__ */ jsxs("section", { className: "paw-section", children: [
342
+ /* @__PURE__ */ jsx("h1", { children: petBrowseLabels[kind] || "Community pets" }),
343
+ body
344
+ ] }) });
345
+ }
346
+
347
+ export { PetAccountPage, PetBrowsePage, PetStoryPage, PetSubmitPage, petBrowseLabels, petCollectionRequest, petReaderAuthenticated, publicationPetPaths, standalonePetPaths };