@gadgetinc/ggt 0.4.7 → 0.4.9

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 (84) hide show
  1. package/README.md +2 -2
  2. package/bin/dev.js +2 -1
  3. package/bin/run.js +3 -1
  4. package/lib/commands/deploy.js +11 -15
  5. package/lib/commands/deploy.js.map +1 -1
  6. package/lib/commands/list.js +7 -11
  7. package/lib/commands/list.js.map +1 -1
  8. package/lib/commands/login.js +8 -12
  9. package/lib/commands/login.js.map +1 -1
  10. package/lib/commands/logout.js +3 -7
  11. package/lib/commands/logout.js.map +1 -1
  12. package/lib/commands/root.js +17 -44
  13. package/lib/commands/root.js.map +1 -1
  14. package/lib/commands/sync.js +10 -29
  15. package/lib/commands/sync.js.map +1 -1
  16. package/lib/commands/version.js +2 -6
  17. package/lib/commands/version.js.map +1 -1
  18. package/lib/commands/whoami.js +5 -9
  19. package/lib/commands/whoami.js.map +1 -1
  20. package/lib/ggt.js +40 -0
  21. package/lib/ggt.js.map +1 -0
  22. package/lib/services/app/app.js +8 -6
  23. package/lib/services/app/app.js.map +1 -1
  24. package/lib/services/app/edit/client.js +176 -0
  25. package/lib/services/app/edit/client.js.map +1 -0
  26. package/lib/services/app/edit/edit.js +155 -0
  27. package/lib/services/app/edit/edit.js.map +1 -0
  28. package/lib/services/app/edit/error.js +65 -0
  29. package/lib/services/app/edit/error.js.map +1 -0
  30. package/lib/services/app/edit/operation.js +87 -0
  31. package/lib/services/app/edit/operation.js.map +1 -0
  32. package/lib/services/command/arg.js +5 -5
  33. package/lib/services/command/arg.js.map +1 -1
  34. package/lib/services/command/command.js +21 -7
  35. package/lib/services/command/command.js.map +1 -1
  36. package/lib/services/command/context.js +108 -56
  37. package/lib/services/command/context.js.map +1 -1
  38. package/lib/services/filesync/changes.js +7 -9
  39. package/lib/services/filesync/changes.js.map +1 -1
  40. package/lib/services/filesync/conflicts.js +11 -9
  41. package/lib/services/filesync/conflicts.js.map +1 -1
  42. package/lib/services/filesync/directory.js +2 -2
  43. package/lib/services/filesync/directory.js.map +1 -1
  44. package/lib/services/filesync/filesync.js +73 -43
  45. package/lib/services/filesync/filesync.js.map +1 -1
  46. package/lib/services/filesync/hashes.js +18 -15
  47. package/lib/services/filesync/hashes.js.map +1 -1
  48. package/lib/services/http/auth.js +4 -4
  49. package/lib/services/http/auth.js.map +1 -1
  50. package/lib/services/http/http.js +83 -23
  51. package/lib/services/http/http.js.map +1 -1
  52. package/lib/services/output/log/logger.js +11 -6
  53. package/lib/services/output/log/logger.js.map +1 -1
  54. package/lib/services/output/log/printer.js.map +1 -1
  55. package/lib/services/output/log/structured.js +2 -2
  56. package/lib/services/output/log/structured.js.map +1 -1
  57. package/lib/services/output/notify.js +3 -7
  58. package/lib/services/output/notify.js.map +1 -1
  59. package/lib/services/output/prompt.js +11 -11
  60. package/lib/services/output/prompt.js.map +1 -1
  61. package/lib/services/output/report.js +51 -67
  62. package/lib/services/output/report.js.map +1 -1
  63. package/lib/services/output/update.js +9 -10
  64. package/lib/services/output/update.js.map +1 -1
  65. package/lib/services/user/user.js +19 -25
  66. package/lib/services/user/user.js.map +1 -1
  67. package/lib/services/util/collection.js +1 -1
  68. package/lib/services/util/collection.js.map +1 -1
  69. package/lib/services/util/function.js +29 -11
  70. package/lib/services/util/function.js.map +1 -1
  71. package/lib/services/util/number.js +3 -3
  72. package/lib/services/util/number.js.map +1 -1
  73. package/lib/services/util/object.js +4 -4
  74. package/lib/services/util/object.js.map +1 -1
  75. package/lib/services/util/paths.js +4 -4
  76. package/lib/services/util/paths.js.map +1 -1
  77. package/lib/services/util/types.js +3 -1
  78. package/lib/services/util/types.js.map +1 -1
  79. package/npm-shrinkwrap.json +579 -411
  80. package/package.json +15 -14
  81. package/lib/main.js +0 -8
  82. package/lib/main.js.map +0 -1
  83. package/lib/services/app/edit-graphql.js +0 -392
  84. package/lib/services/app/edit-graphql.js.map +0 -1
package/README.md CHANGED
@@ -52,7 +52,7 @@ With this running in the background, your local `~/gadget/my-app` folder will be
52
52
  ## Usage
53
53
 
54
54
  ```sh-session
55
- $ npm install -g @gadgetinc/ggt
55
+ $ npm install -g ggt
56
56
  $ ggt
57
57
  The command-line interface for Gadget
58
58
 
@@ -226,5 +226,5 @@ USAGE
226
226
 
227
227
  EXAMPLE
228
228
  $ ggt version
229
- 0.4.7
229
+ 0.4.9
230
230
  ```
package/bin/dev.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node --loader @swc-node/register/esm --no-warnings
2
2
 
3
3
  import process from "node:process";
4
+ import { ggt } from "../src/ggt.js";
4
5
  import { workspacePath } from "../src/services/util/paths.js";
5
6
 
6
7
  process.env["NODE_ENV"] ??= "development";
@@ -10,4 +11,4 @@ process.env["GGT_CONFIG_DIR"] ??= workspacePath("tmp/config");
10
11
  process.env["GGT_CACHE_DIR"] ??= workspacePath("tmp/cache");
11
12
  process.env["GGT_DATA_DIR"] ??= workspacePath("tmp/data");
12
13
 
13
- await import("../src/main.js");
14
+ await ggt();
package/bin/run.js CHANGED
@@ -1,3 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import "../lib/main.js";
3
+ import { ggt } from "../lib/ggt.js";
4
+
5
+ await ggt();
@@ -1,10 +1,9 @@
1
1
  import chalk from "chalk";
2
2
  import ora from "ora";
3
- import { REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION } from "../services/app/edit-graphql.js";
3
+ import { REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION } from "../services/app/edit/operation.js";
4
4
  import { FileSync, FileSyncArgs } from "../services/filesync/filesync.js";
5
5
  import { select } from "../services/output/prompt.js";
6
6
  import { sprint } from "../services/output/sprint.js";
7
- import { getUserOrLogin } from "../services/user/user.js";
8
7
  import { isCloseEvent, isGraphQLErrors } from "../services/util/is.js";
9
8
  export const usage = ()=>sprint`
10
9
  Deploy your Gadget application's development source code to production.
@@ -105,15 +104,12 @@ var AppDeploymentSteps;
105
104
  const spinner = ora();
106
105
  let prevProgress = AppDeploymentStepsToAppDeployState("NOT_STARTED");
107
106
  let action;
108
- const filesync = await FileSync.init({
109
- // deploy --force != sync --force
110
- ctx: ctx.clone({
111
- args: {
112
- "--force": false
113
- }
114
- }),
115
- user: await getUserOrLogin()
116
- });
107
+ // deploy --force != sync --force
108
+ const filesync = await FileSync.init(ctx.child({
109
+ overwrite: {
110
+ "--force": false
111
+ }
112
+ }));
117
113
  if (firstRun) {
118
114
  ctx.log.printlns`App: ${filesync.app.slug}`;
119
115
  }
@@ -122,7 +118,7 @@ var AppDeploymentSteps;
122
118
  ctx.log.printlns`
123
119
  Local files have diverged from remote. Run a sync once to converge your files or keep {italic ggt sync} running in the background.
