@durable-streams/cli 0.1.2 → 0.1.4
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 +30 -12
- package/dist/index.cjs +57 -7
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +59 -9
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -4,31 +4,38 @@ A command-line tool for interacting with durable streams.
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### From npm
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
#
|
|
11
|
-
|
|
10
|
+
# Global installation
|
|
11
|
+
npm install -g @durable-streams/cli
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
|
|
13
|
+
# Or run directly with npx
|
|
14
|
+
npx @durable-streams/cli create my-stream
|
|
15
|
+
npx @durable-streams/cli read my-stream
|
|
15
16
|
```
|
|
16
17
|
|
|
17
|
-
###
|
|
18
|
-
|
|
19
|
-
For development, you can link the CLI globally with live TypeScript execution (no rebuild needed):
|
|
18
|
+
### From source (for development)
|
|
20
19
|
|
|
21
20
|
```bash
|
|
22
|
-
#
|
|
21
|
+
# Clone the repository
|
|
22
|
+
git clone https://github.com/durable-streams/durable-streams.git
|
|
23
|
+
cd durable-streams
|
|
24
|
+
|
|
25
|
+
# Install dependencies
|
|
26
|
+
pnpm install
|
|
27
|
+
|
|
28
|
+
# Build the CLI
|
|
29
|
+
pnpm build
|
|
30
|
+
|
|
31
|
+
# Link globally for development (uses tsx, no rebuild needed)
|
|
32
|
+
cd packages/cli
|
|
23
33
|
pnpm link:dev
|
|
24
34
|
|
|
25
35
|
# Now you can use durable-stream-dev anywhere
|
|
26
|
-
# Changes to src/index.ts are immediately available
|
|
27
36
|
durable-stream-dev create my-stream
|
|
28
37
|
```
|
|
29
38
|
|
|
30
|
-
This uses `tsx` to run the TypeScript source directly, so you see changes immediately without rebuilding.
|
|
31
|
-
|
|
32
39
|
## Quick Start
|
|
33
40
|
|
|
34
41
|
The easiest way to get started is to run the local development server and use the CLI:
|
|
@@ -63,6 +70,11 @@ durable-stream-dev read my-stream
|
|
|
63
70
|
|
|
64
71
|
- `STREAM_URL` - Base URL of the stream server (default: `http://localhost:4437`)
|
|
65
72
|
|
|
73
|
+
### Write Options
|
|
74
|
+
|
|
75
|
+
- `--content-type <type>` - Content-Type for the message (default: `application/octet-stream`)
|
|
76
|
+
- `--json` - Shorthand for `--content-type application/json`
|
|
77
|
+
|
|
66
78
|
### Commands
|
|
67
79
|
|
|
68
80
|
#### Create a stream
|
|
@@ -80,6 +92,12 @@ durable-stream-dev write <stream_id> "Hello, world!"
|
|
|
80
92
|
# Pipe content from stdin
|
|
81
93
|
echo "Hello from stdin" | durable-stream-dev write <stream_id>
|
|
82
94
|
cat file.txt | durable-stream-dev write <stream_id>
|
|
95
|
+
|
|
96
|
+
# Specify content type
|
|
97
|
+
durable-stream-dev write <stream_id> '{"key": "value"}' --content-type application/json
|
|
98
|
+
|
|
99
|
+
# Shorthand for JSON
|
|
100
|
+
durable-stream-dev write <stream_id> '{"key": "value"}' --json
|
|
83
101
|
```
|
|
84
102
|
|
|
85
103
|
#### Read from a stream
|
package/dist/index.cjs
CHANGED
|
@@ -23,9 +23,39 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
}) : target, mod));
|
|
24
24
|
|
|
25
25
|
//#endregion
|
|
26
|
+
const node_path = __toESM(require("node:path"));
|
|
26
27
|
const node_process = __toESM(require("node:process"));
|
|
28
|
+
const node_url = __toESM(require("node:url"));
|
|
27
29
|
const __durable_streams_client = __toESM(require("@durable-streams/client"));
|
|
28
30
|
|
|
31
|
+
//#region src/parseWriteArgs.ts
|
|
32
|
+
/**
|
|
33
|
+
* Parse write command arguments, extracting content-type flags and content.
|
|
34
|
+
* @param args - Arguments after the stream_id (starting from index 2)
|
|
35
|
+
* @returns Parsed content type and content string
|
|
36
|
+
* @throws Error if --content-type is missing its value or if unknown flags are provided
|
|
37
|
+
*/
|
|
38
|
+
function parseWriteArgs(args) {
|
|
39
|
+
let contentType = `application/octet-stream`;
|
|
40
|
+
const contentParts = [];
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
const arg = args[i];
|
|
43
|
+
if (arg === `--json`) contentType = `application/json`;
|
|
44
|
+
else if (arg === `--content-type`) {
|
|
45
|
+
const nextArg = args[i + 1];
|
|
46
|
+
if (!nextArg || nextArg.startsWith(`--`)) throw new Error(`--content-type requires a value`);
|
|
47
|
+
contentType = nextArg;
|
|
48
|
+
i++;
|
|
49
|
+
} else if (arg.startsWith(`--`)) throw new Error(`unknown flag: ${arg}`);
|
|
50
|
+
else contentParts.push(arg);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
contentType,
|
|
54
|
+
content: contentParts.join(` `)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
29
59
|
//#region src/index.ts
|
|
30
60
|
const STREAM_URL = process.env.STREAM_URL || `http://localhost:4437`;
|
|
31
61
|
function printUsage() {
|
|
@@ -37,6 +67,10 @@ Usage:
|
|
|
37
67
|
durable-stream read <stream_id> Follow a stream and write to stdout
|
|
38
68
|
durable-stream delete <stream_id> Delete a stream
|
|
39
69
|
|
|
70
|
+
Write Options:
|
|
71
|
+
--content-type <type> Content-Type for the message (default: application/octet-stream)
|
|
72
|
+
--json Shorthand for --content-type application/json
|
|
73
|
+
|
|
40
74
|
Environment Variables:
|
|
41
75
|
STREAM_URL Base URL of the stream server (default: http://localhost:4437)
|
|
42
76
|
`);
|
|
@@ -54,10 +88,13 @@ async function createStream(streamId) {
|
|
|
54
88
|
process.exit(1);
|
|
55
89
|
}
|
|
56
90
|
}
|
|
57
|
-
async function writeStream(streamId, content) {
|
|
91
|
+
async function writeStream(streamId, contentType, content) {
|
|
58
92
|
const url = `${STREAM_URL}/v1/stream/${streamId}`;
|
|
59
93
|
try {
|
|
60
|
-
const stream = new __durable_streams_client.DurableStream({
|
|
94
|
+
const stream = new __durable_streams_client.DurableStream({
|
|
95
|
+
url,
|
|
96
|
+
contentType
|
|
97
|
+
});
|
|
61
98
|
if (content) {
|
|
62
99
|
const processedContent = content.replace(/\\n/g, `\n`).replace(/\\t/g, `\t`).replace(/\\r/g, `\r`).replace(/\\\\/g, `\\`);
|
|
63
100
|
await stream.append(processedContent);
|
|
@@ -126,9 +163,15 @@ async function main() {
|
|
|
126
163
|
process.exit(1);
|
|
127
164
|
}
|
|
128
165
|
const streamId = args[1];
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
166
|
+
let parsed;
|
|
167
|
+
try {
|
|
168
|
+
parsed = parseWriteArgs(args.slice(2));
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (error instanceof Error) node_process.stderr.write(`Error: ${error.message}\n`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
if (!node_process.stdin.isTTY) await writeStream(streamId, parsed.contentType);
|
|
174
|
+
else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.content);
|
|
132
175
|
else {
|
|
133
176
|
node_process.stderr.write(`Error: content required (provide as argument or pipe to stdin)\n`);
|
|
134
177
|
printUsage();
|
|
@@ -160,9 +203,16 @@ async function main() {
|
|
|
160
203
|
process.exit(1);
|
|
161
204
|
}
|
|
162
205
|
}
|
|
163
|
-
|
|
206
|
+
function isMainModule() {
|
|
207
|
+
if (!process.argv[1]) return false;
|
|
208
|
+
const scriptPath = (0, node_path.resolve)(process.argv[1]);
|
|
209
|
+
const modulePath = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
210
|
+
return scriptPath === modulePath;
|
|
211
|
+
}
|
|
212
|
+
if (isMainModule()) main().catch((error) => {
|
|
164
213
|
node_process.stderr.write(`Fatal error: ${error.message}\n`);
|
|
165
214
|
process.exit(1);
|
|
166
215
|
});
|
|
167
216
|
|
|
168
|
-
//#endregion
|
|
217
|
+
//#endregion
|
|
218
|
+
exports.parseWriteArgs = parseWriteArgs
|
package/dist/index.d.cts
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/parseWriteArgs.d.ts
|
|
2
|
+
interface ParsedWriteArgs {
|
|
3
|
+
contentType: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Parse write command arguments, extracting content-type flags and content.
|
|
8
|
+
* @param args - Arguments after the stream_id (starting from index 2)
|
|
9
|
+
* @returns Parsed content type and content string
|
|
10
|
+
* @throws Error if --content-type is missing its value or if unknown flags are provided
|
|
11
|
+
*/
|
|
12
|
+
declare function parseWriteArgs(args: Array<string>): ParsedWriteArgs;
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { ParsedWriteArgs, parseWriteArgs };
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/parseWriteArgs.d.ts
|
|
2
|
+
interface ParsedWriteArgs {
|
|
3
|
+
contentType: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Parse write command arguments, extracting content-type flags and content.
|
|
8
|
+
* @param args - Arguments after the stream_id (starting from index 2)
|
|
9
|
+
* @returns Parsed content type and content string
|
|
10
|
+
* @throws Error if --content-type is missing its value or if unknown flags are provided
|
|
11
|
+
*/
|
|
12
|
+
declare function parseWriteArgs(args: Array<string>): ParsedWriteArgs;
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { ParsedWriteArgs, parseWriteArgs };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
2
3
|
import { stderr, stdin, stdout } from "node:process";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
3
5
|
import { DurableStream } from "@durable-streams/client";
|
|
4
6
|
|
|
7
|
+
//#region src/parseWriteArgs.ts
|
|
8
|
+
/**
|
|
9
|
+
* Parse write command arguments, extracting content-type flags and content.
|
|
10
|
+
* @param args - Arguments after the stream_id (starting from index 2)
|
|
11
|
+
* @returns Parsed content type and content string
|
|
12
|
+
* @throws Error if --content-type is missing its value or if unknown flags are provided
|
|
13
|
+
*/
|
|
14
|
+
function parseWriteArgs(args) {
|
|
15
|
+
let contentType = `application/octet-stream`;
|
|
16
|
+
const contentParts = [];
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const arg = args[i];
|
|
19
|
+
if (arg === `--json`) contentType = `application/json`;
|
|
20
|
+
else if (arg === `--content-type`) {
|
|
21
|
+
const nextArg = args[i + 1];
|
|
22
|
+
if (!nextArg || nextArg.startsWith(`--`)) throw new Error(`--content-type requires a value`);
|
|
23
|
+
contentType = nextArg;
|
|
24
|
+
i++;
|
|
25
|
+
} else if (arg.startsWith(`--`)) throw new Error(`unknown flag: ${arg}`);
|
|
26
|
+
else contentParts.push(arg);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
contentType,
|
|
30
|
+
content: contentParts.join(` `)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
5
35
|
//#region src/index.ts
|
|
6
36
|
const STREAM_URL = process.env.STREAM_URL || `http://localhost:4437`;
|
|
7
37
|
function printUsage() {
|
|
@@ -13,6 +43,10 @@ Usage:
|
|
|
13
43
|
durable-stream read <stream_id> Follow a stream and write to stdout
|
|
14
44
|
durable-stream delete <stream_id> Delete a stream
|
|
15
45
|
|
|
46
|
+
Write Options:
|
|
47
|
+
--content-type <type> Content-Type for the message (default: application/octet-stream)
|
|
48
|
+
--json Shorthand for --content-type application/json
|
|
49
|
+
|
|
16
50
|
Environment Variables:
|
|
17
51
|
STREAM_URL Base URL of the stream server (default: http://localhost:4437)
|
|
18
52
|
`);
|
|
@@ -30,10 +64,13 @@ async function createStream(streamId) {
|
|
|
30
64
|
process.exit(1);
|
|
31
65
|
}
|
|
32
66
|
}
|
|
33
|
-
async function writeStream(streamId, content) {
|
|
67
|
+
async function writeStream(streamId, contentType, content) {
|
|
34
68
|
const url = `${STREAM_URL}/v1/stream/${streamId}`;
|
|
35
69
|
try {
|
|
36
|
-
const stream = new DurableStream({
|
|
70
|
+
const stream = new DurableStream({
|
|
71
|
+
url,
|
|
72
|
+
contentType
|
|
73
|
+
});
|
|
37
74
|
if (content) {
|
|
38
75
|
const processedContent = content.replace(/\\n/g, `\n`).replace(/\\t/g, `\t`).replace(/\\r/g, `\r`).replace(/\\\\/g, `\\`);
|
|
39
76
|
await stream.append(processedContent);
|
|
@@ -43,8 +80,8 @@ async function writeStream(streamId, content) {
|
|
|
43
80
|
stdin.on(`data`, (chunk) => {
|
|
44
81
|
chunks.push(chunk);
|
|
45
82
|
});
|
|
46
|
-
await new Promise((resolve, reject) => {
|
|
47
|
-
stdin.on(`end`, resolve);
|
|
83
|
+
await new Promise((resolve$1, reject) => {
|
|
84
|
+
stdin.on(`end`, resolve$1);
|
|
48
85
|
stdin.on(`error`, reject);
|
|
49
86
|
});
|
|
50
87
|
const data = Buffer.concat(chunks);
|
|
@@ -102,9 +139,15 @@ async function main() {
|
|
|
102
139
|
process.exit(1);
|
|
103
140
|
}
|
|
104
141
|
const streamId = args[1];
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
142
|
+
let parsed;
|
|
143
|
+
try {
|
|
144
|
+
parsed = parseWriteArgs(args.slice(2));
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (error instanceof Error) stderr.write(`Error: ${error.message}\n`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
if (!stdin.isTTY) await writeStream(streamId, parsed.contentType);
|
|
150
|
+
else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.content);
|
|
108
151
|
else {
|
|
109
152
|
stderr.write(`Error: content required (provide as argument or pipe to stdin)\n`);
|
|
110
153
|
printUsage();
|
|
@@ -136,9 +179,16 @@ async function main() {
|
|
|
136
179
|
process.exit(1);
|
|
137
180
|
}
|
|
138
181
|
}
|
|
139
|
-
|
|
182
|
+
function isMainModule() {
|
|
183
|
+
if (!process.argv[1]) return false;
|
|
184
|
+
const scriptPath = resolve(process.argv[1]);
|
|
185
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
186
|
+
return scriptPath === modulePath;
|
|
187
|
+
}
|
|
188
|
+
if (isMainModule()) main().catch((error) => {
|
|
140
189
|
stderr.write(`Fatal error: ${error.message}\n`);
|
|
141
190
|
process.exit(1);
|
|
142
191
|
});
|
|
143
192
|
|
|
144
|
-
//#endregion
|
|
193
|
+
//#endregion
|
|
194
|
+
export { parseWriteArgs };
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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.4",
|
|
5
5
|
"author": "Durable Stream contributors",
|
|
6
6
|
"bin": {
|
|
7
|
+
"cli": "./dist/index.js",
|
|
7
8
|
"durable-stream": "./dist/index.js",
|
|
8
9
|
"durable-stream-dev": "./bin/durable-stream-dev.mjs"
|
|
9
10
|
},
|
|
@@ -11,14 +12,15 @@
|
|
|
11
12
|
"url": "https://github.com/durable-streams/durable-streams/issues"
|
|
12
13
|
},
|
|
13
14
|
"dependencies": {
|
|
14
|
-
"@durable-streams/client": "0.1.
|
|
15
|
+
"@durable-streams/client": "0.1.3"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/node": "^22.15.21",
|
|
18
19
|
"tsdown": "^0.9.0",
|
|
19
20
|
"tsx": "^4.19.2",
|
|
20
21
|
"typescript": "^5.5.2",
|
|
21
|
-
"
|
|
22
|
+
"vitest": "^3.1.3",
|
|
23
|
+
"@durable-streams/server": "0.1.4"
|
|
22
24
|
},
|
|
23
25
|
"engines": {
|
|
24
26
|
"node": ">=18.0.0"
|
|
@@ -61,6 +63,7 @@
|
|
|
61
63
|
"build": "tsdown",
|
|
62
64
|
"dev": "tsdown --watch",
|
|
63
65
|
"link:dev": "pnpm link --global",
|
|
64
|
-
"start:dev": "tsx --watch example-server.ts"
|
|
66
|
+
"start:dev": "tsx --watch example-server.ts",
|
|
67
|
+
"test": "vitest run"
|
|
65
68
|
}
|
|
66
69
|
}
|