@buildinternet/uploads 0.37.2 → 0.38.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/commands/screenshot.js +24 -3
- package/dist/commands.d.ts +1 -0
- package/dist/commands.js +6 -4
- package/dist/config-file.d.ts +3 -1
- package/dist/embed.d.ts +10 -0
- package/dist/embed.js +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp/args.d.ts +1 -1
- package/dist/mcp/tools.js +4 -0
- package/dist/metadata-vocab.d.ts +2 -0
- package/dist/metadata-vocab.js +4 -0
- package/dist/screenshot.d.ts +28 -0
- package/dist/screenshot.js +31 -1
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { basename } from "node:path";
|
|
3
3
|
import { extractDashValue, flagBool, flagInt, flagString, flagValues, parseCommandArgs, UsageError, } from "../cli-args.js";
|
|
4
4
|
import { writeCommandHelp } from "../cli-style.js";
|
|
5
|
-
import { branchFromFlags, derivedMetaEnabled, frameOptionsFromFlags, ghTargetFromFlags, optimizeOptionsFromFlags, stateAppMetaFromFlags, warnNearMissMeta, syncAttachmentsComment, commentViaSuffix, uploadPreparedImage, resolvePutStagingTarget, putStagingNoteText, resolveStageBindingWarning, mergeStagingMeta, } from "../commands.js";
|
|
5
|
+
import { branchFromFlags, derivedMetaEnabled, frameOptionsFromFlags, ghTargetFromFlags, optimizeOptionsFromFlags, stateAppMetaFromFlags, warnNearMissMeta, syncAttachmentsComment, commentViaSuffix, uploadPreparedImage, resolvePutStagingTarget, putStagingNoteText, resolveStageBindingWarning, mergeStagingMeta, writeReplacedNote, } from "../commands.js";
|
|
6
6
|
import { resolvePutDefaults } from "../config.js";
|
|
7
7
|
import { loadDefaultsRaw, resolveScreenshotDefaults } from "../config-file.js";
|
|
8
8
|
import { resolvePutPrefix } from "../destinations.js";
|
|
@@ -31,6 +31,15 @@ localhost/private-network URLs are reachable only by the
|
|
|
31
31
|
local backend — with --via remote (or auto falling back to remote) these
|
|
32
32
|
fail fast with a clear error instead of sending a doomed request.
|
|
33
33
|
|
|
34
|
+
The object name is derived from the target URL (host + path), not chosen by
|
|
35
|
+
you — e.g. https://app.example/settings becomes app.example-settings.png.
|
|
36
|
+
--state folds into that derived name (a -before/-after/... suffix), so
|
|
37
|
+
capturing the same URL with --state before then --state after produces two
|
|
38
|
+
distinct objects instead of the second silently overwriting the first.
|
|
39
|
+
Re-capturing the same URL + --state replaces that object in place — the
|
|
40
|
+
intended idempotency for repeat captures. --key bypasses all of this and
|
|
41
|
+
sets the whole object key verbatim (no folding).
|
|
42
|
+
|
|
34
43
|
After capture, screenshots share the put upload pipeline: optional --frame,
|
|
35
44
|
optimize-by-default, --pr/--issue attachment + --comment, --gallery, --meta.
|
|
36
45
|
|
|
@@ -381,6 +390,9 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
|
|
|
381
390
|
reducedMotion,
|
|
382
391
|
evalJs,
|
|
383
392
|
initScript,
|
|
393
|
+
// Skip folding when an explicit --key was given — --key sets the whole
|
|
394
|
+
// key, so there's no auto-derived name to fold state into.
|
|
395
|
+
state: keyHint ? undefined : explicitMeta.state,
|
|
384
396
|
measureSelectors: annotateSelectors.length > 0 ? annotateSelectors : undefined,
|
|
385
397
|
apiUrl: ctx.config.apiUrl,
|
|
386
398
|
token: ctx.config.token,
|
|
@@ -497,6 +509,7 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
|
|
|
497
509
|
if (prepared.optimized) {
|
|
498
510
|
process.stderr.write(`>> optimized ${prepared.originalBytes} → ${prepared.outputBytes} bytes\n`);
|
|
499
511
|
}
|
|
512
|
+
writeReplacedNote(result.replaced, ctx.quiet, dryRun, result.wouldRefuse);
|
|
500
513
|
process.stderr.write(`>> key: ${result.key}${dryRun ? " (dry run — not uploaded)" : ""}\n`);
|
|
501
514
|
if (stagingTarget !== undefined) {
|
|
502
515
|
process.stderr.write(`>> find these later: uploads find gh.branch=${stagingTarget.branch.toLowerCase()}\n`);
|
|
@@ -514,8 +527,16 @@ loadAnnotateModule = () => import("../annotate/index.js")) {
|
|
|
514
527
|
process.stderr.write("\n");
|
|
515
528
|
}
|
|
516
529
|
// One JSON `hint` slot (mirrors bare put): the binding warning is more
|
|
517
|
-
// actionable than the generic staging note, so it wins when both fire
|
|
518
|
-
|
|
530
|
+
// actionable than the generic staging note, so it wins when both fire; a
|
|
531
|
+
// replaced-object note (issue #618) is the lowest priority of the three —
|
|
532
|
+
// it only surfaces when nothing else already claimed the slot. Since state
|
|
533
|
+
// folds into the derived key, replaced + state means a same-side re-capture,
|
|
534
|
+
// which is the intended replace-in-place flow — word it as informational,
|
|
535
|
+
// not as a problem.
|
|
536
|
+
const replacedHint = result.replaced && explicitMeta.state
|
|
537
|
+
? `re-capture replaced the previous state=${explicitMeta.state} object at ${result.key} — expected for repeat captures of the same URL + state`
|
|
538
|
+
: undefined;
|
|
539
|
+
const jsonHint = bindingWarning ?? stagingNote ?? replacedHint;
|
|
519
540
|
switch (format) {
|
|
520
541
|
case "json":
|
|
521
542
|
await writeJson({
|
package/dist/commands.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ export declare function warnNearMissMeta(ctx: CliContext, meta: Record<string, s
|
|
|
63
63
|
* point is `--help` discoverability and `--state` validation.
|
|
64
64
|
*/
|
|
65
65
|
export declare function stateAppMetaFromFlags(flags: CommandFlags["flags"]): Record<string, string>;
|
|
66
|
+
export declare function writeReplacedNote(replaced: boolean | undefined, quiet: boolean, dryRun?: boolean, wouldRefuse?: boolean): void;
|
|
66
67
|
export type PreparedUpload = OptimizeImageResult & {
|
|
67
68
|
frame?: Pick<FrameResult, "framed" | "frameId" | "skippedReason">;
|
|
68
69
|
};
|
package/dist/commands.js
CHANGED
|
@@ -4,7 +4,7 @@ import { mapBounded } from "./async.js";
|
|
|
4
4
|
import { createUploadsClient, } from "./client.js";
|
|
5
5
|
import { parseCommandArgs, flagString, flagBool, flagInt, flagValues, UsageError, } from "./cli-args.js";
|
|
6
6
|
import { resolvePutDefaults, workspaceMismatch, workspaceFromToken, } from "./config.js";
|
|
7
|
-
import {
|
|
7
|
+
import { buildUploadMarkdown } from "./embed.js";
|
|
8
8
|
import { readLocalRepoCommentConfig, resolveCommentOptions } from "./comment-config.js";
|
|
9
9
|
import { urlForGithubEmbed } from "./public-urls.js";
|
|
10
10
|
import { UploadsError } from "./errors.js";
|
|
@@ -315,7 +315,7 @@ function formatOptimizeNote(opt) {
|
|
|
315
315
|
}
|
|
316
316
|
return undefined;
|
|
317
317
|
}
|
|
318
|
-
function writeReplacedNote(replaced, quiet, dryRun = false, wouldRefuse = false) {
|
|
318
|
+
export function writeReplacedNote(replaced, quiet, dryRun = false, wouldRefuse = false) {
|
|
319
319
|
if (quiet)
|
|
320
320
|
return;
|
|
321
321
|
if (dryRun && wouldRefuse) {
|
|
@@ -411,9 +411,10 @@ export async function uploadPreparedImage(client, bytes, sourceName, opts) {
|
|
|
411
411
|
}),
|
|
412
412
|
metadata,
|
|
413
413
|
});
|
|
414
|
-
const markdown =
|
|
414
|
+
const markdown = buildUploadMarkdown(urlForGithubEmbed(result.url, result.embedUrl), {
|
|
415
415
|
alt: opts.alt(prepared),
|
|
416
416
|
width: opts.width,
|
|
417
|
+
key: result.key,
|
|
417
418
|
});
|
|
418
419
|
return { result, prepared, markdown, sentMetadata: metadata };
|
|
419
420
|
}
|
|
@@ -748,8 +749,9 @@ async function uploadAttachmentBatch(opts) {
|
|
|
748
749
|
upload: {
|
|
749
750
|
...result,
|
|
750
751
|
file,
|
|
751
|
-
markdown:
|
|
752
|
+
markdown: buildUploadMarkdown(urlForGithubEmbed(result.url, result.embedUrl), {
|
|
752
753
|
alt: sourceName,
|
|
754
|
+
key: result.key,
|
|
753
755
|
}),
|
|
754
756
|
optimize: {
|
|
755
757
|
optimized: prepared.optimized,
|
package/dist/config-file.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { UploadsClientConfig } from "./config.js";
|
|
2
|
-
export declare const UPLOADS_CONFIG_KEYS: readonly ["UPLOADS_API_URL", "UPLOADS_WORKSPACE", "UPLOADS_TOKEN",
|
|
2
|
+
export declare const UPLOADS_CONFIG_KEYS: readonly ["UPLOADS_API_URL", "UPLOADS_WORKSPACE", "UPLOADS_TOKEN",
|
|
3
|
+
/** Better Auth device-flow session bearer — keeps session.cliVersion fresh. */
|
|
4
|
+
"UPLOADS_SESSION_TOKEN", "UPLOADS_DEFAULT_PREFIX", "UPLOADS_DEFAULT_REPO", "UPLOADS_DEFAULT_REF", "UPLOADS_DEFAULT_WIDTH", "UPLOADS_NO_GIT", "UPLOADS_NO_OPTIMIZE", "UPLOADS_KEEP_EXIF", "UPLOADS_NO_AUTO_META", "UPLOADS_SCREENSHOT_VIA", "UPLOADS_NO_NUDGE"];
|
|
3
5
|
export type UploadsConfigKey = (typeof UPLOADS_CONFIG_KEYS)[number];
|
|
4
6
|
export type UploadsConfigValues = Partial<Record<UploadsConfigKey, string>>;
|
|
5
7
|
export interface PutDefaults {
|
package/dist/embed.d.ts
CHANGED
|
@@ -4,3 +4,13 @@ export declare function buildMarkdown(url: string, opts: {
|
|
|
4
4
|
alt: string;
|
|
5
5
|
width?: number;
|
|
6
6
|
}): string;
|
|
7
|
+
/**
|
|
8
|
+
* Null-safe wrapper for upload flows: workspaces with no public base URL
|
|
9
|
+
* (BYO signed-URLs-only) upload fine but have no embeddable URL, and the
|
|
10
|
+
* markdown must degrade to honest plain text instead of ``.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildUploadMarkdown(url: string | null | undefined, opts: {
|
|
13
|
+
alt: string;
|
|
14
|
+
width?: number;
|
|
15
|
+
key: string;
|
|
16
|
+
}): string;
|
package/dist/embed.js
CHANGED
|
@@ -28,3 +28,14 @@ export function buildMarkdown(url, opts) {
|
|
|
28
28
|
}
|
|
29
29
|
return ``;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Null-safe wrapper for upload flows: workspaces with no public base URL
|
|
33
|
+
* (BYO signed-URLs-only) upload fine but have no embeddable URL, and the
|
|
34
|
+
* markdown must degrade to honest plain text instead of ``.
|
|
35
|
+
*/
|
|
36
|
+
export function buildUploadMarkdown(url, opts) {
|
|
37
|
+
if (!url) {
|
|
38
|
+
return `\`${opts.key}\` uploaded (no public URL — this workspace serves signed URLs only)`;
|
|
39
|
+
}
|
|
40
|
+
return buildMarkdown(url, opts);
|
|
41
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { inferContentType, buildMarkdown } from "./embed.js";
|
|
1
|
+
export { inferContentType, buildMarkdown, buildUploadMarkdown } from "./embed.js";
|
|
2
2
|
export { DEFAULT_EMBED_PUBLIC_BASE_URL, embedBaseUrlFromEnv, embedUrlFromPublic, resolveEmbedBaseUrl, resolveEmbedUrl, urlForGithubEmbed, } from "./public-urls.js";
|
|
3
3
|
export { sanitizeKeySegment, sha256Short, deriveRepoFromGit, buildScreenshotKey } from "./keys.js";
|
|
4
4
|
export { BUILTIN_DESTINATIONS, isBuiltinDestination, keyMatchesDestination, resolveDestinationRoot, resolvePutPrefix, type BuiltinDestinationId, } from "./destinations.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { inferContentType, buildMarkdown } from "./embed.js";
|
|
1
|
+
export { inferContentType, buildMarkdown, buildUploadMarkdown } from "./embed.js";
|
|
2
2
|
export { DEFAULT_EMBED_PUBLIC_BASE_URL, embedBaseUrlFromEnv, embedUrlFromPublic, resolveEmbedBaseUrl, resolveEmbedUrl, urlForGithubEmbed, } from "./public-urls.js";
|
|
3
3
|
export { sanitizeKeySegment, sha256Short, deriveRepoFromGit, buildScreenshotKey } from "./keys.js";
|
|
4
4
|
export { BUILTIN_DESTINATIONS, isBuiltinDestination, keyMatchesDestination, resolveDestinationRoot, resolvePutPrefix, } from "./destinations.js";
|
package/dist/mcp/args.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare const metadataProp: {
|
|
|
23
23
|
};
|
|
24
24
|
export declare const stateProp: {
|
|
25
25
|
type: string;
|
|
26
|
-
enum: ("
|
|
26
|
+
enum: ("after" | "before" | "empty" | "error" | "loading")[];
|
|
27
27
|
description: string;
|
|
28
28
|
};
|
|
29
29
|
export declare const appProp: {
|
package/dist/mcp/tools.js
CHANGED
|
@@ -761,6 +761,10 @@ export function createUploadsMcpTools(opts) {
|
|
|
761
761
|
hide: optStringArray(args, "hide"),
|
|
762
762
|
hideDevTools: optBool(args, "noHideDevTools") ? false : undefined,
|
|
763
763
|
reducedMotion: optBool(args, "reducedMotion"),
|
|
764
|
+
// Skip folding when an explicit key was given — key sets the
|
|
765
|
+
// whole object key, so there's no auto-derived name to fold
|
|
766
|
+
// state into.
|
|
767
|
+
state: keyArg ? undefined : metadataWithCaptureFacts?.state,
|
|
764
768
|
apiUrl: config.apiUrl,
|
|
765
769
|
token: config.token,
|
|
766
770
|
});
|
package/dist/metadata-vocab.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export type CanonicalMetaKey = (typeof CANONICAL_META_KEYS)[number];
|
|
|
3
3
|
/** Closed enum for `state` — the highest-value hand-supplied search facet. */
|
|
4
4
|
export declare const META_STATE_VALUES: readonly ["before", "after", "empty", "error", "loading"];
|
|
5
5
|
export type MetaStateValue = (typeof META_STATE_VALUES)[number];
|
|
6
|
+
/** True when `value` is exactly one of the canonical state values. */
|
|
7
|
+
export declare function isMetaStateValue(value: string): value is MetaStateValue;
|
|
6
8
|
/**
|
|
7
9
|
* Validate a `--state` value. Fails fast with a suggestion when the value is a
|
|
8
10
|
* recognized near-miss, otherwise lists the valid set.
|
package/dist/metadata-vocab.js
CHANGED
|
@@ -23,6 +23,10 @@ const CANONICAL_KEY_SET = new Set(CANONICAL_META_KEYS);
|
|
|
23
23
|
/** Closed enum for `state` — the highest-value hand-supplied search facet. */
|
|
24
24
|
export const META_STATE_VALUES = ["before", "after", "empty", "error", "loading"];
|
|
25
25
|
const STATE_VALUE_SET = new Set(META_STATE_VALUES);
|
|
26
|
+
/** True when `value` is exactly one of the canonical state values. */
|
|
27
|
+
export function isMetaStateValue(value) {
|
|
28
|
+
return STATE_VALUE_SET.has(value);
|
|
29
|
+
}
|
|
26
30
|
/** Common spellings agents reach for, mapped to the canonical `state` value. */
|
|
27
31
|
const STATE_ALIASES = {
|
|
28
32
|
pre: "before",
|
package/dist/screenshot.d.ts
CHANGED
|
@@ -65,6 +65,14 @@ export interface CaptureScreenshotOptions {
|
|
|
65
65
|
fullPage?: boolean;
|
|
66
66
|
colorScheme?: "dark" | "light";
|
|
67
67
|
waitUntil?: WaitUntil;
|
|
68
|
+
/**
|
|
69
|
+
* Folded into the auto-derived filename's stem (e.g. `-before`) so a
|
|
70
|
+
* before/after pair of the same URL yields two distinct object names
|
|
71
|
+
* instead of silently overwriting each other. Callers must omit this when
|
|
72
|
+
* the caller also gave an explicit object key/name — folding only applies
|
|
73
|
+
* to the auto-derived name.
|
|
74
|
+
*/
|
|
75
|
+
state?: string;
|
|
68
76
|
/** Extra CSS selectors to hide (display:none) before capture. */
|
|
69
77
|
hide?: string[];
|
|
70
78
|
/**
|
|
@@ -120,6 +128,26 @@ export interface CaptureScreenshotResult {
|
|
|
120
128
|
/** Present when `measureSelectors` was given and the local backend ran. */
|
|
121
129
|
measures?: Record<string, MeasuredBox>;
|
|
122
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Folds a `--state` value into an auto-derived filename's stem, e.g.
|
|
133
|
+
* `localhost-docs-mcp.png` + "before" → `localhost-docs-mcp-before.png`. This
|
|
134
|
+
* is what keeps a before/after pair (same URL, two states) from colliding on
|
|
135
|
+
* the same object key (issue #618) — without it, the second capture silently
|
|
136
|
+
* overwrote the first.
|
|
137
|
+
*
|
|
138
|
+
* No-op when `state` is undefined, and idempotent: re-folding a filename that
|
|
139
|
+
* already ends with `-<state>` (e.g. re-deriving from a stored filename)
|
|
140
|
+
* doesn't double-append.
|
|
141
|
+
*
|
|
142
|
+
* Only the canonical state values fold. Callers pass the merged metadata bag's
|
|
143
|
+
* `state`, which a free-form `--meta state=…` can populate with any printable
|
|
144
|
+
* ASCII (validateMetaMap allows `/` and spaces) — that stays metadata-only
|
|
145
|
+
* rather than entering the object key.
|
|
146
|
+
*
|
|
147
|
+
* Callers must skip this entirely when the caller gave an explicit key/name
|
|
148
|
+
* (e.g. `--key`) — this only applies to the auto-derived filename.
|
|
149
|
+
*/
|
|
150
|
+
export declare function foldStateIntoFilename(filename: string, state: string | undefined): string;
|
|
123
151
|
/**
|
|
124
152
|
* Resolve target + options into PNG bytes via the local or remote backend.
|
|
125
153
|
* Shared by the CLI `screenshot` command and the MCP `screenshot` tool.
|
package/dist/screenshot.js
CHANGED
|
@@ -12,6 +12,7 @@ import { existsSync, readFileSync, statSync } from "node:fs";
|
|
|
12
12
|
import { basename, resolve as resolvePath } from "node:path";
|
|
13
13
|
import { pathToFileURL } from "node:url";
|
|
14
14
|
import { UploadsError } from "./errors.js";
|
|
15
|
+
import { isMetaStateValue } from "./metadata-vocab.js";
|
|
15
16
|
import { captureRemote, MAX_REMOTE_HTML_BYTES } from "./screenshot-remote.js";
|
|
16
17
|
/**
|
|
17
18
|
* Host selectors for framework dev toolbars/overlays that otherwise pollute a
|
|
@@ -159,6 +160,35 @@ function deriveFilename(target) {
|
|
|
159
160
|
const stem = [url.hostname, pathPart].filter(Boolean).join("-");
|
|
160
161
|
return `${stem || "screenshot"}.png`;
|
|
161
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Folds a `--state` value into an auto-derived filename's stem, e.g.
|
|
165
|
+
* `localhost-docs-mcp.png` + "before" → `localhost-docs-mcp-before.png`. This
|
|
166
|
+
* is what keeps a before/after pair (same URL, two states) from colliding on
|
|
167
|
+
* the same object key (issue #618) — without it, the second capture silently
|
|
168
|
+
* overwrote the first.
|
|
169
|
+
*
|
|
170
|
+
* No-op when `state` is undefined, and idempotent: re-folding a filename that
|
|
171
|
+
* already ends with `-<state>` (e.g. re-deriving from a stored filename)
|
|
172
|
+
* doesn't double-append.
|
|
173
|
+
*
|
|
174
|
+
* Only the canonical state values fold. Callers pass the merged metadata bag's
|
|
175
|
+
* `state`, which a free-form `--meta state=…` can populate with any printable
|
|
176
|
+
* ASCII (validateMetaMap allows `/` and spaces) — that stays metadata-only
|
|
177
|
+
* rather than entering the object key.
|
|
178
|
+
*
|
|
179
|
+
* Callers must skip this entirely when the caller gave an explicit key/name
|
|
180
|
+
* (e.g. `--key`) — this only applies to the auto-derived filename.
|
|
181
|
+
*/
|
|
182
|
+
export function foldStateIntoFilename(filename, state) {
|
|
183
|
+
if (!state || !isMetaStateValue(state))
|
|
184
|
+
return filename;
|
|
185
|
+
const match = /^(.*?)(\.[^./]+)?$/.exec(filename);
|
|
186
|
+
const stem = match?.[1] ?? filename;
|
|
187
|
+
const ext = match?.[2] ?? "";
|
|
188
|
+
if (stem.endsWith(`-${state}`))
|
|
189
|
+
return filename;
|
|
190
|
+
return `${stem}-${state}${ext}`;
|
|
191
|
+
}
|
|
162
192
|
/**
|
|
163
193
|
* Best-effort local-browser probe used only to decide `auto` routing. Never
|
|
164
194
|
* throws — any failure (e.g. optional playwright-core not installed) means
|
|
@@ -183,7 +213,7 @@ export async function captureScreenshot(opts) {
|
|
|
183
213
|
const target = classifyTarget(opts.target);
|
|
184
214
|
const viewport = opts.viewport ?? DEFAULT_SCREENSHOT_VIEWPORT;
|
|
185
215
|
const waitUntil = opts.waitUntil ?? "load";
|
|
186
|
-
const filename = deriveFilename(target);
|
|
216
|
+
const filename = foldStateIntoFilename(deriveFilename(target), opts.state);
|
|
187
217
|
// Only private-network URLs are truly unreachable remotely; an .html file
|
|
188
218
|
// is sent to the remote backend as an inline `html` body (though anything
|
|
189
219
|
// it references via file:// or relative paths won't resolve there).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildinternet/uploads",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.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,
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@types/node": "^26.1.0",
|
|
50
50
|
"ai": "^6.0.0",
|
|
51
51
|
"files-sdk": "^2.1.0",
|
|
52
|
-
"typescript": "^
|
|
52
|
+
"typescript": "^7.0.2",
|
|
53
53
|
"vitest": "^4.1.10"
|
|
54
54
|
},
|
|
55
55
|
"publishConfig": {
|