@yefengr/pi-reach 0.0.0-stage → 0.0.2
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/LICENSE +22 -0
- package/README.md +110 -2
- package/dist/actions/handlers.d.ts +143 -0
- package/dist/actions/handlers.js +200 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +39 -0
- package/dist/actions/registry.js +58 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/actions/session_new_bridge.d.ts +35 -0
- package/dist/actions/session_new_bridge.js +88 -0
- package/dist/actions/session_new_bridge.js.map +1 -0
- package/dist/commands.d.ts +29 -0
- package/dist/commands.js +169 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +61 -0
- package/dist/config.js +115 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +618 -0
- package/dist/index.js.map +1 -0
- package/dist/pairing/crypto.d.ts +15 -0
- package/dist/pairing/crypto.js +72 -0
- package/dist/pairing/crypto.js.map +1 -0
- package/dist/pairing/identity-keyring.d.ts +22 -0
- package/dist/pairing/identity-keyring.js +94 -0
- package/dist/pairing/identity-keyring.js.map +1 -0
- package/dist/pairing/identity-lock.d.ts +14 -0
- package/dist/pairing/identity-lock.js +116 -0
- package/dist/pairing/identity-lock.js.map +1 -0
- package/dist/pairing/owner_storage.d.ts +61 -0
- package/dist/pairing/owner_storage.js +263 -0
- package/dist/pairing/owner_storage.js.map +1 -0
- package/dist/pairing/qr.d.ts +39 -0
- package/dist/pairing/qr.js +113 -0
- package/dist/pairing/qr.js.map +1 -0
- package/dist/pairing/storage.d.ts +36 -0
- package/dist/pairing/storage.js +263 -0
- package/dist/pairing/storage.js.map +1 -0
- package/dist/protocol/types.d.ts +225 -0
- package/dist/protocol/types.js +2 -0
- package/dist/protocol/types.js.map +1 -0
- package/dist/protocol/v2/codec.d.ts +6 -0
- package/dist/protocol/v2/codec.js +4 -0
- package/dist/protocol/v2/codec.js.map +1 -0
- package/dist/protocol/v2/index.d.ts +4 -0
- package/dist/protocol/v2/index.js +5 -0
- package/dist/protocol/v2/index.js.map +1 -0
- package/dist/protocol/v2/marker.d.ts +45 -0
- package/dist/protocol/v2/marker.js +47 -0
- package/dist/protocol/v2/marker.js.map +1 -0
- package/dist/protocol/v2/schemas.d.ts +3 -0
- package/dist/protocol/v2/schemas.js +4 -0
- package/dist/protocol/v2/schemas.js.map +1 -0
- package/dist/protocol/v2/session_state.d.ts +79 -0
- package/dist/protocol/v2/session_state.js +166 -0
- package/dist/protocol/v2/session_state.js.map +1 -0
- package/dist/runtime/endpoint_metadata.d.ts +14 -0
- package/dist/runtime/endpoint_metadata.js +18 -0
- package/dist/runtime/endpoint_metadata.js.map +1 -0
- package/dist/runtime/extension_owner.d.ts +12 -0
- package/dist/runtime/extension_owner.js +80 -0
- package/dist/runtime/extension_owner.js.map +1 -0
- package/dist/runtime/footer.d.ts +6 -0
- package/dist/runtime/footer.js +21 -0
- package/dist/runtime/footer.js.map +1 -0
- package/dist/runtime/owner_router.d.ts +16 -0
- package/dist/runtime/owner_router.js +41 -0
- package/dist/runtime/owner_router.js.map +1 -0
- package/dist/runtime/pairing_coordinator.d.ts +42 -0
- package/dist/runtime/pairing_coordinator.js +136 -0
- package/dist/runtime/pairing_coordinator.js.map +1 -0
- package/dist/runtime/relay_lifecycle.d.ts +64 -0
- package/dist/runtime/relay_lifecycle.js +275 -0
- package/dist/runtime/relay_lifecycle.js.map +1 -0
- package/dist/session/local_config.d.ts +7 -0
- package/dist/session/local_config.js +52 -0
- package/dist/session/local_config.js.map +1 -0
- package/dist/timeline/history.d.ts +30 -0
- package/dist/timeline/history.js +170 -0
- package/dist/timeline/history.js.map +1 -0
- package/dist/timeline/partial_delta.d.ts +2 -0
- package/dist/timeline/partial_delta.js +16 -0
- package/dist/timeline/partial_delta.js.map +1 -0
- package/dist/timeline/run_end.d.ts +16 -0
- package/dist/timeline/run_end.js +23 -0
- package/dist/timeline/run_end.js.map +1 -0
- package/dist/timeline/runtime.d.ts +89 -0
- package/dist/timeline/runtime.js +546 -0
- package/dist/timeline/runtime.js.map +1 -0
- package/dist/timeline/sequence.d.ts +7 -0
- package/dist/timeline/sequence.js +16 -0
- package/dist/timeline/sequence.js.map +1 -0
- package/dist/timeline/tool_lifecycle.d.ts +36 -0
- package/dist/timeline/tool_lifecycle.js +171 -0
- package/dist/timeline/tool_lifecycle.js.map +1 -0
- package/dist/timeline/user_delivery.d.ts +96 -0
- package/dist/timeline/user_delivery.js +360 -0
- package/dist/timeline/user_delivery.js.map +1 -0
- package/dist/timeline/user_delivery_binding.d.ts +43 -0
- package/dist/timeline/user_delivery_binding.js +107 -0
- package/dist/timeline/user_delivery_binding.js.map +1 -0
- package/dist/timeline/v2_service.d.ts +82 -0
- package/dist/timeline/v2_service.js +512 -0
- package/dist/timeline/v2_service.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +34 -0
- package/dist/transport/peer_channel.js +116 -0
- package/dist/transport/peer_channel.js.map +1 -0
- package/dist/transport/relay_client.d.ts +54 -0
- package/dist/transport/relay_client.js +270 -0
- package/dist/transport/relay_client.js.map +1 -0
- package/dist/vendor/protocol/constants.d.ts +4 -0
- package/dist/vendor/protocol/constants.js +4 -0
- package/dist/vendor/protocol/encoding.d.ts +9 -0
- package/dist/vendor/protocol/encoding.js +66 -0
- package/dist/vendor/protocol/outer/codec.d.ts +13 -0
- package/dist/vendor/protocol/outer/codec.js +105 -0
- package/dist/vendor/protocol/outer/index.d.ts +4 -0
- package/dist/vendor/protocol/outer/index.js +4 -0
- package/dist/vendor/protocol/outer/types.d.ts +120 -0
- package/dist/vendor/protocol/outer/types.js +1 -0
- package/dist/vendor/protocol/session/codec.d.ts +41 -0
- package/dist/vendor/protocol/session/codec.js +236 -0
- package/dist/vendor/protocol/session/frames.d.ts +5220 -0
- package/dist/vendor/protocol/session/frames.js +83 -0
- package/dist/vendor/protocol/session/index.d.ts +3 -0
- package/dist/vendor/protocol/session/index.js +3 -0
- package/dist/vendor/protocol/session/schema.d.ts +858 -0
- package/dist/vendor/protocol/session/schema.js +256 -0
- package/package.json +74 -3
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Ed25519Keypair {
|
|
2
|
+
publicKey: Uint8Array;
|
|
3
|
+
secretKey: Uint8Array;
|
|
4
|
+
}
|
|
5
|
+
export declare class Ed25519PublicKeyError extends Error {
|
|
6
|
+
constructor(field: string, message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare function generateEd25519Keypair(): Ed25519Keypair;
|
|
9
|
+
export declare function ed25519Sign(sk: Uint8Array, msg: Uint8Array): Uint8Array;
|
|
10
|
+
export declare function ed25519Verify(pk: Uint8Array, msg: Uint8Array, sig: Uint8Array): boolean;
|
|
11
|
+
/** Decodes standard or URL-safe canonical 32-byte Ed25519 public-key base64. */
|
|
12
|
+
export declare function decodeEd25519PublicKey(raw: string, field?: string): Uint8Array;
|
|
13
|
+
export declare function encodeEd25519PublicKey(bytes: Uint8Array, field?: string): string;
|
|
14
|
+
export declare function canonicalizeEd25519PublicKey(raw: string, field?: string): string;
|
|
15
|
+
export declare function publicKeyFingerprint(bytes: Uint8Array): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import * as ed from "@noble/ed25519";
|
|
3
|
+
ed.hashes["sha512"] = (...msgs) => {
|
|
4
|
+
const h = createHash("sha512");
|
|
5
|
+
for (const msg of msgs)
|
|
6
|
+
h.update(msg);
|
|
7
|
+
return Uint8Array.from(h.digest());
|
|
8
|
+
};
|
|
9
|
+
const ED25519_PUBLIC_KEY_BYTES = 32;
|
|
10
|
+
export class Ed25519PublicKeyError extends Error {
|
|
11
|
+
constructor(field, message) {
|
|
12
|
+
super(`${field}: ${message}`);
|
|
13
|
+
this.name = "Ed25519PublicKeyError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function generateEd25519Keypair() {
|
|
17
|
+
const secretKey = randomBytes(32);
|
|
18
|
+
return { secretKey, publicKey: Buffer.from(ed.getPublicKey(secretKey)) };
|
|
19
|
+
}
|
|
20
|
+
export function ed25519Sign(sk, msg) {
|
|
21
|
+
return Buffer.from(ed.sign(msg, sk));
|
|
22
|
+
}
|
|
23
|
+
export function ed25519Verify(pk, msg, sig) {
|
|
24
|
+
return ed.verify(sig, msg, pk);
|
|
25
|
+
}
|
|
26
|
+
/** Decodes standard or URL-safe canonical 32-byte Ed25519 public-key base64. */
|
|
27
|
+
export function decodeEd25519PublicKey(raw, field = "public key") {
|
|
28
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
29
|
+
throw new Ed25519PublicKeyError(field, "invalid base64 encoding");
|
|
30
|
+
}
|
|
31
|
+
const standard = /[+/]/.test(raw);
|
|
32
|
+
const urlSafe = /[-_]/.test(raw);
|
|
33
|
+
if (standard && urlSafe)
|
|
34
|
+
throw new Ed25519PublicKeyError(field, "mixed base64 alphabets");
|
|
35
|
+
const firstPadding = raw.indexOf("=");
|
|
36
|
+
const body = firstPadding === -1 ? raw : raw.slice(0, firstPadding);
|
|
37
|
+
const padding = firstPadding === -1 ? "" : raw.slice(firstPadding);
|
|
38
|
+
const bodyPattern = urlSafe ? /^[A-Za-z0-9_-]+$/ : /^[A-Za-z0-9+/]+$/;
|
|
39
|
+
if (!bodyPattern.test(body) || (padding !== "" && !/^={1,2}$/.test(padding))) {
|
|
40
|
+
throw new Ed25519PublicKeyError(field, "invalid base64 encoding");
|
|
41
|
+
}
|
|
42
|
+
const requiredPadding = (4 - (body.length % 4)) % 4;
|
|
43
|
+
if (requiredPadding === 3 || (padding.length > 0 && padding.length !== requiredPadding)) {
|
|
44
|
+
throw new Ed25519PublicKeyError(field, "invalid base64 padding");
|
|
45
|
+
}
|
|
46
|
+
const normalized = body.replaceAll("-", "+").replaceAll("_", "/");
|
|
47
|
+
const bytes = new Uint8Array(Buffer.from(normalized + "=".repeat(requiredPadding), "base64"));
|
|
48
|
+
if (bytes.length !== ED25519_PUBLIC_KEY_BYTES) {
|
|
49
|
+
throw new Ed25519PublicKeyError(field, `wrong length (${bytes.length}, expected ${ED25519_PUBLIC_KEY_BYTES})`);
|
|
50
|
+
}
|
|
51
|
+
const canonicalPadded = Buffer.from(bytes).toString("base64");
|
|
52
|
+
const canonicalUnpadded = canonicalPadded.replace(/=+$/, "");
|
|
53
|
+
const normalizedInput = normalized + padding;
|
|
54
|
+
if (normalizedInput !== canonicalPadded && normalizedInput !== canonicalUnpadded) {
|
|
55
|
+
throw new Ed25519PublicKeyError(field, "non-canonical base64 trailing bits");
|
|
56
|
+
}
|
|
57
|
+
return bytes;
|
|
58
|
+
}
|
|
59
|
+
export function encodeEd25519PublicKey(bytes, field = "public key") {
|
|
60
|
+
if (!(bytes instanceof Uint8Array) || bytes.length !== ED25519_PUBLIC_KEY_BYTES) {
|
|
61
|
+
const length = bytes instanceof Uint8Array ? bytes.length : 0;
|
|
62
|
+
throw new Ed25519PublicKeyError(field, `wrong length (${length}, expected ${ED25519_PUBLIC_KEY_BYTES})`);
|
|
63
|
+
}
|
|
64
|
+
return Buffer.from(bytes).toString("base64");
|
|
65
|
+
}
|
|
66
|
+
export function canonicalizeEd25519PublicKey(raw, field = "public key") {
|
|
67
|
+
return encodeEd25519PublicKey(decodeEd25519PublicKey(raw, field), field);
|
|
68
|
+
}
|
|
69
|
+
export function publicKeyFingerprint(bytes) {
|
|
70
|
+
return createHash("sha256").update(bytes).digest("hex").slice(0, 8);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/pairing/crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IDENTITY_LOCK_RELEASE_AFTER, type IdentityLockDeferredRelease } from "./identity-lock.js";
|
|
2
|
+
export interface KeyStoreBackend {
|
|
3
|
+
read(service: string, account: string): Promise<string | undefined>;
|
|
4
|
+
write(service: string, account: string, value: string): Promise<void>;
|
|
5
|
+
delete(service: string, account: string): Promise<boolean>;
|
|
6
|
+
}
|
|
7
|
+
export declare class KeyringReadTimeoutError extends Error {
|
|
8
|
+
constructor(op: string, timeoutMs: number);
|
|
9
|
+
}
|
|
10
|
+
export declare class KeyringMutationTimeoutError extends Error implements IdentityLockDeferredRelease {
|
|
11
|
+
readonly [IDENTITY_LOCK_RELEASE_AFTER]: Promise<void>;
|
|
12
|
+
constructor(op: string, timeoutMs: number, settled: Promise<void>);
|
|
13
|
+
}
|
|
14
|
+
export declare function _setKeyringOperationTimeoutForTest(timeoutMs: number | null): void;
|
|
15
|
+
export declare function _runKeyringOperationWithTimeoutForTest<T>(operation: Promise<T>, op: string, mutating: boolean, timeoutMs: number): Promise<T>;
|
|
16
|
+
export declare function nativeBindingUnavailable(): boolean;
|
|
17
|
+
export declare function _setNativeBindingErrorForTest(error: unknown): void;
|
|
18
|
+
export declare class NapiKeyringBackend implements KeyStoreBackend {
|
|
19
|
+
read(service: string, account: string): Promise<string | undefined>;
|
|
20
|
+
write(service: string, account: string, value: string): Promise<void>;
|
|
21
|
+
delete(service: string, account: string): Promise<boolean>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { IDENTITY_LOCK_RELEASE_AFTER, } from "./identity-lock.js";
|
|
2
|
+
export class KeyringReadTimeoutError extends Error {
|
|
3
|
+
constructor(op, timeoutMs) {
|
|
4
|
+
super(`keyring ${op} timed out after ${timeoutMs}ms`);
|
|
5
|
+
this.name = "KeyringReadTimeoutError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class KeyringMutationTimeoutError extends Error {
|
|
9
|
+
[IDENTITY_LOCK_RELEASE_AFTER];
|
|
10
|
+
constructor(op, timeoutMs, settled) {
|
|
11
|
+
super(`keyring ${op} timed out after ${timeoutMs}ms; the underlying operation is still pending`);
|
|
12
|
+
this.name = "KeyringMutationTimeoutError";
|
|
13
|
+
this[IDENTITY_LOCK_RELEASE_AFTER] = settled.then(() => undefined, () => undefined);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
let keyringOperationTimeoutMs = 3_000;
|
|
17
|
+
export function _setKeyringOperationTimeoutForTest(timeoutMs) {
|
|
18
|
+
keyringOperationTimeoutMs = timeoutMs ?? 3_000;
|
|
19
|
+
}
|
|
20
|
+
export function _runKeyringOperationWithTimeoutForTest(operation, op, mutating, timeoutMs) {
|
|
21
|
+
return withKeyringTimeout(operation, op, mutating, timeoutMs);
|
|
22
|
+
}
|
|
23
|
+
function withKeyringTimeout(operation, op, mutating, timeoutMs = keyringOperationTimeoutMs) {
|
|
24
|
+
const settled = operation.then(() => undefined, () => undefined);
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const timer = setTimeout(() => {
|
|
27
|
+
reject(mutating
|
|
28
|
+
? new KeyringMutationTimeoutError(op, timeoutMs, settled)
|
|
29
|
+
: new KeyringReadTimeoutError(op, timeoutMs));
|
|
30
|
+
}, timeoutMs);
|
|
31
|
+
operation.then((value) => {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
resolve(value);
|
|
34
|
+
}, (error) => {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
reject(error);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
let asyncEntryCtor = null;
|
|
41
|
+
let nativeBindingError = null;
|
|
42
|
+
async function loadAsyncEntry() {
|
|
43
|
+
if (asyncEntryCtor)
|
|
44
|
+
return asyncEntryCtor;
|
|
45
|
+
if (nativeBindingError)
|
|
46
|
+
throw nativeBindingError;
|
|
47
|
+
try {
|
|
48
|
+
const mod = await import("@napi-rs/keyring");
|
|
49
|
+
asyncEntryCtor = mod.AsyncEntry;
|
|
50
|
+
return asyncEntryCtor;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
nativeBindingError = error;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function nativeBindingUnavailable() {
|
|
58
|
+
return nativeBindingError !== null;
|
|
59
|
+
}
|
|
60
|
+
export function _setNativeBindingErrorForTest(error) {
|
|
61
|
+
asyncEntryCtor = null;
|
|
62
|
+
nativeBindingError = error;
|
|
63
|
+
}
|
|
64
|
+
export class NapiKeyringBackend {
|
|
65
|
+
async read(service, account) {
|
|
66
|
+
const AsyncEntry = await loadAsyncEntry();
|
|
67
|
+
const entry = new AsyncEntry(service, account);
|
|
68
|
+
return withKeyringTimeout(entry.getPassword(), `read(${service})`, false);
|
|
69
|
+
}
|
|
70
|
+
async write(service, account, value) {
|
|
71
|
+
const AsyncEntry = await loadAsyncEntry();
|
|
72
|
+
const entry = new AsyncEntry(service, account);
|
|
73
|
+
await withKeyringTimeout(entry.setPassword(value), `write(${service})`, true);
|
|
74
|
+
}
|
|
75
|
+
async delete(service, account) {
|
|
76
|
+
let entry;
|
|
77
|
+
try {
|
|
78
|
+
const AsyncEntry = await loadAsyncEntry();
|
|
79
|
+
entry = new AsyncEntry(service, account);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
return await withKeyringTimeout(entry.deleteCredential(), `delete(${service})`, true);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error instanceof KeyringMutationTimeoutError)
|
|
89
|
+
throw error;
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=identity-keyring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-keyring.js","sourceRoot":"","sources":["../../src/pairing/identity-keyring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const IDENTITY_LOCK_RELEASE_AFTER: unique symbol;
|
|
2
|
+
export interface IdentityLockDeferredRelease {
|
|
3
|
+
readonly [IDENTITY_LOCK_RELEASE_AFTER]: Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
export interface IdentityLockOptions {
|
|
6
|
+
readonly waitTimeoutMs?: number;
|
|
7
|
+
readonly pollIntervalMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class IdentityLockTimeoutError extends Error {
|
|
10
|
+
readonly lockPath: string;
|
|
11
|
+
constructor(lockPath: string, waitTimeoutMs: number);
|
|
12
|
+
}
|
|
13
|
+
export declare function ensurePrivateIdentityDirectory(directory: string): Promise<void>;
|
|
14
|
+
export declare function withIdentityLock<T>(directory: string, operation: () => Promise<T>, options?: IdentityLockOptions): Promise<T>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { chmod, mkdir, open, readFile, unlink } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export const IDENTITY_LOCK_RELEASE_AFTER = Symbol("identity-lock-release-after");
|
|
5
|
+
export class IdentityLockTimeoutError extends Error {
|
|
6
|
+
lockPath;
|
|
7
|
+
constructor(lockPath, waitTimeoutMs) {
|
|
8
|
+
super(`Identity initialization lock remained held for ${waitTimeoutMs}ms at ${lockPath}. ` +
|
|
9
|
+
"Another process may still be initializing the identity, or a previous process may " +
|
|
10
|
+
"have exited unexpectedly. The lock is never removed automatically. Confirm that no " +
|
|
11
|
+
"identity initialization or keyring operation is still running before removing it manually.");
|
|
12
|
+
this.name = "IdentityLockTimeoutError";
|
|
13
|
+
this.lockPath = lockPath;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function isNodeErrorWithCode(error, code) {
|
|
17
|
+
return typeof error === "object" && error !== null && "code" in error &&
|
|
18
|
+
error.code === code;
|
|
19
|
+
}
|
|
20
|
+
function sleep(ms) {
|
|
21
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
|
+
}
|
|
23
|
+
export async function ensurePrivateIdentityDirectory(directory) {
|
|
24
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
25
|
+
await chmod(directory, 0o700);
|
|
26
|
+
}
|
|
27
|
+
async function tryAcquire(lockPath) {
|
|
28
|
+
let handle;
|
|
29
|
+
try {
|
|
30
|
+
handle = await open(lockPath, "wx", 0o600);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (isNodeErrorWithCode(error, "EEXIST"))
|
|
34
|
+
return null;
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
const token = randomUUID();
|
|
38
|
+
try {
|
|
39
|
+
await handle.writeFile(JSON.stringify({ pid: process.pid, token, createdAt: new Date().toISOString() }));
|
|
40
|
+
await handle.sync();
|
|
41
|
+
return { handle, path: lockPath, token };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
await handle.close().catch(() => undefined);
|
|
45
|
+
await unlink(lockPath).catch(() => undefined);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function acquireIdentityLock(directory, options) {
|
|
50
|
+
await ensurePrivateIdentityDirectory(directory);
|
|
51
|
+
const lockPath = join(directory, "identity.lock");
|
|
52
|
+
const waitTimeoutMs = options.waitTimeoutMs ?? 15_000;
|
|
53
|
+
const pollIntervalMs = Math.max(1, options.pollIntervalMs ?? 50);
|
|
54
|
+
const deadline = Date.now() + Math.max(0, waitTimeoutMs);
|
|
55
|
+
while (true) {
|
|
56
|
+
const held = await tryAcquire(lockPath);
|
|
57
|
+
if (held)
|
|
58
|
+
return held;
|
|
59
|
+
const remainingMs = deadline - Date.now();
|
|
60
|
+
if (remainingMs <= 0)
|
|
61
|
+
throw new IdentityLockTimeoutError(lockPath, waitTimeoutMs);
|
|
62
|
+
await sleep(Math.min(pollIntervalMs, remainingMs));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function releaseIdentityLock(lock) {
|
|
66
|
+
try {
|
|
67
|
+
let raw;
|
|
68
|
+
try {
|
|
69
|
+
raw = await readFile(lock.path, "utf8");
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (isNodeErrorWithCode(error, "ENOENT"))
|
|
73
|
+
return;
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
let token;
|
|
77
|
+
try {
|
|
78
|
+
token = JSON.parse(raw).token;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (token !== lock.token)
|
|
84
|
+
return;
|
|
85
|
+
await unlink(lock.path);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await lock.handle.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function deferredRelease(error) {
|
|
92
|
+
if (typeof error !== "object" || error === null)
|
|
93
|
+
return null;
|
|
94
|
+
const settled = error[IDENTITY_LOCK_RELEASE_AFTER];
|
|
95
|
+
return settled instanceof Promise ? settled : null;
|
|
96
|
+
}
|
|
97
|
+
export async function withIdentityLock(directory, operation, options = {}) {
|
|
98
|
+
const lock = await acquireIdentityLock(directory, options);
|
|
99
|
+
let releaseWasDeferred = false;
|
|
100
|
+
try {
|
|
101
|
+
return await operation();
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const settled = deferredRelease(error);
|
|
105
|
+
if (settled) {
|
|
106
|
+
releaseWasDeferred = true;
|
|
107
|
+
void settled.then(() => releaseIdentityLock(lock), () => releaseIdentityLock(lock)).catch(() => undefined);
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
if (!releaseWasDeferred)
|
|
113
|
+
await releaseIdentityLock(lock);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=identity-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-lock.js","sourceRoot":"","sources":["../../src/pairing/identity-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAmB,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;AAWjF,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,QAAQ,CAAS;IAE1B,YAAY,QAAgB,EAAE,aAAqB;QACjD,KAAK,CACH,kDAAkD,aAAa,SAAS,QAAQ,IAAI;YACpF,oFAAoF;YACpF,qFAAqF;YACrF,4FAA4F,CAC7F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAQD,SAAS,mBAAmB,CAAC,KAAc,EAAE,IAAY;IACvD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK;QAClE,KAA4B,CAAC,IAAI,KAAK,IAAI,CAAC;AAChD,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,SAAiB;IACpE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,MAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACtD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;QACzG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,SAAiB,EACjB,OAA4B;IAE5B,MAAM,8BAA8B,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,MAAM,CAAC;IACtD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAEzD,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QAEtB,MAAM,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1C,IAAI,WAAW,IAAI,CAAC;YAAE,MAAM,IAAI,wBAAwB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAClF,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,IAAsB;IACvD,IAAI,CAAC;QACH,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAAE,OAAO;YACjD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,KAAc,CAAC;QACnB,IAAI,CAAC;YACH,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC,KAAK,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO;QACjC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,OAAO,GAAI,KAA8C,CAAC,2BAA2B,CAAC,CAAC;IAC7F,OAAO,OAAO,YAAY,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,SAA2B,EAC3B,UAA+B,EAAE;IAEjC,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC3D,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAC/B,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,OAAO,EAAE,CAAC;YACZ,kBAAkB,GAAG,IAAI,CAAC;YAC1B,KAAK,OAAO,CAAC,IAAI,CACf,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAC/B,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAChC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,kBAAkB;YAAE,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface PeerRecord {
|
|
2
|
+
name: string;
|
|
3
|
+
remote_epk: string;
|
|
4
|
+
paired_at: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function listPeers(): Promise<PeerRecord[]>;
|
|
7
|
+
declare const _ownerStorageTokenBrand: unique symbol;
|
|
8
|
+
/** Opaque, process-local provenance for one canonical Owner storage slot. */
|
|
9
|
+
export type OwnerStorageToken = {
|
|
10
|
+
readonly [_ownerStorageTokenBrand]: true;
|
|
11
|
+
};
|
|
12
|
+
export interface OwnerStorageSnapshotRecord {
|
|
13
|
+
readonly rawOwnerPubkey: unknown;
|
|
14
|
+
readonly token: OwnerStorageToken;
|
|
15
|
+
}
|
|
16
|
+
export type ConditionalPeerRemoval = {
|
|
17
|
+
readonly outcome: "removed";
|
|
18
|
+
readonly nextToken: OwnerStorageToken;
|
|
19
|
+
} | {
|
|
20
|
+
readonly outcome: "stale" | "not_found" | "no_authority";
|
|
21
|
+
};
|
|
22
|
+
/** Provenance and pre-write state for one successful addPeer mutation. */
|
|
23
|
+
export interface PeerWriteReceipt {
|
|
24
|
+
readonly record: PeerRecord;
|
|
25
|
+
readonly token: OwnerStorageToken;
|
|
26
|
+
/** The raw record replaced by this write, when addPeer overwrote one. */
|
|
27
|
+
readonly previousRecord?: unknown;
|
|
28
|
+
}
|
|
29
|
+
export type ConditionalPeerRollback = {
|
|
30
|
+
readonly outcome: "removed" | "restored";
|
|
31
|
+
readonly nextToken: OwnerStorageToken;
|
|
32
|
+
} | {
|
|
33
|
+
readonly outcome: "stale" | "not_found" | "no_authority";
|
|
34
|
+
};
|
|
35
|
+
export declare function addPeer(record: PeerRecord): Promise<PeerWriteReceipt>;
|
|
36
|
+
/**
|
|
37
|
+
* Returns the set of distinct `remote_epk` values in peers.json.
|
|
38
|
+
*
|
|
39
|
+
* Each `remote_epk` is the paired Owner's Ed25519 public key and represents a
|
|
40
|
+
* machine-scoped authorization entry.
|
|
41
|
+
*/
|
|
42
|
+
export declare function listOwnerPubkeys(): Promise<unknown[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Atomically snapshots raw Owner handles and their canonical-slot provenance.
|
|
45
|
+
* The token is process-local and opaque to callers.
|
|
46
|
+
*/
|
|
47
|
+
export declare function snapshotOwnerPubkeys(): Promise<readonly OwnerStorageSnapshotRecord[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Removes one exact raw handle only when its snapshot provenance still owns
|
|
50
|
+
* the target canonical Owner slot. The final authority/token checks and sync
|
|
51
|
+
* write share the existing serialized mutation lane.
|
|
52
|
+
*/
|
|
53
|
+
export declare function conditionalRemovePeer(remoteEpk: string, expectedToken: OwnerStorageToken, canCommit?: () => boolean): Promise<ConditionalPeerRemoval>;
|
|
54
|
+
/**
|
|
55
|
+
* Compensates a specific addPeer write only while that write still owns its
|
|
56
|
+
* canonical Owner slot. The receipt's raw written record must still be
|
|
57
|
+
* present, so an out-of-band replacement cannot be removed or overwritten.
|
|
58
|
+
*/
|
|
59
|
+
export declare function conditionalRollbackPeer(receipt: PeerWriteReceipt, canCommit?: () => boolean): Promise<ConditionalPeerRollback>;
|
|
60
|
+
export declare function removePeer(remoteEpk: string, canCommit?: () => boolean): Promise<boolean>;
|
|
61
|
+
export {};
|