@securecoms/agent-bridge 0.11.2 → 0.11.3

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/bin.js CHANGED
@@ -2122,8 +2122,36 @@ var MlsGroupKeyProvider = class _MlsGroupKeyProvider {
2122
2122
  * even then a supersede Welcome self-heals next cycle (held == published again).
2123
2123
  *
2124
2124
  * Best-effort: any error resolving either side returns false, so the caller
2125
- * force-republishes (the conservative recovery). */
2125
+ * force-republishes (the conservative recovery).
2126
+ *
2127
+ * ⛔⛔ THE READINESS BARRIER SITS OUTSIDE THE `try`, AND MOVING IT INSIDE
2128
+ * RE-OPENS A SILENT FLEET-WIDE KEYPACKAGE ROTATION. The bare catch below is
2129
+ * deliberate for the two things it was written for (a store read that fails,
2130
+ * a backend fetch that fails), and for those `false` is the conservative
2131
+ * answer. A readiness-barrier rejection is NOT one of those things. It means
2132
+ * libsodium's WASM heap is broken, so this process cannot answer the question
2133
+ * at all — and `false` is not "I don't know", it is an INSTRUCTION:
2134
+ * `connect-agent-bridge/src/bridge-agent.ts:868` routes `false` straight to
2135
+ * `forceRepublishKeyPackage()`, which DELETES the held bundle at `:1069` below
2136
+ * and mints a replacement KeyPackage, orphaning every in-flight Welcome sealed
2137
+ * to the prior one.
2138
+ *
2139
+ * ⛔ AND THE ROTATION COMPLETES RATHER THAN TEARING, WHICH IS WHY IT IS THE
2140
+ * WORSE OUTCOME. `bytesToHex` is `sodium.to_hex` and touches no WASM heap,
2141
+ * `generateKeyPackage` runs on noble, and the envelope seal runs on
2142
+ * `@noble/ciphers` (`connect-core/src/envelope/aead.ts:41-43`). The daemon ends
2143
+ * CONSISTENT and silently stranded, not crashed.
2144
+ *
2145
+ * ⛔ THIS IS THE ROUTE THAT FALSIFIES "a barrier rejection is always a loud
2146
+ * boot failure". `heldBundleMatchesPublishedKp` also runs on the periodic
2147
+ * self-heal sweep, so it is not a boot-only path. Hoisting the await is what
2148
+ * makes the rejection propagate to the caller instead of being read as a
2149
+ * verdict. Pinned by
2150
+ * `packages/connect-mls-store/src/barrier-rejection-rotation.gate.test.ts`
2151
+ * (G-H1), whose control case proves the resolving path still answers both
2152
+ * `true` and `false`. */
2126
2153
  async heldBundleMatchesPublishedKp() {
2154
+ await ensureSodiumReady();
2127
2155
  try {
2128
2156
  const bundle = await this.o.store.loadPendingBundle(this.o.deviceId);
2129
2157
  if (!bundle)
@@ -4602,9 +4630,9 @@ var SqliteMlsStateStore = class {
4602
4630
  * ⛔ THE WRITE PATH GETS NO READINESS BARRIER, AND THAT IS DELIBERATE. Two
4603
4631
  * independent reasons, and the FIRST is the primary one.
4604
4632
  *
4605
- * 1. `:171` below populates `this.bundles` BEFORE the seal on the next line.
4633
+ * 1. `:191` below populates `this.bundles` BEFORE the seal at `:192`.
4606
4634
  * A same-process reload therefore hits the cache at `loadPendingBundle`'s
4607
- * `:182-183` and NEVER decodes. The decode path is only ever taken for a
4635
+ * `:202-203` and NEVER decodes. The decode path is only ever taken for a
4608
4636
  * bundle written by a PREVIOUS process, which by definition is not this
4609
4637
  * one. A barrier here could not protect the read that actually fails.
4610
4638
  * 2. `encodeBundle`'s `bytesToHex` is cold-safe BECAUSE `to_hex` needs no
package/dist/index.js CHANGED
@@ -2019,8 +2019,36 @@ var MlsGroupKeyProvider = class _MlsGroupKeyProvider {
2019
2019
  * even then a supersede Welcome self-heals next cycle (held == published again).
2020
2020
  *
2021
2021
  * Best-effort: any error resolving either side returns false, so the caller
2022
- * force-republishes (the conservative recovery). */
2022
+ * force-republishes (the conservative recovery).
2023
+ *
2024
+ * ⛔⛔ THE READINESS BARRIER SITS OUTSIDE THE `try`, AND MOVING IT INSIDE
2025
+ * RE-OPENS A SILENT FLEET-WIDE KEYPACKAGE ROTATION. The bare catch below is
2026
+ * deliberate for the two things it was written for (a store read that fails,
2027
+ * a backend fetch that fails), and for those `false` is the conservative
2028
+ * answer. A readiness-barrier rejection is NOT one of those things. It means
2029
+ * libsodium's WASM heap is broken, so this process cannot answer the question
2030
+ * at all — and `false` is not "I don't know", it is an INSTRUCTION:
2031
+ * `connect-agent-bridge/src/bridge-agent.ts:868` routes `false` straight to
2032
+ * `forceRepublishKeyPackage()`, which DELETES the held bundle at `:1069` below
2033
+ * and mints a replacement KeyPackage, orphaning every in-flight Welcome sealed
2034
+ * to the prior one.
2035
+ *
2036
+ * ⛔ AND THE ROTATION COMPLETES RATHER THAN TEARING, WHICH IS WHY IT IS THE
2037
+ * WORSE OUTCOME. `bytesToHex` is `sodium.to_hex` and touches no WASM heap,
2038
+ * `generateKeyPackage` runs on noble, and the envelope seal runs on
2039
+ * `@noble/ciphers` (`connect-core/src/envelope/aead.ts:41-43`). The daemon ends
2040
+ * CONSISTENT and silently stranded, not crashed.
2041
+ *
2042
+ * ⛔ THIS IS THE ROUTE THAT FALSIFIES "a barrier rejection is always a loud
2043
+ * boot failure". `heldBundleMatchesPublishedKp` also runs on the periodic
2044
+ * self-heal sweep, so it is not a boot-only path. Hoisting the await is what
2045
+ * makes the rejection propagate to the caller instead of being read as a
2046
+ * verdict. Pinned by
2047
+ * `packages/connect-mls-store/src/barrier-rejection-rotation.gate.test.ts`
2048
+ * (G-H1), whose control case proves the resolving path still answers both
2049
+ * `true` and `false`. */
2023
2050
  async heldBundleMatchesPublishedKp() {
2051
+ await ensureSodiumReady();
2024
2052
  try {
2025
2053
  const bundle = await this.o.store.loadPendingBundle(this.o.deviceId);
2026
2054
  if (!bundle)
@@ -4499,9 +4527,9 @@ var SqliteMlsStateStore = class {
4499
4527
  * ⛔ THE WRITE PATH GETS NO READINESS BARRIER, AND THAT IS DELIBERATE. Two
4500
4528
  * independent reasons, and the FIRST is the primary one.
4501
4529
  *
4502
- * 1. `:171` below populates `this.bundles` BEFORE the seal on the next line.
4530
+ * 1. `:191` below populates `this.bundles` BEFORE the seal at `:192`.
4503
4531
  * A same-process reload therefore hits the cache at `loadPendingBundle`'s
4504
- * `:182-183` and NEVER decodes. The decode path is only ever taken for a
4532
+ * `:202-203` and NEVER decodes. The decode path is only ever taken for a
4505
4533
  * bundle written by a PREVIOUS process, which by definition is not this
4506
4534
  * one. A barrier here could not protect the read that actually fails.
4507
4535
  * 2. `encodeBundle`'s `bytesToHex` is cold-safe BECAUSE `to_hex` needs no
@@ -21,10 +21,12 @@
21
21
  * ⛔ 1. THE DISCARDED KEYPAIR IS THE READINESS GATE, NOT DEAD CODE. ⇒ ITS
22
22
  * SUBJECT MOVED. The `generateEphemeralKeypair()` await now sits in the SDK
23
23
  * module named above, and the finding travels with it. It still says what it
24
- * always said: `@agentvault/crypto` has no readiness contract on its entire
25
- * synchronous surface, sixteen exported synchronous functions throw when
26
- * libsodium's WASM heap is not yet initialised (`<member> is not a function`
27
- * or `Cannot read properties of undefined (reading '_malloc')`), and
24
+ * always said: `@agentvault/crypto` has no readiness contract on its
25
+ * synchronous surface. ⛔ THE COUNT IS A WITNESSED SET, NOT A BARE NUMBER, and
26
+ * the earlier "sixteen" was not one — see the SDK module for the cold/warm
27
+ * differential that produced it and for the named nine. Cold-throwers fail with
28
+ * `<member> is not a function` or
29
+ * `Cannot read properties of undefined (reading '_malloc')`, and
28
30
  * `generateEphemeralKeypair` is the ASYNC export that awaits `sodium.ready`
29
31
  * internally on the SAME module instance those synchronous exports use. ⛔ Do
30
32
  * not "simplify" the delegate by inlining a keypair mint back here: that is a
@@ -45,9 +47,12 @@
45
47
  * warmed = true;` two CONCURRENT callers both run the body. The bridge has two
46
48
  * independent entry points (send and receive), so that concurrency is real
47
49
  * here, which is why the finding was written here first. It is pinned now by
48
- * `packages/connect-sdk-ts/src/sodium-ready.memo.gate.test.ts` (G-C1) and by
49
- * `src/sodium-ready.retry.test.ts:52-69` in this package, which reaches the SDK
50
- * memo THROUGH this delegate.
50
+ * the G-C1 case in `packages/connect-sdk-ts/src/sodium-ready.memo.gate.test.ts`,
51
+ * which is the CONCURRENT form of the property, and by
52
+ * `src/sodium-ready.retry.test.ts:52-69` in this package, which is the SEQUENTIAL
53
+ * form and reaches the SDK memo THROUGH this delegate.
54
+ * ⛔ G-C1 GATES THIS FINDING ONLY. It cannot fail on finding 4's memo-clearing
55
+ * `catch`, because its mock always resolves. Finding 4 names its own pins.
51
56
  *
52
57
  * ⛔⛔ 4. THE `catch` THAT CLEARS THE MEMO IS NOT REDUNDANT. DO NOT DELETE IT.
53
58
  * ⇒ ITS SUBJECT MOVED, AND THE CONSEQUENCE STILL LANDS IN THIS PACKAGE. A bare
@@ -60,6 +65,9 @@
60
65
  * and logs, so one transient failure becomes a PERMANENT, PROCESS-WIDE
61
66
  * attachment outage that never surfaces as a crash. The SDK module clears the
62
67
  * memo on rejection and RETHROWS, so the first caller still sees the real
63
- * failure. Pinned by `src/sodium-ready.retry.test.ts`, both halves.
68
+ * failure. Pinned by `src/sodium-ready.retry.test.ts` in this package, both
69
+ * halves, and by the G-C1b case in
70
+ * `packages/connect-sdk-ts/src/sodium-ready.memo.gate.test.ts`. ⛔ NOT by G-C1,
71
+ * which cannot fail on that `catch` — see finding 3 above.
64
72
  */
65
73
  export declare function ensureSodiumReady(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@securecoms/agent-bridge",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  },
24
24
  "scripts": {
25
25
  "prepack": "npm run build",
26
+ "prepublishOnly": "bash scripts/pack-smoke.sh",
26
27
  "build": "tsc && node esbuild.config.mjs",
27
28
  "test": "vitest run",
28
29
  "test:watch": "vitest"