@slicemachine/manager 0.17.1-dev-next-release.0 → 0.17.1-dev-next-release.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/dist/managers/telemetry/TelemetryManager.cjs +19 -16
- package/dist/managers/telemetry/TelemetryManager.cjs.map +1 -1
- package/dist/managers/telemetry/TelemetryManager.js +19 -16
- package/dist/managers/telemetry/TelemetryManager.js.map +1 -1
- package/package.json +4 -5
- package/src/managers/telemetry/TelemetryManager.ts +28 -23
|
@@ -7,13 +7,13 @@ var __publicField = (obj, key, value) => {
|
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
9
|
const crypto = require("node:crypto");
|
|
10
|
-
const
|
|
10
|
+
const analyticsNode = require("@segment/analytics-node");
|
|
11
11
|
const prismicrc = require("../../lib/prismicrc.cjs");
|
|
12
12
|
const API_TOKENS = require("../../constants/API_TOKENS.cjs");
|
|
13
13
|
const BaseManager = require("../BaseManager.cjs");
|
|
14
14
|
const types = require("./types.cjs");
|
|
15
15
|
function assertTelemetryInitialized(segmentClient) {
|
|
16
|
-
if (segmentClient
|
|
16
|
+
if (segmentClient === void 0) {
|
|
17
17
|
throw new Error("Telemetry has not been initialized. Run `SliceMachineManager.telemetry.prototype.initTelemetry()` before re-calling this method.");
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -26,17 +26,20 @@ class TelemetryManager extends BaseManager.BaseManager {
|
|
|
26
26
|
__publicField(this, "_context");
|
|
27
27
|
}
|
|
28
28
|
async initTelemetry(args) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
const isTelemetryEnabled = await this.checkIsTelemetryEnabled();
|
|
30
|
+
this._segmentClient = () => {
|
|
31
|
+
const analytics = new analyticsNode.Analytics({
|
|
32
|
+
writeKey: API_TOKENS.API_TOKENS.SegmentKey,
|
|
33
|
+
// Since it's a local app, we do not benefit from event batching the way a server would normally do, all tracking event will be awaited.
|
|
34
|
+
maxEventsInBatch: 1,
|
|
35
|
+
// TODO: Verify that this actually does not send data to Segment when false.
|
|
36
|
+
disable: !isTelemetryEnabled
|
|
37
|
+
});
|
|
38
|
+
analytics.on("error", (error) => {
|
|
39
|
+
console.error(`An error occurred with Segment`, error);
|
|
40
|
+
});
|
|
41
|
+
return analytics;
|
|
42
|
+
};
|
|
40
43
|
this._anonymousID = crypto.randomUUID();
|
|
41
44
|
this._context = { app: { name: args.appName, version: args.appVersion } };
|
|
42
45
|
}
|
|
@@ -72,7 +75,7 @@ class TelemetryManager extends BaseManager.BaseManager {
|
|
|
72
75
|
}
|
|
73
76
|
return new Promise((resolve) => {
|
|
74
77
|
assertTelemetryInitialized(this._segmentClient);
|
|
75
|
-
this._segmentClient.track(payload, (maybeError) => {
|
|
78
|
+
this._segmentClient().track(payload, (maybeError) => {
|
|
76
79
|
if (maybeError && false) {
|
|
77
80
|
console.warn(`An error occurred during Segment tracking`, maybeError);
|
|
78
81
|
}
|
|
@@ -97,7 +100,7 @@ class TelemetryManager extends BaseManager.BaseManager {
|
|
|
97
100
|
this._userID = args.userID;
|
|
98
101
|
return new Promise((resolve) => {
|
|
99
102
|
assertTelemetryInitialized(this._segmentClient);
|
|
100
|
-
this._segmentClient.identify(payload, (maybeError) => {
|
|
103
|
+
this._segmentClient().identify(payload, (maybeError) => {
|
|
101
104
|
if (maybeError && false) {
|
|
102
105
|
console.warn(`An error occurred during Segment identify`, maybeError);
|
|
103
106
|
}
|
|
@@ -129,7 +132,7 @@ class TelemetryManager extends BaseManager.BaseManager {
|
|
|
129
132
|
}
|
|
130
133
|
return new Promise((resolve) => {
|
|
131
134
|
assertTelemetryInitialized(this._segmentClient);
|
|
132
|
-
this._segmentClient.group(payload, (maybeError) => {
|
|
135
|
+
this._segmentClient().group(payload, (maybeError) => {
|
|
133
136
|
if (maybeError && false) {
|
|
134
137
|
console.warn(`An error occurred during Segment group`, maybeError);
|
|
135
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelemetryManager.cjs","sources":["../../../../src/managers/telemetry/TelemetryManager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\n\nimport
|
|
1
|
+
{"version":3,"file":"TelemetryManager.cjs","sources":["../../../../src/managers/telemetry/TelemetryManager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\n\nimport { Analytics, GroupParams, TrackParams } from \"@segment/analytics-node\";\n\nimport { readPrismicrc } from \"../../lib/prismicrc\";\n\nimport { API_TOKENS } from \"../../constants/API_TOKENS\";\n\nimport { BaseManager } from \"../BaseManager\";\n\nimport {\n\tHumanSegmentEventType,\n\tHumanSegmentEventTypes,\n\tSegmentEvents,\n} from \"./types\";\n\ntype TelemetryManagerInitTelemetryArgs = {\n\tappName: string;\n\tappVersion: string;\n};\n\ntype TelemetryManagerTrackArgs = SegmentEvents;\n\ntype TelemetryManagerIdentifyArgs = {\n\tuserID: string;\n\tintercomHash: string;\n};\n\ntype TelemetryManagerGroupArgs = {\n\tmanualLibsCount: number;\n\tdownloadedLibsCount: number;\n\tnpmLibsCount: number;\n\tdownloadedLibs: string[];\n};\n\ntype TelemetryManagerContext = {\n\tapp: {\n\t\tname: string;\n\t\tversion: string;\n\t};\n};\n\nfunction assertTelemetryInitialized(\n\tsegmentClient: (() => Analytics) | undefined,\n): asserts segmentClient is NonNullable<typeof segmentClient> {\n\tif (segmentClient === undefined) {\n\t\tthrow new Error(\n\t\t\t\"Telemetry has not been initialized. Run `SliceMachineManager.telemetry.prototype.initTelemetry()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\nexport class TelemetryManager extends BaseManager {\n\tprivate _segmentClient: (() => Analytics) | undefined = undefined;\n\tprivate _anonymousID: string | undefined = undefined;\n\tprivate _userID: string | undefined = undefined;\n\tprivate _context: TelemetryManagerContext | undefined = undefined;\n\n\tasync initTelemetry(args: TelemetryManagerInitTelemetryArgs): Promise<void> {\n\t\tconst isTelemetryEnabled = await this.checkIsTelemetryEnabled();\n\n\t\tthis._segmentClient = () => {\n\t\t\tconst analytics = new Analytics({\n\t\t\t\twriteKey: API_TOKENS.SegmentKey,\n\t\t\t\t// Since it's a local app, we do not benefit from event batching the way a server would normally do, all tracking event will be awaited.\n\t\t\t\tmaxEventsInBatch: 1,\n\t\t\t\t// TODO: Verify that this actually does not send data to Segment when false.\n\t\t\t\tdisable: !isTelemetryEnabled,\n\t\t\t});\n\n\t\t\tanalytics.on(\"error\", (error) => {\n\t\t\t\t// noop - We don't care if the tracking event\n\t\t\t\t// failed. Some users or networks intentionally\n\t\t\t\t// block Segment, so we can't block the app if\n\t\t\t\t// a tracking event is unsuccessful.\n\t\t\t\tconsole.error(`An error occurred with Segment`, error);\n\t\t\t});\n\n\t\t\treturn analytics;\n\t\t};\n\n\t\tthis._anonymousID = randomUUID();\n\t\tthis._context = { app: { name: args.appName, version: args.appVersion } };\n\t}\n\n\t// TODO: Should `userId` be automatically populated by the logged in\n\t// user? We already have their info via UserRepository.\n\tasync track(args: TelemetryManagerTrackArgs): Promise<void> {\n\t\tconst { event, repository, ...properties } = args;\n\t\tlet repositoryName = repository;\n\n\t\tif (repositoryName === undefined) {\n\t\t\ttry {\n\t\t\t\trepositoryName = await this.project.getRepositoryName();\n\t\t\t} catch (error) {\n\t\t\t\t// noop, happen only when the user is not in a project\n\t\t\t}\n\t\t}\n\n\t\tconst payload: {\n\t\t\tevent: HumanSegmentEventTypes;\n\t\t\tuserId?: string;\n\t\t\tanonymousId?: string;\n\t\t\tproperties?: Record<string, unknown>;\n\t\t\tcontext?: Partial<TelemetryManagerContext> & {\n\t\t\t\tgroupId?: {\n\t\t\t\t\tRepository?: string;\n\t\t\t\t};\n\t\t\t};\n\t\t} = {\n\t\t\tevent: HumanSegmentEventType[event],\n\t\t\tproperties: {\n\t\t\t\tnodeVersion: process.versions.node,\n\t\t\t\t...properties,\n\t\t\t},\n\t\t\tcontext: { ...this._context },\n\t\t};\n\n\t\tif (this._userID) {\n\t\t\tpayload.userId = this._userID;\n\t\t} else {\n\t\t\tpayload.anonymousId = this._anonymousID;\n\t\t}\n\n\t\tif (repositoryName) {\n\t\t\tpayload.context ||= {};\n\t\t\tpayload.context.groupId ||= {};\n\t\t\tpayload.context.groupId.Repository = repositoryName;\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tassertTelemetryInitialized(this._segmentClient);\n\n\t\t\t// TODO: Make sure client fails gracefully when no internet connection\n\t\t\tthis._segmentClient().track(\n\t\t\t\tpayload as TrackParams,\n\t\t\t\t(maybeError?: unknown) => {\n\t\t\t\t\tif (maybeError && import.meta.env.DEV) {\n\t\t\t\t\t\t// TODO: Not sure how we want to deal with that\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`An error occurred during Segment tracking`,\n\t\t\t\t\t\t\tmaybeError,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\t// TODO: Should `userID` and `intercomHash` be automatically populated\n\t// by the logged in user? We already have their info via\n\t// UserRepository.\n\tidentify(args: TelemetryManagerIdentifyArgs): Promise<void> {\n\t\tconst payload = {\n\t\t\tuserId: args.userID,\n\t\t\tanonymousId: this._anonymousID,\n\t\t\tintegrations: {\n\t\t\t\tIntercom: {\n\t\t\t\t\tuser_hash: args.intercomHash,\n\t\t\t\t},\n\t\t\t},\n\t\t\tcontext: { ...this._context },\n\t\t};\n\n\t\tthis._userID = args.userID;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tassertTelemetryInitialized(this._segmentClient);\n\n\t\t\t// TODO: Make sure client fails gracefully when no internet connection\n\t\t\tthis._segmentClient().identify(payload, (maybeError?: unknown) => {\n\t\t\t\tif (maybeError && import.meta.env.DEV) {\n\t\t\t\t\t// TODO: Not sure how we want to deal with that\n\t\t\t\t\tconsole.warn(`An error occurred during Segment identify`, maybeError);\n\t\t\t\t}\n\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync group(args: TelemetryManagerGroupArgs): Promise<void> {\n\t\tlet repositoryName;\n\n\t\ttry {\n\t\t\trepositoryName = await this.project.getRepositoryName();\n\t\t} catch (error) {\n\t\t\t// noop, happen only when the user is not in a project\n\t\t}\n\n\t\tconst payload: {\n\t\t\tgroupId?: string;\n\t\t\tuserId?: string;\n\t\t\tanonymousId?: string;\n\t\t\ttraits?: Record<string, unknown>;\n\t\t\tcontext?: Partial<TelemetryManagerContext> & {\n\t\t\t\tgroupId?: {\n\t\t\t\t\tRepository?: string;\n\t\t\t\t};\n\t\t\t};\n\t\t} = {\n\t\t\ttraits: args,\n\t\t\tcontext: { ...this._context },\n\t\t};\n\n\t\tif (this._userID) {\n\t\t\tpayload.userId = this._userID;\n\t\t} else {\n\t\t\tpayload.anonymousId = this._anonymousID;\n\t\t}\n\n\t\tif (repositoryName) {\n\t\t\tpayload.groupId = repositoryName;\n\t\t\tpayload.context ||= {};\n\t\t\tpayload.context.groupId ||= {};\n\t\t\tpayload.context.groupId.Repository = repositoryName;\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tassertTelemetryInitialized(this._segmentClient);\n\n\t\t\tthis._segmentClient().group(\n\t\t\t\tpayload as GroupParams,\n\t\t\t\t(maybeError?: unknown) => {\n\t\t\t\t\tif (maybeError && import.meta.env.DEV) {\n\t\t\t\t\t\t// TODO: Not sure how we want to deal with that\n\t\t\t\t\t\tconsole.warn(`An error occurred during Segment group`, maybeError);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\tasync checkIsTelemetryEnabled(): Promise<boolean> {\n\t\tlet root: string;\n\t\ttry {\n\t\t\troot = await this.project.getRoot();\n\t\t} catch {\n\t\t\troot = await this.project.suggestRoot();\n\t\t}\n\n\t\treturn readPrismicrc(root).telemetry !== false;\n\t}\n}\n"],"names":["BaseManager","Analytics","API_TOKENS","randomUUID","HumanSegmentEventType","readPrismicrc"],"mappings":";;;;;;;;;;;;;;AA0CA,SAAS,2BACR,eAA4C;AAE5C,MAAI,kBAAkB,QAAW;AAC1B,UAAA,IAAI,MACT,kIAAkI;AAAA,EAEnI;AACF;AAEM,MAAO,yBAAyBA,YAAAA,YAAW;AAAA,EAA3C;AAAA;AACG;AACA;AACA;AACA;AAAA;AAAA,EAER,MAAM,cAAc,MAAuC;AACpD,UAAA,qBAAqB,MAAM,KAAK;AAEtC,SAAK,iBAAiB,MAAK;AACpB,YAAA,YAAY,IAAIC,wBAAU;AAAA,QAC/B,UAAUC,WAAW,WAAA;AAAA;AAAA,QAErB,kBAAkB;AAAA;AAAA,QAElB,SAAS,CAAC;AAAA,MAAA,CACV;AAES,gBAAA,GAAG,SAAS,CAAC,UAAS;AAKvB,gBAAA,MAAM,kCAAkC,KAAK;AAAA,MAAA,CACrD;AAEM,aAAA;AAAA,IAAA;AAGR,SAAK,eAAeC,OAAAA;AACf,SAAA,WAAW,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,SAAS,KAAK;EAC5D;AAAA;AAAA;AAAA,EAIA,MAAM,MAAM,MAA+B;;AAC1C,UAAM,EAAE,OAAO,YAAY,GAAG,eAAe;AAC7C,QAAI,iBAAiB;AAErB,QAAI,mBAAmB,QAAW;AAC7B,UAAA;AACc,yBAAA,MAAM,KAAK,QAAQ;eAC5B;MAER;AAAA,IACD;AAED,UAAM,UAUF;AAAA,MACH,OAAOC,4BAAsB,KAAK;AAAA,MAClC,YAAY;AAAA,QACX,aAAa,QAAQ,SAAS;AAAA,QAC9B,GAAG;AAAA,MACH;AAAA,MACD,SAAS,EAAE,GAAG,KAAK,SAAU;AAAA,IAAA;AAG9B,QAAI,KAAK,SAAS;AACjB,cAAQ,SAAS,KAAK;AAAA,IAAA,OAChB;AACN,cAAQ,cAAc,KAAK;AAAA,IAC3B;AAED,QAAI,gBAAgB;AACnB,cAAQ,YAAR,QAAQ,UAAY;AACZ,oBAAA,SAAQ,YAAR,GAAQ,UAAY;AACpB,cAAA,QAAQ,QAAQ,aAAa;AAAA,IACrC;AAEM,WAAA,IAAI,QAAQ,CAAC,YAAW;AAC9B,iCAA2B,KAAK,cAAc;AAG9C,WAAK,eAAc,EAAG,MACrB,SACA,CAAC,eAAwB;AACpB,YAAA,cAAc,OAAqB;AAE9B,kBAAA,KACP,6CACA,UAAU;AAAA,QAEX;;OAGD;AAAA,IAAA,CAEF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,MAAkC;AAC1C,UAAM,UAAU;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,aAAa,KAAK;AAAA,MAClB,cAAc;AAAA,QACb,UAAU;AAAA,UACT,WAAW,KAAK;AAAA,QAChB;AAAA,MACD;AAAA,MACD,SAAS,EAAE,GAAG,KAAK,SAAU;AAAA,IAAA;AAG9B,SAAK,UAAU,KAAK;AAEb,WAAA,IAAI,QAAQ,CAAC,YAAW;AAC9B,iCAA2B,KAAK,cAAc;AAG9C,WAAK,eAAc,EAAG,SAAS,SAAS,CAAC,eAAwB;AAC5D,YAAA,cAAc,OAAqB;AAE9B,kBAAA,KAAK,6CAA6C,UAAU;AAAA,QACpE;;OAGD;AAAA,IAAA,CACD;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,MAA+B;;AACtC,QAAA;AAEA,QAAA;AACc,uBAAA,MAAM,KAAK,QAAQ;aAC5B;IAER;AAED,UAAM,UAUF;AAAA,MACH,QAAQ;AAAA,MACR,SAAS,EAAE,GAAG,KAAK,SAAU;AAAA,IAAA;AAG9B,QAAI,KAAK,SAAS;AACjB,cAAQ,SAAS,KAAK;AAAA,IAAA,OAChB;AACN,cAAQ,cAAc,KAAK;AAAA,IAC3B;AAED,QAAI,gBAAgB;AACnB,cAAQ,UAAU;AAClB,cAAQ,YAAR,QAAQ,UAAY;AACZ,oBAAA,SAAQ,YAAR,GAAQ,UAAY;AACpB,cAAA,QAAQ,QAAQ,aAAa;AAAA,IACrC;AAEM,WAAA,IAAI,QAAQ,CAAC,YAAW;AAC9B,iCAA2B,KAAK,cAAc;AAE9C,WAAK,eAAc,EAAG,MACrB,SACA,CAAC,eAAwB;AACpB,YAAA,cAAc,OAAqB;AAE9B,kBAAA,KAAK,0CAA0C,UAAU;AAAA,QACjE;;OAGD;AAAA,IAAA,CAEF;AAAA,EACF;AAAA,EAEA,MAAM,0BAAuB;AACxB,QAAA;AACA,QAAA;AACI,aAAA,MAAM,KAAK,QAAQ;YACzB;AACM,aAAA,MAAM,KAAK,QAAQ;IAC1B;AAEM,WAAAC,wBAAc,IAAI,EAAE,cAAc;AAAA,EAC1C;AACA;;"}
|
|
@@ -5,13 +5,13 @@ var __publicField = (obj, key, value) => {
|
|
|
5
5
|
return value;
|
|
6
6
|
};
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
|
-
import
|
|
8
|
+
import { Analytics } from "@segment/analytics-node";
|
|
9
9
|
import { readPrismicrc } from "../../lib/prismicrc.js";
|
|
10
10
|
import { API_TOKENS } from "../../constants/API_TOKENS.js";
|
|
11
11
|
import { BaseManager } from "../BaseManager.js";
|
|
12
12
|
import { HumanSegmentEventType } from "./types.js";
|
|
13
13
|
function assertTelemetryInitialized(segmentClient) {
|
|
14
|
-
if (segmentClient
|
|
14
|
+
if (segmentClient === void 0) {
|
|
15
15
|
throw new Error("Telemetry has not been initialized. Run `SliceMachineManager.telemetry.prototype.initTelemetry()` before re-calling this method.");
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -24,17 +24,20 @@ class TelemetryManager extends BaseManager {
|
|
|
24
24
|
__publicField(this, "_context");
|
|
25
25
|
}
|
|
26
26
|
async initTelemetry(args) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
const isTelemetryEnabled = await this.checkIsTelemetryEnabled();
|
|
28
|
+
this._segmentClient = () => {
|
|
29
|
+
const analytics = new Analytics({
|
|
30
|
+
writeKey: API_TOKENS.SegmentKey,
|
|
31
|
+
// Since it's a local app, we do not benefit from event batching the way a server would normally do, all tracking event will be awaited.
|
|
32
|
+
maxEventsInBatch: 1,
|
|
33
|
+
// TODO: Verify that this actually does not send data to Segment when false.
|
|
34
|
+
disable: !isTelemetryEnabled
|
|
35
|
+
});
|
|
36
|
+
analytics.on("error", (error) => {
|
|
37
|
+
console.error(`An error occurred with Segment`, error);
|
|
38
|
+
});
|
|
39
|
+
return analytics;
|
|
40
|
+
};
|
|
38
41
|
this._anonymousID = randomUUID();
|
|
39
42
|
this._context = { app: { name: args.appName, version: args.appVersion } };
|
|
40
43
|
}
|
|
@@ -70,7 +73,7 @@ class TelemetryManager extends BaseManager {
|
|
|
70
73
|
}
|
|
71
74
|
return new Promise((resolve) => {
|
|
72
75
|
assertTelemetryInitialized(this._segmentClient);
|
|
73
|
-
this._segmentClient.track(payload, (maybeError) => {
|
|
76
|
+
this._segmentClient().track(payload, (maybeError) => {
|
|
74
77
|
if (maybeError && false) {
|
|
75
78
|
console.warn(`An error occurred during Segment tracking`, maybeError);
|
|
76
79
|
}
|
|
@@ -95,7 +98,7 @@ class TelemetryManager extends BaseManager {
|
|
|
95
98
|
this._userID = args.userID;
|
|
96
99
|
return new Promise((resolve) => {
|
|
97
100
|
assertTelemetryInitialized(this._segmentClient);
|
|
98
|
-
this._segmentClient.identify(payload, (maybeError) => {
|
|
101
|
+
this._segmentClient().identify(payload, (maybeError) => {
|
|
99
102
|
if (maybeError && false) {
|
|
100
103
|
console.warn(`An error occurred during Segment identify`, maybeError);
|
|
101
104
|
}
|
|
@@ -127,7 +130,7 @@ class TelemetryManager extends BaseManager {
|
|
|
127
130
|
}
|
|
128
131
|
return new Promise((resolve) => {
|
|
129
132
|
assertTelemetryInitialized(this._segmentClient);
|
|
130
|
-
this._segmentClient.group(payload, (maybeError) => {
|
|
133
|
+
this._segmentClient().group(payload, (maybeError) => {
|
|
131
134
|
if (maybeError && false) {
|
|
132
135
|
console.warn(`An error occurred during Segment group`, maybeError);
|
|
133
136
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelemetryManager.js","sources":["../../../../src/managers/telemetry/TelemetryManager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\n\nimport
|
|
1
|
+
{"version":3,"file":"TelemetryManager.js","sources":["../../../../src/managers/telemetry/TelemetryManager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\n\nimport { Analytics, GroupParams, TrackParams } from \"@segment/analytics-node\";\n\nimport { readPrismicrc } from \"../../lib/prismicrc\";\n\nimport { API_TOKENS } from \"../../constants/API_TOKENS\";\n\nimport { BaseManager } from \"../BaseManager\";\n\nimport {\n\tHumanSegmentEventType,\n\tHumanSegmentEventTypes,\n\tSegmentEvents,\n} from \"./types\";\n\ntype TelemetryManagerInitTelemetryArgs = {\n\tappName: string;\n\tappVersion: string;\n};\n\ntype TelemetryManagerTrackArgs = SegmentEvents;\n\ntype TelemetryManagerIdentifyArgs = {\n\tuserID: string;\n\tintercomHash: string;\n};\n\ntype TelemetryManagerGroupArgs = {\n\tmanualLibsCount: number;\n\tdownloadedLibsCount: number;\n\tnpmLibsCount: number;\n\tdownloadedLibs: string[];\n};\n\ntype TelemetryManagerContext = {\n\tapp: {\n\t\tname: string;\n\t\tversion: string;\n\t};\n};\n\nfunction assertTelemetryInitialized(\n\tsegmentClient: (() => Analytics) | undefined,\n): asserts segmentClient is NonNullable<typeof segmentClient> {\n\tif (segmentClient === undefined) {\n\t\tthrow new Error(\n\t\t\t\"Telemetry has not been initialized. Run `SliceMachineManager.telemetry.prototype.initTelemetry()` before re-calling this method.\",\n\t\t);\n\t}\n}\n\nexport class TelemetryManager extends BaseManager {\n\tprivate _segmentClient: (() => Analytics) | undefined = undefined;\n\tprivate _anonymousID: string | undefined = undefined;\n\tprivate _userID: string | undefined = undefined;\n\tprivate _context: TelemetryManagerContext | undefined = undefined;\n\n\tasync initTelemetry(args: TelemetryManagerInitTelemetryArgs): Promise<void> {\n\t\tconst isTelemetryEnabled = await this.checkIsTelemetryEnabled();\n\n\t\tthis._segmentClient = () => {\n\t\t\tconst analytics = new Analytics({\n\t\t\t\twriteKey: API_TOKENS.SegmentKey,\n\t\t\t\t// Since it's a local app, we do not benefit from event batching the way a server would normally do, all tracking event will be awaited.\n\t\t\t\tmaxEventsInBatch: 1,\n\t\t\t\t// TODO: Verify that this actually does not send data to Segment when false.\n\t\t\t\tdisable: !isTelemetryEnabled,\n\t\t\t});\n\n\t\t\tanalytics.on(\"error\", (error) => {\n\t\t\t\t// noop - We don't care if the tracking event\n\t\t\t\t// failed. Some users or networks intentionally\n\t\t\t\t// block Segment, so we can't block the app if\n\t\t\t\t// a tracking event is unsuccessful.\n\t\t\t\tconsole.error(`An error occurred with Segment`, error);\n\t\t\t});\n\n\t\t\treturn analytics;\n\t\t};\n\n\t\tthis._anonymousID = randomUUID();\n\t\tthis._context = { app: { name: args.appName, version: args.appVersion } };\n\t}\n\n\t// TODO: Should `userId` be automatically populated by the logged in\n\t// user? We already have their info via UserRepository.\n\tasync track(args: TelemetryManagerTrackArgs): Promise<void> {\n\t\tconst { event, repository, ...properties } = args;\n\t\tlet repositoryName = repository;\n\n\t\tif (repositoryName === undefined) {\n\t\t\ttry {\n\t\t\t\trepositoryName = await this.project.getRepositoryName();\n\t\t\t} catch (error) {\n\t\t\t\t// noop, happen only when the user is not in a project\n\t\t\t}\n\t\t}\n\n\t\tconst payload: {\n\t\t\tevent: HumanSegmentEventTypes;\n\t\t\tuserId?: string;\n\t\t\tanonymousId?: string;\n\t\t\tproperties?: Record<string, unknown>;\n\t\t\tcontext?: Partial<TelemetryManagerContext> & {\n\t\t\t\tgroupId?: {\n\t\t\t\t\tRepository?: string;\n\t\t\t\t};\n\t\t\t};\n\t\t} = {\n\t\t\tevent: HumanSegmentEventType[event],\n\t\t\tproperties: {\n\t\t\t\tnodeVersion: process.versions.node,\n\t\t\t\t...properties,\n\t\t\t},\n\t\t\tcontext: { ...this._context },\n\t\t};\n\n\t\tif (this._userID) {\n\t\t\tpayload.userId = this._userID;\n\t\t} else {\n\t\t\tpayload.anonymousId = this._anonymousID;\n\t\t}\n\n\t\tif (repositoryName) {\n\t\t\tpayload.context ||= {};\n\t\t\tpayload.context.groupId ||= {};\n\t\t\tpayload.context.groupId.Repository = repositoryName;\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tassertTelemetryInitialized(this._segmentClient);\n\n\t\t\t// TODO: Make sure client fails gracefully when no internet connection\n\t\t\tthis._segmentClient().track(\n\t\t\t\tpayload as TrackParams,\n\t\t\t\t(maybeError?: unknown) => {\n\t\t\t\t\tif (maybeError && import.meta.env.DEV) {\n\t\t\t\t\t\t// TODO: Not sure how we want to deal with that\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`An error occurred during Segment tracking`,\n\t\t\t\t\t\t\tmaybeError,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\t// TODO: Should `userID` and `intercomHash` be automatically populated\n\t// by the logged in user? We already have their info via\n\t// UserRepository.\n\tidentify(args: TelemetryManagerIdentifyArgs): Promise<void> {\n\t\tconst payload = {\n\t\t\tuserId: args.userID,\n\t\t\tanonymousId: this._anonymousID,\n\t\t\tintegrations: {\n\t\t\t\tIntercom: {\n\t\t\t\t\tuser_hash: args.intercomHash,\n\t\t\t\t},\n\t\t\t},\n\t\t\tcontext: { ...this._context },\n\t\t};\n\n\t\tthis._userID = args.userID;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tassertTelemetryInitialized(this._segmentClient);\n\n\t\t\t// TODO: Make sure client fails gracefully when no internet connection\n\t\t\tthis._segmentClient().identify(payload, (maybeError?: unknown) => {\n\t\t\t\tif (maybeError && import.meta.env.DEV) {\n\t\t\t\t\t// TODO: Not sure how we want to deal with that\n\t\t\t\t\tconsole.warn(`An error occurred during Segment identify`, maybeError);\n\t\t\t\t}\n\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync group(args: TelemetryManagerGroupArgs): Promise<void> {\n\t\tlet repositoryName;\n\n\t\ttry {\n\t\t\trepositoryName = await this.project.getRepositoryName();\n\t\t} catch (error) {\n\t\t\t// noop, happen only when the user is not in a project\n\t\t}\n\n\t\tconst payload: {\n\t\t\tgroupId?: string;\n\t\t\tuserId?: string;\n\t\t\tanonymousId?: string;\n\t\t\ttraits?: Record<string, unknown>;\n\t\t\tcontext?: Partial<TelemetryManagerContext> & {\n\t\t\t\tgroupId?: {\n\t\t\t\t\tRepository?: string;\n\t\t\t\t};\n\t\t\t};\n\t\t} = {\n\t\t\ttraits: args,\n\t\t\tcontext: { ...this._context },\n\t\t};\n\n\t\tif (this._userID) {\n\t\t\tpayload.userId = this._userID;\n\t\t} else {\n\t\t\tpayload.anonymousId = this._anonymousID;\n\t\t}\n\n\t\tif (repositoryName) {\n\t\t\tpayload.groupId = repositoryName;\n\t\t\tpayload.context ||= {};\n\t\t\tpayload.context.groupId ||= {};\n\t\t\tpayload.context.groupId.Repository = repositoryName;\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tassertTelemetryInitialized(this._segmentClient);\n\n\t\t\tthis._segmentClient().group(\n\t\t\t\tpayload as GroupParams,\n\t\t\t\t(maybeError?: unknown) => {\n\t\t\t\t\tif (maybeError && import.meta.env.DEV) {\n\t\t\t\t\t\t// TODO: Not sure how we want to deal with that\n\t\t\t\t\t\tconsole.warn(`An error occurred during Segment group`, maybeError);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\t}\n\n\tasync checkIsTelemetryEnabled(): Promise<boolean> {\n\t\tlet root: string;\n\t\ttry {\n\t\t\troot = await this.project.getRoot();\n\t\t} catch {\n\t\t\troot = await this.project.suggestRoot();\n\t\t}\n\n\t\treturn readPrismicrc(root).telemetry !== false;\n\t}\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slicemachine/manager",
|
|
3
|
-
"version": "0.17.1-dev-next-release.
|
|
3
|
+
"version": "0.17.1-dev-next-release.1",
|
|
4
4
|
"description": "Manage all aspects of a Slice Machine project.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"@prismicio/custom-types-client": "1.2.0-alpha.0",
|
|
69
69
|
"@prismicio/mocks": "2.0.0",
|
|
70
70
|
"@prismicio/types-internal": "^2.2.0",
|
|
71
|
-
"@
|
|
71
|
+
"@segment/analytics-node": "1.1.3",
|
|
72
|
+
"@slicemachine/plugin-kit": "^0.4.27-dev-next-release.1",
|
|
72
73
|
"@wooorm/starry-night": "^1.6.0",
|
|
73
|
-
"analytics-node": "^6.2.0",
|
|
74
74
|
"cookie": "^0.5.0",
|
|
75
75
|
"cors": "^2.8.5",
|
|
76
76
|
"execa": "^7.1.1",
|
|
@@ -99,7 +99,6 @@
|
|
|
99
99
|
"devDependencies": {
|
|
100
100
|
"@prismicio/mock": "0.2.0",
|
|
101
101
|
"@size-limit/preset-small-lib": "8.2.4",
|
|
102
|
-
"@types/analytics-node": "3.1.11",
|
|
103
102
|
"@types/cookie": "0.5.1",
|
|
104
103
|
"@types/express": "4.17.17",
|
|
105
104
|
"@types/semver": "7.3.13",
|
|
@@ -134,5 +133,5 @@
|
|
|
134
133
|
"engines": {
|
|
135
134
|
"node": ">=14.15.0"
|
|
136
135
|
},
|
|
137
|
-
"gitHead": "
|
|
136
|
+
"gitHead": "8f90a3fcb3d524b0cb2ecdfe848b059884e49c11"
|
|
138
137
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { Analytics, GroupParams, TrackParams } from "@segment/analytics-node";
|
|
4
4
|
|
|
5
5
|
import { readPrismicrc } from "../../lib/prismicrc";
|
|
6
6
|
|
|
@@ -41,9 +41,9 @@ type TelemetryManagerContext = {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
function assertTelemetryInitialized(
|
|
44
|
-
segmentClient:
|
|
44
|
+
segmentClient: (() => Analytics) | undefined,
|
|
45
45
|
): asserts segmentClient is NonNullable<typeof segmentClient> {
|
|
46
|
-
if (segmentClient
|
|
46
|
+
if (segmentClient === undefined) {
|
|
47
47
|
throw new Error(
|
|
48
48
|
"Telemetry has not been initialized. Run `SliceMachineManager.telemetry.prototype.initTelemetry()` before re-calling this method.",
|
|
49
49
|
);
|
|
@@ -51,29 +51,34 @@ function assertTelemetryInitialized(
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export class TelemetryManager extends BaseManager {
|
|
54
|
-
private _segmentClient:
|
|
54
|
+
private _segmentClient: (() => Analytics) | undefined = undefined;
|
|
55
55
|
private _anonymousID: string | undefined = undefined;
|
|
56
56
|
private _userID: string | undefined = undefined;
|
|
57
57
|
private _context: TelemetryManagerContext | undefined = undefined;
|
|
58
58
|
|
|
59
59
|
async initTelemetry(args: TelemetryManagerInitTelemetryArgs): Promise<void> {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
const isTelemetryEnabled = await this.checkIsTelemetryEnabled();
|
|
61
|
+
|
|
62
|
+
this._segmentClient = () => {
|
|
63
|
+
const analytics = new Analytics({
|
|
64
|
+
writeKey: API_TOKENS.SegmentKey,
|
|
65
|
+
// Since it's a local app, we do not benefit from event batching the way a server would normally do, all tracking event will be awaited.
|
|
66
|
+
maxEventsInBatch: 1,
|
|
67
|
+
// TODO: Verify that this actually does not send data to Segment when false.
|
|
68
|
+
disable: !isTelemetryEnabled,
|
|
69
|
+
});
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
// Since it's a local app, we do not benefit from event batching the way a server would normally do, all tracking event will be awaited.
|
|
67
|
-
flushAt: 1,
|
|
68
|
-
// TODO: Verify that this actually does not send data to Segment when false.
|
|
69
|
-
enable: await this.checkIsTelemetryEnabled(),
|
|
70
|
-
errorHandler: () => {
|
|
71
|
+
analytics.on("error", (error) => {
|
|
71
72
|
// noop - We don't care if the tracking event
|
|
72
73
|
// failed. Some users or networks intentionally
|
|
73
74
|
// block Segment, so we can't block the app if
|
|
74
75
|
// a tracking event is unsuccessful.
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
console.error(`An error occurred with Segment`, error);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return analytics;
|
|
80
|
+
};
|
|
81
|
+
|
|
77
82
|
this._anonymousID = randomUUID();
|
|
78
83
|
this._context = { app: { name: args.appName, version: args.appVersion } };
|
|
79
84
|
}
|
|
@@ -127,9 +132,9 @@ export class TelemetryManager extends BaseManager {
|
|
|
127
132
|
assertTelemetryInitialized(this._segmentClient);
|
|
128
133
|
|
|
129
134
|
// TODO: Make sure client fails gracefully when no internet connection
|
|
130
|
-
this._segmentClient.track(
|
|
131
|
-
payload as
|
|
132
|
-
(maybeError?:
|
|
135
|
+
this._segmentClient().track(
|
|
136
|
+
payload as TrackParams,
|
|
137
|
+
(maybeError?: unknown) => {
|
|
133
138
|
if (maybeError && import.meta.env.DEV) {
|
|
134
139
|
// TODO: Not sure how we want to deal with that
|
|
135
140
|
console.warn(
|
|
@@ -165,7 +170,7 @@ export class TelemetryManager extends BaseManager {
|
|
|
165
170
|
assertTelemetryInitialized(this._segmentClient);
|
|
166
171
|
|
|
167
172
|
// TODO: Make sure client fails gracefully when no internet connection
|
|
168
|
-
this._segmentClient.identify(payload, (maybeError?:
|
|
173
|
+
this._segmentClient().identify(payload, (maybeError?: unknown) => {
|
|
169
174
|
if (maybeError && import.meta.env.DEV) {
|
|
170
175
|
// TODO: Not sure how we want to deal with that
|
|
171
176
|
console.warn(`An error occurred during Segment identify`, maybeError);
|
|
@@ -216,9 +221,9 @@ export class TelemetryManager extends BaseManager {
|
|
|
216
221
|
return new Promise((resolve) => {
|
|
217
222
|
assertTelemetryInitialized(this._segmentClient);
|
|
218
223
|
|
|
219
|
-
this._segmentClient.group(
|
|
220
|
-
payload as
|
|
221
|
-
(maybeError?:
|
|
224
|
+
this._segmentClient().group(
|
|
225
|
+
payload as GroupParams,
|
|
226
|
+
(maybeError?: unknown) => {
|
|
222
227
|
if (maybeError && import.meta.env.DEV) {
|
|
223
228
|
// TODO: Not sure how we want to deal with that
|
|
224
229
|
console.warn(`An error occurred during Segment group`, maybeError);
|