@gadgetinc/ggt 0.4.1 → 0.4.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.
package/README.md CHANGED
@@ -29,7 +29,6 @@
29
29
  - [Usage](#usage)
30
30
  - [Commands](#commands)
31
31
  - [`ggt sync`](#ggt-sync)
32
- - [`ggt deploy`](#ggt-deploy)
33
32
  - [`ggt list`](#ggt-list)
34
33
  - [`ggt login`](#ggt-login)
35
34
  - [`ggt logout`](#ggt-logout)
@@ -62,7 +61,6 @@ USAGE
62
61
 
63
62
  COMMANDS
64
63
  sync Sync your Gadget application's source code
65
- deploy Deploy your app to production
66
64
  list List your apps
67
65
  login Log in to your account
68
66
  logout Log out of your account
@@ -152,62 +150,6 @@ EXAMPLE
152
150
  Goodbye!
153
151
  ```
154
152
 
155
- ### `ggt deploy`
156
-
157
- ```
158
- Deploy your Gadget application's development source code to production.
159
-
160
- USAGE
161
- ggt deploy [DIRECTORY] [--app=<name>]
162
-
163
- ARGUMENTS
164
- DIRECTORY The directory to sync files to and deploy (default: ".")
165
-
166
- FLAGS
167
- -a, --app=<name> The Gadget application to deploy
168
- --force Deploy the Gadget application regardless of any issues it may have
169
-
170
- DESCRIPTION
171
- Deploy allows you to deploy your current Gadget application in development to production.
172
-
173
- It detects if local files are up to date with remote and if the Gadget application
174
- is in a deployable state. If there are any issues, it will display them and ask if
175
- you would like to deploy anyways.
176
-
177
- Note:
178
- • If local files are not up to date or have not recently been synced with remote ones,
179
- you will be prompted to run a one-time sync to ensure the files remain consistent with
180
- what is on the remote.
181
- • You may wish to keep ggt sync running in the background before trying to run ggt deploy
182
-
183
- EXAMPLE
184
- $ ggt deploy ~/gadget/example --app example
185
-
186
- App example
187
- Editor https://example.gadget.app/edit
188
- Playground https://example.gadget.app/api/graphql/playground
189
- Docs https://docs.gadget.dev/api/example
190
-
191
- Endpoints
192
- • https://example.gadget.app
193
- • https://example--development.gadget.app
194
-
195
-
196
- Building frontend assets ...
197
- ✔ DONE
198
-
199
- Setting up database ...
200
- ✔ DONE
201
-
202
- Copying development ...
203
- ✔ DONE
204
-
205
- Restarting app ...
206
- ✔ DONE
207
-
208
- Deploy completed. Good bye!
209
- ```
210
-
211
153
  ### `ggt list`
212
154
 
213
155
  ```
@@ -278,5 +220,5 @@ USAGE
278
220
 
279
221
  EXAMPLES
280
222
  $ ggt version
281
- 0.4.1
223
+ 0.4.3
282
224
  ```
@@ -20,7 +20,6 @@ export const rootUsage = ()=>sprint`
20
20
 
21
21
  {bold COMMANDS}
22
22
  sync Sync your Gadget application's source code
23
- deploy Deploy your app to production
24
23
  list List your apps
25
24
  login Log in to your account
26
25
  logout Log out of your account
@@ -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 deploy Deploy your app to production\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;;;;;;;;;;;;;;;;;;;;;AAqB7C,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 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"}
package/lib/main.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { command as root } from "./commands/root.js";
2
2
  import { installErrorHandlers } from "./services/output/report.js";
3
+ import { installJsonExtensions } from "./services/util/json.js";
3
4
  installErrorHandlers();
5
+ installJsonExtensions();
4
6
  await root();
5
7
 
6
8
  //# sourceMappingURL=main.js.map
package/lib/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/main.ts"],"sourcesContent":["import { command as root } from \"./commands/root.js\";\nimport { installErrorHandlers } from \"./services/output/report.js\";\n\ninstallErrorHandlers();\n\nawait root();\n"],"names":["command","root","installErrorHandlers"],"mappings":"AAAA,SAASA,WAAWC,IAAI,QAAQ,qBAAqB;AACrD,SAASC,oBAAoB,QAAQ,8BAA8B;AAEnEA;AAEA,MAAMD"}
1
+ {"version":3,"sources":["../src/main.ts"],"sourcesContent":["import { command as root } from \"./commands/root.js\";\nimport { installErrorHandlers } from \"./services/output/report.js\";\nimport { installJsonExtensions } from \"./services/util/json.js\";\n\ninstallErrorHandlers();\ninstallJsonExtensions();\n\nawait root();\n"],"names":["command","root","installErrorHandlers","installJsonExtensions"],"mappings":"AAAA,SAASA,WAAWC,IAAI,QAAQ,qBAAqB;AACrD,SAASC,oBAAoB,QAAQ,8BAA8B;AACnE,SAASC,qBAAqB,QAAQ,0BAA0B;AAEhED;AACAC;AAEA,MAAMF"}
@@ -4,7 +4,6 @@ import { config } from "../config/config.js";
4
4
  import { relativeToThisFile } from "../util/paths.js";
5
5
  export const AvailableCommands = [
6
6
  "sync",
7
- "deploy",
8
7
  "list",
9
8
  "login",
10
9
  "logout",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/command/command.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/consistent-type-imports */\nimport assert from \"node:assert\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Promisable } from \"type-fest\";\nimport type { rootArgs } from \"../../commands/root.js\";\nimport { config } from \"../config/config.js\";\nimport { relativeToThisFile } from \"../util/paths.js\";\nimport type { ArgsSpec } from \"./arg.js\";\nimport type { Context } from \"./context.js\";\n\nexport const AvailableCommands = [\"sync\", \"deploy\", \"list\", \"login\", \"logout\", \"whoami\", \"version\"] as const;\n\nexport type AvailableCommand = (typeof AvailableCommands)[number];\n\nexport const isAvailableCommand = (command: string): command is AvailableCommand => {\n return AvailableCommands.includes(command as AvailableCommand);\n};\n\nexport const importCommand = async (cmd: AvailableCommand): Promise<CommandSpec> => {\n assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);\n let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);\n if (config.windows) {\n // https://github.com/nodejs/node/issues/31710\n commandPath = pathToFileURL(commandPath).toString();\n }\n return (await import(commandPath)) as CommandSpec;\n};\n\nexport type CommandSpec<Args extends ArgsSpec = ArgsSpec, ParentArgsSpec extends ArgsSpec = typeof rootArgs> = {\n args?: Args;\n usage: () => string;\n command: (ctx: Context<Args, ParentArgsSpec>) => Promisable<void>;\n};\n\nexport type Command<Spec extends ArgsSpec = ArgsSpec, ParentSpec extends ArgsSpec = typeof rootArgs> = CommandSpec<\n Spec,\n ParentSpec\n>[\"command\"];\n\nexport type Usage = CommandSpec[\"usage\"];\n"],"names":["assert","pathToFileURL","config","relativeToThisFile","AvailableCommands","isAvailableCommand","command","includes","importCommand","cmd","commandPath","windows","toString"],"mappings":"AAAA,6DAA6D,GAC7D,OAAOA,YAAY,cAAc;AACjC,SAASC,aAAa,QAAQ,WAAW;AAGzC,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,kBAAkB,QAAQ,mBAAmB;AAItD,OAAO,MAAMC,oBAAoB;IAAC;IAAQ;IAAU;IAAQ;IAAS;IAAU;IAAU;CAAU,CAAU;AAI7G,OAAO,MAAMC,qBAAqB,CAACC;IACjC,OAAOF,kBAAkBG,QAAQ,CAACD;AACpC,EAAE;AAEF,OAAO,MAAME,gBAAgB,OAAOC;IAClCT,OAAOK,mBAAmBI,MAAM,CAAC,iBAAiB,EAAEA,IAAI,CAAC;IACzD,IAAIC,cAAcP,mBAAmB,CAAC,eAAe,EAAEM,IAAI,GAAG,CAAC;IAC/D,IAAIP,OAAOS,OAAO,EAAE;QAClB,8CAA8C;QAC9CD,cAAcT,cAAcS,aAAaE,QAAQ;IACnD;IACA,OAAQ,MAAM,MAAM,CAACF;AACvB,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/command/command.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/consistent-type-imports */\nimport assert from \"node:assert\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Promisable } from \"type-fest\";\nimport type { rootArgs } from \"../../commands/root.js\";\nimport { config } from \"../config/config.js\";\nimport { relativeToThisFile } from \"../util/paths.js\";\nimport type { ArgsSpec } from \"./arg.js\";\nimport type { Context } from \"./context.js\";\n\nexport const AvailableCommands = [\"sync\", \"list\", \"login\", \"logout\", \"whoami\", \"version\"] as const;\n\nexport type AvailableCommand = (typeof AvailableCommands)[number];\n\nexport const isAvailableCommand = (command: string): command is AvailableCommand => {\n return AvailableCommands.includes(command as AvailableCommand);\n};\n\nexport const importCommand = async (cmd: AvailableCommand): Promise<CommandSpec> => {\n assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);\n let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);\n if (config.windows) {\n // https://github.com/nodejs/node/issues/31710\n commandPath = pathToFileURL(commandPath).toString();\n }\n return (await import(commandPath)) as CommandSpec;\n};\n\nexport type CommandSpec<Args extends ArgsSpec = ArgsSpec, ParentArgsSpec extends ArgsSpec = typeof rootArgs> = {\n args?: Args;\n usage: () => string;\n command: (ctx: Context<Args, ParentArgsSpec>) => Promisable<void>;\n};\n\nexport type Command<Spec extends ArgsSpec = ArgsSpec, ParentSpec extends ArgsSpec = typeof rootArgs> = CommandSpec<\n Spec,\n ParentSpec\n>[\"command\"];\n\nexport type Usage = CommandSpec[\"usage\"];\n"],"names":["assert","pathToFileURL","config","relativeToThisFile","AvailableCommands","isAvailableCommand","command","includes","importCommand","cmd","commandPath","windows","toString"],"mappings":"AAAA,6DAA6D,GAC7D,OAAOA,YAAY,cAAc;AACjC,SAASC,aAAa,QAAQ,WAAW;AAGzC,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,kBAAkB,QAAQ,mBAAmB;AAItD,OAAO,MAAMC,oBAAoB;IAAC;IAAQ;IAAQ;IAAS;IAAU;IAAU;CAAU,CAAU;AAInG,OAAO,MAAMC,qBAAqB,CAACC;IACjC,OAAOF,kBAAkBG,QAAQ,CAACD;AACpC,EAAE;AAEF,OAAO,MAAME,gBAAgB,OAAOC;IAClCT,OAAOK,mBAAmBI,MAAM,CAAC,iBAAiB,EAAEA,IAAI,CAAC;IACzD,IAAIC,cAAcP,mBAAmB,CAAC,eAAe,EAAEM,IAAI,GAAG,CAAC;IAC/D,IAAIP,OAAOS,OAAO,EAAE;QAClB,8CAA8C;QAC9CD,cAAcT,cAAcS,aAAaE,QAAQ;IACnD;IACA,OAAQ,MAAM,MAAM,CAACF;AACvB,EAAE"}
@@ -23,7 +23,7 @@ const log = createLogger({
23
23
  if (localChange.type === "delete" && gadgetChange.type === "delete") {
24
24
  continue;
25
25
  }
26
- if ("targetHash" in localChange && "targetHash" in gadgetChange && isEqualHash(localChange.targetHash, gadgetChange.targetHash)) {
26
+ if ("targetHash" in localChange && "targetHash" in gadgetChange && isEqualHash(filepath, localChange.targetHash, gadgetChange.targetHash)) {
27
27
  continue;
28
28
  }
29
29
  // local and gadget both updated the same file with different
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/filesync/conflicts.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { ChangesWithHash, isEqualHash, type ChangeWithHash } from \"./hashes.js\";\n\nconst log = createLogger({ name: \"conflicts\" });\n\n/**\n * A map of conflicting changes made between the user's local filesystem\n * and Gadget's filesystem where the key is the path of the conflicting\n * file and the value is an object containing the conflicting changes.\n */\nexport class Conflicts extends Map<string, { localChange: ChangeWithHash; gadgetChange: ChangeWithHash }> {}\n\n/**\n * Returns the conflicting changes between the user's local filesystem\n * and Gadget's filesystem.\n */\nexport const getConflicts = ({\n localChanges,\n gadgetChanges,\n}: {\n localChanges: ChangesWithHash;\n gadgetChanges: ChangesWithHash;\n}): Conflicts => {\n const conflicts = new Conflicts();\n\n for (const [filepath, localChange] of localChanges) {\n const gadgetChange = gadgetChanges.get(filepath);\n if (!gadgetChange) {\n // gadget doesn't have this change, so there's no conflict\n continue;\n }\n\n if (localChange.type === \"delete\" && gadgetChange.type === \"delete\") {\n // local and gadget both deleted the same file\n continue;\n }\n\n if (\"targetHash\" in localChange && \"targetHash\" in gadgetChange && isEqualHash(localChange.targetHash, gadgetChange.targetHash)) {\n // local and gadget both created/updated the same file with the same content\n continue;\n }\n\n // local and gadget both updated the same file with different\n // content or one updated and the other deleted\n conflicts.set(filepath, { localChange, gadgetChange });\n }\n\n // ignore .gadget/ file conflicts and always use gadget's version\n // since gadget is the source of truth for .gadget/ files\n for (const filepath of conflicts.keys()) {\n if (filepath.startsWith(\".gadget/\")) {\n conflicts.delete(filepath);\n }\n }\n\n return conflicts;\n};\n\n/**\n * Returns a new `Changes` object that contains only the changes that do\n * not have conflicts.\n *\n * @param conflicts - The conflicts to check against.\n * @param changes - The changes to filter.\n * @returns A new `Changes` object without conflicts.\n */\nexport const withoutConflictingChanges = ({ conflicts, changes }: { conflicts: Conflicts; changes: ChangesWithHash }): ChangesWithHash => {\n const changesWithoutConflicts = new ChangesWithHash(changes);\n\n for (const [filepath] of changesWithoutConflicts) {\n if (conflicts.has(filepath)) {\n changesWithoutConflicts.delete(filepath);\n }\n }\n\n return changesWithoutConflicts;\n};\n\n/**\n * Prints a table of conflicts between local changes and gadget changes.\n */\nexport const printConflicts = ({ message, conflicts }: { message: string; conflicts: Conflicts }): void => {\n const created = chalk.greenBright(\"+ created\");\n const updated = chalk.blueBright(\"± updated\");\n const deleted = chalk.redBright(\"- deleted\");\n\n log.printTable({\n message,\n colAligns: [\"left\", \"center\", \"center\"],\n headers: [\"\", \"You\", \"Gadget\"],\n spaceY: 1,\n rows: Array.from(conflicts.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([path, { localChange, gadgetChange }]) => {\n switch (true) {\n case localChange.type === \"create\" && gadgetChange.type === \"create\":\n return [path, created, created];\n case localChange.type === \"create\" && gadgetChange.type === \"update\":\n return [path, created, updated];\n case localChange.type === \"create\" && gadgetChange.type === \"delete\":\n return [path, created, deleted];\n case localChange.type === \"update\" && gadgetChange.type === \"create\":\n return [path, updated, created];\n case localChange.type === \"update\" && gadgetChange.type === \"update\":\n return [path, updated, updated];\n case localChange.type === \"update\" && gadgetChange.type === \"delete\":\n return [path, updated, deleted];\n case localChange.type === \"delete\" && gadgetChange.type === \"create\":\n return [path, deleted, created];\n case localChange.type === \"delete\" && gadgetChange.type === \"update\":\n return [path, deleted, updated];\n default:\n throw new Error(`Unexpected conflict: ${localChange.type} vs ${gadgetChange.type}`);\n }\n }),\n });\n};\n"],"names":["chalk","createLogger","ChangesWithHash","isEqualHash","log","name","Conflicts","Map","getConflicts","localChanges","gadgetChanges","conflicts","filepath","localChange","gadgetChange","get","type","targetHash","set","keys","startsWith","delete","withoutConflictingChanges","changes","changesWithoutConflicts","has","printConflicts","message","created","greenBright","updated","blueBright","deleted","redBright","printTable","colAligns","headers","spaceY","rows","Array","from","entries","sort","a","b","localeCompare","map","path","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/services/filesync/conflicts.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { ChangesWithHash, isEqualHash, type ChangeWithHash } from \"./hashes.js\";\n\nconst log = createLogger({ name: \"conflicts\" });\n\n/**\n * A map of conflicting changes made between the user's local filesystem\n * and Gadget's filesystem where the key is the path of the conflicting\n * file and the value is an object containing the conflicting changes.\n */\nexport class Conflicts extends Map<string, { localChange: ChangeWithHash; gadgetChange: ChangeWithHash }> {}\n\n/**\n * Returns the conflicting changes between the user's local filesystem\n * and Gadget's filesystem.\n */\nexport const getConflicts = ({\n localChanges,\n gadgetChanges,\n}: {\n localChanges: ChangesWithHash;\n gadgetChanges: ChangesWithHash;\n}): Conflicts => {\n const conflicts = new Conflicts();\n\n for (const [filepath, localChange] of localChanges) {\n const gadgetChange = gadgetChanges.get(filepath);\n if (!gadgetChange) {\n // gadget doesn't have this change, so there's no conflict\n continue;\n }\n\n if (localChange.type === \"delete\" && gadgetChange.type === \"delete\") {\n // local and gadget both deleted the same file\n continue;\n }\n\n if (\n \"targetHash\" in localChange &&\n \"targetHash\" in gadgetChange &&\n isEqualHash(filepath, localChange.targetHash, gadgetChange.targetHash)\n ) {\n // local and gadget both created/updated the same file with the same content\n continue;\n }\n\n // local and gadget both updated the same file with different\n // content or one updated and the other deleted\n conflicts.set(filepath, { localChange, gadgetChange });\n }\n\n // ignore .gadget/ file conflicts and always use gadget's version\n // since gadget is the source of truth for .gadget/ files\n for (const filepath of conflicts.keys()) {\n if (filepath.startsWith(\".gadget/\")) {\n conflicts.delete(filepath);\n }\n }\n\n return conflicts;\n};\n\n/**\n * Returns a new `Changes` object that contains only the changes that do\n * not have conflicts.\n *\n * @param conflicts - The conflicts to check against.\n * @param changes - The changes to filter.\n * @returns A new `Changes` object without conflicts.\n */\nexport const withoutConflictingChanges = ({ conflicts, changes }: { conflicts: Conflicts; changes: ChangesWithHash }): ChangesWithHash => {\n const changesWithoutConflicts = new ChangesWithHash(changes);\n\n for (const [filepath] of changesWithoutConflicts) {\n if (conflicts.has(filepath)) {\n changesWithoutConflicts.delete(filepath);\n }\n }\n\n return changesWithoutConflicts;\n};\n\n/**\n * Prints a table of conflicts between local changes and gadget changes.\n */\nexport const printConflicts = ({ message, conflicts }: { message: string; conflicts: Conflicts }): void => {\n const created = chalk.greenBright(\"+ created\");\n const updated = chalk.blueBright(\"± updated\");\n const deleted = chalk.redBright(\"- deleted\");\n\n log.printTable({\n message,\n colAligns: [\"left\", \"center\", \"center\"],\n headers: [\"\", \"You\", \"Gadget\"],\n spaceY: 1,\n rows: Array.from(conflicts.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([path, { localChange, gadgetChange }]) => {\n switch (true) {\n case localChange.type === \"create\" && gadgetChange.type === \"create\":\n return [path, created, created];\n case localChange.type === \"create\" && gadgetChange.type === \"update\":\n return [path, created, updated];\n case localChange.type === \"create\" && gadgetChange.type === \"delete\":\n return [path, created, deleted];\n case localChange.type === \"update\" && gadgetChange.type === \"create\":\n return [path, updated, created];\n case localChange.type === \"update\" && gadgetChange.type === \"update\":\n return [path, updated, updated];\n case localChange.type === \"update\" && gadgetChange.type === \"delete\":\n return [path, updated, deleted];\n case localChange.type === \"delete\" && gadgetChange.type === \"create\":\n return [path, deleted, created];\n case localChange.type === \"delete\" && gadgetChange.type === \"update\":\n return [path, deleted, updated];\n default:\n throw new Error(`Unexpected conflict: ${localChange.type} vs ${gadgetChange.type}`);\n }\n }),\n });\n};\n"],"names":["chalk","createLogger","ChangesWithHash","isEqualHash","log","name","Conflicts","Map","getConflicts","localChanges","gadgetChanges","conflicts","filepath","localChange","gadgetChange","get","type","targetHash","set","keys","startsWith","delete","withoutConflictingChanges","changes","changesWithoutConflicts","has","printConflicts","message","created","greenBright","updated","blueBright","deleted","redBright","printTable","colAligns","headers","spaceY","rows","Array","from","entries","sort","a","b","localeCompare","map","path","Error"],"mappings":"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"}
@@ -46,7 +46,7 @@ export class ChangesWithHash extends Map {
46
46
  sourceHash
47
47
  });
48
48
  }
49
- } else if (!isEqualHash(sourceHash, targetHash)) {
49
+ } else if (!isEqualHash(sourcePath, sourceHash, targetHash)) {
50
50
  // the file or directory exists in target, but has a different
51
51
  // hash, so it's been updated
52
52
  changes.set(sourcePath, {
@@ -100,7 +100,7 @@ export class ChangesWithHash extends Map {
100
100
  });
101
101
  continue;
102
102
  }
103
- if (change.type !== "delete" && existingHash && isEqualHash(change.targetHash, existingHash)) {
103
+ if (change.type !== "delete" && existingHash && isEqualHash(path, change.targetHash, existingHash)) {
104
104
  // already created or updated
105
105
  log.trace("already created or updated", {
106
106
  path,
@@ -119,13 +119,27 @@ export class ChangesWithHash extends Map {
119
119
  }
120
120
  return necessaryChanges;
121
121
  };
122
- export const isEqualHash = (a, b)=>{
123
- return a.sha1 === b.sha1 && (isNil(a.permissions) || isNil(b.permissions) || a.permissions === b.permissions);
122
+ export const isEqualHash = (path, aHash, bHash)=>{
123
+ if (aHash.sha1 !== bHash.sha1) {
124
+ // the contents are different
125
+ return false;
126
+ }
127
+ if (path.endsWith("/")) {
128
+ // it's a directory, so we don't care about permissions
129
+ return true;
130
+ }
131
+ if (isNil(aHash.permissions) || isNil(bHash.permissions)) {
132
+ // one of the filesystems doesn't support permissions, so ignore them
133
+ return true;
134
+ }
135
+ // the contents are the same, and both filesystems support permissions
136
+ // so ensure the permissions are also the same
137
+ return aHash.permissions === bHash.permissions;
124
138
  };
125
139
  export const isEqualHashes = (a, b)=>{
126
140
  for (const [aPath, aHash] of Object.entries(a)){
127
141
  const bHash = b[aPath];
128
- if (!bHash || !isEqualHash(aHash, bHash)) {
142
+ if (!bHash || !isEqualHash(aPath, aHash, bHash)) {
129
143
  log.trace("hashes are not equal", {
130
144
  path: aPath,
131
145
  aHash,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/filesync/hashes.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { isNil } from \"../util/is.js\";\nimport { type Create, type Delete, type Update } from \"./changes.js\";\nimport type { Hash, Hashes } from \"./directory.js\";\n\nconst log = createLogger({ name: \"hashes\" });\n\nexport type CreateWithHash = Create & { targetHash: Hash };\nexport type UpdateWithHash = Update & { sourceHash: Hash; targetHash: Hash };\nexport type DeleteWithHash = Delete & { sourceHash: Hash };\nexport type ChangeWithHash = CreateWithHash | UpdateWithHash | DeleteWithHash;\n\nexport class ChangesWithHash extends Map<string, ChangeWithHash> {\n created(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"create\")\n .map(([path]) => path);\n }\n\n updated(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"update\")\n .map(([path]) => path);\n }\n\n deleted(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"delete\")\n .map(([path]) => path);\n }\n}\n\n/**\n * Calculates the changes that were made to `from` to make it end up as `to`.\n *\n * If `existing` is provided, only the changes that are necessary to\n * apply to `existing` are returned.\n *\n * If `ignore` is provided, any changes that were made to a path that\n * starts with any of the `ignore` paths are skipped.\n */\nexport const getChanges = ({\n from: source,\n to: target,\n existing,\n ignore,\n}: {\n from: Hashes;\n to: Hashes;\n existing?: Hashes;\n ignore?: string[];\n}): ChangesWithHash => {\n const changes = new ChangesWithHash();\n const targetPaths = Object.keys(target);\n\n for (const [sourcePath, sourceHash] of Object.entries(source)) {\n if (ignore?.some((ignored) => sourcePath.startsWith(ignored))) {\n continue;\n }\n\n const targetHash = target[sourcePath];\n if (!targetHash) {\n if (!sourcePath.endsWith(\"/\") || !targetPaths.some((targetPath) => targetPath.startsWith(sourcePath))) {\n // sourcePath is a file and it doesn't exist in target OR\n // sourcePath is a directory and target doesn't have any\n // existing files inside it, therefor the sourcePath has been\n // deleted\n changes.set(sourcePath, { type: \"delete\", sourceHash });\n log.trace(\"file deleted\", { path: sourcePath, sourceHash });\n }\n } else if (!isEqualHash(sourceHash, targetHash)) {\n // the file or directory exists in target, but has a different\n // hash, so it's been updated\n changes.set(sourcePath, { type: \"update\", sourceHash, targetHash });\n log.trace(\"file updated\", { path: sourcePath, sourceHash, targetHash });\n }\n }\n\n for (const targetPath of targetPaths) {\n if (ignore?.some((ignored) => targetPath.startsWith(ignored))) {\n continue;\n }\n\n if (!source[targetPath]) {\n // the targetPath doesn't exist in source, so it's been created\n const targetHash = target[targetPath];\n assert(targetHash, \"targetHash should exist\");\n\n changes.set(targetPath, { type: \"create\", targetHash });\n log.trace(\"file created\", { path: targetPath, targetHash });\n }\n }\n\n if (!existing) {\n return changes;\n }\n\n return withoutUnnecessaryChanges({ changes, existing });\n};\n\n/**\n * Filters out changes that the existing filesystem already has.\n */\nexport const withoutUnnecessaryChanges = ({ changes, existing }: { changes: ChangesWithHash; existing: Hashes }): ChangesWithHash => {\n const necessaryChanges = new ChangesWithHash();\n\n for (const [path, change] of changes) {\n const existingHash = existing[path];\n if (change.type === \"delete\" && !existingHash) {\n // already deleted\n log.trace(\"already deleted\", { path });\n continue;\n }\n\n if (change.type !== \"delete\" && existingHash && isEqualHash(change.targetHash, existingHash)) {\n // already created or updated\n log.trace(\"already created or updated\", { path, existingHash, targetHash: change.targetHash });\n continue;\n }\n\n // we could do this:\n // if (change.type === \"update\" && !existingHash) {\n // change = { type: \"create\", targetHash: change.targetHash };\n // }\n // but, changing the type makes the output look confusing and it\n // doesn't change the outcome, so we just leave it as is\n\n necessaryChanges.set(path, change);\n }\n\n return necessaryChanges;\n};\n\nexport const isEqualHash = (a: Hash, b: Hash): boolean => {\n return a.sha1 === b.sha1 && (isNil(a.permissions) || isNil(b.permissions) || a.permissions === b.permissions);\n};\n\nexport const isEqualHashes = (a: Hashes, b: Hashes): boolean => {\n for (const [aPath, aHash] of Object.entries(a)) {\n const bHash = b[aPath];\n if (!bHash || !isEqualHash(aHash, bHash)) {\n log.trace(\"hashes are not equal\", { path: aPath, aHash, bHash });\n return false;\n }\n }\n\n for (const bPath of Object.keys(b)) {\n if (!a[bPath]) {\n log.trace(\"hashes are not equal\", { path: bPath, aHash: undefined, bHash: b[bPath] });\n return false;\n }\n }\n\n return true;\n};\n"],"names":["assert","createLogger","isNil","log","name","ChangesWithHash","Map","created","Array","from","entries","filter","change","type","map","path","updated","deleted","getChanges","source","to","target","existing","ignore","changes","targetPaths","Object","keys","sourcePath","sourceHash","some","ignored","startsWith","targetHash","endsWith","targetPath","set","trace","isEqualHash","withoutUnnecessaryChanges","necessaryChanges","existingHash","a","b","sha1","permissions","isEqualHashes","aPath","aHash","bHash","bPath","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/services/filesync/hashes.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { isNil } from \"../util/is.js\";\nimport { type Create, type Delete, type Update } from \"./changes.js\";\nimport type { Hash, Hashes } from \"./directory.js\";\n\nconst log = createLogger({ name: \"hashes\" });\n\nexport type CreateWithHash = Create & { targetHash: Hash };\nexport type UpdateWithHash = Update & { sourceHash: Hash; targetHash: Hash };\nexport type DeleteWithHash = Delete & { sourceHash: Hash };\nexport type ChangeWithHash = CreateWithHash | UpdateWithHash | DeleteWithHash;\n\nexport class ChangesWithHash extends Map<string, ChangeWithHash> {\n created(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"create\")\n .map(([path]) => path);\n }\n\n updated(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"update\")\n .map(([path]) => path);\n }\n\n deleted(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"delete\")\n .map(([path]) => path);\n }\n}\n\n/**\n * Calculates the changes that were made to `from` to make it end up as `to`.\n *\n * If `existing` is provided, only the changes that are necessary to\n * apply to `existing` are returned.\n *\n * If `ignore` is provided, any changes that were made to a path that\n * starts with any of the `ignore` paths are skipped.\n */\nexport const getChanges = ({\n from: source,\n to: target,\n existing,\n ignore,\n}: {\n from: Hashes;\n to: Hashes;\n existing?: Hashes;\n ignore?: string[];\n}): ChangesWithHash => {\n const changes = new ChangesWithHash();\n const targetPaths = Object.keys(target);\n\n for (const [sourcePath, sourceHash] of Object.entries(source)) {\n if (ignore?.some((ignored) => sourcePath.startsWith(ignored))) {\n continue;\n }\n\n const targetHash = target[sourcePath];\n if (!targetHash) {\n if (!sourcePath.endsWith(\"/\") || !targetPaths.some((targetPath) => targetPath.startsWith(sourcePath))) {\n // sourcePath is a file and it doesn't exist in target OR\n // sourcePath is a directory and target doesn't have any\n // existing files inside it, therefor the sourcePath has been\n // deleted\n changes.set(sourcePath, { type: \"delete\", sourceHash });\n log.trace(\"file deleted\", { path: sourcePath, sourceHash });\n }\n } else if (!isEqualHash(sourcePath, sourceHash, targetHash)) {\n // the file or directory exists in target, but has a different\n // hash, so it's been updated\n changes.set(sourcePath, { type: \"update\", sourceHash, targetHash });\n log.trace(\"file updated\", { path: sourcePath, sourceHash, targetHash });\n }\n }\n\n for (const targetPath of targetPaths) {\n if (ignore?.some((ignored) => targetPath.startsWith(ignored))) {\n continue;\n }\n\n if (!source[targetPath]) {\n // the targetPath doesn't exist in source, so it's been created\n const targetHash = target[targetPath];\n assert(targetHash, \"targetHash should exist\");\n\n changes.set(targetPath, { type: \"create\", targetHash });\n log.trace(\"file created\", { path: targetPath, targetHash });\n }\n }\n\n if (!existing) {\n return changes;\n }\n\n return withoutUnnecessaryChanges({ changes, existing });\n};\n\n/**\n * Filters out changes that the existing filesystem already has.\n */\nexport const withoutUnnecessaryChanges = ({ changes, existing }: { changes: ChangesWithHash; existing: Hashes }): ChangesWithHash => {\n const necessaryChanges = new ChangesWithHash();\n\n for (const [path, change] of changes) {\n const existingHash = existing[path];\n if (change.type === \"delete\" && !existingHash) {\n // already deleted\n log.trace(\"already deleted\", { path });\n continue;\n }\n\n if (change.type !== \"delete\" && existingHash && isEqualHash(path, change.targetHash, existingHash)) {\n // already created or updated\n log.trace(\"already created or updated\", { path, existingHash, targetHash: change.targetHash });\n continue;\n }\n\n // we could do this:\n // if (change.type === \"update\" && !existingHash) {\n // change = { type: \"create\", targetHash: change.targetHash };\n // }\n // but, changing the type makes the output look confusing and it\n // doesn't change the outcome, so we just leave it as is\n\n necessaryChanges.set(path, change);\n }\n\n return necessaryChanges;\n};\n\nexport const isEqualHash = (path: string, aHash: Hash, bHash: Hash): boolean => {\n if (aHash.sha1 !== bHash.sha1) {\n // the contents are different\n return false;\n }\n\n if (path.endsWith(\"/\")) {\n // it's a directory, so we don't care about permissions\n return true;\n }\n\n if (isNil(aHash.permissions) || isNil(bHash.permissions)) {\n // one of the filesystems doesn't support permissions, so ignore them\n return true;\n }\n\n // the contents are the same, and both filesystems support permissions\n // so ensure the permissions are also the same\n return aHash.permissions === bHash.permissions;\n};\n\nexport const isEqualHashes = (a: Hashes, b: Hashes): boolean => {\n for (const [aPath, aHash] of Object.entries(a)) {\n const bHash = b[aPath];\n if (!bHash || !isEqualHash(aPath, aHash, bHash)) {\n log.trace(\"hashes are not equal\", { path: aPath, aHash, bHash });\n return false;\n }\n }\n\n for (const bPath of Object.keys(b)) {\n if (!a[bPath]) {\n log.trace(\"hashes are not equal\", { path: bPath, aHash: undefined, bHash: b[bPath] });\n return false;\n }\n }\n\n return true;\n};\n"],"names":["assert","createLogger","isNil","log","name","ChangesWithHash","Map","created","Array","from","entries","filter","change","type","map","path","updated","deleted","getChanges","source","to","target","existing","ignore","changes","targetPaths","Object","keys","sourcePath","sourceHash","some","ignored","startsWith","targetHash","endsWith","targetPath","set","trace","isEqualHash","withoutUnnecessaryChanges","necessaryChanges","existingHash","aHash","bHash","sha1","permissions","isEqualHashes","a","b","aPath","bPath","undefined"],"mappings":"AAAA,OAAOA,YAAY,cAAc;AACjC,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,KAAK,QAAQ,gBAAgB;AAItC,MAAMC,MAAMF,aAAa;IAAEG,MAAM;AAAS;AAO1C,OAAO,MAAMC,wBAAwBC;IACnCC,UAAoB;QAClB,OAAOC,MAAMC,IAAI,CAAC,IAAI,CAACC,OAAO,IAC3BC,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,UACvCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA;IACrB;IAEAC,UAAoB;QAClB,OAAOR,MAAMC,IAAI,CAAC,IAAI,CAACC,OAAO,IAC3BC,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,UACvCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA;IACrB;IAEAE,UAAoB;QAClB,OAAOT,MAAMC,IAAI,CAAC,IAAI,CAACC,OAAO,IAC3BC,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,UACvCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA;IACrB;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,MAAMG,aAAa,CAAC,EACzBT,MAAMU,MAAM,EACZC,IAAIC,MAAM,EACVC,QAAQ,EACRC,MAAM,EAMP;IACC,MAAMC,UAAU,IAAInB;IACpB,MAAMoB,cAAcC,OAAOC,IAAI,CAACN;IAEhC,KAAK,MAAM,CAACO,YAAYC,WAAW,IAAIH,OAAOhB,OAAO,CAACS,QAAS;QAC7D,IAAII,QAAQO,KAAK,CAACC,UAAYH,WAAWI,UAAU,CAACD,WAAW;YAC7D;QACF;QAEA,MAAME,aAAaZ,MAAM,CAACO,WAAW;QACrC,IAAI,CAACK,YAAY;YACf,IAAI,CAACL,WAAWM,QAAQ,CAAC,QAAQ,CAACT,YAAYK,IAAI,CAAC,CAACK,aAAeA,WAAWH,UAAU,CAACJ,cAAc;gBACrG,yDAAyD;gBACzD,wDAAwD;gBACxD,6DAA6D;gBAC7D,UAAU;gBACVJ,QAAQY,GAAG,CAACR,YAAY;oBAAEf,MAAM;oBAAUgB;gBAAW;gBACrD1B,IAAIkC,KAAK,CAAC,gBAAgB;oBAAEtB,MAAMa;oBAAYC;gBAAW;YAC3D;QACF,OAAO,IAAI,CAACS,YAAYV,YAAYC,YAAYI,aAAa;YAC3D,8DAA8D;YAC9D,6BAA6B;YAC7BT,QAAQY,GAAG,CAACR,YAAY;gBAAEf,MAAM;gBAAUgB;gBAAYI;YAAW;YACjE9B,IAAIkC,KAAK,CAAC,gBAAgB;gBAAEtB,MAAMa;gBAAYC;gBAAYI;YAAW;QACvE;IACF;IAEA,KAAK,MAAME,cAAcV,YAAa;QACpC,IAAIF,QAAQO,KAAK,CAACC,UAAYI,WAAWH,UAAU,CAACD,WAAW;YAC7D;QACF;QAEA,IAAI,CAACZ,MAAM,CAACgB,WAAW,EAAE;YACvB,+DAA+D;YAC/D,MAAMF,aAAaZ,MAAM,CAACc,WAAW;YACrCnC,OAAOiC,YAAY;YAEnBT,QAAQY,GAAG,CAACD,YAAY;gBAAEtB,MAAM;gBAAUoB;YAAW;YACrD9B,IAAIkC,KAAK,CAAC,gBAAgB;gBAAEtB,MAAMoB;gBAAYF;YAAW;QAC3D;IACF;IAEA,IAAI,CAACX,UAAU;QACb,OAAOE;IACT;IAEA,OAAOe,0BAA0B;QAAEf;QAASF;IAAS;AACvD,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMiB,4BAA4B,CAAC,EAAEf,OAAO,EAAEF,QAAQ,EAAkD;IAC7G,MAAMkB,mBAAmB,IAAInC;IAE7B,KAAK,MAAM,CAACU,MAAMH,OAAO,IAAIY,QAAS;QACpC,MAAMiB,eAAenB,QAAQ,CAACP,KAAK;QACnC,IAAIH,OAAOC,IAAI,KAAK,YAAY,CAAC4B,cAAc;YAC7C,kBAAkB;YAClBtC,IAAIkC,KAAK,CAAC,mBAAmB;gBAAEtB;YAAK;YACpC;QACF;QAEA,IAAIH,OAAOC,IAAI,KAAK,YAAY4B,gBAAgBH,YAAYvB,MAAMH,OAAOqB,UAAU,EAAEQ,eAAe;YAClG,6BAA6B;YAC7BtC,IAAIkC,KAAK,CAAC,8BAA8B;gBAAEtB;gBAAM0B;gBAAcR,YAAYrB,OAAOqB,UAAU;YAAC;YAC5F;QACF;QAEA,oBAAoB;QACpB,mDAAmD;QACnD,gEAAgE;QAChE,IAAI;QACJ,gEAAgE;QAChE,wDAAwD;QAExDO,iBAAiBJ,GAAG,CAACrB,MAAMH;IAC7B;IAEA,OAAO4B;AACT,EAAE;AAEF,OAAO,MAAMF,cAAc,CAACvB,MAAc2B,OAAaC;IACrD,IAAID,MAAME,IAAI,KAAKD,MAAMC,IAAI,EAAE;QAC7B,6BAA6B;QAC7B,OAAO;IACT;IAEA,IAAI7B,KAAKmB,QAAQ,CAAC,MAAM;QACtB,uDAAuD;QACvD,OAAO;IACT;IAEA,IAAIhC,MAAMwC,MAAMG,WAAW,KAAK3C,MAAMyC,MAAME,WAAW,GAAG;QACxD,qEAAqE;QACrE,OAAO;IACT;IAEA,sEAAsE;IACtE,8CAA8C;IAC9C,OAAOH,MAAMG,WAAW,KAAKF,MAAME,WAAW;AAChD,EAAE;AAEF,OAAO,MAAMC,gBAAgB,CAACC,GAAWC;IACvC,KAAK,MAAM,CAACC,OAAOP,MAAM,IAAIhB,OAAOhB,OAAO,CAACqC,GAAI;QAC9C,MAAMJ,QAAQK,CAAC,CAACC,MAAM;QACtB,IAAI,CAACN,SAAS,CAACL,YAAYW,OAAOP,OAAOC,QAAQ;YAC/CxC,IAAIkC,KAAK,CAAC,wBAAwB;gBAAEtB,MAAMkC;gBAAOP;gBAAOC;YAAM;YAC9D,OAAO;QACT;IACF;IAEA,KAAK,MAAMO,SAASxB,OAAOC,IAAI,CAACqB,GAAI;QAClC,IAAI,CAACD,CAAC,CAACG,MAAM,EAAE;YACb/C,IAAIkC,KAAK,CAAC,wBAAwB;gBAAEtB,MAAMmC;gBAAOR,OAAOS;gBAAWR,OAAOK,CAAC,CAACE,MAAM;YAAC;YACnF,OAAO;QACT;IACF;IAEA,OAAO;AACT,EAAE"}
@@ -1,8 +1,5 @@
1
- import assert from "node:assert";
2
1
  import stripAnsi from "strip-ansi";
3
- import { config } from "../../../config/config.js";
4
2
  import { isObject, isString } from "../../../util/is.js";
5
- import { Level } from "../level.js";
6
3
  export const formatJson = (level, name, msg, fields)=>{
7
4
  return JSON.stringify({
8
5
  level,
@@ -23,11 +20,6 @@ const serializeValue = (value)=>{
23
20
  value = Array.from(value);
24
21
  }
25
22
  if (Array.isArray(value)) {
26
- if (value.length > 10 && config.logLevel > Level.TRACE) {
27
- // truncate arrays to 10 elements when not tracing
28
- value = value.slice(0, 10);
29
- assert(Array.isArray(value));
30
- }
31
23
  return value.map(serializeValue);
32
24
  }
33
25
  if (value instanceof Map) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/services/output/log/format/json.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport stripAnsi from \"strip-ansi\";\nimport { config } from \"../../../config/config.js\";\nimport { isObject, isString } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatJson: Formatter = (level, name, msg, fields) => {\n return JSON.stringify({ level, name, msg: stripAnsi(msg).trim(), fields: serializeFields(fields) }) + \"\\n\";\n};\n\nconst serializeFields = (fields: Record<string, unknown>): Record<string, unknown> => {\n const result = {} as Record<string, unknown>;\n for (const [key, value] of Object.entries(fields)) {\n result[key] = serializeValue(value);\n }\n return result;\n};\n\nconst serializeValue = (value: unknown): unknown => {\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length > 10 && config.logLevel > Level.TRACE) {\n // truncate arrays to 10 elements when not tracing\n value = value.slice(0, 10);\n assert(Array.isArray(value));\n }\n return value.map(serializeValue);\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value)) {\n return serializeFields(value as Record<string, unknown>);\n }\n\n if (isString(value)) {\n return stripAnsi(value).trim();\n }\n\n return value;\n};\n"],"names":["assert","stripAnsi","config","isObject","isString","Level","formatJson","level","name","msg","fields","JSON","stringify","trim","serializeFields","result","key","value","Object","entries","serializeValue","Set","Array","from","isArray","length","logLevel","TRACE","slice","map","Map","fromEntries"],"mappings":"AAAA,OAAOA,YAAY,cAAc;AACjC,OAAOC,eAAe,aAAa;AACnC,SAASC,MAAM,QAAQ,4BAA4B;AACnD,SAASC,QAAQ,EAAEC,QAAQ,QAAQ,sBAAsB;AACzD,SAASC,KAAK,QAAQ,cAAc;AAGpC,OAAO,MAAMC,aAAwB,CAACC,OAAOC,MAAMC,KAAKC;IACtD,OAAOC,KAAKC,SAAS,CAAC;QAAEL;QAAOC;QAAMC,KAAKR,UAAUQ,KAAKI,IAAI;QAAIH,QAAQI,gBAAgBJ;IAAQ,KAAK;AACxG,EAAE;AAEF,MAAMI,kBAAkB,CAACJ;IACvB,MAAMK,SAAS,CAAC;IAChB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACT,QAAS;QACjDK,MAAM,CAACC,IAAI,GAAGI,eAAeH;IAC/B;IACA,OAAOF;AACT;AAEA,MAAMK,iBAAiB,CAACH;IACtB,IAAIA,iBAAiBI,KAAK;QACxBJ,QAAQK,MAAMC,IAAI,CAACN;IACrB;IAEA,IAAIK,MAAME,OAAO,CAACP,QAAQ;QACxB,IAAIA,MAAMQ,MAAM,GAAG,MAAMvB,OAAOwB,QAAQ,GAAGrB,MAAMsB,KAAK,EAAE;YACtD,kDAAkD;YAClDV,QAAQA,MAAMW,KAAK,CAAC,GAAG;YACvB5B,OAAOsB,MAAME,OAAO,CAACP;QACvB;QACA,OAAOA,MAAMY,GAAG,CAACT;IACnB;IAEA,IAAIH,iBAAiBa,KAAK;QACxBb,QAAQC,OAAOa,WAAW,CAACd,MAAME,OAAO;IAC1C;IAEA,IAAIhB,SAASc,QAAQ;QACnB,OAAOH,gBAAgBG;IACzB;IAEA,IAAIb,SAASa,QAAQ;QACnB,OAAOhB,UAAUgB,OAAOJ,IAAI;IAC9B;IAEA,OAAOI;AACT"}
1
+ {"version":3,"sources":["../../../../../src/services/output/log/format/json.ts"],"sourcesContent":["import stripAnsi from \"strip-ansi\";\nimport { isObject, isString } from \"../../../util/is.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatJson: Formatter = (level, name, msg, fields) => {\n return JSON.stringify({ level, name, msg: stripAnsi(msg).trim(), fields: serializeFields(fields) }) + \"\\n\";\n};\n\nconst serializeFields = (fields: Record<string, unknown>): Record<string, unknown> => {\n const result = {} as Record<string, unknown>;\n for (const [key, value] of Object.entries(fields)) {\n result[key] = serializeValue(value);\n }\n return result;\n};\n\nconst serializeValue = (value: unknown): unknown => {\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n return value.map(serializeValue);\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value)) {\n return serializeFields(value as Record<string, unknown>);\n }\n\n if (isString(value)) {\n return stripAnsi(value).trim();\n }\n\n return value;\n};\n"],"names":["stripAnsi","isObject","isString","formatJson","level","name","msg","fields","JSON","stringify","trim","serializeFields","result","key","value","Object","entries","serializeValue","Set","Array","from","isArray","map","Map","fromEntries"],"mappings":"AAAA,OAAOA,eAAe,aAAa;AACnC,SAASC,QAAQ,EAAEC,QAAQ,QAAQ,sBAAsB;AAGzD,OAAO,MAAMC,aAAwB,CAACC,OAAOC,MAAMC,KAAKC;IACtD,OAAOC,KAAKC,SAAS,CAAC;QAAEL;QAAOC;QAAMC,KAAKN,UAAUM,KAAKI,IAAI;QAAIH,QAAQI,gBAAgBJ;IAAQ,KAAK;AACxG,EAAE;AAEF,MAAMI,kBAAkB,CAACJ;IACvB,MAAMK,SAAS,CAAC;IAChB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACT,QAAS;QACjDK,MAAM,CAACC,IAAI,GAAGI,eAAeH;IAC/B;IACA,OAAOF;AACT;AAEA,MAAMK,iBAAiB,CAACH;IACtB,IAAIA,iBAAiBI,KAAK;QACxBJ,QAAQK,MAAMC,IAAI,CAACN;IACrB;IAEA,IAAIK,MAAME,OAAO,CAACP,QAAQ;QACxB,OAAOA,MAAMQ,GAAG,CAACL;IACnB;IAEA,IAAIH,iBAAiBS,KAAK;QACxBT,QAAQC,OAAOS,WAAW,CAACV,MAAME,OAAO;IAC1C;IAEA,IAAIf,SAASa,QAAQ;QACnB,OAAOH,gBAAgBG;IACzB;IAEA,IAAIZ,SAASY,QAAQ;QACnB,OAAOd,UAAUc,OAAOJ,IAAI;IAC9B;IAEA,OAAOI;AACT"}
@@ -78,17 +78,24 @@ const formatFields = (fields, indent = 2)=>{
78
78
  buf.push(formatValue(" []", gray, indent));
79
79
  continue;
80
80
  }
81
- if (value.length > 10 && config.logLevel > Level.TRACE) {
82
- // truncate arrays to 10 elements when not tracing
83
- value = value.slice(0, 10);
84
- assert(Array.isArray(value));
85
- }
86
- value = Object.fromEntries(value.entries());
87
- }
88
- if (value instanceof Map) {
89
81
  value = Object.fromEntries(value.entries());
90
82
  }
91
- if (isObject(value)) {
83
+ if (isObject(value) || value instanceof Map) {
84
+ const entries = Object.entries(value);
85
+ if (entries.length === 0) {
86
+ buf.push(formatValue(" {}", gray, indent));
87
+ continue;
88
+ }
89
+ if (entries.length > 10 && config.logLevel > Level.TRACE) {
90
+ // truncate objects to 10 keys when not tracing
91
+ value = Object.fromEntries([
92
+ ...entries.slice(0, 10),
93
+ [
94
+ "…",
95
+ `${entries.length - 10} more`
96
+ ]
97
+ ]);
98
+ }
92
99
  buf.push(formatFields(value, indent + 2));
93
100
  continue;
94
101
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/services/output/log/format/pretty.ts"],"sourcesContent":["import chalk, { Chalk } from \"chalk\";\nimport dayjs from \"dayjs\";\nimport assert from \"node:assert\";\nimport { config } from \"../../../config/config.js\";\nimport { env } from \"../../../config/env.js\";\nimport { isObject } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatPretty: Formatter = (level, name, msg, fields) => {\n return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;\n};\n\nconst color = new Chalk({\n // we always turn off colors in tests (FORCE_COLOR=0) so that we get\n // predictable output, but if we're running with logs enabled\n // (GGT_LOG_LEVEL=info), we still want to see colors in our logs\n level: env.testLike && config.logLevel < Level.PRINT ? 3 : chalk.level,\n});\n\nconst blue = color.hex(\"#86B5F7\");\nconst blueLight = color.hex(\"#B2D0FA\");\nconst gray = color.hex(\"#D6D6D6\");\nconst grayDark = color.hex(\"#C2C2C2\");\nconst green = color.hex(\"#9DE6A4\");\nconst greenLight = color.hex(\"#BEEEC3\");\nconst orange = color.hex(\"#EEAC78\");\nconst orangeLight = color.hex(\"#F4C7A4\");\nconst pink = color.hex(\"#FAACB5\");\nconst red = color.hex(\"#A64E4E\");\nconst white = color.hex(\"#FFFFFF\");\n\nconst EMPTY = \"\";\nconst SPACE = \" \";\nconst NEW_LINE = \"\\n\";\nconst COLON = \":\";\nconst QUOTE = \"'\";\n\nconst formatKey = (key: string, indent: number): string => {\n const color = key === \"error\" ? red : gray;\n\n const buf: string[] = [];\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n buf.push(color(key));\n buf.push(COLON);\n\n return buf.join(\"\");\n};\n\nconst formatValue = (value: string, color: (s: string) => string, indent: number): string => {\n const lines = value.split(NEW_LINE);\n if (lines.length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n const firstLine = lines.shift();\n assert(firstLine);\n buf.push(color(firstLine));\n\n // color the rest of the lines\n for (const line of lines) {\n if (!line) {\n continue;\n }\n\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n\n buf.push(color(line));\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatFields = (fields: Record<string, unknown>, indent = 2): string => {\n if (Object.keys(fields).length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n for (let [key, value] of Object.entries(fields)) {\n buf.push(formatKey(key, indent));\n\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n buf.push(formatValue(\" []\", gray, indent));\n continue;\n }\n\n if (value.length > 10 && config.logLevel > Level.TRACE) {\n // truncate arrays to 10 elements when not tracing\n value = value.slice(0, 10);\n assert(Array.isArray(value));\n }\n\n value = Object.fromEntries(value.entries());\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value)) {\n buf.push(formatFields(value as Record<string, unknown>, indent + 2));\n continue;\n }\n\n buf.push(SPACE);\n\n switch (typeof value) {\n case \"string\":\n buf.push(formatValue(QUOTE + value.replaceAll(NEW_LINE, NEW_LINE + SPACE.repeat(indent + key.length)) + QUOTE, blueLight, indent));\n break;\n case \"number\":\n buf.push(formatValue(String(value), orangeLight, indent));\n break;\n case \"bigint\":\n buf.push(formatValue(String(value) + \"n\", orangeLight, indent));\n break;\n case \"boolean\":\n buf.push(formatValue(String(value), greenLight, indent));\n break;\n default:\n buf.push(formatValue(String(value), white, indent));\n break;\n }\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatTimestamp = (): string => {\n const ts = dayjs().format(\"hh:mm:ss\");\n return grayDark(ts);\n};\n\nconst formatLevel = (level: Level): string => {\n switch (level) {\n case Level.PRINT:\n return gray(\"PRINT\");\n case Level.TRACE:\n return blue(\"TRACE\");\n case Level.DEBUG:\n return orange(\"DEBUG\");\n case Level.INFO:\n return green(\"INFO\");\n case Level.WARN:\n return pink(\"WARN\");\n case Level.ERROR:\n return red(\"ERROR\");\n // case \"fatal\":\n // return red(colors.bold(level));\n }\n};\n\nconst formatName = (name: string): string => {\n return white(name);\n};\n\nconst formatMessage = (msg: string): string => {\n const lines = msg.split(NEW_LINE);\n if (lines.length === 1) {\n return SPACE + white(msg);\n }\n return NEW_LINE + lines.map((line) => SPACE + SPACE + line).join(NEW_LINE);\n};\n"],"names":["chalk","Chalk","dayjs","assert","config","env","isObject","Level","formatPretty","level","name","msg","fields","formatTimestamp","formatLevel","formatName","formatMessage","formatFields","NEW_LINE","color","testLike","logLevel","PRINT","blue","hex","blueLight","gray","grayDark","green","greenLight","orange","orangeLight","pink","red","white","EMPTY","SPACE","COLON","QUOTE","formatKey","key","indent","buf","push","i","join","formatValue","value","lines","split","length","firstLine","shift","line","Object","keys","entries","Set","Array","from","isArray","TRACE","slice","fromEntries","Map","replaceAll","repeat","String","ts","format","DEBUG","INFO","WARN","ERROR","map"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/services/output/log/format/pretty.ts"],"sourcesContent":["import chalk, { Chalk } from \"chalk\";\nimport dayjs from \"dayjs\";\nimport assert from \"node:assert\";\nimport { config } from \"../../../config/config.js\";\nimport { env } from \"../../../config/env.js\";\nimport { isObject } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatPretty: Formatter = (level, name, msg, fields) => {\n return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;\n};\n\nconst color = new Chalk({\n // we always turn off colors in tests (FORCE_COLOR=0) so that we get\n // predictable output, but if we're running with logs enabled\n // (GGT_LOG_LEVEL=info), we still want to see colors in our logs\n level: env.testLike && config.logLevel < Level.PRINT ? 3 : chalk.level,\n});\n\nconst blue = color.hex(\"#86B5F7\");\nconst blueLight = color.hex(\"#B2D0FA\");\nconst gray = color.hex(\"#D6D6D6\");\nconst grayDark = color.hex(\"#C2C2C2\");\nconst green = color.hex(\"#9DE6A4\");\nconst greenLight = color.hex(\"#BEEEC3\");\nconst orange = color.hex(\"#EEAC78\");\nconst orangeLight = color.hex(\"#F4C7A4\");\nconst pink = color.hex(\"#FAACB5\");\nconst red = color.hex(\"#A64E4E\");\nconst white = color.hex(\"#FFFFFF\");\n\nconst EMPTY = \"\";\nconst SPACE = \" \";\nconst NEW_LINE = \"\\n\";\nconst COLON = \":\";\nconst QUOTE = \"'\";\n\nconst formatKey = (key: string, indent: number): string => {\n const color = key === \"error\" ? red : gray;\n\n const buf: string[] = [];\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n buf.push(color(key));\n buf.push(COLON);\n\n return buf.join(\"\");\n};\n\nconst formatValue = (value: string, color: (s: string) => string, indent: number): string => {\n const lines = value.split(NEW_LINE);\n if (lines.length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n const firstLine = lines.shift();\n assert(firstLine);\n buf.push(color(firstLine));\n\n // color the rest of the lines\n for (const line of lines) {\n if (!line) {\n continue;\n }\n\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n\n buf.push(color(line));\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatFields = (fields: Record<string, unknown>, indent = 2): string => {\n if (Object.keys(fields).length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n for (let [key, value] of Object.entries(fields)) {\n buf.push(formatKey(key, indent));\n\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n buf.push(formatValue(\" []\", gray, indent));\n continue;\n }\n\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value) || value instanceof Map) {\n const entries = Object.entries(value);\n if (entries.length === 0) {\n buf.push(formatValue(\" {}\", gray, indent));\n continue;\n }\n\n if (entries.length > 10 && config.logLevel > Level.TRACE) {\n // truncate objects to 10 keys when not tracing\n value = Object.fromEntries([...entries.slice(0, 10), [\"…\", `${entries.length - 10} more`]]);\n }\n\n buf.push(formatFields(value as Record<string, unknown>, indent + 2));\n continue;\n }\n\n buf.push(SPACE);\n\n switch (typeof value) {\n case \"string\":\n buf.push(formatValue(QUOTE + value.replaceAll(NEW_LINE, NEW_LINE + SPACE.repeat(indent + key.length)) + QUOTE, blueLight, indent));\n break;\n case \"number\":\n buf.push(formatValue(String(value), orangeLight, indent));\n break;\n case \"bigint\":\n buf.push(formatValue(String(value) + \"n\", orangeLight, indent));\n break;\n case \"boolean\":\n buf.push(formatValue(String(value), greenLight, indent));\n break;\n default:\n buf.push(formatValue(String(value), white, indent));\n break;\n }\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatTimestamp = (): string => {\n const ts = dayjs().format(\"hh:mm:ss\");\n return grayDark(ts);\n};\n\nconst formatLevel = (level: Level): string => {\n switch (level) {\n case Level.PRINT:\n return gray(\"PRINT\");\n case Level.TRACE:\n return blue(\"TRACE\");\n case Level.DEBUG:\n return orange(\"DEBUG\");\n case Level.INFO:\n return green(\"INFO\");\n case Level.WARN:\n return pink(\"WARN\");\n case Level.ERROR:\n return red(\"ERROR\");\n // case \"fatal\":\n // return red(colors.bold(level));\n }\n};\n\nconst formatName = (name: string): string => {\n return white(name);\n};\n\nconst formatMessage = (msg: string): string => {\n const lines = msg.split(NEW_LINE);\n if (lines.length === 1) {\n return SPACE + white(msg);\n }\n return NEW_LINE + lines.map((line) => SPACE + SPACE + line).join(NEW_LINE);\n};\n"],"names":["chalk","Chalk","dayjs","assert","config","env","isObject","Level","formatPretty","level","name","msg","fields","formatTimestamp","formatLevel","formatName","formatMessage","formatFields","NEW_LINE","color","testLike","logLevel","PRINT","blue","hex","blueLight","gray","grayDark","green","greenLight","orange","orangeLight","pink","red","white","EMPTY","SPACE","COLON","QUOTE","formatKey","key","indent","buf","push","i","join","formatValue","value","lines","split","length","firstLine","shift","line","Object","keys","entries","Set","Array","from","isArray","fromEntries","Map","TRACE","slice","replaceAll","repeat","String","ts","format","DEBUG","INFO","WARN","ERROR","map"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ export const installJsonExtensions = ()=>{
2
+ if (!Object.prototype.hasOwnProperty.call(BigInt, "toJSON")) {
3
+ BigInt.prototype.toJSON = function() {
4
+ return String(this);
5
+ };
6
+ }
7
+ if (!Object.prototype.hasOwnProperty.call(Map, "toJSON")) {
8
+ Map.prototype.toJSON = function() {
9
+ return Object.fromEntries(this);
10
+ };
11
+ }
12
+ if (!Object.prototype.hasOwnProperty.call(Set, "toJSON")) {
13
+ Set.prototype.toJSON = function() {
14
+ return Array.from(this);
15
+ };
16
+ }
17
+ };
18
+ export const uninstallJsonExtensions = ()=>{
19
+ if (Object.prototype.hasOwnProperty.call(BigInt, "toJSON")) {
20
+ delete BigInt.prototype.toJSON;
21
+ }
22
+ if (Object.prototype.hasOwnProperty.call(Map, "toJSON")) {
23
+ delete Map.prototype.toJSON;
24
+ }
25
+ if (Object.prototype.hasOwnProperty.call(Set, "toJSON")) {
26
+ delete Set.prototype.toJSON;
27
+ }
28
+ };
29
+
30
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/util/json.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/consistent-type-definitions */\n\ndeclare global {\n interface BigInt {\n toJSON?(): string;\n }\n interface Map<K, V> {\n toJSON?(): Record<string, V>;\n }\n interface Set<T> {\n toJSON?(): T[];\n }\n}\n\nexport const installJsonExtensions = (): void => {\n if (!Object.prototype.hasOwnProperty.call(BigInt, \"toJSON\")) {\n BigInt.prototype.toJSON = function () {\n return String(this);\n };\n }\n\n if (!Object.prototype.hasOwnProperty.call(Map, \"toJSON\")) {\n Map.prototype.toJSON = function () {\n return Object.fromEntries(this);\n };\n }\n\n if (!Object.prototype.hasOwnProperty.call(Set, \"toJSON\")) {\n Set.prototype.toJSON = function () {\n return Array.from(this);\n };\n }\n};\n\nexport const uninstallJsonExtensions = (): void => {\n if (Object.prototype.hasOwnProperty.call(BigInt, \"toJSON\")) {\n delete BigInt.prototype.toJSON;\n }\n\n if (Object.prototype.hasOwnProperty.call(Map, \"toJSON\")) {\n delete Map.prototype.toJSON;\n }\n\n if (Object.prototype.hasOwnProperty.call(Set, \"toJSON\")) {\n delete Set.prototype.toJSON;\n }\n};\n"],"names":["installJsonExtensions","Object","prototype","hasOwnProperty","call","BigInt","toJSON","String","Map","fromEntries","Set","Array","from","uninstallJsonExtensions"],"mappings":"AAAA,oDAAoD,GACpD,sDAAsD,GACtD,iEAAiE,GAcjE,OAAO,MAAMA,wBAAwB;IACnC,IAAI,CAACC,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACC,QAAQ,WAAW;QAC3DA,OAAOH,SAAS,CAACI,MAAM,GAAG;YACxB,OAAOC,OAAO,IAAI;QACpB;IACF;IAEA,IAAI,CAACN,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACI,KAAK,WAAW;QACxDA,IAAIN,SAAS,CAACI,MAAM,GAAG;YACrB,OAAOL,OAAOQ,WAAW,CAAC,IAAI;QAChC;IACF;IAEA,IAAI,CAACR,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACM,KAAK,WAAW;QACxDA,IAAIR,SAAS,CAACI,MAAM,GAAG;YACrB,OAAOK,MAAMC,IAAI,CAAC,IAAI;QACxB;IACF;AACF,EAAE;AAEF,OAAO,MAAMC,0BAA0B;IACrC,IAAIZ,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACC,QAAQ,WAAW;QAC1D,OAAOA,OAAOH,SAAS,CAACI,MAAM;IAChC;IAEA,IAAIL,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACI,KAAK,WAAW;QACvD,OAAOA,IAAIN,SAAS,CAACI,MAAM;IAC7B;IAEA,IAAIL,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACM,KAAK,WAAW;QACvD,OAAOA,IAAIR,SAAS,CAACI,MAAM;IAC7B;AACF,EAAE"}
@@ -75,6 +75,9 @@ import { workspaceRoot } from "./paths.js";
75
75
  * Wraps `serialize-error` with some handy stuff, like special support
76
76
  * for Got HTTP errors
77
77
  */ export const serializeError = (error)=>{
78
+ if (Array.isArray(error) && error.length === 1) {
79
+ error = error[0];
80
+ }
78
81
  let serialized = baseSerializeError(Array.isArray(error) ? new AggregateError(error) : error);
79
82
  if (typeof serialized == "string") {
80
83
  serialized = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/util/object.ts"],"sourcesContent":["import cleanStack from \"clean-stack\";\nimport { RequestError } from \"got\";\nimport { inspect } from \"node:util\";\nimport { serializeError as baseSerializeError, type ErrorObject } from \"serialize-error\";\nimport type { Simplify } from \"type-fest\";\nimport { workspaceRoot } from \"./paths.js\";\n\n/**\n * Returns a new object with the properties of the input object merged\n * with the properties of the defaults object. If a property exists in\n * both objects, the property of the input object will be used.\n *\n * @param input - The input object to merge with the defaults object.\n * @param defaults - The defaults object to merge with the input object.\n * @returns A new object with the properties of the input object merged\n * with the properties of the defaults object.\n */\nexport const defaults = <Input extends Record<string, unknown>, Defaults extends Partial<Input>>(\n input: Input | null | undefined,\n defaults: Defaults,\n): Simplify<Defaults & Input> => {\n const result = { ...input };\n for (const [key, defaultValue] of Object.entries(defaults)) {\n if (!result[key]) {\n result[key] = defaultValue;\n }\n }\n return result as Simplify<Defaults & Input>;\n};\n\n/**\n * Creates a new object with only the specified properties of the\n * original object.\n *\n * @param object - The original object to pick properties from.\n * @param keys - The keys of the properties to pick.\n * @returns A new object with only the specified properties of the\n * original object.\n */\nexport const pick = <T extends Record<string, unknown>, K extends keyof T>(object: T, keys: readonly K[]): Pick<T, K> => {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n result[key] = object[key];\n }\n return result;\n};\n\n/**\n * Returns a new object with the specified keys omitted.\n *\n * @param record The input object.\n * @param keys The keys to omit.\n * @returns A new object with the specified keys omitted.\n */\nexport const omit = <T extends Record<string, unknown>, K extends keyof T>(record: T, keys: readonly K[]): Omit<T, K> => {\n const result = { ...record };\n for (const key of keys) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete result[key];\n }\n return result;\n};\n\n/**\n * Maps the values of an object to a new set of values using the\n * provided function.\n *\n * @param obj The input object to map.\n * @param fn The function to apply to each value in the input object.\n * @returns A new object with the same keys as the input object, but\n * with the values mapped to new values using the provided function.\n */\nexport const mapValues = <Key extends string | number | symbol, Value, MappedValue>(\n obj: Record<Key, Value>,\n fn: (value: Value) => MappedValue,\n): Record<Key, MappedValue> => {\n const result = {} as Record<Key, MappedValue>;\n for (const [key, value] of Object.entries(obj)) {\n result[key as Key] = fn(value as Value);\n }\n return result;\n};\n\n/**\n * Universal Error object to json blob serializer.\n *\n * Wraps `serialize-error` with some handy stuff, like special support\n * for Got HTTP errors\n */\nexport const serializeError = (error: unknown): ErrorObject => {\n let serialized = baseSerializeError(Array.isArray(error) ? new AggregateError(error) : error);\n if (typeof serialized == \"string\") {\n serialized = { message: serialized };\n }\n\n if (serialized.stack) {\n serialized.stack = cleanStack(serialized.stack, { pretty: true, basePath: workspaceRoot }).replaceAll(/file:\\/\\/\\//g, \"\");\n }\n\n if (error instanceof RequestError) {\n serialized[\"timings\"] = undefined;\n serialized[\"options\"] = {\n method: error.options.method,\n url: error.options.url instanceof URL ? error.options.url.toJSON() : error.options.url,\n };\n serialized[\"responseBody\"] = inspect(error.response?.body);\n }\n\n return serialized;\n};\n"],"names":["cleanStack","RequestError","inspect","serializeError","baseSerializeError","workspaceRoot","defaults","input","result","key","defaultValue","Object","entries","pick","object","keys","omit","record","mapValues","obj","fn","value","error","serialized","Array","isArray","AggregateError","message","stack","pretty","basePath","replaceAll","undefined","method","options","url","URL","toJSON","response","body"],"mappings":"AAAA,OAAOA,gBAAgB,cAAc;AACrC,SAASC,YAAY,QAAQ,MAAM;AACnC,SAASC,OAAO,QAAQ,YAAY;AACpC,SAASC,kBAAkBC,kBAAkB,QAA0B,kBAAkB;AAEzF,SAASC,aAAa,QAAQ,aAAa;AAE3C;;;;;;;;;CASC,GACD,OAAO,MAAMC,WAAW,CACtBC,OACAD;IAEA,MAAME,SAAS;QAAE,GAAGD,KAAK;IAAC;IAC1B,KAAK,MAAM,CAACE,KAAKC,aAAa,IAAIC,OAAOC,OAAO,CAACN,UAAW;QAC1D,IAAI,CAACE,MAAM,CAACC,IAAI,EAAE;YAChBD,MAAM,CAACC,IAAI,GAAGC;QAChB;IACF;IACA,OAAOF;AACT,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAMK,OAAO,CAAuDC,QAAWC;IACpF,MAAMP,SAAS,CAAC;IAChB,KAAK,MAAMC,OAAOM,KAAM;QACtBP,MAAM,CAACC,IAAI,GAAGK,MAAM,CAACL,IAAI;IAC3B;IACA,OAAOD;AACT,EAAE;AAEF;;;;;;CAMC,GACD,OAAO,MAAMQ,OAAO,CAAuDC,QAAWF;IACpF,MAAMP,SAAS;QAAE,GAAGS,MAAM;IAAC;IAC3B,KAAK,MAAMR,OAAOM,KAAM;QACtB,gEAAgE;QAChE,OAAOP,MAAM,CAACC,IAAI;IACpB;IACA,OAAOD;AACT,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAMU,YAAY,CACvBC,KACAC;IAEA,MAAMZ,SAAS,CAAC;IAChB,KAAK,MAAM,CAACC,KAAKY,MAAM,IAAIV,OAAOC,OAAO,CAACO,KAAM;QAC9CX,MAAM,CAACC,IAAW,GAAGW,GAAGC;IAC1B;IACA,OAAOb;AACT,EAAE;AAEF;;;;;CAKC,GACD,OAAO,MAAML,iBAAiB,CAACmB;IAC7B,IAAIC,aAAanB,mBAAmBoB,MAAMC,OAAO,CAACH,SAAS,IAAII,eAAeJ,SAASA;IACvF,IAAI,OAAOC,cAAc,UAAU;QACjCA,aAAa;YAAEI,SAASJ;QAAW;IACrC;IAEA,IAAIA,WAAWK,KAAK,EAAE;QACpBL,WAAWK,KAAK,GAAG5B,WAAWuB,WAAWK,KAAK,EAAE;YAAEC,QAAQ;YAAMC,UAAUzB;QAAc,GAAG0B,UAAU,CAAC,gBAAgB;IACxH;IAEA,IAAIT,iBAAiBrB,cAAc;QACjCsB,UAAU,CAAC,UAAU,GAAGS;QACxBT,UAAU,CAAC,UAAU,GAAG;YACtBU,QAAQX,MAAMY,OAAO,CAACD,MAAM;YAC5BE,KAAKb,MAAMY,OAAO,CAACC,GAAG,YAAYC,MAAMd,MAAMY,OAAO,CAACC,GAAG,CAACE,MAAM,KAAKf,MAAMY,OAAO,CAACC,GAAG;QACxF;QACAZ,UAAU,CAAC,eAAe,GAAGrB,QAAQoB,MAAMgB,QAAQ,EAAEC;IACvD;IAEA,OAAOhB;AACT,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/util/object.ts"],"sourcesContent":["import cleanStack from \"clean-stack\";\nimport { RequestError } from \"got\";\nimport { inspect } from \"node:util\";\nimport { serializeError as baseSerializeError, type ErrorObject } from \"serialize-error\";\nimport type { Simplify } from \"type-fest\";\nimport { workspaceRoot } from \"./paths.js\";\n\n/**\n * Returns a new object with the properties of the input object merged\n * with the properties of the defaults object. If a property exists in\n * both objects, the property of the input object will be used.\n *\n * @param input - The input object to merge with the defaults object.\n * @param defaults - The defaults object to merge with the input object.\n * @returns A new object with the properties of the input object merged\n * with the properties of the defaults object.\n */\nexport const defaults = <Input extends Record<string, unknown>, Defaults extends Partial<Input>>(\n input: Input | null | undefined,\n defaults: Defaults,\n): Simplify<Defaults & Input> => {\n const result = { ...input };\n for (const [key, defaultValue] of Object.entries(defaults)) {\n if (!result[key]) {\n result[key] = defaultValue;\n }\n }\n return result as Simplify<Defaults & Input>;\n};\n\n/**\n * Creates a new object with only the specified properties of the\n * original object.\n *\n * @param object - The original object to pick properties from.\n * @param keys - The keys of the properties to pick.\n * @returns A new object with only the specified properties of the\n * original object.\n */\nexport const pick = <T extends Record<string, unknown>, K extends keyof T>(object: T, keys: readonly K[]): Pick<T, K> => {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n result[key] = object[key];\n }\n return result;\n};\n\n/**\n * Returns a new object with the specified keys omitted.\n *\n * @param record The input object.\n * @param keys The keys to omit.\n * @returns A new object with the specified keys omitted.\n */\nexport const omit = <T extends Record<string, unknown>, K extends keyof T>(record: T, keys: readonly K[]): Omit<T, K> => {\n const result = { ...record };\n for (const key of keys) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete result[key];\n }\n return result;\n};\n\n/**\n * Maps the values of an object to a new set of values using the\n * provided function.\n *\n * @param obj The input object to map.\n * @param fn The function to apply to each value in the input object.\n * @returns A new object with the same keys as the input object, but\n * with the values mapped to new values using the provided function.\n */\nexport const mapValues = <Key extends string | number | symbol, Value, MappedValue>(\n obj: Record<Key, Value>,\n fn: (value: Value) => MappedValue,\n): Record<Key, MappedValue> => {\n const result = {} as Record<Key, MappedValue>;\n for (const [key, value] of Object.entries(obj)) {\n result[key as Key] = fn(value as Value);\n }\n return result;\n};\n\n/**\n * Universal Error object to json blob serializer.\n *\n * Wraps `serialize-error` with some handy stuff, like special support\n * for Got HTTP errors\n */\nexport const serializeError = (error: unknown): ErrorObject => {\n if (Array.isArray(error) && error.length === 1) {\n error = error[0];\n }\n\n let serialized = baseSerializeError(Array.isArray(error) ? new AggregateError(error) : error);\n if (typeof serialized == \"string\") {\n serialized = { message: serialized };\n }\n\n if (serialized.stack) {\n serialized.stack = cleanStack(serialized.stack, { pretty: true, basePath: workspaceRoot }).replaceAll(/file:\\/\\/\\//g, \"\");\n }\n\n if (error instanceof RequestError) {\n serialized[\"timings\"] = undefined;\n serialized[\"options\"] = {\n method: error.options.method,\n url: error.options.url instanceof URL ? error.options.url.toJSON() : error.options.url,\n };\n serialized[\"responseBody\"] = inspect(error.response?.body);\n }\n\n return serialized;\n};\n"],"names":["cleanStack","RequestError","inspect","serializeError","baseSerializeError","workspaceRoot","defaults","input","result","key","defaultValue","Object","entries","pick","object","keys","omit","record","mapValues","obj","fn","value","error","Array","isArray","length","serialized","AggregateError","message","stack","pretty","basePath","replaceAll","undefined","method","options","url","URL","toJSON","response","body"],"mappings":"AAAA,OAAOA,gBAAgB,cAAc;AACrC,SAASC,YAAY,QAAQ,MAAM;AACnC,SAASC,OAAO,QAAQ,YAAY;AACpC,SAASC,kBAAkBC,kBAAkB,QAA0B,kBAAkB;AAEzF,SAASC,aAAa,QAAQ,aAAa;AAE3C;;;;;;;;;CASC,GACD,OAAO,MAAMC,WAAW,CACtBC,OACAD;IAEA,MAAME,SAAS;QAAE,GAAGD,KAAK;IAAC;IAC1B,KAAK,MAAM,CAACE,KAAKC,aAAa,IAAIC,OAAOC,OAAO,CAACN,UAAW;QAC1D,IAAI,CAACE,MAAM,CAACC,IAAI,EAAE;YAChBD,MAAM,CAACC,IAAI,GAAGC;QAChB;IACF;IACA,OAAOF;AACT,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAMK,OAAO,CAAuDC,QAAWC;IACpF,MAAMP,SAAS,CAAC;IAChB,KAAK,MAAMC,OAAOM,KAAM;QACtBP,MAAM,CAACC,IAAI,GAAGK,MAAM,CAACL,IAAI;IAC3B;IACA,OAAOD;AACT,EAAE;AAEF;;;;;;CAMC,GACD,OAAO,MAAMQ,OAAO,CAAuDC,QAAWF;IACpF,MAAMP,SAAS;QAAE,GAAGS,MAAM;IAAC;IAC3B,KAAK,MAAMR,OAAOM,KAAM;QACtB,gEAAgE;QAChE,OAAOP,MAAM,CAACC,IAAI;IACpB;IACA,OAAOD;AACT,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAMU,YAAY,CACvBC,KACAC;IAEA,MAAMZ,SAAS,CAAC;IAChB,KAAK,MAAM,CAACC,KAAKY,MAAM,IAAIV,OAAOC,OAAO,CAACO,KAAM;QAC9CX,MAAM,CAACC,IAAW,GAAGW,GAAGC;IAC1B;IACA,OAAOb;AACT,EAAE;AAEF;;;;;CAKC,GACD,OAAO,MAAML,iBAAiB,CAACmB;IAC7B,IAAIC,MAAMC,OAAO,CAACF,UAAUA,MAAMG,MAAM,KAAK,GAAG;QAC9CH,QAAQA,KAAK,CAAC,EAAE;IAClB;IAEA,IAAII,aAAatB,mBAAmBmB,MAAMC,OAAO,CAACF,SAAS,IAAIK,eAAeL,SAASA;IACvF,IAAI,OAAOI,cAAc,UAAU;QACjCA,aAAa;YAAEE,SAASF;QAAW;IACrC;IAEA,IAAIA,WAAWG,KAAK,EAAE;QACpBH,WAAWG,KAAK,GAAG7B,WAAW0B,WAAWG,KAAK,EAAE;YAAEC,QAAQ;YAAMC,UAAU1B;QAAc,GAAG2B,UAAU,CAAC,gBAAgB;IACxH;IAEA,IAAIV,iBAAiBrB,cAAc;QACjCyB,UAAU,CAAC,UAAU,GAAGO;QACxBP,UAAU,CAAC,UAAU,GAAG;YACtBQ,QAAQZ,MAAMa,OAAO,CAACD,MAAM;YAC5BE,KAAKd,MAAMa,OAAO,CAACC,GAAG,YAAYC,MAAMf,MAAMa,OAAO,CAACC,GAAG,CAACE,MAAM,KAAKhB,MAAMa,OAAO,CAACC,GAAG;QACxF;QACAV,UAAU,CAAC,eAAe,GAAGxB,QAAQoB,MAAMiB,QAAQ,EAAEC;IACvD;IAEA,OAAOd;AACT,EAAE"}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@gadgetinc/ggt",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@gadgetinc/ggt",
9
- "version": "0.4.1",
9
+ "version": "0.4.3",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@sentry/node": "^7.88.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadgetinc/ggt",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "The command-line interface for Gadget",
5
5
  "homepage": "https://github.com/gadget-inc/ggt",
6
6
  "bugs": {