drtrace 0.2.0 → 0.4.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.
Files changed (53) hide show
  1. package/README.md +74 -4
  2. package/agents/CONTRIBUTING.md +296 -0
  3. package/agents/README.md +174 -0
  4. package/agents/daemon-method-selection.md +370 -0
  5. package/agents/integration-guides/cpp-best-practices.md +218 -0
  6. package/agents/integration-guides/cpp-ros-integration.md +88 -0
  7. package/agents/log-analysis.md +218 -0
  8. package/agents/log-help.md +226 -0
  9. package/agents/log-init.md +933 -0
  10. package/agents/log-it.md +1126 -0
  11. package/bin/init.js +4 -4
  12. package/dist/bin/init.js +31 -0
  13. package/dist/browser.d.ts +28 -0
  14. package/dist/browser.js +91 -0
  15. package/dist/config-schema.d.ts +2 -2
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +2 -2
  18. package/dist/init.d.ts +44 -2
  19. package/dist/init.js +460 -30
  20. package/dist/logger.d.ts +7 -0
  21. package/dist/logger.js +30 -4
  22. package/dist/node.d.ts +13 -0
  23. package/dist/node.js +67 -0
  24. package/dist/resources/agents/CONTRIBUTING.md +296 -0
  25. package/dist/resources/agents/README.md +174 -0
  26. package/dist/resources/agents/daemon-method-selection.md +370 -0
  27. package/dist/resources/agents/integration-guides/cpp-best-practices.md +218 -0
  28. package/dist/resources/agents/integration-guides/cpp-ros-integration.md +88 -0
  29. package/dist/resources/agents/log-analysis.md +218 -0
  30. package/dist/resources/agents/log-help.md +226 -0
  31. package/dist/resources/agents/log-init.md +933 -0
  32. package/dist/resources/agents/log-it.md +1126 -0
  33. package/dist/resources/cpp/drtrace_sink.hpp +1249 -0
  34. package/dist/transport.js +5 -1
  35. package/dist/types.d.ts +8 -2
  36. package/package.json +28 -4
  37. package/.eslintrc.js +0 -20
  38. package/jest.config.js +0 -11
  39. package/src/client.ts +0 -68
  40. package/src/config-schema.ts +0 -115
  41. package/src/config.ts +0 -326
  42. package/src/index.ts +0 -3
  43. package/src/init.ts +0 -451
  44. package/src/logger.ts +0 -56
  45. package/src/queue.ts +0 -105
  46. package/src/transport.ts +0 -60
  47. package/src/types.ts +0 -20
  48. package/tests/client.test.ts +0 -66
  49. package/tests/config-schema.test.ts +0 -198
  50. package/tests/config.test.ts +0 -456
  51. package/tests/queue.test.ts +0 -72
  52. package/tests/transport.test.ts +0 -52
  53. package/tsconfig.json +0 -18
