@dharma-ai-labs/agent-fabric 0.2.178 → 0.2.179

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.
Files changed (34) hide show
  1. package/dist/connectionSessionScope.d.ts +3 -0
  2. package/dist/connectionSessionScope.d.ts.map +1 -0
  3. package/dist/connectionSessionScope.js +10 -0
  4. package/dist/connectionSessionScope.js.map +1 -0
  5. package/dist/deviceConnection.d.ts +35 -0
  6. package/dist/deviceConnection.d.ts.map +1 -0
  7. package/dist/deviceConnection.js +164 -0
  8. package/dist/deviceConnection.js.map +1 -0
  9. package/dist/deviceConnection.test.d.ts +2 -0
  10. package/dist/deviceConnection.test.d.ts.map +1 -0
  11. package/dist/deviceConnection.test.js +265 -0
  12. package/dist/deviceConnection.test.js.map +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +245 -99
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.test.js +3 -3
  17. package/dist/index.test.js.map +1 -1
  18. package/dist/relaySupervisor.test.js +6 -1
  19. package/dist/relaySupervisor.test.js.map +1 -1
  20. package/dist/repositoryOnboardingCaller.test.js +3 -1
  21. package/dist/repositoryOnboardingCaller.test.js.map +1 -1
  22. package/dist/resumeLoginCaller.test.d.ts +2 -0
  23. package/dist/resumeLoginCaller.test.d.ts.map +1 -0
  24. package/dist/resumeLoginCaller.test.js +461 -0
  25. package/dist/resumeLoginCaller.test.js.map +1 -0
  26. package/dist/schemas/device-admission.schema.json +61 -0
  27. package/dist/schemas/device-config.schema.json +26 -0
  28. package/dist/schemas/device-connection-preference.schema.json +27 -0
  29. package/dist/skillSyncPolicy.test.js +1 -0
  30. package/dist/skillSyncPolicy.test.js.map +1 -1
  31. package/dist/usage.d.ts.map +1 -1
  32. package/dist/usage.js +1 -0
  33. package/dist/usage.js.map +1 -1
  34. package/package.json +4 -4
