@rebasepro/cli 0.19.2-canary.g9b599d4 → 0.20.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.
package/dist/index.es.js
CHANGED
|
@@ -1474,33 +1474,12 @@ async function recordEvent(event, properties = {}, options = {}) {
|
|
|
1474
1474
|
}
|
|
1475
1475
|
//#endregion
|
|
1476
1476
|
//#region src/telemetry/consent.ts
|
|
1477
|
-
/**
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
* is the one where no consent exists yet. Asking before scaffolding puts a
|
|
1484
|
-
* privacy negotiation in front of someone who has not yet seen the tool do
|
|
1485
|
-
* anything — the worst possible moment, and a reliable way to get a reflexive
|
|
1486
|
-
* no.
|
|
1487
|
-
*
|
|
1488
|
-
* So the question is asked once the project exists and the user has seen it
|
|
1489
|
-
* work. The event's data is still in memory at that point, so nothing is lost
|
|
1490
|
-
* by waiting, and — this is the part that matters — **nothing has been
|
|
1491
|
-
* transmitted or written**. Declining leaves no id, no file, no record.
|
|
1492
|
-
*
|
|
1493
|
-
* ## Why the payload is shown rather than described
|
|
1494
|
-
*
|
|
1495
|
-
* "Anonymous usage data" is a phrase that has been used to mean almost
|
|
1496
|
-
* anything. Printing the exact JSON costs four lines of output and replaces a
|
|
1497
|
-
* claim the user has to take on faith with something they can read. It is also
|
|
1498
|
-
* the same builder the sender uses, so it cannot drift into a comfortable
|
|
1499
|
-
* fiction.
|
|
1500
|
-
*/
|
|
1501
|
-
/** True when we may ask: no decision recorded, and nothing else forbids it. */
|
|
1502
|
-
function shouldPrompt(env = process.env) {
|
|
1503
|
-
return suppressionReason(env) === "not_asked" && Boolean(process.stdin.isTTY);
|
|
1477
|
+
/** True when we may ask: nothing forbids it, and there is a question to ask. */
|
|
1478
|
+
function shouldPrompt(env = process.env, { reAskDeclined = false } = {}) {
|
|
1479
|
+
if (!process.stdin.isTTY) return false;
|
|
1480
|
+
const reason = suppressionReason(env);
|
|
1481
|
+
if (reason === "not_asked") return true;
|
|
1482
|
+
return reAskDeclined && reason === "declined";
|
|
1504
1483
|
}
|
|
1505
1484
|
function renderPreview(event, properties) {
|
|
1506
1485
|
const preview = buildEvent(event, properties, {
|
|
@@ -1516,8 +1495,9 @@ function renderPreview(event, properties) {
|
|
|
1516
1495
|
* CI must behave exactly as it does today, which means not asking and not
|
|
1517
1496
|
* sending.
|
|
1518
1497
|
*/
|
|
1519
|
-
async function promptForConsent(event, properties) {
|
|
1520
|
-
if (!shouldPrompt()) return false;
|
|
1498
|
+
async function promptForConsent(event, properties, options = {}) {
|
|
1499
|
+
if (!shouldPrompt(process.env, options)) return false;
|
|
1500
|
+
const askedBefore = suppressionReason(process.env) === "declined";
|
|
1521
1501
|
try {
|
|
1522
1502
|
console.log("");
|
|
1523
1503
|
console.log(chalk.bold("Help improve Rebase?"));
|
|
@@ -1531,6 +1511,11 @@ async function promptForConsent(event, properties) {
|
|
|
1531
1511
|
console.log("");
|
|
1532
1512
|
console.log(chalk.gray(" No project names, paths, schemas, URLs or error messages. Change your"));
|
|
1533
1513
|
console.log(chalk.gray(` mind any time with ${chalk.cyan("rebase telemetry disable")}.`));
|
|
1514
|
+
if (askedBefore) {
|
|
1515
|
+
console.log("");
|
|
1516
|
+
console.log(chalk.gray(" You declined before, and that is still the answer unless you change it"));
|
|
1517
|
+
console.log(chalk.gray(" here. Asked once per new project; never during ordinary work."));
|
|
1518
|
+
}
|
|
1534
1519
|
console.log("");
|
|
1535
1520
|
const { accepted } = await inquirer.prompt([{
|
|
1536
1521
|
type: "confirm",
|
|
@@ -1539,7 +1524,7 @@ async function promptForConsent(event, properties) {
|
|
|
1539
1524
|
default: false
|
|
1540
1525
|
}]);
|
|
1541
1526
|
setConsent(Boolean(accepted));
|
|
1542
|
-
console.log(accepted ? chalk.green(" Thank you — sharing enabled.") : chalk.gray(" Nothing will be sent. You will not be asked again."));
|
|
1527
|
+
console.log(accepted ? chalk.green(" Thank you — sharing enabled.") : chalk.gray(" Nothing will be sent." + (options.reAskDeclined ? " You will be asked again the next time you scaffold a project." : " You will not be asked again.")));
|
|
1543
1528
|
console.log("");
|
|
1544
1529
|
return Boolean(accepted);
|
|
1545
1530
|
} catch {
|
|
@@ -2139,7 +2124,7 @@ async function createProject$1(options) {
|
|
|
2139
2124
|
git: Boolean(options.git),
|
|
2140
2125
|
duration: durationBucket(Date.now() - startedAt)
|
|
2141
2126
|
};
|
|
2142
|
-
if (await promptForConsent("cli.init", initProperties)) await recordEvent("cli.init", initProperties, { projectRoot: options.targetDirectory });
|
|
2127
|
+
if (await promptForConsent("cli.init", initProperties, { reAskDeclined: true })) await recordEvent("cli.init", initProperties, { projectRoot: options.targetDirectory });
|
|
2143
2128
|
}
|
|
2144
2129
|
/**
|
|
2145
2130
|
* Apply a template preset by replacing the default collection files.
|
|
@@ -15174,7 +15159,31 @@ function resolveDeployArgs(rawArgs) {
|
|
|
15174
15159
|
appName: positionals[0]
|
|
15175
15160
|
};
|
|
15176
15161
|
}
|
|
15162
|
+
/**
|
|
15163
|
+
* `cli.deploy` — the event that says whether anyone ever ships.
|
|
15164
|
+
*
|
|
15165
|
+
* Declared in `TelemetryEventName` from the start and recorded nowhere, so a
|
|
15166
|
+
* consenting user reported scaffolding, dev servers and schema pushes and never
|
|
15167
|
+
* the one act the product exists for.
|
|
15168
|
+
*
|
|
15169
|
+
* What it carries is deliberately thin. No project id, no app name, no
|
|
15170
|
+
* deployment id, no URL: those are the "project names" and "URLs" the consent
|
|
15171
|
+
* screen promises are never sent, and a deployment id is a durable handle on
|
|
15172
|
+
* somebody's infrastructure. `frameworkVersion` is *our* version, not the
|
|
15173
|
+
* user's data, and it is the one field that makes the rest legible — a failure
|
|
15174
|
+
* rate means nothing without knowing which release it is a rate for.
|
|
15175
|
+
*/
|
|
15176
|
+
async function recordDeploy(o) {
|
|
15177
|
+
await recordEvent("cli.deploy", {
|
|
15178
|
+
followed: o.followed,
|
|
15179
|
+
status: o.status,
|
|
15180
|
+
deduplicated: o.deduplicated,
|
|
15181
|
+
framework_version: o.frameworkVersion ?? null,
|
|
15182
|
+
duration: durationBucket(Date.now() - o.startedAt)
|
|
15183
|
+
}, { projectRoot: process.cwd() });
|
|
15184
|
+
}
|
|
15177
15185
|
async function deployCommand(rawArgs, projectRef) {
|
|
15186
|
+
const startedAt = Date.now();
|
|
15178
15187
|
const { flags: args, appName } = resolveDeployArgs(rawArgs);
|
|
15179
15188
|
if (args["--wait"] && args["--no-follow"]) fail("--wait and --no-follow ask for opposite things.", "`deploy` follows by default — pass neither, or `--no-follow` to return as soon as the build is triggered.", "usage");
|
|
15180
15189
|
const { client, url } = await requireClient(rawArgs);
|
|
@@ -15258,6 +15267,13 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
15258
15267
|
following: false,
|
|
15259
15268
|
...warningPayload(warnings)
|
|
15260
15269
|
});
|
|
15270
|
+
await recordDeploy({
|
|
15271
|
+
followed: false,
|
|
15272
|
+
status: "not_followed",
|
|
15273
|
+
deduplicated,
|
|
15274
|
+
frameworkVersion,
|
|
15275
|
+
startedAt
|
|
15276
|
+
});
|
|
15261
15277
|
return;
|
|
15262
15278
|
}
|
|
15263
15279
|
if (!isJsonMode()) {
|
|
@@ -15270,6 +15286,13 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
15270
15286
|
projectId,
|
|
15271
15287
|
url
|
|
15272
15288
|
});
|
|
15289
|
+
await recordDeploy({
|
|
15290
|
+
followed: true,
|
|
15291
|
+
status,
|
|
15292
|
+
deduplicated,
|
|
15293
|
+
frameworkVersion,
|
|
15294
|
+
startedAt
|
|
15295
|
+
});
|
|
15273
15296
|
emit(() => {}, {
|
|
15274
15297
|
deploymentId,
|
|
15275
15298
|
deduplicated,
|
|
@@ -19079,6 +19102,24 @@ async function entry(args) {
|
|
|
19079
19102
|
return;
|
|
19080
19103
|
}
|
|
19081
19104
|
const effectiveSubcommand = parsedArgs["--help"] && !subcommand ? "--help" : subcommand;
|
|
19105
|
+
try {
|
|
19106
|
+
await dispatch(command, effectiveSubcommand, args, parsedArgs, namespacedCommands);
|
|
19107
|
+
} catch (error) {
|
|
19108
|
+
await recordEvent("cli.error", {
|
|
19109
|
+
command: command ?? "none",
|
|
19110
|
+
subcommand: effectiveSubcommand ?? "none",
|
|
19111
|
+
error_type: error instanceof Error ? error.constructor.name : "unknown",
|
|
19112
|
+
usage: Boolean(error && typeof error === "object" && error.isUsageError)
|
|
19113
|
+
}, { projectRoot: process.cwd() });
|
|
19114
|
+
throw error;
|
|
19115
|
+
}
|
|
19116
|
+
}
|
|
19117
|
+
/**
|
|
19118
|
+
* The dispatch, lifted out of {@link entry} so the whole of it sits inside one
|
|
19119
|
+
* `try`. Inlining the switch there would have put the `catch` around the flag
|
|
19120
|
+
* parsing too, which throws its own usage errors before a command is even named.
|
|
19121
|
+
*/
|
|
19122
|
+
async function dispatch(command, effectiveSubcommand, args, parsedArgs, namespacedCommands) {
|
|
19082
19123
|
switch (command) {
|
|
19083
19124
|
case "__dev-db-daemon": {
|
|
19084
19125
|
const { parseDaemonArgs, runDaemon } = await import("./daemon-entry-LTFKtpHy.js");
|