@bitvea/feedback-toolbar 0.0.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/README.md +262 -0
- package/dist/FeedbackPanel.d.ts +117 -0
- package/dist/FeedbackPanel.d.ts.map +1 -0
- package/dist/FeedbackPanel.js +622 -0
- package/dist/FeedbackPanel.js.map +1 -0
- package/dist/FeedbackToolbar.d.ts +54 -0
- package/dist/FeedbackToolbar.d.ts.map +1 -0
- package/dist/FeedbackToolbar.js +1149 -0
- package/dist/FeedbackToolbar.js.map +1 -0
- package/dist/InboxSheet.d.ts +80 -0
- package/dist/InboxSheet.d.ts.map +1 -0
- package/dist/InboxSheet.js +580 -0
- package/dist/InboxSheet.js.map +1 -0
- package/dist/PinLayer.d.ts +59 -0
- package/dist/PinLayer.d.ts.map +1 -0
- package/dist/PinLayer.js +1702 -0
- package/dist/PinLayer.js.map +1 -0
- package/dist/RichText.d.ts +6 -0
- package/dist/RichText.d.ts.map +1 -0
- package/dist/RichText.js +135 -0
- package/dist/RichText.js.map +1 -0
- package/dist/browser/entry.d.ts +3 -0
- package/dist/browser/entry.d.ts.map +1 -0
- package/dist/browser/entry.js +13 -0
- package/dist/browser/entry.js.map +1 -0
- package/dist/browser/mount.d.ts +37 -0
- package/dist/browser/mount.d.ts.map +1 -0
- package/dist/browser/mount.js +150 -0
- package/dist/browser/mount.js.map +1 -0
- package/dist/browser/toolbar.js +38 -0
- package/dist/browser/toolbar.js.map +7 -0
- package/dist/capture.d.ts +58 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +98 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +196 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/fs.d.ts +16 -0
- package/dist/cli/fs.d.ts.map +1 -0
- package/dist/cli/fs.js +33 -0
- package/dist/cli/fs.js.map +1 -0
- package/dist/cli/init.d.ts +75 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +266 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/register.d.ts +55 -0
- package/dist/cli/register.d.ts.map +1 -0
- package/dist/cli/register.js +84 -0
- package/dist/cli/register.js.map +1 -0
- package/dist/cli/registration.d.ts +37 -0
- package/dist/cli/registration.d.ts.map +1 -0
- package/dist/cli/registration.js +69 -0
- package/dist/cli/registration.js.map +1 -0
- package/dist/cli/strategies.d.ts +98 -0
- package/dist/cli/strategies.d.ts.map +1 -0
- package/dist/cli/strategies.js +198 -0
- package/dist/cli/strategies.js.map +1 -0
- package/dist/client.d.ts +59 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +113 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +92 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -0
- package/dist/deepLink.d.ts +86 -0
- package/dist/deepLink.d.ts.map +1 -0
- package/dist/deepLink.js +185 -0
- package/dist/deepLink.js.map +1 -0
- package/dist/fontFace.d.ts +70 -0
- package/dist/fontFace.d.ts.map +1 -0
- package/dist/fontFace.js +88 -0
- package/dist/fontFace.js.map +1 -0
- package/dist/gating.d.ts +32 -0
- package/dist/gating.d.ts.map +1 -0
- package/dist/gating.js +49 -0
- package/dist/gating.js.map +1 -0
- package/dist/icons.d.ts +68 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +97 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown.d.ts +59 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +130 -0
- package/dist/markdown.js.map +1 -0
- package/dist/motion.d.ts +178 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +302 -0
- package/dist/motion.js.map +1 -0
- package/dist/preferences.d.ts +71 -0
- package/dist/preferences.d.ts.map +1 -0
- package/dist/preferences.js +195 -0
- package/dist/preferences.js.map +1 -0
- package/dist/rasterise.d.ts +45 -0
- package/dist/rasterise.d.ts.map +1 -0
- package/dist/rasterise.js +490 -0
- package/dist/rasterise.js.map +1 -0
- package/dist/selector.d.ts +19 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/selector.js +142 -0
- package/dist/selector.js.map +1 -0
- package/dist/session.d.ts +19 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +36 -0
- package/dist/session.js.map +1 -0
- package/dist/shortcut.d.ts +88 -0
- package/dist/shortcut.d.ts.map +1 -0
- package/dist/shortcut.js +149 -0
- package/dist/shortcut.js.map +1 -0
- package/dist/tokens.d.ts +709 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +749 -0
- package/dist/tokens.js.map +1 -0
- package/dist/vendor/types/account.d.ts +26 -0
- package/dist/vendor/types/account.d.ts.map +1 -0
- package/dist/vendor/types/account.js +23 -0
- package/dist/vendor/types/account.js.map +1 -0
- package/dist/vendor/types/apiKey.d.ts +38 -0
- package/dist/vendor/types/apiKey.d.ts.map +1 -0
- package/dist/vendor/types/apiKey.js +36 -0
- package/dist/vendor/types/apiKey.js.map +1 -0
- package/dist/vendor/types/auth.d.ts +10 -0
- package/dist/vendor/types/auth.d.ts.map +1 -0
- package/dist/vendor/types/auth.js +15 -0
- package/dist/vendor/types/auth.js.map +1 -0
- package/dist/vendor/types/entity.d.ts +74 -0
- package/dist/vendor/types/entity.d.ts.map +1 -0
- package/dist/vendor/types/entity.js +111 -0
- package/dist/vendor/types/entity.js.map +1 -0
- package/dist/vendor/types/feedback.d.ts +285 -0
- package/dist/vendor/types/feedback.d.ts.map +1 -0
- package/dist/vendor/types/feedback.js +286 -0
- package/dist/vendor/types/feedback.js.map +1 -0
- package/dist/vendor/types/index.d.ts +14 -0
- package/dist/vendor/types/index.d.ts.map +1 -0
- package/dist/vendor/types/index.js +16 -0
- package/dist/vendor/types/index.js.map +1 -0
- package/dist/vendor/types/invite.d.ts +42 -0
- package/dist/vendor/types/invite.d.ts.map +1 -0
- package/dist/vendor/types/invite.js +30 -0
- package/dist/vendor/types/invite.js.map +1 -0
- package/dist/vendor/types/mcpToken.d.ts +38 -0
- package/dist/vendor/types/mcpToken.d.ts.map +1 -0
- package/dist/vendor/types/mcpToken.js +39 -0
- package/dist/vendor/types/mcpToken.js.map +1 -0
- package/dist/vendor/types/organization.d.ts +13 -0
- package/dist/vendor/types/organization.d.ts.map +1 -0
- package/dist/vendor/types/organization.js +12 -0
- package/dist/vendor/types/organization.js.map +1 -0
- package/dist/vendor/types/project.d.ts +73 -0
- package/dist/vendor/types/project.d.ts.map +1 -0
- package/dist/vendor/types/project.js +117 -0
- package/dist/vendor/types/project.js.map +1 -0
- package/dist/vendor/types/role.d.ts +12 -0
- package/dist/vendor/types/role.d.ts.map +1 -0
- package/dist/vendor/types/role.js +20 -0
- package/dist/vendor/types/role.js.map +1 -0
- package/dist/vendor/types/roleDefinition.d.ts +61 -0
- package/dist/vendor/types/roleDefinition.d.ts.map +1 -0
- package/dist/vendor/types/roleDefinition.js +45 -0
- package/dist/vendor/types/roleDefinition.js.map +1 -0
- package/dist/vendor/types/team.d.ts +25 -0
- package/dist/vendor/types/team.d.ts.map +1 -0
- package/dist/vendor/types/team.js +17 -0
- package/dist/vendor/types/team.js.map +1 -0
- package/dist/vendor/types/util.d.ts +39 -0
- package/dist/vendor/types/util.d.ts.map +1 -0
- package/dist/vendor/types/util.js +31 -0
- package/dist/vendor/types/util.js.map +1 -0
- package/package.json +59 -0
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
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 "../config.js";
|
|
35
|
+
import { joinPath } from "./fs.js";
|
|
36
|
+
export { API_URL_ENV_VAR };
|
|
37
|
+
import { DEFAULT_SCRIPT_ENVIRONMENT, InjectionError, PACKAGE_NAME, SCRIPT_BUNDLE_PATH, STRATEGIES, } from "./strategies.js";
|
|
38
|
+
import { API_KEY_ENV_VAR, inferProjectUrl, register } from "./register.js";
|
|
39
|
+
const TOOLBAR_VERSION = "^0.0.1";
|
|
40
|
+
const ENV_FILES = [".env.local", ".env"];
|
|
41
|
+
/**
|
|
42
|
+
* The command wired into the host app's build, and the marker that says it is
|
|
43
|
+
* already wired. `--optional` is load-bearing: see the comment on
|
|
44
|
+
* `wirePrebuild` for why a registration failure must not fail a deploy.
|
|
45
|
+
*/
|
|
46
|
+
export const REGISTER_COMMAND = "feedback-toolbar register";
|
|
47
|
+
/**
|
|
48
|
+
* The prebuild line, with the backend URL BAKED IN.
|
|
49
|
+
*
|
|
50
|
+
* This is the second half of #11's reopened acceptance criterion, and the
|
|
51
|
+
* reason it reopened twice. `register` resolves its backend URL from a flag or
|
|
52
|
+
* from the build environment - and the build environment does not have it:
|
|
53
|
+
* `init` writes `NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL` into `.env.local`,
|
|
54
|
+
* which create-next-app gitignores, and a plain node process does not load a
|
|
55
|
+
* dotenv file anyway. So on a real Vercel build the prebuild step threw "no
|
|
56
|
+
* backend URL", `--optional` turned that into one warning line, and no project
|
|
57
|
+
* ever appeared.
|
|
58
|
+
*
|
|
59
|
+
* package.json IS committed, so putting the URL here is what carries it into
|
|
60
|
+
* the build. It is a public URL, not a credential; the key still comes from
|
|
61
|
+
* `FEEDBACK_TOOLBAR_API_KEY` in the build environment and from nowhere else.
|
|
62
|
+
*/
|
|
63
|
+
export function prebuildScript(apiUrl) {
|
|
64
|
+
return `${REGISTER_COMMAND} --optional --api-url ${apiUrl}`;
|
|
65
|
+
}
|
|
66
|
+
export async function init(fs, options) {
|
|
67
|
+
const { root, apiUrl } = options;
|
|
68
|
+
const env = options.env ?? {};
|
|
69
|
+
const strategies = options.strategies ?? STRATEGIES;
|
|
70
|
+
const packageJsonPath = joinPath(root, "package.json");
|
|
71
|
+
if (!fs.exists(packageJsonPath)) {
|
|
72
|
+
throw new InjectionError(`no package.json at ${root}. Run this from the root of the app you want to install into.`);
|
|
73
|
+
}
|
|
74
|
+
const pkg = JSON.parse(fs.readFile(packageJsonPath));
|
|
75
|
+
// Resolved before the injection, because the script-tag strategy writes it
|
|
76
|
+
// into the markup and refuses to install without it.
|
|
77
|
+
const projectUrl = options.projectUrl ?? inferProjectUrl(env);
|
|
78
|
+
// Find the injection site FIRST. It is the only step that can fail for a
|
|
79
|
+
// reason the developer has to fix, and finding out after writing package.json
|
|
80
|
+
// and .env.local is exactly the half-install this must not produce.
|
|
81
|
+
const strategy = strategies.find((s) => s.detect(fs, root) !== null);
|
|
82
|
+
if (!strategy) {
|
|
83
|
+
throw new InjectionError([
|
|
84
|
+
"could not find a root layout to inject the toolbar into.",
|
|
85
|
+
`Tried: ${strategies.map((s) => s.label).join(", ")}.`,
|
|
86
|
+
"Nothing was changed. Add the provider by hand instead:",
|
|
87
|
+
"",
|
|
88
|
+
` import { FeedbackToolbar } from "${PACKAGE_NAME}";`,
|
|
89
|
+
" // ...then render <FeedbackToolbar /> inside <body> in your root layout.",
|
|
90
|
+
].join("\n"));
|
|
91
|
+
}
|
|
92
|
+
const site = strategy.detect(fs, root);
|
|
93
|
+
const layoutSource = fs.readFile(site.path);
|
|
94
|
+
const alreadyInjected = strategy.isInstalled(layoutSource);
|
|
95
|
+
// Computed before any write: `inject` throws rather than returning a
|
|
96
|
+
// half-edited file, and this is where that throw has to happen.
|
|
97
|
+
const injected = alreadyInjected
|
|
98
|
+
? layoutSource
|
|
99
|
+
: strategy.inject(layoutSource, {
|
|
100
|
+
apiUrl,
|
|
101
|
+
projectUrl,
|
|
102
|
+
environment: options.environment,
|
|
103
|
+
});
|
|
104
|
+
// A script-tag install has no dependency to add, no env file to read at
|
|
105
|
+
// runtime, and no build to hook - the toolbar is a file served from the
|
|
106
|
+
// backend and configured from the tag's own attributes. Skipping those
|
|
107
|
+
// steps is the whole difference between the two delivery routes.
|
|
108
|
+
const scriptTag = strategy.delivery === "script-tag";
|
|
109
|
+
const changes = [];
|
|
110
|
+
const notes = [];
|
|
111
|
+
let packageJsonChanged = false;
|
|
112
|
+
// 1. Dependency.
|
|
113
|
+
if (!scriptTag) {
|
|
114
|
+
const deps = pkg.dependencies ?? {};
|
|
115
|
+
if (!deps[PACKAGE_NAME]) {
|
|
116
|
+
pkg.dependencies = { ...deps, [PACKAGE_NAME]: TOOLBAR_VERSION };
|
|
117
|
+
packageJsonChanged = true;
|
|
118
|
+
changes.push(`added ${PACKAGE_NAME} to dependencies`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// 2. Env var, in whichever env file already exists, else .env.local.
|
|
122
|
+
//
|
|
123
|
+
// A local-development convenience, and only that. It is deliberately NOT
|
|
124
|
+
// how the deployed toolbar finds the backend: `.env.local` is gitignored
|
|
125
|
+
// by create-next-app, so it never reaches a build, which is why the URL
|
|
126
|
+
// is written into the injected component and into the prebuild command
|
|
127
|
+
// as well. Kept because a developer running `next dev` before their
|
|
128
|
+
// first deploy expects the variable to be there.
|
|
129
|
+
if (!scriptTag) {
|
|
130
|
+
const envPath = ENV_FILES.map((f) => joinPath(root, f)).find((p) => fs.exists(p));
|
|
131
|
+
const targetEnvPath = envPath ?? joinPath(root, ENV_FILES[0]);
|
|
132
|
+
const existingEnv = envPath ? fs.readFile(envPath) : "";
|
|
133
|
+
if (!existingEnv.includes(`${API_URL_ENV_VAR}=`)) {
|
|
134
|
+
const separator = existingEnv.length === 0 || existingEnv.endsWith("\n") ? "" : "\n";
|
|
135
|
+
fs.writeFile(targetEnvPath, `${existingEnv}${separator}${API_URL_ENV_VAR}=${apiUrl}\n`);
|
|
136
|
+
changes.push(`wrote ${API_URL_ENV_VAR} to ${targetEnvPath} (local development; the ` +
|
|
137
|
+
"deployed toolbar reads the URL from the component it injected)");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// 3. The provider.
|
|
141
|
+
if (!alreadyInjected) {
|
|
142
|
+
fs.writeFile(site.path, injected);
|
|
143
|
+
const what = scriptTag
|
|
144
|
+
? `injected the ${SCRIPT_BUNDLE_PATH} script tag into the ${site.description}`
|
|
145
|
+
: `injected <FeedbackToolbar /> into the ${site.description}`;
|
|
146
|
+
changes.push(what);
|
|
147
|
+
if (scriptTag) {
|
|
148
|
+
// The gate cannot be resolved from a static file - absent means off - so
|
|
149
|
+
// the tag has to declare one or it mounts nothing. Written rather than
|
|
150
|
+
// left to the developer, and said out loud here because it is the one
|
|
151
|
+
// value in the install that decides whether their own customers see a
|
|
152
|
+
// feedback widget.
|
|
153
|
+
const environment = options.environment ?? DEFAULT_SCRIPT_ENVIRONMENT;
|
|
154
|
+
notes.push(`the tag declares data-environment="${environment}", which is what makes it mount. ` +
|
|
155
|
+
"Change it to production on any page real customers reach, or re-run with " +
|
|
156
|
+
"--environment production.");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// 4. The build hook. This is the step #11 was reopened for: without it,
|
|
160
|
+
// nothing ever registers the project except a developer who happened to
|
|
161
|
+
// pass two flags by hand.
|
|
162
|
+
if (!scriptTag) {
|
|
163
|
+
const wired = wirePrebuild(pkg, apiUrl);
|
|
164
|
+
if (wired) {
|
|
165
|
+
packageJsonChanged = true;
|
|
166
|
+
changes.push(wired);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (packageJsonChanged) {
|
|
170
|
+
fs.writeFile(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
171
|
+
}
|
|
172
|
+
// 5. Register the project, if this machine happens to know enough to. On a
|
|
173
|
+
// developer's laptop it usually does not, and that is fine now: step 4
|
|
174
|
+
// put the command in the build, where the URL and the key live.
|
|
175
|
+
const apiKey = options.apiKey ?? env[API_KEY_ENV_VAR];
|
|
176
|
+
if (!projectUrl || !apiKey) {
|
|
177
|
+
notes.push(registrationDeferredNote({ projectUrl, apiKey, scriptTag }));
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
try {
|
|
181
|
+
const outcome = await register({
|
|
182
|
+
apiUrl,
|
|
183
|
+
apiKey,
|
|
184
|
+
projectUrl,
|
|
185
|
+
packageName: pkg.name,
|
|
186
|
+
env,
|
|
187
|
+
registerProject: options.registerProject,
|
|
188
|
+
});
|
|
189
|
+
if (outcome.created) {
|
|
190
|
+
changes.push(`registered ${projectUrl} as a project`);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
notes.push(`${projectUrl} was already registered`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
// A registration that did not go through is not a failed install: the
|
|
198
|
+
// code is in place and the next build registers. Say so and carry on.
|
|
199
|
+
notes.push(`could not register ${projectUrl} (${String(err)}); it will register on the next build`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
changes,
|
|
204
|
+
notes,
|
|
205
|
+
alreadyInstalled: changes.length === 0,
|
|
206
|
+
strategy: strategy.id,
|
|
207
|
+
delivery: scriptTag ? "script-tag" : "npm-package",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Add `feedback-toolbar register` to the host app's `prebuild`, once.
|
|
212
|
+
*
|
|
213
|
+
* npm, pnpm and yarn all run `prebuild` before `build`, which is why the hook
|
|
214
|
+
* goes there rather than into `build` itself: appending to somebody's build
|
|
215
|
+
* command changes the command they debug, and prepending to it changes what
|
|
216
|
+
* their CI logs look like at the top. `prebuild` is the slot the package
|
|
217
|
+
* managers reserve for exactly this.
|
|
218
|
+
*
|
|
219
|
+
* `--optional` is not decoration. This runs on every deploy of somebody
|
|
220
|
+
* else's product forever, and a feedback tool that fails a deploy because our
|
|
221
|
+
* backend was slow, or because a key was rotated, has done far more damage
|
|
222
|
+
* than the missing project row it was trying to create.
|
|
223
|
+
*
|
|
224
|
+
* Refusing to add it twice is the same idempotency rule as everything else
|
|
225
|
+
* here, and it has to survive the developer having edited the line: the check
|
|
226
|
+
* is for the command, not for the exact string this wrote. Like every other
|
|
227
|
+
* step, a second run says nothing rather than reporting a non-change.
|
|
228
|
+
*
|
|
229
|
+
* Returns the line to report, or undefined when there was nothing to do.
|
|
230
|
+
*/
|
|
231
|
+
function wirePrebuild(pkg, apiUrl) {
|
|
232
|
+
const scripts = pkg.scripts ?? {};
|
|
233
|
+
const existing = scripts.prebuild;
|
|
234
|
+
const line = prebuildScript(apiUrl);
|
|
235
|
+
if (existing === undefined) {
|
|
236
|
+
pkg.scripts = { ...scripts, prebuild: line };
|
|
237
|
+
return `added a "prebuild" script that registers this deployment on every build: ${line}`;
|
|
238
|
+
}
|
|
239
|
+
if (existing.includes(REGISTER_COMMAND))
|
|
240
|
+
return undefined;
|
|
241
|
+
// Their command first, ours after it, joined rather than replaced: the
|
|
242
|
+
// existing prebuild is somebody's build prerequisite and must still run,
|
|
243
|
+
// and must still be the thing that fails the build if it fails.
|
|
244
|
+
pkg.scripts = { ...scripts, prebuild: `${existing} && ${line}` };
|
|
245
|
+
return (`edited the existing "prebuild" script to also register this deployment: ` +
|
|
246
|
+
`${existing} && ${line}`);
|
|
247
|
+
}
|
|
248
|
+
/** Why registration did not happen here, and what will do it instead. */
|
|
249
|
+
function registrationDeferredNote(input) {
|
|
250
|
+
if (input.scriptTag) {
|
|
251
|
+
// No build to hook, so nothing will do this on its own. #17's answer: run
|
|
252
|
+
// the command once, from a terminal or CI, where a key belongs.
|
|
253
|
+
return ("a script-tag install has no build step, so nothing registers the project for you. " +
|
|
254
|
+
`Run it once: npx ${PACKAGE_NAME} register --project-url <url> --api-key <key>`);
|
|
255
|
+
}
|
|
256
|
+
if (!input.apiKey) {
|
|
257
|
+
return ("no deploy key here, so nothing was registered yet. The prebuild step will do it " +
|
|
258
|
+
`on the next build, and it needs one thing from you: set ${API_KEY_ENV_VAR} in your ` +
|
|
259
|
+
"hosting provider's environment variables (dashboard > Settings > Deploy keys). " +
|
|
260
|
+
"The backend URL is already baked into the prebuild command and into the injected " +
|
|
261
|
+
"component, so there is nothing else to configure.");
|
|
262
|
+
}
|
|
263
|
+
return ("this machine does not report a deployment URL, so nothing was registered yet - " +
|
|
264
|
+
"the prebuild step will do it on the next build, where VERCEL_URL is set");
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/cli/register.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,gBAAgB,CAAC;AAExB,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,CAyC1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,MAAM,GAAG,SAAS,CAGpB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// `feedback-toolbar register` - make sure this deployment exists as a project.
|
|
2
|
+
//
|
|
3
|
+
// A first-class command, not a step inside `init`, and issues #11 and #17 both
|
|
4
|
+
// needed it to be:
|
|
5
|
+
//
|
|
6
|
+
// - #11 reopened because `init` runs on a laptop, where VERCEL_URL does not
|
|
7
|
+
// exist, so the project URL was undefined and registration was silently
|
|
8
|
+
// skipped. The fix is to register where those variables DO exist: in the
|
|
9
|
+
// build. `init` wires this command in as a prebuild step.
|
|
10
|
+
// - #17 added the script-tag install, which has no build to hook at all. Its
|
|
11
|
+
// project is registered by running this command once from a terminal or CI.
|
|
12
|
+
//
|
|
13
|
+
// Both callers want the same three things: resolve where the values come from,
|
|
14
|
+
// call the one registration service, and say clearly what happened. None of
|
|
15
|
+
// them wants a second opinion on what a valid URL is - see ./registration.ts.
|
|
16
|
+
import { RegistrationError, postRegistration, } from "./registration.js";
|
|
17
|
+
/** Where `--api-url` falls back to. The public name is what a build already has. */
|
|
18
|
+
export const API_URL_ENV_VARS = [
|
|
19
|
+
"NEXT_PUBLIC_FEEDBACK_TOOLBAR_API_URL",
|
|
20
|
+
"FEEDBACK_TOOLBAR_API_URL",
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Where `--api-key` falls back to, and the only place a key is ever read from.
|
|
24
|
+
* Never a file, never a `data-` attribute, never an argument this CLI writes
|
|
25
|
+
* down: a deploy key's whole power is creating projects, so it lives in the
|
|
26
|
+
* build environment and nowhere else.
|
|
27
|
+
*/
|
|
28
|
+
export const API_KEY_ENV_VAR = "FEEDBACK_TOOLBAR_API_KEY";
|
|
29
|
+
/**
|
|
30
|
+
* Register the deployment, or confirm it is already registered.
|
|
31
|
+
*
|
|
32
|
+
* Idempotent because the backend is: the second call with the same normalised
|
|
33
|
+
* URL is a no-op that answers `created: false`. That is what makes this safe
|
|
34
|
+
* as a prebuild step, which runs on every deploy forever.
|
|
35
|
+
*
|
|
36
|
+
* Throws `RegistrationError` with a message naming the missing piece when it
|
|
37
|
+
* cannot proceed. It never guesses: a registration under a URL nobody meant
|
|
38
|
+
* creates a project that collects feedback from a page that does not exist.
|
|
39
|
+
*/
|
|
40
|
+
export async function register(options) {
|
|
41
|
+
const { env } = options;
|
|
42
|
+
const transport = options.registerProject ?? postRegistration;
|
|
43
|
+
const apiUrl = options.apiUrl ?? API_URL_ENV_VARS.map((name) => env[name]).find(Boolean);
|
|
44
|
+
if (!apiUrl) {
|
|
45
|
+
throw new RegistrationError("no backend URL. Pass --api-url https://feedback.bitvea.com, or set " +
|
|
46
|
+
`${API_URL_ENV_VARS[0]} in the build environment (\`init\` writes it into .env.local).`);
|
|
47
|
+
}
|
|
48
|
+
const apiKey = options.apiKey ?? env[API_KEY_ENV_VAR];
|
|
49
|
+
if (!apiKey) {
|
|
50
|
+
throw new RegistrationError(`no deploy key. Pass --api-key, or set ${API_KEY_ENV_VAR} in the build ` +
|
|
51
|
+
"environment. Create one in the dashboard under Settings > Deploy keys. " +
|
|
52
|
+
"It must never be committed or put in a page.");
|
|
53
|
+
}
|
|
54
|
+
const projectUrl = options.projectUrl ?? inferProjectUrl(env);
|
|
55
|
+
if (!projectUrl) {
|
|
56
|
+
throw new RegistrationError("could not tell which URL to register. Pass --project-url https://myapp.com. " +
|
|
57
|
+
"Inside a Vercel build this is read from VERCEL_PROJECT_PRODUCTION_URL or " +
|
|
58
|
+
"VERCEL_URL, neither of which is set here.");
|
|
59
|
+
}
|
|
60
|
+
const { created, project } = await transport({
|
|
61
|
+
apiUrl,
|
|
62
|
+
apiKey,
|
|
63
|
+
projectUrl,
|
|
64
|
+
repoOwner: env.VERCEL_GIT_REPO_OWNER,
|
|
65
|
+
repoSlug: env.VERCEL_GIT_REPO_SLUG,
|
|
66
|
+
packageName: options.packageName,
|
|
67
|
+
});
|
|
68
|
+
return { projectUrl, created, projectName: project?.name };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The URL to register the project under, from the build environment.
|
|
72
|
+
*
|
|
73
|
+
* Same precedence as the toolbar's own `resolveConfig`, and that agreement is
|
|
74
|
+
* the point: the toolbar reports this value back at runtime, so if the two
|
|
75
|
+
* picked differently the lookup would miss on every preview deployment. The
|
|
76
|
+
* production hostname wins because a preview URL changes on every commit, and
|
|
77
|
+
* keying on it would create a project per deploy instead of collecting a
|
|
78
|
+
* project's feedback in one place.
|
|
79
|
+
*/
|
|
80
|
+
export function inferProjectUrl(env) {
|
|
81
|
+
const host = env.VERCEL_PROJECT_PRODUCTION_URL ?? env.VERCEL_URL;
|
|
82
|
+
return host ? `https://${host}` : undefined;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/cli/register.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,+EAA+E;AAC/E,mBAAmB;AACnB,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,6EAA6E;AAC7E,8DAA8D;AAC9D,+EAA+E;AAC/E,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GAEjB,MAAM,gBAAgB,CAAC;AAExB,oFAAoF;AACpF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,sCAAsC;IACtC,0BAA0B;CAClB,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAyB1D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAwB;IAExB,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IACxB,MAAM,SAAS,GAAG,OAAO,CAAC,eAAe,IAAI,gBAAgB,CAAC;IAE9D,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,iBAAiB,CACzB,qEAAqE;YACnE,GAAG,gBAAgB,CAAC,CAAC,CAAC,iEAAiE,CAC1F,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,iBAAiB,CACzB,yCAAyC,eAAe,gBAAgB;YACtE,yEAAyE;YACzE,8CAA8C,CACjD,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,iBAAiB,CACzB,8EAA8E;YAC5E,2EAA2E;YAC3E,2CAA2C,CAC9C,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC;QAC3C,MAAM;QACN,MAAM;QACN,UAAU;QACV,SAAS,EAAE,GAAG,CAAC,qBAAqB;QACpC,QAAQ,EAAE,GAAG,CAAC,oBAAoB;QAClC,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC,CAAC;IAEH,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAuC;IAEvC,MAAM,IAAI,GAAG,GAAG,CAAC,6BAA6B,IAAI,GAAG,CAAC,UAAU,CAAC;IACjE,OAAO,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** What a build environment can tell the backend about the deployment. */
|
|
2
|
+
export interface RegisterProjectRequest {
|
|
3
|
+
/** Base URL of the BitVea Feedback backend. */
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
/** Deploy key. Read from a flag or the environment, never from a file. */
|
|
6
|
+
apiKey: string;
|
|
7
|
+
/** The deployment URL to register, exactly as the caller resolved it. */
|
|
8
|
+
projectUrl: string;
|
|
9
|
+
repoOwner?: string | undefined;
|
|
10
|
+
repoSlug?: string | undefined;
|
|
11
|
+
packageName?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* `created` is the whole answer: false means the URL was already registered,
|
|
15
|
+
* which is a success, not a conflict. `project` is what the backend named it,
|
|
16
|
+
* so the CLI can echo something recognisable back.
|
|
17
|
+
*/
|
|
18
|
+
export interface RegisterProjectResponse {
|
|
19
|
+
created: boolean;
|
|
20
|
+
project?: {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
slug: string;
|
|
24
|
+
url: string | null;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export type RegisterProjectTransport = (input: RegisterProjectRequest) => Promise<RegisterProjectResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* A failure the person running the command can act on, as opposed to a bug.
|
|
30
|
+
* The CLI prints `message` and exits; nothing else is expected to catch it.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RegistrationError extends Error {
|
|
33
|
+
constructor(message: string);
|
|
34
|
+
}
|
|
35
|
+
/** The real transport. Injected everywhere else so tests stay off the network. */
|
|
36
|
+
export declare const postRegistration: RegisterProjectTransport;
|
|
37
|
+
//# sourceMappingURL=registration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/cli/registration.ts"],"names":[],"mappings":"AAcA,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,sBAAsB,KAC1B,OAAO,CAAC,uBAAuB,CAAC,CAAC;AAEtC;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,EAAE,wBAqD9B,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
// DNS, TLS, a wrong host, no network in the build container. Worth naming
|
|
44
|
+
// the URL: the commonest cause is an --api-url pointing at nothing.
|
|
45
|
+
throw new RegistrationError(`could not reach ${input.apiUrl} (${String(err)}). Check --api-url.`);
|
|
46
|
+
}
|
|
47
|
+
if (res.status === 401) {
|
|
48
|
+
// The commonest real failure, and the one a bare status code explains
|
|
49
|
+
// worst. Absent, mistyped and revoked all answer 401 on purpose - the
|
|
50
|
+
// route refuses to be an oracle for which - so say all three.
|
|
51
|
+
throw new RegistrationError("the deploy key was refused (401): it is missing, wrong or revoked. " +
|
|
52
|
+
"Create one in the dashboard under Settings > Deploy keys, then pass it as " +
|
|
53
|
+
"--api-key or set FEEDBACK_TOOLBAR_API_KEY.");
|
|
54
|
+
}
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
// The backend's own error code, verbatim. `invalid_project_url` is the one
|
|
57
|
+
// that matters, and paraphrasing it here would be the beginning of a
|
|
58
|
+
// second set of validation rules.
|
|
59
|
+
const code = await res
|
|
60
|
+
.json()
|
|
61
|
+
.then((body) => body !== null && typeof body === "object" && "error" in body
|
|
62
|
+
? String(body.error)
|
|
63
|
+
: undefined)
|
|
64
|
+
.catch(() => undefined);
|
|
65
|
+
throw new RegistrationError(`registration failed with ${res.status}${code ? ` (${code})` : ""}.`);
|
|
66
|
+
}
|
|
67
|
+
return (await res.json());
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=registration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.js","sourceRoot":"","sources":["../../src/cli/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;AA6BxD;;;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;aAC/B,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;QAC1B,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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { type InstallerFs } from "./fs.js";
|
|
2
|
+
export declare const PACKAGE_NAME = "@bitvea/feedback-toolbar";
|
|
3
|
+
export declare const COMPONENT_NAME = "FeedbackToolbar";
|
|
4
|
+
/** The file the script-tag route is served as, relative to the backend URL. */
|
|
5
|
+
export declare const SCRIPT_BUNDLE_PATH = "/toolbar.js";
|
|
6
|
+
export interface InjectionSite {
|
|
7
|
+
/** The file to edit. */
|
|
8
|
+
path: string;
|
|
9
|
+
/** Human-readable description of what was found, for the CLI's output. */
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* How a strategy's host app gets the toolbar's *code*, which decides which of
|
|
14
|
+
* the installer's other steps apply at all.
|
|
15
|
+
*
|
|
16
|
+
* `npm-package`: the toolbar is a dependency the host's bundler compiles, so
|
|
17
|
+
* the install needs a package.json entry, an env var for the API URL, and a
|
|
18
|
+
* prebuild hook to register the project from the build.
|
|
19
|
+
*
|
|
20
|
+
* `script-tag`: the toolbar is a file served from the backend and configured
|
|
21
|
+
* from `data-` attributes on the tag. There is no dependency to add, no env
|
|
22
|
+
* file to read at runtime, and - the reason #17 called this out - no build to
|
|
23
|
+
* hook, so its project is registered by running `register` by hand.
|
|
24
|
+
*/
|
|
25
|
+
export type Delivery = "npm-package" | "script-tag";
|
|
26
|
+
/**
|
|
27
|
+
* The environment a script-tag install declares, when the developer has not
|
|
28
|
+
* said otherwise.
|
|
29
|
+
*
|
|
30
|
+
* The gate treats "absent" as off, and a static HTML file cannot know which
|
|
31
|
+
* deployment served it - so a tag with no `data-environment` mounts nothing,
|
|
32
|
+
* ever. That is the correct default for a value we could only guess, and the
|
|
33
|
+
* wrong default for an installer whose whole job is to leave a working
|
|
34
|
+
* install behind: #17 asks for a toolbar that mounts on a plain page with no
|
|
35
|
+
* build step, and a tag the developer has to hand-edit is not that.
|
|
36
|
+
*
|
|
37
|
+
* So `init` writes an environment, and the value is a review environment
|
|
38
|
+
* because installing a review tool on a page is what the command means. The
|
|
39
|
+
* result is printed as a change and called out as a note, and `--environment`
|
|
40
|
+
* overrides it - including with `production`, which is how somebody turns the
|
|
41
|
+
* tag off without removing it.
|
|
42
|
+
*/
|
|
43
|
+
export declare const DEFAULT_SCRIPT_ENVIRONMENT = "preview";
|
|
44
|
+
/** What `inject` needs to know about the install to write the markup. */
|
|
45
|
+
export interface InjectionContext {
|
|
46
|
+
/** Base URL of the BitVea Feedback backend, no trailing slash. */
|
|
47
|
+
apiUrl: string;
|
|
48
|
+
/** The deployment URL the project is registered under, when known. */
|
|
49
|
+
projectUrl?: string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* What the injected markup declares as its environment. Only the script-tag
|
|
52
|
+
* route uses it: an npm install reads `NEXT_PUBLIC_VERCEL_ENV`, which the
|
|
53
|
+
* host's own build populates per deployment.
|
|
54
|
+
*/
|
|
55
|
+
environment?: string | undefined;
|
|
56
|
+
}
|
|
57
|
+
export interface InjectionStrategy {
|
|
58
|
+
/** Stable id, reported in the CLI's output. */
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly label: string;
|
|
61
|
+
/** Which of the installer's steps apply. Defaults to `npm-package`. */
|
|
62
|
+
readonly delivery?: Delivery;
|
|
63
|
+
/** Find the file to inject into, or null when this strategy does not apply. */
|
|
64
|
+
detect(fs: InstallerFs, root: string): InjectionSite | null;
|
|
65
|
+
/** True when the provider is already there, which makes a re-run a no-op. */
|
|
66
|
+
isInstalled(source: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Return the edited source. Only called when `isInstalled` is false, and
|
|
69
|
+
* throws when it cannot do the edit, so a partial write is not possible:
|
|
70
|
+
* the caller writes only what this returns.
|
|
71
|
+
*/
|
|
72
|
+
inject(source: string, context: InjectionContext): string;
|
|
73
|
+
}
|
|
74
|
+
export declare const nextAppRouterStrategy: InjectionStrategy;
|
|
75
|
+
/**
|
|
76
|
+
* The `<script src>` install, for an app with no build step to add a
|
|
77
|
+
* dependency to. Second in the list on purpose: an App Router app usually
|
|
78
|
+
* also has an index.html somewhere, and the npm install is the better one.
|
|
79
|
+
*
|
|
80
|
+
* Note what the injected tag does NOT carry: a deploy key. There is no
|
|
81
|
+
* supported way to put one in a page, and the bundle refuses to mount when it
|
|
82
|
+
* finds anything that looks like one - a key in a page is a key in every
|
|
83
|
+
* visitor's hands, and its whole power is creating projects.
|
|
84
|
+
*
|
|
85
|
+
* It does carry an environment, and it has to. A static file cannot know which
|
|
86
|
+
* deployment served it and the gate treats absent as off, so a tag without one
|
|
87
|
+
* mounts nothing at all - which is what #17's "mounts a working toolbar on a
|
|
88
|
+
* plain HTML page" cannot mean. The value is written, printed as a change, and
|
|
89
|
+
* called out as a note; `--environment production` is how a developer turns
|
|
90
|
+
* the tag off without deleting it. See DEFAULT_SCRIPT_ENVIRONMENT.
|
|
91
|
+
*/
|
|
92
|
+
export declare const htmlScriptTagStrategy: InjectionStrategy;
|
|
93
|
+
/** A failure the developer can act on, as opposed to an internal error. */
|
|
94
|
+
export declare class InjectionError extends Error {
|
|
95
|
+
constructor(message: string);
|
|
96
|
+
}
|
|
97
|
+
export declare const STRATEGIES: readonly InjectionStrategy[];
|
|
98
|
+
//# sourceMappingURL=strategies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategies.d.ts","sourceRoot":"","sources":["../../src/cli/strategies.ts"],"names":[],"mappings":"AAOA,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,MAAM,CAAC;AAElD,eAAO,MAAM,YAAY,6BAA6B,CAAC;AACvD,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,YAAY,CAAC;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,0BAA0B,YAAY,CAAC;AAEpD,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAAC;IAC5D,6EAA6E;IAC7E,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAAC;CAC3D;AAUD,eAAO,MAAM,qBAAqB,EAAE,iBAwDnC,CAAC;AAKF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAuCnC,CAAC;AAgEF,2EAA2E;AAC3E,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,iBAAiB,EAGlD,CAAC"}
|