@gadgetinc/ggt 1.0.2 → 1.0.3

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 (99) hide show
  1. package/README.md +192 -128
  2. package/lib/__generated__/graphql.js.map +1 -1
  3. package/lib/commands/add.js +385 -0
  4. package/lib/commands/add.js.map +1 -0
  5. package/lib/commands/deploy.js +20 -102
  6. package/lib/commands/deploy.js.map +1 -1
  7. package/lib/commands/dev.js +43 -114
  8. package/lib/commands/dev.js.map +1 -1
  9. package/lib/commands/list.js +3 -6
  10. package/lib/commands/list.js.map +1 -1
  11. package/lib/commands/login.js +2 -5
  12. package/lib/commands/login.js.map +1 -1
  13. package/lib/commands/logout.js +2 -5
  14. package/lib/commands/logout.js.map +1 -1
  15. package/lib/commands/open.js +45 -86
  16. package/lib/commands/open.js.map +1 -1
  17. package/lib/commands/pull.js +19 -76
  18. package/lib/commands/pull.js.map +1 -1
  19. package/lib/commands/push.js +19 -76
  20. package/lib/commands/push.js.map +1 -1
  21. package/lib/commands/root.js +4 -3
  22. package/lib/commands/root.js.map +1 -1
  23. package/lib/commands/status.js +3 -8
  24. package/lib/commands/status.js.map +1 -1
  25. package/lib/commands/version.js +6 -5
  26. package/lib/commands/version.js.map +1 -1
  27. package/lib/commands/whoami.js +2 -5
  28. package/lib/commands/whoami.js.map +1 -1
  29. package/lib/ggt.js.map +1 -1
  30. package/lib/main.js.map +1 -1
  31. package/lib/services/app/api/api.js.map +1 -1
  32. package/lib/services/app/api/operation.js +11 -0
  33. package/lib/services/app/api/operation.js.map +1 -1
  34. package/lib/services/app/app.js +21 -2
  35. package/lib/services/app/app.js.map +1 -1
  36. package/lib/services/app/arg.js.map +1 -1
  37. package/lib/services/app/client.js.map +1 -1
  38. package/lib/services/app/edit/edit.js.map +1 -1
  39. package/lib/services/app/edit/operation.js +52 -0
  40. package/lib/services/app/edit/operation.js.map +1 -1
  41. package/lib/services/app/error.js.map +1 -1
  42. package/lib/services/command/arg.js +3 -1
  43. package/lib/services/command/arg.js.map +1 -1
  44. package/lib/services/command/command.js +1 -0
  45. package/lib/services/command/command.js.map +1 -1
  46. package/lib/services/command/context.js.map +1 -1
  47. package/lib/services/config/config.js.map +1 -1
  48. package/lib/services/config/env.js.map +1 -1
  49. package/lib/services/config/package-json.js.map +1 -1
  50. package/lib/services/filesync/changes.js.map +1 -1
  51. package/lib/services/filesync/conflicts.js.map +1 -1
  52. package/lib/services/filesync/directory.js.map +1 -1
  53. package/lib/services/filesync/error.js +1 -0
  54. package/lib/services/filesync/error.js.map +1 -1
  55. package/lib/services/filesync/file.js.map +1 -1
  56. package/lib/services/filesync/filesync.js +179 -174
  57. package/lib/services/filesync/filesync.js.map +1 -1
  58. package/lib/services/filesync/hashes.js.map +1 -1
  59. package/lib/services/filesync/strategy.js.map +1 -1
  60. package/lib/services/filesync/sync-json.js.map +1 -1
  61. package/lib/services/http/auth.js.map +1 -1
  62. package/lib/services/http/http.js.map +1 -1
  63. package/lib/services/output/confirm.js.map +1 -1
  64. package/lib/services/output/footer.js.map +1 -1
  65. package/lib/services/output/log/field.js.map +1 -1
  66. package/lib/services/output/log/format/format.js.map +1 -1
  67. package/lib/services/output/log/format/json.js.map +1 -1
  68. package/lib/services/output/log/format/pretty.js.map +1 -1
  69. package/lib/services/output/log/level.js.map +1 -1
  70. package/lib/services/output/log/logger.js.map +1 -1
  71. package/lib/services/output/log/structured.js.map +1 -1
  72. package/lib/services/output/notify.js.map +1 -1
  73. package/lib/services/output/output.js.map +1 -1
  74. package/lib/services/output/print.js.map +1 -1
  75. package/lib/services/output/problems.js.map +1 -1
  76. package/lib/services/output/prompt.js.map +1 -1
  77. package/lib/services/output/report.js.map +1 -1
  78. package/lib/services/output/select.js.map +1 -1
  79. package/lib/services/output/spinner.js.map +1 -1
  80. package/lib/services/output/sprint.js.map +1 -1
  81. package/lib/services/output/symbols.js.map +1 -1
  82. package/lib/services/output/table.js.map +1 -1
  83. package/lib/services/output/timestamp.js.map +1 -1
  84. package/lib/services/output/update.js.map +1 -1
  85. package/lib/services/user/session.js.map +1 -1
  86. package/lib/services/user/user.js.map +1 -1
  87. package/lib/services/util/assert.js.map +1 -1
  88. package/lib/services/util/boolean.js.map +1 -1
  89. package/lib/services/util/collection.js.map +1 -1
  90. package/lib/services/util/function.js.map +1 -1
  91. package/lib/services/util/is.js.map +1 -1
  92. package/lib/services/util/json.js.map +1 -1
  93. package/lib/services/util/number.js.map +1 -1
  94. package/lib/services/util/object.js.map +1 -1
  95. package/lib/services/util/paths.js.map +1 -1
  96. package/lib/services/util/promise.js.map +1 -1
  97. package/lib/services/util/types.js.map +1 -1
  98. package/npm-shrinkwrap.json +2071 -1684
  99. package/package.json +30 -30
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport terminalLink from \"terminal-link\";\nimport { PUBLISH_STATUS_SUBSCRIPTION } from \"../services/app/edit/operation.js\";\nimport { type Command, type Usage } from \"../services/command/command.js\";\nimport { DeployDisallowedError } from \"../services/filesync/error.js\";\nimport { FileSync } from \"../services/filesync/filesync.js\";\nimport { SyncJson, loadSyncJsonDirectory } from \"../services/filesync/sync-json.js\";\nimport { confirm } from \"../services/output/confirm.js\";\nimport { output } from \"../services/output/output.js\";\nimport { println } from \"../services/output/print.js\";\nimport { ProblemSeverity, printProblems, publishIssuesToProblems } from \"../services/output/problems.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { spin, type spinner } from \"../services/output/spinner.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { ts } from \"../services/output/timestamp.js\";\nimport { unreachable } from \"../services/util/assert.js\";\nimport { isGraphQLErrors } from \"../services/util/is.js\";\nimport { args as PushArgs } from \"./push.js\";\n\nexport type DeployArgs = typeof args;\n\nexport const args = {\n ...PushArgs,\n \"--env\": { type: String, alias: [\"-e\", \"--environment\", \"--from\"] },\n \"--allow-problems\": { type: Boolean, alias: \"--allow-issues\" },\n \"--allow-charges\": { type: Boolean },\n};\n\nexport const usage: Usage = (ctx) => {\n if (ctx.args[\"-h\"]) {\n return sprint`\n Deploy an environment to production.\n\n Your local files must match your environment's files\n before you can deploy. Changes are tracked from\n the last \"ggt dev\", \"ggt push\", or \"ggt pull\" run locally.\n\n {bold USAGE}\n ggt deploy\n\n {bold EXAMPLES}\n $ ggt deploy\n $ ggt deploy --from=staging\n $ ggt deploy --from=staging --force\n $ ggt deploy --from=staging --force --allow-problems\n\n {bold FLAGS}\n -a, --app=<name> The application to deploy\n -e, --from=<env> The environment to deploy from\n --force Discard changes to your environment's filesystem\n --allow-problems Deploy regardless of any problems the environment has\n --allow-charges Deploy even if doing so will add charges to your account\n\n Run \"ggt deploy --help\" for more information.\n `;\n }\n\n return sprint`\n Deploy an environment to production.\n\n Your local files must match your environment's files\n before you can deploy. Changes are tracked from\n the last \"ggt dev\", \"ggt push\", or \"ggt pull\" run locally.\n\n If your local files don't match your environment's files, you will\n be prompted to push your local files before you can deploy.\n\n If your environment has un-pulled changes, and \"--force\" is not\n passed, you will be prompted to {underline discard them} or abort the deploy.\n\n {bold USAGE}\n\n ggt deploy [--app=<name>] [--from=<env>] [--force]\n [--allow-problems] [--allow-charges]\n\n {bold EXAMPLES}\n\n $ ggt deploy\n $ ggt deploy --from=staging\n $ ggt deploy --from=staging --force\n $ ggt deploy --from=staging --force --allow-problems\n $ ggt deploy --from=staging --force --allow-problems --allow-charges\n\n {bold FLAGS}\n\n -a, --app, --application=<name>\n The application to deploy.\n\n Defaults to the application within the \".gadget/sync.json\"\n file in the current directory or any parent directories.\n\n -e, --env, --environment, --from=<name>\n The environment to deploy from.\n\n Defaults to the environment within the \".gadget/sync.json\"\n file in the current directory or any parent directories.\n\n -f, --force\n Discard any changes made to your environment's filesystem\n since the last \"ggt dev\", \"ggt push\", or \"ggt pull\".\n\n Defaults to false.\n\n --allow-problems, --allow-issues\n Deploy your environment to production regardless of any problems\n it may have.\n\n These problems may include:\n • Gelly syntax errors\n • TypeScript errors\n • Models with missing fields\n\n Defaults to false.\n\n --allow-charges\n Allows \"ggt deploy\" to continue when deploying your environment\n to production will add charges to your account.\n\n Defaults to false.\n\n --allow-unknown-directory\n Allows \"ggt deploy\" to continue when the current directory, nor\n any parent directories, contain a \".gadget/sync.json\" file\n within it.\n\n Defaults to false.\n\n --allow-different-app\n Allows \"ggt deploy\" to continue with a different \"--app\" than the\n one found within the \".gadget/sync.json\" file.\n\n Defaults to false.\n\n Run \"ggt deploy -h\" for less information.\n`;\n};\n\nexport const command: Command<DeployArgs> = async (ctx) => {\n const directory = await loadSyncJsonDirectory(process.cwd());\n const syncJson = await SyncJson.loadOrInit(ctx, { directory });\n\n println({ ensureEmptyLineAbove: true })`\n Deploying ${syncJson.env.name} to ${terminalLink(syncJson.app.primaryDomain, `https://${syncJson.app.primaryDomain}/`)}\n `;\n\n const filesync = new FileSync(syncJson);\n const hashes = await filesync.hashes(ctx);\n if (!hashes.inSync && (hashes.localChangesToPush.size > 0 || !hashes.onlyDotGadgetFilesChanged)) {\n // the following is true:\n // 1. our local files don't match our environment's files\n // 2. we have local changes to push or non .gadget/ files have changed on our environment\n // therefor, we need to push before we can deploy\n await filesync.print(ctx, { hashes });\n\n println({ ensureEmptyLineAbove: true })`\n Your environment's files must match your local files before you can deploy.\n `;\n\n // some scenarios make the confirmation to push changes imply the\n // --force flag (e.g. when both local and environment files have\n // changed, or when only environment files have changed)\n let implicitForce = false;\n\n if (output.isInteractive) {\n let message: string;\n switch (true) {\n case hashes.bothChanged:\n message = sprint`Would you like to push your local changes and {underline discard your environment's} changes now?`;\n implicitForce = true;\n break;\n case hashes.localChangesToPush.size > 0:\n message = sprint`Would you like to push your local changes now?`;\n break;\n case hashes.environmentChanges.size > 0:\n message = sprint`Do you want to {underline discard your environment's} changes now?`;\n implicitForce = true;\n break;\n default:\n unreachable(\"no changes to push or discard\");\n }\n\n await confirm({ ensureEmptyLineAbove: true })(message);\n } else {\n println({ ensureEmptyLineAbove: true })`\n Assuming you want to push your local files now.\n `;\n }\n\n await filesync.push(ctx, { hashes, force: implicitForce || ctx.args[\"--force\"] });\n }\n\n const variables = {\n localFilesVersion: String(syncJson.filesVersion),\n force: ctx.args[\"--allow-problems\"],\n allowCharges: ctx.args[\"--allow-charges\"],\n };\n\n let spinner: spinner | undefined;\n let currentStep: AppDeploymentSteps = AppDeploymentSteps.NOT_STARTED;\n let printedProblems = false;\n\n const subscription = syncJson.edit.subscribe({\n subscription: PUBLISH_STATUS_SUBSCRIPTION,\n variables,\n onError: async (error) => {\n ctx.log.error(\"failed to deploy\", { error });\n spinner?.fail(stepToSpinnerStart(syncJson, currentStep) + \" \" + ts());\n\n if (isGraphQLErrors(error.cause)) {\n const graphqlError = error.cause[0];\n assert(graphqlError, \"expected graphqlError to be defined\");\n\n switch (true) {\n case graphqlError.extensions[\"requiresUpgrade\"]:\n println({ ensureEmptyLineAbove: true })(graphqlError.message.replace(/GGT_PAYMENT_REQUIRED:?\\s*/, \"\"));\n process.exit(1);\n break;\n case graphqlError.extensions[\"requiresAdditionalCharge\"]:\n println({ ensureEmptyLineAbove: true })(graphqlError.message.replace(/GGT_PAYMENT_REQUIRED:?\\s*/, \"\"));\n await confirm({ ensureEmptyLineAbove: true })(\"Do you want to continue?\");\n subscription.resubscribe({ ...variables, allowCharges: true });\n return;\n }\n }\n\n await reportErrorAndExit(ctx, error);\n },\n onData: async ({ publishStatus }): Promise<void> => {\n if (!publishStatus) {\n ctx.log.warn(\"received empty publish status\");\n return;\n }\n\n const { publishStarted, progress: step, issues, status } = publishStatus;\n if (!printedProblems && issues.length > 0) {\n printedProblems = true;\n\n const fatalIssues = issues.filter((issue) => issue.severity === ProblemSeverity.Fatal);\n if (fatalIssues.length > 0) {\n await reportErrorAndExit(ctx, new DeployDisallowedError(publishIssuesToProblems(fatalIssues)));\n }\n\n println({ ensureEmptyLineAbove: true })`{bold Problems found.}`;\n printProblems({ problems: publishIssuesToProblems(issues) });\n\n if (!publishStarted) {\n await confirm(\"Do you want to continue?\");\n subscription.resubscribe({ ...variables, force: true });\n } else {\n assert(ctx.args[\"--allow-problems\"], \"expected --allow-problems to be true\");\n println({ ensureEmptyLineAbove: true })`Deploying regardless of problems because {bold \"--allow-problems\"} was passed.`;\n }\n\n return;\n }\n\n if (status?.code === \"Errored\") {\n subscription.unsubscribe();\n spinner?.fail(stepToSpinnerStart(syncJson, currentStep) + \" \" + ts());\n\n if (status.message) {\n println({ ensureEmptyLineAbove: true })`{red ${status.message}}`;\n }\n if (status.output) {\n println({ ensureEmptyLineAbove: true })`${terminalLink(\"Check logs\", status.output)}`;\n }\n return;\n }\n\n if (step === AppDeploymentSteps.COMPLETED) {\n subscription.unsubscribe();\n spinner?.succeed(stepToSpinnerEnd(syncJson, currentStep));\n\n let message = sprint`{green Deploy successful!}`;\n if (status?.output) {\n message += ` ${terminalLink(\"Check logs\", status.output)}.`;\n }\n\n println({ ensureEmptyLineAbove: true })(message);\n return;\n }\n\n if (step !== currentStep) {\n const spinnerText = stepToSpinnerStart(syncJson, step);\n if (spinnerText !== spinner?.text) {\n // stop the current spinner, if any, and start a new one\n spinner?.succeed(stepToSpinnerEnd(syncJson, currentStep));\n\n const ensureEmptyLineAbove = currentStep === AppDeploymentSteps.NOT_STARTED || !output.isInteractive;\n spinner = spin({ ensureEmptyLineAbove })(spinnerText);\n }\n\n currentStep = step as AppDeploymentSteps;\n }\n },\n });\n};\n\nexport const AppDeploymentSteps = Object.freeze({\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\nexport type AppDeploymentSteps = (typeof AppDeploymentSteps)[keyof typeof AppDeploymentSteps];\n\nexport const stepToSpinnerStart = (syncJson: SyncJson, step: string): string => {\n switch (step) {\n case AppDeploymentSteps.NOT_STARTED:\n case AppDeploymentSteps.STARTING:\n case AppDeploymentSteps.BUILDING_ASSETS:\n case AppDeploymentSteps.UPLOADING_ASSETS:\n return \"Building frontend assets.\";\n case AppDeploymentSteps.CONVERGING_STORAGE:\n return \"Setting up database.\";\n case AppDeploymentSteps.PUBLISHING_TREE:\n return `Copying ${syncJson.env.name}.`;\n case AppDeploymentSteps.RELOADING_SANDBOX:\n return \"Restarting app.\";\n case AppDeploymentSteps.COMPLETED:\n return \"Deploy complete!\";\n default:\n return \"Unknown step.\";\n }\n};\n\nexport const stepToSpinnerEnd = (syncJson: SyncJson, step: string): string => {\n switch (step) {\n case AppDeploymentSteps.NOT_STARTED:\n case AppDeploymentSteps.STARTING:\n case AppDeploymentSteps.BUILDING_ASSETS:\n case AppDeploymentSteps.UPLOADING_ASSETS:\n return `Built frontend assets. ${ts()}`;\n case AppDeploymentSteps.CONVERGING_STORAGE:\n return `Setup database. ${ts()}`;\n case AppDeploymentSteps.PUBLISHING_TREE:\n return `Copied ${syncJson.env.name}. ${ts()}`;\n case AppDeploymentSteps.RELOADING_SANDBOX:\n return `Restarted app. ${ts()}`;\n case AppDeploymentSteps.COMPLETED:\n return \"Deploy successful!\";\n default:\n return `Completed unknown step. ${ts()}`;\n }\n};\n"],"names":["assert","terminalLink","PUBLISH_STATUS_SUBSCRIPTION","DeployDisallowedError","FileSync","SyncJson","loadSyncJsonDirectory","confirm","output","println","ProblemSeverity","printProblems","publishIssuesToProblems","reportErrorAndExit","spin","sprint","ts","unreachable","isGraphQLErrors","args","PushArgs","type","String","alias","Boolean","usage","ctx","command","directory","process","cwd","syncJson","loadOrInit","ensureEmptyLineAbove","env","name","app","primaryDomain","filesync","hashes","inSync","localChangesToPush","size","onlyDotGadgetFilesChanged","print","implicitForce","isInteractive","message","bothChanged","environmentChanges","push","force","variables","localFilesVersion","filesVersion","allowCharges","spinner","currentStep","AppDeploymentSteps","NOT_STARTED","printedProblems","subscription","edit","subscribe","onError","error","log","fail","stepToSpinnerStart","cause","graphqlError","extensions","replace","exit","resubscribe","onData","publishStatus","warn","publishStarted","progress","step","issues","status","length","fatalIssues","filter","issue","severity","Fatal","problems","code","unsubscribe","COMPLETED","succeed","stepToSpinnerEnd","spinnerText","text","Object","freeze","STARTING","BUILDING_ASSETS","UPLOADING_ASSETS","CONVERGING_STORAGE","PUBLISHING_TREE","RELOADING_SANDBOX"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport terminalLink from \"terminal-link\";\nimport { PUBLISH_STATUS_SUBSCRIPTION } from \"../services/app/edit/operation.js\";\nimport { type Command, type Usage } from \"../services/command/command.js\";\nimport { DeployDisallowedError } from \"../services/filesync/error.js\";\nimport { FileSync } from \"../services/filesync/filesync.js\";\nimport { SyncJson, loadSyncJsonDirectory } from \"../services/filesync/sync-json.js\";\nimport { confirm } from \"../services/output/confirm.js\";\nimport { output } from \"../services/output/output.js\";\nimport { println } from \"../services/output/print.js\";\nimport { ProblemSeverity, printProblems, publishIssuesToProblems } from \"../services/output/problems.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { spin, type spinner } from \"../services/output/spinner.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { ts } from \"../services/output/timestamp.js\";\nimport { unreachable } from \"../services/util/assert.js\";\nimport { isGraphQLErrors } from \"../services/util/is.js\";\nimport { args as PushArgs } from \"./push.js\";\n\nexport type DeployArgs = typeof args;\n\nexport const args = {\n ...PushArgs,\n \"--env\": { type: String, alias: [\"-e\", \"--environment\", \"--from\"] },\n \"--allow-problems\": { type: Boolean, alias: \"--allow-issues\" },\n \"--allow-charges\": { type: Boolean },\n};\n\nexport const usage: Usage = (_ctx) => {\n return sprint`\n Deploys your app to production.\n\n This command first performs a sync to ensure that your local and environment directories\n match, changes are tracked since last sync. If any conflicts are detected, they must be\n resolved before deployment.\n\n {gray Usage}\n $ ggt deploy [options]\n \n {gray Options}\n -a, --app <app_name> Selects a specific app to deploy. Default set on \".gadget/sync.json\"\n --from, -e, --env <env_name> Selects a specific environment to sync and deploy from. Default set on \".gadget/sync.json\"\n --force Deploys by discarding any changes made to the environment directory since last sync\n --allow-different-directory Deploys from any local directory with existing files, even if the \".gadget/sync.json\" file is missing\n --allow-different-app Deploys a different app using the --app command, instead of the one specified in the “.gadget/sync.json” file\n --allow-problems Deploys despite any existing issues found in the app (gelly errors, typescript errors etc.)\n --allow-charges Deploys even if it results in additional charges to your plan\n \n {gray Examples}\n Deploys code from the staging environment of a myBlog\n {cyanBright $ ggt deploy -a myBlog -from staging} \n`;\n};\n\nexport const command: Command<DeployArgs> = async (ctx) => {\n const directory = await loadSyncJsonDirectory(process.cwd());\n const syncJson = await SyncJson.loadOrInit(ctx, { directory });\n\n println({ ensureEmptyLineAbove: true })`\n Deploying ${syncJson.env.name} to ${terminalLink(syncJson.app.primaryDomain, `https://${syncJson.app.primaryDomain}/`)}\n `;\n\n const filesync = new FileSync(syncJson);\n const hashes = await filesync.hashes(ctx);\n if (!hashes.inSync && (hashes.localChangesToPush.size > 0 || !hashes.onlyDotGadgetFilesChanged)) {\n // the following is true:\n // 1. our local files don't match our environment's files\n // 2. we have local changes to push or non .gadget/ files have changed on our environment\n // therefor, we need to push before we can deploy\n await filesync.print(ctx, { hashes });\n\n println({ ensureEmptyLineAbove: true })`\n Your environment's files must match your local files before you can deploy.\n `;\n\n // some scenarios make the confirmation to push changes imply the\n // --force flag (e.g. when both local and environment files have\n // changed, or when only environment files have changed)\n let implicitForce = false;\n\n if (output.isInteractive) {\n let message: string;\n switch (true) {\n case hashes.bothChanged:\n message = sprint`Would you like to push your local changes and {underline discard your environment's} changes now?`;\n implicitForce = true;\n break;\n case hashes.localChangesToPush.size > 0:\n message = sprint`Would you like to push your local changes now?`;\n break;\n case hashes.environmentChanges.size > 0:\n message = sprint`Do you want to {underline discard your environment's} changes now?`;\n implicitForce = true;\n break;\n default:\n unreachable(\"no changes to push or discard\");\n }\n\n await confirm({ ensureEmptyLineAbove: true })(message);\n } else {\n println({ ensureEmptyLineAbove: true })`\n Assuming you want to push your local files now.\n `;\n }\n\n await filesync.push(ctx, { hashes, force: implicitForce || ctx.args[\"--force\"] });\n }\n\n const variables = {\n localFilesVersion: String(syncJson.filesVersion),\n force: ctx.args[\"--allow-problems\"],\n allowCharges: ctx.args[\"--allow-charges\"],\n };\n\n let spinner: spinner | undefined;\n let currentStep: AppDeploymentSteps = AppDeploymentSteps.NOT_STARTED;\n let printedProblems = false;\n\n const subscription = syncJson.edit.subscribe({\n subscription: PUBLISH_STATUS_SUBSCRIPTION,\n variables,\n onError: async (error) => {\n ctx.log.error(\"failed to deploy\", { error });\n spinner?.fail(stepToSpinnerStart(syncJson, currentStep) + \" \" + ts());\n\n if (isGraphQLErrors(error.cause)) {\n const graphqlError = error.cause[0];\n assert(graphqlError, \"expected graphqlError to be defined\");\n\n switch (true) {\n case graphqlError.extensions[\"requiresUpgrade\"]:\n println({ ensureEmptyLineAbove: true })(graphqlError.message.replace(/GGT_PAYMENT_REQUIRED:?\\s*/, \"\"));\n process.exit(1);\n break;\n case graphqlError.extensions[\"requiresAdditionalCharge\"]:\n println({ ensureEmptyLineAbove: true })(graphqlError.message.replace(/GGT_PAYMENT_REQUIRED:?\\s*/, \"\"));\n await confirm({ ensureEmptyLineAbove: true })(\"Do you want to continue?\");\n subscription.resubscribe({ ...variables, allowCharges: true });\n return;\n }\n }\n\n await reportErrorAndExit(ctx, error);\n },\n onData: async ({ publishStatus }): Promise<void> => {\n if (!publishStatus) {\n ctx.log.warn(\"received empty publish status\");\n return;\n }\n\n const { publishStarted, progress: step, issues, status } = publishStatus;\n if (!printedProblems && issues.length > 0) {\n printedProblems = true;\n\n const fatalIssues = issues.filter((issue) => issue.severity === ProblemSeverity.Fatal);\n if (fatalIssues.length > 0) {\n await reportErrorAndExit(ctx, new DeployDisallowedError(publishIssuesToProblems(fatalIssues)));\n }\n\n println({ ensureEmptyLineAbove: true })`{bold Problems found.}`;\n printProblems({ problems: publishIssuesToProblems(issues) });\n\n if (!publishStarted) {\n await confirm(\"Do you want to continue?\");\n subscription.resubscribe({ ...variables, force: true });\n } else {\n assert(ctx.args[\"--allow-problems\"], \"expected --allow-problems to be true\");\n println({ ensureEmptyLineAbove: true })`Deploying regardless of problems because {bold \"--allow-problems\"} was passed.`;\n }\n\n return;\n }\n\n if (status?.code === \"Errored\") {\n subscription.unsubscribe();\n spinner?.fail(stepToSpinnerStart(syncJson, currentStep) + \" \" + ts());\n\n if (status.message) {\n println({ ensureEmptyLineAbove: true })`{red ${status.message}}`;\n }\n if (status.output) {\n println({ ensureEmptyLineAbove: true })`${terminalLink(\"Check logs\", status.output)}`;\n }\n return;\n }\n\n if (step === AppDeploymentSteps.COMPLETED) {\n subscription.unsubscribe();\n spinner?.succeed(stepToSpinnerEnd(syncJson, currentStep));\n\n let message = sprint`{green Deploy successful!}`;\n if (status?.output) {\n message += ` ${terminalLink(\"Check logs\", status.output)}.`;\n }\n\n println({ ensureEmptyLineAbove: true })(message);\n return;\n }\n\n if (step !== currentStep) {\n const spinnerText = stepToSpinnerStart(syncJson, step);\n if (spinnerText !== spinner?.text) {\n // stop the current spinner, if any, and start a new one\n spinner?.succeed(stepToSpinnerEnd(syncJson, currentStep));\n\n const ensureEmptyLineAbove = currentStep === AppDeploymentSteps.NOT_STARTED || !output.isInteractive;\n spinner = spin({ ensureEmptyLineAbove })(spinnerText);\n }\n\n currentStep = step as AppDeploymentSteps;\n }\n },\n });\n};\n\nexport const AppDeploymentSteps = Object.freeze({\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\nexport type AppDeploymentSteps = (typeof AppDeploymentSteps)[keyof typeof AppDeploymentSteps];\n\nexport const stepToSpinnerStart = (syncJson: SyncJson, step: string): string => {\n switch (step) {\n case AppDeploymentSteps.NOT_STARTED:\n case AppDeploymentSteps.STARTING:\n case AppDeploymentSteps.BUILDING_ASSETS:\n case AppDeploymentSteps.UPLOADING_ASSETS:\n return \"Building frontend assets.\";\n case AppDeploymentSteps.CONVERGING_STORAGE:\n return \"Setting up database.\";\n case AppDeploymentSteps.PUBLISHING_TREE:\n return `Copying ${syncJson.env.name}.`;\n case AppDeploymentSteps.RELOADING_SANDBOX:\n return \"Restarting app.\";\n case AppDeploymentSteps.COMPLETED:\n return \"Deploy complete!\";\n default:\n return \"Unknown step.\";\n }\n};\n\nexport const stepToSpinnerEnd = (syncJson: SyncJson, step: string): string => {\n switch (step) {\n case AppDeploymentSteps.NOT_STARTED:\n case AppDeploymentSteps.STARTING:\n case AppDeploymentSteps.BUILDING_ASSETS:\n case AppDeploymentSteps.UPLOADING_ASSETS:\n return `Built frontend assets. ${ts()}`;\n case AppDeploymentSteps.CONVERGING_STORAGE:\n return `Setup database. ${ts()}`;\n case AppDeploymentSteps.PUBLISHING_TREE:\n return `Copied ${syncJson.env.name}. ${ts()}`;\n case AppDeploymentSteps.RELOADING_SANDBOX:\n return `Restarted app. ${ts()}`;\n case AppDeploymentSteps.COMPLETED:\n return \"Deploy successful!\";\n default:\n return `Completed unknown step. ${ts()}`;\n }\n};\n"],"names":["assert","terminalLink","PUBLISH_STATUS_SUBSCRIPTION","DeployDisallowedError","FileSync","SyncJson","loadSyncJsonDirectory","confirm","output","println","ProblemSeverity","printProblems","publishIssuesToProblems","reportErrorAndExit","spin","sprint","ts","unreachable","isGraphQLErrors","args","PushArgs","type","String","alias","Boolean","usage","_ctx","command","ctx","directory","process","cwd","syncJson","loadOrInit","ensureEmptyLineAbove","env","name","app","primaryDomain","filesync","hashes","inSync","localChangesToPush","size","onlyDotGadgetFilesChanged","print","implicitForce","isInteractive","message","bothChanged","environmentChanges","push","force","variables","localFilesVersion","filesVersion","allowCharges","spinner","currentStep","AppDeploymentSteps","NOT_STARTED","printedProblems","subscription","edit","subscribe","onError","error","log","fail","stepToSpinnerStart","cause","graphqlError","extensions","replace","exit","resubscribe","onData","publishStatus","warn","publishStarted","progress","step","issues","status","length","fatalIssues","filter","issue","severity","Fatal","problems","code","unsubscribe","COMPLETED","succeed","stepToSpinnerEnd","spinnerText","text","Object","freeze","STARTING","BUILDING_ASSETS","UPLOADING_ASSETS","CONVERGING_STORAGE","PUBLISHING_TREE","RELOADING_SANDBOX"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -44,121 +44,50 @@ export const args = {
44
44
  default: ms("1.25s")
45
45
  }
46
46
  };
