@gadgetinc/ggt 0.4.6 → 0.4.8

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 (87) hide show
  1. package/README.md +1 -1
  2. package/bin/dev.js +2 -1
  3. package/bin/run.js +3 -1
  4. package/lib/__generated__/graphql.js.map +1 -1
  5. package/lib/commands/deploy.js +43 -49
  6. package/lib/commands/deploy.js.map +1 -1
  7. package/lib/commands/list.js +7 -11
  8. package/lib/commands/list.js.map +1 -1
  9. package/lib/commands/login.js +8 -12
  10. package/lib/commands/login.js.map +1 -1
  11. package/lib/commands/logout.js +3 -7
  12. package/lib/commands/logout.js.map +1 -1
  13. package/lib/commands/root.js +17 -43
  14. package/lib/commands/root.js.map +1 -1
  15. package/lib/commands/sync.js +10 -39
  16. package/lib/commands/sync.js.map +1 -1
  17. package/lib/commands/version.js +2 -6
  18. package/lib/commands/version.js.map +1 -1
  19. package/lib/commands/whoami.js +5 -9
  20. package/lib/commands/whoami.js.map +1 -1
  21. package/lib/ggt.js +40 -0
  22. package/lib/ggt.js.map +1 -0
  23. package/lib/services/app/app.js +8 -6
  24. package/lib/services/app/app.js.map +1 -1
  25. package/lib/services/app/edit/client.js +176 -0
  26. package/lib/services/app/edit/client.js.map +1 -0
  27. package/lib/services/app/edit/edit.js +155 -0
  28. package/lib/services/app/edit/edit.js.map +1 -0
  29. package/lib/services/app/edit/error.js +65 -0
  30. package/lib/services/app/edit/error.js.map +1 -0
  31. package/lib/services/app/edit/operation.js +87 -0
  32. package/lib/services/app/edit/operation.js.map +1 -0
  33. package/lib/services/command/arg.js +5 -5
  34. package/lib/services/command/arg.js.map +1 -1
  35. package/lib/services/command/command.js +23 -5
  36. package/lib/services/command/command.js.map +1 -1
  37. package/lib/services/command/context.js +123 -36
  38. package/lib/services/command/context.js.map +1 -1
  39. package/lib/services/filesync/changes.js +7 -9
  40. package/lib/services/filesync/changes.js.map +1 -1
  41. package/lib/services/filesync/conflicts.js +11 -9
  42. package/lib/services/filesync/conflicts.js.map +1 -1
  43. package/lib/services/filesync/directory.js +2 -2
  44. package/lib/services/filesync/directory.js.map +1 -1
  45. package/lib/services/filesync/filesync.js +187 -96
  46. package/lib/services/filesync/filesync.js.map +1 -1
  47. package/lib/services/filesync/hashes.js +18 -15
  48. package/lib/services/filesync/hashes.js.map +1 -1
  49. package/lib/services/http/auth.js +4 -4
  50. package/lib/services/http/auth.js.map +1 -1
  51. package/lib/services/http/http.js +54 -27
  52. package/lib/services/http/http.js.map +1 -1
  53. package/lib/services/output/log/logger.js +11 -6
  54. package/lib/services/output/log/logger.js.map +1 -1
  55. package/lib/services/output/log/printer.js.map +1 -1
  56. package/lib/services/output/log/structured.js +2 -2
  57. package/lib/services/output/log/structured.js.map +1 -1
  58. package/lib/services/output/notify.js +3 -7
  59. package/lib/services/output/notify.js.map +1 -1
  60. package/lib/services/output/prompt.js +11 -11
  61. package/lib/services/output/prompt.js.map +1 -1
  62. package/lib/services/output/report.js +51 -67
  63. package/lib/services/output/report.js.map +1 -1
  64. package/lib/services/output/update.js +9 -10
  65. package/lib/services/output/update.js.map +1 -1
  66. package/lib/services/user/user.js +19 -25
  67. package/lib/services/user/user.js.map +1 -1
  68. package/lib/services/util/collection.js +1 -1
  69. package/lib/services/util/collection.js.map +1 -1
  70. package/lib/services/util/function.js +29 -11
  71. package/lib/services/util/function.js.map +1 -1
  72. package/lib/services/util/is.js +19 -1
  73. package/lib/services/util/is.js.map +1 -1
  74. package/lib/services/util/number.js +3 -3
  75. package/lib/services/util/number.js.map +1 -1
  76. package/lib/services/util/object.js +4 -4
  77. package/lib/services/util/object.js.map +1 -1
  78. package/lib/services/util/paths.js +4 -4
  79. package/lib/services/util/paths.js.map +1 -1
  80. package/lib/services/util/types.js +5 -0
  81. package/lib/services/util/types.js.map +1 -0
  82. package/npm-shrinkwrap.json +586 -418
  83. package/package.json +17 -15
  84. package/lib/main.js +0 -8
  85. package/lib/main.js.map +0 -1
  86. package/lib/services/app/edit-graphql.js +0 -389
  87. package/lib/services/app/edit-graphql.js.map +0 -1
@@ -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,26 +43,28 @@ export const rootArgs = {
49
43
  type: Boolean
50
44
  }
51
45
  };
