@lightninglabs/wavelength-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +31 -0
- package/dist/activity-options.d.ts +15 -0
- package/dist/activity-options.d.ts.map +1 -0
- package/dist/activity-options.js +7 -0
- package/dist/base-client.d.ts +59 -0
- package/dist/base-client.d.ts.map +1 -0
- package/dist/base-client.js +144 -0
- package/dist/casing.d.ts +4 -0
- package/dist/casing.d.ts.map +1 -0
- package/dist/casing.js +42 -0
- package/dist/client.d.ts +90 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1 -0
- package/dist/config.d.ts +128 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +142 -0
- package/dist/destination.d.ts +56 -0
- package/dist/destination.d.ts.map +1 -0
- package/dist/destination.js +90 -0
- package/dist/engine/activity.d.ts +25 -0
- package/dist/engine/activity.d.ts.map +1 -0
- package/dist/engine/activity.js +119 -0
- package/dist/engine/constants.d.ts +29 -0
- package/dist/engine/constants.d.ts.map +1 -0
- package/dist/engine/constants.js +29 -0
- package/dist/engine/engine.d.ts +115 -0
- package/dist/engine/engine.d.ts.map +1 -0
- package/dist/engine/engine.js +548 -0
- package/dist/engine/machine.d.ts +50 -0
- package/dist/engine/machine.d.ts.map +1 -0
- package/dist/engine/machine.js +55 -0
- package/dist/engine/optionsAssertions.d.ts +2 -0
- package/dist/engine/optionsAssertions.d.ts.map +1 -0
- package/dist/engine/optionsAssertions.js +20 -0
- package/dist/engine/poller.d.ts +20 -0
- package/dist/engine/poller.d.ts.map +1 -0
- package/dist/engine/poller.js +51 -0
- package/dist/engine/reconcile.d.ts +36 -0
- package/dist/engine/reconcile.d.ts.map +1 -0
- package/dist/engine/reconcile.js +81 -0
- package/dist/engine/snapshot.d.ts +58 -0
- package/dist/engine/snapshot.d.ts.map +1 -0
- package/dist/engine/snapshot.js +10 -0
- package/dist/engine/stabilize.d.ts +8 -0
- package/dist/engine/stabilize.d.ts.map +1 -0
- package/dist/engine/stabilize.js +17 -0
- package/dist/engine/store.d.ts +21 -0
- package/dist/engine/store.d.ts.map +1 -0
- package/dist/engine/store.js +46 -0
- package/dist/errors.d.ts +55 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +80 -0
- package/dist/events.d.ts +62 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +1 -0
- package/dist/exit.d.ts +93 -0
- package/dist/exit.d.ts.map +1 -0
- package/dist/exit.js +86 -0
- package/dist/facade.d.ts +88 -0
- package/dist/facade.d.ts.map +1 -0
- package/dist/facade.js +150 -0
- package/dist/generated.d.ts +1197 -0
- package/dist/generated.d.ts.map +1 -0
- package/dist/generated.js +206 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/passkey.d.ts +46 -0
- package/dist/passkey.d.ts.map +1 -0
- package/dist/passkey.js +16 -0
- package/dist/public-api-assertions.d.ts +2 -0
- package/dist/public-api-assertions.d.ts.map +1 -0
- package/dist/public-api-assertions.js +42 -0
- package/dist/request-assertions.d.ts +2 -0
- package/dist/request-assertions.d.ts.map +1 -0
- package/dist/request-assertions.js +12 -0
- package/dist/requests.d.ts +186 -0
- package/dist/requests.d.ts.map +1 -0
- package/dist/requests.js +5 -0
- package/dist/response-normalization.d.ts +5 -0
- package/dist/response-normalization.d.ts.map +1 -0
- package/dist/response-normalization.js +101 -0
- package/dist/results.d.ts +49 -0
- package/dist/results.d.ts.map +1 -0
- package/dist/results.js +4 -0
- package/dist/state.d.ts +87 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +87 -0
- package/dist/version.d.ts +18 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +17 -0
- package/package.json +42 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-interval async poll with an optional consecutive-failure budget.
|
|
3
|
+
* The sync poll and the restore readiness poll are both instances of this.
|
|
4
|
+
*/
|
|
5
|
+
export declare class Poller {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(opts: {
|
|
8
|
+
intervalMs: number;
|
|
9
|
+
/** Run one tick immediately on start, before the first interval. */
|
|
10
|
+
immediate?: boolean;
|
|
11
|
+
/** Consecutive rejected ticks before the poll gives up. Unset means never. */
|
|
12
|
+
failureLimit?: number;
|
|
13
|
+
tick: () => Promise<void>;
|
|
14
|
+
onExhausted?: (error: unknown) => void;
|
|
15
|
+
});
|
|
16
|
+
get running(): boolean;
|
|
17
|
+
start(): void;
|
|
18
|
+
stop(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=poller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poller.d.ts","sourceRoot":"","sources":["../../src/engine/poller.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,MAAM;;gBAcL,IAAI,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,oEAAoE;QACpE,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,8EAA8E;QAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;KACxC;IAID,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,KAAK,IAAI,IAAI;IAWb,IAAI,IAAI,IAAI;CAwBb"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-interval async poll with an optional consecutive-failure budget.
|
|
3
|
+
* The sync poll and the restore readiness poll are both instances of this.
|
|
4
|
+
*/
|
|
5
|
+
export class Poller {
|
|
6
|
+
#timer;
|
|
7
|
+
#failures = 0;
|
|
8
|
+
#inFlight = false;
|
|
9
|
+
#opts;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.#opts = opts;
|
|
12
|
+
}
|
|
13
|
+
get running() {
|
|
14
|
+
return this.#timer !== undefined;
|
|
15
|
+
}
|
|
16
|
+
start() {
|
|
17
|
+
if (this.#timer) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.#failures = 0;
|
|
21
|
+
this.#timer = setInterval(() => void this.#tick(), this.#opts.intervalMs);
|
|
22
|
+
if (this.#opts.immediate) {
|
|
23
|
+
void this.#tick();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
stop() {
|
|
27
|
+
clearInterval(this.#timer);
|
|
28
|
+
this.#timer = undefined;
|
|
29
|
+
}
|
|
30
|
+
async #tick() {
|
|
31
|
+
// A tick slower than the interval must not stack up behind itself.
|
|
32
|
+
if (this.#inFlight || !this.#timer) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.#inFlight = true;
|
|
36
|
+
try {
|
|
37
|
+
await this.#opts.tick();
|
|
38
|
+
this.#failures = 0;
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
this.#failures += 1;
|
|
42
|
+
if (this.#opts.failureLimit && this.#failures >= this.#opts.failureLimit) {
|
|
43
|
+
this.stop();
|
|
44
|
+
this.#opts.onExhausted?.(err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
this.#inFlight = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Balance } from '../results.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Whether two balance snapshots carry the same figures. The settle reconcile
|
|
4
|
+
* uses it to decide when a post-activity re-read has caught up: once the
|
|
5
|
+
* balance stops changing across reads there is nothing left to reconcile.
|
|
6
|
+
*/
|
|
7
|
+
export declare function balancesEqual(a: Balance | null, b: Balance | null): boolean;
|
|
8
|
+
/** The outcome of one serialized background refresh; never a rejection. */
|
|
9
|
+
export type BackgroundRefreshResult = {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
balance: Balance | null;
|
|
12
|
+
};
|
|
13
|
+
type SettleReconcilerOptions = {
|
|
14
|
+
refresh: () => Promise<BackgroundRefreshResult>;
|
|
15
|
+
baseline: () => Balance | null;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Balance can lag the activity event that announced a settled entry: the
|
|
19
|
+
* daemon may report the entry complete a beat before balance() reflects the
|
|
20
|
+
* new funds. A single refresh would then capture a stale balance and, with no
|
|
21
|
+
* polling while ready, leave it stale until a manual refresh. Each activity
|
|
22
|
+
* event triggers a cycle: one refresh, then bounded re-reads that stop only
|
|
23
|
+
* once the balance has moved off the pre-event baseline and then held steady.
|
|
24
|
+
* Equality of two consecutive reads alone cannot distinguish settled from
|
|
25
|
+
* still-lagging, so when the balance never moves the whole bounded schedule
|
|
26
|
+
* is probed. A failed refresh deliberately ends the cycle rather than continuing
|
|
27
|
+
* the probe schedule; the next activity event or manual refresh converges it.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SettleReconciler {
|
|
30
|
+
#private;
|
|
31
|
+
constructor(opts: SettleReconcilerOptions);
|
|
32
|
+
trigger(): void;
|
|
33
|
+
cancel(): void;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../src/engine/reconcile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAe3E;AAED,2EAA2E;AAC3E,MAAM,MAAM,uBAAuB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/E,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAChD,QAAQ,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAgB;;gBAQf,IAAI,EAAE,uBAAuB;IAIzC,OAAO,IAAI,IAAI;IAaf,MAAM,IAAI,IAAI;CA+Bf"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { SETTLE_RECONCILE_DELAYS_MS } from "./constants.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether two balance snapshots carry the same figures. The settle reconcile
|
|
4
|
+
* uses it to decide when a post-activity re-read has caught up: once the
|
|
5
|
+
* balance stops changing across reads there is nothing left to reconcile.
|
|
6
|
+
*/
|
|
7
|
+
export function balancesEqual(a, b) {
|
|
8
|
+
if (a === b) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (!a || !b) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
if (a[key] !== b[key]) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Balance can lag the activity event that announced a settled entry: the
|
|
24
|
+
* daemon may report the entry complete a beat before balance() reflects the
|
|
25
|
+
* new funds. A single refresh would then capture a stale balance and, with no
|
|
26
|
+
* polling while ready, leave it stale until a manual refresh. Each activity
|
|
27
|
+
* event triggers a cycle: one refresh, then bounded re-reads that stop only
|
|
28
|
+
* once the balance has moved off the pre-event baseline and then held steady.
|
|
29
|
+
* Equality of two consecutive reads alone cannot distinguish settled from
|
|
30
|
+
* still-lagging, so when the balance never moves the whole bounded schedule
|
|
31
|
+
* is probed. A failed refresh deliberately ends the cycle rather than continuing
|
|
32
|
+
* the probe schedule; the next activity event or manual refresh converges it.
|
|
33
|
+
*/
|
|
34
|
+
export class SettleReconciler {
|
|
35
|
+
// Monotonic id for the current cycle. Every trigger bumps it, retiring any
|
|
36
|
+
// cycle still in flight: clearing the timer alone would only cancel a
|
|
37
|
+
// scheduled probe, not a refresh already in flight.
|
|
38
|
+
#generation = 0;
|
|
39
|
+
#timer;
|
|
40
|
+
#opts;
|
|
41
|
+
constructor(opts) {
|
|
42
|
+
this.#opts = opts;
|
|
43
|
+
}
|
|
44
|
+
trigger() {
|
|
45
|
+
this.#generation += 1;
|
|
46
|
+
const gen = this.#generation;
|
|
47
|
+
clearTimeout(this.#timer);
|
|
48
|
+
const baseline = this.#opts.baseline();
|
|
49
|
+
void this.#opts.refresh().then((first) => {
|
|
50
|
+
if (gen !== this.#generation || !first.ok) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.#probe(0, gen, baseline, first.balance);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
cancel() {
|
|
57
|
+
this.#generation += 1;
|
|
58
|
+
clearTimeout(this.#timer);
|
|
59
|
+
}
|
|
60
|
+
#probe(attempt, gen, baseline, prev) {
|
|
61
|
+
if (attempt >= SETTLE_RECONCILE_DELAYS_MS.length) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.#timer = setTimeout(() => {
|
|
65
|
+
if (gen !== this.#generation) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
void this.#opts.refresh().then((res) => {
|
|
69
|
+
if (gen !== this.#generation || !res.ok) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const moved = !balancesEqual(baseline, res.balance);
|
|
73
|
+
const steady = balancesEqual(prev, res.balance);
|
|
74
|
+
if (moved && steady) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.#probe(attempt + 1, gen, baseline, res.balance);
|
|
78
|
+
});
|
|
79
|
+
}, SETTLE_RECONCILE_DELAYS_MS[attempt]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Balance, CreateWalletResult, Entry } from '../results.ts';
|
|
2
|
+
import type { WalletInfo, RuntimePhase } from '../state.ts';
|
|
3
|
+
import type { WavelengthLogPayload } from '../events.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The state of a background wallet recovery started by restoreWallet, a
|
|
6
|
+
* discriminated union keyed on `status`: `idle` before any tracked restore
|
|
7
|
+
* (and after acknowledgeRecovery); `restoring` while the daemon's
|
|
8
|
+
* server-assisted scan runs; `done` once it completes (carrying the scan's
|
|
9
|
+
* result counters); `failed` if either the background scan errored on an
|
|
10
|
+
* already-usable wallet, or the restore itself failed before the wallet came
|
|
11
|
+
* up at all. In the first case the wallet is still usable and its state just
|
|
12
|
+
* may be incomplete; in the second the phase falls back to needsWallet, so
|
|
13
|
+
* read the phase alongside recovery.status to disambiguate. Read it to drive
|
|
14
|
+
* a "restoring your balance and history" banner, or a failure banner, across
|
|
15
|
+
* a possible component unmount (the phase and recovery state live in the
|
|
16
|
+
* snapshot, not hook-local state).
|
|
17
|
+
*/
|
|
18
|
+
export type RecoveryState = {
|
|
19
|
+
readonly status: 'idle';
|
|
20
|
+
} | {
|
|
21
|
+
readonly status: 'restoring';
|
|
22
|
+
} | {
|
|
23
|
+
readonly status: 'done';
|
|
24
|
+
readonly result: CreateWalletResult;
|
|
25
|
+
} | {
|
|
26
|
+
readonly status: 'failed';
|
|
27
|
+
readonly error: Error;
|
|
28
|
+
/**
|
|
29
|
+
* True when the recovery scan failed on an already-usable wallet: the
|
|
30
|
+
* wallet works, but its state may be incomplete. False when the
|
|
31
|
+
* restore failed before the wallet came up.
|
|
32
|
+
*/
|
|
33
|
+
readonly walletUsable: boolean;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The engine's immutable state snapshot. A new object per change; refresh fetches
|
|
37
|
+
* that changed nothing keep the previous field references, so consumers can
|
|
38
|
+
* cheaply compare slices with Object.is.
|
|
39
|
+
*/
|
|
40
|
+
export type WalletSnapshot = {
|
|
41
|
+
/** The current runtime/wallet lifecycle phase. */
|
|
42
|
+
readonly phase: RuntimePhase;
|
|
43
|
+
/** The last fatal runtime-level error, or null. */
|
|
44
|
+
readonly error: Error | null;
|
|
45
|
+
/** The most recent complete wallet info, or null before the runtime reports it. */
|
|
46
|
+
readonly info: WalletInfo | null;
|
|
47
|
+
/** The most recent wallet balance, or null before it is known. */
|
|
48
|
+
readonly balance: Balance | null;
|
|
49
|
+
/** The most recent activity entries, newest-first as returned by the daemon. */
|
|
50
|
+
readonly activity: readonly Entry[];
|
|
51
|
+
/** The background recovery status set by restoreWallet. */
|
|
52
|
+
readonly recovery: RecoveryState;
|
|
53
|
+
/** A bounded tail of 'log' events from the runtime, newest last. */
|
|
54
|
+
readonly logs: readonly WavelengthLogPayload[];
|
|
55
|
+
};
|
|
56
|
+
/** The snapshot every engine starts from. */
|
|
57
|
+
export declare const INITIAL_SNAPSHOT: WalletSnapshot;
|
|
58
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/engine/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAChE;IACE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC,CAAC;AAEN;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,EAAE,SAAS,KAAK,EAAE,CAAC;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAChD,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,EAAE,cAQ7B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns `prev` when `next` encodes to the same JSON, so refresh fetches that
|
|
3
|
+
* changed nothing keep the previous object identity and Object.is-based
|
|
4
|
+
* subscribers (useSyncExternalStore) skip the re-render. JSON comparison is
|
|
5
|
+
* acceptable at these payload sizes (activity is a bounded page).
|
|
6
|
+
*/
|
|
7
|
+
export declare function stabilize<T>(prev: T, next: T): T;
|
|
8
|
+
//# sourceMappingURL=stabilize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stabilize.d.ts","sourceRoot":"","sources":["../../src/engine/stabilize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAShD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns `prev` when `next` encodes to the same JSON, so refresh fetches that
|
|
3
|
+
* changed nothing keep the previous object identity and Object.is-based
|
|
4
|
+
* subscribers (useSyncExternalStore) skip the re-render. JSON comparison is
|
|
5
|
+
* acceptable at these payload sizes (activity is a bounded page).
|
|
6
|
+
*/
|
|
7
|
+
export function stabilize(prev, next) {
|
|
8
|
+
if (prev === next || prev == null || next == null) {
|
|
9
|
+
return next;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
return JSON.stringify(prev) === JSON.stringify(next) ? prev : next;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return next;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type WalletSnapshot } from './snapshot.ts';
|
|
2
|
+
/**
|
|
3
|
+
* A minimal immutable snapshot holder: getSnapshot/subscribe for consumers
|
|
4
|
+
* (React's useSyncExternalStore contract) and update(patch) for the engine.
|
|
5
|
+
* getSnapshot and subscribe are arrow-function properties so their identities
|
|
6
|
+
* are stable across the engine's lifetime.
|
|
7
|
+
*/
|
|
8
|
+
export declare class SnapshotStore {
|
|
9
|
+
#private;
|
|
10
|
+
getSnapshot: () => WalletSnapshot;
|
|
11
|
+
subscribe: (listener: () => void) => (() => void);
|
|
12
|
+
/**
|
|
13
|
+
* Shallow-merges the patch into a fresh snapshot and notifies listeners.
|
|
14
|
+
* Skips the allocation and the notification entirely when every key in the
|
|
15
|
+
* patch is already Object.is-equal to the current value: a no-op patch
|
|
16
|
+
* would otherwise still mint a new snapshot object and fire every
|
|
17
|
+
* subscriber for nothing.
|
|
18
|
+
*/
|
|
19
|
+
update(patch: Partial<WalletSnapshot>): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/engine/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAEtE;;;;;GAKG;AACH,qBAAa,aAAa;;IAIxB,WAAW,QAAO,cAAc,CAAmB;IAEnD,SAAS,GAAI,UAAU,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAM9C;IAEF;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;CAoB7C"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { INITIAL_SNAPSHOT } from "./snapshot.js";
|
|
2
|
+
/**
|
|
3
|
+
* A minimal immutable snapshot holder: getSnapshot/subscribe for consumers
|
|
4
|
+
* (React's useSyncExternalStore contract) and update(patch) for the engine.
|
|
5
|
+
* getSnapshot and subscribe are arrow-function properties so their identities
|
|
6
|
+
* are stable across the engine's lifetime.
|
|
7
|
+
*/
|
|
8
|
+
export class SnapshotStore {
|
|
9
|
+
#snapshot = INITIAL_SNAPSHOT;
|
|
10
|
+
#listeners = new Set();
|
|
11
|
+
getSnapshot = () => this.#snapshot;
|
|
12
|
+
subscribe = (listener) => {
|
|
13
|
+
this.#listeners.add(listener);
|
|
14
|
+
return () => {
|
|
15
|
+
this.#listeners.delete(listener);
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Shallow-merges the patch into a fresh snapshot and notifies listeners.
|
|
20
|
+
* Skips the allocation and the notification entirely when every key in the
|
|
21
|
+
* patch is already Object.is-equal to the current value: a no-op patch
|
|
22
|
+
* would otherwise still mint a new snapshot object and fire every
|
|
23
|
+
* subscriber for nothing.
|
|
24
|
+
*/
|
|
25
|
+
update(patch) {
|
|
26
|
+
let changed = false;
|
|
27
|
+
for (const key in patch) {
|
|
28
|
+
if (!Object.is(this.#snapshot[key], patch[key])) {
|
|
29
|
+
changed = true;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (!changed) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.#snapshot = { ...this.#snapshot, ...patch };
|
|
37
|
+
for (const listener of [...this.#listeners]) {
|
|
38
|
+
try {
|
|
39
|
+
listener();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// A throwing listener must not break the store or other listeners.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A stable, machine-readable classification on {@link WavelengthError} so consumers
|
|
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.
|
|
8
|
+
*/
|
|
9
|
+
export type WavelengthErrorCode = 'wavelength_error' | 'runtime_not_ready' | 'asset_load_failed' | 'worker_error' | 'unsupported_facade_method' | 'invalid_cursor' | 'invalid_config' | (string & {});
|
|
10
|
+
/**
|
|
11
|
+
* The error type thrown by the SDK. Carries a machine-readable {@link code} so
|
|
12
|
+
* consumers can branch without string-matching the message.
|
|
13
|
+
*/
|
|
14
|
+
export declare class WavelengthError extends Error {
|
|
15
|
+
/** The machine-readable error classification. */
|
|
16
|
+
readonly code: WavelengthErrorCode;
|
|
17
|
+
/**
|
|
18
|
+
* @param message - The human-readable error message.
|
|
19
|
+
* @param code - The machine-readable error classification; defaults to `'wavelength_error'`.
|
|
20
|
+
* @param options - Standard error options; pass `{ cause }` to retain the underlying error for debugging.
|
|
21
|
+
*/
|
|
22
|
+
constructor(message: string, code?: WavelengthErrorCode, options?: {
|
|
23
|
+
cause?: unknown;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extracts a human-readable message from an unknown thrown value. Tries in order:
|
|
28
|
+
* an Error's message, a string value as-is, a .message property on plain objects,
|
|
29
|
+
* and finally JSON serialization of anything else.
|
|
30
|
+
*/
|
|
31
|
+
export declare function errorMessage(err: unknown): string;
|
|
32
|
+
/**
|
|
33
|
+
* Thrown by passkey ceremonies when the user dismisses the OS prompt, so hosts
|
|
34
|
+
* can suppress cancellation copy without string matching. The React binding's
|
|
35
|
+
* useWalletPasskey rethrows it without recording it as an error.
|
|
36
|
+
*/
|
|
37
|
+
export declare class PasskeyCancelledError extends Error {
|
|
38
|
+
constructor(message?: string);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Reports whether `err` is a passkey cancellation. Checks `instanceof
|
|
42
|
+
* PasskeyCancelledError` first, then falls back to matching `err.name` on any
|
|
43
|
+
* Error: a duplicate copy of core (a second bundled instance of this package,
|
|
44
|
+
* for example one pulled in by a transport with its own dependency graph)
|
|
45
|
+
* produces a `PasskeyCancelledError` that fails `instanceof` across the
|
|
46
|
+
* bundle boundary even though it is functionally the same error, and the name
|
|
47
|
+
* check still recognizes it.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isPasskeyCancelled(err: unknown): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Normalizes an unknown thrown value to an Error, preserving an existing
|
|
52
|
+
* instance (and therefore its stack and cause) unchanged.
|
|
53
|
+
*/
|
|
54
|
+
export declare function toError(value: unknown): Error;
|
|
55
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error type thrown by the SDK. Carries a machine-readable {@link code} so
|
|
3
|
+
* consumers can branch without string-matching the message.
|
|
4
|
+
*/
|
|
5
|
+
export class WavelengthError extends Error {
|
|
6
|
+
/** The machine-readable error classification. */
|
|
7
|
+
code;
|
|
8
|
+
/**
|
|
9
|
+
* @param message - The human-readable error message.
|
|
10
|
+
* @param code - The machine-readable error classification; defaults to `'wavelength_error'`.
|
|
11
|
+
* @param options - Standard error options; pass `{ cause }` to retain the underlying error for debugging.
|
|
12
|
+
*/
|
|
13
|
+
constructor(message, code = 'wavelength_error', options) {
|
|
14
|
+
super(message, options);
|
|
15
|
+
this.name = 'WavelengthError';
|
|
16
|
+
// Assigned explicitly rather than via a constructor parameter property,
|
|
17
|
+
// which node's strip-only TypeScript loader (used by the unit tests) does
|
|
18
|
+
// not support.
|
|
19
|
+
this.code = code;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extracts a human-readable message from an unknown thrown value. Tries in order:
|
|
24
|
+
* an Error's message, a string value as-is, a .message property on plain objects,
|
|
25
|
+
* and finally JSON serialization of anything else.
|
|
26
|
+
*/
|
|
27
|
+
export function errorMessage(err) {
|
|
28
|
+
if (err instanceof Error && err.message) {
|
|
29
|
+
return err.message;
|
|
30
|
+
}
|
|
31
|
+
if (typeof err === 'string') {
|
|
32
|
+
return err;
|
|
33
|
+
}
|
|
34
|
+
// Duck-typed error-like objects from across serialization boundaries read
|
|
35
|
+
// better as their message than as JSON.
|
|
36
|
+
if (err !== null &&
|
|
37
|
+
typeof err === 'object' &&
|
|
38
|
+
'message' in err &&
|
|
39
|
+
typeof err.message === 'string') {
|
|
40
|
+
return err.message;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return JSON.stringify(err);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// JSON.stringify throws on circular structures or BigInt; fall back to a
|
|
47
|
+
// plain string so the error path never throws a new error.
|
|
48
|
+
return String(err);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Thrown by passkey ceremonies when the user dismisses the OS prompt, so hosts
|
|
53
|
+
* can suppress cancellation copy without string matching. The React binding's
|
|
54
|
+
* useWalletPasskey rethrows it without recording it as an error.
|
|
55
|
+
*/
|
|
56
|
+
export class PasskeyCancelledError extends Error {
|
|
57
|
+
constructor(message = 'passkey ceremony was cancelled') {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = 'PasskeyCancelledError';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Reports whether `err` is a passkey cancellation. Checks `instanceof
|
|
64
|
+
* PasskeyCancelledError` first, then falls back to matching `err.name` on any
|
|
65
|
+
* Error: a duplicate copy of core (a second bundled instance of this package,
|
|
66
|
+
* for example one pulled in by a transport with its own dependency graph)
|
|
67
|
+
* produces a `PasskeyCancelledError` that fails `instanceof` across the
|
|
68
|
+
* bundle boundary even though it is functionally the same error, and the name
|
|
69
|
+
* check still recognizes it.
|
|
70
|
+
*/
|
|
71
|
+
export function isPasskeyCancelled(err) {
|
|
72
|
+
return err instanceof PasskeyCancelledError || (err instanceof Error && err.name === 'PasskeyCancelledError');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Normalizes an unknown thrown value to an Error, preserving an existing
|
|
76
|
+
* instance (and therefore its stack and cause) unchanged.
|
|
77
|
+
*/
|
|
78
|
+
export function toError(value) {
|
|
79
|
+
return value instanceof Error ? value : new Error(errorMessage(value));
|
|
80
|
+
}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Entry } from './generated.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The severity of a `'log'` event emitted by the runtime.
|
|
4
|
+
*/
|
|
5
|
+
export type WavelengthLogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
6
|
+
/**
|
|
7
|
+
* The payload carried by a `'log'` event.
|
|
8
|
+
*/
|
|
9
|
+
export type WavelengthLogPayload = {
|
|
10
|
+
/** The severity of the log line. */
|
|
11
|
+
level: WavelengthLogLevel;
|
|
12
|
+
/** The human-readable log message. */
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Whether an activity stream that the consumer did not close ended without an
|
|
17
|
+
* error ('ended') or failed with one ('failed'). A client-initiated close
|
|
18
|
+
* emits no event at all.
|
|
19
|
+
*/
|
|
20
|
+
export type ActivityStreamState = 'ended' | 'failed';
|
|
21
|
+
/**
|
|
22
|
+
* The payload carried by an `'activityStream'` event. `message` is present
|
|
23
|
+
* exactly when the stream failed, so narrowing on `state` yields it without a
|
|
24
|
+
* null check.
|
|
25
|
+
*/
|
|
26
|
+
export type ActivityStreamPayload = {
|
|
27
|
+
state: 'ended';
|
|
28
|
+
} | {
|
|
29
|
+
state: 'failed';
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The discriminated union of runtime events delivered to subscribers. Narrow on
|
|
34
|
+
* `type` to read the payload: `'activity'` carries the changed {@link Entry},
|
|
35
|
+
* `'log'` carries a level and message, and the lifecycle events
|
|
36
|
+
* (`'runtimeReady'`, `'runtimeStopped'`) carry none. `'activityStream'` reports
|
|
37
|
+
* that the activity subscription ended or failed for a reason the consumer did
|
|
38
|
+
* not initiate.
|
|
39
|
+
*/
|
|
40
|
+
export type WavelengthEvent = {
|
|
41
|
+
type: 'runtimeReady';
|
|
42
|
+
} | {
|
|
43
|
+
type: 'runtimeStopped';
|
|
44
|
+
} | {
|
|
45
|
+
type: 'activity';
|
|
46
|
+
payload: Entry;
|
|
47
|
+
} | {
|
|
48
|
+
type: 'activityStream';
|
|
49
|
+
payload: ActivityStreamPayload;
|
|
50
|
+
} | {
|
|
51
|
+
type: 'log';
|
|
52
|
+
payload: WavelengthLogPayload;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The set of {@link WavelengthEvent} discriminants.
|
|
56
|
+
*/
|
|
57
|
+
export type WavelengthEventType = WavelengthEvent['type'];
|
|
58
|
+
/**
|
|
59
|
+
* A subscriber callback invoked with each {@link WavelengthEvent}.
|
|
60
|
+
*/
|
|
61
|
+
export type WavelengthListener = (event: WavelengthEvent) => void;
|
|
62
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,oCAAoC;IACpC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErD;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAClB;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,KAAK,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,qBAAqB,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|