@durable-streams/cli 0.1.5 → 0.1.7

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 CHANGED
@@ -69,6 +69,11 @@ durable-stream-dev read my-stream
69
69
  ### Environment Variables
70
70
 
71
71
  - `STREAM_URL` - Base URL of the stream server (default: `http://localhost:4437`)
72
+ - `STREAM_AUTH` - Authorization header value (e.g., `Bearer my-token`)
73
+
74
+ ### Global Options
75
+
76
+ - `--auth <value>` - Authorization header value (overrides `STREAM_AUTH` env var)
72
77
 
73
78
  ### Write Options
74
79
 
@@ -125,6 +130,23 @@ durable-stream-dev read <stream_id>
125
130
  durable-stream-dev delete <stream_id>
126
131
  ```
127
132
 
133
+ ### Authentication
134
+
135
+ Use the `--auth` flag or `STREAM_AUTH` environment variable to authenticate:
136
+
137
+ ```bash
138
+ # Using environment variable
139
+ export STREAM_AUTH="Bearer my-token"
140
+ durable-stream-dev read my-stream
141
+
142
+ # Using --auth flag (overrides env var)
143
+ durable-stream-dev --auth "Bearer my-token" read my-stream
144
+
145
+ # Works with any auth scheme
146
+ durable-stream-dev --auth "Basic dXNlcjpwYXNz" read my-stream
147
+ durable-stream-dev --auth "ApiKey abc123" read my-stream
148
+ ```
149
+
128
150
  ## Complete Example Workflow
129
151
 
130
152
  ```bash
