@veilio-inc/cli 0.1.0 → 0.3.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,52 @@
1
+ export declare const CREDENTIAL_FILE = "credential.json";
2
+ export interface Credential {
3
+ /** The session bearer token, exactly as issued. */
4
+ token: string;
5
+ /** The email it belongs to, so `whoami` need not make a request. */
6
+ account: string;
7
+ /** Base URL it was issued by, so a self-hosted instance is addressable. */
8
+ instance: string;
9
+ }
10
+ /**
11
+ * Where the credential lives.
12
+ *
13
+ * Under the user's home directory, not the project store: a token authorises a
14
+ * person, not a repository, and putting it beside `.veilio/map.json` would drop
15
+ * it into whatever directory the CLI happened to run in — including, eventually,
16
+ * one somebody commits.
17
+ *
18
+ * `home` is injectable so tests do not write to the real one.
19
+ */
20
+ export declare function credentialPath(home?: string): string;
21
+ /** https, or a loopback address for local development. Nothing else. */
22
+ export declare function isSafeInstance(value: string): boolean;
23
+ /**
24
+ * The stored credential, or null.
25
+ *
26
+ * Null means "not signed in", and it means that for every reason a read can
27
+ * fail. Callers get one case to handle, and no caller has to decide whether a
28
+ * particular kind of breakage is worth reporting — none of them is.
29
+ */
30
+ export declare function readCredential(home?: string): Credential | null;
31
+ /**
32
+ * Write the credential, 0600.
33
+ *
34
+ * Called only after the server has accepted a sign-in — validate, then persist
35
+ * (Constitution IV). A file written before the check leaves a credential behind
36
+ * for an attempt that failed.
37
+ *
38
+ * `chmodSync` after the write because `mode` on `writeFileSync` applies only
39
+ * when the file is created; without it, re-signing in over a world-readable file
40
+ * left from some earlier mistake would leave it world-readable.
41
+ */
42
+ export declare function writeCredential(credential: Credential, home?: string): void;
43
+ /**
44
+ * Remove the credential. Returns whether there was one to remove.
45
+ *
46
+ * Never throws, for the same reason reads do not: `logout` on a machine that was
47
+ * never signed in should say so and exit cleanly, not fail. Note the ordering
48
+ * this does NOT own — `logout` revokes server-side FIRST and only then calls
49
+ * this, because deleting first leaves a live session the user believes is gone.
50
+ */
51
+ export declare function removeCredential(home?: string): boolean;
52
+ //# sourceMappingURL=credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAEhD,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAA;IACf,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAE/D;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CASrD;AAqBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAkB,GAAG,UAAU,GAAG,IAAI,CAc1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,GAAE,MAAkB,GAAG,IAAI,CAKtF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAkB,GAAG,OAAO,CAiBlE"}
@@ -0,0 +1,135 @@
1
+ // The signed-in credential, on disk.
2
+ //
3
+ // One file per machine per instance, holding the session token the server
4
+ // issued, the account it belongs to, and the instance that issued it. It is
5
+ // never transmitted and never sent anywhere — `whoami` answers from it, which is
6
+ // why it carries the account and the instance rather than the token alone.
7
+ //
8
+ // EVERY read tolerates absence and corruption, and that is the whole design.
9
+ // This file sits underneath commands that must work for someone who has never
10
+ // heard of the Cloud edition (FR-001, FR-003). A reader that throws on a
11
+ // truncated file turns a half-written credential into a broken `veilio scrub`,
12
+ // and the person it breaks for is the one who never signed in.
13
+ //
14
+ // So there is exactly one failure mode here: "not signed in". Missing file,
15
+ // unreadable file, a directory where the file should be, invalid JSON, JSON of
16
+ // the wrong shape, an empty token — all of it reads as signed out, because every
17
+ // one of them means the same thing to the caller and none of them is worth
18
+ // stopping a local command over.
19
+ import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
20
+ import { dirname, join } from 'node:path';
21
+ import { homedir } from 'node:os';
22
+ import { STORE_DIR } from '@veilio-inc/engine';
23
+ export const CREDENTIAL_FILE = 'credential.json';
24
+ /**
25
+ * Where the credential lives.
26
+ *
27
+ * Under the user's home directory, not the project store: a token authorises a
28
+ * person, not a repository, and putting it beside `.veilio/map.json` would drop
29
+ * it into whatever directory the CLI happened to run in — including, eventually,
30
+ * one somebody commits.
31
+ *
32
+ * `home` is injectable so tests do not write to the real one.
33
+ */
34
+ export function credentialPath(home = homedir()) {
35
+ return join(home, STORE_DIR, CREDENTIAL_FILE);
36
+ }
37
+ /** https, or a loopback address for local development. Nothing else. */
38
+ export function isSafeInstance(value) {
39
+ let url;
40
+ try {
41
+ url = new URL(value);
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ if (url.protocol === 'https:')
47
+ return true;
48
+ return url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';
49
+ }
50
+ function isCredential(value) {
51
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
52
+ return false;
53
+ const c = value;
54
+ return (typeof c.token === 'string' &&
55
+ c.token !== '' &&
56
+ typeof c.account === 'string' &&
57
+ c.account !== '' &&
58
+ typeof c.instance === 'string' &&
59
+ c.instance !== '' &&
60
+ // A credential naming an `http://` instance would put the bearer token on
61
+ // the wire in the clear, on every request, for ever — and self-hosted LAN
62
+ // setups are exactly where somebody writes one by hand. Refusing to read it
63
+ // reads as "not signed in", which is the safe direction and the one the
64
+ // rest of this module already takes.
65
+ isSafeInstance(c.instance));
66
+ }
67
+ /**
68
+ * The stored credential, or null.
69
+ *
70
+ * Null means "not signed in", and it means that for every reason a read can
71
+ * fail. Callers get one case to handle, and no caller has to decide whether a
72
+ * particular kind of breakage is worth reporting — none of them is.
73
+ */
74
+ export function readCredential(home = homedir()) {
75
+ let raw;
76
+ try {
77
+ raw = readFileSync(credentialPath(home), 'utf8');
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ let parsed;
83
+ try {
84
+ parsed = JSON.parse(raw);
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ return isCredential(parsed) ? parsed : null;
90
+ }
91
+ /**
92
+ * Write the credential, 0600.
93
+ *
94
+ * Called only after the server has accepted a sign-in — validate, then persist
95
+ * (Constitution IV). A file written before the check leaves a credential behind
96
+ * for an attempt that failed.
97
+ *
98
+ * `chmodSync` after the write because `mode` on `writeFileSync` applies only
99
+ * when the file is created; without it, re-signing in over a world-readable file
100
+ * left from some earlier mistake would leave it world-readable.
101
+ */
102
+ export function writeCredential(credential, home = homedir()) {
103
+ const path = credentialPath(home);
104
+ mkdirSync(dirname(path), { recursive: true });
105
+ writeFileSync(path, `${JSON.stringify(credential, null, 2)}\n`, { mode: 0o600 });
106
+ chmodSync(path, 0o600);
107
+ }
108
+ /**
109
+ * Remove the credential. Returns whether there was one to remove.
110
+ *
111
+ * Never throws, for the same reason reads do not: `logout` on a machine that was
112
+ * never signed in should say so and exit cleanly, not fail. Note the ordering
113
+ * this does NOT own — `logout` revokes server-side FIRST and only then calls
114
+ * this, because deleting first leaves a live session the user believes is gone.
115
+ */
116
+ export function removeCredential(home = homedir()) {
117
+ const path = credentialPath(home);
118
+ try {
119
+ statSync(path);
120
+ }
121
+ catch {
122
+ // Genuinely not signed in. Nothing to do, and not an error.
123
+ return false;
124
+ }
125
+ // A failure to DELETE is a different thing entirely, and it throws.
126
+ //
127
+ // Returning false for both meant `logout` would print "you weren't signed in"
128
+ // while a live bearer token sat on disk — an unsearchable parent directory, a
129
+ // read-only mount, a file held open on Windows. That inverts FR-005 and
130
+ // contradicts the whole reason this function is called before the file is
131
+ // considered gone. The caller catches and reports the path.
132
+ rmSync(path, { recursive: true, force: true });
133
+ return true;
134
+ }
135
+ //# sourceMappingURL=credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { type Io } from './commands.js';
3
- export declare const VERSION = "0.1.0";
3
+ export declare const VERSION: string;
4
4
  /** Testable entry point: everything that touches the process is injected. */
5
5
  export declare function main(argv: readonly string[], io: Io): Promise<number>;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAA2D,KAAK,EAAE,EAAE,MAAM,eAAe,CAAA;AAIhG,eAAO,MAAM,OAAO,UAAU,CAAA;AAE9B,6EAA6E;AAC7E,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiC3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAA2D,KAAK,EAAE,EAAE,MAAM,eAAe,CAAA;AAqBhG,eAAO,MAAM,OAAO,EAAE,MAEb,CAAA;AAET,6EAA6E;AAC7E,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoE3E"}
package/dist/index.js CHANGED
@@ -1,9 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
2
3
  import { parseArgs, UsageError } from './args.js';
3
4
  import { EXIT_ERROR, HELP, runMap, runRestore, runScan, runScrub } from './commands.js';
5
+ import { runLogin, runLogout, runWhoami, runMapsList, runMapsPull, runMapsPush, runTeamUnlock, runTeamLock, runRulesPull, } from './cloud-commands.js';
6
+ import { resolveMapPath } from './store.js';
7
+ import { createInterface } from 'node:readline';
4
8
  import { realpathSync } from 'node:fs';
5
9
  import { pathToFileURL } from 'node:url';
6
- export const VERSION = '0.1.0';
10
+ // Read from the package, not typed here: changesets bump package.json only, so
11
+ // a literal drifted - the published 0.2.0 reported 0.1.0 (found 2026-09-26).
12
+ // npm always ships package.json, and ../package.json resolves from src/ and
13
+ // dist/ alike.
14
+ export const VERSION = createRequire(import.meta.url)('../package.json').version;
7
15
  /** Testable entry point: everything that touches the process is injected. */
8
16
  export async function main(argv, io) {
9
17
  let args;
@@ -33,6 +41,42 @@ export async function main(argv, io) {
33
41
  return await runScan(args, io);
34
42
  case 'map':
35
43
  return await runMap(args, io);
44
+ case 'login':
45
+ return await runLogin(args.instance, io);
46
+ case 'logout':
47
+ return await runLogout(io);
48
+ case 'whoami':
49
+ return runWhoami(io);
50
+ case 'maps': {
51
+ const mapPath = resolveMapPath(args.mapPath, io.cwd);
52
+ switch (args.mapsAction) {
53
+ case 'list':
54
+ return await runMapsList(io);
55
+ case 'pull':
56
+ return await runMapsPull(args.files[0] ?? null, mapPath, io, { force: args.force });
57
+ case 'push':
58
+ return await runMapsPush(args.files[0] ?? null, mapPath, io);
59
+ default:
60
+ io.stderr('veilio: maps needs an action — list, pull or push.\n');
61
+ return EXIT_ERROR;
62
+ }
63
+ }
64
+ case 'team': {
65
+ switch (args.teamAction) {
66
+ case 'unlock':
67
+ return await runTeamUnlock(io);
68
+ case 'lock':
69
+ return runTeamLock(io);
70
+ default:
71
+ io.stderr('veilio: team needs an action — unlock or lock.\n');
72
+ return EXIT_ERROR;
73
+ }
74
+ }
75
+ case 'rules':
76
+ if (args.rulesAction === 'pull')
77
+ return await runRulesPull(io);
78
+ io.stderr('veilio: rules needs an action — pull.\n');
79
+ return EXIT_ERROR;
36
80
  }
37
81
  }
38
82
  catch (err) {
@@ -40,6 +84,117 @@ export async function main(argv, io) {
40
84
  return EXIT_ERROR;
41
85
  }
42
86
  }
87
+ // A piped/scripted session (no TTY) commonly delivers every line in ONE data
88
+ // chunk — `echo "email\npassword" | veilio login`, or any single-`input`
89
+ // spawn. `readline.Interface` parses every complete line out of a chunk
90
+ // synchronously as that chunk arrives, emitting one 'line' event per line
91
+ // BEFORE returning control to the event loop — so if the first line's
92
+ // `question()` callback resolves a promise and only THEN (on a later
93
+ // microtask) calls `question()` again for the next line, that second line's
94
+ // 'line' event already fired with no listener attached to catch it and is
95
+ // simply dropped. `question()` recreating the interface per call has the
96
+ // same failure one layer up: a fresh interface attaches to an
97
+ // already-ended stream with nothing left to read, and its `question()`
98
+ // never answers — with nothing else keeping the event loop alive, the
99
+ // process just exits 0 having attempted nothing.
100
+ //
101
+ // The fix: one interface for the whole process's non-TTY prompts, with a
102
+ // PERMANENT 'line' listener attached from the moment stdin starts flowing,
103
+ // so a line that arrives before anything is waiting for it is queued
104
+ // instead of dropped.
105
+ let pipedInterface;
106
+ const pipedQueuedLines = [];
107
+ const pipedWaiters = [];
108
+ function ensurePipedInterface() {
109
+ if (pipedInterface)
110
+ return;
111
+ pipedInterface = createInterface({ input: process.stdin, output: process.stderr });
112
+ pipedInterface.on('line', (line) => {
113
+ const waiter = pipedWaiters.shift();
114
+ if (waiter)
115
+ waiter(line);
116
+ else
117
+ pipedQueuedLines.push(line);
118
+ });
119
+ // EOF with a prompt still pending (fewer lines piped than the command
120
+ // asked for) resolves it to '' rather than hanging forever — matches the
121
+ // existing "no email/password given" handling in the callers.
122
+ pipedInterface.on('close', () => {
123
+ let waiter;
124
+ while ((waiter = pipedWaiters.shift()))
125
+ waiter('');
126
+ });
127
+ }
128
+ function readPipedLine(label) {
129
+ process.stderr.write(label);
130
+ ensurePipedInterface();
131
+ const queued = pipedQueuedLines.shift();
132
+ if (queued !== undefined)
133
+ return Promise.resolve(queued);
134
+ return new Promise((resolvePromise) => pipedWaiters.push(resolvePromise));
135
+ }
136
+ /** Read one line from the terminal. */
137
+ function readLine(label) {
138
+ if (!process.stdin.isTTY)
139
+ return readPipedLine(label);
140
+ // A TTY closes and recreates the interface per prompt — safe there
141
+ // because a human necessarily delivers each line in its own chunk (typed,
142
+ // then Enter), so the drop above never has a second buffered line to lose
143
+ // — and closing hands raw stdin control back cleanly to `readSecret`'s
144
+ // manual raw-mode path for the password prompt that follows.
145
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
146
+ return new Promise((resolvePromise) => {
147
+ rl.question(label, (answer) => {
148
+ rl.close();
149
+ resolvePromise(answer);
150
+ });
151
+ });
152
+ }
153
+ /**
154
+ * Read a line without echoing it.
155
+ *
156
+ * The prompt goes to stderr, not stdout, for the same reason every other message
157
+ * in this CLI does: stdout is the pipe, and a password prompt appearing in
158
+ * `veilio scrub x.ts | pbcopy` would be a bug. The echo is suppressed by putting
159
+ * the TTY in raw mode; without a TTY there is nothing to suppress and the line
160
+ * is read normally, which is what a scripted `echo pw | veilio login` needs.
161
+ */
162
+ function readSecret(label) {
163
+ if (!process.stdin.isTTY)
164
+ return readLine(label);
165
+ process.stderr.write(label);
166
+ return new Promise((resolvePromise, rejectPromise) => {
167
+ const stdin = process.stdin;
168
+ stdin.setRawMode(true);
169
+ stdin.resume();
170
+ stdin.setEncoding('utf8');
171
+ let value = '';
172
+ const done = (err) => {
173
+ stdin.setRawMode(false);
174
+ stdin.pause();
175
+ stdin.removeListener('data', onData);
176
+ process.stderr.write('\n');
177
+ if (err)
178
+ rejectPromise(err);
179
+ else
180
+ resolvePromise(value);
181
+ };
182
+ const onData = (chunk) => {
183
+ for (const ch of chunk) {
184
+ if (ch === '\n' || ch === '\r' || ch === '\u0004')
185
+ return done();
186
+ // Ctrl-C must still abort, or raw mode traps the terminal.
187
+ if (ch === '\u0003')
188
+ return done(new Error('cancelled'));
189
+ if (ch === '\u007f' || ch === '\b')
190
+ value = value.slice(0, -1);
191
+ else
192
+ value += ch;
193
+ }
194
+ };
195
+ stdin.on('data', onData);
196
+ });
197
+ }
43
198
  function readStdin() {
44
199
  return new Promise((resolvePromise, rejectPromise) => {
45
200
  // A TTY with no piped input would hang forever waiting for EOF. Fail with
@@ -90,6 +245,8 @@ if (invokedAsProgram()) {
90
245
  stdin: readStdin,
91
246
  stdout: (text) => process.stdout.write(text),
92
247
  stderr: (text) => process.stderr.write(text),
248
+ prompt: readLine,
249
+ password: readSecret,
93
250
  };
94
251
  main(process.argv.slice(2), io).then((code) => {
95
252
  process.exitCode = code;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type CustomRule } from '@veilio-inc/engine';
2
+ export declare const RULES_FILE = "rules.json";
3
+ export interface CachedRules {
4
+ /** Which account these belong to - a different sign-in does not inherit them. */
5
+ instance: string;
6
+ account: string;
7
+ /** ISO time of the pull, so `scrub` can say how old they are. */
8
+ pulledAt: string;
9
+ /** Already merged into the order the engine applies them in. */
10
+ rules: CustomRule[];
11
+ }
12
+ export declare function rulesPath(home?: string): string;
13
+ /**
14
+ * Personal and team rules in the order the web app applies them:
15
+ * team whitelist, personal whitelist, team replace, personal replace.
16
+ *
17
+ * Whitelists first so a name either list keeps readable is never renamed by a
18
+ * replace rule; team before personal so the team's naming wins on a clash,
19
+ * which is what keeps two members' output interchangeable. Disabled rules are
20
+ * dropped and sort_order renumbered 0..n-1, so the engine sees one sequence.
21
+ * Must match `useMergedRules` in the Cloud frontend.
22
+ */
23
+ export declare function mergeRules(personal: readonly CustomRule[], team: readonly CustomRule[]): CustomRule[];
24
+ /** The cached rules for this account, or null. Null for every kind of failure. */
25
+ export declare function readRules(owner: {
26
+ instance: string;
27
+ account: string;
28
+ }, home?: string): CachedRules | null;
29
+ /** 0600: the patterns name what a team considers sensitive. */
30
+ export declare function writeRules(cached: CachedRules, home?: string): void;
31
+ /** Remove the cache. Missing is not an error; failing to delete is. */
32
+ export declare function removeRules(home?: string): boolean;
33
+ /** "3 hours ago" - coarse on purpose; it answers "is this stale", no more. */
34
+ export declare function describeAge(pulledAt: string, now?: Date): string;
35
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/D,eAAO,MAAM,UAAU,eAAe,CAAA;AAEtC,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;IAChB,gEAAgE;IAChE,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,wBAAgB,SAAS,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,SAAS,UAAU,EAAE,EAC/B,IAAI,EAAE,SAAS,UAAU,EAAE,GAC1B,UAAU,EAAE,CAUd;AAUD,kFAAkF;AAClF,wBAAgB,SAAS,CACvB,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC5C,IAAI,GAAE,MAAkB,GACvB,WAAW,GAAG,IAAI,CAcpB;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,GAAE,MAAkB,GAAG,IAAI,CAK9E;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,IAAI,GAAE,MAAkB,GAAG,OAAO,CAS7D;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAQ5E"}
package/dist/rules.js ADDED
@@ -0,0 +1,103 @@
1
+ // The account's custom rules, cached on this machine.
2
+ //
3
+ // Custom rules are defined in the web app and live in Cloud. Before this file
4
+ // the terminal and the MCP server never applied them: the same code masked
5
+ // differently in the browser than in `veilio scrub`, and a whitelisted name
6
+ // that the browser left readable came back as a placeholder here (found on
7
+ // staging, 2026-09-26).
8
+ //
9
+ // `veilio scrub` must stay offline (see offline.test.ts), so it cannot ask Cloud
10
+ // for them. `veilio rules pull` fetches them and writes this cache; `scrub`
11
+ // applies what the cache holds and says how old it is. Reads tolerate absence
12
+ // and damage the way credential.ts does: a broken cache reads as "no rules",
13
+ // never as a failed scrub.
14
+ import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
15
+ import { dirname, join } from 'node:path';
16
+ import { homedir } from 'node:os';
17
+ import { STORE_DIR } from '@veilio-inc/engine';
18
+ export const RULES_FILE = 'rules.json';
19
+ export function rulesPath(home = homedir()) {
20
+ return join(home, STORE_DIR, RULES_FILE);
21
+ }
22
+ /**
23
+ * Personal and team rules in the order the web app applies them:
24
+ * team whitelist, personal whitelist, team replace, personal replace.
25
+ *
26
+ * Whitelists first so a name either list keeps readable is never renamed by a
27
+ * replace rule; team before personal so the team's naming wins on a clash,
28
+ * which is what keeps two members' output interchangeable. Disabled rules are
29
+ * dropped and sort_order renumbered 0..n-1, so the engine sees one sequence.
30
+ * Must match `useMergedRules` in the Cloud frontend.
31
+ */
32
+ export function mergeRules(personal, team) {
33
+ const byOrder = (a, b) => a.sort_order - b.sort_order;
34
+ const on = (list, type) => list.filter((r) => r.enabled && r.type === type).sort(byOrder);
35
+ return [
36
+ ...on(team, 'whitelist'),
37
+ ...on(personal, 'whitelist'),
38
+ ...on(team, 'replace'),
39
+ ...on(personal, 'replace'),
40
+ ].map((r, i) => ({ ...r, sort_order: i }));
41
+ }
42
+ function isRule(value) {
43
+ if (typeof value !== 'object' || value === null)
44
+ return false;
45
+ const r = value;
46
+ if (typeof r.pattern !== 'string' || typeof r.sort_order !== 'number')
47
+ return false;
48
+ if (r.type === 'whitelist')
49
+ return true;
50
+ return r.type === 'replace' && typeof r.placeholder === 'string';
51
+ }
52
+ /** The cached rules for this account, or null. Null for every kind of failure. */
53
+ export function readRules(owner, home = homedir()) {
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(readFileSync(rulesPath(home), 'utf8'));
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ if (typeof parsed !== 'object' || parsed === null)
62
+ return null;
63
+ const c = parsed;
64
+ if (c.instance !== owner.instance || c.account !== owner.account)
65
+ return null;
66
+ if (typeof c.pulledAt !== 'string' || !Array.isArray(c.rules) || !c.rules.every(isRule)) {
67
+ return null;
68
+ }
69
+ return parsed;
70
+ }
71
+ /** 0600: the patterns name what a team considers sensitive. */
72
+ export function writeRules(cached, home = homedir()) {
73
+ const path = rulesPath(home);
74
+ mkdirSync(dirname(path), { recursive: true });
75
+ writeFileSync(path, `${JSON.stringify(cached, null, 2)}\n`, { mode: 0o600 });
76
+ chmodSync(path, 0o600);
77
+ }
78
+ /** Remove the cache. Missing is not an error; failing to delete is. */
79
+ export function removeRules(home = homedir()) {
80
+ const path = rulesPath(home);
81
+ try {
82
+ statSync(path);
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ rmSync(path, { recursive: true, force: true });
88
+ return true;
89
+ }
90
+ /** "3 hours ago" - coarse on purpose; it answers "is this stale", no more. */
91
+ export function describeAge(pulledAt, now = new Date()) {
92
+ const ms = now.getTime() - new Date(pulledAt).getTime();
93
+ if (!Number.isFinite(ms))
94
+ return 'at an unknown time';
95
+ const minutes = Math.max(0, Math.floor(ms / 60_000));
96
+ if (minutes < 60)
97
+ return minutes <= 1 ? 'just now' : `${minutes} minutes ago`;
98
+ const hours = Math.floor(minutes / 60);
99
+ if (hours < 48)
100
+ return `${hours} hour${hours === 1 ? '' : 's'} ago`;
101
+ return `${Math.floor(hours / 24)} days ago`;
102
+ }
103
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
package/dist/store.d.ts CHANGED
@@ -12,7 +12,31 @@ export interface StoredMap {
12
12
  /** Schema marker so a future format change can be detected rather than
13
13
  * silently misread as a map. */
14
14
  version: 1;
15
+ /**
16
+ * Where this map came from in Cloud, if it came from Cloud.
17
+ *
18
+ * Present only for a map that was pulled or pushed. Its whole purpose is to
19
+ * make divergence DETECTABLE: without it, `pull` cannot tell "this is the map
20
+ * I pulled and have not touched" from "this is a different map with the same
21
+ * name", and the only safe behaviour left would be to overwrite or to refuse
22
+ * always. Neither is the answer — the contract says a conflict is reported.
23
+ */
24
+ remote?: {
25
+ id: string;
26
+ /** Cloud's `updated_at` at the moment we pulled. */
27
+ updatedAt: string;
28
+ pulledAt?: string;
29
+ pushedAt?: string;
30
+ };
15
31
  }
32
+ /**
33
+ * The Cloud provenance recorded alongside the local map, if any.
34
+ *
35
+ * Separate from `loadMap` because every existing caller wants the map and
36
+ * nothing else, and because a store written before this existed simply has no
37
+ * `remote` — which reads correctly as "this map did not come from Cloud".
38
+ */
39
+ export declare function loadRemote(path: string): StoredMap['remote'] | undefined;
16
40
  /** Read the stored map, or an empty map when there is none. Throws only when a
17
41
  * file exists but cannot be understood — silently starting from empty there
18
42
  * would orphan every placeholder the user already has in flight. */
@@ -36,6 +60,7 @@ export declare class MapOverwriteError extends Error {
36
60
  */
37
61
  export declare function saveMap(path: string, map: SymbolMap, options?: {
38
62
  force?: boolean;
63
+ remote?: StoredMap['remote'];
39
64
  }): void;
40
65
  export declare function clearMap(path: string): boolean;
41
66
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9D,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAO,MAAM,UAAU,aAAa,CAAA;AAEpC;;oCAEoC;AACpC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,SAAS,CAAA;IACd;qCACiC;IACjC,OAAO,EAAE,CAAC,CAAA;CACX;AAOD;;qEAEqE;AACrE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAgB/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,IAAI,CA8B7F;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAI9C"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9D,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAO,MAAM,UAAU,aAAa,CAAA;AAEpC;;oCAEoC;AACpC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,SAAS,CAAA;IACd;qCACiC;IACjC,OAAO,EAAE,CAAC,CAAA;IACV;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE;QACP,EAAE,EAAE,MAAM,CAAA;QACV,oDAAoD;QACpD,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAOD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,SAAS,CAYxE;AAED;;qEAEqE;AACrE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAgB/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,SAAS,EACd,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAA;CAAO,GAC9D,IAAI,CAiCN;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAI9C"}