dropley 0.1.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.

Potentially problematic release.


This version of dropley might be problematic. Click here for more details.

Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/dist/api.d.ts +55 -0
  4. package/dist/api.js +126 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/args.d.ts +21 -0
  7. package/dist/args.js +83 -0
  8. package/dist/args.js.map +1 -0
  9. package/dist/bin/dropley.d.ts +2 -0
  10. package/dist/bin/dropley.js +4 -0
  11. package/dist/bin/dropley.js.map +1 -0
  12. package/dist/cli.d.ts +2 -0
  13. package/dist/cli.js +112 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/collect.d.ts +15 -0
  16. package/dist/collect.js +59 -0
  17. package/dist/collect.js.map +1 -0
  18. package/dist/commands/context.d.ts +14 -0
  19. package/dist/commands/context.js +28 -0
  20. package/dist/commands/context.js.map +1 -0
  21. package/dist/commands/delete.d.ts +3 -0
  22. package/dist/commands/delete.js +14 -0
  23. package/dist/commands/delete.js.map +1 -0
  24. package/dist/commands/pack.d.ts +10 -0
  25. package/dist/commands/pack.js +45 -0
  26. package/dist/commands/pack.js.map +1 -0
  27. package/dist/commands/publish.d.ts +4 -0
  28. package/dist/commands/publish.js +94 -0
  29. package/dist/commands/publish.js.map +1 -0
  30. package/dist/commands/status.d.ts +3 -0
  31. package/dist/commands/status.js +27 -0
  32. package/dist/commands/status.js.map +1 -0
  33. package/dist/commands/update.d.ts +3 -0
  34. package/dist/commands/update.js +23 -0
  35. package/dist/commands/update.js.map +1 -0
  36. package/dist/config.d.ts +8 -0
  37. package/dist/config.js +68 -0
  38. package/dist/config.js.map +1 -0
  39. package/dist/errors.d.ts +12 -0
  40. package/dist/errors.js +19 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/mime.d.ts +1 -0
  43. package/dist/mime.js +47 -0
  44. package/dist/mime.js.map +1 -0
  45. package/dist/output.d.ts +9 -0
  46. package/dist/output.js +24 -0
  47. package/dist/output.js.map +1 -0
  48. package/dist/target.d.ts +5 -0
  49. package/dist/target.js +29 -0
  50. package/dist/target.js.map +1 -0
  51. package/dist/zip.d.ts +14 -0
  52. package/dist/zip.js +136 -0
  53. package/dist/zip.js.map +1 -0
  54. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dropley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # dropley