@@ -0,0 +1,3 @@
1
+ export declare function isIsolatedDeviceSession(): boolean;
2
+ export declare function runInIsolatedDeviceSession<T>(operation: () => Promise<T>): Promise<T>;
3
+ //# sourceMappingURL=connectionSessionScope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectionSessionScope.d.ts","sourceRoot":"","sources":["../src/connectionSessionScope.ts"],"names":[],"mappings":"AAMA,wBAAgB,uBAAuB,IAAI,OAAO,CAAoC;AACtF,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAErF"}
@@ -0,0 +1,10 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ // Preserve isolation across the entire asynchronous bootstrap continuation,
3
+ // including nested onboarding and client factories. Concurrent calls do not
4
+ // borrow a sibling operation's durable protocol session or outbox.
5
+ const scope = new AsyncLocalStorage();
6
+ export function isIsolatedDeviceSession() { return scope.getStore() === true; }
7
+ export function runInIsolatedDeviceSession(operation) {
8
+ return scope.run(true, operation);
9
+ }
10
+ //# sourceMappingURL=connectionSessionScope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectionSessionScope.js","sourceRoot":"","sources":["../src/connectionSessionScope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAEnD,4EAA4E;AAC5E,4EAA4E;AAC5E,mEAAmE;AACnE,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAW,CAAC;AAC/C,MAAM,UAAU,uBAAuB,KAAa,OAAO,KAAK,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,CAAA,CAAC;AACtF,MAAM,UAAU,0BAA0B,CAAI,SAA2B;IACvE,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { AgentFabricClient, type DeviceConfig, type HostOperationScope } from '@dharma-ai-labs/agent-fabric-relay-client';
2
+ export type ConnectionFlags = Map<string, string | boolean>;
3
+ /** Only ENOENT means absent. Never convert unavailable or malformed state to enrollment. */
4
+ export declare function readExistingDeviceConfig(path: string): Promise<DeviceConfig | null>;
5
+ export declare function connectionPreference(flags: ConnectionFlags): DeviceConfig['connectionMode'];
6
+ export declare function assertConnectionScope(config: DeviceConfig, organizationId: string, hqUrl: string): void;
7
+ export declare function assertInstallationContinuity(config: DeviceConfig, path: string): Promise<void>;
8
+ export declare function assertUnenrolledHome(paths: string[]): Promise<void>;
9
+ /** Approval verifies current trust without silently migrating a historical config. */
10
+ export declare function assertReauthenticationSigningTrust(config: DeviceConfig, approvedKeyset: unknown): void;
11
+ export type ConnectionProbeClient = Pick<AgentFabricClient, 'config' | 'openSession'>;
12
+ export declare function resumeDeviceConnection(input: {
13
+ config: DeviceConfig;
14
+ configPath: string;
15
+ statePath: string;
16
+ installationPath: string;
17
+ version: string;
18
+ hostScope?: HostOperationScope;
19
+ openClient?: () => Promise<ConnectionProbeClient>;
20
+ }): Promise<{
21
+ ok: boolean;
22
+ status: string;
23
+ connected: boolean;
24
+ deviceId: string;
25
+ organizationId: string;
26
+ installationId: string | undefined;
27
+ relayUrl: string;
28
+ relayVersion: string;
29
+ providerAuthentication: string;
30
+ admissionTransport: string;
31
+ relayTransport: string;
32
+ }>;
33
+ /** Automatic bootstrap may reuse device authority only without new authority input. */
34
+ export declare function automaticBootstrapResume(flags: ConnectionFlags, config: DeviceConfig | null): boolean;
35
+ //# sourceMappingURL=deviceConnection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deviceConnection.d.ts","sourceRoot":"","sources":["../src/deviceConnection.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,iBAAiB,EACvB,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAC,MAAM,2CAA2C,CAAC;AAE/F,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AAE5D,4FAA4F;AAC5F,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAQzF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAM3F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAGhG;AAED,wBAAsB,4BAA4B,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,iBAWpF;AAED,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,iBASzD;AAcD,sFAAsF;AACtF,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,QAkB/F;AAED,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,aAAa,CAAC,CAAC;AACtF,wBAAsB,sBAAsB,CAAC,KAAK,EAAE;IAClD,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IACtF,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACnD;;;;;;;;;;;;GAyCA;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG,OAAO,CAUrG"}
@@ -0,0 +1,164 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { createPublicKey } from 'node:crypto';
3
+ import { canonicalize, validateDeviceAdmissionContract, validateTrustedServerSigningKeysetContract, verifyInitialServerSigningKeyset } from '@dharma-ai-labs/agent-fabric-contracts';
4
+ import { AgentFabricClient, AgentFabricRequestError, parseDeviceConfig, readDeviceConnectionPreference } from '@dharma-ai-labs/agent-fabric-relay-client';
5
+ /** Only ENOENT means absent. Never convert unavailable or malformed state to enrollment. */
6
+ export async function readExistingDeviceConfig(path) {
7
+ let bytes;
8
+ try {
9
+ bytes = await readFile(path, 'utf8');
10
+ }
11
+ catch (error) {
12
+ if (error.code === 'ENOENT')
13
+ return null;
14
+ throw new Error('connection_config_unreadable');
15
+ }
16
+ return readDeviceConnectionPreference(path, parseDeviceConfig(bytes));
17
+ }
18
+ export function connectionPreference(flags) {
19
+ if (flags.has('unattended') && flags.has('no-unattended')
20
+ || ['unattended', 'no-unattended'].some(key => flags.has(key) && flags.get(key) !== true)) {
21
+ throw new Error('connection_options_invalid');
22
+ }
23
+ return flags.has('unattended') ? 'resume' : flags.has('no-unattended') ? 'manual' : undefined;
24
+ }
25
+ export function assertConnectionScope(config, organizationId, hqUrl) {
26
+ if (config.organizationId !== organizationId)
27
+ throw new Error('connection_scope_mismatch: this DHARMA_HOME is enrolled to a different organization. Use a separate DHARMA_HOME.');
28
+ if (config.hqUrl !== hqUrl)
29
+ throw new Error('connection_scope_mismatch: this DHARMA_HOME is enrolled to a different Dharma portal origin. Use a separate DHARMA_HOME.');
30
+ }
31
+ export async function assertInstallationContinuity(config, path) {
32
+ let bytes;
33
+ try {
34
+ bytes = await readFile(path, 'utf8');
35
+ }
36
+ catch (error) {
37
+ if (error.code === 'ENOENT' && config.installationId === undefined)
38
+ return;
39
+ throw new Error('connection_installation_unavailable');
40
+ }
41
+ let marker;
42
+ try {
43
+ marker = JSON.parse(bytes);
44
+ }
45
+ catch {
46
+ throw new Error('connection_installation_corrupt');
47
+ }
48
+ if (!marker || marker.schema !== 'dharma.installation-identity/v1'
49
+ || marker.installationId !== config.installationId)
50
+ throw new Error('connection_installation_mismatch');
51
+ }
52
+ export async function assertUnenrolledHome(paths) {
53
+ for (const path of paths) {
54
+ try {
55
+ await readFile(path);
56
+ }
57
+ catch (error) {
58
+ if (error.code === 'ENOENT')
59
+ continue;
60
+ throw new Error('connection_prior_state_unreadable');
61
+ }
62
+ throw new Error('connection_prior_state_requires_recovery: preserve this home and resume its supported setup.');
63
+ }
64
+ }
65
+ function assertCurrentTrust(config) {
66
+ const keys = config.serverSigningKeyset;
67
+ if (!keys)
68
+ return; // Legacy trust still needs its protected anchor and current server admission.
69
+ const now = Date.now();
70
+ if (!validateTrustedServerSigningKeysetContract(keys).ok
71
+ || keys.organizationId !== config.organizationId
72
+ || Date.parse(keys.issuedAt) > now || Date.parse(keys.expiresAt) <= now
73
+ || !keys.keys.some(key => key.status === 'active' && Date.parse(key.notBefore) <= now && Date.parse(key.notAfter) > now)) {
74
+ throw new Error('connection_trust_requires_recovery');
75
+ }
76
+ }
77
+ /** Approval verifies current trust without silently migrating a historical config. */
78
+ export function assertReauthenticationSigningTrust(config, approvedKeyset) {
79
+ if (config.serverSigningKeyset) {
80
+ assertCurrentTrust(config);
81
+ if (canonicalize(approvedKeyset ?? null) !== canonicalize(config.serverSigningKeyset)) {
82
+ throw new Error('connection_reauthentication_identity_mismatch');
83
+ }
84
+ return;
85
+ }
86
+ // Historical servers may return no keyset. Current servers must return one
87
+ // signed by this exact legacy root; accepting it never installs new trust.
88
+ if (approvedKeyset === undefined)
89
+ return;
90
+ try {
91
+ const verification = verifyInitialServerSigningKeyset(approvedKeyset, createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: config.serverPublicKeyEd25519 }, format: 'jwk' }), config.organizationId);
92
+ if (verification.ok)
93
+ return;
94
+ }
95
+ catch { /* Invalid keys or schema remain a closed recovery boundary. */ }
96
+ throw new Error('connection_reauthentication_trust_rejected');
97
+ }
98
+ export async function resumeDeviceConnection(input) {
99
+ const expected = canonicalize(input.config);
100
+ await assertInstallationContinuity(input.config, input.installationPath);
101
+ assertCurrentTrust(input.config);
102
+ let instance;
103
+ try {
104
+ instance = await (input.openClient ?? (() => AgentFabricClient.open({ configPath: input.configPath,
105
+ statePath: input.statePath, hostScope: input.hostScope, readOnly: true,
106
+ // Admission must come from the protected HQ origin. A mutable saved relay
107
+ // endpoint cannot establish current member/device authority.
108
+ fetcher: (url, init) => fetch(url, { ...init, redirect: 'error',
109
+ signal: init?.signal ? AbortSignal.any([init.signal, AbortSignal.timeout(30_000)]) : AbortSignal.timeout(30_000) }) })))();
110
+ }
111
+ catch (error) {
112
+ const message = error instanceof Error ? error.message : '';
113
+ if (message.startsWith('connection_config_'))
114
+ throw error;
115
+ if (/relay_host_device_identity_unavailable/.test(message))
116
+ throw new Error('connection_identity_requires_recovery');
117
+ if (/anchor|anchored|keyset|signing|configuration does not match|Legacy device enrollment must be reauthenticated/i.test(message))
118
+ throw new Error('connection_trust_requires_recovery');
119
+ throw new Error('connection_identity_store_unavailable');
120
+ }
121
+ if (canonicalize(instance.config) !== expected)
122
+ throw new Error('connection_state_changed');
123
+ try {
124
+ const acknowledgement = await instance.openSession(input.version);
125
+ if (!validateDeviceAdmissionContract(acknowledgement)
126
+ || acknowledgement.organizationId !== input.config.organizationId
127
+ || acknowledgement.deviceAuthority.deviceId !== input.config.deviceId
128
+ || acknowledgement.relayUrl !== input.config.relayUrl
129
+ || acknowledgement.serverPublicKeyEd25519 !== input.config.serverPublicKeyEd25519) {
130
+ throw new Error('connection_authority_unconfirmed');
131
+ }
132
+ }
133
+ catch (error) {
134
+ if (error instanceof AgentFabricRequestError && error.definitive)
135
+ throw new Error('connection_authority_rejected: use supported approval or recovery.');
136
+ if (error instanceof Error && error.message === 'connection_authority_unconfirmed')
137
+ throw error;
138
+ throw new Error('connection_transport_unavailable: preserve enrollment and retry when connectivity returns.');
139
+ }
140
+ const current = await readExistingDeviceConfig(input.configPath);
141
+ if (!current || canonicalize(current) !== expected)
142
+ throw new Error('connection_state_changed');
143
+ await assertInstallationContinuity(input.config, input.installationPath);
144
+ return { ok: true, status: 'resumed', connected: true, deviceId: input.config.deviceId,
145
+ organizationId: input.config.organizationId, installationId: input.config.installationId,
146
+ relayUrl: input.config.relayUrl, relayVersion: input.version, providerAuthentication: 'not_checked',
147
+ admissionTransport: 'anchored_hq_https', relayTransport: 'not_checked' };
148
+ }
149
+ /** Automatic bootstrap may reuse device authority only without new authority input. */
150
+ export function automaticBootstrapResume(flags, config) {
151
+ connectionPreference(flags);
152
+ if (!config || config.connectionMode !== 'resume' || flags.has('resume'))
153
+ return false;
154
+ if (flags.has('no-unattended'))
155
+ throw new Error('connection_resume_opt_in_required');
156
+ if (flags.has('grant') || flags.has('grant-prompt') || flags.has('setup-reference')
157
+ || flags.has('replace-existing-enrollment'))
158
+ return false;
159
+ if (!flags.has('complete') || flags.has('join-repository-binding-id') || flags.has('repository-url-base64url')) {
160
+ throw new Error('connection_new_scope_requires_approval');
161
+ }
162
+ return true;
163
+ }
164
+ //# sourceMappingURL=deviceConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deviceConnection.js","sourceRoot":"","sources":["../src/deviceConnection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=deviceConnection.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deviceConnection.test.d.ts","sourceRoot":"","sources":["../src/deviceConnection.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,265 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { createHash } from 'node:crypto';
6
+ import test from 'node:test';
7
+ import { AgentFabricClient, loadDeviceConfig, loadOrCreateDeviceIdentity, saveDeviceConfig, saveDeviceConnectionPreference, saveDeviceEnrollmentAnchor } from '@dharma-ai-labs/agent-fabric-relay-client';
8
+ import { automaticBootstrapResume, connectionPreference, readExistingDeviceConfig, resumeDeviceConnection } from './deviceConnection.js';
9
+ function admission(config) {
10
+ return { ok: true, organizationId: config.organizationId, relayUrl: config.relayUrl,
11
+ serverPublicKeyEd25519: config.serverPublicKeyEd25519, deviceAuthority: { schema: 'dharma.device-admission/v1',
12
+ deviceId: config.deviceId, ownerMembershipId: '44444444-4444-4444-8444-444444444444', deviceStatus: 'active', memberStatus: 'active' } };
13
+ }
14
+ async function fixture(t) {
15
+ const home = await mkdtemp(join(tmpdir(), 'fabric-connection-matrix-'));
16
+ t.after(() => rm(home, { recursive: true, force: true }));
17
+ const values = new Map();
18
+ const writes = [], requests = [];
19
+ const store = { backend: 'windows-credential-manager',
20
+ compareAndPutEnrollmentAnchor: async (input) => {
21
+ if ((values.get(input.account) ?? null) !== input.expectedCurrent
22
+ || (values.get(input.legacyAccount) ?? null) !== input.expectedLegacy)
23
+ return false;
24
+ await store.put(input.account, input.secret);
25
+ return true;
26
+ },
27
+ get: async (account) => values.get(account) ?? null,
28
+ put: async (account, value) => { writes.push(account); values.set(account, value); },
29
+ delete: async (account) => { writes.push(account); values.delete(account); } };
30
+ const installationId = '11111111-1111-4111-8111-111111111111';
31
+ const identity = await loadOrCreateDeviceIdentity({ hqUrl: 'https://hq.example', organizationId: 'org_fixture', installationId, store });
32
+ const config = { schema: 'dharma.device-config/v1', hqUrl: 'https://hq.example', organizationId: 'org_fixture',
33
+ deviceId: '22222222-2222-4222-8222-222222222222', installationId, deviceName: 'Synthetic', platform: 'windows',
34
+ publicKeyEd25519: identity.publicKeyEd25519, serverPublicKeyEd25519: identity.publicKeyEd25519,
35
+ relayUrl: 'wss://relay.example', enrolledAt: '2026-10-01T00:00:00.000Z', connectionMode: 'resume' };
36
+ const configPath = join(home, 'device.json'), statePath = join(home, 'state.json'), installationPath = join(home, 'installation.json');
37
+ await saveDeviceConfig(configPath, config);
38
+ await saveDeviceEnrollmentAnchor({ config, store });
39
+ await writeFile(installationPath, JSON.stringify({ schema: 'dharma.installation-identity/v1', installationId }));
40
+ const state = JSON.stringify({ schema: 'dharma.protocol-state/v1', sessionId: 'old', nextSequence: 7,
41
+ pending: { method: 'POST', pathname: '/api/v1/orgs/org_fixture/agent-fabric/tasks/poll', body: '{}', headers: {} } });
42
+ await writeFile(statePath, state);
43
+ writes.length = 0;
44
+ const fetcher = async (url, init) => {
45
+ requests.push({ path: new URL(String(url)).pathname, headers: new Headers(init?.headers), body: String(init?.body) });
46
+ return new Response(JSON.stringify(admission(config)), { status: 201 });
47
+ };
48
+ const input = { config, configPath, statePath, installationPath, version: '0.1.177',
49
+ openClient: () => AgentFabricClient.open({ configPath, statePath, store, fetcher, readOnly: true }) };
50
+ return { home, values, writes, requests, store, config, configPath, statePath, installationPath, identity, state, fetcher, input };
51
+ }
52
+ test('restart, outage recovery, upgrade and concurrent probes reuse the original accepted identity', async (t) => {
53
+ const f = await fixture(t), bytes = await readFile(f.configPath, 'utf8');
54
+ const before = new Map(f.values);
55
+ const first = await resumeDeviceConnection(f.input);
56
+ const restarted = await resumeDeviceConnection({ ...f.input, version: '0.1.178' });
57
+ const concurrent = await Promise.all(Array.from({ length: 8 }, () => resumeDeviceConnection(f.input)));
58
+ for (const result of [first, restarted, ...concurrent]) {
59
+ assert.equal(result.deviceId, f.config.deviceId);
60
+ assert.equal(result.installationId, f.config.installationId);
61
+ assert.equal(result.providerAuthentication, 'not_checked');
62
+ }
63
+ assert.equal(restarted.relayVersion, '0.1.178');
64
+ assert.equal(f.requests.length, 10);
65
+ for (const request of f.requests) {
66
+ assert.ok(request.path.endsWith('/agent-fabric/sessions'));
67
+ assert.equal(request.headers.get('x-dharma-device-id'), f.config.deviceId);
68
+ assert.equal(JSON.parse(request.body).relayVersion.startsWith('0.1.'), true);
69
+ }
70
+ assert.equal(new Set(f.requests.map(request => request.headers.get('x-dharma-session-id'))).size, 10);
71
+ assert.deepEqual(f.writes, []);
72
+ assert.deepEqual(f.values, before);
73
+ assert.equal(await readFile(f.configPath, 'utf8'), bytes);
74
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state, 'No sibling outbox replay or protocol write');
75
+ });
76
+ for (const state of ['missing', 'corrupt', 'locked'])
77
+ test(`${state} protected identity fails without enrollment or key writes`, async (t) => {
78
+ const f = await fixture(t);
79
+ const store = { ...f.store, get: state === 'locked'
80
+ ? async () => { throw Error('private-credential-detail'); }
81
+ : async (account) => account === f.identity.account ? state === 'missing' ? null : '{broken' : f.store.get(account) };
82
+ await assert.rejects(resumeDeviceConnection({ ...f.input,
83
+ openClient: () => AgentFabricClient.open({ configPath: f.configPath, statePath: f.statePath, store, fetcher: f.fetcher, readOnly: true }) }), state === 'locked' ? /connection_identity_store_unavailable/ : /connection_identity_requires_recovery/);
84
+ assert.deepEqual(f.writes, []);
85
+ assert.deepEqual(f.requests, []);
86
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state);
87
+ });
88
+ for (const status of [401, 403, 409])
89
+ test(`current server authority rejection ${status} fails closed`, async (t) => {
90
+ const f = await fixture(t);
91
+ const rejected = async () => new Response(JSON.stringify({ ok: false, error: { message: 'private-server-detail' } }), { status });
92
+ await assert.rejects(resumeDeviceConnection({ ...f.input,
93
+ openClient: () => AgentFabricClient.open({ configPath: f.configPath, statePath: f.statePath, store: f.store, fetcher: rejected, readOnly: true }) }), /connection_authority_rejected/);
94
+ assert.deepEqual(f.writes, []);
95
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state);
96
+ });
97
+ test('temporary network failure preserves identity and the same invocation succeeds after connectivity returns', async (t) => {
98
+ const f = await fixture(t), before = new Map(f.values);
99
+ await assert.rejects(resumeDeviceConnection({ ...f.input,
100
+ openClient: () => AgentFabricClient.open({ configPath: f.configPath, statePath: f.statePath, store: f.store,
101
+ fetcher: async () => { throw Error('fetch failed: private endpoint detail'); }, readOnly: true }) }), /connection_transport_unavailable/);
102
+ const result = await resumeDeviceConnection(f.input);
103
+ assert.equal(result.deviceId, f.config.deviceId);
104
+ assert.deepEqual(f.values, before);
105
+ assert.deepEqual(f.writes, []);
106
+ });
107
+ test('mismatched installation and changed enrollment during probe cannot report resumed', async (t) => {
108
+ const f = await fixture(t);
109
+ await writeFile(f.installationPath, JSON.stringify({ schema: 'dharma.installation-identity/v1', installationId: '33333333-3333-4333-8333-333333333333' }));
110
+ await assert.rejects(resumeDeviceConnection(f.input), /connection_installation_mismatch/);
111
+ assert.deepEqual(f.requests, []);
112
+ await writeFile(f.installationPath, JSON.stringify({ schema: 'dharma.installation-identity/v1', installationId: f.config.installationId }));
113
+ await assert.rejects(resumeDeviceConnection({ ...f.input, openClient: async () => ({ config: f.config,
114
+ openSession: async () => { await writeFile(f.configPath, JSON.stringify({ ...f.config, deviceId: 'changed' })); return admission(f.config); } }) }), /connection_state_changed/);
115
+ assert.deepEqual(f.writes, []);
116
+ });
117
+ test('expired or malformed cached signing trust cannot reconnect or refresh itself', async (t) => {
118
+ const f = await fixture(t);
119
+ const config = { ...f.config, serverSigningKeyset: { schema: 'dharma.server-signing-keyset/v1',
120
+ organizationId: f.config.organizationId, generation: 1, keys: [], signedByKeyVersion: 'old',
121
+ issuedAt: '2026-10-01T00:00:00.000Z', expiresAt: '2026-10-02T00:00:00.000Z', signature: 'old' } };
122
+ await assert.rejects(resumeDeviceConnection({ ...f.input, config }), /connection_trust_requires_recovery/);
123
+ assert.deepEqual(f.requests, []);
124
+ assert.deepEqual(f.writes, []);
125
+ });
126
+ test('only ENOENT means absent; empty, invalid-schema, invalid preference and malformed config remain failures', async (t) => {
127
+ const f = await fixture(t);
128
+ assert.equal(await readExistingDeviceConfig(join(f.home, 'absent.json')), null);
129
+ for (const [bytes, code] of [['', 'corrupt'], ['{broken', 'corrupt'], ['{}', 'invalid'],
130
+ [JSON.stringify({ ...f.config, connectionMode: 'forever' }), 'invalid']]) {
131
+ await writeFile(f.configPath, bytes);
132
+ await assert.rejects(readExistingDeviceConfig(f.configPath), new RegExp(`connection_config_${code}`));
133
+ assert.equal(await readFile(f.configPath, 'utf8'), bytes);
134
+ }
135
+ });
136
+ test('unattended is explicit opt-in, absent preference is manual, and new bootstrap scope requires approval', async (t) => {
137
+ const f = await fixture(t);
138
+ assert.equal(connectionPreference(new Map()), undefined);
139
+ assert.equal(connectionPreference(new Map([['unattended', true]])), 'resume');
140
+ assert.equal(connectionPreference(new Map([['no-unattended', true]])), 'manual');
141
+ assert.throws(() => connectionPreference(new Map([['unattended', 'true']])), /connection_options_invalid/);
142
+ assert.throws(() => connectionPreference(new Map([['unattended', true], ['no-unattended', true]])), /connection_options_invalid/);
143
+ assert.equal(automaticBootstrapResume(new Map([['complete', true]]), f.config), true);
144
+ assert.equal(automaticBootstrapResume(new Map([['complete', true]]), { ...f.config, connectionMode: undefined }), false);
145
+ assert.equal(automaticBootstrapResume(new Map([['setup-reference', 'reference'], ['complete', true]]), f.config), false);
146
+ assert.throws(() => automaticBootstrapResume(new Map([['complete', true], ['join-repository-binding-id', 'new']]), f.config), /connection_new_scope_requires_approval/);
147
+ });
148
+ test('actual default factory cannot accept a saved relay acknowledgement when protected HQ rejects authority', async (t) => {
149
+ const f = await fixture(t);
150
+ const config = { ...f.config, relayUrl: 'wss://untrusted-relay.example' };
151
+ await saveDeviceConfig(f.configPath, config);
152
+ const relayCalls = [], hqCalls = [];
153
+ const originalOpen = AgentFabricClient.open, originalFetch = globalThis.fetch, OriginalWebSocket = globalThis.WebSocket;
154
+ class UntrustedRelay {
155
+ static CLOSING = 2;
156
+ readyState = 1;
157
+ message;
158
+ constructor(url) { relayCalls.push(String(url)); }
159
+ addEventListener(type, callback) {
160
+ if (type === 'open')
161
+ queueMicrotask(() => callback({ data: '' }));
162
+ if (type === 'message')
163
+ this.message = callback;
164
+ }
165
+ send(bytes) {
166
+ const request = JSON.parse(bytes);
167
+ this.message({ data: JSON.stringify({ requestId: request.requestId, status: 201, body: JSON.stringify({ ok: true }) }) });
168
+ }
169
+ close() { this.readyState = 3; }
170
+ }
171
+ AgentFabricClient.open = input => originalOpen({ ...input, store: f.store });
172
+ globalThis.WebSocket = UntrustedRelay;
173
+ globalThis.fetch = async (url, init) => {
174
+ hqCalls.push({ url: String(url), redirect: init?.redirect, signal: init?.signal });
175
+ return new Response(JSON.stringify({ ok: false }), { status: 403 });
176
+ };
177
+ try {
178
+ await assert.rejects(resumeDeviceConnection({ ...f.input, config, openClient: undefined }), /connection_authority_rejected/);
179
+ assert.equal(relayCalls.length, 0);
180
+ assert.equal(hqCalls.length, 1);
181
+ assert.equal(new URL(hqCalls[0].url).origin, f.config.hqUrl);
182
+ assert.equal(hqCalls[0].redirect, 'error');
183
+ assert.ok(hqCalls[0].signal instanceof AbortSignal);
184
+ assert.deepEqual(f.writes, []);
185
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state);
186
+ globalThis.fetch = async () => new Response(JSON.stringify(admission(f.config)), { status: 201 });
187
+ await assert.rejects(resumeDeviceConnection({ ...f.input, config, openClient: undefined }), /connection_authority_unconfirmed/, 'Protected HQ must approve the same saved relay endpoint');
188
+ await saveDeviceConfig(f.configPath, f.config);
189
+ const admitted = await resumeDeviceConnection({ ...f.input, openClient: undefined });
190
+ assert.equal(admitted.deviceId, f.config.deviceId);
191
+ assert.equal(admitted.admissionTransport, 'anchored_hq_https');
192
+ assert.equal(admitted.relayTransport, 'not_checked');
193
+ assert.equal(relayCalls.length, 0);
194
+ assert.deepEqual(f.writes, []);
195
+ }
196
+ finally {
197
+ AgentFabricClient.open = originalOpen;
198
+ globalThis.fetch = originalFetch;
199
+ globalThis.WebSocket = OriginalWebSocket;
200
+ }
201
+ });
202
+ test('default read-only factory accepts a validated legacy anchor without migration writes', async (t) => {
203
+ const f = await fixture(t);
204
+ const anchorEntry = [...f.values].find(([account]) => account.startsWith('device-enrollment-'));
205
+ f.values.delete(anchorEntry[0]);
206
+ const legacy = `device-enrollment-${createHash('sha256').update(`${f.config.hqUrl}:${f.config.organizationId}`).digest('hex').slice(0, 32)}`;
207
+ f.values.set(legacy, anchorEntry[1]);
208
+ const before = new Map(f.values), originalOpen = AgentFabricClient.open, originalFetch = globalThis.fetch;
209
+ AgentFabricClient.open = input => originalOpen({ ...input, store: f.store });
210
+ globalThis.fetch = f.fetcher;
211
+ try {
212
+ assert.equal((await resumeDeviceConnection({ ...f.input, openClient: undefined })).deviceId, f.config.deviceId);
213
+ assert.deepEqual(f.values, before);
214
+ assert.deepEqual(f.writes, []);
215
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state);
216
+ }
217
+ finally {
218
+ AgentFabricClient.open = originalOpen;
219
+ globalThis.fetch = originalFetch;
220
+ }
221
+ });
222
+ test('an unguarded old session acknowledgement cannot establish current member authority', async (t) => {
223
+ const f = await fixture(t);
224
+ const before = await readFile(f.configPath, 'utf8');
225
+ await assert.rejects(resumeDeviceConnection({ ...f.input, openClient: async () => ({ config: f.config,
226
+ openSession: async () => ({ ok: true, organizationId: f.config.organizationId, relayUrl: f.config.relayUrl,
227
+ serverPublicKeyEd25519: f.config.serverPublicKeyEd25519 }) }) }), /connection_authority_unconfirmed/);
228
+ assert.equal(await readFile(f.configPath, 'utf8'), before);
229
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state);
230
+ assert.deepEqual(f.writes, []);
231
+ });
232
+ test('member, device, organization and endpoint substitutions cannot report resumed', async (t) => {
233
+ const f = await fixture(t), accepted = admission(f.config);
234
+ for (const response of [
235
+ { ...accepted, organizationId: 'org_other' }, { ...accepted, relayUrl: 'wss://other-relay.example' },
236
+ { ...accepted, serverPublicKeyEd25519: 'Z'.repeat(43) },
237
+ { ...accepted, deviceAuthority: { ...accepted.deviceAuthority, deviceId: '33333333-3333-4333-8333-333333333333' } },
238
+ { ...accepted, deviceAuthority: { ...accepted.deviceAuthority, memberStatus: 'revoked' } },
239
+ { ...accepted, deviceAuthority: { ...accepted.deviceAuthority, ownerMembershipId: null } },
240
+ { ...accepted, deviceAuthority: { ...accepted.deviceAuthority, deviceStatus: 'revoked' } },
241
+ ])
242
+ await assert.rejects(resumeDeviceConnection({ ...f.input,
243
+ openClient: async () => ({ config: f.config, openSession: async () => response }) }), /connection_authority_unconfirmed/);
244
+ assert.deepEqual(f.writes, []);
245
+ assert.equal(await readFile(f.statePath, 'utf8'), f.state);
246
+ });
247
+ test('bound preference survives trust metadata updates and fails closed on corruption', async (t) => {
248
+ const f = await fixture(t), configBytes = await readFile(f.configPath, 'utf8');
249
+ await saveDeviceConnectionPreference({ configPath: f.configPath, config: f.config, connectionMode: 'manual' });
250
+ assert.equal((await loadDeviceConfig(f.configPath)).connectionMode, 'manual');
251
+ assert.equal(await readFile(f.configPath, 'utf8'), configBytes, 'Preference does not rewrite trust metadata');
252
+ const file = (await readdir(f.home)).find(name => name.startsWith('device.json.connection.'));
253
+ const path = join(f.home, file), saved = JSON.parse(await readFile(path, 'utf8'));
254
+ for (const [bytes, code] of [['{broken', 'corrupt'],
255
+ [JSON.stringify({ ...saved, connectionMode: 'forever' }), 'invalid']]) {
256
+ await writeFile(path, bytes);
257
+ await assert.rejects(readExistingDeviceConfig(f.configPath), new RegExp(`connection_preference_${code}`));
258
+ assert.equal(await readFile(path, 'utf8'), bytes);
259
+ }
260
+ await writeFile(path, JSON.stringify(saved));
261
+ await saveDeviceConfig(f.configPath, { ...f.config, relayUrl: 'wss://changed.example' });
262
+ assert.equal((await loadDeviceConfig(f.configPath)).connectionMode, 'manual', 'Changed scope cannot resurrect an inline opt-in');
263
+ assert.deepEqual(f.writes, []);
264
+ });
265
+ //# sourceMappingURL=deviceConnection.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deviceConnection.test.js","sourceRoot":"","sources":["../src/deviceConnection.test.ts"],"names":[],"mappings":"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"}