@lix-js/sdk 0.16.0 → 0.17.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.
Files changed (73) hide show
  1. package/README.md +187 -22
  2. package/dist/binding-types.d.ts +20 -6
  3. package/dist/binding.browser.d.ts +2 -0
  4. package/dist/binding.browser.js +14 -4
  5. package/dist/binding.node-wasm.d.ts +1 -1
  6. package/dist/binding.node-wasm.js +5 -3
  7. package/dist/binding.node.d.ts +2 -0
  8. package/dist/binding.node.js +34 -8
  9. package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
  10. package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
  11. package/dist/compatibility.d.ts +6 -0
  12. package/dist/compatibility.js +6 -0
  13. package/dist/component-host/dispatch.d.ts +12 -0
  14. package/dist/component-host/dispatch.js +364 -0
  15. package/dist/component-host/index.d.ts +15 -0
  16. package/dist/component-host/index.js +84 -0
  17. package/dist/component-host/instrument.d.ts +6 -0
  18. package/dist/component-host/instrument.js +260 -0
  19. package/dist/conversion-provider.d.ts +4 -0
  20. package/dist/conversion-provider.js +20 -0
  21. package/dist/hosted-lix.js +1 -1
  22. package/dist/http-transport.d.ts +25 -0
  23. package/dist/http-transport.js +162 -0
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +1 -0
  26. package/dist/lix.d.ts +20 -10
  27. package/dist/lix.js +68 -23
  28. package/dist/migration-binding.browser.d.ts +33 -0
  29. package/dist/migration-binding.browser.js +46 -0
  30. package/dist/migration-binding.node.d.ts +6 -0
  31. package/dist/migration-binding.node.js +5 -0
  32. package/dist/migration-wasm/lix_js_sdk.d.ts +271 -0
  33. package/dist/migration-wasm/lix_js_sdk.js +1852 -0
  34. package/dist/migration-wasm/lix_js_sdk_bg.wasm +4 -0
  35. package/dist/migration-wasm/lix_js_sdk_bg.wasm.d.ts +101 -0
  36. package/dist/migration.d.ts +23 -0
  37. package/dist/migration.js +55 -0
  38. package/dist/open-lix.js +29 -18
  39. package/dist/open-progress.d.ts +10 -0
  40. package/dist/open-progress.js +59 -0
  41. package/dist/remote/client.d.ts +2 -1
  42. package/dist/remote/client.js +11 -1
  43. package/dist/result.d.ts +4 -3
  44. package/dist/result.js +3 -4
  45. package/dist/storage-adapter.d.ts +7 -5
  46. package/dist/storage-ownership.d.ts +5 -0
  47. package/dist/storage-ownership.js +4 -0
  48. package/dist/types.d.ts +132 -22
  49. package/dist/wasm/lix_js_sdk.d.ts +57 -16
  50. package/dist/wasm/lix_js_sdk.js +268 -60
  51. package/dist/wasm/lix_js_sdk_bg.wasm +2 -2
  52. package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +23 -9
  53. package/dist/worker/client.d.ts +12 -3
  54. package/dist/worker/client.js +98 -81
  55. package/dist/worker/durable-local-admission.d.ts +20 -0
  56. package/dist/worker/durable-local-admission.js +87 -0
  57. package/dist/worker/entry.shared.browser.d.ts +1 -0
  58. package/dist/worker/entry.shared.browser.js +211 -0
  59. package/dist/worker/factory.browser.d.ts +2 -0
  60. package/dist/worker/factory.browser.js +65 -1
  61. package/dist/worker/factory.node.d.ts +1 -0
  62. package/dist/worker/factory.node.js +3 -0
  63. package/dist/worker/host.d.ts +4 -2
  64. package/dist/worker/host.js +92 -32
  65. package/dist/worker/protocol.d.ts +33 -8
  66. package/dist/worker/protocol.js +25 -7
  67. package/dist/worker/shared-admission.d.ts +26 -0
  68. package/dist/worker/shared-admission.js +116 -0
  69. package/dist/worker/shared-engine.d.ts +34 -0
  70. package/dist/worker/shared-engine.js +194 -0
  71. package/package.json +21 -13
  72. package/dist/remote/server-protocol.d.ts +0 -185
  73. package/dist/remote/server-protocol.js +0 -417
