autotel-subscribers 56.0.1 → 56.1.1
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/NOTICE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
autotel
|
|
2
|
+
Copyright 2026 Jag Reehal
|
|
3
|
+
|
|
4
|
+
This product is licensed under the Apache License, Version 2.0.
|
|
5
|
+
See the LICENSE file for the full license text.
|
|
6
|
+
|
|
7
|
+
"autotel" is a trademark of Jag Reehal. The Apache License, Version 2.0
|
|
8
|
+
does not grant rights to use the "autotel" name. See TRADEMARKS.md for
|
|
9
|
+
the trademark policy.
|
|
@@ -13,6 +13,33 @@ node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
|
13
13
|
* downstream consumers, so add fields rather than rename existing ones.
|
|
14
14
|
*/
|
|
15
15
|
const ARCHITECTURE_SNAPSHOT_SPEC = "autotel-architecture/v0.1.0";
|
|
16
|
+
/**
|
|
17
|
+
* Order two (producer, channel) pairs, comparing the fields rather than a
|
|
18
|
+
* joined key.
|
|
19
|
+
*
|
|
20
|
+
* Both come from caller-supplied `_autotel` metadata and may contain any
|
|
21
|
+
* character, so joining them with a separator is ambiguous: `('A|B', 'C')` and
|
|
22
|
+
* `('A', 'B|C')` produce the same string and would merge into one source.
|
|
23
|
+
*/
|
|
24
|
+
function compareSources(a, b) {
|
|
25
|
+
return (a.producer ?? "").localeCompare(b.producer ?? "") || (a.channel ?? "").localeCompare(b.channel ?? "");
|
|
26
|
+
}
|
|
27
|
+
function recordSource(observation, producer, channel, now) {
|
|
28
|
+
const sources = observation.sources ??= [];
|
|
29
|
+
const existing = sources.find((source) => source.producer === producer && source.channel === channel);
|
|
30
|
+
if (existing) {
|
|
31
|
+
existing.count += 1;
|
|
32
|
+
existing.lastSeen = now;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
sources.push({
|
|
36
|
+
...producer !== void 0 && { producer },
|
|
37
|
+
...channel !== void 0 && { channel },
|
|
38
|
+
count: 1,
|
|
39
|
+
firstSeen: now,
|
|
40
|
+
lastSeen: now
|
|
41
|
+
});
|
|
42
|
+
}
|
|
16
43
|
const DEFAULT_MAX_SAMPLES = 3;
|
|
17
44
|
var ArchitectureSnapshotSubscriber = class extends require_event_subscriber_base.EventSubscriber {
|
|
18
45
|
name = "ArchitectureSnapshotSubscriber";
|
|
@@ -50,7 +77,14 @@ var ArchitectureSnapshotSubscriber = class extends require_event_subscriber_base
|
|
|
50
77
|
source: payload.schema.source,
|
|
51
78
|
jsonSchema: payload.schema.jsonSchema,
|
|
52
79
|
hash: payload.schema.hash
|
|
53
|
-
} : void 0
|
|
80
|
+
} : void 0,
|
|
81
|
+
sources: [{
|
|
82
|
+
...autotelMeta.producer !== void 0 && { producer: autotelMeta.producer },
|
|
83
|
+
...autotelMeta.channel !== void 0 && { channel: autotelMeta.channel },
|
|
84
|
+
count: 1,
|
|
85
|
+
firstSeen: now,
|
|
86
|
+
lastSeen: now
|
|
87
|
+
}]
|
|
54
88
|
});
|
|
55
89
|
return;
|
|
56
90
|
}
|
|
@@ -61,6 +95,7 @@ var ArchitectureSnapshotSubscriber = class extends require_event_subscriber_base
|
|
|
61
95
|
if (traceId && !existing.sampleTraceIds.includes(traceId) && existing.sampleTraceIds.length < this.maxSampleTraceIds) existing.sampleTraceIds.push(traceId);
|
|
62
96
|
existing.channel ??= autotelMeta.channel;
|
|
63
97
|
existing.producer ??= autotelMeta.producer;
|
|
98
|
+
recordSource(existing, autotelMeta.producer, autotelMeta.channel, now);
|
|
64
99
|
existing.consumers = mergeUnique(existing.consumers ?? [], autotelMeta.consumers ?? []);
|
|
65
100
|
existing.schema ??= payload.schema ? {
|
|
66
101
|
source: payload.schema.source,
|
|
@@ -93,7 +128,12 @@ var ArchitectureSnapshotSubscriber = class extends require_event_subscriber_base
|
|
|
93
128
|
lastSeen: freezeTimestamps ?? obs.lastSeen,
|
|
94
129
|
fieldPaths: obs.fieldPaths.toSorted(),
|
|
95
130
|
sampleTraceIds: obs.sampleTraceIds.toSorted(),
|
|
96
|
-
fieldStats: sortFieldStats(obs.fieldStats)
|
|
131
|
+
fieldStats: sortFieldStats(obs.fieldStats),
|
|
132
|
+
...obs.sources && { sources: obs.sources.map((source) => ({
|
|
133
|
+
...source,
|
|
134
|
+
firstSeen: freezeTimestamps ?? source.firstSeen,
|
|
135
|
+
lastSeen: freezeTimestamps ?? source.lastSeen
|
|
136
|
+
})).toSorted(compareSources) }
|
|
97
137
|
};
|
|
98
138
|
}
|
|
99
139
|
return {
|
|
@@ -27,6 +27,17 @@ type EventObservation = {
|
|
|
27
27
|
producer?: string;
|
|
28
28
|
/** Services known to consume this event (optional metadata from _autotel.consumers). */
|
|
29
29
|
consumers?: string[];
|
|
30
|
+
/**
|
|
31
|
+
* One entry per distinct (producer, channel) pair this event was seen on,
|
|
32
|
+
* with that pair's own count.
|
|
33
|
+
*
|
|
34
|
+
* `producer` and `channel` above are first-write-wins and `observedCount` is
|
|
35
|
+
* an event-level total, so two services publishing the same event name
|
|
36
|
+
* collapse into one: the second producer disappears and its observations are
|
|
37
|
+
* silently credited to the first. Anything attributing counts to a specific
|
|
38
|
+
* relationship must read this instead.
|
|
39
|
+
*/
|
|
40
|
+
sources?: EventSource[];
|
|
30
41
|
/** Observed runtime types and sample primitive values per field path. */
|
|
31
42
|
fieldStats?: Record<string, FieldStats>;
|
|
32
43
|
/** Optional contract schema metadata carried from track() call sites. */
|
|
@@ -36,6 +47,14 @@ type EventObservation = {
|
|
|
36
47
|
hash: string;
|
|
37
48
|
};
|
|
38
49
|
};
|
|
50
|
+
/** One (producer, channel) pair an event was observed on, with its own count. */
|
|
51
|
+
type EventSource = {
|
|
52
|
+
producer?: string;
|
|
53
|
+
channel?: string;
|
|
54
|
+
count: number;
|
|
55
|
+
firstSeen: string;
|
|
56
|
+
lastSeen: string;
|
|
57
|
+
};
|
|
39
58
|
type FieldStats = {
|
|
40
59
|
/** Runtime types observed for this field path (e.g. string, number). */
|
|
41
60
|
types: string[];
|
|
@@ -91,4 +110,4 @@ declare class ArchitectureSnapshotSubscriber extends EventSubscriber {
|
|
|
91
110
|
*/
|
|
92
111
|
declare function extractFieldPaths(value: unknown, prefix?: string): string[];
|
|
93
112
|
//#endregion
|
|
94
|
-
export { ARCHITECTURE_SNAPSHOT_SPEC, ArchitectureSnapshot, ArchitectureSnapshotConfig, ArchitectureSnapshotSubscriber, EventObservation, FieldStats, extractFieldPaths };
|
|
113
|
+
export { ARCHITECTURE_SNAPSHOT_SPEC, ArchitectureSnapshot, ArchitectureSnapshotConfig, ArchitectureSnapshotSubscriber, EventObservation, EventSource, FieldStats, extractFieldPaths };
|
|
@@ -27,6 +27,17 @@ type EventObservation = {
|
|
|
27
27
|
producer?: string;
|
|
28
28
|
/** Services known to consume this event (optional metadata from _autotel.consumers). */
|
|
29
29
|
consumers?: string[];
|
|
30
|
+
/**
|
|
31
|
+
* One entry per distinct (producer, channel) pair this event was seen on,
|
|
32
|
+
* with that pair's own count.
|
|
33
|
+
*
|
|
34
|
+
* `producer` and `channel` above are first-write-wins and `observedCount` is
|
|
35
|
+
* an event-level total, so two services publishing the same event name
|
|
36
|
+
* collapse into one: the second producer disappears and its observations are
|
|
37
|
+
* silently credited to the first. Anything attributing counts to a specific
|
|
38
|
+
* relationship must read this instead.
|
|
39
|
+
*/
|
|
40
|
+
sources?: EventSource[];
|
|
30
41
|
/** Observed runtime types and sample primitive values per field path. */
|
|
31
42
|
fieldStats?: Record<string, FieldStats>;
|
|
32
43
|
/** Optional contract schema metadata carried from track() call sites. */
|
|
@@ -36,6 +47,14 @@ type EventObservation = {
|
|
|
36
47
|
hash: string;
|
|
37
48
|
};
|
|
38
49
|
};
|
|
50
|
+
/** One (producer, channel) pair an event was observed on, with its own count. */
|
|
51
|
+
type EventSource = {
|
|
52
|
+
producer?: string;
|
|
53
|
+
channel?: string;
|
|
54
|
+
count: number;
|
|
55
|
+
firstSeen: string;
|
|
56
|
+
lastSeen: string;
|
|
57
|
+
};
|
|
39
58
|
type FieldStats = {
|
|
40
59
|
/** Runtime types observed for this field path (e.g. string, number). */
|
|
41
60
|
types: string[];
|
|
@@ -91,4 +110,4 @@ declare class ArchitectureSnapshotSubscriber extends EventSubscriber {
|
|
|
91
110
|
*/
|
|
92
111
|
declare function extractFieldPaths(value: unknown, prefix?: string): string[];
|
|
93
112
|
//#endregion
|
|
94
|
-
export { ARCHITECTURE_SNAPSHOT_SPEC, ArchitectureSnapshot, ArchitectureSnapshotConfig, ArchitectureSnapshotSubscriber, EventObservation, FieldStats, extractFieldPaths };
|
|
113
|
+
export { ARCHITECTURE_SNAPSHOT_SPEC, ArchitectureSnapshot, ArchitectureSnapshotConfig, ArchitectureSnapshotSubscriber, EventObservation, EventSource, FieldStats, extractFieldPaths };
|
|
@@ -9,6 +9,33 @@ import path from "node:path";
|
|
|
9
9
|
* downstream consumers, so add fields rather than rename existing ones.
|
|
10
10
|
*/
|
|
11
11
|
const ARCHITECTURE_SNAPSHOT_SPEC = "autotel-architecture/v0.1.0";
|
|
12
|
+
/**
|
|
13
|
+
* Order two (producer, channel) pairs, comparing the fields rather than a
|
|
14
|
+
* joined key.
|
|
15
|
+
*
|
|
16
|
+
* Both come from caller-supplied `_autotel` metadata and may contain any
|
|
17
|
+
* character, so joining them with a separator is ambiguous: `('A|B', 'C')` and
|
|
18
|
+
* `('A', 'B|C')` produce the same string and would merge into one source.
|
|
19
|
+
*/
|
|
20
|
+
function compareSources(a, b) {
|
|
21
|
+
return (a.producer ?? "").localeCompare(b.producer ?? "") || (a.channel ?? "").localeCompare(b.channel ?? "");
|
|
22
|
+
}
|
|
23
|
+
function recordSource(observation, producer, channel, now) {
|
|
24
|
+
const sources = observation.sources ??= [];
|
|
25
|
+
const existing = sources.find((source) => source.producer === producer && source.channel === channel);
|
|
26
|
+
if (existing) {
|
|
27
|
+
existing.count += 1;
|
|
28
|
+
existing.lastSeen = now;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
sources.push({
|
|
32
|
+
...producer !== void 0 && { producer },
|
|
33
|
+
...channel !== void 0 && { channel },
|
|
34
|
+
count: 1,
|
|
35
|
+
firstSeen: now,
|
|
36
|
+
lastSeen: now
|
|
37
|
+
});
|
|
38
|
+
}
|
|
12
39
|
const DEFAULT_MAX_SAMPLES = 3;
|
|
13
40
|
var ArchitectureSnapshotSubscriber = class extends EventSubscriber {
|
|
14
41
|
name = "ArchitectureSnapshotSubscriber";
|
|
@@ -46,7 +73,14 @@ var ArchitectureSnapshotSubscriber = class extends EventSubscriber {
|
|
|
46
73
|
source: payload.schema.source,
|
|
47
74
|
jsonSchema: payload.schema.jsonSchema,
|
|
48
75
|
hash: payload.schema.hash
|
|
49
|
-
} : void 0
|
|
76
|
+
} : void 0,
|
|
77
|
+
sources: [{
|
|
78
|
+
...autotelMeta.producer !== void 0 && { producer: autotelMeta.producer },
|
|
79
|
+
...autotelMeta.channel !== void 0 && { channel: autotelMeta.channel },
|
|
80
|
+
count: 1,
|
|
81
|
+
firstSeen: now,
|
|
82
|
+
lastSeen: now
|
|
83
|
+
}]
|
|
50
84
|
});
|
|
51
85
|
return;
|
|
52
86
|
}
|
|
@@ -57,6 +91,7 @@ var ArchitectureSnapshotSubscriber = class extends EventSubscriber {
|
|
|
57
91
|
if (traceId && !existing.sampleTraceIds.includes(traceId) && existing.sampleTraceIds.length < this.maxSampleTraceIds) existing.sampleTraceIds.push(traceId);
|
|
58
92
|
existing.channel ??= autotelMeta.channel;
|
|
59
93
|
existing.producer ??= autotelMeta.producer;
|
|
94
|
+
recordSource(existing, autotelMeta.producer, autotelMeta.channel, now);
|
|
60
95
|
existing.consumers = mergeUnique(existing.consumers ?? [], autotelMeta.consumers ?? []);
|
|
61
96
|
existing.schema ??= payload.schema ? {
|
|
62
97
|
source: payload.schema.source,
|
|
@@ -89,7 +124,12 @@ var ArchitectureSnapshotSubscriber = class extends EventSubscriber {
|
|
|
89
124
|
lastSeen: freezeTimestamps ?? obs.lastSeen,
|
|
90
125
|
fieldPaths: obs.fieldPaths.toSorted(),
|
|
91
126
|
sampleTraceIds: obs.sampleTraceIds.toSorted(),
|
|
92
|
-
fieldStats: sortFieldStats(obs.fieldStats)
|
|
127
|
+
fieldStats: sortFieldStats(obs.fieldStats),
|
|
128
|
+
...obs.sources && { sources: obs.sources.map((source) => ({
|
|
129
|
+
...source,
|
|
130
|
+
firstSeen: freezeTimestamps ?? source.firstSeen,
|
|
131
|
+
lastSeen: freezeTimestamps ?? source.lastSeen
|
|
132
|
+
})).toSorted(compareSources) }
|
|
93
133
|
};
|
|
94
134
|
}
|
|
95
135
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-subscribers",
|
|
3
|
-
"version": "56.
|
|
3
|
+
"version": "56.1.1",
|
|
4
4
|
"description": "Write Once, Observe Anywhere - Event subscribers for autotel (Mixpanel, Amplitude, Segment, Slack, webhooks, Loki, file)",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -76,7 +76,9 @@
|
|
|
76
76
|
"files": [
|
|
77
77
|
"dist",
|
|
78
78
|
"examples",
|
|
79
|
-
"README.md"
|
|
79
|
+
"README.md",
|
|
80
|
+
"LICENSE",
|
|
81
|
+
"NOTICE"
|
|
80
82
|
],
|
|
81
83
|
"keywords": [
|
|
82
84
|
"autotel",
|
|
@@ -101,7 +103,7 @@
|
|
|
101
103
|
"slow-redact": "^0.3.2"
|
|
102
104
|
},
|
|
103
105
|
"peerDependencies": {
|
|
104
|
-
"autotel": "7.6.
|
|
106
|
+
"autotel": "7.6.2"
|
|
105
107
|
},
|
|
106
108
|
"peerDependenciesMeta": {
|
|
107
109
|
"posthog-node": {
|
|
@@ -126,7 +128,7 @@
|
|
|
126
128
|
"@types/node": "^26.1.2",
|
|
127
129
|
"@typescript-eslint/eslint-plugin": "^8.65.0",
|
|
128
130
|
"@typescript-eslint/parser": "^8.65.0",
|
|
129
|
-
"autotel": "7.6.
|
|
131
|
+
"autotel": "7.6.2",
|
|
130
132
|
"drizzle-orm": "^0.45.2",
|
|
131
133
|
"eslint-config-prettier": "^10.1.8",
|
|
132
134
|
"eslint-plugin-unicorn": "^64.0.0",
|