@glyphteck/veyl 0.68.0 → 0.69.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.
@@ -48,39 +48,7 @@ var __export = (target, all) => {
48
48
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
49
49
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
50
50
 
51
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/_u64.js
52
- function fromBig(n, le = false) {
53
- if (le)
54
- return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
55
- return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
56
- }
57
- function split(lst, le = false) {
58
- const len = lst.length;
59
- let Ah = new Uint32Array(len);
60
- let Al = new Uint32Array(len);
61
- for (let i = 0;i < len; i++) {
62
- const { h, l } = fromBig(lst[i], le);
63
- [Ah[i], Al[i]] = [h, l];
64
- }
65
- return [Ah, Al];
66
- }
67
- function setU64FromNum(view, byteOffset, n, isLE) {
68
- const h = fromNumH(n);
69
- const l = fromNumL(n);
70
- view.setUint32(byteOffset, isLE ? l : h, isLE);
71
- view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
72
- }
73
- function add(Ah, Al, Bh, Bl) {
74
- const l = (Al >>> 0) + (Bl >>> 0);
75
- return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 };
76
- }
77
- var U32_MASK64, _32n, fromNumH = (n) => n / 2 ** 32 | 0, fromNumL = (n) => n >>> 0, shrSH = (h, _l, s) => h >>> s, shrSL = (h, l, s) => h << 32 - s | l >>> s, rotrSH = (h, l, s) => h >>> s | l << 32 - s, rotrSL = (h, l, s) => h << 32 - s | l >>> s, rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32, rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s, rotr32H = (_h, l) => l, rotr32L = (h, _l) => h, add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0), add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0, add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0), add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0, add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0), add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
78
- var init__u64 = __esm(() => {
79
- U32_MASK64 = /* @__PURE__ */ (() => BigInt(2 ** 32 - 1))();
80
- _32n = /* @__PURE__ */ BigInt(32);
81
- });
82
-
83
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/utils.js
51
+ // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/utils.js
84
52
  function isBytes(a) {
85
53
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
86
54
  }
@@ -198,7 +166,12 @@ function hexToBytes(hex) {
198
166
  function utf8ToBytes(str) {
199
167
  if (typeof str !== "string")
200
168
  throw new TypeError("string expected");
201
- return new Uint8Array(new TextEncoder().encode(str));
169
+ const encoded = new TextEncoder().encode(str);
170
+ try {
171
+ return new Uint8Array(encoded);
172
+ } finally {
173
+ clean(encoded);
174
+ }
202
175
  }
203
176
  function kdfInputToBytes(data, errorTitle = "") {
204
177
  if (typeof data === "string")
@@ -221,10 +194,10 @@ function concatBytes(...arrays) {
221
194
  return res;
222
195
  }
223
196
  function checkOpts(defaults, opts, title = "opts") {
224
- aobject(defaults, "defaults");
197
+ aopts(defaults, "defaults");
225
198
  if (opts !== undefined)
226
- aobject(opts, title);
227
- const merged = Object.assign(defaults, opts);
199
+ aopts(opts, title);
200
+ const merged = Object.assign(Object.create(null), defaults, opts);
228
201
  return merged;
229
202
  }
230
203
  function createHasher(hashCons, info = {}) {
@@ -252,6 +225,13 @@ function randomBytes(bytesLength = 32) {
252
225
  var atitle = (title) => title ? `"${title}" ` : "", aobject = (value, label) => {
253
226
  if (value === null || typeof value !== "object" || Array.isArray(value))
254
227
  throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value);
228
+ }, aopts = (value, label) => {
229
+ aobject(value, label);
230
+ const proto = Object.getPrototypeOf(value);
231
+ if (proto !== Object.prototype && proto !== null)
232
+ throw new TypeError(`"${label}" expected plain object`);
233
+ if (Object.hasOwn(value, "__proto__"))
234
+ throw new TypeError(`"${label}.__proto__" is not allowed`);
255
235
  }, isLE, swap8IfBE, swap32IfBE, hasHexBuiltin, hexes, oidNist = (suffix) => ({
256
236
  oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
257
237
  });
@@ -263,7 +243,39 @@ var init_utils = __esm(() => {
263
243
  hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
264
244
  });
265
245
 
266
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/_md.js
246
+ // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/_u64.js
247
+ function fromBig(n, le = false) {
248
+ if (le)
249
+ return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
250
+ return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
251
+ }
252
+ function split(lst, le = false) {
253
+ const len = lst.length;
254
+ let Ah = new Uint32Array(len);
255
+ let Al = new Uint32Array(len);
256
+ for (let i = 0;i < len; i++) {
257
+ const { h, l } = fromBig(lst[i], le);
258
+ [Ah[i], Al[i]] = [h, l];
259
+ }
260
+ return [Ah, Al];
261
+ }
262
+ function setU64FromNum(view, byteOffset, n, isLE2) {
263
+ const h = fromNumH(n);
264
+ const l = fromNumL(n);
265
+ view.setUint32(byteOffset, isLE2 ? l : h, isLE2);
266
+ view.setUint32(byteOffset + 4, isLE2 ? h : l, isLE2);
267
+ }
268
+ function add(Ah, Al, Bh, Bl) {
269
+ const l = (Al >>> 0) + (Bl >>> 0);
270
+ return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 };
271
+ }
272
+ var U32_MASK64, _32n, fromNumH = (n) => n / 2 ** 32 | 0, fromNumL = (n) => n >>> 0, shrSH = (h, _l, s) => h >>> s, shrSL = (h, l, s) => h << 32 - s | l >>> s, rotrSH = (h, l, s) => h >>> s | l << 32 - s, rotrSL = (h, l, s) => h << 32 - s | l >>> s, rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32, rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s, rotr32H = (_h, l) => l, rotr32L = (h, _l) => h, add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0), add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0, add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0), add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0, add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0), add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
273
+ var init__u64 = __esm(() => {
274
+ U32_MASK64 = /* @__PURE__ */ (() => BigInt(2 ** 32 - 1))();
275
+ _32n = /* @__PURE__ */ BigInt(32);
276
+ });
277
+
278
+ // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/_md.js
267
279
  function Chi(a, b, c) {
268
280
  return a & b ^ ~a & c;
269
281
  }