@@ -1,19 +1,20 @@
1
- export function serializeWorkerError(error) {
1
+ export function serializeWorkerError(error, depth = 0) {
2
2
  if (!(error instanceof Error)) {
3
- return { name: "Error", message: String(error) };
3
+ return { name: "Error", message: "Non-error failure" };
4
4
  }
5
5
  const lixError = error;
6
6
  return {
7
7
  name: error.name,
8
- message: error.message,
9
- stack: error.stack,
8
+ message: redactDiagnostic(error.message),
9
+ stack: error.stack ? redactDiagnostic(error.stack) : undefined,
10
10
  code: typeof lixError.code === "string" ? lixError.code : undefined,
11
- hint: typeof lixError.hint === "string" ? lixError.hint : undefined,
12
- details: lixError.details,
11
+ hint: typeof lixError.hint === "string" ? redactDiagnostic(lixError.hint) : undefined,
12
+ details: redactDetails(lixError.details),
13
+ cause: depth < 3 && error.cause !== undefined ? serializeWorkerError(error.cause, depth + 1) : undefined,
13
14
  };
14
15
  }
15
16
  export function deserializeWorkerError(error) {
16
- const restored = new Error(error.message);
17
+ const restored = new Error(error.message, error.cause ? { cause: deserializeWorkerError(error.cause) } : undefined);
17
18
  restored.name = error.name;
18
19
  restored.stack = error.stack;
19
20
  restored.code = error.code;
@@ -21,3 +22,20 @@ export function deserializeWorkerError(error) {
21
22
  restored.details = error.details;
22
23
  return restored;
23
24
  }
25
+ function redactDiagnostic(value) {
26
+ return value.slice(0, 4096).replace(/Bearer\s+[^\s,;"']+/gi, "Bearer [redacted]")
27
+ .replace(/((?:authorization|cookie|token|password|secret)\s*[:=]\s*)[^\n]+/gi, "$1[redacted]");
28
+ }
29
+ function redactDetails(value, depth = 0) {
30
+ if (depth > 3)
31
+ return "[truncated]";
32
+ if (typeof value === "string")
33
+ return redactDiagnostic(value);
34
+ if (value === null || typeof value === "number" || typeof value === "boolean" || value === undefined)
35
+ return value;
36
+ if (Array.isArray(value))
37
+ return value.slice(0, 32).map(item => redactDetails(item, depth + 1));
38
+ if (typeof value === "object")
39
+ return Object.fromEntries(Object.entries(value).slice(0, 32).map(([key, item]) => [key, /authorization|cookie|token|password|secret|headers/i.test(key) ? "[redacted]" : redactDetails(item, depth + 1)]));
40
+ return "[unsupported]";
41
+ }
@@ -0,0 +1,26 @@
1
+ import { type HttpTransport } from "../http-transport.js";
2
+ export declare const ADMISSION_PROTOCOL_EPOCH = 17;
3
+ export declare const ADMISSION_STORAGE_EPOCH = 81;
4
+ export type AdmissionIdentity = {
5
+ repositoryId: string;
6
+ principalId: string;
7
+ protocolEpoch: number;
8
+ storageEpoch: number;
9
+ };
10
+ export declare function sharedCredentialKey(url: string, headers: [string, string][]): string;
11
+ export declare function sameAdmission(a: AdmissionIdentity, b: AdmissionIdentity): boolean;
12
+ /** Authorize attachment, awaiting any server-owned repository upgrade. */
13
+ export declare function requestAdmission(url: string, credentials: [string, string][], transport: HttpTransport): Promise<AdmissionIdentity>;
14
+ /** Memory-only proofs grant cached local attachment, never remote authorization. */
15
+ export declare class SharedAdmissionCache {
16
+ private readonly revocations;
17
+ private readonly proofs;
18
+ record(url: string, headers: [string, string][], identity: AdmissionIdentity): void;
19
+ generation(url: string, headers: [string, string][]): number;
20
+ remove(url: string, headers: [string, string][]): void;
21
+ persistLocal(url: string, headers: [string, string][], generation: number, write: () => Promise<void>, remove: () => Promise<void>): Promise<void>;
22
+ verify(url: string, headers: [string, string][], expected: AdmissionIdentity | undefined, probe: () => Promise<AdmissionIdentity>, allowOffline?: boolean): Promise<{
23
+ identity: AdmissionIdentity;
24
+ online: boolean;
25
+ }>;
26
+ }
@@ -0,0 +1,116 @@
1
+ import { HttpTransportError } from "../http-transport.js";
2
+ export const ADMISSION_PROTOCOL_EPOCH = 17;
3
+ export const ADMISSION_STORAGE_EPOCH = 81;
4
+ const ANONYMOUS_ACCOUNT_ID = "00000000-0000-7000-8000-000000000002";
5
+ export function sharedCredentialKey(url, headers) {
6
+ const entries = [];
7
+ new Headers(headers).forEach((value, key) => entries.push([key, value]));
8
+ return JSON.stringify([url, entries]);
9
+ }
10
+ export function sameAdmission(a, b) {
11
+ return a.repositoryId === b.repositoryId && a.principalId === b.principalId &&
12
+ a.protocolEpoch === b.protocolEpoch && a.storageEpoch === b.storageEpoch;
13
+ }
14
+ /** Authorize attachment, awaiting any server-owned repository upgrade. */
15
+ export async function requestAdmission(url, credentials, transport) {
16
+ const locator = new URL(url);
17
+ const repositoryId = locator.pathname.match(/\/lix\/([0-9a-f-]{36})\/?$/i)?.[1];
18
+ if (!repositoryId || locator.search || locator.hash || locator.username || locator.password) {
19
+ throw new HttpTransportError("LIX_TRANSPORT_CONTRACT", "Admission requires a repository protocol URL");
20
+ }
21
+ const headers = new Headers(credentials);
22
+ headers.set("lix-sync-protocol-version", String(ADMISSION_PROTOCOL_EPOCH));
23
+ locator.pathname = `/lix/v1/${repositoryId}/admission`;
24
+ let response;
25
+ for (;;) {
26
+ response = await transport({ url: locator.toString(),
27
+ init: { method: "GET", headers, signal: AbortSignal.timeout(10_000), cache: "no-store", redirect: "error", credentials: "omit" },
28
+ response: { mode: "buffered", maxBytes: 16 * 1024 } });
29
+ if (response.status !== 503)
30
+ break;
31
+ const body = await response.clone().json().catch(() => null);
32
+ if (body?.error?.code !== "LIX_REPOSITORY_MIGRATING")
33
+ break;
34
+ // The authority owns the migration independently of this request. Poll only
35
+ // its explicit in-progress response; other failures retain their semantics.
36
+ await new Promise(resolve => setTimeout(resolve, 1_000));
37
+ }
38
+ if (response.status === 401 || response.status === 403) {
39
+ throw new HttpTransportError("LIX_ADMISSION_AUTH_REJECTED", "Authority rejected repository admission");
40
+ }
41
+ if (response.status === 409 || response.status === 426) {
42
+ throw new HttpTransportError("LIX_ADMISSION_EPOCH", "Repository is incompatible with this client version");
43
+ }
44
+ if (!response.ok)
45
+ throw new HttpTransportError("LIX_ADMISSION_HTTP", `Authority admission returned HTTP ${response.status}`);
46
+ let result;
47
+ try {
48
+ result = await response.json();
49
+ }
50
+ catch {
51
+ throw new HttpTransportError("LIX_ADMISSION_PROTOCOL", "Authority returned invalid admission metadata");
52
+ }
53
+ if (!result || result.repositoryId !== repositoryId ||
54
+ typeof result.principalId !== "string" || !/^[\x21-\x7e]{1,255}$/.test(result.principalId)) {
55
+ throw new HttpTransportError("LIX_ADMISSION_PROTOCOL", "Authority admission identity does not match the repository");
56
+ }
57
+ if (result.protocolEpoch !== ADMISSION_PROTOCOL_EPOCH || result.storageEpoch !== ADMISSION_STORAGE_EPOCH) {
58
+ throw new HttpTransportError("LIX_ADMISSION_EPOCH", "Repository is incompatible with this client version");
59
+ }
60
+ return result;
61
+ }
62
+ /** Memory-only proofs grant cached local attachment, never remote authorization. */
63
+ export class SharedAdmissionCache {
64
+ revocations = new Map();
65
+ proofs = new Map();
66
+ record(url, headers, identity) {
67
+ // Invisible cookies/custom-fetch identity cannot be a credential proof.
68
+ if (!new Headers(headers).get("authorization") && identity.principalId !== ANONYMOUS_ACCOUNT_ID)
69
+ return;
70
+ if (this.proofs.size >= 64)
71
+ this.proofs.delete(this.proofs.keys().next().value);
72
+ this.proofs.set(sharedCredentialKey(url, headers), { ...identity });
73
+ }
74
+ generation(url, headers) {
75
+ return this.revocations.get(sharedCredentialKey(url, headers)) ?? 0;
76
+ }
77
+ remove(url, headers) {
78
+ const key = sharedCredentialKey(url, headers);
79
+ this.revocations.set(key, this.generation(url, headers) + 1);
80
+ this.proofs.delete(key);
81
+ }
82
+ async persistLocal(url, headers, generation, write, remove) {
83
+ if (this.generation(url, headers) !== generation)
84
+ return;
85
+ await write();
86
+ if (this.generation(url, headers) !== generation)
87
+ await remove();
88
+ }
89
+ async verify(url, headers, expected, probe, allowOffline = true) {
90
+ const generation = this.generation(url, headers);
91
+ let identity;
92
+ let online = true;
93
+ try {
94
+ identity = await probe();
95
+ }
96
+ catch (error) {
97
+ if (!(error instanceof Error) || error.code !== "LIX_TRANSPORT_NETWORK")
98
+ throw error;
99
+ const known = this.proofs.get(sharedCredentialKey(url, headers));
100
+ if (!allowOffline || !known || !expected || !sameAdmission(known, expected)) {
101
+ throw new HttpTransportError("LIX_IDENTITY_UNVERIFIED_OFFLINE", "Repository identity cannot be verified while offline", { cause: error });
102
+ }
103
+ identity = known;
104
+ online = false;
105
+ }
106
+ if (this.generation(url, headers) !== generation) {
107
+ throw new HttpTransportError("LIX_ADMISSION_AUTH_REJECTED", "Credentials were rejected while admission was in flight");
108
+ }
109
+ if (expected && !sameAdmission(identity, expected)) {
110
+ throw new HttpTransportError("LIX_SHARED_ENGINE_IDENTITY_MISMATCH", "Shared engine repository/account does not match this client");
111
+ }
112
+ if (online)
113
+ this.record(url, headers, identity);
114
+ return { identity, online };
115
+ }
116
+ }
@@ -0,0 +1,34 @@
1
+ import type { LixBinding, SyncServerBindingOptions, TelemetryDispatch, TelemetryParentContext, OpenProgressDispatch } from "../binding-types.js";
2
+ export type SharedEngineClient = {
3
+ server: SyncServerBindingOptions;
4
+ isDisconnected?(): boolean;
5
+ telemetry?: TelemetryDispatch;
6
+ parent?: TelemetryParentContext;
7
+ progress?: OpenProgressDispatch;
8
+ commitIdentity?(): void | Promise<void>;
9
+ rejectCredentials?(headers: [string, string][]): void | Promise<void>;
10
+ verifyIdentity(): Promise<{
11
+ authorityUrl: string;
12
+ accountId: string;
13
+ headers: [string, string][];
14
+ online?: boolean;
15
+ }>;
16
+ };
17
+ /** One physical owner; ports receive independent sessions, never the root. */
18
+ export declare class SharedEngineOwner {
19
+ private readonly open;
20
+ private root;
21
+ private principalId;
22
+ private state;
23
+ get lifecycleState(): "closed" | "ready" | "closing" | "opening" | "migration-exclusive";
24
+ private readonly clients;
25
+ private queue;
26
+ constructor(open: (server: SyncServerBindingOptions, telemetry: TelemetryDispatch, client: SharedEngineClient) => Promise<LixBinding>);
27
+ private readonly backgroundTelemetry;
28
+ attach(client: SharedEngineClient): Promise<LixBinding>;
29
+ /** Serialize closed-storage conversion with root admission across all ports. */
30
+ convert(client: SharedEngineClient, conversion: (server: SyncServerBindingOptions) => Promise<void>, branchId?: string): Promise<void>;
31
+ deactivate(client: SharedEngineClient): void;
32
+ detach(client: SharedEngineClient): Promise<void>;
33
+ private transport;
34
+ }
@@ -0,0 +1,194 @@
1
+ import { fetchTransport, HttpTransportError } from "../http-transport.js";
2
+ /** One physical owner; ports receive independent sessions, never the root. */
3
+ export class SharedEngineOwner {
4
+ open;
5
+ root;
6
+ principalId;
7
+ state = "closed";
8
+ get lifecycleState() { return this.state; }
9
+ clients = new Set();
10
+ queue = Promise.resolve();
11
+ constructor(open) {
12
+ this.open = open;
13
+ }
14
+ backgroundTelemetry = span => {
15
+ for (const client of this.clients) {
16
+ try {
17
+ client.telemetry?.(span);
18
+ }
19
+ catch { /* Host telemetry cannot interrupt engine work. */ }
20
+ }
21
+ };
22
+ attach(client) {
23
+ const operation = this.queue.then(async () => {
24
+ if (client.isDisconnected?.())
25
+ throw new Error("Shared engine client disconnected before admission");
26
+ // Admission precedes storage opening and captures initial credentials.
27
+ if (this.state === "closing")
28
+ throw new HttpTransportError("LIX_OWNER_CLOSE_FAILED", "Storage owner has not completed closing");
29
+ const identity = await client.verifyIdentity();
30
+ if (client.isDisconnected?.())
31
+ throw new HttpTransportError("LIX_TRANSPORT_UNAVAILABLE", "Client disconnected during admission");
32
+ if (identity.authorityUrl !== client.server.url)
33
+ throw new HttpTransportError("LIX_SHARED_ENGINE_IDENTITY_MISMATCH", "Admission authority does not match this client");
34
+ const opensRoot = this.root === undefined;
35
+ if (!this.root) {
36
+ this.state = "opening";
37
+ const originalServer = client.server;
38
+ const headers = identity.headers;
39
+ // Bind native admission to the exact credentials actually used during
40
+ // opening; a later dynamic-header read cannot authorize another principal.
41
+ client.server = { ...originalServer, headers, headerProvider: identity.online === false
42
+ ? async () => { throw new HttpTransportError("LIX_IDENTITY_UNVERIFIED_OFFLINE", "Cached local admission does not authorize remote requests"); }
43
+ : undefined };
44
+ this.clients.add(client);
45
+ try {
46
+ this.root = await this.open(this.transport(), this.backgroundTelemetry, client);
47
+ const principal = await this.root.activeAccountId();
48
+ if (principal !== identity.accountId)
49
+ throw new HttpTransportError("LIX_SHARED_ENGINE_IDENTITY_MISMATCH", "Stored replica account does not match admission");
50
+ this.principalId = principal;
51
+ this.state = "ready";
52
+ }
53
+ catch (error) {
54
+ this.clients.delete(client);
55
+ if (this.root) {
56
+ this.state = "closing";
57
+ await this.root.close();
58
+ this.root = undefined;
59
+ this.principalId = undefined;
60
+ }
61
+ this.state = "closed";
62
+ throw error;
63
+ }
64
+ finally {
65
+ client.server = originalServer;
66
+ }
67
+ }
68
+ const root = this.root;
69
+ try {
70
+ if (client.server.url !== identity.authorityUrl ||
71
+ this.principalId !== identity.accountId) {
72
+ throw Object.assign(new Error("Shared engine repository/account does not match this client"), { code: "LIX_SHARED_ENGINE_IDENTITY_MISMATCH" });
73
+ }
74
+ await client.commitIdentity?.();
75
+ this.clients.add(client);
76
+ const report = opensRoot ? root.openReport?.() : undefined;
77
+ const child = await root.openAnotherSession({}, client.telemetry ?? (() => { }));
78
+ if (report === undefined)
79
+ return child;
80
+ // Only the opening caller performed initialization/migration. Later
81
+ // attachments must not inherit that first caller's opening report.
82
+ return new Proxy(child, {
83
+ get(target, property) {
84
+ if (property === "openReport")
85
+ return () => report;
86
+ const value = Reflect.get(target, property, target);
87
+ return typeof value === "function" ? value.bind(target) : value;
88
+ },
89
+ });
90
+ }
91
+ catch (error) {
92
+ this.clients.delete(client);
93
+ if (this.clients.size === 0) {
94
+ this.state = "closing";
95
+ await root.close();
96
+ this.root = undefined;
97
+ this.principalId = undefined;
98
+ this.state = "closed";
99
+ }
100
+ throw error;
101
+ }
102
+ });
103
+ this.queue = operation.catch(() => undefined);
104
+ return operation;
105
+ }
106
+ /** Serialize closed-storage conversion with root admission across all ports. */
107
+ convert(client, conversion, branchId) {
108
+ const operation = this.queue.then(async () => {
109
+ if (client.isDisconnected?.())
110
+ throw new Error("Shared engine client disconnected before conversion");
111
+ if (this.root) {
112
+ const identity = await client.verifyIdentity();
113
+ if (client.server.url !== identity.authorityUrl ||
114
+ this.principalId !== identity.accountId) {
115
+ throw Object.assign(new Error("Shared engine repository/account does not match this client"), { code: "LIX_SHARED_ENGINE_IDENTITY_MISMATCH" });
116
+ }
117
+ if (branchId !== undefined && branchId !== await this.root.activeBranchId()) {
118
+ throw Object.assign(new Error("The converted replica selected a different branch"), { code: "LIX_PARTIAL_CONVERSION_BRANCH_MISMATCH" });
119
+ }
120
+ // A competing caller already admitted the converted partial store.
121
+ // Never close its live sessions just to repeat an explicit conversion.
122
+ return;
123
+ }
124
+ if (this.state !== "closed")
125
+ throw new HttpTransportError("LIX_OWNER_NOT_CLOSED", "Migration requires a closed storage owner");
126
+ this.state = "migration-exclusive";
127
+ this.clients.add(client);
128
+ try {
129
+ await conversion(this.transport());
130
+ }
131
+ finally {
132
+ this.clients.delete(client);
133
+ this.state = "closed";
134
+ }
135
+ });
136
+ this.queue = operation.catch(() => undefined);
137
+ return operation;
138
+ }
139
+ deactivate(client) {
140
+ this.clients.delete(client);
141
+ }
142
+ async detach(client) {
143
+ const operation = this.queue.then(async () => {
144
+ this.clients.delete(client);
145
+ if (this.clients.size === 0 && this.root) {
146
+ const root = this.root;
147
+ // Keep ownership on a failed close; never open a second engine over it.
148
+ this.state = "closing";
149
+ await root.close();
150
+ this.root = undefined;
151
+ this.principalId = undefined;
152
+ this.state = "closed";
153
+ }
154
+ });
155
+ this.queue = operation.catch(() => undefined);
156
+ await operation;
157
+ }
158
+ transport() {
159
+ const first = this.clients.values().next().value;
160
+ if (!first)
161
+ throw new HttpTransportError("LIX_TRANSPORT_UNAVAILABLE", "No live shared-engine transport");
162
+ return {
163
+ url: first.server.url,
164
+ headers: [],
165
+ transport: async (request) => {
166
+ let unavailable;
167
+ // Credentials and callback remain paired when a tab leaves or suspends.
168
+ for (const client of this.clients) {
169
+ if (client.isDisconnected?.())
170
+ continue;
171
+ const server = client.server;
172
+ let supplied;
173
+ try {
174
+ supplied = (server.headerProvider ? await server.headerProvider() : server.headers).map(([name, value]) => [name, value]);
175
+ }
176
+ catch (error) {
177
+ unavailable = error;
178
+ continue;
179
+ }
180
+ if (!this.clients.has(client) || client.isDisconnected?.())
181
+ continue;
182
+ const headers = new Headers(request.init.headers);
183
+ for (const [name, value] of supplied)
184
+ headers.set(name, value);
185
+ const response = await (server.transport ?? fetchTransport())({ ...request, init: { ...request.init, headers, credentials: "omit" } });
186
+ if (response.status === 401 || response.status === 403)
187
+ await client.rejectCredentials?.(supplied);
188
+ return response;
189
+ }
190
+ throw unavailable ?? new HttpTransportError("LIX_TRANSPORT_UNAVAILABLE", "No verified live shared-engine transport");
191
+ },
192
+ };
193
+ }
194
+ }
package/package.json CHANGED
@@ -1,20 +1,24 @@
1
1
  {
2
2
  "name": "@lix-js/sdk",
3
3
  "type": "module",
4
- "version": "0.16.0",
4
+ "version": "0.17.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/opral/lix"
9
9
  },
10
10
  "exports": {
11
+ "./compatibility": {
12
+ "types": "./dist/compatibility.d.ts",
13
+ "default": "./dist/compatibility.js"
14
+ },
15
+ "./migration": {
16
+ "types": "./dist/migration.d.ts",
17
+ "default": "./dist/migration.js"
18
+ },
11
19
  ".": {
12
20
  "types": "./dist/index.d.ts",
13
21
  "default": "./dist/index.js"
14
- },
15
- "./server-protocol": {
16
- "types": "./dist/remote/server-protocol.d.ts",
17
- "default": "./dist/remote/server-protocol.js"
18
22
  }
19
23
  },
20
24
  "imports": {
@@ -31,17 +35,19 @@
31
35
  "dist"
32
36
  ],
33
37
  "scripts": {
34
- "build": "npm run clean && npm run build:native && npm run build:wasm && npm run build:ts && npm run build:plugins",
35
- "build:browser": "npm run clean && npm run build:wasm && npm run build:ts && npm run build:plugins",
38
+ "build": "npm run clean && npm run build:native && npm run build:migration:native && npm run build:wasm && npm run build:migration:wasm && npm run build:ts && npm run build:plugins",
39
+ "build:browser": "npm run clean && npm run build:wasm && npm run build:migration:wasm && npm run build:ts && npm run build:plugins",
36
40
  "build:native": "node ./scripts/build-native.js",
37
41
  "build:wasm": "node ./scripts/build-wasm.js",
42
+ "build:migration:wasm": "LIX_OFFLINE_MIGRATION=1 node ./scripts/build-wasm.js",
43
+ "build:migration:native": "LIX_OFFLINE_MIGRATION=1 node ./scripts/build-native.js",
38
44
  "build:wasm:dev": "LIX_WASM_PROFILE=dev node ./scripts/build-wasm.js",
39
45
  "build:plugins": "node ./scripts/build-bundled-plugins.js",
40
46
  "benchmark:plugin-reopen": "node ./scripts/benchmark-plugin-reopen.mjs",
41
47
  "benchmark:storage-boundary": "LIX_WASM_STORAGE_BENCH=1 npm run build:browser && LIX_WASM_STORAGE_BENCH=1 vitest run --config vitest.browser.config.ts src/storage-bridge.bench.browser.test.ts",
42
48
  "clean": "node ./scripts/clean.js",
43
49
  "prepare:native-package": "node ./scripts/prepare-native-package.js",
44
- "build:ts": "tsc -p tsconfig.json",
50
+ "build:ts": "tsc -p tsconfig.json && node ./scripts/build-compatibility.js",
45
51
  "test": "npm run build && vitest run",
46
52
  "test:browser": "npm run build:browser && vitest run --config vitest.browser.config.ts",
47
53
  "test:browser:built": "vitest run --config vitest.browser.config.ts",
@@ -49,20 +55,22 @@
49
55
  "typecheck": "tsc -p tsconfig.test.json --noEmit"
50
56
  },
51
57
  "optionalDependencies": {
52
- "@lix-js/sdk-darwin-arm64": "0.16.0",
53
- "@lix-js/sdk-linux-arm64": "0.16.0",
54
- "@lix-js/sdk-linux-x64": "0.16.0",
55
- "@lix-js/sdk-win32-x64": "0.16.0"
58
+ "@lix-js/sdk-darwin-arm64": "0.17.0",
59
+ "@lix-js/sdk-linux-arm64": "0.17.0",
60
+ "@lix-js/sdk-linux-x64": "0.17.0",
61
+ "@lix-js/sdk-win32-x64": "0.17.0"
56
62
  },
57
63
  "devDependencies": {
58
- "@vitest/browser-playwright": "4.1.10",
59
64
  "@types/node": "^24.10.2",
65
+ "@vitest/browser-playwright": "4.1.10",
60
66
  "playwright": "1.57.0",
61
67
  "typescript": "^5.5.4",
62
68
  "vite": "8.1.4",
63
69
  "vitest": "4.1.10"
64
70
  },
65
71
  "dependencies": {
72
+ "@bytecodealliance/jco-transpile": "0.13.0",
73
+ "binaryen": "130.0.0",
66
74
  "fflate": "^0.8.3"
67
75
  }
68
76
  }