package/src/init.ts DELETED
@@ -1,451 +0,0 @@
1
- /**
2
- * Interactive project initialization for DrTrace (JavaScript/TypeScript)
3
- * Mirrors Python init_project.py with interactive prompts via prompts library
4
- */
5
-
6
- import * as fs from "fs";
7
- import * as path from "path";
8
- import prompts from "prompts";
9
- import { ConfigSchema, DrTraceConfig } from "./config-schema";
10
-
11
- export interface InitOptions {
12
- projectRoot?: string;
13
- nonInteractive?: boolean;
14
- config?: Partial<DrTraceConfig>;
15
- }
16
-
17
- export class ProjectInitializer {
18
- private projectRoot: string;
19
- private drtraceDir: string;
20
- private configPath: string;
21
-
22
- constructor(projectRoot: string = process.cwd()) {
23
- this.projectRoot = projectRoot;
24
- this.drtraceDir = path.join(projectRoot, "_drtrace");
25
- this.configPath = path.join(this.drtraceDir, "config.json");
26
- }
27
-
28
- /**
29
- * Run the interactive initialization workflow
30
- */
31
- async runInteractive(): Promise<boolean> {
32
- console.log("\nšŸš€ DrTrace Project Initialization\n");
33
- console.log("=".repeat(50));
34
-
35
- // Collect project information
36
- console.log("\nšŸ“‹ Project Information:");
37
- const projectName = await this.promptText(
38
- "Project name",
39
- "my-app"
40
- );
41
- const applicationId = await this.promptText(
42
- "Application ID",
43
- projectName.toLowerCase().replace(/\s+/g, "-")
44
- );
45
-
46
- // Language selection
47
- console.log("\nšŸ”§ Technology Stack:");
48
- const language = await this.promptChoice(
49
- "Select language/runtime:",
50
- ["python", "javascript", "both"],
51
- "javascript"
52
- );
53
-
54
- // Daemon configuration
55
- console.log("\nšŸ“” DrTrace Daemon Configuration:");
56
- const daemonUrl = await this.promptText(
57
- "Daemon URL",
58
- "http://localhost:8001"
59
- );
60
- const enabled = await this.promptYesNo("Enable DrTrace by default?", true);
61
-
62
- // Environment selection
63
- console.log("\nšŸŒ Environments:");
64
- const selectedEnvs = await this.promptMultiSelect(
65
- "Which environments to configure?",
66
- ["development", "staging", "production", "ci"]
67
- );
68
- const environments = selectedEnvs.length > 0 ? selectedEnvs : ["development"];
69
-
70
- // Agent configuration
71
- console.log("\nšŸ¤– Agent Integration (Optional):");
72
- const agentEnabled = await this.promptYesNo(
73
- "Enable agent interface?",
74
- false
75
- );
76
-
77
- let agentFramework = "bmad";
78
- if (agentEnabled) {
79
- agentFramework = await this.promptChoice(
80
- "Select agent framework:",
81
- ["bmad", "langchain", "other"],
82
- "bmad"
83
- );
84
- }
85
-
86
- // Check for existing config
87
- if (!this.handleExistingConfig()) {
88
- console.log("\nāŒ Initialization cancelled.");
89
- return false;
90
- }
91
-
92
- // Create directory structure
93
- this.createDirectoryStructure();
94
-
95
- // Generate and save main config
96
- const config = ConfigSchema.getDefaultConfig({
97
- project_name: projectName,
98
- application_id: applicationId,
99
- language: language as "python" | "javascript" | "both",
100
- daemon_url: daemonUrl,
101
- enabled,
102
- environments,
103
- agent_enabled: agentEnabled,
104
- agent_framework: agentFramework as "bmad" | "langchain" | "other",
105
- });
106
-
107
- ConfigSchema.save(config, this.configPath);
108
- console.log(`\nāœ“ Main config created: ${this.configPath}`);
109
-
110
- // Generate environment-specific configs
111
- this.generateEnvironmentConfigs(config);
112
-
113
- // Copy default agent spec
114
- if (agentEnabled) {
115
- this.copyAgentSpec();
116
- }
117
-
118
- // Generate .env.example
119
- this.generateEnvExample(config);
120
-
121
- // Generate README
122
- this.generateReadme();
123
-
124
- // Summary and next steps
125
- this.printSummary(config);
126
-
127
- return true;
128
- }
129
-
130
- /**
131
- * Prompt for text input
132
- */
133
- private async promptText(
134
- question: string,
135
- defaultValue?: string
136
- ): Promise<string> {
137
- const response = await prompts({
138
- type: "text",
139
- name: "value",
140
- message: question,
141
- initial: defaultValue,
142
- });
143
- return response.value || defaultValue || "";
144
- }
145
-
146
- /**
147
- * Prompt for yes/no
148
- */
149
- private async promptYesNo(
150
- question: string,
151
- defaultValue: boolean = true
152
- ): Promise<boolean> {
153
- const response = await prompts({
154
- type: "confirm",
155
- name: "value",
156
- message: question,
157
- initial: defaultValue,
158
- });
159
- return response.value;
160
- }
161
-
162
- /**
163
- * Prompt for single choice
164
- */
165
- private async promptChoice(
166
- question: string,
167
- choices: string[],
168
- defaultValue?: string
169
- ): Promise<string> {
170
- const response = await prompts({
171
- type: "select",
172
- name: "value",
173
- message: question,
174
- choices: choices.map((c) => ({ title: c, value: c })),
175
- initial: defaultValue ? choices.indexOf(defaultValue) : 0,
176
- });
177
- return response.value;
178
- }
179
-
180
- /**
181
- * Prompt for multiple selections
182
- */
183
- private async promptMultiSelect(
184
- question: string,
185
- choices: string[]
186
- ): Promise<string[]> {
187
- const response = await prompts({
188
- type: "multiselect",
189
- name: "value",
190
- message: question,
191
- choices: choices.map((c) => ({ title: c, value: c })),
192
- initial: 0, // Development selected by default
193
- });
194
- return response.value || [];
195
- }
196
-
197
- /**
198
- * Handle existing config
199
- */
200
- private handleExistingConfig(): boolean {
201
- if (!fs.existsSync(this.configPath)) {
202
- return true;
203
- }
204
-
205
- console.log(
206
- `\nāš ļø Configuration already exists at ${this.configPath}`
207
- );
208
- // In interactive mode, we would prompt here
209
- // For now, we'll require confirmation via prompts
210
- return true;
211
- }
212
-
213
- /**
214
- * Create _drtrace directory structure
215
- */
216
- private createDirectoryStructure(): void {
217
- const agentsDir = path.join(this.drtraceDir, "agents");
218
- fs.mkdirSync(agentsDir, { recursive: true });
219
- console.log(`āœ“ Created directory: ${this.drtraceDir}`);
220
- }
221
-
222
- /**
223
- * Generate environment-specific configs
224
- */
225
- private generateEnvironmentConfigs(baseConfig: DrTraceConfig): void {
226
- const environments = baseConfig.environments || ["development"];
227
-
228
- for (const env of environments) {
229
- const envConfig = { ...baseConfig };
230
- const envConfigPath = path.join(this.drtraceDir, `config.${env}.json`);
231
- ConfigSchema.save(envConfig, envConfigPath);
232
- console.log(`āœ“ Generated: ${envConfigPath}`);
233
- }
234
- }
235
-
236
- /**
237
- * Copy agent spec to _drtrace/agents/
238
- */
239
- private copyAgentSpec(): void {
240
- try {
241
- const agentPath = path.join(
242
- this.drtraceDir,
243
- "agents",
244
- "log-analysis.md"
245
- );
246
- const defaultSpec = this.getDefaultAgentSpec();
247
- fs.writeFileSync(agentPath, defaultSpec);
248
- console.log(`āœ“ Copied agent spec: ${agentPath}`);
249
- } catch (error) {
250
- console.warn(`āš ļø Could not copy agent spec: ${error}`);
251
- }
252
- }
253
-
254
- /**
255
- * Get default agent spec from shared agents/ or bundled resources
256
- *
257
- * Search order:
258
- * 1. Root repo agents/ directory (development)
259
- * 2. Bundled default agent from node_modules
260
- */
261
- private getDefaultAgentSpec(): string {
262
- // Try root agents/ first (development mode)
263
- const rootAgentPath = path.join(
264
- this.projectRoot,
265
- "..",
266
- "..",
267
- "agents",
268
- "log-analysis.default.md"
269
- );
270
-
271
- try {
272
- if (fs.existsSync(rootAgentPath)) {
273
- return fs.readFileSync(rootAgentPath, "utf-8");
274
- }
275
- } catch (error) {
276
- // Fall through to bundled resource
277
- }
278
-
279
- // Fallback to bundled default agent
280
- return this.getBundledAgentSpec();
281
- }
282
-
283
- /**
284
- * Get bundled agent spec (fallback when root agents/ not available)
285
- */
286
- private getBundledAgentSpec(): string {
287
- return `---
288
- name: "log-analysis"
289
- description: "Log Analysis Agent"
290
- ---
291
-
292
- You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
293
-
294
- \`\`\`xml
295
- <agent id="log-analysis.agent.yaml" name="drtrace" title="Log Analysis Agent" icon="šŸ“Š">
296
- <activation critical="MANDATORY">
297
- <step n="1">Load persona from this current agent file (already in context)</step>
298
- <step n="2">Remember: You are a Log Analysis Specialist</step>
299
- <step n="3">Show greeting, then display numbered list of menu items</step>
300
- <step n="4">STOP and WAIT for user input</step>
301
- <step n="5">On user input: Process as natural language query</step>
302
- </activation>
303
-
304
- <persona>
305
- <role>Log Analysis Specialist</role>
306
- <identity>Expert at analyzing application logs and identifying root causes of errors</identity>
307
- <communication_style>Clear and concise. Provides structured markdown responses.</communication_style>
308
- </persona>
309
- \`\`\`
310
-
311
- ## Log Analysis Guide
312
-
313
- This agent helps you understand what went wrong in your application by analyzing logs.
314
-
315
- ### How to Use
316
-
317
- 1. Describe the error or issue
318
- 2. Provide log entries or time window
319
- 3. Get root cause analysis with suggested fixes
320
- `;
321
- }
322
- private generateEnvExample(config: DrTraceConfig): void {
323
- const envFile = path.join(this.drtraceDir, ".env.example");
324
- const content = `# DrTrace Configuration - Copy to .env and customize
325
-
326
- # Basic Configuration
327
- DRTRACE_APPLICATION_ID=${config.application_id}
328
- DRTRACE_DAEMON_URL=${config.daemon_url || "http://localhost:8001"}
329
- DRTRACE_ENABLED=${config.enabled !== false ? "true" : "false"}
330
-
331
- # Environment-specific overrides
332
- # Uncomment and modify for your environment
333
- # DRTRACE_DAEMON_HOST=localhost
334
- # DRTRACE_DAEMON_PORT=8001
335
- # DRTRACE_RETENTION_DAYS=7
336
-
337
- # Agent configuration
338
- # DRTRACE_AGENT_ENABLED=false
339
- # DRTRACE_AGENT_FRAMEWORK=bmad
340
- `;
341
- fs.writeFileSync(envFile, content);
342
- console.log(`āœ“ Generated: ${envFile}`);
343
- }
344
-
345
- /**
346
- * Generate README.md
347
- */
348
- private generateReadme(): void {
349
- const readmeFile = path.join(this.drtraceDir, "README.md");
350
- const content = `# DrTrace Configuration Guide
351
-
352
- This directory contains configuration files for the DrTrace (Web Workflow Integration) system.
353
-
354
- ## Files
355
-
356
- - **config.json** - Main project configuration
357
- - **config.{environment}.json** - Environment-specific overrides
358
- - **.env.example** - Environment variable template
359
- - **agents/** - Agent specifications and custom rules
360
-
361
- ## Configuration
362
-
363
- ### Basic Setup
364
-
365
- 1. Review and customize \`config.json\`
366
- 2. For environment-specific settings, edit \`config.{environment}.json\`
367
- 3. Create \`.env\` from \`.env.example\` and set your environment variables
368
-
369
- ### Environment Variables
370
-
371
- - \`DRTRACE_APPLICATION_ID\` - Unique application identifier
372
- - \`DRTRACE_DAEMON_URL\` - URL of the DrTrace daemon
373
- - \`DRTRACE_ENABLED\` - Enable/disable DrTrace globally (true/false)
374
- - \`DRTRACE_RETENTION_DAYS\` - How long to retain logs (days)
375
-
376
- ### Environments
377
-
378
- Configure separate settings for:
379
- - **development** - Local development setup
380
- - **staging** - Pre-production testing
381
- - **production** - Live environment
382
- - **ci** - Continuous integration/testing
383
-
384
- ## Usage
385
-
386
- Load configuration based on your environment:
387
-
388
- \`\`\`javascript
389
- import { ConfigSchema } from 'drtrace';
390
- const config = ConfigSchema.load('./_drtrace/config.json');
391
- \`\`\`
392
-
393
- ## Further Reading
394
-
395
- - See \`docs/\` for complete documentation
396
- - Check \`agents/\` for agent specifications
397
- `;
398
- fs.writeFileSync(readmeFile, content);
399
- console.log(`āœ“ Generated: ${readmeFile}`);
400
- }
401
-
402
- /**
403
- * Print initialization summary
404
- */
405
- private printSummary(config: DrTraceConfig): void {
406
- console.log("\n" + "=".repeat(50));
407
- console.log("āœ… Project Initialization Complete!\n");
408
-
409
- console.log(`šŸ“ Configuration Location: ${this.drtraceDir}\n`);
410
-
411
- console.log("šŸ“‹ Generated Files:");
412
- console.log(` • ${this.configPath}`);
413
- for (const env of config.environments || []) {
414
- console.log(` • ${path.join(this.drtraceDir, `config.${env}.json`)}`);
415
- }
416
- console.log(` • ${path.join(this.drtraceDir, ".env.example")}`);
417
- console.log(` • ${path.join(this.drtraceDir, "README.md")}`);
418
-
419
- if (config.agent?.enabled) {
420
- console.log(
421
- ` • ${path.join(this.drtraceDir, "agents", "log-analysis.md")}`
422
- );
423
- }
424
-
425
- console.log("\nšŸ“– Next Steps:");
426
- console.log(` 1. Review ${this.configPath}`);
427
- console.log(` 2. Create .env: cp ${path.join(this.drtraceDir, ".env.example")} .env`);
428
- console.log(` 3. Start the daemon: drtrace daemon start`);
429
- console.log(
430
- ` 4. Read ${path.join(this.drtraceDir, "README.md")} for more details`
431
- );
432
-
433
- console.log("\n" + "=".repeat(50) + "\n");
434
- }
435
- }
436
-
437
- /**
438
- * Entry point for init command
439
- */
440
- export async function runInitProject(
441
- projectRoot?: string
442
- ): Promise<number> {
443
- try {
444
- const initializer = new ProjectInitializer(projectRoot);
445
- const success = await initializer.runInteractive();
446
- return success ? 0 : 1;
447
- } catch (error) {
448
- console.error(`\nāŒ Error during initialization:`, error);
449
- return 1;
450
- }
451
- }
package/src/logger.ts DELETED
@@ -1,56 +0,0 @@
1
- import type { LogEvent, LogLevel } from './types';
2
- import { LogQueue } from './queue';
3
-
4
- export class DrTraceLogger {
5
- private queue: LogQueue;
6
- private applicationId: string;
7
- private logLevel: LogLevel;
8
- private originalConsole?: { log: typeof console.log; error: typeof console.error };
9
-
10
- constructor(opts: { queue: LogQueue; applicationId: string; logLevel: LogLevel }) {
11
- this.queue = opts.queue;
12
- this.applicationId = opts.applicationId;
13
- this.logLevel = opts.logLevel || 'info';
14
- }
15
-
16
- attachToConsole(): void {
17
- if (this.originalConsole) return;
18
- this.originalConsole = { log: console.log, error: console.error };
19
-
20
- console.log = (...args: any[]) => {
21
- try {
22
- this.log('info', args.map(String).join(' '));
23
- } catch {
24
- // Silently ignore logging errors
25
- }
26
- this.originalConsole!.log.apply(console, args);
27
- };
28
-
29
- console.error = (...args: any[]) => {
30
- try {
31
- this.log('error', args.map(String).join(' '));
32
- } catch {
33
- // Silently ignore logging errors
34
- }
35
- this.originalConsole!.error.apply(console, args);
36
- };
37
- }
38
-
39
- detachFromConsole(): void {
40
- if (!this.originalConsole) return;
41
- console.log = this.originalConsole.log;
42
- console.error = this.originalConsole.error;
43
- this.originalConsole = undefined;
44
- }
45
-
46
- log(level: LogLevel, message: string, context?: Record<string, unknown>): void {
47
- const event: LogEvent = {
48
- timestamp: new Date().toISOString(),
49
- applicationId: this.applicationId,
50
- level,
51
- message,
52
- context,
53
- };
54
- this.queue.push(event);
55
- }
56
- }
package/src/queue.ts DELETED
@@ -1,105 +0,0 @@
1
- import type { LogEvent } from './types';
2
- import { Transport } from './transport';
3
-
4
- export class LogQueue {
5
- private buffer: LogEvent[] = [];
6
- private transport: Transport;
7
- private batchSize: number;
8
- private flushIntervalMs: number;
9
- private timer: NodeJS.Timeout | null = null;
10
- private running = false;
11
- private maxQueueSize: number;
12
- private exitHandlerBound = false;
13
- private exitHandler?: () => Promise<void>;
14
-
15
- constructor(opts: { transport: Transport; batchSize: number; flushIntervalMs: number; maxQueueSize?: number }) {
16
- this.transport = opts.transport;
17
- this.batchSize = Math.max(1, opts.batchSize);
18
- this.flushIntervalMs = Math.max(100, opts.flushIntervalMs);
19
- this.maxQueueSize = Math.max(1, opts.maxQueueSize ?? 10000);
20
- }
21
-
22
- start(): void {
23
- if (this.running) return;
24
- this.running = true;
25
- this.scheduleFlush();
26
- this.registerExitHandlers();
27
- }
28
-
29
- stop(): void {
30
- this.running = false;
31
- if (this.timer) {
32
- clearTimeout(this.timer);
33
- this.timer = null;
34
- }
35
- this.unregisterExitHandlers();
36
- }
37
-
38
- push(event: LogEvent): void {
39
- this.buffer.push(event);
40
- if (this.buffer.length > this.maxQueueSize) {
41
- // Drop oldest to enforce limit
42
- const dropCount = this.buffer.length - this.maxQueueSize;
43
- this.buffer.splice(0, dropCount);
44
- console.warn?.(`DrTrace: maxQueueSize exceeded, dropped ${dropCount} log(s)`);
45
- }
46
- if (this.buffer.length >= this.batchSize) {
47
- this.flush();
48
- }
49
- }
50
-
51
- async flush(): Promise<void> {
52
- if (this.buffer.length === 0) {
53
- this.scheduleFlush();
54
- return;
55
- }
56
- const toSend = this.buffer.splice(0, this.buffer.length);
57
- try {
58
- await this.transport.sendBatch(toSend);
59
- } finally {
60
- this.scheduleFlush();
61
- }
62
- }
63
-
64
- private scheduleFlush(): void {
65
- if (!this.running) return;
66
- if (this.timer) {
67
- clearTimeout(this.timer);
68
- this.timer = null;
69
- }
70
- this.timer = setTimeout(() => {
71
- this.flush();
72
- }, this.flushIntervalMs);
73
- this.timer.unref?.();
74
- }
75
-
76
- private registerExitHandlers(): void {
77
- if (this.exitHandlerBound) return;
78
- const handler = async () => {
79
- try {
80
- const flushPromise = this.flush();
81
- const timeout = new Promise((resolve) => {
82
- const to = setTimeout(resolve, 2000);
83
- (to as any).unref?.();
84
- });
85
- await Promise.race([flushPromise, timeout]);
86
- } catch {
87
- // ignore
88
- }
89
- };
90
- this.exitHandler = handler;
91
- process.on('SIGINT', handler);
92
- process.on('SIGTERM', handler);
93
- this.exitHandlerBound = true;
94
- }
95
-
96
- private unregisterExitHandlers(): void {
97
- if (!this.exitHandlerBound) return;
98
- if (this.exitHandler) {
99
- process.removeListener('SIGINT', this.exitHandler);
100
- process.removeListener('SIGTERM', this.exitHandler);
101
- this.exitHandler = undefined;
102
- }
103
- this.exitHandlerBound = false;
104
- }
105
- }
package/src/transport.ts DELETED
@@ -1,60 +0,0 @@
1
- import type { LogEvent } from './types';
2
-
3
- const DEFAULT_TIMEOUT_MS = 5000;
4
- const DEFAULT_MAX_RETRIES = 3;
5
- const BACKOFF_MS = [100, 200, 400];
6
- const USER_AGENT = 'drtrace-client-js/0.1.0';
7
-
8
- export class Transport {
9
- private daemonUrl: string;
10
- private timeoutMs: number;
11
- private maxRetries: number;
12
-
13
- constructor(opts: { daemonUrl: string; timeoutMs?: number; maxRetries?: number }) {
14
- this.daemonUrl = opts.daemonUrl.replace(/\/$/, '');
15
- this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
16
- this.maxRetries = Math.max(0, opts.maxRetries ?? DEFAULT_MAX_RETRIES);
17
- }
18
-
19
- async sendBatch(events: LogEvent[]): Promise<void> {
20
- if (events.length === 0) return;
21
- const url = `${this.daemonUrl}/logs/ingest`;
22
- const payload = { logs: events };
23
-
24
- const fetchImpl: typeof fetch | undefined = (globalThis as any).fetch;
25
- if (!fetchImpl) return; // Non-blocking skip
26
-
27
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
28
- const controller = new AbortController();
29
- const to = setTimeout(() => controller.abort(), this.timeoutMs);
30
- to.unref?.();
31
- try {
32
- const res = await fetchImpl(url, {
33
- method: 'POST',
34
- headers: {
35
- 'Content-Type': 'application/json',
36
- 'User-Agent': USER_AGENT,
37
- },
38
- body: JSON.stringify(payload),
39
- signal: controller.signal,
40
- });
41
- // Consume body to free resources
42
- res.body && (await res.text().catch(() => ''));
43
- // Treat non-2xx as retryable
44
- if (res.ok) return;
45
- } catch (_err) {
46
- // swallow and retry
47
- } finally {
48
- clearTimeout(to);
49
- }
50
-
51
- if (attempt < this.maxRetries) {
52
- const delay = BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)];
53
- await new Promise((resolve) => {
54
- const to = setTimeout(resolve, delay);
55
- to.unref?.();
56
- });
57
- }
58
- }
59
- }
60
- }
package/src/types.ts DELETED
@@ -1,20 +0,0 @@
1
- export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
-
3
- export interface LogEvent {
4
- timestamp: string;
5
- applicationId: string;
6
- level: LogLevel;
7
- message: string;
8
- context?: Record<string, unknown>;
9
- }
10
-
11
- export interface ClientOptions {
12
- applicationId: string;
13
- daemonUrl: string;
14
- enabled?: boolean;
15
- logLevel?: LogLevel;
16
- batchSize?: number;
17
- flushIntervalMs?: number;
18
- maxRetries?: number;
19
- maxQueueSize?: number;
20
- }