@postfetch/core 0.13.3 → 0.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -409,13 +409,13 @@ async function instagramUnavailable(net, code, pageReason) {
409
409
  url.searchParams.set("url", `https://www.instagram.com/p/${code}/`);
410
410
  const response = await net(url.href, { headers: mobileHeaders() }, 1).catch(() => null);
411
411
  const body = response ? await response.text().catch(() => "") : "";
412
- const reason = pageReason ?? instagramUnavailableReason(response?.status ?? 0, body);
412
+ const reason = pageReason ?? instagramUnavailableReason(response?.status ?? 0, body, code);
413
413
  const probe = response ? `oembed ${response.status}` : "oembed unreachable";
414
414
  return new PostfetchError(reasonStatus(reason), `Instagram post unavailable: ${reason} (${probe})`, reason);
415
415
  }
416
- function instagramUnavailableReason(status, body) {
416
+ function instagramUnavailableReason(status, body, code) {
417
417
  if (status === 404) {
418
- return "notFound";
418
+ return code && isPrivateShortcode(code) ? "private" : "notFound";
419
419
  }
420
420
  if (status === 429) {
421
421
  return "rateLimited";
@@ -434,6 +434,9 @@ function instagramUnavailableReason(status, body) {
434
434
  }
435
435
  return "unavailable";
436
436
  }
437
+ function isPrivateShortcode(code) {
438
+ return code.length > 11;
439
+ }
437
440
  function reasonStatus(reason) {
438
441
  switch (reason) {
439
442
  case "ageRestricted":
@@ -1,6 +1,6 @@
1
1
  import { type InstagramExtra, type PostMetadata, type PostfetchReason, type ResolveContext, type Json, type PostfetchResult } from "./internal";
2
2
  export declare function resolveInstagram(input: ResolveContext): Promise<PostfetchResult>;
3
- export declare function instagramUnavailableReason(status: number, body: string): PostfetchReason;
3
+ export declare function instagramUnavailableReason(status: number, body: string, code?: string): PostfetchReason;
4
4
  export declare function instagramMetadata(media: Json): PostMetadata & {
5
5
  extra?: InstagramExtra;
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postfetch/core",
3
- "version": "0.13.3",
3
+ "version": "0.13.4",
4
4
  "description": "Zero-dependency typed core that turns Facebook, Instagram, LinkedIn, Pinterest, Reddit, SoundCloud, Spotify, TikTok, X and YouTube post URLs into media files.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/instagram.ts CHANGED
@@ -91,7 +91,7 @@ async function instagramUnavailable(net: Net, code: string, pageReason?: Postfet
91
91
  const body = response ? await response.text().catch(() => "") : "";
92
92
  // The page can identify an age gate even when oembed only reports a generic
93
93
  // geoblock_required error with no MIN_AGE_ACCOUNT marker.
94
- const reason = pageReason ?? instagramUnavailableReason(response?.status ?? 0, body);
94
+ const reason = pageReason ?? instagramUnavailableReason(response?.status ?? 0, body, code);
95
95
  // Carry the oembed status so an unclassified failure still leaves a raw clue
96
96
  // (200 = post is public but no media could be parsed; 429 = throttled; …).
97
97
  const probe = response ? `oembed ${response.status}` : "oembed unreachable";
@@ -101,10 +101,11 @@ async function instagramUnavailable(net: Net, code: string, pageReason?: Postfet
101
101
  // Classifies why the post is gone from the oembed endpoint, which returns a
102
102
  // telling status and body (404 when removed; 429 when throttled; 400 with a
103
103
  // MIN_AGE_ACCOUNT block for 18+ accounts) while the media endpoints just come
104
- // back empty.
105
- export function instagramUnavailableReason(status: number, body: string): PostfetchReason {
104
+ // back empty. Share links to posts from private accounts carry a long
105
+ // shortcode, and oembed answers those with the same 404 as a removed post.
106
+ export function instagramUnavailableReason(status: number, body: string, code?: string): PostfetchReason {
106
107
  if (status === 404) {
107
- return "notFound";
108
+ return code && isPrivateShortcode(code) ? "private" : "notFound";
108
109
  }
109
110
  if (status === 429) {
110
111
  return "rateLimited";
@@ -124,6 +125,12 @@ export function instagramUnavailableReason(status: number, body: string): Postfe
124
125
  return "unavailable";
125
126
  }
126
127
 
128
+ // Public shortcodes are at most 11 characters; private share links append an
129
+ // owner-scoped suffix (for example 39 characters in total).
130
+ function isPrivateShortcode(code: string): boolean {
131
+ return code.length > 11;
132
+ }
133
+
127
134
  function reasonStatus(reason: PostfetchReason): number {
128
135
  switch (reason) {
129
136
  case "ageRestricted":