@durable-streams/cli 0.1.4 → 0.1.5
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 +12 -0
- package/dist/index.cjs +84 -13
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +83 -14
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -100,6 +100,18 @@ durable-stream-dev write <stream_id> '{"key": "value"}' --content-type applicati
|
|
|
100
100
|
durable-stream-dev write <stream_id> '{"key": "value"}' --json
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
##### JSON Mode Array Flattening
|
|
104
|
+
|
|
105
|
+
In JSON mode (`--json` or `--content-type application/json`), top-level arrays are flattened into individual messages:
|
|
106
|
+
|
|
107
|
+
| Input | Messages stored |
|
|
108
|
+
| ------------ | ---------------------- |
|
|
109
|
+
| `{}` | 1 message: `{}` |
|
|
110
|
+
| `[{}, {}]` | 2 messages: `{}`, `{}` |
|
|
111
|
+
| `[[{}, {}]]` | 1 message: `[{}, {}]` |
|
|
112
|
+
|
|
113
|
+
This matches the protocol's batch semantics.
|
|
114
|
+
|
|
103
115
|
#### Read from a stream
|
|
104
116
|
|
|
105
117
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,28 @@ const node_process = __toESM(require("node:process"));
|
|
|
28
28
|
const node_url = __toESM(require("node:url"));
|
|
29
29
|
const __durable_streams_client = __toESM(require("@durable-streams/client"));
|
|
30
30
|
|
|
31
|
+
//#region src/jsonUtils.ts
|
|
32
|
+
/**
|
|
33
|
+
* Check if content-type indicates JSON mode.
|
|
34
|
+
* Handles cases like "application/json; charset=utf-8".
|
|
35
|
+
*/
|
|
36
|
+
function isJsonContentType(contentType) {
|
|
37
|
+
return contentType.split(`;`)[0].trim().toLowerCase() === `application/json`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* One-level array flattening for JSON batch semantics.
|
|
41
|
+
* - Single object: `{}` → yields once
|
|
42
|
+
* - Array: `[{}, {}]` → yields each element (flattened)
|
|
43
|
+
* - Nested array: `[[{}, {}]]` → yields `[{}, {}]` (outer array flattened, inner preserved)
|
|
44
|
+
*
|
|
45
|
+
* This matches the protocol's batch semantics where servers flatten exactly one level.
|
|
46
|
+
*/
|
|
47
|
+
function* flattenJsonForAppend(parsed) {
|
|
48
|
+
if (Array.isArray(parsed)) for (const item of parsed) yield item;
|
|
49
|
+
else yield parsed;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
31
53
|
//#region src/parseWriteArgs.ts
|
|
32
54
|
/**
|
|
33
55
|
* Parse write command arguments, extracting content-type flags and content.
|
|
@@ -37,21 +59,33 @@ const __durable_streams_client = __toESM(require("@durable-streams/client"));
|
|
|
37
59
|
*/
|
|
38
60
|
function parseWriteArgs(args) {
|
|
39
61
|
let contentType = `application/octet-stream`;
|
|
62
|
+
let batchJson = false;
|
|
40
63
|
const contentParts = [];
|
|
41
64
|
for (let i = 0; i < args.length; i++) {
|
|
42
65
|
const arg = args[i];
|
|
43
|
-
if (arg === `--json`)
|
|
44
|
-
|
|
66
|
+
if (arg === `--json`) {
|
|
67
|
+
contentType = `application/json`;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (arg === `--batch-json`) {
|
|
71
|
+
batchJson = true;
|
|
72
|
+
contentType = `application/json`;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (arg === `--content-type`) {
|
|
45
76
|
const nextArg = args[i + 1];
|
|
46
77
|
if (!nextArg || nextArg.startsWith(`--`)) throw new Error(`--content-type requires a value`);
|
|
47
78
|
contentType = nextArg;
|
|
48
79
|
i++;
|
|
49
|
-
|
|
50
|
-
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (arg.startsWith(`--`)) throw new Error(`unknown flag: ${arg}`);
|
|
83
|
+
contentParts.push(arg);
|
|
51
84
|
}
|
|
52
85
|
return {
|
|
53
86
|
contentType,
|
|
54
|
-
content: contentParts.join(` `)
|
|
87
|
+
content: contentParts.join(` `),
|
|
88
|
+
batchJson
|
|
55
89
|
};
|
|
56
90
|
}
|
|
57
91
|
|
|
@@ -69,7 +103,8 @@ Usage:
|
|
|
69
103
|
|
|
70
104
|
Write Options:
|
|
71
105
|
--content-type <type> Content-Type for the message (default: application/octet-stream)
|
|
72
|
-
--json
|
|
106
|
+
--json Write as JSON (input stored as single message)
|
|
107
|
+
--batch-json Write as JSON array of messages (each array element stored separately)
|
|
73
108
|
|
|
74
109
|
Environment Variables:
|
|
75
110
|
STREAM_URL Base URL of the stream server (default: http://localhost:4437)
|
|
@@ -88,8 +123,20 @@ async function createStream(streamId) {
|
|
|
88
123
|
process.exit(1);
|
|
89
124
|
}
|
|
90
125
|
}
|
|
91
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Append JSON data to a stream with one-level array flattening.
|
|
128
|
+
*/
|
|
129
|
+
async function appendJson(stream, parsed) {
|
|
130
|
+
let count = 0;
|
|
131
|
+
for (const item of flattenJsonForAppend(parsed)) {
|
|
132
|
+
await stream.append(item);
|
|
133
|
+
count++;
|
|
134
|
+
}
|
|
135
|
+
return count;
|
|
136
|
+
}
|
|
137
|
+
async function writeStream(streamId, contentType, batchJson, content) {
|
|
92
138
|
const url = `${STREAM_URL}/v1/stream/${streamId}`;
|
|
139
|
+
const isJson = isJsonContentType(contentType);
|
|
93
140
|
try {
|
|
94
141
|
const stream = new __durable_streams_client.DurableStream({
|
|
95
142
|
url,
|
|
@@ -97,8 +144,19 @@ async function writeStream(streamId, contentType, content) {
|
|
|
97
144
|
});
|
|
98
145
|
if (content) {
|
|
99
146
|
const processedContent = content.replace(/\\n/g, `\n`).replace(/\\t/g, `\t`).replace(/\\r/g, `\r`).replace(/\\\\/g, `\\`);
|
|
100
|
-
|
|
101
|
-
|
|
147
|
+
if (isJson) {
|
|
148
|
+
const parsed = JSON.parse(processedContent);
|
|
149
|
+
if (batchJson) {
|
|
150
|
+
const count = await appendJson(stream, parsed);
|
|
151
|
+
console.log(`Wrote ${count} message(s) to ${streamId}`);
|
|
152
|
+
} else {
|
|
153
|
+
await stream.append(parsed);
|
|
154
|
+
console.log(`Wrote 1 message to ${streamId}`);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
await stream.append(processedContent);
|
|
158
|
+
console.log(`Wrote ${processedContent.length} bytes to ${streamId}`);
|
|
159
|
+
}
|
|
102
160
|
} else {
|
|
103
161
|
const chunks = [];
|
|
104
162
|
node_process.stdin.on(`data`, (chunk) => {
|
|
@@ -109,8 +167,19 @@ async function writeStream(streamId, contentType, content) {
|
|
|
109
167
|
node_process.stdin.on(`error`, reject);
|
|
110
168
|
});
|
|
111
169
|
const data = Buffer.concat(chunks);
|
|
112
|
-
|
|
113
|
-
|
|
170
|
+
if (isJson) {
|
|
171
|
+
const parsed = JSON.parse(data.toString(`utf8`));
|
|
172
|
+
if (batchJson) {
|
|
173
|
+
const count = await appendJson(stream, parsed);
|
|
174
|
+
console.log(`Wrote ${count} message(s) to ${streamId}`);
|
|
175
|
+
} else {
|
|
176
|
+
await stream.append(parsed);
|
|
177
|
+
console.log(`Wrote 1 message to ${streamId}`);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
await stream.append(data);
|
|
181
|
+
console.log(`Wrote ${data.length} bytes to ${streamId}`);
|
|
182
|
+
}
|
|
114
183
|
}
|
|
115
184
|
} catch (error) {
|
|
116
185
|
if (error instanceof Error) node_process.stderr.write(`Error writing to stream: ${error.message}\n`);
|
|
@@ -170,8 +239,8 @@ async function main() {
|
|
|
170
239
|
if (error instanceof Error) node_process.stderr.write(`Error: ${error.message}\n`);
|
|
171
240
|
process.exit(1);
|
|
172
241
|
}
|
|
173
|
-
if (!node_process.stdin.isTTY) await writeStream(streamId, parsed.contentType);
|
|
174
|
-
else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.content);
|
|
242
|
+
if (!node_process.stdin.isTTY) await writeStream(streamId, parsed.contentType, parsed.batchJson);
|
|
243
|
+
else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.batchJson, parsed.content);
|
|
175
244
|
else {
|
|
176
245
|
node_process.stderr.write(`Error: content required (provide as argument or pipe to stdin)\n`);
|
|
177
246
|
printUsage();
|
|
@@ -215,4 +284,6 @@ if (isMainModule()) main().catch((error) => {
|
|
|
215
284
|
});
|
|
216
285
|
|
|
217
286
|
//#endregion
|
|
287
|
+
exports.flattenJsonForAppend = flattenJsonForAppend
|
|
288
|
+
exports.isJsonContentType = isJsonContentType
|
|
218
289
|
exports.parseWriteArgs = parseWriteArgs
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
//#region src/jsonUtils.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check if content-type indicates JSON mode.
|
|
4
|
+
* Handles cases like "application/json; charset=utf-8".
|
|
5
|
+
*/
|
|
6
|
+
declare function isJsonContentType(contentType: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* One-level array flattening for JSON batch semantics.
|
|
9
|
+
* - Single object: `{}` → yields once
|
|
10
|
+
* - Array: `[{}, {}]` → yields each element (flattened)
|
|
11
|
+
* - Nested array: `[[{}, {}]]` → yields `[{}, {}]` (outer array flattened, inner preserved)
|
|
12
|
+
*
|
|
13
|
+
* This matches the protocol's batch semantics where servers flatten exactly one level.
|
|
14
|
+
*/
|
|
15
|
+
declare function flattenJsonForAppend(parsed: unknown): Generator<unknown>;
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
1
18
|
//#region src/parseWriteArgs.d.ts
|
|
2
19
|
interface ParsedWriteArgs {
|
|
3
20
|
contentType: string;
|
|
4
21
|
content: string;
|
|
22
|
+
batchJson: boolean;
|
|
5
23
|
}
|
|
6
24
|
/**
|
|
7
25
|
* Parse write command arguments, extracting content-type flags and content.
|
|
@@ -12,4 +30,4 @@ interface ParsedWriteArgs {
|
|
|
12
30
|
declare function parseWriteArgs(args: Array<string>): ParsedWriteArgs;
|
|
13
31
|
|
|
14
32
|
//#endregion
|
|
15
|
-
export { ParsedWriteArgs, parseWriteArgs };
|
|
33
|
+
export { ParsedWriteArgs, flattenJsonForAppend, isJsonContentType, parseWriteArgs };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
//#region src/jsonUtils.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check if content-type indicates JSON mode.
|
|
4
|
+
* Handles cases like "application/json; charset=utf-8".
|
|
5
|
+
*/
|
|
6
|
+
declare function isJsonContentType(contentType: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* One-level array flattening for JSON batch semantics.
|
|
9
|
+
* - Single object: `{}` → yields once
|
|
10
|
+
* - Array: `[{}, {}]` → yields each element (flattened)
|
|
11
|
+
* - Nested array: `[[{}, {}]]` → yields `[{}, {}]` (outer array flattened, inner preserved)
|
|
12
|
+
*
|
|
13
|
+
* This matches the protocol's batch semantics where servers flatten exactly one level.
|
|
14
|
+
*/
|
|
15
|
+
declare function flattenJsonForAppend(parsed: unknown): Generator<unknown>;
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
1
18
|
//#region src/parseWriteArgs.d.ts
|
|
2
19
|
interface ParsedWriteArgs {
|
|
3
20
|
contentType: string;
|
|
4
21
|
content: string;
|
|
22
|
+
batchJson: boolean;
|
|
5
23
|
}
|
|
6
24
|
/**
|
|
7
25
|
* Parse write command arguments, extracting content-type flags and content.
|
|
@@ -12,4 +30,4 @@ interface ParsedWriteArgs {
|
|
|
12
30
|
declare function parseWriteArgs(args: Array<string>): ParsedWriteArgs;
|
|
13
31
|
|
|
14
32
|
//#endregion
|
|
15
|
-
export { ParsedWriteArgs, parseWriteArgs };
|
|
33
|
+
export { ParsedWriteArgs, flattenJsonForAppend, isJsonContentType, parseWriteArgs };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,28 @@ import { stderr, stdin, stdout } from "node:process";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { DurableStream } from "@durable-streams/client";
|
|
6
6
|
|
|
7
|
+
//#region src/jsonUtils.ts
|
|
8
|
+
/**
|
|
9
|
+
* Check if content-type indicates JSON mode.
|
|
10
|
+
* Handles cases like "application/json; charset=utf-8".
|
|
11
|
+
*/
|
|
12
|
+
function isJsonContentType(contentType) {
|
|
13
|
+
return contentType.split(`;`)[0].trim().toLowerCase() === `application/json`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One-level array flattening for JSON batch semantics.
|
|
17
|
+
* - Single object: `{}` → yields once
|
|
18
|
+
* - Array: `[{}, {}]` → yields each element (flattened)
|
|
19
|
+
* - Nested array: `[[{}, {}]]` → yields `[{}, {}]` (outer array flattened, inner preserved)
|
|
20
|
+
*
|
|
21
|
+
* This matches the protocol's batch semantics where servers flatten exactly one level.
|
|
22
|
+
*/
|
|
23
|
+
function* flattenJsonForAppend(parsed) {
|
|
24
|
+
if (Array.isArray(parsed)) for (const item of parsed) yield item;
|
|
25
|
+
else yield parsed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
7
29
|
//#region src/parseWriteArgs.ts
|
|
8
30
|
/**
|
|
9
31
|
* Parse write command arguments, extracting content-type flags and content.
|
|
@@ -13,21 +35,33 @@ import { DurableStream } from "@durable-streams/client";
|
|
|
13
35
|
*/
|
|
14
36
|
function parseWriteArgs(args) {
|
|
15
37
|
let contentType = `application/octet-stream`;
|
|
38
|
+
let batchJson = false;
|
|
16
39
|
const contentParts = [];
|
|
17
40
|
for (let i = 0; i < args.length; i++) {
|
|
18
41
|
const arg = args[i];
|
|
19
|
-
if (arg === `--json`)
|
|
20
|
-
|
|
42
|
+
if (arg === `--json`) {
|
|
43
|
+
contentType = `application/json`;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === `--batch-json`) {
|
|
47
|
+
batchJson = true;
|
|
48
|
+
contentType = `application/json`;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (arg === `--content-type`) {
|
|
21
52
|
const nextArg = args[i + 1];
|
|
22
53
|
if (!nextArg || nextArg.startsWith(`--`)) throw new Error(`--content-type requires a value`);
|
|
23
54
|
contentType = nextArg;
|
|
24
55
|
i++;
|
|
25
|
-
|
|
26
|
-
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (arg.startsWith(`--`)) throw new Error(`unknown flag: ${arg}`);
|
|
59
|
+
contentParts.push(arg);
|
|
27
60
|
}
|
|
28
61
|
return {
|
|
29
62
|
contentType,
|
|
30
|
-
content: contentParts.join(` `)
|
|
63
|
+
content: contentParts.join(` `),
|
|
64
|
+
batchJson
|
|
31
65
|
};
|
|
32
66
|
}
|
|
33
67
|
|
|
@@ -45,7 +79,8 @@ Usage:
|
|
|
45
79
|
|
|
46
80
|
Write Options:
|
|
47
81
|
--content-type <type> Content-Type for the message (default: application/octet-stream)
|
|
48
|
-
--json
|
|
82
|
+
--json Write as JSON (input stored as single message)
|
|
83
|
+
--batch-json Write as JSON array of messages (each array element stored separately)
|
|
49
84
|
|
|
50
85
|
Environment Variables:
|
|
51
86
|
STREAM_URL Base URL of the stream server (default: http://localhost:4437)
|
|
@@ -64,8 +99,20 @@ async function createStream(streamId) {
|
|
|
64
99
|
process.exit(1);
|
|
65
100
|
}
|
|
66
101
|
}
|
|
67
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Append JSON data to a stream with one-level array flattening.
|
|
104
|
+
*/
|
|
105
|
+
async function appendJson(stream, parsed) {
|
|
106
|
+
let count = 0;
|
|
107
|
+
for (const item of flattenJsonForAppend(parsed)) {
|
|
108
|
+
await stream.append(item);
|
|
109
|
+
count++;
|
|
110
|
+
}
|
|
111
|
+
return count;
|
|
112
|
+
}
|
|
113
|
+
async function writeStream(streamId, contentType, batchJson, content) {
|
|
68
114
|
const url = `${STREAM_URL}/v1/stream/${streamId}`;
|
|
115
|
+
const isJson = isJsonContentType(contentType);
|
|
69
116
|
try {
|
|
70
117
|
const stream = new DurableStream({
|
|
71
118
|
url,
|
|
@@ -73,8 +120,19 @@ async function writeStream(streamId, contentType, content) {
|
|
|
73
120
|
});
|
|
74
121
|
if (content) {
|
|
75
122
|
const processedContent = content.replace(/\\n/g, `\n`).replace(/\\t/g, `\t`).replace(/\\r/g, `\r`).replace(/\\\\/g, `\\`);
|
|
76
|
-
|
|
77
|
-
|
|
123
|
+
if (isJson) {
|
|
124
|
+
const parsed = JSON.parse(processedContent);
|
|
125
|
+
if (batchJson) {
|
|
126
|
+
const count = await appendJson(stream, parsed);
|
|
127
|
+
console.log(`Wrote ${count} message(s) to ${streamId}`);
|
|
128
|
+
} else {
|
|
129
|
+
await stream.append(parsed);
|
|
130
|
+
console.log(`Wrote 1 message to ${streamId}`);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
await stream.append(processedContent);
|
|
134
|
+
console.log(`Wrote ${processedContent.length} bytes to ${streamId}`);
|
|
135
|
+
}
|
|
78
136
|
} else {
|
|
79
137
|
const chunks = [];
|
|
80
138
|
stdin.on(`data`, (chunk) => {
|
|
@@ -85,8 +143,19 @@ async function writeStream(streamId, contentType, content) {
|
|
|
85
143
|
stdin.on(`error`, reject);
|
|
86
144
|
});
|
|
87
145
|
const data = Buffer.concat(chunks);
|
|
88
|
-
|
|
89
|
-
|
|
146
|
+
if (isJson) {
|
|
147
|
+
const parsed = JSON.parse(data.toString(`utf8`));
|
|
148
|
+
if (batchJson) {
|
|
149
|
+
const count = await appendJson(stream, parsed);
|
|
150
|
+
console.log(`Wrote ${count} message(s) to ${streamId}`);
|
|
151
|
+
} else {
|
|
152
|
+
await stream.append(parsed);
|
|
153
|
+
console.log(`Wrote 1 message to ${streamId}`);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
await stream.append(data);
|
|
157
|
+
console.log(`Wrote ${data.length} bytes to ${streamId}`);
|
|
158
|
+
}
|
|
90
159
|
}
|
|
91
160
|
} catch (error) {
|
|
92
161
|
if (error instanceof Error) stderr.write(`Error writing to stream: ${error.message}\n`);
|
|
@@ -146,8 +215,8 @@ async function main() {
|
|
|
146
215
|
if (error instanceof Error) stderr.write(`Error: ${error.message}\n`);
|
|
147
216
|
process.exit(1);
|
|
148
217
|
}
|
|
149
|
-
if (!stdin.isTTY) await writeStream(streamId, parsed.contentType);
|
|
150
|
-
else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.content);
|
|
218
|
+
if (!stdin.isTTY) await writeStream(streamId, parsed.contentType, parsed.batchJson);
|
|
219
|
+
else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.batchJson, parsed.content);
|
|
151
220
|
else {
|
|
152
221
|
stderr.write(`Error: content required (provide as argument or pipe to stdin)\n`);
|
|
153
222
|
printUsage();
|
|
@@ -191,4 +260,4 @@ if (isMainModule()) main().catch((error) => {
|
|
|
191
260
|
});
|
|
192
261
|
|
|
193
262
|
//#endregion
|
|
194
|
-
export { parseWriteArgs };
|
|
263
|
+
export { flattenJsonForAppend, isJsonContentType, parseWriteArgs };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@durable-streams/cli",
|
|
3
3
|
"description": "CLI tool for working with Durable Streams",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"author": "Durable Stream contributors",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cli": "./dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"url": "https://github.com/durable-streams/durable-streams/issues"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@durable-streams/client": "0.1.
|
|
15
|
+
"@durable-streams/client": "0.1.4"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/node": "^22.15.21",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"tsx": "^4.19.2",
|
|
21
21
|
"typescript": "^5.5.2",
|
|
22
22
|
"vitest": "^3.1.3",
|
|
23
|
-
"@durable-streams/server": "0.1.
|
|
23
|
+
"@durable-streams/server": "0.1.5"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": ">=18.0.0"
|