gitpreflight 0.1.14 → 0.1.16

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/README.md CHANGED
@@ -16,6 +16,8 @@ gitpreflight version
16
16
 
17
17
  `gitpreflight` is a lightweight npm wrapper that downloads and runs the official GitPreflight binary for your platform.
18
18
 
19
+ By default, install flow sends a minimal anonymous install event with only a random install ID so we can measure install usage. No user identity or repo contents are included. Set `GITPREFLIGHT_ANON_TELEMETRY=0` to disable.
20
+
19
21
  Docs and source:
20
22
 
21
23
  - https://github.com/un/gitPreflight
@@ -3,6 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { ensureGitPreflightBinary } = require("../lib/installer");
6
+ const { sendInstallUsageEvent } = require("../lib/telemetry");
6
7
 
7
8
  async function main() {
8
9
  const interactive = Boolean(process.stdout.isTTY) && Boolean(process.stderr.isTTY) && process.env.CI !== "1" && process.env.CI !== "true";
@@ -30,6 +31,7 @@ async function main() {
30
31
  }
31
32
 
32
33
  await ensureGitPreflightBinary({ reason: "postinstall" });
34
+ await sendInstallUsageEvent();
33
35
 
34
36
  if (interactive) {
35
37
  process.stderr.write("GitPreflight installed. Next: run `gitpreflight setup` to configure hooks.\n");
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+
3
+ const fsp = require("node:fs/promises");
4
+ const os = require("node:os");
5
+ const path = require("node:path");
6
+ const crypto = require("node:crypto");
7
+
8
+ const DEFAULT_TELEMETRY_BASE_URL = "https://gitpreflight.ai";
9
+
10
+ function isTruthy(v) {
11
+ if (!v) return false;
12
+ const t = String(v).trim().toLowerCase();
13
+ return t === "1" || t === "true" || t === "yes";
14
+ }
15
+
16
+ function isFalsy(v) {
17
+ if (!v) return false;
18
+ const t = String(v).trim().toLowerCase();
19
+ return t === "0" || t === "false" || t === "no";
20
+ }
21
+
22
+ function telemetryEnabled(env) {
23
+ if (isTruthy(env.GITPREFLIGHT_DISABLE_ANON_TELEMETRY)) return false;
24
+ if (isFalsy(env.GITPREFLIGHT_ANON_TELEMETRY)) return false;
25
+ return true;
26
+ }
27
+
28
+ function configDir() {
29
+ const xdg = process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim();
30
+ if (xdg) return path.join(xdg, "gitpreflight");
31
+ return path.join(os.homedir(), ".config", "gitpreflight");
32
+ }
33
+
34
+ function installIdPath() {
35
+ return path.join(configDir(), "install-id");
36
+ }
37
+
38
+ function isValidInstallId(value) {
39
+ return typeof value === "string" && value.length >= 16 && value.length <= 128;
40
+ }
41
+
42
+ function generateInstallId() {
43
+ if (typeof crypto.randomUUID === "function") {
44
+ const id = crypto.randomUUID();
45
+ if (id) return id;
46
+ }
47
+ return crypto.randomBytes(16).toString("hex");
48
+ }
49
+
50
+ async function loadOrCreateInstallId() {
51
+ const abs = installIdPath();
52
+ try {
53
+ const raw = await fsp.readFile(abs, "utf8");
54
+ const value = raw.trim();
55
+ if (isValidInstallId(value)) return value;
56
+ } catch {
57
+ // Fall through.
58
+ }
59
+
60
+ await fsp.mkdir(path.dirname(abs), { recursive: true });
61
+ const next = generateInstallId();
62
+ await fsp.writeFile(abs, `${next}\n`, "utf8");
63
+ try {
64
+ await fsp.chmod(abs, 0o600);
65
+ } catch {
66
+ // best-effort
67
+ }
68
+ return next;
69
+ }
70
+
71
+ function telemetryBaseUrl(env) {
72
+ const base =
73
+ (env.GITPREFLIGHT_TELEMETRY_BASE_URL && env.GITPREFLIGHT_TELEMETRY_BASE_URL.trim()) ||
74
+ (env.GITPREFLIGHT_API_BASE_URL && env.GITPREFLIGHT_API_BASE_URL.trim()) ||
75
+ DEFAULT_TELEMETRY_BASE_URL;
76
+ return base.replace(/\/+$/, "");
77
+ }
78
+
79
+ async function postJson(url, body, timeoutMs) {
80
+ const ac = new AbortController();
81
+ const timeout = setTimeout(() => ac.abort(), timeoutMs);
82
+ try {
83
+ await fetch(url, {
84
+ method: "POST",
85
+ headers: {
86
+ "content-type": "application/json",
87
+ "user-agent": "gitpreflight-installer"
88
+ },
89
+ body: JSON.stringify(body),
90
+ signal: ac.signal
91
+ });
92
+ } finally {
93
+ clearTimeout(timeout);
94
+ }
95
+ }
96
+
97
+ async function sendInstallUsageEvent() {
98
+ const env = process.env;
99
+ if (!telemetryEnabled(env)) return;
100
+
101
+ try {
102
+ const installId = await loadOrCreateInstallId();
103
+ const baseUrl = telemetryBaseUrl(env);
104
+ await postJson(
105
+ `${baseUrl}/api/v1/usage/install`,
106
+ {
107
+ installId
108
+ },
109
+ 1500
110
+ );
111
+ } catch {
112
+ // Best-effort telemetry only.
113
+ }
114
+ }
115
+
116
+ module.exports = {
117
+ sendInstallUsageEvent
118
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitpreflight",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "GitPreflight CLI installer/wrapper (downloads the platform binary)",
5
5
  "repository": {
6
6
  "type": "git",