@dwk/microsub 0.1.0-beta.0
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/LICENSE +15 -0
- package/README.md +92 -0
- package/dist/auth.d.ts +53 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +102 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +102 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/consumer.d.ts +40 -0
- package/dist/consumer.d.ts.map +1 -0
- package/dist/consumer.js +87 -0
- package/dist/consumer.js.map +1 -0
- package/dist/discovery.d.ts +59 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +190 -0
- package/dist/discovery.js.map +1 -0
- package/dist/fetch.d.ts +28 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +72 -0
- package/dist/fetch.js.map +1 -0
- package/dist/handler.d.ts +24 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +434 -0
- package/dist/handler.js.map +1 -0
- package/dist/hfeed.d.ts +25 -0
- package/dist/hfeed.d.ts.map +1 -0
- package/dist/hfeed.js +252 -0
- package/dist/hfeed.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/jf2.d.ts +69 -0
- package/dist/jf2.d.ts.map +1 -0
- package/dist/jf2.js +295 -0
- package/dist/jf2.js.map +1 -0
- package/dist/log.d.ts +44 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +42 -0
- package/dist/log.js.map +1 -0
- package/dist/poll.d.ts +22 -0
- package/dist/poll.d.ts.map +1 -0
- package/dist/poll.js +39 -0
- package/dist/poll.js.map +1 -0
- package/dist/queue.d.ts +25 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +13 -0
- package/dist/queue.js.map +1 -0
- package/dist/replay.d.ts +34 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +49 -0
- package/dist/replay.js.map +1 -0
- package/dist/safe-fetch.d.ts +86 -0
- package/dist/safe-fetch.d.ts.map +1 -0
- package/dist/safe-fetch.js +311 -0
- package/dist/safe-fetch.js.map +1 -0
- package/dist/store.d.ts +131 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +393 -0
- package/dist/store.js.map +1 -0
- package/dist/xml.d.ts +51 -0
- package/dist/xml.d.ts.map +1 -0
- package/dist/xml.js +196 -0
- package/dist/xml.js.map +1 -0
- package/package.json +49 -0
- package/src/auth.ts +184 -0
- package/src/config.ts +156 -0
- package/src/consumer.ts +140 -0
- package/src/discovery.ts +270 -0
- package/src/fetch.ts +82 -0
- package/src/handler.ts +594 -0
- package/src/hfeed.ts +287 -0
- package/src/index.ts +86 -0
- package/src/jf2.ts +394 -0
- package/src/log.ts +46 -0
- package/src/poll.ts +72 -0
- package/src/queue.ts +26 -0
- package/src/replay.ts +68 -0
- package/src/safe-fetch.ts +346 -0
- package/src/store.ts +644 -0
- package/src/xml.ts +229 -0
package/dist/hfeed.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dwk/microsub` — `h-feed` / `h-entry` microformats parsing.
|
|
3
|
+
*
|
|
4
|
+
* When a followed source is an HTML page rather than a syndication feed, its
|
|
5
|
+
* entries are expressed as [microformats2](https://microformats.org/wiki/h-entry)
|
|
6
|
+
* `h-entry` items (usually inside an `h-feed`). This module extracts them into
|
|
7
|
+
* the same JF2 shape the other formats produce, using the Workers runtime's
|
|
8
|
+
* streaming `HTMLRewriter` rather than a regex or a bundled parser
|
|
9
|
+
* (`HTMLRewriter` is built into the runtime — zero script-size cost; see
|
|
10
|
+
* `spec/non-functional-requirements.md`). Because `HTMLRewriter` is a `workerd`
|
|
11
|
+
* global, this parser is async and exercised under the Workers test pool.
|
|
12
|
+
*
|
|
13
|
+
* It is a pragmatic extractor of the common `h-entry` properties — `u-url`,
|
|
14
|
+
* `p-name`, `e-content`, `dt-published`, `p-author` / nested `h-card`,
|
|
15
|
+
* `u-photo`, `p-category`, `u-in-reply-to`, `u-like-of` — not a full mf2 engine.
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
function classes(value) {
|
|
20
|
+
return value === null ? [] : value.trim().split(/\s+/).filter(Boolean);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* HTML void elements have no end tag, so `HTMLRewriter#onEndTag` throws on them.
|
|
24
|
+
* They also carry no text content — a `u-photo` / `dt-published` on one always
|
|
25
|
+
* takes its value from an attribute — so we commit immediately and never
|
|
26
|
+
* register an end-tag handler for them.
|
|
27
|
+
*/
|
|
28
|
+
const VOID_ELEMENTS = new Set([
|
|
29
|
+
"area",
|
|
30
|
+
"base",
|
|
31
|
+
"br",
|
|
32
|
+
"col",
|
|
33
|
+
"embed",
|
|
34
|
+
"hr",
|
|
35
|
+
"img",
|
|
36
|
+
"input",
|
|
37
|
+
"link",
|
|
38
|
+
"meta",
|
|
39
|
+
"param",
|
|
40
|
+
"source",
|
|
41
|
+
"track",
|
|
42
|
+
"wbr",
|
|
43
|
+
]);
|
|
44
|
+
function absolute(href, base) {
|
|
45
|
+
try {
|
|
46
|
+
return new URL(href, base).toString();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return href;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** FNV-1a hash (base36), matching {@link ./jf2}'s fallback id derivation. */
|
|
53
|
+
function hash(input) {
|
|
54
|
+
let h = 0x811c9dc5;
|
|
55
|
+
for (let i = 0; i < input.length; i++) {
|
|
56
|
+
h ^= input.charCodeAt(i);
|
|
57
|
+
h = Math.imul(h, 0x01000193);
|
|
58
|
+
}
|
|
59
|
+
return (h >>> 0).toString(36);
|
|
60
|
+
}
|
|
61
|
+
/** The first `(p|u|e|dt)-name` microformats class on an element, if any. */
|
|
62
|
+
function propertyClass(classList) {
|
|
63
|
+
for (const cls of classList) {
|
|
64
|
+
const match = /^(p|u|e|dt)-(.+)$/.exec(cls);
|
|
65
|
+
if (match) {
|
|
66
|
+
return { name: match[2], format: match[1] };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function commitEntry(entry, baseUrl) {
|
|
72
|
+
const url = entry.url ? absolute(entry.url, baseUrl) : undefined;
|
|
73
|
+
const content = entry.content
|
|
74
|
+
? { text: entry.content }
|
|
75
|
+
: undefined;
|
|
76
|
+
const author = entry.author
|
|
77
|
+
? (() => {
|
|
78
|
+
const card = {
|
|
79
|
+
type: "card",
|
|
80
|
+
...(entry.author.name ? { name: entry.author.name } : {}),
|
|
81
|
+
...(entry.author.url
|
|
82
|
+
? { url: absolute(entry.author.url, baseUrl) }
|
|
83
|
+
: {}),
|
|
84
|
+
...(entry.author.photo
|
|
85
|
+
? { photo: absolute(entry.author.photo, baseUrl) }
|
|
86
|
+
: {}),
|
|
87
|
+
};
|
|
88
|
+
return card.name || card.url || card.photo ? card : undefined;
|
|
89
|
+
})()
|
|
90
|
+
: undefined;
|
|
91
|
+
const id = url ?? hash(`${entry.name ?? ""}${entry.content ?? ""}`);
|
|
92
|
+
const out = { type: "entry", _id: id };
|
|
93
|
+
if (url)
|
|
94
|
+
out.url = url;
|
|
95
|
+
if (entry.published)
|
|
96
|
+
out.published = entry.published;
|
|
97
|
+
if (entry.name)
|
|
98
|
+
out.name = entry.name;
|
|
99
|
+
if (content)
|
|
100
|
+
out.content = content;
|
|
101
|
+
if (author)
|
|
102
|
+
out.author = author;
|
|
103
|
+
if (entry.category.length > 0)
|
|
104
|
+
out.category = entry.category;
|
|
105
|
+
if (entry.photo.length > 0)
|
|
106
|
+
out.photo = entry.photo.map((p) => absolute(p, baseUrl));
|
|
107
|
+
if (entry.inReplyTo)
|
|
108
|
+
out["in-reply-to"] = absolute(entry.inReplyTo, baseUrl);
|
|
109
|
+
if (entry.likeOf)
|
|
110
|
+
out["like-of"] = absolute(entry.likeOf, baseUrl);
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Extract JF2 entries from an HTML document's `h-entry` microformats. Entries
|
|
115
|
+
* are returned in document order. Returns `[]` when the document has none.
|
|
116
|
+
*/
|
|
117
|
+
export async function parseHFeed(html, baseUrl) {
|
|
118
|
+
if (html === "")
|
|
119
|
+
return [];
|
|
120
|
+
const entries = [];
|
|
121
|
+
const entryStack = [];
|
|
122
|
+
const cardStack = [];
|
|
123
|
+
const propStack = [];
|
|
124
|
+
const top = (arr) => arr[arr.length - 1];
|
|
125
|
+
const rewriter = new HTMLRewriter().on("*", {
|
|
126
|
+
element(el) {
|
|
127
|
+
const classList = classes(el.getAttribute("class"));
|
|
128
|
+
const isVoid = VOID_ELEMENTS.has(el.tagName);
|
|
129
|
+
if (classList.includes("h-entry") && !isVoid) {
|
|
130
|
+
const entry = { photo: [], category: [] };
|
|
131
|
+
entryStack.push(entry);
|
|
132
|
+
el.onEndTag(() => {
|
|
133
|
+
const finished = entryStack.pop();
|
|
134
|
+
if (finished)
|
|
135
|
+
entries.push(commitEntry(finished, baseUrl));
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (classList.includes("h-card") && !isVoid) {
|
|
140
|
+
const card = {};
|
|
141
|
+
const entry = top(entryStack);
|
|
142
|
+
// A bare p-author h-card attaches as the current entry's author.
|
|
143
|
+
if (entry && entry.author === undefined)
|
|
144
|
+
entry.author = card;
|
|
145
|
+
cardStack.push(card);
|
|
146
|
+
el.onEndTag(() => {
|
|
147
|
+
cardStack.pop();
|
|
148
|
+
});
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const prop = propertyClass(classList);
|
|
152
|
+
if (prop === null)
|
|
153
|
+
return;
|
|
154
|
+
const target = top(cardStack) ?? top(entryStack);
|
|
155
|
+
if (target === undefined)
|
|
156
|
+
return;
|
|
157
|
+
const frame = {
|
|
158
|
+
name: prop.name,
|
|
159
|
+
format: prop.format,
|
|
160
|
+
target,
|
|
161
|
+
buf: "",
|
|
162
|
+
};
|
|
163
|
+
// u-* and dt-* take their value from an attribute when present; that value
|
|
164
|
+
// is committed immediately, so no text capture (or end tag) is needed.
|
|
165
|
+
if (prop.format === "u") {
|
|
166
|
+
const attr = el.getAttribute("href") ??
|
|
167
|
+
el.getAttribute("src") ??
|
|
168
|
+
el.getAttribute("data") ??
|
|
169
|
+
el.getAttribute("poster");
|
|
170
|
+
if (attr !== null) {
|
|
171
|
+
assignProperty(frame, attr);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (prop.format === "dt") {
|
|
176
|
+
const attr = el.getAttribute("datetime") ?? el.getAttribute("value");
|
|
177
|
+
if (attr !== null) {
|
|
178
|
+
assignProperty(frame, attr);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Text-valued property: a void element has no text to capture.
|
|
183
|
+
if (isVoid)
|
|
184
|
+
return;
|
|
185
|
+
propStack.push(frame);
|
|
186
|
+
el.onEndTag(() => {
|
|
187
|
+
const finished = propStack.pop();
|
|
188
|
+
if (finished)
|
|
189
|
+
assignProperty(finished, finished.buf.trim());
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
text(chunk) {
|
|
193
|
+
const frame = top(propStack);
|
|
194
|
+
if (frame)
|
|
195
|
+
frame.buf += chunk.text;
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
await rewriter.transform(new Response(html)).text();
|
|
199
|
+
return entries;
|
|
200
|
+
}
|
|
201
|
+
/** Write a resolved property value onto its target entry or card. */
|
|
202
|
+
function assignProperty(frame, value) {
|
|
203
|
+
if (value === "")
|
|
204
|
+
return;
|
|
205
|
+
const target = frame.target;
|
|
206
|
+
// Card target (author).
|
|
207
|
+
if (isCard(target)) {
|
|
208
|
+
if (frame.name === "name" && target.name === undefined)
|
|
209
|
+
target.name = value;
|
|
210
|
+
else if (frame.name === "url" && target.url === undefined)
|
|
211
|
+
target.url = value;
|
|
212
|
+
else if (frame.name === "photo" && target.photo === undefined)
|
|
213
|
+
target.photo = value;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Entry target.
|
|
217
|
+
switch (frame.name) {
|
|
218
|
+
case "url":
|
|
219
|
+
target.url ??= value;
|
|
220
|
+
break;
|
|
221
|
+
case "name":
|
|
222
|
+
target.name ??= value;
|
|
223
|
+
break;
|
|
224
|
+
case "content":
|
|
225
|
+
target.content ??= value;
|
|
226
|
+
break;
|
|
227
|
+
case "summary":
|
|
228
|
+
target.content ??= value;
|
|
229
|
+
break;
|
|
230
|
+
case "published":
|
|
231
|
+
target.published ??= value;
|
|
232
|
+
break;
|
|
233
|
+
case "photo":
|
|
234
|
+
target.photo.push(value);
|
|
235
|
+
break;
|
|
236
|
+
case "category":
|
|
237
|
+
target.category.push(value);
|
|
238
|
+
break;
|
|
239
|
+
case "in-reply-to":
|
|
240
|
+
target.inReplyTo ??= value;
|
|
241
|
+
break;
|
|
242
|
+
case "like-of":
|
|
243
|
+
target.likeOf ??= value;
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function isCard(target) {
|
|
250
|
+
return !("photo" in target && Array.isArray(target.photo));
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=hfeed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hfeed.js","sourceRoot":"","sources":["../src/hfeed.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dwk/microsub` — a [Microsub](https://indieweb.org/Microsub-spec) server: the
|
|
3
|
+
* IndieWeb **read side**.
|
|
4
|
+
*
|
|
5
|
+
* Endpoint package: exports a factory returning a `fetch`-compatible handler,
|
|
6
|
+
* mountable under a path prefix so it composes with other `@dwk` packages in one
|
|
7
|
+
* Worker. It manages feed **subscriptions** organised into **channels**, polls
|
|
8
|
+
* and parses sources server-side (Atom / RSS / JSON Feed / `h-feed`), and serves
|
|
9
|
+
* a normalised **JF2** timeline to reader clients (Monocle, Together,
|
|
10
|
+
* Indigenous) — keeping the user's reading state on infrastructure they own.
|
|
11
|
+
*
|
|
12
|
+
* It consumes the DPoP-bound IndieAuth access tokens issued by `@dwk/indieauth`
|
|
13
|
+
* (same authorization as `@dwk/micropub`), so a token minted for a different
|
|
14
|
+
* `me` cannot read here. Subscriptions, timeline, and read-state live in D1 — a
|
|
15
|
+
* strongly-consistent store, never KV. Polling runs off the read path on a
|
|
16
|
+
* Cron-triggered queue; every outbound fetch is SSRF-guarded.
|
|
17
|
+
*
|
|
18
|
+
* @see spec/packages/microsub.md
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
export { createMicrosub } from "./handler";
|
|
22
|
+
export type { MicrosubHandler } from "./handler";
|
|
23
|
+
export { createMicrosubPoller } from "./poll";
|
|
24
|
+
export type { MicrosubScheduledHandler } from "./poll";
|
|
25
|
+
export { createMicrosubQueueConsumer } from "./consumer";
|
|
26
|
+
export type { MicrosubQueueConsumer, ConsumerOptions } from "./consumer";
|
|
27
|
+
export { resolveConfig } from "./config";
|
|
28
|
+
export type { MicrosubConfig, MicrosubEnv, ResolvedConfig } from "./config";
|
|
29
|
+
export { createMicrosubStore, NOTIFICATIONS_CHANNEL, type MicrosubStore, type MicrosubStoreEnv, type ChannelRecord, type FollowRecord, type StoredItem, type ItemPage, type ListOptions, type FeedCache, } from "./store";
|
|
30
|
+
export { authorize, tokenFromHeader, hasScope, type AuthEnv, type AuthResult, type AuthSuccess, type AuthFailure, } from "./auth";
|
|
31
|
+
export { parseFeed, type Jf2Entry, type Jf2Author, type Jf2Content, } from "./jf2";
|
|
32
|
+
export { parseHFeed } from "./hfeed";
|
|
33
|
+
export { discoverFeed, fetchFeed, type DiscoveredFeed, type FetchedFeed, type DiscoveryOptions, } from "./discovery";
|
|
34
|
+
export { safeFetch, assertPublicUrl, isPrivateOrReservedHost, SsrfError, type SsrfReason, } from "./safe-fetch";
|
|
35
|
+
export type { FetchLike } from "./fetch";
|
|
36
|
+
export type { MicrosubJob, PollJob } from "./queue";
|
|
37
|
+
export { MicrosubLogEvent } from "./log";
|
|
38
|
+
export type { Logger, Metrics } from "@dwk/log";
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,wBAAwB,EAAE,MAAM,QAAQ,CAAC;AAEvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE5E,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,SAAS,EACT,eAAe,EACf,QAAQ,EACR,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,SAAS,EACT,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EACL,YAAY,EACZ,SAAS,EACT,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,SAAS,EACT,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dwk/microsub` — a [Microsub](https://indieweb.org/Microsub-spec) server: the
|
|
3
|
+
* IndieWeb **read side**.
|
|
4
|
+
*
|
|
5
|
+
* Endpoint package: exports a factory returning a `fetch`-compatible handler,
|
|
6
|
+
* mountable under a path prefix so it composes with other `@dwk` packages in one
|
|
7
|
+
* Worker. It manages feed **subscriptions** organised into **channels**, polls
|
|
8
|
+
* and parses sources server-side (Atom / RSS / JSON Feed / `h-feed`), and serves
|
|
9
|
+
* a normalised **JF2** timeline to reader clients (Monocle, Together,
|
|
10
|
+
* Indigenous) — keeping the user's reading state on infrastructure they own.
|
|
11
|
+
*
|
|
12
|
+
* It consumes the DPoP-bound IndieAuth access tokens issued by `@dwk/indieauth`
|
|
13
|
+
* (same authorization as `@dwk/micropub`), so a token minted for a different
|
|
14
|
+
* `me` cannot read here. Subscriptions, timeline, and read-state live in D1 — a
|
|
15
|
+
* strongly-consistent store, never KV. Polling runs off the read path on a
|
|
16
|
+
* Cron-triggered queue; every outbound fetch is SSRF-guarded.
|
|
17
|
+
*
|
|
18
|
+
* @see spec/packages/microsub.md
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
export { createMicrosub } from "./handler";
|
|
22
|
+
export { createMicrosubPoller } from "./poll";
|
|
23
|
+
export { createMicrosubQueueConsumer } from "./consumer";
|
|
24
|
+
export { resolveConfig } from "./config";
|
|
25
|
+
export { createMicrosubStore, NOTIFICATIONS_CHANNEL, } from "./store";
|
|
26
|
+
export { authorize, tokenFromHeader, hasScope, } from "./auth";
|
|
27
|
+
export { parseFeed, } from "./jf2";
|
|
28
|
+
export { parseHFeed } from "./hfeed";
|
|
29
|
+
export { discoverFeed, fetchFeed, } from "./discovery";
|
|
30
|
+
export { safeFetch, assertPublicUrl, isPrivateOrReservedHost, SsrfError, } from "./safe-fetch";
|
|
31
|
+
export { MicrosubLogEvent } from "./log";
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAG9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAGzD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GAStB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,SAAS,EACT,eAAe,EACf,QAAQ,GAKT,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,SAAS,GAIV,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EACL,YAAY,EACZ,SAAS,GAIV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,SAAS,GAEV,MAAM,cAAc,CAAC;AAKtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC"}
|
package/dist/jf2.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dwk/microsub` — feed → JF2 normalisation.
|
|
3
|
+
*
|
|
4
|
+
* Microsub serves a single normalised timeline regardless of a source's wire
|
|
5
|
+
* format. This module turns the four feed formats a reader meets — JSON Feed,
|
|
6
|
+
* Atom, RSS 2.0, and `h-feed` microformats (the last parsed upstream in
|
|
7
|
+
* {@link ./hfeed}) — into [JF2](https://jf2.spec.indieweb.org/) `entry` objects.
|
|
8
|
+
*
|
|
9
|
+
* Everything here is **pure**: a feed body (and the format-sniffing on its
|
|
10
|
+
* content type) in, an array of JF2 entries out, each carrying a stable `_id`
|
|
11
|
+
* derived from the source's own identifier so the store can dedupe across polls.
|
|
12
|
+
* The XML formats go through the dependency-free reader in {@link ./xml}.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
/** A JF2 author card. */
|
|
17
|
+
export interface Jf2Author {
|
|
18
|
+
readonly type: "card";
|
|
19
|
+
readonly name?: string;
|
|
20
|
+
readonly url?: string;
|
|
21
|
+
readonly photo?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Structured JF2 content (`html` and/or its plain-text rendering). */
|
|
24
|
+
export interface Jf2Content {
|
|
25
|
+
readonly html?: string;
|
|
26
|
+
readonly text?: string;
|
|
27
|
+
}
|
|
28
|
+
/** A normalised JF2 timeline entry. */
|
|
29
|
+
export interface Jf2Entry {
|
|
30
|
+
readonly type: "entry";
|
|
31
|
+
/**
|
|
32
|
+
* Stable per-entry identifier, derived from the source's own id/guid/url. The
|
|
33
|
+
* store keys timeline rows on this so re-polling a feed does not duplicate
|
|
34
|
+
* entries.
|
|
35
|
+
*/
|
|
36
|
+
readonly _id: string;
|
|
37
|
+
readonly url?: string;
|
|
38
|
+
readonly published?: string;
|
|
39
|
+
readonly name?: string;
|
|
40
|
+
readonly summary?: string;
|
|
41
|
+
readonly content?: Jf2Content;
|
|
42
|
+
readonly author?: Jf2Author;
|
|
43
|
+
readonly category?: readonly string[];
|
|
44
|
+
readonly photo?: readonly string[];
|
|
45
|
+
readonly "in-reply-to"?: string;
|
|
46
|
+
readonly "like-of"?: string;
|
|
47
|
+
/** Read flag, attached by the store on read (never by the parser). */
|
|
48
|
+
readonly _is_read?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Order a feed's entries oldest-first for insertion, so the newest entry is
|
|
52
|
+
* appended last and receives the highest paging `seq`.
|
|
53
|
+
*
|
|
54
|
+
* When the entries carry dates they are sorted chronologically (a feed's own
|
|
55
|
+
* order is not trusted). When none do — some `h-feed` pages — the feed is
|
|
56
|
+
* assumed newest-first and simply reversed. The sort is stable, so undated
|
|
57
|
+
* entries keep their relative position among dated ones.
|
|
58
|
+
*/
|
|
59
|
+
export declare function orderEntriesForInsert(entries: readonly Jf2Entry[]): Jf2Entry[];
|
|
60
|
+
/**
|
|
61
|
+
* Parse a fetched feed body into JF2 entries, sniffing the format from the
|
|
62
|
+
* content type and the document root. Returns `[]` for an unrecognised or
|
|
63
|
+
* unparseable body (the caller treats an empty parse as "nothing new").
|
|
64
|
+
*
|
|
65
|
+
* `h-feed` HTML is **not** handled here — it needs the runtime's `HTMLRewriter`
|
|
66
|
+
* and lives in {@link ./hfeed}; this module is pure and runtime-free.
|
|
67
|
+
*/
|
|
68
|
+
export declare function parseFeed(body: string, contentType: string, baseUrl: string): Jf2Entry[];
|
|
69
|
+
//# sourceMappingURL=jf2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jf2.d.ts","sourceRoot":"","sources":["../src/jf2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,yBAAyB;AACzB,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uCAAuC;AACvC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAgRD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,QAAQ,EAAE,GAC3B,QAAQ,EAAE,CAYZ;AAcD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,QAAQ,EAAE,CAYZ"}
|