@within-7/jetr 0.1.1 → 0.2.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 +3 -1
- package/dist/cli.js +137 -11
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -133,7 +133,9 @@ Config is stored at `~/.jetr/config.json`:
|
|
|
133
133
|
|
|
134
134
|
```json
|
|
135
135
|
{
|
|
136
|
-
"apiUrl": "https://jetr-api.
|
|
136
|
+
"apiUrl": "https://your-jetr-api.workers.dev",
|
|
137
137
|
"token": "eyJhbG..."
|
|
138
138
|
}
|
|
139
139
|
```
|
|
140
|
+
|
|
141
|
+
Override API URL with `jetr login <token> --api-url <url>`.
|
package/dist/cli.js
CHANGED
|
@@ -128,34 +128,149 @@ var api = {
|
|
|
128
128
|
|
|
129
129
|
// src/deploy.ts
|
|
130
130
|
import { createHash } from "crypto";
|
|
131
|
-
import { readFileSync as
|
|
132
|
-
import { resolve, join as
|
|
131
|
+
import { readFileSync as readFileSync3, statSync } from "fs";
|
|
132
|
+
import { resolve, join as join3, posix } from "path";
|
|
133
133
|
import { glob } from "glob";
|
|
134
|
+
|
|
135
|
+
// src/ignore.ts
|
|
136
|
+
import ignore from "ignore";
|
|
137
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
138
|
+
import { join as join2 } from "path";
|
|
139
|
+
var DEFAULT_JETRIGNORE = `# Dependencies
|
|
140
|
+
node_modules/
|
|
141
|
+
.pnp
|
|
142
|
+
.pnp.js
|
|
143
|
+
|
|
144
|
+
# Build outputs
|
|
145
|
+
dist/
|
|
146
|
+
build/
|
|
147
|
+
out/
|
|
148
|
+
.next/
|
|
149
|
+
.nuxt/
|
|
150
|
+
.output/
|
|
151
|
+
.cache/
|
|
152
|
+
|
|
153
|
+
# Logs
|
|
154
|
+
*.log
|
|
155
|
+
npm-debug.log*
|
|
156
|
+
yarn-debug.log*
|
|
157
|
+
yarn-error.log*
|
|
158
|
+
pnpm-debug.log*
|
|
159
|
+
|
|
160
|
+
# Environment
|
|
161
|
+
.env
|
|
162
|
+
.env.*
|
|
163
|
+
.env.local
|
|
164
|
+
.env.*.local
|
|
165
|
+
|
|
166
|
+
# IDE & Editor
|
|
167
|
+
.vscode/
|
|
168
|
+
.idea/
|
|
169
|
+
*.swp
|
|
170
|
+
*.swo
|
|
171
|
+
*~
|
|
172
|
+
.project
|
|
173
|
+
.classpath
|
|
174
|
+
.settings/
|
|
175
|
+
|
|
176
|
+
# OS files
|
|
177
|
+
.DS_Store
|
|
178
|
+
Thumbs.db
|
|
179
|
+
desktop.ini
|
|
180
|
+
|
|
181
|
+
# Git
|
|
182
|
+
.git/
|
|
183
|
+
.gitignore
|
|
184
|
+
|
|
185
|
+
# Testing
|
|
186
|
+
coverage/
|
|
187
|
+
.nyc_output/
|
|
188
|
+
|
|
189
|
+
# Package managers
|
|
190
|
+
package-lock.json
|
|
191
|
+
yarn.lock
|
|
192
|
+
pnpm-lock.yaml
|
|
193
|
+
|
|
194
|
+
# Misc
|
|
195
|
+
*.zip
|
|
196
|
+
*.tar.gz
|
|
197
|
+
`;
|
|
198
|
+
var ALWAYS_IGNORE = [".jetrignore", ".jetrkeep", ".jetrrc"];
|
|
199
|
+
function loadIgnore(dir) {
|
|
200
|
+
const ig = ignore();
|
|
201
|
+
ig.add(ALWAYS_IGNORE);
|
|
202
|
+
const ignorePath = join2(dir, ".jetrignore");
|
|
203
|
+
if (existsSync2(ignorePath)) {
|
|
204
|
+
const content = readFileSync2(ignorePath, "utf-8");
|
|
205
|
+
ig.add(content);
|
|
206
|
+
} else {
|
|
207
|
+
ig.add(DEFAULT_JETRIGNORE);
|
|
208
|
+
}
|
|
209
|
+
return ig;
|
|
210
|
+
}
|
|
211
|
+
function loadKeep(dir) {
|
|
212
|
+
const keepPath = join2(dir, ".jetrkeep");
|
|
213
|
+
if (!existsSync2(keepPath)) return null;
|
|
214
|
+
const keep = ignore();
|
|
215
|
+
keep.add(readFileSync2(keepPath, "utf-8"));
|
|
216
|
+
return keep;
|
|
217
|
+
}
|
|
218
|
+
function shouldInclude(relativePath, ig, keep) {
|
|
219
|
+
if (ig.ignores(relativePath) || ig.ignores(relativePath + "/")) {
|
|
220
|
+
if (keep && keep.ignores(relativePath)) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
function createJetrignore(dir) {
|
|
228
|
+
const ignorePath = join2(dir, ".jetrignore");
|
|
229
|
+
if (existsSync2(ignorePath)) return false;
|
|
230
|
+
writeFileSync2(ignorePath, DEFAULT_JETRIGNORE);
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/deploy.ts
|
|
134
235
|
function hashFile(filePath) {
|
|
135
|
-
const content =
|
|
236
|
+
const content = readFileSync3(filePath);
|
|
136
237
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
137
238
|
return `sha256:${hash}`;
|
|
138
239
|
}
|
|
139
240
|
async function deploy(siteName, directory, onProgress) {
|
|
140
241
|
const absDir = resolve(directory);
|
|
242
|
+
const ig = loadIgnore(absDir);
|
|
243
|
+
const keep = loadKeep(absDir);
|
|
141
244
|
onProgress?.("Scanning files...");
|
|
142
|
-
const
|
|
245
|
+
const allFiles = await glob("**/*", {
|
|
143
246
|
cwd: absDir,
|
|
144
247
|
nodir: true,
|
|
145
|
-
dot:
|
|
248
|
+
dot: true
|
|
146
249
|
});
|
|
250
|
+
let ignoredCount = 0;
|
|
251
|
+
const filePaths = [];
|
|
252
|
+
for (const fp of allFiles) {
|
|
253
|
+
const normalizedPath = fp.split("/").join(posix.sep);
|
|
254
|
+
if (shouldInclude(normalizedPath, ig, keep)) {
|
|
255
|
+
filePaths.push(fp);
|
|
256
|
+
} else {
|
|
257
|
+
ignoredCount++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
147
260
|
if (filePaths.length === 0) {
|
|
148
|
-
throw new Error(
|
|
261
|
+
throw new Error(
|
|
262
|
+
`No files to deploy in ${directory} (${allFiles.length} files found, all ignored)`
|
|
263
|
+
);
|
|
149
264
|
}
|
|
265
|
+
onProgress?.(`Found ${filePaths.length} files (${ignoredCount} ignored)`);
|
|
150
266
|
const manifest = {};
|
|
151
267
|
for (const fp of filePaths) {
|
|
152
|
-
const absPath =
|
|
268
|
+
const absPath = join3(absDir, fp);
|
|
153
269
|
const hash = hashFile(absPath);
|
|
154
270
|
const size = statSync(absPath).size;
|
|
155
271
|
const normalizedPath = fp.split("/").join(posix.sep);
|
|
156
272
|
manifest[normalizedPath] = { hash, size };
|
|
157
273
|
}
|
|
158
|
-
onProgress?.(`Found ${filePaths.length} files`);
|
|
159
274
|
onProgress?.("Computing diff...");
|
|
160
275
|
const diff = await api.deployDiff(siteName, manifest);
|
|
161
276
|
onProgress?.(
|
|
@@ -164,8 +279,8 @@ async function deploy(siteName, directory, onProgress) {
|
|
|
164
279
|
if (diff.upload.length > 0) {
|
|
165
280
|
for (let i = 0; i < diff.upload.length; i++) {
|
|
166
281
|
const fp = diff.upload[i];
|
|
167
|
-
const absPath =
|
|
168
|
-
const content =
|
|
282
|
+
const absPath = join3(absDir, fp);
|
|
283
|
+
const content = readFileSync3(absPath);
|
|
169
284
|
onProgress?.(`Uploading (${i + 1}/${diff.upload.length}) ${fp}`);
|
|
170
285
|
await api.uploadFile(siteName, fp, content, diff.deploy_id, manifest[fp].hash);
|
|
171
286
|
}
|
|
@@ -177,13 +292,14 @@ async function deploy(siteName, directory, onProgress) {
|
|
|
177
292
|
filesUploaded: result.files_uploaded,
|
|
178
293
|
filesDeleted: result.files_deleted,
|
|
179
294
|
filesUnchanged: diff.unchanged.length,
|
|
295
|
+
filesIgnored: ignoredCount,
|
|
180
296
|
totalSize: result.total_size
|
|
181
297
|
};
|
|
182
298
|
}
|
|
183
299
|
|
|
184
300
|
// src/cli.ts
|
|
185
301
|
var program = new Command();
|
|
186
|
-
program.name("jetr").description("CLI for Jetr static site hosting").version("0.
|
|
302
|
+
program.name("jetr").description("CLI for Jetr static site hosting").version("0.2.0");
|
|
187
303
|
program.command("login").description("Save JWT token for authentication").argument("<token>", "JWT token from auth-gateway login").option("--api-url <url>", "API base URL").action((token, opts) => {
|
|
188
304
|
saveConfig({ token, ...opts.apiUrl ? { apiUrl: opts.apiUrl } : {} });
|
|
189
305
|
console.log(chalk.green("\u2713 Token saved to ~/.jetr/config.json"));
|
|
@@ -193,6 +309,15 @@ program.command("whoami").description("Show current config").action(() => {
|
|
|
193
309
|
console.log(`API: ${config.apiUrl}`);
|
|
194
310
|
console.log(`Token: ${config.token ? config.token.slice(0, 20) + "..." : chalk.red("not set")}`);
|
|
195
311
|
});
|
|
312
|
+
program.command("init").description("Create a .jetrignore file with default patterns").argument("[directory]", "Target directory", ".").action(async (directory) => {
|
|
313
|
+
const { resolve: resolve2 } = await import("path");
|
|
314
|
+
const created = createJetrignore(resolve2(directory));
|
|
315
|
+
if (created) {
|
|
316
|
+
console.log(chalk.green("\u2713 Created .jetrignore with default patterns"));
|
|
317
|
+
} else {
|
|
318
|
+
console.log(chalk.yellow(".jetrignore already exists"));
|
|
319
|
+
}
|
|
320
|
+
});
|
|
196
321
|
program.command("create").description("Create a new site").argument("<name>", "Site name (becomes {name}.jetr.within-7.com)").option("-p, --password <password>", "Set access password").option("-e, --expires <seconds>", "Expire after N seconds", parseInt).action(async (name, opts) => {
|
|
197
322
|
const spinner = ora("Creating site...").start();
|
|
198
323
|
try {
|
|
@@ -220,6 +345,7 @@ program.command("deploy").description("Deploy a directory to a site").argument("
|
|
|
220
345
|
console.log(` Uploaded: ${result.filesUploaded} files`);
|
|
221
346
|
if (result.filesDeleted > 0) console.log(` Deleted: ${result.filesDeleted} files`);
|
|
222
347
|
if (result.filesUnchanged > 0) console.log(` Unchanged: ${result.filesUnchanged} files`);
|
|
348
|
+
if (result.filesIgnored > 0) console.log(` Ignored: ${chalk.dim(`${result.filesIgnored} files`)}`);
|
|
223
349
|
console.log(` Size: ${formatBytes(result.totalSize)}`);
|
|
224
350
|
} catch (e) {
|
|
225
351
|
spinner.fail(e.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@within-7/jetr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI for Jetr static site hosting",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"commander": "^13",
|
|
17
17
|
"chalk": "^5",
|
|
18
18
|
"ora": "^8",
|
|
19
|
-
"glob": "^11"
|
|
19
|
+
"glob": "^11",
|
|
20
|
+
"ignore": "^6"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
22
23
|
"tsup": "^8",
|