@maka/maka-cli 5.91.0 → 5.92.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/bundle/typescript/package.json +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +9 -9
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.d.ts +54 -3
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.js +987 -53
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.d.ts +0 -14
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js +22 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js +14 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/call.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/call.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +10 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js +8 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js +13 -7
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/project.js +12 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/project.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/reload.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +7 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/use.js +3 -3
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +69 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js +62 -16
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +26 -3
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +95 -3
- package/bundle/typescript/src/commands/game/sideQuest/game.js +191 -13
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/inventory.d.ts +13 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/inventory.js +45 -2
- package/bundle/typescript/src/commands/game/sideQuest/models/inventory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +65 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js +83 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +106 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +128 -9
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/qualities.d.ts +33 -1
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js +12 -2
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene1.json +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene2.json +4 -4
- package/bundle/typescript/src/commands/game/sideQuest/skill-groups.d.ts +120 -0
- package/bundle/typescript/src/commands/game/sideQuest/skill-groups.js +135 -0
- package/bundle/typescript/src/commands/game/sideQuest/skill-groups.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +20 -2
- package/bundle/typescript/src/commands/game/sideQuest/ui.js +14 -0
- package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/alarmed-staff.d.ts +116 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/alarmed-staff.js +127 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/alarmed-staff.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js +123 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.d.ts +131 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js +170 -12
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.d.ts +139 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js +307 -5
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.d.ts +38 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +101 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/session-lock.js +19 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/session-lock.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.d.ts +22 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js +27 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +63 -30
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,11 +6,33 @@ import * as https from 'https';
|
|
|
6
6
|
import { Logger } from './logger.js';
|
|
7
7
|
import { saveSlug, readSave, writeSaveAtomic, tombstonePathFor } from './persistence.js';
|
|
8
8
|
/**
|
|
9
|
-
* CLOUD
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* CLOUD STORAGE for the save slots, and the header this file carried
|
|
10
|
+
* for most of its life is no longer true of half its callers.
|
|
11
|
+
*
|
|
12
|
+
* IT SAID "LOCAL-FIRST -- the local file is always written and always
|
|
13
|
+
* authoritative for play; the cloud is a mirror". That still describes
|
|
14
|
+
* an ANONYMOUS runner exactly, and anonymous is deliberately untouched
|
|
15
|
+
* by all of this. It does NOT describe a BOUND one: the user's ruling
|
|
16
|
+
* is that an account-bound character lives ONLY on the server, because
|
|
17
|
+
* storing them twice produced a class of real bugs -- a deleted
|
|
18
|
+
* character resurrected from the cloud copy, a shared run loading a
|
|
19
|
+
* stale snapshot because the push was never awaited, and silent
|
|
20
|
+
* newest-wins resolution of divergences nobody was told about.
|
|
21
|
+
*
|
|
22
|
+
* So the model is now split, and every branch gates on bound:
|
|
23
|
+
*
|
|
24
|
+
* ANONYMOUS -- local file, authoritative, never leaves the machine.
|
|
25
|
+
* BOUND -- the server is the save. A synchronous local SPILL
|
|
26
|
+
* (persistence.spillPathFor) is a crash journal, not a
|
|
27
|
+
* second home: it exists only between a beat and its
|
|
28
|
+
* confirmed upload, and the next launch uploads and
|
|
29
|
+
* deletes it. Bound is online-only by ruling; an outage
|
|
30
|
+
* mid-session degrades to the spill rather than ending
|
|
31
|
+
* the session.
|
|
32
|
+
*
|
|
33
|
+
* PR1 NOTE: bound runners still write `<slug>.json` as well, so this
|
|
34
|
+
* change is a revert-trivial superset of the old behaviour. PR2 removes
|
|
35
|
+
* that write once the server contract is deployed.
|
|
14
36
|
*
|
|
15
37
|
* Auth rides the same rails as login/logout: the Meteor resume token
|
|
16
38
|
* from global-config.json's `token` property, sent as `x-auth-token`.
|
|
@@ -127,6 +149,15 @@ export async function pushSave(saveFilePath, save) {
|
|
|
127
149
|
noteUnauthorized();
|
|
128
150
|
return 'unauthorized';
|
|
129
151
|
}
|
|
152
|
+
// THE MONOTONIC GUARD (§8): the stored save is newer than ours, so
|
|
153
|
+
// this push would move the runner BACKWARDS. Reported distinctly
|
|
154
|
+
// because retrying it is exactly the wrong response -- see
|
|
155
|
+
// CloudResult. An equal savedAt is idempotent and answers 200, so a
|
|
156
|
+
// 409 always means genuinely behind.
|
|
157
|
+
if (res.statusCode === 409) {
|
|
158
|
+
logger.write(`Cloud sync: push refused as stale (server copy is newer than ${save.savedAt}).`);
|
|
159
|
+
return 'stale';
|
|
160
|
+
}
|
|
130
161
|
logger.write(`Cloud sync: push got ${res.statusCode} -- staying local.`);
|
|
131
162
|
return 'offline';
|
|
132
163
|
}
|
|
@@ -275,4 +306,275 @@ export function reconcile(local, cloud) {
|
|
|
275
306
|
return 'pull-cloud';
|
|
276
307
|
return 'diverged';
|
|
277
308
|
}
|
|
309
|
+
let pending;
|
|
310
|
+
let inFlight = false;
|
|
311
|
+
let retryTimer;
|
|
312
|
+
/** One notice per OUTAGE, not per failed beat -- see noteOutage. */
|
|
313
|
+
let outageAnnounced = false;
|
|
314
|
+
/** Set when a 409 says the server holds something newer than us. */
|
|
315
|
+
let staleAnnounced = false;
|
|
316
|
+
/** Retry cadence when the grid is down. Unref'd: a pending retry must
|
|
317
|
+
* never hold the process open at exit. */
|
|
318
|
+
const RETRY_MS = 60_000;
|
|
319
|
+
function noteOutage() {
|
|
320
|
+
if (outageAnnounced)
|
|
321
|
+
return;
|
|
322
|
+
outageAnnounced = true;
|
|
323
|
+
const logger = Logger.getInstance();
|
|
324
|
+
const line = `The grid dropped -- your progress is recording locally and will upload automatically next launch.`;
|
|
325
|
+
if (logger.hasScreen())
|
|
326
|
+
logger.logWithColor(line, 'yellow');
|
|
327
|
+
else
|
|
328
|
+
logger.write(`Cloud sync: outage -- ${line}`);
|
|
329
|
+
}
|
|
330
|
+
function noteRecovered() {
|
|
331
|
+
if (!outageAnnounced)
|
|
332
|
+
return;
|
|
333
|
+
outageAnnounced = false;
|
|
334
|
+
const logger = Logger.getInstance();
|
|
335
|
+
const line = `The grid's back -- your progress is synced.`;
|
|
336
|
+
if (logger.hasScreen())
|
|
337
|
+
logger.logWithColor(line, 'green');
|
|
338
|
+
else
|
|
339
|
+
logger.write('Cloud sync: recovered.');
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* A 409 means the SERVER is ahead of us: another machine pushed a newer
|
|
343
|
+
* save for this runner. Never overwrite play state from here -- this
|
|
344
|
+
* process is mid-session and its player is looking at the world it
|
|
345
|
+
* believes in. The spill survives, the warning fires once, and the
|
|
346
|
+
* launcher reconciles at the next launch where a human can be asked.
|
|
347
|
+
*/
|
|
348
|
+
function noteStale() {
|
|
349
|
+
if (staleAnnounced)
|
|
350
|
+
return;
|
|
351
|
+
staleAnnounced = true;
|
|
352
|
+
const logger = Logger.getInstance();
|
|
353
|
+
const line = `This runner was saved from somewhere else more recently. Your progress is being kept locally -- sort it out at the next launch.`;
|
|
354
|
+
if (logger.hasScreen())
|
|
355
|
+
logger.logWithColor(line, 'yellow');
|
|
356
|
+
else
|
|
357
|
+
logger.write('Cloud sync: 409 stale -- server copy is newer.');
|
|
358
|
+
}
|
|
359
|
+
/** Test seam: the queue is module state, and a suite that ran two cases
|
|
360
|
+
* against one dirty queue would be testing the previous test. */
|
|
361
|
+
export function _resetPushQueue() {
|
|
362
|
+
pending = undefined;
|
|
363
|
+
inFlight = false;
|
|
364
|
+
if (retryTimer)
|
|
365
|
+
clearTimeout(retryTimer);
|
|
366
|
+
retryTimer = undefined;
|
|
367
|
+
outageAnnounced = false;
|
|
368
|
+
staleAnnounced = false;
|
|
369
|
+
}
|
|
370
|
+
function armRetry() {
|
|
371
|
+
if (retryTimer || !pending)
|
|
372
|
+
return;
|
|
373
|
+
retryTimer = setTimeout(() => {
|
|
374
|
+
retryTimer = undefined;
|
|
375
|
+
void drainQueue();
|
|
376
|
+
}, RETRY_MS);
|
|
377
|
+
// A save waiting to retry must not keep the game alive at exit; the
|
|
378
|
+
// spill on disk is the guarantee, not this timer.
|
|
379
|
+
retryTimer.unref?.();
|
|
380
|
+
}
|
|
381
|
+
async function drainQueue() {
|
|
382
|
+
if (inFlight)
|
|
383
|
+
return;
|
|
384
|
+
const next = pending;
|
|
385
|
+
if (!next)
|
|
386
|
+
return;
|
|
387
|
+
pending = undefined;
|
|
388
|
+
inFlight = true;
|
|
389
|
+
try {
|
|
390
|
+
const res = await next.push(next.saveFilePath, next.save);
|
|
391
|
+
if (res === 'ok') {
|
|
392
|
+
noteRecovered();
|
|
393
|
+
// THE SPILL DIES ONLY ON A CONFIRMED PUSH OF THIS EXACT SAVE.
|
|
394
|
+
// Deleting it on any 200 would drop a NEWER beat's journal when an
|
|
395
|
+
// older push confirmed late -- the out-of-order case single-flight
|
|
396
|
+
// mostly prevents and this makes impossible.
|
|
397
|
+
if (next.spillPath && !pending)
|
|
398
|
+
clearSpill(next.spillPath, next.save.savedAt);
|
|
399
|
+
}
|
|
400
|
+
else if (res === 'stale') {
|
|
401
|
+
noteStale();
|
|
402
|
+
}
|
|
403
|
+
else if (res !== 'unauthorized') {
|
|
404
|
+
noteOutage();
|
|
405
|
+
// Put it back ONLY if nothing newer arrived while we were away.
|
|
406
|
+
if (!pending)
|
|
407
|
+
pending = next;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
finally {
|
|
411
|
+
inFlight = false;
|
|
412
|
+
}
|
|
413
|
+
if (pending) {
|
|
414
|
+
if (outageAnnounced || staleAnnounced)
|
|
415
|
+
armRetry();
|
|
416
|
+
else
|
|
417
|
+
await drainQueue();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Enqueue a bound save. Returns immediately -- requestSave's contract is
|
|
422
|
+
* synchronous (game.ts) and the spill has already been written by the
|
|
423
|
+
* time this is called, so nothing here is allowed to block a beat.
|
|
424
|
+
*/
|
|
425
|
+
export function enqueueBoundPush(saveFilePath, save, spillPath, push = pushSave) {
|
|
426
|
+
pending = { saveFilePath, save, spillPath, push };
|
|
427
|
+
void drainQueue();
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Drain to completion -- the QUIT SEAL and the job-accept handoff.
|
|
431
|
+
*
|
|
432
|
+
* These are the two places where "eventually" is not good enough: quit
|
|
433
|
+
* ends the process (nothing later will retry), and accepting a job hands
|
|
434
|
+
* this character to a shared run that loads it from the SERVER, so an
|
|
435
|
+
* unpushed beat is a stale snapshot the whole table then plays against.
|
|
436
|
+
* That race exists today and this is what closes it.
|
|
437
|
+
*
|
|
438
|
+
* Resolves true when the server has the newest save. False means the
|
|
439
|
+
* spill stands and the next launch will carry it.
|
|
440
|
+
*/
|
|
441
|
+
export async function flushPushQueue() {
|
|
442
|
+
if (retryTimer) {
|
|
443
|
+
clearTimeout(retryTimer);
|
|
444
|
+
retryTimer = undefined;
|
|
445
|
+
}
|
|
446
|
+
// Bounded: each pass either lands the newest save or fails, and a
|
|
447
|
+
// failure stops the loop rather than spinning on a dead link.
|
|
448
|
+
for (let i = 0; i < 3 && pending; i++) {
|
|
449
|
+
const before = pending;
|
|
450
|
+
await drainQueue();
|
|
451
|
+
if (pending === before)
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
return pending === undefined;
|
|
455
|
+
}
|
|
456
|
+
/** True while a bound save has not reached the server. */
|
|
457
|
+
export function hasPendingPush() {
|
|
458
|
+
return pending !== undefined;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Remove a spill whose contents the server has confirmed. Guarded on
|
|
462
|
+
* savedAt: a spill rewritten by a newer beat between the push and the
|
|
463
|
+
* confirmation is NOT the file we just uploaded, and deleting it would
|
|
464
|
+
* throw away the only copy of that beat.
|
|
465
|
+
*/
|
|
466
|
+
export function clearSpill(spillPath, confirmedSavedAt) {
|
|
467
|
+
try {
|
|
468
|
+
if (!fs.existsSync(spillPath))
|
|
469
|
+
return;
|
|
470
|
+
const onDisk = readSave(spillPath);
|
|
471
|
+
if (onDisk.ok && onDisk.save.savedAt !== confirmedSavedAt)
|
|
472
|
+
return;
|
|
473
|
+
fs.rmSync(spillPath, { force: true });
|
|
474
|
+
Logger.getInstance().write(`Cloud sync: spill cleared (${confirmedSavedAt}).`);
|
|
475
|
+
}
|
|
476
|
+
catch (err) {
|
|
477
|
+
// A spill we cannot delete is a spill that gets uploaded again next
|
|
478
|
+
// launch and found to be identical -- harmless. Never fatal.
|
|
479
|
+
Logger.getInstance().write(`Cloud sync: could not clear spill -- ${err.message ?? err}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Write the spill, SYNCHRONOUSLY, and never throw.
|
|
484
|
+
*
|
|
485
|
+
* requestSave's signature is synchronous and that is load-bearing: it is
|
|
486
|
+
* called from `process.on('exit')`, where nothing asynchronous can run
|
|
487
|
+
* at all. For a bound runner the spill write IS the durability
|
|
488
|
+
* guarantee at that moment -- the push is best-effort and the process is
|
|
489
|
+
* already leaving.
|
|
490
|
+
*
|
|
491
|
+
* SWALLOWS ITS ERRORS ON PURPOSE, and this is the one place where that
|
|
492
|
+
* is right rather than lazy: a full disk or a permissions fault during
|
|
493
|
+
* the exit hook must not turn a clean quit into a crash on the way out.
|
|
494
|
+
* The player would lose the beat either way; throwing loses the exit
|
|
495
|
+
* too, and prints a stack trace over their last screen.
|
|
496
|
+
*/
|
|
497
|
+
export function writeSpill(spillPath, save) {
|
|
498
|
+
try {
|
|
499
|
+
writeSaveAtomic(spillPath, save);
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
catch (err) {
|
|
503
|
+
Logger.getInstance().write(`Cloud sync: spill write FAILED (${err.message ?? err}).`);
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
async function leaseCall(slug, sessionId, action) {
|
|
508
|
+
const token = authToken();
|
|
509
|
+
if (!token)
|
|
510
|
+
return { ok: false, reason: 'unauthorized' };
|
|
511
|
+
try {
|
|
512
|
+
const res = await request('POST', `/${API_BASE}/${slug}/lease`, token, { sessionId, action });
|
|
513
|
+
if (res.statusCode === 200) {
|
|
514
|
+
const body = parseLease(res.data);
|
|
515
|
+
return { ok: true, ttlMs: body?.ttlMs };
|
|
516
|
+
}
|
|
517
|
+
if (res.statusCode === 401) {
|
|
518
|
+
noteUnauthorized();
|
|
519
|
+
return { ok: false, reason: 'unauthorized' };
|
|
520
|
+
}
|
|
521
|
+
if (res.statusCode === 409) {
|
|
522
|
+
const body = parseLease(res.data);
|
|
523
|
+
return { ok: false, reason: 'held', heldBy: body?.heldBy, since: body?.since };
|
|
524
|
+
}
|
|
525
|
+
// See the transitional note above: an unimplemented endpoint is not
|
|
526
|
+
// a free lease and is not an outage either.
|
|
527
|
+
if (res.statusCode === 404) {
|
|
528
|
+
Logger.getInstance().write(`Lease: server has no lease endpoint -- proceeding without cross-machine locking.`);
|
|
529
|
+
return { ok: false, reason: 'unsupported' };
|
|
530
|
+
}
|
|
531
|
+
return { ok: false, reason: 'offline' };
|
|
532
|
+
}
|
|
533
|
+
catch {
|
|
534
|
+
return { ok: false, reason: 'offline' };
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function parseLease(raw) {
|
|
538
|
+
try {
|
|
539
|
+
const parsed = JSON.parse(raw);
|
|
540
|
+
const body = (parsed?.data ?? parsed);
|
|
541
|
+
return body;
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
export const acquireLease = (slug, sessionId) => leaseCall(slug, sessionId, 'acquire');
|
|
548
|
+
export const releaseLease = (slug, sessionId) => leaseCall(slug, sessionId, 'release');
|
|
549
|
+
/**
|
|
550
|
+
* Whether a lease failure should STOP the boot.
|
|
551
|
+
*
|
|
552
|
+
* ONLY a held lease does. Offline, unauthorized and unsupported all mean
|
|
553
|
+
* "we could not ask", and refusing to play because the lock server was
|
|
554
|
+
* unreachable would turn every outage into a lockout -- which is the
|
|
555
|
+
* opposite of ruling 2 (an outage degrades to the spill, it does not end
|
|
556
|
+
* the session). A HELD lease is the one case where we know the answer
|
|
557
|
+
* and the answer is no.
|
|
558
|
+
*/
|
|
559
|
+
export function leaseRefusesBoot(result) {
|
|
560
|
+
return result.ok === false && result.reason === 'held';
|
|
561
|
+
}
|
|
562
|
+
let renewTimer;
|
|
563
|
+
/**
|
|
564
|
+
* Keep the lease alive while playing. Renewal FAILURES ARE TOLERATED:
|
|
565
|
+
* a dropped renew during an outage must not kill a live session -- the
|
|
566
|
+
* server's TTL expires it on its own, and a crash is exactly what the
|
|
567
|
+
* TTL is for.
|
|
568
|
+
*/
|
|
569
|
+
export function startLeaseRenewal(slug, sessionId, everyMs = 30_000) {
|
|
570
|
+
stopLeaseRenewal();
|
|
571
|
+
renewTimer = setInterval(() => { void leaseCall(slug, sessionId, 'renew'); }, everyMs);
|
|
572
|
+
// Never hold the process open for a lock we are about to release.
|
|
573
|
+
renewTimer.unref?.();
|
|
574
|
+
}
|
|
575
|
+
export function stopLeaseRenewal() {
|
|
576
|
+
if (renewTimer)
|
|
577
|
+
clearInterval(renewTimer);
|
|
578
|
+
renewTimer = undefined;
|
|
579
|
+
}
|
|
278
580
|
//# sourceMappingURL=cloud-saves.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-saves.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/cloud-saves.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cloud-saves.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/cloud-saves.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,44 @@ export declare function savePathFor(dir: string, playerName: string): string;
|
|
|
21
21
|
* copy couldn't be deleted (offline) -- the launcher honors it later
|
|
22
22
|
* instead of resurrecting the dead from the cloud. */
|
|
23
23
|
export declare function tombstonePathFor(dir: string, playerName: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* THE SPILL: a bound runner's crash journal, NOT a second home.
|
|
26
|
+
*
|
|
27
|
+
* A bound character's save lives on the server (user ruling: bound is
|
|
28
|
+
* online-only). The spill is what keeps that honest when the grid drops
|
|
29
|
+
* mid-session -- every beat still writes here synchronously, and the
|
|
30
|
+
* NEXT launch uploads it and deletes it. It never outlives one
|
|
31
|
+
* successful sync, which is the whole difference between a journal and
|
|
32
|
+
* the dual storage this change exists to remove.
|
|
33
|
+
*
|
|
34
|
+
* `.spill`, DELIBERATELY NOT `.json`, and that extension is the entire
|
|
35
|
+
* mechanism keeping it out of the menu: listSaves filters on `.json`,
|
|
36
|
+
* so a spill can never be offered as a slot to load. Naming it
|
|
37
|
+
* `<slug>.spill.json` would have put a half-written recovery file in
|
|
38
|
+
* front of the player as a playable character.
|
|
39
|
+
*
|
|
40
|
+
* Same slug as the save and the tombstone, so all three names for one
|
|
41
|
+
* runner are derivable from the runner and from nothing else.
|
|
42
|
+
*/
|
|
43
|
+
export declare function spillPathFor(dir: string, playerName: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* THE LOCK ANCHOR: the extensionless path all of a runner's sidecar
|
|
46
|
+
* files hang off.
|
|
47
|
+
*
|
|
48
|
+
* session-lock.ts builds `<slot>.lock` by stripping `.json` off the save
|
|
49
|
+
* path, which quietly assumes the save FILE exists to derive a name
|
|
50
|
+
* from. For a bound runner after PR2 it will not -- their save lives on
|
|
51
|
+
* the server -- and the lock would have had nowhere to hang.
|
|
52
|
+
*
|
|
53
|
+
* Anchoring on the SLUG instead makes the lock a property of the
|
|
54
|
+
* RUNNER rather than of a file that may or may not be on this disk.
|
|
55
|
+
* `lockPathFor(lockAnchorFor(dir, name))` is byte-identical to today's
|
|
56
|
+
* `lockPathFor(savePathFor(dir, name))` -- the anchor simply has no
|
|
57
|
+
* `.json` for the strip to remove -- so no existing lock is orphaned and
|
|
58
|
+
* a half-upgraded machine cannot end up with two lock paths for one
|
|
59
|
+
* runner, which would be one lock each and no exclusion at all.
|
|
60
|
+
*/
|
|
61
|
+
export declare function lockAnchorFor(dir: string, playerName: string): string;
|
|
24
62
|
/**
|
|
25
63
|
* Atomic-enough for one slot: write a .tmp beside the target, then
|
|
26
64
|
* rename over it. A crash mid-write leaves a stale .tmp, never a
|
|
@@ -33,6 +33,48 @@ export function savePathFor(dir, playerName) {
|
|
|
33
33
|
export function tombstonePathFor(dir, playerName) {
|
|
34
34
|
return path.join(dir, `${saveSlug(playerName)}.dead`);
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* THE SPILL: a bound runner's crash journal, NOT a second home.
|
|
38
|
+
*
|
|
39
|
+
* A bound character's save lives on the server (user ruling: bound is
|
|
40
|
+
* online-only). The spill is what keeps that honest when the grid drops
|
|
41
|
+
* mid-session -- every beat still writes here synchronously, and the
|
|
42
|
+
* NEXT launch uploads it and deletes it. It never outlives one
|
|
43
|
+
* successful sync, which is the whole difference between a journal and
|
|
44
|
+
* the dual storage this change exists to remove.
|
|
45
|
+
*
|
|
46
|
+
* `.spill`, DELIBERATELY NOT `.json`, and that extension is the entire
|
|
47
|
+
* mechanism keeping it out of the menu: listSaves filters on `.json`,
|
|
48
|
+
* so a spill can never be offered as a slot to load. Naming it
|
|
49
|
+
* `<slug>.spill.json` would have put a half-written recovery file in
|
|
50
|
+
* front of the player as a playable character.
|
|
51
|
+
*
|
|
52
|
+
* Same slug as the save and the tombstone, so all three names for one
|
|
53
|
+
* runner are derivable from the runner and from nothing else.
|
|
54
|
+
*/
|
|
55
|
+
export function spillPathFor(dir, playerName) {
|
|
56
|
+
return path.join(dir, `${saveSlug(playerName)}.spill`);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* THE LOCK ANCHOR: the extensionless path all of a runner's sidecar
|
|
60
|
+
* files hang off.
|
|
61
|
+
*
|
|
62
|
+
* session-lock.ts builds `<slot>.lock` by stripping `.json` off the save
|
|
63
|
+
* path, which quietly assumes the save FILE exists to derive a name
|
|
64
|
+
* from. For a bound runner after PR2 it will not -- their save lives on
|
|
65
|
+
* the server -- and the lock would have had nowhere to hang.
|
|
66
|
+
*
|
|
67
|
+
* Anchoring on the SLUG instead makes the lock a property of the
|
|
68
|
+
* RUNNER rather than of a file that may or may not be on this disk.
|
|
69
|
+
* `lockPathFor(lockAnchorFor(dir, name))` is byte-identical to today's
|
|
70
|
+
* `lockPathFor(savePathFor(dir, name))` -- the anchor simply has no
|
|
71
|
+
* `.json` for the strip to remove -- so no existing lock is orphaned and
|
|
72
|
+
* a half-upgraded machine cannot end up with two lock paths for one
|
|
73
|
+
* runner, which would be one lock each and no exclusion at all.
|
|
74
|
+
*/
|
|
75
|
+
export function lockAnchorFor(dir, playerName) {
|
|
76
|
+
return path.join(dir, saveSlug(playerName));
|
|
77
|
+
}
|
|
36
78
|
/**
|
|
37
79
|
* Atomic-enough for one slot: write a .tmp beside the target, then
|
|
38
80
|
* rename over it. A crash mid-write leaves a stale .tmp, never a
|
|
@@ -107,6 +149,10 @@ export function serializeItem(item) {
|
|
|
107
149
|
atSpot: item.atSpot,
|
|
108
150
|
};
|
|
109
151
|
// The runtime block, sparse: only what diverges from a fresh item.
|
|
152
|
+
// Sparse, like the two scalars below it: a stack of one is the
|
|
153
|
+
// default, so writing it would bloat every save for nothing.
|
|
154
|
+
if (item.quantity > 1)
|
|
155
|
+
out.quantity = item.quantity;
|
|
110
156
|
if (item.isFirearm() && item.ammo !== Item.MAGAZINE_CAPACITY)
|
|
111
157
|
out.ammo = item.ammo;
|
|
112
158
|
if (item.jammed)
|
|
@@ -148,6 +194,8 @@ export function restoreItem(json) {
|
|
|
148
194
|
}
|
|
149
195
|
if (json.owner !== undefined)
|
|
150
196
|
item.owner = json.owner;
|
|
197
|
+
if (json.quantity !== undefined)
|
|
198
|
+
item.quantity = json.quantity;
|
|
151
199
|
if (json.ammo !== undefined)
|
|
152
200
|
item.ammo = json.ammo;
|
|
153
201
|
if (json.jammed)
|
|
@@ -217,6 +265,7 @@ export function serializePlayer(p) {
|
|
|
217
265
|
magic: p.magic, strength: p.strength, willpower: p.willpower, logic: p.logic,
|
|
218
266
|
intuition: p.intuition, charisma: p.charisma, edge: p.edge, resonance: p.resonance,
|
|
219
267
|
adept: p.adept,
|
|
268
|
+
powerPoints: p.powerPoints > 0 ? p.powerPoints : undefined,
|
|
220
269
|
},
|
|
221
270
|
baseMagic: p.baseMagic,
|
|
222
271
|
baseResonance: p.baseResonance,
|
|
@@ -292,6 +341,9 @@ export function restorePlayer(p, s) {
|
|
|
292
341
|
p.edge = s.attributes.edge;
|
|
293
342
|
p.resonance = s.attributes.resonance;
|
|
294
343
|
p.adept = s.attributes.adept;
|
|
344
|
+
// Absent on any save older than the mystic adept path -- zero is a
|
|
345
|
+
// magician or a full adept, which is what those saves are.
|
|
346
|
+
p.powerPoints = Math.max(0, Math.floor(s.attributes.powerPoints ?? 0));
|
|
295
347
|
p.skills = { ...s.skills };
|
|
296
348
|
// REGISTERING SPLIT OUT OF COMPILING (2026-08-27). `register` used to
|
|
297
349
|
// roll Compiling, which the books don't support -- Registering is its
|
|
@@ -319,6 +371,55 @@ export function restorePlayer(p, s) {
|
|
|
319
371
|
if (sk.decompiling === undefined && (sk.compiling ?? 0) > 0) {
|
|
320
372
|
sk.decompiling = sk.compiling;
|
|
321
373
|
}
|
|
374
|
+
// FIREARMS SPLIT THREE WAYS (2026-08-31) -- the same shape again, and
|
|
375
|
+
// now canon rather than a bug fix. SR5 p.90 has no `firearms` skill:
|
|
376
|
+
// it has Automatics, Longarms and Pistols, picked by the gun in your
|
|
377
|
+
// hands (p.130/132).
|
|
378
|
+
//
|
|
379
|
+
// A CONDENSED SKILL WAS EFFECTIVELY A GROUP, so it migrates as a GROUP
|
|
380
|
+
// PURCHASE: p.88's rule is that a group bought at rating N means every
|
|
381
|
+
// skill in it is held at N, which is exactly what `firearms: 4` always
|
|
382
|
+
// meant here -- good with guns, all of them. That is not free power,
|
|
383
|
+
// it is the group mechanic doing what the group mechanic does, and it
|
|
384
|
+
// is the only reading that neither demotes a runner nor invents a
|
|
385
|
+
// specialisation they never chose.
|
|
386
|
+
//
|
|
387
|
+
// Written out three times rather than looped, per the note above: the
|
|
388
|
+
// next person adding a split should be able to copy a block, not
|
|
389
|
+
// decode one. AT ELEVEN OF THESE (athletics and conjuring are still to
|
|
390
|
+
// come) that trade flips, and whoever adds the last family should
|
|
391
|
+
// reach for a named helper instead of a fourth copy of this comment.
|
|
392
|
+
if (sk.automatics === undefined && (sk.firearms ?? 0) > 0) {
|
|
393
|
+
sk.automatics = sk.firearms;
|
|
394
|
+
}
|
|
395
|
+
if (sk.pistols === undefined && (sk.firearms ?? 0) > 0) {
|
|
396
|
+
sk.pistols = sk.firearms;
|
|
397
|
+
}
|
|
398
|
+
if (sk.longarms === undefined && (sk.firearms ?? 0) > 0) {
|
|
399
|
+
sk.longarms = sk.firearms;
|
|
400
|
+
}
|
|
401
|
+
// The retired name is dropped once its ratings have been carried over,
|
|
402
|
+
// so a re-save does not keep resurrecting a skill the engine no longer
|
|
403
|
+
// has. Deliberately AFTER the three reads above.
|
|
404
|
+
delete sk.firearms;
|
|
405
|
+
// ATHLETICS SPLIT THREE WAYS (2026-08-31), the same group-purchase
|
|
406
|
+
// reading: `athletics: 4` meant good at moving your body, all of it.
|
|
407
|
+
// Gymnastics, Running and Swimming are the Athletics group (p.90).
|
|
408
|
+
//
|
|
409
|
+
// FREE-FALL IS DELIBERATELY NOT GRANTED. It is groupless (p.133), so
|
|
410
|
+
// it was never part of what `athletics` bought -- handing it out here
|
|
411
|
+
// would be inventing a rating the character never had, which is the
|
|
412
|
+
// opposite failure from demoting them.
|
|
413
|
+
if (sk.gymnastics === undefined && (sk.athletics ?? 0) > 0) {
|
|
414
|
+
sk.gymnastics = sk.athletics;
|
|
415
|
+
}
|
|
416
|
+
if (sk.running === undefined && (sk.athletics ?? 0) > 0) {
|
|
417
|
+
sk.running = sk.athletics;
|
|
418
|
+
}
|
|
419
|
+
if (sk.swimming === undefined && (sk.athletics ?? 0) > 0) {
|
|
420
|
+
sk.swimming = sk.athletics;
|
|
421
|
+
}
|
|
422
|
+
delete sk.athletics;
|
|
322
423
|
p.karma = s.karma;
|
|
323
424
|
p.careerKarma = s.careerKarma;
|
|
324
425
|
for (const reason of s.notorietyReasons)
|