sealcode 1.1.1 → 1.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/package.json +1 -1
- package/src/cli-grants.js +96 -3
- package/src/cli-watch.js +8 -1
- package/src/cli.js +40 -1
package/package.json
CHANGED
package/src/cli-grants.js
CHANGED
|
@@ -299,8 +299,14 @@ async function runGrants({ projectRoot, json = false }) {
|
|
|
299
299
|
process.stdout.write(`\n${link.projectName || link.projectId}: ${grants.length} grant(s)\n`);
|
|
300
300
|
for (const g of grants) {
|
|
301
301
|
const state = g.state.padEnd(8);
|
|
302
|
-
|
|
303
|
-
|
|
302
|
+
let remaining;
|
|
303
|
+
if (g.state === 'active') {
|
|
304
|
+
remaining = formatRemaining(g.remainingMs);
|
|
305
|
+
} else if (g.state === 'paused') {
|
|
306
|
+
remaining = 'paused';
|
|
307
|
+
} else {
|
|
308
|
+
remaining = g.state;
|
|
309
|
+
}
|
|
304
310
|
const who = g.developerEmail || g.developerLabel || '(no label)';
|
|
305
311
|
process.stdout.write(
|
|
306
312
|
` ${state} ${g.codePrefix.padEnd(12)} ${remaining.padEnd(10)} ${who} id=${g.id}\n`,
|
|
@@ -309,6 +315,85 @@ async function runGrants({ projectRoot, json = false }) {
|
|
|
309
315
|
process.stdout.write('\n');
|
|
310
316
|
}
|
|
311
317
|
|
|
318
|
+
/**
|
|
319
|
+
* sealcode@1.2.0 — Pause an active access code from the CLI.
|
|
320
|
+
*
|
|
321
|
+
* sealcode pause <grantId> [--reason "<text>"] [--extend-on-resume]
|
|
322
|
+
*
|
|
323
|
+
* Mirrors the dashboard pause modal. Owner must be `sealcode login`ed
|
|
324
|
+
* and be admin (or owner) of the project.
|
|
325
|
+
*/
|
|
326
|
+
async function runPause({ grantId, reason, extendOnResume = false }) {
|
|
327
|
+
if (!grantId) throw new Error('Usage: sealcode pause <grantId> [--reason "<text>"] [--extend-on-resume]');
|
|
328
|
+
const body = {};
|
|
329
|
+
if (reason) body.reason = String(reason).slice(0, 500);
|
|
330
|
+
if (extendOnResume) body.extendsExpiry = true;
|
|
331
|
+
try {
|
|
332
|
+
await request(
|
|
333
|
+
'POST',
|
|
334
|
+
`/api/v1/grants/${encodeURIComponent(grantId)}/pause`,
|
|
335
|
+
{ auth: true, body },
|
|
336
|
+
);
|
|
337
|
+
} catch (err) {
|
|
338
|
+
if (err instanceof ApiError && err.status === 409 && err.apiCode === 'wrong_state') {
|
|
339
|
+
ui.fail(err.message || 'Grant is not in a pausable state.');
|
|
340
|
+
process.exitCode = 1;
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
throw err;
|
|
344
|
+
}
|
|
345
|
+
process.stdout.write(`⏸ paused grant ${grantId}\n`);
|
|
346
|
+
if (reason) process.stdout.write(` reason: ${reason}\n`);
|
|
347
|
+
if (extendOnResume) {
|
|
348
|
+
process.stdout.write(` extend-on-resume: expiry will shift forward by the paused duration\n`);
|
|
349
|
+
}
|
|
350
|
+
process.stdout.write(' Any live watcher will re-lock the recipient\'s files within seconds.\n');
|
|
351
|
+
process.stdout.write(` Resume with: ${ui.c.cyan(`sealcode resume ${grantId}`)}\n`);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* sealcode@1.2.0 — Resume a paused access code from the CLI.
|
|
356
|
+
*
|
|
357
|
+
* sealcode resume <grantId>
|
|
358
|
+
*
|
|
359
|
+
* If the grant was paused with --extend-on-resume, the expiresAt shifts
|
|
360
|
+
* forward by the just-elapsed pause duration. The recipient must run
|
|
361
|
+
* `sealcode redeem <code>` again to re-open their working copy.
|
|
362
|
+
*/
|
|
363
|
+
async function runResume({ grantId }) {
|
|
364
|
+
if (!grantId) throw new Error('Usage: sealcode resume <grantId>');
|
|
365
|
+
let res;
|
|
366
|
+
try {
|
|
367
|
+
res = await request(
|
|
368
|
+
'POST',
|
|
369
|
+
`/api/v1/grants/${encodeURIComponent(grantId)}/resume`,
|
|
370
|
+
{ auth: true, body: {} },
|
|
371
|
+
);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
if (err instanceof ApiError) {
|
|
374
|
+
if (err.status === 410) {
|
|
375
|
+
ui.fail(err.message || 'Grant expired while paused.');
|
|
376
|
+
ui.hint(' Issue a fresh access code instead: `sealcode share ...`');
|
|
377
|
+
process.exitCode = 1;
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (err.status === 409 && err.apiCode === 'wrong_state') {
|
|
381
|
+
ui.fail(err.message || 'Grant is not paused.');
|
|
382
|
+
process.exitCode = 1;
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
throw err;
|
|
387
|
+
}
|
|
388
|
+
process.stdout.write(`▶ resumed grant ${grantId}\n`);
|
|
389
|
+
if (res.newExpiresAt) process.stdout.write(` expires: ${res.newExpiresAt}\n`);
|
|
390
|
+
if (res.extendedExpiry) {
|
|
391
|
+
const mins = Math.round((res.pausedDurationMs || 0) / 60000);
|
|
392
|
+
process.stdout.write(` expiry shifted forward by ~${mins}m (paused duration)\n`);
|
|
393
|
+
}
|
|
394
|
+
process.stdout.write(' Recipient must re-redeem the code to re-open the vault.\n');
|
|
395
|
+
}
|
|
396
|
+
|
|
312
397
|
async function runRevoke({ grantId }) {
|
|
313
398
|
if (!grantId) throw new Error('Usage: sealcode revoke <grantId>');
|
|
314
399
|
const res = await request(
|
|
@@ -574,4 +659,12 @@ async function runLockdown({ projectRoot, confirm = true } = {}) {
|
|
|
574
659
|
}
|
|
575
660
|
}
|
|
576
661
|
|
|
577
|
-
module.exports = {
|
|
662
|
+
module.exports = {
|
|
663
|
+
runShare,
|
|
664
|
+
runGrants,
|
|
665
|
+
runRevoke,
|
|
666
|
+
runRedeem,
|
|
667
|
+
runLockdown,
|
|
668
|
+
runPause,
|
|
669
|
+
runResume,
|
|
670
|
+
};
|
package/src/cli-watch.js
CHANGED
|
@@ -780,7 +780,14 @@ async function finalLock(projectRoot, config, code, reason, json, daemon) {
|
|
|
780
780
|
process.stdout.write(JSON.stringify({ type: 'locked', count: res.count, reason: label }) + '\n');
|
|
781
781
|
} else {
|
|
782
782
|
ui.ok(`[${ts()}] re-locked ${ui.c.bold(res.count)} files into ${ui.c.cyan(config.lockedDir + '/')} — session cleared`);
|
|
783
|
-
|
|
783
|
+
// sealcode@1.2.0 — be specific about the "paused" case so the
|
|
784
|
+
// recipient knows it's reversible and what their next step is.
|
|
785
|
+
if (label === 'paused') {
|
|
786
|
+
ui.hint(' This access code was PAUSED by the owner — not revoked.');
|
|
787
|
+
ui.hint(` Wait for the owner to resume, then run: ${ui.c.cyan(`sealcode redeem ${code}`)}`);
|
|
788
|
+
} else {
|
|
789
|
+
ui.hint(' Your local plaintext has been wiped. Ask the owner for a fresh code if you still need access.');
|
|
790
|
+
}
|
|
784
791
|
}
|
|
785
792
|
process.exit(0);
|
|
786
793
|
}
|
package/src/cli.js
CHANGED
|
@@ -33,7 +33,14 @@ const { installHook, uninstallHook } = require('./hooks');
|
|
|
33
33
|
const { exportBundle, importBundle } = require('./bundle');
|
|
34
34
|
const { runLogin, runSignout, runWhoami } = require('./cli-auth');
|
|
35
35
|
const { runLink, runUnlink, runLinkInfo } = require('./cli-link');
|
|
36
|
-
const {
|
|
36
|
+
const {
|
|
37
|
+
runShare,
|
|
38
|
+
runGrants,
|
|
39
|
+
runRevoke,
|
|
40
|
+
runRedeem,
|
|
41
|
+
runPause,
|
|
42
|
+
runResume,
|
|
43
|
+
} = require('./cli-grants');
|
|
37
44
|
const {
|
|
38
45
|
runCiCreate,
|
|
39
46
|
runCiList,
|
|
@@ -748,6 +755,38 @@ function build() {
|
|
|
748
755
|
}
|
|
749
756
|
});
|
|
750
757
|
|
|
758
|
+
// -------- pause (sealcode@1.2.0) --------
|
|
759
|
+
program
|
|
760
|
+
.command('pause')
|
|
761
|
+
.argument('<grantId>', 'grant ID to pause (see `sealcode grants`)')
|
|
762
|
+
.description('Pause an active access code. Reversible: any live watcher re-locks immediately, but you can resume later.')
|
|
763
|
+
.option('--reason <text>', 'optional note visible to project admins (≤500 chars)')
|
|
764
|
+
.option('--extend-on-resume', 'on resume, shift expiry forward by the paused duration (default: clock keeps ticking)', false)
|
|
765
|
+
.action(async (grantId, opts) => {
|
|
766
|
+
try {
|
|
767
|
+
await runPause({
|
|
768
|
+
grantId,
|
|
769
|
+
reason: opts.reason,
|
|
770
|
+
extendOnResume: !!opts.extendOnResume,
|
|
771
|
+
});
|
|
772
|
+
} catch (err) {
|
|
773
|
+
process.exitCode = reportError(err);
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
// -------- resume (sealcode@1.2.0) --------
|
|
778
|
+
program
|
|
779
|
+
.command('resume')
|
|
780
|
+
.argument('<grantId>', 'grant ID to resume (see `sealcode grants`)')
|
|
781
|
+
.description('Resume a paused access code. The recipient must `sealcode redeem <code>` again to re-open their working copy.')
|
|
782
|
+
.action(async (grantId) => {
|
|
783
|
+
try {
|
|
784
|
+
await runResume({ grantId });
|
|
785
|
+
} catch (err) {
|
|
786
|
+
process.exitCode = reportError(err);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
|
|
751
790
|
// -------- lockdown (sealcode@1.1.0) --------
|
|
752
791
|
program
|
|
753
792
|
.command('lockdown')
|