@buildinternet/uploads 0.8.0 → 0.10.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/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type UploadsErrorCode = "MISSING_TOKEN" | "NO_PUBLIC_URL" | "FILE_NOT_FOUND" | "NOT_FOUND" | "UNAUTHORIZED" | "INVALID_KEY" | "KEY_POLICY" | "STORAGE_QUOTA" | "UPLOAD_BUDGET" | "API_ERROR" | "NETWORK" | "USAGE";
1
+ export type UploadsErrorCode = "MISSING_TOKEN" | "NO_PUBLIC_URL" | "FILE_NOT_FOUND" | "NOT_FOUND" | "UNAUTHORIZED" | "INVALID_KEY" | "KEY_POLICY" | "STORAGE_QUOTA" | "UPLOAD_BUDGET" | "GITHUB_REQUIRED" | "API_ERROR" | "NETWORK" | "USAGE";
2
2
  export declare class UploadsError extends Error {
3
3
  readonly code: UploadsErrorCode;
4
4
  readonly status?: number;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Human-readable size for CLI notes (1024-based).
3
+ * files-sdk has no size formatter — only raw `size` on head/upload results.
4
+ */
5
+ export declare function formatByteSize(bytes: number): string;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Human-readable size for CLI notes (1024-based).
3
+ * files-sdk has no size formatter — only raw `size` on head/upload results.
4
+ */
5
+ export function formatByteSize(bytes) {
6
+ if (!Number.isFinite(bytes) || bytes <= 0)
7
+ return "0 B";
8
+ const units = ["B", "KB", "MB", "GB", "TB"];
9
+ const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
10
+ return `${(bytes / 1024 ** exponent).toFixed(exponent === 0 ? 0 : 1)} ${units[exponent]}`;
11
+ }
@@ -9,6 +9,13 @@ export declare const execRunner: CommandRunner;
9
9
  export declare function resolveRepo(explicit: string | undefined, run?: CommandRunner): string;
10
10
  /** Resolve the pull request associated with the current branch. */
11
11
  export declare function resolveCurrentPullRequest(repo: string, run?: CommandRunner): GhTarget;
12
+ /**
13
+ * Classify a bare PR/issue number via the GitHub API so the default `put`
14
+ * path can stamp the right `gh.kind`. Returns undefined on any failure (gh
15
+ * missing, 404, network) — the caller treats that as "no gh context" and
16
+ * uploads without metadata.
17
+ */
18
+ export declare function classifyGhNumber(repo: string, num: number, run?: CommandRunner): GhTarget | undefined;
12
19
  /**
13
20
  * Create the managed attachments comment, or edit it in place if it already
14
21
  * exists. Never touches any other comment. Body is passed via stdin
package/dist/github-gh.js CHANGED
@@ -61,6 +61,30 @@ export function resolveCurrentPullRequest(repo, run = execRunner) {
61
61
  }
62
62
  throw new UsageError("could not infer a pull request for the current branch — pass --pr <num> or --issue <num>");
63
63
  }
64
+ /**
65
+ * Classify a bare PR/issue number via the GitHub API so the default `put`
66
+ * path can stamp the right `gh.kind`. Returns undefined on any failure (gh
67
+ * missing, 404, network) — the caller treats that as "no gh context" and
68
+ * uploads without metadata.
69
+ */
70
+ export function classifyGhNumber(repo, num, run = execRunner) {
71
+ try {
72
+ const out = run("gh", [
73
+ "api",
74
+ `repos/${repo}/issues/${num}`,
75
+ "--jq",
76
+ 'if .pull_request then "pull" else "issue" end',
77
+ ]).trim();
78
+ if (out === "pull")
79
+ return { repo, kind: "pull", num };
80
+ if (out === "issue")
81
+ return { repo, kind: "issues", num };
82
+ }
83
+ catch {
84
+ // gh missing / not found / network — caller skips
85
+ }
86
+ return undefined;
87
+ }
64
88
  /**
65
89
  * PR comments live on the issues endpoint, so one path covers PRs and issues.
66
90
  * Only the first 100 comments are searched (accepted v1 limitation).
@@ -23,6 +23,16 @@ export declare function parseSemver(version: string): [number, number, number] |
23
23
  export declare function isNewerVersion(latest: string, current: string): boolean;
24
24
  export declare function readUpdateCache(path: string): UpdateCache | undefined;
25
25
  export declare function writeUpdateCache(path: string, cache: UpdateCache): void;
26
+ export interface UpdateStatus {
27
+ current: string;
28
+ latest?: string;
29
+ updateAvailable: boolean;
30
+ }
31
+ /**
32
+ * Resolve current vs latest published version (cache + optional network).
33
+ * Always resolves; never throws. Does not print.
34
+ */
35
+ export declare function checkForUpdate(opts?: UpdateCheckOptions): Promise<UpdateStatus>;
26
36
  /**
27
37
  * If a newer published version is known (or can be fetched within the timeout),
28
38
  * write a one-line stderr hint. Always resolves; never throws.
@@ -69,20 +69,21 @@ export function writeUpdateCache(path, cache) {
69
69
  }
70
70
  }
71
71
  /**
72
- * If a newer published version is known (or can be fetched within the timeout),
73
- * write a one-line stderr hint. Always resolves; never throws.
72
+ * Resolve current vs latest published version (cache + optional network).
73
+ * Always resolves; never throws. Does not print.
74
74
  */
75
- export async function maybeHintUpdate(opts = {}) {
75
+ export async function checkForUpdate(opts = {}) {
76
+ const current = opts.currentVersion ?? packageVersion();
76
77
  try {
77
- if (opts.quiet || opts.command === "mcp")
78
- return;
79
- if (truthyEnv("UPLOADS_NO_UPDATE") || truthyEnv("NO_UPDATE_NOTIFIER"))
80
- return;
81
- const current = opts.currentVersion ?? packageVersion();
78
+ if (opts.quiet || opts.command === "mcp") {
79
+ return { current, updateAvailable: false };
80
+ }
81
+ if (truthyEnv("UPLOADS_NO_UPDATE") || truthyEnv("NO_UPDATE_NOTIFIER")) {
82
+ return { current, updateAvailable: false };
83
+ }
82
84
  const cachePath = opts.cachePath ?? defaultCachePath();
83
85
  const now = opts.now ?? Date.now();
84
86
  const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
85
- const write = opts.write ?? ((text) => process.stderr.write(text));
86
87
  const cached = readUpdateCache(cachePath);
87
88
  let latest;
88
89
  if (cached && now - cached.checkedAt < ttlMs && cached.current === current) {
@@ -98,9 +99,24 @@ export async function maybeHintUpdate(opts = {}) {
98
99
  latest = cached.latest; // stale cache if network failed
99
100
  }
100
101
  }
101
- if (latest && isNewerVersion(latest, current)) {
102
- write(`hint: ${PACKAGE_NAME}@${latest} is available (you have ${current}). Update: npm i -g ${PACKAGE_NAME}\n`);
103
- }
102
+ const updateAvailable = Boolean(latest && isNewerVersion(latest, current));
103
+ return { current, latest, updateAvailable };
104
+ }
105
+ catch {
106
+ return { current, updateAvailable: false };
107
+ }
108
+ }
109
+ /**
110
+ * If a newer published version is known (or can be fetched within the timeout),
111
+ * write a one-line stderr hint. Always resolves; never throws.
112
+ */
113
+ export async function maybeHintUpdate(opts = {}) {
114
+ try {
115
+ const status = await checkForUpdate(opts);
116
+ if (!status.updateAvailable || !status.latest)
117
+ return;
118
+ const write = opts.write ?? ((text) => process.stderr.write(text));
119
+ write(`hint: ${PACKAGE_NAME}@${status.latest} is available (you have ${status.current}). Update: npm i -g ${PACKAGE_NAME}\n`);
104
120
  }
105
121
  catch {
106
122
  // Never surface update-check failures.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildinternet/uploads",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "CLI and client for uploads.sh — workspace-scoped image hosting for GitHub embeds",
5
5
  "type": "module",
6
6
  "sideEffects": false,