@@ -402,10 +414,7 @@ var init__md = __esm(() => {
402
414
  // src/runtime/kdf-worker-thread.js
403
415
  import { parentPort } from "node:worker_threads";
404
416
 
405
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/argon2.js
406
- init__u64();
407
-
408
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/_blake.js
417
+ // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/_blake.js
409
418
  var BSIGMA = /* @__PURE__ */ Uint8Array.from([
410
419
  0,
411
420
  1,
@@ -665,7 +674,7 @@ var BSIGMA = /* @__PURE__ */ Uint8Array.from([
665
674
  9
666
675
  ]);
667
676
 
668
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/blake2.js
677
+ // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/blake2.js
669
678
  init__u64();
670
679
  init_utils();
671
680
  var B2B_IV = /* @__PURE__ */ Uint32Array.from([
@@ -1000,7 +1009,7 @@ class _BLAKE2b extends _BLAKE2 {
1000
1009
  }
1001
1010
  var blake2b = /* @__PURE__ */ createHasher((opts) => new _BLAKE2b(opts));
1002
1011
 
1003
- // ../../node_modules/.bun/@noble+hashes@2.3.0/node_modules/@noble/hashes/argon2.js
1012
+ // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/argon2.js
1004
1013
  init_utils();
1005
1014
  var AT = { Argon2d: 0, Argon2i: 1, Argon2id: 2 };
1006
1015
  var ARGON2_SYNC_POINTS = 4;
@@ -1009,25 +1018,6 @@ var abytesOrZero = (buf, errorTitle = "") => {
1009
1018
  return Uint8Array.of();
1010
1019
  return kdfInputToBytes(buf, errorTitle);
1011
1020
  };
1012
- function mul(a, b) {
1013
- const aL = a & 65535;
1014
- const aH = a >>> 16;
1015
- const bL = b & 65535;
1016
- const bH = b >>> 16;
1017
- const ll = Math.imul(aL, bL);
1018
- const hl = Math.imul(aH, bL);
1019
- const lh = Math.imul(aL, bH);
1020
- const hh = Math.imul(aH, bH);
1021
- const carry = (ll >>> 16) + (hl & 65535) + lh;
1022
- const high = hh + (hl >>> 16) + (carry >>> 16) | 0;
1023
- const low = carry << 16 | ll & 65535;
1024
- return { h: high, l: low };
1025
- }
1026
- function mulHi(a, b) {
1027
- const aL = a & 65535, aH = a >>> 16, bL = b & 65535, bH = b >>> 16;
1028
- const carry = (Math.imul(aL, bL) >>> 16) + (Math.imul(aH, bL) & 65535) + Math.imul(aL, bH);
1029
- return Math.imul(aH, bH) + (Math.imul(aH, bL) >>> 16) + (carry >>> 16) | 0;
1030
- }
1031
1021
  var A2_BUF = new Uint32Array(256);
1032
1022
  function G(a, b, c, d) {
1033
1023
  let Al = A2_BUF[2 * a], Ah = A2_BUF[2 * a + 1];
@@ -1036,41 +1026,41 @@ function G(a, b, c, d) {
1036
1026
  let Dl = A2_BUF[2 * d], Dh = A2_BUF[2 * d + 1];
1037
1027
  let ml = 0, mh = 0, rl = 0, xh = 0, xl = 0;
1038
1028
  ml = Math.imul(Al, Bl);
1039
- mh = mulHi(Al, Bl);
1029
+ mh = ((Al >>> 0) * (Bl >>> 0) - (ml >>> 0)) / 4294967296 + 0.5 | 0;
1040
1030
  rl = (Al >>> 0) + (Bl >>> 0) + (ml << 1 >>> 0);
1041
1031
  Ah = Ah + Bh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0;
1042
1032
  Al = rl | 0;
1043
1033
  xh = Dh ^ Ah;
1044
1034
  xl = Dl ^ Al;
1045
- Dh = rotr32H(xh, xl);
1046
- Dl = rotr32L(xh, xl);
1035
+ Dh = xl;
1036
+ Dl = xh;
1047
1037
  ml = Math.imul(Cl, Dl);
1048
- mh = mulHi(Cl, Dl);
1038
+ mh = ((Cl >>> 0) * (Dl >>> 0) - (ml >>> 0)) / 4294967296 + 0.5 | 0;
1049
1039
  rl = (Cl >>> 0) + (Dl >>> 0) + (ml << 1 >>> 0);
1050
1040
  Ch = Ch + Dh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0;
1051
1041
  Cl = rl | 0;
1052
1042
  xh = Bh ^ Ch;
1053
1043
  xl = Bl ^ Cl;
1054
- Bh = rotrSH(xh, xl, 24);
1055
- Bl = rotrSL(xh, xl, 24);
1044
+ Bh = xh >>> 24 | xl << 8;
1045
+ Bl = xh << 8 | xl >>> 24;
1056
1046
  ml = Math.imul(Al, Bl);
1057
- mh = mulHi(Al, Bl);
1047
+ mh = ((Al >>> 0) * (Bl >>> 0) - (ml >>> 0)) / 4294967296 + 0.5 | 0;
1058
1048
  rl = (Al >>> 0) + (Bl >>> 0) + (ml << 1 >>> 0);
1059
1049
  Ah = Ah + Bh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0;
1060
1050
  Al = rl | 0;
1061
1051
  xh = Dh ^ Ah;
1062
1052
  xl = Dl ^ Al;
1063
- Dh = rotrSH(xh, xl, 16);
1064
- Dl = rotrSL(xh, xl, 16);
1053
+ Dh = xh >>> 16 | xl << 16;
1054
+ Dl = xh << 16 | xl >>> 16;
1065
1055
  ml = Math.imul(Cl, Dl);
1066
- mh = mulHi(Cl, Dl);
1056
+ mh = ((Cl >>> 0) * (Dl >>> 0) - (ml >>> 0)) / 4294967296 + 0.5 | 0;
1067
1057
  rl = (Cl >>> 0) + (Dl >>> 0) + (ml << 1 >>> 0);
1068
1058
  Ch = Ch + Dh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0;
1069
1059
  Cl = rl | 0;
1070
1060
  xh = Bh ^ Ch;
1071
1061
  xl = Bl ^ Cl;
1072
- Bh = rotrBH(xh, xl, 63);
1073
- Bl = rotrBL(xh, xl, 63);
1062
+ Bh = xh << 1 | xl >>> 31;
1063
+ Bl = xh >>> 31 | xl << 1;
1074
1064
  A2_BUF[2 * a] = Al, A2_BUF[2 * a + 1] = Ah;
1075
1065
  A2_BUF[2 * b] = Bl, A2_BUF[2 * b + 1] = Bh;
1076
1066
  A2_BUF[2 * c] = Cl, A2_BUF[2 * c + 1] = Ch;
@@ -1087,20 +1077,27 @@ function P(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13,
1087
1077
  G(v03, v04, v09, v14);
1088
1078
  }
1089
1079
  function block(x, xPos, yPos, outPos, needXor) {
1090
- for (let i = 0;i < 256; i++)
1091
- A2_BUF[i] = x[xPos + i] ^ x[yPos + i];
1080
+ if (needXor) {
1081
+ for (let i = 0;i < 256; i++) {
1082
+ const r = x[xPos + i] ^ x[yPos + i];
1083
+ A2_BUF[i] = r;
1084
+ x[outPos + i] ^= r;
1085
+ }
1086
+ } else {
1087
+ for (let i = 0;i < 256; i++) {
1088
+ const r = x[xPos + i] ^ x[yPos + i];
1089
+ A2_BUF[i] = r;
1090
+ x[outPos + i] = r;
1091
+ }
1092
+ }
1092
1093
  for (let i = 0;i < 128; i += 16) {
1093
1094
  P(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15);
1094
1095
  }
1095
1096
  for (let i = 0;i < 16; i += 2) {
1096
1097
  P(i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113);
1097
1098
  }
1098
- if (needXor)
1099
- for (let i = 0;i < 256; i++)
1100
- x[outPos + i] ^= A2_BUF[i] ^ x[xPos + i] ^ x[yPos + i];
1101
- else
1102
- for (let i = 0;i < 256; i++)
1103
- x[outPos + i] = A2_BUF[i] ^ x[xPos + i] ^ x[yPos + i];
1099
+ for (let i = 0;i < 256; i++)
1100
+ x[outPos + i] ^= A2_BUF[i];
1104
1101
  clean(A2_BUF);
1105
1102
  }
1106
1103
  function Hp(A, dkLen) {
@@ -1139,19 +1136,28 @@ function indexAlpha(r, s, laneLen, segmentLen, index, randL, sameLane = false) {
1139
1136
  else
1140
1137
  area = laneLen - segmentLen + (index == 0 ? -1 : 0);
1141
1138
  const startPos = r !== 0 && s !== ARGON2_SYNC_POINTS - 1 ? (s + 1) * segmentLen : 0;
1142
- const rel = area - 1 - mul(area, mul(randL, randL).h).h;
1139
+ const randLow = Math.imul(randL, randL);
1140
+ const randHigh = ((randL >>> 0) * (randL >>> 0) - (randLow >>> 0)) / 4294967296 + 0.5 | 0;
1141
+ const areaLow = Math.imul(area, randHigh);
1142
+ const areaHigh = ((area >>> 0) * (randHigh >>> 0) - (areaLow >>> 0)) / 4294967296 + 0.5 | 0;
1143
+ const rel = area - 1 - areaHigh;
1143
1144
  return (startPos + rel) % laneLen;
1144
1145
  }
1145
1146
  var maxUint32 = Math.pow(2, 32);
1147
+ var ARGON2_DEFAULT_MEMORY = 1024 ** 2;
1148
+ var ARGON2_DEFAULT_MAXMEM = ARGON2_DEFAULT_MEMORY * 1024;
1146
1149
  function isU32(num) {
1147
1150
  return Number.isSafeInteger(num) && num >= 0 && num < maxUint32;
1148
1151
  }
1149
- function argon2Opts(opts) {
1152
+ function argon2Opts(opts = {}) {
1150
1153
  opts = checkOpts({}, opts);
1151
1154
  const merged = {
1155
+ t: 3,
1156
+ m: ARGON2_DEFAULT_MEMORY,
1157
+ p: 1,
1152
1158
  version: 19,
1153
1159
  dkLen: 32,
1154
- maxmem: maxUint32 - 1,
1160
+ maxmem: ARGON2_DEFAULT_MAXMEM,
1155
1161
  asyncTick: 10
1156
1162
  };
1157
1163
  for (let [k, v] of Object.entries(opts))
@@ -1175,63 +1181,89 @@ function argon2Opts(opts) {
1175
1181
  throw new Error('"version" must be 0x10 or 0x13, got ' + version);
1176
1182
  return merged;
1177
1183
  }
1178
- function argon2Init(password, salt, type, opts) {
1179
- password = kdfInputToBytes(password, "password");
1180
- salt = kdfInputToBytes(salt, "salt");
1181
- if (!isU32(password.length))
1182
- throw new Error('"password" must be less of length 1..4Gb');
1183
- if (!isU32(salt.length) || salt.length < 8)
1184
- throw new Error('"salt" must be of length 8..4Gb');
1185
- if (!Object.values(AT).includes(type))
1186
- throw new Error('"type" was invalid');
1187
- let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress, asyncTick } = argon2Opts(opts);
1188
- key = abytesOrZero(key, "key");
1189
- personalization = abytesOrZero(personalization, "personalization");
1190
- const h = blake2b.create();
1184
+ function argon2InitialHash(password, salt, type, opts) {
1185
+ const ownedInputs = [];
1191
1186
  const BUF = new Uint32Array(1);
1192
1187
  const BUF8 = u8(BUF);
1193
- for (let item of [p, dkLen, m, t, version, type]) {
1194
- BUF[0] = swap8IfBE(item);
1195
- h.update(BUF8);
1196
- }
1197
- for (let i of [password, salt, key, personalization]) {
1198
- BUF[0] = swap8IfBE(i.length);
1199
- h.update(BUF8).update(i);
1200
- }
1201
- const H0 = new Uint32Array(18);
1202
- const H0_8 = u8(H0);
1203
- h.digestInto(H0_8);
1204
- const lanes = p;
1205
- const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p));
1206
- const laneLen = Math.floor(mP / p);
1207
- const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS);
1208
- const memUsed = mP * 1024;
1209
- if (!isU32(maxmem))
1210
- throw new Error('"maxmem" expected <2**32, got ' + maxmem);
1211
- if (memUsed > maxmem)
1212
- throw new Error('"maxmem" limit was hit: memUsed(mP*1024)=' + memUsed + ", maxmem=" + maxmem);
1213
- const B = new Uint32Array(memUsed / 4);
1214
- for (let l = 0;l < p; l++) {
1215
- const i = 256 * laneLen * l;
1216
- H0[17] = swap8IfBE(l);
1217
- H0[16] = swap8IfBE(0);
1218
- B.set(swap32IfBE(u32(Hp(H0, 1024))), i);
1219
- H0[16] = swap8IfBE(1);
1220
- B.set(swap32IfBE(u32(Hp(H0, 1024))), i + 256);
1188
+ let h;
1189
+ let H0;
1190
+ let succeeded = false;
1191
+ const rememberOwned = (input, bytes) => {
1192
+ if (typeof input === "string")
1193
+ ownedInputs.push(bytes);
1194
+ return bytes;
1195
+ };
1196
+ try {
1197
+ const passwordBytes = rememberOwned(password, kdfInputToBytes(password, "password"));
1198
+ const saltBytes = rememberOwned(salt, kdfInputToBytes(salt, "salt"));
1199
+ if (!isU32(passwordBytes.length))
1200
+ throw new Error('"password" must be less of length 1..4Gb');
1201
+ if (!isU32(saltBytes.length) || saltBytes.length < 8)
1202
+ throw new Error('"salt" must be of length 8..4Gb');
1203
+ if (!Object.values(AT).includes(type))
1204
+ throw new Error('"type" was invalid');
1205
+ let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress, asyncTick } = argon2Opts(opts);
1206
+ const keyInput = key;
1207
+ key = rememberOwned(keyInput, abytesOrZero(keyInput, "key"));
1208
+ const personalizationInput = personalization;
1209
+ personalization = rememberOwned(personalizationInput, abytesOrZero(personalizationInput, "personalization"));
1210
+ h = blake2b.create();
1211
+ for (let item of [p, dkLen, m, t, version, type]) {
1212
+ BUF[0] = swap8IfBE(item);
1213
+ h.update(BUF8);
1214
+ }
1215
+ for (let i of [passwordBytes, saltBytes, key, personalization]) {
1216
+ BUF[0] = swap8IfBE(i.length);
1217
+ h.update(BUF8).update(i);
1218
+ }
1219
+ H0 = new Uint32Array(18);
1220
+ h.digestInto(u8(H0));
1221
+ succeeded = true;
1222
+ return { H0, p, dkLen, m, t, version, maxmem, onProgress, asyncTick };
1223
+ } finally {
1224
+ if (h)
1225
+ h.destroy();
1226
+ clean(BUF, ...ownedInputs);
1227
+ if (!succeeded && H0)
1228
+ clean(H0);
1221
1229
  }
1222
- let perBlock = () => {};
1223
- if (onProgress) {
1224
- const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen - 2 * p;
1225
- const callbackPer = Math.max(Math.floor(totalBlock / 1e4), 1);
1226
- let blockCnt = 0;
1227
- perBlock = () => {
1228
- blockCnt++;
1229
- if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock))
1230
- onProgress(blockCnt / totalBlock);
1231
- };
1230
+ }
1231
+ function argon2Init(password, salt, type, opts) {
1232
+ const { H0, p, dkLen, m, t, version, maxmem, onProgress, asyncTick } = argon2InitialHash(password, salt, type, opts);
1233
+ try {
1234
+ const lanes = p;
1235
+ const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p));
1236
+ const laneLen = Math.floor(mP / p);
1237
+ const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS);
1238
+ const memUsed = mP * 1024;
1239
+ if (!isU32(maxmem))
1240
+ throw new Error('"maxmem" expected <2**32, got ' + maxmem);
1241
+ if (memUsed > maxmem)
1242
+ throw new Error('"maxmem" limit was hit: memUsed(mP*1024)=' + memUsed + ", maxmem=" + maxmem);
1243
+ const B = new Uint32Array(memUsed / 4);
1244
+ for (let l = 0;l < p; l++) {
1245
+ const i = 256 * laneLen * l;
1246
+ H0[17] = swap8IfBE(l);
1247
+ H0[16] = swap8IfBE(0);
1248
+ B.set(swap32IfBE(u32(Hp(H0, 1024))), i);
1249
+ H0[16] = swap8IfBE(1);
1250
+ B.set(swap32IfBE(u32(Hp(H0, 1024))), i + 256);
1251
+ }
1252
+ let perBlock = () => {};
1253
+ if (onProgress) {
1254
+ const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen - 2 * p;
1255
+ const callbackPer = Math.max(Math.floor(totalBlock / 1e4), 1);
1256
+ let blockCnt = 0;
1257
+ perBlock = () => {
1258
+ blockCnt++;
1259
+ if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock))
1260
+ onProgress(blockCnt / totalBlock);
1261
+ };
1262
+ }
1263
+ return { type, mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick };
1264
+ } finally {
1265
+ clean(H0);
1232
1266
  }
1233
- clean(BUF, H0);
1234
- return { type, mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick };
1235
1267
  }
1236
1268
  function argon2Output(B, p, laneLen, dkLen) {
1237
1269
  const B_final = new Uint32Array(256);
@@ -1242,9 +1274,8 @@ function argon2Output(B, p, laneLen, dkLen) {
1242
1274
  clean(B, B_final);
1243
1275
  return res;
1244
1276
  }
1245
- function* argon2Blocks(ctx) {
1277
+ function* argon2Blocks(ctx, address) {
1246
1278
  const { type, mP, p, t, version, B, laneLen, lanes, segmentLen, perBlock } = ctx;
1247
- const address = new Uint32Array(3 * 256);
1248
1279
  address[256 + 6] = mP;
1249
1280
  address[256 + 8] = t;
1250
1281
  address[256 + 10] = type;
@@ -1298,11 +1329,11 @@ function* argon2Blocks(ctx) {
1298
1329
  }
1299
1330
  function argon2(type, password, salt, opts) {
1300
1331
  const ctx = argon2Init(password, salt, type, opts);
1301
- const blocks = argon2Blocks(ctx);
1332
+ const blocks = argon2Blocks(ctx, new Uint32Array(3 * 256));
1302
1333
  while (!blocks.next().done) {}
1303
1334
  return argon2Output(ctx.B, ctx.p, ctx.laneLen, ctx.dkLen);
1304
1335
  }
1305
- var argon2id = (password, salt, opts) => argon2(AT.Argon2id, password, salt, opts);
1336
+ var argon2id = (password, salt, opts = {}) => argon2(AT.Argon2id, password, salt, opts);
1306
1337
 
1307
1338
  // src/runtime/kdf-worker-thread.js
1308
1339
  if (!parentPort)
package/docs/agents.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use the JavaScript API for a long-running agent and the canonical CLI for one-off shell work. A local read-only MCP resource server can help an MCP-capable host discover the installed SDK documentation, but it cannot operate Veyl.
4
4
 
5
- The SDK is not a privileged backend. It authenticates, decrypts the vault, signs wallet operations, encrypts/signs chat actions, and maintains encrypted local cache state exactly like web and iOS. Machine credentials and passkeys are authentication capabilities, not human-or-bot classifications. Third-party agents use ordinary public profiles; only namespace-authorized Glyphteck services carry the managed bot marker.
5
+ The SDK is not a privileged backend. It authenticates, decrypts the vault, signs wallet operations, encrypts/signs chat actions, and maintains encrypted local cache state exactly like web and iOS. A public profile is `sdk` while it is machine-only and becomes `app` if a passkey is linked. That describes its available client surface, not whether a person or agent operates it.
6
6
 
7
7
  ## Setup
8
8
 
@@ -101,7 +101,7 @@ Agents should correct normal validation errors from their messages. They should
101
101
  - preserve `operationId`;
102
102
  - do not blindly repeat a Spark send, request payment, external invoice payment, or withdrawal;
103
103
  - reconcile public wallet history or application state first;
104
- - retry Lightning only when `retryable === true`, using the exact same `idempotencyKey`.
104
+ - retry Lightning only when `retryable === true`, using `operationId` as the exact same `transferId`.
105
105
 
106
106
  This is intentionally a small contract for the one class of error where automatic self-correction can lose money. Veyl does not maintain a large error taxonomy for ordinary mistakes.
107
107
 
package/docs/api.md CHANGED
@@ -25,6 +25,14 @@ The auth and account compositions consume explicit runtime ports and have no dir
25
25
 
26
26
  Most product methods ensure login and vault unlock when saved account and vault keys are available. Long-running callers should explicitly login/unlock once and call `close()` when finished.
27
27
 
28
+ ### Local access and connectivity
29
+
30
+ The shared account owner separates `localReady`, `online`, and `connection` in its snapshot. `localReady` means the exact locally signed-in account has enough encrypted bootstrap data for vault unlock; it is not server authorization. Unlock opens encrypted cached chats and wallet history without waiting for cloud services. Cached balance is display-only and must be labeled last known. `online` becomes true after cloud reads and online proof succeed; reconnect attaches services to the same unlocked session. Chat writes fail with `unavailable` while offline, and live wallet readiness remains mandatory for payments. There is no offline mutation queue.
31
+
32
+ Custom platform hosts may provide `bootstrapStorage.read(uid)`, `write(uid, snapshot)`, and `remove(uid)` to `openAccount`, and call `setInternetAvailable(false | true | null)` with platform reachability. Encrypt bootstrap data under the account/environment-bound install key; never put decrypted private content there. Standard web, iOS and Node adapters supply encrypted storage. Logout or observed revocation removes it.
33
+
34
+ Node authentication is currently process-local: a fresh SDK/CLI process still needs the network to authenticate, even with saved credentials. Cached access supports an already-authenticated long-running SDK process; saved username/profile metadata cannot establish an offline session. Web and iOS can restore their platform-persisted signed-in auth slots.
35
+
28
36
  ## Graphical auth owner
29
37
 
30
38
  ```js
@@ -193,7 +201,7 @@ try {
193
201
  }
194
202
  ```
195
203
 
196
- An unknown Spark send, payment-request payment, invoice payment, or withdrawal outcome has `retryable: false`. Reconcile wallet transactions or the named operation before deciding what to do; blindly repeating it can spend twice. An unknown Lightning payment is retryable only when the same caller-supplied `idempotencyKey` will be reused. Direct CLI errors and persistent-session transport preserve these fields instead of reducing them to an error string.
204
+ An unknown Spark send, payment-request payment, invoice payment, or withdrawal outcome has `retryable: false`. Reconcile wallet transactions or the named operation before deciding what to do; blindly repeating it can spend twice. An unknown Lightning payment is retryable only when the same `transferId` will be reused. Veyl creates that UUID before the first attempt and returns it as `operationId` on an uncertain outcome. Direct CLI errors and persistent-session transport preserve these fields instead of reducing them to an error string.
197
205
 
198
206
  ## Account
199
207
 
@@ -214,7 +222,7 @@ await veyl.account.logoutAll();
214
222
  await veyl.account.delete({ confirm: true });
215
223
  ```
216
224
 
217
- - `create` makes an ordinary account authenticated by a local machine credential and returns its account key directly. Authentication does not assign a public bot label.
225
+ - `create` makes an account authenticated by a local machine credential, publishes its account type as `sdk`, and returns its account key directly.
218
226
  - `createPasskey({ username, webUrl, onUrl })` creates a normal passkey account through a browser-assisted WebAuthn flow, installs a local machine credential for future CLI sessions, and returns that account key directly.
219
227
  - `login({ username?, key?, saveKey? })` authenticates with an account key. The key can instead come from `open({ accountKey })` or `VEYL_ACCOUNT_KEY`.
220
228
  - `loginPasskey({ username?, webUrl?, onUrl? })` authenticates through the browser-assisted passkey flow.
@@ -225,7 +233,7 @@ await veyl.account.delete({ confirm: true });
225
233
  - `logoutAll` revokes every product session generation, tears down this runtime locally, and stops a persistent CLI owner after its in-flight work drains.
226
234
  - `delete({ confirm: true, key? })` drains decryptable inbox state, marks all discoverable chats deleted, destroys the complete account/network encrypted cache scope, proves vault possession inside the same destructive operation, deletes identifiable account data, removes the local profile, and stops a persistent CLI owner after its in-flight work drains. `key` is required only when the runtime has no saved vault key.
227
235
 
228
- Account summaries report identity, network, local credential/vault availability, public wallet/chat keys, auth kind, an explicit managed-bot marker when assigned by Glyphteck's owner namespace, and current signed-in/unlocked state. Account and vault keys are never included in summaries.
236
+ Account summaries report identity, network, local credential/vault availability, public wallet/chat keys, auth kind, public `app` or `sdk` account type, and current signed-in/unlocked state. Linking a passkey promotes the type to `app`; account and vault keys are never included in summaries.
229
237
 
230
238
  ## Vault
231
239
 
@@ -257,7 +265,7 @@ await veyl.cache.show();
257
265
  await veyl.cache.clear();
258
266
  ```
259
267
 
260
- `uploadAvatar` accepts prepared WebP bytes and uses the shared profile/avatar backend owner. `setChatAdmission` publishes a public `direct` mode (`open`, `requests`, or `closed`), a `groups` mode (`open` or `closed`), and a fixed-size padded set of private pair-capability commitments for up to eight allowed direct peers. Allowed peers may be usernames or public chat keys; their identities are resolved locally and are not published in the policy. Missing policies remain open for ordinary accounts, while malformed present policies fail closed. Existing chats retain their private routes.
268
+ `uploadAvatar` accepts prepared WebP bytes and uses the shared profile/avatar backend owner. `setChatAdmission` publishes a public `direct` mode (`open`, `requests`, or `closed`), a `groups` mode (`open` or `closed`), and a fixed-size padded set of private pair-capability commitments for up to eight allowed direct peers. Allowed peers may be usernames or public chat keys; their identities are resolved locally and are not published in the policy. Missing policies remain open for ordinary accounts, while malformed present policies fail closed. Existing membership does not bypass a closed policy: disallowed chats are hidden and unavailable for admission-controlled actions, but policy changes never delete a direct or leave a group. `groups: closed` also prevents new group membership.
261
269
 
262
270
  Settings use the shared normalization and encrypted settings document. Changing `walletNetwork` locks the current vault so the next unlock boots the selected network. Cache methods operate on the same vault-encrypted display and media cache as the other clients.
263
271
 
@@ -272,7 +280,7 @@ await veyl.peers.block('@alice');
272
280
  await veyl.peers.unblock('@alice');
273
281
  ```
274
282
 
275
- Peer resolution accepts `@username`, username, chat public key, or wallet public key when the operation supports it. Blocking self is rejected. Peer/profile results are public projections and do not expose local cache internals. `peers.show` authoritatively refreshes a cached identity; a confirmed missing profile evicts it and deletes loaded chats through the shared missing-peer owner. Normal chat/wallet actions keep the shared cached fast path, while their server-side operations still validate the authoritative route they mutate.
283
+ Peer resolution accepts `@username`, username, chat public key, or wallet public key when the operation supports it. Blocking self is rejected. A block independently submits a narrow user report, retires every private chat route containing that peer, and returns `reported` separately from `blocked`; report failure never prevents the block. Peer/profile results are public projections and do not expose local cache internals. `peers.show` authoritatively refreshes a cached identity; a confirmed missing profile evicts it and deletes loaded chats through the shared missing-peer owner. Normal chat/wallet actions keep the shared cached fast path, while their server-side operations still validate the authoritative route they mutate.
276
284
 
277
285
  ## Chat
278
286
 
@@ -326,7 +334,7 @@ await veyl.chat.react('@alice', sent.message.id, '+1');
326
334
  await veyl.chat.unreact('@alice', sent.message.id);
327
335
  await veyl.chat.save('@alice', sent.message.id);
328
336
  await veyl.chat.unsave('@alice', sent.message.id);
329
- await veyl.chat.update('@alice', sent.message.id, 'edited');
337
+ await veyl.chat.update('@alice', sent.message.id, 'edited'); // own text, strictly within 10 minutes
330
338
  await veyl.chat.delete('@alice', sent.message.id);
331
339
  await veyl.chat.retention('@alice', '24h');
332
340
  await veyl.chat.deleteChat('@alice', { cleanup: true });
@@ -419,7 +427,7 @@ await veyl.lightning.quote(invoice.encodedInvoice, { amountSats: 10 });
419
427
  await veyl.lightning.pay(invoice.encodedInvoice, {
420
428
  amountSats: 10,
421
429
  maxFeeSats: 5,
422
- idempotencyKey: 'order-123',
430
+ transferId: '019c0000-0000-7000-8000-000000000001',
423
431
  });
424
432
  await veyl.lightning.receive(receiveId);
425
433
  await veyl.lightning.send(sendId);
@@ -552,7 +560,7 @@ Losing the root loses every derived account. Back it up as carefully as a wallet
552
560
 
553
561
  An existing account cannot retroactively acquire a derived master seed. Adopting one requires a one-time authenticated handoff that installs its root-derived account key and encrypts the existing master seed under its root-derived vault key without changing wallet/chat material.
554
562
 
555
- The Glyphteck namespace seed is separate from a fleet root. `veyl namespace init` creates that owner-only local key once. When its default file exists under the fleet `homeDir`, provisioning automatically signs a short-lived claim bound to the exact derived machine credential so a reserved canonical username can use the normal public account-creation transaction. The seed is never stored in the manifest or an account profile. Other fleet operators do not have this key and cannot claim the reserved namespace.
563
+ The Veyl namespace seed is separate from a fleet root. `veyl namespace init` creates that owner-only local key once. When its default file exists under the fleet `homeDir`, provisioning automatically signs a short-lived claim bound to the exact derived machine credential so a reserved canonical username can use the normal public account-creation transaction. The seed is never stored in the manifest or an account profile. Other fleet operators do not have this key and cannot claim the reserved namespace.
556
564
 
557
565
  The owner opens one ordinary public client per enabled ready profile, runs account boots with bounded concurrency, tags events with their manifest account, preserves per-account policy order, fails visibly on backlog overflow, and closes every client on stop. An owner-only PID lock prevents two local processes from operating the fleet. It reclaims a dead same-host PID after a crash but never signals or replaces a healthy owner. Shared owners still control chat ordering, wallet serialization, encryption, cache, and account revocation.
558
566
 
package/docs/cli.md CHANGED
@@ -10,7 +10,7 @@ Run `veyl help` for the live inventory. The command families are summarized belo
10
10
  veyl namespace init
11
11
  ```
12
12
 
13
- This one-time owner command creates `~/.veyl/namespace.seed` with mode `0600` and prints only its public key and fingerprint. It never prints the private seed. `veyl account create @name --reserved` signs a short-lived reserved-name claim for the exact new machine credential. The explicit flag prevents ordinary account creation from disclosing an unnecessary namespace-owner signature. The fleet owner detects the same file under its `homeDir` because a Glyphteck-operated fleet is already public operator context. Ordinary installations without the trusted seed cannot claim a reserved username.
13
+ This one-time owner command creates `~/.veyl/namespace.seed` with mode `0600` and prints only its public key and fingerprint. It never prints the private seed. `veyl account create @name --reserved` signs a short-lived reserved-name claim for the exact new machine credential. The explicit flag prevents ordinary account creation from disclosing an unnecessary namespace-owner signature. The fleet owner detects the same file under its `homeDir` because a Veyl-managed fleet is already public operator context. Ordinary installations without the trusted seed cannot claim a reserved username.
14
14
 
15
15
  The namespace seed is not accepted through a command argument, environment variable, profile, or fleet manifest. Back up the file offline; losing it removes the ability to authorize another reserved account.
16
16
 
@@ -63,7 +63,7 @@ veyl peers block @alice
63
63
  veyl peers unblock @alice
64
64
  ```
65
65
 
66
- Blocking yourself is rejected. Blocking deletes the canonical direct chat and leaves every decrypted group containing that UID. A future successor containing the block is dropped locally; no readable server membership graph exists.
66
+ Blocking yourself is rejected. Blocking independently submits a narrow user report, deletes the canonical direct chat, and leaves every decrypted group containing that UID. Report failure does not prevent the block and is exposed separately in the command result. A future successor containing the block is dropped locally; no readable server membership graph exists.
67
67
 
68
68
  ## Chat
69
69
 
@@ -150,7 +150,7 @@ veyl wallet search @alice
150
150
  ```bash
151
151
  veyl lightning invoice 10 --memo "coffee" --expiry 3600
152
152
  veyl lightning quote INVOICE [--amount SATS]
153
- veyl lightning pay INVOICE [--amount SATS] [--max-fee SATS] [--idempotency-key KEY] [--operation-id AGENT_JOB_ID]
153
+ veyl lightning pay INVOICE [--amount SATS] [--max-fee SATS] [--transfer-id UUID]
154
154
  veyl lightning receive ID
155
155
  veyl lightning send ID
156
156
 
@@ -161,7 +161,7 @@ veyl withdrawal confirm ADDRESS SATS [--speed MEDIUM] [--fee-quote-id ID --fee-a
161
161
 
162
162
  `withdrawal quote` and `withdrawal prepare` do not spend or broadcast, but the Spark SDK may restructure wallet leaves while producing an exact quote. Pass both reviewed `feeQuoteId` and `feeAmountSats` back to `withdrawal confirm`; omitting both requests a fresh quote, while providing only one is rejected. `withdrawal confirm` performs the spend.
163
163
 
164
- Money commands print stable `code`, `operation`, `operationId`, `outcome`, and `retryable` fields when the SDK cannot determine whether a mutation committed. Do not replay a result with `code: "operation_outcome_unknown"` unless `retryable` is true. Today that is true only for Lightning when the exact same `--idempotency-key` can be reused; otherwise reconcile wallet history first.
164
+ Money commands print stable `code`, `operation`, `operationId`, `outcome`, and `retryable` fields when the SDK cannot determine whether a mutation committed. Do not replay a result with `code: "operation_outcome_unknown"` unless `retryable` is true. Today that is true only for Lightning: reuse the returned `operationId` as the exact same `--transfer-id`; otherwise reconcile wallet history first.
165
165
 
166
166
  ## Invites
167
167
 
@@ -28,7 +28,7 @@ CLI paths and persistent-session dispatch come from `src/commands.js`. Both one-
28
28
 
29
29
  The canonical registry defines 78 CLI commands, 70 persistent-session product commands, and 16 command groups. Wallet mnemonic export and passkey-link creation stay one-shot CLI/JavaScript API only; the namespace key, session owner, and documentation resource process controls also remain CLI-only. Registry coverage checks map every enabled session command and real CLI path to its declared public client method, with `chat.reactTo` retained only as a JavaScript convenience alias over the same reaction operation.
30
30
 
31
- Focused contract coverage mounts the real framework-free chat route through the public SDK runtime, verifies live projection, explicit leave, and manual/disabled read policy, and exercises persistent-session streaming plus abort-driven embedding shutdown. Agent-listener coverage proves a changed conversation uses a transient message window and releases it instead of retaining one listener per loaded chat, including a 500-chat requested window. Replay coverage expands older pages until a per-chat checkpoint is found, then emits only the newer messages. New-chat admission coverage uses real MLS Welcomes to prove a frozen public callback boundary, block precedence, fail-closed decisions, prekey cleanup, and established-chat bypass. The packaged single-agent example proves pinned owner filtering, default Node live transport, stable typing-to-message composition, deterministic final delivery, app-server JSONL/backpressure/errors, steering, owner-only state, and completed-turn recovery. Fleet coverage opens fake public clients under bounded concurrency, tags their events, runs policies, and proves all account and policy lifecycles close. Root coverage proves stable isolated account derivation, monotonically indexed recovery, and owner-only seed storage; manifest and profile coverage rejects or omits per-account secrets. Namespace coverage proves the local private seed is mode `0600`, never returned by initialization, and produces a claim that verifies only for its exact username, machine credential, and expiry; it also keeps the generated Functions trust anchor aligned with the shared public key. Local-owner coverage proves a second healthy process is never replaced and a dead same-host PID lock can be reclaimed without signaling it. The bounded event checkpoint persists processed IDs and baseline policy coverage proves historical messages are recorded without bot behavior. Action-journal coverage proves completed effects survive restart, replay-safe chat actions can reuse their deterministic CID, interrupted money actions stop for reconciliation, and a replayed faucet request is paid and mirrored once. The canonical Glyphteck runtime now consumes the packaged fleet example through ordinary SDK clients; remaining live fleet observations belong only in the root manual queue.
31
+ Focused contract coverage mounts the real framework-free chat route through the public SDK runtime, verifies live projection, explicit leave, and manual/disabled read policy, and exercises persistent-session streaming plus abort-driven embedding shutdown. Agent-listener coverage proves a changed conversation uses a transient message window and releases it instead of retaining one listener per loaded chat, including a 500-chat requested window. Replay coverage expands older pages until a per-chat checkpoint is found, then emits only the newer messages. Chat-admission coverage uses real MLS Welcomes to prove a frozen public callback boundary, block precedence, fail-closed decisions, prekey cleanup, and ongoing enforcement for established chats without automatic delete or leave events. The packaged single-agent example proves pinned owner filtering, default Node live transport, stable typing-to-message composition, deterministic final delivery, app-server JSONL/backpressure/errors, steering, owner-only state, and completed-turn recovery. Fleet coverage opens fake public clients under bounded concurrency, tags their events, runs policies, and proves all account and policy lifecycles close. Root coverage proves stable isolated account derivation, monotonically indexed recovery, and owner-only seed storage; manifest and profile coverage rejects or omits per-account secrets. Namespace coverage proves the local private seed is mode `0600`, never returned by initialization, and produces a claim that verifies only for its exact username, machine credential, and expiry; it also keeps the generated Functions trust anchor aligned with the shared public key. Local-owner coverage proves a second healthy process is never replaced and a dead same-host PID lock can be reclaimed without signaling it. The bounded event checkpoint persists processed IDs and baseline policy coverage proves historical messages are recorded without bot behavior. Action-journal coverage proves completed effects survive restart, replay-safe chat actions can reuse their deterministic CID, interrupted money actions stop for reconciliation, and a replayed faucet request is paid and mirrored once. The canonical Veyl-managed runtime now consumes the packaged fleet example through ordinary SDK clients; remaining live fleet observations belong only in the root manual queue.
32
32
 
33
33
  Run `bun check:sdk` from the repository root to validate the exact public package artifact without mutating the intentionally versionless source manifest. The check builds the SDK, stamps the root product version into a temporary copy, dry-run packs it, verifies the required public runtime entries, documentation, fleet example, and single-account connector, and rejects private source or tests.
34
34