package/dist/index.cjs CHANGED
@@ -92,6 +92,38 @@ function parseWriteArgs(args) {
92
92
  //#endregion
93
93
  //#region src/index.ts
94
94
  const STREAM_URL = process.env.STREAM_URL || `http://localhost:4437`;
95
+ const STREAM_AUTH = process.env.STREAM_AUTH;
96
+ /**
97
+ * Parse global options (like --auth) from args.
98
+ * Falls back to STREAM_AUTH env var if --auth flag not provided.
99
+ * Returns the parsed options and remaining args.
100
+ */
101
+ function parseGlobalOptions(args) {
102
+ const options = {};
103
+ const remainingArgs = [];
104
+ for (let i = 0; i < args.length; i++) {
105
+ const arg = args[i];
106
+ if (arg === `--auth`) {
107
+ const value = args[i + 1];
108
+ if (!value || value.startsWith(`--`)) throw new Error(`--auth requires a value (e.g., --auth "Bearer token")`);
109
+ if (!value.trim()) throw new Error(`--auth value cannot be empty or whitespace`);
110
+ options.auth = value;
111
+ i++;
112
+ } else remainingArgs.push(arg);
113
+ }
114
+ if (!options.auth && STREAM_AUTH) {
115
+ if (!STREAM_AUTH.trim()) throw new Error(`STREAM_AUTH environment variable cannot be empty or whitespace`);
116
+ options.auth = STREAM_AUTH;
117
+ }
118
+ return {
119
+ options,
120
+ remainingArgs
121
+ };
122
+ }
123
+ function buildHeaders(options) {
124
+ if (options.auth) return { Authorization: options.auth };
125
+ return {};
126
+ }
95
127
  function printUsage() {
96
128
  console.error(`
97
129
  Usage:
@@ -101,6 +133,9 @@ Usage:
101
133
  durable-stream read <stream_id> Follow a stream and write to stdout
102
134
  durable-stream delete <stream_id> Delete a stream
103
135
 
136
+ Global Options:
137
+ --auth <value> Authorization header value (e.g., "Bearer my-token")
138
+
104
139
  Write Options:
105
140
  --content-type <type> Content-Type for the message (default: application/octet-stream)
106
141
  --json Write as JSON (input stored as single message)
@@ -108,18 +143,21 @@ Write Options:
108
143
 
109
144
  Environment Variables:
110
145
  STREAM_URL Base URL of the stream server (default: http://localhost:4437)
146
+ STREAM_AUTH Authorization header value (overridden by --auth flag)
111
147
  `);
112
148
  }
113
- async function createStream(streamId) {
149
+ async function createStream(streamId, headers) {
114
150
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
115
151
  try {
116
152
  await __durable_streams_client.DurableStream.create({
117
153
  url,
154
+ headers,
118
155
  contentType: `application/octet-stream`
119
156
  });
120
157
  console.log(`Created stream: ${streamId}`);
121
158
  } catch (error) {
122
- if (error instanceof Error) node_process.stderr.write(`Error creating stream: ${error.message}\n`);
159
+ const message = error instanceof Error ? error.message : String(error);
160
+ node_process.stderr.write(`Error creating stream: ${message}\n`);
123
161
  process.exit(1);
124
162
  }
125
163
  }
@@ -134,12 +172,13 @@ async function appendJson(stream, parsed) {
134
172
  }
135
173
  return count;
136
174
  }
137
- async function writeStream(streamId, contentType, batchJson, content) {
175
+ async function writeStream(streamId, contentType, batchJson, headers, content) {
138
176
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
139
177
  const isJson = isJsonContentType(contentType);
140
178
  try {
141
179
  const stream = new __durable_streams_client.DurableStream({
142
180
  url,
181
+ headers,
143
182
  contentType
144
183
  });
145
184
  if (content) {
@@ -182,34 +221,54 @@ async function writeStream(streamId, contentType, batchJson, content) {
182
221
  }
183
222
  }
184
223
  } catch (error) {
185
- if (error instanceof Error) node_process.stderr.write(`Error writing to stream: ${error.message}\n`);
224
+ const message = error instanceof Error ? error.message : String(error);
225
+ node_process.stderr.write(`Error writing to stream: ${message}\n`);
186
226
  process.exit(1);
187
227
  }
188
228
  }
189
- async function readStream(streamId) {
229
+ async function readStream(streamId, headers) {
190
230
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
191
231
  try {
192
- const stream = new __durable_streams_client.DurableStream({ url });
232
+ const stream = new __durable_streams_client.DurableStream({
233
+ url,
234
+ headers
235
+ });
193
236
  const res = await stream.stream({ live: `auto` });
194
237
  for await (const chunk of res.bodyStream()) if (chunk.length > 0) node_process.stdout.write(chunk);
195
238
  } catch (error) {
196
- if (error instanceof Error) node_process.stderr.write(`Error reading stream: ${error.message}\n`);
239
+ const message = error instanceof Error ? error.message : String(error);
240
+ node_process.stderr.write(`Error reading stream: ${message}\n`);
197
241
  process.exit(1);
198
242
  }
199
243
  }
200
- async function deleteStream(streamId) {
244
+ async function deleteStream(streamId, headers) {
201
245
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
202
246
  try {
203
- const stream = new __durable_streams_client.DurableStream({ url });
247
+ const stream = new __durable_streams_client.DurableStream({
248
+ url,
249
+ headers
250
+ });
204
251
  await stream.delete();
205
252
  console.log(`Deleted stream: ${streamId}`);
206
253
  } catch (error) {
207
- if (error instanceof Error) node_process.stderr.write(`Error deleting stream: ${error.message}\n`);
254
+ const message = error instanceof Error ? error.message : String(error);
255
+ node_process.stderr.write(`Error deleting stream: ${message}\n`);
208
256
  process.exit(1);
209
257
  }
210
258
  }
211
259
  async function main() {
212
- const args = process.argv.slice(2);
260
+ let options;
261
+ let args;
262
+ try {
263
+ const parsed = parseGlobalOptions(process.argv.slice(2));
264
+ options = parsed.options;
265
+ args = parsed.remainingArgs;
266
+ } catch (error) {
267
+ const message = error instanceof Error ? error.message : String(error);
268
+ node_process.stderr.write(`Error: ${message}\n`);
269
+ process.exit(1);
270
+ }
271
+ const headers = buildHeaders(options);
213
272
  if (args.length < 1) {
214
273
  printUsage();
215
274
  process.exit(1);
@@ -222,7 +281,7 @@ async function main() {
222
281
  printUsage();
223
282
  process.exit(1);
224
283
  }
225
- await createStream(args[1]);
284
+ await createStream(args[1], headers);
226
285
  break;
227
286
  }
228
287
  case `write`: {
@@ -236,11 +295,12 @@ async function main() {
236
295
  try {
237
296
  parsed = parseWriteArgs(args.slice(2));
238
297
  } catch (error) {
239
- if (error instanceof Error) node_process.stderr.write(`Error: ${error.message}\n`);
298
+ const message = error instanceof Error ? error.message : String(error);
299
+ node_process.stderr.write(`Error: ${message}\n`);
240
300
  process.exit(1);
241
301
  }
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);
302
+ if (!node_process.stdin.isTTY) await writeStream(streamId, parsed.contentType, parsed.batchJson, headers);
303
+ else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.batchJson, headers, parsed.content);
244
304
  else {
245
305
  node_process.stderr.write(`Error: content required (provide as argument or pipe to stdin)\n`);
246
306
  printUsage();
@@ -254,7 +314,7 @@ async function main() {
254
314
  printUsage();
255
315
  process.exit(1);
256
316
  }
257
- await readStream(args[1]);
317
+ await readStream(args[1], headers);
258
318
  break;
259
319
  }
260
320
  case `delete`: {
@@ -263,7 +323,7 @@ async function main() {
263
323
  printUsage();
264
324
  process.exit(1);
265
325
  }
266
- await deleteStream(args[1]);
326
+ await deleteStream(args[1], headers);
267
327
  break;
268
328
  }
269
329
  default:
@@ -279,11 +339,14 @@ function isMainModule() {
279
339
  return scriptPath === modulePath;
280
340
  }
281
341
  if (isMainModule()) main().catch((error) => {
282
- node_process.stderr.write(`Fatal error: ${error.message}\n`);
342
+ const message = error instanceof Error ? error.message : String(error);
343
+ node_process.stderr.write(`Fatal error: ${message}\n`);
283
344
  process.exit(1);
284
345
  });
285
346
 
286
347
  //#endregion
348
+ exports.buildHeaders = buildHeaders
287
349
  exports.flattenJsonForAppend = flattenJsonForAppend
288
350
  exports.isJsonContentType = isJsonContentType
351
+ exports.parseGlobalOptions = parseGlobalOptions
289
352
  exports.parseWriteArgs = parseWriteArgs
package/dist/index.d.cts CHANGED
@@ -30,4 +30,20 @@ interface ParsedWriteArgs {
30
30
  declare function parseWriteArgs(args: Array<string>): ParsedWriteArgs;
31
31
 
32
32
  //#endregion
33
- export { ParsedWriteArgs, flattenJsonForAppend, isJsonContentType, parseWriteArgs };
33
+ //#region src/index.d.ts
34
+ interface GlobalOptions {
35
+ auth?: string;
36
+ }
37
+ /**
38
+ * Parse global options (like --auth) from args.
39
+ * Falls back to STREAM_AUTH env var if --auth flag not provided.
40
+ * Returns the parsed options and remaining args.
41
+ */
42
+ declare function parseGlobalOptions(args: Array<string>): {
43
+ options: GlobalOptions;
44
+ remainingArgs: Array<string>;
45
+ };
46
+ declare function buildHeaders(options: GlobalOptions): Record<string, string>;
47
+
48
+ //#endregion
49
+ export { GlobalOptions, ParsedWriteArgs, buildHeaders, flattenJsonForAppend, isJsonContentType, parseGlobalOptions, parseWriteArgs };
package/dist/index.d.ts CHANGED
@@ -30,4 +30,20 @@ interface ParsedWriteArgs {
30
30
  declare function parseWriteArgs(args: Array<string>): ParsedWriteArgs;
31
31
 
32
32
  //#endregion
33
- export { ParsedWriteArgs, flattenJsonForAppend, isJsonContentType, parseWriteArgs };
33
+ //#region src/index.d.ts
34
+ interface GlobalOptions {
35
+ auth?: string;
36
+ }
37
+ /**
38
+ * Parse global options (like --auth) from args.
39
+ * Falls back to STREAM_AUTH env var if --auth flag not provided.
40
+ * Returns the parsed options and remaining args.
41
+ */
42
+ declare function parseGlobalOptions(args: Array<string>): {
43
+ options: GlobalOptions;
44
+ remainingArgs: Array<string>;
45
+ };
46
+ declare function buildHeaders(options: GlobalOptions): Record<string, string>;
47
+
48
+ //#endregion
49
+ export { GlobalOptions, ParsedWriteArgs, buildHeaders, flattenJsonForAppend, isJsonContentType, parseGlobalOptions, parseWriteArgs };
package/dist/index.js CHANGED
@@ -68,6 +68,38 @@ function parseWriteArgs(args) {
68
68
  //#endregion
69
69
  //#region src/index.ts
70
70
  const STREAM_URL = process.env.STREAM_URL || `http://localhost:4437`;
71
+ const STREAM_AUTH = process.env.STREAM_AUTH;
72
+ /**
73
+ * Parse global options (like --auth) from args.
74
+ * Falls back to STREAM_AUTH env var if --auth flag not provided.
75
+ * Returns the parsed options and remaining args.
76
+ */
77
+ function parseGlobalOptions(args) {
78
+ const options = {};
79
+ const remainingArgs = [];
80
+ for (let i = 0; i < args.length; i++) {
81
+ const arg = args[i];
82
+ if (arg === `--auth`) {
83
+ const value = args[i + 1];
84
+ if (!value || value.startsWith(`--`)) throw new Error(`--auth requires a value (e.g., --auth "Bearer token")`);
85
+ if (!value.trim()) throw new Error(`--auth value cannot be empty or whitespace`);
86
+ options.auth = value;
87
+ i++;
88
+ } else remainingArgs.push(arg);
89
+ }
90
+ if (!options.auth && STREAM_AUTH) {
91
+ if (!STREAM_AUTH.trim()) throw new Error(`STREAM_AUTH environment variable cannot be empty or whitespace`);
92
+ options.auth = STREAM_AUTH;
93
+ }
94
+ return {
95
+ options,
96
+ remainingArgs
97
+ };
98
+ }
99
+ function buildHeaders(options) {
100
+ if (options.auth) return { Authorization: options.auth };
101
+ return {};
102
+ }
71
103
  function printUsage() {
72
104
  console.error(`
73
105
  Usage:
@@ -77,6 +109,9 @@ Usage:
77
109
  durable-stream read <stream_id> Follow a stream and write to stdout
78
110
  durable-stream delete <stream_id> Delete a stream
79
111
 
112
+ Global Options:
113
+ --auth <value> Authorization header value (e.g., "Bearer my-token")
114
+
80
115
  Write Options:
81
116
  --content-type <type> Content-Type for the message (default: application/octet-stream)
82
117
  --json Write as JSON (input stored as single message)
@@ -84,18 +119,21 @@ Write Options:
84
119
 
85
120
  Environment Variables:
86
121
  STREAM_URL Base URL of the stream server (default: http://localhost:4437)
122
+ STREAM_AUTH Authorization header value (overridden by --auth flag)
87
123
  `);
88
124
  }
89
- async function createStream(streamId) {
125
+ async function createStream(streamId, headers) {
90
126
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
91
127
  try {
92
128
  await DurableStream.create({
93
129
  url,
130
+ headers,
94
131
  contentType: `application/octet-stream`
95
132
  });
96
133
  console.log(`Created stream: ${streamId}`);
97
134
  } catch (error) {
98
- if (error instanceof Error) stderr.write(`Error creating stream: ${error.message}\n`);
135
+ const message = error instanceof Error ? error.message : String(error);
136
+ stderr.write(`Error creating stream: ${message}\n`);
99
137
  process.exit(1);
100
138
  }
101
139
  }
@@ -110,12 +148,13 @@ async function appendJson(stream, parsed) {
110
148
  }
111
149
  return count;
112
150
  }
113
- async function writeStream(streamId, contentType, batchJson, content) {
151
+ async function writeStream(streamId, contentType, batchJson, headers, content) {
114
152
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
115
153
  const isJson = isJsonContentType(contentType);
116
154
  try {
117
155
  const stream = new DurableStream({
118
156
  url,
157
+ headers,
119
158
  contentType
120
159
  });
121
160
  if (content) {
@@ -158,34 +197,54 @@ async function writeStream(streamId, contentType, batchJson, content) {
158
197
  }
159
198
  }
160
199
  } catch (error) {
161
- if (error instanceof Error) stderr.write(`Error writing to stream: ${error.message}\n`);
200
+ const message = error instanceof Error ? error.message : String(error);
201
+ stderr.write(`Error writing to stream: ${message}\n`);
162
202
  process.exit(1);
163
203
  }
164
204
  }
165
- async function readStream(streamId) {
205
+ async function readStream(streamId, headers) {
166
206
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
167
207
  try {
168
- const stream = new DurableStream({ url });
208
+ const stream = new DurableStream({
209
+ url,
210
+ headers
211
+ });
169
212
  const res = await stream.stream({ live: `auto` });
170
213
  for await (const chunk of res.bodyStream()) if (chunk.length > 0) stdout.write(chunk);
171
214
  } catch (error) {
172
- if (error instanceof Error) stderr.write(`Error reading stream: ${error.message}\n`);
215
+ const message = error instanceof Error ? error.message : String(error);
216
+ stderr.write(`Error reading stream: ${message}\n`);
173
217
  process.exit(1);
174
218
  }
175
219
  }
176
- async function deleteStream(streamId) {
220
+ async function deleteStream(streamId, headers) {
177
221
  const url = `${STREAM_URL}/v1/stream/${streamId}`;
178
222
  try {
179
- const stream = new DurableStream({ url });
223
+ const stream = new DurableStream({
224
+ url,
225
+ headers
226
+ });
180
227
  await stream.delete();
181
228
  console.log(`Deleted stream: ${streamId}`);
182
229
  } catch (error) {
183
- if (error instanceof Error) stderr.write(`Error deleting stream: ${error.message}\n`);
230
+ const message = error instanceof Error ? error.message : String(error);
231
+ stderr.write(`Error deleting stream: ${message}\n`);
184
232
  process.exit(1);
185
233
  }
186
234
  }
187
235
  async function main() {
188
- const args = process.argv.slice(2);
236
+ let options;
237
+ let args;
238
+ try {
239
+ const parsed = parseGlobalOptions(process.argv.slice(2));
240
+ options = parsed.options;
241
+ args = parsed.remainingArgs;
242
+ } catch (error) {
243
+ const message = error instanceof Error ? error.message : String(error);
244
+ stderr.write(`Error: ${message}\n`);
245
+ process.exit(1);
246
+ }
247
+ const headers = buildHeaders(options);
189
248
  if (args.length < 1) {
190
249
  printUsage();
191
250
  process.exit(1);
@@ -198,7 +257,7 @@ async function main() {
198
257
  printUsage();
199
258
  process.exit(1);
200
259
  }
201
- await createStream(args[1]);
260
+ await createStream(args[1], headers);
202
261
  break;
203
262
  }
204
263
  case `write`: {
@@ -212,11 +271,12 @@ async function main() {
212
271
  try {
213
272
  parsed = parseWriteArgs(args.slice(2));
214
273
  } catch (error) {
215
- if (error instanceof Error) stderr.write(`Error: ${error.message}\n`);
274
+ const message = error instanceof Error ? error.message : String(error);
275
+ stderr.write(`Error: ${message}\n`);
216
276
  process.exit(1);
217
277
  }
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);
278
+ if (!stdin.isTTY) await writeStream(streamId, parsed.contentType, parsed.batchJson, headers);
279
+ else if (parsed.content) await writeStream(streamId, parsed.contentType, parsed.batchJson, headers, parsed.content);
220
280
  else {
221
281
  stderr.write(`Error: content required (provide as argument or pipe to stdin)\n`);
222
282
  printUsage();
@@ -230,7 +290,7 @@ async function main() {
230
290
  printUsage();
231
291
  process.exit(1);
232
292
  }
233
- await readStream(args[1]);
293
+ await readStream(args[1], headers);
234
294
  break;
235
295
  }
236
296
  case `delete`: {
@@ -239,7 +299,7 @@ async function main() {
239
299
  printUsage();
240
300
  process.exit(1);
241
301
  }
242
- await deleteStream(args[1]);
302
+ await deleteStream(args[1], headers);
243
303
  break;
244
304
  }
245
305
  default:
@@ -255,9 +315,10 @@ function isMainModule() {
255
315
  return scriptPath === modulePath;
256
316
  }
257
317
  if (isMainModule()) main().catch((error) => {
258
- stderr.write(`Fatal error: ${error.message}\n`);
318
+ const message = error instanceof Error ? error.message : String(error);
319
+ stderr.write(`Fatal error: ${message}\n`);
259
320
  process.exit(1);
260
321
  });
261
322
 
262
323
  //#endregion
263
- export { flattenJsonForAppend, isJsonContentType, parseWriteArgs };
324
+ export { buildHeaders, flattenJsonForAppend, isJsonContentType, parseGlobalOptions, 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.5",
4
+ "version": "0.1.7",
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.4"
15
+ "@durable-streams/client": "0.1.5"
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.5"
23
+ "@durable-streams/server": "0.1.6"
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=18.0.0"