sign-off-axi 0.5.6 → 0.5.8
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/dist/cli.js +10 -1
- package/dist/store.js +14 -0
- package/package.json +1 -1
- package/web/index.html +560 -131
- package/web/tokens.css +2 -2
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { parseArgs } from 'node:util';
|
|
|
13
13
|
import { encode } from '@toon-format/toon';
|
|
14
14
|
import { acknowledgeOwner, checkOwner, deliveries, dispatchOwners, registerOwner } from './owner.js';
|
|
15
15
|
import { AxiError, runAxiCli } from 'axi-sdk-js';
|
|
16
|
-
import { ATTACH_DEFAULT_MB, ATTACH_MAX, ATTACH_NAME, CHAPTERS_MAX, SIGNED_IN, CLEARED, InputError, MEDIA_MAX, NOTE_MAX, REPLY, answersPath, appendAnnotation, appendPartComment, annotationsPath, markCommentsRead, readPartComments, replyComment, asks, appendAnswer, appendDismissed, appendSendBack, appendDesignAnswer, appendMessage, appendRound, awaitsVerdict, lapsed, askEngagement, checkEngagement, markEngagementSeen, appendRead, answerDeeper, askDeeper, deeperPath, guidePart, markDeeperRead, readDeeper, readReads, seenAt, isKey, loadDecisions, markDelivered, markSeen, messagesPath, readAnnotations, readAnswers, reading, readDismissed, readItems, sameDecision, readMessages, readRounds, roundsPath, seenBy, seenPath, sentIds, unreadable as reasonOf, writeItems } from './store.js';
|
|
16
|
+
import { ATTACH_DEFAULT_MB, ATTACH_MAX, ATTACH_NAME, CHAPTERS_MAX, SIGNED_IN, CLEARED, InputError, MEDIA_MAX, NOTE_MAX, REPLY, answersPath, appendAnnotation, appendPartComment, annotationsPath, markCommentsRead, readPartComments, replyComment, asks, appendAnswer, appendDismissed, appendSendBack, appendDesignAnswer, appendMessage, appendRound, awaitsVerdict, lapsed, askEngagement, checkEngagement, markEngagementSeen, appendRead, appendOpened, readOpened, answerDeeper, askDeeper, deeperPath, guidePart, markDeeperRead, readDeeper, readReads, seenAt, isKey, loadDecisions, markDelivered, markSeen, messagesPath, readAnnotations, readAnswers, reading, readDismissed, readItems, sameDecision, readMessages, readRounds, roundsPath, seenBy, seenPath, sentIds, unreadable as reasonOf, writeItems } from './store.js';
|
|
17
17
|
import { ContractError, KINDS, MEDIA_BYTES, REPORT_INIT, checkMessage, diagramPages, diagramViews, guided, mediaFiles, parseMessage, reportPage } from './contract.js';
|
|
18
18
|
import { faults, isStill } from './evidence-text.js';
|
|
19
19
|
import { deliverVault, errors, readVaultExpiry, sweepVault, takeVaultExpiries, VaultError } from './vault.js';
|
|
@@ -2655,6 +2655,7 @@ const state = () => {
|
|
|
2655
2655
|
seen: Object.values(answers).filter(taken).map((a) => a.key),
|
|
2656
2656
|
seen_at: Object.fromEntries(Object.values(answers).flatMap((a) => { const t = seenAt(file)(a); return t ? [[a.key, t]] : []; })),
|
|
2657
2657
|
reads: readReads(file),
|
|
2658
|
+
opened: readOpened(file),
|
|
2658
2659
|
deeper: readDeeper(file),
|
|
2659
2660
|
delivery: deliveries(file),
|
|
2660
2661
|
rounds,
|
|
@@ -2986,6 +2987,14 @@ async function route(req) {
|
|
|
2986
2987
|
askEngagement(file, input);
|
|
2987
2988
|
return [200, state()];
|
|
2988
2989
|
}
|
|
2990
|
+
if (req.url === '/api/reads' && Array.isArray(JSON.parse(body)?.keys)) {
|
|
2991
|
+
// A whole report opened, or marked read or unread from Reports: keys and read, no part.
|
|
2992
|
+
const { keys, read } = JSON.parse(body), have = new Set(board(file).map((x) => x.key));
|
|
2993
|
+
if (!keys.length || keys.length > 200 || typeof read !== 'boolean' || !keys.every((k) => typeof k === 'string' && have.has(k)))
|
|
2994
|
+
return [400, { error: 'Send 1 to 200 keys on the board and read true or false' }];
|
|
2995
|
+
appendOpened(file, [...new Set(keys)], read);
|
|
2996
|
+
return [200, state()];
|
|
2997
|
+
}
|
|
2989
2998
|
if (req.url === '/api/reads' || req.url === '/api/deeper') {
|
|
2990
2999
|
const { key, part, q } = JSON.parse(body) ?? {}, d = loadDecisions(file).find((x) => x.key === key), about = typeof part === 'string' && d ? guidePart(d, part) : undefined;
|
|
2991
3000
|
if (!about)
|
package/dist/store.js
CHANGED
|
@@ -595,6 +595,20 @@ export const appendRead = (decisionsPath, key, part) => {
|
|
|
595
595
|
if (readReads(decisionsPath)[`${key}/${part}`] === undefined)
|
|
596
596
|
appendLine(readsPath(decisionsPath), { key, part, by: 'captain', at: now() });
|
|
597
597
|
};
|
|
598
|
+
/** Whole reports opened or marked unread, in the same file with no part: the last line for a key wins, so Reports' read and unread toggle (true read, false unread). */
|
|
599
|
+
export function readOpened(decisionsPath) {
|
|
600
|
+
const last = {};
|
|
601
|
+
readRaw(readsPath(decisionsPath)).split('\n').forEach((line) => {
|
|
602
|
+
try {
|
|
603
|
+
const r = line && JSON.parse(line);
|
|
604
|
+
if (r && typeof r.key === 'string' && r.part === undefined && typeof r.read === 'boolean')
|
|
605
|
+
last[r.key] = r.read;
|
|
606
|
+
}
|
|
607
|
+
catch { }
|
|
608
|
+
});
|
|
609
|
+
return last;
|
|
610
|
+
}
|
|
611
|
+
export const appendOpened = (decisionsPath, keys, read) => keys.forEach((key) => appendLine(readsPath(decisionsPath), { key, read, by: 'captain', at: now() }));
|
|
598
612
|
export const deeperPath = (decisionsPath) => decisionsPath.replace(/\.json$/, '') + '.deeper.jsonl';
|
|
599
613
|
export function readDeeper(decisionsPath) {
|
|
600
614
|
const all = new Map();
|