easyeda-mcp-pro 1.1.0 → 1.2.1
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/README.md +11 -8
- package/dist/bridge/listener-ownership.d.ts +7 -1
- package/dist/bridge/listener-ownership.js +26 -5
- package/dist/bridge/listener-ownership.js.map +1 -1
- package/dist/bridge/local-bridge-relay.d.ts +53 -0
- package/dist/bridge/local-bridge-relay.js +318 -0
- package/dist/bridge/local-bridge-relay.js.map +1 -0
- package/dist/bridge/manager.d.ts +12 -0
- package/dist/bridge/manager.js +185 -14
- package/dist/bridge/manager.js.map +1 -1
- package/dist/bridge/types.d.ts +7 -6
- package/dist/bridge/types.js +1 -0
- package/dist/bridge/types.js.map +1 -1
- package/dist/config/profiles.js +3 -3
- package/dist/config/version.d.ts +1 -1
- package/dist/config/version.js +1 -1
- package/dist/package-build-manifest.json +45 -30
- package/dist/tools/L1_pcb_write.js +332 -4
- package/dist/tools/L1_pcb_write.js.map +1 -1
- package/easyeda-bridge-extension.checksums.json +8 -8
- package/easyeda-bridge-extension.eext +0 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
<a href="https://scorecard.dev/viewer/?uri=github.com/oaslananka/easyeda-mcp-pro">
|
|
38
38
|
<img src="https://api.scorecard.dev/projects/github.com/oaslananka/easyeda-mcp-pro/badge" alt="OpenSSF Scorecard" />
|
|
39
39
|
</a>
|
|
40
|
+
<a href="https://app.codspeed.io/oaslananka/easyeda-mcp-pro?utm_source=badge">
|
|
41
|
+
<img src="https://img.shields.io/endpoint?url=https://codspeed.io/badge.json" alt="CodSpeed" />
|
|
42
|
+
</a>
|
|
40
43
|
</p>
|
|
41
44
|
|
|
42
45
|
[](https://deepwiki.com/oaslananka/easyeda-mcp-pro)
|
|
@@ -108,7 +111,7 @@ For advanced configurations, manual instructions, and specific clients, see [Ins
|
|
|
108
111
|
|
|
109
112
|
## Overview
|
|
110
113
|
|
|
111
|
-
easyeda-mcp-pro is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that bridges AI assistants with hardware design workflows in EasyEDA Pro. It exposes up to
|
|
114
|
+
easyeda-mcp-pro is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that bridges AI assistants with hardware design workflows in EasyEDA Pro. It exposes up to 119 profile-gated MCP tools for schematic inspection and editing, controlled EasyEDA Pro API calls, BOM management, design rule checks, PCB board analysis, fabrication exports, diagnostics, and supplier integration.
|
|
112
115
|
|
|
113
116
|
The server connects to EasyEDA Pro via a WebSocket bridge extension, enabling real-time access to open project data. It integrates with JLCPCB, LCSC, Mouser, and DigiKey for BOM sourcing and pricing.
|
|
114
117
|
|
|
@@ -147,7 +150,7 @@ node scripts/check-runtime.mjs --require-pnpm
|
|
|
147
150
|
|
|
148
151
|
## Installation & Client Configuration
|
|
149
152
|
|
|
150
|
-
>
|
|
153
|
+
> Stable v1 is published. If you are upgrading from a pre-v1 release, follow [Migrating to v1](docs/MIGRATING_TO_V1.md).
|
|
151
154
|
|
|
152
155
|
You can configure `easyeda-mcp-pro` automatically or manually.
|
|
153
156
|
|
|
@@ -594,9 +597,9 @@ The server registers profile-gated tools according to the active `TOOL_PROFILE`.
|
|
|
594
597
|
| -------------- | ---------------: |
|
|
595
598
|
| `core` | 73 |
|
|
596
599
|
| `pro` | 100 |
|
|
597
|
-
| `full` |
|
|
598
|
-
| `dev` |
|
|
599
|
-
| `experimental` |
|
|
600
|
+
| `full` | 114 |
|
|
601
|
+
| `dev` | 119 |
|
|
602
|
+
| `experimental` | 119 |
|
|
600
603
|
|
|
601
604
|
<!-- capability-counts:end -->
|
|
602
605
|
|
|
@@ -700,7 +703,7 @@ The schematic write APIs use EasyEDA Pro extension APIs that EasyEDA currently m
|
|
|
700
703
|
│ (via Plugin) │ Protocol │ └───────────────┘ │
|
|
701
704
|
└─────────────────┘ │ ┌───────────────┐ │
|
|
702
705
|
│ │ ToolRegistry │ │
|
|
703
|
-
│ │ (up to
|
|
706
|
+
│ │ (up to 119 tools) │ │
|
|
704
707
|
│ └───────────────┘ │
|
|
705
708
|
│ ┌───────────────┐ │
|
|
706
709
|
│ │ Storage │──┼──► SQLite
|
|
@@ -920,7 +923,7 @@ See [Security Architecture & Threat Model](docs/security-architecture.md) for th
|
|
|
920
923
|
- **Secret redaction**: API keys, tokens, passwords are redacted from logs and diagnostic output
|
|
921
924
|
- **Branch protection**: Governance policy requires code reviews and status checks on the `main` branch (see [Repository Governance](docs/REPOSITORY_GOVERNANCE.md))
|
|
922
925
|
- **Code scanning**: CodeQL analysis runs on every push and PR (security-extended + security-and-quality queries)
|
|
923
|
-
- **Dependency management**: Renovate
|
|
926
|
+
- **Dependency management**: Renovate policy is configured in-repository; hosted-provider activity is verified through a Renovate Dependency Dashboard or Renovate-authored update activity. Dependency Audit, Dependency Review, Socket, and CodeQL provide independent security signals.
|
|
924
927
|
- **Supply-chain hygiene**: pnpm workspace build, pinned GitHub Actions, and no native SQLite addon dependency
|
|
925
928
|
- **Reporting**: See [SECURITY.md](SECURITY.md) for vulnerability disclosure
|
|
926
929
|
|
|
@@ -930,7 +933,7 @@ See [Security Architecture & Threat Model](docs/security-architecture.md) for th
|
|
|
930
933
|
|
|
931
934
|
This repository uses automated workflows to manage dependencies and releases:
|
|
932
935
|
|
|
933
|
-
- **Renovate**:
|
|
936
|
+
- **Renovate**: [.github/renovate.json](.github/renovate.json) defines the repository's dependency-update policy. Hosted Renovate is an account-level prerequisite; treat a Dependency Dashboard or Renovate-authored update activity as proof that the provider is active. See [Repository Governance](docs/REPOSITORY_GOVERNANCE.md).
|
|
934
937
|
- **Release Please**: Automates stable version bumps, release metadata, and `CHANGELOG.md`. Numbered `rc.N` candidates use the isolated prerelease path. See the [Release Policy](docs/RELEASE_POLICY.md) and [Release Process](docs/RELEASE_PROCESS.md).
|
|
935
938
|
- **Secure Publishing**: The release workflow rebuilds and verifies all assets, publishes npm with provenance to channel-safe `latest` or `next` dist-tags, uploads the extension and SBOM to the matching GitHub Release, and keeps GHCR/MCP Registry promotion aligned with the selected channel.
|
|
936
939
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LocalBridgeRelayEndpoint } from './local-bridge-relay.js';
|
|
1
2
|
export interface BridgeOwnershipConflict {
|
|
2
3
|
blockedByOtherInstance: true;
|
|
3
4
|
ownerPid: number;
|
|
@@ -7,7 +8,8 @@ export interface BridgeOwnershipConflict {
|
|
|
7
8
|
}
|
|
8
9
|
export declare class BridgeOwnershipConflictError extends Error {
|
|
9
10
|
readonly conflict: BridgeOwnershipConflict;
|
|
10
|
-
|
|
11
|
+
readonly relayEndpoint?: LocalBridgeRelayEndpoint | undefined;
|
|
12
|
+
constructor(conflict: BridgeOwnershipConflict, relayEndpoint?: LocalBridgeRelayEndpoint | undefined);
|
|
11
13
|
}
|
|
12
14
|
export declare class BridgeListenerOwnership {
|
|
13
15
|
private readonly dataDirectory;
|
|
@@ -18,10 +20,13 @@ export declare class BridgeListenerOwnership {
|
|
|
18
20
|
private readonly startedAt;
|
|
19
21
|
private held;
|
|
20
22
|
private port;
|
|
23
|
+
private relayPort;
|
|
21
24
|
constructor(dataDirectory: string, host: string);
|
|
22
25
|
acquire(): void;
|
|
23
26
|
private tryAcquireFreshLock;
|
|
24
27
|
updatePort(port: number): void;
|
|
28
|
+
updateRelayPort(port: number): void;
|
|
29
|
+
get relayAuthToken(): string;
|
|
25
30
|
release(): void;
|
|
26
31
|
private writeOwnerRecord;
|
|
27
32
|
private readLockSnapshot;
|
|
@@ -30,5 +35,6 @@ export declare class BridgeListenerOwnership {
|
|
|
30
35
|
private isStillStale;
|
|
31
36
|
private assertMovedOwnerUnchanged;
|
|
32
37
|
private restoreQuarantine;
|
|
38
|
+
private buildRelayEndpoint;
|
|
33
39
|
private buildConflict;
|
|
34
40
|
}
|
|
@@ -8,9 +8,11 @@ const INITIALIZATION_GRACE_MS = 5_000;
|
|
|
8
8
|
const MAX_ACQUIRE_ATTEMPTS = 4;
|
|
9
9
|
export class BridgeOwnershipConflictError extends Error {
|
|
10
10
|
conflict;
|
|
11
|
-
|
|
11
|
+
relayEndpoint;
|
|
12
|
+
constructor(conflict, relayEndpoint) {
|
|
12
13
|
super(conflict.message);
|
|
13
14
|
this.conflict = conflict;
|
|
15
|
+
this.relayEndpoint = relayEndpoint;
|
|
14
16
|
this.name = 'BridgeOwnershipConflictError';
|
|
15
17
|
}
|
|
16
18
|
}
|
|
@@ -43,7 +45,8 @@ function parseOwnerRecord(raw) {
|
|
|
43
45
|
Number(value.pid) <= 0 ||
|
|
44
46
|
typeof value.startedAt !== 'string' ||
|
|
45
47
|
typeof value.host !== 'string' ||
|
|
46
|
-
(value.port !== undefined && !isValidPort(value.port))
|
|
48
|
+
(value.port !== undefined && !isValidPort(value.port)) ||
|
|
49
|
+
(value.relayPort !== undefined && !isValidPort(value.relayPort))) {
|
|
47
50
|
return undefined;
|
|
48
51
|
}
|
|
49
52
|
return {
|
|
@@ -53,6 +56,7 @@ function parseOwnerRecord(raw) {
|
|
|
53
56
|
startedAt: value.startedAt,
|
|
54
57
|
host: value.host,
|
|
55
58
|
port: value.port === undefined ? undefined : Number(value.port),
|
|
59
|
+
relayPort: value.relayPort === undefined ? undefined : Number(value.relayPort),
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
catch {
|
|
@@ -68,6 +72,7 @@ export class BridgeListenerOwnership {
|
|
|
68
72
|
startedAt = new Date().toISOString();
|
|
69
73
|
held = false;
|
|
70
74
|
port;
|
|
75
|
+
relayPort;
|
|
71
76
|
constructor(dataDirectory, host) {
|
|
72
77
|
this.dataDirectory = dataDirectory;
|
|
73
78
|
this.host = host;
|
|
@@ -81,7 +86,7 @@ export class BridgeListenerOwnership {
|
|
|
81
86
|
return;
|
|
82
87
|
const snapshot = this.readLockSnapshot();
|
|
83
88
|
if (snapshot.owner && isProcessAlive(snapshot.owner.pid)) {
|
|
84
|
-
throw new BridgeOwnershipConflictError(this.buildConflict(snapshot.owner));
|
|
89
|
+
throw new BridgeOwnershipConflictError(this.buildConflict(snapshot.owner), this.buildRelayEndpoint(snapshot.owner));
|
|
85
90
|
}
|
|
86
91
|
const staleOwnerToken = snapshot.owner?.token;
|
|
87
92
|
const oldEnough = Date.now() - snapshot.mtimeMs >= INITIALIZATION_GRACE_MS;
|
|
@@ -120,6 +125,15 @@ export class BridgeListenerOwnership {
|
|
|
120
125
|
this.port = port;
|
|
121
126
|
this.writeOwnerRecord();
|
|
122
127
|
}
|
|
128
|
+
updateRelayPort(port) {
|
|
129
|
+
if (!this.held)
|
|
130
|
+
return;
|
|
131
|
+
this.relayPort = port;
|
|
132
|
+
this.writeOwnerRecord();
|
|
133
|
+
}
|
|
134
|
+
get relayAuthToken() {
|
|
135
|
+
return this.token;
|
|
136
|
+
}
|
|
123
137
|
release() {
|
|
124
138
|
if (!this.held)
|
|
125
139
|
return;
|
|
@@ -149,6 +163,7 @@ export class BridgeListenerOwnership {
|
|
|
149
163
|
startedAt: this.startedAt,
|
|
150
164
|
host: this.host,
|
|
151
165
|
port: this.port,
|
|
166
|
+
relayPort: this.relayPort,
|
|
152
167
|
};
|
|
153
168
|
const temporaryFile = join(this.lockDirectory, `.owner-${this.token}.tmp`);
|
|
154
169
|
writeFileSync(temporaryFile, `${JSON.stringify(record)}\n`, {
|
|
@@ -244,6 +259,11 @@ export class BridgeListenerOwnership {
|
|
|
244
259
|
throw error;
|
|
245
260
|
}
|
|
246
261
|
}
|
|
262
|
+
buildRelayEndpoint(owner) {
|
|
263
|
+
if (owner.relayPort === undefined)
|
|
264
|
+
return undefined;
|
|
265
|
+
return { host: '127.0.0.1', port: owner.relayPort, token: owner.token };
|
|
266
|
+
}
|
|
247
267
|
buildConflict(owner) {
|
|
248
268
|
const portText = owner.port === undefined ? '' : `, port ${owner.port}`;
|
|
249
269
|
return {
|
|
@@ -251,8 +271,9 @@ export class BridgeListenerOwnership {
|
|
|
251
271
|
ownerPid: owner.pid,
|
|
252
272
|
ownerPort: owner.port,
|
|
253
273
|
ownerHost: owner.host,
|
|
254
|
-
message: `Local EasyEDA bridge listener is owned by another easyeda-mcp-pro process (PID ${owner.pid}${portText})
|
|
255
|
-
|
|
274
|
+
message: `Local EasyEDA bridge listener is owned by another easyeda-mcp-pro process (PID ${owner.pid}${portText}) ` +
|
|
275
|
+
'that does not expose a compatible local follower relay. Ensure every local MCP client uses the current easyeda-mcp-pro version; ' +
|
|
276
|
+
`if the owner is stale, terminate PID ${owner.pid} and restart this MCP client.`,
|
|
256
277
|
};
|
|
257
278
|
}
|
|
258
279
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener-ownership.js","sourceRoot":"","sources":["../../src/bridge/listener-ownership.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,SAAS,EACT,SAAS,EACT,YAAY,EACZ,UAAU,EACV,MAAM,EACN,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"listener-ownership.js","sourceRoot":"","sources":["../../src/bridge/listener-ownership.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { type BridgeHello } from './protocol.js';
|
|
3
|
+
export declare const LOCAL_BRIDGE_RELAY_PROTOCOL_VERSION: 1;
|
|
4
|
+
export type SharedBridgeState = 'disconnected' | 'connecting' | 'connected' | 'error';
|
|
5
|
+
export interface SharedBridgeSnapshot {
|
|
6
|
+
state: SharedBridgeState;
|
|
7
|
+
hello: BridgeHello | null;
|
|
8
|
+
activePort: number;
|
|
9
|
+
connectedAtMs: number;
|
|
10
|
+
lastHeartbeatMs: number;
|
|
11
|
+
extensionVersion?: string;
|
|
12
|
+
extensionMethodListHash?: string;
|
|
13
|
+
loaderVersion?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface LocalBridgeRelayEndpoint {
|
|
16
|
+
host: '127.0.0.1';
|
|
17
|
+
port: number;
|
|
18
|
+
token: string;
|
|
19
|
+
}
|
|
20
|
+
interface RelayCallOptions {
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
traceparent?: string;
|
|
23
|
+
}
|
|
24
|
+
interface RelayServerOptions {
|
|
25
|
+
token: string;
|
|
26
|
+
maxPayloadBytes: number;
|
|
27
|
+
snapshot: () => SharedBridgeSnapshot;
|
|
28
|
+
call: (method: string, params: unknown, options: RelayCallOptions) => Promise<unknown>;
|
|
29
|
+
authTimeoutMs?: number;
|
|
30
|
+
maxClients?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare class LocalBridgeRelayServer {
|
|
33
|
+
private readonly options;
|
|
34
|
+
private wss;
|
|
35
|
+
private readonly clients;
|
|
36
|
+
constructor(options: RelayServerOptions);
|
|
37
|
+
start(): Promise<number>;
|
|
38
|
+
broadcast(snapshot?: SharedBridgeSnapshot): void;
|
|
39
|
+
close(): void;
|
|
40
|
+
private handleConnection;
|
|
41
|
+
}
|
|
42
|
+
export declare class LocalBridgeRelayClient extends EventEmitter {
|
|
43
|
+
private readonly endpoint;
|
|
44
|
+
private socket;
|
|
45
|
+
private attached;
|
|
46
|
+
private requestCounter;
|
|
47
|
+
private readonly pending;
|
|
48
|
+
constructor(endpoint: LocalBridgeRelayEndpoint);
|
|
49
|
+
connect(timeoutMs?: number): Promise<SharedBridgeSnapshot>;
|
|
50
|
+
call<TResult>(method: string, params: unknown, options: RelayCallOptions, responseTimeoutMs: number): Promise<TResult>;
|
|
51
|
+
disconnect(): void;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { WebSocket, WebSocketServer } from 'ws';
|
|
3
|
+
import { EasyedaApiMethodSchema } from './types.js';
|
|
4
|
+
export const LOCAL_BRIDGE_RELAY_PROTOCOL_VERSION = 1;
|
|
5
|
+
const DEFAULT_RELAY_AUTH_TIMEOUT_MS = 2_000;
|
|
6
|
+
const DEFAULT_MAX_RELAY_CLIENTS = 32;
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function rawMessageToString(raw) {
|
|
11
|
+
if (Array.isArray(raw))
|
|
12
|
+
return Buffer.concat(raw).toString('utf8');
|
|
13
|
+
if (Buffer.isBuffer(raw))
|
|
14
|
+
return raw.toString('utf8');
|
|
15
|
+
return Buffer.from(raw).toString('utf8');
|
|
16
|
+
}
|
|
17
|
+
function errorPayload(error) {
|
|
18
|
+
const record = isRecord(error) ? error : {};
|
|
19
|
+
return {
|
|
20
|
+
code: typeof record.code === 'string' ? record.code : undefined,
|
|
21
|
+
message: error instanceof Error ? error.message : String(error),
|
|
22
|
+
suggestion: typeof record.suggestion === 'string' ? record.suggestion : undefined,
|
|
23
|
+
data: record.data,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function errorFromPayload(payload) {
|
|
27
|
+
const error = new Error(payload.message);
|
|
28
|
+
Object.assign(error, {
|
|
29
|
+
code: payload.code,
|
|
30
|
+
suggestion: payload.suggestion,
|
|
31
|
+
data: payload.data,
|
|
32
|
+
});
|
|
33
|
+
return error;
|
|
34
|
+
}
|
|
35
|
+
export class LocalBridgeRelayServer {
|
|
36
|
+
options;
|
|
37
|
+
wss = null;
|
|
38
|
+
clients = new Set();
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.options = options;
|
|
41
|
+
}
|
|
42
|
+
async start() {
|
|
43
|
+
if (this.wss)
|
|
44
|
+
throw new Error('Local bridge follower relay is already running.');
|
|
45
|
+
const wss = new WebSocketServer({
|
|
46
|
+
host: '127.0.0.1',
|
|
47
|
+
port: 0,
|
|
48
|
+
maxPayload: this.options.maxPayloadBytes,
|
|
49
|
+
});
|
|
50
|
+
this.wss = wss;
|
|
51
|
+
wss.on('connection', (socket) => {
|
|
52
|
+
this.handleConnection(socket);
|
|
53
|
+
});
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
const onError = (error) => {
|
|
56
|
+
wss.off('listening', onListening);
|
|
57
|
+
reject(error);
|
|
58
|
+
};
|
|
59
|
+
const onListening = () => {
|
|
60
|
+
wss.off('error', onError);
|
|
61
|
+
resolve();
|
|
62
|
+
};
|
|
63
|
+
wss.once('error', onError);
|
|
64
|
+
wss.once('listening', onListening);
|
|
65
|
+
});
|
|
66
|
+
const address = wss.address();
|
|
67
|
+
if (!address || typeof address === 'string') {
|
|
68
|
+
wss.close();
|
|
69
|
+
this.wss = null;
|
|
70
|
+
throw new Error('Local bridge follower relay did not expose a TCP port.');
|
|
71
|
+
}
|
|
72
|
+
return address.port;
|
|
73
|
+
}
|
|
74
|
+
broadcast(snapshot = this.options.snapshot()) {
|
|
75
|
+
const payload = JSON.stringify({
|
|
76
|
+
type: 'status',
|
|
77
|
+
protocolVersion: LOCAL_BRIDGE_RELAY_PROTOCOL_VERSION,
|
|
78
|
+
snapshot,
|
|
79
|
+
});
|
|
80
|
+
for (const client of this.clients) {
|
|
81
|
+
if (client.readyState === WebSocket.OPEN)
|
|
82
|
+
client.send(payload);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
close() {
|
|
86
|
+
const wss = this.wss;
|
|
87
|
+
this.wss = null;
|
|
88
|
+
for (const client of this.clients) {
|
|
89
|
+
client.close(1001, 'owner_shutdown');
|
|
90
|
+
}
|
|
91
|
+
this.clients.clear();
|
|
92
|
+
wss?.close();
|
|
93
|
+
}
|
|
94
|
+
handleConnection(socket) {
|
|
95
|
+
const maxClients = this.options.maxClients ?? DEFAULT_MAX_RELAY_CLIENTS;
|
|
96
|
+
if ((this.wss?.clients.size ?? 0) > maxClients) {
|
|
97
|
+
socket.close(1013, 'relay_capacity');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
let authenticated = false;
|
|
101
|
+
const authTimer = setTimeout(() => {
|
|
102
|
+
if (!authenticated && socket.readyState === WebSocket.OPEN) {
|
|
103
|
+
socket.close(4003, 'relay_auth_timeout');
|
|
104
|
+
}
|
|
105
|
+
}, this.options.authTimeoutMs ?? DEFAULT_RELAY_AUTH_TIMEOUT_MS);
|
|
106
|
+
socket.on('message', (raw) => {
|
|
107
|
+
let data;
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(rawMessageToString(raw));
|
|
110
|
+
if (!isRecord(parsed))
|
|
111
|
+
throw new Error('relay message must be an object');
|
|
112
|
+
data = parsed;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
socket.close(4001, 'invalid_message');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (!authenticated) {
|
|
119
|
+
if (data.type !== 'attach' ||
|
|
120
|
+
data.protocolVersion !== LOCAL_BRIDGE_RELAY_PROTOCOL_VERSION ||
|
|
121
|
+
data.token !== this.options.token) {
|
|
122
|
+
socket.close(4003, 'invalid_relay_auth');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
authenticated = true;
|
|
126
|
+
clearTimeout(authTimer);
|
|
127
|
+
this.clients.add(socket);
|
|
128
|
+
socket.send(JSON.stringify({
|
|
129
|
+
type: 'attached',
|
|
130
|
+
protocolVersion: LOCAL_BRIDGE_RELAY_PROTOCOL_VERSION,
|
|
131
|
+
snapshot: this.options.snapshot(),
|
|
132
|
+
}));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (data.type !== 'call' || typeof data.id !== 'string' || typeof data.method !== 'string') {
|
|
136
|
+
socket.close(4001, 'invalid_relay_message');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (!EasyedaApiMethodSchema.options.includes(data.method)) {
|
|
140
|
+
socket.send(JSON.stringify({
|
|
141
|
+
type: 'response',
|
|
142
|
+
id: data.id,
|
|
143
|
+
ok: false,
|
|
144
|
+
error: {
|
|
145
|
+
code: 'METHOD_NOT_FOUND',
|
|
146
|
+
message: `Unknown bridge method: "${data.method}"`,
|
|
147
|
+
},
|
|
148
|
+
}));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const timeoutMs = typeof data.timeoutMs === 'number' && Number.isFinite(data.timeoutMs) && data.timeoutMs > 0
|
|
152
|
+
? data.timeoutMs
|
|
153
|
+
: undefined;
|
|
154
|
+
const traceparent = typeof data.traceparent === 'string' ? data.traceparent : undefined;
|
|
155
|
+
void this.options
|
|
156
|
+
.call(data.method, data.params, { timeoutMs, traceparent })
|
|
157
|
+
.then((result) => {
|
|
158
|
+
if (socket.readyState !== WebSocket.OPEN)
|
|
159
|
+
return;
|
|
160
|
+
socket.send(JSON.stringify({ type: 'response', id: data.id, ok: true, result }));
|
|
161
|
+
})
|
|
162
|
+
.catch((error) => {
|
|
163
|
+
if (socket.readyState !== WebSocket.OPEN)
|
|
164
|
+
return;
|
|
165
|
+
socket.send(JSON.stringify({
|
|
166
|
+
type: 'response',
|
|
167
|
+
id: data.id,
|
|
168
|
+
ok: false,
|
|
169
|
+
error: errorPayload(error),
|
|
170
|
+
}));
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
socket.on('close', () => {
|
|
174
|
+
clearTimeout(authTimer);
|
|
175
|
+
this.clients.delete(socket);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export class LocalBridgeRelayClient extends EventEmitter {
|
|
180
|
+
endpoint;
|
|
181
|
+
socket = null;
|
|
182
|
+
attached = false;
|
|
183
|
+
requestCounter = 0;
|
|
184
|
+
pending = new Map();
|
|
185
|
+
constructor(endpoint) {
|
|
186
|
+
super();
|
|
187
|
+
this.endpoint = endpoint;
|
|
188
|
+
}
|
|
189
|
+
async connect(timeoutMs = 1_500) {
|
|
190
|
+
if (this.socket)
|
|
191
|
+
throw new Error('Local bridge follower relay is already connected.');
|
|
192
|
+
const socket = new WebSocket(`ws://${this.endpoint.host}:${this.endpoint.port}`);
|
|
193
|
+
this.socket = socket;
|
|
194
|
+
return new Promise((resolve, reject) => {
|
|
195
|
+
let settled = false;
|
|
196
|
+
const timer = setTimeout(() => {
|
|
197
|
+
if (settled)
|
|
198
|
+
return;
|
|
199
|
+
settled = true;
|
|
200
|
+
socket.close(4000, 'attach_timeout');
|
|
201
|
+
this.socket = null;
|
|
202
|
+
reject(new Error('Timed out attaching to the local EasyEDA bridge owner.'));
|
|
203
|
+
}, timeoutMs);
|
|
204
|
+
const fail = (error) => {
|
|
205
|
+
if (settled)
|
|
206
|
+
return;
|
|
207
|
+
settled = true;
|
|
208
|
+
clearTimeout(timer);
|
|
209
|
+
this.socket = null;
|
|
210
|
+
reject(error);
|
|
211
|
+
};
|
|
212
|
+
socket.once('open', () => {
|
|
213
|
+
socket.send(JSON.stringify({
|
|
214
|
+
type: 'attach',
|
|
215
|
+
protocolVersion: LOCAL_BRIDGE_RELAY_PROTOCOL_VERSION,
|
|
216
|
+
token: this.endpoint.token,
|
|
217
|
+
}));
|
|
218
|
+
});
|
|
219
|
+
socket.once('error', (error) => {
|
|
220
|
+
fail(error);
|
|
221
|
+
});
|
|
222
|
+
socket.on('message', (raw) => {
|
|
223
|
+
let message;
|
|
224
|
+
try {
|
|
225
|
+
const parsed = JSON.parse(rawMessageToString(raw));
|
|
226
|
+
if (!isRecord(parsed))
|
|
227
|
+
return;
|
|
228
|
+
message = parsed;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (!this.attached && message.type === 'attached' && isRecord(message.snapshot)) {
|
|
234
|
+
this.attached = true;
|
|
235
|
+
if (!settled) {
|
|
236
|
+
settled = true;
|
|
237
|
+
clearTimeout(timer);
|
|
238
|
+
resolve(message.snapshot);
|
|
239
|
+
}
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (message.type === 'status' && isRecord(message.snapshot)) {
|
|
243
|
+
this.emit('status', message.snapshot);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (message.type !== 'response' || typeof message.id !== 'string')
|
|
247
|
+
return;
|
|
248
|
+
const pending = this.pending.get(message.id);
|
|
249
|
+
if (!pending)
|
|
250
|
+
return;
|
|
251
|
+
clearTimeout(pending.timer);
|
|
252
|
+
this.pending.delete(message.id);
|
|
253
|
+
if (message.ok === true) {
|
|
254
|
+
pending.resolve(message.result);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const payload = isRecord(message.error)
|
|
258
|
+
? message.error
|
|
259
|
+
: { message: 'Shared EasyEDA bridge call failed.' };
|
|
260
|
+
pending.reject(errorFromPayload(payload));
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
socket.on('close', (code, reason) => {
|
|
264
|
+
clearTimeout(timer);
|
|
265
|
+
this.socket = null;
|
|
266
|
+
this.attached = false;
|
|
267
|
+
const error = new Error(`Local EasyEDA bridge owner relay disconnected (${code}: ${reason.toString() || 'closed'}).`);
|
|
268
|
+
for (const [, pending] of this.pending) {
|
|
269
|
+
clearTimeout(pending.timer);
|
|
270
|
+
pending.reject(error);
|
|
271
|
+
}
|
|
272
|
+
this.pending.clear();
|
|
273
|
+
if (!settled)
|
|
274
|
+
fail(error);
|
|
275
|
+
else
|
|
276
|
+
this.emit('close', error);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
call(method, params, options, responseTimeoutMs) {
|
|
281
|
+
const socket = this.socket;
|
|
282
|
+
if (!socket || !this.attached || socket.readyState !== WebSocket.OPEN) {
|
|
283
|
+
return Promise.reject(new Error('Local EasyEDA bridge owner relay is not connected.'));
|
|
284
|
+
}
|
|
285
|
+
const id = `relay_${process.pid}_${++this.requestCounter}`;
|
|
286
|
+
return new Promise((resolve, reject) => {
|
|
287
|
+
const timer = setTimeout(() => {
|
|
288
|
+
this.pending.delete(id);
|
|
289
|
+
reject(new Error(`Shared bridge method "${method}" timed out after ${responseTimeoutMs}ms`));
|
|
290
|
+
}, responseTimeoutMs);
|
|
291
|
+
this.pending.set(id, {
|
|
292
|
+
resolve: resolve,
|
|
293
|
+
reject,
|
|
294
|
+
timer,
|
|
295
|
+
});
|
|
296
|
+
socket.send(JSON.stringify({
|
|
297
|
+
type: 'call',
|
|
298
|
+
id,
|
|
299
|
+
method,
|
|
300
|
+
params,
|
|
301
|
+
timeoutMs: options.timeoutMs,
|
|
302
|
+
traceparent: options.traceparent,
|
|
303
|
+
}));
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
disconnect() {
|
|
307
|
+
const socket = this.socket;
|
|
308
|
+
this.socket = null;
|
|
309
|
+
this.attached = false;
|
|
310
|
+
for (const [, pending] of this.pending) {
|
|
311
|
+
clearTimeout(pending.timer);
|
|
312
|
+
pending.reject(new Error('Local EasyEDA bridge follower disconnected.'));
|
|
313
|
+
}
|
|
314
|
+
this.pending.clear();
|
|
315
|
+
socket?.close(1000, 'follower_shutdown');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=local-bridge-relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-bridge-relay.js","sourceRoot":"","sources":["../../src/bridge/local-bridge-relay.ts"],"names":[],"mappings":"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"}
|