wirecopy 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.
@@ -0,0 +1,15 @@
1
+ export declare class UsageError extends Error {
2
+ readonly exitCode = 64;
3
+ }
4
+ export declare class ApiError extends Error {
5
+ readonly code: string;
6
+ readonly status?: number | undefined;
7
+ readonly exitCode = 69;
8
+ constructor(code: string, message: string, status?: number | undefined);
9
+ }
10
+ export declare class ConfigurationError extends Error {
11
+ readonly exitCode = 78;
12
+ }
13
+ export declare function exitCodeFor(error: unknown): number;
14
+ export declare function errorMessage(error: unknown): string;
15
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,QAAQ,MAAM;CACxB;AAED,qBAAa,QAAS,SAAQ,KAAK;IAI/B,QAAQ,CAAC,IAAI,EAAE,MAAM;IAErB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAL1B,QAAQ,CAAC,QAAQ,MAAM;gBAGZ,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACN,MAAM,CAAC,EAAE,MAAM,YAAA;CAI3B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,MAAM;CACxB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASlD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD"}
package/dist/errors.js ADDED
@@ -0,0 +1,28 @@
1
+ export class UsageError extends Error {
2
+ exitCode = 64;
3
+ }
4
+ export class ApiError extends Error {
5
+ code;
6
+ status;
7
+ exitCode = 69;
8
+ constructor(code, message, status) {
9
+ super(message);
10
+ this.code = code;
11
+ this.status = status;
12
+ }
13
+ }
14
+ export class ConfigurationError extends Error {
15
+ exitCode = 78;
16
+ }
17
+ export function exitCodeFor(error) {
18
+ if (error instanceof UsageError ||
19
+ error instanceof ApiError ||
20
+ error instanceof ConfigurationError) {
21
+ return error.exitCode;
22
+ }
23
+ return 1;
24
+ }
25
+ export function errorMessage(error) {
26
+ return error instanceof Error ? error.message : String(error);
27
+ }
28
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,QAAQ,GAAG,EAAE,CAAC;CACxB;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IAItB;IAEA;IALF,QAAQ,GAAG,EAAE,CAAC;IAEvB,YACW,IAAY,EACrB,OAAe,EACN,MAAe;QAExB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,SAAI,GAAJ,IAAI,CAAQ;QAEZ,WAAM,GAAN,MAAM,CAAS;IAG1B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,QAAQ,GAAG,EAAE,CAAC;CACxB;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IACE,KAAK,YAAY,UAAU;QAC3B,KAAK,YAAY,QAAQ;QACzB,KAAK,YAAY,kBAAkB,EACnC,CAAC;QACD,OAAO,KAAK,CAAC,QAAQ,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,296 @@
1
+ #!/usr/bin/env node
2
+ import { clearConfig, loadConfig, parsePositiveInteger, saveConfig } from "./config.js";
3
+ import { ApiError, UsageError, errorMessage, exitCodeFor } from "./errors.js";
4
+ import { prepareFiles, prepareSite } from "./input.js";
5
+ import { WirecopyApi, waitForAvailable } from "./api.js";
6
+ const USAGE = `Wirecopy - publish files and working web artifacts
7
+
8
+ Usage:
9
+ wirecopy configure [--token wc_live_...] [--server URL] [--expires seconds]
10
+ wirecopy logout
11
+ wirecopy publish <path> [more paths] [--expires seconds] [--format raw|markdown|html|json]
12
+ wirecopy site <index.html|site.zip|folder> [--storage managed|byos] [--expires seconds] [--json]
13
+ wirecopy links [--json]
14
+ wirecopy links revoke <id>
15
+
16
+ Environment:
17
+ WIRECOPY_TOKEN, WIRECOPY_SERVER, WIRECOPY_EXPIRES_IN, WIRECOPY_CONFIG_FILE`;
18
+ async function main(arguments_) {
19
+ const [command, ...argumentsAfterCommand] = arguments_;
20
+ if (!command || ["help", "--help", "-h"].includes(command)) {
21
+ console.log(USAGE);
22
+ return;
23
+ }
24
+ switch (command) {
25
+ case "configure":
26
+ await configure(argumentsAfterCommand);
27
+ break;
28
+ case "logout":
29
+ await clearConfig();
30
+ console.log("Removed the stored Wirecopy token.");
31
+ break;
32
+ case "publish":
33
+ case "send":
34
+ await publish(argumentsAfterCommand);
35
+ break;
36
+ case "site":
37
+ await publishSite(argumentsAfterCommand);
38
+ break;
39
+ case "links":
40
+ await links(argumentsAfterCommand);
41
+ break;
42
+ default:
43
+ throw new UsageError(`Unknown command: ${command}`);
44
+ }
45
+ }
46
+ async function configure(arguments_) {
47
+ const options = parseOptions(arguments_, ["--token", "--server", "--expires"], []);
48
+ if (options.positionals.length > 0) {
49
+ throw new UsageError("configure does not accept positional arguments.");
50
+ }
51
+ const token = options.values.get("--token");
52
+ const resolvedToken = token ?? process.env.WIRECOPY_TOKEN ?? await readSecret();
53
+ if (!resolvedToken) {
54
+ throw new UsageError("configure requires an interactive terminal, --token wc_live_…, or WIRECOPY_TOKEN.");
55
+ }
56
+ const server = options.values.get("--server");
57
+ const expires = options.values.get("--expires");
58
+ const path = await saveConfig({
59
+ token: resolvedToken,
60
+ ...(server ? { server } : {}),
61
+ ...(expires ? { expiresIn: positiveInteger(expires, "--expires") } : {}),
62
+ });
63
+ console.log(`Configured Wirecopy. Credentials stored in ${path}.`);
64
+ }
65
+ async function publish(arguments_) {
66
+ const options = parseOptions(arguments_, ["--expires", "--format"], ["--json"]);
67
+ if (options.positionals.length === 0) {
68
+ throw new UsageError("publish requires one or more file paths.");
69
+ }
70
+ const config = await loadConfig();
71
+ const expiresIn = options.values.has("--expires")
72
+ ? positiveInteger(options.values.get("--expires"), "--expires")
73
+ : config.expiresIn;
74
+ const format = options.flags.has("--json")
75
+ ? "json"
76
+ : options.values.get("--format") ?? "raw";
77
+ if (!["raw", "markdown", "html", "json"].includes(format)) {
78
+ throw new UsageError("--format must be raw, markdown, html, or json.");
79
+ }
80
+ const input = await prepareFiles(options.positionals);
81
+ try {
82
+ const api = new WirecopyApi(config.server, config.token);
83
+ progress("Authorizing");
84
+ const created = await api.createIntent(input, expiresIn);
85
+ if (!created.upload) {
86
+ throw new ApiError("invalid_response", "The Wirecopy service did not return an upload grant.");
87
+ }
88
+ progress("Uploading");
89
+ await api.upload(input, created.upload);
90
+ progress("Safety check");
91
+ const intent = await waitForAvailable(api, await api.completeIntent(created.id));
92
+ clearProgress();
93
+ const link = {
94
+ url: intent.link.url,
95
+ filename: input.filename,
96
+ byte_size: input.byteSize,
97
+ expires_at: intent.link.expires_at,
98
+ };
99
+ console.log(formatLink(link, format));
100
+ }
101
+ finally {
102
+ await input.cleanup();
103
+ }
104
+ }
105
+ async function publishSite(arguments_) {
106
+ const options = parseOptions(arguments_, ["--expires", "--storage"], ["--json"]);
107
+ if (options.positionals.length !== 1) {
108
+ throw new UsageError("site requires one HTML file, ZIP, or site folder.");
109
+ }
110
+ const storage = options.values.get("--storage");
111
+ if (storage && !["managed", "byos"].includes(storage)) {
112
+ throw new UsageError("--storage must be managed or byos.");
113
+ }
114
+ const config = await loadConfig();
115
+ const expiresIn = options.values.has("--expires")
116
+ ? positiveInteger(options.values.get("--expires"), "--expires")
117
+ : config.expiresIn;
118
+ const input = await prepareSite(options.positionals[0]);
119
+ try {
120
+ progress("Publishing site");
121
+ const site = await new WirecopyApi(config.server, config.token).publishSite(input, expiresIn, storage);
122
+ clearProgress();
123
+ console.log(options.flags.has("--json") ? JSON.stringify(site) : site.url);
124
+ }
125
+ catch (error) {
126
+ throw storageHint(error);
127
+ }
128
+ finally {
129
+ await input.cleanup();
130
+ }
131
+ }
132
+ async function links(arguments_) {
133
+ const config = await loadConfig();
134
+ const api = new WirecopyApi(config.server, config.token);
135
+ if (arguments_[0] === "revoke") {
136
+ if (arguments_.length !== 2 || !/^[1-9]\d*$/.test(arguments_[1])) {
137
+ throw new UsageError("links revoke requires a numeric link ID.");
138
+ }
139
+ const id = Number(arguments_[1]);
140
+ await api.revokeLink(id);
141
+ console.log(`Revoked link ${id}.`);
142
+ return;
143
+ }
144
+ const options = parseOptions(arguments_, [], ["--json"]);
145
+ if (options.positionals.length > 0) {
146
+ throw new UsageError(`Unknown links action: ${options.positionals[0]}`);
147
+ }
148
+ const result = await api.links();
149
+ if (options.flags.has("--json")) {
150
+ console.log(JSON.stringify(result));
151
+ }
152
+ else if (result.length === 0) {
153
+ console.log("No links.");
154
+ }
155
+ else {
156
+ for (const link of result) {
157
+ console.log(formatLinkRow(link));
158
+ }
159
+ }
160
+ }
161
+ function parseOptions(arguments_, valueOptions, flagOptions) {
162
+ const positionals = [];
163
+ const flags = new Set();
164
+ const values = new Map();
165
+ for (let index = 0; index < arguments_.length; index += 1) {
166
+ const argument = arguments_[index];
167
+ if (valueOptions.includes(argument)) {
168
+ const value = arguments_[index + 1];
169
+ if (!value || value.startsWith("--")) {
170
+ throw new UsageError(`${argument} requires a value.`);
171
+ }
172
+ values.set(argument, value);
173
+ index += 1;
174
+ }
175
+ else if (flagOptions.includes(argument)) {
176
+ flags.add(argument);
177
+ }
178
+ else if (argument.startsWith("--")) {
179
+ throw new UsageError(`Unknown option: ${argument}`);
180
+ }
181
+ else {
182
+ positionals.push(argument);
183
+ }
184
+ }
185
+ return { positionals, flags, values };
186
+ }
187
+ function positiveInteger(value, label) {
188
+ try {
189
+ return parsePositiveInteger(value, label);
190
+ }
191
+ catch (error) {
192
+ throw new UsageError(errorMessage(error));
193
+ }
194
+ }
195
+ function formatLink(link, format) {
196
+ switch (format) {
197
+ case "markdown":
198
+ return `[${link.filename.replaceAll("\\", "\\\\").replaceAll("]", "\\]")}](${link.url})`;
199
+ case "html":
200
+ return `<a href="${escapeHtml(link.url)}">${escapeHtml(link.filename)}</a>`;
201
+ case "json":
202
+ return JSON.stringify(link);
203
+ default:
204
+ return link.url;
205
+ }
206
+ }
207
+ function formatLinkRow(link) {
208
+ const available = link.revoked_at === null && new Date(link.expires_at) > new Date();
209
+ return `${link.id}\t${available ? "live" : "ended"}\t${link.filename}\t${link.url}`;
210
+ }
211
+ function escapeHtml(value) {
212
+ return value
213
+ .replaceAll("&", "&amp;")
214
+ .replaceAll('"', "&quot;")
215
+ .replaceAll("<", "&lt;")
216
+ .replaceAll(">", "&gt;");
217
+ }
218
+ function progress(message) {
219
+ if (process.stderr.isTTY) {
220
+ process.stderr.write(`\r${message.padEnd(24)}`);
221
+ }
222
+ else {
223
+ process.stderr.write(`${message}\n`);
224
+ }
225
+ }
226
+ function clearProgress() {
227
+ if (process.stderr.isTTY) {
228
+ process.stderr.write("\r \r");
229
+ }
230
+ }
231
+ function storageHint(error) {
232
+ if (!(error instanceof ApiError)) {
233
+ return error;
234
+ }
235
+ if (error.code === "plan_required") {
236
+ return new ApiError(error.code, `${error.message}\nHint: your bucket needs a Pro plan. Omit --storage byos to use managed storage.`, error.status);
237
+ }
238
+ if (error.code === "byos_unavailable") {
239
+ return new ApiError(error.code, `${error.message}\nHint: connect and verify a bucket in the web dashboard, or omit --storage byos.`, error.status);
240
+ }
241
+ return error;
242
+ }
243
+ async function readSecret() {
244
+ if (!process.stdin.isTTY || !process.stderr.isTTY || !process.stdin.setRawMode) {
245
+ return undefined;
246
+ }
247
+ process.stderr.write("Device token: ");
248
+ process.stdin.setEncoding("utf8");
249
+ process.stdin.setRawMode(true);
250
+ process.stdin.resume();
251
+ let value = "";
252
+ try {
253
+ return await new Promise((resolve, reject) => {
254
+ const finish = (callback) => {
255
+ process.stdin.off("data", onData);
256
+ process.stdin.off("error", onError);
257
+ callback();
258
+ };
259
+ const onError = (error) => finish(() => reject(error));
260
+ const onData = (chunk) => {
261
+ for (const character of chunk) {
262
+ if (character === "\u0003") {
263
+ finish(() => reject(new UsageError("Configuration cancelled.")));
264
+ return;
265
+ }
266
+ if (character === "\r" || character === "\n") {
267
+ finish(() => resolve(value.trim()));
268
+ return;
269
+ }
270
+ if (character === "\u007f" || character === "\b") {
271
+ value = value.slice(0, -1);
272
+ }
273
+ else {
274
+ value += character;
275
+ }
276
+ }
277
+ };
278
+ process.stdin.on("data", onData);
279
+ process.stdin.on("error", onError);
280
+ });
281
+ }
282
+ finally {
283
+ process.stdin.setRawMode(false);
284
+ process.stdin.pause();
285
+ process.stderr.write("\n");
286
+ }
287
+ }
288
+ main(process.argv.slice(2)).catch((error) => {
289
+ clearProgress();
290
+ process.stderr.write(`wirecopy: ${errorMessage(error)}\n`);
291
+ if (error instanceof UsageError) {
292
+ process.stderr.write("Run 'wirecopy --help' for usage.\n");
293
+ }
294
+ process.exitCode = exitCodeFor(error);
295
+ });
296
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface PreparedInput {
2
+ path: string;
3
+ filename: string;
4
+ contentType: string;
5
+ byteSize: number;
6
+ cleanup(): Promise<void>;
7
+ }
8
+ export declare function prepareFiles(inputs: string[]): Promise<PreparedInput>;
9
+ export declare function prepareSite(input: string): Promise<PreparedInput>;
10
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CA4B3E;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA6BvE"}
package/dist/input.js ADDED
@@ -0,0 +1,95 @@
1
+ import { mkdtemp, rm, stat } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { basename, extname, join, resolve } from "node:path";
4
+ import { UsageError } from "./errors.js";
5
+ import { zipFiles, zipSite } from "./zip.js";
6
+ export async function prepareFiles(inputs) {
7
+ const paths = inputs.map((input) => resolvePath(input));
8
+ if (paths.length === 1) {
9
+ const path = paths[0];
10
+ const info = await stat(path).catch(() => undefined);
11
+ if (!info?.isFile()) {
12
+ throw new UsageError(`Cannot publish unreadable file or directory: ${path}`);
13
+ }
14
+ return {
15
+ path,
16
+ filename: safeFilename(basename(path)),
17
+ contentType: contentTypeFor(path),
18
+ byteSize: info.size,
19
+ cleanup: async () => { },
20
+ };
21
+ }
22
+ const temporaryDirectory = await mkdtemp(join(tmpdir(), "wirecopy-"));
23
+ const output = join(temporaryDirectory, "wirecopy-files.zip");
24
+ await zipFiles(paths, output);
25
+ const info = await stat(output);
26
+ return {
27
+ path: output,
28
+ filename: "wirecopy-files.zip",
29
+ contentType: "application/zip",
30
+ byteSize: info.size,
31
+ cleanup: () => rm(temporaryDirectory, { recursive: true, force: true }),
32
+ };
33
+ }
34
+ export async function prepareSite(input) {
35
+ const path = resolvePath(input);
36
+ const info = await stat(path).catch(() => undefined);
37
+ if (info?.isDirectory()) {
38
+ const temporaryDirectory = await mkdtemp(join(tmpdir(), "wirecopy-site-"));
39
+ const output = join(temporaryDirectory, `${safeFilename(basename(path)) || "site"}.zip`);
40
+ await zipSite(path, output);
41
+ const archiveInfo = await stat(output);
42
+ return {
43
+ path: output,
44
+ filename: basename(output),
45
+ contentType: "application/zip",
46
+ byteSize: archiveInfo.size,
47
+ cleanup: () => rm(temporaryDirectory, { recursive: true, force: true }),
48
+ };
49
+ }
50
+ if (!info?.isFile()) {
51
+ throw new UsageError("Choose an HTML file, ZIP, or folder containing index.html.");
52
+ }
53
+ if (![".html", ".htm", ".zip"].includes(extname(path).toLowerCase())) {
54
+ throw new UsageError("Site publishing accepts .html, .htm, or .zip inputs.");
55
+ }
56
+ return {
57
+ path,
58
+ filename: safeFilename(basename(path)),
59
+ contentType: contentTypeFor(path),
60
+ byteSize: info.size,
61
+ cleanup: async () => { },
62
+ };
63
+ }
64
+ function resolvePath(input) {
65
+ if (input === "~") {
66
+ return process.env.HOME ?? input;
67
+ }
68
+ if (input.startsWith("~/") && process.env.HOME) {
69
+ return resolve(process.env.HOME, input.slice(2));
70
+ }
71
+ return resolve(input);
72
+ }
73
+ function safeFilename(value) {
74
+ return value.replaceAll("/", "_").replaceAll("\0", "_");
75
+ }
76
+ function contentTypeFor(path) {
77
+ const types = {
78
+ ".css": "text/css",
79
+ ".gif": "image/gif",
80
+ ".htm": "text/html",
81
+ ".html": "text/html",
82
+ ".jpeg": "image/jpeg",
83
+ ".jpg": "image/jpeg",
84
+ ".json": "application/json",
85
+ ".md": "text/markdown",
86
+ ".pdf": "application/pdf",
87
+ ".png": "image/png",
88
+ ".svg": "image/svg+xml",
89
+ ".txt": "text/plain",
90
+ ".webp": "image/webp",
91
+ ".zip": "application/zip",
92
+ };
93
+ return types[extname(path).toLowerCase()] ?? "application/octet-stream";
94
+ }
95
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
package/dist/zip.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare function zipFiles(paths: string[], destination: string): Promise<void>;
2
+ export declare function zipSite(directory: string, destination: string): Promise<void>;
3
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../src/zip.ts"],"names":[],"mappings":"AAuBA,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlF;AAED,wBAAsB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnF"}
package/dist/zip.js ADDED
@@ -0,0 +1,158 @@
1
+ import { open, readFile, readdir, stat } from "node:fs/promises";
2
+ import { basename, relative, resolve, sep } from "node:path";
3
+ import { UsageError } from "./errors.js";
4
+ const LOCAL_SIGNATURE = 0x04034b50;
5
+ const CENTRAL_SIGNATURE = 0x02014b50;
6
+ const END_SIGNATURE = 0x06054b50;
7
+ const UTF8_FLAG = 0x0800;
8
+ const DOS_DATE_1980_01_01 = 0x0021;
9
+ export async function zipFiles(paths, destination) {
10
+ const used = new Set();
11
+ const sources = [];
12
+ const sorted = [...paths].sort((left, right) => basename(left).localeCompare(basename(right)));
13
+ for (const path of sorted) {
14
+ const info = await stat(path).catch(() => undefined);
15
+ if (!info?.isFile()) {
16
+ throw new UsageError(`Cannot publish unreadable file or directory: ${path}`);
17
+ }
18
+ sources.push({ absolutePath: path, archivePath: uniqueName(basename(path), used) });
19
+ }
20
+ await writeZip(sources, destination);
21
+ }
22
+ export async function zipSite(directory, destination) {
23
+ const root = resolve(directory);
24
+ const sources = await collectSiteFiles(root);
25
+ if (!sources.some((source) => source.archivePath === "index.html")) {
26
+ throw new UsageError("The site folder needs an index.html file at its root.");
27
+ }
28
+ await writeZip(sources, destination);
29
+ }
30
+ async function collectSiteFiles(root, current = root) {
31
+ const entries = await readdir(current, { withFileTypes: true });
32
+ const sources = [];
33
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
34
+ if (entry.name.startsWith(".")) {
35
+ continue;
36
+ }
37
+ const path = resolve(current, entry.name);
38
+ if (entry.isSymbolicLink()) {
39
+ throw new UsageError("Site folders cannot contain symbolic links.");
40
+ }
41
+ if (entry.isDirectory()) {
42
+ sources.push(...await collectSiteFiles(root, path));
43
+ }
44
+ else if (entry.isFile()) {
45
+ const archivePath = relative(root, path).split(sep).join("/");
46
+ if (!archivePath || archivePath.split("/").includes("..")) {
47
+ throw new UsageError("The site folder contains an unsafe path.");
48
+ }
49
+ sources.push({ absolutePath: path, archivePath });
50
+ }
51
+ }
52
+ return sources;
53
+ }
54
+ async function writeZip(sources, destination) {
55
+ if (sources.length > 65_535) {
56
+ throw new UsageError("ZIP archives cannot contain more than 65,535 files.");
57
+ }
58
+ const output = await open(destination, "w", 0o600);
59
+ const entries = [];
60
+ let position = 0;
61
+ try {
62
+ for (const source of sources) {
63
+ const bytes = await readFile(source.absolutePath);
64
+ const name = Buffer.from(source.archivePath, "utf8");
65
+ const crc = crc32(bytes);
66
+ assertZip32(position, bytes.length);
67
+ const header = Buffer.alloc(30);
68
+ header.writeUInt32LE(LOCAL_SIGNATURE, 0);
69
+ header.writeUInt16LE(20, 4);
70
+ header.writeUInt16LE(UTF8_FLAG, 6);
71
+ header.writeUInt16LE(0, 8);
72
+ header.writeUInt16LE(0, 10);
73
+ header.writeUInt16LE(DOS_DATE_1980_01_01, 12);
74
+ header.writeUInt32LE(crc, 14);
75
+ header.writeUInt32LE(bytes.length, 18);
76
+ header.writeUInt32LE(bytes.length, 22);
77
+ header.writeUInt16LE(name.length, 26);
78
+ header.writeUInt16LE(0, 28);
79
+ await output.write(header, 0, header.length, position);
80
+ await output.write(name, 0, name.length, position + header.length);
81
+ await output.write(bytes, 0, bytes.length, position + header.length + name.length);
82
+ entries.push({ name, crc, size: bytes.length, offset: position });
83
+ position += header.length + name.length + bytes.length;
84
+ }
85
+ const centralOffset = position;
86
+ for (const entry of entries) {
87
+ const header = Buffer.alloc(46);
88
+ header.writeUInt32LE(CENTRAL_SIGNATURE, 0);
89
+ header.writeUInt16LE(0x0314, 4);
90
+ header.writeUInt16LE(20, 6);
91
+ header.writeUInt16LE(UTF8_FLAG, 8);
92
+ header.writeUInt16LE(0, 10);
93
+ header.writeUInt16LE(0, 12);
94
+ header.writeUInt16LE(DOS_DATE_1980_01_01, 14);
95
+ header.writeUInt32LE(entry.crc, 16);
96
+ header.writeUInt32LE(entry.size, 20);
97
+ header.writeUInt32LE(entry.size, 24);
98
+ header.writeUInt16LE(entry.name.length, 28);
99
+ header.writeUInt16LE(0, 30);
100
+ header.writeUInt16LE(0, 32);
101
+ header.writeUInt16LE(0, 34);
102
+ header.writeUInt16LE(0, 36);
103
+ header.writeUInt32LE(0x81a40000, 38);
104
+ header.writeUInt32LE(entry.offset, 42);
105
+ await output.write(header, 0, header.length, position);
106
+ await output.write(entry.name, 0, entry.name.length, position + header.length);
107
+ position += header.length + entry.name.length;
108
+ }
109
+ const centralSize = position - centralOffset;
110
+ assertZip32(centralOffset, centralSize);
111
+ const end = Buffer.alloc(22);
112
+ end.writeUInt32LE(END_SIGNATURE, 0);
113
+ end.writeUInt16LE(0, 4);
114
+ end.writeUInt16LE(0, 6);
115
+ end.writeUInt16LE(entries.length, 8);
116
+ end.writeUInt16LE(entries.length, 10);
117
+ end.writeUInt32LE(centralSize, 12);
118
+ end.writeUInt32LE(centralOffset, 16);
119
+ end.writeUInt16LE(0, 20);
120
+ await output.write(end, 0, end.length, position);
121
+ }
122
+ finally {
123
+ await output.close();
124
+ }
125
+ }
126
+ function uniqueName(input, used) {
127
+ const clean = input.replaceAll("/", "_").replaceAll("\0", "_");
128
+ if (!used.has(clean)) {
129
+ used.add(clean);
130
+ return clean;
131
+ }
132
+ const dot = clean.lastIndexOf(".");
133
+ const stem = dot > 0 ? clean.slice(0, dot) : clean;
134
+ const extension = dot > 0 ? clean.slice(dot) : "";
135
+ for (let index = 2;; index += 1) {
136
+ const candidate = `${stem}-${index}${extension}`;
137
+ if (!used.has(candidate)) {
138
+ used.add(candidate);
139
+ return candidate;
140
+ }
141
+ }
142
+ }
143
+ function assertZip32(...values) {
144
+ if (values.some((value) => value > 0xffff_ffff)) {
145
+ throw new UsageError("The archive is too large for the supported ZIP format.");
146
+ }
147
+ }
148
+ function crc32(bytes) {
149
+ let crc = 0xffff_ffff;
150
+ for (const byte of bytes) {
151
+ crc ^= byte;
152
+ for (let bit = 0; bit < 8; bit += 1) {
153
+ crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
154
+ }
155
+ }
156
+ return (crc ^ 0xffff_ffff) >>> 0;
157
+ }
158
+ //# sourceMappingURL=zip.js.map