47
- export const usage = (ctx)=>{
48
- if (ctx.args["-h"]) {
49
- return sprint`
50
- Develop your app by synchronizing your local files with your
51
- environment's files, in real-time. Changes are tracked from
52
- the last "ggt dev", "ggt push", or "ggt pull" run locally.
53
-
54
- {bold USAGE}
55
- ggt dev [DIRECTORY]
56
-
57
- {bold EXAMPLES}
58
- $ ggt dev
59
- $ ggt dev ~/gadget/example
60
- $ ggt dev ~/gadget/example
61
- $ ggt dev ~/gadget/example --app=example
62
- $ ggt dev ~/gadget/example --app=example --env=development --prefer=local
63
-
64
- {bold ARGUMENTS}
65
- DIRECTORY The directory to synchronize files to (default: ".")
66
-
67
- {bold FLAGS}
68
- -a, --app=<name> The application to synchronize files with
69
- -e, --env=<name> The environment to synchronize files with
70
- --prefer=<filesystem> Prefer "local" or "environment" conflicting changes
71
-
72
- Run "ggt dev --help" for more information.
73
- `;
74
- }
47
+ export const usage = (_ctx)=>{
75
48
  return sprint`
76
- Develop your app by synchronizing your local files with your
77
- environment's files, in real-time. Changes are tracked from
78
- the last "ggt dev", "ggt push", or "ggt pull" run locally.
79
-
80
- While "ggt dev" is running, changes on your local filesystem are
81
- immediately pushed to your environment, while file changes on
82
- your environment are immediately pulled to your local filesystem.
83
-
84
- If conflicting changes are detected, and "--prefer" is not passed,
85
- you will be prompted to choose which changes to keep before
86
- "ggt dev" resumes.
87
-
88
- "ggt dev" looks for an ".ignore" file to exclude files and
89
- directories from being pushed or pulled. The format is identical
90
- to Git's.
91
-
92
- The following files and directories are always ignored:
93
- .DS_Store
94
- • .gadget
95
- .git
96
- node_modules
97
-
98
- Note:
99
- "ggt dev" only works with development environments
100
- "ggt dev" only supports "yarn" v1 for installing dependencies
101
- Avoid deleting or moving all of your files while "ggt dev" is running
102
-
103
- {bold USAGE}
104
-
105
- ggt dev [DIRECTORY] [--app=<name>] [--env=<name>] [--prefer=<filesystem>]
106
- [--allow-unknown-directory] [--allow-different-app]
107
-
108
- {bold EXAMPLES}
109
-
110
- $ ggt dev
111
- $ ggt dev ~/gadget/example
112
- $ ggt dev ~/gadget/example
113
- $ ggt dev ~/gadget/example --app=example
114
- $ ggt dev ~/gadget/example --app=example --env=development --prefer=local
115
-
116
- {bold ARGUMENTS}
117
-
118
- DIRECTORY
119
- The path to the directory to synchronize files to.
120
- The directory will be created if it does not exist.
121
-
122
- Defaults to the current working directory. (default: ".")
123
-
124
- {bold FLAGS}
125
-
126
- -a, --app, --application=<name>
127
- The application to synchronize files with.
128
-
129
- Defaults to the application within the ".gadget/sync.json"
130
- file in the chosen directory or any parent directories.
131
-
132
- -e, --env, --environment=<name>
133
- The development environment to synchronize files with.
134
-
135
- Defaults to the environment within the ".gadget/sync.json"
136
- file in the chosen directory or any parent directories.
137
-
138
- --prefer=<filesystem>
139
- Which filesystem's changes to automatically keep when
140
- conflicting changes are detected.
141
-
142
- Must be one of "local" or "environment".
143
-
144
- If not provided, "ggt dev" will pause when conflicting changes
145
- are detected and you will be prompted to choose which changes to
146
- keep before "ggt dev" resumes.
147
-
148
- --allow-unknown-directory
149
- Allows "ggt dev" to continue when the chosen directory, nor
150
- any parent directories, contain a ".gadget/sync.json" file
151
- within it.
152
-
153
- Defaults to false.
154
-
155
- --allow-different-app
156
- Allows "ggt dev" to continue with a different "--app" than the
157
- one found within the ".gadget/sync.json" file.
158
-
159
- Defaults to false.
160
-
161
- Run "ggt dev -h" for less information.
49
+ Clones your Gadget environment's files to your local machine and keeps it in sync, in order to
50
+ enable local development with your text editor and source code with Git.
51
+
52
+ If your app's local directory already exists, this command first performs a sync to ensure
53
+ that your local and environment directories match, changes are tracked since last sync. If any
54
+ conflicts are detected, they must be resolved before development starts.
55
+
56
+ {gray Usage}
57
+ $ ggt dev [DIRECTORY] [options]
58
+
59
+ DIRECTORY: The directory to sync files to (default: the current directory)
60
+
61
+ {gray Options}
62
+ -a, --app <app_name> Selects the app to sync files with. Default set on ".gadget/sync.json"
63
+ -e, --env <env_name> Selects the environment to sync files with. Default set on ".gadget/sync.json"
64
+ --prefer <source> Auto-select changes from 'local' or 'environment' source on conflict
65
+ --allow-unknown-directory Syncs to any local directory with existing files, even if the ".gadget/sync.json" file is missing
66
+ --allow-different-app Syncs with a different app using the --app command, instead of the one specified in the .gadget/sync.json file
67
+
68
+ {gray Ignoring files}
69
+ ggt dev uses a .ignore file, similar to .gitignore, to exclude specific files and
70
+ folders from syncing. These files are always ignored:
71
+
72
+ .DS_Store
73
+ .gadget
74
+ .git
75
+ • node_modules
76
+
77
+ {gray Notes}
78
+ • "ggt dev" only works with development environments
79
+ "ggt dev" only supports "yarn" v1 for installing dependencies
80
+ • Avoid deleting or moving all of your files while "ggt dev" is running
81
+
82
+ {gray Examples}
83
+ sync an app in a custom path
84
+ {cyanBright $ ggt dev ~/myGadgetApps/myBlog --app myBlogApp}
85
+
86
+ sync with a specific environment and preselect all local changes on conflicts
87
+ {cyanBright $ ggt dev --env main --prefer local}
88
+
89
+ sync a custom path with a specific app, environment and preselect all changes from local on conflicts
90
+ {cyanBright $ ggt dev ~/gadget/example --app=example --env=development --prefer=local}
162
91
  `;
163
92
  };
164
93
  export const command = async (ctx)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/dev.ts"],"sourcesContent":["import dayjs from \"dayjs\";\nimport ms from \"ms\";\nimport path from \"node:path\";\nimport Watcher from \"watcher\";\nimport which from \"which\";\nimport type { ArgsDefinition } from \"../services/command/arg.js\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport type { Context } from \"../services/command/context.js\";\nimport { Changes } from \"../services/filesync/changes.js\";\nimport { YarnNotFoundError } from \"../services/filesync/error.js\";\nimport { FileSync } from \"../services/filesync/filesync.js\";\nimport { FileSyncStrategy, MergeConflictPreferenceArg } from \"../services/filesync/strategy.js\";\nimport { SyncJson, SyncJsonArgs, loadSyncJsonDirectory } from \"../services/filesync/sync-json.js\";\nimport { footer } from \"../services/output/footer.js\";\nimport { notify } from \"../services/output/notify.js\";\nimport { println } from \"../services/output/print.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { select } from \"../services/output/select.js\";\nimport { spin } from \"../services/output/spinner.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { symbol } from \"../services/output/symbols.js\";\nimport { unreachable } from \"../services/util/assert.js\";\nimport { debounceAsync } from \"../services/util/function.js\";\nimport { isAbortError } from \"../services/util/is.js\";\nimport { delay } from \"../services/util/promise.js\";\nimport type { PullArgs } from \"./pull.js\";\nimport type { PushArgs } from \"./push.js\";\n\nexport type DevArgs = typeof args;\n\nexport const args = {\n ...SyncJsonArgs,\n \"--prefer\": MergeConflictPreferenceArg,\n \"--file-push-delay\": { type: Number, default: ms(\"100ms\") },\n \"--file-watch-debounce\": { type: Number, default: ms(\"300ms\") },\n \"--file-watch-poll-interval\": { type: Number, default: ms(\"3s\") },\n \"--file-watch-poll-timeout\": { type: Number, default: ms(\"20s\") },\n \"--file-watch-rename-timeout\": { type: Number, default: ms(\"1.25s\") },\n} satisfies ArgsDefinition;\n\nexport const usage: Usage = (ctx) => {\n if (ctx.args[\"-h\"]) {\n return sprint`\n Develop your app by synchronizing your local files with your\n environment's files, in real-time. Changes are tracked from\n the last \"ggt dev\", \"ggt push\", or \"ggt pull\" run locally.\n\n {bold USAGE}\n ggt dev [DIRECTORY]\n\n {bold EXAMPLES}\n $ ggt dev\n $ ggt dev ~/gadget/example\n $ ggt dev ~/gadget/example\n $ ggt dev ~/gadget/example --app=example\n $ ggt dev ~/gadget/example --app=example --env=development --prefer=local\n\n {bold ARGUMENTS}\n DIRECTORY The directory to synchronize files to (default: \".\")\n\n {bold FLAGS}\n -a, --app=<name> The application to synchronize files with\n -e, --env=<name> The environment to synchronize files with\n --prefer=<filesystem> Prefer \"local\" or \"environment\" conflicting changes\n\n Run \"ggt dev --help\" for more information.\n `;\n }\n\n return sprint`\n Develop your app by synchronizing your local files with your\n environment's files, in real-time. Changes are tracked from\n the last \"ggt dev\", \"ggt push\", or \"ggt pull\" run locally.\n\n While \"ggt dev\" is running, changes on your local filesystem are\n immediately pushed to your environment, while file changes on\n your environment are immediately pulled to your local filesystem.\n\n If conflicting changes are detected, and \"--prefer\" is not passed,\n you will be prompted to choose which changes to keep before\n \"ggt dev\" resumes.\n\n \"ggt dev\" looks for an \".ignore\" file to exclude files and\n directories from being pushed or pulled. The format is identical\n to Git's.\n\n The following files and directories are always ignored:\n • .DS_Store\n • .gadget\n • .git\n • node_modules\n\n Note:\n • \"ggt dev\" only works with development environments\n • \"ggt dev\" only supports \"yarn\" v1 for installing dependencies\n • Avoid deleting or moving all of your files while \"ggt dev\" is running\n\n {bold USAGE}\n\n ggt dev [DIRECTORY] [--app=<name>] [--env=<name>] [--prefer=<filesystem>]\n [--allow-unknown-directory] [--allow-different-app]\n\n {bold EXAMPLES}\n\n $ ggt dev\n $ ggt dev ~/gadget/example\n $ ggt dev ~/gadget/example\n $ ggt dev ~/gadget/example --app=example\n $ ggt dev ~/gadget/example --app=example --env=development --prefer=local\n\n {bold ARGUMENTS}\n\n DIRECTORY\n The path to the directory to synchronize files to.\n The directory will be created if it does not exist.\n\n Defaults to the current working directory. (default: \".\")\n\n {bold FLAGS}\n\n -a, --app, --application=<name>\n The application to synchronize files with.\n\n Defaults to the application within the \".gadget/sync.json\"\n file in the chosen directory or any parent directories.\n\n -e, --env, --environment=<name>\n The development environment to synchronize files with.\n\n Defaults to the environment within the \".gadget/sync.json\"\n file in the chosen directory or any parent directories.\n\n --prefer=<filesystem>\n Which filesystem's changes to automatically keep when\n conflicting changes are detected.\n\n Must be one of \"local\" or \"environment\".\n\n If not provided, \"ggt dev\" will pause when conflicting changes\n are detected and you will be prompted to choose which changes to\n keep before \"ggt dev\" resumes.\n\n --allow-unknown-directory\n Allows \"ggt dev\" to continue when the chosen directory, nor\n any parent directories, contain a \".gadget/sync.json\" file\n within it.\n\n Defaults to false.\n\n --allow-different-app\n Allows \"ggt dev\" to continue with a different \"--app\" than the\n one found within the \".gadget/sync.json\" file.\n\n Defaults to false.\n\n Run \"ggt dev -h\" for less information.\n `;\n};\n\nexport const command: Command<DevArgs> = async (ctx) => {\n if (!(await which(\"yarn\", { nothrow: true }))) {\n throw new YarnNotFoundError();\n }\n\n const directory = await loadSyncJsonDirectory(ctx.args._[0] || process.cwd());\n const syncJson = await SyncJson.loadOrInit(ctx, { directory });\n footer({ ensureEmptyLineAbove: true })(syncJson.sprint());\n\n const filesync = new FileSync(syncJson);\n const hashes = await filesync.hashes(ctx);\n\n if (!hashes.inSync) {\n // our local files don't match our environment's files\n if (!syncJson.previousEnvironment || (hashes.localChangesToPush.size === 0 && hashes.onlyDotGadgetFilesChanged)) {\n // one of the following is true:\n // - we're developing on this environment for the first time\n // - we're developing on the same environment as last time\n // - we're developing on a different environment, but only .gadget/ files have changed\n // merge the changes (if any) and continue\n await filesync.merge(ctx, {\n hashes,\n printLocalChangesOptions: {\n limit: 5,\n },\n printEnvironmentChangesOptions: {\n limit: 5,\n },\n });\n } else {\n // we're switching environment's and files outside of .gadget/\n // have changed, so ask the user what to do\n await filesync.print(ctx, { hashes });\n const choices = Object.values(FileSyncStrategy);\n\n const strategy = await select({\n ensureEmptyLineAbove: true,\n choices: hashes.bothChanged ? choices : choices.filter((choice) => choice !== FileSyncStrategy.MERGE),\n formatChoice: (choice) => {\n switch (choice) {\n case FileSyncStrategy.CANCEL:\n return sprint`Cancel (Ctrl+C)`;\n case FileSyncStrategy.MERGE:\n return sprint`Merge local and environment's changes`;\n case FileSyncStrategy.PUSH:\n switch (true) {\n case hashes.bothChanged:\n return sprint`Push local changes and {underline discard environment's} changes`;\n case hashes.localChanges.size > 0:\n return sprint`Push local changes`;\n case hashes.environmentChanges.size > 0:\n return sprint`Discard environment's changes`;\n default:\n return unreachable(\"no changes to push or discard\");\n }\n case FileSyncStrategy.PULL:\n switch (true) {\n case hashes.bothChanged:\n return sprint`Pull environment's changes and {underline discard local} changes`;\n case hashes.localChanges.size > 0:\n return sprint`Discard local changes`;\n case hashes.environmentChanges.size > 0:\n return sprint`Pull environment's changes`;\n default:\n return unreachable(\"no changes to pull or discard\");\n }\n }\n },\n })`\n {bold What do you want to do?}\n `;\n\n switch (strategy) {\n case FileSyncStrategy.CANCEL:\n process.exit(0);\n break;\n case FileSyncStrategy.MERGE:\n await filesync.merge(ctx, { hashes });\n break;\n case FileSyncStrategy.PUSH:\n await filesync.push(ctx as unknown as Context<PushArgs>, { hashes, force: true });\n break;\n case FileSyncStrategy.PULL:\n await filesync.pull(ctx as unknown as Context<PullArgs>, { hashes, force: true });\n break;\n }\n }\n }\n\n /**\n * A list of filepaths that have changed because we (this ggt process)\n * modified them. This is used to avoid reacting to filesystem events\n * that we caused, which would cause an infinite loop.\n */\n const recentWritesToLocalFilesystem = new Map<string, number>();\n\n const clearRecentWritesInterval = setInterval(() => {\n for (const [path, timestamp] of recentWritesToLocalFilesystem) {\n if (dayjs().isAfter(timestamp + ms(\"5s\"))) {\n // this change should have been seen by now\n recentWritesToLocalFilesystem.delete(path);\n }\n }\n }, ms(\"1s\")).unref();\n\n /**\n * Subscribe to file changes on Gadget and apply them to the local\n * filesystem.\n */\n const filesyncSubscription = filesync.subscribeToEnvironmentChanges(ctx, {\n onError: (error) => ctx.abort(error),\n beforeChanges: ({ changed, deleted }) => {\n // add all the files and directories we're about to touch to\n // recentWritesToLocalFilesystem so that we don't send them back\n // to Gadget\n for (const filepath of [...changed, ...deleted]) {\n recentWritesToLocalFilesystem.set(filepath, Date.now());\n\n let dir = path.dirname(filepath);\n while (dir !== \".\") {\n recentWritesToLocalFilesystem.set(dir + \"/\", Date.now());\n dir = path.dirname(dir);\n }\n }\n },\n });\n\n /**\n * A buffer of local file changes to send to Gadget.\n */\n const localChangesBuffer = new Changes();\n\n /**\n * A debounced function that sends the local file changes to Gadget.\n */\n const mergeChangesWithEnvironment = debounceAsync(ctx.args[\"--file-push-delay\"], async (): Promise<void> => {\n try {\n const lastGitBranch = syncJson.gitBranch;\n await syncJson.loadGitBranch();\n\n if (lastGitBranch !== syncJson.gitBranch) {\n println({ ensureEmptyLineAbove: true })`\n Your git branch changed.\n\n ${lastGitBranch} → ${syncJson.gitBranch}\n `;\n\n // we need all the changes to be sent in a single batch, so wait\n // a bit in case there are changes the watcher hasn't seen yet\n const spinner = spin({ ensureEmptyLineAbove: true })(\"Waiting for file changes to settle.\");\n await delay(\"3s\"); // this time was chosen arbitrarily\n spinner.succeed();\n }\n\n const changes = new Changes(localChangesBuffer.entries());\n localChangesBuffer.clear();\n\n await filesync.mergeChangesWithEnvironment(ctx, { changes });\n } catch (error) {\n ctx.log.error(\"error sending changes to gadget\", { error });\n ctx.abort(error);\n }\n });\n\n ctx.log.debug(\"watching\", { path: syncJson.directory.path });\n\n /**\n * Watches the local filesystem for changes.\n */\n const fileWatcher = new Watcher(\n syncJson.directory.path,\n {\n // don't emit an event for every watched file when we start watching\n ignoreInitial: true,\n // watch everything\n recursive: true,\n // don't emit changes to .gadget/ files because they're readonly (Gadget manages them)\n ignore: (path: string) => syncJson.directory.relative(path).startsWith(\".gadget\") || syncJson.directory.ignores(path),\n // emit rename/renameDir events\n renameDetection: true,\n // how long to wait for an add event to be followed by an unlink\n // event, and vice versa (i.e. a rename event)\n renameTimeout: ctx.args[\"--file-watch-rename-timeout\"],\n // how long to wait before emitting a change event (helps avoid duplicate events)\n debounce: ctx.args[\"--file-watch-debounce\"],\n },\n (event: string, absolutePath: string, renamedPath: string) => {\n const filepath = event === \"rename\" || event === \"renameDir\" ? renamedPath : absolutePath;\n const isDirectory = event === \"renameDir\" || event === \"addDir\" || event === \"unlinkDir\";\n const normalizedPath = syncJson.directory.normalize(filepath, isDirectory);\n\n ctx.log.trace(\"file event\", { event, isDirectory, path: normalizedPath });\n\n if (filepath === syncJson.directory.absolute(\".ignore\")) {\n syncJson.directory.loadIgnoreFile().catch((error) => ctx.abort(error));\n } else if (syncJson.directory.ignores(filepath)) {\n return;\n }\n\n if (recentWritesToLocalFilesystem.delete(normalizedPath)) {\n ctx.log.trace(\"ignoring event because we caused it\", { event, path: normalizedPath });\n return;\n }\n\n switch (event) {\n case \"add\":\n case \"addDir\":\n localChangesBuffer.set(normalizedPath, { type: \"create\" });\n break;\n case \"rename\":\n case \"renameDir\": {\n const oldNormalizedPath = syncJson.directory.normalize(absolutePath, isDirectory);\n localChangesBuffer.set(normalizedPath, { type: \"create\", oldPath: oldNormalizedPath });\n break;\n }\n case \"change\": {\n localChangesBuffer.set(normalizedPath, { type: \"update\" });\n break;\n }\n case \"unlink\":\n case \"unlinkDir\": {\n localChangesBuffer.set(normalizedPath, { type: \"delete\" });\n break;\n }\n }\n\n mergeChangesWithEnvironment();\n },\n ).once(\"error\", (error) => ctx.abort(error));\n\n ctx.onAbort(async (reason) => {\n ctx.log.info(\"stopping\", { reason });\n\n filesyncSubscription.unsubscribe();\n fileWatcher.close();\n clearInterval(clearRecentWritesInterval);\n await mergeChangesWithEnvironment.flush();\n\n try {\n await filesync.idle();\n } catch (error) {\n ctx.log.error(\"error while waiting for idle\", { error });\n }\n\n if (isAbortError(reason)) {\n return;\n }\n\n notify(ctx, { subtitle: \"Uh oh!\", message: \"An error occurred while syncing files\" });\n await reportErrorAndExit(ctx, reason);\n });\n\n footer({ ensureEmptyLineAbove: true })`\n${syncJson.sprint({ indent: 4 })}\n\n Waiting for file changes${symbol.ellipsis} {gray Press Ctrl+C to stop}\n `;\n};\n"],"names":["dayjs","ms","path","Watcher","which","Changes","YarnNotFoundError","FileSync","FileSyncStrategy","MergeConflictPreferenceArg","SyncJson","SyncJsonArgs","loadSyncJsonDirectory","footer","notify","println","reportErrorAndExit","select","spin","sprint","symbol","unreachable","debounceAsync","isAbortError","delay","args","type","Number","default","usage","ctx","command","nothrow","directory","_","process","cwd","syncJson","loadOrInit","ensureEmptyLineAbove","filesync","hashes","inSync","previousEnvironment","localChangesToPush","size","onlyDotGadgetFilesChanged","merge","printLocalChangesOptions","limit","printEnvironmentChangesOptions","print","choices","Object","values","strategy","bothChanged","filter","choice","MERGE","formatChoice","CANCEL","PUSH","localChanges","environmentChanges","PULL","exit","push","force","pull","recentWritesToLocalFilesystem","Map","clearRecentWritesInterval","setInterval","timestamp","isAfter","delete","unref","filesyncSubscription","subscribeToEnvironmentChanges","onError","error","abort","beforeChanges","changed","deleted","filepath","set","Date","now","dir","dirname","localChangesBuffer","mergeChangesWithEnvironment","lastGitBranch","gitBranch","loadGitBranch","spinner","succeed","changes","entries","clear","log","debug","fileWatcher","ignoreInitial","recursive","ignore","relative","startsWith","ignores","renameDetection","renameTimeout","debounce","event","absolutePath","renamedPath","isDirectory","normalizedPath","normalize","trace","absolute","loadIgnoreFile","catch","oldNormalizedPath","oldPath","once","onAbort","reason","info","unsubscribe","close","clearInterval","flush","idle","subtitle","message","indent","ellipsis"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/dev.ts"],"sourcesContent":["import dayjs from \"dayjs\";\nimport ms from \"ms\";\nimport path from \"node:path\";\nimport Watcher from \"watcher\";\nimport which from \"which\";\nimport type { ArgsDefinition } from \"../services/command/arg.js\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport type { Context } from \"../services/command/context.js\";\nimport { Changes } from \"../services/filesync/changes.js\";\nimport { YarnNotFoundError } from \"../services/filesync/error.js\";\nimport { FileSync } from \"../services/filesync/filesync.js\";\nimport { FileSyncStrategy, MergeConflictPreferenceArg } from \"../services/filesync/strategy.js\";\nimport { SyncJson, SyncJsonArgs, loadSyncJsonDirectory } from \"../services/filesync/sync-json.js\";\nimport { footer } from \"../services/output/footer.js\";\nimport { notify } from \"../services/output/notify.js\";\nimport { println } from \"../services/output/print.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { select } from \"../services/output/select.js\";\nimport { spin } from \"../services/output/spinner.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { symbol } from \"../services/output/symbols.js\";\nimport { unreachable } from \"../services/util/assert.js\";\nimport { debounceAsync } from \"../services/util/function.js\";\nimport { isAbortError } from \"../services/util/is.js\";\nimport { delay } from \"../services/util/promise.js\";\nimport type { PullArgs } from \"./pull.js\";\nimport type { PushArgs } from \"./push.js\";\n\nexport type DevArgs = typeof args;\n\nexport const args = {\n ...SyncJsonArgs,\n \"--prefer\": MergeConflictPreferenceArg,\n \"--file-push-delay\": { type: Number, default: ms(\"100ms\") },\n \"--file-watch-debounce\": { type: Number, default: ms(\"300ms\") },\n \"--file-watch-poll-interval\": { type: Number, default: ms(\"3s\") },\n \"--file-watch-poll-timeout\": { type: Number, default: ms(\"20s\") },\n \"--file-watch-rename-timeout\": { type: Number, default: ms(\"1.25s\") },\n} satisfies ArgsDefinition;\n\nexport const usage: Usage = (_ctx) => {\n return sprint`\n Clones your Gadget environment's files to your local machine and keeps it in sync, in order to\n enable local development with your text editor and source code with Git.\n\n If your app's local directory already exists, this command first performs a sync to ensure\n that your local and environment directories match, changes are tracked since last sync. If any \n conflicts are detected, they must be resolved before development starts.\n\n {gray Usage}\n $ ggt dev [DIRECTORY] [options]\n\n DIRECTORY: The directory to sync files to (default: the current directory)\n \n {gray Options}\n -a, --app <app_name> Selects the app to sync files with. Default set on \".gadget/sync.json\"\n -e, --env <env_name> Selects the environment to sync files with. Default set on \".gadget/sync.json\"\n --prefer <source> Auto-select changes from 'local' or 'environment' source on conflict\n --allow-unknown-directory Syncs to any local directory with existing files, even if the \".gadget/sync.json\" file is missing\n --allow-different-app Syncs with a different app using the --app command, instead of the one specified in the .gadget/sync.json file\n\n {gray Ignoring files}\n ggt dev uses a .ignore file, similar to .gitignore, to exclude specific files and \n folders from syncing. These files are always ignored:\n\n • .DS_Store\n • .gadget\n • .git\n • node_modules\n \n {gray Notes}\n • \"ggt dev\" only works with development environments\n • \"ggt dev\" only supports \"yarn\" v1 for installing dependencies\n • Avoid deleting or moving all of your files while \"ggt dev\" is running\n \n {gray Examples}\n sync an app in a custom path \n {cyanBright $ ggt dev ~/myGadgetApps/myBlog --app myBlogApp}\n \n sync with a specific environment and preselect all local changes on conflicts\n {cyanBright $ ggt dev --env main --prefer local}\n\n sync a custom path with a specific app, environment and preselect all changes from local on conflicts\n {cyanBright $ ggt dev ~/gadget/example --app=example --env=development --prefer=local}\n `;\n};\n\nexport const command: Command<DevArgs> = async (ctx) => {\n if (!(await which(\"yarn\", { nothrow: true }))) {\n throw new YarnNotFoundError();\n }\n\n const directory = await loadSyncJsonDirectory(ctx.args._[0] || process.cwd());\n const syncJson = await SyncJson.loadOrInit(ctx, { directory });\n footer({ ensureEmptyLineAbove: true })(syncJson.sprint());\n\n const filesync = new FileSync(syncJson);\n const hashes = await filesync.hashes(ctx);\n\n if (!hashes.inSync) {\n // our local files don't match our environment's files\n if (!syncJson.previousEnvironment || (hashes.localChangesToPush.size === 0 && hashes.onlyDotGadgetFilesChanged)) {\n // one of the following is true:\n // - we're developing on this environment for the first time\n // - we're developing on the same environment as last time\n // - we're developing on a different environment, but only .gadget/ files have changed\n // merge the changes (if any) and continue\n await filesync.merge(ctx, {\n hashes,\n printLocalChangesOptions: {\n limit: 5,\n },\n printEnvironmentChangesOptions: {\n limit: 5,\n },\n });\n } else {\n // we're switching environment's and files outside of .gadget/\n // have changed, so ask the user what to do\n await filesync.print(ctx, { hashes });\n const choices = Object.values(FileSyncStrategy);\n\n const strategy = await select({\n ensureEmptyLineAbove: true,\n choices: hashes.bothChanged ? choices : choices.filter((choice) => choice !== FileSyncStrategy.MERGE),\n formatChoice: (choice) => {\n switch (choice) {\n case FileSyncStrategy.CANCEL:\n return sprint`Cancel (Ctrl+C)`;\n case FileSyncStrategy.MERGE:\n return sprint`Merge local and environment's changes`;\n case FileSyncStrategy.PUSH:\n switch (true) {\n case hashes.bothChanged:\n return sprint`Push local changes and {underline discard environment's} changes`;\n case hashes.localChanges.size > 0:\n return sprint`Push local changes`;\n case hashes.environmentChanges.size > 0:\n return sprint`Discard environment's changes`;\n default:\n return unreachable(\"no changes to push or discard\");\n }\n case FileSyncStrategy.PULL:\n switch (true) {\n case hashes.bothChanged:\n return sprint`Pull environment's changes and {underline discard local} changes`;\n case hashes.localChanges.size > 0:\n return sprint`Discard local changes`;\n case hashes.environmentChanges.size > 0:\n return sprint`Pull environment's changes`;\n default:\n return unreachable(\"no changes to pull or discard\");\n }\n }\n },\n })`\n {bold What do you want to do?}\n `;\n\n switch (strategy) {\n case FileSyncStrategy.CANCEL:\n process.exit(0);\n break;\n case FileSyncStrategy.MERGE:\n await filesync.merge(ctx, { hashes });\n break;\n case FileSyncStrategy.PUSH:\n await filesync.push(ctx as unknown as Context<PushArgs>, { hashes, force: true });\n break;\n case FileSyncStrategy.PULL:\n await filesync.pull(ctx as unknown as Context<PullArgs>, { hashes, force: true });\n break;\n }\n }\n }\n\n /**\n * A list of filepaths that have changed because we (this ggt process)\n * modified them. This is used to avoid reacting to filesystem events\n * that we caused, which would cause an infinite loop.\n */\n const recentWritesToLocalFilesystem = new Map<string, number>();\n\n const clearRecentWritesInterval = setInterval(() => {\n for (const [path, timestamp] of recentWritesToLocalFilesystem) {\n if (dayjs().isAfter(timestamp + ms(\"5s\"))) {\n // this change should have been seen by now\n recentWritesToLocalFilesystem.delete(path);\n }\n }\n }, ms(\"1s\")).unref();\n\n /**\n * Subscribe to file changes on Gadget and apply them to the local\n * filesystem.\n */\n const filesyncSubscription = filesync.subscribeToEnvironmentChanges(ctx, {\n onError: (error) => ctx.abort(error),\n beforeChanges: ({ changed, deleted }) => {\n // add all the files and directories we're about to touch to\n // recentWritesToLocalFilesystem so that we don't send them back\n // to Gadget\n for (const filepath of [...changed, ...deleted]) {\n recentWritesToLocalFilesystem.set(filepath, Date.now());\n\n let dir = path.dirname(filepath);\n while (dir !== \".\") {\n recentWritesToLocalFilesystem.set(dir + \"/\", Date.now());\n dir = path.dirname(dir);\n }\n }\n },\n });\n\n /**\n * A buffer of local file changes to send to Gadget.\n */\n const localChangesBuffer = new Changes();\n\n /**\n * A debounced function that sends the local file changes to Gadget.\n */\n const mergeChangesWithEnvironment = debounceAsync(ctx.args[\"--file-push-delay\"], async (): Promise<void> => {\n try {\n const lastGitBranch = syncJson.gitBranch;\n await syncJson.loadGitBranch();\n\n if (lastGitBranch !== syncJson.gitBranch) {\n println({ ensureEmptyLineAbove: true })`\n Your git branch changed.\n\n ${lastGitBranch} → ${syncJson.gitBranch}\n `;\n\n // we need all the changes to be sent in a single batch, so wait\n // a bit in case there are changes the watcher hasn't seen yet\n const spinner = spin({ ensureEmptyLineAbove: true })(\"Waiting for file changes to settle.\");\n await delay(\"3s\"); // this time was chosen arbitrarily\n spinner.succeed();\n }\n\n const changes = new Changes(localChangesBuffer.entries());\n localChangesBuffer.clear();\n\n await filesync.mergeChangesWithEnvironment(ctx, { changes });\n } catch (error) {\n ctx.log.error(\"error sending changes to gadget\", { error });\n ctx.abort(error);\n }\n });\n\n ctx.log.debug(\"watching\", { path: syncJson.directory.path });\n\n /**\n * Watches the local filesystem for changes.\n */\n const fileWatcher = new Watcher(\n syncJson.directory.path,\n {\n // don't emit an event for every watched file when we start watching\n ignoreInitial: true,\n // watch everything\n recursive: true,\n // don't emit changes to .gadget/ files because they're readonly (Gadget manages them)\n ignore: (path: string) => syncJson.directory.relative(path).startsWith(\".gadget\") || syncJson.directory.ignores(path),\n // emit rename/renameDir events\n renameDetection: true,\n // how long to wait for an add event to be followed by an unlink\n // event, and vice versa (i.e. a rename event)\n renameTimeout: ctx.args[\"--file-watch-rename-timeout\"],\n // how long to wait before emitting a change event (helps avoid duplicate events)\n debounce: ctx.args[\"--file-watch-debounce\"],\n },\n (event: string, absolutePath: string, renamedPath: string) => {\n const filepath = event === \"rename\" || event === \"renameDir\" ? renamedPath : absolutePath;\n const isDirectory = event === \"renameDir\" || event === \"addDir\" || event === \"unlinkDir\";\n const normalizedPath = syncJson.directory.normalize(filepath, isDirectory);\n\n ctx.log.trace(\"file event\", { event, isDirectory, path: normalizedPath });\n\n if (filepath === syncJson.directory.absolute(\".ignore\")) {\n syncJson.directory.loadIgnoreFile().catch((error) => ctx.abort(error));\n } else if (syncJson.directory.ignores(filepath)) {\n return;\n }\n\n if (recentWritesToLocalFilesystem.delete(normalizedPath)) {\n ctx.log.trace(\"ignoring event because we caused it\", { event, path: normalizedPath });\n return;\n }\n\n switch (event) {\n case \"add\":\n case \"addDir\":\n localChangesBuffer.set(normalizedPath, { type: \"create\" });\n break;\n case \"rename\":\n case \"renameDir\": {\n const oldNormalizedPath = syncJson.directory.normalize(absolutePath, isDirectory);\n localChangesBuffer.set(normalizedPath, { type: \"create\", oldPath: oldNormalizedPath });\n break;\n }\n case \"change\": {\n localChangesBuffer.set(normalizedPath, { type: \"update\" });\n break;\n }\n case \"unlink\":\n case \"unlinkDir\": {\n localChangesBuffer.set(normalizedPath, { type: \"delete\" });\n break;\n }\n }\n\n mergeChangesWithEnvironment();\n },\n ).once(\"error\", (error) => ctx.abort(error));\n\n ctx.onAbort(async (reason) => {\n ctx.log.info(\"stopping\", { reason });\n\n filesyncSubscription.unsubscribe();\n fileWatcher.close();\n clearInterval(clearRecentWritesInterval);\n await mergeChangesWithEnvironment.flush();\n\n try {\n await filesync.idle();\n } catch (error) {\n ctx.log.error(\"error while waiting for idle\", { error });\n }\n\n if (isAbortError(reason)) {\n return;\n }\n\n notify(ctx, { subtitle: \"Uh oh!\", message: \"An error occurred while syncing files\" });\n await reportErrorAndExit(ctx, reason);\n });\n\n footer({ ensureEmptyLineAbove: true })`\n${syncJson.sprint({ indent: 4 })}\n\n Waiting for file changes${symbol.ellipsis} {gray Press Ctrl+C to stop}\n `;\n};\n"],"names":["dayjs","ms","path","Watcher","which","Changes","YarnNotFoundError","FileSync","FileSyncStrategy","MergeConflictPreferenceArg","SyncJson","SyncJsonArgs","loadSyncJsonDirectory","footer","notify","println","reportErrorAndExit","select","spin","sprint","symbol","unreachable","debounceAsync","isAbortError","delay","args","type","Number","default","usage","_ctx","command","ctx","nothrow","directory","_","process","cwd","syncJson","loadOrInit","ensureEmptyLineAbove","filesync","hashes","inSync","previousEnvironment","localChangesToPush","size","onlyDotGadgetFilesChanged","merge","printLocalChangesOptions","limit","printEnvironmentChangesOptions","print","choices","Object","values","strategy","bothChanged","filter","choice","MERGE","formatChoice","CANCEL","PUSH","localChanges","environmentChanges","PULL","exit","push","force","pull","recentWritesToLocalFilesystem","Map","clearRecentWritesInterval","setInterval","timestamp","isAfter","delete","unref","filesyncSubscription","subscribeToEnvironmentChanges","onError","error","abort","beforeChanges","changed","deleted","filepath","set","Date","now","dir","dirname","localChangesBuffer","mergeChangesWithEnvironment","lastGitBranch","gitBranch","loadGitBranch","spinner","succeed","changes","entries","clear","log","debug","fileWatcher","ignoreInitial","recursive","ignore","relative","startsWith","ignores","renameDetection","renameTimeout","debounce","event","absolutePath","renamedPath","isDirectory","normalizedPath","normalize","trace","absolute","loadIgnoreFile","catch","oldNormalizedPath","oldPath","once","onAbort","reason","info","unsubscribe","close","clearInterval","flush","idle","subtitle","message","indent","ellipsis"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -5,13 +5,10 @@ import { sprint, sprintln } from "../services/output/sprint.js";
5
5
  import { printTable } from "../services/output/table.js";
6
6
  import { getUserOrLogin } from "../services/user/user.js";
7
7
  export const usage = ()=>sprint`
8
- List your available applications.
8
+ List the apps available to the currently logged-in user.
9
9
 
10
- {bold USAGE}
11
- ggt list
12
-
13
- {bold EXAMPLES}
14
- $ ggt list
10
+ {bold Usage}
11
+ ggt list
15
12
  `;
16
13
  export const command = async (ctx)=>{
17
14
  await getUserOrLogin(ctx);
@@ -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 { output } from \"../services/output/output.js\";\nimport { println } from \"../services/output/print.js\";\nimport { sprint, sprintln } from \"../services/output/sprint.js\";\nimport { printTable } from \"../services/output/table.js\";\nimport { getUserOrLogin } from \"../services/user/user.js\";\n\nexport const usage: Usage = () => sprint`\n List your available applications.\n\n {bold USAGE}\n ggt list\n\n {bold EXAMPLES}\n $ ggt list\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 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 if (output.isInteractive) {\n printTable({\n json: apps,\n headers: [\"Name\", \"Domain\"],\n rows: apps.map((app) => [app.slug, app.primaryDomain]),\n });\n } else {\n let simpleOutput = \"\";\n for (const app of apps) {\n simpleOutput += sprintln`${app.slug}\\t${app.primaryDomain}`;\n }\n\n println({ json: apps })(simpleOutput);\n }\n};\n"],"names":["getApps","output","println","sprint","sprintln","printTable","getUserOrLogin","usage","command","ctx","apps","length","isInteractive","json","headers","rows","map","app","slug","primaryDomain","simpleOutput"],"mappings":"AAAA,SAASA,OAAO,QAAQ,yBAAyB;AAEjD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,OAAO,QAAQ,8BAA8B;AACtD,SAASC,MAAM,EAAEC,QAAQ,QAAQ,+BAA+B;AAChE,SAASC,UAAU,QAAQ,8BAA8B;AACzD,SAASC,cAAc,QAAQ,2BAA2B;AAE1D,OAAO,MAAMC,QAAe,IAAMJ,MAAM,CAAC;;;;;;;;AAQzC,CAAC,CAAC;AAEF,OAAO,MAAMK,UAAmB,OAAOC;IACrC,MAAMH,eAAeG;IAErB,MAAMC,OAAO,MAAMV,QAAQS;IAC3B,IAAIC,KAAKC,MAAM,KAAK,GAAG;QACrBT,OAAO,CAAC;;;;IAIR,CAAC;QACD;IACF;IAEA,IAAID,OAAOW,aAAa,EAAE;QACxBP,WAAW;YACTQ,MAAMH;YACNI,SAAS;gBAAC;gBAAQ;aAAS;YAC3BC,MAAML,KAAKM,GAAG,CAAC,CAACC,MAAQ;oBAACA,IAAIC,IAAI;oBAAED,IAAIE,aAAa;iBAAC;QACvD;IACF,OAAO;QACL,IAAIC,eAAe;QACnB,KAAK,MAAMH,OAAOP,KAAM;YACtBU,gBAAgBhB,QAAQ,CAAC,EAAEa,IAAIC,IAAI,CAAC,EAAE,EAAED,IAAIE,aAAa,CAAC,CAAC;QAC7D;QAEAjB,QAAQ;YAAEW,MAAMH;QAAK,GAAGU;IAC1B;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 { output } from \"../services/output/output.js\";\nimport { println } from \"../services/output/print.js\";\nimport { sprint, sprintln } from \"../services/output/sprint.js\";\nimport { printTable } from \"../services/output/table.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\nexport const command: Command = async (ctx) => {\n await getUserOrLogin(ctx);\n\n const apps = await getApps(ctx);\n if (apps.length === 0) {\n 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 if (output.isInteractive) {\n printTable({\n json: apps,\n headers: [\"Name\", \"Domain\"],\n rows: apps.map((app) => [app.slug, app.primaryDomain]),\n });\n } else {\n let simpleOutput = \"\";\n for (const app of apps) {\n simpleOutput += sprintln`${app.slug}\\t${app.primaryDomain}`;\n }\n\n println({ json: apps })(simpleOutput);\n }\n};\n"],"names":["getApps","output","println","sprint","sprintln","printTable","getUserOrLogin","usage","command","ctx","apps","length","isInteractive","json","headers","rows","map","app","slug","primaryDomain","simpleOutput"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,OAAO,QAAQ,yBAAyB;AAEjD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,OAAO,QAAQ,8BAA8B;AACtD,SAASC,MAAM,EAAEC,QAAQ,QAAQ,+BAA+B;AAChE,SAASC,UAAU,QAAQ,8BAA8B;AACzD,SAASC,cAAc,QAAQ,2BAA2B;AAE1D,OAAO,MAAMC,QAAe,IAAMJ,MAAM,CAAC;;;;;AAKzC,CAAC,CAAC;AAEF,OAAO,MAAMK,UAAmB,OAAOC;IACrC,MAAMH,eAAeG;IAErB,MAAMC,OAAO,MAAMV,QAAQS;IAC3B,IAAIC,KAAKC,MAAM,KAAK,GAAG;QACrBT,OAAO,CAAC;;;;IAIR,CAAC;QACD;IACF;IAEA,IAAID,OAAOW,aAAa,EAAE;QACxBP,WAAW;YACTQ,MAAMH;YACNI,SAAS;gBAAC;gBAAQ;aAAS;YAC3BC,MAAML,KAAKM,GAAG,CAAC,CAACC,MAAQ;oBAACA,IAAIC,IAAI;oBAAED,IAAIE,aAAa;iBAAC;QACvD;IACF,OAAO;QACL,IAAIC,eAAe;QACnB,KAAK,MAAMH,OAAOP,KAAM;YACtBU,gBAAgBhB,QAAQ,CAAC,EAAEa,IAAIC,IAAI,CAAC,EAAE,EAAED,IAAIE,aAAa,CAAC,CAAC;QAC7D;QAEAjB,QAAQ;YAAEW,MAAMH;QAAK,GAAGU;IAC1B;AACF,EAAE"}
@@ -10,11 +10,8 @@ import { getUser } from "../services/user/user.js";
10
10
  export const usage = ()=>sprint`
11
11
  Log in to your account.
12
12
 
13
- {bold USAGE}
14
- ggt login
15
-
16
- {bold EXAMPLES}
17
- $ ggt login
13
+ {bold Usage}
14
+ ggt login
18
15
  `;
19
16
  export const login = async (ctx)=>{
20
17
  let server;
@@ -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 { println } from \"../services/output/print.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 EXAMPLES}\n $ ggt login\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 println({ ensureEmptyLineAbove: true })`Hello, ${user.name} {gray (${user.email})}`;\n } else {\n println({ ensureEmptyLineAbove: true })`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 as 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 println({ ensureEmptyLineAbove: true })`\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 println({ ensureEmptyLineAbove: true })`\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","println","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","ensureEmptyLineAbove","email","set","error","undefined","writeHead","Location","toString","end","log","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,OAAO,QAAQ,8BAA8B;AACtD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,8BAA8B;AAC3D,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;;;;AAQzC,CAAC,CAAC;AAEF,OAAO,MAAMI,QAAiB,OAAOC;IACnC,IAAIC;IAEJ,IAAI;QACF,MAAMC,OAAO,MAAMb;QACnB,MAAMc,iBAAiB,IAAIC,QAAc,CAACC,SAASC;YACjD,kEAAkE;YAClEL,SAASV,KAAKgB,YAAY,CAAC,OAAOC,KAAKC;gBACrC,MAAMC,cAAc,IAAIC,IAAI,CAAC,QAAQ,EAAElB,OAAOmB,OAAO,CAACC,QAAQ,CAAC,SAAS,CAAC;gBAEzE,IAAI;oBACFvB,OAAOkB,IAAIM,GAAG,EAAE;oBAChB,MAAMC,UAAU,IAAIJ,IAAIH,IAAIM,GAAG,EAAE,CAAC,iBAAiB,EAAEZ,KAAK,CAAC,EAAEc,YAAY,CAACC,GAAG,CAAC;oBAC9E3B,OAAOyB,SAAS;oBAEhBnB,aAAamB;oBAEb,MAAMG,OAAO,MAAMrB,QAAQG;oBAC3BV,OAAO4B,MAAM;oBAEb,IAAIA,KAAKC,IAAI,EAAE;wBACbzB,QAAQ;4BAAE0B,sBAAsB;wBAAK,EAAE,CAAC,OAAO,EAAEF,KAAKC,IAAI,CAAC,QAAQ,EAAED,KAAKG,KAAK,CAAC,EAAE,CAAC;oBACrF,OAAO;wBACL3B,QAAQ;4BAAE0B,sBAAsB;wBAAK,EAAE,CAAC,OAAO,EAAEF,KAAKG,KAAK,CAAC,CAAC;oBAC/D;oBAEAX,YAAYM,YAAY,CAACM,GAAG,CAAC,WAAW;oBACxCjB;gBACF,EAAE,OAAOkB,OAAO;oBACd3B,aAAa4B;oBACbd,YAAYM,YAAY,CAACM,GAAG,CAAC,WAAW;oBACxChB,OAAOiB;gBACT,SAAU;oBACRd,IAAIgB,SAAS,CAAC,KAAK;wBAAEC,UAAUhB,YAAYiB,QAAQ;oBAAG;oBACtDlB,IAAImB,GAAG;gBACT;YACF;YAEA5B,IAAI6B,GAAG,CAACC,IAAI,CAAC,yBAAyB;gBAAE5B;YAAK;YAC7CD,OAAO8B,MAAM,CAAC7B;QAChB;QAEA,4DAA4D;QAC5D,kEAAkE;QAClE,kDAAkD;QAClD,MAAMY,MAAM,IAAIH,IAAI,CAAC,QAAQ,EAAElB,OAAOmB,OAAO,CAACC,QAAQ,CAAC,WAAW,CAAC;QACnEC,IAAIE,YAAY,CAACM,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE7B,OAAOmB,OAAO,CAACC,QAAQ,CAAC,wBAAwB,EAAEX,KAAK,CAAC;QAEpG,IAAI;YACF,MAAMV,KAAKsB,IAAIa,QAAQ;YACvBjC,QAAQ;gBAAE0B,sBAAsB;YAAK,EAAE,CAAC;;;;MAIxC,CAAC;QACH,EAAE,OAAOG,OAAO;YACdvB,IAAI6B,GAAG,CAACN,KAAK,CAAC,0BAA0B;gBAAEA;YAAM;YAChD7B,QAAQ;gBAAE0B,sBAAsB;YAAK,EAAE,CAAC;;;gBAG9B,EAAEN,IAAIa,QAAQ,GAAG;;;MAG3B,CAAC;QACH;QAEA,MAAMxB;IACR,SAAU;QACRF,QAAQ+B;IACV;AACF,EAAE;AAEF,OAAO,MAAMC,UAAUlC,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 { println } from \"../services/output/print.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\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 println({ ensureEmptyLineAbove: true })`Hello, ${user.name} {gray (${user.email})}`;\n } else {\n println({ ensureEmptyLineAbove: true })`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 as 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 println({ ensureEmptyLineAbove: true })`\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 println({ ensureEmptyLineAbove: true })`\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","println","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","ensureEmptyLineAbove","email","set","error","undefined","writeHead","Location","toString","end","log","info","listen","close","command"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","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,OAAO,QAAQ,8BAA8B;AACtD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,8BAA8B;AAC3D,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;AAKzC,CAAC,CAAC;AAEF,OAAO,MAAMI,QAAiB,OAAOC;IACnC,IAAIC;IAEJ,IAAI;QACF,MAAMC,OAAO,MAAMb;QACnB,MAAMc,iBAAiB,IAAIC,QAAc,CAACC,SAASC;YACjD,kEAAkE;YAClEL,SAASV,KAAKgB,YAAY,CAAC,OAAOC,KAAKC;gBACrC,MAAMC,cAAc,IAAIC,IAAI,CAAC,QAAQ,EAAElB,OAAOmB,OAAO,CAACC,QAAQ,CAAC,SAAS,CAAC;gBAEzE,IAAI;oBACFvB,OAAOkB,IAAIM,GAAG,EAAE;oBAChB,MAAMC,UAAU,IAAIJ,IAAIH,IAAIM,GAAG,EAAE,CAAC,iBAAiB,EAAEZ,KAAK,CAAC,EAAEc,YAAY,CAACC,GAAG,CAAC;oBAC9E3B,OAAOyB,SAAS;oBAEhBnB,aAAamB;oBAEb,MAAMG,OAAO,MAAMrB,QAAQG;oBAC3BV,OAAO4B,MAAM;oBAEb,IAAIA,KAAKC,IAAI,EAAE;wBACbzB,QAAQ;4BAAE0B,sBAAsB;wBAAK,EAAE,CAAC,OAAO,EAAEF,KAAKC,IAAI,CAAC,QAAQ,EAAED,KAAKG,KAAK,CAAC,EAAE,CAAC;oBACrF,OAAO;wBACL3B,QAAQ;4BAAE0B,sBAAsB;wBAAK,EAAE,CAAC,OAAO,EAAEF,KAAKG,KAAK,CAAC,CAAC;oBAC/D;oBAEAX,YAAYM,YAAY,CAACM,GAAG,CAAC,WAAW;oBACxCjB;gBACF,EAAE,OAAOkB,OAAO;oBACd3B,aAAa4B;oBACbd,YAAYM,YAAY,CAACM,GAAG,CAAC,WAAW;oBACxChB,OAAOiB;gBACT,SAAU;oBACRd,IAAIgB,SAAS,CAAC,KAAK;wBAAEC,UAAUhB,YAAYiB,QAAQ;oBAAG;oBACtDlB,IAAImB,GAAG;gBACT;YACF;YAEA5B,IAAI6B,GAAG,CAACC,IAAI,CAAC,yBAAyB;gBAAE5B;YAAK;YAC7CD,OAAO8B,MAAM,CAAC7B;QAChB;QAEA,4DAA4D;QAC5D,kEAAkE;QAClE,kDAAkD;QAClD,MAAMY,MAAM,IAAIH,IAAI,CAAC,QAAQ,EAAElB,OAAOmB,OAAO,CAACC,QAAQ,CAAC,WAAW,CAAC;QACnEC,IAAIE,YAAY,CAACM,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE7B,OAAOmB,OAAO,CAACC,QAAQ,CAAC,wBAAwB,EAAEX,KAAK,CAAC;QAEpG,IAAI;YACF,MAAMV,KAAKsB,IAAIa,QAAQ;YACvBjC,QAAQ;gBAAE0B,sBAAsB;YAAK,EAAE,CAAC;;;;MAIxC,CAAC;QACH,EAAE,OAAOG,OAAO;YACdvB,IAAI6B,GAAG,CAACN,KAAK,CAAC,0BAA0B;gBAAEA;YAAM;YAChD7B,QAAQ;gBAAE0B,sBAAsB;YAAK,EAAE,CAAC;;;gBAG9B,EAAEN,IAAIa,QAAQ,GAAG;;;MAG3B,CAAC;QACH;QAEA,MAAMxB;IACR,SAAU;QACRF,QAAQ+B;IACV;AACF,EAAE;AAEF,OAAO,MAAMC,UAAUlC,MAAM"}
@@ -4,11 +4,8 @@ import { readSession, writeSession } from "../services/user/session.js";
4
4
  export const usage = ()=>sprint`
5
5
  Log out of your account.
6
6
 
7
- {bold USAGE}
8
- ggt logout
9
-
10
- {bold EXAMPLES}
11
- $ ggt logout
7
+ {bold Usage}
8
+ ggt logout
12
9
  `;
13
10
  export const command = (_ctx)=>{
14
11
  const token = readSession();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/logout.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { println } from \"../services/output/print.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 EXAMPLES}\n $ ggt logout\n`;\n\nexport const command: Command = (_ctx) => {\n const token = readSession();\n if (token) {\n writeSession(undefined);\n println(\"Goodbye\");\n } else {\n println(\"You are not logged in\");\n }\n};\n"],"names":["println","sprint","readSession","writeSession","usage","command","_ctx","token","undefined"],"mappings":"AACA,SAASA,OAAO,QAAQ,8BAA8B;AACtD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,WAAW,EAAEC,YAAY,QAAQ,8BAA8B;AAExE,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;;;;AAQzC,CAAC,CAAC;AAEF,OAAO,MAAMI,UAAmB,CAACC;IAC/B,MAAMC,QAAQL;IACd,IAAIK,OAAO;QACTJ,aAAaK;QACbR,QAAQ;IACV,OAAO;QACLA,QAAQ;IACV;AACF,EAAE"}
1
+ {"version":3,"sources":["../../src/commands/logout.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { println } from \"../services/output/print.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\nexport const command: Command = (_ctx) => {\n const token = readSession();\n if (token) {\n writeSession(undefined);\n println(\"Goodbye\");\n } else {\n println(\"You are not logged in\");\n }\n};\n"],"names":["println","sprint","readSession","writeSession","usage","command","_ctx","token","undefined"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,OAAO,QAAQ,8BAA8B;AACtD,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,WAAW,EAAEC,YAAY,QAAQ,8BAA8B;AAExE,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;AAKzC,CAAC,CAAC;AAEF,OAAO,MAAMI,UAAmB,CAACC;IAC/B,MAAMC,QAAQL;IACd,IAAIK,OAAO;QACTJ,aAAaK;QACbR,QAAQ;IACV,OAAO;QACLA,QAAQ;IACV;AACF,EAAE"}