124
120
  `;
125
- action = await select({
121
+ action = await select(ctx, {
126
122
  message: "How would you like to proceed?",
127
123
  choices: [
128
124
  "Cancel (Ctrl+C)",
@@ -142,8 +138,8 @@ var AppDeploymentSteps;
142
138
  }
143
139
  }
144
140
  // subscribes to the graphql subscription that will listen and send back the server contract status
145
- const unsubscribe = filesync.editGraphQL.subscribe({
146
- query: REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION,
141
+ const unsubscribe = filesync.edit.subscribe({
142
+ subscription: REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION,
147
143
  variables: ()=>({
148
144
  localFilesVersion: String(filesync.filesVersion),
149
145
  force: ctx.args["--force"]
@@ -183,7 +179,7 @@ var AppDeploymentSteps;
183
179
  }
184
180
  if (!ctx.args["--force"]) {
185
181
  unsubscribe();
186
- action = await select({
182
+ action = await select(ctx, {
187
183
  message: "Detected some issues with your app. How would you like to proceed?",
188
184
  choices: [
189
185
  "Cancel (Ctrl+C)",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION } from \"../services/app/edit-graphql.js\";\nimport type { ArgsSpec } from \"../services/command/arg.js\";\nimport { type Command, type Usage } from \"../services/command/command.js\";\nimport { FileSync, FileSyncArgs } from \"../services/filesync/filesync.js\";\nimport { select } from \"../services/output/prompt.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUserOrLogin } from \"../services/user/user.js\";\nimport { isCloseEvent, isGraphQLErrors } from \"../services/util/is.js\";\n\nexport const usage: Usage = () => sprint`\n Deploy your Gadget application's development source code to production.\n\n {bold USAGE}\n ggt deploy [DIRECTORY] [--app=<name>]\n\n {bold ARGUMENTS}\n DIRECTORY The directory to sync files to and deploy (default: \".\")\n\n {bold FLAGS}\n -a, --app=<name> The Gadget application to deploy\n --force Deploy the Gadget application regardless of any issues it may have\n\n {bold DESCRIPTION}\n Deploy allows you to deploy your current Gadget application in development to production.\n\n It detects if local files are up to date with remote and if the Gadget application\n is in a deployable state. If there are any issues, it will display them and ask if\n you would like to deploy anyways.\n\n Note:\n • If local files are not up to date or have not recently been synced with remote ones,\n you will be prompted to run a one-time sync to ensure the files remain consistent with\n what is on the remote.\n • You may wish to keep ggt sync running in the background before trying to run ggt deploy\n\n {bold EXAMPLE}\n $ ggt deploy ~/gadget/example --app example\n\n App example\n Editor https://example.gadget.app/edit\n Playground https://example.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/example\n\n Endpoints\n • https://example.gadget.app\n • https://example--development.gadget.app\n\n\n Building frontend assets ...\n ✔ DONE\n\n Setting up database ...\n ✔ DONE\n\n Copying development ...\n ✔ DONE\n\n Restarting app ...\n ✔ DONE\n\n Deploy completed. Good bye!\n`;\n\nexport const args = {\n ...FileSyncArgs,\n} satisfies ArgsSpec;\n\nexport enum Action {\n DEPLOY_ANYWAYS = \"Deploy anyways\",\n SYNC_ONCE = \"Sync once\",\n CANCEL = \"Cancel (Ctrl+C)\",\n}\n\nconst AppDeploymentStepsToAppDeployState = (step: string | undefined): string => {\n switch (step) {\n case \"NOT_STARTED\":\n return \"Deploy not started\";\n case \"STARTING\":\n case \"BUILDING_ASSETS\":\n case \"UPLOADING_ASSETS\":\n return \"Building frontend assets\";\n case \"CONVERGING_STORAGE\":\n return \"Setting up database\";\n case \"PUBLISHING_TREE\":\n return \"Copying development\";\n case \"RELOADING_SANDBOX\":\n return \"Restarting app\";\n case \"COMPLETED\":\n return \"Deploy completed\";\n default:\n return \"Unknown step\";\n }\n};\n\nenum AppDeploymentSteps {\n NOT_STARTED = \"NOT_STARTED\",\n STARTING = \"STARTING\",\n BUILDING_ASSETS = \"BUILDING_ASSETS\",\n UPLOADING_ASSETS = \"UPLOADING_ASSETS\",\n CONVERGING_STORAGE = \"CONVERGING_STORAGE\",\n PUBLISHING_TREE = \"PUBLISHING_TREE\",\n RELOADING_SANDBOX = \"RELOADING_SANDBOX\",\n COMPLETED = \"COMPLETED\",\n}\n\n/**\n * Runs the deploy process.\n */\n\nexport const command = (async (ctx, firstRun = true) => {\n const spinner = ora();\n let prevProgress: string | undefined = AppDeploymentStepsToAppDeployState(\"NOT_STARTED\");\n let action: Action;\n\n const filesync = await FileSync.init({\n // deploy --force != sync --force\n ctx: ctx.clone({ args: { \"--force\": false } }),\n user: await getUserOrLogin(),\n });\n\n if (firstRun) {\n ctx.log.printlns`App: ${filesync.app.slug}`;\n }\n\n const { inSync } = await filesync.hashes();\n if (!inSync) {\n ctx.log.printlns`\n Local files have diverged from remote. Run a sync once to converge your files or keep {italic ggt sync} running in the background.\n `;\n\n action = await select({\n message: \"How would you like to proceed?\",\n choices: [Action.CANCEL, Action.SYNC_ONCE],\n });\n\n switch (action) {\n case Action.SYNC_ONCE: {\n await filesync.sync();\n\n break;\n }\n case Action.CANCEL: {\n process.exit(0);\n }\n }\n }\n\n // subscribes to the graphql subscription that will listen and send back the server contract status\n const unsubscribe = filesync.editGraphQL.subscribe({\n query: REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION,\n variables: () => ({ localFilesVersion: String(filesync.filesVersion), force: ctx.args[\"--force\"] }),\n onError: (error) => {\n if (isCloseEvent(error.cause)) {\n spinner.fail(\"Failed\");\n ctx.log.printlns(error.message);\n } else if (isGraphQLErrors(error.cause)) {\n const message = error.cause[0]?.message;\n if (message && message.includes(\"GGT_PAYMENT_REQUIRED\")) {\n ctx.log.println(\"Production environment limit reached. Upgrade your plan to deploy\");\n } else {\n ctx.log.println(`${message}`);\n }\n }\n ctx.log.error(\"failed to deploy\", { error });\n unsubscribe();\n return;\n },\n onData: async ({ publishStatus }): Promise<void> => {\n const { progress, issues } = publishStatus ?? {};\n\n const hasIssues = issues?.length;\n\n if (firstRun && hasIssues) {\n ctx.log.printlns`{underline Issues detected}`;\n\n for (const issue of issues) {\n const message = issue.message.replace(/\"/g, \"\");\n const nodeType = issue.node?.type;\n const nodeName = issue.node?.apiIdentifier ?? issue.node?.name;\n const nodeParent = issue.node?.parentApiIdentifier;\n\n ctx.log.printlns(\n `\n • ${message}\n ${nodeType ? `${nodeType}: ${chalk.cyan(nodeName)}` : \"\"} ${\n nodeParent ? `ParentResource: ${chalk.cyan(nodeParent)}` : \"\"\n }\n `.trim(),\n );\n }\n\n if (!ctx.args[\"--force\"]) {\n unsubscribe();\n\n action = await select({\n message: \"Detected some issues with your app. How would you like to proceed?\",\n choices: [Action.CANCEL, Action.DEPLOY_ANYWAYS],\n });\n\n switch (action) {\n case Action.DEPLOY_ANYWAYS: {\n ctx.args[\"--force\"] = true;\n await command(ctx, false);\n break;\n }\n case Action.CANCEL: {\n process.exit(0);\n }\n }\n }\n\n firstRun = false;\n } else {\n if (progress === AppDeploymentSteps.COMPLETED) {\n spinner.succeed(\"DONE\");\n ctx.log.printlns(\"Deploy completed. Good bye!\");\n unsubscribe();\n return;\n }\n\n const currentProgress = AppDeploymentStepsToAppDeployState(progress);\n\n if (progress && currentProgress !== prevProgress) {\n if ((progress as AppDeploymentSteps) !== AppDeploymentSteps.STARTING) {\n spinner.succeed(\"DONE\");\n }\n\n prevProgress = currentProgress;\n ctx.log.printlns(`${currentProgress} ...`);\n spinner.start(\"Working ...\");\n }\n }\n },\n });\n}) satisfies Command<typeof args>;\n"],"names":["chalk","ora","REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION","FileSync","FileSyncArgs","select","sprint","getUserOrLogin","isCloseEvent","isGraphQLErrors","usage","args","Action","AppDeploymentStepsToAppDeployState","step","AppDeploymentSteps","command","ctx","firstRun","spinner","prevProgress","action","filesync","init","clone","user","log","printlns","app","slug","inSync","hashes","message","choices","sync","process","exit","unsubscribe","editGraphQL","subscribe","query","variables","localFilesVersion","String","filesVersion","force","onError","error","cause","fail","includes","println","onData","publishStatus","progress","issues","hasIssues","length","issue","replace","nodeType","node","type","nodeName","apiIdentifier","name","nodeParent","parentApiIdentifier","cyan","trim","succeed","currentProgress","start"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION } from \"../services/app/edit/operation.js\";\nimport type { ArgsDefinition } from \"../services/command/arg.js\";\nimport { type Command, type Usage } from \"../services/command/command.js\";\nimport { FileSync, FileSyncArgs } from \"../services/filesync/filesync.js\";\nimport { select } from \"../services/output/prompt.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { isCloseEvent, isGraphQLErrors } from \"../services/util/is.js\";\n\nexport const usage: Usage = () => sprint`\n Deploy your Gadget application's development source code to production.\n\n {bold USAGE}\n ggt deploy [DIRECTORY] [--app=<name>]\n\n {bold ARGUMENTS}\n DIRECTORY The directory to sync files to and deploy (default: \".\")\n\n {bold FLAGS}\n -a, --app=<name> The Gadget application to deploy\n --force Deploy the Gadget application regardless of any issues it may have\n\n {bold DESCRIPTION}\n Deploy allows you to deploy your current Gadget application in development to production.\n\n It detects if local files are up to date with remote and if the Gadget application\n is in a deployable state. If there are any issues, it will display them and ask if\n you would like to deploy anyways.\n\n Note:\n • If local files are not up to date or have not recently been synced with remote ones,\n you will be prompted to run a one-time sync to ensure the files remain consistent with\n what is on the remote.\n • You may wish to keep ggt sync running in the background before trying to run ggt deploy\n\n {bold EXAMPLE}\n $ ggt deploy ~/gadget/example --app example\n\n App example\n Editor https://example.gadget.app/edit\n Playground https://example.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/example\n\n Endpoints\n • https://example.gadget.app\n • https://example--development.gadget.app\n\n\n Building frontend assets ...\n ✔ DONE\n\n Setting up database ...\n ✔ DONE\n\n Copying development ...\n ✔ DONE\n\n Restarting app ...\n ✔ DONE\n\n Deploy completed. Good bye!\n`;\n\nexport const args = {\n ...FileSyncArgs,\n} satisfies ArgsDefinition;\n\nexport enum Action {\n DEPLOY_ANYWAYS = \"Deploy anyways\",\n SYNC_ONCE = \"Sync once\",\n CANCEL = \"Cancel (Ctrl+C)\",\n}\n\nconst AppDeploymentStepsToAppDeployState = (step: string | undefined): string => {\n switch (step) {\n case \"NOT_STARTED\":\n return \"Deploy not started\";\n case \"STARTING\":\n case \"BUILDING_ASSETS\":\n case \"UPLOADING_ASSETS\":\n return \"Building frontend assets\";\n case \"CONVERGING_STORAGE\":\n return \"Setting up database\";\n case \"PUBLISHING_TREE\":\n return \"Copying development\";\n case \"RELOADING_SANDBOX\":\n return \"Restarting app\";\n case \"COMPLETED\":\n return \"Deploy completed\";\n default:\n return \"Unknown step\";\n }\n};\n\nenum AppDeploymentSteps {\n NOT_STARTED = \"NOT_STARTED\",\n STARTING = \"STARTING\",\n BUILDING_ASSETS = \"BUILDING_ASSETS\",\n UPLOADING_ASSETS = \"UPLOADING_ASSETS\",\n CONVERGING_STORAGE = \"CONVERGING_STORAGE\",\n PUBLISHING_TREE = \"PUBLISHING_TREE\",\n RELOADING_SANDBOX = \"RELOADING_SANDBOX\",\n COMPLETED = \"COMPLETED\",\n}\n\n/**\n * Runs the deploy process.\n */\nexport const command = (async (ctx, firstRun = true) => {\n const spinner = ora();\n let prevProgress: string | undefined = AppDeploymentStepsToAppDeployState(\"NOT_STARTED\");\n let action: Action;\n\n // deploy --force != sync --force\n const filesync = await FileSync.init(ctx.child({ overwrite: { \"--force\": false } }));\n\n if (firstRun) {\n ctx.log.printlns`App: ${filesync.app.slug}`;\n }\n\n const { inSync } = await filesync.hashes();\n if (!inSync) {\n ctx.log.printlns`\n Local files have diverged from remote. Run a sync once to converge your files or keep {italic ggt sync} running in the background.\n `;\n\n action = await select(ctx, {\n message: \"How would you like to proceed?\",\n choices: [Action.CANCEL, Action.SYNC_ONCE],\n });\n\n switch (action) {\n case Action.SYNC_ONCE: {\n await filesync.sync();\n\n break;\n }\n case Action.CANCEL: {\n process.exit(0);\n }\n }\n }\n\n // subscribes to the graphql subscription that will listen and send back the server contract status\n const unsubscribe = filesync.edit.subscribe({\n subscription: REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION,\n variables: () => ({ localFilesVersion: String(filesync.filesVersion), force: ctx.args[\"--force\"] }),\n onError: (error) => {\n if (isCloseEvent(error.cause)) {\n spinner.fail(\"Failed\");\n ctx.log.printlns(error.message);\n } else if (isGraphQLErrors(error.cause)) {\n const message = error.cause[0]?.message;\n if (message && message.includes(\"GGT_PAYMENT_REQUIRED\")) {\n ctx.log.println(\"Production environment limit reached. Upgrade your plan to deploy\");\n } else {\n ctx.log.println(`${message}`);\n }\n }\n ctx.log.error(\"failed to deploy\", { error });\n unsubscribe();\n return;\n },\n onData: async ({ publishStatus }): Promise<void> => {\n const { progress, issues } = publishStatus ?? {};\n\n const hasIssues = issues?.length;\n\n if (firstRun && hasIssues) {\n ctx.log.printlns`{underline Issues detected}`;\n\n for (const issue of issues) {\n const message = issue.message.replace(/\"/g, \"\");\n const nodeType = issue.node?.type;\n const nodeName = issue.node?.apiIdentifier ?? issue.node?.name;\n const nodeParent = issue.node?.parentApiIdentifier;\n\n ctx.log.printlns(\n `\n • ${message}\n ${nodeType ? `${nodeType}: ${chalk.cyan(nodeName)}` : \"\"} ${\n nodeParent ? `ParentResource: ${chalk.cyan(nodeParent)}` : \"\"\n }\n `.trim(),\n );\n }\n\n if (!ctx.args[\"--force\"]) {\n unsubscribe();\n\n action = await select(ctx, {\n message: \"Detected some issues with your app. How would you like to proceed?\",\n choices: [Action.CANCEL, Action.DEPLOY_ANYWAYS],\n });\n\n switch (action) {\n case Action.DEPLOY_ANYWAYS: {\n ctx.args[\"--force\"] = true;\n await command(ctx, false);\n break;\n }\n case Action.CANCEL: {\n process.exit(0);\n }\n }\n }\n\n firstRun = false;\n } else {\n if (progress === AppDeploymentSteps.COMPLETED) {\n spinner.succeed(\"DONE\");\n ctx.log.printlns(\"Deploy completed. Good bye!\");\n unsubscribe();\n return;\n }\n\n const currentProgress = AppDeploymentStepsToAppDeployState(progress);\n\n if (progress && currentProgress !== prevProgress) {\n if ((progress as AppDeploymentSteps) !== AppDeploymentSteps.STARTING) {\n spinner.succeed(\"DONE\");\n }\n\n prevProgress = currentProgress;\n ctx.log.printlns(`${currentProgress} ...`);\n spinner.start(\"Working ...\");\n }\n }\n },\n });\n}) satisfies Command<typeof args>;\n"],"names":["chalk","ora","REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION","FileSync","FileSyncArgs","select","sprint","isCloseEvent","isGraphQLErrors","usage","args","Action","AppDeploymentStepsToAppDeployState","step","AppDeploymentSteps","command","ctx","firstRun","spinner","prevProgress","action","filesync","init","child","overwrite","log","printlns","app","slug","inSync","hashes","message","choices","sync","process","exit","unsubscribe","edit","subscribe","subscription","variables","localFilesVersion","String","filesVersion","force","onError","error","cause","fail","includes","println","onData","publishStatus","progress","issues","hasIssues","length","issue","replace","nodeType","node","type","nodeName","apiIdentifier","name","nodeParent","parentApiIdentifier","cyan","trim","succeed","currentProgress","start"],"mappings":"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"}
