@gadgetinc/ggt 0.4.10 → 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 (142) hide show
  1. package/README.md +165 -93
  2. package/lib/__generated__/graphql.js +66 -1
  3. package/lib/__generated__/graphql.js.map +1 -1
  4. package/lib/commands/deploy.js +328 -230
  5. package/lib/commands/deploy.js.map +1 -1
  6. package/lib/commands/dev.js +445 -0
  7. package/lib/commands/dev.js.map +1 -0
  8. package/lib/commands/list.js +27 -19
  9. package/lib/commands/list.js.map +1 -1
  10. package/lib/commands/login.js +15 -11
  11. package/lib/commands/login.js.map +1 -1
  12. package/lib/commands/logout.js +5 -5
  13. package/lib/commands/logout.js.map +1 -1
  14. package/lib/commands/open.js +200 -0
  15. package/lib/commands/open.js.map +1 -0
  16. package/lib/commands/pull.js +128 -0
  17. package/lib/commands/pull.js.map +1 -0
  18. package/lib/commands/push.js +126 -0
  19. package/lib/commands/push.js.map +1 -0
  20. package/lib/commands/root.js +46 -28
  21. package/lib/commands/root.js.map +1 -1
  22. package/lib/commands/status.js +61 -0
  23. package/lib/commands/status.js.map +1 -0
  24. package/lib/commands/version.js +6 -6
  25. package/lib/commands/version.js.map +1 -1
  26. package/lib/commands/whoami.js +6 -6
  27. package/lib/commands/whoami.js.map +1 -1
  28. package/lib/ggt.js +33 -8
  29. package/lib/ggt.js.map +1 -1
  30. package/lib/main.js +5 -0
  31. package/lib/main.js.map +1 -0
  32. package/lib/services/app/api/api.js +191 -0
  33. package/lib/services/app/api/api.js.map +1 -0
  34. package/lib/services/app/api/operation.js +12 -0
  35. package/lib/services/app/api/operation.js.map +1 -0
  36. package/lib/services/app/app.js +44 -10
  37. package/lib/services/app/app.js.map +1 -1
  38. package/lib/services/app/{edit/client.js → client.js} +29 -19
  39. package/lib/services/app/client.js.map +1 -0
  40. package/lib/services/app/edit/edit.js +67 -31
  41. package/lib/services/app/edit/edit.js.map +1 -1
  42. package/lib/services/app/edit/operation.js +4 -3
  43. package/lib/services/app/edit/operation.js.map +1 -1
  44. package/lib/services/app/{edit/error.js → error.js} +6 -6
  45. package/lib/services/app/error.js.map +1 -0
  46. package/lib/services/command/arg.js +4 -4
  47. package/lib/services/command/arg.js.map +1 -1
  48. package/lib/services/command/command.js +9 -7
  49. package/lib/services/command/command.js.map +1 -1
  50. package/lib/services/command/context.js +82 -20
  51. package/lib/services/command/context.js.map +1 -1
  52. package/lib/services/config/config.js +4 -7
  53. package/lib/services/config/config.js.map +1 -1
  54. package/lib/services/config/env.js +1 -1
  55. package/lib/services/config/env.js.map +1 -1
  56. package/lib/services/filesync/changes.js +76 -37
  57. package/lib/services/filesync/changes.js.map +1 -1
  58. package/lib/services/filesync/conflicts.js +10 -9
  59. package/lib/services/filesync/conflicts.js.map +1 -1
  60. package/lib/services/filesync/directory.js +16 -1
  61. package/lib/services/filesync/directory.js.map +1 -1
  62. package/lib/services/filesync/error.js +96 -27
  63. package/lib/services/filesync/error.js.map +1 -1
  64. package/lib/services/filesync/filesync.js +448 -490
  65. package/lib/services/filesync/filesync.js.map +1 -1
  66. package/lib/services/filesync/hashes.js +8 -5
  67. package/lib/services/filesync/hashes.js.map +1 -1
  68. package/lib/services/filesync/strategy.js +59 -0
  69. package/lib/services/filesync/strategy.js.map +1 -0
  70. package/lib/services/filesync/sync-json.js +475 -0
  71. package/lib/services/filesync/sync-json.js.map +1 -0
  72. package/lib/services/http/auth.js +30 -1
  73. package/lib/services/http/auth.js.map +1 -1
  74. package/lib/services/http/http.js +5 -0
  75. package/lib/services/http/http.js.map +1 -1
  76. package/lib/services/output/confirm.js +149 -0
  77. package/lib/services/output/confirm.js.map +1 -0
  78. package/lib/services/output/footer.js +22 -0
  79. package/lib/services/output/footer.js.map +1 -0
  80. package/lib/services/output/log/format/pretty.js +2 -1
  81. package/lib/services/output/log/format/pretty.js.map +1 -1
  82. package/lib/services/output/log/logger.js +13 -5
  83. package/lib/services/output/log/logger.js.map +1 -1
  84. package/lib/services/output/log/structured.js +2 -2
  85. package/lib/services/output/log/structured.js.map +1 -1
  86. package/lib/services/output/output.js +197 -0
  87. package/lib/services/output/output.js.map +1 -0
  88. package/lib/services/output/print.js +31 -0
  89. package/lib/services/output/print.js.map +1 -0
  90. package/lib/services/output/problems.js +84 -0
  91. package/lib/services/output/problems.js.map +1 -0
  92. package/lib/services/output/prompt.js +173 -40
  93. package/lib/services/output/prompt.js.map +1 -1
  94. package/lib/services/output/report.js +63 -19
  95. package/lib/services/output/report.js.map +1 -1
  96. package/lib/services/output/select.js +198 -0
  97. package/lib/services/output/select.js.map +1 -0
  98. package/lib/services/output/spinner.js +141 -0
  99. package/lib/services/output/spinner.js.map +1 -0
  100. package/lib/services/output/sprint.js +38 -15
  101. package/lib/services/output/sprint.js.map +1 -1
  102. package/lib/services/output/symbols.js +23 -0
  103. package/lib/services/output/symbols.js.map +1 -0
  104. package/lib/services/output/table.js +98 -0
  105. package/lib/services/output/table.js.map +1 -0
  106. package/lib/services/output/timestamp.js +12 -0
  107. package/lib/services/output/timestamp.js.map +1 -0
  108. package/lib/services/output/update.js +29 -9
  109. package/lib/services/output/update.js.map +1 -1
  110. package/lib/services/user/session.js +4 -0
  111. package/lib/services/user/session.js.map +1 -1
  112. package/lib/services/user/user.js +15 -10
  113. package/lib/services/user/user.js.map +1 -1
  114. package/lib/services/util/assert.js +11 -0
  115. package/lib/services/util/assert.js.map +1 -0
  116. package/lib/services/util/boolean.js +2 -2
  117. package/lib/services/util/boolean.js.map +1 -1
  118. package/lib/services/util/function.js +45 -7
  119. package/lib/services/util/function.js.map +1 -1
  120. package/lib/services/util/is.js +23 -2
  121. package/lib/services/util/is.js.map +1 -1
  122. package/lib/services/util/json.js +16 -13
  123. package/lib/services/util/json.js.map +1 -1
  124. package/lib/services/util/object.js +2 -2
  125. package/lib/services/util/object.js.map +1 -1
  126. package/lib/services/util/promise.js +5 -2
  127. package/lib/services/util/promise.js.map +1 -1
  128. package/lib/services/util/types.js.map +1 -1
  129. package/npm-shrinkwrap.json +3415 -2973
  130. package/package.json +47 -40
  131. package/bin/dev.cmd +0 -3
  132. package/bin/dev.js +0 -14
  133. package/bin/run.cmd +0 -3
  134. package/bin/run.js +0 -5
  135. package/lib/commands/sync.js +0 -284
  136. package/lib/commands/sync.js.map +0 -1
  137. package/lib/services/app/edit/client.js.map +0 -1
  138. package/lib/services/app/edit/error.js.map +0 -1
  139. package/lib/services/output/log/printer.js +0 -120
  140. package/lib/services/output/log/printer.js.map +0 -1
  141. package/lib/services/output/stream.js +0 -54
  142. package/lib/services/output/stream.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ import chalk from "chalk";
