@bitvea/feedback-cli 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 (42) hide show
  1. package/README.md +38 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +24 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/commands/init.d.ts +97 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +273 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/register.d.ts +84 -0
  11. package/dist/commands/register.d.ts.map +1 -0
  12. package/dist/commands/register.js +125 -0
  13. package/dist/commands/register.js.map +1 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +9 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/install/env.d.ts +2 -0
  19. package/dist/install/env.d.ts.map +1 -0
  20. package/dist/install/env.js +19 -0
  21. package/dist/install/env.js.map +1 -0
  22. package/dist/install/fs.d.ts +16 -0
  23. package/dist/install/fs.d.ts.map +1 -0
  24. package/dist/install/fs.js +33 -0
  25. package/dist/install/fs.js.map +1 -0
  26. package/dist/install/strategies.d.ts +109 -0
  27. package/dist/install/strategies.d.ts.map +1 -0
  28. package/dist/install/strategies.js +208 -0
  29. package/dist/install/strategies.js.map +1 -0
  30. package/dist/registration.d.ts +43 -0
  31. package/dist/registration.d.ts.map +1 -0
  32. package/dist/registration.js +84 -0
  33. package/dist/registration.js.map +1 -0
  34. package/dist/run.d.ts +14 -0
  35. package/dist/run.d.ts.map +1 -0
  36. package/dist/run.js +293 -0
  37. package/dist/run.js.map +1 -0
  38. package/dist/toolbarVersion.d.ts +36 -0
  39. package/dist/toolbarVersion.d.ts.map +1 -0
  40. package/dist/toolbarVersion.js +106 -0
  41. package/dist/toolbarVersion.js.map +1 -0
  42. package/package.json +46 -0