52
- export const command = async ()=>{
53
- const ctx = new Context(rootArgs, {
46
+ export const command = async (parent)=>{
47
+ const ctx = parent.child({
48
+ name: "root",
49
+ parse: args,
54
50
  argv: process.argv.slice(2),
55
51
  permissive: true
56
52
  });
57
- await warnIfUpdateAvailable();
58
53
  if (ctx.args["--json"]) {
59
54
  process.env["GGT_LOG_FORMAT"] = "json";
60
55
  }
61
56
  if (ctx.args["--verbose"]) {
62
57
  process.env["GGT_LOG_LEVEL"] = verbosityToLevel(ctx.args["--verbose"]).toString();
63
58
  }
59
+ await warnIfUpdateAvailable(ctx);
64
60
  const cmd = ctx.args._.shift();
65
61
  if (isNil(cmd)) {
66
- log.println(rootUsage());
62
+ ctx.log.println(usage());
67
63
  process.exit(0);
68
64
  }
69
65
  if (!isAvailableCommand(cmd)) {
70
- const [closest] = sortBySimilar(cmd, AvailableCommands);
71
- log.println`
66
+ const [closest] = sortBySimilar(cmd, Commands);
67
+ ctx.log.println`
72
68
  Unknown command {yellow ${cmd}}
73
69
 
74
70
  Did you mean {blueBright ${closest}}?
@@ -77,40 +73,18 @@ export const command = async ()=>{
77
73
  `;
78
74
  process.exit(1);
79
75
  }
80
- const { usage, command, args } = await importCommand(cmd);
76
+ const subcommand = await importCommand(cmd);
81
77
  if (ctx.args["--help"]) {
82
- log.println(usage());
78
+ ctx.log.println(subcommand.usage());
83
79
  process.exit(0);
84
80
  }
85
81
  try {
86
- await command(ctx.extend({
87
- args,
88
- logName: cmd
82
+ await subcommand.command(ctx.child({
83
+ name: cmd,
84
+ parse: subcommand.args
89
85
  }));
90
86
  } catch (error) {
91
- await reportErrorAndExit(error);
92
- }
93
- for (const signal of [
94
- "SIGINT",
95
- "SIGTERM"
96
- ]){
97
- process.once(signal, ()=>{
98
- log.trace("received signal", {
99
- signal
100
- });
101
- log.println` Stopping... {gray Press Ctrl+C again to force}`;
102
- ctx.abort();
103
- // when ggt is run via npx, and the user presses ctrl+c, npx
104
- // sends sigint twice in quick succession. in order to prevent
105
- // the second sigint from triggering the force exit listener,
106
- // we wait a bit before registering it
107
- setTimeout(()=>{
108
- process.once(signal, ()=>{
109
- log.println(" Exiting immediately");
110
- process.exit(1);
111
- });
112
- }, ms("100ms")).unref();
113
- });
87
+ await reportErrorAndExit(ctx, error);
114
88
  }
115
89
  };
116
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\": {\n type: Boolean,\n alias: \"-h\",\n },\n \"--verbose\": {\n type: arg.COUNT,\n alias: [\"-v\", \"--debug\"],\n },\n \"--json\": {\n type: Boolean,\n },\n} satisfies ArgsSpec;\n\nexport const command = async (): Promise<void> => {\n const ctx = new Context(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, logName: 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","argv","process","slice","permissive","args","env","toString","cmd","_","shift","println","exit","closest","usage","extend","logName","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;QACRC,MAAMC;QACNC,OAAO;IACT;IACA,aAAa;QACXF,MAAMjB,IAAIoB,KAAK;QACfD,OAAO;YAAC;YAAM;SAAU;IAC1B;IACA,UAAU;QACRF,MAAMC;IACR;AACF,EAAqB;AAErB,OAAO,MAAMG,UAAU;IACrB,MAAMC,MAAM,IAAIjB,QAAQW,UAAU;QAAEO,MAAMC,QAAQD,IAAI,CAACE,KAAK,CAAC;QAAIC,YAAY;IAAK;IAElF,MAAMhB;IAEN,IAAIY,IAAIK,IAAI,CAAC,SAAS,EAAE;QACtBH,QAAQI,GAAG,CAAC,iBAAiB,GAAG;IAClC;IAEA,IAAIN,IAAIK,IAAI,CAAC,YAAY,EAAE;QACzBH,QAAQI,GAAG,CAAC,gBAAgB,GAAGtB,iBAAiBgB,IAAIK,IAAI,CAAC,YAAY,EAAEE,QAAQ;IACjF;IAEA,MAAMC,MAAMR,IAAIK,IAAI,CAACI,CAAC,CAACC,KAAK;IAC5B,IAAIpB,MAAMkB,MAAM;QACdjB,IAAIoB,OAAO,CAAClB;QACZS,QAAQU,IAAI,CAAC;IACf;IAEA,IAAI,CAAC9B,mBAAmB0B,MAAM;QAC5B,MAAM,CAACK,QAAQ,GAAGxB,cAAcmB,KAAK5B;QACrCW,IAAIoB,OAAO,CAAC;8BACc,EAAEH,IAAI;;+BAEL,EAAEK,QAAQ;;;IAGrC,CAAC;QACDX,QAAQU,IAAI,CAAC;IACf;IAEA,MAAM,EAAEE,KAAK,EAAEf,OAAO,EAAEM,IAAI,EAAE,GAAG,MAAMxB,cAAc2B;IAErD,IAAIR,IAAIK,IAAI,CAAC,SAAS,EAAE;QACtBd,IAAIoB,OAAO,CAACG;QACZZ,QAAQU,IAAI,CAAC;IACf;IAEA,IAAI;QACF,MAAMb,QAAQC,IAAIe,MAAM,CAAC;YAAEV;YAAMW,SAASR;QAAI;IAChD,EAAE,OAAOS,OAAO;QACd,MAAM/B,mBAAmB+B;IAC3B;IAEA,KAAK,MAAMC,UAAU;QAAC;QAAU;KAAU,CAAW;QACnDhB,QAAQiB,IAAI,CAACD,QAAQ;YACnB3B,IAAI6B,KAAK,CAAC,mBAAmB;gBAAEF;YAAO;YACtC3B,IAAIoB,OAAO,CAAC,+CAA+C,CAAC;YAC5DX,IAAIqB,KAAK;YAET,4DAA4D;YAC5D,8DAA8D;YAC9D,6DAA6D;YAC7D,sCAAsC;YACtCC,WAAW;gBACTpB,QAAQiB,IAAI,CAACD,QAAQ;oBACnB3B,IAAIoB,OAAO,CAAC;oBACZT,QAAQU,IAAI,CAAC;gBACf;YACF,GAAGjC,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,18 +1,15 @@
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";
6
5
  import which from "which";
7
- import { AppArg } from "../services/app/arg.js";
8
6
  import { config } from "../services/config/config.js";
9
7
  import { Changes } from "../services/filesync/changes.js";
10
8
  import { YarnNotFoundError } from "../services/filesync/error.js";
11
- import { ConflictPreferenceArg, FileSync } from "../services/filesync/filesync.js";
9
+ import { FileSync, FileSyncArgs } from "../services/filesync/filesync.js";
12
10
  import { notify } from "../services/output/notify.js";
13
11
  import { reportErrorAndExit } from "../services/output/report.js";
14
12
  import { sprint } from "../services/output/sprint.js";
15
- import { getUserOrLogin } from "../services/user/user.js";
16
13
  import { debounce } from "../services/util/function.js";
17
14
  import { isAbortError } from "../services/util/is.js";
18
15
  export const usage = ()=>sprint`
@@ -86,13 +83,8 @@ export const usage = ()=>sprint`
86
83
  Goodbye!
87
84
  `;
88
85
  export const args = {
89
- "--app": {
90
- type: AppArg,
91
- alias: "-a"
92
- },
93
- "--force": Boolean,
86
+ ...FileSyncArgs,
94
87
  "--once": Boolean,
95
- "--prefer": ConflictPreferenceArg,
96
88
  "--file-push-delay": {
97
89
  type: Number,
98
90
  default: ms("100ms")
@@ -117,24 +109,17 @@ export const args = {
117
109
  /**
118
110
  * Runs the sync process until it is stopped or an error occurs.
119
111
  */ export const command = async (ctx)=>{
120
- const filesync = await FileSync.init({
121
- user: await getUserOrLogin(),
122
- dir: ctx.args._[0],
123
- app: ctx.args["--app"],
124
- force: ctx.args["--force"]
125
- });
126
- await filesync.sync({
127
- preference: ctx.args["--prefer"]
128
- });
129
- if (ctx.args["--once"]) {
130
- ctx.log.println("Done!");
131
- return;
132
- }
133
112
  if (!which.sync("yarn", {
134
113
  nothrow: true
135
114
  })) {
136
115
  throw new YarnNotFoundError();
137
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
+ }
138
123
  /**
139
124
  * A list of filepaths that have changed because we (this ggt process)
140
125
  * modified them. This is used to avoid reacting to filesystem events
@@ -168,20 +153,6 @@ export const args = {
168
153
  dir = path.dirname(dir);
169
154
  }
170
155
  }
171
- },
172
- afterChanges: async ({ changes })=>{
173
- if (changes.has("yarn.lock")) {
174
- await execa("yarn", [
175
- "install",
176
- "--check-files"
177
- ], {
178
- cwd: filesync.directory.path
179
- }).catch((error)=>{
180
- ctx.log.error("yarn install failed", {
181
- error
182
- });
183
- });
184
- }
185
156
  }
186
157
  });
187
158
  /**
@@ -302,11 +273,11 @@ export const args = {
302
273
  ctx.log.printlns("Goodbye!");
303
274
  return;
304
275
  }
305
- notify({
276
+ notify(ctx, {
306
277
  subtitle: "Uh oh!",
307
278
  message: "An error occurred while syncing files"
308
279
  });
309
- await reportErrorAndExit(reason);
280
+ await reportErrorAndExit(ctx, reason);
310
281
  });
311
282
  };
312
283
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/sync.ts"],"sourcesContent":["import dayjs from \"dayjs\";\nimport { execa } from \"execa\";\nimport ms from \"ms\";\nimport path from \"node:path\";\nimport Watcher from \"watcher\";\nimport which from \"which\";\nimport { AppArg } from \"../services/app/arg.js\";\nimport type { ArgsSpec } from \"../services/command/arg.js\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport { config } from \"../services/config/config.js\";\nimport { Changes } from \"../services/filesync/changes.js\";\nimport { YarnNotFoundError } from \"../services/filesync/error.js\";\nimport { ConflictPreferenceArg, FileSync } from \"../services/filesync/filesync.js\";\nimport { notify } from \"../services/output/notify.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUserOrLogin } from \"../services/user/user.js\";\nimport { debounce } from \"../services/util/function.js\";\nimport { isAbortError } from \"../services/util/is.js\";\n\nexport const usage: Usage = () => sprint`\n Sync your Gadget environment's source code with your local filesystem.\n\n {bold USAGE}\n ggt sync [DIRECTORY]\n\n {bold ARGUMENTS}\n DIRECTORY The directory to sync files to (default: \".\")\n\n {bold FLAGS}\n -a, --app=<name> The Gadget application to sync files to\n --prefer=<filesystem> Prefer \"local\" or \"gadget\" conflicting changes\n --once Sync once and exit\n --force Sync regardless of local filesystem state\n\n {bold DESCRIPTION}\n Sync allows you to synchronize your Gadget application's source\n code with your local filesystem.\n\n While ggt sync is running, local file changes are immediately\n reflected within Gadget, while files that are changed in Gadget are\n immediately saved to your local filesystem.\n\n Ideal for:\n • Local development with editors like VSCode\n • Storing source code in a Git repository like GitHub\n\n Sync looks for a \".ignore\" file to exclude certain files/directories\n from being synced. The format is identical to Git's.\n\n These files are always ignored:\n • .DS_Store\n • .gadget\n • .git\n • node_modules\n\n Note:\n • Sync only works with your development environment\n • Avoid deleting/moving all your files while sync is running\n • Gadget only supports Yarn v1 for dependency installation\n\n {bold EXAMPLE}\n $ ggt sync ~/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 Watching for file changes... {gray Press Ctrl+C to stop}\n\n → Sent {gray 09:06:25 AM}\n {greenBright routes/GET-hello.js + created}\n\n → Sent {gray 09:06:49 AM}\n {blueBright routes/GET-hello.js ± updated}\n\n ← Received {gray 09:06:54 AM}\n {blueBright routes/GET-hello.js ± updated}\n\n ← Received {gray 09:06:56 AM}\n {redBright routes/GET-hello.js - deleted}\n ^C Stopping... {gray press Ctrl+C again to force}\n\n Goodbye!\n`;\n\nexport const args = {\n \"--app\": { type: AppArg, alias: \"-a\" },\n \"--force\": Boolean,\n \"--once\": Boolean,\n \"--prefer\": ConflictPreferenceArg,\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 ArgsSpec;\n\n/**\n * Runs the sync process until it is stopped or an error occurs.\n */\nexport const command: Command<typeof args> = async (ctx) => {\n const filesync = await FileSync.init({\n user: await getUserOrLogin(),\n dir: ctx.args._[0],\n app: ctx.args[\"--app\"],\n force: ctx.args[\"--force\"],\n });\n\n await filesync.sync({ preference: ctx.args[\"--prefer\"] });\n\n if (ctx.args[\"--once\"]) {\n ctx.log.println(\"Done!\");\n return;\n }\n\n if (!which.sync(\"yarn\", { nothrow: true })) {\n throw new YarnNotFoundError();\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 unsubscribeFromGadgetChanges = filesync.subscribeToGadgetChanges({\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 afterChanges: async ({ changes }) => {\n if (changes.has(\"yarn.lock\")) {\n await execa(\"yarn\", [\"install\", \"--check-files\"], { cwd: filesync.directory.path }).catch((error) => {\n ctx.log.error(\"yarn install failed\", { error });\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 sendChangesToGadget = debounce(ctx.args[\"--file-push-delay\"], () => {\n const changes = new Changes(localChangesBuffer.entries());\n localChangesBuffer.clear();\n filesync.sendChangesToGadget({ changes }).catch((error) => ctx.abort(error));\n });\n\n ctx.log.debug(\"watching\", { path: filesync.directory.path });\n\n /**\n * Watches the local filesystem for changes.\n */\n const fileWatcher = new Watcher(\n filesync.directory.path,\n {\n // don't emit an event for every watched file on boot\n ignoreInitial: true,\n // don't emit changes to .gadget/ files because they're readonly (Gadget manages them)\n ignore: (path: string) => filesync.directory.relative(path).startsWith(\".gadget\") || filesync.directory.ignores(path),\n renameDetection: true,\n recursive: true,\n debounce: ctx.args[\"--file-watch-debounce\"],\n pollingInterval: ctx.args[\"--file-watch-poll-interval\"],\n pollingTimeout: ctx.args[\"--file-watch-poll-timeout\"],\n renameTimeout: ctx.args[\"--file-watch-rename-timeout\"],\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 = filesync.directory.normalize(filepath, isDirectory);\n\n ctx.log.trace(\"file event\", { event, isDirectory, path: normalizedPath });\n\n if (filepath === filesync.directory.absolute(\".ignore\")) {\n filesync.directory.loadIgnoreFile().catch((error) => ctx.abort(error));\n } else if (filesync.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 = filesync.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 sendChangesToGadget();\n },\n ).once(\"error\", (error) => ctx.abort(error));\n\n ctx.log.printlns`\n ggt v${config.version}\n\n App ${filesync.app.slug}\n Editor https://${filesync.app.slug}.gadget.app/edit\n Playground https://${filesync.app.slug}.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/${filesync.app.slug}\n\n Endpoints ${\n filesync.app.hasSplitEnvironments\n ? `\n • https://${filesync.app.primaryDomain}\n • https://${filesync.app.slug}--development.gadget.app`\n : `\n • https://${filesync.app.primaryDomain}`\n }\n\n Watching for file changes... {gray Press Ctrl+C to stop}\n `;\n\n ctx.onAbort(async (reason) => {\n ctx.log.info(\"stopping\", { reason });\n\n unsubscribeFromGadgetChanges();\n fileWatcher.close();\n clearInterval(clearRecentWritesInterval);\n sendChangesToGadget.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 ctx.log.printlns(\"Goodbye!\");\n return;\n }\n\n notify({ subtitle: \"Uh oh!\", message: \"An error occurred while syncing files\" });\n await reportErrorAndExit(reason);\n });\n};\n"],"names":["dayjs","execa","ms","path","Watcher","which","AppArg","config","Changes","YarnNotFoundError","ConflictPreferenceArg","FileSync","notify","reportErrorAndExit","sprint","getUserOrLogin","debounce","isAbortError","usage","args","type","alias","Boolean","Number","default","command","ctx","filesync","init","user","dir","_","app","force","sync","preference","log","println","nothrow","recentWritesToLocalFilesystem","Map","clearRecentWritesInterval","setInterval","timestamp","isAfter","delete","unref","unsubscribeFromGadgetChanges","subscribeToGadgetChanges","onError","error","abort","beforeChanges","changed","deleted","filepath","set","Date","now","dirname","afterChanges","changes","has","cwd","directory","catch","localChangesBuffer","sendChangesToGadget","entries","clear","debug","fileWatcher","ignoreInitial","ignore","relative","startsWith","ignores","renameDetection","recursive","pollingInterval","pollingTimeout","renameTimeout","event","absolutePath","renamedPath","isDirectory","normalizedPath","normalize","trace","absolute","loadIgnoreFile","oldNormalizedPath","oldPath","once","printlns","version","slug","hasSplitEnvironments","primaryDomain","onAbort","reason","info","close","clearInterval","flush","idle","subtitle","message"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/sync.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 { config } from \"../services/config/config.js\";\nimport { Changes } from \"../services/filesync/changes.js\";\nimport { YarnNotFoundError } from \"../services/filesync/error.js\";\nimport { FileSync, FileSyncArgs } from \"../services/filesync/filesync.js\";\nimport { notify } from \"../services/output/notify.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { debounce } from \"../services/util/function.js\";\nimport { isAbortError } from \"../services/util/is.js\";\n\nexport const usage: Usage = () => sprint`\n Sync your Gadget environment's source code with your local filesystem.\n\n {bold USAGE}\n ggt sync [DIRECTORY]\n\n {bold ARGUMENTS}\n DIRECTORY The directory to sync files to (default: \".\")\n\n {bold FLAGS}\n -a, --app=<name> The Gadget application to sync files to\n --prefer=<filesystem> Prefer \"local\" or \"gadget\" conflicting changes\n --once Sync once and exit\n --force Sync regardless of local filesystem state\n\n {bold DESCRIPTION}\n Sync allows you to synchronize your Gadget application's source\n code with your local filesystem.\n\n While ggt sync is running, local file changes are immediately\n reflected within Gadget, while files that are changed in Gadget are\n immediately saved to your local filesystem.\n\n Ideal for:\n • Local development with editors like VSCode\n • Storing source code in a Git repository like GitHub\n\n Sync looks for a \".ignore\" file to exclude certain files/directories\n from being synced. The format is identical to Git's.\n\n These files are always ignored:\n • .DS_Store\n • .gadget\n • .git\n • node_modules\n\n Note:\n • Sync only works with your development environment\n • Avoid deleting/moving all your files while sync is running\n • Gadget only supports Yarn v1 for dependency installation\n\n {bold EXAMPLE}\n $ ggt sync ~/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 Watching for file changes... {gray Press Ctrl+C to stop}\n\n → Sent {gray 09:06:25 AM}\n {greenBright routes/GET-hello.js + created}\n\n → Sent {gray 09:06:49 AM}\n {blueBright routes/GET-hello.js ± updated}\n\n ← Received {gray 09:06:54 AM}\n {blueBright routes/GET-hello.js ± updated}\n\n ← Received {gray 09:06:56 AM}\n {redBright routes/GET-hello.js - deleted}\n ^C Stopping... {gray press Ctrl+C again to force}\n\n Goodbye!\n`;\n\nexport const args = {\n ...FileSyncArgs,\n \"--once\": Boolean,\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 type SyncArgs = typeof args;\n\n/**\n * Runs the sync process until it is stopped or an error occurs.\n */\nexport const command: Command<SyncArgs> = async (ctx) => {\n if (!which.sync(\"yarn\", { nothrow: true })) {\n throw new YarnNotFoundError();\n }\n\n const filesync = await FileSync.init(ctx);\n await filesync.sync();\n\n if (ctx.args[\"--once\"]) {\n ctx.log.println(\"Done!\");\n return;\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 unsubscribeFromGadgetChanges = filesync.subscribeToGadgetChanges({\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 sendChangesToGadget = debounce(ctx.args[\"--file-push-delay\"], () => {\n const changes = new Changes(localChangesBuffer.entries());\n localChangesBuffer.clear();\n filesync.sendChangesToGadget({ changes }).catch((error) => ctx.abort(error));\n });\n\n ctx.log.debug(\"watching\", { path: filesync.directory.path });\n\n /**\n * Watches the local filesystem for changes.\n */\n const fileWatcher = new Watcher(\n filesync.directory.path,\n {\n // don't emit an event for every watched file on boot\n ignoreInitial: true,\n // don't emit changes to .gadget/ files because they're readonly (Gadget manages them)\n ignore: (path: string) => filesync.directory.relative(path).startsWith(\".gadget\") || filesync.directory.ignores(path),\n renameDetection: true,\n recursive: true,\n debounce: ctx.args[\"--file-watch-debounce\"],\n pollingInterval: ctx.args[\"--file-watch-poll-interval\"],\n pollingTimeout: ctx.args[\"--file-watch-poll-timeout\"],\n renameTimeout: ctx.args[\"--file-watch-rename-timeout\"],\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 = filesync.directory.normalize(filepath, isDirectory);\n\n ctx.log.trace(\"file event\", { event, isDirectory, path: normalizedPath });\n\n if (filepath === filesync.directory.absolute(\".ignore\")) {\n filesync.directory.loadIgnoreFile().catch((error) => ctx.abort(error));\n } else if (filesync.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 = filesync.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 sendChangesToGadget();\n },\n ).once(\"error\", (error) => ctx.abort(error));\n\n ctx.log.printlns`\n ggt v${config.version}\n\n App ${filesync.app.slug}\n Editor https://${filesync.app.slug}.gadget.app/edit\n Playground https://${filesync.app.slug}.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/${filesync.app.slug}\n\n Endpoints ${\n filesync.app.hasSplitEnvironments\n ? `\n • https://${filesync.app.primaryDomain}\n • https://${filesync.app.slug}--development.gadget.app`\n : `\n • https://${filesync.app.primaryDomain}`\n }\n\n Watching for file changes... {gray Press Ctrl+C to stop}\n `;\n\n ctx.onAbort(async (reason) => {\n ctx.log.info(\"stopping\", { reason });\n\n unsubscribeFromGadgetChanges();\n fileWatcher.close();\n clearInterval(clearRecentWritesInterval);\n sendChangesToGadget.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 ctx.log.printlns(\"Goodbye!\");\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"],"names":["dayjs","ms","path","Watcher","which","config","Changes","YarnNotFoundError","FileSync","FileSyncArgs","notify","reportErrorAndExit","sprint","debounce","isAbortError","usage","args","Boolean","type","Number","default","command","ctx","sync","nothrow","filesync","init","log","println","recentWritesToLocalFilesystem","Map","clearRecentWritesInterval","setInterval","timestamp","isAfter","delete","unref","unsubscribeFromGadgetChanges","subscribeToGadgetChanges","onError","error","abort","beforeChanges","changed","deleted","filepath","set","Date","now","dir","dirname","localChangesBuffer","sendChangesToGadget","changes","entries","clear","catch","debug","directory","fileWatcher","ignoreInitial","ignore","relative","startsWith","ignores","renameDetection","recursive","pollingInterval","pollingTimeout","renameTimeout","event","absolutePath","renamedPath","isDirectory","normalizedPath","normalize","trace","absolute","loadIgnoreFile","oldNormalizedPath","oldPath","once","printlns","version","app","slug","hasSplitEnvironments","primaryDomain","onAbort","reason","info","close","clearInterval","flush","idle","subtitle","message"],"mappings":"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"}
@@ -1,9 +1,5 @@
1
1
  import { config } from "../services/config/config.js";
2
- import { createLogger } from "../services/output/log/logger.js";
3
2
  import { sprint } from "../services/output/sprint.js";
4
- const log = createLogger({
5
- name: "version"
6
- });
7
3
  export const usage = ()=>sprint`
8
4
  Print the version of ggt
9
5
 
@@ -14,8 +10,8 @@ export const usage = ()=>sprint`
14
10
  $ ggt version
15
11
  ${config.version}
16
12
  `;
17
- export const command = ()=>{
18
- log.println(config.version);
13
+ export const command = (ctx)=>{
14
+ ctx.log.println(config.version);
19
15
  };
20
16
 
21
17
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/version.ts"],"sourcesContent":["import 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\";\n\nconst log = createLogger({ name: \"version\" });\n\nexport const usage: Usage = () => sprint`\n Print the version of ggt\n\n {bold USAGE}\n ggt version\n\n {bold EXAMPLE}\n $ ggt version\n ${config.version}\n`;\n\nexport const command: Command = () => {\n log.println(config.version);\n};\n"],"names":["config","createLogger","sprint","log","name","usage","version","command","println"],"mappings":"AACA,SAASA,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AAEtD,MAAMC,MAAMF,aAAa;IAAEG,MAAM;AAAU;AAE3C,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;;;;MAQnC,EAAEF,OAAOM,OAAO,CAAC;AACvB,CAAC,CAAC;AAEF,OAAO,MAAMC,UAAmB;IAC9BJ,IAAIK,OAAO,CAACR,OAAOM,OAAO;AAC5B,EAAE"}
1
+ {"version":3,"sources":["../../src/commands/version.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { config } from \"../services/config/config.js\";\nimport { sprint } from \"../services/output/sprint.js\";\n\nexport const usage: Usage = () => sprint`\n Print the version of ggt\n\n {bold USAGE}\n ggt version\n\n {bold EXAMPLE}\n $ ggt version\n ${config.version}\n`;\n\nexport const command: Command = (ctx) => {\n ctx.log.println(config.version);\n};\n"],"names":["config","sprint","usage","version","command","ctx","log","println"],"mappings":"AACA,SAASA,MAAM,QAAQ,+BAA+B;AACtD,SAASC,MAAM,QAAQ,+BAA+B;AAEtD,OAAO,MAAMC,QAAe,IAAMD,MAAM,CAAC;;;;;;;;MAQnC,EAAED,OAAOG,OAAO,CAAC;AACvB,CAAC,CAAC;AAEF,OAAO,MAAMC,UAAmB,CAACC;IAC/BA,IAAIC,GAAG,CAACC,OAAO,CAACP,OAAOG,OAAO;AAChC,EAAE"}
@@ -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 { getUser } from "../services/user/user.js";
4
- const log = createLogger({
5
- name: "whoami"
6
- });
7
3
  export const usage = ()=>sprint`
8
4
  Show the name and email address of the currently logged in user
9
5
 
@@ -14,16 +10,16 @@ export const usage = ()=>sprint`
14
10
  $ ggt whoami
15
11
  You are logged in as Jane Doe (jane@example.com)
16
12
  `;
17
- export const command = async ()=>{
18
- const user = await getUser();
13
+ export const command = async (ctx)=>{
14
+ const user = await getUser(ctx);
19
15
  if (!user) {
20
- log.println`You are not logged in`;
16
+ ctx.log.println`You are not logged in`;
21
17
  return;
22
18
  }
23
19
  if (user.name) {
24
- log.println`You are logged in as ${user.name} {gray (${user.email})}`;
20
+ ctx.log.println`You are logged in as ${user.name} {gray (${user.email})}`;
25
21
  } else {
26
- log.println`You are logged in as ${user.email}`;
22
+ ctx.log.println`You are logged in as ${user.email}`;
27
23
  }
28
24
  };
29
25
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/whoami.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 { getUser } from \"../services/user/user.js\";\n\nconst log = createLogger({ name: \"whoami\" });\n\nexport const usage: Usage = () => sprint`\n Show the name and email address of the currently logged in user\n\n {bold USAGE}\n ggt whoami\n\n {bold EXAMPLE}\n $ ggt whoami\n You are logged in as Jane Doe (jane@example.com)\n`;\n\nexport const command: Command = async () => {\n const user = await getUser();\n if (!user) {\n log.println`You are not logged in`;\n return;\n }\n\n if (user.name) {\n log.println`You are logged in as ${user.name} {gray (${user.email})}`;\n } else {\n log.println`You are logged in as ${user.email}`;\n }\n};\n"],"names":["createLogger","sprint","getUser","log","name","usage","command","user","println","email"],"mappings":"AACA,SAASA,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,MAAMC,MAAMH,aAAa;IAAEI,MAAM;AAAS;AAE1C,OAAO,MAAMC,QAAe,IAAMJ,MAAM,CAAC;;;;;;;;;AASzC,CAAC,CAAC;AAEF,OAAO,MAAMK,UAAmB;IAC9B,MAAMC,OAAO,MAAML;IACnB,IAAI,CAACK,MAAM;QACTJ,IAAIK,OAAO,CAAC,qBAAqB,CAAC;QAClC;IACF;IAEA,IAAID,KAAKH,IAAI,EAAE;QACbD,IAAIK,OAAO,CAAC,qBAAqB,EAAED,KAAKH,IAAI,CAAC,QAAQ,EAAEG,KAAKE,KAAK,CAAC,EAAE,CAAC;IACvE,OAAO;QACLN,IAAIK,OAAO,CAAC,qBAAqB,EAAED,KAAKE,KAAK,CAAC,CAAC;IACjD;AACF,EAAE"}
1
+ {"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUser } from \"../services/user/user.js\";\n\nexport const usage: Usage = () => sprint`\n Show the name and email address of the currently logged in user\n\n {bold USAGE}\n ggt whoami\n\n {bold EXAMPLE}\n $ ggt whoami\n You are logged in as Jane Doe (jane@example.com)\n`;\n\nexport const command: Command = async (ctx) => {\n const user = await getUser(ctx);\n if (!user) {\n ctx.log.println`You are not logged in`;\n return;\n }\n\n if (user.name) {\n ctx.log.println`You are logged in as ${user.name} {gray (${user.email})}`;\n } else {\n ctx.log.println`You are logged in as ${user.email}`;\n }\n};\n"],"names":["sprint","getUser","usage","command","ctx","user","log","println","name","email"],"mappings":"AACA,SAASA,MAAM,QAAQ,+BAA+B;AACtD,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,OAAO,MAAMC,QAAe,IAAMF,MAAM,CAAC;;;;;;;;;AASzC,CAAC,CAAC;AAEF,OAAO,MAAMG,UAAmB,OAAOC;IACrC,MAAMC,OAAO,MAAMJ,QAAQG;IAC3B,IAAI,CAACC,MAAM;QACTD,IAAIE,GAAG,CAACC,OAAO,CAAC,qBAAqB,CAAC;QACtC;IACF;IAEA,IAAIF,KAAKG,IAAI,EAAE;QACbJ,IAAIE,GAAG,CAACC,OAAO,CAAC,qBAAqB,EAAEF,KAAKG,IAAI,CAAC,QAAQ,EAAEH,KAAKI,KAAK,CAAC,EAAE,CAAC;IAC3E,OAAO;QACLL,IAAIE,GAAG,CAACC,OAAO,CAAC,qBAAqB,EAAEF,KAAKI,KAAK,CAAC,CAAC;IACrD;AACF,EAAE"}
package/lib/ggt.js ADDED
@@ -0,0 +1,40 @@
1
+ import ms from "ms";
2
+ import * as root from "./commands/root.js";
3
+ import { Context } from "./services/command/context.js";
4
+ import { installErrorHandlers, reportErrorAndExit } from "./services/output/report.js";
5
+ import { installJsonExtensions } from "./services/util/json.js";
6
+ export const ggt = async (ctx = Context.init({
7
+ name: "ggt"
8
+ }))=>{
9
+ installJsonExtensions();
10
+ installErrorHandlers(ctx);
11
+ try {
12
+ for (const signal of [
13
+ "SIGINT",
14
+ "SIGTERM"
15
+ ]){
16
+ process.once(signal, ()=>{
17
+ ctx.log.trace("received signal", {
18
+ signal
19
+ });
20
+ ctx.log.println` Stopping... {gray Press Ctrl+C again to force}`;
21
+ ctx.abort();
22
+ // when ggt is run via npx, and the user presses ctrl+c, npx
23
+ // sends sigint twice in quick succession. in order to prevent
24
+ // the second sigint from triggering the force exit listener,
25
+ // we wait a bit before registering it
26
+ setTimeout(()=>{
27
+ process.once(signal, ()=>{
28
+ ctx.log.println(" Exiting immediately");
29
+ process.exit(1);
30
+ });
31
+ }, ms("100ms")).unref();
32
+ });
33
+ }
34
+ await root.command(ctx);
35
+ } catch (error) {
36
+ await reportErrorAndExit(ctx, error);
37
+ }
38
+ };
39
+
40
+ //# sourceMappingURL=ggt.js.map
package/lib/ggt.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ggt.ts"],"sourcesContent":["import ms from \"ms\";\nimport * as root from \"./commands/root.js\";\nimport { Context } from \"./services/command/context.js\";\nimport { installErrorHandlers, reportErrorAndExit } from \"./services/output/report.js\";\nimport { installJsonExtensions } from \"./services/util/json.js\";\n\nexport const ggt = async (ctx = Context.init({ name: \"ggt\" })): Promise<void> => {\n installJsonExtensions();\n installErrorHandlers(ctx);\n\n try {\n for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) {\n process.once(signal, () => {\n ctx.log.trace(\"received signal\", { signal });\n ctx.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 ctx.log.println(\" Exiting immediately\");\n process.exit(1);\n });\n }, ms(\"100ms\")).unref();\n });\n }\n\n await root.command(ctx);\n } catch (error) {\n await reportErrorAndExit(ctx, error);\n }\n};\n"],"names":["ms","root","Context","installErrorHandlers","reportErrorAndExit","installJsonExtensions","ggt","ctx","init","name","signal","process","once","log","trace","println","abort","setTimeout","exit","unref","command","error"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,YAAYC,UAAU,qBAAqB;AAC3C,SAASC,OAAO,QAAQ,gCAAgC;AACxD,SAASC,oBAAoB,EAAEC,kBAAkB,QAAQ,8BAA8B;AACvF,SAASC,qBAAqB,QAAQ,0BAA0B;AAEhE,OAAO,MAAMC,MAAM,OAAOC,MAAML,QAAQM,IAAI,CAAC;IAAEC,MAAM;AAAM,EAAE;IAC3DJ;IACAF,qBAAqBI;IAErB,IAAI;QACF,KAAK,MAAMG,UAAU;YAAC;YAAU;SAAU,CAAW;YACnDC,QAAQC,IAAI,CAACF,QAAQ;gBACnBH,IAAIM,GAAG,CAACC,KAAK,CAAC,mBAAmB;oBAAEJ;gBAAO;gBAC1CH,IAAIM,GAAG,CAACE,OAAO,CAAC,+CAA+C,CAAC;gBAChER,IAAIS,KAAK;gBAET,4DAA4D;gBAC5D,8DAA8D;gBAC9D,6DAA6D;gBAC7D,sCAAsC;gBACtCC,WAAW;oBACTN,QAAQC,IAAI,CAACF,QAAQ;wBACnBH,IAAIM,GAAG,CAACE,OAAO,CAAC;wBAChBJ,QAAQO,IAAI,CAAC;oBACf;gBACF,GAAGlB,GAAG,UAAUmB,KAAK;YACvB;QACF;QAEA,MAAMlB,KAAKmB,OAAO,CAACb;IACrB,EAAE,OAAOc,OAAO;QACd,MAAMjB,mBAAmBG,KAAKc;IAChC;AACF,EAAE"}
@@ -1,3 +1,4 @@
1
+ import assert from "node:assert";
1
2
  import { z } from "zod";
2
3
  import { config } from "../config/config.js";
3
4
  import { loadCookie } from "../http/auth.js";
@@ -16,14 +17,18 @@ export const App = z.object({
16
17
  * Retrieves a list of apps for the given user. If the user is not
17
18
  * logged in, an empty array is returned instead.
18
19
  *
19
- * @param user The user for whom to retrieve the apps.
20
+ * @param ctx - The current context.
20
21
  * @returns A promise that resolves to an array of App objects.
21
- */ export const getApps = async (user)=>{
22
+ */ export const getApps = async (ctx)=>{
22
23
  const cookie = loadCookie();
23
24
  if (!cookie) {
24
25
  return [];
25
26
  }
27
+ assert(ctx.user, "must get user before getting apps");
26
28
  const json = await http({
29
+ context: {
30
+ ctx
31
+ },
27
32
  url: `https://${config.domains.services}/auth/api/apps`,
28
33
  headers: {
29
34
  cookie
@@ -31,10 +36,7 @@ export const App = z.object({
31
36
  responseType: "json",
32
37
  resolveBodyOnly: true
33
38
  });
34
- return z.array(App).parse(json).map((app)=>({
35
- ...app,
36
- user
37
- }));
39
+ return z.array(App).parse(json);
38
40
  };
39
41
 
40
42
  //# sourceMappingURL=app.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/app/app.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { config } from \"../config/config.js\";\nimport { loadCookie } from \"../http/auth.js\";\nimport { http } from \"../http/http.js\";\nimport type { User } from \"../user/user.js\";\n\nexport const App = z.object({\n id: z.union([z.string(), z.number(), z.bigint()]),\n slug: z.string(),\n primaryDomain: z.string(),\n hasSplitEnvironments: z.boolean(),\n});\n\nexport type App = z.infer<typeof App> & { user: User };\n\n/**\n * Retrieves a list of apps for the given user. If the user is not\n * logged in, an empty array is returned instead.\n *\n * @param user The user for whom to retrieve the apps.\n * @returns A promise that resolves to an array of App objects.\n */\nexport const getApps = async (user: User): Promise<App[]> => {\n const cookie = loadCookie();\n if (!cookie) {\n return [];\n }\n\n const json = await http({\n url: `https://${config.domains.services}/auth/api/apps`,\n headers: { cookie },\n responseType: \"json\",\n resolveBodyOnly: true,\n });\n\n return z\n .array(App)\n .parse(json)\n .map((app) => ({ ...app, user }));\n};\n"],"names":["z","config","loadCookie","http","App","object","id","union","string","number","bigint","slug","primaryDomain","hasSplitEnvironments","boolean","getApps","user","cookie","json","url","domains","services","headers","responseType","resolveBodyOnly","array","parse","map","app"],"mappings":"AAAA,SAASA,CAAC,QAAQ,MAAM;AACxB,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,IAAI,QAAQ,kBAAkB;AAGvC,OAAO,MAAMC,MAAMJ,EAAEK,MAAM,CAAC;IAC1BC,IAAIN,EAAEO,KAAK,CAAC;QAACP,EAAEQ,MAAM;QAAIR,EAAES,MAAM;QAAIT,EAAEU,MAAM;KAAG;IAChDC,MAAMX,EAAEQ,MAAM;IACdI,eAAeZ,EAAEQ,MAAM;IACvBK,sBAAsBb,EAAEc,OAAO;AACjC,GAAG;AAIH;;;;;;CAMC,GACD,OAAO,MAAMC,UAAU,OAAOC;IAC5B,MAAMC,SAASf;IACf,IAAI,CAACe,QAAQ;QACX,OAAO,EAAE;IACX;IAEA,MAAMC,OAAO,MAAMf,KAAK;QACtBgB,KAAK,CAAC,QAAQ,EAAElB,OAAOmB,OAAO,CAACC,QAAQ,CAAC,cAAc,CAAC;QACvDC,SAAS;YAAEL;QAAO;QAClBM,cAAc;QACdC,iBAAiB;IACnB;IAEA,OAAOxB,EACJyB,KAAK,CAACrB,KACNsB,KAAK,CAACR,MACNS,GAAG,CAAC,CAACC,MAAS,CAAA;YAAE,GAAGA,GAAG;YAAEZ;QAAK,CAAA;AAClC,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/app/app.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { z } from \"zod\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { loadCookie } from \"../http/auth.js\";\nimport { http } from \"../http/http.js\";\n\nexport const App = z.object({\n id: z.union([z.string(), z.number(), z.bigint()]),\n slug: z.string(),\n primaryDomain: z.string(),\n hasSplitEnvironments: z.boolean(),\n});\n\nexport type App = z.infer<typeof App>;\n\n/**\n * Retrieves a list of apps for the given user. If the user is not\n * logged in, an empty array is returned instead.\n *\n * @param ctx - The current context.\n * @returns A promise that resolves to an array of App objects.\n */\nexport const getApps = async (ctx: Context): Promise<App[]> => {\n const cookie = loadCookie();\n if (!cookie) {\n return [];\n }\n\n assert(ctx.user, \"must get user before getting apps\");\n\n const json = await http({\n context: { ctx },\n url: `https://${config.domains.services}/auth/api/apps`,\n headers: { cookie },\n responseType: \"json\",\n resolveBodyOnly: true,\n });\n\n return z.array(App).parse(json);\n};\n"],"names":["assert","z","config","loadCookie","http","App","object","id","union","string","number","bigint","slug","primaryDomain","hasSplitEnvironments","boolean","getApps","ctx","cookie","user","json","context","url","domains","services","headers","responseType","resolveBodyOnly","array","parse"],"mappings":"AAAA,OAAOA,YAAY,cAAc;AACjC,SAASC,CAAC,QAAQ,MAAM;AAExB,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,IAAI,QAAQ,kBAAkB;AAEvC,OAAO,MAAMC,MAAMJ,EAAEK,MAAM,CAAC;IAC1BC,IAAIN,EAAEO,KAAK,CAAC;QAACP,EAAEQ,MAAM;QAAIR,EAAES,MAAM;QAAIT,EAAEU,MAAM;KAAG;IAChDC,MAAMX,EAAEQ,MAAM;IACdI,eAAeZ,EAAEQ,MAAM;IACvBK,sBAAsBb,EAAEc,OAAO;AACjC,GAAG;AAIH;;;;;;CAMC,GACD,OAAO,MAAMC,UAAU,OAAOC;IAC5B,MAAMC,SAASf;IACf,IAAI,CAACe,QAAQ;QACX,OAAO,EAAE;IACX;IAEAlB,OAAOiB,IAAIE,IAAI,EAAE;IAEjB,MAAMC,OAAO,MAAMhB,KAAK;QACtBiB,SAAS;YAAEJ;QAAI;QACfK,KAAK,CAAC,QAAQ,EAAEpB,OAAOqB,OAAO,CAACC,QAAQ,CAAC,cAAc,CAAC;QACvDC,SAAS;YAAEP;QAAO;QAClBQ,cAAc;QACdC,iBAAiB;IACnB;IAEA,OAAO1B,EAAE2B,KAAK,CAACvB,KAAKwB,KAAK,CAACT;AAC5B,EAAE"}