@lightninglabs/wavelength-core 0.1.0 → 0.1.1-rc2

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
@@ -7,8 +7,9 @@ and no inbound liquidity to manage, while their keys stay on their own device.
7
7
 
8
8
  This package is transport- and framework-agnostic. It carries the
9
9
  `WavelengthClient` interface, the request/response types, `RuntimeConfig` and
10
- its per-network endpoint defaults, the errors and enums, and the generated
11
- daemon types. It has no DOM and no transport of its own.
10
+ its per-network endpoint defaults, the errors and enums, the generated daemon
11
+ types, and the `WalletEngine` that the framework bindings build on. It has no
12
+ DOM and no transport of its own.
12
13
 
13
14
  You usually don't install this package directly. Each transport re-exports
14
15
  everything here, so an app imports the client and its types from one place:
@@ -16,6 +17,8 @@ everything here, so an app imports the client and its types from one place:
16
17
  - [`@lightninglabs/wavelength-web`](https://www.npmjs.com/package/@lightninglabs/wavelength-web) for the browser (WebAssembly).
17
18
  - [`@lightninglabs/wavelength-react-native`](https://www.npmjs.com/package/@lightninglabs/wavelength-react-native) for React Native.
18
19
 
20
+ ## Install
21
+
19
22
  Install it on its own only when you need the types or the client contract
20
23
  without a transport, for example in shared code:
21
24
 
@@ -23,6 +26,8 @@ without a transport, for example in shared code:
23
26
  npm install @lightninglabs/wavelength-core
24
27
  ```
25
28
 
29
+ ## Use
30
+
26
31
  ```ts
27
32
  import type { WavelengthClient, RuntimeConfig } from "@lightninglabs/wavelength-core";
28
33
  ```
@@ -17,6 +17,7 @@ import { type ActivityStreamOptions } from './activity-options.ts';
17
17
  * normalization remain separate synchronization points.
18
18
  */
19
19
  export declare abstract class BaseWavelengthClient implements WavelengthClient {
20
+ #private;
20
21
  protected readonly listeners: Set<WavelengthListener>;
21
22
  abstract ready(): Promise<void>;
22
23
  protected abstract invokeFacade<T = unknown>(method: FacadeMethod, params?: unknown): Promise<T>;
@@ -25,10 +26,45 @@ export declare abstract class BaseWavelengthClient implements WavelengthClient {
25
26
  /** How this transport's daemon dials the Ark and swap servers. */
26
27
  protected abstract readonly serverTransport: ServerTransport;
27
28
  callFacade<T = unknown>(method: FacadeMethod, params?: unknown): Promise<T>;
29
+ protected callFacadeInternal<T = unknown>(method: FacadeMethod, params?: unknown): Promise<T>;
28
30
  isRunning(): Promise<boolean>;
29
31
  startActivity(opts?: ActivityStreamOptions): Promise<void>;
32
+ /**
33
+ * Runs a runtime lifecycle operation serialized against every other one on
34
+ * this client, in invocation order. A transport that owns an exclusive
35
+ * resource for the daemon's lifetime (the web transport's cross-tab runtime
36
+ * lock) routes its start()/stop() through this so overlapping host calls
37
+ * cannot interleave: two starts cannot share one lock lease, and a stop cannot
38
+ * release the lock while a start is still opening the databases. A failed
39
+ * operation does not poison the queue for the next caller.
40
+ */
41
+ protected enqueueLifecycle<T>(op: () => Promise<T>): Promise<T>;
30
42
  start(config: RuntimeConfig): Promise<WalletInfo>;
31
43
  stop(): Promise<void>;
44
+ /**
45
+ * Called at the very start of a stop, before the daemon RPC, so a transport
46
+ * can capture whatever identifies the session being stopped (the web
47
+ * transport's runtime-lock lease). The value is handed back to
48
+ * {@link afterDaemonStopped}. Default: nothing to capture.
49
+ */
50
+ protected beforeDaemonStop(): unknown;
51
+ /**
52
+ * Called once the daemon has acknowledged a stop and before subscribers are
53
+ * told about it. A transport holding an exclusive resource for the daemon's
54
+ * lifetime (the web transport's cross-tab runtime lock, say) releases it
55
+ * here: the acknowledgement is the proof the daemon let its storage go, and
56
+ * running before the event means a subscriber that restarts the runtime
57
+ * cannot race the release. Not called when the stop call fails, because an
58
+ * unacknowledged stop is no evidence the daemon is down.
59
+ *
60
+ * Receives the token {@link beforeDaemonStop} captured, so the release can be
61
+ * scoped to the session this stop belongs to and a stop whose start has
62
+ * already been superseded frees nothing. Awaited, so a transport whose
63
+ * release only completes asynchronously (the Web Locks API frees a lock when
64
+ * the holder's promise settles, not when it is asked to) can resolve once the
65
+ * resource is genuinely free.
66
+ */
67
+ protected afterDaemonStopped(_token?: unknown): void | Promise<void>;
32
68
  getInfo(): Promise<WalletInfo>;
33
69
  status(): Promise<WalletStatus>;
34
70
  balance(): Promise<Balance>;
@@ -1 +1 @@
1
- {"version":3,"file":"base-client.d.ts","sourceRoot":"","sources":["../src/base-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base-client.d.ts","sourceRoot":"","sources":["../src/base-client.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { validateRuntimeConfig } from "./config.js";
2
2
  import { assertFacadeMethod, toGoCreateWalletReq, toGoUnlockWalletReq, toMobileConfig, } from "./facade.js";
3
- import { errorMessage } from "./errors.js";
3
+ import { WavelengthError, errorMessage } from "./errors.js";
4
4
  import { normalizeEntry, normalizeFacadeResult, } from "./response-normalization.js";
5
5
  import { validateActivityStreamOptions, } from "./activity-options.js";
6
6
  /**
@@ -14,7 +14,28 @@ import { validateActivityStreamOptions, } from "./activity-options.js";
14
14
  */
15
15
  export class BaseWavelengthClient {
16
16
  listeners = new Set();
17
+ // Serializes runtime lifecycle operations for transports that route start and
18
+ // stop through enqueueLifecycle, so a host's overlapping calls (a double
19
+ // click, a stop issued mid-start) run one at a time in invocation order
20
+ // instead of interleaving at the transport's exclusive resources.
21
+ #lifecycleTail = Promise.resolve();
22
+ // The raw facade escape hatch. It rejects the lifecycle verbs 'start' and
23
+ // 'stop' so they can only run through the typed start()/stop(): those are
24
+ // where the web transports take and release the cross-tab runtime lock, and a
25
+ // raw call would bypass it. The typed methods dispatch through
26
+ // callFacadeInternal, which carries no such guard.
17
27
  async callFacade(method, params = {}) {
28
+ if (method === 'start' || method === 'stop') {
29
+ throw new WavelengthError(`Call ${method}() instead of callFacade('${method}'): the ${method} ` +
30
+ 'lifecycle verb runs through the typed method, which manages the ' +
31
+ 'cross-tab runtime lock.');
32
+ }
33
+ return this.callFacadeInternal(method, params);
34
+ }
35
+ // The unguarded facade dispatch behind callFacade. The typed lifecycle verbs
36
+ // (start/stop) call this directly so callFacade's guard does not reject the
37
+ // very verbs they exist to issue.
38
+ async callFacadeInternal(method, params = {}) {
18
39
  assertFacadeMethod(method);
19
40
  const raw = await this.invokeFacade(method, params);
20
41
  return normalizeFacadeResult(method, raw);
@@ -26,19 +47,65 @@ export class BaseWavelengthClient {
26
47
  validateActivityStreamOptions(opts);
27
48
  await this.openActivityStream(opts);
28
49
  }
50
+ /**
51
+ * Runs a runtime lifecycle operation serialized against every other one on
52
+ * this client, in invocation order. A transport that owns an exclusive
53
+ * resource for the daemon's lifetime (the web transport's cross-tab runtime
54
+ * lock) routes its start()/stop() through this so overlapping host calls
55
+ * cannot interleave: two starts cannot share one lock lease, and a stop cannot
56
+ * release the lock while a start is still opening the databases. A failed
57
+ * operation does not poison the queue for the next caller.
58
+ */
59
+ enqueueLifecycle(op) {
60
+ const run = this.#lifecycleTail.then(op, op);
61
+ // The tail tracks only completion, never the value or a rejection.
62
+ this.#lifecycleTail = run.then(() => undefined, () => undefined);
63
+ return run;
64
+ }
29
65
  // start boots the embedded daemon and returns the post-boot WalletInfo. The
30
66
  // facade's start verb resolves nothing useful on its own, so the client
31
67
  // fetches getInfo afterwards; the React provider derives the runtime phase
32
68
  // from it.
33
69
  async start(config) {
34
70
  validateRuntimeConfig(config, this.serverTransport);
35
- await this.callFacade('start', toMobileConfig(config, this.serverTransport));
71
+ await this.callFacadeInternal('start', toMobileConfig(config, this.serverTransport));
36
72
  return this.getInfo();
37
73
  }
38
74
  async stop() {
39
- await this.callFacade('stop');
75
+ // Snapshot any per-session teardown token before the stop is issued, so
76
+ // afterDaemonStopped acts on the session this stop belongs to even if a new
77
+ // start takes over while the stop RPC is in flight.
78
+ const token = this.beforeDaemonStop();
79
+ await this.callFacadeInternal('stop');
80
+ await this.afterDaemonStopped(token);
40
81
  this.emit({ type: 'runtimeStopped' });
41
82
  }
83
+ /**
84
+ * Called at the very start of a stop, before the daemon RPC, so a transport
85
+ * can capture whatever identifies the session being stopped (the web
86
+ * transport's runtime-lock lease). The value is handed back to
87
+ * {@link afterDaemonStopped}. Default: nothing to capture.
88
+ */
89
+ beforeDaemonStop() {
90
+ return undefined;
91
+ }
92
+ /**
93
+ * Called once the daemon has acknowledged a stop and before subscribers are
94
+ * told about it. A transport holding an exclusive resource for the daemon's
95
+ * lifetime (the web transport's cross-tab runtime lock, say) releases it
96
+ * here: the acknowledgement is the proof the daemon let its storage go, and
97
+ * running before the event means a subscriber that restarts the runtime
98
+ * cannot race the release. Not called when the stop call fails, because an
99
+ * unacknowledged stop is no evidence the daemon is down.
100
+ *
101
+ * Receives the token {@link beforeDaemonStop} captured, so the release can be
102
+ * scoped to the session this stop belongs to and a stop whose start has
103
+ * already been superseded frees nothing. Awaited, so a transport whose
104
+ * release only completes asynchronously (the Web Locks API frees a lock when
105
+ * the holder's promise settles, not when it is asked to) can resolve once the
106
+ * resource is genuinely free.
107
+ */
108
+ afterDaemonStopped(_token) { }
42
109
  getInfo() {
43
110
  return this.callFacade('getInfo');
44
111
  }
package/dist/client.d.ts CHANGED
@@ -13,7 +13,12 @@ import type { Balance, CreateWalletResult, DepositResult, ExitResult, ExitStatus
13
13
  export interface WavelengthClient {
14
14
  /** Resolves once the runtime assets are loaded and the client is usable. */
15
15
  ready(): Promise<void>;
16
- /** Starts the embedded daemon with the given config and resolves with its initial info. */
16
+ /**
17
+ * Starts the embedded daemon with the given config and resolves with its
18
+ * initial info. Calling start() while a session is already running coalesces
19
+ * onto it and resolves with the current info; the passed config is ignored,
20
+ * so stop() first to start under a different one.
21
+ */
17
22
  start(config: RuntimeConfig): Promise<WalletInfo>;
18
23
  /** Stops the embedded daemon. */
19
24
  stop(): Promise<void>;
@@ -65,7 +70,17 @@ export interface WavelengthClient {
65
70
  * `broadcast: false` first to preview; `broadcast: true` moves funds.
66
71
  */
67
72
  sweepWallet(req: SweepWalletRequest): Promise<SweepWalletResult>;
68
- /** Invokes a portable daemon facade method with a normalized response. */
73
+ /**
74
+ * Invokes a portable daemon facade method with a normalized response. A
75
+ * low-level escape hatch for facade verbs the typed methods do not cover;
76
+ * prefer the typed methods wherever they exist.
77
+ *
78
+ * Rejects the lifecycle verbs `'start'` and `'stop'`: use the typed
79
+ * {@link start} and {@link stop} instead. On the web transports those verbs
80
+ * take and release the cross-tab runtime lock, so allowing a raw
81
+ * `callFacade('start')` or `callFacade('stop')` would bypass it, defeat the
82
+ * multi-tab guard, and could strand the lock until the page reloads.
83
+ */
69
84
  callFacade<T = unknown>(method: FacadeMethod, params?: unknown): Promise<T>;
70
85
  /** Reports whether the embedded daemon is running. */
71
86
  isRunning(): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -50,8 +50,13 @@ export interface WalletEngine {
50
50
  subscribe(listener: () => void): () => void;
51
51
  /**
52
52
  * Starts the runtime. Falls back to the engine's configured config when
53
- * called without an argument; throws if neither exists. A failure moves the
54
- * phase to 'error' and rejects.
53
+ * called without an argument; throws if neither exists. On success it
54
+ * dispatches the info and best-effort refreshes; a failure moves the phase to
55
+ * 'error' and rejects. Either way, a stop() the host issued while the start
56
+ * was in flight takes precedence: that stop governs the phase, and the start
57
+ * leaves the snapshot to it (no info dispatch and no refresh on success, no
58
+ * error surfaced on failure). The promise still settles the ordinary way,
59
+ * resolving with the info or rejecting.
55
60
  */
56
61
  start(config?: RuntimeConfig): Promise<WalletInfo>;
57
62
  /** Stops the runtime and clears the in-memory snapshot (info, balance, activity, error); persisted wallet data is untouched. A failure moves the phase to 'error'. */
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,9 @@ class WavelengthEngine {
17
17
  #store = new SnapshotStore();
18
18
  #config;
19
19
  #disposed = false;
20
+ // Counts stops the host asked for, so a start that rejects afterwards can
21
+ // tell an intentional shutdown from a runtime that died underneath it.
22
+ #deliberateStops = 0;
20
23
  #unsubscribe;
21
24
  // Background refreshes are serialized: two concurrent reads would race on
22
25
  // the snapshot, and the slower one would win with the staler data.
@@ -110,9 +113,20 @@ class WavelengthEngine {
110
113
  throw new Error('cannot start while the runtime is stopping');
111
114
  }
112
115
  this.#refreshFailures = 0;
116
+ const stopsBefore = this.#deliberateStops;
113
117
  this.#dispatch({ type: 'startRequested' }, { error: null });
114
118
  try {
115
119
  const info = await this.client.start(cfg);
120
+ // A stop the host issued while this start was in flight owns the outcome,
121
+ // the same precedence the catch below applies to a rejected start. The
122
+ // phase has already moved to stopping or stopped; dispatching infoReceived
123
+ // would ignore-transition through the machine but still apply the { info }
124
+ // patch, repopulating a snapshot the host asked to tear down (the hazard
125
+ // #fetchAll guards on its sibling path). Hand the caller the info the RPC
126
+ // returned without touching the snapshot, and skip the refresh with it.
127
+ if (this.#deliberateStops !== stopsBefore) {
128
+ return info;
129
+ }
116
130
  this.#dispatch({ type: 'infoReceived', info }, { info });
117
131
  try {
118
132
  await this.refresh();
@@ -124,12 +138,34 @@ class WavelengthEngine {
124
138
  }
125
139
  catch (err) {
126
140
  const error = toError(err);
141
+ // A stop the host asked for while this start was in flight owns the
142
+ // outcome. Reporting the abandoned start's failure would drag the
143
+ // phase back off 'stopped' and show an error the host already moved
144
+ // past. A runtime that died on its own is different: it reaches
145
+ // 'stopped' without a stop request, and the failure still has to
146
+ // surface (see the machine's startFailed transition).
147
+ if (this.#deliberateStops !== stopsBefore) {
148
+ // The phase intentionally stays 'stopped', so the cause is dropped
149
+ // from the snapshot; log it so it is still recoverable. The promise
150
+ // rejection below carries it too.
151
+ const logs = [
152
+ ...this.getSnapshot().logs,
153
+ {
154
+ level: 'debug',
155
+ message: 'start failed but a deliberate stop took precedence; error ' +
156
+ `kept off the phase: ${error.message}`,
157
+ },
158
+ ].slice(-MAX_LOGS);
159
+ this.#store.update({ logs });
160
+ throw error;
161
+ }
127
162
  this.#dispatch({ type: 'startFailed' }, { error });
128
163
  throw error;
129
164
  }
130
165
  }
131
166
  async stop() {
132
167
  this.#assertNotDisposed();
168
+ this.#deliberateStops += 1;
133
169
  this.#dispatch({ type: 'stopRequested' });
134
170
  try {
135
171
  await this.client.stop();
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../src/engine/machine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,4BAA4B,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3B;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,iBAAiB,GACvB,YAAY,CA+Dd"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../src/engine/machine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,4BAA4B,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3B;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,iBAAiB,GACvB,YAAY,CA4Fd"}
@@ -10,15 +10,44 @@ export function transition(phase, event) {
10
10
  case 'runtimeReady':
11
11
  return phase === 'loading' ? 'runtimeReady' : phase;
12
12
  case 'runtimeFailed':
13
- return phase === 'loading' ? 'error' : phase;
13
+ // 'stopped' is accepted alongside 'loading' for the same reason startFailed
14
+ // accepts it: a runtime that dies before ready() settles announces its stop
15
+ // (moving loading -> stopped) before the ready() rejection dispatches
16
+ // runtimeFailed. Without this the boot failure would be swallowed by the
17
+ // stop it caused, leaving the host on a generic stopped screen. Unlike a
18
+ // start failure, a runtime that failed to load is a genuine error worth
19
+ // surfacing even if a stop coincided, so this needs no deliberate-stop
20
+ // guard: a clean stop during loading never produces a runtimeFailed.
21
+ return phase === 'loading' || phase === 'stopped' ? 'error' : phase;
14
22
  case 'runtimeStopped':
15
23
  // A clean stop or a runtime crash; either way the engine is gone, so
16
- // this always wins.
17
- return 'stopped';
24
+ // this wins over every phase except 'error'. An error outranks the stop
25
+ // that caused it: a runtime dying because a start failed announces both
26
+ // the failure and the stop, in an order that depends on transport timing
27
+ // (a synchronous emit lands before the rejection, one deferred behind an
28
+ // async lock release lands after), and the host must end on the failure
29
+ // either way. Preserving 'error' here is what frees transports from
30
+ // ordering their rejection against their stop event. A clean stop never
31
+ // passes through 'error', so it is unaffected, and startRequested still
32
+ // exits 'error', so retry flows are too.
33
+ //
34
+ // This preserves 'error' for every error, not only a start failure: a
35
+ // live-runtime error (a lost activity stream, refresh-budget exhaustion)
36
+ // followed by a runtime death also stays on 'error' rather than moving to
37
+ // 'stopped'. That is intentional: an error screen is a safe terminal state
38
+ // the host recovers from with a retry (startRequested exits it), and
39
+ // scoping the rule to start failures would mean tracking which error is in
40
+ // flight for a difference the user does not feel.
41
+ return phase === 'error' ? phase : 'stopped';
18
42
  case 'startRequested':
19
43
  return phase === 'stopping' ? phase : 'starting';
20
44
  case 'startFailed':
21
- return phase === 'starting' ? 'error' : phase;
45
+ // 'stopped' is accepted alongside 'starting' because a runtime that dies
46
+ // mid-start announces the stop before the start rejection has finished
47
+ // propagating. Without this the failure would be swallowed by the stop
48
+ // that it caused, leaving the host on a generic stopped screen with no
49
+ // way to show (for instance) that the wallet is open in another tab.
50
+ return phase === 'starting' || phase === 'stopped' ? 'error' : phase;
22
51
  case 'infoReceived':
23
52
  switch (phase) {
24
53
  case 'starting':
package/dist/errors.d.ts CHANGED
@@ -1,12 +1,18 @@
1
1
  /**
2
2
  * A stable, machine-readable classification on {@link WavelengthError} so consumers
3
3
  * can branch without string-matching the message. The SDK's own failures use the
4
- * named codes; daemon-originated errors currently fall back to `'wavelength_error'`
5
- * (a richer daemon-code mapping is planned). The `(string & {})` arm keeps the
6
- * union open for forward compatibility while still offering autocomplete on the
7
- * known codes.
4
+ * named codes; most daemon-originated errors fall back to `'wavelength_error'`
5
+ * (a richer daemon-code mapping is planned), except storage-contention failures
6
+ * on `start()`, which the web transports map to `'wallet_locked'`. `'wallet_locked'` means the wallet
7
+ * runtime is already open in another tab or window of the same origin: the
8
+ * daemon's OPFS databases are exclusive, so a start attempt fails fast with this
9
+ * code until the other tab stops the runtime or closes. `'runtime_lock_unavailable'`
10
+ * means the browser refused or dropped the lock request itself (for example
11
+ * while the document is shutting down), which says nothing about another tab.
12
+ * The `(string & {})` arm keeps the union open for forward
13
+ * compatibility while still offering autocomplete on the known codes.
8
14
  */
9
- export type WavelengthErrorCode = 'wavelength_error' | 'runtime_not_ready' | 'asset_load_failed' | 'worker_error' | 'unsupported_facade_method' | 'invalid_cursor' | 'invalid_config' | (string & {});
15
+ export type WavelengthErrorCode = 'wavelength_error' | 'runtime_not_ready' | 'asset_load_failed' | 'worker_error' | 'wallet_locked' | 'runtime_lock_unavailable' | 'unsupported_facade_method' | 'invalid_cursor' | 'invalid_config' | (string & {});
10
16
  /**
11
17
  * The error type thrown by the SDK. Carries a machine-readable {@link code} so
12
18
  * consumers can branch without string-matching the message.
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAC3B,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,GACd,2BAA2B,GAC3B,gBAAgB,GAChB,gBAAgB,GAChB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAEnC;;;;OAIG;gBAED,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,mBAAwC,EAC9C,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAShC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CA0BjD;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,SAAmC;CAIvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE7C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,mBAAmB,GAC3B,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,GACd,eAAe,GACf,0BAA0B,GAC1B,2BAA2B,GAC3B,gBAAgB,GAChB,gBAAgB,GAChB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAEnC;;;;OAIG;gBAED,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,mBAAwC,EAC9C,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAShC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CA0BjD;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,SAAmC;CAIvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE7C"}
package/dist/version.d.ts CHANGED
@@ -7,12 +7,12 @@
7
7
  * Hosted runtime assets live in a directory named after this value
8
8
  * (`<assets root>/<RUNTIME_MANIFEST_VERSION>/<file>`), so every asset set gets
9
9
  * a unique URL and a browser can never serve a stale cached runtime. Bump it
10
- * together with regenerating the daemon types and publishing the matching
11
- * asset set.
10
+ * together with regenerating the daemon types, and only to a published
11
+ * wavelength release: the matching asset set is attached to that release.
12
12
  *
13
13
  * Build tooling reads this value from the source text via
14
14
  * scripts/runtime-version.mjs, so keep the declaration in this exact
15
15
  * single-quoted literal form.
16
16
  */
17
- export declare const RUNTIME_MANIFEST_VERSION = "v0.1.0";
17
+ export declare const RUNTIME_MANIFEST_VERSION = "v0.1.1-rc2";
18
18
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,wBAAwB,WAAW,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,wBAAwB,eAAe,CAAC"}
package/dist/version.js CHANGED
@@ -7,11 +7,11 @@
7
7
  * Hosted runtime assets live in a directory named after this value
8
8
  * (`<assets root>/<RUNTIME_MANIFEST_VERSION>/<file>`), so every asset set gets
9
9
  * a unique URL and a browser can never serve a stale cached runtime. Bump it
10
- * together with regenerating the daemon types and publishing the matching
11
- * asset set.
10
+ * together with regenerating the daemon types, and only to a published
11
+ * wavelength release: the matching asset set is attached to that release.
12
12
  *
13
13
  * Build tooling reads this value from the source text via
14
14
  * scripts/runtime-version.mjs, so keep the declaration in this exact
15
15
  * single-quoted literal form.
16
16
  */
17
- export const RUNTIME_MANIFEST_VERSION = 'v0.1.0';
17
+ export const RUNTIME_MANIFEST_VERSION = 'v0.1.1-rc2';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightninglabs/wavelength-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1-rc2",
4
4
  "private": false,
5
5
  "description": "Transport- and framework-agnostic contract for the Wavelength self-custodial Lightning wallet SDK.",
6
6
  "license": "MIT",