@runtime-digital-twin/sdk 1.0.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 (56) hide show
  1. package/README.md +214 -0
  2. package/dist/constants.d.ts +11 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +13 -0
  5. package/dist/db-wrapper.d.ts +258 -0
  6. package/dist/db-wrapper.d.ts.map +1 -0
  7. package/dist/db-wrapper.js +636 -0
  8. package/dist/event-envelope.d.ts +35 -0
  9. package/dist/event-envelope.d.ts.map +1 -0
  10. package/dist/event-envelope.js +101 -0
  11. package/dist/fastify-plugin.d.ts +29 -0
  12. package/dist/fastify-plugin.d.ts.map +1 -0
  13. package/dist/fastify-plugin.js +243 -0
  14. package/dist/http-sentinels.d.ts +39 -0
  15. package/dist/http-sentinels.d.ts.map +1 -0
  16. package/dist/http-sentinels.js +169 -0
  17. package/dist/http-wrapper.d.ts +25 -0
  18. package/dist/http-wrapper.d.ts.map +1 -0
  19. package/dist/http-wrapper.js +477 -0
  20. package/dist/index.d.ts +19 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +93 -0
  23. package/dist/invariants.d.ts +58 -0
  24. package/dist/invariants.d.ts.map +1 -0
  25. package/dist/invariants.js +192 -0
  26. package/dist/multi-service-edge-builder.d.ts +80 -0
  27. package/dist/multi-service-edge-builder.d.ts.map +1 -0
  28. package/dist/multi-service-edge-builder.js +107 -0
  29. package/dist/outbound-matcher.d.ts +192 -0
  30. package/dist/outbound-matcher.d.ts.map +1 -0
  31. package/dist/outbound-matcher.js +457 -0
  32. package/dist/peer-service-resolver.d.ts +22 -0
  33. package/dist/peer-service-resolver.d.ts.map +1 -0
  34. package/dist/peer-service-resolver.js +85 -0
  35. package/dist/redaction.d.ts +111 -0
  36. package/dist/redaction.d.ts.map +1 -0
  37. package/dist/redaction.js +487 -0
  38. package/dist/replay-logger.d.ts +438 -0
  39. package/dist/replay-logger.d.ts.map +1 -0
  40. package/dist/replay-logger.js +434 -0
  41. package/dist/root-cause-analyzer.d.ts +45 -0
  42. package/dist/root-cause-analyzer.d.ts.map +1 -0
  43. package/dist/root-cause-analyzer.js +606 -0
  44. package/dist/shape-digest-utils.d.ts +45 -0
  45. package/dist/shape-digest-utils.d.ts.map +1 -0
  46. package/dist/shape-digest-utils.js +154 -0
  47. package/dist/trace-bundle-writer.d.ts +52 -0
  48. package/dist/trace-bundle-writer.d.ts.map +1 -0
  49. package/dist/trace-bundle-writer.js +267 -0
  50. package/dist/trace-loader.d.ts +69 -0
  51. package/dist/trace-loader.d.ts.map +1 -0
  52. package/dist/trace-loader.js +146 -0
  53. package/dist/trace-uploader.d.ts +25 -0
  54. package/dist/trace-uploader.d.ts.map +1 -0
  55. package/dist/trace-uploader.js +132 -0
  56. package/package.json +63 -0
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadTraceMeta = loadTraceMeta;
4
+ exports.validateTraceStructure = validateTraceStructure;
5
+ exports.formatTraceLoadFailure = formatTraceLoadFailure;
6
+ const promises_1 = require("fs/promises");
7
+ const path_1 = require("path");
8
+ const fs_1 = require("fs");
9
+ const constants_1 = require("./constants");
10
+ /**
11
+ * Check if a file exists
12
+ */
13
+ async function fileExists(path) {
14
+ try {
15
+ await (0, promises_1.access)(path, fs_1.constants.F_OK);
16
+ return true;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ /**
23
+ * Load trace metadata with version guard.
24
+ *
25
+ * - If trace_format_version is missing: assumes version 1 and emits a warning
26
+ * - If trace_format_version > CURRENT_TRACE_FORMAT_VERSION: throws TraceLoadFailure
27
+ *
28
+ * @param traceDir - Path to the trace directory
29
+ * @returns TraceLoadResult with metadata and any warnings
30
+ * @throws TraceLoadFailure if trace cannot be loaded or version is unsupported
31
+ */
32
+ async function loadTraceMeta(traceDir) {
33
+ const metaPath = (0, path_1.join)(traceDir, 'meta.json');
34
+ // Check file exists
35
+ if (!(await fileExists(metaPath))) {
36
+ const failure = {
37
+ type: 'missing_file',
38
+ location: metaPath,
39
+ expected: 'meta.json file',
40
+ actual: 'file not found',
41
+ hint: 'Ensure the trace directory contains a valid meta.json file',
42
+ };
43
+ throw failure;
44
+ }
45
+ // Read and parse meta.json
46
+ let rawMeta;
47
+ try {
48
+ const content = await (0, promises_1.readFile)(metaPath, 'utf8');
49
+ rawMeta = JSON.parse(content);
50
+ }
51
+ catch (error) {
52
+ const failure = {
53
+ type: 'parse_error',
54
+ location: metaPath,
55
+ expected: 'valid JSON',
56
+ actual: `parse error: ${error instanceof Error ? error.message : String(error)}`,
57
+ hint: 'Check that meta.json contains valid JSON',
58
+ };
59
+ throw failure;
60
+ }
61
+ const warnings = [];
62
+ let version;
63
+ // Check trace_format_version
64
+ if (rawMeta.trace_format_version === undefined) {
65
+ // Missing version: assume version 1 and emit warning
66
+ version = 1;
67
+ const warning = {
68
+ type: 'warning',
69
+ code: 'missing_trace_format_version',
70
+ message: `trace_format_version missing in ${metaPath}, assuming version 1`,
71
+ traceDir,
72
+ assumedVersion: 1,
73
+ };
74
+ warnings.push(warning);
75
+ // Output warning to stderr for CLI visibility
76
+ console.warn(`[Trace Loader] Warning: ${warning.message}`);
77
+ }
78
+ else {
79
+ version = Number(rawMeta.trace_format_version);
80
+ if (isNaN(version) || version < 1) {
81
+ const failure = {
82
+ type: 'validation_error',
83
+ location: metaPath,
84
+ expected: 'positive integer trace_format_version',
85
+ actual: String(rawMeta.trace_format_version),
86
+ hint: 'trace_format_version must be a positive integer',
87
+ };
88
+ throw failure;
89
+ }
90
+ }
91
+ // Check if version is higher than supported
92
+ if (version > constants_1.CURRENT_TRACE_FORMAT_VERSION) {
93
+ const failure = {
94
+ type: 'schema_drift',
95
+ location: metaPath,
96
+ expected: `trace_format_version <= ${constants_1.CURRENT_TRACE_FORMAT_VERSION}`,
97
+ actual: `trace_format_version = ${version}`,
98
+ hint: `This trace was created with a newer version of the SDK. Upgrade your SDK to version that supports trace format version ${version}.`,
99
+ };
100
+ throw failure;
101
+ }
102
+ // Build typed metadata
103
+ const meta = {
104
+ trace_format_version: version,
105
+ traceId: String(rawMeta.traceId || ''),
106
+ startedAt: String(rawMeta.startedAt || ''),
107
+ completedAt: rawMeta.completedAt ? String(rawMeta.completedAt) : null,
108
+ serviceName: String(rawMeta.serviceName || ''),
109
+ serviceVersion: String(rawMeta.serviceVersion || ''),
110
+ environment: String(rawMeta.environment || ''),
111
+ mode: rawMeta.mode === 'replay' ? 'replay' : 'record',
112
+ inboundRequest: rawMeta.inboundRequest,
113
+ };
114
+ return { meta, warnings };
115
+ }
116
+ /**
117
+ * Validate that a trace directory contains required files.
118
+ *
119
+ * @param traceDir - Path to the trace directory
120
+ * @throws TraceLoadFailure if required files are missing
121
+ */
122
+ async function validateTraceStructure(traceDir) {
123
+ const eventsPath = (0, path_1.join)(traceDir, 'events.jsonl');
124
+ if (!(await fileExists(eventsPath))) {
125
+ const failure = {
126
+ type: 'missing_file',
127
+ location: eventsPath,
128
+ expected: 'events.jsonl file',
129
+ actual: 'file not found',
130
+ hint: 'Ensure the trace directory contains a valid events.jsonl file',
131
+ };
132
+ throw failure;
133
+ }
134
+ }
135
+ /**
136
+ * Helper to format TraceLoadFailure for CLI output
137
+ */
138
+ function formatTraceLoadFailure(failure) {
139
+ return [
140
+ `[Trace Load Error] ${failure.type}`,
141
+ ` Location: ${failure.location}`,
142
+ ` Expected: ${failure.expected}`,
143
+ ` Actual: ${failure.actual}`,
144
+ ` Hint: ${failure.hint}`,
145
+ ].join('\n');
146
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Trace Uploader
3
+ *
4
+ * Uploads trace bundles to the ingestion endpoint after capture
5
+ */
6
+ export interface TraceUploadOptions {
7
+ uploadUrl: string;
8
+ apiKey: string;
9
+ traceDir: string;
10
+ traceId: string;
11
+ serviceName: string;
12
+ serviceVersion?: string;
13
+ environment?: string;
14
+ }
15
+ export interface TraceUploadResult {
16
+ success: boolean;
17
+ traceId: string;
18
+ blobRoot?: string;
19
+ error?: string;
20
+ }
21
+ /**
22
+ * Upload trace to ingestion endpoint
23
+ */
24
+ export declare function uploadTrace(options: TraceUploadOptions): Promise<TraceUploadResult>;
25
+ //# sourceMappingURL=trace-uploader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-uploader.d.ts","sourceRoot":"","sources":["../src/trace-uploader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA+CD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAiF5B"}
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ /**
3
+ * Trace Uploader
4
+ *
5
+ * Uploads trace bundles to the ingestion endpoint after capture
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.uploadTrace = uploadTrace;
9
+ const promises_1 = require("fs/promises");
10
+ const path_1 = require("path");
11
+ const fs_1 = require("fs");
12
+ const readline_1 = require("readline");
13
+ /**
14
+ * Read trace events from events.jsonl
15
+ */
16
+ async function readTraceEvents(eventsPath) {
17
+ const events = [];
18
+ try {
19
+ const fileStream = (0, fs_1.createReadStream)(eventsPath);
20
+ const rl = (0, readline_1.createInterface)({
21
+ input: fileStream,
22
+ crlfDelay: Infinity,
23
+ });
24
+ for await (const line of rl) {
25
+ const trimmed = line.trim();
26
+ if (trimmed) {
27
+ try {
28
+ events.push(JSON.parse(trimmed));
29
+ }
30
+ catch (error) {
31
+ console.warn(`[SDK] Failed to parse event line: ${error}`);
32
+ }
33
+ }
34
+ }
35
+ }
36
+ catch (error) {
37
+ // If file doesn't exist or can't be read, return empty array
38
+ if (error.code !== 'ENOENT') {
39
+ console.warn(`[SDK] Failed to read events.jsonl: ${error.message}`);
40
+ }
41
+ }
42
+ return events;
43
+ }
44
+ /**
45
+ * Read trace metadata from meta.json
46
+ */
47
+ async function readTraceMeta(metaPath) {
48
+ try {
49
+ const content = await (0, promises_1.readFile)(metaPath, 'utf-8');
50
+ return JSON.parse(content);
51
+ }
52
+ catch (error) {
53
+ throw new Error(`Failed to read meta.json: ${error.message}`);
54
+ }
55
+ }
56
+ /**
57
+ * Upload trace to ingestion endpoint
58
+ */
59
+ async function uploadTrace(options) {
60
+ const { uploadUrl, apiKey, traceDir, traceId, serviceName, serviceVersion, environment } = options;
61
+ try {
62
+ // Trace files are stored in traceDir/traceId/
63
+ const tracePath = (0, path_1.join)(traceDir, traceId);
64
+ const metaPath = (0, path_1.join)(tracePath, 'meta.json');
65
+ const eventsPath = (0, path_1.join)(tracePath, 'events.jsonl');
66
+ // Read metadata
67
+ const meta = await readTraceMeta(metaPath);
68
+ // Read events
69
+ const events = await readTraceEvents(eventsPath);
70
+ if (events.length === 0) {
71
+ return {
72
+ success: false,
73
+ traceId,
74
+ error: 'No events found in trace',
75
+ };
76
+ }
77
+ // Extract startedAt from metadata (convert ISO string to timestamp)
78
+ const startedAt = meta.startedAt
79
+ ? new Date(meta.startedAt).getTime()
80
+ : Date.now();
81
+ // Build batch payload
82
+ const batch = {
83
+ metadata: {
84
+ traceId,
85
+ serviceName,
86
+ serviceVersion: serviceVersion || meta.serviceVersion || '1.0.0',
87
+ environment: environment || meta.environment || 'production',
88
+ startedAt,
89
+ correlationIds: meta.correlationIds || [],
90
+ },
91
+ events: events.map(event => {
92
+ // Ensure all events have required base envelope fields
93
+ return {
94
+ ...event,
95
+ traceId: event.traceId || traceId,
96
+ serviceName: event.serviceName || serviceName,
97
+ parentSpanId: event.parentSpanId ?? null,
98
+ };
99
+ }),
100
+ };
101
+ // Upload to ingestion endpoint
102
+ const response = await fetch(uploadUrl, {
103
+ method: 'POST',
104
+ headers: {
105
+ 'Content-Type': 'application/json',
106
+ 'Authorization': `Bearer ${apiKey}`,
107
+ },
108
+ body: JSON.stringify(batch),
109
+ });
110
+ if (!response.ok) {
111
+ const errorText = await response.text();
112
+ return {
113
+ success: false,
114
+ traceId,
115
+ error: `Upload failed: ${response.status} ${response.statusText} - ${errorText}`,
116
+ };
117
+ }
118
+ const result = await response.json();
119
+ return {
120
+ success: true,
121
+ traceId: result.traceId || traceId,
122
+ blobRoot: result.blobRoot,
123
+ };
124
+ }
125
+ catch (error) {
126
+ return {
127
+ success: false,
128
+ traceId,
129
+ error: error.message || String(error),
130
+ };
131
+ }
132
+ }
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@runtime-digital-twin/sdk",
3
+ "version": "1.0.0",
4
+ "description": "SDK for capturing runtime behavior - automatic incident response and debugging",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./src/*": "./src/*",
13
+ "./dist/*": "./dist/*"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch",
18
+ "test": "jest",
19
+ "test:watch": "jest --watch",
20
+ "prepublishOnly": "pnpm build"
21
+ },
22
+ "dependencies": {
23
+ "@runtime-digital-twin/core": "^1.0.0",
24
+ "fastify": "^4.24.0",
25
+ "fastify-plugin": "^4.5.0"
26
+ },
27
+ "devDependencies": {
28
+ "@jest/globals": "^29.7.0",
29
+ "@types/jest": "^29.5.0",
30
+ "@types/node": "^20.0.0",
31
+ "jest": "^29.7.0",
32
+ "ts-jest": "^29.1.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "license": "MIT",
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/your-org/WraithOnCallEngineer.git",
42
+ "directory": "packages/sdk"
43
+ },
44
+ "keywords": [
45
+ "runtime",
46
+ "digital-twin",
47
+ "tracing",
48
+ "replay",
49
+ "debugging",
50
+ "fastify",
51
+ "instrumentation",
52
+ "observability"
53
+ ],
54
+ "engines": {
55
+ "node": ">=18.0.0"
56
+ },
57
+ "files": [
58
+ "dist",
59
+ "README.md",
60
+ "LICENSE"
61
+ ]
62
+ }
63
+