@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.
- package/README.md +187 -22
- package/dist/binding-types.d.ts +20 -6
- package/dist/binding.browser.d.ts +2 -0
- package/dist/binding.browser.js +14 -4
- package/dist/binding.node-wasm.d.ts +1 -1
- package/dist/binding.node-wasm.js +5 -3
- package/dist/binding.node.d.ts +2 -0
- package/dist/binding.node.js +34 -8
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
- package/dist/compatibility.d.ts +6 -0
- package/dist/compatibility.js +6 -0
- package/dist/component-host/dispatch.d.ts +12 -0
- package/dist/component-host/dispatch.js +364 -0
- package/dist/component-host/index.d.ts +15 -0
- package/dist/component-host/index.js +84 -0
- package/dist/component-host/instrument.d.ts +6 -0
- package/dist/component-host/instrument.js +260 -0
- package/dist/conversion-provider.d.ts +4 -0
- package/dist/conversion-provider.js +20 -0
- package/dist/hosted-lix.js +1 -1
- package/dist/http-transport.d.ts +25 -0
- package/dist/http-transport.js +162 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/lix.d.ts +20 -10
- package/dist/lix.js +68 -23
- package/dist/migration-binding.browser.d.ts +33 -0
- package/dist/migration-binding.browser.js +46 -0
- package/dist/migration-binding.node.d.ts +6 -0
- package/dist/migration-binding.node.js +5 -0
- package/dist/migration-wasm/lix_js_sdk.d.ts +271 -0
- package/dist/migration-wasm/lix_js_sdk.js +1852 -0
- package/dist/migration-wasm/lix_js_sdk_bg.wasm +4 -0
- package/dist/migration-wasm/lix_js_sdk_bg.wasm.d.ts +101 -0
- package/dist/migration.d.ts +23 -0
- package/dist/migration.js +55 -0
- package/dist/open-lix.js +29 -18
- package/dist/open-progress.d.ts +10 -0
- package/dist/open-progress.js +59 -0
- package/dist/remote/client.d.ts +2 -1
- package/dist/remote/client.js +11 -1
- package/dist/result.d.ts +4 -3
- package/dist/result.js +3 -4
- package/dist/storage-adapter.d.ts +7 -5
- package/dist/storage-ownership.d.ts +5 -0
- package/dist/storage-ownership.js +4 -0
- package/dist/types.d.ts +132 -22
- package/dist/wasm/lix_js_sdk.d.ts +57 -16
- package/dist/wasm/lix_js_sdk.js +268 -60
- package/dist/wasm/lix_js_sdk_bg.wasm +2 -2
- package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +23 -9
- package/dist/worker/client.d.ts +12 -3
- package/dist/worker/client.js +98 -81
- package/dist/worker/durable-local-admission.d.ts +20 -0
- package/dist/worker/durable-local-admission.js +87 -0
- package/dist/worker/entry.shared.browser.d.ts +1 -0
- package/dist/worker/entry.shared.browser.js +211 -0
- package/dist/worker/factory.browser.d.ts +2 -0
- package/dist/worker/factory.browser.js +65 -1
- package/dist/worker/factory.node.d.ts +1 -0
- package/dist/worker/factory.node.js +3 -0
- package/dist/worker/host.d.ts +4 -2
- package/dist/worker/host.js +92 -32
- package/dist/worker/protocol.d.ts +33 -8
- package/dist/worker/protocol.js +25 -7
- package/dist/worker/shared-admission.d.ts +26 -0
- package/dist/worker/shared-admission.js +116 -0
- package/dist/worker/shared-engine.d.ts +34 -0
- package/dist/worker/shared-engine.js +194 -0
- package/package.json +21 -13
- package/dist/remote/server-protocol.d.ts +0 -185
- package/dist/remote/server-protocol.js +0 -417
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import type { BindingExecuteResult, BindingObserveEvent } from "../binding-types.js";
|
|
2
|
-
import type { NativeLixValue } from "../value.js";
|
|
3
|
-
export declare const SERVER_PROTOCOL_VERSION = 7;
|
|
4
|
-
export type WireValue = {
|
|
5
|
-
kind: "null";
|
|
6
|
-
value: null;
|
|
7
|
-
} | {
|
|
8
|
-
kind: "bool";
|
|
9
|
-
value: boolean;
|
|
10
|
-
} | {
|
|
11
|
-
kind: "int";
|
|
12
|
-
value: number;
|
|
13
|
-
} | {
|
|
14
|
-
kind: "float";
|
|
15
|
-
value: number;
|
|
16
|
-
} | {
|
|
17
|
-
kind: "text";
|
|
18
|
-
value: string;
|
|
19
|
-
} | {
|
|
20
|
-
kind: "jsonb";
|
|
21
|
-
value: unknown;
|
|
22
|
-
} | {
|
|
23
|
-
kind: "row_ref";
|
|
24
|
-
value: string;
|
|
25
|
-
} | {
|
|
26
|
-
kind: "timestamptz";
|
|
27
|
-
value: string;
|
|
28
|
-
} | {
|
|
29
|
-
kind: "blob";
|
|
30
|
-
base64: string;
|
|
31
|
-
};
|
|
32
|
-
export type WireRequestBlobSplice = {
|
|
33
|
-
kind: "blob-splice";
|
|
34
|
-
baseSha256: string;
|
|
35
|
-
resultSha256: string;
|
|
36
|
-
prefixBytes: number;
|
|
37
|
-
suffixBytes: number;
|
|
38
|
-
insertBase64: string;
|
|
39
|
-
};
|
|
40
|
-
export type WireRequestValue = WireValue | WireRequestBlobSplice;
|
|
41
|
-
export type ServerProtocolHandshake = {
|
|
42
|
-
protocolVersion: number;
|
|
43
|
-
activeBranchId: string;
|
|
44
|
-
activeAccountId: string;
|
|
45
|
-
sessionId: string;
|
|
46
|
-
};
|
|
47
|
-
export type ServerProtocolHandshakeRequest = {
|
|
48
|
-
activeBranchId?: string;
|
|
49
|
-
};
|
|
50
|
-
export type ServerProtocolExecuteRequest = {
|
|
51
|
-
sql: string;
|
|
52
|
-
params: WireRequestValue[];
|
|
53
|
-
options?: {
|
|
54
|
-
originKey?: string;
|
|
55
|
-
};
|
|
56
|
-
cacheBlobs?: true;
|
|
57
|
-
};
|
|
58
|
-
export type ServerProtocolExecuteBatchRequest = {
|
|
59
|
-
statements: Array<{
|
|
60
|
-
sql: string;
|
|
61
|
-
params: WireRequestValue[];
|
|
62
|
-
label?: string;
|
|
63
|
-
}>;
|
|
64
|
-
options?: {
|
|
65
|
-
originKey?: string;
|
|
66
|
-
};
|
|
67
|
-
cacheBlobs?: true;
|
|
68
|
-
};
|
|
69
|
-
export type ServerProtocolExecuteResponse = {
|
|
70
|
-
columns: BindingExecuteResult["columns"];
|
|
71
|
-
rows: WireValue[][];
|
|
72
|
-
rowsAffected: number;
|
|
73
|
-
notices: Array<{
|
|
74
|
-
code: string;
|
|
75
|
-
message: string;
|
|
76
|
-
hint?: string;
|
|
77
|
-
}>;
|
|
78
|
-
};
|
|
79
|
-
export type ServerProtocolExecuteBatchResponse = ServerProtocolExecuteResponse & {
|
|
80
|
-
statementIndex: number;
|
|
81
|
-
label?: string;
|
|
82
|
-
};
|
|
83
|
-
export type ServerProtocolObserveRequest = {
|
|
84
|
-
sql: string;
|
|
85
|
-
params: WireValue[];
|
|
86
|
-
};
|
|
87
|
-
export type ServerProtocolObserveSubscription = ServerProtocolObserveRequest & {
|
|
88
|
-
id: string;
|
|
89
|
-
};
|
|
90
|
-
export type ServerProtocolMultiplexObserveRequest = {
|
|
91
|
-
subscriptions: ServerProtocolObserveSubscription[];
|
|
92
|
-
};
|
|
93
|
-
type ServerProtocolObserveEventBase = {
|
|
94
|
-
sequence: number;
|
|
95
|
-
mutationSequence: number;
|
|
96
|
-
};
|
|
97
|
-
export type ServerProtocolObserveBlobDelta = {
|
|
98
|
-
kind: "single-blob-splice";
|
|
99
|
-
baseSequence: number;
|
|
100
|
-
prefixBytes: number;
|
|
101
|
-
suffixBytes: number;
|
|
102
|
-
insertBase64: string;
|
|
103
|
-
};
|
|
104
|
-
type ServerProtocolObserveRowSplice = {
|
|
105
|
-
kind: "row-splice";
|
|
106
|
-
baseSequence: number;
|
|
107
|
-
prefixRows: number;
|
|
108
|
-
deleteRows: number;
|
|
109
|
-
insertRows: WireValue[][];
|
|
110
|
-
};
|
|
111
|
-
type ServerProtocolObserveDelta = ServerProtocolObserveBlobDelta | ServerProtocolObserveRowSplice;
|
|
112
|
-
export type ServerProtocolObserveEvent = ServerProtocolObserveEventBase & ({
|
|
113
|
-
result: ServerProtocolExecuteResponse;
|
|
114
|
-
delta?: never;
|
|
115
|
-
} | {
|
|
116
|
-
result?: never;
|
|
117
|
-
delta: ServerProtocolObserveDelta;
|
|
118
|
-
});
|
|
119
|
-
export type ServerProtocolMultiplexObserveEvent = ServerProtocolObserveEvent & {
|
|
120
|
-
subscriptionId: string;
|
|
121
|
-
};
|
|
122
|
-
export type ServerProtocolCreateBranchRequest = {
|
|
123
|
-
id?: string;
|
|
124
|
-
name: string;
|
|
125
|
-
fromCommitId?: string;
|
|
126
|
-
};
|
|
127
|
-
export type ServerProtocolCreateBranchResponse = {
|
|
128
|
-
id: string;
|
|
129
|
-
name: string;
|
|
130
|
-
hidden: boolean;
|
|
131
|
-
commitId: string;
|
|
132
|
-
};
|
|
133
|
-
export type ServerProtocolUndoResponse = {
|
|
134
|
-
branchId: string;
|
|
135
|
-
targetCommitId: string;
|
|
136
|
-
inverseCommitId: string;
|
|
137
|
-
};
|
|
138
|
-
export type ServerProtocolRedoResponse = {
|
|
139
|
-
branchId: string;
|
|
140
|
-
targetCommitId: string;
|
|
141
|
-
replayCommitId: string;
|
|
142
|
-
};
|
|
143
|
-
export type ServerProtocolSwitchBranchRequest = {
|
|
144
|
-
branchId: string;
|
|
145
|
-
};
|
|
146
|
-
export type ServerProtocolSwitchBranchResponse = {
|
|
147
|
-
branchId: string;
|
|
148
|
-
};
|
|
149
|
-
export type ServerProtocolErrorBody = {
|
|
150
|
-
error: {
|
|
151
|
-
code?: string;
|
|
152
|
-
message?: string;
|
|
153
|
-
hint?: string;
|
|
154
|
-
details?: unknown;
|
|
155
|
-
};
|
|
156
|
-
};
|
|
157
|
-
export type ServerProtocolObserveErrorEvent = ServerProtocolErrorBody & {
|
|
158
|
-
retryable?: boolean;
|
|
159
|
-
};
|
|
160
|
-
export type ServerProtocolMultiplexObserveErrorEvent = ServerProtocolObserveErrorEvent & {
|
|
161
|
-
subscriptionId?: string;
|
|
162
|
-
};
|
|
163
|
-
export declare function encodeWireValue(value: NativeLixValue): WireValue;
|
|
164
|
-
export declare function decodeExecuteResult(value: unknown): BindingExecuteResult;
|
|
165
|
-
export declare function decodeExecuteBatchResult(value: unknown): BindingExecuteResult;
|
|
166
|
-
export declare function decodeHandshake(value: unknown): ServerProtocolHandshake;
|
|
167
|
-
export declare function decodeObserveEvent(value: unknown, base?: BindingObserveEvent): BindingObserveEvent;
|
|
168
|
-
export declare function remoteError(code: string, message: string, options?: {
|
|
169
|
-
hint?: string;
|
|
170
|
-
details?: unknown;
|
|
171
|
-
status?: number;
|
|
172
|
-
}): Error & {
|
|
173
|
-
code: string;
|
|
174
|
-
hint?: string;
|
|
175
|
-
details?: unknown;
|
|
176
|
-
status?: number;
|
|
177
|
-
};
|
|
178
|
-
export declare function protocolError(message: string): Error & {
|
|
179
|
-
code: string;
|
|
180
|
-
};
|
|
181
|
-
export declare function errorFromResponseBody(value: unknown, status?: number): Error & {
|
|
182
|
-
code: string;
|
|
183
|
-
};
|
|
184
|
-
export declare function record(value: unknown, description: string): Record<string, unknown>;
|
|
185
|
-
export {};
|
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
export const SERVER_PROTOCOL_VERSION = 7;
|
|
2
|
-
export function encodeWireValue(value) {
|
|
3
|
-
switch (value.kind) {
|
|
4
|
-
case "null":
|
|
5
|
-
return { kind: "null", value: null };
|
|
6
|
-
case "boolean":
|
|
7
|
-
return { kind: "bool", value: value.value };
|
|
8
|
-
case "integer":
|
|
9
|
-
return { kind: "int", value: value.value };
|
|
10
|
-
case "real":
|
|
11
|
-
return { kind: "float", value: value.value };
|
|
12
|
-
case "text":
|
|
13
|
-
return { kind: "text", value: value.value };
|
|
14
|
-
case "jsonb":
|
|
15
|
-
return { kind: "jsonb", value: value.value };
|
|
16
|
-
case "row_ref":
|
|
17
|
-
return { kind: "row_ref", value: value.value };
|
|
18
|
-
case "timestamptz":
|
|
19
|
-
return { kind: "timestamptz", value: value.value };
|
|
20
|
-
case "blob":
|
|
21
|
-
return { kind: "blob", base64: bytesToBase64(value.blob) };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export function decodeExecuteResult(value) {
|
|
25
|
-
const result = record(value, "execute result");
|
|
26
|
-
if (!Array.isArray(result.columns)) {
|
|
27
|
-
throw protocolError("execute result columns must be an array");
|
|
28
|
-
}
|
|
29
|
-
const columns = result.columns.map((column, index) => {
|
|
30
|
-
const item = record(column, `execute result column ${index}`);
|
|
31
|
-
if (typeof item.name !== "string" || !isResultColumnType(item.type)) {
|
|
32
|
-
throw protocolError(`execute result column ${index} requires a string name and valid type`);
|
|
33
|
-
}
|
|
34
|
-
return { name: item.name, type: item.type };
|
|
35
|
-
});
|
|
36
|
-
if (!Array.isArray(result.rows)) {
|
|
37
|
-
throw protocolError("execute result rows must be an array");
|
|
38
|
-
}
|
|
39
|
-
const rows = result.rows.map((row, rowIndex) => {
|
|
40
|
-
if (!Array.isArray(row)) {
|
|
41
|
-
throw protocolError(`execute result row ${rowIndex} must be an array`);
|
|
42
|
-
}
|
|
43
|
-
if (row.length !== columns.length) {
|
|
44
|
-
throw protocolError(`execute result row ${rowIndex} has ${row.length} values for ${columns.length} columns`);
|
|
45
|
-
}
|
|
46
|
-
return row.map((entry, columnIndex) => {
|
|
47
|
-
const decoded = decodeWireValue(entry);
|
|
48
|
-
const declaredType = columns[columnIndex]?.type;
|
|
49
|
-
if (decoded.kind !== "null" && decoded.kind !== declaredType) {
|
|
50
|
-
throw protocolError(`execute result row ${rowIndex} column ${columnIndex} declares ${String(declaredType)} but contains ${decoded.kind}`);
|
|
51
|
-
}
|
|
52
|
-
return decoded;
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
if (typeof result.rowsAffected !== "number" ||
|
|
56
|
-
!Number.isSafeInteger(result.rowsAffected) ||
|
|
57
|
-
result.rowsAffected < 0) {
|
|
58
|
-
throw protocolError("execute result rowsAffected must be a non-negative safe integer");
|
|
59
|
-
}
|
|
60
|
-
if (!Array.isArray(result.notices)) {
|
|
61
|
-
throw protocolError("execute result notices must be an array");
|
|
62
|
-
}
|
|
63
|
-
const notices = result.notices.map((notice, index) => {
|
|
64
|
-
const item = record(notice, `execute result notice ${index}`);
|
|
65
|
-
if (typeof item.code !== "string" || typeof item.message !== "string") {
|
|
66
|
-
throw protocolError(`execute result notice ${index} requires code and message`);
|
|
67
|
-
}
|
|
68
|
-
if (item.hint !== undefined && typeof item.hint !== "string") {
|
|
69
|
-
throw protocolError(`execute result notice ${index} hint must be a string`);
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
code: item.code,
|
|
73
|
-
message: item.message,
|
|
74
|
-
...(item.hint === undefined ? {} : { hint: item.hint }),
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
return { columns, rows, rowsAffected: result.rowsAffected, notices };
|
|
78
|
-
}
|
|
79
|
-
function isResultColumnType(value) {
|
|
80
|
-
return (value === "null" ||
|
|
81
|
-
value === "boolean" ||
|
|
82
|
-
value === "integer" ||
|
|
83
|
-
value === "real" ||
|
|
84
|
-
value === "text" ||
|
|
85
|
-
value === "jsonb" ||
|
|
86
|
-
value === "row_ref" ||
|
|
87
|
-
value === "timestamptz" ||
|
|
88
|
-
value === "blob");
|
|
89
|
-
}
|
|
90
|
-
export function decodeExecuteBatchResult(value) {
|
|
91
|
-
const result = record(value, "execute batch result");
|
|
92
|
-
const statementIndex = nonNegativeSafeInteger(result.statementIndex, "execute batch result statementIndex");
|
|
93
|
-
if (result.label !== undefined && typeof result.label !== "string") {
|
|
94
|
-
throw protocolError("execute batch result label must be a string when present");
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
...decodeExecuteResult(value),
|
|
98
|
-
statementIndex,
|
|
99
|
-
...(result.label === undefined ? {} : { label: result.label }),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
export function decodeHandshake(value) {
|
|
103
|
-
const handshake = record(value, "Lix Server Protocol handshake");
|
|
104
|
-
if (handshake.protocolVersion !== SERVER_PROTOCOL_VERSION) {
|
|
105
|
-
throw protocolError(`unsupported Lix Server Protocol version: ${String(handshake.protocolVersion)}`);
|
|
106
|
-
}
|
|
107
|
-
if (typeof handshake.activeBranchId !== "string" ||
|
|
108
|
-
handshake.activeBranchId.length === 0) {
|
|
109
|
-
throw protocolError("Lix Server Protocol handshake requires activeBranchId");
|
|
110
|
-
}
|
|
111
|
-
if (typeof handshake.activeAccountId !== "string" ||
|
|
112
|
-
handshake.activeAccountId.length === 0) {
|
|
113
|
-
throw protocolError("Lix Server Protocol handshake requires activeAccountId");
|
|
114
|
-
}
|
|
115
|
-
if (typeof handshake.sessionId !== "string" ||
|
|
116
|
-
!/^[\x21-\x7e]{1,256}$/.test(handshake.sessionId)) {
|
|
117
|
-
throw protocolError("Lix Server Protocol handshake requires a valid sessionId");
|
|
118
|
-
}
|
|
119
|
-
return {
|
|
120
|
-
protocolVersion: SERVER_PROTOCOL_VERSION,
|
|
121
|
-
activeBranchId: handshake.activeBranchId,
|
|
122
|
-
activeAccountId: handshake.activeAccountId,
|
|
123
|
-
sessionId: handshake.sessionId,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
export function decodeObserveEvent(value, base) {
|
|
127
|
-
const event = record(value, "observe event");
|
|
128
|
-
if (typeof event.sequence !== "number" ||
|
|
129
|
-
!Number.isSafeInteger(event.sequence) ||
|
|
130
|
-
event.sequence < 0) {
|
|
131
|
-
throw protocolError("observe event sequence must be a non-negative safe integer");
|
|
132
|
-
}
|
|
133
|
-
if (typeof event.mutationSequence !== "number" ||
|
|
134
|
-
!Number.isSafeInteger(event.mutationSequence) ||
|
|
135
|
-
event.mutationSequence < 0) {
|
|
136
|
-
throw protocolError("observe event mutationSequence must be a non-negative safe integer");
|
|
137
|
-
}
|
|
138
|
-
const hasResult = event.result !== undefined;
|
|
139
|
-
const hasDelta = event.delta !== undefined;
|
|
140
|
-
if (hasResult === hasDelta) {
|
|
141
|
-
throw protocolError("observe event requires exactly one of result or delta");
|
|
142
|
-
}
|
|
143
|
-
const sequence = event.sequence;
|
|
144
|
-
return {
|
|
145
|
-
sequence,
|
|
146
|
-
mutationSequence: event.mutationSequence,
|
|
147
|
-
rows: hasResult
|
|
148
|
-
? decodeExecuteResult(event.result)
|
|
149
|
-
: applyObserveDelta(event.delta, sequence, base),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
function applyObserveDelta(value, sequence, base) {
|
|
153
|
-
const delta = record(value, "observe event delta");
|
|
154
|
-
switch (delta.kind) {
|
|
155
|
-
case "single-blob-splice":
|
|
156
|
-
return applyObserveBlobDelta(delta, sequence, base);
|
|
157
|
-
case "row-splice":
|
|
158
|
-
return applyObserveRowSplice(delta, sequence, base);
|
|
159
|
-
default:
|
|
160
|
-
throw protocolError(`unknown observe delta kind: ${String(delta.kind)}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
function applyObserveBlobDelta(delta, sequence, base) {
|
|
164
|
-
const baseSequence = nonNegativeSafeInteger(delta.baseSequence, "observe delta baseSequence");
|
|
165
|
-
const prefixBytes = nonNegativeSafeInteger(delta.prefixBytes, "observe delta prefixBytes");
|
|
166
|
-
const suffixBytes = nonNegativeSafeInteger(delta.suffixBytes, "observe delta suffixBytes");
|
|
167
|
-
if (typeof delta.insertBase64 !== "string") {
|
|
168
|
-
throw protocolError("observe delta insertBase64 must be a string");
|
|
169
|
-
}
|
|
170
|
-
if (base === undefined ||
|
|
171
|
-
base.sequence !== baseSequence ||
|
|
172
|
-
sequence !== baseSequence + 1) {
|
|
173
|
-
throw protocolError("observe blob delta does not match its transport base");
|
|
174
|
-
}
|
|
175
|
-
const baseValue = base.rows.rows[0]?.[0];
|
|
176
|
-
if (base.rows.columns.length !== 1 ||
|
|
177
|
-
base.rows.columns[0]?.name !== "content" ||
|
|
178
|
-
base.rows.columns[0]?.type !== "blob" ||
|
|
179
|
-
base.rows.rows.length !== 1 ||
|
|
180
|
-
base.rows.rows[0]?.length !== 1 ||
|
|
181
|
-
base.rows.rowsAffected !== 0 ||
|
|
182
|
-
base.rows.notices.length !== 0 ||
|
|
183
|
-
baseValue?.kind !== "blob") {
|
|
184
|
-
throw protocolError("observe blob delta base is not a point blob result");
|
|
185
|
-
}
|
|
186
|
-
if (prefixBytes + suffixBytes > baseValue.blob.byteLength) {
|
|
187
|
-
throw protocolError("observe blob delta prefix and suffix overlap");
|
|
188
|
-
}
|
|
189
|
-
const insert = base64ToBytes(delta.insertBase64);
|
|
190
|
-
const nextLength = prefixBytes + insert.byteLength + suffixBytes;
|
|
191
|
-
if (!Number.isSafeInteger(nextLength)) {
|
|
192
|
-
throw protocolError("observe blob delta result is too large");
|
|
193
|
-
}
|
|
194
|
-
let blob;
|
|
195
|
-
try {
|
|
196
|
-
blob = new Uint8Array(nextLength);
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
throw protocolError("observe blob delta result is too large");
|
|
200
|
-
}
|
|
201
|
-
blob.set(baseValue.blob.subarray(0, prefixBytes), 0);
|
|
202
|
-
blob.set(insert, prefixBytes);
|
|
203
|
-
blob.set(baseValue.blob.subarray(baseValue.blob.byteLength - suffixBytes), prefixBytes + insert.byteLength);
|
|
204
|
-
return {
|
|
205
|
-
columns: [{ name: "content", type: "blob" }],
|
|
206
|
-
rows: [[{ kind: "blob", value: null, blob }]],
|
|
207
|
-
rowsAffected: 0,
|
|
208
|
-
notices: [],
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
function applyObserveRowSplice(delta, sequence, base) {
|
|
212
|
-
const baseSequence = nonNegativeSafeInteger(delta.baseSequence, "observe row delta baseSequence");
|
|
213
|
-
const prefixRows = nonNegativeSafeInteger(delta.prefixRows, "observe row delta prefixRows");
|
|
214
|
-
const deleteRows = nonNegativeSafeInteger(delta.deleteRows, "observe row delta deleteRows");
|
|
215
|
-
if (base === undefined ||
|
|
216
|
-
base.sequence !== baseSequence ||
|
|
217
|
-
sequence !== baseSequence + 1) {
|
|
218
|
-
throw protocolError("observe row delta does not match its transport base");
|
|
219
|
-
}
|
|
220
|
-
if (!Array.isArray(delta.insertRows)) {
|
|
221
|
-
throw protocolError("observe row delta insertRows must be an array");
|
|
222
|
-
}
|
|
223
|
-
if (prefixRows > base.rows.rows.length ||
|
|
224
|
-
deleteRows > base.rows.rows.length - prefixRows) {
|
|
225
|
-
throw protocolError("observe row delta splice range is outside its transport base");
|
|
226
|
-
}
|
|
227
|
-
const suffixStart = prefixRows + deleteRows;
|
|
228
|
-
const nextRowCount = prefixRows + delta.insertRows.length + (base.rows.rows.length - suffixStart);
|
|
229
|
-
if (!Number.isSafeInteger(nextRowCount) ||
|
|
230
|
-
nextRowCount > 0xffff_ffff) {
|
|
231
|
-
throw protocolError("observe row delta result is too large");
|
|
232
|
-
}
|
|
233
|
-
let rows;
|
|
234
|
-
try {
|
|
235
|
-
rows = new Array(nextRowCount);
|
|
236
|
-
}
|
|
237
|
-
catch {
|
|
238
|
-
throw protocolError("observe row delta result is too large");
|
|
239
|
-
}
|
|
240
|
-
let destination = 0;
|
|
241
|
-
for (let index = 0; index < prefixRows; index += 1) {
|
|
242
|
-
rows[destination++] = base.rows.rows[index];
|
|
243
|
-
}
|
|
244
|
-
for (let rowIndex = 0; rowIndex < delta.insertRows.length; rowIndex += 1) {
|
|
245
|
-
const row = delta.insertRows[rowIndex];
|
|
246
|
-
if (!Array.isArray(row)) {
|
|
247
|
-
throw protocolError(`observe row delta insert row ${rowIndex} must be an array`);
|
|
248
|
-
}
|
|
249
|
-
if (row.length !== base.rows.columns.length) {
|
|
250
|
-
throw protocolError(`observe row delta insert row ${rowIndex} has ${row.length} values for ${base.rows.columns.length} columns`);
|
|
251
|
-
}
|
|
252
|
-
rows[destination++] = row.map((entry) => decodeWireValue(entry));
|
|
253
|
-
}
|
|
254
|
-
for (let index = suffixStart; index < base.rows.rows.length; index += 1) {
|
|
255
|
-
rows[destination++] = base.rows.rows[index];
|
|
256
|
-
}
|
|
257
|
-
return {
|
|
258
|
-
columns: [...base.rows.columns],
|
|
259
|
-
rows,
|
|
260
|
-
rowsAffected: base.rows.rowsAffected,
|
|
261
|
-
notices: base.rows.notices.map((notice) => ({ ...notice })),
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
export function remoteError(code, message, options = {}) {
|
|
265
|
-
const error = new Error(message);
|
|
266
|
-
error.name = "LixError";
|
|
267
|
-
error.code = code;
|
|
268
|
-
error.hint = options.hint;
|
|
269
|
-
error.details = options.details;
|
|
270
|
-
error.status = options.status;
|
|
271
|
-
return error;
|
|
272
|
-
}
|
|
273
|
-
export function protocolError(message) {
|
|
274
|
-
return remoteError("LIX_SERVER_PROTOCOL_ERROR", message);
|
|
275
|
-
}
|
|
276
|
-
export function errorFromResponseBody(value, status) {
|
|
277
|
-
const body = record(value, "Lix Server Protocol error response");
|
|
278
|
-
const rawError = record(body.error, "Lix Server Protocol error response error");
|
|
279
|
-
return remoteError(typeof rawError.code === "string"
|
|
280
|
-
? rawError.code
|
|
281
|
-
: "LIX_REMOTE_REQUEST_FAILED", typeof rawError.message === "string"
|
|
282
|
-
? rawError.message
|
|
283
|
-
: status === undefined
|
|
284
|
-
? "Remote Lix operation failed"
|
|
285
|
-
: `Remote Lix request failed with status ${status}`, {
|
|
286
|
-
hint: typeof rawError.hint === "string" ? rawError.hint : undefined,
|
|
287
|
-
details: rawError.details,
|
|
288
|
-
status,
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
export function record(value, description) {
|
|
292
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
293
|
-
throw protocolError(`${description} must be an object`);
|
|
294
|
-
}
|
|
295
|
-
return value;
|
|
296
|
-
}
|
|
297
|
-
function decodeWireValue(value) {
|
|
298
|
-
const wire = record(value, "wire value");
|
|
299
|
-
switch (wire.kind) {
|
|
300
|
-
case "null":
|
|
301
|
-
if (wire.value !== null)
|
|
302
|
-
throw protocolError("null wire value is invalid");
|
|
303
|
-
return { kind: "null", value: null };
|
|
304
|
-
case "bool":
|
|
305
|
-
if (typeof wire.value !== "boolean") {
|
|
306
|
-
throw protocolError("bool wire value is invalid");
|
|
307
|
-
}
|
|
308
|
-
return { kind: "boolean", value: wire.value };
|
|
309
|
-
case "int":
|
|
310
|
-
if (typeof wire.value !== "number" || !Number.isSafeInteger(wire.value)) {
|
|
311
|
-
throw protocolError("int wire value is invalid");
|
|
312
|
-
}
|
|
313
|
-
return { kind: "integer", value: wire.value };
|
|
314
|
-
case "float":
|
|
315
|
-
if (typeof wire.value !== "number" || !Number.isFinite(wire.value)) {
|
|
316
|
-
throw protocolError("float wire value is invalid");
|
|
317
|
-
}
|
|
318
|
-
return { kind: "real", value: wire.value };
|
|
319
|
-
case "text":
|
|
320
|
-
if (typeof wire.value !== "string") {
|
|
321
|
-
throw protocolError("text wire value is invalid");
|
|
322
|
-
}
|
|
323
|
-
return { kind: "text", value: wire.value };
|
|
324
|
-
case "jsonb":
|
|
325
|
-
assertJsonValue(wire.value, "jsonb wire value");
|
|
326
|
-
return { kind: "jsonb", value: wire.value };
|
|
327
|
-
case "row_ref":
|
|
328
|
-
if (typeof wire.value !== "string") {
|
|
329
|
-
throw protocolError("row_ref wire value is invalid");
|
|
330
|
-
}
|
|
331
|
-
return { kind: "row_ref", value: wire.value };
|
|
332
|
-
case "timestamptz":
|
|
333
|
-
if (typeof wire.value !== "string") {
|
|
334
|
-
throw protocolError("timestamptz wire value is invalid");
|
|
335
|
-
}
|
|
336
|
-
return { kind: "timestamptz", value: wire.value };
|
|
337
|
-
case "blob":
|
|
338
|
-
if (typeof wire.base64 !== "string") {
|
|
339
|
-
throw protocolError("blob wire value is invalid");
|
|
340
|
-
}
|
|
341
|
-
return { kind: "blob", value: null, blob: base64ToBytes(wire.base64) };
|
|
342
|
-
default:
|
|
343
|
-
throw protocolError(`unknown wire value kind: ${String(wire.kind)}`);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
function stringArray(value, description) {
|
|
347
|
-
if (!Array.isArray(value) ||
|
|
348
|
-
!value.every((entry) => typeof entry === "string")) {
|
|
349
|
-
throw protocolError(`${description} must be an array of strings`);
|
|
350
|
-
}
|
|
351
|
-
return [...value];
|
|
352
|
-
}
|
|
353
|
-
function nonNegativeSafeInteger(value, description) {
|
|
354
|
-
if (typeof value !== "number" ||
|
|
355
|
-
!Number.isSafeInteger(value) ||
|
|
356
|
-
value < 0) {
|
|
357
|
-
throw protocolError(`${description} must be a non-negative safe integer`);
|
|
358
|
-
}
|
|
359
|
-
return value;
|
|
360
|
-
}
|
|
361
|
-
function assertJsonValue(value, description) {
|
|
362
|
-
if (value === null ||
|
|
363
|
-
typeof value === "boolean" ||
|
|
364
|
-
(typeof value === "number" &&
|
|
365
|
-
Number.isFinite(value) &&
|
|
366
|
-
(!Number.isInteger(value) || Number.isSafeInteger(value))) ||
|
|
367
|
-
(typeof value === "string" && value.isWellFormed())) {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
if (Array.isArray(value)) {
|
|
371
|
-
for (const entry of value)
|
|
372
|
-
assertJsonValue(entry, description);
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
if (value && typeof value === "object") {
|
|
376
|
-
for (const entry of Object.values(value)) {
|
|
377
|
-
assertJsonValue(entry, description);
|
|
378
|
-
}
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
throw protocolError(`${description} is not valid Lix JSON`);
|
|
382
|
-
}
|
|
383
|
-
function bytesToBase64(bytes) {
|
|
384
|
-
const nativeToBase64 = bytes.toBase64;
|
|
385
|
-
if (typeof nativeToBase64 === "function") {
|
|
386
|
-
return nativeToBase64.call(bytes);
|
|
387
|
-
}
|
|
388
|
-
let binary = "";
|
|
389
|
-
const chunkSize = 0x8000;
|
|
390
|
-
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
391
|
-
binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
|
|
392
|
-
}
|
|
393
|
-
return btoa(binary);
|
|
394
|
-
}
|
|
395
|
-
function base64ToBytes(base64) {
|
|
396
|
-
const nativeFromBase64 = Uint8Array.fromBase64;
|
|
397
|
-
if (typeof nativeFromBase64 === "function") {
|
|
398
|
-
try {
|
|
399
|
-
return nativeFromBase64(base64);
|
|
400
|
-
}
|
|
401
|
-
catch {
|
|
402
|
-
throw protocolError("blob wire value contains invalid base64");
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
let binary;
|
|
406
|
-
try {
|
|
407
|
-
binary = atob(base64);
|
|
408
|
-
}
|
|
409
|
-
catch {
|
|
410
|
-
throw protocolError("blob wire value contains invalid base64");
|
|
411
|
-
}
|
|
412
|
-
const bytes = new Uint8Array(binary.length);
|
|
413
|
-
for (let index = 0; index < binary.length; index += 1) {
|
|
414
|
-
bytes[index] = binary.charCodeAt(index);
|
|
415
|
-
}
|
|
416
|
-
return bytes;
|
|
417
|
-
}
|