@@ -0,0 +1,84 @@
1
+ // Talking to the registration endpoint, and nothing else.
2
+ //
3
+ // The rule this file exists to keep is that the CLI does not know what a valid
4
+ // project URL is. Registration's contract - normalise the URL, key on it, be
5
+ // idempotent, lose the race gracefully - lives once in
6
+ // `packages/api/src/services/projects.ts`, behind
7
+ // `POST /api/v1/projects/register`. A second opinion here would be a second
8
+ // implementation, and the failure mode of two implementations disagreeing is a
9
+ // duplicate project: two rows for one deployment, each holding half its
10
+ // feedback, with no way to merge them afterwards.
11
+ //
12
+ // So this module posts what it was given and translates the answer. It trims
13
+ // no slashes, lowercases no hosts, and rejects nothing.
14
+ /**
15
+ * A failure the person running the command can act on, as opposed to a bug.
16
+ * The CLI prints `message` and exits; nothing else is expected to catch it.
17
+ */
18
+ export class RegistrationError extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "RegistrationError";
22
+ }
23
+ }
24
+ /** The real transport. Injected everywhere else so tests stay off the network. */
25
+ export const postRegistration = async (input) => {
26
+ let res;
27
+ try {
28
+ res = await fetch(`${input.apiUrl}/api/v1/projects/register`, {
29
+ method: "POST",
30
+ headers: {
31
+ "content-type": "application/json",
32
+ authorization: `Bearer ${input.apiKey}`,
33
+ },
34
+ body: JSON.stringify({
35
+ url: input.projectUrl,
36
+ repoOwner: input.repoOwner,
37
+ repoSlug: input.repoSlug,
38
+ packageName: input.packageName,
39
+ origins: input.origins,
40
+ }),
41
+ });
42
+ }
43
+ catch (err) {
44
+ // DNS, TLS, a wrong host, no network in the build container. Worth naming
45
+ // the URL: the commonest cause is an --api-url pointing at nothing.
46
+ throw new RegistrationError(`could not reach ${input.apiUrl} (${String(err)}). Check --api-url.`);
47
+ }
48
+ if (res.status === 401) {
49
+ // The commonest real failure, and the one a bare status code explains
50
+ // worst. Absent, mistyped and revoked all answer 401 on purpose - the
51
+ // route refuses to be an oracle for which - so say all three.
52
+ throw new RegistrationError("the deploy key was refused (401): it is missing, wrong or revoked. " +
53
+ "Create one in the dashboard under Settings > Deploy keys, then pass it as " +
54
+ "--api-key or set FEEDBACK_TOOLBAR_API_KEY.");
55
+ }
56
+ if (!res.ok) {
57
+ // The backend's own error code, verbatim. `invalid_project_url` is the one
58
+ // that matters, and paraphrasing it here would be the beginning of a
59
+ // second set of validation rules.
60
+ const code = await res
61
+ .json()
62
+ .then((body) => body !== null && typeof body === "object" && "error" in body
63
+ ? String(body.error)
64
+ : undefined)
65
+ .catch(() => undefined);
66
+ // The one refusal a build operator can act on, and the one whose bare code
67
+ // explains nothing. A deploy key belongs to exactly one agency and may
68
+ // register URLs into that agency alone, so this fires when the URL is
69
+ // already registered somewhere the key cannot write. What it deliberately
70
+ // does NOT say is where: the route answers one opaque code precisely so it
71
+ // cannot be used to enumerate which deployment URLs exist in an install and
72
+ // which customer runs them, and repeating a guess here would give away by
73
+ // paraphrase what the status code refuses to give away directly.
74
+ if (code === "project_url_unavailable") {
75
+ throw new RegistrationError(`${input.projectUrl} cannot be registered with this deploy key (409). ` +
76
+ "Either it is already registered outside this key's agency, or the key " +
77
+ "belongs to a different agency than the one that should own it. Check " +
78
+ "which key the build is using under Settings > Deploy keys.");
79
+ }
80
+ throw new RegistrationError(`registration failed with ${res.status}${code ? ` (${code})` : ""}.`);
81
+ }
82
+ return (await res.json());
83
+ };
84
+ //# sourceMappingURL=registration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.js","sourceRoot":"","sources":["../src/registration.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,uDAAuD;AACvD,kDAAkD;AAClD,4EAA4E;AAC5E,+EAA+E;AAC/E,wEAAwE;AACxE,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,wDAAwD;AAmCxD;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,kFAAkF;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAA6B,KAAK,EAAE,KAAK,EAAE,EAAE;IACxE,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,2BAA2B,EAAE;YAC5D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,CAAC,MAAM,EAAE;aACxC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,GAAG,EAAE,KAAK,CAAC,UAAU;gBACrB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0EAA0E;QAC1E,oEAAoE;QACpE,MAAM,IAAI,iBAAiB,CACzB,mBAAmB,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,GAAG,CAAC,qBAAqB,CACrE,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,sEAAsE;QACtE,sEAAsE;QACtE,8DAA8D;QAC9D,MAAM,IAAI,iBAAiB,CACzB,qEAAqE;YACnE,4EAA4E;YAC5E,4CAA4C,CAC/C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,2EAA2E;QAC3E,qEAAqE;QACrE,kCAAkC;QAClC,MAAM,IAAI,GAAG,MAAM,GAAG;aACnB,IAAI,EAAE;aACN,IAAI,CAAC,CAAC,IAAa,EAAE,EAAE,CACtB,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI;YAC1D,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,SAAS,CACd;aACA,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAE1B,2EAA2E;QAC3E,uEAAuE;QACvE,sEAAsE;QACtE,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,0EAA0E;QAC1E,iEAAiE;QACjE,IAAI,IAAI,KAAK,yBAAyB,EAAE,CAAC;YACvC,MAAM,IAAI,iBAAiB,CACzB,GAAG,KAAK,CAAC,UAAU,oDAAoD;gBACrE,wEAAwE;gBACxE,uEAAuE;gBACvE,4DAA4D,CAC/D,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,iBAAiB,CACzB,4BAA4B,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CACrE,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;AACvD,CAAC,CAAC"}
package/dist/run.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface RunOptions {
2
+ /**
3
+ * The version of `@bitvea/feedback-toolbar` the caller was launched
4
+ * through, when there was one.
5
+ *
6
+ * Only `@bitvea/feedback-toolbar`'s own bin passes this, from the
7
+ * `package.json` sitting next to it, and it is the third rung of the ladder
8
+ * in ./toolbarVersion.ts - the one every `npx @bitvea/feedback-toolbar init`
9
+ * takes. Absent when this CLI was run directly.
10
+ */
11
+ toolbarVersion?: string | undefined;
12
+ }
13
+ export declare function run(argv: string[], options?: RunOptions): Promise<number>;
14
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,UAAU;IACzB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AA2PD,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
package/dist/run.js ADDED
@@ -0,0 +1,293 @@
1
+ // The command table, as a function: argv in, exit code out.
2
+ //
3
+ // THIS PACKAGE HAS ZERO RUNTIME DEPENDENCIES, and its publishable check fails
4
+ // if `dependencies` is ever non-empty. That is not asceticism. The whole
5
+ // reason the installer was hard to grow inside the toolbar is that every
6
+ // argument parser, every colour library, every prompt library it might want
7
+ // would land in a customer's browser app - and after the split it still would,
8
+ // because `@bitvea/feedback-toolbar` depends on this package, so this package
9
+ // is installed transitively into every app that installs the toolbar. Moving
10
+ // the files without taking the dependency budget with them would buy a package
11
+ // boundary and nothing else. Node's standard library covers what this CLI
12
+ // needs: `node:util`'s `parseArgs` and `styleText` when the hand-rolled flag
13
+ // reader below stops being enough, `node:readline` if a prompt is ever wanted.
14
+ //
15
+ // `run` is exported from the package root rather than being reachable only as
16
+ // a bin, and that is what lets `@bitvea/feedback-toolbar`'s own `bin` be an
17
+ // in-process call instead of a subprocess: same argv, same stdout, same exit
18
+ // codes, because it is the same function in the same process.
19
+ //
20
+ // Everything of substance is in commands/init.ts and commands/register.ts,
21
+ // behind an InstallerFs and an injected transport respectively. This file is
22
+ // the part that touches the real disk and the real network, parses argv, and
23
+ // turns a thrown error into an exit code and a message a developer can act on.
24
+ //
25
+ // `register` is a first-class command rather than a step inside `init`,
26
+ // because two install paths need it on its own: a Next.js app runs it from its
27
+ // build (init wires it in as `prebuild`), and a script-tag install has no
28
+ // build at all and runs it once from a terminal or CI.
29
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
30
+ import { dirname, join } from "node:path";
31
+ import { mkdirSync } from "node:fs";
32
+ import { fileURLToPath } from "node:url";
33
+ import { init } from "./commands/init.js";
34
+ import { API_KEY_ENV_VAR, register } from "./commands/register.js";
35
+ import { RegistrationError, postRegistration } from "./registration.js";
36
+ import { InjectionError, PACKAGE_NAME } from "./install/strategies.js";
37
+ import { ToolbarVersionError, resolveToolbarRange, } from "./toolbarVersion.js";
38
+ const realFs = {
39
+ exists: (path) => existsSync(path),
40
+ readFile: (path) => readFileSync(path, "utf8"),
41
+ writeFile: (path, contents) => {
42
+ mkdirSync(dirname(path), { recursive: true });
43
+ writeFileSync(path, contents, "utf8");
44
+ },
45
+ };
46
+ // The usage text names `feedback-toolbar`, not this package, and that is
47
+ // deliberate rather than stale. `npx @bitvea/feedback-toolbar init` is printed
48
+ // on the product's homepage, in two dashboard panels and in a `prebuild` line
49
+ // committed in repositories nobody here controls; this package's name is an
50
+ // implementation detail that nobody should have to learn. The text is also
51
+ // read by both packages' publishable checks, which compare this stdout byte
52
+ // for byte across the launcher and this bin - so it says the same thing
53
+ // whichever door a person came in through.
54
+ const USAGE = `feedback-toolbar - BitVea Feedback installer
55
+
56
+ init Install the toolbar into the app in the current directory.
57
+ register Make sure this deployment exists as a project in the dashboard.
58
+
59
+ npx @bitvea/feedback-toolbar init --api-url https://feedback.bitvea.com
60
+ npx @bitvea/feedback-toolbar register --project-url https://myapp.com --api-key <key>
61
+
62
+ Flags
63
+
64
+ --api-url <url> BitVea Feedback backend. Falls back to
65
+ NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL.
66
+ --project-url <url> The deployment to register. Falls back to
67
+ VERCEL_PROJECT_PRODUCTION_URL, then VERCEL_URL.
68
+ --api-key <key> Deploy key. Falls back to FEEDBACK_TOOLBAR_API_KEY,
69
+ which is the better place for it: a key on a command
70
+ line ends up in shell history and CI logs. It is never
71
+ written to disk and never reaches a browser.
72
+ --root <path> The app to work on. Defaults to the current directory.
73
+ --environment <name> init, script-tag installs only: what the injected tag
74
+ declares. Defaults to "preview", which is what makes it
75
+ mount; pass "production" to leave the tag inert.
76
+ --toolbar-version <r> init only: the range to write into package.json for
77
+ @bitvea/feedback-toolbar. Defaults to the version this
78
+ command was launched through, then to the latest on the
79
+ registry. Nothing is guessed: if neither answers, the
80
+ install refuses rather than pin a number nobody chose.
81
+ --optional register only: report a failure and exit 0. This is
82
+ what the prebuild hook uses, so a registration problem
83
+ can never fail somebody's deploy.
84
+ --version Print versions. Two packages are in play since the
85
+ installer moved out of the toolbar, so this prints both
86
+ when it knows both.`;
87
+ function readFlag(argv, name) {
88
+ const withEquals = argv.find((a) => a.startsWith(`--${name}=`));
89
+ if (withEquals)
90
+ return withEquals.slice(name.length + 3);
91
+ const index = argv.indexOf(`--${name}`);
92
+ return index >= 0 ? argv[index + 1] : undefined;
93
+ }
94
+ /**
95
+ * The host app's package name, which the backend uses to name a project when
96
+ * there is no git metadata to name it from. Best effort by design: a missing
97
+ * or unreadable package.json is not a reason to refuse to register.
98
+ */
99
+ function readPackageName(root) {
100
+ const path = join(root, "package.json");
101
+ if (!existsSync(path))
102
+ return undefined;
103
+ try {
104
+ const pkg = JSON.parse(readFileSync(path, "utf8"));
105
+ return pkg.name;
106
+ }
107
+ catch {
108
+ return undefined;
109
+ }
110
+ }
111
+ /**
112
+ * This package's own version, read off its own manifest.
113
+ *
114
+ * `../package.json` from this module resolves to the package root from both
115
+ * `src/` and `dist/`, which is why nothing here has to be stamped at build
116
+ * time. Unknown rather than fatal: `--version` failing to read a manifest is
117
+ * not a reason to fail the process it was asked to describe.
118
+ */
119
+ function cliVersion() {
120
+ try {
121
+ const here = dirname(fileURLToPath(import.meta.url));
122
+ const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
123
+ return pkg.version ?? "unknown";
124
+ }
125
+ catch {
126
+ return "unknown";
127
+ }
128
+ }
129
+ async function runInit(argv, options) {
130
+ const apiUrl = readFlag(argv, "api-url") ??
131
+ process.env.NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL;
132
+ if (!apiUrl) {
133
+ console.error("missing --api-url. Pass the BitVea Feedback backend URL, e.g.\n" +
134
+ " npx @bitvea/feedback-toolbar init --api-url https://feedback.bitvea.com");
135
+ return 1;
136
+ }
137
+ // Resolved lazily, and reported once: only the npm route writes a
138
+ // dependency, and a script-tag install on a machine with no registry must
139
+ // not be refused for a number it will never use.
140
+ let resolved;
141
+ try {
142
+ const result = await init(realFs, {
143
+ root: readFlag(argv, "root") ?? process.cwd(),
144
+ apiUrl,
145
+ // Only needed to register the project from this machine, which is the
146
+ // exception rather than the rule: the prebuild step init writes is what
147
+ // normally registers, from a build environment that has the key.
148
+ apiKey: readFlag(argv, "api-key") ?? process.env.FEEDBACK_TOOLBAR_API_KEY,
149
+ projectUrl: readFlag(argv, "project-url"),
150
+ environment: readFlag(argv, "environment"),
151
+ resolveToolbarRange: async () => {
152
+ resolved = await resolveToolbarRange({
153
+ flag: readFlag(argv, "toolbar-version"),
154
+ launcherVersion: options.toolbarVersion,
155
+ env: process.env,
156
+ });
157
+ return resolved.range;
158
+ },
159
+ registerProject: postRegistration,
160
+ env: process.env,
161
+ });
162
+ if (result.alreadyInstalled) {
163
+ console.log("Already installed. Nothing to change.");
164
+ for (const note of result.notes)
165
+ console.log(` - ${note}`);
166
+ return 0;
167
+ }
168
+ console.log(`Installed via the ${result.strategy} strategy:`);
169
+ for (const change of result.changes)
170
+ console.log(` - ${change}`);
171
+ for (const note of result.notes)
172
+ console.log(` - ${note}`);
173
+ const provenance = resolved && describeRange(resolved);
174
+ if (provenance)
175
+ console.log(` - ${provenance}`);
176
+ // What is actually left to do, named. The previous sign-off ("redeploy to
177
+ // finish") was wrong in a way that cost a whole issue: the deploy key is
178
+ // a secret, it can only come from the build environment, and without it
179
+ // the prebuild step registers nothing and no project ever appears.
180
+ console.log(result.delivery === "script-tag"
181
+ ? "\nDeploy the page to finish. Nothing to install.\n" +
182
+ "Then register the project once, from a terminal or CI:\n" +
183
+ ` npx ${PACKAGE_NAME} register --api-url ${apiUrl} --project-url <url> --api-key <key>`
184
+ : "\nTwo things left:\n" +
185
+ " 1. install dependencies, commit, and deploy\n" +
186
+ ` 2. set ${API_KEY_ENV_VAR} in your hosting provider's environment variables\n` +
187
+ " (dashboard > Settings > Deploy keys)\n" +
188
+ "The build then registers this deployment itself, on every deploy. The backend\n" +
189
+ "URL needs no configuration: it is committed in package.json and in your layout.");
190
+ return 0;
191
+ }
192
+ catch (err) {
193
+ if (err instanceof InjectionError || err instanceof ToolbarVersionError) {
194
+ console.error(`Could not install: ${err.message}`);
195
+ return 1;
196
+ }
197
+ throw err;
198
+ }
199
+ }
200
+ /**
201
+ * Where that range came from, when the person running this did not choose it.
202
+ *
203
+ * Silent for `--toolbar-version` and `FEEDBACK_TOOLBAR_VERSION`, because
204
+ * telling somebody what they just typed is noise. The other two are worth a
205
+ * line: the number is about to be committed in their repository, and which of
206
+ * the two answered is the difference between "the toolbar you just downloaded"
207
+ * and "whatever npm currently calls latest".
208
+ */
209
+ function describeRange(resolved) {
210
+ switch (resolved.source) {
211
+ case "launcher":
212
+ return "that range is the toolbar this command was launched through";
213
+ case "registry":
214
+ return "that range is the latest published version";
215
+ default:
216
+ return undefined;
217
+ }
218
+ }
219
+ async function runRegister(argv) {
220
+ const root = readFlag(argv, "root") ?? process.cwd();
221
+ // See USAGE: the prebuild hook passes this so that a registration problem
222
+ // is reported and forgiven rather than failing the host app's deploy.
223
+ const optional = argv.includes("--optional");
224
+ try {
225
+ const outcome = await register({
226
+ apiUrl: readFlag(argv, "api-url"),
227
+ apiKey: readFlag(argv, "api-key"),
228
+ projectUrl: readFlag(argv, "project-url"),
229
+ packageName: readPackageName(root),
230
+ env: process.env,
231
+ registerProject: postRegistration,
232
+ });
233
+ // Two distinct successes, said differently on purpose: somebody running
234
+ // this by hand needs to know whether they just created a project, and
235
+ // somebody reading a build log needs to see that a repeat run is normal.
236
+ if (outcome.created) {
237
+ const named = outcome.projectName ? ` as "${outcome.projectName}"` : "";
238
+ console.log(`Registered ${outcome.projectUrl}${named}. It is in the dashboard now.`);
239
+ }
240
+ else {
241
+ console.log(`${outcome.projectUrl} is already registered. Nothing to do.`);
242
+ }
243
+ return 0;
244
+ }
245
+ catch (err) {
246
+ if (err instanceof RegistrationError) {
247
+ if (optional) {
248
+ console.warn(`feedback-toolbar register: skipped - ${err.message}`);
249
+ return 0;
250
+ }
251
+ console.error(`Could not register: ${err.message}`);
252
+ return 1;
253
+ }
254
+ throw err;
255
+ }
256
+ }
257
+ /**
258
+ * Both numbers, because after the split there are two.
259
+ *
260
+ * The installer and the component it installs now ship as separate packages on
261
+ * separate version lines, so "which halves are in play" stopped being
262
+ * answerable from the outside - and it is the first question of every support
263
+ * conversation about an install. No network: this reports what is on this
264
+ * machine, not what could be.
265
+ */
266
+ function runVersion(options) {
267
+ console.log(`@bitvea/feedback-cli ${cliVersion()}`);
268
+ if (options.toolbarVersion) {
269
+ console.log(`${PACKAGE_NAME} ${options.toolbarVersion}`);
270
+ }
271
+ return 0;
272
+ }
273
+ export async function run(argv, options = {}) {
274
+ const command = argv[0];
275
+ switch (command) {
276
+ case "init":
277
+ return runInit(argv, options);
278
+ case "register":
279
+ return runRegister(argv);
280
+ case "help":
281
+ case "--help":
282
+ case "-h":
283
+ console.log(USAGE);
284
+ return 0;
285
+ case "--version":
286
+ case "-v":
287
+ return runVersion(options);
288
+ default:
289
+ console.error(USAGE);
290
+ return 1;
291
+ }
292
+ }
293
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /** Where the answer came from, so `--version` and `init` can say. */
2
+ export type ToolbarRangeSource = "flag" | "env" | "launcher" | "registry";
3
+ export declare const TOOLBAR_VERSION_ENV_VAR = "FEEDBACK_TOOLBAR_VERSION";
4
+ export interface ToolbarRangeInput {
5
+ /** `--toolbar-version`. */
6
+ flag?: string | undefined;
7
+ /** What the launcher in `@bitvea/feedback-toolbar` read off its own disk. */
8
+ launcherVersion?: string | undefined;
9
+ env: Record<string, string | undefined>;
10
+ /** Injected so tests stay off the network. */
11
+ fetchLatestVersion?: () => Promise<string | undefined>;
12
+ }
13
+ export interface ResolvedToolbarRange {
14
+ /** The range as it will be written, e.g. `^1.1.2`. */
15
+ range: string;
16
+ source: ToolbarRangeSource;
17
+ }
18
+ /**
19
+ * A refusal the person running the command can act on, as opposed to a bug.
20
+ * Carries the remedy, because the remedy is a flag they can type immediately.
21
+ */
22
+ export declare class ToolbarVersionError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ export declare function resolveToolbarRange(input: ToolbarRangeInput): Promise<ResolvedToolbarRange>;
26
+ /**
27
+ * A bare `x.y.z` becomes `^x.y.z`; anything that already reads as a range is
28
+ * written through untouched.
29
+ *
30
+ * Untouched rather than normalised, because the shapes a person reaches for
31
+ * here - an exact pin, a `~`, a dist-tag like `next` - are all things they
32
+ * mean, and quietly turning a pin into a caret would be this command
33
+ * overruling the one decision it was explicitly told.
34
+ */
35
+ export declare function asRange(value: string): string;
36
+ //# sourceMappingURL=toolbarVersion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbarVersion.d.ts","sourceRoot":"","sources":["../src/toolbarVersion.ts"],"names":[],"mappings":"AA0CA,qEAAqE;AACrE,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,CAAC;AAE1E,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,oBAAoB,CAAC,CAoB/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG7C"}
@@ -0,0 +1,106 @@
1
+ // Which version of `@bitvea/feedback-toolbar` `init` writes into a host app.
2
+ //
3
+ // This used to be one literal in `init.ts`, rewritten by the toolbar's release
4
+ // script at publish time. That coupling could not survive the split - a
5
+ // release script editing another package's source is a boundary in name only,
6
+ // and a CLI published between two toolbar releases would carry a number
7
+ // nothing could tell it was stale. So the number is asked for, in this order,
8
+ // and the order is the whole design:
9
+ //
10
+ // 1. `--toolbar-version <range>`, for pinning deliberately, and for tests.
11
+ // 2. FEEDBACK_TOOLBAR_VERSION in the environment, for a CI that pins.
12
+ // 3. What the launcher passed, which it read out of the installed
13
+ // `@bitvea/feedback-toolbar/package.json` sitting next to it. This is the
14
+ // normal path - `npx @bitvea/feedback-toolbar init` - and it is correct
15
+ // by construction: whatever version npx just resolved is the version
16
+ // written into the host app, including `@1.1.2`, `@pr-42` and an old pin.
17
+ // The baked literal got exactly those cases wrong and could not express
18
+ // them at all.
19
+ // 4. The registry, once, with a short timeout. This is the
20
+ // `npx @bitvea/feedback-cli init` path, where there is no toolbar next to
21
+ // us to ask. `init` on that path is interactive and has network by
22
+ // definition, since npx just used it.
23
+ //
24
+ // And then it REFUSES. There is deliberately no fallback constant: a fallback
25
+ // is the stale literal wearing a different name, and it would be stale exactly
26
+ // on the path that has no launcher to correct it. `init` already refuses
27
+ // before touching the tree for everything else that can fail, and a range is
28
+ // the most consequential thing it writes into a stranger's committed
29
+ // package.json - so a refusal that names `--toolbar-version` beats a wrong
30
+ // number committed under their name.
31
+ /** The package whose version is being resolved. Never imported, only named. */
32
+ const TOOLBAR_PACKAGE = "@bitvea/feedback-toolbar";
33
+ const REGISTRY_URL = `https://registry.npmjs.org/${TOOLBAR_PACKAGE}/latest`;
34
+ /**
35
+ * Long enough for a warm registry, short enough that a machine with no route
36
+ * to npm reaches the refusal while somebody is still watching the terminal.
37
+ */
38
+ const REGISTRY_TIMEOUT_MS = 3_000;
39
+ export const TOOLBAR_VERSION_ENV_VAR = "FEEDBACK_TOOLBAR_VERSION";
40
+ /**
41
+ * A refusal the person running the command can act on, as opposed to a bug.
42
+ * Carries the remedy, because the remedy is a flag they can type immediately.
43
+ */
44
+ export class ToolbarVersionError extends Error {
45
+ constructor(message) {
46
+ super(message);
47
+ this.name = "ToolbarVersionError";
48
+ }
49
+ }
50
+ export async function resolveToolbarRange(input) {
51
+ if (input.flag)
52
+ return { range: asRange(input.flag), source: "flag" };
53
+ const fromEnv = input.env[TOOLBAR_VERSION_ENV_VAR];
54
+ if (fromEnv)
55
+ return { range: asRange(fromEnv), source: "env" };
56
+ if (input.launcherVersion) {
57
+ return { range: asRange(input.launcherVersion), source: "launcher" };
58
+ }
59
+ const latest = await (input.fetchLatestVersion ?? fetchLatestVersion)();
60
+ if (latest)
61
+ return { range: asRange(latest), source: "registry" };
62
+ throw new ToolbarVersionError(`could not tell which version of ${TOOLBAR_PACKAGE} to install, and this ` +
63
+ "command will not guess one: the range goes into your committed " +
64
+ "package.json.\n" +
65
+ "Pass it: --toolbar-version ^1.2.0 (or set " +
66
+ `${TOOLBAR_VERSION_ENV_VAR}).`);
67
+ }
68
+ /**
69
+ * A bare `x.y.z` becomes `^x.y.z`; anything that already reads as a range is
70
+ * written through untouched.
71
+ *
72
+ * Untouched rather than normalised, because the shapes a person reaches for
73
+ * here - an exact pin, a `~`, a dist-tag like `next` - are all things they
74
+ * mean, and quietly turning a pin into a caret would be this command
75
+ * overruling the one decision it was explicitly told.
76
+ */
77
+ export function asRange(value) {
78
+ const trimmed = value.trim();
79
+ return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(trimmed) ? `^${trimmed}` : trimmed;
80
+ }
81
+ /**
82
+ * One GET of the registry's `latest` document. Every failure - no network, a
83
+ * proxy, a 404, a body that is not what we expect - is the same answer here:
84
+ * nothing, so the caller refuses. Nothing is inferred from a failed lookup.
85
+ */
86
+ async function fetchLatestVersion() {
87
+ try {
88
+ const res = await fetch(REGISTRY_URL, {
89
+ headers: { accept: "application/json" },
90
+ signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
91
+ });
92
+ if (!res.ok)
93
+ return undefined;
94
+ const body = await res.json();
95
+ if (body !== null && typeof body === "object" && "version" in body) {
96
+ const version = body.version;
97
+ if (typeof version === "string" && version.length > 0)
98
+ return version;
99
+ }
100
+ return undefined;
101
+ }
102
+ catch {
103
+ return undefined;
104
+ }
105
+ }
106
+ //# sourceMappingURL=toolbarVersion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbarVersion.js","sourceRoot":"","sources":["../src/toolbarVersion.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@bitvea/feedback-cli",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "BitVea Feedback installer: install the toolbar into an app, and register a deployment as a project",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "bin": {
16
+ "feedback-cli": "./dist/bin.js"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "dependencies": {},
22
+ "devDependencies": {
23
+ "@types/node": "^24.0.0",
24
+ "eslint": "^10.9.1",
25
+ "typescript": "^6.0.0",
26
+ "vitest": "^2.1.9",
27
+ "@bitvea/release-tools": "0.0.0",
28
+ "@bitvea/config": "0.0.0"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.build.json && node scripts/add-emitted-import-extensions.mjs",
39
+ "check-publishable": "node scripts/check-publishable.mjs",
40
+ "release": "node scripts/release.mjs",
41
+ "type-check": "tsc -p tsconfig.json --noEmit",
42
+ "lint": "eslint .",
43
+ "test": "vitest run --passWithNoTests",
44
+ "clean": "rm -rf dist .turbo *.tsbuildinfo"
45
+ }
46
+ }