@@ -1,10 +1,6 @@
1
1
  import { getApps } from "../services/app/app.js";
2
- import { createLogger } from "../services/output/log/logger.js";
3
2
  import { sprint } from "../services/output/sprint.js";
4
3
  import { getUserOrLogin } from "../services/user/user.js";
5
- const log = createLogger({
6
- name: "list"
7
- });
8
4
  export const usage = ()=>sprint`
9
5
  List the apps available to the currently logged in user.
10
6
 
@@ -19,11 +15,11 @@ export const usage = ()=>sprint`
19
15
  example example.gadget.app
20
16
  test test.gadget.app
21
17
  `;
22
- export const command = async ()=>{
23
- const user = await getUserOrLogin();
24
- const apps = await getApps(user);
18
+ export const command = async (ctx)=>{
19
+ await getUserOrLogin(ctx);
20
+ const apps = await getApps(ctx);
25
21
  if (apps.length === 0) {
26
- log.println`
22
+ ctx.log.println`
27
23
  It doesn't look like you have any applications.
28
24
 
29
25
  Visit https://gadget.new to create one!
@@ -36,10 +32,10 @@ export const command = async ()=>{
36
32
  longestSlug = Math.max(longestSlug, app.slug.length);
37
33
  longestDomain = Math.max(longestDomain, app.primaryDomain.length);
38
34
  }
39
- log.println`{bold Slug}${" ".repeat(longestSlug - 4)} {bold Domain}`;
40
- log.println`${"─".repeat(Math.max(longestSlug, 4))} ${"─".repeat(Math.max(longestDomain, 6))}`;
35
+ ctx.log.println`{bold Slug}${" ".repeat(longestSlug - 4)} {bold Domain}`;
36
+ ctx.log.println`${"─".repeat(Math.max(longestSlug, 4))} ${"─".repeat(Math.max(longestDomain, 6))}`;
41
37
  for (const app of apps.sort((a, b)=>a.slug.localeCompare(b.slug))){
42
- log.println`${app.slug}${" ".repeat(longestSlug - app.slug.length)} ${app.primaryDomain}`;
38
+ ctx.log.println`${app.slug}${" ".repeat(longestSlug - app.slug.length)} ${app.primaryDomain}`;
43
39
  }
44
40
  };
45
41
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/list.ts"],"sourcesContent":["import { getApps } from \"../services/app/app.js\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport { createLogger } from \"../services/output/log/logger.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUserOrLogin } from \"../services/user/user.js\";\n\nconst log = createLogger({ name: \"list\" });\n\nexport const usage: Usage = () => sprint`\n List the apps available to the currently logged in user.\n\n {bold USAGE}\n ggt list\n\n {bold EXAMPLE}\n $ ggt list\n Slug Domain\n ─────── ──────────────────\n my-app my-app.gadget.app\n example example.gadget.app\n test test.gadget.app\n`;\n\nexport const command: Command = async () => {\n const user = await getUserOrLogin();\n\n const apps = await getApps(user);\n if (apps.length === 0) {\n log.println`\n It doesn't look like you have any applications.\n\n Visit https://gadget.new to create one!\n `;\n return;\n }\n\n let longestSlug = 0;\n let longestDomain = 0;\n\n for (const app of apps) {\n longestSlug = Math.max(longestSlug, app.slug.length);\n longestDomain = Math.max(longestDomain, app.primaryDomain.length);\n }\n\n log.println`{bold Slug}${\" \".repeat(longestSlug - 4)} {bold Domain}`;\n log.println`${\"─\".repeat(Math.max(longestSlug, 4))} ${\"─\".repeat(Math.max(longestDomain, 6))}`;\n for (const app of apps.sort((a, b) => a.slug.localeCompare(b.slug))) {\n log.println`${app.slug}${\" \".repeat(longestSlug - app.slug.length)} ${app.primaryDomain}`;\n }\n};\n"],"names":["getApps","createLogger","sprint","getUserOrLogin","log","name","usage","command","user","apps","length","println","longestSlug","longestDomain","app","Math","max","slug","primaryDomain","repeat","sort","a","b","localeCompare"],"mappings":"AAAA,SAASA,OAAO,QAAQ,yBAAyB;AAEjD,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,cAAc,QAAQ,2BAA2B;AAE1D,MAAMC,MAAMH,aAAa;IAAEI,MAAM;AAAO;AAExC,OAAO,MAAMC,QAAe,IAAMJ,MAAM,CAAC;;;;;;;;;;;;;AAazC,CAAC,CAAC;AAEF,OAAO,MAAMK,UAAmB;IAC9B,MAAMC,OAAO,MAAML;IAEnB,MAAMM,OAAO,MAAMT,QAAQQ;IAC3B,IAAIC,KAAKC,MAAM,KAAK,GAAG;QACrBN,IAAIO,OAAO,CAAC;;;;IAIZ,CAAC;QACD;IACF;IAEA,IAAIC,cAAc;IAClB,IAAIC,gBAAgB;IAEpB,KAAK,MAAMC,OAAOL,KAAM;QACtBG,cAAcG,KAAKC,GAAG,CAACJ,aAAaE,IAAIG,IAAI,CAACP,MAAM;QACnDG,gBAAgBE,KAAKC,GAAG,CAACH,eAAeC,IAAII,aAAa,CAACR,MAAM;IAClE;IAEAN,IAAIO,OAAO,CAAC,WAAW,EAAE,IAAIQ,MAAM,CAACP,cAAc,GAAG,cAAc,CAAC;IACpER,IAAIO,OAAO,CAAC,EAAE,IAAIQ,MAAM,CAACJ,KAAKC,GAAG,CAACJ,aAAa,IAAI,CAAC,EAAE,IAAIO,MAAM,CAACJ,KAAKC,GAAG,CAACH,eAAe,IAAI,CAAC;IAC9F,KAAK,MAAMC,OAAOL,KAAKW,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEJ,IAAI,CAACM,aAAa,CAACD,EAAEL,IAAI,GAAI;QACnEb,IAAIO,OAAO,CAAC,EAAEG,IAAIG,IAAI,CAAC,EAAE,IAAIE,MAAM,CAACP,cAAcE,IAAIG,IAAI,CAACP,MAAM,EAAE,CAAC,EAAEI,IAAII,aAAa,CAAC,CAAC;IAC3F;AACF,EAAE"}
1
+ {"version":3,"sources":["../../src/commands/list.ts"],"sourcesContent":["import { getApps } from \"../services/app/app.js\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUserOrLogin } from \"../services/user/user.js\";\n\nexport const usage: Usage = () => sprint`\n List the apps available to the currently logged in user.\n\n {bold USAGE}\n ggt list\n\n {bold EXAMPLE}\n $ ggt list\n Slug Domain\n ─────── ──────────────────\n my-app my-app.gadget.app\n example example.gadget.app\n test test.gadget.app\n`;\n\nexport const command: Command = async (ctx) => {\n await getUserOrLogin(ctx);\n\n const apps = await getApps(ctx);\n if (apps.length === 0) {\n ctx.log.println`\n It doesn't look like you have any applications.\n\n Visit https://gadget.new to create one!\n `;\n return;\n }\n\n let longestSlug = 0;\n let longestDomain = 0;\n\n for (const app of apps) {\n longestSlug = Math.max(longestSlug, app.slug.length);\n longestDomain = Math.max(longestDomain, app.primaryDomain.length);\n }\n\n ctx.log.println`{bold Slug}${\" \".repeat(longestSlug - 4)} {bold Domain}`;\n ctx.log.println`${\"─\".repeat(Math.max(longestSlug, 4))} ${\"─\".repeat(Math.max(longestDomain, 6))}`;\n for (const app of apps.sort((a, b) => a.slug.localeCompare(b.slug))) {\n ctx.log.println`${app.slug}${\" \".repeat(longestSlug - app.slug.length)} ${app.primaryDomain}`;\n }\n};\n"],"names":["getApps","sprint","getUserOrLogin","usage","command","ctx","apps","length","log","println","longestSlug","longestDomain","app","Math","max","slug","primaryDomain","repeat","sort","a","b","localeCompare"],"mappings":"AAAA,SAASA,OAAO,QAAQ,yBAAyB;AAEjD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,cAAc,QAAQ,2BAA2B;AAE1D,OAAO,MAAMC,QAAe,IAAMF,MAAM,CAAC;;;;;;;;;;;;;AAazC,CAAC,CAAC;AAEF,OAAO,MAAMG,UAAmB,OAAOC;IACrC,MAAMH,eAAeG;IAErB,MAAMC,OAAO,MAAMN,QAAQK;IAC3B,IAAIC,KAAKC,MAAM,KAAK,GAAG;QACrBF,IAAIG,GAAG,CAACC,OAAO,CAAC;;;;IAIhB,CAAC;QACD;IACF;IAEA,IAAIC,cAAc;IAClB,IAAIC,gBAAgB;IAEpB,KAAK,MAAMC,OAAON,KAAM;QACtBI,cAAcG,KAAKC,GAAG,CAACJ,aAAaE,IAAIG,IAAI,CAACR,MAAM;QACnDI,gBAAgBE,KAAKC,GAAG,CAACH,eAAeC,IAAII,aAAa,CAACT,MAAM;IAClE;IAEAF,IAAIG,GAAG,CAACC,OAAO,CAAC,WAAW,EAAE,IAAIQ,MAAM,CAACP,cAAc,GAAG,cAAc,CAAC;IACxEL,IAAIG,GAAG,CAACC,OAAO,CAAC,EAAE,IAAIQ,MAAM,CAACJ,KAAKC,GAAG,CAACJ,aAAa,IAAI,CAAC,EAAE,IAAIO,MAAM,CAACJ,KAAKC,GAAG,CAACH,eAAe,IAAI,CAAC;IAClG,KAAK,MAAMC,OAAON,KAAKY,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEJ,IAAI,CAACM,aAAa,CAACD,EAAEL,IAAI,GAAI;QACnEV,IAAIG,GAAG,CAACC,OAAO,CAAC,EAAEG,IAAIG,IAAI,CAAC,EAAE,IAAIE,MAAM,CAACP,cAAcE,IAAIG,IAAI,CAACR,MAAM,EAAE,CAAC,EAAEK,IAAII,aAAa,CAAC,CAAC;IAC/F;AACF,EAAE"}
@@ -3,13 +3,9 @@ import assert from "node:assert";
3
3
  import http from "node:http";
