@seedprotocol/feed 0.4.30 → 0.4.32

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/index.js CHANGED
@@ -1,168 +1,198 @@
1
- import { BaseArweaveClient as _e, isKnownArweaveGatewayHostname as Ve, getSeedsBySchemaName as Ke, withExcludeRevokedFilter as Ie, EasClient as $e, getItemVersionsFromEas as Ye, getItemPropertiesFromEas as qe, pickLatestPropertyAttestationsByRefAndSchema as Ze, setSchemaUidForSchemaDefinition as Qe, DEFAULT_ARWEAVE_GATEWAYS as Me, ensureReadGatewaySelected as et, client as L, DEFAULT_ARWEAVE_HOST as tt } from "@seedprotocol/sdk";
2
- import { classifyMediaRef as En, getFeedItemStringField as _n, normalizeFeedItemFields as In, resolveMediaRef as $n } from "@seedprotocol/sdk";
3
- import { gql as nt } from "graphql-request";
4
- import U from "pluralize";
5
- import rt from "rss-parser";
6
- import { generateJsonFeed as ot, generateAtomFeed as st } from "feedsmith";
7
- import { create as at } from "xmlbuilder2";
8
- import { createHash as it } from "crypto";
9
- import { promises as E } from "fs";
10
- import { join as F } from "path";
11
- import ue from "image-size";
12
- function j(t) {
13
- return `https://${_e.getHost()}/${t}`;
14
- }
15
- function G() {
16
- const t = process.env.FEED_ITEM_URL_BASE?.trim() || "https://optimism-sepolia.easscan.org", e = process.env.FEED_ITEM_URL_PATH?.trim() || "attestation/view", n = process.env.FEED_SITE_URL?.trim() || "https://seedprotocol.io", s = process.env.FEED_EXPAND_RELATIONS?.toLowerCase() !== "false", o = parseInt(process.env.FEED_PAGE_SIZE || "25", 10), i = process.env.FEED_INCLUDE_DATA_URI_HTML_ITEMS?.toLowerCase() === "true" ? "include_items" : "omit_items";
17
- return { itemUrlBase: t, itemUrlPath: e, siteUrl: n, expandRelations: s, pageSize: o, richTextDataUriImages: i };
18
- }
19
- const ct = /^(.+?)([A-Z][a-zA-Z]+)Ids$/;
20
- function le(t) {
21
- const e = ct.exec(t);
22
- if (e) {
23
- const n = e[1];
24
- if (n) return U(n);
25
- }
26
- if (t.endsWith("_ids")) {
27
- const n = t.slice(0, -4), s = n.split("_").filter(Boolean);
28
- if (s.length >= 2) {
29
- const o = s[0];
30
- return o.endsWith("s") ? o : U(o);
31
- }
32
- return U(n);
33
- }
34
- return t;
35
- }
36
- function Fe(t, e) {
37
- for (const n of Object.keys(t))
38
- n !== e && le(n) === e && delete t[n];
39
- }
40
- function be(t) {
41
- if (Array.isArray(t) || typeof t != "string") return t;
42
- const e = t.trim();
43
- if (!e.startsWith("[")) return t;
44
- try {
45
- const n = JSON.parse(e);
46
- if (Array.isArray(n)) return n;
47
- } catch {
48
- }
49
- return t;
50
- }
51
- function lt(t) {
52
- const e = t.storageTransactionId ?? t.storage_transaction_id;
53
- if (e && typeof e == "string" && e.trim())
54
- try {
55
- t.arweaveUrl = j(e.trim());
56
- } catch {
57
- }
58
- }
59
- const dt = /* @__PURE__ */ new Set(["html", "file", "json"]), Ue = "_feedFieldStorageModels", ve = "_feedListElementStorageModels";
60
- function Q(t) {
61
- return t.trim().toLowerCase();
62
- }
63
- function B(t) {
64
- return dt.has(Q(t));
65
- }
66
- function he(t) {
67
- const e = Q(t);
68
- return e === "html" ? 0 : e === "file" ? 1 : e === "json" ? 2 : 99;
69
- }
70
- function ee(t) {
71
- const e = t[Ue];
72
- if (e !== null && typeof e == "object" && !Array.isArray(e))
73
- return e;
74
- }
75
- function te(t) {
76
- const e = t[ve];
77
- if (e !== null && typeof e == "object" && !Array.isArray(e))
78
- return e;
79
- }
80
- function ge(t, e, n) {
81
- const s = Q(n);
82
- let o = ee(t);
83
- o || (o = {}, t[Ue] = o), o[e] = s;
84
- }
85
- function ft(t, e, n) {
86
- let s = te(t);
87
- s || (s = {}, t[ve] = s), s[e] = n.map(Q);
88
- }
89
- const ut = ["html", "Html", "body", "Body", "content", "Content"], ht = 8e6;
90
- function xe(t) {
91
- const e = t.trim();
92
- if (!e.startsWith("http://") && !e.startsWith("https://")) return !1;
93
- try {
94
- const n = new URL(e), s = n.hostname.toLowerCase(), o = _e.getHost().toLowerCase();
95
- if (s !== o && !Ve(s)) return !1;
96
- const i = n.pathname.replace(/^\//, "").split("/").filter(Boolean);
97
- if (i.length !== 1) return !1;
98
- const r = i[0];
99
- return /^[A-Za-z0-9_-]{43}$/.test(r);
100
- } catch {
101
- return !1;
102
- }
103
- }
104
- async function ke(t) {
105
- try {
106
- const e = await fetch(t, {
107
- headers: { Accept: "text/html, text/plain, text/markdown, application/json, */*" },
108
- signal: AbortSignal.timeout(15e3)
109
- });
110
- if (!e.ok) return null;
111
- const n = e.headers.get("content-type") ?? "";
112
- if (/^(image|video|audio)\//i.test(n)) return null;
113
- const s = await e.arrayBuffer();
114
- if (s.byteLength > ht) return null;
115
- const o = new TextDecoder("utf-8", { fatal: !1 }).decode(s);
116
- return o.length === 0 || o.includes("\0") ? null : o;
117
- } catch {
118
- return null;
119
- }
120
- }
121
- async function gt(t, e) {
122
- const n = t[e];
123
- if (typeof n != "string" || n.trim() === "" || !xe(n)) return;
124
- const s = await ke(n);
125
- s !== null && (t[e] = s);
126
- }
127
- async function pt(t) {
128
- for (const e of t) {
129
- const n = /* @__PURE__ */ new Set([...ut]), s = ee(e);
130
- if (s)
131
- for (const [i, r] of Object.entries(s))
132
- B(r) && n.add(i);
133
- for (const i of n)
134
- await gt(e, i);
135
- const o = te(e);
136
- if (o)
137
- for (const [i, r] of Object.entries(o)) {
138
- const a = e[i];
139
- if (!Array.isArray(a)) continue;
140
- const c = Math.min(r.length, a.length);
141
- for (let l = 0; l < c; l++) {
142
- if (!B(r[l])) continue;
143
- const d = a[l];
144
- if (typeof d != "string" || !xe(d)) continue;
145
- const h = await ke(d);
146
- h !== null && (a[l] = h);
147
- }
148
- }
149
- }
150
- }
151
- function mt(t) {
152
- const e = typeof t == "string" ? t.trim() : "";
153
- if (!e)
154
- return { ok: !1, reason: "empty" };
155
- let n;
156
- try {
157
- n = JSON.parse(e);
158
- } catch (o) {
159
- return { ok: !1, reason: "parse", error: o };
160
- }
161
- return !Array.isArray(n) || n.length === 0 || !n[0]?.value ? { ok: !1, reason: "shape" } : { ok: !0, metadata: n[0].value };
162
- }
163
- const J = "image", O = [
164
- "0x0000000000000000000000000000000000000000000000000000000000000020"
165
- ], Re = nt`
1
+ import { BaseArweaveClient as e, DEFAULT_ARWEAVE_GATEWAYS as t, DEFAULT_ARWEAVE_HOST as n, EasClient as r, classifyMediaRef as i, client as a, ensureReadGatewaySelected as o, getFeedItemStringField as s, getItemPropertiesFromEas as c, getItemVersionsFromEas as l, getSeedsBySchemaName as u, isKnownArweaveGatewayHostname as d, normalizeFeedItemFields as f, pickLatestPropertyAttestationsByRefAndSchema as p, resolveMediaRef as m, setSchemaUidForSchemaDefinition as h, withExcludeRevokedFilter as g } from "@seedprotocol/sdk";
2
+ import { gql as _ } from "graphql-request";
3
+ import v from "pluralize";
4
+ import ee from "rss-parser";
5
+ import { generateAtomFeed as te, generateJsonFeed as ne } from "feedsmith";
6
+ import { create as re } from "xmlbuilder2";
7
+ import { createHash as ie } from "crypto";
8
+ import { promises as y } from "fs";
9
+ import { join as b } from "path";
10
+ import ae from "image-size";
11
+ //#region src/utils/arweaveUrl.ts
12
+ function x(t) {
13
+ return `https://${e.getHost()}/${t}`;
14
+ }
15
+ //#endregion
16
+ //#region src/config.ts
17
+ function S() {
18
+ return {
19
+ itemUrlBase: process.env.FEED_ITEM_URL_BASE?.trim() || "https://optimism-sepolia.easscan.org",
20
+ itemUrlPath: process.env.FEED_ITEM_URL_PATH?.trim() || "attestation/view",
21
+ siteUrl: process.env.FEED_SITE_URL?.trim() || "https://seedprotocol.io",
22
+ expandRelations: process.env.FEED_EXPAND_RELATIONS?.toLowerCase() !== "false",
23
+ pageSize: parseInt(process.env.FEED_PAGE_SIZE || "25", 10),
24
+ richTextDataUriImages: process.env.FEED_INCLUDE_DATA_URI_HTML_ITEMS?.toLowerCase() === "true" ? "include_items" : "omit_items"
25
+ };
26
+ }
27
+ //#endregion
28
+ //#region src/listRelationKey.ts
29
+ var oe = /^(.+?)([A-Z][a-zA-Z]+)Ids$/;
30
+ function C(e) {
31
+ let t = oe.exec(e);
32
+ if (t) {
33
+ let e = t[1];
34
+ if (e) return v(e);
35
+ }
36
+ if (e.endsWith("_ids")) {
37
+ let t = e.slice(0, -4), n = t.split("_").filter(Boolean);
38
+ if (n.length >= 2) {
39
+ let e = n[0];
40
+ return e.endsWith("s") ? e : v(e);
41
+ }
42
+ return v(t);
43
+ }
44
+ return e;
45
+ }
46
+ function se(e, t) {
47
+ for (let n of Object.keys(e)) n !== t && C(n) === t && delete e[n];
48
+ }
49
+ function ce(e) {
50
+ if (Array.isArray(e) || typeof e != "string") return e;
51
+ let t = e.trim();
52
+ if (!t.startsWith("[")) return e;
53
+ try {
54
+ let e = JSON.parse(t);
55
+ if (Array.isArray(e)) return e;
56
+ } catch {}
57
+ return e;
58
+ }
59
+ //#endregion
60
+ //#region src/imageRelationEnrichment.ts
61
+ function le(e) {
62
+ let t = e.storageTransactionId ?? e.storage_transaction_id;
63
+ if (t && typeof t == "string" && t.trim()) try {
64
+ e.arweaveUrl = x(t.trim());
65
+ } catch {}
66
+ }
67
+ //#endregion
68
+ //#region src/feedFieldStorageModel.ts
69
+ var ue = new Set([
70
+ "html",
71
+ "file",
72
+ "json"
73
+ ]), de = "_feedFieldStorageModels", fe = "_feedListElementStorageModels";
74
+ function w(e) {
75
+ return e.trim().toLowerCase();
76
+ }
77
+ function T(e) {
78
+ return ue.has(w(e));
79
+ }
80
+ function pe(e) {
81
+ let t = w(e);
82
+ return t === "html" ? 0 : t === "file" ? 1 : t === "json" ? 2 : 99;
83
+ }
84
+ function E(e) {
85
+ let t = e[de];
86
+ if (typeof t == "object" && t && !Array.isArray(t)) return t;
87
+ }
88
+ function D(e) {
89
+ let t = e[fe];
90
+ if (typeof t == "object" && t && !Array.isArray(t)) return t;
91
+ }
92
+ function me(e, t, n) {
93
+ let r = w(n), i = E(e);
94
+ i || (i = {}, e[de] = i), i[t] = r;
95
+ }
96
+ function he(e, t, n) {
97
+ let r = D(e);
98
+ r || (r = {}, e[fe] = r), r[t] = n.map(w);
99
+ }
100
+ //#endregion
101
+ //#region src/hydrateArweaveRichText.ts
102
+ var ge = [
103
+ "html",
104
+ "Html",
105
+ "body",
106
+ "Body",
107
+ "content",
108
+ "Content"
109
+ ], _e = 8e6;
110
+ function ve(t) {
111
+ let n = t.trim();
112
+ if (!n.startsWith("http://") && !n.startsWith("https://")) return !1;
113
+ try {
114
+ let t = new URL(n), r = t.hostname.toLowerCase();
115
+ if (r !== e.getHost().toLowerCase() && !d(r)) return !1;
116
+ let i = t.pathname.replace(/^\//, "").split("/").filter(Boolean);
117
+ if (i.length !== 1) return !1;
118
+ let a = i[0];
119
+ return /^[A-Za-z0-9_-]{43}$/.test(a);
120
+ } catch {
121
+ return !1;
122
+ }
123
+ }
124
+ async function ye(e) {
125
+ try {
126
+ let t = await fetch(e, {
127
+ headers: { Accept: "text/html, text/plain, text/markdown, application/json, */*" },
128
+ signal: AbortSignal.timeout(15e3)
129
+ });
130
+ if (!t.ok) return null;
131
+ let n = t.headers.get("content-type") ?? "";
132
+ if (/^(image|video|audio)\//i.test(n)) return null;
133
+ let r = await t.arrayBuffer();
134
+ if (r.byteLength > _e) return null;
135
+ let i = new TextDecoder("utf-8", { fatal: !1 }).decode(r);
136
+ return i.length === 0 || i.includes("\0") ? null : i;
137
+ } catch {
138
+ return null;
139
+ }
140
+ }
141
+ async function be(e, t) {
142
+ let n = e[t];
143
+ if (typeof n != "string" || n.trim() === "" || !ve(n)) return;
144
+ let r = await ye(n);
145
+ r !== null && (e[t] = r);
146
+ }
147
+ async function xe(e) {
148
+ for (let t of e) {
149
+ let e = new Set([...ge]), n = E(t);
150
+ if (n) for (let [t, r] of Object.entries(n)) T(r) && e.add(t);
151
+ for (let n of e) await be(t, n);
152
+ let r = D(t);
153
+ if (r) for (let [e, n] of Object.entries(r)) {
154
+ let r = t[e];
155
+ if (!Array.isArray(r)) continue;
156
+ let i = Math.min(n.length, r.length);
157
+ for (let e = 0; e < i; e++) {
158
+ if (!T(n[e])) continue;
159
+ let t = r[e];
160
+ if (typeof t != "string" || !ve(t)) continue;
161
+ let i = await ye(t);
162
+ i !== null && (r[e] = i);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ //#endregion
168
+ //#region src/parseEasPropertyMetadataForFeed.ts
169
+ function Se(e) {
170
+ let t = typeof e == "string" ? e.trim() : "";
171
+ if (!t) return {
172
+ ok: !1,
173
+ reason: "empty"
174
+ };
175
+ let n;
176
+ try {
177
+ n = JSON.parse(t);
178
+ } catch (e) {
179
+ return {
180
+ ok: !1,
181
+ reason: "parse",
182
+ error: e
183
+ };
184
+ }
185
+ return !Array.isArray(n) || n.length === 0 || !n[0]?.value ? {
186
+ ok: !1,
187
+ reason: "shape"
188
+ } : {
189
+ ok: !0,
190
+ metadata: n[0].value
191
+ };
192
+ }
193
+ //#endregion
194
+ //#region src/getFeedItems.ts
195
+ var O = "image", k = ["0x0000000000000000000000000000000000000000000000000000000000000020"], Ce = _`
166
196
  query GetSeeds($where: AttestationWhereInput!, $take: Int, $skip: Int) {
167
197
  itemSeeds: attestations(where: $where, orderBy: [{ timeCreated: desc }], take: $take, skip: $skip) {
168
198
  id
@@ -180,2140 +210,1817 @@ const J = "image", O = [
180
210
  isOffchain
181
211
  }
182
212
  }
183
- `, W = (t) => t.replace(/_([a-z])/g, (e, n) => n.toUpperCase()), yt = (t) => {
184
- const e = new Date(t * 1e3), n = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], s = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], o = n[e.getUTCDay()], i = s[e.getUTCMonth()], r = e.getUTCFullYear(), a = e.getUTCDate().toString().padStart(2, "0"), c = e.getUTCHours().toString().padStart(2, "0"), l = e.getUTCMinutes().toString().padStart(2, "0"), d = e.getUTCSeconds().toString().padStart(2, "0");
185
- return `${o}, ${a} ${i} ${r} ${c}:${l}:${d} GMT`;
186
- }, wt = (t) => t === "image" ? "images" : t === "post" ? "posts" : t.toLowerCase() + "s", Ct = (t) => {
187
- const [e, n, s] = t.split("_");
188
- if (!e || !n) return null;
189
- const o = s === "ids";
190
- return { propertyName: e.endsWith("s") ? e : e + "s", modelName: n, isList: o };
191
- }, oe = (t, e, n, s) => {
192
- const { itemUrlBase: o, itemUrlPath: i, siteUrl: r } = s;
193
- !t.title && !t.Title ? (t.title = e, t.Title = e) : t.title && !t.Title ? t.Title = t.title : t.Title && !t.title && (t.title = t.Title);
194
- const a = t.storage_transaction_id && typeof t.storage_transaction_id == "string" && t.storage_transaction_id.trim() !== "" && t.storage_transaction_id !== "undefined" && t.storage_transaction_id !== e ? t.storage_transaction_id.trim() : null, c = t.storageTransactionId && typeof t.storageTransactionId == "string" && t.storageTransactionId.trim() !== "" && t.storageTransactionId !== "undefined" && t.storageTransactionId !== e ? t.storageTransactionId.trim() : null, l = a || c, d = wt(n), h = e && typeof e == "string" && e.trim() !== "" ? e : "unknown";
195
- let g;
196
- if (l && l !== e && l.length > 0)
197
- try {
198
- g = j(l);
199
- } catch (p) {
200
- console.error("[feed] [setFeedItemDefaults] Error generating Arweave URL:", p), o != null ? g = `${o.replace(/\/$/, "")}/${(i ?? "attestation/view").replace(/^\//, "")}/${h}` : g = `${r.replace(/\/$/, "")}/${d}/${h}`;
201
- }
202
- else
203
- o != null ? g = `${o.replace(/\/$/, "")}/${(i ?? "attestation/view").replace(/^\//, "")}/${h}` : g = `${r.replace(/\/$/, "")}/${d}/${h}`;
204
- const f = t.link || t.Link;
205
- !f || f === "undefined" || typeof f == "string" && f.trim() === "" ? (t.link = g, t.Link = g) : ((!t.link || t.link === "undefined") && (t.link = f), (!t.Link || t.Link === "undefined") && (t.Link = f));
206
- const y = t.guid || t.Guid;
207
- if (!y || y === "undefined" || typeof y == "string" && y.trim() === "" ? (t.guid = t.link || g, t.Guid = t.guid) : ((!t.guid || t.guid === "undefined") && (t.guid = y), (!t.Guid || t.Guid === "undefined") && (t.Guid = y)), t.timeCreated && !t.pubDate && !t.PubDate) {
208
- const p = yt(t.timeCreated);
209
- t.pubDate = p, t.PubDate = p;
210
- } else t.pubDate && !t.PubDate ? t.PubDate = t.pubDate : t.PubDate && !t.pubDate && (t.pubDate = t.PubDate);
211
- !t.seedUid && !t.SeedUid ? (t.seedUid = e, t.SeedUid = e) : t.seedUid && !t.SeedUid ? t.SeedUid = t.seedUid : t.SeedUid && !t.seedUid && (t.seedUid = t.SeedUid), t.attester && !t.Attester ? t.Attester = t.attester : t.Attester && !t.attester && (t.attester = t.Attester);
212
- }, M = /* @__PURE__ */ new Map(), Y = /* @__PURE__ */ new Set(), de = /* @__PURE__ */ new Map(), $ = /* @__PURE__ */ new Map(), V = /* @__PURE__ */ new Map(), Le = /* @__PURE__ */ new Map();
213
- function St() {
214
- M.clear(), Y.clear(), de.clear(), $.clear(), V.clear(), Le.clear();
215
- }
216
- const Dt = async (t, e) => {
217
- const n = mt(t.decodedDataJson);
218
- if (!n.ok) {
219
- const { id: p, refUID: w, schemaId: u } = t;
220
- n.reason === "empty" ? console.warn(
221
- "[feed] [processItemProperty] empty decodedDataJson for property:",
222
- p,
223
- w,
224
- u
225
- ) : n.reason === "parse" ? console.warn(
226
- "[feed] [processItemProperty] failed to parse decodedDataJson for property:",
227
- p,
228
- w,
229
- u,
230
- n.error
231
- ) : console.warn(
232
- "[feed] [processItemProperty] invalid decodedDataJson structure for property:",
233
- p,
234
- w,
235
- u
236
- );
237
- return;
238
- }
239
- const s = n.metadata;
240
- let o = s.name;
241
- if (!o)
242
- return;
243
- const i = t.schemaId;
244
- Qe({
245
- text: o,
246
- schemaUid: i
247
- });
248
- let r = !1, a = !1;
249
- const c = s.type, l = (c === "bytes32" || c === "bytes32[]") && o !== "storage_transaction_id" && o !== "storage_provider_transaction_id", d = !l && (o.endsWith("_id") || o.endsWith("_ids")) && o !== "storage_transaction_id" && o !== "storage_provider_transaction_id";
250
- if (l || d)
251
- if (r = !0, Array.isArray(s.value)) {
252
- if (a = !0, d) {
253
- const p = Ct(o);
254
- p && (o = p.propertyName);
255
- }
256
- s.value.forEach((p) => {
257
- O.includes(p) || Y.add(p);
258
- });
259
- } else O.includes(s.value) || Y.add(s.value);
260
- let h = s.value;
261
- r && a && Array.isArray(h) ? h = h.map((p) => String(p)) : typeof h != "string" && (h = JSON.stringify(h)), r && !a && e.find((w) => w.id === s.value)?.schema?.schemaNames, r && a && e.filter(
262
- (w) => Array.isArray(s.value) && s.value.includes(w.id)
263
- ).length > 0;
264
- const g = de.get(t.refUID);
265
- if (!g)
266
- return;
267
- const f = $.get(g) || {};
268
- f[o] = h;
269
- const y = W(o);
270
- y !== o && (f[y] = h), $.set(g, f);
271
- }, pe = async (t) => {
272
- const e = t.map((r) => r.id);
273
- for (let r = 0; r < t.length; r++) {
274
- const a = t[r];
275
- if (!a) continue;
276
- e.push(a.id);
277
- const c = a.schema?.schemaNames?.[0]?.name ?? "unknown";
278
- M.set(a.id, c), $.has(a.id) || $.set(a.id, {
279
- seedUid: a.id,
280
- timeCreated: a.timeCreated,
281
- attester: a.attester
282
- });
283
- }
284
- const n = await Ye({ seedUids: e });
285
- for (let r = 0; r < n.length; r++) {
286
- const a = n[r], c = a.refUID;
287
- de.set(a.id, c);
288
- const l = V.get(c) || [];
289
- V.set(c, [...l, a]);
290
- }
291
- const s = [];
292
- for (const [r, a] of V.entries()) {
293
- const l = [...a].sort((d, h) => h.timeCreated - d.timeCreated)[0];
294
- l && (s.push(l.id), Le.set(r, l.id));
295
- }
296
- const o = await qe({ versionUids: s }), i = Ze(o);
297
- for (let r = 0; r < i.length; r++)
298
- await Dt(i[r], t);
299
- }, Pe = /* @__PURE__ */ new Set([
300
- "seedUid",
301
- "SeedUid",
302
- "timeCreated",
303
- "attester",
304
- "Attester",
305
- "storage_transaction_id",
306
- "storage_provider_transaction_id",
307
- "storageTransactionId",
308
- "storageProviderTransactionId"
213
+ `, A = (e) => e.replace(/_([a-z])/g, (e, t) => t.toUpperCase()), we = (e) => {
214
+ let t = /* @__PURE__ */ new Date(e * 1e3), n = [
215
+ "Sun",
216
+ "Mon",
217
+ "Tue",
218
+ "Wed",
219
+ "Thu",
220
+ "Fri",
221
+ "Sat"
222
+ ], r = [
223
+ "Jan",
224
+ "Feb",
225
+ "Mar",
226
+ "Apr",
227
+ "May",
228
+ "Jun",
229
+ "Jul",
230
+ "Aug",
231
+ "Sep",
232
+ "Oct",
233
+ "Nov",
234
+ "Dec"
235
+ ], i = n[t.getUTCDay()], a = r[t.getUTCMonth()], o = t.getUTCFullYear();
236
+ return `${i}, ${t.getUTCDate().toString().padStart(2, "0")} ${a} ${o} ${t.getUTCHours().toString().padStart(2, "0")}:${t.getUTCMinutes().toString().padStart(2, "0")}:${t.getUTCSeconds().toString().padStart(2, "0")} GMT`;
237
+ }, Te = (e) => e === "image" ? "images" : e === "post" ? "posts" : e.toLowerCase() + "s", Ee = (e) => {
238
+ let [t, n, r] = e.split("_");
239
+ if (!t || !n) return null;
240
+ let i = r === "ids";
241
+ return {
242
+ propertyName: t.endsWith("s") ? t : t + "s",
243
+ modelName: n,
244
+ isList: i
245
+ };
246
+ }, j = (e, t, n, r) => {
247
+ let { itemUrlBase: i, itemUrlPath: a, siteUrl: o } = r;
248
+ !e.title && !e.Title ? (e.title = t, e.Title = t) : e.title && !e.Title ? e.Title = e.title : e.Title && !e.title && (e.title = e.Title);
249
+ let s = e.storage_transaction_id && typeof e.storage_transaction_id == "string" && e.storage_transaction_id.trim() !== "" && e.storage_transaction_id !== "undefined" && e.storage_transaction_id !== t ? e.storage_transaction_id.trim() : null, c = e.storageTransactionId && typeof e.storageTransactionId == "string" && e.storageTransactionId.trim() !== "" && e.storageTransactionId !== "undefined" && e.storageTransactionId !== t ? e.storageTransactionId.trim() : null, l = s || c, u = Te(n), d = t && typeof t == "string" && t.trim() !== "" ? t : "unknown", f;
250
+ if (l && l !== t && l.length > 0) try {
251
+ f = x(l);
252
+ } catch (e) {
253
+ console.error("[feed] [setFeedItemDefaults] Error generating Arweave URL:", e), f = i == null ? `${o.replace(/\/$/, "")}/${u}/${d}` : `${i.replace(/\/$/, "")}/${(a ?? "attestation/view").replace(/^\//, "")}/${d}`;
254
+ }
255
+ else f = i == null ? `${o.replace(/\/$/, "")}/${u}/${d}` : `${i.replace(/\/$/, "")}/${(a ?? "attestation/view").replace(/^\//, "")}/${d}`;
256
+ let p = e.link || e.Link;
257
+ !p || p === "undefined" || typeof p == "string" && p.trim() === "" ? (e.link = f, e.Link = f) : ((!e.link || e.link === "undefined") && (e.link = p), (!e.Link || e.Link === "undefined") && (e.Link = p));
258
+ let m = e.guid || e.Guid;
259
+ if (!m || m === "undefined" || typeof m == "string" && m.trim() === "" ? (e.guid = e.link || f, e.Guid = e.guid) : ((!e.guid || e.guid === "undefined") && (e.guid = m), (!e.Guid || e.Guid === "undefined") && (e.Guid = m)), e.timeCreated && !e.pubDate && !e.PubDate) {
260
+ let t = we(e.timeCreated);
261
+ e.pubDate = t, e.PubDate = t;
262
+ } else e.pubDate && !e.PubDate ? e.PubDate = e.pubDate : e.PubDate && !e.pubDate && (e.pubDate = e.PubDate);
263
+ !e.seedUid && !e.SeedUid ? (e.seedUid = t, e.SeedUid = t) : e.seedUid && !e.SeedUid ? e.SeedUid = e.seedUid : e.SeedUid && !e.seedUid && (e.seedUid = e.SeedUid), e.attester && !e.Attester ? e.Attester = e.attester : e.Attester && !e.attester && (e.attester = e.Attester);
264
+ }, M = /* @__PURE__ */ new Map(), N = /* @__PURE__ */ new Set(), P = /* @__PURE__ */ new Map(), F = /* @__PURE__ */ new Map(), I = /* @__PURE__ */ new Map(), De = /* @__PURE__ */ new Map();
265
+ function Oe() {
266
+ M.clear(), N.clear(), P.clear(), F.clear(), I.clear(), De.clear();
267
+ }
268
+ var ke = async (e, t) => {
269
+ let n = Se(e.decodedDataJson);
270
+ if (!n.ok) {
271
+ let { id: t, refUID: r, schemaId: i } = e;
272
+ n.reason === "empty" ? console.warn("[feed] [processItemProperty] empty decodedDataJson for property:", t, r, i) : n.reason === "parse" ? console.warn("[feed] [processItemProperty] failed to parse decodedDataJson for property:", t, r, i, n.error) : console.warn("[feed] [processItemProperty] invalid decodedDataJson structure for property:", t, r, i);
273
+ return;
274
+ }
275
+ let r = n.metadata, i = r.name;
276
+ if (!i) return;
277
+ let a = e.schemaId;
278
+ h({
279
+ text: i,
280
+ schemaUid: a
281
+ });
282
+ let o = !1, s = !1, c = r.type, l = (c === "bytes32" || c === "bytes32[]") && i !== "storage_transaction_id" && i !== "storage_provider_transaction_id", u = !l && (i.endsWith("_id") || i.endsWith("_ids")) && i !== "storage_transaction_id" && i !== "storage_provider_transaction_id";
283
+ if (l || u) if (o = !0, Array.isArray(r.value)) {
284
+ if (s = !0, u) {
285
+ let e = Ee(i);
286
+ e && (i = e.propertyName);
287
+ }
288
+ r.value.forEach((e) => {
289
+ k.includes(e) || N.add(e);
290
+ });
291
+ } else k.includes(r.value) || N.add(r.value);
292
+ let d = r.value;
293
+ o && s && Array.isArray(d) ? d = d.map((e) => String(e)) : typeof d != "string" && (d = JSON.stringify(d)), o && !s && t.find((e) => e.id === r.value)?.schema?.schemaNames, o && s && t.filter((e) => Array.isArray(r.value) && r.value.includes(e.id)).length;
294
+ let f = P.get(e.refUID);
295
+ if (!f) return;
296
+ let p = F.get(f) || {};
297
+ p[i] = d;
298
+ let m = A(i);
299
+ m !== i && (p[m] = d), F.set(f, p);
300
+ }, Ae = async (e) => {
301
+ let t = e.map((e) => e.id);
302
+ for (let n = 0; n < e.length; n++) {
303
+ let r = e[n];
304
+ if (!r) continue;
305
+ t.push(r.id);
306
+ let i = r.schema?.schemaNames?.[0]?.name ?? "unknown";
307
+ M.set(r.id, i), F.has(r.id) || F.set(r.id, {
308
+ seedUid: r.id,
309
+ timeCreated: r.timeCreated,
310
+ attester: r.attester
311
+ });
312
+ }
313
+ let n = await l({ seedUids: t });
314
+ for (let e = 0; e < n.length; e++) {
315
+ let t = n[e], r = t.refUID;
316
+ P.set(t.id, r);
317
+ let i = I.get(r) || [];
318
+ I.set(r, [...i, t]);
319
+ }
320
+ let r = [];
321
+ for (let [e, t] of I.entries()) {
322
+ let n = [...t].sort((e, t) => t.timeCreated - e.timeCreated)[0];
323
+ n && (r.push(n.id), De.set(e, n.id));
324
+ }
325
+ let i = p(await c({ versionUids: r }));
326
+ for (let t = 0; t < i.length; t++) await ke(i[t], e);
327
+ }, je = new Set([
328
+ "seedUid",
329
+ "SeedUid",
330
+ "timeCreated",
331
+ "attester",
332
+ "Attester",
333
+ "storage_transaction_id",
334
+ "storage_provider_transaction_id",
335
+ "storageTransactionId",
336
+ "storageProviderTransactionId"
309
337
  ]);
310
- function At(t) {
311
- const e = Array.from($.entries()).filter(
312
- ([n]) => M.get(n) === t
313
- );
314
- for (const [, n] of e) {
315
- const s = Object.keys(n).filter(
316
- (o) => !o.startsWith("_") && !Pe.has(o)
317
- );
318
- for (const o of s) {
319
- let i = n[o];
320
- const r = be(i);
321
- if (r !== i && Array.isArray(r) && (n[o] = r, i = r), Array.isArray(i)) {
322
- const c = i;
323
- if (!c.some(
324
- (f) => typeof f == "string" && !O.includes(f) && $.has(f)
325
- )) continue;
326
- const d = [], h = [];
327
- let g = !1;
328
- for (const f of c) {
329
- if (typeof f != "string" || O.includes(f)) {
330
- d.push(String(f)), h.push("unknown");
331
- continue;
332
- }
333
- const y = M.get(f) ?? "unknown";
334
- if (y === J) {
335
- d.push(f), h.push(J);
336
- continue;
337
- }
338
- const p = $.get(f), w = p?.storageTransactionId ?? p?.storage_transaction_id;
339
- if (w && typeof w == "string" && w.trim())
340
- try {
341
- d.push(j(w)), h.push(y), g = !0;
342
- } catch {
343
- d.push(f), h.push(y);
344
- }
345
- else
346
- d.push(f), h.push(y);
347
- }
348
- if (g) {
349
- const f = le(o);
350
- if (n[f] = d, ft(n, f, h), Fe(n, f), f !== o) {
351
- delete n[o];
352
- const y = W(o);
353
- y !== o && delete n[y];
354
- }
355
- }
356
- } else if (typeof i == "string") {
357
- if (O.includes(i) || !$.has(i)) continue;
358
- const c = $.get(i);
359
- if (M.get(i) === J)
360
- continue;
361
- const l = c?.storageTransactionId ?? c?.storage_transaction_id;
362
- if (l && typeof l == "string" && l.trim())
363
- try {
364
- const d = o.endsWith("_id") ? o.replace(/_id$/, "") : o;
365
- n[d] = j(l);
366
- const h = M.get(i) ?? "unknown";
367
- ge(n, d, h);
368
- const g = W(d);
369
- if (g !== d && ge(n, g, h), d !== o) {
370
- delete n[o];
371
- const f = W(o);
372
- f !== o && delete n[f];
373
- }
374
- } catch {
375
- }
376
- }
377
- }
378
- }
379
- }
380
- function Tt(t, e, n) {
381
- if (!n) return;
382
- const s = Array.from($.entries()).filter(
383
- ([o]) => M.get(o) === t
384
- );
385
- for (const [, o] of s) {
386
- const i = Object.keys(o).filter(
387
- (r) => !r.startsWith("_") && !Pe.has(r)
388
- );
389
- for (const r of i) {
390
- let a = o[r];
391
- const c = be(a);
392
- c !== a && Array.isArray(c) && (o[r] = c, a = c);
393
- const l = Array.isArray(a), d = l ? a : [a], h = [];
394
- let g = !1;
395
- for (const f of d) {
396
- if (typeof f != "string" || O.includes(f)) {
397
- h.push(f);
398
- continue;
399
- }
400
- const y = $.get(f);
401
- if (!y) {
402
- h.push(f);
403
- continue;
404
- }
405
- const p = y?.storageTransactionId ?? y?.storage_transaction_id;
406
- if (M.get(f) === J) {
407
- const C = M.get(f) ?? "unknown", S = { ...y };
408
- oe(S, f, C, e), lt(S), h.push(S), g = !0;
409
- continue;
410
- }
411
- if (p && typeof p == "string" && p.trim()) {
412
- h.push(f);
413
- continue;
414
- }
415
- const u = M.get(f) ?? "unknown", m = { ...y };
416
- oe(m, f, u, e), h.push(m), g = !0;
417
- }
418
- if (g) {
419
- const f = l ? le(r) : r.endsWith("_id") ? r.replace(/_id$/, "") : r;
420
- if (o[f] = l ? h : h[0], Fe(o, f), f !== r) {
421
- delete o[r];
422
- const y = W(r);
423
- y !== r && delete o[y];
424
- }
425
- }
426
- }
427
- }
428
- }
429
- async function Ne(t, e, n) {
430
- St(), await pe(e);
431
- const s = $e.getEasClient(), o = Array.from(Y), { itemSeeds: i } = await s.request(Re, {
432
- where: Ie({
433
- id: {
434
- in: o
435
- }
436
- }),
437
- take: o.length || 1,
438
- skip: 0
439
- });
440
- await pe(i ?? []), At(t);
441
- const r = G(), a = {
442
- itemUrlBase: r.itemUrlBase,
443
- itemUrlPath: r.itemUrlPath,
444
- siteUrl: r.siteUrl
445
- };
446
- Tt(
447
- t,
448
- a,
449
- n
450
- );
451
- const c = Array.from($.entries()).filter(([l]) => M.get(l) === t).map(([, l]) => {
452
- const d = l.seedUid || l.SeedUid;
453
- return oe(l, d, t, a), l;
454
- });
455
- return await pt(c), c;
456
- }
457
- const ne = async (t, e) => {
458
- const n = G(), s = e?.limit ?? 100, o = e?.skip ?? 0, i = await Ke(t, s, o);
459
- return await Ne(t, i, n.expandRelations !== !1);
460
- }, Et = async (t, e, n) => {
461
- const s = G(), o = new Date(e, n - 1, 1), i = new Date(e, n, 0, 23, 59, 59), r = Math.floor(o.getTime() / 1e3), a = Math.floor(i.getTime() / 1e3) + 1, c = Ie({
462
- AND: [
463
- {
464
- schema: {
465
- is: {
466
- schemaNames: {
467
- some: {
468
- name: { equals: t }
469
- }
470
- }
471
- }
472
- }
473
- },
474
- {
475
- timeCreated: { gte: r, lt: a }
476
- }
477
- ]
478
- }), l = $e.getEasClient(), { itemSeeds: d } = await l.request(Re, {
479
- where: c,
480
- take: 1e3,
481
- skip: 0
482
- });
483
- return Ne(t, d ?? [], s.expandRelations !== !1);
338
+ function Me(e) {
339
+ let t = Array.from(F.entries()).filter(([t]) => M.get(t) === e);
340
+ for (let [, e] of t) {
341
+ let t = Object.keys(e).filter((e) => !e.startsWith("_") && !je.has(e));
342
+ for (let n of t) {
343
+ let t = e[n], r = ce(t);
344
+ if (r !== t && Array.isArray(r) && (e[n] = r, t = r), Array.isArray(t)) {
345
+ let r = t;
346
+ if (!r.some((e) => typeof e == "string" && !k.includes(e) && F.has(e))) continue;
347
+ let i = [], a = [], o = !1;
348
+ for (let e of r) {
349
+ if (typeof e != "string" || k.includes(e)) {
350
+ i.push(String(e)), a.push("unknown");
351
+ continue;
352
+ }
353
+ let t = M.get(e) ?? "unknown";
354
+ if (t === O) {
355
+ i.push(e), a.push(O);
356
+ continue;
357
+ }
358
+ let n = F.get(e), r = n?.storageTransactionId ?? n?.storage_transaction_id;
359
+ if (r && typeof r == "string" && r.trim()) try {
360
+ i.push(x(r)), a.push(t), o = !0;
361
+ } catch {
362
+ i.push(e), a.push(t);
363
+ }
364
+ else i.push(e), a.push(t);
365
+ }
366
+ if (o) {
367
+ let t = C(n);
368
+ if (e[t] = i, he(e, t, a), se(e, t), t !== n) {
369
+ delete e[n];
370
+ let t = A(n);
371
+ t !== n && delete e[t];
372
+ }
373
+ }
374
+ } else if (typeof t == "string") {
375
+ if (k.includes(t) || !F.has(t)) continue;
376
+ let r = F.get(t);
377
+ if (M.get(t) === O) continue;
378
+ let i = r?.storageTransactionId ?? r?.storage_transaction_id;
379
+ if (i && typeof i == "string" && i.trim()) try {
380
+ let r = n.endsWith("_id") ? n.replace(/_id$/, "") : n;
381
+ e[r] = x(i);
382
+ let a = M.get(t) ?? "unknown";
383
+ me(e, r, a);
384
+ let o = A(r);
385
+ if (o !== r && me(e, o, a), r !== n) {
386
+ delete e[n];
387
+ let t = A(n);
388
+ t !== n && delete e[t];
389
+ }
390
+ } catch {}
391
+ }
392
+ }
393
+ }
394
+ }
395
+ function Ne(e, t, n) {
396
+ if (!n) return;
397
+ let r = Array.from(F.entries()).filter(([t]) => M.get(t) === e);
398
+ for (let [, e] of r) {
399
+ let n = Object.keys(e).filter((e) => !e.startsWith("_") && !je.has(e));
400
+ for (let r of n) {
401
+ let n = e[r], i = ce(n);
402
+ i !== n && Array.isArray(i) && (e[r] = i, n = i);
403
+ let a = Array.isArray(n), o = a ? n : [n], s = [], c = !1;
404
+ for (let e of o) {
405
+ if (typeof e != "string" || k.includes(e)) {
406
+ s.push(e);
407
+ continue;
408
+ }
409
+ let n = F.get(e);
410
+ if (!n) {
411
+ s.push(e);
412
+ continue;
413
+ }
414
+ let r = n?.storageTransactionId ?? n?.storage_transaction_id;
415
+ if (M.get(e) === O) {
416
+ let r = M.get(e) ?? "unknown", i = { ...n };
417
+ j(i, e, r, t), le(i), s.push(i), c = !0;
418
+ continue;
419
+ }
420
+ if (r && typeof r == "string" && r.trim()) {
421
+ s.push(e);
422
+ continue;
423
+ }
424
+ let i = M.get(e) ?? "unknown", a = { ...n };
425
+ j(a, e, i, t), s.push(a), c = !0;
426
+ }
427
+ if (c) {
428
+ let t = a ? C(r) : r.endsWith("_id") ? r.replace(/_id$/, "") : r;
429
+ if (e[t] = a ? s : s[0], se(e, t), t !== r) {
430
+ delete e[r];
431
+ let t = A(r);
432
+ t !== r && delete e[t];
433
+ }
434
+ }
435
+ }
436
+ }
437
+ }
438
+ async function Pe(e, t, n) {
439
+ Oe(), await Ae(t);
440
+ let i = r.getEasClient(), a = Array.from(N), { itemSeeds: o } = await i.request(Ce, {
441
+ where: g({ id: { in: a } }),
442
+ take: a.length || 1,
443
+ skip: 0
444
+ });
445
+ await Ae(o ?? []), Me(e);
446
+ let s = S(), c = {
447
+ itemUrlBase: s.itemUrlBase,
448
+ itemUrlPath: s.itemUrlPath,
449
+ siteUrl: s.siteUrl
450
+ };
451
+ Ne(e, c, n);
452
+ let l = Array.from(F.entries()).filter(([t]) => M.get(t) === e).map(([, t]) => (j(t, t.seedUid || t.SeedUid, e, c), t));
453
+ return await xe(l), l;
454
+ }
455
+ var L = async (e, t) => {
456
+ let n = S();
457
+ return await Pe(e, await u(e, t?.limit ?? 100, t?.skip ?? 0), n.expandRelations !== !1);
458
+ }, Fe = async (e, t, n) => {
459
+ let i = S(), a = new Date(t, n - 1, 1), o = new Date(t, n, 0, 23, 59, 59), s = Math.floor(a.getTime() / 1e3), c = Math.floor(o.getTime() / 1e3) + 1, l = g({ AND: [{ schema: { is: { schemaNames: { some: { name: { equals: e } } } } } }, { timeCreated: {
460
+ gte: s,
461
+ lt: c
462
+ } }] }), { itemSeeds: u } = await r.getEasClient().request(Ce, {
463
+ where: l,
464
+ take: 1e3,
465
+ skip: 0
466
+ });
467
+ return Pe(e, u ?? [], i.expandRelations !== !1);
484
468
  };
485
- function _t(t) {
486
- try {
487
- return JSON.parse(JSON.stringify(t));
488
- } catch {
489
- return { ...t };
490
- }
491
- }
492
- const It = new rt({
493
- customFields: {
494
- item: [
495
- "featureImage",
496
- "feature_image",
497
- "content:encoded",
498
- "seedUid",
499
- "SeedUid"
500
- ]
501
- }
502
- });
503
- async function yn(t) {
504
- const e = await It.parseString(t);
505
- return {
506
- title: e.title,
507
- link: e.link,
508
- description: e.description,
509
- items: (e.items ?? []).map(_t)
510
- };
511
- }
512
- const H = "http://purl.org/dc/elements/1.1/", q = "http://purl.org/rss/1.0/modules/content/", R = "http://search.yahoo.com/mrss/", $t = {
513
- publication: {
514
- prefix: "publication",
515
- uri: "https://seedprotocol.io/ns/publication/1.0"
516
- }
517
- }, Mt = "https://seedprotocol.io/ns/relations", me = /* @__PURE__ */ new Set(["xml", "xmlns", "dc", "media", "content", "atom", "fh"]), Ft = /* @__PURE__ */ new Set(["Title", "Link", "Guid", "PubDate", "SeedUid"]);
518
- function bt(t, e) {
519
- return Ft.has(t) ? t.charAt(0).toLowerCase() + t.slice(1) in e : !1;
520
- }
521
- const se = [
522
- "title",
523
- "link",
524
- "description",
525
- "guid",
526
- "pubDate",
527
- "author",
528
- "authors",
529
- "categories",
530
- "comments",
531
- "enclosures",
532
- "source",
533
- "dc",
534
- "content:encoded",
535
- "media:content",
536
- "media:thumbnail",
537
- "media:title",
538
- "media:description",
539
- "media:keywords",
540
- "media:credit",
541
- "media:copyright",
542
- "media:category",
543
- "media:group"
469
+ //#endregion
470
+ //#region src/consume/parseRss.ts
471
+ function Ie(e) {
472
+ try {
473
+ return JSON.parse(JSON.stringify(e));
474
+ } catch {
475
+ return { ...e };
476
+ }
477
+ }
478
+ var Le = new ee({ customFields: { item: [
479
+ "featureImage",
480
+ "feature_image",
481
+ "content:encoded",
482
+ "seedUid",
483
+ "SeedUid"
484
+ ] } });
485
+ async function Re(e) {
486
+ let t = await Le.parseString(e);
487
+ return {
488
+ title: t.title,
489
+ link: t.link,
490
+ description: t.description,
491
+ items: (t.items ?? []).map(Ie)
492
+ };
493
+ }
494
+ //#endregion
495
+ //#region src/rss/generateRssXml.ts
496
+ var R = "http://purl.org/dc/elements/1.1/", z = "http://purl.org/rss/1.0/modules/content/", B = "http://search.yahoo.com/mrss/", ze = { publication: {
497
+ prefix: "publication",
498
+ uri: "https://seedprotocol.io/ns/publication/1.0"
499
+ } }, Be = "https://seedprotocol.io/ns/relations", Ve = new Set([
500
+ "xml",
501
+ "xmlns",
502
+ "dc",
503
+ "media",
504
+ "content",
505
+ "atom",
506
+ "fh"
507
+ ]), He = new Set([
508
+ "Title",
509
+ "Link",
510
+ "Guid",
511
+ "PubDate",
512
+ "SeedUid"
513
+ ]);
514
+ function Ue(e, t) {
515
+ return He.has(e) ? e.charAt(0).toLowerCase() + e.slice(1) in t : !1;
516
+ }
517
+ var V = [
518
+ "title",
519
+ "link",
520
+ "description",
521
+ "guid",
522
+ "pubDate",
523
+ "author",
524
+ "authors",
525
+ "categories",
526
+ "comments",
527
+ "enclosures",
528
+ "source",
529
+ "dc",
530
+ "content:encoded",
531
+ "media:content",
532
+ "media:thumbnail",
533
+ "media:title",
534
+ "media:description",
535
+ "media:keywords",
536
+ "media:credit",
537
+ "media:copyright",
538
+ "media:category",
539
+ "media:group"
544
540
  ];
545
- function ae(t) {
546
- if (t instanceof Date)
547
- return t.toUTCString();
548
- if (typeof t == "string") {
549
- const e = new Date(t);
550
- return Number.isNaN(e.getTime()) ? t : e.toUTCString();
551
- }
552
- return String(t);
553
- }
554
- function Ut(t) {
555
- return /[<>&]|]]>/.test(t);
556
- }
557
- function I(t, e) {
558
- const n = String(e);
559
- if (n !== "")
560
- if (Ut(n))
561
- if (n.includes("]]>")) {
562
- const s = n.split("]]>");
563
- for (let o = 0; o < s.length; o++)
564
- t.dat(s[o]), o < s.length - 1 && t.txt("]]>");
565
- } else
566
- t.dat(n);
567
- else
568
- t.txt(n);
569
- }
570
- function b(t) {
571
- return t !== null && typeof t == "object" && !Array.isArray(t) && !(t instanceof Date);
572
- }
573
- const vt = 4, xt = /* @__PURE__ */ new Set([
574
- ...se,
575
- "guid",
576
- "source",
577
- "dc",
578
- "content",
579
- "content:encoded",
580
- "items"
541
+ function H(e) {
542
+ if (e instanceof Date) return e.toUTCString();
543
+ if (typeof e == "string") {
544
+ let t = new Date(e);
545
+ return Number.isNaN(t.getTime()) ? e : t.toUTCString();
546
+ }
547
+ return String(e);
548
+ }
549
+ function We(e) {
550
+ return /[<>&]|]]>/.test(e);
551
+ }
552
+ function U(e, t) {
553
+ let n = String(t);
554
+ if (n !== "") if (We(n)) if (n.includes("]]>")) {
555
+ let t = n.split("]]>");
556
+ for (let n = 0; n < t.length; n++) e.dat(t[n]), n < t.length - 1 && e.txt("]]>");
557
+ } else e.dat(n);
558
+ else e.txt(n);
559
+ }
560
+ function W(e) {
561
+ return typeof e == "object" && !!e && !Array.isArray(e) && !(e instanceof Date);
562
+ }
563
+ var Ge = 4, Ke = new Set([
564
+ ...V,
565
+ "guid",
566
+ "source",
567
+ "dc",
568
+ "content",
569
+ "content:encoded",
570
+ "items"
581
571
  ]);
582
- function kt(t) {
583
- return t.endsWith("s") && t.length > 1 ? t.slice(0, -1) : t;
584
- }
585
- function Rt(t) {
586
- return t.trim().replace(/[^A-Za-z0-9_.-]+/g, "_").replace(/^[^A-Za-z_]+/, "").replace(/^$/, "rel").toLowerCase();
587
- }
588
- function Lt(t, e) {
589
- if (!e.has(t) && !me.has(t))
590
- return e.add(t), t;
591
- let n = 2;
592
- for (; ; ) {
593
- const s = `${t}${n}`;
594
- if (!e.has(s) && !me.has(s))
595
- return e.add(s), s;
596
- n += 1;
597
- }
598
- }
599
- function ye(t) {
600
- return Array.isArray(t) && t.length > 0 && t.every((e) => b(e));
601
- }
602
- function Pt(t) {
603
- const e = { ...$t }, n = new Set(
604
- Object.values(e).map((i) => i.prefix)
605
- ), s = /* @__PURE__ */ new Set();
606
- for (const i of t)
607
- for (const [r, a] of Object.entries(i)) {
608
- const c = r === "author" && b(a) || r === "authors" && ye(a);
609
- r.startsWith("_") || xt.has(r) && !c || (b(a) || ye(a)) && s.add(kt(r));
610
- }
611
- const o = [...s].sort();
612
- for (const i of o) {
613
- if (e[i]) continue;
614
- const r = Rt(i), a = Lt(r, n);
615
- e[i] = {
616
- prefix: a,
617
- uri: `${Mt}/${i}/1.0`
618
- };
619
- }
620
- return e;
621
- }
622
- function X(t, e) {
623
- if (t in e) return e[t];
624
- if (t.endsWith("s") && t.length > 1) {
625
- const n = t.slice(0, -1);
626
- if (n in e) return e[n];
627
- }
628
- }
629
- function we(t, e) {
630
- return e ? `${e.prefix}:${t}` : t;
631
- }
632
- function P(t, e, n, s, o = 0, i) {
633
- const r = t.ele(n);
634
- for (const [a, c] of Object.entries(e)) {
635
- if (c == null || a.startsWith("_") || a === "items") continue;
636
- const l = we(a, i);
637
- if (o >= vt) {
638
- const h = r.ele(l);
639
- I(h, typeof c == "object" ? JSON.stringify(c) : String(c));
640
- continue;
641
- }
642
- if (Array.isArray(c)) {
643
- const h = a.endsWith("s") && a.length > 1 ? a.slice(0, -1) : a, g = we(h, i);
644
- for (const f of c)
645
- if (f != null)
646
- if (b(f))
647
- P(r, f, g, !1, o + 1, i);
648
- else {
649
- const y = r.ele(g);
650
- I(y, String(f));
651
- }
652
- continue;
653
- }
654
- if (b(c)) {
655
- P(
656
- r,
657
- c,
658
- l,
659
- !1,
660
- o + 1,
661
- i
662
- );
663
- continue;
664
- }
665
- const d = r.ele(l);
666
- I(d, String(c));
667
- }
668
- if (s) {
669
- const a = e.name ?? e.seedUid;
670
- a && t.ele(H, "creator").txt(String(a));
671
- }
672
- }
673
- function Ce(t, e, n, s, o) {
674
- if (n == null || e.startsWith("_") || e === "items") return;
675
- if (e === "guid") {
676
- const r = n, a = r?.value ?? String(n);
677
- if (!a) return;
678
- const c = {};
679
- typeof r?.isPermaLink == "boolean" && (c.isPermaLink = r.isPermaLink ? "true" : "false");
680
- const l = t.ele("guid", c);
681
- I(l, a);
682
- return;
683
- }
684
- if (e === "source" && n !== null && typeof n == "object") {
685
- const r = n, a = r.title ?? String(n);
686
- if (!a) return;
687
- const c = r.url ? { url: r.url } : {};
688
- t.ele("source", c).txt(a);
689
- return;
690
- }
691
- if (e === "enclosures" && Array.isArray(n)) {
692
- for (const r of n)
693
- if (r && typeof r == "object" && "url" in r) {
694
- const a = {
695
- url: String(r.url),
696
- type: String(r.type ?? "application/octet-stream")
697
- };
698
- r.length != null && (a.length = String(r.length)), t.ele("enclosure", a);
699
- }
700
- return;
701
- }
702
- if (e === "dc" && n !== null && typeof n == "object") {
703
- const r = n;
704
- for (const [a, c] of Object.entries(r))
705
- if (c != null)
706
- if (Array.isArray(c)) {
707
- for (const l of c)
708
- if (l != null) {
709
- const d = t.ele(H, a);
710
- l instanceof Date ? d.txt(l.toISOString()) : I(d, String(l));
711
- }
712
- } else {
713
- const l = t.ele(H, a);
714
- c instanceof Date ? l.txt(c.toISOString()) : I(l, String(c));
715
- }
716
- return;
717
- }
718
- if (e === "content:encoded") {
719
- const r = t.ele(q, "encoded");
720
- I(r, String(n));
721
- return;
722
- }
723
- if (e === "content" && typeof n == "string" && !("content:encoded" in s)) {
724
- const r = t.ele(q, "encoded");
725
- I(r, String(n));
726
- return;
727
- }
728
- if (e === "content") return;
729
- if (e === "media:group" && Array.isArray(n)) {
730
- for (const r of n)
731
- if (r && typeof r == "object") {
732
- const a = t.ele(R, "group");
733
- for (const [c, l] of Object.entries(r))
734
- if (l != null && c.startsWith("media:")) {
735
- const d = c.slice(6);
736
- if (Array.isArray(l)) {
737
- for (const h of l)
738
- if (h && typeof h == "object") {
739
- const g = a.ele(R, d);
740
- for (const [f, y] of Object.entries(h))
741
- y != null && (f === "url" || f === "value" ? I(g, String(y)) : g.att(f, String(y)));
742
- }
743
- } else typeof l == "string" && I(a.ele(R, d), l);
744
- }
745
- }
746
- return;
747
- }
748
- if (e.startsWith("media:") && Array.isArray(n)) {
749
- const r = e.slice(6);
750
- for (const a of n) {
751
- if (a === null || typeof a != "object") continue;
752
- const c = {};
753
- let l = null;
754
- for (const [h, g] of Object.entries(a))
755
- g != null && (h === "value" ? l = String(g) : c[h] = String(g));
756
- const d = t.ele(R, r, c);
757
- l !== null && I(d, l);
758
- }
759
- return;
760
- }
761
- if (e.startsWith("media:") && typeof n == "string") {
762
- const r = e.slice(6), a = t.ele(R, r);
763
- I(a, n);
764
- return;
765
- }
766
- if (n instanceof Date) {
767
- t.ele(e).txt(ae(n));
768
- return;
769
- }
770
- if (e === "author" && b(n)) {
771
- const r = X(e, o);
772
- P(t, n, "author", !0, 0, r);
773
- return;
774
- }
775
- if (e === "authors" && Array.isArray(n)) {
776
- const r = X(e, o);
777
- for (const a of n)
778
- if (a && b(a))
779
- P(t, a, "author", !0, 0, r);
780
- else {
781
- const c = typeof a == "string" ? a : a && typeof a == "object" && "name" in a ? `${a.email ?? ""} (${a.name ?? ""})`.trim() || a.name : String(a);
782
- c && t.ele("author").txt(c);
783
- }
784
- return;
785
- }
786
- if (e === "categories" && Array.isArray(n)) {
787
- for (const r of n) {
788
- const a = r && typeof r == "object" && "name" in r ? r.name : String(r);
789
- if (a) {
790
- const c = r && typeof r == "object" && "domain" in r && r.domain ? { domain: r.domain } : {};
791
- t.ele("category", c).txt(a);
792
- }
793
- }
794
- return;
795
- }
796
- if (Array.isArray(n) && n.length > 0 && n.every((r) => b(r))) {
797
- const r = e.endsWith("s") ? e.slice(0, -1) : e, a = X(e, o);
798
- for (const c of n)
799
- c && P(t, c, r, !1, 0, a);
800
- return;
801
- }
802
- if (Array.isArray(n) && n.every((r) => typeof r == "string")) {
803
- const r = e.endsWith("s") ? e.slice(0, -1) : e;
804
- for (const a of n)
805
- if (a) {
806
- const c = t.ele(r);
807
- I(c, a);
808
- }
809
- return;
810
- }
811
- if (b(n)) {
812
- const r = X(e, o);
813
- P(t, n, e, !1, 0, r);
814
- return;
815
- }
816
- const i = t.ele(e);
817
- I(i, String(n));
818
- }
819
- const Se = "http://www.w3.org/2005/Atom", De = "http://purl.org/syndication/history/1.0";
820
- function Nt(t) {
821
- const e = at({ version: "1.0", encoding: "UTF-8" }), n = Pt(t.items), s = Object.values(n).reduce(
822
- (c, l) => (c[`xmlns:${l.prefix}`] = l.uri, c),
823
- {}
824
- ), o = {
825
- "xmlns:dc": H,
826
- "xmlns:content": q,
827
- "xmlns:media": R,
828
- "xmlns:atom": Se,
829
- ...s
830
- };
831
- t.isArchive && (o["xmlns:fh"] = De);
832
- const r = e.ele("rss", { version: "2.0", ...o }).ele("channel", {
833
- "xmlns:dc": H,
834
- "xmlns:content": q,
835
- "xmlns:media": R
836
- });
837
- if (r.ele("title").txt(t.title), t.link && r.ele("link").txt(t.link), r.ele("description").txt(t.description), t.language && r.ele("language").txt(t.language), t.copyright && r.ele("copyright").txt(t.copyright), t.webMaster && r.ele("webMaster").txt(t.webMaster), t.pubDate && r.ele("pubDate").txt(ae(t.pubDate)), t.lastBuildDate && r.ele("lastBuildDate").txt(ae(t.lastBuildDate)), t.links?.length)
838
- for (const c of t.links) {
839
- const l = { rel: c.rel, href: c.href };
840
- c.type && (l.type = c.type), r.ele(Se, "link", l);
841
- }
842
- t.isArchive && r.ele(De, "archive");
843
- const a = new Set(se);
844
- for (const c of t.items) {
845
- const l = r.ele("item"), d = /* @__PURE__ */ new Set();
846
- for (const g of se)
847
- g in c && (Ce(l, g, c[g], c, n), d.add(g));
848
- const h = Object.keys(c).filter(
849
- (g) => !d.has(g) && !a.has(g) && !g.startsWith("_") && !bt(g, c)
850
- ).sort();
851
- for (const g of h)
852
- Ce(l, g, c[g], c, n);
853
- }
854
- return e.end({ prettyPrint: !0 });
855
- }
856
- function ie(t, e, n) {
857
- return n?.archive ? `${t}:${e}:archive-${n.archive.year}-${n.archive.month}` : n?.page != null && n.page > 1 ? `${t}:${e}:page-${n.page}` : `${t}:${e}`;
858
- }
859
- function Oe(t) {
860
- return `"${it("md5").update(t).digest("hex").substring(0, 16)}"`;
861
- }
862
- function Ot(t, e, n, s) {
863
- const o = `${t}-${e}-${n}-${s}`;
864
- return Oe(o);
865
- }
866
- function jt(t, e, n, s) {
867
- const o = `${t}-${e}-${n}-${s}`;
868
- return Oe(o);
869
- }
870
- function Bt(t, e) {
871
- const n = (s) => s.replace(/^"|"$/g, "");
872
- return n(t) === n(e);
873
- }
874
- function zt(t) {
875
- return t ? t.split(",").map((e) => e.trim()).filter((e) => e.length > 0) : [];
876
- }
877
- function je(t, e) {
878
- const n = zt(t);
879
- return n.length === 0 ? !1 : n.includes("*") ? !0 : n.some((s) => Bt(s, e));
880
- }
881
- class Wt {
882
- feedDataCache = /* @__PURE__ */ new Map();
883
- feedContentCache = /* @__PURE__ */ new Map();
884
- imageMetadataCache = /* @__PURE__ */ new Map();
885
- config;
886
- refreshLocks = /* @__PURE__ */ new Map();
887
- constructor(e) {
888
- this.config = e;
889
- }
890
- /**
891
- * Get cached feed data for a schema
892
- */
893
- getFeedData(e) {
894
- const n = this.feedDataCache.get(e);
895
- return n ? Math.floor(Date.now() / 1e3) - n.lastUpdated > this.config.ttl ? (this.feedDataCache.delete(e), this.clearContentCache(e), null) : n : null;
896
- }
897
- /**
898
- * Set cached feed data for a schema
899
- */
900
- setFeedData(e, n) {
901
- const s = Math.floor(Date.now() / 1e3);
902
- let o = 0, i = "";
903
- for (const c of n) {
904
- const l = c.timeCreated;
905
- l && l > o && (o = l, i = c.id || c.seedUid || c.SeedUid || "");
906
- }
907
- o === 0 && (o = s);
908
- const r = Ot(e, "data", o, n.length), a = {
909
- items: [...n],
910
- // Create a copy
911
- lastProcessedTimestamp: o,
912
- lastProcessedItemId: i,
913
- lastUpdated: s,
914
- etag: r
915
- };
916
- this.feedDataCache.set(e, a);
917
- }
918
- /**
919
- * Get cached feed content for a schema and format
920
- */
921
- getFeedContent(e, n, s) {
922
- const o = ie(e, n, s), i = this.feedContentCache.get(o);
923
- return i ? Math.floor(Date.now() / 1e3) > i.expiresAt ? (this.feedContentCache.delete(o), null) : i : null;
924
- }
925
- /**
926
- * Set cached feed content for a schema and format
927
- */
928
- setFeedContent(e, n, s, o, i, r) {
929
- const a = ie(e, n, i), c = Math.floor(Date.now() / 1e3), l = r ?? this.config.ttl, d = c + l, h = jt(e, n, c, s.length), g = {
930
- content: s,
931
- contentType: o,
932
- etag: h,
933
- lastModified: c,
934
- expiresAt: d
935
- };
936
- this.feedContentCache.set(a, g);
937
- }
938
- /**
939
- * Clear feed data cache for a schema
940
- */
941
- clearFeedData(e) {
942
- this.feedDataCache.delete(e);
943
- }
944
- /**
945
- * Clear content cache for a schema (all formats)
946
- */
947
- clearContentCache(e) {
948
- const n = [];
949
- for (const s of this.feedContentCache.keys())
950
- s.startsWith(`${e}:`) && n.push(s);
951
- n.forEach((s) => this.feedContentCache.delete(s));
952
- }
953
- /**
954
- * Get cached image metadata for a transaction ID
955
- */
956
- getImageMetadata(e) {
957
- const n = this.imageMetadataCache.get(e);
958
- return n ? Math.floor(Date.now() / 1e3) > n.expiresAt ? (this.imageMetadataCache.delete(e), null) : n.metadata : null;
959
- }
960
- /**
961
- * Set cached image metadata for a transaction ID
962
- */
963
- setImageMetadata(e, n) {
964
- const s = Math.floor(Date.now() / 1e3), o = this.config.imageMetadata?.ttl || 604800, i = s + o, r = {
965
- metadata: n,
966
- cachedAt: s,
967
- expiresAt: i
968
- };
969
- this.imageMetadataCache.set(e, r);
970
- }
971
- /**
972
- * Clear all caches
973
- */
974
- clearAll() {
975
- this.feedDataCache.clear(), this.feedContentCache.clear(), this.imageMetadataCache.clear();
976
- }
977
- /**
978
- * Get or create a refresh lock for a schema
979
- * Prevents concurrent fetches for the same schema
980
- */
981
- async withRefreshLock(e, n) {
982
- const s = this.refreshLocks.get(e);
983
- s && (await s, this.getFeedData(e));
984
- const o = (async () => {
985
- try {
986
- return await n();
987
- } finally {
988
- this.refreshLocks.delete(e);
989
- }
990
- })();
991
- return this.refreshLocks.set(e, o), o;
992
- }
993
- /**
994
- * Update configuration
995
- */
996
- updateConfig(e) {
997
- this.config = { ...this.config, ...e };
998
- }
999
- /**
1000
- * Get cache statistics
1001
- */
1002
- getStats() {
1003
- return {
1004
- feedDataCount: this.feedDataCache.size,
1005
- feedContentCount: this.feedContentCache.size,
1006
- imageMetadataCount: this.imageMetadataCache.size,
1007
- activeLocks: this.refreshLocks.size
1008
- };
1009
- }
1010
- }
1011
- class Ht {
1012
- cacheDir;
1013
- config;
1014
- constructor(e) {
1015
- this.cacheDir = e.cacheDir, this.config = e, this.ensureCacheDir().catch((n) => {
1016
- console.error("Failed to create cache directory:", n);
1017
- });
1018
- }
1019
- /**
1020
- * Ensure cache directory exists
1021
- */
1022
- async ensureCacheDir() {
1023
- try {
1024
- await E.mkdir(this.cacheDir, { recursive: !0 });
1025
- } catch (e) {
1026
- if (e.code !== "EEXIST")
1027
- throw e;
1028
- }
1029
- }
1030
- /**
1031
- * Get file path for feed data
1032
- */
1033
- getFeedDataPath(e) {
1034
- return F(this.cacheDir, `${e}.json`);
1035
- }
1036
- /**
1037
- * Get file path for feed content
1038
- */
1039
- getFeedContentPath(e, n, s) {
1040
- const i = ie(e, n, s).replace(/:/g, "-");
1041
- return F(this.cacheDir, `${i}.json`);
1042
- }
1043
- /**
1044
- * Get file path for image metadata
1045
- */
1046
- getImageMetadataPath(e) {
1047
- const n = F(this.cacheDir, "image-metadata");
1048
- return F(n, `${e}.json`);
1049
- }
1050
- /**
1051
- * Ensure image metadata directory exists
1052
- */
1053
- async ensureImageMetadataDir() {
1054
- try {
1055
- const e = F(this.cacheDir, "image-metadata");
1056
- await E.mkdir(e, { recursive: !0 });
1057
- } catch (e) {
1058
- if (e.code !== "EEXIST")
1059
- throw e;
1060
- }
1061
- }
1062
- /**
1063
- * Get cached feed data for a schema
1064
- */
1065
- async getFeedData(e) {
1066
- try {
1067
- const n = this.getFeedDataPath(e), s = await E.readFile(n, "utf-8"), o = JSON.parse(s);
1068
- return Math.floor(Date.now() / 1e3) - o.lastUpdated > this.config.ttl ? (await this.clearFeedData(e), null) : o;
1069
- } catch (n) {
1070
- return n.code === "ENOENT" || console.error(`Error reading feed data cache for ${e}:`, n), null;
1071
- }
1072
- }
1073
- /**
1074
- * Set cached feed data for a schema
1075
- */
1076
- async setFeedData(e, n) {
1077
- try {
1078
- await this.ensureCacheDir();
1079
- const s = this.getFeedDataPath(e);
1080
- await E.writeFile(s, JSON.stringify(n, null, 2), "utf-8");
1081
- } catch (s) {
1082
- console.error(`Error writing feed data cache for ${e}:`, s);
1083
- }
1084
- }
1085
- /**
1086
- * Get cached feed content for a schema and format
1087
- */
1088
- async getFeedContent(e, n, s) {
1089
- try {
1090
- const o = this.getFeedContentPath(e, n, s), i = await E.readFile(o, "utf-8"), r = JSON.parse(i);
1091
- return Math.floor(Date.now() / 1e3) > r.expiresAt ? (await this.clearFeedContent(e, n, s), null) : r;
1092
- } catch (o) {
1093
- return o.code === "ENOENT" || console.error(
1094
- `Error reading feed content cache for ${e}:${n}:`,
1095
- o
1096
- ), null;
1097
- }
1098
- }
1099
- /**
1100
- * Set cached feed content for a schema and format
1101
- */
1102
- async setFeedContent(e, n, s, o) {
1103
- try {
1104
- await this.ensureCacheDir();
1105
- const i = this.getFeedContentPath(e, n, o);
1106
- await E.writeFile(i, JSON.stringify(s, null, 2), "utf-8");
1107
- } catch (i) {
1108
- console.error(
1109
- `Error writing feed content cache for ${e}:${n}:`,
1110
- i
1111
- );
1112
- }
1113
- }
1114
- /**
1115
- * Clear feed data cache for a schema
1116
- */
1117
- async clearFeedData(e) {
1118
- try {
1119
- const n = this.getFeedDataPath(e);
1120
- await E.unlink(n);
1121
- } catch (n) {
1122
- n.code !== "ENOENT" && console.error(`Error clearing feed data cache for ${e}:`, n);
1123
- }
1124
- }
1125
- /**
1126
- * Clear content cache for a schema and format
1127
- */
1128
- async clearFeedContent(e, n, s) {
1129
- try {
1130
- const o = this.getFeedContentPath(e, n, s);
1131
- await E.unlink(o);
1132
- } catch (o) {
1133
- o.code !== "ENOENT" && console.error(
1134
- `Error clearing feed content cache for ${e}:${n}:`,
1135
- o
1136
- );
1137
- }
1138
- }
1139
- /**
1140
- * Clear all content cache for a schema (all formats)
1141
- */
1142
- async clearAllContentCache(e) {
1143
- try {
1144
- const n = await E.readdir(this.cacheDir), s = `${e}-`, o = ".json";
1145
- for (const i of n)
1146
- i.startsWith(s) && i.endsWith(o) && i !== `${e}.json` && await E.unlink(F(this.cacheDir, i));
1147
- } catch (n) {
1148
- console.error(`Error clearing all content cache for ${e}:`, n);
1149
- }
1150
- }
1151
- /**
1152
- * Get cached image metadata for a transaction ID
1153
- */
1154
- async getImageMetadata(e) {
1155
- try {
1156
- const n = this.getImageMetadataPath(e), s = await E.readFile(n, "utf-8"), o = JSON.parse(s);
1157
- return Math.floor(Date.now() / 1e3) > o.expiresAt ? (await this.clearImageMetadata(e), null) : o.metadata;
1158
- } catch (n) {
1159
- return n.code === "ENOENT" || console.error(`Error reading image metadata cache for ${e}:`, n), null;
1160
- }
1161
- }
1162
- /**
1163
- * Set cached image metadata for a transaction ID
1164
- */
1165
- async setImageMetadata(e, n) {
1166
- try {
1167
- await this.ensureImageMetadataDir();
1168
- const s = this.getImageMetadataPath(e), o = Math.floor(Date.now() / 1e3), i = this.config.imageMetadata?.ttl || 604800, r = o + i, a = {
1169
- metadata: n,
1170
- cachedAt: o,
1171
- expiresAt: r
1172
- };
1173
- await E.writeFile(s, JSON.stringify(a, null, 2), "utf-8");
1174
- } catch (s) {
1175
- console.error(`Error writing image metadata cache for ${e}:`, s);
1176
- }
1177
- }
1178
- /**
1179
- * Clear image metadata cache for a transaction ID
1180
- */
1181
- async clearImageMetadata(e) {
1182
- try {
1183
- const n = this.getImageMetadataPath(e);
1184
- await E.unlink(n);
1185
- } catch (n) {
1186
- n.code !== "ENOENT" && console.error(`Error clearing image metadata cache for ${e}:`, n);
1187
- }
1188
- }
1189
- /**
1190
- * Clear all caches
1191
- */
1192
- async clearAll() {
1193
- try {
1194
- const e = await E.readdir(this.cacheDir);
1195
- for (const s of e)
1196
- s.endsWith(".json") && await E.unlink(F(this.cacheDir, s));
1197
- const n = F(this.cacheDir, "image-metadata");
1198
- try {
1199
- const s = await E.readdir(n);
1200
- for (const o of s)
1201
- o.endsWith(".json") && await E.unlink(F(n, o));
1202
- } catch {
1203
- }
1204
- } catch (e) {
1205
- console.error("Error clearing all caches:", e);
1206
- }
1207
- }
1208
- }
1209
- class Gt {
1210
- memoryCache;
1211
- fileCache;
1212
- config;
1213
- stats = {
1214
- hits: 0,
1215
- misses: 0,
1216
- refreshes: 0,
1217
- errors: 0
1218
- };
1219
- constructor(e) {
1220
- this.config = e, this.memoryCache = new Wt(e), this.fileCache = new Ht(e);
1221
- }
1222
- /**
1223
- * Get cached feed data for a schema
1224
- * Checks memory cache first, then file cache
1225
- */
1226
- async getFeedData(e) {
1227
- if (!this.config.enabled)
1228
- return null;
1229
- try {
1230
- let n = this.memoryCache.getFeedData(e);
1231
- return n ? (this.stats.hits++, n) : (n = await this.fileCache.getFeedData(e), n ? (this.memoryCache.setFeedData(e, n.items), this.stats.hits++, n) : (this.stats.misses++, null));
1232
- } catch (n) {
1233
- return console.error(`Error getting feed data cache for ${e}:`, n), this.stats.errors++, null;
1234
- }
1235
- }
1236
- /**
1237
- * Set cached feed data for a schema
1238
- * Updates both memory and file cache
1239
- */
1240
- async setFeedData(e, n) {
1241
- if (this.config.enabled)
1242
- try {
1243
- this.memoryCache.setFeedData(e, n);
1244
- const s = this.memoryCache.getFeedData(e);
1245
- s && await this.fileCache.setFeedData(e, s);
1246
- } catch (s) {
1247
- console.error(`Error setting feed data cache for ${e}:`, s), this.stats.errors++;
1248
- }
1249
- }
1250
- /**
1251
- * Get cached feed content for a schema and format
1252
- * Checks memory cache first, then file cache
1253
- */
1254
- async getFeedContent(e, n, s) {
1255
- if (!this.config.enabled)
1256
- return null;
1257
- try {
1258
- let o = this.memoryCache.getFeedContent(e, n, s);
1259
- return o ? (this.stats.hits++, o) : (o = await this.fileCache.getFeedContent(e, n, s), o ? (this.memoryCache.setFeedContent(
1260
- e,
1261
- n,
1262
- o.content,
1263
- o.contentType,
1264
- s
1265
- ), this.stats.hits++, o) : (this.stats.misses++, null));
1266
- } catch (o) {
1267
- return console.error(
1268
- `Error getting feed content cache for ${e}:${n}:`,
1269
- o
1270
- ), this.stats.errors++, null;
1271
- }
1272
- }
1273
- /**
1274
- * Set cached feed content for a schema and format
1275
- * Updates both memory and file cache
1276
- */
1277
- async setFeedContent(e, n, s, o, i) {
1278
- if (this.config.enabled)
1279
- try {
1280
- let r;
1281
- i?.archive ? r = this.config.archiveTtl ?? 86400 : i?.page != null && i.page > 1 && (r = this.config.pageTtl ?? 300), this.memoryCache.setFeedContent(
1282
- e,
1283
- n,
1284
- s,
1285
- o,
1286
- i,
1287
- r
1288
- );
1289
- const a = this.memoryCache.getFeedContent(e, n, i);
1290
- a && await this.fileCache.setFeedContent(e, n, a, i);
1291
- } catch (r) {
1292
- console.error(
1293
- `Error setting feed content cache for ${e}:${n}:`,
1294
- r
1295
- ), this.stats.errors++;
1296
- }
1297
- }
1298
- /**
1299
- * Clear feed data cache for a schema
1300
- */
1301
- async clearFeedData(e) {
1302
- this.memoryCache.clearFeedData(e), await this.fileCache.clearFeedData(e), this.memoryCache.clearContentCache(e), await this.fileCache.clearAllContentCache(e);
1303
- }
1304
- /**
1305
- * Clear all caches
1306
- */
1307
- async clearAll() {
1308
- this.memoryCache.clearAll(), await this.fileCache.clearAll();
1309
- }
1310
- /**
1311
- * Get or create a refresh lock for a schema
1312
- * Prevents concurrent fetches for the same schema
1313
- */
1314
- async withRefreshLock(e, n) {
1315
- return this.memoryCache.withRefreshLock(e, n);
1316
- }
1317
- /**
1318
- * Merge new items with cached items
1319
- * Deduplicates by item ID and sorts by timeCreated (descending)
1320
- */
1321
- mergeItems(e, n) {
1322
- const s = /* @__PURE__ */ new Map();
1323
- for (const i of e) {
1324
- const r = i.id || i.seedUid || i.SeedUid || "";
1325
- r && s.set(r, i);
1326
- }
1327
- for (const i of n) {
1328
- const r = i.id || i.seedUid || i.SeedUid || "";
1329
- r ? s.set(r, i) : s.set(`temp-${Date.now()}-${Math.random()}`, i);
1330
- }
1331
- const o = Array.from(s.values());
1332
- return o.sort((i, r) => {
1333
- const a = i.timeCreated || 0;
1334
- return (r.timeCreated || 0) - a;
1335
- }), o;
1336
- }
1337
- /**
1338
- * Filter items to only include those newer than the given timestamp
1339
- */
1340
- filterNewItems(e, n) {
1341
- return e.filter((s) => {
1342
- const o = s.timeCreated;
1343
- return o && o > n;
1344
- });
1345
- }
1346
- /**
1347
- * Update configuration
1348
- */
1349
- updateConfig(e) {
1350
- this.config = { ...this.config, ...e }, this.memoryCache.updateConfig(this.config);
1351
- }
1352
- /**
1353
- * Get cache statistics
1354
- */
1355
- getStats() {
1356
- return {
1357
- ...this.stats,
1358
- memoryStats: this.memoryCache.getStats()
1359
- };
1360
- }
1361
- /**
1362
- * Get cached image metadata for a transaction ID
1363
- * Checks memory cache first, then file cache
1364
- */
1365
- async getImageMetadata(e) {
1366
- if (!this.config.enabled || !this.config.imageMetadata?.enabled)
1367
- return null;
1368
- try {
1369
- let n = this.memoryCache.getImageMetadata(e);
1370
- return n ? (this.stats.hits++, n) : (n = await this.fileCache.getImageMetadata(e), n ? (this.memoryCache.setImageMetadata(e, n), this.stats.hits++, n) : (this.stats.misses++, null));
1371
- } catch (n) {
1372
- return console.error(`Error getting image metadata cache for ${e}:`, n), this.stats.errors++, null;
1373
- }
1374
- }
1375
- /**
1376
- * Set cached image metadata for a transaction ID
1377
- * Updates both memory and file cache
1378
- */
1379
- async setImageMetadata(e, n) {
1380
- if (!(!this.config.enabled || !this.config.imageMetadata?.enabled))
1381
- try {
1382
- this.memoryCache.setImageMetadata(e, n), await this.fileCache.setImageMetadata(e, n);
1383
- } catch (s) {
1384
- console.error(`Error setting image metadata cache for ${e}:`, s), this.stats.errors++;
1385
- }
1386
- }
1387
- /**
1388
- * Reset statistics
1389
- */
1390
- resetStats() {
1391
- this.stats = {
1392
- hits: 0,
1393
- misses: 0,
1394
- refreshes: 0,
1395
- errors: 0
1396
- };
1397
- }
1398
- }
1399
- function fe() {
1400
- const t = parseInt(process.env.CACHE_TTL || "3600", 10), e = process.env.CACHE_DIR || "./cache", n = process.env.CACHE_ENABLED === "false" || process.env.CACHE_ENABLED === "0" || process.env.CACHE_ENABLED === "no" || process.env.CACHE_ENABLED === "off", s = process.env.CACHE_ENABLED === "true" || process.env.CACHE_ENABLED === "1" || process.env.CACHE_ENABLED === "yes", o = process.env.NODE_ENV === "development";
1401
- let i;
1402
- n ? i = !1 : s ? i = !0 : o ? i = !1 : i = !0;
1403
- const r = process.env.CACHE_BACKGROUND_REFRESH === "true", a = parseInt(
1404
- process.env.CACHE_REFRESH_INTERVAL || "300",
1405
- 10
1406
- );
1407
- i || console.log(`⚠️ Cache is DISABLED (${n ? "CACHE_ENABLED=false" : o ? "NODE_ENV=development" : "CACHE_ENABLED=false"})`);
1408
- const c = process.env.IMAGE_METADATA_ENABLED !== "false", l = parseInt(process.env.IMAGE_METADATA_TTL || "604800", 10), d = process.env.IMAGE_METADATA_GATEWAYS ? process.env.IMAGE_METADATA_GATEWAYS.split(",").map((p) => p.trim()) : [...Me], h = parseInt(process.env.IMAGE_METADATA_TIMEOUT || "5000", 10), g = {
1409
- enabled: c,
1410
- ttl: l,
1411
- gateways: d,
1412
- timeout: h
1413
- }, f = parseInt(process.env.CACHE_PAGE_TTL || "300", 10), y = parseInt(process.env.CACHE_ARCHIVE_TTL || "86400", 10);
1414
- return {
1415
- ttl: t,
1416
- cacheDir: e,
1417
- enabled: i,
1418
- backgroundRefresh: r,
1419
- refreshInterval: a,
1420
- imageMetadata: g,
1421
- pageTtl: f,
1422
- archiveTtl: y
1423
- };
1424
- }
1425
- class Ae {
1426
- config;
1427
- constructor(e) {
1428
- this.config = e;
1429
- }
1430
- /**
1431
- * Detect if an Arweave transaction ID links to an image and extract metadata
1432
- */
1433
- async detectImage(e) {
1434
- await et().catch(() => {
1435
- });
1436
- const n = this.config.gateways || [...Me];
1437
- for (const s of n)
1438
- try {
1439
- const o = `https://${s}/${e}`, i = await this.getImageMetadata(o);
1440
- if (i.isImage)
1441
- return i;
1442
- } catch (o) {
1443
- console.warn(`Failed to fetch from gateway ${s} for transaction ${e}:`, o);
1444
- continue;
1445
- }
1446
- return {
1447
- isImage: !1,
1448
- url: `https://${n[0]}/${e}`
1449
- };
1450
- }
1451
- /**
1452
- * Get image metadata from a URL
1453
- */
1454
- async getImageMetadata(e) {
1455
- try {
1456
- const n = await this.fetchWithTimeout(e, { method: "HEAD" });
1457
- if (!n.ok)
1458
- return { isImage: !1, url: e };
1459
- const s = n.headers.get("content-type") || "", o = n.headers.get("content-length");
1460
- if (!this.isImageContentType(s))
1461
- return {
1462
- isImage: !1,
1463
- url: e,
1464
- mimeType: s || void 0,
1465
- size: o ? parseInt(o, 10) : void 0
1466
- };
1467
- const i = await this.fetchWithTimeout(e, {
1468
- headers: {
1469
- Range: "bytes=0-8192"
1470
- // First 8KB should be enough for most image headers
1471
- }
1472
- });
1473
- if (!i.ok)
1474
- return await this.getImageMetadataFromFullRequest(e, s, o);
1475
- const r = Buffer.from(await i.arrayBuffer()), a = this.extractImageDimensions(r, s), c = this.getImageFormat(s, r);
1476
- return {
1477
- isImage: !0,
1478
- url: e,
1479
- mimeType: s,
1480
- width: a.width,
1481
- height: a.height,
1482
- size: o ? parseInt(o, 10) : void 0,
1483
- format: c
1484
- };
1485
- } catch (n) {
1486
- return console.warn(`Error fetching image metadata from ${e}:`, n), { isImage: !1, url: e };
1487
- }
1488
- }
1489
- /**
1490
- * Fetch image metadata from full request (fallback when range requests fail)
1491
- */
1492
- async getImageMetadataFromFullRequest(e, n, s) {
1493
- try {
1494
- const o = await this.fetchWithTimeout(e);
1495
- if (!o.ok)
1496
- return { isImage: !1, url: e };
1497
- const i = Buffer.from(await o.arrayBuffer()), r = this.extractImageDimensions(i, n), a = this.getImageFormat(n, i);
1498
- return {
1499
- isImage: !0,
1500
- url: e,
1501
- mimeType: n,
1502
- width: r.width,
1503
- height: r.height,
1504
- size: i.length,
1505
- format: a
1506
- };
1507
- } catch (o) {
1508
- return console.warn(`Error in full request for ${e}:`, o), { isImage: !1, url: e };
1509
- }
1510
- }
1511
- /**
1512
- * Validate if Content-Type indicates an image
1513
- */
1514
- isImageContentType(e) {
1515
- return e ? (e.toLowerCase().split(";")[0] ?? "").trim().startsWith("image/") : !1;
1516
- }
1517
- /**
1518
- * Extract image dimensions from buffer
1519
- */
1520
- extractImageDimensions(e, n) {
1521
- try {
1522
- const s = ue(e);
1523
- if (s.width && s.height)
1524
- return {
1525
- width: s.width,
1526
- height: s.height
1527
- };
1528
- } catch (s) {
1529
- console.warn("Failed to extract dimensions:", s);
1530
- }
1531
- return { width: 0, height: 0 };
1532
- }
1533
- /**
1534
- * Get image format from Content-Type or buffer analysis
1535
- */
1536
- getImageFormat(e, n) {
1537
- if (e) {
1538
- const s = e.toLowerCase().match(/image\/([^;]+)/);
1539
- if (s && s[1]) {
1540
- const o = s[1].toLowerCase();
1541
- return o === "jpeg" ? "jpeg" : o === "png" ? "png" : o === "gif" ? "gif" : o === "webp" ? "webp" : o === "svg+xml" ? "svg" : o;
1542
- }
1543
- }
1544
- try {
1545
- const s = ue(n);
1546
- if (s.type)
1547
- return s.type.toLowerCase();
1548
- } catch {
1549
- }
1550
- }
1551
- /**
1552
- * Fetch with timeout
1553
- */
1554
- async fetchWithTimeout(e, n = {}) {
1555
- const s = new AbortController(), o = setTimeout(() => s.abort(), this.config.timeout);
1556
- try {
1557
- const i = await fetch(e, {
1558
- ...n,
1559
- signal: s.signal
1560
- });
1561
- return clearTimeout(o), i;
1562
- } catch (i) {
1563
- throw clearTimeout(o), i instanceof Error && i.name === "AbortError" ? new Error(`Request timeout after ${this.config.timeout}ms`) : i;
1564
- }
1565
- }
1566
- }
1567
- function ce(t, e) {
1568
- for (const n of e) {
1569
- const s = t[n];
1570
- if (typeof s == "string" && s.trim() !== "")
1571
- return s;
1572
- }
1573
- return "";
1574
- }
1575
- const Be = ["summary", "Summary", "description", "Description", "text", "Text"], ze = ["html", "Html", "body", "Body", "content", "Content"], Xt = ["summary", "Summary", "description", "Description", "text", "Text"];
1576
- function Te(t, e) {
1577
- const n = he(t.model) - he(e.model);
1578
- if (n !== 0) return n;
1579
- const s = t.key.localeCompare(e.key);
1580
- return s !== 0 ? s : t.index - e.index;
1581
- }
1582
- function Jt(t) {
1583
- const e = ee(t), n = te(t);
1584
- let s = null;
1585
- if (e)
1586
- for (const [o, i] of Object.entries(e)) {
1587
- if (!B(i)) continue;
1588
- const r = t[o];
1589
- if (typeof r != "string" || r.trim() === "") continue;
1590
- const a = { model: i, key: o, index: 0, value: r };
1591
- (!s || Te(a, s) < 0) && (s = a);
1592
- }
1593
- if (n)
1594
- for (const [o, i] of Object.entries(n)) {
1595
- const r = t[o];
1596
- if (!Array.isArray(r)) continue;
1597
- const a = Math.min(i.length, r.length);
1598
- for (let c = 0; c < a; c++) {
1599
- const l = i[c];
1600
- if (!B(l)) continue;
1601
- const d = r[c];
1602
- if (typeof d != "string" || d.trim() === "") continue;
1603
- const h = { model: l, key: o, index: c, value: d };
1604
- (!s || Te(h, s) < 0) && (s = h);
1605
- }
1606
- }
1607
- return s?.value ?? "";
1608
- }
1609
- function Vt(t) {
1610
- return ce(t, Be);
1611
- }
1612
- function Kt(t) {
1613
- const e = Jt(t);
1614
- if (e !== "") return e;
1615
- const n = ce(t, ze);
1616
- return n !== "" ? n : ce(t, Xt);
1617
- }
1618
- function Z(t) {
1619
- return typeof t != "string" ? !1 : t.includes("data:image/") && t.includes(";base64,");
1620
- }
1621
- function Yt(t) {
1622
- const e = ee(t);
1623
- if (e) {
1624
- for (const [s, o] of Object.entries(e))
1625
- if (B(o) && Z(t[s]))
1626
- return !0;
1627
- }
1628
- const n = te(t);
1629
- if (n)
1630
- for (const [s, o] of Object.entries(n)) {
1631
- const i = t[s];
1632
- if (!Array.isArray(i)) continue;
1633
- const r = Math.min(o.length, i.length);
1634
- for (let a = 0; a < r; a++)
1635
- if (B(o[a]) && Z(i[a]))
1636
- return !0;
1637
- }
1638
- return !1;
1639
- }
1640
- function qt(t) {
1641
- if (Yt(t)) return !0;
1642
- for (const e of ze)
1643
- if (Z(t[e])) return !0;
1644
- for (const e of Be)
1645
- if (Z(t[e])) return !0;
1646
- return !1;
1647
- }
1648
- function Zt(t, e = "omit_items") {
1649
- return e === "include_items" ? [...t] : t.filter((n) => !qt(n));
1650
- }
1651
- function Qt(t) {
1652
- if (t != null) {
1653
- if (typeof t == "string") {
1654
- if (t.startsWith("http://") || t.startsWith("https://")) return t;
1655
- try {
1656
- return j(t);
1657
- } catch {
1658
- return;
1659
- }
1660
- }
1661
- if (typeof t == "object" && !Array.isArray(t)) {
1662
- const e = t, n = e.arweaveUrl;
1663
- if (typeof n == "string" && n.trim()) return n.trim();
1664
- const s = e.storageTransactionId ?? e.storage_transaction_id;
1665
- if (s && typeof s == "string" && s.trim())
1666
- try {
1667
- return j(s.trim());
1668
- } catch {
1669
- return;
1670
- }
1671
- }
1672
- }
1673
- }
1674
- function re(t) {
1675
- if (typeof t == "number" && Number.isFinite(t) && t > 0) return t;
1676
- if (typeof t == "string") {
1677
- const e = Number(t);
1678
- if (Number.isFinite(e) && e > 0) return e;
1679
- }
1680
- }
1681
- function We(t) {
1682
- if (Array.isArray(t)) {
1683
- for (const n of t) {
1684
- const s = We(n);
1685
- if (s) return s;
1686
- }
1687
- return;
1688
- }
1689
- const e = Qt(t);
1690
- if (e) {
1691
- if (t && typeof t == "object" && !Array.isArray(t)) {
1692
- const n = t, s = typeof n.mimeType == "string" && n.mimeType || typeof n.type == "string" && n.type || typeof n.contentType == "string" && n.contentType || void 0;
1693
- return {
1694
- url: e,
1695
- mimeType: s,
1696
- width: re(n.width),
1697
- height: re(n.height),
1698
- size: re(n.size ?? n.fileSize),
1699
- format: typeof n.format == "string" ? n.format : void 0
1700
- };
1701
- }
1702
- return { url: e };
1703
- }
1704
- }
1705
- function en(t) {
1706
- if (t._hasImage && t._imageMetadata && typeof t._imageMetadata == "object") {
1707
- const n = t._imageMetadata;
1708
- if (n.url)
1709
- return {
1710
- url: n.url,
1711
- mimeType: n.mimeType,
1712
- width: n.width,
1713
- height: n.height,
1714
- size: n.size,
1715
- format: n.format
1716
- };
1717
- }
1718
- const e = [
1719
- "feature_image",
1720
- "featureImage",
1721
- "image",
1722
- "images",
1723
- "cover_image",
1724
- "coverImage",
1725
- "thumbnail",
1726
- "thumbnail_image",
1727
- "thumbnailImage"
1728
- ];
1729
- for (const n of e) {
1730
- if (!(n in t)) continue;
1731
- const s = We(t[n]);
1732
- if (s) return s;
1733
- }
1734
- }
1735
- function tn(t, e, n, s, o, i) {
1736
- const r = n.mimeType || "image/jpeg";
1737
- t.enclosures = [
1738
- {
1739
- url: n.url,
1740
- type: r,
1741
- ...n.size ? { length: n.size } : {}
1742
- }
1743
- ];
1744
- const a = {
1745
- url: n.url,
1746
- type: r,
1747
- medium: "image"
1748
- };
1749
- n.width && (a.width = n.width), n.height && (a.height = n.height), n.size && (a.fileSize = n.size), n.format && (a.format = n.format), t["media:content"] = [a];
1750
- const c = { url: n.url };
1751
- n.width && (c.width = n.width), n.height && (c.height = n.height), t["media:thumbnail"] = [c], e.title && (t["media:title"] = e.title);
1752
- const l = e.description || e.summary || e.title || "";
1753
- if (l && (t["media:description"] = l), e.title) {
1754
- const d = [];
1755
- d.push(...String(e.title).toLowerCase().split(/\s+/).filter((h) => h.length > 3)), e.description && d.push(...String(e.description).toLowerCase().split(/\s+/).filter((h) => h.length > 3)), d.length > 0 && (t["media:keywords"] = [...new Set(d)].slice(0, 10).join(", "));
1756
- }
1757
- if (Array.isArray(e.authors) && e.authors.length > 0 ? t["media:credit"] = e.authors.map((d) => ({
1758
- value: d.name || d.displayName || "Unknown",
1759
- role: "author"
1760
- })) : o && (t["media:credit"] = [{ value: o.name, role: "author" }]), i && (t["media:copyright"] = i), s && (t["media:category"] = [
1761
- {
1762
- value: s,
1763
- scheme: "http://www.schema.org/"
1764
- }
1765
- ]), t["media:group"] = [
1766
- {
1767
- "media:content": [a],
1768
- "media:thumbnail": [c],
1769
- "media:title": e.title || "Untitled",
1770
- "media:description": l
1771
- }
1772
- ], n.url && typeof e.content == "string" && e.content.trim() !== "" && !e.content.includes(n.url)) {
1773
- const d = `<img src="${n.url}" alt="${e.title || ""}"${n.width ? ` width="${n.width}"` : ""}${n.height ? ` height="${n.height}"` : ""} />`;
1774
- t["content:encoded"] = `${d}
1775
- ${e.content}`;
1776
- }
1777
- }
1778
- let N, x = null, K = null;
1779
- function He() {
1780
- if (!K) {
1781
- const t = fe();
1782
- K = new Gt(t);
1783
- }
1784
- return K;
1785
- }
1786
- function wn() {
1787
- K = null;
1788
- }
1789
- const nn = async () => {
1790
- if (x)
1791
- return x;
1792
- if (!N)
1793
- return x = (async () => {
1794
- try {
1795
- console.log("Initializing Seed Protocol client..."), await L.init({ config: {
1796
- endpoints: {
1797
- filePaths: "app-files",
1798
- files: "/app-files"
1799
- },
1800
- arweaveDomain: tt
1801
- }, addresses: [] }), console.log("✅ Seed Protocol client initialized successfully"), N = L, x = null;
1802
- } catch (t) {
1803
- throw console.error("❌ Failed to initialize Seed Protocol client:", t), x = null, t;
1804
- }
1805
- })(), x;
1806
- }, rn = async () => N || (x ? (await x, N) : (await nn(), N)), Cn = async () => {
1807
- try {
1808
- console.log("Tearing down Seed Protocol client..."), typeof L.stop == "function" && (await L.stop(), console.log("✅ Seed Protocol client stopped")), typeof L.unload == "function" && (await L.unload(), console.log("✅ Seed Protocol client unloaded")), console.log("✅ Seed Protocol client teardown complete");
1809
- } catch (t) {
1810
- console.error("❌ Failed to teardown Seed Protocol client:", t);
1811
- }
1812
- }, T = {
1813
- title: "Seed Protocol",
1814
- description: "Content published via Seed Protocol",
1815
- siteUrl: "https://seedprotocol.io",
1816
- feedUrl: "https://feed.seedprotocol.io",
1817
- language: "en",
1818
- copyright: `© ${(/* @__PURE__ */ new Date()).getFullYear()} All rights reserved`,
1819
- author: {
1820
- name: "Seed Protocol",
1821
- email: "info@seedprotocol.io",
1822
- link: "https://seedprotocol.io"
1823
- }
572
+ function qe(e) {
573
+ return e.endsWith("s") && e.length > 1 ? e.slice(0, -1) : e;
574
+ }
575
+ function Je(e) {
576
+ return e.trim().replace(/[^A-Za-z0-9_.-]+/g, "_").replace(/^[^A-Za-z_]+/, "").replace(/^$/, "rel").toLowerCase();
577
+ }
578
+ function Ye(e, t) {
579
+ if (!t.has(e) && !Ve.has(e)) return t.add(e), e;
580
+ let n = 2;
581
+ for (;;) {
582
+ let r = `${e}${n}`;
583
+ if (!t.has(r) && !Ve.has(r)) return t.add(r), r;
584
+ n += 1;
585
+ }
586
+ }
587
+ function Xe(e) {
588
+ return Array.isArray(e) && e.length > 0 && e.every((e) => W(e));
589
+ }
590
+ function Ze(e) {
591
+ let t = { ...ze }, n = new Set(Object.values(t).map((e) => e.prefix)), r = /* @__PURE__ */ new Set();
592
+ for (let t of e) for (let [e, n] of Object.entries(t)) {
593
+ let t = e === "author" && W(n) || e === "authors" && Xe(n);
594
+ e.startsWith("_") || Ke.has(e) && !t || (W(n) || Xe(n)) && r.add(qe(e));
595
+ }
596
+ let i = [...r].sort();
597
+ for (let e of i) t[e] || (t[e] = {
598
+ prefix: Ye(Je(e), n),
599
+ uri: `${Be}/${e}/1.0`
600
+ });
601
+ return t;
602
+ }
603
+ function G(e, t) {
604
+ if (e in t) return t[e];
605
+ if (e.endsWith("s") && e.length > 1) {
606
+ let n = e.slice(0, -1);
607
+ if (n in t) return t[n];
608
+ }
609
+ }
610
+ function Qe(e, t) {
611
+ return t ? `${t.prefix}:${e}` : e;
612
+ }
613
+ function K(e, t, n, r, i = 0, a) {
614
+ let o = e.ele(n);
615
+ for (let [e, n] of Object.entries(t)) {
616
+ if (n == null || e.startsWith("_") || e === "items") continue;
617
+ let t = Qe(e, a);
618
+ if (i >= Ge) {
619
+ U(o.ele(t), typeof n == "object" ? JSON.stringify(n) : String(n));
620
+ continue;
621
+ }
622
+ if (Array.isArray(n)) {
623
+ let t = Qe(e.endsWith("s") && e.length > 1 ? e.slice(0, -1) : e, a);
624
+ for (let e of n) e != null && (W(e) ? K(o, e, t, !1, i + 1, a) : U(o.ele(t), String(e)));
625
+ continue;
626
+ }
627
+ if (W(n)) {
628
+ K(o, n, t, !1, i + 1, a);
629
+ continue;
630
+ }
631
+ U(o.ele(t), String(n));
632
+ }
633
+ if (r) {
634
+ let n = t.name ?? t.seedUid;
635
+ n && e.ele(R, "creator").txt(String(n));
636
+ }
637
+ }
638
+ function $e(e, t, n, r, i) {
639
+ if (!(n == null || t.startsWith("_")) && t !== "items") {
640
+ if (t === "guid") {
641
+ let t = n, r = t?.value ?? String(n);
642
+ if (!r) return;
643
+ let i = {};
644
+ typeof t?.isPermaLink == "boolean" && (i.isPermaLink = t.isPermaLink ? "true" : "false"), U(e.ele("guid", i), r);
645
+ return;
646
+ }
647
+ if (t === "source" && typeof n == "object" && n) {
648
+ let t = n, r = t.title ?? String(n);
649
+ if (!r) return;
650
+ let i = t.url ? { url: t.url } : {};
651
+ e.ele("source", i).txt(r);
652
+ return;
653
+ }
654
+ if (t === "enclosures" && Array.isArray(n)) {
655
+ for (let t of n) if (t && typeof t == "object" && "url" in t) {
656
+ let n = {
657
+ url: String(t.url),
658
+ type: String(t.type ?? "application/octet-stream")
659
+ };
660
+ t.length != null && (n.length = String(t.length)), e.ele("enclosure", n);
661
+ }
662
+ return;
663
+ }
664
+ if (t === "dc" && typeof n == "object" && n) {
665
+ let t = n;
666
+ for (let [n, r] of Object.entries(t)) if (r != null) if (Array.isArray(r)) {
667
+ for (let t of r) if (t != null) {
668
+ let r = e.ele(R, n);
669
+ t instanceof Date ? r.txt(t.toISOString()) : U(r, String(t));
670
+ }
671
+ } else {
672
+ let t = e.ele(R, n);
673
+ r instanceof Date ? t.txt(r.toISOString()) : U(t, String(r));
674
+ }
675
+ return;
676
+ }
677
+ if (t === "content:encoded") {
678
+ U(e.ele(z, "encoded"), String(n));
679
+ return;
680
+ }
681
+ if (t === "content" && typeof n == "string" && !("content:encoded" in r)) {
682
+ U(e.ele(z, "encoded"), String(n));
683
+ return;
684
+ }
685
+ if (t !== "content") {
686
+ if (t === "media:group" && Array.isArray(n)) {
687
+ for (let t of n) if (t && typeof t == "object") {
688
+ let n = e.ele(B, "group");
689
+ for (let [e, r] of Object.entries(t)) if (r != null && e.startsWith("media:")) {
690
+ let t = e.slice(6);
691
+ if (Array.isArray(r)) {
692
+ for (let e of r) if (e && typeof e == "object") {
693
+ let r = n.ele(B, t);
694
+ for (let [t, n] of Object.entries(e)) n != null && (t === "url" || t === "value" ? U(r, String(n)) : r.att(t, String(n)));
695
+ }
696
+ } else typeof r == "string" && U(n.ele(B, t), r);
697
+ }
698
+ }
699
+ return;
700
+ }
701
+ if (t.startsWith("media:") && Array.isArray(n)) {
702
+ let r = t.slice(6);
703
+ for (let t of n) {
704
+ if (typeof t != "object" || !t) continue;
705
+ let n = {}, i = null;
706
+ for (let [e, r] of Object.entries(t)) r != null && (e === "value" ? i = String(r) : n[e] = String(r));
707
+ let a = e.ele(B, r, n);
708
+ i !== null && U(a, i);
709
+ }
710
+ return;
711
+ }
712
+ if (t.startsWith("media:") && typeof n == "string") {
713
+ let r = t.slice(6);
714
+ U(e.ele(B, r), n);
715
+ return;
716
+ }
717
+ if (n instanceof Date) {
718
+ e.ele(t).txt(H(n));
719
+ return;
720
+ }
721
+ if (t === "author" && W(n)) {
722
+ K(e, n, "author", !0, 0, G(t, i));
723
+ return;
724
+ }
725
+ if (t === "authors" && Array.isArray(n)) {
726
+ let r = G(t, i);
727
+ for (let t of n) if (t && W(t)) K(e, t, "author", !0, 0, r);
728
+ else {
729
+ let n = typeof t == "string" ? t : t && typeof t == "object" && "name" in t ? `${t.email ?? ""} (${t.name ?? ""})`.trim() || t.name : String(t);
730
+ n && e.ele("author").txt(n);
731
+ }
732
+ return;
733
+ }
734
+ if (t === "categories" && Array.isArray(n)) {
735
+ for (let t of n) {
736
+ let n = t && typeof t == "object" && "name" in t ? t.name : String(t);
737
+ if (n) {
738
+ let r = t && typeof t == "object" && "domain" in t && t.domain ? { domain: t.domain } : {};
739
+ e.ele("category", r).txt(n);
740
+ }
741
+ }
742
+ return;
743
+ }
744
+ if (Array.isArray(n) && n.length > 0 && n.every((e) => W(e))) {
745
+ let r = t.endsWith("s") ? t.slice(0, -1) : t, a = G(t, i);
746
+ for (let t of n) t && K(e, t, r, !1, 0, a);
747
+ return;
748
+ }
749
+ if (Array.isArray(n) && n.every((e) => typeof e == "string")) {
750
+ let r = t.endsWith("s") ? t.slice(0, -1) : t;
751
+ for (let t of n) t && U(e.ele(r), t);
752
+ return;
753
+ }
754
+ if (W(n)) {
755
+ K(e, n, t, !1, 0, G(t, i));
756
+ return;
757
+ }
758
+ U(e.ele(t), String(n));
759
+ }
760
+ }
761
+ }
762
+ var et = "http://www.w3.org/2005/Atom", tt = "http://purl.org/syndication/history/1.0";
763
+ function nt(e) {
764
+ let t = re({
765
+ version: "1.0",
766
+ encoding: "UTF-8"
767
+ }), n = Ze(e.items), r = {
768
+ "xmlns:dc": R,
769
+ "xmlns:content": z,
770
+ "xmlns:media": B,
771
+ "xmlns:atom": et,
772
+ ...Object.values(n).reduce((e, t) => (e[`xmlns:${t.prefix}`] = t.uri, e), {})
773
+ };
774
+ e.isArchive && (r["xmlns:fh"] = tt);
775
+ let i = t.ele("rss", {
776
+ version: "2.0",
777
+ ...r
778
+ }).ele("channel", {
779
+ "xmlns:dc": R,
780
+ "xmlns:content": z,
781
+ "xmlns:media": B
782
+ });
783
+ if (i.ele("title").txt(e.title), e.link && i.ele("link").txt(e.link), i.ele("description").txt(e.description), e.language && i.ele("language").txt(e.language), e.copyright && i.ele("copyright").txt(e.copyright), e.webMaster && i.ele("webMaster").txt(e.webMaster), e.pubDate && i.ele("pubDate").txt(H(e.pubDate)), e.lastBuildDate && i.ele("lastBuildDate").txt(H(e.lastBuildDate)), e.links?.length) for (let t of e.links) {
784
+ let e = {
785
+ rel: t.rel,
786
+ href: t.href
787
+ };
788
+ t.type && (e.type = t.type), i.ele(et, "link", e);
789
+ }
790
+ e.isArchive && i.ele(tt, "archive");
791
+ let a = new Set(V);
792
+ for (let t of e.items) {
793
+ let e = i.ele("item"), r = /* @__PURE__ */ new Set();
794
+ for (let i of V) i in t && ($e(e, i, t[i], t, n), r.add(i));
795
+ let o = Object.keys(t).filter((e) => !r.has(e) && !a.has(e) && !e.startsWith("_") && !Ue(e, t)).sort();
796
+ for (let r of o) $e(e, r, t[r], t, n);
797
+ }
798
+ return t.end({ prettyPrint: !0 });
799
+ }
800
+ //#endregion
801
+ //#region src/cache/types.ts
802
+ function q(e, t, n) {
803
+ return n?.archive ? `${e}:${t}:archive-${n.archive.year}-${n.archive.month}` : n?.page != null && n.page > 1 ? `${e}:${t}:page-${n.page}` : `${e}:${t}`;
804
+ }
805
+ //#endregion
806
+ //#region src/utils/etag.ts
807
+ function rt(e) {
808
+ return `"${ie("md5").update(e).digest("hex").substring(0, 16)}"`;
809
+ }
810
+ function it(e, t, n, r) {
811
+ return rt(`${e}-${t}-${n}-${r}`);
812
+ }
813
+ function at(e, t, n, r) {
814
+ return rt(`${e}-${t}-${n}-${r}`);
815
+ }
816
+ function ot(e, t) {
817
+ let n = (e) => e.replace(/^"|"$/g, "");
818
+ return n(e) === n(t);
819
+ }
820
+ function st(e) {
821
+ return e ? e.split(",").map((e) => e.trim()).filter((e) => e.length > 0) : [];
822
+ }
823
+ function ct(e, t) {
824
+ let n = st(e);
825
+ return n.length === 0 ? !1 : n.includes("*") ? !0 : n.some((e) => ot(e, t));
826
+ }
827
+ //#endregion
828
+ //#region src/cache/MemoryCache.ts
829
+ var lt = class {
830
+ feedDataCache = /* @__PURE__ */ new Map();
831
+ feedContentCache = /* @__PURE__ */ new Map();
832
+ imageMetadataCache = /* @__PURE__ */ new Map();
833
+ config;
834
+ refreshLocks = /* @__PURE__ */ new Map();
835
+ constructor(e) {
836
+ this.config = e;
837
+ }
838
+ getFeedData(e) {
839
+ let t = this.feedDataCache.get(e);
840
+ return t ? Math.floor(Date.now() / 1e3) - t.lastUpdated > this.config.ttl ? (this.feedDataCache.delete(e), this.clearContentCache(e), null) : t : null;
841
+ }
842
+ setFeedData(e, t) {
843
+ let n = Math.floor(Date.now() / 1e3), r = 0, i = "";
844
+ for (let e of t) {
845
+ let t = e.timeCreated;
846
+ t && t > r && (r = t, i = e.id || e.seedUid || e.SeedUid || "");
847
+ }
848
+ r === 0 && (r = n);
849
+ let a = it(e, "data", r, t.length), o = {
850
+ items: [...t],
851
+ lastProcessedTimestamp: r,
852
+ lastProcessedItemId: i,
853
+ lastUpdated: n,
854
+ etag: a
855
+ };
856
+ this.feedDataCache.set(e, o);
857
+ }
858
+ getFeedContent(e, t, n) {
859
+ let r = q(e, t, n), i = this.feedContentCache.get(r);
860
+ return i ? Math.floor(Date.now() / 1e3) > i.expiresAt ? (this.feedContentCache.delete(r), null) : i : null;
861
+ }
862
+ setFeedContent(e, t, n, r, i, a) {
863
+ let o = q(e, t, i), s = Math.floor(Date.now() / 1e3), c = s + (a ?? this.config.ttl), l = {
864
+ content: n,
865
+ contentType: r,
866
+ etag: at(e, t, s, n.length),
867
+ lastModified: s,
868
+ expiresAt: c
869
+ };
870
+ this.feedContentCache.set(o, l);
871
+ }
872
+ clearFeedData(e) {
873
+ this.feedDataCache.delete(e);
874
+ }
875
+ clearContentCache(e) {
876
+ let t = [];
877
+ for (let n of this.feedContentCache.keys()) n.startsWith(`${e}:`) && t.push(n);
878
+ t.forEach((e) => this.feedContentCache.delete(e));
879
+ }
880
+ getImageMetadata(e) {
881
+ let t = this.imageMetadataCache.get(e);
882
+ return t ? Math.floor(Date.now() / 1e3) > t.expiresAt ? (this.imageMetadataCache.delete(e), null) : t.metadata : null;
883
+ }
884
+ setImageMetadata(e, t) {
885
+ let n = Math.floor(Date.now() / 1e3), r = {
886
+ metadata: t,
887
+ cachedAt: n,
888
+ expiresAt: n + (this.config.imageMetadata?.ttl || 604800)
889
+ };
890
+ this.imageMetadataCache.set(e, r);
891
+ }
892
+ clearAll() {
893
+ this.feedDataCache.clear(), this.feedContentCache.clear(), this.imageMetadataCache.clear();
894
+ }
895
+ async withRefreshLock(e, t) {
896
+ let n = this.refreshLocks.get(e);
897
+ n && (await n, this.getFeedData(e));
898
+ let r = (async () => {
899
+ try {
900
+ return await t();
901
+ } finally {
902
+ this.refreshLocks.delete(e);
903
+ }
904
+ })();
905
+ return this.refreshLocks.set(e, r), r;
906
+ }
907
+ updateConfig(e) {
908
+ this.config = {
909
+ ...this.config,
910
+ ...e
911
+ };
912
+ }
913
+ getStats() {
914
+ return {
915
+ feedDataCount: this.feedDataCache.size,
916
+ feedContentCount: this.feedContentCache.size,
917
+ imageMetadataCount: this.imageMetadataCache.size,
918
+ activeLocks: this.refreshLocks.size
919
+ };
920
+ }
921
+ }, ut = class {
922
+ cacheDir;
923
+ config;
924
+ constructor(e) {
925
+ this.cacheDir = e.cacheDir, this.config = e, this.ensureCacheDir().catch((e) => {
926
+ console.error("Failed to create cache directory:", e);
927
+ });
928
+ }
929
+ async ensureCacheDir() {
930
+ try {
931
+ await y.mkdir(this.cacheDir, { recursive: !0 });
932
+ } catch (e) {
933
+ if (e.code !== "EEXIST") throw e;
934
+ }
935
+ }
936
+ getFeedDataPath(e) {
937
+ return b(this.cacheDir, `${e}.json`);
938
+ }
939
+ getFeedContentPath(e, t, n) {
940
+ let r = q(e, t, n).replace(/:/g, "-");
941
+ return b(this.cacheDir, `${r}.json`);
942
+ }
943
+ getImageMetadataPath(e) {
944
+ return b(b(this.cacheDir, "image-metadata"), `${e}.json`);
945
+ }
946
+ async ensureImageMetadataDir() {
947
+ try {
948
+ let e = b(this.cacheDir, "image-metadata");
949
+ await y.mkdir(e, { recursive: !0 });
950
+ } catch (e) {
951
+ if (e.code !== "EEXIST") throw e;
952
+ }
953
+ }
954
+ async getFeedData(e) {
955
+ try {
956
+ let t = this.getFeedDataPath(e), n = await y.readFile(t, "utf-8"), r = JSON.parse(n);
957
+ return Math.floor(Date.now() / 1e3) - r.lastUpdated > this.config.ttl ? (await this.clearFeedData(e), null) : r;
958
+ } catch (t) {
959
+ return t.code === "ENOENT" || console.error(`Error reading feed data cache for ${e}:`, t), null;
960
+ }
961
+ }
962
+ async setFeedData(e, t) {
963
+ try {
964
+ await this.ensureCacheDir();
965
+ let n = this.getFeedDataPath(e);
966
+ await y.writeFile(n, JSON.stringify(t, null, 2), "utf-8");
967
+ } catch (t) {
968
+ console.error(`Error writing feed data cache for ${e}:`, t);
969
+ }
970
+ }
971
+ async getFeedContent(e, t, n) {
972
+ try {
973
+ let r = this.getFeedContentPath(e, t, n), i = await y.readFile(r, "utf-8"), a = JSON.parse(i);
974
+ return Math.floor(Date.now() / 1e3) > a.expiresAt ? (await this.clearFeedContent(e, t, n), null) : a;
975
+ } catch (n) {
976
+ return n.code === "ENOENT" || console.error(`Error reading feed content cache for ${e}:${t}:`, n), null;
977
+ }
978
+ }
979
+ async setFeedContent(e, t, n, r) {
980
+ try {
981
+ await this.ensureCacheDir();
982
+ let i = this.getFeedContentPath(e, t, r);
983
+ await y.writeFile(i, JSON.stringify(n, null, 2), "utf-8");
984
+ } catch (n) {
985
+ console.error(`Error writing feed content cache for ${e}:${t}:`, n);
986
+ }
987
+ }
988
+ async clearFeedData(e) {
989
+ try {
990
+ let t = this.getFeedDataPath(e);
991
+ await y.unlink(t);
992
+ } catch (t) {
993
+ t.code !== "ENOENT" && console.error(`Error clearing feed data cache for ${e}:`, t);
994
+ }
995
+ }
996
+ async clearFeedContent(e, t, n) {
997
+ try {
998
+ let r = this.getFeedContentPath(e, t, n);
999
+ await y.unlink(r);
1000
+ } catch (n) {
1001
+ n.code !== "ENOENT" && console.error(`Error clearing feed content cache for ${e}:${t}:`, n);
1002
+ }
1003
+ }
1004
+ async clearAllContentCache(e) {
1005
+ try {
1006
+ let t = await y.readdir(this.cacheDir), n = `${e}-`;
1007
+ for (let r of t) r.startsWith(n) && r.endsWith(".json") && r !== `${e}.json` && await y.unlink(b(this.cacheDir, r));
1008
+ } catch (t) {
1009
+ console.error(`Error clearing all content cache for ${e}:`, t);
1010
+ }
1011
+ }
1012
+ async getImageMetadata(e) {
1013
+ try {
1014
+ let t = this.getImageMetadataPath(e), n = await y.readFile(t, "utf-8"), r = JSON.parse(n);
1015
+ return Math.floor(Date.now() / 1e3) > r.expiresAt ? (await this.clearImageMetadata(e), null) : r.metadata;
1016
+ } catch (t) {
1017
+ return t.code === "ENOENT" || console.error(`Error reading image metadata cache for ${e}:`, t), null;
1018
+ }
1019
+ }
1020
+ async setImageMetadata(e, t) {
1021
+ try {
1022
+ await this.ensureImageMetadataDir();
1023
+ let n = this.getImageMetadataPath(e), r = Math.floor(Date.now() / 1e3), i = {
1024
+ metadata: t,
1025
+ cachedAt: r,
1026
+ expiresAt: r + (this.config.imageMetadata?.ttl || 604800)
1027
+ };
1028
+ await y.writeFile(n, JSON.stringify(i, null, 2), "utf-8");
1029
+ } catch (t) {
1030
+ console.error(`Error writing image metadata cache for ${e}:`, t);
1031
+ }
1032
+ }
1033
+ async clearImageMetadata(e) {
1034
+ try {
1035
+ let t = this.getImageMetadataPath(e);
1036
+ await y.unlink(t);
1037
+ } catch (t) {
1038
+ t.code !== "ENOENT" && console.error(`Error clearing image metadata cache for ${e}:`, t);
1039
+ }
1040
+ }
1041
+ async clearAll() {
1042
+ try {
1043
+ let e = await y.readdir(this.cacheDir);
1044
+ for (let t of e) t.endsWith(".json") && await y.unlink(b(this.cacheDir, t));
1045
+ let t = b(this.cacheDir, "image-metadata");
1046
+ try {
1047
+ let e = await y.readdir(t);
1048
+ for (let n of e) n.endsWith(".json") && await y.unlink(b(t, n));
1049
+ } catch {}
1050
+ } catch (e) {
1051
+ console.error("Error clearing all caches:", e);
1052
+ }
1053
+ }
1054
+ }, dt = class {
1055
+ memoryCache;
1056
+ fileCache;
1057
+ config;
1058
+ stats = {
1059
+ hits: 0,
1060
+ misses: 0,
1061
+ refreshes: 0,
1062
+ errors: 0
1063
+ };
1064
+ constructor(e) {
1065
+ this.config = e, this.memoryCache = new lt(e), this.fileCache = new ut(e);
1066
+ }
1067
+ async getFeedData(e) {
1068
+ if (!this.config.enabled) return null;
1069
+ try {
1070
+ let t = this.memoryCache.getFeedData(e);
1071
+ return t ? (this.stats.hits++, t) : (t = await this.fileCache.getFeedData(e), t ? (this.memoryCache.setFeedData(e, t.items), this.stats.hits++, t) : (this.stats.misses++, null));
1072
+ } catch (t) {
1073
+ return console.error(`Error getting feed data cache for ${e}:`, t), this.stats.errors++, null;
1074
+ }
1075
+ }
1076
+ async setFeedData(e, t) {
1077
+ if (this.config.enabled) try {
1078
+ this.memoryCache.setFeedData(e, t);
1079
+ let n = this.memoryCache.getFeedData(e);
1080
+ n && await this.fileCache.setFeedData(e, n);
1081
+ } catch (t) {
1082
+ console.error(`Error setting feed data cache for ${e}:`, t), this.stats.errors++;
1083
+ }
1084
+ }
1085
+ async getFeedContent(e, t, n) {
1086
+ if (!this.config.enabled) return null;
1087
+ try {
1088
+ let r = this.memoryCache.getFeedContent(e, t, n);
1089
+ return r ? (this.stats.hits++, r) : (r = await this.fileCache.getFeedContent(e, t, n), r ? (this.memoryCache.setFeedContent(e, t, r.content, r.contentType, n), this.stats.hits++, r) : (this.stats.misses++, null));
1090
+ } catch (n) {
1091
+ return console.error(`Error getting feed content cache for ${e}:${t}:`, n), this.stats.errors++, null;
1092
+ }
1093
+ }
1094
+ async setFeedContent(e, t, n, r, i) {
1095
+ if (this.config.enabled) try {
1096
+ let a;
1097
+ i?.archive ? a = this.config.archiveTtl ?? 86400 : i?.page != null && i.page > 1 && (a = this.config.pageTtl ?? 300), this.memoryCache.setFeedContent(e, t, n, r, i, a);
1098
+ let o = this.memoryCache.getFeedContent(e, t, i);
1099
+ o && await this.fileCache.setFeedContent(e, t, o, i);
1100
+ } catch (n) {
1101
+ console.error(`Error setting feed content cache for ${e}:${t}:`, n), this.stats.errors++;
1102
+ }
1103
+ }
1104
+ async clearFeedData(e) {
1105
+ this.memoryCache.clearFeedData(e), await this.fileCache.clearFeedData(e), this.memoryCache.clearContentCache(e), await this.fileCache.clearAllContentCache(e);
1106
+ }
1107
+ async clearAll() {
1108
+ this.memoryCache.clearAll(), await this.fileCache.clearAll();
1109
+ }
1110
+ async withRefreshLock(e, t) {
1111
+ return this.memoryCache.withRefreshLock(e, t);
1112
+ }
1113
+ mergeItems(e, t) {
1114
+ let n = /* @__PURE__ */ new Map();
1115
+ for (let t of e) {
1116
+ let e = t.id || t.seedUid || t.SeedUid || "";
1117
+ e && n.set(e, t);
1118
+ }
1119
+ for (let e of t) {
1120
+ let t = e.id || e.seedUid || e.SeedUid || "";
1121
+ t ? n.set(t, e) : n.set(`temp-${Date.now()}-${Math.random()}`, e);
1122
+ }
1123
+ let r = Array.from(n.values());
1124
+ return r.sort((e, t) => {
1125
+ let n = e.timeCreated || 0;
1126
+ return (t.timeCreated || 0) - n;
1127
+ }), r;
1128
+ }
1129
+ filterNewItems(e, t) {
1130
+ return e.filter((e) => {
1131
+ let n = e.timeCreated;
1132
+ return n && n > t;
1133
+ });
1134
+ }
1135
+ updateConfig(e) {
1136
+ this.config = {
1137
+ ...this.config,
1138
+ ...e
1139
+ }, this.memoryCache.updateConfig(this.config);
1140
+ }
1141
+ getStats() {
1142
+ return {
1143
+ ...this.stats,
1144
+ memoryStats: this.memoryCache.getStats()
1145
+ };
1146
+ }
1147
+ async getImageMetadata(e) {
1148
+ if (!this.config.enabled || !this.config.imageMetadata?.enabled) return null;
1149
+ try {
1150
+ let t = this.memoryCache.getImageMetadata(e);
1151
+ return t ? (this.stats.hits++, t) : (t = await this.fileCache.getImageMetadata(e), t ? (this.memoryCache.setImageMetadata(e, t), this.stats.hits++, t) : (this.stats.misses++, null));
1152
+ } catch (t) {
1153
+ return console.error(`Error getting image metadata cache for ${e}:`, t), this.stats.errors++, null;
1154
+ }
1155
+ }
1156
+ async setImageMetadata(e, t) {
1157
+ if (!(!this.config.enabled || !this.config.imageMetadata?.enabled)) try {
1158
+ this.memoryCache.setImageMetadata(e, t), await this.fileCache.setImageMetadata(e, t);
1159
+ } catch (t) {
1160
+ console.error(`Error setting image metadata cache for ${e}:`, t), this.stats.errors++;
1161
+ }
1162
+ }
1163
+ resetStats() {
1164
+ this.stats = {
1165
+ hits: 0,
1166
+ misses: 0,
1167
+ refreshes: 0,
1168
+ errors: 0
1169
+ };
1170
+ }
1824
1171
  };
1825
- async function Ee(t, e, n) {
1826
- const s = t.filter(
1827
- (a) => a.storageTransactionId || a.storage_transaction_id
1828
- );
1829
- if (s.length === 0)
1830
- return t;
1831
- console.log(`Enriching ${s.length} items with image metadata`);
1832
- const o = s.map(async (a) => {
1833
- const c = a.storageTransactionId || a.storage_transaction_id;
1834
- if (!c) return a;
1835
- try {
1836
- let l = await n.getImageMetadata(c);
1837
- return l || (console.log(`Detecting image for transaction ${c}`), l = await e.detectImage(c), await n.setImageMetadata(c, l)), l.isImage && (a._imageMetadata = l, a._hasImage = !0), a;
1838
- } catch (l) {
1839
- return console.warn(`Error enriching item with transaction ${c}:`, l), a;
1840
- }
1841
- }), i = await Promise.all(o), r = /* @__PURE__ */ new Map();
1842
- return i.forEach((a) => {
1843
- const c = a.id || a.seedUid || a.SeedUid || "";
1844
- c && r.set(c, a);
1845
- }), t.map((a) => {
1846
- const c = a.id || a.seedUid || a.SeedUid || "";
1847
- return r.get(c) || a;
1848
- });
1849
- }
1850
- function on(t, e) {
1851
- const { schemaName: n, siteUrl: s, itemUrlBase: o, itemUrlPath: i, richTextDataUriImages: r = "omit_items" } = e;
1852
- return Zt(
1853
- t,
1854
- r
1855
- ).map((c) => {
1856
- const l = c.id || c.seedUid || c.SeedUid || c.storageTransactionId || c.storage_transaction_id, d = o != null ? `${o.replace(/\/$/, "")}/${(i ?? "attestation/view").replace(/^\//, "")}/${l}` : `${s}/${U(n)}/${l}`, h = c.link || c.Link || c.import_url || c.importUrl || d;
1857
- let g;
1858
- if (c.pubDate || c.PubDate) {
1859
- const w = c.pubDate || c.PubDate;
1860
- g = new Date(w);
1861
- } else if (c.timeCreated)
1862
- g = new Date(c.timeCreated * 1e3);
1863
- else if (c.publishedAt || c.createdAt || c.updatedAt) {
1864
- const w = c.publishedAt || c.createdAt || c.updatedAt;
1865
- g = w && typeof w == "object" && w.constructor === Date ? w : new Date(w);
1866
- } else
1867
- g = /* @__PURE__ */ new Date();
1868
- const f = Vt(c), y = Kt(c), p = {
1869
- ...c,
1870
- // Preserve all dynamic properties first
1871
- // Map to standard feed fields
1872
- id: l,
1873
- title: c.title || c.Title || "Untitled",
1874
- link: h,
1875
- description: f,
1876
- content: y,
1877
- pubDate: g,
1878
- date: g,
1879
- // Map guid - use full URL when available for proper permalink
1880
- guid: c.guid || c.Guid || c.link || c.Link || h
1881
- };
1882
- if (typeof p.html == "string" && p.Html === void 0 && (p.Html = p.html), typeof p.Html == "string" && p.html === void 0 && (p.html = p.Html), typeof p.body == "string" && p.Body === void 0 && (p.Body = p.body), typeof p.Body == "string" && p.body === void 0 && (p.body = p.Body), c._imageMetadata && c._hasImage) {
1883
- const w = c._imageMetadata;
1884
- p._imageMetadata = w, p._hasImage = !0;
1885
- }
1886
- return Object.keys(p).forEach((w) => {
1887
- const u = p[w];
1888
- if (typeof u == "string" && /date|time|published|created|updated/i.test(w) && w !== "pubDate" && w !== "date") {
1889
- const m = new Date(u);
1890
- isNaN(m.getTime()) || (p[w] = m);
1891
- }
1892
- }), p;
1893
- });
1894
- }
1895
- const Ge = (t, e, n, s, o, i, r, a) => {
1896
- const c = U(e), l = `${T.siteUrl}/${c}/${n}`, d = s ? `${l}?v=${s}` : l, h = `${T.title} - ${sn(c)}`, g = /* @__PURE__ */ new Date(), f = G(), y = [];
1897
- if (o) {
1898
- const w = o.baseUrl.replace(/\?.*$/, ""), u = w.includes("?") ? "&" : "?";
1899
- o.hasNext && y.push({ rel: "next", href: `${w}${u}page=${o.page + 1}` }), o.page > 1 && (y.push({ rel: "previous", href: `${w}${u}page=${o.page - 1}` }), y.push({ rel: "first", href: `${w}${u}page=1` }));
1900
- }
1901
- if (i?.length)
1902
- for (const w of i)
1903
- y.push({ rel: w.rel, href: w.href });
1904
- const p = on(t, {
1905
- schemaName: e,
1906
- siteUrl: T.siteUrl,
1907
- itemUrlBase: f.itemUrlBase,
1908
- itemUrlPath: f.itemUrlPath,
1909
- richTextDataUriImages: a?.richTextDataUriImages ?? f.richTextDataUriImages
1910
- });
1911
- switch (n) {
1912
- case "atom": {
1913
- const w = [
1914
- { href: d, rel: "self" },
1915
- { href: T.siteUrl }
1916
- ];
1917
- for (const m of y)
1918
- w.push({
1919
- href: m.href,
1920
- rel: m.rel,
1921
- type: m.type
1922
- });
1923
- const u = {
1924
- id: d,
1925
- title: h,
1926
- updated: g,
1927
- links: w,
1928
- subtitle: T.description,
1929
- rights: T.copyright,
1930
- author: T.author ? {
1931
- name: T.author.name,
1932
- email: T.author.email,
1933
- uri: T.author.link
1934
- } : void 0,
1935
- entries: p.map((m) => {
1936
- const C = {
1937
- id: m.id || m.link,
1938
- title: m.title || "Untitled",
1939
- updated: m.date || m.pubDate || g,
1940
- links: m.link ? [{ href: m.link }] : [],
1941
- ...m
1942
- // Preserve all dynamic properties
1943
- };
1944
- if (m.content && (C.content = m.content), m.description && (C.summary = m.description), m._imageMetadata && m._hasImage) {
1945
- const S = m._imageMetadata;
1946
- if (C.links || (C.links = []), C.links.push({
1947
- href: S.url,
1948
- rel: "enclosure",
1949
- type: S.mimeType || "image/jpeg",
1950
- length: S.size
1951
- }), S.url && C.content && !C.content.includes(S.url)) {
1952
- const D = `<img src="${S.url}" alt="${m.title || ""}"${S.width ? ` width="${S.width}"` : ""}${S.height ? ` height="${S.height}"` : ""} />`;
1953
- C.content = typeof C.content == "string" ? `${D}
1954
- ${C.content}` : { type: "html", value: `${D}
1955
- ${C.content.value || C.content}` };
1956
- }
1957
- }
1958
- return C;
1959
- })
1960
- };
1961
- return Promise.resolve(st(u));
1962
- }
1963
- case "json": {
1964
- const w = o?.hasNext ? `${o.baseUrl.replace(/\?.*$/, "")}?page=${o.page + 1}` : void 0, u = {
1965
- title: h,
1966
- home_page_url: T.siteUrl,
1967
- feed_url: d,
1968
- ...w && { next_url: w },
1969
- description: T.description,
1970
- author: T.author ? {
1971
- name: T.author.name,
1972
- url: T.author.link
1973
- } : void 0,
1974
- items: p.map((C) => {
1975
- const S = {
1976
- id: C.id || C.link,
1977
- ...C
1978
- // Preserve all dynamic properties
1979
- };
1980
- if (C.title && (S.title = C.title), C.link && (S.url = C.link), C.content && (S.content_html = C.content), C.description && (S.summary = C.description), (C.date || C.pubDate) && (S.date_published = C.date || C.pubDate), C._imageMetadata && C._hasImage) {
1981
- const D = C._imageMetadata;
1982
- if (S.image = D.url, S.attachments || (S.attachments = []), S.attachments.push({
1983
- url: D.url,
1984
- mime_type: D.mimeType || "image/jpeg",
1985
- size_in_bytes: D.size,
1986
- title: C.title || "Image"
1987
- }), D.url && S.content_html && !S.content_html.includes(D.url)) {
1988
- const k = `<img src="${D.url}" alt="${C.title || ""}"${D.width ? ` width="${D.width}"` : ""}${D.height ? ` height="${D.height}"` : ""} />`;
1989
- S.content_html = `${k}
1990
- ${S.content_html}`;
1991
- }
1992
- }
1993
- return S;
1994
- })
1995
- }, m = ot(u);
1996
- return Promise.resolve(typeof m == "string" ? m : JSON.stringify(m));
1997
- }
1998
- case "rss":
1999
- default: {
2000
- const w = {
2001
- title: h,
2002
- link: T.siteUrl,
2003
- description: T.description,
2004
- links: y.length ? y.map((u) => ({ rel: u.rel, href: u.href, type: u.type })) : void 0,
2005
- isArchive: r ?? !1,
2006
- language: T.language,
2007
- copyright: T.copyright,
2008
- webMaster: T.author?.email,
2009
- pubDate: g,
2010
- lastBuildDate: g,
2011
- items: p.map((u) => {
2012
- const m = {
2013
- ...u
2014
- // Preserve all dynamic properties
2015
- };
2016
- u.title && (m.title = u.title), u.link && (m.link = u.link), u.description && (m.description = u.description), (u.date || u.pubDate) && (m.pubDate = u.date || u.pubDate), u.guid ? m.guid = {
2017
- value: u.guid,
2018
- isPermaLink: typeof u.guid == "string" && (u.guid.startsWith("http://") || u.guid.startsWith("https://"))
2019
- } : u.id && (m.guid = {
2020
- value: u.id,
2021
- isPermaLink: typeof u.id == "string" && (u.id.startsWith("http://") || u.id.startsWith("https://"))
2022
- });
2023
- const C = en(u);
2024
- if (C && tn(
2025
- m,
2026
- u,
2027
- C,
2028
- e,
2029
- T.author,
2030
- T.copyright
2031
- ), typeof u.content == "string" && u.content.trim() !== "" && m["content:encoded"] === void 0 && (m["content:encoded"] = u.content), m.dc = {}, (u.date || u.pubDate) && (m.dc.date = u.date || u.pubDate), u.timeCreated) {
2032
- const S = new Date(u.timeCreated * 1e3);
2033
- m.dc.dates || (m.dc.dates = []), m.dc.dates.push(S);
2034
- }
2035
- return (u.seedUid || u.SeedUid) && (m.dc.identifier || (m.dc.identifier = []), m.dc.identifier.push(u.seedUid || u.SeedUid)), (u.storageTransactionId || u.storage_transaction_id) && (m.dc.identifier || (m.dc.identifier = []), m.dc.identifier.push(u.storageTransactionId || u.storage_transaction_id)), (u.import_url || u.importUrl) && (m.dc.source = u.import_url || u.importUrl), (u.seedUid || u.SeedUid) && (m.seedUid = u.seedUid || u.SeedUid), (u.storageTransactionId || u.storage_transaction_id) && (m.storageTransactionId = u.storageTransactionId || u.storage_transaction_id), u.timeCreated && (m.timeCreated = u.timeCreated), m;
2036
- })
2037
- };
2038
- return Promise.resolve(Nt(w));
2039
- }
2040
- }
1172
+ //#endregion
1173
+ //#region src/cache/config.ts
1174
+ function J() {
1175
+ let e = parseInt(process.env.CACHE_TTL || "3600", 10), n = process.env.CACHE_DIR || "./cache", r = process.env.CACHE_ENABLED === "false" || process.env.CACHE_ENABLED === "0" || process.env.CACHE_ENABLED === "no" || process.env.CACHE_ENABLED === "off", i = process.env.CACHE_ENABLED === "true" || process.env.CACHE_ENABLED === "1" || process.env.CACHE_ENABLED === "yes", a = process.env.NODE_ENV === "development", o;
1176
+ o = r ? !1 : i ? !0 : !a;
1177
+ let s = process.env.CACHE_BACKGROUND_REFRESH === "true", c = parseInt(process.env.CACHE_REFRESH_INTERVAL || "300", 10);
1178
+ o || console.log(`⚠️ Cache is DISABLED (${r ? "CACHE_ENABLED=false" : a ? "NODE_ENV=development" : "CACHE_ENABLED=false"})`);
1179
+ let l = {
1180
+ enabled: process.env.IMAGE_METADATA_ENABLED !== "false",
1181
+ ttl: parseInt(process.env.IMAGE_METADATA_TTL || "604800", 10),
1182
+ gateways: process.env.IMAGE_METADATA_GATEWAYS ? process.env.IMAGE_METADATA_GATEWAYS.split(",").map((e) => e.trim()) : [...t],
1183
+ timeout: parseInt(process.env.IMAGE_METADATA_TIMEOUT || "5000", 10)
1184
+ }, u = parseInt(process.env.CACHE_PAGE_TTL || "300", 10), d = parseInt(process.env.CACHE_ARCHIVE_TTL || "86400", 10);
1185
+ return {
1186
+ ttl: e,
1187
+ cacheDir: n,
1188
+ enabled: o,
1189
+ backgroundRefresh: s,
1190
+ refreshInterval: c,
1191
+ imageMetadata: l,
1192
+ pageTtl: u,
1193
+ archiveTtl: d
1194
+ };
1195
+ }
1196
+ //#endregion
1197
+ //#region src/services/arweaveImageService.ts
1198
+ var ft = class {
1199
+ config;
1200
+ constructor(e) {
1201
+ this.config = e;
1202
+ }
1203
+ async detectImage(e) {
1204
+ await o().catch(() => {});
1205
+ let n = this.config.gateways || [...t];
1206
+ for (let t of n) try {
1207
+ let n = `https://${t}/${e}`, r = await this.getImageMetadata(n);
1208
+ if (r.isImage) return r;
1209
+ } catch (n) {
1210
+ console.warn(`Failed to fetch from gateway ${t} for transaction ${e}:`, n);
1211
+ continue;
1212
+ }
1213
+ return {
1214
+ isImage: !1,
1215
+ url: `https://${n[0]}/${e}`
1216
+ };
1217
+ }
1218
+ async getImageMetadata(e) {
1219
+ try {
1220
+ let t = await this.fetchWithTimeout(e, { method: "HEAD" });
1221
+ if (!t.ok) return {
1222
+ isImage: !1,
1223
+ url: e
1224
+ };
1225
+ let n = t.headers.get("content-type") || "", r = t.headers.get("content-length");
1226
+ if (!this.isImageContentType(n)) return {
1227
+ isImage: !1,
1228
+ url: e,
1229
+ mimeType: n || void 0,
1230
+ size: r ? parseInt(r, 10) : void 0
1231
+ };
1232
+ let i = await this.fetchWithTimeout(e, { headers: { Range: "bytes=0-8192" } });
1233
+ if (!i.ok) return await this.getImageMetadataFromFullRequest(e, n, r);
1234
+ let a = Buffer.from(await i.arrayBuffer()), o = this.extractImageDimensions(a, n), s = this.getImageFormat(n, a);
1235
+ return {
1236
+ isImage: !0,
1237
+ url: e,
1238
+ mimeType: n,
1239
+ width: o.width,
1240
+ height: o.height,
1241
+ size: r ? parseInt(r, 10) : void 0,
1242
+ format: s
1243
+ };
1244
+ } catch (t) {
1245
+ return console.warn(`Error fetching image metadata from ${e}:`, t), {
1246
+ isImage: !1,
1247
+ url: e
1248
+ };
1249
+ }
1250
+ }
1251
+ async getImageMetadataFromFullRequest(e, t, n) {
1252
+ try {
1253
+ let n = await this.fetchWithTimeout(e);
1254
+ if (!n.ok) return {
1255
+ isImage: !1,
1256
+ url: e
1257
+ };
1258
+ let r = Buffer.from(await n.arrayBuffer()), i = this.extractImageDimensions(r, t), a = this.getImageFormat(t, r);
1259
+ return {
1260
+ isImage: !0,
1261
+ url: e,
1262
+ mimeType: t,
1263
+ width: i.width,
1264
+ height: i.height,
1265
+ size: r.length,
1266
+ format: a
1267
+ };
1268
+ } catch (t) {
1269
+ return console.warn(`Error in full request for ${e}:`, t), {
1270
+ isImage: !1,
1271
+ url: e
1272
+ };
1273
+ }
1274
+ }
1275
+ isImageContentType(e) {
1276
+ return e ? (e.toLowerCase().split(";")[0] ?? "").trim().startsWith("image/") : !1;
1277
+ }
1278
+ extractImageDimensions(e, t) {
1279
+ try {
1280
+ let t = ae(e);
1281
+ if (t.width && t.height) return {
1282
+ width: t.width,
1283
+ height: t.height
1284
+ };
1285
+ } catch (e) {
1286
+ console.warn("Failed to extract dimensions:", e);
1287
+ }
1288
+ return {
1289
+ width: 0,
1290
+ height: 0
1291
+ };
1292
+ }
1293
+ getImageFormat(e, t) {
1294
+ if (e) {
1295
+ let t = e.toLowerCase().match(/image\/([^;]+)/);
1296
+ if (t && t[1]) {
1297
+ let e = t[1].toLowerCase();
1298
+ return e === "jpeg" ? "jpeg" : e === "png" ? "png" : e === "gif" ? "gif" : e === "webp" ? "webp" : e === "svg+xml" ? "svg" : e;
1299
+ }
1300
+ }
1301
+ try {
1302
+ let e = ae(t);
1303
+ if (e.type) return e.type.toLowerCase();
1304
+ } catch {}
1305
+ }
1306
+ async fetchWithTimeout(e, t = {}) {
1307
+ let n = new AbortController(), r = setTimeout(() => n.abort(), this.config.timeout);
1308
+ try {
1309
+ let i = await fetch(e, {
1310
+ ...t,
1311
+ signal: n.signal
1312
+ });
1313
+ return clearTimeout(r), i;
1314
+ } catch (e) {
1315
+ throw clearTimeout(r), e instanceof Error && e.name === "AbortError" ? Error(`Request timeout after ${this.config.timeout}ms`) : e;
1316
+ }
1317
+ }
2041
1318
  };
2042
- function Xe(t) {
2043
- switch (t) {
2044
- case "atom":
2045
- return "application/atom+xml; charset=utf-8";
2046
- case "json":
2047
- return "application/feed+json; charset=utf-8";
2048
- case "rss":
2049
- default:
2050
- return "application/rss+xml; charset=utf-8";
2051
- }
2052
- }
2053
- function Je(t) {
2054
- const e = t.toLowerCase();
2055
- return ["rss", "atom", "json"].includes(e) ? e : null;
2056
- }
2057
- function sn(t) {
2058
- return t.charAt(0).toUpperCase() + t.slice(1);
2059
- }
2060
- async function Sn(t, e, n, s, o) {
2061
- const i = Je(e);
2062
- if (!i)
2063
- return new Response(
2064
- JSON.stringify({ error: `Invalid feed format: ${e}` }),
2065
- {
2066
- status: 400,
2067
- headers: { "Content-Type": "application/json" }
2068
- }
2069
- );
2070
- const r = U.singular(t.toLowerCase()), a = U(r), c = G(), l = Math.max(1, o ?? 1), d = c.pageSize, h = (l - 1) * d, g = l > 1 ? { page: l } : void 0;
2071
- console.log(`Schema name: ${r}`), console.log(`Collection name: ${a}`);
2072
- const f = He(), y = fe();
2073
- try {
2074
- if (y.enabled) {
2075
- const A = await f.getFeedContent(r, i, g);
2076
- if (A)
2077
- return n && je(n, A.etag) ? (console.log(`Cache hit with ETag match for ${r}:${i} - returning 304`), new Response(null, {
2078
- status: 304,
2079
- headers: {
2080
- ETag: A.etag,
2081
- "Last-Modified": new Date(A.lastModified * 1e3).toUTCString(),
2082
- "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate"
2083
- }
2084
- })) : (console.log(`Cache hit for ${r}:${i}`), new Response(A.content, {
2085
- status: 200,
2086
- headers: {
2087
- "Content-Type": A.contentType,
2088
- ETag: A.etag,
2089
- "Last-Modified": new Date(A.lastModified * 1e3).toUTCString(),
2090
- "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
2091
- "X-Feed-Schema": r,
2092
- "X-Feed-Format": i,
2093
- "X-Cache": "HIT"
2094
- }
2095
- }));
2096
- }
2097
- console.log(`Cache miss for ${r}:${i} - fetching items`);
2098
- const p = async () => {
2099
- const A = await ne(r, { limit: d, skip: h });
2100
- if (y.imageMetadata?.enabled) {
2101
- const _ = new Ae({
2102
- gateways: y.imageMetadata.gateways,
2103
- timeout: y.imageMetadata.timeout
2104
- });
2105
- return Ee(A, _, f);
2106
- }
2107
- return A;
2108
- }, w = y.enabled && l === 1 ? await f.withRefreshLock(r, async () => {
2109
- const A = await f.getFeedData(r);
2110
- let _;
2111
- if (A) {
2112
- console.log(`Incremental fetch: last processed timestamp: ${A.lastProcessedTimestamp}`);
2113
- const v = await ne(r, { limit: d, skip: 0 }), z = f.filterNewItems(v, A.lastProcessedTimestamp);
2114
- z.length > 0 ? (console.log(`Found ${z.length} new items, merging with ${A.items.length} cached items`), _ = f.mergeItems(A.items, z).slice(0, d)) : _ = A.items;
2115
- } else {
2116
- console.log("Cold cache - fetching page 1");
2117
- const v = await rn();
2118
- v && console.log(`Client initialized: ${v.isInitialized()}`), _ = await ne(r, { limit: d, skip: 0 }), console.log(`Found ${_.length} feed items for schema ${r}`);
2119
- }
2120
- if (y.imageMetadata?.enabled) {
2121
- const v = new Ae({
2122
- gateways: y.imageMetadata.gateways,
2123
- timeout: y.imageMetadata.timeout
2124
- }), z = await Ee(_, v, f);
2125
- return await f.setFeedData(r, _), z;
2126
- }
2127
- return await f.setFeedData(r, _), _;
2128
- }) : await p(), u = `${T.feedUrl}/${a}/${i}`, m = w.length === d, C = [];
2129
- if (l === 1) {
2130
- const A = /* @__PURE__ */ new Date(), _ = new Date(A.getFullYear(), A.getMonth() - 1, 1);
2131
- C.push({
2132
- rel: "prev-archive",
2133
- href: `${T.feedUrl}/${a}/archive/${_.getFullYear()}/${_.getMonth() + 1}/${i}`
2134
- });
2135
- }
2136
- const D = await Ge(
2137
- w,
2138
- r,
2139
- i,
2140
- s,
2141
- {
2142
- page: l,
2143
- pageSize: d,
2144
- hasNext: m,
2145
- baseUrl: u
2146
- },
2147
- C.length ? C : void 0,
2148
- !1
2149
- ), k = Xe(i);
2150
- if (y.enabled) {
2151
- await f.setFeedContent(r, i, D, k, g);
2152
- const A = await f.getFeedContent(r, i, g), _ = A?.etag || "", v = A?.lastModified || Math.floor(Date.now() / 1e3);
2153
- return new Response(D, {
2154
- status: 200,
2155
- headers: {
2156
- "Content-Type": k,
2157
- ETag: _,
2158
- "Last-Modified": new Date(v * 1e3).toUTCString(),
2159
- "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
2160
- "X-Feed-Schema": r,
2161
- "X-Feed-Format": i,
2162
- "X-Cache": "MISS"
2163
- }
2164
- });
2165
- }
2166
- return new Response(D, {
2167
- status: 200,
2168
- headers: {
2169
- "Content-Type": k,
2170
- "Cache-Control": "public, max-age=3600, s-maxage=3600",
2171
- "X-Feed-Schema": r,
2172
- "X-Feed-Format": i
2173
- }
2174
- });
2175
- } catch (p) {
2176
- if (console.error("Feed generation error:", p), y.enabled) {
2177
- const w = await f.getFeedContent(r, i, g);
2178
- if (w)
2179
- return console.log("Serving stale cache due to error"), new Response(w.content, {
2180
- status: 200,
2181
- headers: {
2182
- "Content-Type": w.contentType,
2183
- ETag: w.etag,
2184
- "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
2185
- "X-Feed-Schema": r,
2186
- "X-Feed-Format": i,
2187
- "X-Cache": "STALE",
2188
- Warning: '299 - "Cache is stale"'
2189
- }
2190
- });
2191
- }
2192
- return new Response(
2193
- JSON.stringify({
2194
- error: "Failed to generate feed",
2195
- message: p instanceof Error ? p.message : "Unknown error"
2196
- }),
2197
- {
2198
- status: 500,
2199
- headers: { "Content-Type": "application/json" }
2200
- }
2201
- );
2202
- }
2203
- }
2204
- async function Dn(t, e, n, s, o, i) {
2205
- if (e < 1970 || e > 2100)
2206
- return new Response(
2207
- JSON.stringify({ error: `Invalid year: ${e}` }),
2208
- { status: 400, headers: { "Content-Type": "application/json" } }
2209
- );
2210
- if (n < 1 || n > 12)
2211
- return new Response(
2212
- JSON.stringify({ error: `Invalid month: ${n}` }),
2213
- { status: 400, headers: { "Content-Type": "application/json" } }
2214
- );
2215
- const r = Je(s);
2216
- if (!r)
2217
- return new Response(
2218
- JSON.stringify({ error: `Invalid feed format: ${s}` }),
2219
- { status: 400, headers: { "Content-Type": "application/json" } }
2220
- );
2221
- const a = U.singular(t.toLowerCase()), c = U(a), l = { archive: { year: e, month: n } }, d = He(), h = fe();
2222
- try {
2223
- if (h.enabled) {
2224
- const D = await d.getFeedContent(a, r, l);
2225
- if (D)
2226
- return o && je(o, D.etag) ? new Response(null, {
2227
- status: 304,
2228
- headers: {
2229
- ETag: D.etag,
2230
- "Last-Modified": new Date(D.lastModified * 1e3).toUTCString(),
2231
- "Cache-Control": "public, max-age=86400, s-maxage=86400, must-revalidate"
2232
- }
2233
- }) : new Response(D.content, {
2234
- status: 200,
2235
- headers: {
2236
- "Content-Type": D.contentType,
2237
- ETag: D.etag,
2238
- "Last-Modified": new Date(D.lastModified * 1e3).toUTCString(),
2239
- "Cache-Control": "public, max-age=86400, s-maxage=86400, must-revalidate",
2240
- "X-Feed-Schema": a,
2241
- "X-Feed-Format": r,
2242
- "X-Cache": "HIT"
2243
- }
2244
- });
2245
- }
2246
- const g = await Et(a, e, n), f = `${T.feedUrl}/${c}/${r}`, y = `${T.feedUrl}/${c}/archive`, p = [
2247
- { rel: "prev-archive", href: `${y}/${n === 1 ? e - 1 : e}/${n === 1 ? 12 : n - 1}/${r}` },
2248
- { rel: "current", href: f }
2249
- ], w = n === 12 ? e + 1 : e, u = n === 12 ? 1 : n + 1, m = /* @__PURE__ */ new Date();
2250
- (w < m.getFullYear() || w === m.getFullYear() && u <= m.getMonth() + 1) && p.push({ rel: "next-archive", href: `${y}/${w}/${u}/${r}` });
2251
- const C = await Ge(
2252
- g,
2253
- a,
2254
- r,
2255
- i,
2256
- void 0,
2257
- p,
2258
- !0
2259
- ), S = Xe(r);
2260
- if (h.enabled) {
2261
- await d.setFeedContent(a, r, C, S, l);
2262
- const D = await d.getFeedContent(a, r, l), k = D?.etag || "", A = D?.lastModified || Math.floor(Date.now() / 1e3);
2263
- return new Response(C, {
2264
- status: 200,
2265
- headers: {
2266
- "Content-Type": S,
2267
- ETag: k,
2268
- "Last-Modified": new Date(A * 1e3).toUTCString(),
2269
- "Cache-Control": "public, max-age=86400, s-maxage=86400, must-revalidate",
2270
- "X-Feed-Schema": a,
2271
- "X-Feed-Format": r,
2272
- "X-Cache": "MISS"
2273
- }
2274
- });
2275
- }
2276
- return new Response(C, {
2277
- status: 200,
2278
- headers: {
2279
- "Content-Type": S,
2280
- "Cache-Control": "public, max-age=86400, s-maxage=86400",
2281
- "X-Feed-Schema": a,
2282
- "X-Feed-Format": r
2283
- }
2284
- });
2285
- } catch (g) {
2286
- return console.error("Archive feed generation error:", g), new Response(
2287
- JSON.stringify({
2288
- error: "Failed to generate archive feed",
2289
- message: g instanceof Error ? g.message : "Unknown error"
2290
- }),
2291
- { status: 500, headers: { "Content-Type": "application/json" } }
2292
- );
2293
- }
2294
- }
2295
- export {
2296
- dt as FEED_RICH_BODY_STORAGE_SCHEMAS,
2297
- En as classifyMediaRef,
2298
- Ge as createFeed,
2299
- lt as enrichImageSeedCloneForFeed,
2300
- qt as feedItemRichTextContainsDataUriImage,
2301
- Zt as filterItemsByRichTextDataUriImagePolicy,
2302
- rn as getClient,
2303
- _n as getFeedItemStringField,
2304
- ne as getFeedItemsBySchemaName,
2305
- Et as getFeedItemsBySchemaNameForMonth,
2306
- Dn as handleArchiveFeedRequest,
2307
- Sn as handleFeedRequest,
2308
- nn as initializeSeedClient,
2309
- B as isFeedRichBodyStorageSchema,
2310
- G as loadFeedConfig,
2311
- In as normalizeFeedItemFields,
2312
- yn as parseRssString,
2313
- Kt as pickFeedItemContent,
2314
- Vt as pickFeedItemDescription,
2315
- wn as resetCacheManager,
2316
- $n as resolveMediaRef,
2317
- Cn as teardownSeedClient
1319
+ //#endregion
1320
+ //#region src/pickFeedItemRichText.ts
1321
+ function pt(e, t) {
1322
+ for (let n of t) {
1323
+ let t = e[n];
1324
+ if (typeof t == "string" && t.trim() !== "") return t;
1325
+ }
1326
+ return "";
1327
+ }
1328
+ var mt = [
1329
+ "summary",
1330
+ "Summary",
1331
+ "description",
1332
+ "Description",
1333
+ "text",
1334
+ "Text"
1335
+ ], ht = [
1336
+ "html",
1337
+ "Html",
1338
+ "body",
1339
+ "Body",
1340
+ "content",
1341
+ "Content"
1342
+ ], gt = [
1343
+ "summary",
1344
+ "Summary",
1345
+ "description",
1346
+ "Description",
1347
+ "text",
1348
+ "Text"
1349
+ ];
1350
+ function _t(e, t) {
1351
+ let n = pe(e.model) - pe(t.model);
1352
+ if (n !== 0) return n;
1353
+ let r = e.key.localeCompare(t.key);
1354
+ return r === 0 ? e.index - t.index : r;
1355
+ }
1356
+ function vt(e) {
1357
+ let t = E(e), n = D(e), r = null;
1358
+ if (t) for (let [n, i] of Object.entries(t)) {
1359
+ if (!T(i)) continue;
1360
+ let t = e[n];
1361
+ if (typeof t != "string" || t.trim() === "") continue;
1362
+ let a = {
1363
+ model: i,
1364
+ key: n,
1365
+ index: 0,
1366
+ value: t
1367
+ };
1368
+ (!r || _t(a, r) < 0) && (r = a);
1369
+ }
1370
+ if (n) for (let [t, i] of Object.entries(n)) {
1371
+ let n = e[t];
1372
+ if (!Array.isArray(n)) continue;
1373
+ let a = Math.min(i.length, n.length);
1374
+ for (let e = 0; e < a; e++) {
1375
+ let a = i[e];
1376
+ if (!T(a)) continue;
1377
+ let o = n[e];
1378
+ if (typeof o != "string" || o.trim() === "") continue;
1379
+ let s = {
1380
+ model: a,
1381
+ key: t,
1382
+ index: e,
1383
+ value: o
1384
+ };
1385
+ (!r || _t(s, r) < 0) && (r = s);
1386
+ }
1387
+ }
1388
+ return r?.value ?? "";
1389
+ }
1390
+ function yt(e) {
1391
+ return pt(e, mt);
1392
+ }
1393
+ function bt(e) {
1394
+ let t = vt(e);
1395
+ if (t !== "") return t;
1396
+ let n = pt(e, ht);
1397
+ return n === "" ? pt(e, gt) : n;
1398
+ }
1399
+ function Y(e) {
1400
+ return typeof e == "string" ? e.includes("data:image/") && e.includes(";base64,") : !1;
1401
+ }
1402
+ function xt(e) {
1403
+ let t = E(e);
1404
+ if (t) {
1405
+ for (let [n, r] of Object.entries(t)) if (T(r) && Y(e[n])) return !0;
1406
+ }
1407
+ let n = D(e);
1408
+ if (n) for (let [t, r] of Object.entries(n)) {
1409
+ let n = e[t];
1410
+ if (!Array.isArray(n)) continue;
1411
+ let i = Math.min(r.length, n.length);
1412
+ for (let e = 0; e < i; e++) if (T(r[e]) && Y(n[e])) return !0;
1413
+ }
1414
+ return !1;
1415
+ }
1416
+ function St(e) {
1417
+ if (xt(e)) return !0;
1418
+ for (let t of ht) if (Y(e[t])) return !0;
1419
+ for (let t of mt) if (Y(e[t])) return !0;
1420
+ return !1;
1421
+ }
1422
+ function Ct(e, t = "omit_items") {
1423
+ return t === "include_items" ? [...e] : e.filter((e) => !St(e));
1424
+ }
1425
+ //#endregion
1426
+ //#region src/index.ts
1427
+ function wt(e) {
1428
+ if (e != null) {
1429
+ if (typeof e == "string") {
1430
+ if (e.startsWith("http://") || e.startsWith("https://")) return e;
1431
+ try {
1432
+ return x(e);
1433
+ } catch {
1434
+ return;
1435
+ }
1436
+ }
1437
+ if (typeof e == "object" && !Array.isArray(e)) {
1438
+ let t = e, n = t.arweaveUrl;
1439
+ if (typeof n == "string" && n.trim()) return n.trim();
1440
+ let r = t.storageTransactionId ?? t.storage_transaction_id;
1441
+ if (r && typeof r == "string" && r.trim()) try {
1442
+ return x(r.trim());
1443
+ } catch {
1444
+ return;
1445
+ }
1446
+ }
1447
+ }
1448
+ }
1449
+ function Tt(e) {
1450
+ if (typeof e == "number" && Number.isFinite(e) && e > 0) return e;
1451
+ if (typeof e == "string") {
1452
+ let t = Number(e);
1453
+ if (Number.isFinite(t) && t > 0) return t;
1454
+ }
1455
+ }
1456
+ function Et(e) {
1457
+ if (Array.isArray(e)) {
1458
+ for (let t of e) {
1459
+ let e = Et(t);
1460
+ if (e) return e;
1461
+ }
1462
+ return;
1463
+ }
1464
+ let t = wt(e);
1465
+ if (t) {
1466
+ if (e && typeof e == "object" && !Array.isArray(e)) {
1467
+ let n = e;
1468
+ return {
1469
+ url: t,
1470
+ mimeType: typeof n.mimeType == "string" && n.mimeType || typeof n.type == "string" && n.type || typeof n.contentType == "string" && n.contentType || void 0,
1471
+ width: Tt(n.width),
1472
+ height: Tt(n.height),
1473
+ size: Tt(n.size ?? n.fileSize),
1474
+ format: typeof n.format == "string" ? n.format : void 0
1475
+ };
1476
+ }
1477
+ return { url: t };
1478
+ }
1479
+ }
1480
+ function Dt(e) {
1481
+ if (e._hasImage && e._imageMetadata && typeof e._imageMetadata == "object") {
1482
+ let t = e._imageMetadata;
1483
+ if (t.url) return {
1484
+ url: t.url,
1485
+ mimeType: t.mimeType,
1486
+ width: t.width,
1487
+ height: t.height,
1488
+ size: t.size,
1489
+ format: t.format
1490
+ };
1491
+ }
1492
+ for (let t of [
1493
+ "feature_image",
1494
+ "featureImage",
1495
+ "image",
1496
+ "images",
1497
+ "cover_image",
1498
+ "coverImage",
1499
+ "thumbnail",
1500
+ "thumbnail_image",
1501
+ "thumbnailImage"
1502
+ ]) {
1503
+ if (!(t in e)) continue;
1504
+ let n = Et(e[t]);
1505
+ if (n) return n;
1506
+ }
1507
+ }
1508
+ function Ot(e, t, n, r, i, a) {
1509
+ let o = n.mimeType || "image/jpeg";
1510
+ e.enclosures = [{
1511
+ url: n.url,
1512
+ type: o,
1513
+ ...n.size ? { length: n.size } : {}
1514
+ }];
1515
+ let s = {
1516
+ url: n.url,
1517
+ type: o,
1518
+ medium: "image"
1519
+ };
1520
+ n.width && (s.width = n.width), n.height && (s.height = n.height), n.size && (s.fileSize = n.size), n.format && (s.format = n.format), e["media:content"] = [s];
1521
+ let c = { url: n.url };
1522
+ n.width && (c.width = n.width), n.height && (c.height = n.height), e["media:thumbnail"] = [c], t.title && (e["media:title"] = t.title);
1523
+ let l = t.description || t.summary || t.title || "";
1524
+ if (l && (e["media:description"] = l), t.title) {
1525
+ let n = [];
1526
+ n.push(...String(t.title).toLowerCase().split(/\s+/).filter((e) => e.length > 3)), t.description && n.push(...String(t.description).toLowerCase().split(/\s+/).filter((e) => e.length > 3)), n.length > 0 && (e["media:keywords"] = [...new Set(n)].slice(0, 10).join(", "));
1527
+ }
1528
+ Array.isArray(t.authors) && t.authors.length > 0 ? e["media:credit"] = t.authors.map((e) => ({
1529
+ value: e.name || e.displayName || "Unknown",
1530
+ role: "author"
1531
+ })) : i && (e["media:credit"] = [{
1532
+ value: i.name,
1533
+ role: "author"
1534
+ }]), a && (e["media:copyright"] = a), r && (e["media:category"] = [{
1535
+ value: r,
1536
+ scheme: "http://www.schema.org/"
1537
+ }]), e["media:group"] = [{
1538
+ "media:content": [s],
1539
+ "media:thumbnail": [c],
1540
+ "media:title": t.title || "Untitled",
1541
+ "media:description": l
1542
+ }], n.url && typeof t.content == "string" && t.content.trim() !== "" && !t.content.includes(n.url) && (e["content:encoded"] = `${`<img src="${n.url}" alt="${t.title || ""}"${n.width ? ` width="${n.width}"` : ""}${n.height ? ` height="${n.height}"` : ""} />`}\n${t.content}`);
1543
+ }
1544
+ var X, Z = null, kt = null;
1545
+ function At() {
1546
+ return kt ||= new dt(J()), kt;
1547
+ }
1548
+ function jt() {
1549
+ kt = null;
1550
+ }
1551
+ var Mt = async () => {
1552
+ if (Z) return Z;
1553
+ if (!X) return Z = (async () => {
1554
+ try {
1555
+ console.log("Initializing Seed Protocol client..."), await a.init({
1556
+ config: {
1557
+ endpoints: {
1558
+ filePaths: "app-files",
1559
+ files: "/app-files"
1560
+ },
1561
+ arweaveDomain: n
1562
+ },
1563
+ addresses: []
1564
+ }), console.log("✅ Seed Protocol client initialized successfully"), X = a, Z = null;
1565
+ } catch (e) {
1566
+ throw console.error("❌ Failed to initialize Seed Protocol client:", e), Z = null, e;
1567
+ }
1568
+ })(), Z;
1569
+ }, Nt = async () => X || (Z ? (await Z, X) : (await Mt(), X)), Pt = async () => {
1570
+ try {
1571
+ console.log("Tearing down Seed Protocol client..."), typeof a.stop == "function" && (await a.stop(), console.log("✅ Seed Protocol client stopped")), typeof a.unload == "function" && (await a.unload(), console.log("✅ Seed Protocol client unloaded")), console.log("✅ Seed Protocol client teardown complete");
1572
+ } catch (e) {
1573
+ console.error("❌ Failed to teardown Seed Protocol client:", e);
1574
+ }
1575
+ }, Q = {
1576
+ title: "Seed Protocol",
1577
+ description: "Content published via Seed Protocol",
1578
+ siteUrl: "https://seedprotocol.io",
1579
+ feedUrl: "https://feed.seedprotocol.io",
1580
+ language: "en",
1581
+ copyright: ${(/* @__PURE__ */ new Date()).getFullYear()} All rights reserved`,
1582
+ author: {
1583
+ name: "Seed Protocol",
1584
+ email: "info@seedprotocol.io",
1585
+ link: "https://seedprotocol.io"
1586
+ }
1587
+ };
1588
+ async function Ft(e, t, n) {
1589
+ let r = e.filter((e) => e.storageTransactionId || e.storage_transaction_id);
1590
+ if (r.length === 0) return e;
1591
+ console.log(`Enriching ${r.length} items with image metadata`);
1592
+ let i = r.map(async (e) => {
1593
+ let r = e.storageTransactionId || e.storage_transaction_id;
1594
+ if (!r) return e;
1595
+ try {
1596
+ let i = await n.getImageMetadata(r);
1597
+ return i || (console.log(`Detecting image for transaction ${r}`), i = await t.detectImage(r), await n.setImageMetadata(r, i)), i.isImage && (e._imageMetadata = i, e._hasImage = !0), e;
1598
+ } catch (t) {
1599
+ return console.warn(`Error enriching item with transaction ${r}:`, t), e;
1600
+ }
1601
+ }), a = await Promise.all(i), o = /* @__PURE__ */ new Map();
1602
+ return a.forEach((e) => {
1603
+ let t = e.id || e.seedUid || e.SeedUid || "";
1604
+ t && o.set(t, e);
1605
+ }), e.map((e) => {
1606
+ let t = e.id || e.seedUid || e.SeedUid || "";
1607
+ return o.get(t) || e;
1608
+ });
1609
+ }
1610
+ function It(e, t) {
1611
+ let { schemaName: n, siteUrl: r, itemUrlBase: i, itemUrlPath: a, richTextDataUriImages: o = "omit_items" } = t;
1612
+ return Ct(e, o).map((e) => {
1613
+ let t = e.id || e.seedUid || e.SeedUid || e.storageTransactionId || e.storage_transaction_id, o = i == null ? `${r}/${v(n)}/${t}` : `${i.replace(/\/$/, "")}/${(a ?? "attestation/view").replace(/^\//, "")}/${t}`, s = e.link || e.Link || e.import_url || e.importUrl || o, c;
1614
+ if (e.pubDate || e.PubDate) {
1615
+ let t = e.pubDate || e.PubDate;
1616
+ c = new Date(t);
1617
+ } else if (e.timeCreated) c = /* @__PURE__ */ new Date(e.timeCreated * 1e3);
1618
+ else if (e.publishedAt || e.createdAt || e.updatedAt) {
1619
+ let t = e.publishedAt || e.createdAt || e.updatedAt;
1620
+ c = t && typeof t == "object" && t.constructor === Date ? t : new Date(t);
1621
+ } else c = /* @__PURE__ */ new Date();
1622
+ let l = yt(e), u = bt(e), d = {
1623
+ ...e,
1624
+ id: t,
1625
+ title: e.title || e.Title || "Untitled",
1626
+ link: s,
1627
+ description: l,
1628
+ content: u,
1629
+ pubDate: c,
1630
+ date: c,
1631
+ guid: e.guid || e.Guid || e.link || e.Link || s
1632
+ };
1633
+ return typeof d.html == "string" && d.Html === void 0 && (d.Html = d.html), typeof d.Html == "string" && d.html === void 0 && (d.html = d.Html), typeof d.body == "string" && d.Body === void 0 && (d.Body = d.body), typeof d.Body == "string" && d.body === void 0 && (d.body = d.Body), e._imageMetadata && e._hasImage && (d._imageMetadata = e._imageMetadata, d._hasImage = !0), Object.keys(d).forEach((e) => {
1634
+ let t = d[e];
1635
+ if (typeof t == "string" && /date|time|published|created|updated/i.test(e) && e !== "pubDate" && e !== "date") {
1636
+ let n = new Date(t);
1637
+ isNaN(n.getTime()) || (d[e] = n);
1638
+ }
1639
+ }), d;
1640
+ });
1641
+ }
1642
+ var $ = (e, t, n, r, i, a, o, s) => {
1643
+ let c = v(t), l = `${Q.siteUrl}/${c}/${n}`, u = r ? `${l}?v=${r}` : l, d = `${Q.title} - ${zt(c)}`, f = /* @__PURE__ */ new Date(), p = S(), m = [];
1644
+ if (i) {
1645
+ let e = i.baseUrl.replace(/\?.*$/, ""), t = e.includes("?") ? "&" : "?";
1646
+ i.hasNext && m.push({
1647
+ rel: "next",
1648
+ href: `${e}${t}page=${i.page + 1}`
1649
+ }), i.page > 1 && (m.push({
1650
+ rel: "previous",
1651
+ href: `${e}${t}page=${i.page - 1}`
1652
+ }), m.push({
1653
+ rel: "first",
1654
+ href: `${e}${t}page=1`
1655
+ }));
1656
+ }
1657
+ if (a?.length) for (let e of a) m.push({
1658
+ rel: e.rel,
1659
+ href: e.href
1660
+ });
1661
+ let h = It(e, {
1662
+ schemaName: t,
1663
+ siteUrl: Q.siteUrl,
1664
+ itemUrlBase: p.itemUrlBase,
1665
+ itemUrlPath: p.itemUrlPath,
1666
+ richTextDataUriImages: s?.richTextDataUriImages ?? p.richTextDataUriImages
1667
+ });
1668
+ switch (n) {
1669
+ case "atom": {
1670
+ let e = [{
1671
+ href: u,
1672
+ rel: "self"
1673
+ }, { href: Q.siteUrl }];
1674
+ for (let t of m) e.push({
1675
+ href: t.href,
1676
+ rel: t.rel,
1677
+ type: t.type
1678
+ });
1679
+ let t = {
1680
+ id: u,
1681
+ title: d,
1682
+ updated: f,
1683
+ links: e,
1684
+ subtitle: Q.description,
1685
+ rights: Q.copyright,
1686
+ author: Q.author ? {
1687
+ name: Q.author.name,
1688
+ email: Q.author.email,
1689
+ uri: Q.author.link
1690
+ } : void 0,
1691
+ entries: h.map((e) => {
1692
+ let t = {
1693
+ id: e.id || e.link,
1694
+ title: e.title || "Untitled",
1695
+ updated: e.date || e.pubDate || f,
1696
+ links: e.link ? [{ href: e.link }] : [],
1697
+ ...e
1698
+ };
1699
+ if (e.content && (t.content = e.content), e.description && (t.summary = e.description), e._imageMetadata && e._hasImage) {
1700
+ let n = e._imageMetadata;
1701
+ if (t.links ||= [], t.links.push({
1702
+ href: n.url,
1703
+ rel: "enclosure",
1704
+ type: n.mimeType || "image/jpeg",
1705
+ length: n.size
1706
+ }), n.url && t.content && !t.content.includes(n.url)) {
1707
+ let r = `<img src="${n.url}" alt="${e.title || ""}"${n.width ? ` width="${n.width}"` : ""}${n.height ? ` height="${n.height}"` : ""} />`;
1708
+ t.content = typeof t.content == "string" ? `${r}\n${t.content}` : {
1709
+ type: "html",
1710
+ value: `${r}\n${t.content.value || t.content}`
1711
+ };
1712
+ }
1713
+ }
1714
+ return t;
1715
+ })
1716
+ };
1717
+ return Promise.resolve(te(t));
1718
+ }
1719
+ case "json": {
1720
+ let e = i?.hasNext ? `${i.baseUrl.replace(/\?.*$/, "")}?page=${i.page + 1}` : void 0, t = ne({
1721
+ title: d,
1722
+ home_page_url: Q.siteUrl,
1723
+ feed_url: u,
1724
+ ...e && { next_url: e },
1725
+ description: Q.description,
1726
+ author: Q.author ? {
1727
+ name: Q.author.name,
1728
+ url: Q.author.link
1729
+ } : void 0,
1730
+ items: h.map((e) => {
1731
+ let t = {
1732
+ id: e.id || e.link,
1733
+ ...e
1734
+ };
1735
+ if (e.title && (t.title = e.title), e.link && (t.url = e.link), e.content && (t.content_html = e.content), e.description && (t.summary = e.description), (e.date || e.pubDate) && (t.date_published = e.date || e.pubDate), e._imageMetadata && e._hasImage) {
1736
+ let n = e._imageMetadata;
1737
+ t.image = n.url, t.attachments ||= [], t.attachments.push({
1738
+ url: n.url,
1739
+ mime_type: n.mimeType || "image/jpeg",
1740
+ size_in_bytes: n.size,
1741
+ title: e.title || "Image"
1742
+ }), n.url && t.content_html && !t.content_html.includes(n.url) && (t.content_html = `${`<img src="${n.url}" alt="${e.title || ""}"${n.width ? ` width="${n.width}"` : ""}${n.height ? ` height="${n.height}"` : ""} />`}\n${t.content_html}`);
1743
+ }
1744
+ return t;
1745
+ })
1746
+ });
1747
+ return Promise.resolve(typeof t == "string" ? t : JSON.stringify(t));
1748
+ }
1749
+ default: {
1750
+ let e = {
1751
+ title: d,
1752
+ link: Q.siteUrl,
1753
+ description: Q.description,
1754
+ links: m.length ? m.map((e) => ({
1755
+ rel: e.rel,
1756
+ href: e.href,
1757
+ type: e.type
1758
+ })) : void 0,
1759
+ isArchive: o ?? !1,
1760
+ language: Q.language,
1761
+ copyright: Q.copyright,
1762
+ webMaster: Q.author?.email,
1763
+ pubDate: f,
1764
+ lastBuildDate: f,
1765
+ items: h.map((e) => {
1766
+ let n = { ...e };
1767
+ e.title && (n.title = e.title), e.link && (n.link = e.link), e.description && (n.description = e.description), (e.date || e.pubDate) && (n.pubDate = e.date || e.pubDate), e.guid ? n.guid = {
1768
+ value: e.guid,
1769
+ isPermaLink: typeof e.guid == "string" && (e.guid.startsWith("http://") || e.guid.startsWith("https://"))
1770
+ } : e.id && (n.guid = {
1771
+ value: e.id,
1772
+ isPermaLink: typeof e.id == "string" && (e.id.startsWith("http://") || e.id.startsWith("https://"))
1773
+ });
1774
+ let r = Dt(e);
1775
+ if (r && Ot(n, e, r, t, Q.author, Q.copyright), typeof e.content == "string" && e.content.trim() !== "" && n["content:encoded"] === void 0 && (n["content:encoded"] = e.content), n.dc = {}, (e.date || e.pubDate) && (n.dc.date = e.date || e.pubDate), e.timeCreated) {
1776
+ let t = /* @__PURE__ */ new Date(e.timeCreated * 1e3);
1777
+ n.dc.dates || (n.dc.dates = []), n.dc.dates.push(t);
1778
+ }
1779
+ return (e.seedUid || e.SeedUid) && (n.dc.identifier || (n.dc.identifier = []), n.dc.identifier.push(e.seedUid || e.SeedUid)), (e.storageTransactionId || e.storage_transaction_id) && (n.dc.identifier || (n.dc.identifier = []), n.dc.identifier.push(e.storageTransactionId || e.storage_transaction_id)), (e.import_url || e.importUrl) && (n.dc.source = e.import_url || e.importUrl), (e.seedUid || e.SeedUid) && (n.seedUid = e.seedUid || e.SeedUid), (e.storageTransactionId || e.storage_transaction_id) && (n.storageTransactionId = e.storageTransactionId || e.storage_transaction_id), e.timeCreated && (n.timeCreated = e.timeCreated), n;
1780
+ })
1781
+ };
1782
+ return Promise.resolve(nt(e));
1783
+ }
1784
+ }
2318
1785
  };
2319
- //# sourceMappingURL=index.js.map
1786
+ function Lt(e) {
1787
+ switch (e) {
1788
+ case "atom": return "application/atom+xml; charset=utf-8";
1789
+ case "json": return "application/feed+json; charset=utf-8";
1790
+ default: return "application/rss+xml; charset=utf-8";
1791
+ }
1792
+ }
1793
+ function Rt(e) {
1794
+ let t = e.toLowerCase();
1795
+ return [
1796
+ "rss",
1797
+ "atom",
1798
+ "json"
1799
+ ].includes(t) ? t : null;
1800
+ }
1801
+ function zt(e) {
1802
+ return e.charAt(0).toUpperCase() + e.slice(1);
1803
+ }
1804
+ async function Bt(e, t, n, r, i) {
1805
+ let a = Rt(t);
1806
+ if (!a) return new Response(JSON.stringify({ error: `Invalid feed format: ${t}` }), {
1807
+ status: 400,
1808
+ headers: { "Content-Type": "application/json" }
1809
+ });
1810
+ let o = v.singular(e.toLowerCase()), s = v(o), c = S(), l = Math.max(1, i ?? 1), u = c.pageSize, d = (l - 1) * u, f = l > 1 ? { page: l } : void 0;
1811
+ console.log(`Schema name: ${o}`), console.log(`Collection name: ${s}`);
1812
+ let p = At(), m = J();
1813
+ try {
1814
+ if (m.enabled) {
1815
+ let e = await p.getFeedContent(o, a, f);
1816
+ if (e) return n && ct(n, e.etag) ? (console.log(`Cache hit with ETag match for ${o}:${a} - returning 304`), new Response(null, {
1817
+ status: 304,
1818
+ headers: {
1819
+ ETag: e.etag,
1820
+ "Last-Modified": (/* @__PURE__ */ new Date(e.lastModified * 1e3)).toUTCString(),
1821
+ "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate"
1822
+ }
1823
+ })) : (console.log(`Cache hit for ${o}:${a}`), new Response(e.content, {
1824
+ status: 200,
1825
+ headers: {
1826
+ "Content-Type": e.contentType,
1827
+ ETag: e.etag,
1828
+ "Last-Modified": (/* @__PURE__ */ new Date(e.lastModified * 1e3)).toUTCString(),
1829
+ "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
1830
+ "X-Feed-Schema": o,
1831
+ "X-Feed-Format": a,
1832
+ "X-Cache": "HIT"
1833
+ }
1834
+ }));
1835
+ }
1836
+ console.log(`Cache miss for ${o}:${a} - fetching items`);
1837
+ let e = m.enabled && l === 1 ? await p.withRefreshLock(o, async () => {
1838
+ let e = await p.getFeedData(o), t;
1839
+ if (e) {
1840
+ console.log(`Incremental fetch: last processed timestamp: ${e.lastProcessedTimestamp}`);
1841
+ let n = await L(o, {
1842
+ limit: u,
1843
+ skip: 0
1844
+ }), r = p.filterNewItems(n, e.lastProcessedTimestamp);
1845
+ r.length > 0 ? (console.log(`Found ${r.length} new items, merging with ${e.items.length} cached items`), t = p.mergeItems(e.items, r).slice(0, u)) : t = e.items;
1846
+ } else {
1847
+ console.log("Cold cache - fetching page 1");
1848
+ let e = await Nt();
1849
+ e && console.log(`Client initialized: ${e.isInitialized()}`), t = await L(o, {
1850
+ limit: u,
1851
+ skip: 0
1852
+ }), console.log(`Found ${t.length} feed items for schema ${o}`);
1853
+ }
1854
+ if (m.imageMetadata?.enabled) {
1855
+ let e = new ft({
1856
+ gateways: m.imageMetadata.gateways,
1857
+ timeout: m.imageMetadata.timeout
1858
+ }), n = await Ft(t, e, p);
1859
+ return await p.setFeedData(o, t), n;
1860
+ }
1861
+ return await p.setFeedData(o, t), t;
1862
+ }) : await (async () => {
1863
+ let e = await L(o, {
1864
+ limit: u,
1865
+ skip: d
1866
+ });
1867
+ return m.imageMetadata?.enabled ? Ft(e, new ft({
1868
+ gateways: m.imageMetadata.gateways,
1869
+ timeout: m.imageMetadata.timeout
1870
+ }), p) : e;
1871
+ })(), t = `${Q.feedUrl}/${s}/${a}`, i = e.length === u, c = [];
1872
+ if (l === 1) {
1873
+ let e = /* @__PURE__ */ new Date(), t = new Date(e.getFullYear(), e.getMonth() - 1, 1);
1874
+ c.push({
1875
+ rel: "prev-archive",
1876
+ href: `${Q.feedUrl}/${s}/archive/${t.getFullYear()}/${t.getMonth() + 1}/${a}`
1877
+ });
1878
+ }
1879
+ let h = await $(e, o, a, r, {
1880
+ page: l,
1881
+ pageSize: u,
1882
+ hasNext: i,
1883
+ baseUrl: t
1884
+ }, c.length ? c : void 0, !1), g = Lt(a);
1885
+ if (m.enabled) {
1886
+ await p.setFeedContent(o, a, h, g, f);
1887
+ let e = await p.getFeedContent(o, a, f), t = e?.etag || "", n = e?.lastModified || Math.floor(Date.now() / 1e3);
1888
+ return new Response(h, {
1889
+ status: 200,
1890
+ headers: {
1891
+ "Content-Type": g,
1892
+ ETag: t,
1893
+ "Last-Modified": (/* @__PURE__ */ new Date(n * 1e3)).toUTCString(),
1894
+ "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
1895
+ "X-Feed-Schema": o,
1896
+ "X-Feed-Format": a,
1897
+ "X-Cache": "MISS"
1898
+ }
1899
+ });
1900
+ }
1901
+ return new Response(h, {
1902
+ status: 200,
1903
+ headers: {
1904
+ "Content-Type": g,
1905
+ "Cache-Control": "public, max-age=3600, s-maxage=3600",
1906
+ "X-Feed-Schema": o,
1907
+ "X-Feed-Format": a
1908
+ }
1909
+ });
1910
+ } catch (e) {
1911
+ if (console.error("Feed generation error:", e), m.enabled) {
1912
+ let e = await p.getFeedContent(o, a, f);
1913
+ if (e) return console.log("Serving stale cache due to error"), new Response(e.content, {
1914
+ status: 200,
1915
+ headers: {
1916
+ "Content-Type": e.contentType,
1917
+ ETag: e.etag,
1918
+ "Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
1919
+ "X-Feed-Schema": o,
1920
+ "X-Feed-Format": a,
1921
+ "X-Cache": "STALE",
1922
+ Warning: "299 - \"Cache is stale\""
1923
+ }
1924
+ });
1925
+ }
1926
+ return new Response(JSON.stringify({
1927
+ error: "Failed to generate feed",
1928
+ message: e instanceof Error ? e.message : "Unknown error"
1929
+ }), {
1930
+ status: 500,
1931
+ headers: { "Content-Type": "application/json" }
1932
+ });
1933
+ }
1934
+ }
1935
+ async function Vt(e, t, n, r, i, a) {
1936
+ if (t < 1970 || t > 2100) return new Response(JSON.stringify({ error: `Invalid year: ${t}` }), {
1937
+ status: 400,
1938
+ headers: { "Content-Type": "application/json" }
1939
+ });
1940
+ if (n < 1 || n > 12) return new Response(JSON.stringify({ error: `Invalid month: ${n}` }), {
1941
+ status: 400,
1942
+ headers: { "Content-Type": "application/json" }
1943
+ });
1944
+ let o = Rt(r);
1945
+ if (!o) return new Response(JSON.stringify({ error: `Invalid feed format: ${r}` }), {
1946
+ status: 400,
1947
+ headers: { "Content-Type": "application/json" }
1948
+ });
1949
+ let s = v.singular(e.toLowerCase()), c = v(s), l = { archive: {
1950
+ year: t,
1951
+ month: n
1952
+ } }, u = At(), d = J();
1953
+ try {
1954
+ if (d.enabled) {
1955
+ let e = await u.getFeedContent(s, o, l);
1956
+ if (e) return i && ct(i, e.etag) ? new Response(null, {
1957
+ status: 304,
1958
+ headers: {
1959
+ ETag: e.etag,
1960
+ "Last-Modified": (/* @__PURE__ */ new Date(e.lastModified * 1e3)).toUTCString(),
1961
+ "Cache-Control": "public, max-age=86400, s-maxage=86400, must-revalidate"
1962
+ }
1963
+ }) : new Response(e.content, {
1964
+ status: 200,
1965
+ headers: {
1966
+ "Content-Type": e.contentType,
1967
+ ETag: e.etag,
1968
+ "Last-Modified": (/* @__PURE__ */ new Date(e.lastModified * 1e3)).toUTCString(),
1969
+ "Cache-Control": "public, max-age=86400, s-maxage=86400, must-revalidate",
1970
+ "X-Feed-Schema": s,
1971
+ "X-Feed-Format": o,
1972
+ "X-Cache": "HIT"
1973
+ }
1974
+ });
1975
+ }
1976
+ let e = await Fe(s, t, n), r = `${Q.feedUrl}/${c}/${o}`, f = `${Q.feedUrl}/${c}/archive`, p = [{
1977
+ rel: "prev-archive",
1978
+ href: `${f}/${n === 1 ? t - 1 : t}/${n === 1 ? 12 : n - 1}/${o}`
1979
+ }, {
1980
+ rel: "current",
1981
+ href: r
1982
+ }], m = n === 12 ? t + 1 : t, h = n === 12 ? 1 : n + 1, g = /* @__PURE__ */ new Date();
1983
+ (m < g.getFullYear() || m === g.getFullYear() && h <= g.getMonth() + 1) && p.push({
1984
+ rel: "next-archive",
1985
+ href: `${f}/${m}/${h}/${o}`
1986
+ });
1987
+ let _ = await $(e, s, o, a, void 0, p, !0), v = Lt(o);
1988
+ if (d.enabled) {
1989
+ await u.setFeedContent(s, o, _, v, l);
1990
+ let e = await u.getFeedContent(s, o, l), t = e?.etag || "", n = e?.lastModified || Math.floor(Date.now() / 1e3);
1991
+ return new Response(_, {
1992
+ status: 200,
1993
+ headers: {
1994
+ "Content-Type": v,
1995
+ ETag: t,
1996
+ "Last-Modified": (/* @__PURE__ */ new Date(n * 1e3)).toUTCString(),
1997
+ "Cache-Control": "public, max-age=86400, s-maxage=86400, must-revalidate",
1998
+ "X-Feed-Schema": s,
1999
+ "X-Feed-Format": o,
2000
+ "X-Cache": "MISS"
2001
+ }
2002
+ });
2003
+ }
2004
+ return new Response(_, {
2005
+ status: 200,
2006
+ headers: {
2007
+ "Content-Type": v,
2008
+ "Cache-Control": "public, max-age=86400, s-maxage=86400",
2009
+ "X-Feed-Schema": s,
2010
+ "X-Feed-Format": o
2011
+ }
2012
+ });
2013
+ } catch (e) {
2014
+ return console.error("Archive feed generation error:", e), new Response(JSON.stringify({
2015
+ error: "Failed to generate archive feed",
2016
+ message: e instanceof Error ? e.message : "Unknown error"
2017
+ }), {
2018
+ status: 500,
2019
+ headers: { "Content-Type": "application/json" }
2020
+ });
2021
+ }
2022
+ }
2023
+ //#endregion
2024
+ export { ue as FEED_RICH_BODY_STORAGE_SCHEMAS, i as classifyMediaRef, $ as createFeed, le as enrichImageSeedCloneForFeed, St as feedItemRichTextContainsDataUriImage, Ct as filterItemsByRichTextDataUriImagePolicy, Nt as getClient, s as getFeedItemStringField, L as getFeedItemsBySchemaName, Fe as getFeedItemsBySchemaNameForMonth, Vt as handleArchiveFeedRequest, Bt as handleFeedRequest, Mt as initializeSeedClient, T as isFeedRichBodyStorageSchema, S as loadFeedConfig, f as normalizeFeedItemFields, Re as parseRssString, bt as pickFeedItemContent, yt as pickFeedItemDescription, jt as resetCacheManager, m as resolveMediaRef, Pt as teardownSeedClient };
2025
+
2026
+ //# sourceMappingURL=index.js.map