@s2-dev/streamstore 0.16.12 → 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/dist/cjs/basin.d.ts +6 -2
- package/dist/cjs/basin.d.ts.map +1 -1
- package/dist/cjs/basin.js +11 -5
- package/dist/cjs/basin.js.map +1 -1
- package/dist/cjs/batch-transform.d.ts +64 -0
- package/dist/cjs/batch-transform.d.ts.map +1 -0
- package/dist/cjs/batch-transform.js +144 -0
- package/dist/cjs/batch-transform.js.map +1 -0
- package/dist/cjs/generated/proto/s2.d.ts.map +1 -0
- package/dist/cjs/generated/proto/s2.js.map +1 -0
- package/dist/cjs/index.d.ts +4 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/stream/factory.d.ts +15 -0
- package/dist/cjs/lib/stream/factory.d.ts.map +1 -0
- package/dist/cjs/lib/stream/factory.js +36 -0
- package/dist/cjs/lib/stream/factory.js.map +1 -0
- package/dist/cjs/lib/stream/runtime.d.ts +13 -0
- package/dist/cjs/lib/stream/runtime.d.ts.map +1 -0
- package/dist/cjs/lib/stream/runtime.js +50 -0
- package/dist/cjs/lib/stream/runtime.js.map +1 -0
- package/dist/cjs/lib/stream/transport/fetch/index.d.ts +79 -0
- package/dist/cjs/lib/stream/transport/fetch/index.d.ts.map +1 -0
- package/dist/cjs/lib/stream/transport/fetch/index.js +382 -0
- package/dist/cjs/lib/stream/transport/fetch/index.js.map +1 -0
- package/dist/cjs/lib/stream/transport/fetch/shared.d.ts +7 -0
- package/dist/cjs/lib/stream/transport/fetch/shared.d.ts.map +1 -0
- package/dist/cjs/lib/stream/transport/fetch/shared.js +170 -0
- package/dist/cjs/lib/stream/transport/fetch/shared.js.map +1 -0
- package/dist/cjs/lib/stream/transport/s2s/framing.d.ts +47 -0
- package/dist/cjs/lib/stream/transport/s2s/framing.d.ts.map +1 -0
- package/dist/cjs/lib/stream/transport/s2s/framing.js +123 -0
- package/dist/cjs/lib/stream/transport/s2s/framing.js.map +1 -0
- package/dist/cjs/lib/stream/transport/s2s/index.d.ts +23 -0
- package/dist/cjs/lib/stream/transport/s2s/index.d.ts.map +1 -0
- package/dist/cjs/lib/stream/transport/s2s/index.js +785 -0
- package/dist/cjs/lib/stream/transport/s2s/index.js.map +1 -0
- package/dist/cjs/lib/stream/types.d.ts +53 -0
- package/dist/cjs/lib/stream/types.d.ts.map +1 -0
- package/dist/cjs/lib/stream/types.js +3 -0
- package/dist/cjs/lib/stream/types.js.map +1 -0
- package/dist/cjs/stream.d.ts +22 -116
- package/dist/cjs/stream.d.ts.map +1 -1
- package/dist/cjs/stream.js +35 -551
- package/dist/cjs/stream.js.map +1 -1
- package/dist/cjs/utils.d.ts +32 -6
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +129 -34
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/basin.d.ts +6 -2
- package/dist/esm/basin.d.ts.map +1 -1
- package/dist/esm/basin.js +11 -5
- package/dist/esm/basin.js.map +1 -1
- package/dist/esm/batch-transform.d.ts +64 -0
- package/dist/esm/batch-transform.d.ts.map +1 -0
- package/dist/esm/batch-transform.js +140 -0
- package/dist/esm/batch-transform.js.map +1 -0
- package/dist/esm/generated/proto/s2.d.ts.map +1 -0
- package/dist/esm/generated/proto/s2.js.map +1 -0
- package/dist/esm/index.d.ts +4 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/stream/factory.d.ts +15 -0
- package/dist/esm/lib/stream/factory.d.ts.map +1 -0
- package/dist/esm/lib/stream/factory.js +33 -0
- package/dist/esm/lib/stream/factory.js.map +1 -0
- package/dist/esm/lib/stream/runtime.d.ts +13 -0
- package/dist/esm/lib/stream/runtime.d.ts.map +1 -0
- package/dist/esm/lib/stream/runtime.js +46 -0
- package/dist/esm/lib/stream/runtime.js.map +1 -0
- package/dist/esm/lib/stream/transport/fetch/index.d.ts +79 -0
- package/dist/esm/lib/stream/transport/fetch/index.d.ts.map +1 -0
- package/dist/esm/lib/stream/transport/fetch/index.js +376 -0
- package/dist/esm/lib/stream/transport/fetch/index.js.map +1 -0
- package/dist/esm/lib/stream/transport/fetch/shared.d.ts +7 -0
- package/dist/esm/lib/stream/transport/fetch/shared.d.ts.map +1 -0
- package/dist/esm/lib/stream/transport/fetch/shared.js +166 -0
- package/dist/esm/lib/stream/transport/fetch/shared.js.map +1 -0
- package/dist/esm/lib/stream/transport/s2s/framing.d.ts +47 -0
- package/dist/esm/lib/stream/transport/s2s/framing.d.ts.map +1 -0
- package/dist/esm/lib/stream/transport/s2s/framing.js +118 -0
- package/dist/esm/lib/stream/transport/s2s/framing.js.map +1 -0
- package/dist/esm/lib/stream/transport/s2s/index.d.ts +23 -0
- package/dist/esm/lib/stream/transport/s2s/index.d.ts.map +1 -0
- package/dist/esm/lib/stream/transport/s2s/index.js +781 -0
- package/dist/esm/lib/stream/transport/s2s/index.js.map +1 -0
- package/dist/esm/lib/stream/types.d.ts +53 -0
- package/dist/esm/lib/stream/types.d.ts.map +1 -0
- package/dist/esm/lib/stream/types.js +2 -0
- package/dist/esm/lib/stream/types.js.map +1 -0
- package/dist/esm/stream.d.ts +22 -116
- package/dist/esm/stream.d.ts.map +1 -1
- package/dist/esm/stream.js +36 -551
- package/dist/esm/stream.js.map +1 -1
- package/dist/esm/utils.d.ts +32 -6
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +126 -34
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/dist/cjs/generated/proto/s2/v1/s2.d.ts.map +0 -1
- package/dist/cjs/generated/proto/s2/v1/s2.js.map +0 -1
- package/dist/esm/generated/proto/s2/v1/s2.d.ts.map +0 -1
- package/dist/esm/generated/proto/s2/v1/s2.js.map +0 -1
- /package/dist/cjs/generated/proto/{s2/v1/s2.d.ts → s2.d.ts} +0 -0
- /package/dist/cjs/generated/proto/{s2/v1/s2.js → s2.js} +0 -0
- /package/dist/esm/generated/proto/{s2/v1/s2.d.ts → s2.d.ts} +0 -0
- /package/dist/esm/generated/proto/{s2/v1/s2.js → s2.js} +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { FencingTokenMismatchError, RangeNotSatisfiableError, S2Error, SeqNumMismatchError, } from "../../../../error.js";
|
|
2
|
+
import { append, checkTail, read, } from "../../../../generated/index.js";
|
|
3
|
+
import { computeAppendRecordFormat, meteredSizeBytes, } from "../../../../utils.js";
|
|
4
|
+
import { decodeFromBase64, encodeToBase64 } from "../../../base64.js";
|
|
5
|
+
export async function streamRead(stream, client, args, options) {
|
|
6
|
+
const { as, ...queryParams } = args ?? {};
|
|
7
|
+
const response = await read({
|
|
8
|
+
client,
|
|
9
|
+
path: {
|
|
10
|
+
stream,
|
|
11
|
+
},
|
|
12
|
+
headers: {
|
|
13
|
+
...(as === "bytes" ? { "s2-format": "base64" } : {}),
|
|
14
|
+
},
|
|
15
|
+
query: queryParams,
|
|
16
|
+
...options,
|
|
17
|
+
});
|
|
18
|
+
if (response.error) {
|
|
19
|
+
if ("message" in response.error) {
|
|
20
|
+
throw new S2Error({
|
|
21
|
+
message: response.error.message,
|
|
22
|
+
code: response.error.code ?? undefined,
|
|
23
|
+
status: response.response.status,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// special case for 416 - Range Not Satisfiable
|
|
28
|
+
throw new RangeNotSatisfiableError({
|
|
29
|
+
status: response.response.status,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (args?.as === "bytes") {
|
|
34
|
+
const res = {
|
|
35
|
+
...response.data,
|
|
36
|
+
records: response.data.records?.map((record) => ({
|
|
37
|
+
...record,
|
|
38
|
+
body: record.body ? decodeFromBase64(record.body) : undefined,
|
|
39
|
+
headers: record.headers?.map((header) => header.map((h) => decodeFromBase64(h))),
|
|
40
|
+
})),
|
|
41
|
+
};
|
|
42
|
+
return res;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const res = {
|
|
46
|
+
...response.data,
|
|
47
|
+
records: response.data.records.map((record) => ({
|
|
48
|
+
...record,
|
|
49
|
+
headers: record.headers
|
|
50
|
+
? Object.fromEntries(record.headers)
|
|
51
|
+
: undefined,
|
|
52
|
+
})),
|
|
53
|
+
};
|
|
54
|
+
return res;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function streamAppend(stream, client, records, args, options) {
|
|
58
|
+
const recordsArray = Array.isArray(records) ? records : [records];
|
|
59
|
+
if (recordsArray.length === 0) {
|
|
60
|
+
throw new S2Error({ message: "Cannot append empty array of records" });
|
|
61
|
+
}
|
|
62
|
+
let batchMeteredSize = 0;
|
|
63
|
+
for (const record of recordsArray) {
|
|
64
|
+
batchMeteredSize += meteredSizeBytes(record);
|
|
65
|
+
}
|
|
66
|
+
if (batchMeteredSize > 1024 * 1024) {
|
|
67
|
+
throw new S2Error({
|
|
68
|
+
message: `Batch size ${batchMeteredSize} bytes exceeds maximum of 1 MiB (1048576 bytes)`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (recordsArray.length > 1000) {
|
|
72
|
+
throw new S2Error({
|
|
73
|
+
message: `Batch of ${recordsArray.length} exceeds maximum batch size of 1000 records`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
let encodedRecords = [];
|
|
77
|
+
let hasAnyBytesRecords = false;
|
|
78
|
+
for (const record of recordsArray) {
|
|
79
|
+
const format = computeAppendRecordFormat(record);
|
|
80
|
+
if (format === "bytes") {
|
|
81
|
+
const formattedRecord = record;
|
|
82
|
+
const encodedRecord = {
|
|
83
|
+
...formattedRecord,
|
|
84
|
+
body: formattedRecord.body
|
|
85
|
+
? encodeToBase64(formattedRecord.body)
|
|
86
|
+
: undefined,
|
|
87
|
+
headers: formattedRecord.headers?.map((header) => header.map((h) => encodeToBase64(h))),
|
|
88
|
+
};
|
|
89
|
+
encodedRecords.push(encodedRecord);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Normalize headers to array format
|
|
93
|
+
const normalizeHeaders = (headers) => {
|
|
94
|
+
if (headers === undefined) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
else if (Array.isArray(headers)) {
|
|
98
|
+
return headers;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return Object.entries(headers);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const formattedRecord = record;
|
|
105
|
+
const encodedRecord = {
|
|
106
|
+
...formattedRecord,
|
|
107
|
+
headers: formattedRecord.headers
|
|
108
|
+
? normalizeHeaders(formattedRecord.headers)
|
|
109
|
+
: undefined,
|
|
110
|
+
};
|
|
111
|
+
encodedRecords.push(encodedRecord);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const response = await append({
|
|
115
|
+
client,
|
|
116
|
+
path: {
|
|
117
|
+
stream,
|
|
118
|
+
},
|
|
119
|
+
body: {
|
|
120
|
+
fencing_token: args?.fencing_token,
|
|
121
|
+
match_seq_num: args?.match_seq_num,
|
|
122
|
+
records: encodedRecords,
|
|
123
|
+
},
|
|
124
|
+
headers: {
|
|
125
|
+
...(hasAnyBytesRecords ? { "s2-format": "base64" } : {}),
|
|
126
|
+
},
|
|
127
|
+
...options,
|
|
128
|
+
});
|
|
129
|
+
if (response.error) {
|
|
130
|
+
if ("message" in response.error) {
|
|
131
|
+
throw new S2Error({
|
|
132
|
+
message: response.error.message,
|
|
133
|
+
code: response.error.code ?? undefined,
|
|
134
|
+
status: response.response.status,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// special case for 412 - append condition failed
|
|
139
|
+
if ("seq_num_mismatch" in response.error) {
|
|
140
|
+
throw new SeqNumMismatchError({
|
|
141
|
+
message: "Append condition failed: sequence number mismatch",
|
|
142
|
+
code: "APPEND_CONDITION_FAILED",
|
|
143
|
+
status: response.response.status,
|
|
144
|
+
expectedSeqNum: response.error.seq_num_mismatch,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else if ("fencing_token_mismatch" in response.error) {
|
|
148
|
+
throw new FencingTokenMismatchError({
|
|
149
|
+
message: "Append condition failed: fencing token mismatch",
|
|
150
|
+
code: "APPEND_CONDITION_FAILED",
|
|
151
|
+
status: response.response.status,
|
|
152
|
+
expectedFencingToken: response.error.fencing_token_mismatch,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// fallback for unknown 412 error format
|
|
157
|
+
throw new S2Error({
|
|
158
|
+
message: "Append condition failed",
|
|
159
|
+
status: response.response.status,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return response.data;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../../../src/lib/stream/transport/fetch/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S2S Protocol Message Framing
|
|
3
|
+
*
|
|
4
|
+
* Message format:
|
|
5
|
+
* - 3 bytes: Length prefix (total message length including flag byte, big-endian)
|
|
6
|
+
* - 1 byte: Flag byte [T][CC][RRRRR]
|
|
7
|
+
* - T (bit 7): Terminal flag (1 = stream ends after this message)
|
|
8
|
+
* - CC (bits 6-5): Compression (00=none, 01=zstd, 10=gzip)
|
|
9
|
+
* - RRRRR (bits 4-0): Reserved
|
|
10
|
+
* - Variable: Body (protobuf message or JSON error for terminal frames)
|
|
11
|
+
*/
|
|
12
|
+
export type CompressionType = "none" | "zstd" | "gzip";
|
|
13
|
+
export interface S2SFrame {
|
|
14
|
+
terminal: boolean;
|
|
15
|
+
compression: CompressionType;
|
|
16
|
+
body: Uint8Array;
|
|
17
|
+
statusCode?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Frame a message for s2s protocol
|
|
21
|
+
*/
|
|
22
|
+
export declare function frameMessage(opts: {
|
|
23
|
+
terminal: boolean;
|
|
24
|
+
compression?: CompressionType;
|
|
25
|
+
body: Uint8Array;
|
|
26
|
+
statusCode?: number;
|
|
27
|
+
}): Uint8Array;
|
|
28
|
+
/**
|
|
29
|
+
* Parser for reading s2s frames from a stream
|
|
30
|
+
*/
|
|
31
|
+
export declare class S2SFrameParser {
|
|
32
|
+
private buffer;
|
|
33
|
+
/**
|
|
34
|
+
* Add data to the parser buffer
|
|
35
|
+
*/
|
|
36
|
+
push(data: Uint8Array): void;
|
|
37
|
+
/**
|
|
38
|
+
* Try to parse the next frame from the buffer
|
|
39
|
+
* Returns null if not enough data available
|
|
40
|
+
*/
|
|
41
|
+
parseFrame(): S2SFrame | null;
|
|
42
|
+
/**
|
|
43
|
+
* Check if parser has any buffered data
|
|
44
|
+
*/
|
|
45
|
+
hasData(): boolean;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=framing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/stream/transport/s2s/framing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,eAAe,CAAC;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,UAAU,CA+Cb;AAED;;GAEG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,MAAM,CAAiC;IAE/C;;OAEG;IACI,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAOnC;;;OAGG;IACI,UAAU,IAAI,QAAQ,GAAG,IAAI;IA8CpC;;OAEG;IACI,OAAO,IAAI,OAAO;CAGzB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S2S Protocol Message Framing
|
|
3
|
+
*
|
|
4
|
+
* Message format:
|
|
5
|
+
* - 3 bytes: Length prefix (total message length including flag byte, big-endian)
|
|
6
|
+
* - 1 byte: Flag byte [T][CC][RRRRR]
|
|
7
|
+
* - T (bit 7): Terminal flag (1 = stream ends after this message)
|
|
8
|
+
* - CC (bits 6-5): Compression (00=none, 01=zstd, 10=gzip)
|
|
9
|
+
* - RRRRR (bits 4-0): Reserved
|
|
10
|
+
* - Variable: Body (protobuf message or JSON error for terminal frames)
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Frame a message for s2s protocol
|
|
14
|
+
*/
|
|
15
|
+
export function frameMessage(opts) {
|
|
16
|
+
const compression = opts.compression ?? "none";
|
|
17
|
+
// Build flag byte
|
|
18
|
+
let flag = 0;
|
|
19
|
+
if (opts.terminal) {
|
|
20
|
+
flag |= 0x80; // Set bit 7
|
|
21
|
+
}
|
|
22
|
+
if (compression === "zstd") {
|
|
23
|
+
flag |= 0x20; // Set bit 5
|
|
24
|
+
}
|
|
25
|
+
else if (compression === "gzip") {
|
|
26
|
+
flag |= 0x40; // Set bit 6
|
|
27
|
+
}
|
|
28
|
+
// For terminal frames with status code, prepend 2-byte status code to body
|
|
29
|
+
let body = opts.body;
|
|
30
|
+
if (opts.terminal && opts.statusCode !== undefined) {
|
|
31
|
+
const statusBytes = new Uint8Array(2);
|
|
32
|
+
statusBytes[0] = (opts.statusCode >> 8) & 0xff;
|
|
33
|
+
statusBytes[1] = opts.statusCode & 0xff;
|
|
34
|
+
body = new Uint8Array(statusBytes.length + opts.body.length);
|
|
35
|
+
body.set(statusBytes, 0);
|
|
36
|
+
body.set(opts.body, statusBytes.length);
|
|
37
|
+
}
|
|
38
|
+
// Calculate total length (flag + body)
|
|
39
|
+
const length = 1 + body.length;
|
|
40
|
+
if (length > 0xffffff) {
|
|
41
|
+
throw new Error(`Message too large: ${length} bytes (max 16MB)`);
|
|
42
|
+
}
|
|
43
|
+
// Allocate frame buffer
|
|
44
|
+
const frame = new Uint8Array(3 + length);
|
|
45
|
+
// Write 3-byte length prefix (big-endian)
|
|
46
|
+
frame[0] = (length >> 16) & 0xff;
|
|
47
|
+
frame[1] = (length >> 8) & 0xff;
|
|
48
|
+
frame[2] = length & 0xff;
|
|
49
|
+
// Write flag byte
|
|
50
|
+
frame[3] = flag;
|
|
51
|
+
// Write body
|
|
52
|
+
frame.set(body, 4);
|
|
53
|
+
return frame;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parser for reading s2s frames from a stream
|
|
57
|
+
*/
|
|
58
|
+
export class S2SFrameParser {
|
|
59
|
+
buffer = new Uint8Array(0);
|
|
60
|
+
/**
|
|
61
|
+
* Add data to the parser buffer
|
|
62
|
+
*/
|
|
63
|
+
push(data) {
|
|
64
|
+
const newBuffer = new Uint8Array(this.buffer.length + data.length);
|
|
65
|
+
newBuffer.set(this.buffer, 0);
|
|
66
|
+
newBuffer.set(data, this.buffer.length);
|
|
67
|
+
this.buffer = newBuffer;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Try to parse the next frame from the buffer
|
|
71
|
+
* Returns null if not enough data available
|
|
72
|
+
*/
|
|
73
|
+
parseFrame() {
|
|
74
|
+
// Need at least 4 bytes (3-byte length + 1-byte flag)
|
|
75
|
+
if (this.buffer.length < 4) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
// Read 3-byte length prefix (big-endian)
|
|
79
|
+
const length = (this.buffer[0] << 16) | (this.buffer[1] << 8) | this.buffer[2];
|
|
80
|
+
// Check if we have the full message
|
|
81
|
+
if (this.buffer.length < 3 + length) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
// Read flag byte
|
|
85
|
+
const flag = this.buffer[3];
|
|
86
|
+
const terminal = (flag & 0x80) !== 0;
|
|
87
|
+
let compression = "none";
|
|
88
|
+
if ((flag & 0x20) !== 0) {
|
|
89
|
+
compression = "zstd";
|
|
90
|
+
}
|
|
91
|
+
else if ((flag & 0x40) !== 0) {
|
|
92
|
+
compression = "gzip";
|
|
93
|
+
}
|
|
94
|
+
// Extract body (length includes flag byte, so body is length - 1 bytes)
|
|
95
|
+
let body = this.buffer.slice(4, 4 + length - 1);
|
|
96
|
+
let statusCode;
|
|
97
|
+
// For terminal frames, check for status code
|
|
98
|
+
if (terminal && body.length >= 2) {
|
|
99
|
+
statusCode = (body[0] << 8) | body[1];
|
|
100
|
+
body = body.slice(2);
|
|
101
|
+
}
|
|
102
|
+
// Remove parsed frame from buffer
|
|
103
|
+
this.buffer = this.buffer.slice(3 + length);
|
|
104
|
+
return {
|
|
105
|
+
terminal,
|
|
106
|
+
compression,
|
|
107
|
+
body,
|
|
108
|
+
statusCode,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if parser has any buffered data
|
|
113
|
+
*/
|
|
114
|
+
hasData() {
|
|
115
|
+
return this.buffer.length > 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=framing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.js","sourceRoot":"","sources":["../../../../../../src/lib/stream/transport/s2s/framing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S2S HTTP/2 transport for Node.js
|
|
3
|
+
* Uses the s2s binary protocol over HTTP/2 for efficient streaming
|
|
4
|
+
*
|
|
5
|
+
* This file should only be imported in Node.js environments
|
|
6
|
+
*/
|
|
7
|
+
import type { S2RequestOptions } from "../../../../common.js";
|
|
8
|
+
import type { AppendSession, AppendSessionOptions, ReadArgs, ReadSession, SessionTransport, TransportConfig } from "../../types.js";
|
|
9
|
+
export declare class S2STransport implements SessionTransport {
|
|
10
|
+
private readonly client;
|
|
11
|
+
private readonly transportConfig;
|
|
12
|
+
private connection?;
|
|
13
|
+
private connectionPromise?;
|
|
14
|
+
constructor(config: TransportConfig);
|
|
15
|
+
makeAppendSession(stream: string, sessionOptions?: AppendSessionOptions, requestOptions?: S2RequestOptions): Promise<AppendSession>;
|
|
16
|
+
makeReadSession<Format extends "string" | "bytes" = "string">(stream: string, args?: ReadArgs<Format>, options?: S2RequestOptions): Promise<ReadSession<Format>>;
|
|
17
|
+
/**
|
|
18
|
+
* Get or create HTTP/2 connection (one per transport)
|
|
19
|
+
*/
|
|
20
|
+
private getConnection;
|
|
21
|
+
private createConnection;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/stream/transport/s2s/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAgB9D,OAAO,KAAK,EAGX,aAAa,EACb,oBAAoB,EACpB,QAAQ,EAER,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,MAAM,gBAAgB,CAAC;AAGxB,qBAAa,YAAa,YAAW,gBAAgB;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,UAAU,CAAC,CAA2B;IAC9C,OAAO,CAAC,iBAAiB,CAAC,CAAoC;gBAElD,MAAM,EAAE,eAAe;IAU7B,iBAAiB,CACtB,MAAM,EAAE,MAAM,EACd,cAAc,CAAC,EAAE,oBAAoB,EACrC,cAAc,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,aAAa,CAAC;IAWnB,eAAe,CAAC,MAAM,SAAS,QAAQ,GAAG,OAAO,GAAG,QAAQ,EACjE,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAW/B;;OAEG;YACW,aAAa;YAyBb,gBAAgB;CA4B9B"}
|