@sockethub/platform-metadata 1.0.1-beta.0 → 1.0.1-beta.2

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 CHANGED
@@ -67,7 +67,15 @@ The platform returns an ActivityStream object with extracted metadata:
67
67
  ],
68
68
  "url": "https://example.com/canonical-url",
69
69
  "favicon": "https://example.com/favicon.ico",
70
- "charset": "utf-8"
70
+ "charset": "utf-8",
71
+ "event": {
72
+ "name": "Tech Talks",
73
+ "startDate": "2026-11-09T18:00:00-06:00",
74
+ "endDate": "2026-11-09T20:00:00-06:00",
75
+ "location": "Civic Center, 1218 West Ave, Austin, TX",
76
+ "url": "https://example.com/canonical-url",
77
+ "status": "scheduled"
78
+ }
71
79
  }
72
80
  }
73
81
  ```
@@ -83,6 +91,13 @@ The platform extracts the following metadata when available:
83
91
  * **Canonical URLs**: Resolved and canonical page URLs
84
92
  * **Media**: Images with dimensions and type information; for X/Twitter posts,
85
93
  a `video` object (direct media URL, poster `thumbnail`, dimensions, duration)
94
+ * **Events**: When the page embeds a schema.org `Event` (or subtype) as
95
+ JSON-LD — Luma, Meetup, Eventbrite and most ticketing sites — an `event`
96
+ object carries `name`, `startDate` (ISO 8601 as published, possibly
97
+ date-only), and optionally `endDate`, `location` (place name and address
98
+ flattened to one string, or the virtual location URL), `url`, and `status`
99
+ (`scheduled`, `cancelled`, `postponed`, `rescheduled`). Only present when
100
+ both a name and a start date are declared.
86
101
 
87
102
  ## Site-Specific Handling
88
103
 
@@ -101,8 +116,20 @@ so those URLs are resolved through preview services built for this purpose:
101
116
  self-text, and direct `i.redd.it` image are mapped into the preview; text posts
102
117
  intentionally have no image. oEmbed remains a title-only failure fallback.
103
118
  See `compatUserAgent` below.
104
- * **Facebook** remains best-effort: post text usually comes through, but
105
- media requires authentication and no public preview service exists.
119
+ * **Facebook** remains best-effort: post text usually comes through. The
120
+ video or photo thumbnail is taken from the post's Open Graph image, then
121
+ its Twitter card image, and finally the image rendered by Facebook's public
122
+ embed plugin (`/plugins/video.php` or `/plugins/post.php`), which Facebook
123
+ serves to third parties when it withholds Open Graph media from a
124
+ datacenter address. Full media still requires authentication. Facebook
125
+ publishes no site name, so `actor.name` and `object.name` fall back to
126
+ `Facebook`.
127
+ * **Facebook engagement prefixes**: video titles and image alt text often
128
+ start with a localized view or reaction count, such as
129
+ `2.2M views · 21K reactions | …` or `347K views | …`. When the prefix is
130
+ recognized it is stripped from `object.title` and from each image `alt`. A
131
+ title that merely starts with a small plain number, such as
132
+ `10 Goals | Author`, is kept.
106
133
 
107
134
  ### `userAgent`
108
135
 
@@ -151,9 +178,14 @@ Because the server fetches whatever URL a client supplies as `actor.id`, metadat
151
178
  requests are hardened against server-side request forgery (SSRF) and resource
152
179
  exhaustion. The fetch runs through a guarded connection layer that:
153
180
 
181
+ * rejects URL schemes other than `http` and `https`;
154
182
  * refuses to connect to loopback, private, link-local, carrier-grade NAT, or
155
- cloud-metadata addresses (e.g. `169.254.169.254`), in every IPv4/IPv6 spelling,
156
- validated at connection time so it also covers redirect hops;
183
+ cloud-metadata addresses (e.g. `169.254.169.254`), validated at connection
184
+ time so it also covers redirect hops. IPv4-mapped, IPv4-compatible, and
185
+ well-known NAT64 (`64:ff9b::/96`) embeddings are judged as the embedded IPv4
186
+ address. The local-use NAT64 prefix `64:ff9b:1::/48` is refused entirely.
187
+ The ranges are listed under
188
+ [Outbound URL guard](../../docs/configuration.md#outbound-url-guard);
157
189
  * caps the response body size.
158
190
 
159
191
  ### `allowPrivateAddresses`
@@ -0,0 +1,17 @@
1
+ /** Scheduling facts from a page's schema.org `Event` JSON-LD. */
2
+ export interface PageEvent {
3
+ name: string;
4
+ startDate: string;
5
+ endDate?: string;
6
+ location?: string;
7
+ url?: string;
8
+ status?: "scheduled" | "cancelled" | "postponed" | "rescheduled";
9
+ }
10
+ /**
11
+ * Pick the first schema.org `Event` (or subtype such as `MusicEvent`) out of
12
+ * the page's JSON-LD blocks and reduce it to the scheduling facts a client
13
+ * needs to build a calendar entry. Nodes may be bare objects, arrays, or
14
+ * `@graph` wrappers. Returns undefined when no node carries a name and a
15
+ * start date — a half-filled block is worth nothing to a calendar.
16
+ */
17
+ export declare function schemaOrgEvent(jsonLD: unknown): PageEvent | undefined;
package/dist/index.d.ts CHANGED
@@ -122,6 +122,31 @@ export default class Metadata implements PlatformInterface {
122
122
  charset: {
123
123
  type: string;
124
124
  };
125
+ event: {
126
+ type: string;
127
+ required: string[];
128
+ additionalProperties: boolean;
129
+ properties: {
130
+ name: {
131
+ type: string;
132
+ };
133
+ startDate: {
134
+ type: string;
135
+ };
136
+ endDate: {
137
+ type: string;
138
+ };
139
+ location: {
140
+ type: string;
141
+ };
142
+ url: {
143
+ type: string;
144
+ };
145
+ status: {
146
+ enum: string[];
147
+ };
148
+ };
149
+ };
125
150
  };
126
151
  };
127
152
  ogImage: {
@@ -168,6 +193,12 @@ export default class Metadata implements PlatformInterface {
168
193
  private fetchDirectImage;
169
194
  /** Fetch and validate YouTube's official preview metadata. */
170
195
  private fetchYouTubeEmbed;
196
+ /**
197
+ * Last-resort thumbnail for a Facebook post whose page carried no
198
+ * Open Graph image: the media image rendered by Facebook's public embed
199
+ * plugin, which is served to third parties without a login wall.
200
+ */
201
+ private fetchFacebookEmbedImage;
171
202
  private fetchTweet;
172
203
  private fetchReddit;
173
204
  /**