@hraness/ghostget 0.18.14 → 0.18.16

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.
@@ -238,43 +238,40 @@ export function bindXWebOperationMetadataValues(
238
238
  export const xWebQueryDescriptorEvidenceSnapshot = Object.freeze({
239
239
  schemaVersion: 1,
240
240
  role: "revision-evidence-only" as const,
241
- observedOn: "2026-07-22",
241
+ observedOn: "2026-09-17",
242
242
  currentBundleResolutionRequired: true,
243
- mainBundleUrl: "https://abs.twimg.com/responsive-web/client-web/main.7792f4fa.js",
243
+ mainBundleUrl: "https://abs.twimg.com/responsive-web/client-web/main.52fc4dd0aada586aa.js",
244
244
  descriptors: Object.freeze([
245
- { operationName: "HomeTimeline", operationType: "query", queryId: "wp06oo3fRGU4P1sK8rECqQ", sourceChunk: "shared~bundle.LoggedInMain~bundle.HomeTimeline.c12c8a9a.js", observedOn: "2026-08-20" },
246
- { operationName: "HomeLatestTimeline", operationType: "query", queryId: "BLQWpfVqtgBqAqwRRJcJjA", sourceChunk: "shared~bundle.LoggedInMain~bundle.HomeTimeline.c12c8a9a.js", observedOn: "2026-08-20" },
247
- { operationName: "ListLatestTweetsTimeline", operationType: "query", queryId: "LV64djPRhnsVhGCK76s13w", sourceChunk: "shared~loader.Dock~bundle.BookmarkFolders~bundle.Bookmarks~bundle.Explore~bundle.HomeTimeline~bundle.Notifica.3b894e0a.js" },
248
- { operationName: "ListRankedTweetsTimeline", operationType: "query", queryId: "dPN7GrkxeMF4SUYCo9D9YA", sourceChunk: "shared~loader.Dock~bundle.BookmarkFolders~bundle.Bookmarks~bundle.Explore~bundle.HomeTimeline~bundle.Notifica.3b894e0a.js" },
249
- { operationName: "Bookmarks", operationType: "query", queryId: "tF6KOjmZM0WGcB2Q0mfwhw", sourceChunk: "shared~bundle.BookmarkFolders~bundle.Bookmarks.42881d01aa4e5708a.js", observedOn: "2026-09-13" },
250
- { operationName: "BookmarkSearchTimeline", operationType: "query", queryId: "SpDsqmz6FfYESd1e7TPcAw", sourceChunk: "main.9929b02a.js" },
251
- { operationName: "SearchTimeline", operationType: "query", queryId: "hyPfJYJ_XAtDYoslQc-Rgg", sourceChunk: "main.ae82e9d02d3328bba.js", observedOn: "2026-09-06" },
252
- { operationName: "NotificationsTimeline", operationType: "query", queryId: "dDSNxYH-uWwVo2r3Y5VVqg", sourceChunk: "bundle.Notifications.eea6257a.js" },
253
- { operationName: "TweetDetail", operationType: "query", queryId: "rZA6K31W4E90vZKBmxXV3g", sourceChunk: "main.9929b02a.js" },
254
- { operationName: "TweetResultByRestId", operationType: "query", queryId: "4hhGRbehkcUVTKf8n0f0xw", sourceChunk: "main.9929b02a.js" },
255
- { operationName: "TweetResultsByRestIds", operationType: "query", queryId: "aSkhsainBPfEWA4mG8wnFA", sourceChunk: "main.9929b02a.js" },
256
- { operationName: "UserTweets", operationType: "query", queryId: "eviprbEPLvNG88V3smUngQ", sourceChunk: "main.ae82e9d02d3328bba.js", observedOn: "2026-09-06" },
257
- { operationName: "UserTweetsAndReplies", operationType: "query", queryId: "klja8a2iJX_3to5RdfVlgw", sourceChunk: "main.9929b02a.js" },
258
- { operationName: "UserMedia", operationType: "query", queryId: "IS3w9vvPg1SJysLErvnFGg", sourceChunk: "main.9929b02a.js" },
259
- { operationName: "FavoriteTweet", operationType: "mutation", queryId: "lI07N6Otwv1PhnEgXILM7A", sourceChunk: "main.9929b02a.js" },
260
- { operationName: "UnfavoriteTweet", operationType: "mutation", queryId: "ZYKSe-w7KEslx3JhSIk5LA", sourceChunk: "main.9929b02a.js" },
261
- { operationName: "CreateBookmark", operationType: "mutation", queryId: "aoDbu3RHznuiSkQ9aNM67Q", sourceChunk: "main.9929b02a.js" },
262
- { operationName: "DeleteBookmark", operationType: "mutation", queryId: "Wlmlj2-xzyS1GN3a6cj-mQ", sourceChunk: "main.9929b02a.js" },
263
- { operationName: "CreateRetweet", operationType: "mutation", queryId: "mbRO74GrOvSfRcJnlMapnQ", sourceChunk: "main.9929b02a.js" },
264
- { operationName: "DeleteRetweet", operationType: "mutation", queryId: "ZyZigVsNiFO6v1dEks1eWg", sourceChunk: "main.9929b02a.js" },
265
- { operationName: "CreateTweet", operationType: "mutation", queryId: "WXTdKnLddrQOunD6MhWi3g", sourceChunk: "main.7792f4fa.js", observedOn: "2026-08-20" },
266
- { operationName: "CreateNoteTweet", operationType: "mutation", queryId: "uGXMU9aKbNB9qxxAg4jxkA", sourceChunk: "main.9929b02a.js" },
267
- { operationName: "DeleteTweet", operationType: "mutation", queryId: "nxpZCY2K-I6QoFHAHeojFQ", sourceChunk: "main.9929b02a.js" },
268
- { operationName: "DmAllSearchSlice", operationType: "query", queryId: "zd0F6a_svKAXdlMGbCZDFg", sourceChunk: "bundle.DirectMessages.265735ba.js" },
269
- { operationName: "DmGroupSearchSlice", operationType: "query", queryId: "LxrvmqF3Lokl_BYZ1c83LA", sourceChunk: "bundle.DirectMessages.265735ba.js" },
270
- { operationName: "DmPeopleSearchSlice", operationType: "query", queryId: "c1MnRRmI-_Bggpntlq9-hQ", sourceChunk: "bundle.DirectMessages.265735ba.js" },
271
- { operationName: "Viewer", operationType: "query", queryId: "9t128XgFic52jPUEkJMf6w", sourceChunk: "main.59435dbf6f40166da.js", observedOn: "2026-09-13" },
272
- { operationName: "UserByScreenName", operationType: "query", queryId: "Gb-d6r0vxPOADdG62OEBpQ", sourceChunk: "main.dd6a5b6a.js", observedOn: "2026-08-21" },
273
- { operationName: "ArticleEntityDraftCreate", operationType: "mutation", queryId: "btD9FyMDa3_vydVp7fr87Q", sourceChunk: "bundle.TwitterArticles.305538ca.js", observedOn: "2026-08-14" },
274
- { operationName: "ArticleEntityUpdateContent", operationType: "mutation", queryId: "P5Nc3DYs9D4XqVthNrig8w", sourceChunk: "bundle.TwitterArticles.305538ca.js", observedOn: "2026-08-14" },
275
- { operationName: "ArticleEntityUpdateTitle", operationType: "mutation", queryId: "z_xdvTUbZjSVjt232b4D4A", sourceChunk: "bundle.TwitterArticles.305538ca.js", observedOn: "2026-08-14" },
276
- { operationName: "ArticleEntityPublish", operationType: "mutation", queryId: "UyL9qgpV23A8471opeYQbw", sourceChunk: "bundle.TwitterArticles.305538ca.js", observedOn: "2026-08-14" },
277
- { operationName: "ArticleEntityResultByRestId", operationType: "query", queryId: "rPdndX2XxQoXIMUafLSSJQ", sourceChunk: "bundle.TwitterArticles.305538ca.js", observedOn: "2026-08-14" },
245
+ { operationName: "HomeTimeline", operationType: "query", queryId: "og4a4SdSF3WiQkkwaPCdPg", sourceChunk: "shared~bundle.LoggedInMain~bundle.HomeTimeline~bundle.Compose.d2799da549fa4165a.js", observedOn: "2026-09-17" },
246
+ { operationName: "HomeLatestTimeline", operationType: "query", queryId: "OQPHTgwczzp9RMAPt6BH9A", sourceChunk: "shared~bundle.LoggedInMain~bundle.HomeTimeline~bundle.Compose.d2799da549fa4165a.js", observedOn: "2026-09-17" },
247
+ { operationName: "ListLatestTweetsTimeline", operationType: "query", queryId: "qIrerw_1oakhehcLoFbaOw", sourceChunk: "shared~loader.Dock~bundle.BookmarkFolders~bundle.Bookmarks~bundle.Explore~bundle.HomeTimeline~bundle.Notifica.bd9965b893a1c830a.js", observedOn: "2026-09-17" },
248
+ { operationName: "ListRankedTweetsTimeline", operationType: "query", queryId: "K3JUG9l3MeWDoLKeFYex9g", sourceChunk: "shared~loader.Dock~bundle.BookmarkFolders~bundle.Bookmarks~bundle.Explore~bundle.HomeTimeline~bundle.Notifica.bd9965b893a1c830a.js", observedOn: "2026-09-17" },
249
+ { operationName: "Bookmarks", operationType: "query", queryId: "-dgKZ58Dr9YSJYrcgEb5KA", sourceChunk: "shared~bundle.BookmarkFolders~bundle.Bookmarks.12cb1875a99ef5b3a.js", observedOn: "2026-09-17" },
250
+ { operationName: "BookmarkSearchTimeline", operationType: "query", queryId: "rbwiGBFqb93lmG7mw_OYZQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
251
+ { operationName: "SearchTimeline", operationType: "query", queryId: "auLkqtmHqYEpRvflfvLhyQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
252
+ { operationName: "NotificationsTimeline", operationType: "query", queryId: "MSUPE4KwuxyghDO60Bv5uQ", sourceChunk: "bundle.Notifications.62eab6a0a03e5036a.js", observedOn: "2026-09-17" },
253
+ { operationName: "TweetDetail", operationType: "query", queryId: "zoF7_t363wZyzylk-BLfZQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
254
+ { operationName: "TweetResultByRestId", operationType: "query", queryId: "Xl0tsHf4AzflMRjbw9e70A", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
255
+ { operationName: "TweetResultsByRestIds", operationType: "query", queryId: "mQnBPxNdkMLfhXINDDYUSg", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
256
+ { operationName: "UserTweets", operationType: "query", queryId: "jeAA-59Y9FL7FmjgBNIVPw", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
257
+ { operationName: "UserTweetsAndReplies", operationType: "query", queryId: "wI-ubAWfScnG6odLK4XgCg", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
258
+ { operationName: "UserMedia", operationType: "query", queryId: "TwLiEVUhRjjjKVc98IT0TQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
259
+ { operationName: "FavoriteTweet", operationType: "mutation", queryId: "lI07N6Otwv1PhnEgXILM7A", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
260
+ { operationName: "UnfavoriteTweet", operationType: "mutation", queryId: "ZYKSe-w7KEslx3JhSIk5LA", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
261
+ { operationName: "CreateBookmark", operationType: "mutation", queryId: "aoDbu3RHznuiSkQ9aNM67Q", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
262
+ { operationName: "DeleteBookmark", operationType: "mutation", queryId: "Wlmlj2-xzyS1GN3a6cj-mQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
263
+ { operationName: "CreateRetweet", operationType: "mutation", queryId: "mbRO74GrOvSfRcJnlMapnQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
264
+ { operationName: "DeleteRetweet", operationType: "mutation", queryId: "ZyZigVsNiFO6v1dEks1eWg", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
265
+ { operationName: "CreateTweet", operationType: "mutation", queryId: "GYdIGqVWfZNho79bQ2XDoA", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
266
+ { operationName: "CreateNoteTweet", operationType: "mutation", queryId: "u-Vsy3HZId2j10nbdqMI0A", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
267
+ { operationName: "DeleteTweet", operationType: "mutation", queryId: "nxpZCY2K-I6QoFHAHeojFQ", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
268
+ { operationName: "Viewer", operationType: "query", queryId: "9t128XgFic52jPUEkJMf6w", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
269
+ { operationName: "UserByScreenName", operationType: "query", queryId: "KybxDj9RrADIITXlGG8kpw", sourceChunk: "main.52fc4dd0aada586aa.js", observedOn: "2026-09-17" },
270
+ { operationName: "ArticleEntityDraftCreate", operationType: "mutation", queryId: "_rbmb_NKLqKVBr5X_MSoMQ", sourceChunk: "bundle.TwitterArticles.b3c21fed7d9db030a.js", observedOn: "2026-09-17" },
271
+ { operationName: "ArticleEntityUpdateContent", operationType: "mutation", queryId: "x4Pz2ifYkOD6uSvzxOIUig", sourceChunk: "bundle.TwitterArticles.b3c21fed7d9db030a.js", observedOn: "2026-09-17" },
272
+ { operationName: "ArticleEntityUpdateTitle", operationType: "mutation", queryId: "brHFCBTXXg8WOqc7BnXfAw", sourceChunk: "bundle.TwitterArticles.b3c21fed7d9db030a.js", observedOn: "2026-09-17" },
273
+ { operationName: "ArticleEntityPublish", operationType: "mutation", queryId: "872mse3gUSifcgeJBBl4WA", sourceChunk: "bundle.TwitterArticles.b3c21fed7d9db030a.js", observedOn: "2026-09-17" },
274
+ { operationName: "ArticleEntityResultByRestId", operationType: "query", queryId: "OF2ES8qTOPLFBU_oZWVkQw", sourceChunk: "bundle.TwitterArticles.b3c21fed7d9db030a.js", observedOn: "2026-09-17" },
278
275
  ] satisfies readonly XWebQueryDescriptorEvidence[]),
279
276
  });
280
277
 
@@ -1138,6 +1135,10 @@ export function projectXWebProfileStats(
1138
1135
  observedAt: string,
1139
1136
  ): XWebProfileStats {
1140
1137
  const expectedHandle = normalizeXWebProfileHandle(expectedHandleValue);
1138
+ const profileData = responseData(response, "X profiles.by-handle response");
1139
+ if (profileData.user === undefined || profileData.user === null) {
1140
+ throw new XProfileTargetUnavailableError();
1141
+ }
1141
1142
  const result = record(
1142
1143
  extractXWebGraphQlReadResponseRoot("profiles.by-handle", response),
1143
1144
  "X profile response result",
package/src/storage.ts CHANGED
@@ -10,7 +10,6 @@ import {
10
10
  mkdtempSync,
11
11
  openSync,
12
12
  opendirSync,
13
- readSync,
14
13
  realpathSync,
15
14
  rmSync,
16
15
  writeFileSync,
@@ -18,6 +17,7 @@ import {
18
17
  type Dirent,
19
18
  } from "node:fs";
20
19
  import { spawnSync } from "node:child_process";
20
+ import { readOwnedFileStableSync } from "@hraness/local-custody/private-paths";
21
21
  import { homedir, tmpdir } from "node:os";
22
22
  import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
23
23
  import { fileURLToPath } from "node:url";
@@ -363,20 +363,6 @@ function hasCode(error: unknown, code: string): boolean {
363
363
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
364
364
  }
365
365
 
366
- function readDescriptorBounded(descriptor: number, maximumBytes: number): Buffer {
367
- const chunks: Buffer[] = [];
368
- const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, maximumBytes + 1));
369
- let total = 0;
370
- for (;;) {
371
- const remaining = maximumBytes + 1 - total;
372
- const count = readSync(descriptor, buffer, 0, Math.min(buffer.byteLength, remaining), null);
373
- if (count === 0) return Buffer.concat(chunks, total);
374
- total += count;
375
- if (total > maximumBytes) throw new Error("file grew beyond its byte bound");
376
- chunks.push(Buffer.from(buffer.subarray(0, count)));
377
- }
378
- }
379
-
380
366
  function pathInside(root: string, target: string): boolean {
381
367
  const child = relative(root, target);
382
368
  return child === "" || (!isAbsolute(child) && child !== ".." && !child.startsWith(`..${sep}`));
@@ -1037,18 +1023,17 @@ function ownedByCurrentUser(stats: { readonly uid: number | bigint }): boolean {
1037
1023
  }
1038
1024
 
1039
1025
  function readStateMarker(path: string): void {
1040
- const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
1041
- const nonBlocking = "O_NONBLOCK" in constants ? constants.O_NONBLOCK : 0;
1042
- const descriptor = openSync(path, constants.O_RDONLY | noFollow | nonBlocking);
1026
+ let bytes: Buffer;
1043
1027
  try {
1044
- const stats = fstatSync(descriptor);
1045
- if (!stats.isFile() || stats.size > 256 || !ownedByCurrentUser(stats) || (stats.mode & 0o077) !== 0) {
1046
- throw new Error("ghostget state marker must be a private, owned regular file");
1047
- }
1028
+ bytes = readOwnedFileStableSync(path, 256).bytes;
1029
+ } catch (error) {
1030
+ throw new Error("ghostget state marker must be a private, owned regular file", { cause: error });
1031
+ }
1032
+ {
1048
1033
  const content = new TextDecoder("utf-8", {
1049
1034
  fatal: true,
1050
1035
  ignoreBOM: true,
1051
- }).decode(readDescriptorBounded(descriptor, 256));
1036
+ }).decode(bytes);
1052
1037
  if (content !== stateMarkerText) throw new Error("ghostget state marker is malformed");
1053
1038
  const value = JSON.parse(content) as unknown;
1054
1039
  if (
@@ -1061,8 +1046,6 @@ function readStateMarker(path: string): void {
1061
1046
  || !("kind" in value)
1062
1047
  || value.kind !== "io-state"
1063
1048
  ) throw new Error("ghostget state marker is malformed");
1064
- } finally {
1065
- closeSync(descriptor);
1066
1049
  }
1067
1050
  }
1068
1051
 
package/src/usage.ts CHANGED
@@ -6,6 +6,8 @@
6
6
  * optional provider runtime is broken.
7
7
  */
8
8
  export const ghostgetUsage = `Usage:
9
+ ghostget login [--json] Sign in to Hraness Accounts
10
+ ghostget logout [--json] Sign out of Hraness Accounts
9
11
  ghostget --version Print the exact Ghostget release version
10
12
  ghostget support [--json] View optional product updates and support
11
13
  ghostget support protocol --json Read the optional agent closeout protocol
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Canonical immutable Ghostget package release identity. */
2
- export const GHOSTGET_VERSION = "0.18.14" as const;
2
+ export const GHOSTGET_VERSION = "0.18.16" as const;