@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
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @bitvea/feedback-cli
2
+
3
+ The installer for [BitVea Feedback](https://github.com/bitvea/feedback-toolbar): it installs the toolbar into an app, and it registers a deployment as a project.
4
+
5
+ You are not expected to type this package's name.
6
+ The command everybody uses is the toolbar's:
7
+
8
+ ```bash
9
+ npx @bitvea/feedback-toolbar init --api-url https://feedback.bitvea.com
10
+ ```
11
+
12
+ That package depends on this one and hands it the argv, in the same process, so the command behaves exactly as it did when the installer lived inside it - and so the `prebuild` line it writes keeps working in repositories nobody here can edit.
13
+
14
+ ## Commands
15
+
16
+ `init` installs the toolbar into the app in the current directory: the dependency, the backend URL, `<FeedbackToolbar />` in the root layout, and a `prebuild` script that registers the deployment on every build.
17
+ Re-running it changes nothing, and a run that cannot find a root layout changes nothing either.
18
+
19
+ `register` makes sure a deployment exists as a project in the dashboard.
20
+ It is what the `prebuild` line runs, and it is a command of its own because a script-tag install has no build to hook.
21
+ `--optional` reports a failure and exits 0, so a registration problem can never fail somebody's deploy.
22
+
23
+ `help` and `--version` print usage and the versions in play.
24
+
25
+ ## Which toolbar version does `init` pin?
26
+
27
+ Whichever one it was launched through.
28
+ `npx @bitvea/feedback-toolbar init` writes a caret on exactly the toolbar npx just downloaded.
29
+ `--toolbar-version <range>` overrides it, `FEEDBACK_TOOLBAR_VERSION` does the same from the environment, and running this package directly falls back to the latest published version.
30
+
31
+ If none of those answers, `init` refuses and says so before touching your repository.
32
+ It will not guess a range: the one it writes ends up committed in your `package.json`.
33
+
34
+ ## Dependencies
35
+
36
+ None, permanently.
37
+ This package is installed alongside the toolbar into every app that installs the toolbar, so its dependency tree is somebody else's dependency tree.
38
+ Its publishable check fails if `dependencies` is ever non-empty.
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ // `npx @bitvea/feedback-cli` - three lines, on purpose.
3
+ //
4
+ // Everything is in ./run.ts so that the toolbar's own bin can call the same
5
+ // function in the same process rather than spawning this file. Two entry
6
+ // points into one `run` is what makes "same argv, same stdout, same exit
7
+ // codes" true by construction instead of by care.
8
+ //
9
+ // The bin is named `feedback-cli` and never `feedback-toolbar`: both packages
10
+ // can end up in one `node_modules/.bin`, and two packages declaring one bin
11
+ // name is a last-writer-wins symlink that npm resolves silently. The loser
12
+ // would be the name every committed `prebuild` line invokes.
13
+ //
14
+ // The rejection handler is the one from the file this replaced, kept rather
15
+ // than swapped for a top-level `await`: an unexpected throw prints the error
16
+ // and exits 1, instead of Node's unhandled-rejection crash.
17
+ import { run } from "./run.js";
18
+ run(process.argv.slice(2)).then((code) => {
19
+ process.exitCode = code;
20
+ }, (err) => {
21
+ console.error(err);
22
+ process.exitCode = 1;
23
+ });
24
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,wDAAwD;AACxD,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,yEAAyE;AACzE,kDAAkD;AAClD,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,6DAA6D;AAC7D,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,4DAA4D;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAE5B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7B,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,EACD,CAAC,GAAY,EAAE,EAAE;IACf,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CACF,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { API_URL_ENV_VAR } from "../install/env.js";
2
+ import { type InstallerFs } from "../install/fs.js";
3
+ export { API_URL_ENV_VAR };
4
+ import { type Delivery, type InjectionStrategy } from "../install/strategies.js";
5
+ import type { RegisterProjectTransport } from "../registration.js";
6
+ /**
7
+ * The command wired into the host app's build, and the marker that says it is
8
+ * already wired. `--optional` is load-bearing: see the comment on
9
+ * `wirePrebuild` for why a registration failure must not fail a deploy.
10
+ */
11
+ export declare const REGISTER_COMMAND = "feedback-toolbar register";
12
+ /**
13
+ * The prebuild line, with the backend URL BAKED IN.
14
+ *
15
+ * This is the second half of #11's reopened acceptance criterion, and the
16
+ * reason it reopened twice. `register` resolves its backend URL from a flag or
17
+ * from the build environment - and the build environment does not have it:
18
+ * `init` writes `NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL` into `.env.local`,
19
+ * which create-next-app gitignores, and a plain node process does not load a
20
+ * dotenv file anyway. So on a real Vercel build the prebuild step threw "no
21
+ * backend URL", `--optional` turned that into one warning line, and no project
22
+ * ever appeared.
23
+ *
24
+ * package.json IS committed, so putting the URL here is what carries it into
25
+ * the build. It is a public URL, not a credential; the key still comes from
26
+ * `FEEDBACK_TOOLBAR_API_KEY` in the build environment and from nowhere else.
27
+ */
28
+ export declare function prebuildScript(apiUrl: string): string;
29
+ export interface InitOptions {
30
+ /** Repository root to install into. */
31
+ root: string;
32
+ /** Base URL of the BitVea Feedback backend. */
33
+ apiUrl: string;
34
+ /**
35
+ * Deploy key authorising registration. Optional: without it the install
36
+ * still happens, and only the registration step is skipped - the prebuild
37
+ * step this writes registers on the next build instead.
38
+ */
39
+ apiKey?: string;
40
+ /** Deployment URL to register the project under, when it is known. */
41
+ projectUrl?: string;
42
+ /**
43
+ * How to find out which range to write into the host app's `dependencies`
44
+ * for `@bitvea/feedback-toolbar`.
45
+ *
46
+ * It used to be a literal in this file, rewritten inside the toolbar's own
47
+ * `scripts/release.mjs` at publish time. After the split that rewrite would
48
+ * have had to reach across a package boundary, and any CLI published
49
+ * between two toolbar releases would have carried a number it had no way to
50
+ * know was stale. So the range is asked for, at the moment it is needed,
51
+ * and there is deliberately no fallback constant: a wrong range silently
52
+ * committed into somebody else's repository under their name is worse than
53
+ * a refusal naming a flag. See `resolveToolbarRange`.
54
+ *
55
+ * A function rather than a value because only the npm route writes a
56
+ * dependency at all. A script-tag install has no `package.json` entry to
57
+ * make, and refusing one for want of a number it will never use - on a
58
+ * machine that may have no registry to ask - would be a refusal about
59
+ * nothing.
60
+ */
61
+ resolveToolbarRange?: () => string | Promise<string>;
62
+ /**
63
+ * What a script-tag install declares as its environment. Ignored by the npm
64
+ * route, which resolves it from the host build's own provider variables -
65
+ * see buildEnv.ts, and the neutral `NEXT_PUBLIC_FEEDBACK_TOOLBAR_ENV` for a
66
+ * host that has no entry there.
67
+ */
68
+ environment?: string;
69
+ /** Injected so tests do not have to reach the network. */
70
+ registerProject?: RegisterProjectTransport;
71
+ /** Env bag, for the Vercel git metadata. Defaults to `process.env`. */
72
+ env?: Record<string, string | undefined>;
73
+ strategies?: readonly InjectionStrategy[];
74
+ }
75
+ export interface InitResult {
76
+ /** What actually changed, one line each, for the CLI to print. */
77
+ changes: string[];
78
+ /**
79
+ * Things worth saying that are not changes: a project that was already
80
+ * registered, or a registration that did not go through. These are kept
81
+ * apart from `changes` because `alreadyInstalled` is derived from that
82
+ * list, and a re-run must still report itself as a no-op even though it
83
+ * talks to the backend every time.
84
+ */
85
+ notes: string[];
86
+ /** True when nothing needed doing, which is what a re-run should report. */
87
+ alreadyInstalled: boolean;
88
+ strategy: string;
89
+ /**
90
+ * How the host app gets the code. Reported because it decides what the
91
+ * developer has to do next: an npm install needs a dependency install and a
92
+ * redeploy, a script tag needs neither.
93
+ */
94
+ delivery: Delivery;
95
+ }
96
+ export declare function init(fs: InstallerFs, options: InitOptions): Promise<InitResult>;
97
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAIhE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAE5D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,UAAU;IACzB,kEAAkE;IAClE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,wBAAsB,IAAI,CACxB,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAsLrB"}
@@ -0,0 +1,273 @@
1
+ // `npx @bitvea/feedback-toolbar init` - the whole codemod, as one pure
2
+ // function over an InstallerFs so it can be driven by tests against a tree
3
+ // they control.
4
+ //
5
+ // Two properties matter more than anything else here, because this edits
6
+ // somebody else's repository:
7
+ //
8
+ // 1. Re-running changes nothing. Every step detects its own prior work
9
+ // rather than blindly appending, so the second run reports "already
10
+ // installed" and writes no file.
11
+ // 2. It never leaves a half-install. Everything that can fail is computed
12
+ // before anything is written, so a missing root layout ends the run with
13
+ // an untouched repository and a message saying what to do by hand.
14
+ //
15
+ // What changed after #11 was reopened: this command no longer pretends to be
16
+ // where registration happens. `init` runs on a laptop, where VERCEL_URL does
17
+ // not exist, so it had nothing to register and said nothing about it - a real
18
+ // install registered silently nothing. It now writes a `prebuild` script that
19
+ // runs `feedback-toolbar register`, so registration happens in the build,
20
+ // where those variables do exist. Registering here too is a convenience for
21
+ // the developer who passed both flags, not the mechanism.
22
+ //
23
+ // And what changed after it reopened a second time: NOTHING THIS COMMAND
24
+ // WRITES MAY DEPEND ON A GITIGNORED FILE. The install used to put the backend
25
+ // URL in `.env.local` alone, which create-next-app gitignores - so the
26
+ // prebuild step reached the build with no URL and skipped itself (one warning
27
+ // line, exit 0, because `--optional` must never fail a deploy), and the
28
+ // deployed toolbar had no URL either and rendered nothing. Two silent
29
+ // failures from one gitignored file. The URL is a public value, so it now
30
+ // goes where it survives a commit: into the injected component, and into the
31
+ // prebuild command in package.json. The only thing left for a developer to
32
+ // set by hand is the deploy KEY, which is a secret and belongs in the build
33
+ // environment - and the notes below say so explicitly.
34
+ import { API_URL_ENV_VAR } from "../install/env.js";
35
+ import { joinPath } from "../install/fs.js";
36
+ export { API_URL_ENV_VAR };
37
+ import { DEFAULT_SCRIPT_ENVIRONMENT, InjectionError, PACKAGE_NAME, SCRIPT_BUNDLE_PATH, STRATEGIES, } from "../install/strategies.js";
38
+ import { API_KEY_ENV_VAR, inferProjectUrl, register } from "./register.js";
39
+ const ENV_FILES = [".env.local", ".env"];
40
+ /**
41
+ * The command wired into the host app's build, and the marker that says it is
42
+ * already wired. `--optional` is load-bearing: see the comment on
43
+ * `wirePrebuild` for why a registration failure must not fail a deploy.
44
+ */
45
+ export const REGISTER_COMMAND = "feedback-toolbar register";
46
+ /**
47
+ * The prebuild line, with the backend URL BAKED IN.
48
+ *
49
+ * This is the second half of #11's reopened acceptance criterion, and the
50
+ * reason it reopened twice. `register` resolves its backend URL from a flag or
51
+ * from the build environment - and the build environment does not have it:
52
+ * `init` writes `NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL` into `.env.local`,
53
+ * which create-next-app gitignores, and a plain node process does not load a
54
+ * dotenv file anyway. So on a real Vercel build the prebuild step threw "no
55
+ * backend URL", `--optional` turned that into one warning line, and no project
56
+ * ever appeared.
57
+ *
58
+ * package.json IS committed, so putting the URL here is what carries it into
59
+ * the build. It is a public URL, not a credential; the key still comes from
60
+ * `FEEDBACK_TOOLBAR_API_KEY` in the build environment and from nowhere else.
61
+ */
62
+ export function prebuildScript(apiUrl) {
63
+ return `${REGISTER_COMMAND} --optional --api-url ${apiUrl}`;
64
+ }
65
+ export async function init(fs, options) {
66
+ const { root, apiUrl } = options;
67
+ const env = options.env ?? {};
68
+ const strategies = options.strategies ?? STRATEGIES;
69
+ const packageJsonPath = joinPath(root, "package.json");
70
+ if (!fs.exists(packageJsonPath)) {
71
+ throw new InjectionError(`no package.json at ${root}. Run this from the root of the app you want to install into.`);
72
+ }
73
+ const pkg = JSON.parse(fs.readFile(packageJsonPath));
74
+ // Resolved before the injection, because the script-tag strategy writes it
75
+ // into the markup and refuses to install without it.
76
+ const projectUrl = options.projectUrl ?? inferProjectUrl(env);
77
+ // Find the injection site FIRST. It is the only step that can fail for a
78
+ // reason the developer has to fix, and finding out after writing package.json
79
+ // and .env.local is exactly the half-install this must not produce.
80
+ const strategy = strategies.find((s) => s.detect(fs, root) !== null);
81
+ if (!strategy) {
82
+ throw new InjectionError([
83
+ "could not find a root layout to inject the toolbar into.",
84
+ `Tried: ${strategies.map((s) => s.label).join(", ")}.`,
85
+ "Nothing was changed. Add the provider by hand instead:",
86
+ "",
87
+ ` import { FeedbackToolbar } from "${PACKAGE_NAME}";`,
88
+ " // ...then render <FeedbackToolbar /> inside <body> in your root layout.",
89
+ ].join("\n"));
90
+ }
91
+ const site = strategy.detect(fs, root);
92
+ const layoutSource = fs.readFile(site.path);
93
+ const alreadyInjected = strategy.isInstalled(layoutSource);
94
+ // Computed before any write: `inject` throws rather than returning a
95
+ // half-edited file, and this is where that throw has to happen.
96
+ const injected = alreadyInjected
97
+ ? layoutSource
98
+ : strategy.inject(layoutSource, {
99
+ apiUrl,
100
+ projectUrl,
101
+ environment: options.environment,
102
+ });
103
+ // A script-tag install has no dependency to add, no env file to read at
104
+ // runtime, and no build to hook - the toolbar is a file served from the
105
+ // backend and configured from the tag's own attributes. Skipping those
106
+ // steps is the whole difference between the two delivery routes.
107
+ const scriptTag = strategy.delivery === "script-tag";
108
+ const changes = [];
109
+ const notes = [];
110
+ let packageJsonChanged = false;
111
+ // 1. Dependency. Resolved here rather than by the caller because this is
112
+ // the only step that needs it, and resolved BEFORE the first write like
113
+ // everything else that can fail: a refusal has to leave the tree
114
+ // untouched.
115
+ if (!scriptTag) {
116
+ const deps = pkg.dependencies ?? {};
117
+ if (!deps[PACKAGE_NAME]) {
118
+ if (!options.resolveToolbarRange) {
119
+ throw new InjectionError(`could not tell which version of ${PACKAGE_NAME} to install. ` +
120
+ "Re-run with --toolbar-version <range>.");
121
+ }
122
+ const range = await options.resolveToolbarRange();
123
+ pkg.dependencies = { ...deps, [PACKAGE_NAME]: range };
124
+ packageJsonChanged = true;
125
+ changes.push(`added ${PACKAGE_NAME}@${range} to dependencies`);
126
+ }
127
+ }
128
+ // 2. Env var, in whichever env file already exists, else .env.local.
129
+ //
130
+ // A local-development convenience, and only that. It is deliberately NOT
131
+ // how the deployed toolbar finds the backend: `.env.local` is gitignored
132
+ // by create-next-app, so it never reaches a build, which is why the URL
133
+ // is written into the injected component and into the prebuild command
134
+ // as well. Kept because a developer running `next dev` before their
135
+ // first deploy expects the variable to be there.
136
+ if (!scriptTag) {
137
+ const envPath = ENV_FILES.map((f) => joinPath(root, f)).find((p) => fs.exists(p));
138
+ const targetEnvPath = envPath ?? joinPath(root, ENV_FILES[0]);
139
+ const existingEnv = envPath ? fs.readFile(envPath) : "";
140
+ if (!existingEnv.includes(`${API_URL_ENV_VAR}=`)) {
141
+ const separator = existingEnv.length === 0 || existingEnv.endsWith("\n") ? "" : "\n";
142
+ fs.writeFile(targetEnvPath, `${existingEnv}${separator}${API_URL_ENV_VAR}=${apiUrl}\n`);
143
+ changes.push(`wrote ${API_URL_ENV_VAR} to ${targetEnvPath} (local development; the ` +
144
+ "deployed toolbar reads the URL from the component it injected)");
145
+ }
146
+ }
147
+ // 3. The provider.
148
+ if (!alreadyInjected) {
149
+ fs.writeFile(site.path, injected);
150
+ const what = scriptTag
151
+ ? `injected the ${SCRIPT_BUNDLE_PATH} script tag into the ${site.description}`
152
+ : `injected <FeedbackToolbar /> into the ${site.description}`;
153
+ changes.push(what);
154
+ if (scriptTag) {
155
+ // The gate cannot be resolved from a static file - absent means off - so
156
+ // the tag has to declare one or it mounts nothing. Written rather than
157
+ // left to the developer, and said out loud here because it is the one
158
+ // value in the install that decides whether their own customers see a
159
+ // feedback widget.
160
+ const environment = options.environment ?? DEFAULT_SCRIPT_ENVIRONMENT;
161
+ notes.push(`the tag declares data-environment="${environment}", which is what makes it mount. ` +
162
+ "Change it to production on any page real customers reach, or re-run with " +
163
+ "--environment production.");
164
+ }
165
+ }
166
+ // 4. The build hook. This is the step #11 was reopened for: without it,
167
+ // nothing ever registers the project except a developer who happened to
168
+ // pass two flags by hand.
169
+ if (!scriptTag) {
170
+ const wired = wirePrebuild(pkg, apiUrl);
171
+ if (wired) {
172
+ packageJsonChanged = true;
173
+ changes.push(wired);
174
+ }
175
+ }
176
+ if (packageJsonChanged) {
177
+ fs.writeFile(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
178
+ }
179
+ // 5. Register the project, if this machine happens to know enough to. On a
180
+ // developer's laptop it usually does not, and that is fine now: step 4
181
+ // put the command in the build, where the URL and the key live.
182
+ const apiKey = options.apiKey ?? env[API_KEY_ENV_VAR];
183
+ if (!projectUrl || !apiKey) {
184
+ notes.push(registrationDeferredNote({ projectUrl, apiKey, scriptTag }));
185
+ }
186
+ else {
187
+ try {
188
+ const outcome = await register({
189
+ apiUrl,
190
+ apiKey,
191
+ projectUrl,
192
+ packageName: pkg.name,
193
+ env,
194
+ registerProject: options.registerProject,
195
+ });
196
+ if (outcome.created) {
197
+ changes.push(`registered ${projectUrl} as a project`);
198
+ }
199
+ else {
200
+ notes.push(`${projectUrl} was already registered`);
201
+ }
202
+ }
203
+ catch (err) {
204
+ // A registration that did not go through is not a failed install: the
205
+ // code is in place and the next build registers. Say so and carry on.
206
+ notes.push(`could not register ${projectUrl} (${String(err)}); it will register on the next build`);
207
+ }
208
+ }
209
+ return {
210
+ changes,
211
+ notes,
212
+ alreadyInstalled: changes.length === 0,
213
+ strategy: strategy.id,
214
+ delivery: scriptTag ? "script-tag" : "npm-package",
215
+ };
216
+ }
217
+ /**
218
+ * Add `feedback-toolbar register` to the host app's `prebuild`, once.
219
+ *
220
+ * npm, pnpm and yarn all run `prebuild` before `build`, which is why the hook
221
+ * goes there rather than into `build` itself: appending to somebody's build
222
+ * command changes the command they debug, and prepending to it changes what
223
+ * their CI logs look like at the top. `prebuild` is the slot the package
224
+ * managers reserve for exactly this.
225
+ *
226
+ * `--optional` is not decoration. This runs on every deploy of somebody
227
+ * else's product forever, and a feedback tool that fails a deploy because our
228
+ * backend was slow, or because a key was rotated, has done far more damage
229
+ * than the missing project row it was trying to create.
230
+ *
231
+ * Refusing to add it twice is the same idempotency rule as everything else
232
+ * here, and it has to survive the developer having edited the line: the check
233
+ * is for the command, not for the exact string this wrote. Like every other
234
+ * step, a second run says nothing rather than reporting a non-change.
235
+ *
236
+ * Returns the line to report, or undefined when there was nothing to do.
237
+ */
238
+ function wirePrebuild(pkg, apiUrl) {
239
+ const scripts = pkg.scripts ?? {};
240
+ const existing = scripts.prebuild;
241
+ const line = prebuildScript(apiUrl);
242
+ if (existing === undefined) {
243
+ pkg.scripts = { ...scripts, prebuild: line };
244
+ return `added a "prebuild" script that registers this deployment on every build: ${line}`;
245
+ }
246
+ if (existing.includes(REGISTER_COMMAND))
247
+ return undefined;
248
+ // Their command first, ours after it, joined rather than replaced: the
249
+ // existing prebuild is somebody's build prerequisite and must still run,
250
+ // and must still be the thing that fails the build if it fails.
251
+ pkg.scripts = { ...scripts, prebuild: `${existing} && ${line}` };
252
+ return (`edited the existing "prebuild" script to also register this deployment: ` +
253
+ `${existing} && ${line}`);
254
+ }
255
+ /** Why registration did not happen here, and what will do it instead. */
256
+ function registrationDeferredNote(input) {
257
+ if (input.scriptTag) {
258
+ // No build to hook, so nothing will do this on its own. #17's answer: run
259
+ // the command once, from a terminal or CI, where a key belongs.
260
+ return ("a script-tag install has no build step, so nothing registers the project for you. " +
261
+ `Run it once: npx ${PACKAGE_NAME} register --project-url <url> --api-key <key>`);
262
+ }
263
+ if (!input.apiKey) {
264
+ return ("no deploy key here, so nothing was registered yet. The prebuild step will do it " +
265
+ `on the next build, and it needs one thing from you: set ${API_KEY_ENV_VAR} in your ` +
266
+ "hosting provider's environment variables (dashboard > Settings > Deploy keys). " +
267
+ "The backend URL is already baked into the prebuild command and into the injected " +
268
+ "component, so there is nothing else to configure.");
269
+ }
270
+ return ("this machine does not report a deployment URL, so nothing was registered yet - " +
271
+ "the prebuild step will do it on the next build, where VERCEL_URL is set");
272
+ }
273
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import { type RegisterProjectTransport } from "../registration.js";
2
+ /** Where `--api-url` falls back to. The public name is what a build already has. */
3
+ export declare const API_URL_ENV_VARS: readonly ["NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL", "FEEDBACK_TOOLBAR_API_URL"];
4
+ /**
5
+ * Where `--api-key` falls back to, and the only place a key is ever read from.
6
+ * Never a file, never a `data-` attribute, never an argument this CLI writes
7
+ * down: a deploy key's whole power is creating projects, so it lives in the
8
+ * build environment and nowhere else.
9
+ */
10
+ export declare const API_KEY_ENV_VAR = "FEEDBACK_TOOLBAR_API_KEY";
11
+ export interface RegisterOptions {
12
+ /** `--api-url`, else one of API_URL_ENV_VARS. */
13
+ apiUrl?: string | undefined;
14
+ /** `--api-key`, else API_KEY_ENV_VAR. */
15
+ apiKey?: string | undefined;
16
+ /** `--project-url`, else whatever the build environment reports. */
17
+ projectUrl?: string | undefined;
18
+ /** The host app's package name, as a fallback for naming the project. */
19
+ packageName?: string | undefined;
20
+ /** The build environment. Explicit so this stays a pure function. */
21
+ env: Record<string, string | undefined>;
22
+ /** Injected so tests do not reach the network. */
23
+ registerProject?: RegisterProjectTransport;
24
+ }
25
+ export interface RegisterOutcome {
26
+ projectUrl: string;
27
+ /** False when the URL was already registered, which is a success. */
28
+ created: boolean;
29
+ /** What the backend called it, when it said. */
30
+ projectName?: string | undefined;
31
+ }
32
+ /**
33
+ * Register the deployment, or confirm it is already registered.
34
+ *
35
+ * Idempotent because the backend is: the second call with the same normalised
36
+ * URL is a no-op that answers `created: false`. That is what makes this safe
37
+ * as a prebuild step, which runs on every deploy forever.
38
+ *
39
+ * Throws `RegistrationError` with a message naming the missing piece when it
40
+ * cannot proceed. It never guesses: a registration under a URL nobody meant
41
+ * creates a project that collects feedback from a page that does not exist.
42
+ */
43
+ export declare function register(options: RegisterOptions): Promise<RegisterOutcome>;
44
+ /**
45
+ * The URL to register the project under, from the build environment.
46
+ *
47
+ * Same precedence as the toolbar's own `resolveConfig`, and that agreement is
48
+ * the point: the toolbar reports this value back at runtime, so if the two
49
+ * picked differently the lookup would miss on every preview deployment. The
50
+ * production hostname wins because a preview URL changes on every commit, and
51
+ * keying on it would create a project per deploy instead of collecting a
52
+ * project's feedback in one place.
53
+ */
54
+ export declare function inferProjectUrl(env: Record<string, string | undefined>): string | undefined;
55
+ /**
56
+ * The browser origins this deployment serves the toolbar from.
57
+ *
58
+ * A DIFFERENT question from `inferProjectUrl`, and conflating them is what
59
+ * made the toolbar unusable everywhere it was installed. That function answers
60
+ * "which project is this", and answers it with the production URL because a
61
+ * project's feedback has to collect in one place across every deploy. This one
62
+ * answers "where will a browser be calling us from", and on a Vercel install
63
+ * the answer is never the production URL: the toolbar is off in production by
64
+ * design, so it only ever runs on a preview, whose origin is per-branch or
65
+ * per-commit.
66
+ *
67
+ * Both are reported, in this order:
68
+ *
69
+ * - `VERCEL_BRANCH_URL` - `<project>-git-<branch>-<team>.vercel.app`. Stable
70
+ * for the life of the branch, and the URL a reviewer is actually sent, so
71
+ * it is the one that matters. It is also bounded by branch count rather
72
+ * than by deploy count, which is what keeps the allow-list from growing
73
+ * without limit.
74
+ * - `VERCEL_URL` - this deployment alone. Included because a reviewer handed
75
+ * a specific deployment's URL is a real case, and because a build with no
76
+ * branch alias (a `vercel deploy` from a terminal) has nothing else.
77
+ *
78
+ * Empty off Vercel, where neither exists and there is no preview to allow.
79
+ * The backend normalises and de-duplicates, and drops the project's own URL,
80
+ * so this does not have to be careful about overlap - only about never
81
+ * inventing a host it was not told.
82
+ */
83
+ export declare function inferProjectOrigins(env: Record<string, string | undefined>): string[];
84
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,iBAAiB,CAAC;AAEzB,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,+EAGnB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,eAAe,6BAA6B,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,kDAAkD;IAClD,eAAe,CAAC,EAAE,wBAAwB,CAAC;CAC5C;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,eAAe,CAAC,CA6C1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,MAAM,EAAE,CAKV"}