4
4
  import open from "open";
5
5
  import { config } from "../services/config/config.js";
6
- import { createLogger } from "../services/output/log/logger.js";
7
6
  import { sprint } from "../services/output/sprint.js";
8
7
  import { writeSession } from "../services/user/session.js";
9
8
  import { getUser } from "../services/user/user.js";
10
- const log = createLogger({
11
- name: "login"
12
- });
13
9
  export const usage = ()=>sprint`
14
10
  Log in to your account.
15
11
 
@@ -24,7 +20,7 @@ export const usage = ()=>sprint`
24
20
 
25
21
  Hello, Jane Doe (jane@example.com)
26
22
  `;
27
- export const login = async ()=>{
23
+ export const login = async (ctx)=>{
28
24
  let server;
29
25
  try {
30
26
  const port = await getPort();
@@ -37,12 +33,12 @@ export const login = async ()=>{
37
33
  const session = new URL(req.url, `http://localhost:${port}`).searchParams.get("session");
38
34
  assert(session, "missing session");
39
35
  writeSession(session);
40
- const user = await getUser();
36
+ const user = await getUser(ctx);
41
37
  assert(user, "missing user after successful login");
42
38
  if (user.name) {
43
- log.printlns`Hello, ${user.name} {gray (${user.email})}`;
39
+ ctx.log.printlns`Hello, ${user.name} {gray (${user.email})}`;
44
40
  } else {
45
- log.printlns`Hello, ${user.email}`;
41
+ ctx.log.printlns`Hello, ${user.email}`;
46
42
  }
47
43
  landingPage.searchParams.set("success", "true");
48
44
  resolve();
@@ -57,7 +53,7 @@ export const login = async ()=>{
57
53
  res.end();
58
54
  }
59
55
  });
