flowlint 0.3.2 → 0.3.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/dist/commands/init.js +1 -1
- package/dist/commands/scan.js +1 -1
- package/dist/packages/config/flowlint-config.d.ts +64 -0
- package/dist/packages/config/flowlint-config.js +103 -0
- package/dist/packages/config/flowlint-config.js.map +1 -0
- package/dist/packages/config/index.d.ts +4 -0
- package/dist/packages/config/index.js +21 -0
- package/dist/packages/config/index.js.map +1 -0
- package/dist/packages/github/client.d.ts +2 -0
- package/dist/packages/github/client.js +94 -0
- package/dist/packages/github/client.js.map +1 -0
- package/dist/packages/logger/index.d.ts +11 -0
- package/dist/packages/logger/index.js +40 -0
- package/dist/packages/logger/index.js.map +1 -0
- package/dist/packages/observability/collectors.d.ts +40 -0
- package/dist/packages/observability/collectors.js +75 -0
- package/dist/packages/observability/collectors.js.map +1 -0
- package/dist/packages/observability/index.d.ts +10 -0
- package/dist/packages/observability/index.js +35 -0
- package/dist/packages/observability/index.js.map +1 -0
- package/dist/packages/observability/metrics.d.ts +119 -0
- package/dist/packages/observability/metrics.js +194 -0
- package/dist/packages/observability/metrics.js.map +1 -0
- package/dist/packages/observability/middleware.d.ts +32 -0
- package/dist/packages/observability/middleware.js +58 -0
- package/dist/packages/observability/middleware.js.map +1 -0
- package/dist/packages/review/analysis-engine.d.ts +19 -0
- package/dist/packages/review/analysis-engine.js +111 -0
- package/dist/packages/review/analysis-engine.js.map +1 -0
- package/dist/packages/review/index.d.ts +12 -0
- package/dist/packages/review/index.js +29 -0
- package/dist/packages/review/index.js.map +1 -0
- package/dist/packages/review/parser-n8n.d.ts +2 -0
- package/dist/packages/review/parser-n8n.js +118 -0
- package/dist/packages/review/parser-n8n.js.map +1 -0
- package/dist/packages/review/providers/github.d.ts +62 -0
- package/dist/packages/review/providers/github.js +275 -0
- package/dist/packages/review/providers/github.js.map +1 -0
- package/dist/packages/review/providers.d.ts +106 -0
- package/dist/packages/review/providers.js +12 -0
- package/dist/packages/review/providers.js.map +1 -0
- package/dist/packages/review/reporter.d.ts +17 -0
- package/dist/packages/review/reporter.js +62 -0
- package/dist/packages/review/reporter.js.map +1 -0
- package/dist/packages/review/rules/index.d.ts +9 -0
- package/dist/packages/review/rules/index.js +313 -0
- package/dist/packages/review/rules/index.js.map +1 -0
- package/dist/packages/review/rules/rule-utils.d.ts +36 -0
- package/dist/packages/review/rules/rule-utils.js +75 -0
- package/dist/packages/review/rules/rule-utils.js.map +1 -0
- package/dist/packages/review/schemas/index.d.ts +17 -0
- package/dist/packages/review/schemas/index.js +139 -0
- package/dist/packages/review/schemas/index.js.map +1 -0
- package/dist/packages/review/schemas/n8n-workflow.schema.json +177 -0
- package/dist/packages/review/sniffer.d.ts +15 -0
- package/dist/packages/review/sniffer.js +47 -0
- package/dist/packages/review/sniffer.js.map +1 -0
- package/dist/packages/review/types.d.ts +38 -0
- package/dist/packages/review/types.js +3 -0
- package/dist/packages/review/types.js.map +1 -0
- package/dist/packages/review/utils/findings.d.ts +23 -0
- package/dist/packages/review/utils/findings.js +34 -0
- package/dist/packages/review/utils/findings.js.map +1 -0
- package/dist/packages/review/utils/merge.d.ts +12 -0
- package/dist/packages/review/utils/merge.js +40 -0
- package/dist/packages/review/utils/merge.js.map +1 -0
- package/dist/packages/review/utils.d.ts +60 -0
- package/dist/packages/review/utils.js +214 -0
- package/dist/packages/review/utils.js.map +1 -0
- package/dist/packages/tracing/github-tracer.d.ts +38 -0
- package/dist/packages/tracing/github-tracer.js +79 -0
- package/dist/packages/tracing/github-tracer.js.map +1 -0
- package/dist/packages/tracing/index.d.ts +81 -0
- package/dist/packages/tracing/index.js +240 -0
- package/dist/packages/tracing/index.js.map +1 -0
- package/dist/packages/tracing/tracer.d.ts +30 -0
- package/dist/packages/tracing/tracer.js +141 -0
- package/dist/packages/tracing/tracer.js.map +1 -0
- package/dist/providers/local-config-provider.js +2 -2
- package/dist/reporters/console-reporter.js +1 -1
- package/dist/reporters/json-reporter.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EXAMPLES_BASE_URL = void 0;
|
|
4
|
+
exports.flattenConnections = flattenConnections;
|
|
5
|
+
exports.buildValidationErrors = buildValidationErrors;
|
|
6
|
+
exports.collectStrings = collectStrings;
|
|
7
|
+
exports.toRegex = toRegex;
|
|
8
|
+
exports.isApiNode = isApiNode;
|
|
9
|
+
exports.isMutationNode = isMutationNode;
|
|
10
|
+
exports.isErrorProneNode = isErrorProneNode;
|
|
11
|
+
exports.isNotificationNode = isNotificationNode;
|
|
12
|
+
exports.isErrorHandlerNode = isErrorHandlerNode;
|
|
13
|
+
exports.isRejoinNode = isRejoinNode;
|
|
14
|
+
exports.isMeaningfulConsumer = isMeaningfulConsumer;
|
|
15
|
+
exports.containsCandidate = containsCandidate;
|
|
16
|
+
exports.isTerminalNode = isTerminalNode;
|
|
17
|
+
exports.readNumber = readNumber;
|
|
18
|
+
exports.findAllDownstreamNodes = findAllDownstreamNodes;
|
|
19
|
+
exports.findAllUpstreamNodes = findAllUpstreamNodes;
|
|
20
|
+
exports.getExampleLink = getExampleLink;
|
|
21
|
+
/**
|
|
22
|
+
* Shared utility functions for workflow parsing and validation
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Helper to flatten nested connection arrays from n8n workflow connections.
|
|
26
|
+
* Connections can be nested in various ways (arrays of arrays, objects with node properties).
|
|
27
|
+
* This recursively flattens them to a simple array of connection objects.
|
|
28
|
+
*
|
|
29
|
+
* @param value - The connection value to flatten (can be array, object, or primitive)
|
|
30
|
+
* @returns Array of connection objects with 'node' property
|
|
31
|
+
*/
|
|
32
|
+
function flattenConnections(value) {
|
|
33
|
+
if (!value)
|
|
34
|
+
return [];
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
return value.flatMap((entry) => flattenConnections(entry));
|
|
37
|
+
}
|
|
38
|
+
if (typeof value === 'object' && 'node' in value) {
|
|
39
|
+
return [value];
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build validation error objects from a collection of items using provided templates.
|
|
45
|
+
* This utility eliminates code duplication in validation error construction.
|
|
46
|
+
*
|
|
47
|
+
* @template T - Type of items to process
|
|
48
|
+
* @param items - Set or array of items to convert to validation errors
|
|
49
|
+
* @param errorConfig - Configuration object containing:
|
|
50
|
+
* - path: The JSON path where the error occurred
|
|
51
|
+
* - messageTemplate: Function to generate error message for each item
|
|
52
|
+
* - suggestionTemplate: Function to generate actionable suggestion for each item
|
|
53
|
+
* @returns Array of validation error objects with path, message, and suggestion fields
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const duplicates = new Set(['node1', 'node2']);
|
|
58
|
+
* const errors = buildValidationErrors(duplicates, {
|
|
59
|
+
* path: 'nodes[].id',
|
|
60
|
+
* messageTemplate: (id) => `Duplicate node ID: "${id}"`,
|
|
61
|
+
* suggestionTemplate: (id) => `Remove or rename the duplicate node with ID "${id}".`
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
function buildValidationErrors(items, errorConfig) {
|
|
66
|
+
const itemArray = Array.isArray(items) ? items : Array.from(items);
|
|
67
|
+
return itemArray.map((item) => ({
|
|
68
|
+
path: errorConfig.path,
|
|
69
|
+
message: errorConfig.messageTemplate(item),
|
|
70
|
+
suggestion: errorConfig.suggestionTemplate(item),
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
function collectStrings(value, out = []) {
|
|
74
|
+
if (typeof value === 'string')
|
|
75
|
+
out.push(value);
|
|
76
|
+
else if (Array.isArray(value))
|
|
77
|
+
value.forEach((entry) => collectStrings(entry, out));
|
|
78
|
+
else if (value && typeof value === 'object')
|
|
79
|
+
Object.values(value).forEach((entry) => collectStrings(entry, out));
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
function toRegex(pattern) {
|
|
83
|
+
let source = pattern;
|
|
84
|
+
let flags = '';
|
|
85
|
+
if (source.startsWith('(?i)')) {
|
|
86
|
+
source = source.slice(4);
|
|
87
|
+
flags += 'i';
|
|
88
|
+
}
|
|
89
|
+
return new RegExp(source, flags);
|
|
90
|
+
}
|
|
91
|
+
function isApiNode(type) {
|
|
92
|
+
return /http|request|google|facebook|ads/i.test(type);
|
|
93
|
+
}
|
|
94
|
+
function isMutationNode(type) {
|
|
95
|
+
return /write|insert|update|delete|post|put|patch|database|mongo|supabase|sheet/i.test(type);
|
|
96
|
+
}
|
|
97
|
+
function isErrorProneNode(type) {
|
|
98
|
+
return isApiNode(type) || isMutationNode(type) || /execute|workflow|function/i.test(type);
|
|
99
|
+
}
|
|
100
|
+
function isNotificationNode(type) {
|
|
101
|
+
return /slack|discord|email|gotify|mattermost|microsoftTeams|pushbullet|pushover|rocketchat|zulip|telegram/i.test(type);
|
|
102
|
+
}
|
|
103
|
+
function isErrorHandlerNode(type, name) {
|
|
104
|
+
const normalizedType = type.toLowerCase();
|
|
105
|
+
if (normalizedType.includes('stopanderror'))
|
|
106
|
+
return true;
|
|
107
|
+
if (normalizedType.includes('errorhandler'))
|
|
108
|
+
return true;
|
|
109
|
+
if (normalizedType.includes('raiseerror'))
|
|
110
|
+
return true;
|
|
111
|
+
const normalizedName = name?.toLowerCase() ?? '';
|
|
112
|
+
if (normalizedName.includes('stop and error'))
|
|
113
|
+
return true;
|
|
114
|
+
if (normalizedName.includes('error handler'))
|
|
115
|
+
return true;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
function isRejoinNode(graph, nodeId) {
|
|
119
|
+
const incoming = graph.edges.filter((e) => e.to === nodeId);
|
|
120
|
+
if (incoming.length <= 1)
|
|
121
|
+
return false;
|
|
122
|
+
const hasErrorEdge = incoming.some((e) => e.on === 'error');
|
|
123
|
+
const hasSuccessEdge = incoming.some((e) => e.on !== 'error');
|
|
124
|
+
return hasErrorEdge && hasSuccessEdge;
|
|
125
|
+
}
|
|
126
|
+
function isMeaningfulConsumer(node) {
|
|
127
|
+
// A meaningful consumer is a node that has an external side-effect.
|
|
128
|
+
return (isMutationNode(node.type) || // Writes to a DB, sheet, etc.
|
|
129
|
+
isNotificationNode(node.type) || // Sends a message to Slack, email, etc.
|
|
130
|
+
isApiNode(node.type) || // Calls an external API
|
|
131
|
+
/respondToWebhook/i.test(node.type) // Specifically nodes that send a response back.
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
function containsCandidate(value, candidates) {
|
|
135
|
+
if (!value || !candidates.length)
|
|
136
|
+
return false;
|
|
137
|
+
const queue = [value];
|
|
138
|
+
const candidateRegex = new RegExp(`(${candidates.join('|')})`, 'i');
|
|
139
|
+
while (queue.length > 0) {
|
|
140
|
+
const current = queue.shift();
|
|
141
|
+
if (typeof current === 'string') {
|
|
142
|
+
if (candidateRegex.test(current))
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
else if (Array.isArray(current)) {
|
|
146
|
+
queue.push(...current);
|
|
147
|
+
}
|
|
148
|
+
else if (current && typeof current === 'object') {
|
|
149
|
+
for (const [key, val] of Object.entries(current)) {
|
|
150
|
+
if (candidateRegex.test(key))
|
|
151
|
+
return true;
|
|
152
|
+
queue.push(val);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const TERMINAL_NODE_PATTERNS = [
|
|
159
|
+
'respond', 'reply', 'end', 'stop', 'terminate', 'return', 'sticky', 'note', 'noop', 'no operation',
|
|
160
|
+
'slack', 'email', 'discord', 'teams', 'webhook', 'telegram', 'pushbullet', 'mattermost', 'notifier', 'notification', 'alert', 'sms', 'call',
|
|
161
|
+
];
|
|
162
|
+
function isTerminalNode(type, name) {
|
|
163
|
+
const label = `${type} ${name ?? ''}`.toLowerCase();
|
|
164
|
+
return TERMINAL_NODE_PATTERNS.some((pattern) => label.includes(pattern));
|
|
165
|
+
}
|
|
166
|
+
function readNumber(source, paths) {
|
|
167
|
+
for (const path of paths) {
|
|
168
|
+
const value = path.split('.').reduce((acc, key) => (acc ? acc[key] : undefined), source);
|
|
169
|
+
if (typeof value === 'number')
|
|
170
|
+
return value;
|
|
171
|
+
if (typeof value === 'string' && !Number.isNaN(Number(value)))
|
|
172
|
+
return Number(value);
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
function findAllDownstreamNodes(graph, startNodeId) {
|
|
177
|
+
const visited = new Set();
|
|
178
|
+
const queue = [startNodeId];
|
|
179
|
+
visited.add(startNodeId);
|
|
180
|
+
let head = 0;
|
|
181
|
+
while (head < queue.length) {
|
|
182
|
+
const currentId = queue[head++];
|
|
183
|
+
const outgoing = graph.edges.filter((e) => e.from === currentId);
|
|
184
|
+
for (const edge of outgoing) {
|
|
185
|
+
if (!visited.has(edge.to)) {
|
|
186
|
+
visited.add(edge.to);
|
|
187
|
+
queue.push(edge.to);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return visited;
|
|
192
|
+
}
|
|
193
|
+
function findAllUpstreamNodes(graph, startNodeId) {
|
|
194
|
+
const visited = new Set();
|
|
195
|
+
const queue = [startNodeId];
|
|
196
|
+
visited.add(startNodeId);
|
|
197
|
+
let head = 0;
|
|
198
|
+
while (head < queue.length) {
|
|
199
|
+
const currentId = queue[head++];
|
|
200
|
+
const incoming = graph.edges.filter((e) => e.to === currentId);
|
|
201
|
+
for (const edge of incoming) {
|
|
202
|
+
if (!visited.has(edge.from)) {
|
|
203
|
+
visited.add(edge.from);
|
|
204
|
+
queue.push(edge.from);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return visited;
|
|
209
|
+
}
|
|
210
|
+
exports.EXAMPLES_BASE_URL = "https://github.com/Replikanti/flowlint/tree/main/flowlint-examples";
|
|
211
|
+
function getExampleLink(ruleId) {
|
|
212
|
+
return `${exports.EXAMPLES_BASE_URL}/${ruleId}`;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../packages/review/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API tracing wrapper
|
|
3
|
+
* Instruments GitHub API calls with OpenTelemetry spans
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Wrap a GitHub API call with tracing
|
|
7
|
+
*/
|
|
8
|
+
export declare function traceGitHubApiCall<T>(method: string, endpoint: string, fn: () => Promise<T>, additionalAttributes?: Record<string, string | number | boolean>): Promise<T>;
|
|
9
|
+
/**
|
|
10
|
+
* GitHub API call attributes for common operations
|
|
11
|
+
*/
|
|
12
|
+
export declare const GitHubApiAttributes: {
|
|
13
|
+
listFiles: (owner: string, repo: string, prNumber: number) => {
|
|
14
|
+
'github.repo.owner': string;
|
|
15
|
+
'github.repo.name': string;
|
|
16
|
+
'github.pr.number': number;
|
|
17
|
+
'github.api.operation': string;
|
|
18
|
+
};
|
|
19
|
+
getContent: (owner: string, repo: string, path: string, ref: string) => {
|
|
20
|
+
'github.repo.owner': string;
|
|
21
|
+
'github.repo.name': string;
|
|
22
|
+
'github.file.path': string;
|
|
23
|
+
'github.ref': string;
|
|
24
|
+
'github.api.operation': string;
|
|
25
|
+
};
|
|
26
|
+
createCheckRun: (owner: string, repo: string, sha: string) => {
|
|
27
|
+
'github.repo.owner': string;
|
|
28
|
+
'github.repo.name': string;
|
|
29
|
+
'github.commit.sha': string;
|
|
30
|
+
'github.api.operation': string;
|
|
31
|
+
};
|
|
32
|
+
updateCheckRun: (owner: string, repo: string, checkRunId: number) => {
|
|
33
|
+
'github.repo.owner': string;
|
|
34
|
+
'github.repo.name': string;
|
|
35
|
+
'github.check_run.id': number;
|
|
36
|
+
'github.api.operation': string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub API tracing wrapper
|
|
4
|
+
* Instruments GitHub API calls with OpenTelemetry spans
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GitHubApiAttributes = void 0;
|
|
8
|
+
exports.traceGitHubApiCall = traceGitHubApiCall;
|
|
9
|
+
const index_1 = require("./index");
|
|
10
|
+
/**
|
|
11
|
+
* Wrap a GitHub API call with tracing
|
|
12
|
+
*/
|
|
13
|
+
async function traceGitHubApiCall(method, endpoint, fn, additionalAttributes) {
|
|
14
|
+
return (0, index_1.withClientSpan)(index_1.SpanNames.GITHUB_API_CALL, async (span) => {
|
|
15
|
+
span.setAttributes({
|
|
16
|
+
'github.api.method': method,
|
|
17
|
+
'github.api.endpoint': endpoint,
|
|
18
|
+
'http.method': method,
|
|
19
|
+
'http.url': endpoint,
|
|
20
|
+
...additionalAttributes,
|
|
21
|
+
});
|
|
22
|
+
const startTime = Date.now();
|
|
23
|
+
try {
|
|
24
|
+
const result = await fn();
|
|
25
|
+
const duration = Date.now() - startTime;
|
|
26
|
+
span.setAttributes({
|
|
27
|
+
'github.api.duration_ms': duration,
|
|
28
|
+
'http.status_code': 200, // Assuming success
|
|
29
|
+
});
|
|
30
|
+
span.addEvent('github.api.call.success', {
|
|
31
|
+
duration_ms: duration,
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const duration = Date.now() - startTime;
|
|
37
|
+
span.setAttributes({
|
|
38
|
+
'github.api.duration_ms': duration,
|
|
39
|
+
'github.api.error': true,
|
|
40
|
+
'error.type': error instanceof Error ? error.constructor.name : 'UnknownError',
|
|
41
|
+
});
|
|
42
|
+
if (error instanceof Error) {
|
|
43
|
+
span.recordException(error);
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* GitHub API call attributes for common operations
|
|
51
|
+
*/
|
|
52
|
+
exports.GitHubApiAttributes = {
|
|
53
|
+
listFiles: (owner, repo, prNumber) => ({
|
|
54
|
+
'github.repo.owner': owner,
|
|
55
|
+
'github.repo.name': repo,
|
|
56
|
+
'github.pr.number': prNumber,
|
|
57
|
+
'github.api.operation': 'list_pr_files',
|
|
58
|
+
}),
|
|
59
|
+
getContent: (owner, repo, path, ref) => ({
|
|
60
|
+
'github.repo.owner': owner,
|
|
61
|
+
'github.repo.name': repo,
|
|
62
|
+
'github.file.path': path,
|
|
63
|
+
'github.ref': ref,
|
|
64
|
+
'github.api.operation': 'get_content',
|
|
65
|
+
}),
|
|
66
|
+
createCheckRun: (owner, repo, sha) => ({
|
|
67
|
+
'github.repo.owner': owner,
|
|
68
|
+
'github.repo.name': repo,
|
|
69
|
+
'github.commit.sha': sha,
|
|
70
|
+
'github.api.operation': 'create_check_run',
|
|
71
|
+
}),
|
|
72
|
+
updateCheckRun: (owner, repo, checkRunId) => ({
|
|
73
|
+
'github.repo.owner': owner,
|
|
74
|
+
'github.repo.name': repo,
|
|
75
|
+
'github.check_run.id': checkRunId,
|
|
76
|
+
'github.api.operation': 'update_check_run',
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=github-tracer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-tracer.js","sourceRoot":"","sources":["../../../packages/tracing/github-tracer.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAQH,gDAkDC;AAxDD,mCAAoD;AAGpD;;GAEG;AACI,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,QAAgB,EAChB,EAAoB,EACpB,oBAAgE;IAEhE,OAAO,IAAA,sBAAc,EACnB,iBAAS,CAAC,eAAe,EACzB,KAAK,EAAE,IAAU,EAAE,EAAE;QACnB,IAAI,CAAC,aAAa,CAAC;YACjB,mBAAmB,EAAE,MAAM;YAC3B,qBAAqB,EAAE,QAAQ;YAC/B,aAAa,EAAE,MAAM;YACrB,UAAU,EAAE,QAAQ;YACpB,GAAG,oBAAoB;SACxB,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAExC,IAAI,CAAC,aAAa,CAAC;gBACjB,wBAAwB,EAAE,QAAQ;gBAClC,kBAAkB,EAAE,GAAG,EAAE,mBAAmB;aAC7C,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,yBAAyB,EAAE;gBACvC,WAAW,EAAE,QAAQ;aACtB,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAExC,IAAI,CAAC,aAAa,CAAC;gBACjB,wBAAwB,EAAE,QAAQ;gBAClC,kBAAkB,EAAE,IAAI;gBACxB,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc;aAC/E,CAAC,CAAC;YAEH,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;YAED,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACU,QAAA,mBAAmB,GAAG;IACjC,SAAS,EAAE,CAAC,KAAa,EAAE,IAAY,EAAE,QAAgB,EAAE,EAAE,CAAC,CAAC;QAC7D,mBAAmB,EAAE,KAAK;QAC1B,kBAAkB,EAAE,IAAI;QACxB,kBAAkB,EAAE,QAAQ;QAC5B,sBAAsB,EAAE,eAAe;KACxC,CAAC;IAEF,UAAU,EAAE,CAAC,KAAa,EAAE,IAAY,EAAE,IAAY,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC;QACvE,mBAAmB,EAAE,KAAK;QAC1B,kBAAkB,EAAE,IAAI;QACxB,kBAAkB,EAAE,IAAI;QACxB,YAAY,EAAE,GAAG;QACjB,sBAAsB,EAAE,aAAa;KACtC,CAAC;IAEF,cAAc,EAAE,CAAC,KAAa,EAAE,IAAY,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC;QAC7D,mBAAmB,EAAE,KAAK;QAC1B,kBAAkB,EAAE,IAAI;QACxB,mBAAmB,EAAE,GAAG;QACxB,sBAAsB,EAAE,kBAAkB;KAC3C,CAAC;IAEF,cAAc,EAAE,CAAC,KAAa,EAAE,IAAY,EAAE,UAAkB,EAAE,EAAE,CAAC,CAAC;QACpE,mBAAmB,EAAE,KAAK;QAC1B,kBAAkB,EAAE,IAAI;QACxB,qBAAqB,EAAE,UAAU;QACjC,sBAAsB,EAAE,kBAAkB;KAC3C,CAAC;CACH,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowLint Distributed Tracing Package
|
|
3
|
+
*
|
|
4
|
+
* Provides OpenTelemetry-based distributed tracing for FlowLint.
|
|
5
|
+
* Tracks request flow from webhook reception through job processing to Check Run creation.
|
|
6
|
+
*
|
|
7
|
+
* @module packages/tracing
|
|
8
|
+
*/
|
|
9
|
+
import { Tracer, Span, SpanStatusCode, Context, context, trace, propagation } from '@opentelemetry/api';
|
|
10
|
+
/**
|
|
11
|
+
* Trace span names following OpenTelemetry semantic conventions
|
|
12
|
+
*/
|
|
13
|
+
export declare const SpanNames: {
|
|
14
|
+
readonly WEBHOOK_RECEIVED: "webhook.received";
|
|
15
|
+
readonly WEBHOOK_VERIFY_SIGNATURE: "webhook.verify_signature";
|
|
16
|
+
readonly JOB_ENQUEUED: "job.enqueued";
|
|
17
|
+
readonly JOB_PROCESSED: "job.processed";
|
|
18
|
+
readonly JOB_FETCH_FILES: "job.fetch_files";
|
|
19
|
+
readonly JOB_LOAD_CONFIG: "job.load_config";
|
|
20
|
+
readonly JOB_PARSE_WORKFLOW: "job.parse_workflow";
|
|
21
|
+
readonly JOB_RUN_RULES: "job.run_rules";
|
|
22
|
+
readonly JOB_CREATE_CHECK_RUN: "job.create_check_run";
|
|
23
|
+
readonly GITHUB_API_CALL: "github.api_call";
|
|
24
|
+
readonly LINT_RULE_EXECUTE: "lint.rule.execute";
|
|
25
|
+
readonly REDIS_OPERATION: "redis.operation";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Get the configured tracer instance
|
|
29
|
+
*/
|
|
30
|
+
export declare function getTracerInstance(): Tracer;
|
|
31
|
+
/**
|
|
32
|
+
* Start a new span with the given name and attributes
|
|
33
|
+
*/
|
|
34
|
+
export declare function startSpan(name: string, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Span;
|
|
35
|
+
/**
|
|
36
|
+
* Start a server span (for incoming requests)
|
|
37
|
+
*/
|
|
38
|
+
export declare function startServerSpan(name: string, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Span;
|
|
39
|
+
/**
|
|
40
|
+
* Start a client span (for outgoing requests)
|
|
41
|
+
*/
|
|
42
|
+
export declare function startClientSpan(name: string, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Span;
|
|
43
|
+
/**
|
|
44
|
+
* Execute a function within a span context
|
|
45
|
+
*/
|
|
46
|
+
export declare function withSpan<T>(name: string, fn: (span: Span) => Promise<T>, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Execute a synchronous function within a span context
|
|
49
|
+
*/
|
|
50
|
+
export declare function withSpanSync<T>(name: string, fn: (span: Span) => T, attributes?: Record<string, string | number | boolean>, parentContext?: Context): T;
|
|
51
|
+
/**
|
|
52
|
+
* Execute a function within a server span context (for incoming requests)
|
|
53
|
+
*/
|
|
54
|
+
export declare function withServerSpan<T>(name: string, fn: (span: Span) => Promise<T>, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Promise<T>;
|
|
55
|
+
/**
|
|
56
|
+
* Execute a function within a client span context (for outgoing requests)
|
|
57
|
+
*/
|
|
58
|
+
export declare function withClientSpan<T>(name: string, fn: (span: Span) => Promise<T>, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Promise<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Add an event to the current active span
|
|
61
|
+
*/
|
|
62
|
+
export declare function addSpanEvent(name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
63
|
+
/**
|
|
64
|
+
* Set attributes on the current active span
|
|
65
|
+
*/
|
|
66
|
+
export declare function setSpanAttributes(attributes: Record<string, string | number | boolean>): void;
|
|
67
|
+
/**
|
|
68
|
+
* Record an exception on the current active span
|
|
69
|
+
*/
|
|
70
|
+
export declare function recordSpanException(error: Error): void;
|
|
71
|
+
/**
|
|
72
|
+
* Get the current active span
|
|
73
|
+
*/
|
|
74
|
+
export declare function getActiveSpan(): Span | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Get the current trace context
|
|
77
|
+
*/
|
|
78
|
+
export declare function getActiveContext(): Context;
|
|
79
|
+
export { Span, SpanStatusCode, Context, trace, context, propagation };
|
|
80
|
+
export { initTracing, shutdownTracing } from './tracer';
|
|
81
|
+
export { traceGitHubApiCall, GitHubApiAttributes } from './github-tracer';
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FlowLint Distributed Tracing Package
|
|
4
|
+
*
|
|
5
|
+
* Provides OpenTelemetry-based distributed tracing for FlowLint.
|
|
6
|
+
* Tracks request flow from webhook reception through job processing to Check Run creation.
|
|
7
|
+
*
|
|
8
|
+
* @module packages/tracing
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.GitHubApiAttributes = exports.traceGitHubApiCall = exports.shutdownTracing = exports.initTracing = exports.propagation = exports.context = exports.trace = exports.SpanStatusCode = exports.SpanNames = void 0;
|
|
12
|
+
exports.getTracerInstance = getTracerInstance;
|
|
13
|
+
exports.startSpan = startSpan;
|
|
14
|
+
exports.startServerSpan = startServerSpan;
|
|
15
|
+
exports.startClientSpan = startClientSpan;
|
|
16
|
+
exports.withSpan = withSpan;
|
|
17
|
+
exports.withSpanSync = withSpanSync;
|
|
18
|
+
exports.withServerSpan = withServerSpan;
|
|
19
|
+
exports.withClientSpan = withClientSpan;
|
|
20
|
+
exports.addSpanEvent = addSpanEvent;
|
|
21
|
+
exports.setSpanAttributes = setSpanAttributes;
|
|
22
|
+
exports.recordSpanException = recordSpanException;
|
|
23
|
+
exports.getActiveSpan = getActiveSpan;
|
|
24
|
+
exports.getActiveContext = getActiveContext;
|
|
25
|
+
const api_1 = require("@opentelemetry/api");
|
|
26
|
+
Object.defineProperty(exports, "SpanStatusCode", { enumerable: true, get: function () { return api_1.SpanStatusCode; } });
|
|
27
|
+
Object.defineProperty(exports, "context", { enumerable: true, get: function () { return api_1.context; } });
|
|
28
|
+
Object.defineProperty(exports, "trace", { enumerable: true, get: function () { return api_1.trace; } });
|
|
29
|
+
Object.defineProperty(exports, "propagation", { enumerable: true, get: function () { return api_1.propagation; } });
|
|
30
|
+
const tracer_1 = require("./tracer");
|
|
31
|
+
/**
|
|
32
|
+
* Trace span names following OpenTelemetry semantic conventions
|
|
33
|
+
*/
|
|
34
|
+
exports.SpanNames = {
|
|
35
|
+
WEBHOOK_RECEIVED: 'webhook.received',
|
|
36
|
+
WEBHOOK_VERIFY_SIGNATURE: 'webhook.verify_signature',
|
|
37
|
+
JOB_ENQUEUED: 'job.enqueued',
|
|
38
|
+
JOB_PROCESSED: 'job.processed',
|
|
39
|
+
JOB_FETCH_FILES: 'job.fetch_files',
|
|
40
|
+
JOB_LOAD_CONFIG: 'job.load_config',
|
|
41
|
+
JOB_PARSE_WORKFLOW: 'job.parse_workflow',
|
|
42
|
+
JOB_RUN_RULES: 'job.run_rules',
|
|
43
|
+
JOB_CREATE_CHECK_RUN: 'job.create_check_run',
|
|
44
|
+
GITHUB_API_CALL: 'github.api_call',
|
|
45
|
+
LINT_RULE_EXECUTE: 'lint.rule.execute',
|
|
46
|
+
REDIS_OPERATION: 'redis.operation',
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Get the configured tracer instance
|
|
50
|
+
*/
|
|
51
|
+
function getTracerInstance() {
|
|
52
|
+
return (0, tracer_1.getTracer)();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Start a new span with the given name and attributes
|
|
56
|
+
*/
|
|
57
|
+
function startSpan(name, attributes, parentContext) {
|
|
58
|
+
const tracer = (0, tracer_1.getTracer)();
|
|
59
|
+
const ctx = parentContext || api_1.context.active();
|
|
60
|
+
return tracer.startSpan(name, {
|
|
61
|
+
kind: api_1.SpanKind.INTERNAL,
|
|
62
|
+
attributes,
|
|
63
|
+
}, ctx);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start a server span (for incoming requests)
|
|
67
|
+
*/
|
|
68
|
+
function startServerSpan(name, attributes, parentContext) {
|
|
69
|
+
const tracer = (0, tracer_1.getTracer)();
|
|
70
|
+
const ctx = parentContext || api_1.context.active();
|
|
71
|
+
return tracer.startSpan(name, {
|
|
72
|
+
kind: api_1.SpanKind.SERVER,
|
|
73
|
+
attributes,
|
|
74
|
+
}, ctx);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Start a client span (for outgoing requests)
|
|
78
|
+
*/
|
|
79
|
+
function startClientSpan(name, attributes, parentContext) {
|
|
80
|
+
const tracer = (0, tracer_1.getTracer)();
|
|
81
|
+
const ctx = parentContext || api_1.context.active();
|
|
82
|
+
return tracer.startSpan(name, {
|
|
83
|
+
kind: api_1.SpanKind.CLIENT,
|
|
84
|
+
attributes,
|
|
85
|
+
}, ctx);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Execute a function within a span context
|
|
89
|
+
*/
|
|
90
|
+
async function withSpan(name, fn, attributes, parentContext) {
|
|
91
|
+
const baseContext = parentContext || api_1.context.active();
|
|
92
|
+
const span = startSpan(name, attributes, parentContext);
|
|
93
|
+
const ctxWithSpan = api_1.trace.setSpan(baseContext, span);
|
|
94
|
+
try {
|
|
95
|
+
const result = await api_1.context.with(ctxWithSpan, () => fn(span));
|
|
96
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
span.setStatus({
|
|
101
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
102
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
103
|
+
});
|
|
104
|
+
if (error instanceof Error) {
|
|
105
|
+
span.recordException(error);
|
|
106
|
+
}
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
span.end();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Execute a synchronous function within a span context
|
|
115
|
+
*/
|
|
116
|
+
function withSpanSync(name, fn, attributes, parentContext) {
|
|
117
|
+
const baseContext = parentContext || api_1.context.active();
|
|
118
|
+
const span = startSpan(name, attributes, parentContext);
|
|
119
|
+
const ctxWithSpan = api_1.trace.setSpan(baseContext, span);
|
|
120
|
+
try {
|
|
121
|
+
const result = api_1.context.with(ctxWithSpan, () => fn(span));
|
|
122
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
span.setStatus({
|
|
127
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
128
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
129
|
+
});
|
|
130
|
+
if (error instanceof Error) {
|
|
131
|
+
span.recordException(error);
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
span.end();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Execute a function within a server span context (for incoming requests)
|
|
141
|
+
*/
|
|
142
|
+
async function withServerSpan(name, fn, attributes, parentContext) {
|
|
143
|
+
const baseContext = parentContext || api_1.context.active();
|
|
144
|
+
const span = startServerSpan(name, attributes, parentContext);
|
|
145
|
+
const ctxWithSpan = api_1.trace.setSpan(baseContext, span);
|
|
146
|
+
try {
|
|
147
|
+
const result = await api_1.context.with(ctxWithSpan, () => fn(span));
|
|
148
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
span.setStatus({
|
|
153
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
154
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
155
|
+
});
|
|
156
|
+
if (error instanceof Error) {
|
|
157
|
+
span.recordException(error);
|
|
158
|
+
}
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
span.end();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Execute a function within a client span context (for outgoing requests)
|
|
167
|
+
*/
|
|
168
|
+
async function withClientSpan(name, fn, attributes, parentContext) {
|
|
169
|
+
const baseContext = parentContext || api_1.context.active();
|
|
170
|
+
const span = startClientSpan(name, attributes, parentContext);
|
|
171
|
+
const ctxWithSpan = api_1.trace.setSpan(baseContext, span);
|
|
172
|
+
try {
|
|
173
|
+
const result = await api_1.context.with(ctxWithSpan, () => fn(span));
|
|
174
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
span.setStatus({
|
|
179
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
180
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
181
|
+
});
|
|
182
|
+
if (error instanceof Error) {
|
|
183
|
+
span.recordException(error);
|
|
184
|
+
}
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
span.end();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Add an event to the current active span
|
|
193
|
+
*/
|
|
194
|
+
function addSpanEvent(name, attributes) {
|
|
195
|
+
const span = api_1.trace.getActiveSpan();
|
|
196
|
+
if (span) {
|
|
197
|
+
span.addEvent(name, attributes);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Set attributes on the current active span
|
|
202
|
+
*/
|
|
203
|
+
function setSpanAttributes(attributes) {
|
|
204
|
+
const span = api_1.trace.getActiveSpan();
|
|
205
|
+
if (span) {
|
|
206
|
+
span.setAttributes(attributes);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Record an exception on the current active span
|
|
211
|
+
*/
|
|
212
|
+
function recordSpanException(error) {
|
|
213
|
+
const span = api_1.trace.getActiveSpan();
|
|
214
|
+
if (span) {
|
|
215
|
+
span.recordException(error);
|
|
216
|
+
span.setStatus({
|
|
217
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
218
|
+
message: error.message,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get the current active span
|
|
224
|
+
*/
|
|
225
|
+
function getActiveSpan() {
|
|
226
|
+
return api_1.trace.getActiveSpan();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get the current trace context
|
|
230
|
+
*/
|
|
231
|
+
function getActiveContext() {
|
|
232
|
+
return api_1.context.active();
|
|
233
|
+
}
|
|
234
|
+
var tracer_2 = require("./tracer");
|
|
235
|
+
Object.defineProperty(exports, "initTracing", { enumerable: true, get: function () { return tracer_2.initTracing; } });
|
|
236
|
+
Object.defineProperty(exports, "shutdownTracing", { enumerable: true, get: function () { return tracer_2.shutdownTracing; } });
|
|
237
|
+
var github_tracer_1 = require("./github-tracer");
|
|
238
|
+
Object.defineProperty(exports, "traceGitHubApiCall", { enumerable: true, get: function () { return github_tracer_1.traceGitHubApiCall; } });
|
|
239
|
+
Object.defineProperty(exports, "GitHubApiAttributes", { enumerable: true, get: function () { return github_tracer_1.GitHubApiAttributes; } });
|
|
240
|
+
//# sourceMappingURL=index.js.map
|