2
+
3
+ Publish files and static sites to [Dropley](https://dropley.app) from your terminal — no browser, no account.
4
+
5
+ `dropley` wraps the [Dropley public API](https://dropley.app/api/v1/openapi.json) so agents and humans can publish artifacts and manage them with four commands. Every published artifact gets a shareable URL and a token for later update/delete.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install -g dropley
11
+ # or run without installing:
12
+ npx dropley publish ./dist
13
+ ```
14
+
15
+ Requires Node.js ≥ 20. Zero runtime dependencies.
16
+
17
+ ## Quickstart
18
+
19
+ ```sh
20
+ # Publish a directory (static site) — uploads each file, skipping OS junk (.DS_Store, .git, …)
21
+ dropley publish ./dist --expiry 7d
22
+ # url: https://preview.dropley.app/p/aB3cD5eF
23
+ # token: tok_a1b2c3… ← keep this; needed to update/delete
24
+
25
+ # A single file is published as the site entry (index.html)
26
+ dropley publish report.html
27
+
28
+ # Show metadata (public without a token)
29
+ dropley status https://preview.dropley.app/p/aB3cD5eF
30
+
31
+ # Change expiry (needs the artifact token)
32
+ dropley update aB3cD5eF --expiry 30d
33
+
34
+ # Delete permanently
35
+ dropley delete aB3cD5eF
36
+ ```
37
+
38
+ ## Agent usage
39
+
40
+ `dropley` is designed for agents: quiet, machine-parsable output on stdout, progress on stderr.
41
+
42
+ ```sh
43
+ # JSON mode — everything needed in one object
44
+ dropley publish ./out --json
45
+ # {
46
+ # "shortId": "aB3cD5eF",
47
+ # "url": "https://preview.dropley.app/p/aB3cD5eF",
48
+ # "expiresAt": "2026-08-30T12:00:00.000Z",
49
+ # "artifactToken": "tok_a1b2c3…"
50
+ # }
51
+ ```
52
+
53
+ - Exit codes: `0` success, `1` failure (API/network errors), `2` usage error.
54
+ - API errors surface the server's `error`/`code`/`hint` verbatim on stderr, including `RATE_LIMITED` 429 responses with their `Retry-After`.
55
+ - The token returned by `publish` is saved locally (per artifact ID, `0600` perms, `~/.config/dropley/tokens.json` or `$XDG_CONFIG_HOME`/`$DROPLEY_CONFIG_DIR`) and reused by `status`/`update`/`delete` automatically.
56
+
57
+ See also the Dropley [agent skills](https://github.com/dropley) collection — `npx skills@latest add dropley/docs` for docs on publishing via agents.
58
+
59
+ ## Commands
60
+
61
+ | Command | Description |
62
+ | --- | --- |
63
+ | `dropley publish <path> [--expiry <t>]` | Publish a file or directory; prints URL + token |
64
+ | `dropley status <url-or-shortId>` | Show artifact metadata |
65
+ | `dropley update <url-or-shortId> --expiry <t>` | Change an artifact's expiry |
66
+ | `dropley delete <url-or-shortId>` | Permanently delete an artifact |
67
+ | `dropley pack <dir> [--out archive.zip]` | Create a byte-reproducible zip (auxiliary; see below) |
68
+
69
+ ### Global options
70
+
71
+ | Option | Description |
72
+ | --- | --- |
73
+ | `--json` | Machine-readable JSON output on stdout |
74
+ | `--api <url>` | API base URL (default `https://dropley.app`; env `DROPLEY_API` for local previews) |
75
+ | `--token <tok>` | Artifact token (env `DROPLEY_TOKEN`); precedence: `--token` > `DROPLEY_TOKEN` > saved token |
76
+ | `--expiry <t>` | `1d` `3d` `7d` `15d` `30d` `1h`… — server-validated |
77
+
78
+ ### Notes
79
+
80
+ - **Directory publishes** upload every file as an individual part with its relative path (Dropley requires the site entry to be `index.html` at the root). OS metadata (`.DS_Store`, `Thumbs.db`, `desktop.ini`, `._*`), VCS internals (`.git`, `.hg`, `.svn`) and `node_modules` are skipped.
81
+ - **`dropley pack`** writes a byte-for-byte reproducible zip archive (sorted entries, fixed timestamps, no junk). Dropley serves uploads as-is and does not expand archives, so publish directories directly for hosting — `pack` is for archiving and reproducible builds.
82
+ - 50MB total / 1000 files per artifact (checked locally before upload).
83
+
84
+ ## Development
85
+
86
+ ```sh
87
+ npm install
88
+ npm run lint # eslint
89
+ npm run typecheck # tsc --noEmit
90
+ npm test # vitest (mocked fetch, no network)
91
+ npm run build # tsc → dist/
92
+ ```
93
+
94
+ ## Release
95
+
96
+ Release: push a `v*` tag; the release workflow runs checks and publishes to npm with `--provenance` via **trusted publishing** (OIDC — no npm token stored in GitHub).
97
+
98
+ Setup (once, by a maintainer):
99
+
100
+ 1. Make the repo public (trusted publishing is identity-based and works fine on public repos).
101
+ 2. On npmjs.com → package settings → **Trusted publishing**: add GitHub owner `dropley`, repository `cli`, environment `npm`, workflow `release.yml`.
102
+ 3. On GitHub → repo settings → **Environments** → `npm`: configure required reviewers (the approval gate the publish waits on).
103
+
104
+ The first publish is always a human step: tag, push, approve the environment.
105
+
106
+ > Note: if the `dropley` package name is not yet claimed on npm, the very first publish may need a one-time token (npm requires the package to exist before trusted publishing can be configured); trusted publishing takes over for all subsequent releases.
107
+
108
+ ## License
109
+
110
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ export declare const DEFAULT_BASE_URL = "https://dropley.app";
2
+ export declare class ApiError extends Error {
3
+ readonly status: number;
4
+ readonly code?: string;
5
+ readonly hint?: string;
6
+ readonly retryAfter?: number;
7
+ readonly requestId?: string;
8
+ constructor(message: string, opts: {
9
+ status: number;
10
+ code?: string;
11
+ hint?: string;
12
+ retryAfter?: number;
13
+ requestId?: string;
14
+ });
15
+ }
16
+ export interface CreateResult {
17
+ shortId: string;
18
+ url: string;
19
+ expiresAt: string | null;
20
+ artifactToken: string;
21
+ }
22
+ export interface ArtifactInfo {
23
+ shortId: string;
24
+ status: string;
25
+ url?: string;
26
+ expiresAt?: string | null;
27
+ source?: string;
28
+ tags?: string[];
29
+ createdAt?: string;
30
+ error?: string;
31
+ [key: string]: unknown;
32
+ }
33
+ export interface UpdateResult {
34
+ success: boolean;
35
+ expiresAt?: string | null;
36
+ source?: string;
37
+ tags?: string[];
38
+ [key: string]: unknown;
39
+ }
40
+ export interface UploadPart {
41
+ /** Path used as the multipart filename and manifest entry (POSIX style). */
42
+ path: string;
43
+ contentType: string;
44
+ data: Uint8Array;
45
+ }
46
+ export declare function createArtifact(baseUrl: string, parts: readonly UploadPart[], opts: {
47
+ expiry?: string;
48
+ entry?: string;
49
+ timeoutMs?: number;
50
+ }): Promise<CreateResult>;
51
+ export declare function getArtifact(baseUrl: string, shortId: string, token?: string): Promise<ArtifactInfo>;
52
+ export declare function updateArtifact(baseUrl: string, shortId: string, token: string, patch: Record<string, unknown>): Promise<UpdateResult>;
53
+ export declare function deleteArtifact(baseUrl: string, shortId: string, token: string): Promise<{
54
+ success: boolean;
55
+ }>;
package/dist/api.js ADDED
@@ -0,0 +1,126 @@
1
+ export const DEFAULT_BASE_URL = 'https://dropley.app';
2
+ export class ApiError extends Error {
3
+ status;
4
+ code;
5
+ hint;
6
+ retryAfter;
7
+ requestId;
8
+ constructor(message, opts) {
9
+ super(message);
10
+ this.name = 'ApiError';
11
+ this.status = opts.status;
12
+ this.code = opts.code;
13
+ this.hint = opts.hint;
14
+ this.retryAfter = opts.retryAfter;
15
+ this.requestId = opts.requestId;
16
+ }
17
+ }
18
+ function parseErrorBody(status, text, retryAfterHeader) {
19
+ let body;
20
+ try {
21
+ body = JSON.parse(text);
22
+ }
23
+ catch {
24
+ // non-JSON body (e.g. HTML error page)
25
+ }
26
+ if (body && typeof body === 'object') {
27
+ // Nested rate-limit shape: { error: { code, message } }
28
+ if (body.error && typeof body.error === 'object') {
29
+ const nested = body.error;
30
+ return new ApiError(String(nested.message ?? 'Request failed'), {
31
+ status,
32
+ code: nested.code !== undefined ? String(nested.code) : undefined,
33
+ hint: nested.hint !== undefined ? String(nested.hint) : undefined,
34
+ retryAfter: parseRetryAfter(retryAfterHeader),
35
+ });
36
+ }
37
+ // Flat shape: { error?, code?, message?, hint? }
38
+ const flatMessage = firstString(body.message) ??
39
+ firstString(body.error) ??
40
+ (body.requestId !== undefined ? `Server error (${String(body.requestId)})` : undefined) ??
41
+ 'Request failed';
42
+ return new ApiError(flatMessage, {
43
+ status,
44
+ code: firstString(body.code),
45
+ hint: firstString(body.hint),
46
+ retryAfter: parseRetryAfter(retryAfterHeader),
47
+ requestId: body.requestId !== undefined ? String(body.requestId) : undefined,
48
+ });
49
+ }
50
+ return new ApiError(text.slice(0, 200) || 'Request failed', {
51
+ status,
52
+ retryAfter: parseRetryAfter(retryAfterHeader),
53
+ });
54
+ }
55
+ function parseRetryAfter(header) {
56
+ if (!header)
57
+ return undefined;
58
+ const n = Number.parseInt(header, 10);
59
+ return Number.isNaN(n) ? undefined : n;
60
+ }
61
+ function firstString(v) {
62
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
63
+ }
64
+ async function request(baseUrl, path, init, timeoutMs) {
65
+ let res;
66
+ try {
67
+ res = await fetch(`${baseUrl}${path}`, { ...init, signal: AbortSignal.timeout(timeoutMs) });
68
+ }
69
+ catch (err) {
70
+ if (err.name === 'TimeoutError' || err.name === 'AbortError') {
71
+ throw new ApiError(`Request timed out after ${timeoutMs / 1000}s`, {
72
+ status: 0,
73
+ hint: 'Check your network connection, or point --api at a reachable server.',
74
+ });
75
+ }
76
+ throw new ApiError(`Network error: ${err.message}`, {
77
+ status: 0,
78
+ hint: 'Check your network connection, or point --api at a reachable server.',
79
+ });
80
+ }
81
+ if (!res.ok) {
82
+ const text = await res.text().catch(() => '');
83
+ throw parseErrorBody(res.status, text, res.headers.get('retry-after'));
84
+ }
85
+ return res;
86
+ }
87
+ async function requestJson(baseUrl, path, init, timeoutMs = 30_000) {
88
+ const res = await request(baseUrl, path, init, timeoutMs);
89
+ return (await res.json());
90
+ }
91
+ function buildManifest(parts, entry) {
92
+ return JSON.stringify({
93
+ manifestVersion: 1,
94
+ entry,
95
+ files: parts.map((p) => ({
96
+ path: p.path,
97
+ size: p.data.length,
98
+ contentType: p.contentType,
99
+ })),
100
+ });
101
+ }
102
+ export function createArtifact(baseUrl, parts, opts) {
103
+ const form = new FormData();
104
+ form.set('manifest', buildManifest(parts, opts.entry ?? 'index.html'));
105
+ if (opts.expiry !== undefined)
106
+ form.set('expiry', opts.expiry);
107
+ for (const part of parts) {
108
+ form.append('file', new File([part.data], part.path, { type: part.contentType }));
109
+ }
110
+ return requestJson(baseUrl, '/api/artifacts', { method: 'POST', body: form }, opts.timeoutMs ?? 300_000);
111
+ }
112
+ export function getArtifact(baseUrl, shortId, token) {
113
+ const query = token ? `?token=${encodeURIComponent(token)}` : '';
114
+ return requestJson(baseUrl, `/api/artifacts/${encodeURIComponent(shortId)}${query}`, { method: 'GET' });
115
+ }
116
+ export function updateArtifact(baseUrl, shortId, token, patch) {
117
+ return requestJson(baseUrl, `/api/artifacts/${encodeURIComponent(shortId)}`, {
118
+ method: 'PATCH',
119
+ headers: { 'X-Artifact-Token': token, 'Content-Type': 'application/json' },
120
+ body: JSON.stringify(patch),
121
+ });
122
+ }
123
+ export function deleteArtifact(baseUrl, shortId, token) {
124
+ return requestJson(baseUrl, `/api/artifacts/${encodeURIComponent(shortId)}`, { method: 'DELETE', headers: { 'X-Artifact-Token': token } });
125
+ }
126
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/args.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ export type FlagKind = 'boolean' | 'value';
2
+ export interface PositionalSpec {
3
+ name: string;
4
+ required: boolean;
5
+ description?: string;
6
+ }
7
+ export interface CommandSpec {
8
+ summary: string;
9
+ flags: Record<string, FlagKind>;
10
+ positionals: PositionalSpec[];
11
+ }
12
+ export declare const GLOBAL_FLAGS: Record<string, FlagKind>;
13
+ export interface ParsedInvocation {
14
+ command: string;
15
+ positionals: string[];
16
+ values: Record<string, string>;
17
+ flags: Set<string>;
18
+ }
19
+ /** Shape handed to command handlers (everything except the command name). */
20
+ export type ParsedArgs = Omit<ParsedInvocation, 'command'>;
21
+ export declare function parseArgv(argv: readonly string[], specs: Record<string, CommandSpec>): ParsedInvocation;
package/dist/args.js ADDED
@@ -0,0 +1,83 @@
1
+ import { UsageError } from './errors.js';
2
+ export const GLOBAL_FLAGS = {
3
+ json: 'boolean',
4
+ api: 'value',
5
+ token: 'value',
6
+ help: 'boolean',
7
+ version: 'boolean',
8
+ };
9
+ const VALUE_RE = /^(--[A-Za-z0-9][A-Za-z0-9-]*)=(.*)$/;
10
+ export function parseArgv(argv, specs) {
11
+ const commandArg = argv[0];
12
+ if (commandArg === undefined || commandArg === '') {
13
+ throw new UsageError('Missing command. Run `dropley --help` for usage.');
14
+ }
15
+ const spec = specs[commandArg];
16
+ if (!spec) {
17
+ throw new UsageError(`Unknown command: ${commandArg}. Run \`dropley --help\` for usage.`);
18
+ }
19
+ const flagKinds = { ...GLOBAL_FLAGS, ...spec.flags };
20
+ const positionals = [];
21
+ const values = {};
22
+ const flags = new Set();
23
+ for (let i = 1; i < argv.length; i++) {
24
+ const arg = argv[i];
25
+ if (arg === undefined)
26
+ break;
27
+ if (!arg.startsWith('-')) {
28
+ positionals.push(arg);
29
+ continue;
30
+ }
31
+ if (arg === '--') {
32
+ for (const rest of argv.slice(i + 1))
33
+ positionals.push(rest);
34
+ break;
35
+ }
36
+ if (arg === '-') {
37
+ throw new UsageError("Unexpected argument '-'.");
38
+ }
39
+ let name;
40
+ let inlineValue;
41
+ const eqMatch = VALUE_RE.exec(arg);
42
+ if (eqMatch && eqMatch[1] !== undefined) {
43
+ name = eqMatch[1].slice(2);
44
+ inlineValue = eqMatch[2] ?? '';
45
+ }
46
+ else {
47
+ name = arg.slice(2);
48
+ }
49
+ const kind = flagKinds[name];
50
+ if (!kind) {
51
+ throw new UsageError(`Unknown option --${name} for '${commandArg}'.`);
52
+ }
53
+ flags.add(name);
54
+ if (kind === 'boolean') {
55
+ if (inlineValue !== undefined && inlineValue !== 'true' && inlineValue !== 'false') {
56
+ throw new UsageError(`Option --${name} does not take a value.`);
57
+ }
58
+ if (inlineValue === 'false')
59
+ flags.delete(name);
60
+ continue;
61
+ }
62
+ const next = argv[i + 1];
63
+ const value = inlineValue ??
64
+ (next !== undefined && !next.startsWith('--') ? ((i++, next)) : undefined);
65
+ if (value === undefined) {
66
+ throw new UsageError(`Option --${name} requires a value.`);
67
+ }
68
+ values[name] = value;
69
+ }
70
+ if (flags.has('help') || flags.has('version')) {
71
+ return { command: commandArg, positionals, values, flags };
72
+ }
73
+ const requiredCount = spec.positionals.filter((p) => p.required).length;
74
+ if (positionals.length < requiredCount) {
75
+ const missing = spec.positionals[positionals.length];
76
+ throw new UsageError(`Missing argument: ${missing?.name ?? '<arg>'}.`);
77
+ }
78
+ if (positionals.length > spec.positionals.length) {
79
+ throw new UsageError(`Too many arguments for '${commandArg}' (expected ${spec.positionals.length}).`);
80
+ }
81
+ return { command: commandArg, positionals, values, flags };
82
+ }
83
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { main } from '../cli.js';
3
+ process.exitCode = await main();
4
+ //# sourceMappingURL=dropley.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropley.js","sourceRoot":"","sources":["../../src/bin/dropley.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,CAAC,QAAQ,GAAG,MAAM,IAAI,EAAE,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare const VERSION: string;
2
+ export declare function main(argv?: readonly string[]): Promise<number>;
package/dist/cli.js ADDED
@@ -0,0 +1,112 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { parseArgv } from './args.js';
4
+ import { ApiError } from './api.js';
5
+ import { EXIT, AuthError, UsageError } from './errors.js';
6
+ import { createIo, formatApiError } from './output.js';
7
+ import { publish } from './commands/publish.js';
8
+ import { status } from './commands/status.js';
9
+ import { update } from './commands/update.js';
10
+ import { del } from './commands/delete.js';
11
+ import { pack } from './commands/pack.js';
12
+ const COMMANDS = {
13
+ publish: {
14
+ summary: 'Publish a file or directory and print its public URL + token.',
15
+ flags: { expiry: 'value' },
16
+ positionals: [{ name: '<path>', required: true, description: 'File or directory to publish' }],
17
+ handler: publish,
18
+ },
19
+ status: {
20
+ summary: 'Show metadata for a published artifact.',
21
+ flags: {},
22
+ positionals: [{ name: '<url-or-shortId>', required: true }],
23
+ handler: status,
24
+ },
25
+ update: {
26
+ summary: 'Update an artifact (expiry).',
27
+ flags: { expiry: 'value' },
28
+ positionals: [{ name: '<url-or-shortId>', required: true }],
29
+ handler: update,
30
+ },
31
+ delete: {
32
+ summary: 'Permanently delete an artifact.',
33
+ flags: {},
34
+ positionals: [{ name: '<url-or-shortId>', required: true }],
35
+ handler: del,
36
+ },
37
+ pack: {
38
+ summary: 'Create a byte-reproducible zip archive of a directory.',
39
+ flags: { out: 'value' },
40
+ positionals: [{ name: '<dir>', required: true }],
41
+ handler: pack,
42
+ },
43
+ };
44
+ export const VERSION = (() => {
45
+ try {
46
+ // cli.js sits at <pkgroot>/dist/cli.js in both the repo and installed layout.
47
+ const pkgUrl = new URL('../package.json', import.meta.url);
48
+ return (JSON.parse(readFileSync(fileURLToPath(pkgUrl), 'utf8')).version ??
49
+ '0.0.0-dev');
50
+ }
51
+ catch {
52
+ return '0.0.0-dev';
53
+ }
54
+ })();
55
+ function usage() {
56
+ const lines = [
57
+ `dropley ${VERSION} — publish files and static sites from your terminal`,
58
+ '',
59
+ 'Usage:',
60
+ ...Object.entries(COMMANDS).map(([name, spec]) => ` dropley ${name} ${spec.positionals.map((p) => p.name).join(' ')}${Object.keys(spec.flags).length ? ' [options]' : ''}`),
61
+ '',
62
+ 'Commands:',
63
+ ];
64
+ for (const [name, spec] of Object.entries(COMMANDS)) {
65
+ lines.push(` ${name.padEnd(10)} ${spec.summary}`);
66
+ }
67
+ lines.push('', 'Options:', ' --json Machine-readable output', ' --api <url> API base URL (default https://dropley.app; env DROPLEY_API)', ' --token <tok> Artifact token (env DROPLEY_TOKEN)', ' --expiry <t> e.g. 1h, 1d, 3d, 7d, 15d, 30d (server-validated)', '', 'Exit codes: 0 success · 1 failure · 2 usage error', 'Docs: https://github.com/dropley/cli');
68
+ return lines.join('\n');
69
+ }
70
+ export async function main(argv = process.argv.slice(2)) {
71
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h' || argv[0] === 'help') {
72
+ process.stdout.write(`${usage()}\n`);
73
+ return argv.length === 0 ? EXIT.usage : EXIT.ok;
74
+ }
75
+ if (argv[0] === '--version' || argv[0] === '-v' || argv[0] === 'version') {
76
+ process.stdout.write(`dropley ${VERSION}\n`);
77
+ return EXIT.ok;
78
+ }
79
+ try {
80
+ const parsed = parseArgv(argv, COMMANDS);
81
+ if (parsed.flags.has('help')) {
82
+ process.stdout.write(`${usage()}\n`);
83
+ return EXIT.ok;
84
+ }
85
+ if (parsed.flags.has('version')) {
86
+ process.stdout.write(`dropley ${VERSION}\n`);
87
+ return EXIT.ok;
88
+ }
89
+ const spec = COMMANDS[parsed.command];
90
+ if (!spec)
91
+ throw new UsageError(`Unknown command: ${parsed.command}`);
92
+ const io = createIo(parsed.flags.has('json'));
93
+ return await spec.handler(parsed, io);
94
+ }
95
+ catch (err) {
96
+ if (err instanceof UsageError) {
97
+ process.stderr.write(`${usage()}\n\nerror: ${err.message}\n`);
98
+ return EXIT.usage;
99
+ }
100
+ if (err instanceof AuthError) {
101
+ process.stderr.write(`${err.message}\n`);
102
+ return EXIT.failure;
103
+ }
104
+ if (err instanceof ApiError) {
105
+ process.stderr.write(`${formatApiError(err)}\n`);
106
+ return EXIT.failure;
107
+ }
108
+ process.stderr.write(`error: ${err.message ?? String(err)}\nRun \`dropley --help\` for usage.\n`);
109
+ return EXIT.failure;
110
+ }
111
+ }
112
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export declare const MAX_TOTAL_BYTES: number;
2
+ export declare const MAX_FILE_COUNT = 1000;
3
+ export interface CollectedFile {
4
+ /** Absolute path on disk. */
5
+ absPath: string;
6
+ /** Relative POSIX path used as the manifest path and multipart filename. */
7
+ path: string;
8
+ size: number;
9
+ }
10
+ /**
11
+ * Walks a directory recursively and returns every non-junk file, sorted by
12
+ * relative POSIX path (byte-stable ordering). Junk = OS metadata (.DS_Store,
13
+ * Thumbs.db, desktop.ini, AppleDouble ._*), VCS internals, and node_modules.
14
+ */
15
+ export declare function collectFiles(rootDir: string): Promise<CollectedFile[]>;
@@ -0,0 +1,59 @@
1
+ import { readdir, stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { UsageError } from './errors.js';
4
+ export const MAX_TOTAL_BYTES = 50 * 1024 * 1024;
5
+ export const MAX_FILE_COUNT = 1000;
6
+ const JUNK_FILES = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']);
7
+ const JUNK_DIRS = new Set(['.git', '.hg', '.svn']);
8
+ function isJunkName(name) {
9
+ return JUNK_FILES.has(name) || name.startsWith('._');
10
+ }
11
+ /**
12
+ * Walks a directory recursively and returns every non-junk file, sorted by
13
+ * relative POSIX path (byte-stable ordering). Junk = OS metadata (.DS_Store,
14
+ * Thumbs.db, desktop.ini, AppleDouble ._*), VCS internals, and node_modules.
15
+ */
16
+ export async function collectFiles(rootDir) {
17
+ const out = [];
18
+ let totalBytes = 0;
19
+ const walk = async (dir) => {
20
+ const entries = await readdir(dir, { withFileTypes: true });
21
+ for (const entry of entries) {
22
+ if (entry.name === 'node_modules' && entry.isDirectory())
23
+ continue;
24
+ if (entry.isDirectory()) {
25
+ if (!JUNK_DIRS.has(entry.name))
26
+ await walk(join(dir, entry.name));
27
+ continue;
28
+ }
29
+ if (!entry.isFile())
30
+ continue;
31
+ if (isJunkName(entry.name))
32
+ continue;
33
+ const absPath = join(dir, entry.name);
34
+ const relPath = absPath.slice(rootDir.length + 1).split('\\').join('/');
35
+ const size = (await stat(absPath)).size;
36
+ totalBytes += size;
37
+ out.push({ absPath, path: relPath, size });
38
+ }
39
+ };
40
+ try {
41
+ await walk(rootDir);
42
+ }
43
+ catch (err) {
44
+ if (err instanceof UsageError)
45
+ throw err;
46
+ throw new UsageError(`Cannot read directory ${rootDir}: ${err.message}`);
47
+ }
48
+ out.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
49
+ if (out.length === 0)
50
+ throw new UsageError(`No files found in ${rootDir}.`);
51
+ if (out.length > MAX_FILE_COUNT) {
52
+ throw new UsageError(`Too many files: ${out.length} (max ${MAX_FILE_COUNT}). Publish a build output directory instead.`);
53
+ }
54
+ if (totalBytes > MAX_TOTAL_BYTES) {
55
+ throw new UsageError(`Total size ${(totalBytes / 1024 / 1024).toFixed(1)}MB exceeds the ${MAX_TOTAL_BYTES / 1024 / 1024}MB limit.`);
56
+ }
57
+ return out;
58
+ }
59
+ //# sourceMappingURL=collect.js.map