2
+ import pluralize from "pluralize";
3
+ import { compact } from "../util/collection.js";
4
+ import { isGellyFile, isJavaScriptFile, isTypeScriptFile } from "../util/is.js";
5
+ import { println } from "./print.js";
6
+ import { sprint, sprintln } from "./sprint.js";
7
+ export const ProblemSeverity = Object.freeze({
8
+ Fatal: "Fatal",
9
+ Error: "Error",
10
+ Warning: "Warning",
11
+ Info: "Info"
12
+ });
13
+ export const sprintProblems = ({ problems: groupedProblems, showFileTypes, ...sprintOptions })=>{
14
+ let output = "";
15
+ for (const [name, problems] of Object.entries(groupedProblems)){
16
+ output += sprintln("");
17
+ output += sprintln`• {cyan ${name}} {redBright ${pluralize("problem", problems.length, true)}}`;
18
+ for (const problem of problems){
19
+ const [message, ...lines] = problem.message.split("\n");
20
+ output += sprint` {red ✖} `;
21
+ if (showFileTypes ?? problem.type === "SourceFile") {
22
+ output += sprint`${filetype(name)} `;
23
+ }
24
+ output += sprint(message);
25
+ for (const line of lines){
26
+ output += sprintln("");
27
+ output += sprint` ${line}`;
28
+ }
29
+ for (const label of problem.labels){
30
+ output += sprint` {dim ${label}}`;
31
+ }
32
+ output += sprintln("");
33
+ }
34
+ }
35
+ return sprintln(sprintOptions)(output);
36
+ };
37
+ export const printProblems = (options)=>{
38
+ println(sprintProblems(options));
39
+ };
40
+ export const filetype = (filename)=>{
41
+ switch(true){
42
+ case isJavaScriptFile(filename):
43
+ return chalk.yellowBright("JavaScript");
44
+ case isTypeScriptFile(filename):
45
+ return chalk.blue("TypeScript");
46
+ case isGellyFile(filename):
47
+ return chalk.magenta("Gelly");
48
+ default:
49
+ return chalk.gray("File");
50
+ }
51
+ };
52
+ export const publishIssuesToProblems = (issues)=>{
53
+ const problems = {};
54
+ for (const issue of issues){
55
+ const name = issue.node?.apiIdentifier ?? issue.node?.name ?? "Other";
56
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
57
+ problems[name] ??= [];
58
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
59
+ problems[name].push({
60
+ type: issue.node?.type ?? "Unknown",
61
+ severity: issue.severity,
62
+ message: issue.message,
63
+ labels: compact(issue.nodeLabels?.map((label)=>label?.identifier) ?? [])
64
+ });
65
+ }
66
+ return problems;
67
+ };
68
+ export const filesyncProblemsToProblems = (filesyncProblems)=>{
69
+ const problems = {};
70
+ for (const filesyncProblem of filesyncProblems){
71
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
72
+ problems[filesyncProblem.path] ??= [];
73
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
74
+ problems[filesyncProblem.path].push({
75
+ type: filesyncProblem.type,
76
+ severity: filesyncProblem.level,
77
+ message: filesyncProblem.message,
78
+ labels: []
79
+ });
80
+ }
81
+ return problems;
82
+ };
83
+
84
+ //# sourceMappingURL=problems.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/output/problems.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport pluralize from \"pluralize\";\nimport type { Problem as FileSyncProblem, PublishIssue } from \"../../__generated__/graphql.js\";\nimport { compact } from \"../util/collection.js\";\nimport { isGellyFile, isJavaScriptFile, isTypeScriptFile } from \"../util/is.js\";\nimport { println } from \"./print.js\";\nimport { sprint, sprintln, type SprintOptions } from \"./sprint.js\";\n\nexport type Problems = Record<string, Problem[]>;\n\nexport type Problem = {\n type: string;\n severity: ProblemSeverity;\n message: string;\n labels: string[];\n};\n\nexport const ProblemSeverity = Object.freeze({\n Fatal: \"Fatal\",\n Error: \"Error\",\n Warning: \"Warning\",\n Info: \"Info\",\n});\n\nexport type ProblemSeverity = keyof typeof ProblemSeverity;\n\nexport type PrintProblemsOptions = SprintOptions & {\n /**\n * The problems to print.\n */\n problems: Problems;\n\n /**\n * Whether to show the file type in the output.\n *\n * @default problem.type === \"SourceFile\"\n */\n showFileTypes?: boolean;\n};\n\nexport const sprintProblems = ({ problems: groupedProblems, showFileTypes, ...sprintOptions }: PrintProblemsOptions): string => {\n let output = \"\";\n\n for (const [name, problems] of Object.entries(groupedProblems)) {\n output += sprintln(\"\");\n output += sprintln`• {cyan ${name}} {redBright ${pluralize(\"problem\", problems.length, true)}}`;\n for (const problem of problems) {\n const [message, ...lines] = problem.message.split(\"\\n\") as [string, ...string[]];\n\n output += sprint` {red ✖} `;\n if (showFileTypes ?? problem.type === \"SourceFile\") {\n output += sprint`${filetype(name)} `;\n }\n output += sprint(message);\n\n for (const line of lines) {\n output += sprintln(\"\");\n output += sprint` ${line}`;\n }\n\n for (const label of problem.labels) {\n output += sprint` {dim ${label}}`;\n }\n\n output += sprintln(\"\");\n }\n }\n\n return sprintln(sprintOptions)(output);\n};\n\nexport const printProblems = (options: PrintProblemsOptions): void => {\n println(sprintProblems(options));\n};\n\nexport const filetype = (filename: string): string => {\n switch (true) {\n case isJavaScriptFile(filename):\n return chalk.yellowBright(\"JavaScript\");\n case isTypeScriptFile(filename):\n return chalk.blue(\"TypeScript\");\n case isGellyFile(filename):\n return chalk.magenta(\"Gelly\");\n default:\n return chalk.gray(\"File\");\n }\n};\n\nexport const publishIssuesToProblems = (issues: PublishIssue[]): Problems => {\n const problems: Problems = {};\n for (const issue of issues) {\n const name = issue.node?.apiIdentifier ?? issue.node?.name ?? \"Other\";\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n problems[name] ??= [];\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n problems[name]!.push({\n type: issue.node?.type ?? \"Unknown\",\n severity: issue.severity as ProblemSeverity,\n message: issue.message,\n labels: compact(issue.nodeLabels?.map((label) => label?.identifier) ?? []),\n });\n }\n return problems;\n};\n\nexport const filesyncProblemsToProblems = (filesyncProblems: FileSyncProblem[]): Problems => {\n const problems: Problems = {};\n for (const filesyncProblem of filesyncProblems) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n problems[filesyncProblem.path] ??= [];\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n problems[filesyncProblem.path]!.push({\n type: filesyncProblem.type,\n severity: filesyncProblem.level as ProblemSeverity,\n message: filesyncProblem.message,\n labels: [],\n });\n }\n return problems;\n};\n"],"names":["chalk","pluralize","compact","isGellyFile","isJavaScriptFile","isTypeScriptFile","println","sprint","sprintln","ProblemSeverity","Object","freeze","Fatal","Error","Warning","Info","sprintProblems","problems","groupedProblems","showFileTypes","sprintOptions","output","name","entries","length","problem","message","lines","split","type","filetype","line","label","labels","printProblems","options","filename","yellowBright","blue","magenta","gray","publishIssuesToProblems","issues","issue","node","apiIdentifier","push","severity","nodeLabels","map","identifier","filesyncProblemsToProblems","filesyncProblems","filesyncProblem","path","level"],"mappings":"AAAA,OAAOA,WAAW,QAAQ;AAC1B,OAAOC,eAAe,YAAY;AAElC,SAASC,OAAO,QAAQ,wBAAwB;AAChD,SAASC,WAAW,EAAEC,gBAAgB,EAAEC,gBAAgB,QAAQ,gBAAgB;AAChF,SAASC,OAAO,QAAQ,aAAa;AACrC,SAASC,MAAM,EAAEC,QAAQ,QAA4B,cAAc;AAWnE,OAAO,MAAMC,kBAAkBC,OAAOC,MAAM,CAAC;IAC3CC,OAAO;IACPC,OAAO;IACPC,SAAS;IACTC,MAAM;AACR,GAAG;AAkBH,OAAO,MAAMC,iBAAiB,CAAC,EAAEC,UAAUC,eAAe,EAAEC,aAAa,EAAE,GAAGC,eAAqC;IACjH,IAAIC,SAAS;IAEb,KAAK,MAAM,CAACC,MAAML,SAAS,IAAIP,OAAOa,OAAO,CAACL,iBAAkB;QAC9DG,UAAUb,SAAS;QACnBa,UAAUb,QAAQ,CAAC,QAAQ,EAAEc,KAAK,aAAa,EAAErB,UAAU,WAAWgB,SAASO,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/F,KAAK,MAAMC,WAAWR,SAAU;YAC9B,MAAM,CAACS,SAAS,GAAGC,MAAM,GAAGF,QAAQC,OAAO,CAACE,KAAK,CAAC;YAElDP,UAAUd,MAAM,CAAC,UAAU,CAAC;YAC5B,IAAIY,iBAAiBM,QAAQI,IAAI,KAAK,cAAc;gBAClDR,UAAUd,MAAM,CAAC,EAAEuB,SAASR,MAAM,CAAC,CAAC;YACtC;YACAD,UAAUd,OAAOmB;YAEjB,KAAK,MAAMK,QAAQJ,MAAO;gBACxBN,UAAUb,SAAS;gBACnBa,UAAUd,MAAM,CAAC,IAAI,EAAEwB,KAAK,CAAC;YAC/B;YAEA,KAAK,MAAMC,SAASP,QAAQQ,MAAM,CAAE;gBAClCZ,UAAUd,MAAM,CAAC,MAAM,EAAEyB,MAAM,CAAC,CAAC;YACnC;YAEAX,UAAUb,SAAS;QACrB;IACF;IAEA,OAAOA,SAASY,eAAeC;AACjC,EAAE;AAEF,OAAO,MAAMa,gBAAgB,CAACC;IAC5B7B,QAAQU,eAAemB;AACzB,EAAE;AAEF,OAAO,MAAML,WAAW,CAACM;IACvB,OAAQ;QACN,KAAKhC,iBAAiBgC;YACpB,OAAOpC,MAAMqC,YAAY,CAAC;QAC5B,KAAKhC,iBAAiB+B;YACpB,OAAOpC,MAAMsC,IAAI,CAAC;QACpB,KAAKnC,YAAYiC;YACf,OAAOpC,MAAMuC,OAAO,CAAC;QACvB;YACE,OAAOvC,MAAMwC,IAAI,CAAC;IACtB;AACF,EAAE;AAEF,OAAO,MAAMC,0BAA0B,CAACC;IACtC,MAAMzB,WAAqB,CAAC;IAC5B,KAAK,MAAM0B,SAASD,OAAQ;QAC1B,MAAMpB,OAAOqB,MAAMC,IAAI,EAAEC,iBAAiBF,MAAMC,IAAI,EAAEtB,QAAQ;QAC9D,uEAAuE;QACvEL,QAAQ,CAACK,KAAK,KAAK,EAAE;QACrB,oEAAoE;QACpEL,QAAQ,CAACK,KAAK,CAAEwB,IAAI,CAAC;YACnBjB,MAAMc,MAAMC,IAAI,EAAEf,QAAQ;YAC1BkB,UAAUJ,MAAMI,QAAQ;YACxBrB,SAASiB,MAAMjB,OAAO;YACtBO,QAAQ/B,QAAQyC,MAAMK,UAAU,EAAEC,IAAI,CAACjB,QAAUA,OAAOkB,eAAe,EAAE;QAC3E;IACF;IACA,OAAOjC;AACT,EAAE;AAEF,OAAO,MAAMkC,6BAA6B,CAACC;IACzC,MAAMnC,WAAqB,CAAC;IAC5B,KAAK,MAAMoC,mBAAmBD,iBAAkB;QAC9C,uEAAuE;QACvEnC,QAAQ,CAACoC,gBAAgBC,IAAI,CAAC,KAAK,EAAE;QACrC,oEAAoE;QACpErC,QAAQ,CAACoC,gBAAgBC,IAAI,CAAC,CAAER,IAAI,CAAC;YACnCjB,MAAMwB,gBAAgBxB,IAAI;YAC1BkB,UAAUM,gBAAgBE,KAAK;YAC/B7B,SAAS2B,gBAAgB3B,OAAO;YAChCO,QAAQ,EAAE;QACZ;IACF;IACA,OAAOhB;AACT,EAAE"}
@@ -1,52 +1,185 @@
1
- import prompts from "prompts";
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ import ansiEscapes from "ansi-escapes";
3
+ import assert from "node:assert";
4
+ import EventEmitter from "node:events";
5
+ import process from "node:process";
6
+ import readline from "node:readline";
7
+ import { output } from "./output.js";
2
8
  /**
3
- * Prompts the user to select an option from a list of choices.
9
+ * Inspired by `prompts`:
10
+ * https://github.com/terkelg/prompts/blob/e0519913ec4fcc6746bb3d97d8cd0960c3f3ffde/lib/elements/prompt.js
4
11
  *
5
- * @param ctx - The current context.
6
- * @param options - The options to use.
7
- * @param options.message - The message to display to the user.
8
- * @param options.choices - The list of choices for the user to select from.
9
- * @returns A promise that resolves to the selected option.
10
- */ export const select = async (ctx, { message, choices })=>{
11
- ctx.log.println("");
12
- try {
13
- const response = await prompts({
14
- name: "value",
15
- type: "autocomplete",
16
- message,
17
- choices: choices.map((value)=>({
18
- title: value,
19
- value
20
- }))
12
+ * MIT License
13
+ *
14
+ * Copyright (c) 2018 Terkel Gjervig Nielsen
15
+ *
16
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ * of this software and associated documentation files (the "Software"), to deal
18
+ * in the Software without restriction, including without limitation the rights
19
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ * copies of the Software, and to permit persons to whom the Software is
21
+ * furnished to do so, subject to the following conditions:
22
+ *
23
+ * The above copyright notice and this permission notice shall be included in all
24
+ * copies or substantial portions of the Software.
25
+ *
26
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
+ * SOFTWARE.
33
+ */ export class Prompt extends EventEmitter {
34
+ _(_str, _key) {
35
+ // noop
36
+ }
37
+ onRender() {
38
+ // noop
39
+ }
40
+ fire() {
41
+ this.emit("state", {
42
+ value: this.value,
43
+ aborted: this.aborted,
44
+ exited: this.exited
45
+ });
46
+ }
47
+ bell() {
48
+ output.writeStdout(ansiEscapes.beep);
49
+ }
50
+ render() {
51
+ this.onRender();
52
+ if (this.firstRender) {
53
+ this.firstRender = false;
54
+ }
55
+ }
56
+ constructor(){
57
+ super();
58
+ // state
59
+ _define_property(this, "value", undefined);
60
+ _define_property(this, "firstRender", true);
61
+ _define_property(this, "done", false);
62
+ _define_property(this, "closed", false);
63
+ _define_property(this, "aborted", false);
64
+ _define_property(this, "exited", false);
65
+ // methods that rely on constructor closure
66
+ _define_property(this, "close", void 0);
67
+ assert(!Prompt.active, "only one prompt can be active at a time");
68
+ Prompt.active = true;
69
+ const rl = readline.createInterface({
70
+ input: process.stdin,
71
+ escapeCodeTimeout: 50
21
72
  });
22
- if (!response.value) {
23
- // The user pressed Ctrl+C
24
- process.exit(0);
73
+ readline.emitKeypressEvents(process.stdin, rl);
74
+ if (process.stdin.isTTY) {
75
+ process.stdin.setRawMode(true);
76
+ }
77
+ const isSelect = [
78
+ "SelectPrompt"
79
+ ].includes(this.constructor.name);
80
+ const keypress = (str, key)=>{
81
+ const action = getPromptAction(key, isSelect);
82
+ if (action === false) {
83
+ this._(str, key);
84
+ } else if (action && typeof this[action] === "function") {
85
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
86
+ this[action](key);
87
+ } else {
88
+ this.bell();
89
+ }
90
+ };
91
+ this.close = ()=>{
92
+ process.stdin.removeListener("keypress", keypress);
93
+ if (process.stdin.isTTY) {
94
+ process.stdin.setRawMode(false);
95
+ }
96
+ rl.close();
97
+ this.emit(this.aborted ? "abort" : this.exited ? "exit" : "submit", this.value);
98
+ this.closed = true;
99
+ Prompt.active = false;
100
+ };
101
+ process.stdin.on("keypress", keypress);
102
+ }
103
+ }
104
+ _define_property(Prompt, "active", false);
105
+ const getPromptAction = (key, isSelect)=>{
106
+ if (key.meta && key.name !== "escape") {
107
+ return;
108
+ }
109
+ if (key.ctrl) {
110
+ switch(key.name){
111
+ case "a":
112
+ return "first";
113
+ case "c":
114
+ case "d":
115
+ return "abort";
116
+ case "e":
117
+ return "last";
118
+ case "g":
119
+ return "reset";
25
120
  }
26
- return response.value;
27
- } catch (error) {
28
- process.exit(0);
121
+ }
122
+ if (isSelect) {
123
+ if (key.name === "j") {
124
+ return "down";
125
+ }
126
+ if (key.name === "k") {
127
+ return "up";
128
+ }
129
+ }
130
+ switch(key.name){
131
+ case "return":
132
+ case "enter":
133
+ return "submit";
134
+ case "backspace":
135
+ return "delete";
136
+ case "delete":
137
+ return "deleteForward";
138
+ case "abort":
139
+ return "abort";
140
+ case "escape":
141
+ return "exit";
142
+ case "tab":
143
+ return "next";
144
+ case "pagedown":
145
+ return "nextPage";
146
+ case "pageup":
147
+ return "prevPage";
148
+ case "home":
149
+ return "home";
150
+ case "end":
151
+ return "end";
152
+ case "up":
153
+ return "up";
154
+ case "down":
155
+ return "down";
156
+ case "right":
157
+ return "right";
158
+ case "left":
159
+ return "left";
160
+ default:
161
+ return false;
29
162
  }
30
163
  };
31
164
  /**
32
- * Displays a confirmation prompt with the specified message. If the
33
- * user confirms, the function resolves, otherwise it exits the process.
165
+ * Determine what entries should be displayed on the screen, based on the
166
+ * currently selected index and the maximum visible. Used in list-based
167
+ * prompts like `select` and `multiselect`.
34
168
  *
35
- * @param ctx - The current context.
36
- * @param options - The options to use.
37
- * @param options.message - The message to display in the confirmation prompt.
38
- * @returns A Promise that resolves when the user confirms the prompt.
39
- */ export const confirm = async (ctx, { message })=>{
40
- ctx.log.println("");
41
- const response = await prompts({
42
- name: "value",
43
- type: "confirm",
44
- message
45
- });
46
- if (!response.value) {
47
- // The user pressed Ctrl+C
48
- process.exit(0);
169
+ * @param cursor - the currently selected entry
170
+ * @param total - the total entries available to display
171
+ * @param [maxVisible] - the number of entries that can be displayed
172
+ */ export const entriesToDisplay = (cursor, total, maxVisible)=>{
173
+ maxVisible = maxVisible || total;
174
+ let startIndex = Math.min(total - maxVisible, cursor - Math.floor(maxVisible / 2));
175
+ if (startIndex < 0) {
176
+ startIndex = 0;
49
177
  }
178
+ const endIndex = Math.min(startIndex + maxVisible, total);
179
+ return {
180
+ startIndex,
181
+ endIndex
182
+ };
50
183
  };
51
184
 
52
185
  //# sourceMappingURL=prompt.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/output/prompt.ts"],"sourcesContent":["import prompts from \"prompts\";\nimport type { Context } from \"../command/context.js\";\n\n/**\n * Prompts the user to select an option from a list of choices.\n *\n * @param ctx - The current context.\n * @param options - The options to use.\n * @param options.message - The message to display to the user.\n * @param options.choices - The list of choices for the user to select from.\n * @returns A promise that resolves to the selected option.\n */\nexport const select = async <T extends string>(ctx: Context, { message, choices }: { message: string; choices: T[] }): Promise<T> => {\n ctx.log.println(\"\");\n\n try {\n const response = await prompts({\n name: \"value\",\n type: \"autocomplete\",\n message,\n choices: choices.map((value) => ({ title: value, value })),\n });\n\n if (!response.value) {\n // The user pressed Ctrl+C\n process.exit(0);\n }\n\n return response.value as T;\n } catch (error) {\n process.exit(0);\n }\n};\n\n/**\n * Displays a confirmation prompt with the specified message. If the\n * user confirms, the function resolves, otherwise it exits the process.\n *\n * @param ctx - The current context.\n * @param options - The options to use.\n * @param options.message - The message to display in the confirmation prompt.\n * @returns A Promise that resolves when the user confirms the prompt.\n */\nexport const confirm = async (ctx: Context, { message }: { message: string }): Promise<void> => {\n ctx.log.println(\"\");\n\n const response = await prompts({\n name: \"value\",\n type: \"confirm\",\n message,\n });\n\n if (!response.value) {\n // The user pressed Ctrl+C\n process.exit(0);\n }\n};\n"],"names":["prompts","select","ctx","message","choices","log","println","response","name","type","map","value","title","process","exit","error","confirm"],"mappings":"AAAA,OAAOA,aAAa,UAAU;AAG9B;;;;;;;;CAQC,GACD,OAAO,MAAMC,SAAS,OAAyBC,KAAc,EAAEC,OAAO,EAAEC,OAAO,EAAqC;IAClHF,IAAIG,GAAG,CAACC,OAAO,CAAC;IAEhB,IAAI;QACF,MAAMC,WAAW,MAAMP,QAAQ;YAC7BQ,MAAM;YACNC,MAAM;YACNN;YACAC,SAASA,QAAQM,GAAG,CAAC,CAACC,QAAW,CAAA;oBAAEC,OAAOD;oBAAOA;gBAAM,CAAA;QACzD;QAEA,IAAI,CAACJ,SAASI,KAAK,EAAE;YACnB,0BAA0B;YAC1BE,QAAQC,IAAI,CAAC;QACf;QAEA,OAAOP,SAASI,KAAK;IACvB,EAAE,OAAOI,OAAO;QACdF,QAAQC,IAAI,CAAC;IACf;AACF,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAME,UAAU,OAAOd,KAAc,EAAEC,OAAO,EAAuB;IAC1ED,IAAIG,GAAG,CAACC,OAAO,CAAC;IAEhB,MAAMC,WAAW,MAAMP,QAAQ;QAC7BQ,MAAM;QACNC,MAAM;QACNN;IACF;IAEA,IAAI,CAACI,SAASI,KAAK,EAAE;QACnB,0BAA0B;QAC1BE,QAAQC,IAAI,CAAC;IACf;AACF,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/output/prompt.ts"],"sourcesContent":["import ansiEscapes from \"ansi-escapes\";\nimport assert from \"node:assert\";\nimport EventEmitter from \"node:events\";\nimport process from \"node:process\";\nimport readline from \"node:readline\";\nimport { output } from \"./output.js\";\n\n/**\n * Inspired by `prompts`:\n * https://github.com/terkelg/prompts/blob/e0519913ec4fcc6746bb3d97d8cd0960c3f3ffde/lib/elements/prompt.js\n *\n * MIT License\n *\n * Copyright (c) 2018 Terkel Gjervig Nielsen\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nexport class Prompt extends EventEmitter {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [action: string]: any; // (key: StdinKey) => void;\n\n static active = false;\n\n // state\n value: unknown = undefined;\n firstRender = true;\n done = false;\n closed = false;\n aborted = false;\n exited = false;\n\n // methods that rely on constructor closure\n close: () => void;\n\n constructor() {\n super();\n assert(!Prompt.active, \"only one prompt can be active at a time\");\n Prompt.active = true;\n\n const rl = readline.createInterface({ input: process.stdin, escapeCodeTimeout: 50 });\n readline.emitKeypressEvents(process.stdin, rl);\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n\n const isSelect = [\"SelectPrompt\"].includes(this.constructor.name);\n const keypress = (str: string, key: StdinKey): void => {\n const action = getPromptAction(key, isSelect);\n if (action === false) {\n this._(str, key);\n } else if (action && typeof this[action] === \"function\") {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n this[action](key);\n } else {\n this.bell();\n }\n };\n\n this.close = () => {\n process.stdin.removeListener(\"keypress\", keypress);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n\n rl.close();\n this.emit(this.aborted ? \"abort\" : this.exited ? \"exit\" : \"submit\", this.value);\n this.closed = true;\n Prompt.active = false;\n };\n\n process.stdin.on(\"keypress\", keypress);\n }\n\n _(_str: string, _key: StdinKey): void {\n // noop\n }\n\n onRender(): void {\n // noop\n }\n\n fire(): void {\n this.emit(\"state\", {\n value: this.value,\n aborted: this.aborted,\n exited: this.exited,\n });\n }\n\n bell(): void {\n output.writeStdout(ansiEscapes.beep);\n }\n\n render(): void {\n this.onRender();\n if (this.firstRender) {\n this.firstRender = false;\n }\n }\n}\n\nexport type PromptAction =\n | \"abort\"\n | \"exit\"\n | \"submit\"\n | \"next\"\n | \"nextPage\"\n | \"prevPage\"\n | \"home\"\n | \"end\"\n | \"up\"\n | \"down\"\n | \"right\"\n | \"left\"\n | \"reset\"\n | \"delete\"\n | \"deleteForward\"\n | \"first\"\n | \"last\";\n\nexport type StdinKey = {\n name: string;\n ctrl: boolean;\n meta: boolean;\n};\n\nconst getPromptAction = (key: StdinKey, isSelect: boolean): PromptAction | false | undefined => {\n if (key.meta && key.name !== \"escape\") {\n return;\n }\n\n if (key.ctrl) {\n switch (key.name) {\n case \"a\":\n return \"first\";\n case \"c\":\n case \"d\":\n return \"abort\";\n case \"e\":\n return \"last\";\n case \"g\":\n return \"reset\";\n }\n }\n\n if (isSelect) {\n if (key.name === \"j\") {\n return \"down\";\n }\n if (key.name === \"k\") {\n return \"up\";\n }\n }\n\n switch (key.name) {\n case \"return\":\n case \"enter\":\n return \"submit\";\n case \"backspace\":\n return \"delete\";\n case \"delete\":\n return \"deleteForward\";\n case \"abort\":\n return \"abort\";\n case \"escape\":\n return \"exit\";\n case \"tab\":\n return \"next\";\n case \"pagedown\":\n return \"nextPage\";\n case \"pageup\":\n return \"prevPage\";\n case \"home\":\n return \"home\";\n case \"end\":\n return \"end\";\n case \"up\":\n return \"up\";\n case \"down\":\n return \"down\";\n case \"right\":\n return \"right\";\n case \"left\":\n return \"left\";\n default:\n return false;\n }\n};\n\n/**\n * Determine what entries should be displayed on the screen, based on the\n * currently selected index and the maximum visible. Used in list-based\n * prompts like `select` and `multiselect`.\n *\n * @param cursor - the currently selected entry\n * @param total - the total entries available to display\n * @param [maxVisible] - the number of entries that can be displayed\n */\nexport const entriesToDisplay = (cursor: number, total: number, maxVisible: number): { startIndex: number; endIndex: number } => {\n maxVisible = maxVisible || total;\n\n let startIndex = Math.min(total - maxVisible, cursor - Math.floor(maxVisible / 2));\n if (startIndex < 0) {\n startIndex = 0;\n }\n\n const endIndex = Math.min(startIndex + maxVisible, total);\n\n return { startIndex, endIndex };\n};\n"],"names":["ansiEscapes","assert","EventEmitter","process","readline","output","Prompt","_","_str","_key","onRender","fire","emit","value","aborted","exited","bell","writeStdout","beep","render","firstRender","constructor","undefined","done","closed","close","active","rl","createInterface","input","stdin","escapeCodeTimeout","emitKeypressEvents","isTTY","setRawMode","isSelect","includes","name","keypress","str","key","action","getPromptAction","removeListener","on","meta","ctrl","entriesToDisplay","cursor","total","maxVisible","startIndex","Math","min","floor","endIndex"],"mappings":"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"}
@@ -4,23 +4,32 @@ import cleanStack from "clean-stack";
4
4
  import ms from "ms";
5
5
  import { randomUUID } from "node:crypto";
6
6
  import os from "node:os";
7
+ import terminalLink from "terminal-link";
7
8
  import { config } from "../config/config.js";
8
9
  import { env } from "../config/env.js";
9
- import { parseBoolean } from "../util/boolean.js";
10
+ import { packageJson } from "../config/package-json.js";
11
+ import { isAbortError } from "../util/is.js";
10
12
  import { serializeError } from "../util/object.js";
11
13
  import { workspaceRoot } from "../util/paths.js";
12
- import { sprint } from "./sprint.js";
14
+ import { println } from "./print.js";
15
+ import { sprintln } from "./sprint.js";
13
16
  export const reportErrorAndExit = async (ctx, cause)=>{
17
+ if (isAbortError(cause)) {
18
+ ctx.log.debug("aborting without reporting error", {
19
+ error: cause
20
+ });
21
+ return process.exit(1);
22
+ }
14
23
  ctx.log.error("reporting error and exiting", {
15
24
  error: cause
16
25
  });
17
26
  try {
18
- const error = CLIError.from(cause);
19
- ctx.log.println(error.toString());
27
+ const error = GGTError.from(cause);
28
+ error.print();
20
29
  if (error.isBug === IsBug.NO) {
21
30
  return undefined;
22
31
  }
23
- Sentry.getCurrentHub().captureException(error, {
32
+ Sentry.captureException(error, {
24
33
  event_id: error.id,
25
34
  captureContext: {
26
35
  user: ctx.user && {
@@ -35,7 +44,7 @@ export const reportErrorAndExit = async (ctx, cause)=>{
35
44
  environment: env.value,
36
45
  platform: config.platform,
37
46
  shell: config.shell,
38
- version: config.version
47
+ version: packageJson.version
39
48
  },
40
49
  contexts: {
41
50
  ctx: {
@@ -44,8 +53,8 @@ export const reportErrorAndExit = async (ctx, cause)=>{
44
53
  },
45
54
  cause: error.cause ? serializeError(error.cause) : undefined,
46
55
  app: {
47
- app_name: config.name,
48
- app_version: config.version
56
+ app_name: packageJson.name,
57
+ app_version: packageJson.version
49
58
  },
50
59
  device: {
51
60
  name: os.hostname(),
@@ -68,8 +77,9 @@ export const installErrorHandlers = (ctx)=>{
68
77
  ctx.log.debug("installing error handlers");
69
78
  Sentry.init({
70
79
  dsn: "https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266",
71
- release: config.version,
72
- enabled: env.productionLike && parseBoolean(process.env["GGT_SENTRY_ENABLED"] ?? "true")
80
+ enabled: env.productionLike && ctx.args["--telemetry"],
81
+ release: packageJson.version,
82
+ environment: packageJson.version.includes("experimental") ? "experimental" : "production"
73
83
  });
74
84
  const handleError = (error)=>void reportErrorAndExit(ctx, error);
75
85
  process.once("uncaughtException", handleError);
@@ -82,28 +92,48 @@ export const IsBug = Object.freeze({
82
92
  });
83
93
  /**
84
94
  * Base class for all errors.
85
- */ export class CLIError extends Error {
95
+ */ export class GGTError extends Error {
86
96
  /**
87
- * Constructs a CLIError from an unknown cause.
97
+ * Constructs a GGTError from an unknown cause.
88
98
  *
89
99
  * @param cause - The cause of the error.
90
100
  */ static from(cause) {
91
- if (cause instanceof CLIError) {
101
+ if (cause instanceof GGTError) {
92
102
  return cause;
93
103
  }
94
104
  return new UnexpectedError(cause);
95
105
  }
96
- toString() {
106
+ sprint() {
97
107
  let rendered = this.render();
98
108
  if (this.isBug !== IsBug.NO) {
99
- rendered += "\n\n" + sprint`
100
- ${this.isBug === IsBug.YES ? "This is a bug" : "If you think this is a bug"}, please submit an issue using the link below.
109
+ // ensure the rendered message ends with a newline
110
+ rendered = sprintln(rendered);
111
+ const thisIsABug = this.isBug === IsBug.YES ? "This is a bug" : "If you think this is a bug";
112
+ const issueLink = `https://github.com/gadget-inc/ggt/issues/new?template=bug_report.yml&error-id=${this.id}`;
113
+ if (terminalLink.isSupported) {
114
+ rendered += sprintln({
115
+ ensureEmptyLineAbove: true
116
+ })`
117
+ ${thisIsABug}, ${terminalLink("click here", issueLink)} to create an issue on GitHub.
118
+ `;
119
+ } else {
120
+ rendered += sprintln({
121
+ ensureEmptyLineAbove: true
122
+ })`
123
+ ${thisIsABug}, use the link below to create an issue on GitHub.
101
124
 
102
- https://github.com/gadget-inc/ggt/issues/new?template=bug_report.yml&error-id=${this.id}
125
+ ${issueLink}
103
126
  `;
127
+ }
104
128
  }
105
129
  return rendered;
106
130
  }
131
+ print(options) {
132
+ println({
133
+ ensureEmptyLineAbove: true,
134
+ ...options
135
+ })(this.sprint());
136
+ }
107
137
  constructor(message){
108
138
  super(message);
109
139
  /**
@@ -128,11 +158,11 @@ export const IsBug = Object.freeze({
128
158
  * If this error is thrown, we almost certainly have a bug, and should
129
159
  * either fix it or add a more specific error so that we can provide
130
160
  * more useful information.
131
- */ export class UnexpectedError extends CLIError {
161
+ */ export class UnexpectedError extends GGTError {
132
162
  render() {
133
163
  const serialized = serializeError(this.cause);
134
164
  const body = serialized.stack || serialized.message || this.stack;
135
- return this.message + "\n\n" + body;
165
+ return this.message + ".\n\n" + body;
136
166
  }
137
167
  constructor(cause){
138
168
  super("An unexpected error occurred");
@@ -142,5 +172,19 @@ export const IsBug = Object.freeze({
142
172
  this.isBug = IsBug.YES;
143
173
  }
144
174
  }
175
+ /**
176
+ * An error that is expected to happen sometimes.
177
+ */ export class EdgeCaseError extends GGTError {
178
+ render() {
179
+ return this.message;
180
+ }
181
+ constructor(message, cause){
182
+ super(message);
183
+ _define_property(this, "cause", void 0);
184
+ _define_property(this, "isBug", void 0);
185
+ this.cause = cause;
186
+ this.isBug = IsBug.MAYBE;
187
+ }
188
+ }
145
189
 
146
190
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/output/report.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport cleanStack from \"clean-stack\";\nimport ms from \"ms\";\nimport { randomUUID } from \"node:crypto\";\nimport os from \"node:os\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { env } from \"../config/env.js\";\nimport { parseBoolean } from \"../util/boolean.js\";\nimport { serializeError } from \"../util/object.js\";\nimport { workspaceRoot } from \"../util/paths.js\";\nimport { sprint } from \"./sprint.js\";\n\nexport const reportErrorAndExit = async (ctx: Context, cause: unknown): Promise<never> => {\n ctx.log.error(\"reporting error and exiting\", { error: cause });\n\n try {\n const error = CLIError.from(cause);\n ctx.log.println(error.toString());\n\n if (error.isBug === IsBug.NO) {\n return undefined as never;\n }\n\n Sentry.getCurrentHub().captureException(error, {\n event_id: error.id,\n captureContext: {\n user: ctx.user && {\n id: String(ctx.user.id),\n email: ctx.user.email,\n username: ctx.user.name ?? undefined,\n },\n tags: {\n application_id: ctx.app?.id,\n arch: config.arch,\n bug: error.isBug,\n environment: env.value,\n platform: config.platform,\n shell: config.shell,\n version: config.version,\n },\n contexts: {\n ctx: {\n argv: process.argv,\n args: ctx.args,\n },\n cause: error.cause ? serializeError(error.cause) : undefined,\n app: {\n app_name: config.name,\n app_version: config.version,\n },\n device: {\n name: os.hostname(),\n family: os.type(),\n arch: os.arch(),\n },\n runtime: {\n name: process.release.name,\n version: process.version,\n },\n },\n },\n });\n\n await Sentry.flush(ms(\"2s\"));\n } finally {\n process.exit(1);\n }\n};\n\nexport const installErrorHandlers = (ctx: Context): void => {\n ctx.log.debug(\"installing error handlers\");\n\n Sentry.init({\n dsn: \"https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266\",\n release: config.version,\n enabled: env.productionLike && parseBoolean(process.env[\"GGT_SENTRY_ENABLED\"] ?? \"true\"),\n });\n\n const handleError = (error: unknown) => void reportErrorAndExit(ctx, error);\n process.once(\"uncaughtException\", handleError);\n process.once(\"unhandledRejection\", handleError);\n};\n\nexport const IsBug = Object.freeze({\n YES: \"yes\",\n NO: \"no\",\n MAYBE: \"maybe\",\n});\n\nexport type IsBug = (typeof IsBug)[keyof typeof IsBug];\n\n/**\n * Base class for all errors.\n */\nexport abstract class CLIError extends Error {\n /**\n * The ID for this error.\n */\n id = env.testLike ? \"00000000-0000-0000-0000-000000000000\" : randomUUID();\n\n /**\n * The underlying *thing* that caused this error.\n */\n cause?: unknown;\n\n /**\n * Assume the stack trace exists.\n */\n override stack!: string;\n\n /**\n * Indicates whether this error is considered a bug or not.\n */\n abstract isBug: IsBug;\n\n constructor(message: string) {\n super(message);\n Error.captureStackTrace(this, this.constructor);\n this.stack = cleanStack(this.stack, { pretty: true, basePath: workspaceRoot });\n }\n\n /**\n * Constructs a CLIError from an unknown cause.\n *\n * @param cause - The cause of the error.\n */\n static from(cause: unknown): CLIError {\n if (cause instanceof CLIError) {\n return cause;\n }\n return new UnexpectedError(cause);\n }\n\n override toString(): string {\n let rendered = this.render();\n\n if (this.isBug !== IsBug.NO) {\n rendered +=\n \"\\n\\n\" +\n sprint`\n ${this.isBug === IsBug.YES ? \"This is a bug\" : \"If you think this is a bug\"}, please submit an issue using the link below.\n\n https://github.com/gadget-inc/ggt/issues/new?template=bug_report.yml&error-id=${this.id}\n `;\n }\n\n return rendered;\n }\n\n /**\n * Turns this error into a user-friendly message that explains what\n * went wrong and how to fix it. A good write up of what an error\n * should look like can be found here:\n * {@link https://clig.dev/#errors}\n */\n protected abstract render(): string;\n}\n\n/**\n * Our \"catch all\" error.\n *\n * If this error is thrown, we almost certainly have a bug, and should\n * either fix it or add a more specific error so that we can provide\n * more useful information.\n */\nexport class UnexpectedError extends CLIError {\n isBug = IsBug.YES;\n\n constructor(override cause: unknown) {\n super(\"An unexpected error occurred\");\n }\n\n protected render(): string {\n const serialized = serializeError(this.cause);\n const body = serialized.stack || serialized.message || this.stack;\n return this.message + \"\\n\\n\" + body;\n }\n}\n"],"names":["Sentry","cleanStack","ms","randomUUID","os","config","env","parseBoolean","serializeError","workspaceRoot","sprint","reportErrorAndExit","ctx","cause","log","error","CLIError","from","println","toString","isBug","IsBug","NO","undefined","getCurrentHub","captureException","event_id","id","captureContext","user","String","email","username","name","tags","application_id","app","arch","bug","environment","value","platform","shell","version","contexts","argv","process","args","app_name","app_version","device","hostname","family","type","runtime","release","flush","exit","installErrorHandlers","debug","init","dsn","enabled","productionLike","handleError","once","Object","freeze","YES","MAYBE","Error","UnexpectedError","rendered","render","constructor","message","testLike","stack","captureStackTrace","pretty","basePath","serialized","body"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/services/output/report.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport cleanStack from \"clean-stack\";\nimport ms from \"ms\";\nimport { randomUUID } from \"node:crypto\";\nimport os from \"node:os\";\nimport terminalLink from \"terminal-link\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { env } from \"../config/env.js\";\nimport { packageJson } from \"../config/package-json.js\";\nimport { isAbortError } from \"../util/is.js\";\nimport { serializeError } from \"../util/object.js\";\nimport { workspaceRoot } from \"../util/paths.js\";\nimport { println } from \"./print.js\";\nimport { sprintln, type SprintOptions } from \"./sprint.js\";\n\nexport const reportErrorAndExit = async (ctx: Context, cause: unknown): Promise<never> => {\n if (isAbortError(cause)) {\n ctx.log.debug(\"aborting without reporting error\", { error: cause });\n return process.exit(1);\n }\n\n ctx.log.error(\"reporting error and exiting\", { error: cause });\n\n try {\n const error = GGTError.from(cause);\n error.print();\n\n if (error.isBug === IsBug.NO) {\n return undefined as never;\n }\n\n Sentry.captureException(error, {\n event_id: error.id,\n captureContext: {\n user: ctx.user && {\n id: String(ctx.user.id),\n email: ctx.user.email,\n username: ctx.user.name ?? undefined,\n },\n tags: {\n application_id: ctx.app?.id,\n arch: config.arch,\n bug: error.isBug,\n environment: env.value,\n platform: config.platform,\n shell: config.shell,\n version: packageJson.version,\n },\n contexts: {\n ctx: {\n argv: process.argv,\n args: ctx.args,\n },\n cause: error.cause ? serializeError(error.cause) : undefined,\n app: {\n app_name: packageJson.name,\n app_version: packageJson.version,\n },\n device: {\n name: os.hostname(),\n family: os.type(),\n arch: os.arch(),\n },\n runtime: {\n name: process.release.name,\n version: process.version,\n },\n },\n },\n });\n\n await Sentry.flush(ms(\"2s\"));\n } finally {\n process.exit(1);\n }\n};\n\nexport const installErrorHandlers = (ctx: Context): void => {\n ctx.log.debug(\"installing error handlers\");\n\n Sentry.init({\n dsn: \"https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266\",\n enabled: env.productionLike && ctx.args[\"--telemetry\"],\n release: packageJson.version,\n environment: packageJson.version.includes(\"experimental\") ? \"experimental\" : \"production\",\n });\n\n const handleError = (error: unknown) => void reportErrorAndExit(ctx, error);\n process.once(\"uncaughtException\", handleError);\n process.once(\"unhandledRejection\", handleError);\n};\n\nexport const IsBug = Object.freeze({\n YES: \"yes\",\n NO: \"no\",\n MAYBE: \"maybe\",\n});\n\nexport type IsBug = (typeof IsBug)[keyof typeof IsBug];\n\n/**\n * Base class for all errors.\n */\nexport abstract class GGTError extends Error {\n /**\n * The ID for this error.\n */\n id = env.testLike ? \"00000000-0000-0000-0000-000000000000\" : randomUUID();\n\n /**\n * The underlying *thing* that caused this error.\n */\n cause?: unknown;\n\n /**\n * Assume the stack trace exists.\n */\n override stack!: string;\n\n /**\n * Indicates whether this error is considered a bug or not.\n */\n abstract isBug: IsBug;\n\n constructor(message: string) {\n super(message);\n Error.captureStackTrace(this, this.constructor);\n this.stack = cleanStack(this.stack, { pretty: true, basePath: workspaceRoot });\n }\n\n /**\n * Constructs a GGTError from an unknown cause.\n *\n * @param cause - The cause of the error.\n */\n static from(cause: unknown): GGTError {\n if (cause instanceof GGTError) {\n return cause;\n }\n return new UnexpectedError(cause);\n }\n\n sprint(): string {\n let rendered = this.render();\n\n if (this.isBug !== IsBug.NO) {\n // ensure the rendered message ends with a newline\n rendered = sprintln(rendered);\n\n const thisIsABug = this.isBug === IsBug.YES ? \"This is a bug\" : \"If you think this is a bug\";\n const issueLink = `https://github.com/gadget-inc/ggt/issues/new?template=bug_report.yml&error-id=${this.id}`;\n\n if (terminalLink.isSupported) {\n rendered += sprintln({ ensureEmptyLineAbove: true })`\n ${thisIsABug}, ${terminalLink(\"click here\", issueLink)} to create an issue on GitHub.\n `;\n } else {\n rendered += sprintln({ ensureEmptyLineAbove: true })`\n ${thisIsABug}, use the link below to create an issue on GitHub.\n\n ${issueLink}\n `;\n }\n }\n\n return rendered;\n }\n\n print(options?: SprintOptions): void {\n println({ ensureEmptyLineAbove: true, ...options })(this.sprint());\n }\n\n /**\n * Turns this error into a user-friendly message that explains what\n * went wrong and how to fix it. A good write up of what an error\n * should look like can be found here:\n * {@link https://clig.dev/#errors}\n */\n protected abstract render(): string;\n}\n\n/**\n * Our \"catch all\" error.\n *\n * If this error is thrown, we almost certainly have a bug, and should\n * either fix it or add a more specific error so that we can provide\n * more useful information.\n */\nexport class UnexpectedError extends GGTError {\n isBug = IsBug.YES;\n\n constructor(override cause: unknown) {\n super(\"An unexpected error occurred\");\n }\n\n protected render(): string {\n const serialized = serializeError(this.cause);\n const body = serialized.stack || serialized.message || this.stack;\n return this.message + \".\\n\\n\" + body;\n }\n}\n\n/**\n * An error that is expected to happen sometimes.\n */\nexport class EdgeCaseError extends GGTError {\n isBug = IsBug.MAYBE;\n\n constructor(\n message: string,\n override cause?: unknown,\n ) {\n super(message);\n }\n\n protected render(): string {\n return this.message;\n }\n}\n"],"names":["Sentry","cleanStack","ms","randomUUID","os","terminalLink","config","env","packageJson","isAbortError","serializeError","workspaceRoot","println","sprintln","reportErrorAndExit","ctx","cause","log","debug","error","process","exit","GGTError","from","print","isBug","IsBug","NO","undefined","captureException","event_id","id","captureContext","user","String","email","username","name","tags","application_id","app","arch","bug","environment","value","platform","shell","version","contexts","argv","args","app_name","app_version","device","hostname","family","type","runtime","release","flush","installErrorHandlers","init","dsn","enabled","productionLike","includes","handleError","once","Object","freeze","YES","MAYBE","Error","UnexpectedError","sprint","rendered","render","thisIsABug","issueLink","isSupported","ensureEmptyLineAbove","options","constructor","message","testLike","stack","captureStackTrace","pretty","basePath","serialized","body","EdgeCaseError"],"mappings":"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"}