@seedprotocol/feed 0.4.7 → 0.4.9
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/README.md +9 -8
- package/dist/cache/config.d.ts +2 -1
- package/dist/cache/config.d.ts.map +1 -1
- package/dist/config.d.ts +4 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/getFeedItems.d.ts +2 -0
- package/dist/getFeedItems.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +815 -427
- package/dist/index.js.map +1 -1
- package/dist/rss/generateRssXml.d.ts +13 -0
- package/dist/rss/generateRssXml.d.ts.map +1 -0
- package/dist/services/arweaveImageService.d.ts.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,34 +1,441 @@
|
|
|
1
|
-
import { client as
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import S from "
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { EasClient as Q, getSeedsBySchemaName as ee, getItemVersionsFromEas as te, getItemPropertiesFromEas as ae, getArweaveUrlForTransaction as U, setSchemaUidForSchemaDefinition as ne, DEFAULT_ARWEAVE_GATEWAYS as X, client as T, DEFAULT_ARWEAVE_HOST as re } from "@seedprotocol/sdk";
|
|
2
|
+
import { gql as se } from "graphql-request";
|
|
3
|
+
import b from "pluralize";
|
|
4
|
+
import { generateJsonFeed as ie, generateAtomFeed as oe } from "feedsmith";
|
|
5
|
+
import { create as ce } from "xmlbuilder2";
|
|
6
|
+
import { createHash as le } from "crypto";
|
|
7
|
+
import { promises as y } from "fs";
|
|
8
|
+
import { join as S } from "path";
|
|
9
|
+
import N from "image-size";
|
|
10
|
+
function K() {
|
|
11
|
+
const a = process.env.FEED_ITEM_URL_BASE?.trim() || "https://optimism-sepolia.easscan.org", e = process.env.FEED_ITEM_URL_PATH?.trim() || "attestation/view", t = process.env.FEED_SITE_URL?.trim() || "https://seedprotocol.io";
|
|
12
|
+
return { itemUrlBase: a, itemUrlPath: e, siteUrl: t };
|
|
11
13
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const M = [
|
|
15
|
+
"0x0000000000000000000000000000000000000000000000000000000000000020"
|
|
16
|
+
], de = se`
|
|
17
|
+
query GetSeeds($where: AttestationWhereInput!, $take: Int) {
|
|
18
|
+
itemSeeds: attestations(where: $where, orderBy: [{ timeCreated: desc }], take: $take) {
|
|
19
|
+
id
|
|
20
|
+
decodedDataJson
|
|
21
|
+
attester
|
|
22
|
+
schema {
|
|
23
|
+
schemaNames {
|
|
24
|
+
name
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
refUID
|
|
28
|
+
revoked
|
|
29
|
+
schemaId
|
|
30
|
+
timeCreated
|
|
31
|
+
isOffchain
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`, L = (a) => a.replace(/_([a-z])/g, (e, t) => t.toUpperCase()), fe = (a) => {
|
|
35
|
+
const e = new Date(a * 1e3), t = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], r = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], i = t[e.getUTCDay()], n = r[e.getUTCMonth()], o = e.getUTCFullYear(), l = e.getUTCDate().toString().padStart(2, "0"), d = e.getUTCHours().toString().padStart(2, "0"), h = e.getUTCMinutes().toString().padStart(2, "0"), u = e.getUTCSeconds().toString().padStart(2, "0");
|
|
36
|
+
return `${i}, ${l} ${n} ${o} ${d}:${h}:${u} GMT`;
|
|
37
|
+
}, he = (a) => a === "image" ? "images" : a === "post" ? "posts" : a.toLowerCase() + "s", ge = (a) => {
|
|
38
|
+
const [e, t, r] = a.split("_");
|
|
39
|
+
if (!e || !t) return null;
|
|
40
|
+
const i = r === "ids";
|
|
41
|
+
return { propertyName: e.endsWith("s") ? e : e + "s", modelName: t, isList: i };
|
|
42
|
+
}, ue = (a, e, t, r) => {
|
|
43
|
+
const { itemUrlBase: i, itemUrlPath: n, siteUrl: o } = r;
|
|
44
|
+
!a.title && !a.Title ? (a.title = e, a.Title = e) : a.title && !a.Title ? a.Title = a.title : a.Title && !a.title && (a.title = a.Title);
|
|
45
|
+
const l = a.storage_transaction_id && typeof a.storage_transaction_id == "string" && a.storage_transaction_id.trim() !== "" && a.storage_transaction_id !== "undefined" && a.storage_transaction_id !== e ? a.storage_transaction_id.trim() : null, d = a.storageTransactionId && typeof a.storageTransactionId == "string" && a.storageTransactionId.trim() !== "" && a.storageTransactionId !== "undefined" && a.storageTransactionId !== e ? a.storageTransactionId.trim() : null, h = l || d, u = he(t), g = e && typeof e == "string" && e.trim() !== "" ? e : "unknown";
|
|
46
|
+
let s;
|
|
47
|
+
if (h && h !== e && h.length > 0)
|
|
48
|
+
try {
|
|
49
|
+
s = U(h);
|
|
50
|
+
} catch (p) {
|
|
51
|
+
console.error("[feed] [setFeedItemDefaults] Error generating Arweave URL:", p), i != null ? s = `${i.replace(/\/$/, "")}/${(n ?? "attestation/view").replace(/^\//, "")}/${g}` : s = `${o.replace(/\/$/, "")}/${u}/${g}`;
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
i != null ? s = `${i.replace(/\/$/, "")}/${(n ?? "attestation/view").replace(/^\//, "")}/${g}` : s = `${o.replace(/\/$/, "")}/${u}/${g}`;
|
|
55
|
+
const c = a.link || a.Link;
|
|
56
|
+
!c || c === "undefined" || typeof c == "string" && c.trim() === "" ? (a.link = s, a.Link = s) : ((!a.link || a.link === "undefined") && (a.link = c), (!a.Link || a.Link === "undefined") && (a.Link = c));
|
|
57
|
+
const f = a.guid || a.Guid;
|
|
58
|
+
if (!f || f === "undefined" || typeof f == "string" && f.trim() === "" ? (a.guid = a.link || s, a.Guid = a.guid) : ((!a.guid || a.guid === "undefined") && (a.guid = f), (!a.Guid || a.Guid === "undefined") && (a.Guid = f)), a.timeCreated && !a.pubDate && !a.PubDate) {
|
|
59
|
+
const p = fe(a.timeCreated);
|
|
60
|
+
a.pubDate = p, a.PubDate = p;
|
|
61
|
+
} else a.pubDate && !a.PubDate ? a.PubDate = a.pubDate : a.PubDate && !a.pubDate && (a.pubDate = a.PubDate);
|
|
62
|
+
!a.seedUid && !a.SeedUid ? (a.seedUid = e, a.SeedUid = e) : a.seedUid && !a.SeedUid ? a.SeedUid = a.seedUid : a.SeedUid && !a.seedUid && (a.seedUid = a.SeedUid), a.attester && !a.Attester ? a.Attester = a.attester : a.Attester && !a.attester && (a.attester = a.Attester);
|
|
63
|
+
}, B = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Set(), q = /* @__PURE__ */ new Map(), D = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map(), pe = /* @__PURE__ */ new Map(), me = async (a, e) => {
|
|
64
|
+
let t;
|
|
65
|
+
try {
|
|
66
|
+
t = JSON.parse(a.decodedDataJson)[0]?.value ?? {};
|
|
67
|
+
} catch (f) {
|
|
68
|
+
console.error("[feed] [processItemProperty] Error parsing metadata:", f);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
let r = t.name;
|
|
72
|
+
if (!r)
|
|
73
|
+
return;
|
|
74
|
+
const i = a.schemaId;
|
|
75
|
+
ne({
|
|
76
|
+
text: r,
|
|
77
|
+
schemaUid: i
|
|
78
|
+
});
|
|
79
|
+
let n = !1, o = !1;
|
|
80
|
+
const l = t.type, d = (l === "bytes32" || l === "bytes32[]") && r !== "storage_transaction_id" && r !== "storage_provider_transaction_id", h = !d && (r.endsWith("_id") || r.endsWith("_ids")) && r !== "storage_transaction_id" && r !== "storage_provider_transaction_id";
|
|
81
|
+
if (d || h)
|
|
82
|
+
if (n = !0, Array.isArray(t.value)) {
|
|
83
|
+
if (o = !0, h) {
|
|
84
|
+
const f = ge(r);
|
|
85
|
+
f && (r = f.propertyName);
|
|
86
|
+
}
|
|
87
|
+
t.value.forEach((f) => {
|
|
88
|
+
M.includes(f) || x.add(f);
|
|
89
|
+
});
|
|
90
|
+
} else M.includes(t.value) || x.add(t.value);
|
|
91
|
+
let u = t.value;
|
|
92
|
+
typeof u != "string" && (u = JSON.stringify(u)), n && !o && e.find((p) => p.id === t.value)?.schema?.schemaNames, n && o && e.filter(
|
|
93
|
+
(p) => Array.isArray(t.value) && t.value.includes(p.id)
|
|
94
|
+
).length > 0;
|
|
95
|
+
const g = q.get(a.refUID);
|
|
96
|
+
if (!g)
|
|
97
|
+
return;
|
|
98
|
+
const s = D.get(g) || {};
|
|
99
|
+
s[r] = u;
|
|
100
|
+
const c = L(r);
|
|
101
|
+
c !== r && (s[c] = u), D.set(g, s);
|
|
102
|
+
}, W = async (a) => {
|
|
103
|
+
const e = a.map((n) => n.id);
|
|
104
|
+
for (let n = 0; n < a.length; n++) {
|
|
105
|
+
const o = a[n];
|
|
106
|
+
if (!o) continue;
|
|
107
|
+
e.push(o.id);
|
|
108
|
+
const l = o.schema?.schemaNames?.[0]?.name ?? "unknown";
|
|
109
|
+
B.set(o.id, l), D.has(o.id) || D.set(o.id, {
|
|
110
|
+
seedUid: o.id,
|
|
111
|
+
timeCreated: o.timeCreated,
|
|
112
|
+
attester: o.attester
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const t = await te({ seedUids: e });
|
|
116
|
+
for (let n = 0; n < t.length; n++) {
|
|
117
|
+
const o = t[n], l = o.refUID;
|
|
118
|
+
q.set(o.id, l);
|
|
119
|
+
const d = P.get(l) || [];
|
|
120
|
+
P.set(l, [...d, o]);
|
|
121
|
+
}
|
|
122
|
+
const r = [];
|
|
123
|
+
for (const [n, o] of P.entries()) {
|
|
124
|
+
const d = [...o].sort((h, u) => u.timeCreated - h.timeCreated)[0];
|
|
125
|
+
d && (r.push(d.id), pe.set(n, d.id));
|
|
126
|
+
}
|
|
127
|
+
const i = await ae({ versionUids: r });
|
|
128
|
+
for (let n = 0; n < i.length; n++)
|
|
129
|
+
await me(i[n], a);
|
|
130
|
+
}, ye = /* @__PURE__ */ new Set([
|
|
131
|
+
"seedUid",
|
|
132
|
+
"SeedUid",
|
|
133
|
+
"timeCreated",
|
|
134
|
+
"attester",
|
|
135
|
+
"Attester",
|
|
136
|
+
"storage_transaction_id",
|
|
137
|
+
"storage_provider_transaction_id",
|
|
138
|
+
"storageTransactionId",
|
|
139
|
+
"storageProviderTransactionId"
|
|
140
|
+
]);
|
|
141
|
+
function we(a) {
|
|
142
|
+
const e = Array.from(D.entries()).filter(
|
|
143
|
+
([t]) => B.get(t) === a
|
|
144
|
+
);
|
|
145
|
+
for (const [, t] of e) {
|
|
146
|
+
const r = Object.keys(t).filter(
|
|
147
|
+
(i) => !i.startsWith("_") && !ye.has(i)
|
|
148
|
+
);
|
|
149
|
+
for (const i of r) {
|
|
150
|
+
const n = t[i];
|
|
151
|
+
if (Array.isArray(n)) {
|
|
152
|
+
const l = n;
|
|
153
|
+
if (!l.some(
|
|
154
|
+
(g) => typeof g == "string" && !M.includes(g) && D.has(g)
|
|
155
|
+
)) continue;
|
|
156
|
+
const h = [];
|
|
157
|
+
let u = !1;
|
|
158
|
+
for (const g of l) {
|
|
159
|
+
if (typeof g != "string" || M.includes(g)) {
|
|
160
|
+
h.push(String(g));
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const s = D.get(g), c = s?.storageTransactionId ?? s?.storage_transaction_id;
|
|
164
|
+
if (c && typeof c == "string" && c.trim())
|
|
165
|
+
try {
|
|
166
|
+
h.push(U(c)), u = !0;
|
|
167
|
+
} catch {
|
|
168
|
+
h.push(g);
|
|
169
|
+
}
|
|
170
|
+
else
|
|
171
|
+
h.push(g);
|
|
172
|
+
}
|
|
173
|
+
if (u) {
|
|
174
|
+
const g = i.endsWith("_ids") ? i.replace(/_ids$/, "") : i;
|
|
175
|
+
if (t[g] = h, g !== i) {
|
|
176
|
+
delete t[i];
|
|
177
|
+
const s = L(i);
|
|
178
|
+
s !== i && delete t[s];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} else if (typeof n == "string") {
|
|
182
|
+
if (M.includes(n) || !D.has(n)) continue;
|
|
183
|
+
const l = D.get(n), d = l?.storageTransactionId ?? l?.storage_transaction_id;
|
|
184
|
+
if (d && typeof d == "string" && d.trim())
|
|
185
|
+
try {
|
|
186
|
+
const h = i.endsWith("_id") ? i.replace(/_id$/, "") : i;
|
|
187
|
+
if (t[h] = U(d), h !== i) {
|
|
188
|
+
delete t[i];
|
|
189
|
+
const u = L(i);
|
|
190
|
+
u !== i && delete t[u];
|
|
191
|
+
}
|
|
192
|
+
} catch {
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
15
197
|
}
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
198
|
+
const k = async (a) => {
|
|
199
|
+
const e = K(), t = Q.getEasClient(), r = await ee(a);
|
|
200
|
+
await W(r);
|
|
201
|
+
const i = Array.from(x), { itemSeeds: n } = await t.request(de, {
|
|
202
|
+
where: {
|
|
203
|
+
id: {
|
|
204
|
+
in: i
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
await W(n ?? []), we(a);
|
|
209
|
+
const o = {
|
|
210
|
+
itemUrlBase: e.itemUrlBase,
|
|
211
|
+
itemUrlPath: e.itemUrlPath,
|
|
212
|
+
siteUrl: e.siteUrl
|
|
213
|
+
};
|
|
214
|
+
return Array.from(D.entries()).filter(([d]) => B.get(d) === a).map(([, d]) => {
|
|
215
|
+
const h = d.seedUid || d.SeedUid;
|
|
216
|
+
return ue(d, h, a, o), d;
|
|
217
|
+
});
|
|
218
|
+
}, R = "http://purl.org/dc/elements/1.1/", j = "http://purl.org/rss/1.0/modules/content/", $ = "http://search.yahoo.com/mrss/", Ce = /* @__PURE__ */ new Set(["Title", "Link", "Guid", "PubDate", "SeedUid"]);
|
|
219
|
+
function De(a, e) {
|
|
220
|
+
return Ce.has(a) ? a.charAt(0).toLowerCase() + a.slice(1) in e : !1;
|
|
221
|
+
}
|
|
222
|
+
const z = [
|
|
223
|
+
"title",
|
|
224
|
+
"link",
|
|
225
|
+
"description",
|
|
226
|
+
"guid",
|
|
227
|
+
"pubDate",
|
|
228
|
+
"authors",
|
|
229
|
+
"categories",
|
|
230
|
+
"comments",
|
|
231
|
+
"enclosures",
|
|
232
|
+
"source",
|
|
233
|
+
"dc",
|
|
234
|
+
"content:encoded",
|
|
235
|
+
"media:content",
|
|
236
|
+
"media:thumbnail",
|
|
237
|
+
"media:title",
|
|
238
|
+
"media:description",
|
|
239
|
+
"media:keywords",
|
|
240
|
+
"media:credit",
|
|
241
|
+
"media:copyright",
|
|
242
|
+
"media:category",
|
|
243
|
+
"media:group"
|
|
244
|
+
];
|
|
245
|
+
function O(a) {
|
|
246
|
+
if (a instanceof Date)
|
|
247
|
+
return a.toUTCString();
|
|
248
|
+
if (typeof a == "string") {
|
|
249
|
+
const e = new Date(a);
|
|
250
|
+
return Number.isNaN(e.getTime()) ? a : e.toUTCString();
|
|
251
|
+
}
|
|
252
|
+
return String(a);
|
|
19
253
|
}
|
|
20
|
-
function
|
|
254
|
+
function Ee(a) {
|
|
255
|
+
return /[<>&]|]]>/.test(a);
|
|
256
|
+
}
|
|
257
|
+
function w(a, e) {
|
|
258
|
+
const t = String(e);
|
|
259
|
+
if (t !== "")
|
|
260
|
+
if (Ee(t))
|
|
261
|
+
if (t.includes("]]>")) {
|
|
262
|
+
const r = t.split("]]>");
|
|
263
|
+
for (let i = 0; i < r.length; i++)
|
|
264
|
+
a.dat(r[i]), i < r.length - 1 && a.txt("]]>");
|
|
265
|
+
} else
|
|
266
|
+
a.dat(t);
|
|
267
|
+
else
|
|
268
|
+
a.txt(t);
|
|
269
|
+
}
|
|
270
|
+
function H(a, e, t, r) {
|
|
271
|
+
if (t == null || e.startsWith("_") || e === "items") return;
|
|
272
|
+
if (e === "guid") {
|
|
273
|
+
const n = t, o = n?.value ?? String(t);
|
|
274
|
+
if (!o) return;
|
|
275
|
+
const l = {};
|
|
276
|
+
typeof n?.isPermaLink == "boolean" && (l.isPermaLink = n.isPermaLink ? "true" : "false");
|
|
277
|
+
const d = a.ele("guid", l);
|
|
278
|
+
w(d, o);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (e === "source" && t !== null && typeof t == "object") {
|
|
282
|
+
const n = t, o = n.title ?? String(t);
|
|
283
|
+
if (!o) return;
|
|
284
|
+
const l = n.url ? { url: n.url } : {};
|
|
285
|
+
a.ele("source", l).txt(o);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (e === "enclosures" && Array.isArray(t)) {
|
|
289
|
+
for (const n of t)
|
|
290
|
+
if (n && typeof n == "object" && "url" in n) {
|
|
291
|
+
const o = {
|
|
292
|
+
url: String(n.url),
|
|
293
|
+
type: String(n.type ?? "application/octet-stream")
|
|
294
|
+
};
|
|
295
|
+
n.length != null && (o.length = String(n.length)), a.ele("enclosure", o);
|
|
296
|
+
}
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (e === "dc" && t !== null && typeof t == "object") {
|
|
300
|
+
const n = t;
|
|
301
|
+
for (const [o, l] of Object.entries(n))
|
|
302
|
+
if (l != null)
|
|
303
|
+
if (Array.isArray(l)) {
|
|
304
|
+
for (const d of l)
|
|
305
|
+
if (d != null) {
|
|
306
|
+
const h = a.ele(R, o);
|
|
307
|
+
d instanceof Date ? h.txt(d.toISOString()) : w(h, String(d));
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
const d = a.ele(R, o);
|
|
311
|
+
l instanceof Date ? d.txt(l.toISOString()) : w(d, String(l));
|
|
312
|
+
}
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (e === "content:encoded") {
|
|
316
|
+
const n = a.ele(j, "encoded");
|
|
317
|
+
w(n, String(t));
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (e === "content" && typeof t == "string" && !("content:encoded" in r)) {
|
|
321
|
+
const n = a.ele(j, "encoded");
|
|
322
|
+
w(n, String(t));
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (e === "content") return;
|
|
326
|
+
if (e.startsWith("media:") && Array.isArray(t)) {
|
|
327
|
+
const n = e.slice(6);
|
|
328
|
+
for (const o of t) {
|
|
329
|
+
if (o === null || typeof o != "object") continue;
|
|
330
|
+
const l = {};
|
|
331
|
+
let d = null;
|
|
332
|
+
for (const [u, g] of Object.entries(o))
|
|
333
|
+
g != null && (u === "value" ? d = String(g) : l[u] = String(g));
|
|
334
|
+
const h = a.ele($, n, l);
|
|
335
|
+
d !== null && w(h, d);
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (e.startsWith("media:") && typeof t == "string") {
|
|
340
|
+
const n = e.slice(6), o = a.ele($, n);
|
|
341
|
+
w(o, t);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (e === "media:group" && Array.isArray(t)) {
|
|
345
|
+
for (const n of t)
|
|
346
|
+
if (n && typeof n == "object") {
|
|
347
|
+
const o = a.ele($, "group");
|
|
348
|
+
for (const [l, d] of Object.entries(n))
|
|
349
|
+
if (d != null && l.startsWith("media:")) {
|
|
350
|
+
const h = l.slice(6);
|
|
351
|
+
if (Array.isArray(d)) {
|
|
352
|
+
for (const u of d)
|
|
353
|
+
if (u && typeof u == "object") {
|
|
354
|
+
const g = o.ele($, h);
|
|
355
|
+
for (const [s, c] of Object.entries(u))
|
|
356
|
+
c != null && (s === "url" || s === "value" ? w(g, String(c)) : g.att(s, String(c)));
|
|
357
|
+
}
|
|
358
|
+
} else typeof d == "string" && w(o.ele($, h), d);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (t instanceof Date) {
|
|
364
|
+
a.ele(e).txt(O(t));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (e === "authors" && Array.isArray(t)) {
|
|
368
|
+
for (const n of t) {
|
|
369
|
+
const o = typeof n == "string" ? n : n && typeof n == "object" && "name" in n ? `${n.email ?? ""} (${n.name ?? ""})`.trim() || n.name : String(n);
|
|
370
|
+
o && a.ele("author").txt(o);
|
|
371
|
+
}
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (e === "categories" && Array.isArray(t)) {
|
|
375
|
+
for (const n of t) {
|
|
376
|
+
const o = n && typeof n == "object" && "name" in n ? n.name : String(n);
|
|
377
|
+
if (o) {
|
|
378
|
+
const l = n && typeof n == "object" && "domain" in n && n.domain ? { domain: n.domain } : {};
|
|
379
|
+
a.ele("category", l).txt(o);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (Array.isArray(t) && t.every((n) => typeof n == "string")) {
|
|
385
|
+
const n = e.endsWith("s") ? e.slice(0, -1) : e;
|
|
386
|
+
for (const o of t)
|
|
387
|
+
if (o) {
|
|
388
|
+
const l = a.ele(n);
|
|
389
|
+
w(l, o);
|
|
390
|
+
}
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const i = a.ele(e);
|
|
394
|
+
w(i, String(t));
|
|
395
|
+
}
|
|
396
|
+
function Se(a) {
|
|
397
|
+
const e = ce({ version: "1.0", encoding: "UTF-8" }), r = e.ele("rss", { version: "2.0" }).ele("channel", {
|
|
398
|
+
"xmlns:dc": R,
|
|
399
|
+
"xmlns:content": j,
|
|
400
|
+
"xmlns:media": $
|
|
401
|
+
});
|
|
402
|
+
r.ele("title").txt(a.title), a.link && r.ele("link").txt(a.link), r.ele("description").txt(a.description), a.language && r.ele("language").txt(a.language), a.copyright && r.ele("copyright").txt(a.copyright), a.webMaster && r.ele("webMaster").txt(a.webMaster), a.pubDate && r.ele("pubDate").txt(O(a.pubDate)), a.lastBuildDate && r.ele("lastBuildDate").txt(O(a.lastBuildDate));
|
|
403
|
+
const i = new Set(z);
|
|
404
|
+
for (const n of a.items) {
|
|
405
|
+
const o = r.ele("item"), l = /* @__PURE__ */ new Set();
|
|
406
|
+
for (const h of z)
|
|
407
|
+
h in n && (H(o, h, n[h], n), l.add(h));
|
|
408
|
+
const d = Object.keys(n).filter(
|
|
409
|
+
(h) => !l.has(h) && !i.has(h) && !h.startsWith("_") && !De(h, n)
|
|
410
|
+
).sort();
|
|
411
|
+
for (const h of d)
|
|
412
|
+
H(o, h, n[h], n);
|
|
413
|
+
}
|
|
414
|
+
return e.end({ prettyPrint: !0 });
|
|
415
|
+
}
|
|
416
|
+
function Y(a) {
|
|
417
|
+
return `"${le("md5").update(a).digest("hex").substring(0, 16)}"`;
|
|
418
|
+
}
|
|
419
|
+
function Ie(a, e, t, r) {
|
|
420
|
+
const i = `${a}-${e}-${t}-${r}`;
|
|
421
|
+
return Y(i);
|
|
422
|
+
}
|
|
423
|
+
function $e(a, e, t, r) {
|
|
424
|
+
const i = `${a}-${e}-${t}-${r}`;
|
|
425
|
+
return Y(i);
|
|
426
|
+
}
|
|
427
|
+
function Te(a, e) {
|
|
21
428
|
const t = (r) => r.replace(/^"|"$/g, "");
|
|
22
|
-
return t(
|
|
429
|
+
return t(a) === t(e);
|
|
23
430
|
}
|
|
24
|
-
function
|
|
25
|
-
return
|
|
431
|
+
function _e(a) {
|
|
432
|
+
return a ? a.split(",").map((e) => e.trim()).filter((e) => e.length > 0) : [];
|
|
26
433
|
}
|
|
27
|
-
function
|
|
28
|
-
const t =
|
|
29
|
-
return t.length === 0 ? !1 : t.includes("*") ? !0 : t.some((r) =>
|
|
434
|
+
function Me(a, e) {
|
|
435
|
+
const t = _e(a);
|
|
436
|
+
return t.length === 0 ? !1 : t.includes("*") ? !0 : t.some((r) => Te(r, e));
|
|
30
437
|
}
|
|
31
|
-
class
|
|
438
|
+
class Ae {
|
|
32
439
|
feedDataCache = /* @__PURE__ */ new Map();
|
|
33
440
|
feedContentCache = /* @__PURE__ */ new Map();
|
|
34
441
|
imageMetadataCache = /* @__PURE__ */ new Map();
|
|
@@ -49,17 +456,17 @@ class X {
|
|
|
49
456
|
*/
|
|
50
457
|
setFeedData(e, t) {
|
|
51
458
|
const r = Math.floor(Date.now() / 1e3);
|
|
52
|
-
let
|
|
53
|
-
for (const
|
|
54
|
-
const
|
|
55
|
-
|
|
459
|
+
let i = 0, n = "";
|
|
460
|
+
for (const d of t) {
|
|
461
|
+
const h = d.timeCreated;
|
|
462
|
+
h && h > i && (i = h, n = d.id || d.seedUid || d.SeedUid || "");
|
|
56
463
|
}
|
|
57
|
-
|
|
58
|
-
const o =
|
|
464
|
+
i === 0 && (i = r);
|
|
465
|
+
const o = Ie(e, "data", i, t.length), l = {
|
|
59
466
|
items: [...t],
|
|
60
467
|
// Create a copy
|
|
61
|
-
lastProcessedTimestamp:
|
|
62
|
-
lastProcessedItemId:
|
|
468
|
+
lastProcessedTimestamp: i,
|
|
469
|
+
lastProcessedItemId: n,
|
|
63
470
|
lastUpdated: r,
|
|
64
471
|
etag: o
|
|
65
472
|
};
|
|
@@ -69,21 +476,21 @@ class X {
|
|
|
69
476
|
* Get cached feed content for a schema and format
|
|
70
477
|
*/
|
|
71
478
|
getFeedContent(e, t) {
|
|
72
|
-
const r = `${e}:${t}`,
|
|
73
|
-
return
|
|
479
|
+
const r = `${e}:${t}`, i = this.feedContentCache.get(r);
|
|
480
|
+
return i ? Math.floor(Date.now() / 1e3) > i.expiresAt ? (this.feedContentCache.delete(r), null) : i : null;
|
|
74
481
|
}
|
|
75
482
|
/**
|
|
76
483
|
* Set cached feed content for a schema and format
|
|
77
484
|
*/
|
|
78
|
-
setFeedContent(e, t, r,
|
|
79
|
-
const
|
|
485
|
+
setFeedContent(e, t, r, i) {
|
|
486
|
+
const n = `${e}:${t}`, o = Math.floor(Date.now() / 1e3), l = o + this.config.ttl, d = $e(e, t, o, r.length), h = {
|
|
80
487
|
content: r,
|
|
81
|
-
contentType:
|
|
82
|
-
etag:
|
|
488
|
+
contentType: i,
|
|
489
|
+
etag: d,
|
|
83
490
|
lastModified: o,
|
|
84
491
|
expiresAt: l
|
|
85
492
|
};
|
|
86
|
-
this.feedContentCache.set(
|
|
493
|
+
this.feedContentCache.set(n, h);
|
|
87
494
|
}
|
|
88
495
|
/**
|
|
89
496
|
* Clear feed data cache for a schema
|
|
@@ -111,10 +518,10 @@ class X {
|
|
|
111
518
|
* Set cached image metadata for a transaction ID
|
|
112
519
|
*/
|
|
113
520
|
setImageMetadata(e, t) {
|
|
114
|
-
const r = Math.floor(Date.now() / 1e3),
|
|
521
|
+
const r = Math.floor(Date.now() / 1e3), i = this.config.imageMetadata?.ttl || 604800, n = r + i, o = {
|
|
115
522
|
metadata: t,
|
|
116
523
|
cachedAt: r,
|
|
117
|
-
expiresAt:
|
|
524
|
+
expiresAt: n
|
|
118
525
|
};
|
|
119
526
|
this.imageMetadataCache.set(e, o);
|
|
120
527
|
}
|
|
@@ -131,14 +538,14 @@ class X {
|
|
|
131
538
|
async withRefreshLock(e, t) {
|
|
132
539
|
const r = this.refreshLocks.get(e);
|
|
133
540
|
r && (await r, this.getFeedData(e));
|
|
134
|
-
const
|
|
541
|
+
const i = (async () => {
|
|
135
542
|
try {
|
|
136
543
|
return await t();
|
|
137
544
|
} finally {
|
|
138
545
|
this.refreshLocks.delete(e);
|
|
139
546
|
}
|
|
140
547
|
})();
|
|
141
|
-
return this.refreshLocks.set(e,
|
|
548
|
+
return this.refreshLocks.set(e, i), i;
|
|
142
549
|
}
|
|
143
550
|
/**
|
|
144
551
|
* Update configuration
|
|
@@ -158,7 +565,7 @@ class X {
|
|
|
158
565
|
};
|
|
159
566
|
}
|
|
160
567
|
}
|
|
161
|
-
class
|
|
568
|
+
class Ue {
|
|
162
569
|
cacheDir;
|
|
163
570
|
config;
|
|
164
571
|
constructor(e) {
|
|
@@ -171,7 +578,7 @@ class J {
|
|
|
171
578
|
*/
|
|
172
579
|
async ensureCacheDir() {
|
|
173
580
|
try {
|
|
174
|
-
await
|
|
581
|
+
await y.mkdir(this.cacheDir, { recursive: !0 });
|
|
175
582
|
} catch (e) {
|
|
176
583
|
if (e.code !== "EEXIST")
|
|
177
584
|
throw e;
|
|
@@ -181,28 +588,28 @@ class J {
|
|
|
181
588
|
* Get file path for feed data
|
|
182
589
|
*/
|
|
183
590
|
getFeedDataPath(e) {
|
|
184
|
-
return
|
|
591
|
+
return S(this.cacheDir, `${e}.json`);
|
|
185
592
|
}
|
|
186
593
|
/**
|
|
187
594
|
* Get file path for feed content
|
|
188
595
|
*/
|
|
189
596
|
getFeedContentPath(e, t) {
|
|
190
|
-
return
|
|
597
|
+
return S(this.cacheDir, `${e}-${t}.json`);
|
|
191
598
|
}
|
|
192
599
|
/**
|
|
193
600
|
* Get file path for image metadata
|
|
194
601
|
*/
|
|
195
602
|
getImageMetadataPath(e) {
|
|
196
|
-
const t =
|
|
197
|
-
return
|
|
603
|
+
const t = S(this.cacheDir, "image-metadata");
|
|
604
|
+
return S(t, `${e}.json`);
|
|
198
605
|
}
|
|
199
606
|
/**
|
|
200
607
|
* Ensure image metadata directory exists
|
|
201
608
|
*/
|
|
202
609
|
async ensureImageMetadataDir() {
|
|
203
610
|
try {
|
|
204
|
-
const e =
|
|
205
|
-
await
|
|
611
|
+
const e = S(this.cacheDir, "image-metadata");
|
|
612
|
+
await y.mkdir(e, { recursive: !0 });
|
|
206
613
|
} catch (e) {
|
|
207
614
|
if (e.code !== "EEXIST")
|
|
208
615
|
throw e;
|
|
@@ -213,8 +620,8 @@ class J {
|
|
|
213
620
|
*/
|
|
214
621
|
async getFeedData(e) {
|
|
215
622
|
try {
|
|
216
|
-
const t = this.getFeedDataPath(e), r = await
|
|
217
|
-
return Math.floor(Date.now() / 1e3) -
|
|
623
|
+
const t = this.getFeedDataPath(e), r = await y.readFile(t, "utf-8"), i = JSON.parse(r);
|
|
624
|
+
return Math.floor(Date.now() / 1e3) - i.lastUpdated > this.config.ttl ? (await this.clearFeedData(e), null) : i;
|
|
218
625
|
} catch (t) {
|
|
219
626
|
return t.code === "ENOENT" || console.error(`Error reading feed data cache for ${e}:`, t), null;
|
|
220
627
|
}
|
|
@@ -226,7 +633,7 @@ class J {
|
|
|
226
633
|
try {
|
|
227
634
|
await this.ensureCacheDir();
|
|
228
635
|
const r = this.getFeedDataPath(e);
|
|
229
|
-
await
|
|
636
|
+
await y.writeFile(r, JSON.stringify(t, null, 2), "utf-8");
|
|
230
637
|
} catch (r) {
|
|
231
638
|
console.error(`Error writing feed data cache for ${e}:`, r);
|
|
232
639
|
}
|
|
@@ -236,8 +643,8 @@ class J {
|
|
|
236
643
|
*/
|
|
237
644
|
async getFeedContent(e, t) {
|
|
238
645
|
try {
|
|
239
|
-
const r = this.getFeedContentPath(e, t),
|
|
240
|
-
return Math.floor(Date.now() / 1e3) >
|
|
646
|
+
const r = this.getFeedContentPath(e, t), i = await y.readFile(r, "utf-8"), n = JSON.parse(i);
|
|
647
|
+
return Math.floor(Date.now() / 1e3) > n.expiresAt ? (await this.clearFeedContent(e, t), null) : n;
|
|
241
648
|
} catch (r) {
|
|
242
649
|
return r.code === "ENOENT" || console.error(
|
|
243
650
|
`Error reading feed content cache for ${e}:${t}:`,
|
|
@@ -251,12 +658,12 @@ class J {
|
|
|
251
658
|
async setFeedContent(e, t, r) {
|
|
252
659
|
try {
|
|
253
660
|
await this.ensureCacheDir();
|
|
254
|
-
const
|
|
255
|
-
await
|
|
256
|
-
} catch (
|
|
661
|
+
const i = this.getFeedContentPath(e, t);
|
|
662
|
+
await y.writeFile(i, JSON.stringify(r, null, 2), "utf-8");
|
|
663
|
+
} catch (i) {
|
|
257
664
|
console.error(
|
|
258
665
|
`Error writing feed content cache for ${e}:${t}:`,
|
|
259
|
-
|
|
666
|
+
i
|
|
260
667
|
);
|
|
261
668
|
}
|
|
262
669
|
}
|
|
@@ -266,7 +673,7 @@ class J {
|
|
|
266
673
|
async clearFeedData(e) {
|
|
267
674
|
try {
|
|
268
675
|
const t = this.getFeedDataPath(e);
|
|
269
|
-
await
|
|
676
|
+
await y.unlink(t);
|
|
270
677
|
} catch (t) {
|
|
271
678
|
t.code !== "ENOENT" && console.error(`Error clearing feed data cache for ${e}:`, t);
|
|
272
679
|
}
|
|
@@ -277,7 +684,7 @@ class J {
|
|
|
277
684
|
async clearFeedContent(e, t) {
|
|
278
685
|
try {
|
|
279
686
|
const r = this.getFeedContentPath(e, t);
|
|
280
|
-
await
|
|
687
|
+
await y.unlink(r);
|
|
281
688
|
} catch (r) {
|
|
282
689
|
r.code !== "ENOENT" && console.error(
|
|
283
690
|
`Error clearing feed content cache for ${e}:${t}:`,
|
|
@@ -290,9 +697,9 @@ class J {
|
|
|
290
697
|
*/
|
|
291
698
|
async clearAllContentCache(e) {
|
|
292
699
|
try {
|
|
293
|
-
const t = await
|
|
294
|
-
for (const
|
|
295
|
-
|
|
700
|
+
const t = await y.readdir(this.cacheDir), r = `${e}-`, i = ".json";
|
|
701
|
+
for (const n of t)
|
|
702
|
+
n.startsWith(r) && n.endsWith(i) && n !== `${e}.json` && await y.unlink(S(this.cacheDir, n));
|
|
296
703
|
} catch (t) {
|
|
297
704
|
console.error(`Error clearing all content cache for ${e}:`, t);
|
|
298
705
|
}
|
|
@@ -302,8 +709,8 @@ class J {
|
|
|
302
709
|
*/
|
|
303
710
|
async getImageMetadata(e) {
|
|
304
711
|
try {
|
|
305
|
-
const t = this.getImageMetadataPath(e), r = await
|
|
306
|
-
return Math.floor(Date.now() / 1e3) >
|
|
712
|
+
const t = this.getImageMetadataPath(e), r = await y.readFile(t, "utf-8"), i = JSON.parse(r);
|
|
713
|
+
return Math.floor(Date.now() / 1e3) > i.expiresAt ? (await this.clearImageMetadata(e), null) : i.metadata;
|
|
307
714
|
} catch (t) {
|
|
308
715
|
return t.code === "ENOENT" || console.error(`Error reading image metadata cache for ${e}:`, t), null;
|
|
309
716
|
}
|
|
@@ -314,12 +721,12 @@ class J {
|
|
|
314
721
|
async setImageMetadata(e, t) {
|
|
315
722
|
try {
|
|
316
723
|
await this.ensureImageMetadataDir();
|
|
317
|
-
const r = this.getImageMetadataPath(e),
|
|
724
|
+
const r = this.getImageMetadataPath(e), i = Math.floor(Date.now() / 1e3), n = this.config.imageMetadata?.ttl || 604800, o = i + n, l = {
|
|
318
725
|
metadata: t,
|
|
319
|
-
cachedAt:
|
|
726
|
+
cachedAt: i,
|
|
320
727
|
expiresAt: o
|
|
321
728
|
};
|
|
322
|
-
await
|
|
729
|
+
await y.writeFile(r, JSON.stringify(l, null, 2), "utf-8");
|
|
323
730
|
} catch (r) {
|
|
324
731
|
console.error(`Error writing image metadata cache for ${e}:`, r);
|
|
325
732
|
}
|
|
@@ -330,7 +737,7 @@ class J {
|
|
|
330
737
|
async clearImageMetadata(e) {
|
|
331
738
|
try {
|
|
332
739
|
const t = this.getImageMetadataPath(e);
|
|
333
|
-
await
|
|
740
|
+
await y.unlink(t);
|
|
334
741
|
} catch (t) {
|
|
335
742
|
t.code !== "ENOENT" && console.error(`Error clearing image metadata cache for ${e}:`, t);
|
|
336
743
|
}
|
|
@@ -340,14 +747,14 @@ class J {
|
|
|
340
747
|
*/
|
|
341
748
|
async clearAll() {
|
|
342
749
|
try {
|
|
343
|
-
const e = await
|
|
750
|
+
const e = await y.readdir(this.cacheDir);
|
|
344
751
|
for (const r of e)
|
|
345
|
-
r.endsWith(".json") && await
|
|
346
|
-
const t =
|
|
752
|
+
r.endsWith(".json") && await y.unlink(S(this.cacheDir, r));
|
|
753
|
+
const t = S(this.cacheDir, "image-metadata");
|
|
347
754
|
try {
|
|
348
|
-
const r = await
|
|
349
|
-
for (const
|
|
350
|
-
|
|
755
|
+
const r = await y.readdir(t);
|
|
756
|
+
for (const i of r)
|
|
757
|
+
i.endsWith(".json") && await y.unlink(S(t, i));
|
|
351
758
|
} catch {
|
|
352
759
|
}
|
|
353
760
|
} catch (e) {
|
|
@@ -355,7 +762,7 @@ class J {
|
|
|
355
762
|
}
|
|
356
763
|
}
|
|
357
764
|
}
|
|
358
|
-
class
|
|
765
|
+
class be {
|
|
359
766
|
memoryCache;
|
|
360
767
|
fileCache;
|
|
361
768
|
config;
|
|
@@ -366,7 +773,7 @@ class N {
|
|
|
366
773
|
errors: 0
|
|
367
774
|
};
|
|
368
775
|
constructor(e) {
|
|
369
|
-
this.config = e, this.memoryCache = new
|
|
776
|
+
this.config = e, this.memoryCache = new Ae(e), this.fileCache = new Ue(e);
|
|
370
777
|
}
|
|
371
778
|
/**
|
|
372
779
|
* Get cached feed data for a schema
|
|
@@ -422,16 +829,16 @@ class N {
|
|
|
422
829
|
* Set cached feed content for a schema and format
|
|
423
830
|
* Updates both memory and file cache
|
|
424
831
|
*/
|
|
425
|
-
async setFeedContent(e, t, r,
|
|
832
|
+
async setFeedContent(e, t, r, i) {
|
|
426
833
|
if (this.config.enabled)
|
|
427
834
|
try {
|
|
428
|
-
this.memoryCache.setFeedContent(e, t, r,
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
} catch (
|
|
835
|
+
this.memoryCache.setFeedContent(e, t, r, i);
|
|
836
|
+
const n = this.memoryCache.getFeedContent(e, t);
|
|
837
|
+
n && await this.fileCache.setFeedContent(e, t, n);
|
|
838
|
+
} catch (n) {
|
|
432
839
|
console.error(
|
|
433
840
|
`Error setting feed content cache for ${e}:${t}:`,
|
|
434
|
-
|
|
841
|
+
n
|
|
435
842
|
), this.stats.errors++;
|
|
436
843
|
}
|
|
437
844
|
}
|
|
@@ -460,27 +867,27 @@ class N {
|
|
|
460
867
|
*/
|
|
461
868
|
mergeItems(e, t) {
|
|
462
869
|
const r = /* @__PURE__ */ new Map();
|
|
463
|
-
for (const
|
|
464
|
-
const o =
|
|
465
|
-
o && r.set(o,
|
|
870
|
+
for (const n of e) {
|
|
871
|
+
const o = n.id || n.seedUid || n.SeedUid || "";
|
|
872
|
+
o && r.set(o, n);
|
|
466
873
|
}
|
|
467
|
-
for (const
|
|
468
|
-
const o =
|
|
469
|
-
o ? r.set(o,
|
|
874
|
+
for (const n of t) {
|
|
875
|
+
const o = n.id || n.seedUid || n.SeedUid || "";
|
|
876
|
+
o ? r.set(o, n) : r.set(`temp-${Date.now()}-${Math.random()}`, n);
|
|
470
877
|
}
|
|
471
|
-
const
|
|
472
|
-
return
|
|
473
|
-
const l =
|
|
878
|
+
const i = Array.from(r.values());
|
|
879
|
+
return i.sort((n, o) => {
|
|
880
|
+
const l = n.timeCreated || 0;
|
|
474
881
|
return (o.timeCreated || 0) - l;
|
|
475
|
-
}),
|
|
882
|
+
}), i;
|
|
476
883
|
}
|
|
477
884
|
/**
|
|
478
885
|
* Filter items to only include those newer than the given timestamp
|
|
479
886
|
*/
|
|
480
887
|
filterNewItems(e, t) {
|
|
481
888
|
return e.filter((r) => {
|
|
482
|
-
const
|
|
483
|
-
return
|
|
889
|
+
const i = r.timeCreated;
|
|
890
|
+
return i && i > t;
|
|
484
891
|
});
|
|
485
892
|
}
|
|
486
893
|
/**
|
|
@@ -536,32 +943,31 @@ class N {
|
|
|
536
943
|
};
|
|
537
944
|
}
|
|
538
945
|
}
|
|
539
|
-
function
|
|
540
|
-
const
|
|
946
|
+
function Z() {
|
|
947
|
+
const a = parseInt(process.env.CACHE_TTL || "3600", 10), e = process.env.CACHE_DIR || "./cache", t = process.env.CACHE_ENABLED === "false" || process.env.CACHE_ENABLED === "0" || process.env.CACHE_ENABLED === "no" || process.env.CACHE_ENABLED === "off", r = process.env.CACHE_ENABLED === "true" || process.env.CACHE_ENABLED === "1" || process.env.CACHE_ENABLED === "yes", i = process.env.NODE_ENV === "development";
|
|
948
|
+
let n;
|
|
949
|
+
t ? n = !1 : r ? n = !0 : i ? n = !1 : n = !0;
|
|
950
|
+
const o = process.env.CACHE_BACKGROUND_REFRESH === "true", l = parseInt(
|
|
541
951
|
process.env.CACHE_REFRESH_INTERVAL || "300",
|
|
542
952
|
10
|
|
543
953
|
);
|
|
544
|
-
|
|
545
|
-
const
|
|
954
|
+
n || console.log(`⚠️ Cache is DISABLED (${t ? "CACHE_ENABLED=false" : i ? "NODE_ENV=development" : "CACHE_ENABLED=false"})`);
|
|
955
|
+
const d = process.env.IMAGE_METADATA_ENABLED !== "false", h = parseInt(process.env.IMAGE_METADATA_TTL || "604800", 10), u = process.env.IMAGE_METADATA_GATEWAYS ? process.env.IMAGE_METADATA_GATEWAYS.split(",").map((c) => c.trim()) : [...X], g = parseInt(process.env.IMAGE_METADATA_TIMEOUT || "5000", 10);
|
|
546
956
|
return {
|
|
547
|
-
ttl:
|
|
957
|
+
ttl: a,
|
|
548
958
|
cacheDir: e,
|
|
549
|
-
enabled:
|
|
550
|
-
backgroundRefresh:
|
|
551
|
-
refreshInterval:
|
|
959
|
+
enabled: n,
|
|
960
|
+
backgroundRefresh: o,
|
|
961
|
+
refreshInterval: l,
|
|
552
962
|
imageMetadata: {
|
|
553
|
-
enabled:
|
|
554
|
-
ttl:
|
|
555
|
-
gateways:
|
|
556
|
-
timeout:
|
|
963
|
+
enabled: d,
|
|
964
|
+
ttl: h,
|
|
965
|
+
gateways: u,
|
|
966
|
+
timeout: g
|
|
557
967
|
}
|
|
558
968
|
};
|
|
559
969
|
}
|
|
560
|
-
|
|
561
|
-
const d = process.env.FEED_ITEM_URL_BASE?.trim() || void 0, e = process.env.FEED_ITEM_URL_PATH?.trim() || "attestation/view";
|
|
562
|
-
return { itemUrlBase: d, itemUrlPath: e };
|
|
563
|
-
}
|
|
564
|
-
class b {
|
|
970
|
+
class V {
|
|
565
971
|
config;
|
|
566
972
|
constructor(e) {
|
|
567
973
|
this.config = e;
|
|
@@ -570,14 +976,14 @@ class b {
|
|
|
570
976
|
* Detect if an Arweave transaction ID links to an image and extract metadata
|
|
571
977
|
*/
|
|
572
978
|
async detectImage(e) {
|
|
573
|
-
const t = this.config.gateways || [
|
|
979
|
+
const t = this.config.gateways || [...X];
|
|
574
980
|
for (const r of t)
|
|
575
981
|
try {
|
|
576
|
-
const
|
|
577
|
-
if (
|
|
578
|
-
return
|
|
579
|
-
} catch (
|
|
580
|
-
console.warn(`Failed to fetch from gateway ${r} for transaction ${e}:`,
|
|
982
|
+
const i = `https://${r}/${e}`, n = await this.getImageMetadata(i);
|
|
983
|
+
if (n.isImage)
|
|
984
|
+
return n;
|
|
985
|
+
} catch (i) {
|
|
986
|
+
console.warn(`Failed to fetch from gateway ${r} for transaction ${e}:`, i);
|
|
581
987
|
continue;
|
|
582
988
|
}
|
|
583
989
|
return {
|
|
@@ -593,31 +999,31 @@ class b {
|
|
|
593
999
|
const t = await this.fetchWithTimeout(e, { method: "HEAD" });
|
|
594
1000
|
if (!t.ok)
|
|
595
1001
|
return { isImage: !1, url: e };
|
|
596
|
-
const r = t.headers.get("content-type") || "",
|
|
1002
|
+
const r = t.headers.get("content-type") || "", i = t.headers.get("content-length");
|
|
597
1003
|
if (!this.isImageContentType(r))
|
|
598
1004
|
return {
|
|
599
1005
|
isImage: !1,
|
|
600
1006
|
url: e,
|
|
601
1007
|
mimeType: r || void 0,
|
|
602
|
-
size:
|
|
1008
|
+
size: i ? parseInt(i, 10) : void 0
|
|
603
1009
|
};
|
|
604
|
-
const
|
|
1010
|
+
const n = await this.fetchWithTimeout(e, {
|
|
605
1011
|
headers: {
|
|
606
1012
|
Range: "bytes=0-8192"
|
|
607
1013
|
// First 8KB should be enough for most image headers
|
|
608
1014
|
}
|
|
609
1015
|
});
|
|
610
|
-
if (!
|
|
611
|
-
return await this.getImageMetadataFromFullRequest(e, r,
|
|
612
|
-
const o = Buffer.from(await
|
|
1016
|
+
if (!n.ok)
|
|
1017
|
+
return await this.getImageMetadataFromFullRequest(e, r, i);
|
|
1018
|
+
const o = Buffer.from(await n.arrayBuffer()), l = this.extractImageDimensions(o, r), d = this.getImageFormat(r, o);
|
|
613
1019
|
return {
|
|
614
1020
|
isImage: !0,
|
|
615
1021
|
url: e,
|
|
616
1022
|
mimeType: r,
|
|
617
1023
|
width: l.width,
|
|
618
1024
|
height: l.height,
|
|
619
|
-
size:
|
|
620
|
-
format:
|
|
1025
|
+
size: i ? parseInt(i, 10) : void 0,
|
|
1026
|
+
format: d
|
|
621
1027
|
};
|
|
622
1028
|
} catch (t) {
|
|
623
1029
|
return console.warn(`Error fetching image metadata from ${e}:`, t), { isImage: !1, url: e };
|
|
@@ -628,21 +1034,21 @@ class b {
|
|
|
628
1034
|
*/
|
|
629
1035
|
async getImageMetadataFromFullRequest(e, t, r) {
|
|
630
1036
|
try {
|
|
631
|
-
const
|
|
632
|
-
if (!
|
|
1037
|
+
const i = await this.fetchWithTimeout(e);
|
|
1038
|
+
if (!i.ok)
|
|
633
1039
|
return { isImage: !1, url: e };
|
|
634
|
-
const
|
|
1040
|
+
const n = Buffer.from(await i.arrayBuffer()), o = this.extractImageDimensions(n, t), l = this.getImageFormat(t, n);
|
|
635
1041
|
return {
|
|
636
1042
|
isImage: !0,
|
|
637
1043
|
url: e,
|
|
638
1044
|
mimeType: t,
|
|
639
1045
|
width: o.width,
|
|
640
1046
|
height: o.height,
|
|
641
|
-
size:
|
|
1047
|
+
size: n.length,
|
|
642
1048
|
format: l
|
|
643
1049
|
};
|
|
644
|
-
} catch (
|
|
645
|
-
return console.warn(`Error in full request for ${e}:`,
|
|
1050
|
+
} catch (i) {
|
|
1051
|
+
return console.warn(`Error in full request for ${e}:`, i), { isImage: !1, url: e };
|
|
646
1052
|
}
|
|
647
1053
|
}
|
|
648
1054
|
/**
|
|
@@ -656,7 +1062,7 @@ class b {
|
|
|
656
1062
|
*/
|
|
657
1063
|
extractImageDimensions(e, t) {
|
|
658
1064
|
try {
|
|
659
|
-
const r =
|
|
1065
|
+
const r = N(e);
|
|
660
1066
|
if (r.width && r.height)
|
|
661
1067
|
return {
|
|
662
1068
|
width: r.width,
|
|
@@ -674,12 +1080,12 @@ class b {
|
|
|
674
1080
|
if (e) {
|
|
675
1081
|
const r = e.toLowerCase().match(/image\/([^;]+)/);
|
|
676
1082
|
if (r && r[1]) {
|
|
677
|
-
const
|
|
678
|
-
return
|
|
1083
|
+
const i = r[1].toLowerCase();
|
|
1084
|
+
return i === "jpeg" ? "jpeg" : i === "png" ? "png" : i === "gif" ? "gif" : i === "webp" ? "webp" : i === "svg+xml" ? "svg" : i;
|
|
679
1085
|
}
|
|
680
1086
|
}
|
|
681
1087
|
try {
|
|
682
|
-
const r =
|
|
1088
|
+
const r = N(t);
|
|
683
1089
|
if (r.type)
|
|
684
1090
|
return r.type.toLowerCase();
|
|
685
1091
|
} catch {
|
|
@@ -689,53 +1095,53 @@ class b {
|
|
|
689
1095
|
* Fetch with timeout
|
|
690
1096
|
*/
|
|
691
1097
|
async fetchWithTimeout(e, t = {}) {
|
|
692
|
-
const r = new AbortController(),
|
|
1098
|
+
const r = new AbortController(), i = setTimeout(() => r.abort(), this.config.timeout);
|
|
693
1099
|
try {
|
|
694
|
-
const
|
|
1100
|
+
const n = await fetch(e, {
|
|
695
1101
|
...t,
|
|
696
1102
|
signal: r.signal
|
|
697
1103
|
});
|
|
698
|
-
return clearTimeout(
|
|
699
|
-
} catch (
|
|
700
|
-
throw clearTimeout(
|
|
1104
|
+
return clearTimeout(i), n;
|
|
1105
|
+
} catch (n) {
|
|
1106
|
+
throw clearTimeout(i), n instanceof Error && n.name === "AbortError" ? new Error(`Request timeout after ${this.config.timeout}ms`) : n;
|
|
701
1107
|
}
|
|
702
1108
|
}
|
|
703
1109
|
}
|
|
704
|
-
let
|
|
705
|
-
function
|
|
706
|
-
if (!
|
|
707
|
-
const
|
|
708
|
-
|
|
1110
|
+
let _, I = null, A = null;
|
|
1111
|
+
function Fe() {
|
|
1112
|
+
if (!A) {
|
|
1113
|
+
const a = Z();
|
|
1114
|
+
A = new be(a);
|
|
709
1115
|
}
|
|
710
|
-
return
|
|
1116
|
+
return A;
|
|
711
1117
|
}
|
|
712
|
-
function
|
|
713
|
-
|
|
1118
|
+
function Je() {
|
|
1119
|
+
A = null;
|
|
714
1120
|
}
|
|
715
|
-
const
|
|
716
|
-
if (
|
|
717
|
-
return
|
|
718
|
-
if (!
|
|
719
|
-
return
|
|
1121
|
+
const ve = async () => {
|
|
1122
|
+
if (I)
|
|
1123
|
+
return I;
|
|
1124
|
+
if (!_)
|
|
1125
|
+
return I = (async () => {
|
|
720
1126
|
try {
|
|
721
|
-
console.log("Initializing Seed Protocol client..."), await
|
|
1127
|
+
console.log("Initializing Seed Protocol client..."), await T.init({ config: {
|
|
722
1128
|
endpoints: {
|
|
723
1129
|
filePaths: "app-files",
|
|
724
1130
|
files: "/app-files"
|
|
725
1131
|
},
|
|
726
|
-
arweaveDomain:
|
|
727
|
-
}, addresses: [] }), console.log("✅ Seed Protocol client initialized successfully"),
|
|
728
|
-
} catch (
|
|
729
|
-
throw console.error("❌ Failed to initialize Seed Protocol client:",
|
|
1132
|
+
arweaveDomain: re
|
|
1133
|
+
}, addresses: [] }), console.log("✅ Seed Protocol client initialized successfully"), _ = T, I = null;
|
|
1134
|
+
} catch (a) {
|
|
1135
|
+
throw console.error("❌ Failed to initialize Seed Protocol client:", a), I = null, a;
|
|
730
1136
|
}
|
|
731
|
-
})(),
|
|
732
|
-
},
|
|
1137
|
+
})(), I;
|
|
1138
|
+
}, G = async () => _ || (I ? (await I, _) : (await ve(), _)), Xe = async () => {
|
|
733
1139
|
try {
|
|
734
|
-
console.log("Tearing down Seed Protocol client..."), typeof
|
|
735
|
-
} catch (
|
|
736
|
-
console.error("❌ Failed to teardown Seed Protocol client:",
|
|
1140
|
+
console.log("Tearing down Seed Protocol client..."), typeof T.stop == "function" && (await T.stop(), console.log("✅ Seed Protocol client stopped")), typeof T.unload == "function" && (await T.unload(), console.log("✅ Seed Protocol client unloaded")), console.log("✅ Seed Protocol client teardown complete");
|
|
1141
|
+
} catch (a) {
|
|
1142
|
+
console.error("❌ Failed to teardown Seed Protocol client:", a);
|
|
737
1143
|
}
|
|
738
|
-
},
|
|
1144
|
+
}, m = {
|
|
739
1145
|
title: "Seed Protocol",
|
|
740
1146
|
description: "Content published via Seed Protocol",
|
|
741
1147
|
siteUrl: "https://seedprotocol.io",
|
|
@@ -746,264 +1152,246 @@ const Y = async () => {
|
|
|
746
1152
|
email: "info@seedprotocol.io",
|
|
747
1153
|
link: "https://seedprotocol.io"
|
|
748
1154
|
}
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
id
|
|
753
|
-
decodedDataJson
|
|
754
|
-
attester
|
|
755
|
-
schema {
|
|
756
|
-
schemaNames {
|
|
757
|
-
name
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
refUID
|
|
761
|
-
revoked
|
|
762
|
-
schemaId
|
|
763
|
-
timeCreated
|
|
764
|
-
isOffchain
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
`;
|
|
768
|
-
async function v(d, e, t) {
|
|
769
|
-
const r = d.filter(
|
|
1155
|
+
};
|
|
1156
|
+
async function J(a, e, t) {
|
|
1157
|
+
const r = a.filter(
|
|
770
1158
|
(l) => l.storageTransactionId || l.storage_transaction_id
|
|
771
1159
|
);
|
|
772
1160
|
if (r.length === 0)
|
|
773
|
-
return
|
|
1161
|
+
return a;
|
|
774
1162
|
console.log(`Enriching ${r.length} items with image metadata`);
|
|
775
|
-
const
|
|
776
|
-
const
|
|
777
|
-
if (!
|
|
1163
|
+
const i = r.map(async (l) => {
|
|
1164
|
+
const d = l.storageTransactionId || l.storage_transaction_id;
|
|
1165
|
+
if (!d) return l;
|
|
778
1166
|
try {
|
|
779
|
-
let
|
|
780
|
-
return
|
|
781
|
-
} catch (
|
|
782
|
-
return console.warn(`Error enriching item with transaction ${
|
|
1167
|
+
let h = await t.getImageMetadata(d);
|
|
1168
|
+
return h || (console.log(`Detecting image for transaction ${d}`), h = await e.detectImage(d), await t.setImageMetadata(d, h)), h.isImage && (l._imageMetadata = h, l._hasImage = !0), l;
|
|
1169
|
+
} catch (h) {
|
|
1170
|
+
return console.warn(`Error enriching item with transaction ${d}:`, h), l;
|
|
783
1171
|
}
|
|
784
|
-
}),
|
|
785
|
-
return
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
}),
|
|
789
|
-
const
|
|
790
|
-
return o.get(
|
|
1172
|
+
}), n = await Promise.all(i), o = /* @__PURE__ */ new Map();
|
|
1173
|
+
return n.forEach((l) => {
|
|
1174
|
+
const d = l.id || l.seedUid || l.SeedUid || "";
|
|
1175
|
+
d && o.set(d, l);
|
|
1176
|
+
}), a.map((l) => {
|
|
1177
|
+
const d = l.id || l.seedUid || l.SeedUid || "";
|
|
1178
|
+
return o.get(d) || l;
|
|
791
1179
|
});
|
|
792
1180
|
}
|
|
793
|
-
function
|
|
794
|
-
const { schemaName: t, siteUrl: r, itemUrlBase:
|
|
795
|
-
return
|
|
796
|
-
const l = o.id || o.seedUid || o.SeedUid || o.storageTransactionId || o.storage_transaction_id,
|
|
797
|
-
let
|
|
1181
|
+
function Pe(a, e) {
|
|
1182
|
+
const { schemaName: t, siteUrl: r, itemUrlBase: i, itemUrlPath: n } = e;
|
|
1183
|
+
return a.map((o) => {
|
|
1184
|
+
const l = o.id || o.seedUid || o.SeedUid || o.storageTransactionId || o.storage_transaction_id, d = i != null ? `${i.replace(/\/$/, "")}/${(n ?? "attestation/view").replace(/^\//, "")}/${l}` : `${r}/${b(t)}/${l}`, h = o.link || o.Link || o.import_url || o.importUrl || d;
|
|
1185
|
+
let u;
|
|
798
1186
|
if (o.pubDate || o.PubDate) {
|
|
799
|
-
const
|
|
800
|
-
|
|
1187
|
+
const s = o.pubDate || o.PubDate;
|
|
1188
|
+
u = new Date(s);
|
|
801
1189
|
} else if (o.timeCreated)
|
|
802
|
-
|
|
1190
|
+
u = new Date(o.timeCreated * 1e3);
|
|
803
1191
|
else if (o.publishedAt || o.createdAt || o.updatedAt) {
|
|
804
|
-
const
|
|
805
|
-
|
|
1192
|
+
const s = o.publishedAt || o.createdAt || o.updatedAt;
|
|
1193
|
+
u = s && typeof s == "object" && s.constructor === Date ? s : new Date(s);
|
|
806
1194
|
} else
|
|
807
|
-
|
|
808
|
-
const
|
|
1195
|
+
u = /* @__PURE__ */ new Date();
|
|
1196
|
+
const g = {
|
|
809
1197
|
...o,
|
|
810
1198
|
// Preserve all dynamic properties first
|
|
811
1199
|
// Map to standard feed fields
|
|
812
1200
|
id: l,
|
|
813
1201
|
title: o.title || o.Title || "Untitled",
|
|
814
|
-
link:
|
|
815
|
-
description: o.summary || o.description || "",
|
|
816
|
-
content: o.html || o.content || o.summary || "",
|
|
817
|
-
pubDate:
|
|
818
|
-
date:
|
|
1202
|
+
link: h,
|
|
1203
|
+
description: o.summary || o.description || o.text || "",
|
|
1204
|
+
content: o.html || o.content || o.summary || o.text || "",
|
|
1205
|
+
pubDate: u,
|
|
1206
|
+
date: u,
|
|
819
1207
|
// Map guid - use full URL when available for proper permalink
|
|
820
|
-
guid: o.guid || o.Guid || o.link || o.Link ||
|
|
1208
|
+
guid: o.guid || o.Guid || o.link || o.Link || h
|
|
821
1209
|
};
|
|
822
1210
|
if (o._imageMetadata && o._hasImage) {
|
|
823
|
-
const
|
|
824
|
-
|
|
1211
|
+
const s = o._imageMetadata;
|
|
1212
|
+
g._imageMetadata = s, g._hasImage = !0;
|
|
825
1213
|
}
|
|
826
|
-
return Object.keys(
|
|
827
|
-
const
|
|
828
|
-
if (typeof
|
|
829
|
-
const
|
|
830
|
-
isNaN(
|
|
1214
|
+
return Object.keys(g).forEach((s) => {
|
|
1215
|
+
const c = g[s];
|
|
1216
|
+
if (typeof c == "string" && /date|time|published|created|updated/i.test(s) && s !== "pubDate" && s !== "date") {
|
|
1217
|
+
const f = new Date(c);
|
|
1218
|
+
isNaN(f.getTime()) || (g[s] = f);
|
|
831
1219
|
}
|
|
832
|
-
}),
|
|
1220
|
+
}), g;
|
|
833
1221
|
});
|
|
834
1222
|
}
|
|
835
|
-
const
|
|
836
|
-
const
|
|
1223
|
+
const ke = (a, e, t, r) => {
|
|
1224
|
+
const i = b(e), n = `${m.siteUrl}/${i}/${t}`, o = r ? `${n}?v=${r}` : n, l = `${m.title} - ${Re(i)}`, d = /* @__PURE__ */ new Date(), h = K(), u = Pe(a, {
|
|
837
1225
|
schemaName: e,
|
|
838
|
-
siteUrl:
|
|
839
|
-
itemUrlBase:
|
|
840
|
-
itemUrlPath:
|
|
1226
|
+
siteUrl: m.siteUrl,
|
|
1227
|
+
itemUrlBase: h.itemUrlBase,
|
|
1228
|
+
itemUrlPath: h.itemUrlPath
|
|
841
1229
|
});
|
|
842
1230
|
switch (t) {
|
|
843
1231
|
case "atom": {
|
|
844
|
-
const
|
|
1232
|
+
const g = {
|
|
845
1233
|
id: o,
|
|
846
1234
|
title: l,
|
|
847
|
-
updated:
|
|
1235
|
+
updated: d,
|
|
848
1236
|
links: [
|
|
849
1237
|
{ href: o, rel: "self" },
|
|
850
|
-
{ href:
|
|
1238
|
+
{ href: m.siteUrl }
|
|
851
1239
|
],
|
|
852
|
-
subtitle:
|
|
853
|
-
rights:
|
|
854
|
-
author:
|
|
855
|
-
name:
|
|
856
|
-
email:
|
|
857
|
-
uri:
|
|
1240
|
+
subtitle: m.description,
|
|
1241
|
+
rights: m.copyright,
|
|
1242
|
+
author: m.author ? {
|
|
1243
|
+
name: m.author.name,
|
|
1244
|
+
email: m.author.email,
|
|
1245
|
+
uri: m.author.link
|
|
858
1246
|
} : void 0,
|
|
859
|
-
entries:
|
|
860
|
-
const
|
|
861
|
-
id:
|
|
862
|
-
title:
|
|
863
|
-
updated:
|
|
864
|
-
links:
|
|
865
|
-
...
|
|
1247
|
+
entries: u.map((s) => {
|
|
1248
|
+
const c = {
|
|
1249
|
+
id: s.id || s.link,
|
|
1250
|
+
title: s.title || "Untitled",
|
|
1251
|
+
updated: s.date || s.pubDate || d,
|
|
1252
|
+
links: s.link ? [{ href: s.link }] : [],
|
|
1253
|
+
...s
|
|
866
1254
|
// Preserve all dynamic properties
|
|
867
1255
|
};
|
|
868
|
-
if (
|
|
869
|
-
const
|
|
870
|
-
if (
|
|
871
|
-
href:
|
|
1256
|
+
if (s.content && (c.content = s.content), s.description && (c.summary = s.description), s._imageMetadata && s._hasImage) {
|
|
1257
|
+
const f = s._imageMetadata;
|
|
1258
|
+
if (c.links || (c.links = []), c.links.push({
|
|
1259
|
+
href: f.url,
|
|
872
1260
|
rel: "enclosure",
|
|
873
|
-
type:
|
|
874
|
-
length:
|
|
875
|
-
}),
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
${
|
|
879
|
-
${
|
|
1261
|
+
type: f.mimeType || "image/jpeg",
|
|
1262
|
+
length: f.size
|
|
1263
|
+
}), f.url && c.content && !c.content.includes(f.url)) {
|
|
1264
|
+
const p = `<img src="${f.url}" alt="${s.title || ""}"${f.width ? ` width="${f.width}"` : ""}${f.height ? ` height="${f.height}"` : ""} />`;
|
|
1265
|
+
c.content = typeof c.content == "string" ? `${p}
|
|
1266
|
+
${c.content}` : { type: "html", value: `${p}
|
|
1267
|
+
${c.content.value || c.content}` };
|
|
880
1268
|
}
|
|
881
1269
|
}
|
|
882
|
-
return
|
|
1270
|
+
return c;
|
|
883
1271
|
})
|
|
884
1272
|
};
|
|
885
|
-
return Promise.resolve(
|
|
1273
|
+
return Promise.resolve(oe(g));
|
|
886
1274
|
}
|
|
887
1275
|
case "json": {
|
|
888
|
-
const
|
|
1276
|
+
const g = {
|
|
889
1277
|
title: l,
|
|
890
|
-
home_page_url:
|
|
1278
|
+
home_page_url: m.siteUrl,
|
|
891
1279
|
feed_url: o,
|
|
892
|
-
description:
|
|
893
|
-
author:
|
|
894
|
-
name:
|
|
895
|
-
url:
|
|
1280
|
+
description: m.description,
|
|
1281
|
+
author: m.author ? {
|
|
1282
|
+
name: m.author.name,
|
|
1283
|
+
url: m.author.link
|
|
896
1284
|
} : void 0,
|
|
897
|
-
items:
|
|
898
|
-
const
|
|
899
|
-
id:
|
|
900
|
-
...
|
|
1285
|
+
items: u.map((c) => {
|
|
1286
|
+
const f = {
|
|
1287
|
+
id: c.id || c.link,
|
|
1288
|
+
...c
|
|
901
1289
|
// Preserve all dynamic properties
|
|
902
1290
|
};
|
|
903
|
-
if (
|
|
904
|
-
const
|
|
905
|
-
if (
|
|
906
|
-
url:
|
|
907
|
-
mime_type:
|
|
908
|
-
size_in_bytes:
|
|
909
|
-
title:
|
|
910
|
-
}),
|
|
911
|
-
const C = `<img src="${
|
|
912
|
-
|
|
913
|
-
${
|
|
1291
|
+
if (c.title && (f.title = c.title), c.link && (f.url = c.link), c.content && (f.content_html = c.content), c.description && (f.summary = c.description), (c.date || c.pubDate) && (f.date_published = c.date || c.pubDate), c._imageMetadata && c._hasImage) {
|
|
1292
|
+
const p = c._imageMetadata;
|
|
1293
|
+
if (f.image = p.url, f.attachments || (f.attachments = []), f.attachments.push({
|
|
1294
|
+
url: p.url,
|
|
1295
|
+
mime_type: p.mimeType || "image/jpeg",
|
|
1296
|
+
size_in_bytes: p.size,
|
|
1297
|
+
title: c.title || "Image"
|
|
1298
|
+
}), p.url && f.content_html && !f.content_html.includes(p.url)) {
|
|
1299
|
+
const C = `<img src="${p.url}" alt="${c.title || ""}"${p.width ? ` width="${p.width}"` : ""}${p.height ? ` height="${p.height}"` : ""} />`;
|
|
1300
|
+
f.content_html = `${C}
|
|
1301
|
+
${f.content_html}`;
|
|
914
1302
|
}
|
|
915
1303
|
}
|
|
916
|
-
return
|
|
1304
|
+
return f;
|
|
917
1305
|
})
|
|
918
|
-
},
|
|
919
|
-
return Promise.resolve(typeof
|
|
1306
|
+
}, s = ie(g);
|
|
1307
|
+
return Promise.resolve(typeof s == "string" ? s : JSON.stringify(s));
|
|
920
1308
|
}
|
|
921
1309
|
case "rss":
|
|
922
1310
|
default: {
|
|
923
|
-
const
|
|
1311
|
+
const g = {
|
|
924
1312
|
title: l,
|
|
925
|
-
link:
|
|
926
|
-
description:
|
|
927
|
-
language:
|
|
928
|
-
copyright:
|
|
929
|
-
webMaster:
|
|
930
|
-
pubDate:
|
|
931
|
-
lastBuildDate:
|
|
932
|
-
items:
|
|
933
|
-
const
|
|
934
|
-
...
|
|
1313
|
+
link: m.siteUrl,
|
|
1314
|
+
description: m.description,
|
|
1315
|
+
language: m.language,
|
|
1316
|
+
copyright: m.copyright,
|
|
1317
|
+
webMaster: m.author?.email,
|
|
1318
|
+
pubDate: d,
|
|
1319
|
+
lastBuildDate: d,
|
|
1320
|
+
items: u.map((s) => {
|
|
1321
|
+
const c = {
|
|
1322
|
+
...s
|
|
935
1323
|
// Preserve all dynamic properties
|
|
936
1324
|
};
|
|
937
|
-
if (
|
|
938
|
-
value:
|
|
939
|
-
isPermaLink: typeof
|
|
940
|
-
} :
|
|
941
|
-
value:
|
|
942
|
-
isPermaLink: typeof
|
|
943
|
-
}),
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
url:
|
|
947
|
-
type:
|
|
948
|
-
length:
|
|
1325
|
+
if (s.title && (c.title = s.title), s.link && (c.link = s.link), s.description && (c.description = s.description), (s.date || s.pubDate) && (c.pubDate = s.date || s.pubDate), s.guid ? c.guid = {
|
|
1326
|
+
value: s.guid,
|
|
1327
|
+
isPermaLink: typeof s.guid == "string" && (s.guid.startsWith("http://") || s.guid.startsWith("https://"))
|
|
1328
|
+
} : s.id && (c.guid = {
|
|
1329
|
+
value: s.id,
|
|
1330
|
+
isPermaLink: typeof s.id == "string" && (s.id.startsWith("http://") || s.id.startsWith("https://"))
|
|
1331
|
+
}), s._imageMetadata && s._hasImage) {
|
|
1332
|
+
const f = s._imageMetadata;
|
|
1333
|
+
c.enclosures = [{
|
|
1334
|
+
url: f.url,
|
|
1335
|
+
type: f.mimeType || "image/jpeg",
|
|
1336
|
+
length: f.size
|
|
949
1337
|
}];
|
|
950
|
-
const
|
|
951
|
-
url:
|
|
952
|
-
type:
|
|
1338
|
+
const p = {
|
|
1339
|
+
url: f.url,
|
|
1340
|
+
type: f.mimeType || "image/jpeg",
|
|
953
1341
|
medium: "image"
|
|
954
1342
|
// image, video, audio, document
|
|
955
1343
|
};
|
|
956
|
-
|
|
1344
|
+
f.width && (p.width = f.width), f.height && (p.height = f.height), f.size && (p.fileSize = f.size), f.format && (p.format = f.format), c["media:content"] = [p];
|
|
957
1345
|
const C = {
|
|
958
|
-
url:
|
|
1346
|
+
url: f.url
|
|
959
1347
|
};
|
|
960
|
-
|
|
961
|
-
const
|
|
962
|
-
if (
|
|
963
|
-
const
|
|
964
|
-
|
|
1348
|
+
f.width && (C.width = f.width), f.height && (C.height = f.height), c["media:thumbnail"] = [C], s.title && (c["media:title"] = s.title);
|
|
1349
|
+
const F = s.description || s.summary || s.title || "";
|
|
1350
|
+
if (F && (c["media:description"] = F), s.title) {
|
|
1351
|
+
const E = [];
|
|
1352
|
+
s.title && E.push(...s.title.toLowerCase().split(/\s+/).filter((v) => v.length > 3)), s.description && E.push(...s.description.toLowerCase().split(/\s+/).filter((v) => v.length > 3)), E.length > 0 && (c["media:keywords"] = [...new Set(E)].slice(0, 10).join(", "));
|
|
965
1353
|
}
|
|
966
|
-
if (
|
|
967
|
-
value:
|
|
1354
|
+
if (s.authors && Array.isArray(s.authors) && s.authors.length > 0 ? c["media:credit"] = s.authors.map((E) => ({
|
|
1355
|
+
value: E.name || E.displayName || "Unknown",
|
|
968
1356
|
role: "author"
|
|
969
|
-
})) :
|
|
970
|
-
value:
|
|
1357
|
+
})) : m.author && (c["media:credit"] = [{
|
|
1358
|
+
value: m.author.name,
|
|
971
1359
|
role: "author"
|
|
972
|
-
}]),
|
|
1360
|
+
}]), m.copyright && (c["media:copyright"] = m.copyright), e && (c["media:category"] = [{
|
|
973
1361
|
value: e,
|
|
974
1362
|
scheme: "http://www.schema.org/"
|
|
975
|
-
}]),
|
|
976
|
-
"media:content": [
|
|
1363
|
+
}]), c["media:group"] = [{
|
|
1364
|
+
"media:content": [p],
|
|
977
1365
|
"media:thumbnail": [C],
|
|
978
|
-
"media:title":
|
|
979
|
-
"media:description":
|
|
980
|
-
}],
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
${
|
|
1366
|
+
"media:title": s.title || "Untitled",
|
|
1367
|
+
"media:description": F
|
|
1368
|
+
}], f.url && s.content && !s.content.includes(f.url)) {
|
|
1369
|
+
const E = `<img src="${f.url}" alt="${s.title || ""}"${f.width ? ` width="${f.width}"` : ""}${f.height ? ` height="${f.height}"` : ""} />`;
|
|
1370
|
+
c["content:encoded"] = `${E}
|
|
1371
|
+
${s.content}`;
|
|
984
1372
|
}
|
|
985
1373
|
}
|
|
986
|
-
if (!
|
|
987
|
-
const
|
|
988
|
-
|
|
989
|
-
url:
|
|
1374
|
+
if (!c.enclosures && (s.feature_image || s.featureImage)) {
|
|
1375
|
+
const f = s.feature_image || s.featureImage, p = typeof f == "string" && f.startsWith("http") ? f : U(f);
|
|
1376
|
+
c.enclosures = [{
|
|
1377
|
+
url: p,
|
|
990
1378
|
type: "image/jpeg"
|
|
991
1379
|
// Default, could be determined from URL or metadata
|
|
992
1380
|
}];
|
|
993
1381
|
}
|
|
994
|
-
if (
|
|
995
|
-
const
|
|
996
|
-
|
|
1382
|
+
if (c.dc = {}, (s.date || s.pubDate) && (c.dc.date = s.date || s.pubDate), s.timeCreated) {
|
|
1383
|
+
const f = new Date(s.timeCreated * 1e3);
|
|
1384
|
+
c.dc.dates || (c.dc.dates = []), c.dc.dates.push(f);
|
|
997
1385
|
}
|
|
998
|
-
return (
|
|
1386
|
+
return (s.seedUid || s.SeedUid) && (c.dc.identifier || (c.dc.identifier = []), c.dc.identifier.push(s.seedUid || s.SeedUid)), (s.storageTransactionId || s.storage_transaction_id) && (c.dc.identifier || (c.dc.identifier = []), c.dc.identifier.push(s.storageTransactionId || s.storage_transaction_id)), (s.import_url || s.importUrl) && (c.dc.source = s.import_url || s.importUrl), (s.seedUid || s.SeedUid) && (c.seedUid = s.seedUid || s.SeedUid), (s.storageTransactionId || s.storage_transaction_id) && (c.storageTransactionId = s.storageTransactionId || s.storage_transaction_id), s.timeCreated && (c.timeCreated = s.timeCreated), c;
|
|
999
1387
|
})
|
|
1000
1388
|
};
|
|
1001
|
-
return Promise.resolve(
|
|
1389
|
+
return Promise.resolve(Se(g));
|
|
1002
1390
|
}
|
|
1003
1391
|
}
|
|
1004
1392
|
};
|
|
1005
|
-
function
|
|
1006
|
-
switch (
|
|
1393
|
+
function Le(a) {
|
|
1394
|
+
switch (a) {
|
|
1007
1395
|
case "atom":
|
|
1008
1396
|
return "application/atom+xml; charset=utf-8";
|
|
1009
1397
|
case "json":
|
|
@@ -1013,16 +1401,16 @@ function Z(d) {
|
|
|
1013
1401
|
return "application/rss+xml; charset=utf-8";
|
|
1014
1402
|
}
|
|
1015
1403
|
}
|
|
1016
|
-
function
|
|
1017
|
-
const e =
|
|
1404
|
+
function xe(a) {
|
|
1405
|
+
const e = a.toLowerCase();
|
|
1018
1406
|
return ["rss", "atom", "json"].includes(e) ? e : null;
|
|
1019
1407
|
}
|
|
1020
|
-
function
|
|
1021
|
-
return
|
|
1408
|
+
function Re(a) {
|
|
1409
|
+
return a.charAt(0).toUpperCase() + a.slice(1);
|
|
1022
1410
|
}
|
|
1023
|
-
async function
|
|
1024
|
-
const
|
|
1025
|
-
if (!
|
|
1411
|
+
async function Ke(a, e, t, r) {
|
|
1412
|
+
const i = xe(e);
|
|
1413
|
+
if (!i)
|
|
1026
1414
|
return new Response(
|
|
1027
1415
|
JSON.stringify({ error: `Invalid feed format: ${e}` }),
|
|
1028
1416
|
{
|
|
@@ -1030,110 +1418,110 @@ async function fe(d, e, t, r) {
|
|
|
1030
1418
|
headers: { "Content-Type": "application/json" }
|
|
1031
1419
|
}
|
|
1032
1420
|
);
|
|
1033
|
-
const
|
|
1034
|
-
console.log(`Schema name: ${
|
|
1035
|
-
const l =
|
|
1421
|
+
const n = b.singular(a.toLowerCase()), o = b(n);
|
|
1422
|
+
console.log(`Schema name: ${n}`), console.log(`Collection name: ${o}`);
|
|
1423
|
+
const l = Fe(), d = Z();
|
|
1036
1424
|
try {
|
|
1037
|
-
if (
|
|
1038
|
-
const
|
|
1039
|
-
if (
|
|
1040
|
-
return t &&
|
|
1425
|
+
if (d.enabled) {
|
|
1426
|
+
const s = await l.getFeedContent(n, i);
|
|
1427
|
+
if (s)
|
|
1428
|
+
return t && Me(t, s.etag) ? (console.log(`Cache hit with ETag match for ${n}:${i} - returning 304`), new Response(null, {
|
|
1041
1429
|
status: 304,
|
|
1042
1430
|
headers: {
|
|
1043
|
-
ETag:
|
|
1044
|
-
"Last-Modified": new Date(
|
|
1431
|
+
ETag: s.etag,
|
|
1432
|
+
"Last-Modified": new Date(s.lastModified * 1e3).toUTCString(),
|
|
1045
1433
|
"Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate"
|
|
1046
1434
|
}
|
|
1047
|
-
})) : (console.log(`Cache hit for ${
|
|
1435
|
+
})) : (console.log(`Cache hit for ${n}:${i}`), new Response(s.content, {
|
|
1048
1436
|
status: 200,
|
|
1049
1437
|
headers: {
|
|
1050
|
-
"Content-Type":
|
|
1051
|
-
ETag:
|
|
1052
|
-
"Last-Modified": new Date(
|
|
1438
|
+
"Content-Type": s.contentType,
|
|
1439
|
+
ETag: s.etag,
|
|
1440
|
+
"Last-Modified": new Date(s.lastModified * 1e3).toUTCString(),
|
|
1053
1441
|
"Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
|
|
1054
|
-
"X-Feed-Schema":
|
|
1055
|
-
"X-Feed-Format":
|
|
1442
|
+
"X-Feed-Schema": n,
|
|
1443
|
+
"X-Feed-Format": i,
|
|
1056
1444
|
"X-Cache": "HIT"
|
|
1057
1445
|
}
|
|
1058
1446
|
}));
|
|
1059
1447
|
}
|
|
1060
|
-
console.log(`Cache miss for ${
|
|
1061
|
-
const
|
|
1062
|
-
const
|
|
1063
|
-
let
|
|
1064
|
-
if (
|
|
1065
|
-
console.log(`Incremental fetch: last processed timestamp: ${
|
|
1066
|
-
const
|
|
1067
|
-
console.log(`First item: ${JSON.stringify(
|
|
1068
|
-
const C = l.filterNewItems(
|
|
1069
|
-
C.length > 0 ? (console.log(`Found ${C.length} new items, merging with ${
|
|
1448
|
+
console.log(`Cache miss for ${n}:${i} - fetching items`);
|
|
1449
|
+
const h = d.enabled ? await l.withRefreshLock(n, async () => {
|
|
1450
|
+
const s = await l.getFeedData(n);
|
|
1451
|
+
let c;
|
|
1452
|
+
if (s) {
|
|
1453
|
+
console.log(`Incremental fetch: last processed timestamp: ${s.lastProcessedTimestamp}`);
|
|
1454
|
+
const p = await k(n);
|
|
1455
|
+
console.log(`First item: ${JSON.stringify(p[0])}`);
|
|
1456
|
+
const C = l.filterNewItems(p, s.lastProcessedTimestamp);
|
|
1457
|
+
C.length > 0 ? (console.log(`Found ${C.length} new items, merging with ${s.items.length} cached items`), c = l.mergeItems(s.items, C)) : (console.log("No new items found, using cached items"), c = s.items);
|
|
1070
1458
|
} else {
|
|
1071
1459
|
console.log("Cold cache - fetching all items");
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1460
|
+
const p = await G();
|
|
1461
|
+
p && console.log(`Client initialized: ${p.isInitialized()}`), c = await k(n), console.log(`Found ${c.length} feed items for schema ${n}`);
|
|
1074
1462
|
}
|
|
1075
|
-
let
|
|
1076
|
-
if (
|
|
1077
|
-
const
|
|
1078
|
-
gateways:
|
|
1079
|
-
timeout:
|
|
1463
|
+
let f = c;
|
|
1464
|
+
if (d.imageMetadata?.enabled) {
|
|
1465
|
+
const p = new V({
|
|
1466
|
+
gateways: d.imageMetadata.gateways,
|
|
1467
|
+
timeout: d.imageMetadata.timeout
|
|
1080
1468
|
});
|
|
1081
|
-
|
|
1469
|
+
f = await J(c, p, l);
|
|
1082
1470
|
}
|
|
1083
|
-
return await l.setFeedData(
|
|
1471
|
+
return await l.setFeedData(n, c), f;
|
|
1084
1472
|
}) : await (async () => {
|
|
1085
1473
|
console.log("Cache disabled - fetching all items directly");
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1088
|
-
const
|
|
1089
|
-
console.log(`Found ${
|
|
1090
|
-
let
|
|
1091
|
-
if (
|
|
1092
|
-
const
|
|
1093
|
-
gateways:
|
|
1094
|
-
timeout:
|
|
1474
|
+
const s = await G();
|
|
1475
|
+
s && console.log(`Client initialized: ${s.isInitialized()}`);
|
|
1476
|
+
const c = await k(n);
|
|
1477
|
+
console.log(`Found ${c.length} feed items for schema ${n}`);
|
|
1478
|
+
let f = c;
|
|
1479
|
+
if (d.imageMetadata?.enabled) {
|
|
1480
|
+
const p = new V({
|
|
1481
|
+
gateways: d.imageMetadata.gateways,
|
|
1482
|
+
timeout: d.imageMetadata.timeout
|
|
1095
1483
|
});
|
|
1096
|
-
|
|
1484
|
+
f = await J(c, p, l);
|
|
1097
1485
|
}
|
|
1098
|
-
return
|
|
1099
|
-
})(),
|
|
1100
|
-
if (
|
|
1101
|
-
await l.setFeedContent(
|
|
1102
|
-
const
|
|
1103
|
-
return new Response(
|
|
1486
|
+
return f;
|
|
1487
|
+
})(), u = await ke(h, n, i, r), g = Le(i);
|
|
1488
|
+
if (d.enabled) {
|
|
1489
|
+
await l.setFeedContent(n, i, u, g);
|
|
1490
|
+
const s = await l.getFeedContent(n, i), c = s?.etag || "", f = s?.lastModified || Math.floor(Date.now() / 1e3);
|
|
1491
|
+
return new Response(u, {
|
|
1104
1492
|
status: 200,
|
|
1105
1493
|
headers: {
|
|
1106
|
-
"Content-Type":
|
|
1107
|
-
ETag:
|
|
1108
|
-
"Last-Modified": new Date(
|
|
1494
|
+
"Content-Type": g,
|
|
1495
|
+
ETag: c,
|
|
1496
|
+
"Last-Modified": new Date(f * 1e3).toUTCString(),
|
|
1109
1497
|
"Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
|
|
1110
|
-
"X-Feed-Schema":
|
|
1111
|
-
"X-Feed-Format":
|
|
1498
|
+
"X-Feed-Schema": n,
|
|
1499
|
+
"X-Feed-Format": i,
|
|
1112
1500
|
"X-Cache": "MISS"
|
|
1113
1501
|
}
|
|
1114
1502
|
});
|
|
1115
1503
|
}
|
|
1116
|
-
return new Response(
|
|
1504
|
+
return new Response(u, {
|
|
1117
1505
|
status: 200,
|
|
1118
1506
|
headers: {
|
|
1119
|
-
"Content-Type":
|
|
1507
|
+
"Content-Type": g,
|
|
1120
1508
|
"Cache-Control": "public, max-age=3600, s-maxage=3600",
|
|
1121
|
-
"X-Feed-Schema":
|
|
1122
|
-
"X-Feed-Format":
|
|
1509
|
+
"X-Feed-Schema": n,
|
|
1510
|
+
"X-Feed-Format": i
|
|
1123
1511
|
}
|
|
1124
1512
|
});
|
|
1125
|
-
} catch (
|
|
1126
|
-
if (console.error("Feed generation error:",
|
|
1127
|
-
const
|
|
1128
|
-
if (
|
|
1129
|
-
return console.log("Serving stale cache due to error"), new Response(
|
|
1513
|
+
} catch (h) {
|
|
1514
|
+
if (console.error("Feed generation error:", h), d.enabled) {
|
|
1515
|
+
const u = await l.getFeedContent(n, i);
|
|
1516
|
+
if (u)
|
|
1517
|
+
return console.log("Serving stale cache due to error"), new Response(u.content, {
|
|
1130
1518
|
status: 200,
|
|
1131
1519
|
headers: {
|
|
1132
|
-
"Content-Type":
|
|
1133
|
-
ETag:
|
|
1520
|
+
"Content-Type": u.contentType,
|
|
1521
|
+
ETag: u.etag,
|
|
1134
1522
|
"Cache-Control": "public, max-age=3600, s-maxage=3600, must-revalidate",
|
|
1135
|
-
"X-Feed-Schema":
|
|
1136
|
-
"X-Feed-Format":
|
|
1523
|
+
"X-Feed-Schema": n,
|
|
1524
|
+
"X-Feed-Format": i,
|
|
1137
1525
|
"X-Cache": "STALE",
|
|
1138
1526
|
Warning: '299 - "Cache is stale"'
|
|
1139
1527
|
}
|
|
@@ -1142,7 +1530,7 @@ async function fe(d, e, t, r) {
|
|
|
1142
1530
|
return new Response(
|
|
1143
1531
|
JSON.stringify({
|
|
1144
1532
|
error: "Failed to generate feed",
|
|
1145
|
-
message:
|
|
1533
|
+
message: h instanceof Error ? h.message : "Unknown error"
|
|
1146
1534
|
}),
|
|
1147
1535
|
{
|
|
1148
1536
|
status: 500,
|
|
@@ -1152,12 +1540,12 @@ async function fe(d, e, t, r) {
|
|
|
1152
1540
|
}
|
|
1153
1541
|
}
|
|
1154
1542
|
export {
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1543
|
+
ke as createFeed,
|
|
1544
|
+
G as getClient,
|
|
1545
|
+
k as getFeedItemsBySchemaName,
|
|
1546
|
+
Ke as handleFeedRequest,
|
|
1547
|
+
ve as initializeSeedClient,
|
|
1548
|
+
Je as resetCacheManager,
|
|
1549
|
+
Xe as teardownSeedClient
|
|
1162
1550
|
};
|
|
1163
1551
|
//# sourceMappingURL=index.js.map
|