@buildinternet/uploads 0.3.0 → 0.4.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/README.md +1 -1
- package/dist/cli.js +1 -1
- package/dist/client.d.ts +13 -0
- package/dist/client.js +8 -1
- package/dist/commands.js +13 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/mcp/tools.js +19 -2
- package/dist/provenance.d.ts +12 -0
- package/dist/provenance.js +29 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @buildinternet/uploads
|
|
2
2
|
|
|
3
|
-
CLI and client for **uploads.sh** — upload files, get public URLs, and produce GitHub-ready markdown.
|
|
3
|
+
CLI and client for **uploads.sh** — upload files, get public URLs, and produce GitHub-ready markdown.
|
|
4
4
|
|
|
5
5
|
## CLI
|
|
6
6
|
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ Config (first match wins, per key):
|
|
|
19
19
|
environment UPLOADS_API_URL, UPLOADS_TOKEN, UPLOADS_WORKSPACE
|
|
20
20
|
--env-file <path>
|
|
21
21
|
$BUILDINTERNET_CONFIG
|
|
22
|
-
~/.config/buildinternet/config
|
|
22
|
+
~/.config/buildinternet/config
|
|
23
23
|
|
|
24
24
|
Workspace (within config layers):
|
|
25
25
|
--workspace, -w override — global (before command) or per-command (after)
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { UploadsClientConfig } from "./config.js";
|
|
2
|
+
/** Allowlisted object provenance (maps to X-Uploads-Meta-* on put). */
|
|
3
|
+
export type ProvenanceInput = {
|
|
4
|
+
client?: string;
|
|
5
|
+
"client-version"?: string;
|
|
6
|
+
"source-name"?: string;
|
|
7
|
+
optimized?: "0" | "1";
|
|
8
|
+
frame?: string;
|
|
9
|
+
"keep-exif"?: "0" | "1";
|
|
10
|
+
};
|
|
2
11
|
export interface PutOptions {
|
|
3
12
|
key?: string;
|
|
4
13
|
contentType?: string;
|
|
@@ -6,6 +15,8 @@ export interface PutOptions {
|
|
|
6
15
|
repo?: string;
|
|
7
16
|
ref?: string;
|
|
8
17
|
deriveRepoFromGit?: boolean;
|
|
18
|
+
/** Stored as R2 custom metadata; echoed on put/head. */
|
|
19
|
+
provenance?: ProvenanceInput;
|
|
9
20
|
}
|
|
10
21
|
export interface ListOptions {
|
|
11
22
|
prefix?: string;
|
|
@@ -18,6 +29,7 @@ export interface PutResult {
|
|
|
18
29
|
url: string;
|
|
19
30
|
size: number;
|
|
20
31
|
contentType: string;
|
|
32
|
+
metadata?: Record<string, string>;
|
|
21
33
|
}
|
|
22
34
|
export interface ListItem {
|
|
23
35
|
key: string;
|
|
@@ -35,6 +47,7 @@ export interface HeadResult {
|
|
|
35
47
|
size: number;
|
|
36
48
|
contentType: string;
|
|
37
49
|
uploaded?: string;
|
|
50
|
+
metadata?: Record<string, string>;
|
|
38
51
|
}
|
|
39
52
|
export interface DeleteResult {
|
|
40
53
|
key: string;
|
package/dist/client.js
CHANGED
|
@@ -117,9 +117,16 @@ export function createUploadsClient(config) {
|
|
|
117
117
|
deriveRepoFromGit: opts.deriveRepoFromGit,
|
|
118
118
|
}));
|
|
119
119
|
const contentType = opts.contentType ?? inferContentType(opts.filename);
|
|
120
|
+
const headers = { "Content-Type": contentType };
|
|
121
|
+
if (opts.provenance) {
|
|
122
|
+
for (const [k, v] of Object.entries(opts.provenance)) {
|
|
123
|
+
if (v !== undefined && v !== "")
|
|
124
|
+
headers[`X-Uploads-Meta-${k}`] = v;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
120
127
|
const result = await request("PUT", `${filesBase(config)}/${encodeKeyPath(key)}`, {
|
|
121
128
|
body,
|
|
122
|
-
headers
|
|
129
|
+
headers,
|
|
123
130
|
});
|
|
124
131
|
if (result.url == null) {
|
|
125
132
|
throw new UploadsError("upload succeeded but workspace has no publicBaseUrl", "NO_PUBLIC_URL", 201);
|
package/dist/commands.js
CHANGED
|
@@ -11,6 +11,7 @@ import { resolveRepo, resolveCurrentPullRequest, execRunner, upsertAttachmentsCo
|
|
|
11
11
|
import { resolvePutPrefix } from "./destinations.js";
|
|
12
12
|
import { optimizeImageForUpload, rewriteKeyExtension, } from "./optimize.js";
|
|
13
13
|
import { applyFrame, resolveFrameId } from "./frame.js";
|
|
14
|
+
import { buildCliProvenance } from "./provenance.js";
|
|
14
15
|
// --- put ---
|
|
15
16
|
const PUT_HELP = `uploads put <file> [options]
|
|
16
17
|
|
|
@@ -230,6 +231,12 @@ export async function runAttach(ctx, args, help = false, run = execRunner) {
|
|
|
230
231
|
filename: prepared.filename,
|
|
231
232
|
key: ghAttachmentKey(target, prepared.filename),
|
|
232
233
|
contentType: prepared.optimized ? prepared.contentType : contentTypeOverride,
|
|
234
|
+
provenance: buildCliProvenance({
|
|
235
|
+
sourceName,
|
|
236
|
+
optimized: prepared.optimized,
|
|
237
|
+
frameId: prepared.frame?.framed ? prepared.frame.frameId : undefined,
|
|
238
|
+
keepExif: optimizeOpts.keepExif === true,
|
|
239
|
+
}),
|
|
233
240
|
});
|
|
234
241
|
results.push({
|
|
235
242
|
...result,
|
|
@@ -363,6 +370,12 @@ export async function runPut(ctx, args, help = false, run = execRunner) {
|
|
|
363
370
|
ref: flagString(parsed.flags, "--ref") ?? defaults.ref,
|
|
364
371
|
contentType: prepared.optimized ? prepared.contentType : contentTypeOverride,
|
|
365
372
|
deriveRepoFromGit: !noGit,
|
|
373
|
+
provenance: buildCliProvenance({
|
|
374
|
+
sourceName,
|
|
375
|
+
optimized: prepared.optimized,
|
|
376
|
+
frameId: prepared.frame?.framed ? prepared.frame.frameId : undefined,
|
|
377
|
+
keepExif: optimizeOpts.keepExif === true,
|
|
378
|
+
}),
|
|
366
379
|
});
|
|
367
380
|
const markdown = buildMarkdown(result.url, { alt, width });
|
|
368
381
|
const optimizeMeta = {
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ export { sanitizeKeySegment, sha256Short, deriveRepoFromGit, buildScreenshotKey
|
|
|
3
3
|
export { BUILTIN_DESTINATIONS, isBuiltinDestination, keyMatchesDestination, resolveDestinationRoot, resolvePutPrefix, type BuiltinDestinationId, } from "./destinations.js";
|
|
4
4
|
export { DEFAULT_API_URL, DEFAULT_WORKSPACE, UPLOADS_CONFIG_KEYS, defaultConfigPath, resolveConfigPath, loadConfigFile, loadEnvFile, resolveApiUrl, resolveConfig, describeConfigSources, redactToken, writeConfigKeys, configValuesFromClient, putDefaultsToConfigValues, resolvePutDefaults, mergePutDefaults, workspaceFromToken, workspaceMismatch, type UploadsClientConfig, type ResolvedConfig, type WorkspaceSource, type ConfigValueSource, type ConfigSources, type UploadsConfigKey, type UploadsConfigValues, type PutDefaults, } from "./config.js";
|
|
5
5
|
export { UploadsError, type UploadsErrorCode } from "./errors.js";
|
|
6
|
-
export { createUploadsClient, type UploadsClient, type PutOptions, type ListOptions, type PutResult, type ListItem, type ListResult, type HeadResult, type DeleteResult, type HealthResult, type UsageResult, type ReconcileResult, type PurgeExpiredResult, type PurgeExpiredResponse, } from "./client.js";
|
|
6
|
+
export { createUploadsClient, type UploadsClient, type PutOptions, type ProvenanceInput, type ListOptions, type PutResult, type ListItem, type ListResult, type HeadResult, type DeleteResult, type HealthResult, type UsageResult, type ReconcileResult, type PurgeExpiredResult, type PurgeExpiredResponse, } from "./client.js";
|
|
7
|
+
export { buildCliProvenance } from "./provenance.js";
|
|
7
8
|
export { ATTACHMENTS_MARKER, attachmentsCommentBody, ghAttachmentKey, ghKeyPrefix, isValidRepo, parseRepoFromRemoteUrl, type AttachmentItem, type GhTarget, type GhTargetKind, } from "./github.js";
|
|
8
9
|
export { DEFAULT_OPTIMIZE_MAX_EDGE, DEFAULT_OPTIMIZE_QUALITY, optimizeImageForUpload, rewriteKeyExtension, withImageExtension, type OptimizeImageOptions, type OptimizeImageResult, type OptimizeOutputFormat, } from "./optimize.js";
|
|
9
10
|
export { FRAME_PRESETS, applyFrame, listFramePresets, resolveFrameId, type FrameFit, type FrameOptions, type FrameResult, } from "./frame.js";
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { BUILTIN_DESTINATIONS, isBuiltinDestination, keyMatchesDestination, reso
|
|
|
4
4
|
export { DEFAULT_API_URL, DEFAULT_WORKSPACE, UPLOADS_CONFIG_KEYS, defaultConfigPath, resolveConfigPath, loadConfigFile, loadEnvFile, resolveApiUrl, resolveConfig, describeConfigSources, redactToken, writeConfigKeys, configValuesFromClient, putDefaultsToConfigValues, resolvePutDefaults, mergePutDefaults, workspaceFromToken, workspaceMismatch, } from "./config.js";
|
|
5
5
|
export { UploadsError } from "./errors.js";
|
|
6
6
|
export { createUploadsClient, } from "./client.js";
|
|
7
|
+
export { buildCliProvenance } from "./provenance.js";
|
|
7
8
|
export { ATTACHMENTS_MARKER, attachmentsCommentBody, ghAttachmentKey, ghKeyPrefix, isValidRepo, parseRepoFromRemoteUrl, } from "./github.js";
|
|
8
9
|
export { DEFAULT_OPTIMIZE_MAX_EDGE, DEFAULT_OPTIMIZE_QUALITY, optimizeImageForUpload, rewriteKeyExtension, withImageExtension, } from "./optimize.js";
|
|
9
10
|
export { FRAME_PRESETS, applyFrame, listFramePresets, resolveFrameId, } from "./frame.js";
|
package/dist/mcp/tools.js
CHANGED
|
@@ -15,6 +15,7 @@ import { buildMarkdown } from "../embed.js";
|
|
|
15
15
|
import { resolvePutPrefix } from "../destinations.js";
|
|
16
16
|
import { ghAttachmentKey, ghKeyPrefix } from "../github.js";
|
|
17
17
|
import { rewriteKeyExtension } from "../optimize.js";
|
|
18
|
+
import { buildCliProvenance } from "../provenance.js";
|
|
18
19
|
import { execRunner, resolveCurrentPullRequest, resolveRepo, } from "../github-gh.js";
|
|
19
20
|
import { optPosInt, optString, usage } from "./args.js";
|
|
20
21
|
function optBool(args, name) {
|
|
@@ -254,9 +255,11 @@ export function createUploadsMcpTools(opts) {
|
|
|
254
255
|
: new Uint8Array(Buffer.from(contentBase64, "base64"));
|
|
255
256
|
const sourceName = file !== undefined ? (filenameArg ?? basename(file)) : filenameArg;
|
|
256
257
|
const defaults = resolvePutDefaults({ envFile: globals.envFile });
|
|
258
|
+
const frameOpts = mcpFrameOptions(args);
|
|
259
|
+
const optimizeOpts = mcpOptimizeOptions(args, defaults);
|
|
257
260
|
const prepared = await prepareImageForUpload(bytes, sourceName, {
|
|
258
|
-
...
|
|
259
|
-
optimize:
|
|
261
|
+
...frameOpts,
|
|
262
|
+
optimize: optimizeOpts,
|
|
260
263
|
});
|
|
261
264
|
const filename = prepared.filename;
|
|
262
265
|
let key = target ? ghAttachmentKey(target, filename) : keyArg;
|
|
@@ -271,6 +274,13 @@ export function createUploadsMcpTools(opts) {
|
|
|
271
274
|
ref: refArg ?? defaults.ref,
|
|
272
275
|
contentType: prepared.optimized ? prepared.contentType : optString(args, "contentType"),
|
|
273
276
|
deriveRepoFromGit: !noGit,
|
|
277
|
+
provenance: buildCliProvenance({
|
|
278
|
+
sourceName,
|
|
279
|
+
client: "uploads-mcp",
|
|
280
|
+
optimized: prepared.optimized,
|
|
281
|
+
frameId: prepared.frame?.framed ? prepared.frame.frameId : undefined,
|
|
282
|
+
keepExif: optimizeOpts.keepExif === true,
|
|
283
|
+
}),
|
|
274
284
|
});
|
|
275
285
|
const markdown = buildMarkdown(result.url, {
|
|
276
286
|
alt: optString(args, "alt") ?? sourceName,
|
|
@@ -352,6 +362,13 @@ export function createUploadsMcpTools(opts) {
|
|
|
352
362
|
filename: prepared.filename,
|
|
353
363
|
key: ghAttachmentKey(target, prepared.filename),
|
|
354
364
|
contentType: prepared.optimized ? prepared.contentType : contentType,
|
|
365
|
+
provenance: buildCliProvenance({
|
|
366
|
+
sourceName,
|
|
367
|
+
client: "uploads-mcp",
|
|
368
|
+
optimized: prepared.optimized,
|
|
369
|
+
frameId: prepared.frame?.framed ? prepared.frame.frameId : undefined,
|
|
370
|
+
keepExif: optimizeOpts.keepExif === true,
|
|
371
|
+
}),
|
|
355
372
|
});
|
|
356
373
|
uploads.push({
|
|
357
374
|
...result,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side provenance headers for put (X-Uploads-Meta-*).
|
|
3
|
+
* API allowlists keys; secrets never go here.
|
|
4
|
+
*/
|
|
5
|
+
import type { ProvenanceInput } from "./client.js";
|
|
6
|
+
export declare function buildCliProvenance(opts: {
|
|
7
|
+
sourceName: string;
|
|
8
|
+
optimized?: boolean;
|
|
9
|
+
frameId?: string;
|
|
10
|
+
keepExif?: boolean;
|
|
11
|
+
client?: string;
|
|
12
|
+
}): ProvenanceInput;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
let cachedVersion;
|
|
3
|
+
function packageVersion() {
|
|
4
|
+
if (cachedVersion)
|
|
5
|
+
return cachedVersion;
|
|
6
|
+
try {
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const pkg = require("../package.json");
|
|
9
|
+
cachedVersion = pkg.version ?? "0.0.0";
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
cachedVersion = "0.0.0";
|
|
13
|
+
}
|
|
14
|
+
return cachedVersion;
|
|
15
|
+
}
|
|
16
|
+
export function buildCliProvenance(opts) {
|
|
17
|
+
const provenance = {
|
|
18
|
+
client: opts.client ?? "uploads-cli",
|
|
19
|
+
"client-version": packageVersion(),
|
|
20
|
+
"source-name": opts.sourceName.slice(0, 128),
|
|
21
|
+
};
|
|
22
|
+
if (opts.optimized)
|
|
23
|
+
provenance.optimized = "1";
|
|
24
|
+
if (opts.frameId)
|
|
25
|
+
provenance.frame = opts.frameId.slice(0, 64);
|
|
26
|
+
if (opts.keepExif)
|
|
27
|
+
provenance["keep-exif"] = "1";
|
|
28
|
+
return provenance;
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildinternet/uploads",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "CLI and client for uploads.sh — workspace-scoped image hosting for GitHub embeds",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
6
7
|
"license": "MIT",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|