60
- log.info("starting login server", {
56
+ ctx.log.info("starting login server", {
61
57
  port
62
58
  });
63
59
  server.listen(port);
@@ -69,16 +65,16 @@ export const login = async ()=>{
69
65
  url.searchParams.set("returnTo", `https://${config.domains.services}/auth/cli/callback?port=${port}`);
70
66
  try {
71
67
  await open(url.toString());
72
- log.printlns`
68
+ ctx.log.printlns`
73
69
  We've opened Gadget's login page using your default browser.
74
70
 
75
71
  Please log in and then return to this terminal.
76
72
  `;
77
73
  } catch (error) {
78
- log.error("failed to open browser", {
74
+ ctx.log.error("failed to open browser", {
79
75
  error
80
76
  });
81
- log.printlns`
77
+ ctx.log.printlns`
82
78
  Please open the following URL in your browser and log in:
83
79
 
84
80
  {gray ${url.toString()}}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import getPort from \"get-port\";\nimport assert from \"node:assert\";\nimport http, { type Server } from \"node:http\";\nimport open from \"open\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport { config } from \"../services/config/config.js\";\nimport { createLogger } from \"../services/output/log/logger.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { writeSession } from \"../services/user/session.js\";\nimport { getUser } from \"../services/user/user.js\";\n\nconst log = createLogger({ name: \"login\" });\n\nexport const usage: Usage = () => sprint`\n Log in to your account.\n\n {bold USAGE}\n ggt login\n\n {bold EXAMPLE}\n $ ggt login\n We've opened Gadget's login page using your default browser.\n\n Please log in and then return to this terminal.\n\n Hello, Jane Doe (jane@example.com)\n`;\n\nexport const login = async (): Promise<void> => {\n let server: Server | undefined;\n\n try {\n const port = await getPort();\n const receiveSession = new Promise<void>((resolve, reject) => {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n server = http.createServer(async (req, res) => {\n const landingPage = new URL(`https://${config.domains.services}/auth/cli`);\n\n try {\n assert(req.url, \"missing url\");\n const session = new URL(req.url, `http://localhost:${port}`).searchParams.get(\"session\");\n assert(session, \"missing session\");\n\n writeSession(session);\n\n const user = await getUser();\n assert(user, \"missing user after successful login\");\n\n if (user.name) {\n log.printlns`Hello, ${user.name} {gray (${user.email})}`;\n } else {\n log.printlns`Hello, ${user.email}`;\n }\n\n landingPage.searchParams.set(\"success\", \"true\");\n resolve();\n } catch (error) {\n writeSession(undefined);\n landingPage.searchParams.set(\"success\", \"false\");\n reject(error);\n } finally {\n res.writeHead(303, { Location: landingPage.toString() });\n res.end();\n }\n });\n\n log.info(\"starting login server\", { port });\n server.listen(port);\n });\n\n // open the login page in the user's default browser have it\n // redirect to the cli callback route. The cli callback route will\n // send the session to the server we just started.\n const url = new URL(`https://${config.domains.services}/auth/login`);\n url.searchParams.set(\"returnTo\", `https://${config.domains.services}/auth/cli/callback?port=${port}`);\n\n try {\n await open(url.toString());\n log.printlns`\n We've opened Gadget's login page using your default browser.\n\n Please log in and then return to this terminal.\n `;\n } catch (error) {\n log.error(\"failed to open browser\", { error });\n log.printlns`\n Please open the following URL in your browser and log in:\n\n {gray ${url.toString()}}\n\n Once logged in, return to this terminal.\n `;\n }\n\n await receiveSession;\n } finally {\n server?.close();\n }\n};\n\nexport const command: Command = login;\n"],"names":["getPort","assert","http","open","config","createLogger","sprint","writeSession","getUser","log","name","usage","login","server","port","receiveSession","Promise","resolve","reject","createServer","req","res","landingPage","URL","domains","services","url","session","searchParams","get","user","printlns","email","set","error","undefined","writeHead","Location","toString","end","info","listen","close","command"],"mappings":"AAAA,OAAOA,aAAa,WAAW;AAC/B,OAAOC,YAAY,cAAc;AACjC,OAAOC,UAA2B,YAAY;AAC9C,OAAOC,UAAU,OAAO;AAExB,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,8BAA8B;AAC3D,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,MAAMC,MAAMJ,aAAa;IAAEK,MAAM;AAAQ;AAEzC,OAAO,MAAMC,QAAe,IAAML,MAAM,CAAC;;;;;;;;;;;;;AAazC,CAAC,CAAC;AAEF,OAAO,MAAMM,QAAQ;IACnB,IAAIC;IAEJ,IAAI;QACF,MAAMC,OAAO,MAAMd;QACnB,MAAMe,iBAAiB,IAAIC,QAAc,CAACC,SAASC;YACjD,kEAAkE;YAClEL,SAASX,KAAKiB,YAAY,CAAC,OAAOC,KAAKC;gBACrC,MAAMC,cAAc,IAAIC,IAAI,CAAC,QAAQ,EAAEnB,OAAOoB,OAAO,CAACC,QAAQ,CAAC,SAAS,CAAC;gBAEzE,IAAI;oBACFxB,OAAOmB,IAAIM,GAAG,EAAE;oBAChB,MAAMC,UAAU,IAAIJ,IAAIH,IAAIM,GAAG,EAAE,CAAC,iBAAiB,EAAEZ,KAAK,CAAC,EAAEc,YAAY,CAACC,GAAG,CAAC;oBAC9E5B,OAAO0B,SAAS;oBAEhBpB,aAAaoB;oBAEb,MAAMG,OAAO,MAAMtB;oBACnBP,OAAO6B,MAAM;oBAEb,IAAIA,KAAKpB,IAAI,EAAE;wBACbD,IAAIsB,QAAQ,CAAC,OAAO,EAAED,KAAKpB,IAAI,CAAC,QAAQ,EAAEoB,KAAKE,KAAK,CAAC,EAAE,CAAC;oBAC1D,OAAO;wBACLvB,IAAIsB,QAAQ,CAAC,OAAO,EAAED,KAAKE,KAAK,CAAC,CAAC;oBACpC;oBAEAV,YAAYM,YAAY,CAACK,GAAG,CAAC,WAAW;oBACxChB;gBACF,EAAE,OAAOiB,OAAO;oBACd3B,aAAa4B;oBACbb,YAAYM,YAAY,CAACK,GAAG,CAAC,WAAW;oBACxCf,OAAOgB;gBACT,SAAU;oBACRb,IAAIe,SAAS,CAAC,KAAK;wBAAEC,UAAUf,YAAYgB,QAAQ;oBAAG;oBACtDjB,IAAIkB,GAAG;gBACT;YACF;YAEA9B,IAAI+B,IAAI,CAAC,yBAAyB;gBAAE1B;YAAK;YACzCD,OAAO4B,MAAM,CAAC3B;QAChB;QAEA,4DAA4D;QAC5D,kEAAkE;QAClE,kDAAkD;QAClD,MAAMY,MAAM,IAAIH,IAAI,CAAC,QAAQ,EAAEnB,OAAOoB,OAAO,CAACC,QAAQ,CAAC,WAAW,CAAC;QACnEC,IAAIE,YAAY,CAACK,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE7B,OAAOoB,OAAO,CAACC,QAAQ,CAAC,wBAAwB,EAAEX,KAAK,CAAC;QAEpG,IAAI;YACF,MAAMX,KAAKuB,IAAIY,QAAQ;YACvB7B,IAAIsB,QAAQ,CAAC;;;;IAIf,CAAC;QACD,EAAE,OAAOG,OAAO;YACdzB,IAAIyB,KAAK,CAAC,0BAA0B;gBAAEA;YAAM;YAC5CzB,IAAIsB,QAAQ,CAAC;;;gBAGH,EAAEL,IAAIY,QAAQ,GAAG;;;MAG3B,CAAC;QACH;QAEA,MAAMvB;IACR,SAAU;QACRF,QAAQ6B;IACV;AACF,EAAE;AAEF,OAAO,MAAMC,UAAmB/B,MAAM"}
1
+ {"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import getPort from \"get-port\";\nimport assert from \"node:assert\";\nimport http, { type Server } from \"node:http\";\nimport open from \"open\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport { config } from \"../services/config/config.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { writeSession } from \"../services/user/session.js\";\nimport { getUser } from \"../services/user/user.js\";\n\nexport const usage: Usage = () => sprint`\n Log in to your account.\n\n {bold USAGE}\n ggt login\n\n {bold EXAMPLE}\n $ ggt login\n We've opened Gadget's login page using your default browser.\n\n Please log in and then return to this terminal.\n\n Hello, Jane Doe (jane@example.com)\n`;\n\nexport const login: Command = async (ctx): Promise<void> => {\n let server: Server | undefined;\n\n try {\n const port = await getPort();\n const receiveSession = new Promise<void>((resolve, reject) => {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n server = http.createServer(async (req, res) => {\n const landingPage = new URL(`https://${config.domains.services}/auth/cli`);\n\n try {\n assert(req.url, \"missing url\");\n const session = new URL(req.url, `http://localhost:${port}`).searchParams.get(\"session\");\n assert(session, \"missing session\");\n\n writeSession(session);\n\n const user = await getUser(ctx);\n assert(user, \"missing user after successful login\");\n\n if (user.name) {\n ctx.log.printlns`Hello, ${user.name} {gray (${user.email})}`;\n } else {\n ctx.log.printlns`Hello, ${user.email}`;\n }\n\n landingPage.searchParams.set(\"success\", \"true\");\n resolve();\n } catch (error) {\n writeSession(undefined);\n landingPage.searchParams.set(\"success\", \"false\");\n reject(error);\n } finally {\n res.writeHead(303, { Location: landingPage.toString() });\n res.end();\n }\n });\n\n ctx.log.info(\"starting login server\", { port });\n server.listen(port);\n });\n\n // open the login page in the user's default browser have it\n // redirect to the cli callback route. The cli callback route will\n // send the session to the server we just started.\n const url = new URL(`https://${config.domains.services}/auth/login`);\n url.searchParams.set(\"returnTo\", `https://${config.domains.services}/auth/cli/callback?port=${port}`);\n\n try {\n await open(url.toString());\n ctx.log.printlns`\n We've opened Gadget's login page using your default browser.\n\n Please log in and then return to this terminal.\n `;\n } catch (error) {\n ctx.log.error(\"failed to open browser\", { error });\n ctx.log.printlns`\n Please open the following URL in your browser and log in:\n\n {gray ${url.toString()}}\n\n Once logged in, return to this terminal.\n `;\n }\n\n await receiveSession;\n } finally {\n server?.close();\n }\n};\n\nexport const command = login;\n"],"names":["getPort","assert","http","open","config","sprint","writeSession","getUser","usage","login","ctx","server","port","receiveSession","Promise","resolve","reject","createServer","req","res","landingPage","URL","domains","services","url","session","searchParams","get","user","name","log","printlns","email","set","error","undefined","writeHead","Location","toString","end","info","listen","close","command"],"mappings":"AAAA,OAAOA,aAAa,WAAW;AAC/B,OAAOC,YAAY,cAAc;AACjC,OAAOC,UAA2B,YAAY;AAC9C,OAAOC,UAAU,OAAO;AAExB,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,8BAA8B;AAC3D,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;;;;;;;;;AAazC,CAAC,CAAC;AAEF,OAAO,MAAMI,QAAiB,OAAOC;IACnC,IAAIC;IAEJ,IAAI;QACF,MAAMC,OAAO,MAAMZ;QACnB,MAAMa,iBAAiB,IAAIC,QAAc,CAACC,SAASC;YACjD,kEAAkE;YAClEL,SAAST,KAAKe,YAAY,CAAC,OAAOC,KAAKC;gBACrC,MAAMC,cAAc,IAAIC,IAAI,CAAC,QAAQ,EAAEjB,OAAOkB,OAAO,CAACC,QAAQ,CAAC,SAAS,CAAC;gBAEzE,IAAI;oBACFtB,OAAOiB,IAAIM,GAAG,EAAE;oBAChB,MAAMC,UAAU,IAAIJ,IAAIH,IAAIM,GAAG,EAAE,CAAC,iBAAiB,EAAEZ,KAAK,CAAC,EAAEc,YAAY,CAACC,GAAG,CAAC;oBAC9E1B,OAAOwB,SAAS;oBAEhBnB,aAAamB;oBAEb,MAAMG,OAAO,MAAMrB,QAAQG;oBAC3BT,OAAO2B,MAAM;oBAEb,IAAIA,KAAKC,IAAI,EAAE;wBACbnB,IAAIoB,GAAG,CAACC,QAAQ,CAAC,OAAO,EAAEH,KAAKC,IAAI,CAAC,QAAQ,EAAED,KAAKI,KAAK,CAAC,EAAE,CAAC;oBAC9D,OAAO;wBACLtB,IAAIoB,GAAG,CAACC,QAAQ,CAAC,OAAO,EAAEH,KAAKI,KAAK,CAAC,CAAC;oBACxC;oBAEAZ,YAAYM,YAAY,CAACO,GAAG,CAAC,WAAW;oBACxClB;gBACF,EAAE,OAAOmB,OAAO;oBACd5B,aAAa6B;oBACbf,YAAYM,YAAY,CAACO,GAAG,CAAC,WAAW;oBACxCjB,OAAOkB;gBACT,SAAU;oBACRf,IAAIiB,SAAS,CAAC,KAAK;wBAAEC,UAAUjB,YAAYkB,QAAQ;oBAAG;oBACtDnB,IAAIoB,GAAG;gBACT;YACF;YAEA7B,IAAIoB,GAAG,CAACU,IAAI,CAAC,yBAAyB;gBAAE5B;YAAK;YAC7CD,OAAO8B,MAAM,CAAC7B;QAChB;QAEA,4DAA4D;QAC5D,kEAAkE;QAClE,kDAAkD;QAClD,MAAMY,MAAM,IAAIH,IAAI,CAAC,QAAQ,EAAEjB,OAAOkB,OAAO,CAACC,QAAQ,CAAC,WAAW,CAAC;QACnEC,IAAIE,YAAY,CAACO,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE7B,OAAOkB,OAAO,CAACC,QAAQ,CAAC,wBAAwB,EAAEX,KAAK,CAAC;QAEpG,IAAI;YACF,MAAMT,KAAKqB,IAAIc,QAAQ;YACvB5B,IAAIoB,GAAG,CAACC,QAAQ,CAAC;;;;IAInB,CAAC;QACD,EAAE,OAAOG,OAAO;YACdxB,IAAIoB,GAAG,CAACI,KAAK,CAAC,0BAA0B;gBAAEA;YAAM;YAChDxB,IAAIoB,GAAG,CAACC,QAAQ,CAAC;;;gBAGP,EAAEP,IAAIc,QAAQ,GAAG;;;MAG3B,CAAC;QACH;QAEA,MAAMzB;IACR,SAAU;QACRF,QAAQ+B;IACV;AACF,EAAE;AAEF,OAAO,MAAMC,UAAUlC,MAAM"}
@@ -1,9 +1,5 @@
1
- import { createLogger } from "../services/output/log/logger.js";
2
1
  import { sprint } from "../services/output/sprint.js";
3
2
  import { readSession, writeSession } from "../services/user/session.js";
4
- const log = createLogger({
5
- name: "logout"
6
- });
7
3
  export const usage = ()=>sprint`
8
4
  Log out of your account.
9
5
 
@@ -14,13 +10,13 @@ export const usage = ()=>sprint`
14
10
  $ ggt logout
15
11
  Goodbye
16
12
  `;
17
- export const command = ()=>{
13
+ export const command = (ctx)=>{
18
14
  const token = readSession();
19
15
  if (token) {
20
16
  writeSession(undefined);
21
- log.println("Goodbye");
17
+ ctx.log.println("Goodbye");
22
18
  } else {
23
- log.println("You are not logged in");
19
+ ctx.log.println("You are not logged in");
24
20
  }
25
21
  };
26
22
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/logout.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { createLogger } from \"../services/output/log/logger.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { readSession, writeSession } from \"../services/user/session.js\";\n\nconst log = createLogger({ name: \"logout\" });\n\nexport const usage: Usage = () => sprint`\n Log out of your account.\n\n {bold USAGE}\n ggt logout\n\n {bold EXAMPLE}\n $ ggt logout\n Goodbye\n`;\n\nexport const command: Command = () => {\n const token = readSession();\n if (token) {\n writeSession(undefined);\n log.println(\"Goodbye\");\n } else {\n log.println(\"You are not logged in\");\n }\n};\n"],"names":["createLogger","sprint","readSession","writeSession","log","name","usage","command","token","undefined","println"],"mappings":"AACA,SAASA,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,WAAW,EAAEC,YAAY,QAAQ,8BAA8B;AAExE,MAAMC,MAAMJ,aAAa;IAAEK,MAAM;AAAS;AAE1C,OAAO,MAAMC,QAAe,IAAML,MAAM,CAAC;;;;;;;;;AASzC,CAAC,CAAC;AAEF,OAAO,MAAMM,UAAmB;IAC9B,MAAMC,QAAQN;IACd,IAAIM,OAAO;QACTL,aAAaM;QACbL,IAAIM,OAAO,CAAC;IACd,OAAO;QACLN,IAAIM,OAAO,CAAC;IACd;AACF,EAAE"}
1
+ {"version":3,"sources":["../../src/commands/logout.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { readSession, writeSession } from \"../services/user/session.js\";\n\nexport const usage: Usage = () => sprint`\n Log out of your account.\n\n {bold USAGE}\n ggt logout\n\n {bold EXAMPLE}\n $ ggt logout\n Goodbye\n`;\n\nexport const command: Command = (ctx) => {\n const token = readSession();\n if (token) {\n writeSession(undefined);\n ctx.log.println(\"Goodbye\");\n } else {\n ctx.log.println(\"You are not logged in\");\n }\n};\n"],"names":["sprint","readSession","writeSession","usage","command","ctx","token","undefined","log","println"],"mappings":"AACA,SAASA,MAAM,QAAQ,+BAA+B;AACtD,SAASC,WAAW,EAAEC,YAAY,QAAQ,8BAA8B;AAExE,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;;;;;AASzC,CAAC,CAAC;AAEF,OAAO,MAAMI,UAAmB,CAACC;IAC/B,MAAMC,QAAQL;IACd,IAAIK,OAAO;QACTJ,aAAaK;QACbF,IAAIG,GAAG,CAACC,OAAO,CAAC;IAClB,OAAO;QACLJ,IAAIG,GAAG,CAACC,OAAO,CAAC;IAClB;AACF,EAAE"}
@@ -1,18 +1,12 @@
1
1
  import arg from "arg";
2
- import ms from "ms";
3
- import { AvailableCommands, importCommand, isAvailableCommand } from "../services/command/command.js";
4
- import { Context } from "../services/command/context.js";
2
+ import { Commands, importCommand, isAvailableCommand } from "../services/command/command.js";
5
3
  import { verbosityToLevel } from "../services/output/log/level.js";
6
- import { createLogger } from "../services/output/log/logger.js";
7
4
  import { reportErrorAndExit } from "../services/output/report.js";
8
5
  import { sprint } from "../services/output/sprint.js";
9
6
  import { warnIfUpdateAvailable } from "../services/output/update.js";
10
7
  import { sortBySimilar } from "../services/util/collection.js";
11
8
  import { isNil } from "../services/util/is.js";
12
- const log = createLogger({
13
- name: "root"
14
- });
15
- export const rootUsage = ()=>sprint`
9
+ export const usage = ()=>sprint`
16
10
  The command-line interface for Gadget
17
11
 
18
12
  {bold USAGE}
@@ -33,7 +27,7 @@ export const rootUsage = ()=>sprint`
33
27
 
34
28
  For more information on a specific command, use 'ggt [COMMAND] --help'
35
29
  `;
36
- export const rootArgs = {
30
+ export const args = {
37
31
  "--help": {
38
32
  type: Boolean,
39
33
  alias: "-h"
@@ -49,27 +43,28 @@ export const rootArgs = {
49
43
  type: Boolean
50
44
  }
51
45
  };
52
- export const command = async ()=>{
53
- const ctx = Context.init({
54
- args: rootArgs,
46
+ export const command = async (parent)=>{
47
+ const ctx = parent.child({
48
+ name: "root",
49
+ parse: args,
55
50
  argv: process.argv.slice(2),
56
51
  permissive: true
57
52
  });
58
- await warnIfUpdateAvailable();
59
53
  if (ctx.args["--json"]) {
60
54
  process.env["GGT_LOG_FORMAT"] = "json";
61
55
  }
62
56
  if (ctx.args["--verbose"]) {
63
57
  process.env["GGT_LOG_LEVEL"] = verbosityToLevel(ctx.args["--verbose"]).toString();
64
58
  }
59
+ await warnIfUpdateAvailable(ctx);
65
60
  const cmd = ctx.args._.shift();
66
61
  if (isNil(cmd)) {
67
- log.println(rootUsage());
62
+ ctx.log.println(usage());
68
63
  process.exit(0);
69
64
  }
70
65
  if (!isAvailableCommand(cmd)) {
71
- const [closest] = sortBySimilar(cmd, AvailableCommands);
72
- log.println`
66
+ const [closest] = sortBySimilar(cmd, Commands);
67
+ ctx.log.println`
73
68
  Unknown command {yellow ${cmd}}
74
69
 
75
70
  Did you mean {blueBright ${closest}}?
@@ -78,40 +73,18 @@ export const command = async ()=>{
78
73
  `;
79
74
  process.exit(1);
80
75
  }
81
- const { usage, command, args = {} } = await importCommand(cmd);
76
+ const subcommand = await importCommand(cmd);
82
77
  if (ctx.args["--help"]) {
83
- log.println(usage());
78
+ ctx.log.println(subcommand.usage());
84
79
  process.exit(0);
85
80
  }
86
81
  try {
87
- await command(ctx.extend({
88
- args,
89
- name: cmd
82
+ await subcommand.command(ctx.child({
83
+ name: cmd,
84
+ parse: subcommand.args
90
85
  }));
91
86
  } catch (error) {
92
- await reportErrorAndExit(error);
93
- }
94
- for (const signal of [
95
- "SIGINT",
96
- "SIGTERM"
97
- ]){
98
- process.once(signal, ()=>{
99
- log.trace("received signal", {
100
- signal
101
- });
102
- log.println` Stopping... {gray Press Ctrl+C again to force}`;
103
- ctx.abort();
104
- // when ggt is run via npx, and the user presses ctrl+c, npx
105
- // sends sigint twice in quick succession. in order to prevent
106
- // the second sigint from triggering the force exit listener,
107
- // we wait a bit before registering it
108
- setTimeout(()=>{
109
- process.once(signal, ()=>{
110
- log.println(" Exiting immediately");
111
- process.exit(1);
112
- });
113
- }, ms("100ms")).unref();
114
- });
87
+ await reportErrorAndExit(ctx, error);
115
88
  }
116
89
  };
117
90
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/root.ts"],"sourcesContent":["import arg from \"arg\";\nimport ms from \"ms\";\nimport type { ArgsSpec } from \"../services/command/arg.js\";\nimport { AvailableCommands, importCommand, isAvailableCommand, type Usage } from \"../services/command/command.js\";\nimport { Context } from \"../services/command/context.js\";\nimport { verbosityToLevel } from \"../services/output/log/level.js\";\nimport { createLogger } from \"../services/output/log/logger.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { warnIfUpdateAvailable } from \"../services/output/update.js\";\nimport { sortBySimilar } from \"../services/util/collection.js\";\nimport { isNil } from \"../services/util/is.js\";\n\nconst log = createLogger({ name: \"root\" });\n\nexport const rootUsage: Usage = () => sprint`\n The command-line interface for Gadget\n\n {bold USAGE}\n ggt [COMMAND]\n\n {bold COMMANDS}\n sync Sync your Gadget application's source code\n list List your apps\n login Log in to your account\n logout Log out of your account\n whoami Print the currently logged in account\n version Print the version of ggt\n\n {bold FLAGS}\n -h, --help Print command's usage\n -v, --verbose Print verbose output\n --json Print output as JSON\n\n For more information on a specific command, use 'ggt [COMMAND] --help'\n`;\n\nexport const rootArgs = {\n \"--help\": { type: Boolean, alias: \"-h\" },\n \"--verbose\": { type: arg.COUNT, alias: [\"-v\", \"--debug\"] },\n \"--json\": { type: Boolean },\n} satisfies ArgsSpec;\n\nexport type RootArgs = typeof rootArgs;\n\nexport const command = async (): Promise<void> => {\n const ctx = Context.init({ args: rootArgs, argv: process.argv.slice(2), permissive: true });\n\n await warnIfUpdateAvailable();\n\n if (ctx.args[\"--json\"]) {\n process.env[\"GGT_LOG_FORMAT\"] = \"json\";\n }\n\n if (ctx.args[\"--verbose\"]) {\n process.env[\"GGT_LOG_LEVEL\"] = verbosityToLevel(ctx.args[\"--verbose\"]).toString();\n }\n\n const cmd = ctx.args._.shift();\n if (isNil(cmd)) {\n log.println(rootUsage());\n process.exit(0);\n }\n\n if (!isAvailableCommand(cmd)) {\n const [closest] = sortBySimilar(cmd, AvailableCommands);\n log.println`\n Unknown command {yellow ${cmd}}\n\n Did you mean {blueBright ${closest}}?\n\n Run {gray ggt --help} for usage\n `;\n process.exit(1);\n }\n\n const { usage, command, args = {} } = await importCommand(cmd);\n\n if (ctx.args[\"--help\"]) {\n log.println(usage());\n process.exit(0);\n }\n\n try {\n await command(ctx.extend({ args, name: cmd }));\n } catch (error) {\n await reportErrorAndExit(error);\n }\n\n for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) {\n process.once(signal, () => {\n log.trace(\"received signal\", { signal });\n log.println` Stopping... {gray Press Ctrl+C again to force}`;\n ctx.abort();\n\n // when ggt is run via npx, and the user presses ctrl+c, npx\n // sends sigint twice in quick succession. in order to prevent\n // the second sigint from triggering the force exit listener,\n // we wait a bit before registering it\n setTimeout(() => {\n process.once(signal, () => {\n log.println(\" Exiting immediately\");\n process.exit(1);\n });\n }, ms(\"100ms\")).unref();\n });\n }\n};\n"],"names":["arg","ms","AvailableCommands","importCommand","isAvailableCommand","Context","verbosityToLevel","createLogger","reportErrorAndExit","sprint","warnIfUpdateAvailable","sortBySimilar","isNil","log","name","rootUsage","rootArgs","type","Boolean","alias","COUNT","command","ctx","init","args","argv","process","slice","permissive","env","toString","cmd","_","shift","println","exit","closest","usage","extend","error","signal","once","trace","abort","setTimeout","unref"],"mappings":"AAAA,OAAOA,SAAS,MAAM;AACtB,OAAOC,QAAQ,KAAK;AAEpB,SAASC,iBAAiB,EAAEC,aAAa,EAAEC,kBAAkB,QAAoB,iCAAiC;AAClH,SAASC,OAAO,QAAQ,iCAAiC;AACzD,SAASC,gBAAgB,QAAQ,kCAAkC;AACnE,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,kBAAkB,QAAQ,+BAA+B;AAClE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,qBAAqB,QAAQ,+BAA+B;AACrE,SAASC,aAAa,QAAQ,iCAAiC;AAC/D,SAASC,KAAK,QAAQ,yBAAyB;AAE/C,MAAMC,MAAMN,aAAa;IAAEO,MAAM;AAAO;AAExC,OAAO,MAAMC,YAAmB,IAAMN,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;AAoB7C,CAAC,CAAC;AAEF,OAAO,MAAMO,WAAW;IACtB,UAAU;QAAEC,MAAMC;QAASC,OAAO;IAAK;IACvC,aAAa;QAAEF,MAAMjB,IAAIoB,KAAK;QAAED,OAAO;YAAC;YAAM;SAAU;IAAC;IACzD,UAAU;QAAEF,MAAMC;IAAQ;AAC5B,EAAqB;AAIrB,OAAO,MAAMG,UAAU;IACrB,MAAMC,MAAMjB,QAAQkB,IAAI,CAAC;QAAEC,MAAMR;QAAUS,MAAMC,QAAQD,IAAI,CAACE,KAAK,CAAC;QAAIC,YAAY;IAAK;IAEzF,MAAMlB;IAEN,IAAIY,IAAIE,IAAI,CAAC,SAAS,EAAE;QACtBE,QAAQG,GAAG,CAAC,iBAAiB,GAAG;IAClC;IAEA,IAAIP,IAAIE,IAAI,CAAC,YAAY,EAAE;QACzBE,QAAQG,GAAG,CAAC,gBAAgB,GAAGvB,iBAAiBgB,IAAIE,IAAI,CAAC,YAAY,EAAEM,QAAQ;IACjF;IAEA,MAAMC,MAAMT,IAAIE,IAAI,CAACQ,CAAC,CAACC,KAAK;IAC5B,IAAIrB,MAAMmB,MAAM;QACdlB,IAAIqB,OAAO,CAACnB;QACZW,QAAQS,IAAI,CAAC;IACf;IAEA,IAAI,CAAC/B,mBAAmB2B,MAAM;QAC5B,MAAM,CAACK,QAAQ,GAAGzB,cAAcoB,KAAK7B;QACrCW,IAAIqB,OAAO,CAAC;8BACc,EAAEH,IAAI;;+BAEL,EAAEK,QAAQ;;;IAGrC,CAAC;QACDV,QAAQS,IAAI,CAAC;IACf;IAEA,MAAM,EAAEE,KAAK,EAAEhB,OAAO,EAAEG,OAAO,CAAC,CAAC,EAAE,GAAG,MAAMrB,cAAc4B;IAE1D,IAAIT,IAAIE,IAAI,CAAC,SAAS,EAAE;QACtBX,IAAIqB,OAAO,CAACG;QACZX,QAAQS,IAAI,CAAC;IACf;IAEA,IAAI;QACF,MAAMd,QAAQC,IAAIgB,MAAM,CAAC;YAAEd;YAAMV,MAAMiB;QAAI;IAC7C,EAAE,OAAOQ,OAAO;QACd,MAAM/B,mBAAmB+B;IAC3B;IAEA,KAAK,MAAMC,UAAU;QAAC;QAAU;KAAU,CAAW;QACnDd,QAAQe,IAAI,CAACD,QAAQ;YACnB3B,IAAI6B,KAAK,CAAC,mBAAmB;gBAAEF;YAAO;YACtC3B,IAAIqB,OAAO,CAAC,+CAA+C,CAAC;YAC5DZ,IAAIqB,KAAK;YAET,4DAA4D;YAC5D,8DAA8D;YAC9D,6DAA6D;YAC7D,sCAAsC;YACtCC,WAAW;gBACTlB,QAAQe,IAAI,CAACD,QAAQ;oBACnB3B,IAAIqB,OAAO,CAAC;oBACZR,QAAQS,IAAI,CAAC;gBACf;YACF,GAAGlC,GAAG,UAAU4C,KAAK;QACvB;IACF;AACF,EAAE"}
1
+ {"version":3,"sources":["../../src/commands/root.ts"],"sourcesContent":["import arg from \"arg\";\nimport type { EmptyObject } from \"type-fest\";\nimport type { ArgsDefinition } from \"../services/command/arg.js\";\nimport { Commands, importCommand, isAvailableCommand, type Command, type Usage } from \"../services/command/command.js\";\nimport { verbosityToLevel } from \"../services/output/log/level.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { warnIfUpdateAvailable } from \"../services/output/update.js\";\nimport { sortBySimilar } from \"../services/util/collection.js\";\nimport { isNil } from \"../services/util/is.js\";\n\nexport const usage: Usage = () => sprint`\n The command-line interface for Gadget\n\n {bold USAGE}\n ggt [COMMAND]\n\n {bold COMMANDS}\n sync Sync your Gadget application's source code\n list List your apps\n login Log in to your account\n logout Log out of your account\n whoami Print the currently logged in account\n version Print the version of ggt\n\n {bold FLAGS}\n -h, --help Print command's usage\n -v, --verbose Print verbose output\n --json Print output as JSON\n\n For more information on a specific command, use 'ggt [COMMAND] --help'\n`;\n\nexport const args = {\n \"--help\": { type: Boolean, alias: \"-h\" },\n \"--verbose\": { type: arg.COUNT, alias: [\"-v\", \"--debug\"] },\n \"--json\": { type: Boolean },\n} satisfies ArgsDefinition;\n\nexport type RootArgs = typeof args;\n\nexport const command: Command<EmptyObject, EmptyObject> = async (parent): Promise<void> => {\n const ctx = parent.child({\n name: \"root\",\n parse: args,\n argv: process.argv.slice(2),\n permissive: true,\n });\n\n if (ctx.args[\"--json\"]) {\n process.env[\"GGT_LOG_FORMAT\"] = \"json\";\n }\n\n if (ctx.args[\"--verbose\"]) {\n process.env[\"GGT_LOG_LEVEL\"] = verbosityToLevel(ctx.args[\"--verbose\"]).toString();\n }\n\n await warnIfUpdateAvailable(ctx);\n\n const cmd = ctx.args._.shift();\n if (isNil(cmd)) {\n ctx.log.println(usage());\n process.exit(0);\n }\n\n if (!isAvailableCommand(cmd)) {\n const [closest] = sortBySimilar(cmd, Commands);\n ctx.log.println`\n Unknown command {yellow ${cmd}}\n\n Did you mean {blueBright ${closest}}?\n\n Run {gray ggt --help} for usage\n `;\n process.exit(1);\n }\n\n const subcommand = await importCommand(cmd);\n\n if (ctx.args[\"--help\"]) {\n ctx.log.println(subcommand.usage());\n process.exit(0);\n }\n\n try {\n await subcommand.command(ctx.child({ name: cmd, parse: subcommand.args }));\n } catch (error) {\n await reportErrorAndExit(ctx, error);\n }\n};\n"],"names":["arg","Commands","importCommand","isAvailableCommand","verbosityToLevel","reportErrorAndExit","sprint","warnIfUpdateAvailable","sortBySimilar","isNil","usage","args","type","Boolean","alias","COUNT","command","parent","ctx","child","name","parse","argv","process","slice","permissive","env","toString","cmd","_","shift","log","println","exit","closest","subcommand","error"],"mappings":"AAAA,OAAOA,SAAS,MAAM;AAGtB,SAASC,QAAQ,EAAEC,aAAa,EAAEC,kBAAkB,QAAkC,iCAAiC;AACvH,SAASC,gBAAgB,QAAQ,kCAAkC;AACnE,SAASC,kBAAkB,QAAQ,+BAA+B;AAClE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,qBAAqB,QAAQ,+BAA+B;AACrE,SAASC,aAAa,QAAQ,iCAAiC;AAC/D,SAASC,KAAK,QAAQ,yBAAyB;AAE/C,OAAO,MAAMC,QAAe,IAAMJ,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;AAoBzC,CAAC,CAAC;AAEF,OAAO,MAAMK,OAAO;IAClB,UAAU;QAAEC,MAAMC;QAASC,OAAO;IAAK;IACvC,aAAa;QAAEF,MAAMZ,IAAIe,KAAK;QAAED,OAAO;YAAC;YAAM;SAAU;IAAC;IACzD,UAAU;QAAEF,MAAMC;IAAQ;AAC5B,EAA2B;AAI3B,OAAO,MAAMG,UAA6C,OAAOC;IAC/D,MAAMC,MAAMD,OAAOE,KAAK,CAAC;QACvBC,MAAM;QACNC,OAAOV;QACPW,MAAMC,QAAQD,IAAI,CAACE,KAAK,CAAC;QACzBC,YAAY;IACd;IAEA,IAAIP,IAAIP,IAAI,CAAC,SAAS,EAAE;QACtBY,QAAQG,GAAG,CAAC,iBAAiB,GAAG;IAClC;IAEA,IAAIR,IAAIP,IAAI,CAAC,YAAY,EAAE;QACzBY,QAAQG,GAAG,CAAC,gBAAgB,GAAGtB,iBAAiBc,IAAIP,IAAI,CAAC,YAAY,EAAEgB,QAAQ;IACjF;IAEA,MAAMpB,sBAAsBW;IAE5B,MAAMU,MAAMV,IAAIP,IAAI,CAACkB,CAAC,CAACC,KAAK;IAC5B,IAAIrB,MAAMmB,MAAM;QACdV,IAAIa,GAAG,CAACC,OAAO,CAACtB;QAChBa,QAAQU,IAAI,CAAC;IACf;IAEA,IAAI,CAAC9B,mBAAmByB,MAAM;QAC5B,MAAM,CAACM,QAAQ,GAAG1B,cAAcoB,KAAK3B;QACrCiB,IAAIa,GAAG,CAACC,OAAO,CAAC;8BACU,EAAEJ,IAAI;;+BAEL,EAAEM,QAAQ;;;IAGrC,CAAC;QACDX,QAAQU,IAAI,CAAC;IACf;IAEA,MAAME,aAAa,MAAMjC,cAAc0B;IAEvC,IAAIV,IAAIP,IAAI,CAAC,SAAS,EAAE;QACtBO,IAAIa,GAAG,CAACC,OAAO,CAACG,WAAWzB,KAAK;QAChCa,QAAQU,IAAI,CAAC;IACf;IAEA,IAAI;QACF,MAAME,WAAWnB,OAAO,CAACE,IAAIC,KAAK,CAAC;YAAEC,MAAMQ;YAAKP,OAAOc,WAAWxB,IAAI;QAAC;IACzE,EAAE,OAAOyB,OAAO;QACd,MAAM/B,mBAAmBa,KAAKkB;IAChC;AACF,EAAE"}
@@ -1,5 +1,4 @@
1
1
  import dayjs from "dayjs";
2
- import { execa } from "execa";
3
2
  import ms from "ms";
4
3
  import path from "node:path";
5
4
  import Watcher from "watcher";
@@ -11,7 +10,6 @@ import { FileSync, FileSyncArgs } from "../services/filesync/filesync.js";
11
10
  import { notify } from "../services/output/notify.js";
12
11
  import { reportErrorAndExit } from "../services/output/report.js";
13
12
  import { sprint } from "../services/output/sprint.js";
14
- import { getUserOrLogin } from "../services/user/user.js";
15
13
  import { debounce } from "../services/util/function.js";
16
14
  import { isAbortError } from "../services/util/is.js";
17
15
  export const usage = ()=>sprint`
@@ -111,20 +109,17 @@ export const args = {
111
109
  /**
112
110
  * Runs the sync process until it is stopped or an error occurs.
113
111
  */ export const command = async (ctx)=>{
114
- const filesync = await FileSync.init({
115
- ctx,
116
- user: await getUserOrLogin()
117
- });
118
- await filesync.sync();
119
- if (ctx.args["--once"]) {
120
- ctx.log.println("Done!");
121
- return;
122
- }
123
112
  if (!which.sync("yarn", {
124
113
  nothrow: true
125
114
  })) {
126
115
  throw new YarnNotFoundError();
127
116
  }
117
+ const filesync = await FileSync.init(ctx);
118
+ await filesync.sync();
119
+ if (ctx.args["--once"]) {
120
+ ctx.log.println("Done!");
121
+ return;
122
+ }
128
123
  /**
129
124
  * A list of filepaths that have changed because we (this ggt process)
130
125
  * modified them. This is used to avoid reacting to filesystem events
@@ -158,20 +153,6 @@ export const args = {
158
153
  dir = path.dirname(dir);
159
154
  }
160
155
  }
161
- },
162
- afterChanges: async ({ changes })=>{
163
- if (changes.has("yarn.lock")) {
164
- await execa("yarn", [
165
- "install",
166
- "--check-files"
167
- ], {
168
- cwd: filesync.directory.path
169
- }).catch((error)=>{
170
- ctx.log.error("yarn install failed", {
171
- error
172
- });
173
- });
174
- }
175
156
  }
176
157
  });
177
158
  /**
@@ -262,8 +243,8 @@ export const args = {
262
243
  ggt v${config.version}
263
244
 
264
245
  App ${filesync.app.slug}
265
- Editor https://${filesync.app.slug}.gadget.app/edit
266
- Playground https://${filesync.app.slug}.gadget.app/api/graphql/playground
246
+ Editor https://${filesync.app.primaryDomain}/edit
247
+ Playground https://${filesync.app.primaryDomain}/api/graphql/playground
267
248
  Docs https://docs.gadget.dev/api/${filesync.app.slug}
268
249
 
269
250
  Endpoints ${filesync.app.hasSplitEnvironments ? `
@@ -292,11 +273,11 @@ export const args = {
292
273
  ctx.log.printlns("Goodbye!");
293
274
  return;
294
275
  }
295
- notify({
276
+ notify(ctx, {
296
277
  subtitle: "Uh oh!",
297
278
  message: "An error occurred while syncing files"
298
279
  });
299
- await reportErrorAndExit(reason);
280
+ await reportErrorAndExit(ctx, reason);
300
281
  });
301
282
  };
302
283