@hydranium/client-browser 1.0.0-next.298 → 1.0.0-next.300

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 CHANGED
@@ -56,11 +56,15 @@ const { capabilities } = await initializeLanguageClient(heads.lsp, {
56
56
  const data = new DataConnectionWithEvents(heads.data);
57
57
  ```
58
58
 
59
- In the worker, read the bootstrap with `isWorkerBootstrapMessage` from
60
- `@hydranium/protocol` and start each head on its port, never on the worker's
61
- global scope. Post a `WorkerErrorMessage` for a failure you catch there; one
62
- under `WORKER_BOOTSTRAP_PHASE` ends the page's heads, any other phase only
63
- reports.
59
+ In the worker, answer the bootstrap with `hostHeadsInWorker` from
60
+ `@hydranium/core/browser`, which starts each head on its port, never on the
61
+ worker's global scope, posts the ready message once they are up and reports
62
+ a failed start, build or rejection. A worker of your own reads the bootstrap
63
+ with `isWorkerBootstrapMessage` from `@hydranium/protocol`, posts a
64
+ `WorkerReadyMessage` once its heads are up and a `WorkerErrorMessage` for a
65
+ failure it catches; one under `WORKER_BOOTSTRAP_PHASE` ends the page's heads,
66
+ any other phase only reports. Until the worker has posted its ready message,
67
+ or anything on a head's port, the `Worker`'s `error` event ends the heads too.
64
68
 
65
69
  Register the handler for the server's diagnostics in `beforeInitialized`,
66
70
  which runs once `initialize` has answered and before `initialized` goes out.
@@ -48,12 +48,13 @@ export interface WorkerHeads {
48
48
  readonly onWorkerError: Event<WorkerErrorMessage>;
49
49
  /**
50
50
  * Fires once when the heads end: on a failed bootstrap, on an `error` event
51
- * before the worker has posted on any head's port, or on {@link dispose}.
52
- * What the heads had pending is rejected then rather than left waiting. Any
53
- * later report, and an `error` event once the worker has posted, ends
54
- * nothing: the worker runs on after an uncaught error, and the heads with
55
- * it. Subscribe before the first `await`: the end fires once, and a
56
- * subscriber after it hears nothing.
51
+ * before the worker is known to be up, or on {@link dispose}. What the heads
52
+ * had pending is rejected then rather than left waiting. The worker is up
53
+ * once it has posted its ready message, or anything on a head's port for a
54
+ * worker that posts no ready message. Any later report, and an `error`
55
+ * event once the worker is up, ends nothing: the worker runs on after an
56
+ * uncaught error, and the heads with it. Subscribe before the first
57
+ * `await`: the end fires once, and a subscriber after it hears nothing.
57
58
  */
58
59
  readonly onDispose: Event<void>;
59
60
  /** End every head. A head whose connection exists signals its close to the worker, which ends the head there. */
@@ -64,9 +65,9 @@ export interface WorkerHeads {
64
65
  * each.
65
66
  *
66
67
  * The worker keeps `port2` of every pair and the page `port1`; neither end is
67
- * given the worker global, which carries the bootstrap, the worker's failure
68
- * reports and whatever the host adds for itself. See the handshake in
69
- * `@hydranium/protocol` for why a head on the global is unusable.
68
+ * given the worker global, which carries the bootstrap, the worker's ready
69
+ * message and failure reports, and whatever the host adds for itself. See the
70
+ * handshake in `@hydranium/protocol` for why a head on the global is unusable.
70
71
  *
71
72
  * **A port reports nothing when its peer dies**, so a worker that fails to
72
73
  * load, throws before its bootstrap or fails it would leave every request on
@@ -1 +1 @@
1
- {"version":3,"file":"worker-heads.d.ts","sourceRoot":"","sources":["../src/worker-heads.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAMJ,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,sBAAsB,EAE3B,KAAK,kBAAkB,EACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAoC,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG/H,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IAChC,mHAAmH;IACnH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,QAAQ,GAAG,UAAU,CAAC;CACrG;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IACzB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC;IAChC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClD;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,iHAAiH;IACjH,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAwEhG"}
1
+ {"version":3,"file":"worker-heads.d.ts","sourceRoot":"","sources":["../src/worker-heads.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAOJ,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,sBAAsB,EAE3B,KAAK,kBAAkB,EACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAoC,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG/H,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IAChC,mHAAmH;IACnH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,QAAQ,GAAG,UAAU,CAAC;CACrG;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IACzB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC;IAChC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClD;;;;;;;;;OASG;IACH,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,iHAAiH;IACjH,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CA8EhG"}
@@ -20,9 +20,9 @@ exports.WORKER_ERROR_EVENT_PHASE = 'worker';
20
20
  * each.
21
21
  *
22
22
  * The worker keeps `port2` of every pair and the page `port1`; neither end is
23
- * given the worker global, which carries the bootstrap, the worker's failure
24
- * reports and whatever the host adds for itself. See the handshake in
25
- * `@hydranium/protocol` for why a head on the global is unusable.
23
+ * given the worker global, which carries the bootstrap, the worker's ready
24
+ * message and failure reports, and whatever the host adds for itself. See the
25
+ * handshake in `@hydranium/protocol` for why a head on the global is unusable.
26
26
  *
27
27
  * **A port reports nothing when its peer dies**, so a worker that fails to
28
28
  * load, throws before its bootstrap or fails it would leave every request on
@@ -49,12 +49,14 @@ function connectWorkerHeads(worker, options = {}) {
49
49
  const glspConnection = (0, browser_1.createMessageConnection)(glspTransport.reader, glspTransport.writer, options.logger?.with('GLSP head'));
50
50
  const errorEmitter = new browser_1.Emitter();
51
51
  const disposeEmitter = new browser_1.Emitter();
52
- // Whether the worker has posted anything on a head's port, which only a
53
- // worker past its bootstrap does. An `error` event before that is a worker
54
- // that never started; one after it is an uncaught error the worker survives.
55
- let workerPosted = false;
52
+ // Whether the worker is past its bootstrap: it says so with its ready
53
+ // message, and a worker that posts none shows it by posting on a head's
54
+ // port, which only a running head does. An `error` event before that is a
55
+ // worker that never started; one after it is an uncaught error the worker
56
+ // survives.
57
+ let workerUp = false;
56
58
  for (const port of [lsp.port1, data.port1, glsp.port1]) {
57
- port.addEventListener('message', () => (workerPosted = true), { once: true });
59
+ port.addEventListener('message', () => (workerUp = true), { once: true });
58
60
  }
59
61
  let disposed = false;
60
62
  const dispose = () => {
@@ -77,11 +79,15 @@ function connectWorkerHeads(worker, options = {}) {
77
79
  phase: exports.WORKER_ERROR_EVENT_PHASE,
78
80
  message: event.message || 'no detail; check that the worker script loaded'
79
81
  });
80
- if (!workerPosted) {
82
+ if (!workerUp) {
81
83
  dispose();
82
84
  }
83
85
  });
84
86
  worker.addEventListener('message', event => {
87
+ if ((0, protocol_1.isWorkerReadyMessage)(event.data)) {
88
+ workerUp = true;
89
+ return;
90
+ }
85
91
  if (!(0, protocol_1.isWorkerErrorMessage)(event.data)) {
86
92
  return;
87
93
  }
@@ -1 +1 @@
1
- {"version":3,"file":"worker-heads.js","sourceRoot":"","sources":["../src/worker-heads.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker-heads.js","sourceRoot":"","sources":["../src/worker-heads.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/client-browser",
3
- "version": "1.0.0-next.298",
3
+ "version": "1.0.0-next.300",
4
4
  "description": "The page side of a hydranium host that runs its heads in a web worker: the worker bootstrap that hands each head its own MessagePort, the page's LSP handshake, the data head's port, and the rejection of what is pending when the worker dies.",
5
5
  "keywords": [
6
6
  "browser",
@@ -50,7 +50,7 @@
50
50
  "watch": "tsc -b -w --preserveWatchOutput"
51
51
  },
52
52
  "devDependencies": {
53
- "@hydranium/protocol": "1.0.0-next.298",
53
+ "@hydranium/protocol": "1.0.0-next.300",
54
54
  "@types/node": "^22.0.0",
55
55
  "rimraf": "^5.0.0",
56
56
  "typescript": "^7.0.2",
@@ -58,7 +58,7 @@
58
58
  "vscode-languageserver-protocol": "3.18.1"
59
59
  },
60
60
  "peerDependencies": {
61
- "@hydranium/protocol": "1.0.0-next.298",
61
+ "@hydranium/protocol": "1.0.0-next.300",
62
62
  "vscode-jsonrpc": "^9.0.0",
63
63
  "vscode-languageserver-protocol": "~3.18.1"
64
64
  },
@@ -10,6 +10,7 @@
10
10
  import {
11
11
  createMessagePortTransport,
12
12
  isWorkerErrorMessage,
13
+ isWorkerReadyMessage,
13
14
  WORKER_BOOTSTRAP_MESSAGE_TYPE,
14
15
  WORKER_BOOTSTRAP_PHASE,
15
16
  WORKER_ERROR_MESSAGE_TYPE,
@@ -64,12 +65,13 @@ export interface WorkerHeads {
64
65
  readonly onWorkerError: Event<WorkerErrorMessage>;
65
66
  /**
66
67
  * Fires once when the heads end: on a failed bootstrap, on an `error` event
67
- * before the worker has posted on any head's port, or on {@link dispose}.
68
- * What the heads had pending is rejected then rather than left waiting. Any
69
- * later report, and an `error` event once the worker has posted, ends
70
- * nothing: the worker runs on after an uncaught error, and the heads with
71
- * it. Subscribe before the first `await`: the end fires once, and a
72
- * subscriber after it hears nothing.
68
+ * before the worker is known to be up, or on {@link dispose}. What the heads
69
+ * had pending is rejected then rather than left waiting. The worker is up
70
+ * once it has posted its ready message, or anything on a head's port for a
71
+ * worker that posts no ready message. Any later report, and an `error`
72
+ * event once the worker is up, ends nothing: the worker runs on after an
73
+ * uncaught error, and the heads with it. Subscribe before the first
74
+ * `await`: the end fires once, and a subscriber after it hears nothing.
73
75
  */
74
76
  readonly onDispose: Event<void>;
75
77
  /** End every head. A head whose connection exists signals its close to the worker, which ends the head there. */
@@ -81,9 +83,9 @@ export interface WorkerHeads {
81
83
  * each.
82
84
  *
83
85
  * The worker keeps `port2` of every pair and the page `port1`; neither end is
84
- * given the worker global, which carries the bootstrap, the worker's failure
85
- * reports and whatever the host adds for itself. See the handshake in
86
- * `@hydranium/protocol` for why a head on the global is unusable.
86
+ * given the worker global, which carries the bootstrap, the worker's ready
87
+ * message and failure reports, and whatever the host adds for itself. See the
88
+ * handshake in `@hydranium/protocol` for why a head on the global is unusable.
87
89
  *
88
90
  * **A port reports nothing when its peer dies**, so a worker that fails to
89
91
  * load, throws before its bootstrap or fails it would leave every request on
@@ -112,12 +114,14 @@ export function connectWorkerHeads(worker: Worker, options: WorkerHeadsOptions =
112
114
  const errorEmitter = new Emitter<WorkerErrorMessage>();
113
115
  const disposeEmitter = new Emitter<void>();
114
116
 
115
- // Whether the worker has posted anything on a head's port, which only a
116
- // worker past its bootstrap does. An `error` event before that is a worker
117
- // that never started; one after it is an uncaught error the worker survives.
118
- let workerPosted = false;
117
+ // Whether the worker is past its bootstrap: it says so with its ready
118
+ // message, and a worker that posts none shows it by posting on a head's
119
+ // port, which only a running head does. An `error` event before that is a
120
+ // worker that never started; one after it is an uncaught error the worker
121
+ // survives.
122
+ let workerUp = false;
119
123
  for (const port of [lsp.port1, data.port1, glsp.port1]) {
120
- port.addEventListener('message', () => (workerPosted = true), { once: true });
124
+ port.addEventListener('message', () => (workerUp = true), { once: true });
121
125
  }
122
126
 
123
127
  let disposed = false;
@@ -142,11 +146,15 @@ export function connectWorkerHeads(worker: Worker, options: WorkerHeadsOptions =
142
146
  phase: WORKER_ERROR_EVENT_PHASE,
143
147
  message: event.message || 'no detail; check that the worker script loaded'
144
148
  });
145
- if (!workerPosted) {
149
+ if (!workerUp) {
146
150
  dispose();
147
151
  }
148
152
  });
149
153
  worker.addEventListener('message', event => {
154
+ if (isWorkerReadyMessage(event.data)) {
155
+ workerUp = true;
156
+ return;
157
+ }
150
158
  if (!isWorkerErrorMessage(event.data)) {
151
159
  return;
152
160
  }