@gadgetinc/ggt 0.2.4 → 0.3.1

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 (72) hide show
  1. package/README.md +79 -91
  2. package/bin/dev.js +11 -19
  3. package/bin/run.js +1 -9
  4. package/lib/__generated__/graphql.js +2 -2
  5. package/lib/__generated__/graphql.js.map +1 -1
  6. package/lib/commands/index.js +9 -0
  7. package/lib/commands/index.js.map +1 -0
  8. package/lib/commands/list.js +34 -49
  9. package/lib/commands/list.js.map +1 -1
  10. package/lib/commands/login.js +74 -17
  11. package/lib/commands/login.js.map +1 -1
  12. package/lib/commands/logout.js +19 -23
  13. package/lib/commands/logout.js.map +1 -1
  14. package/lib/commands/root.js +85 -0
  15. package/lib/commands/root.js.map +1 -0
  16. package/lib/commands/sync.js +319 -685
  17. package/lib/commands/sync.js.map +1 -1
  18. package/lib/commands/whoami.js +23 -27
  19. package/lib/commands/whoami.js.map +1 -1
  20. package/lib/main.js +12 -0
  21. package/lib/main.js.map +1 -0
  22. package/lib/services/app.js +36 -0
  23. package/lib/services/app.js.map +1 -0
  24. package/lib/services/args.js +28 -0
  25. package/lib/services/args.js.map +1 -0
  26. package/lib/services/config.js +139 -0
  27. package/lib/services/config.js.map +1 -0
  28. package/lib/services/edit-graphql.js +193 -0
  29. package/lib/services/edit-graphql.js.map +1 -0
  30. package/lib/services/errors.js +64 -89
  31. package/lib/services/errors.js.map +1 -1
  32. package/lib/services/filesync.js +404 -0
  33. package/lib/services/filesync.js.map +1 -0
  34. package/lib/services/fs-utils.js +18 -91
  35. package/lib/services/fs-utils.js.map +1 -1
  36. package/lib/services/http.js +53 -0
  37. package/lib/services/http.js.map +1 -0
  38. package/lib/services/log.js +45 -0
  39. package/lib/services/log.js.map +1 -0
  40. package/lib/services/notify.js +30 -0
  41. package/lib/services/notify.js.map +1 -0
  42. package/lib/services/output.js +59 -0
  43. package/lib/services/output.js.map +1 -0
  44. package/lib/services/promise.js +8 -5
  45. package/lib/services/promise.js.map +1 -1
  46. package/lib/services/session.js +27 -0
  47. package/lib/services/session.js.map +1 -0
  48. package/lib/services/sleep.js +2 -5
  49. package/lib/services/sleep.js.map +1 -1
  50. package/lib/services/timeout.js +8 -0
  51. package/lib/services/timeout.js.map +1 -0
  52. package/lib/services/user.js +70 -0
  53. package/lib/services/user.js.map +1 -0
  54. package/lib/services/version.js +72 -0
  55. package/lib/services/version.js.map +1 -0
  56. package/npm-shrinkwrap.json +15680 -25737
  57. package/package.json +53 -60
  58. package/lib/commands/help.js +0 -28
  59. package/lib/commands/help.js.map +0 -1
  60. package/lib/index.js +0 -3
  61. package/lib/index.js.map +0 -1
  62. package/lib/services/base-command.js +0 -203
  63. package/lib/services/base-command.js.map +0 -1
  64. package/lib/services/client.js +0 -209
  65. package/lib/services/client.js.map +0 -1
  66. package/lib/services/context.js +0 -143
  67. package/lib/services/context.js.map +0 -1
  68. package/lib/services/flags.js +0 -57
  69. package/lib/services/flags.js.map +0 -1
  70. package/lib/services/help.js +0 -36
  71. package/lib/services/help.js.map +0 -1
  72. package/oclif.manifest.json +0 -244
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/http.ts"],"sourcesContent":["import { got, HTTPError, type OptionsInit } from \"got\";\nimport { config } from \"./config.js\";\nimport { createLogger } from \"./log.js\";\nimport { readSession, writeSession } from \"./session.js\";\n\nconst log = createLogger(\"http\");\n\nexport const http = got.extend({\n hooks: {\n beforeRequest: [\n (options) => {\n options.headers[\"user-agent\"] = config.versionFull;\n log.info(\"http request\", {\n method: options.method,\n url: options.url?.toString(),\n });\n },\n ],\n afterResponse: [\n (response) => {\n log.info(\"http response\", {\n method: response.request.options.method,\n url: response.request.options.url?.toString(),\n statusCode: response.statusCode,\n traceId: response.headers[\"x-trace-id\"],\n });\n\n if (response.statusCode === 401 && isGadgetRequest(response.request.options)) {\n writeSession(undefined);\n }\n return response;\n },\n ],\n },\n});\n\nexport const isUnauthorized = (error: unknown): boolean => {\n return error instanceof HTTPError && error.response.statusCode === 401 && isGadgetRequest(error.request.options);\n};\n\nexport const swallowUnauthorized = (error: unknown): void => {\n if (isUnauthorized(error)) {\n log.warn(\"swallowing unauthorized error\", { error });\n return;\n }\n throw error;\n};\n\nexport const loadCookie = (): string | undefined => {\n const token = readSession();\n return token && `session=${encodeURIComponent(token)};`;\n};\n\nconst isGadgetRequest = (options: OptionsInit) => {\n return options.url instanceof URL && options.url.host === config.domains.services;\n};\n"],"names":["got","HTTPError","config","createLogger","readSession","writeSession","log","http","extend","hooks","beforeRequest","options","headers","versionFull","info","method","url","toString","afterResponse","response","request","statusCode","traceId","isGadgetRequest","undefined","isUnauthorized","error","swallowUnauthorized","warn","loadCookie","token","encodeURIComponent","URL","host","domains","services"],"mappings":"AAAA,SAASA,GAAG,EAAEC,SAAS,QAA0B,MAAM;AACvD,SAASC,MAAM,QAAQ,cAAc;AACrC,SAASC,YAAY,QAAQ,WAAW;AACxC,SAASC,WAAW,EAAEC,YAAY,QAAQ,eAAe;AAEzD,MAAMC,MAAMH,aAAa;AAEzB,OAAO,MAAMI,OAAOP,IAAIQ,MAAM,CAAC;IAC7BC,OAAO;QACLC,eAAe;YACb,CAACC;gBACCA,QAAQC,OAAO,CAAC,aAAa,GAAGV,OAAOW,WAAW;gBAClDP,IAAIQ,IAAI,CAAC,gBAAgB;oBACvBC,QAAQJ,QAAQI,MAAM;oBACtBC,KAAKL,QAAQK,GAAG,EAAEC;gBACpB;YACF;SACD;QACDC,eAAe;YACb,CAACC;gBACCb,IAAIQ,IAAI,CAAC,iBAAiB;oBACxBC,QAAQI,SAASC,OAAO,CAACT,OAAO,CAACI,MAAM;oBACvCC,KAAKG,SAASC,OAAO,CAACT,OAAO,CAACK,GAAG,EAAEC;oBACnCI,YAAYF,SAASE,UAAU;oBAC/BC,SAASH,SAASP,OAAO,CAAC,aAAa;gBACzC;gBAEA,IAAIO,SAASE,UAAU,KAAK,OAAOE,gBAAgBJ,SAASC,OAAO,CAACT,OAAO,GAAG;oBAC5EN,aAAamB;gBACf;gBACA,OAAOL;YACT;SACD;IACH;AACF,GAAG;AAEH,OAAO,MAAMM,iBAAiB,CAACC;IAC7B,OAAOA,iBAAiBzB,aAAayB,MAAMP,QAAQ,CAACE,UAAU,KAAK,OAAOE,gBAAgBG,MAAMN,OAAO,CAACT,OAAO;AACjH,EAAE;AAEF,OAAO,MAAMgB,sBAAsB,CAACD;IAClC,IAAID,eAAeC,QAAQ;QACzBpB,IAAIsB,IAAI,CAAC,iCAAiC;YAAEF;QAAM;QAClD;IACF;IACA,MAAMA;AACR,EAAE;AAEF,OAAO,MAAMG,aAAa;IACxB,MAAMC,QAAQ1B;IACd,OAAO0B,SAAS,CAAC,QAAQ,EAAEC,mBAAmBD,OAAO,CAAC,CAAC;AACzD,EAAE;AAEF,MAAMP,kBAAkB,CAACZ;IACvB,OAAOA,QAAQK,GAAG,YAAYgB,OAAOrB,QAAQK,GAAG,CAACiB,IAAI,KAAK/B,OAAOgC,OAAO,CAACC,QAAQ;AACnF"}
@@ -0,0 +1,45 @@
1
+ /* eslint-disable @typescript-eslint/no-confusing-void-expression */ import { addBreadcrumb as addSentryBreadcrumb } from "@sentry/node";
2
+ import Debug from "debug";
3
+ import _ from "lodash";
4
+ import { serializeError } from "./errors.js";
5
+ let longestName = 0;
6
+ let longestMessage = 0;
7
+ export const createLogger = (name, fields = {})=>{
8
+ longestName = Math.max(longestName, name.length);
9
+ const baseFields = _.isFunction(fields) ? fields : ()=>fields;
10
+ const createLog = (level)=>{
11
+ const debug = Debug(`ggt:${name}`);
12
+ return (msg, fields)=>{
13
+ longestMessage = Math.max(longestMessage, msg.length);
14
+ fields = {
15
+ ...baseFields(),
16
+ ...fields
17
+ };
18
+ if ("error" in fields) {
19
+ fields.error = serializeError(fields.error);
20
+ }
21
+ if (_.isEmpty(fields)) {
22
+ debug("%s%s", _.repeat(" ", longestName - name.length), _.padEnd(msg, longestMessage));
23
+ } else {
24
+ debug("%s%s %o", _.repeat(" ", longestName - name.length), _.padEnd(msg, longestMessage), fields);
25
+ }
26
+ if (level === "debug") {
27
+ // don't send debug logs to Sentry
28
+ return;
29
+ }
30
+ addSentryBreadcrumb({
31
+ level: level === "warn" ? "warning" : level,
32
+ message: msg,
33
+ data: fields
34
+ });
35
+ };
36
+ };
37
+ return {
38
+ debug: createLog("debug"),
39
+ info: createLog("info"),
40
+ warn: createLog("warn"),
41
+ error: createLog("error")
42
+ };
43
+ };
44
+
45
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/log.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-confusing-void-expression */\nimport { addBreadcrumb as addSentryBreadcrumb } from \"@sentry/node\";\nimport Debug from \"debug\";\nimport _ from \"lodash\";\nimport type { Jsonifiable } from \"type-fest\";\nimport { serializeError } from \"./errors.js\";\n\ntype JsonifiableObject = { [Key in string]?: Jsonifiable } | { toJSON: () => Jsonifiable } | { error?: unknown };\n\nlet longestName = 0;\nlet longestMessage = 0;\n\nexport const createLogger = (name: string, fields: JsonifiableObject | (() => JsonifiableObject) = {}) => {\n longestName = Math.max(longestName, name.length);\n const baseFields = _.isFunction(fields) ? fields : () => fields;\n\n const createLog = (level: \"debug\" | \"info\" | \"warn\" | \"error\") => {\n const debug = Debug(`ggt:${name}`);\n\n return (msg: Lowercase<string>, fields?: JsonifiableObject) => {\n longestMessage = Math.max(longestMessage, msg.length);\n fields = { ...baseFields(), ...fields };\n if (\"error\" in fields) {\n fields.error = serializeError(fields.error);\n }\n\n if (_.isEmpty(fields)) {\n debug(\"%s%s\", _.repeat(\" \", longestName - name.length), _.padEnd(msg, longestMessage));\n } else {\n debug(\"%s%s %o\", _.repeat(\" \", longestName - name.length), _.padEnd(msg, longestMessage), fields);\n }\n\n if (level === \"debug\") {\n // don't send debug logs to Sentry\n return;\n }\n\n addSentryBreadcrumb({\n level: level === \"warn\" ? \"warning\" : level,\n message: msg,\n data: fields,\n });\n };\n };\n\n return {\n debug: createLog(\"debug\"),\n info: createLog(\"info\"),\n warn: createLog(\"warn\"),\n error: createLog(\"error\"),\n };\n};\n"],"names":["addBreadcrumb","addSentryBreadcrumb","Debug","_","serializeError","longestName","longestMessage","createLogger","name","fields","Math","max","length","baseFields","isFunction","createLog","level","debug","msg","error","isEmpty","repeat","padEnd","message","data","info","warn"],"mappings":"AAAA,kEAAkE,GAClE,SAASA,iBAAiBC,mBAAmB,QAAQ,eAAe;AACpE,OAAOC,WAAW,QAAQ;AAC1B,OAAOC,OAAO,SAAS;AAEvB,SAASC,cAAc,QAAQ,cAAc;AAI7C,IAAIC,cAAc;AAClB,IAAIC,iBAAiB;AAErB,OAAO,MAAMC,eAAe,CAACC,MAAcC,SAAwD,CAAC,CAAC;IACnGJ,cAAcK,KAAKC,GAAG,CAACN,aAAaG,KAAKI,MAAM;IAC/C,MAAMC,aAAaV,EAAEW,UAAU,CAACL,UAAUA,SAAS,IAAMA;IAEzD,MAAMM,YAAY,CAACC;QACjB,MAAMC,QAAQf,MAAM,CAAC,IAAI,EAAEM,KAAK,CAAC;QAEjC,OAAO,CAACU,KAAwBT;YAC9BH,iBAAiBI,KAAKC,GAAG,CAACL,gBAAgBY,IAAIN,MAAM;YACpDH,SAAS;gBAAE,GAAGI,YAAY;gBAAE,GAAGJ,MAAM;YAAC;YACtC,IAAI,WAAWA,QAAQ;gBACrBA,OAAOU,KAAK,GAAGf,eAAeK,OAAOU,KAAK;YAC5C;YAEA,IAAIhB,EAAEiB,OAAO,CAACX,SAAS;gBACrBQ,MAAM,QAAQd,EAAEkB,MAAM,CAAC,KAAKhB,cAAcG,KAAKI,MAAM,GAAGT,EAAEmB,MAAM,CAACJ,KAAKZ;YACxE,OAAO;gBACLW,MAAM,WAAWd,EAAEkB,MAAM,CAAC,KAAKhB,cAAcG,KAAKI,MAAM,GAAGT,EAAEmB,MAAM,CAACJ,KAAKZ,iBAAiBG;YAC5F;YAEA,IAAIO,UAAU,SAAS;gBACrB,kCAAkC;gBAClC;YACF;YAEAf,oBAAoB;gBAClBe,OAAOA,UAAU,SAAS,YAAYA;gBACtCO,SAASL;gBACTM,MAAMf;YACR;QACF;IACF;IAEA,OAAO;QACLQ,OAAOF,UAAU;QACjBU,MAAMV,UAAU;QAChBW,MAAMX,UAAU;QAChBI,OAAOJ,UAAU;IACnB;AACF,EAAE"}
@@ -0,0 +1,30 @@
1
+ import notifier from "node-notifier";
2
+ import path from "node:path";
3
+ import { workspaceRoot } from "./config.js";
4
+ import { createLogger } from "./log.js";
5
+ const log = createLogger("notify");
6
+ /**
7
+ * Sends a native OS notification to the user.
8
+ *
9
+ * @see {@link https://www.npmjs.com/package/node-notifier node-notifier}
10
+ */ export const notify = (notification)=>{
11
+ log.info("notifying user", {
12
+ notification: notification
13
+ });
14
+ notifier.notify({
15
+ title: "Gadget",
16
+ contentImage: path.join(workspaceRoot, "assets/favicon-128@4x.png"),
17
+ icon: path.join(workspaceRoot, "assets/favicon-128@4x.png"),
18
+ sound: true,
19
+ timeout: false,
20
+ ...notification
21
+ }, (error)=>{
22
+ if (error) {
23
+ log.warn("error notifying user", {
24
+ notification: notification
25
+ });
26
+ }
27
+ });
28
+ };
29
+
30
+ //# sourceMappingURL=notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/notify.ts"],"sourcesContent":["import notifier, { type Notification } from \"node-notifier\";\nimport type WindowsBalloon from \"node-notifier/notifiers/balloon.js\";\nimport type Growl from \"node-notifier/notifiers/growl.js\";\nimport type NotificationCenter from \"node-notifier/notifiers/notificationcenter.js\";\nimport type NotifySend from \"node-notifier/notifiers/notifysend.js\";\nimport type WindowsToaster from \"node-notifier/notifiers/toaster.js\";\nimport path from \"node:path\";\nimport type { Jsonifiable } from \"type-fest\";\nimport { workspaceRoot } from \"./config.js\";\nimport { createLogger } from \"./log.js\";\n\nconst log = createLogger(\"notify\");\n\n/**\n * Sends a native OS notification to the user.\n *\n * @see {@link https://www.npmjs.com/package/node-notifier node-notifier}\n */\nexport const notify = (\n notification:\n | Notification\n | NotificationCenter.Notification\n | NotifySend.Notification\n | WindowsToaster.Notification\n | WindowsBalloon.Notification\n | Growl.Notification,\n) => {\n log.info(\"notifying user\", { notification: notification as Jsonifiable });\n\n notifier.notify(\n {\n title: \"Gadget\",\n contentImage: path.join(workspaceRoot, \"assets/favicon-128@4x.png\"),\n icon: path.join(workspaceRoot, \"assets/favicon-128@4x.png\"),\n sound: true,\n timeout: false,\n ...notification,\n },\n (error) => {\n if (error) {\n log.warn(\"error notifying user\", { notification: notification as Jsonifiable });\n }\n },\n );\n};\n"],"names":["notifier","path","workspaceRoot","createLogger","log","notify","notification","info","title","contentImage","join","icon","sound","timeout","error","warn"],"mappings":"AAAA,OAAOA,cAAqC,gBAAgB;AAM5D,OAAOC,UAAU,YAAY;AAE7B,SAASC,aAAa,QAAQ,cAAc;AAC5C,SAASC,YAAY,QAAQ,WAAW;AAExC,MAAMC,MAAMD,aAAa;AAEzB;;;;CAIC,GACD,OAAO,MAAME,SAAS,CACpBC;IAQAF,IAAIG,IAAI,CAAC,kBAAkB;QAAED,cAAcA;IAA4B;IAEvEN,SAASK,MAAM,CACb;QACEG,OAAO;QACPC,cAAcR,KAAKS,IAAI,CAACR,eAAe;QACvCS,MAAMV,KAAKS,IAAI,CAACR,eAAe;QAC/BU,OAAO;QACPC,SAAS;QACT,GAAGP,YAAY;IACjB,GACA,CAACQ;QACC,IAAIA,OAAO;YACTV,IAAIW,IAAI,CAAC,wBAAwB;gBAAET,cAAcA;YAA4B;QAC/E;IACF;AAEJ,EAAE"}
@@ -0,0 +1,59 @@
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ import chalkTemplate from "chalk-template";
3
+ import levenshtein from "fast-levenshtein";
4
+ import _ from "lodash";
5
+ import assert from "node:assert";
6
+ import process from "node:process";
7
+ import { dedent } from "ts-dedent";
8
+ /**
9
+ * A wrapper around process.stdout and process.stderr that allows us to mock out the streams for testing.
10
+ *
11
+ * @see https://github.com/oclif/core/blob/16139fe8a7f991b4b446a1599ab63f15d9809b8e/src/cli-ux/stream.ts
12
+ */ export class Stream {
13
+ get isTTY() {
14
+ return process[this.channel].isTTY;
15
+ }
16
+ getWindowSize() {
17
+ return process[this.channel].getWindowSize();
18
+ }
19
+ write(data) {
20
+ return process[this.channel].write(data);
21
+ }
22
+ on(event, listener) {
23
+ process[this.channel].on(event, listener);
24
+ return this;
25
+ }
26
+ once(event, listener) {
27
+ process[this.channel].once(event, listener);
28
+ return this;
29
+ }
30
+ constructor(channel){
31
+ _define_property(this, "channel", void 0);
32
+ this.channel = channel;
33
+ process[this.channel].on("error", (err)=>{
34
+ if (err.code === "EPIPE") {
35
+ return;
36
+ }
37
+ throw err;
38
+ });
39
+ }
40
+ }
41
+ export const stdout = new Stream("stdout");
42
+ export const stderr = new Stream("stderr");
43
+ export const sprint = (template, ...values)=>{
44
+ const content = _.isString(template) ? template : chalkTemplate(template, ...values);
45
+ return dedent(content);
46
+ };
47
+ export const print = (template, ...values)=>{
48
+ stdout.write(sprint(template, ...values));
49
+ };
50
+ export const println = (template, ...values)=>{
51
+ if (template) stdout.write(sprint(template, ...values));
52
+ stdout.write("\n");
53
+ };
54
+ export const sortByLevenshtein = (input, options)=>{
55
+ assert(options.length > 0, "options must not be empty");
56
+ return _.sortBy(options, (opt)=>levenshtein.get(opt, input));
57
+ };
58
+
59
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/output.ts"],"sourcesContent":["import chalkTemplate from \"chalk-template\";\nimport levenshtein from \"fast-levenshtein\";\nimport _ from \"lodash\";\nimport assert from \"node:assert\";\nimport process from \"node:process\";\nimport { dedent } from \"ts-dedent\";\n\n/**\n * A wrapper around process.stdout and process.stderr that allows us to mock out the streams for testing.\n *\n * @see https://github.com/oclif/core/blob/16139fe8a7f991b4b446a1599ab63f15d9809b8e/src/cli-ux/stream.ts\n */\nexport class Stream {\n public constructor(public channel: \"stdout\" | \"stderr\") {\n process[this.channel].on(\"error\", (err) => {\n if (err.code === \"EPIPE\") {\n return;\n }\n throw err;\n });\n }\n\n public get isTTY(): boolean {\n return process[this.channel].isTTY;\n }\n\n public getWindowSize(): number[] {\n return process[this.channel].getWindowSize();\n }\n\n public write(data: string): boolean {\n return process[this.channel].write(data);\n }\n\n public on(event: string, listener: (...args: any[]) => void): this {\n process[this.channel].on(event, listener);\n return this;\n }\n\n public once(event: string, listener: (...args: any[]) => void): this {\n process[this.channel].once(event, listener);\n return this;\n }\n}\n\nexport const stdout = new Stream(\"stdout\");\nexport const stderr = new Stream(\"stderr\");\n\nexport const sprint = (template: TemplateStringsArray | string, ...values: unknown[]) => {\n const content = _.isString(template) ? template : chalkTemplate(template, ...values);\n return dedent(content);\n};\n\nexport const print = (template: TemplateStringsArray | string, ...values: unknown[]) => {\n stdout.write(sprint(template, ...values));\n};\n\nexport const println = (template?: TemplateStringsArray | string, ...values: unknown[]) => {\n if (template) stdout.write(sprint(template, ...values));\n stdout.write(\"\\n\");\n};\n\nexport const sortByLevenshtein = (input: string, options: readonly string[]): [closest: string, ...sorted: string[]] => {\n assert(options.length > 0, \"options must not be empty\");\n return _.sortBy(options, (opt) => levenshtein.get(opt, input)) as [string, ...string[]];\n};\n"],"names":["chalkTemplate","levenshtein","_","assert","process","dedent","Stream","isTTY","channel","getWindowSize","write","data","on","event","listener","once","err","code","stdout","stderr","sprint","template","values","content","isString","print","println","sortByLevenshtein","input","options","length","sortBy","opt","get"],"mappings":";AAAA,OAAOA,mBAAmB,iBAAiB;AAC3C,OAAOC,iBAAiB,mBAAmB;AAC3C,OAAOC,OAAO,SAAS;AACvB,OAAOC,YAAY,cAAc;AACjC,OAAOC,aAAa,eAAe;AACnC,SAASC,MAAM,QAAQ,YAAY;AAEnC;;;;CAIC,GACD,OAAO,MAAMC;IAUX,IAAWC,QAAiB;QAC1B,OAAOH,OAAO,CAAC,IAAI,CAACI,OAAO,CAAC,CAACD,KAAK;IACpC;IAEOE,gBAA0B;QAC/B,OAAOL,OAAO,CAAC,IAAI,CAACI,OAAO,CAAC,CAACC,aAAa;IAC5C;IAEOC,MAAMC,IAAY,EAAW;QAClC,OAAOP,OAAO,CAAC,IAAI,CAACI,OAAO,CAAC,CAACE,KAAK,CAACC;IACrC;IAEOC,GAAGC,KAAa,EAAEC,QAAkC,EAAQ;QACjEV,OAAO,CAAC,IAAI,CAACI,OAAO,CAAC,CAACI,EAAE,CAACC,OAAOC;QAChC,OAAO,IAAI;IACb;IAEOC,KAAKF,KAAa,EAAEC,QAAkC,EAAQ;QACnEV,OAAO,CAAC,IAAI,CAACI,OAAO,CAAC,CAACO,IAAI,CAACF,OAAOC;QAClC,OAAO,IAAI;IACb;IA7BA,YAAmB,AAAON,OAA4B,CAAE;;aAA9BA,UAAAA;QACxBJ,OAAO,CAAC,IAAI,CAACI,OAAO,CAAC,CAACI,EAAE,CAAC,SAAS,CAACI;YACjC,IAAIA,IAAIC,IAAI,KAAK,SAAS;gBACxB;YACF;YACA,MAAMD;QACR;IACF;AAuBF;AAEA,OAAO,MAAME,SAAS,IAAIZ,OAAO,UAAU;AAC3C,OAAO,MAAMa,SAAS,IAAIb,OAAO,UAAU;AAE3C,OAAO,MAAMc,SAAS,CAACC,UAAyC,GAAGC;IACjE,MAAMC,UAAUrB,EAAEsB,QAAQ,CAACH,YAAYA,WAAWrB,cAAcqB,aAAaC;IAC7E,OAAOjB,OAAOkB;AAChB,EAAE;AAEF,OAAO,MAAME,QAAQ,CAACJ,UAAyC,GAAGC;IAChEJ,OAAOR,KAAK,CAACU,OAAOC,aAAaC;AACnC,EAAE;AAEF,OAAO,MAAMI,UAAU,CAACL,UAA0C,GAAGC;IACnE,IAAID,UAAUH,OAAOR,KAAK,CAACU,OAAOC,aAAaC;IAC/CJ,OAAOR,KAAK,CAAC;AACf,EAAE;AAEF,OAAO,MAAMiB,oBAAoB,CAACC,OAAeC;IAC/C1B,OAAO0B,QAAQC,MAAM,GAAG,GAAG;IAC3B,OAAO5B,EAAE6B,MAAM,CAACF,SAAS,CAACG,MAAQ/B,YAAYgC,GAAG,CAACD,KAAKJ;AACzD,EAAE"}
@@ -1,7 +1,9 @@
1
1
  /**
2
- * Long lived references to Promises stress the garbage collector in JS. Instead of caching resolved Promises, we cache
3
- * these little data objects instead which reference the resolution or rejection of the Promise, allowing the Promise
4
- * object to be free'd.
2
+ * Long lived references to Promises stress the garbage collector in JS.
3
+ *
4
+ * Instead of caching resolved Promises, we cache these little data
5
+ * objects instead which reference the resolution or rejection of the
6
+ * Promise, allowing the Promise object to be free'd.
5
7
  */ import { _ as _define_property } from "@swc/helpers/_/_define_property";
6
8
  export class PromiseWrapper {
7
9
  async unwrap() {
@@ -33,8 +35,9 @@ let _Symbol_toStringTag = Symbol.toStringTag;
33
35
  /**
34
36
  * A promise that can be resolved or rejected from outside its callback.
35
37
  *
36
- * This is typically used when you want to await a promise that is resolved or rejected from outside the current scope,
37
- * such as from an event handler.
38
+ * This is typically used when you want to await a promise that is
39
+ * resolved or rejected from outside the current scope, such as from an
40
+ * event handler.
38
41
  *
39
42
  * @example
40
43
  * const signal = new PromiseSignal();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/promise.ts"],"sourcesContent":["/**\n * Long lived references to Promises stress the garbage collector in JS. Instead of caching resolved Promises, we cache\n * these little data objects instead which reference the resolution or rejection of the Promise, allowing the Promise\n * object to be free'd.\n */\nexport class PromiseWrapper<T> {\n resolution?: T;\n rejection?: any;\n pendingPromise?: Promise<T>;\n\n constructor(promise: Promise<T>) {\n this.pendingPromise = promise;\n\n promise\n .then((res) => {\n this.resolution = res;\n return res;\n })\n .catch((err) => {\n this.rejection = err;\n })\n .finally(() => {\n delete this.pendingPromise;\n });\n }\n\n async unwrap(): Promise<T> {\n if (this.resolution) {\n return this.resolution;\n } else if (this.rejection) {\n throw this.rejection;\n } else {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return await this.pendingPromise!;\n }\n }\n}\n\n/**\n * A promise that can be resolved or rejected from outside its callback.\n *\n * This is typically used when you want to await a promise that is resolved or rejected from outside the current scope,\n * such as from an event handler.\n *\n * @example\n * const signal = new PromiseSignal();\n * process.on(\"SIGINT\", () => {\n * signal.resolve();\n * });\n * await signal;\n */\nexport class PromiseSignal<T = void> implements Promise<T> {\n readonly [Symbol.toStringTag]!: string;\n\n resolve!: (value: T | PromiseLike<T>) => void;\n reject!: (reason?: any) => void;\n\n private _promise: PromiseWrapper<T>;\n\n constructor() {\n this._promise = new PromiseWrapper<T>(\n new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n }),\n );\n\n this[Symbol.toStringTag] = String(this._promise.pendingPromise);\n }\n\n then<R = T, E = never>(onfulfilled?: (value: T) => R | PromiseLike<R>, onrejected?: (reason: any) => E | PromiseLike<E>): Promise<R | E> {\n return this._promise.unwrap().then(onfulfilled, onrejected);\n }\n\n catch<E = never>(onrejected?: (reason: any) => E | PromiseLike<E>): Promise<T | E> {\n return this._promise.unwrap().catch(onrejected);\n }\n\n finally(onfinally?: () => void): Promise<T> {\n return this._promise.unwrap().finally(onfinally);\n }\n}\n"],"names":["PromiseWrapper","unwrap","resolution","rejection","pendingPromise","constructor","promise","then","res","catch","err","finally","Symbol","toStringTag","PromiseSignal","onfulfilled","onrejected","_promise","onfinally","resolve","reject","Promise","String"],"mappings":"AAAA;;;;CAIC;AACD,OAAO,MAAMA;IAqBX,MAAMC,SAAqB;QACzB,IAAI,IAAI,CAACC,UAAU,EAAE;YACnB,OAAO,IAAI,CAACA,UAAU;QACxB,OAAO,IAAI,IAAI,CAACC,SAAS,EAAE;YACzB,MAAM,IAAI,CAACA,SAAS;QACtB,OAAO;YACL,oEAAoE;YACpE,OAAO,MAAM,IAAI,CAACC,cAAc;QAClC;IACF;IAzBAC,YAAYC,OAAmB,CAAE;QAJjCJ,uBAAAA,cAAAA,KAAAA;QACAC,uBAAAA,aAAAA,KAAAA;QACAC,uBAAAA,kBAAAA,KAAAA;QAGE,IAAI,CAACA,cAAc,GAAGE;QAEtBA,QACGC,IAAI,CAAC,CAACC;YACL,IAAI,CAACN,UAAU,GAAGM;YAClB,OAAOA;QACT,GACCC,KAAK,CAAC,CAACC;YACN,IAAI,CAACP,SAAS,GAAGO;QACnB,GACCC,OAAO,CAAC;YACP,OAAO,IAAI,CAACP,cAAc;QAC5B;IACJ;AAYF;IAgBYQ,sBAAAA,OAAOC,WAAW;AAd9B;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC;IAmBXP,KAAuBQ,WAA8C,EAAEC,UAAgD,EAAkB;QACvI,OAAO,IAAI,CAACC,QAAQ,CAAChB,MAAM,GAAGM,IAAI,CAACQ,aAAaC;IAClD;IAEAP,MAAiBO,UAAgD,EAAkB;QACjF,OAAO,IAAI,CAACC,QAAQ,CAAChB,MAAM,GAAGQ,KAAK,CAACO;IACtC;IAEAL,QAAQO,SAAsB,EAAc;QAC1C,OAAO,IAAI,CAACD,QAAQ,CAAChB,MAAM,GAAGU,OAAO,CAACO;IACxC;IArBAb,aAAc;QAPd,uBAAUO,qBAAV,KAAA;QAEAO,uBAAAA,WAAAA,KAAAA;QACAC,uBAAAA,UAAAA,KAAAA;QAEA,uBAAQH,YAAR,KAAA;QAGE,IAAI,CAACA,QAAQ,GAAG,IAAIjB,eAClB,IAAIqB,QAAQ,CAACF,SAASC;YACpB,IAAI,CAACD,OAAO,GAAGA;YACf,IAAI,CAACC,MAAM,GAAGA;QAChB;QAGF,IAAI,CAACR,OAAOC,WAAW,CAAC,GAAGS,OAAO,IAAI,CAACL,QAAQ,CAACb,cAAc;IAChE;AAaF"}
1
+ {"version":3,"sources":["../../src/services/promise.ts"],"sourcesContent":["/**\n * Long lived references to Promises stress the garbage collector in JS.\n *\n * Instead of caching resolved Promises, we cache these little data\n * objects instead which reference the resolution or rejection of the\n * Promise, allowing the Promise object to be free'd.\n */\nexport class PromiseWrapper<T> {\n resolution?: T;\n rejection?: any;\n pendingPromise?: Promise<T>;\n\n constructor(promise: Promise<T>) {\n this.pendingPromise = promise;\n\n promise\n .then((res) => {\n this.resolution = res;\n return res;\n })\n .catch((err) => {\n this.rejection = err;\n })\n .finally(() => {\n delete this.pendingPromise;\n });\n }\n\n async unwrap(): Promise<T> {\n if (this.resolution) {\n return this.resolution;\n } else if (this.rejection) {\n throw this.rejection;\n } else {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return await this.pendingPromise!;\n }\n }\n}\n\n/**\n * A promise that can be resolved or rejected from outside its callback.\n *\n * This is typically used when you want to await a promise that is\n * resolved or rejected from outside the current scope, such as from an\n * event handler.\n *\n * @example\n * const signal = new PromiseSignal();\n * process.on(\"SIGINT\", () => {\n * signal.resolve();\n * });\n * await signal;\n */\nexport class PromiseSignal<T = void> implements Promise<T> {\n readonly [Symbol.toStringTag]!: string;\n\n resolve!: (value: T | PromiseLike<T>) => void;\n reject!: (reason?: any) => void;\n\n private _promise: PromiseWrapper<T>;\n\n constructor() {\n this._promise = new PromiseWrapper<T>(\n new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n }),\n );\n\n this[Symbol.toStringTag] = String(this._promise.pendingPromise);\n }\n\n then<R = T, E = never>(onfulfilled?: (value: T) => R | PromiseLike<R>, onrejected?: (reason: any) => E | PromiseLike<E>): Promise<R | E> {\n return this._promise.unwrap().then(onfulfilled, onrejected);\n }\n\n catch<E = never>(onrejected?: (reason: any) => E | PromiseLike<E>): Promise<T | E> {\n return this._promise.unwrap().catch(onrejected);\n }\n\n finally(onfinally?: () => void): Promise<T> {\n return this._promise.unwrap().finally(onfinally);\n }\n}\n"],"names":["PromiseWrapper","unwrap","resolution","rejection","pendingPromise","constructor","promise","then","res","catch","err","finally","Symbol","toStringTag","PromiseSignal","onfulfilled","onrejected","_promise","onfinally","resolve","reject","Promise","String"],"mappings":"AAAA;;;;;;CAMC;AACD,OAAO,MAAMA;IAqBX,MAAMC,SAAqB;QACzB,IAAI,IAAI,CAACC,UAAU,EAAE;YACnB,OAAO,IAAI,CAACA,UAAU;QACxB,OAAO,IAAI,IAAI,CAACC,SAAS,EAAE;YACzB,MAAM,IAAI,CAACA,SAAS;QACtB,OAAO;YACL,oEAAoE;YACpE,OAAO,MAAM,IAAI,CAACC,cAAc;QAClC;IACF;IAzBAC,YAAYC,OAAmB,CAAE;QAJjCJ,uBAAAA,cAAAA,KAAAA;QACAC,uBAAAA,aAAAA,KAAAA;QACAC,uBAAAA,kBAAAA,KAAAA;QAGE,IAAI,CAACA,cAAc,GAAGE;QAEtBA,QACGC,IAAI,CAAC,CAACC;YACL,IAAI,CAACN,UAAU,GAAGM;YAClB,OAAOA;QACT,GACCC,KAAK,CAAC,CAACC;YACN,IAAI,CAACP,SAAS,GAAGO;QACnB,GACCC,OAAO,CAAC;YACP,OAAO,IAAI,CAACP,cAAc;QAC5B;IACJ;AAYF;IAiBYQ,sBAAAA,OAAOC,WAAW;AAf9B;;;;;;;;;;;;;CAaC,GACD,OAAO,MAAMC;IAmBXP,KAAuBQ,WAA8C,EAAEC,UAAgD,EAAkB;QACvI,OAAO,IAAI,CAACC,QAAQ,CAAChB,MAAM,GAAGM,IAAI,CAACQ,aAAaC;IAClD;IAEAP,MAAiBO,UAAgD,EAAkB;QACjF,OAAO,IAAI,CAACC,QAAQ,CAAChB,MAAM,GAAGQ,KAAK,CAACO;IACtC;IAEAL,QAAQO,SAAsB,EAAc;QAC1C,OAAO,IAAI,CAACD,QAAQ,CAAChB,MAAM,GAAGU,OAAO,CAACO;IACxC;IArBAb,aAAc;QAPd,uBAAUO,qBAAV,KAAA;QAEAO,uBAAAA,WAAAA,KAAAA;QACAC,uBAAAA,UAAAA,KAAAA;QAEA,uBAAQH,YAAR,KAAA;QAGE,IAAI,CAACA,QAAQ,GAAG,IAAIjB,eAClB,IAAIqB,QAAQ,CAACF,SAASC;YACpB,IAAI,CAACD,OAAO,GAAGA;YACf,IAAI,CAACC,MAAM,GAAGA;QAChB;QAGF,IAAI,CAACR,OAAOC,WAAW,CAAC,GAAGS,OAAO,IAAI,CAACL,QAAQ,CAACb,cAAc;IAChE;AAaF"}
@@ -0,0 +1,27 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { config } from "./config.js";
4
+ import { swallowEnoent } from "./fs-utils.js";
5
+ import { createLogger } from "./log.js";
6
+ const log = createLogger("session");
7
+ export const readSession = ()=>{
8
+ log.debug("reading session from disk");
9
+ try {
10
+ return fs.readFileSync(path.join(config.configDir, "session.txt"), "utf-8");
11
+ } catch (error) {
12
+ swallowEnoent(error);
13
+ return undefined;
14
+ }
15
+ };
16
+ export const writeSession = (session)=>{
17
+ log.debug("writing session to disk", {
18
+ session: Boolean(session)
19
+ });
20
+ if (session) {
21
+ fs.outputFileSync(path.join(config.configDir, "session.txt"), session);
22
+ } else {
23
+ fs.removeSync(path.join(config.configDir, "session.txt"));
24
+ }
25
+ };
26
+
27
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/session.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { config } from \"./config.js\";\nimport { swallowEnoent } from \"./fs-utils.js\";\nimport { createLogger } from \"./log.js\";\n\nconst log = createLogger(\"session\");\n\nexport const readSession = (): string | undefined => {\n log.debug(\"reading session from disk\");\n\n try {\n return fs.readFileSync(path.join(config.configDir, \"session.txt\"), \"utf-8\");\n } catch (error) {\n swallowEnoent(error);\n return undefined;\n }\n};\n\nexport const writeSession = (session: string | undefined) => {\n log.debug(\"writing session to disk\", { session: Boolean(session) });\n\n if (session) {\n fs.outputFileSync(path.join(config.configDir, \"session.txt\"), session);\n } else {\n fs.removeSync(path.join(config.configDir, \"session.txt\"));\n }\n};\n"],"names":["fs","path","config","swallowEnoent","createLogger","log","readSession","debug","readFileSync","join","configDir","error","undefined","writeSession","session","Boolean","outputFileSync","removeSync"],"mappings":"AAAA,OAAOA,QAAQ,WAAW;AAC1B,OAAOC,UAAU,YAAY;AAC7B,SAASC,MAAM,QAAQ,cAAc;AACrC,SAASC,aAAa,QAAQ,gBAAgB;AAC9C,SAASC,YAAY,QAAQ,WAAW;AAExC,MAAMC,MAAMD,aAAa;AAEzB,OAAO,MAAME,cAAc;IACzBD,IAAIE,KAAK,CAAC;IAEV,IAAI;QACF,OAAOP,GAAGQ,YAAY,CAACP,KAAKQ,IAAI,CAACP,OAAOQ,SAAS,EAAE,gBAAgB;IACrE,EAAE,OAAOC,OAAO;QACdR,cAAcQ;QACd,OAAOC;IACT;AACF,EAAE;AAEF,OAAO,MAAMC,eAAe,CAACC;IAC3BT,IAAIE,KAAK,CAAC,2BAA2B;QAAEO,SAASC,QAAQD;IAAS;IAEjE,IAAIA,SAAS;QACXd,GAAGgB,cAAc,CAACf,KAAKQ,IAAI,CAACP,OAAOQ,SAAS,EAAE,gBAAgBI;IAChE,OAAO;QACLd,GAAGiB,UAAU,CAAChB,KAAKQ,IAAI,CAACP,OAAOQ,SAAS,EAAE;IAC5C;AACF,EAAE"}
@@ -1,11 +1,8 @@
1
+ import { timeoutMs } from "./timeout.js";
1
2
  export function sleep(ms = 0) {
2
3
  return new Promise((resolve)=>ms == 0 ? setImmediate(resolve) : setTimeout(resolve, ms));
3
4
  }
4
- export async function sleepUntil(fn, { interval = 0, timeout = 5_000 } = {}) {
5
- if (process.env["CI"]) {
6
- // double the timeout in CI to account for slower machines
7
- timeout *= 2;
8
- }
5
+ export async function sleepUntil(fn, { interval = 0, timeout = timeoutMs("5s") } = {}) {
9
6
  const start = isFinite(timeout) && Date.now();
10
7
  // eslint-disable-next-line no-constant-condition, @typescript-eslint/no-unnecessary-condition
11
8
  while(true){
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/sleep.ts"],"sourcesContent":["export function sleep(ms = 0): Promise<void> {\n return new Promise((resolve) => (ms == 0 ? setImmediate(resolve) : setTimeout(resolve, ms)));\n}\n\nexport async function sleepUntil(fn: () => boolean, { interval = 0, timeout = 5_000 } = {}): Promise<void> {\n if (process.env[\"CI\"]) {\n // double the timeout in CI to account for slower machines\n timeout *= 2;\n }\n\n const start = isFinite(timeout) && Date.now();\n\n // eslint-disable-next-line no-constant-condition, @typescript-eslint/no-unnecessary-condition\n while (true) {\n if (fn()) return;\n await sleep(interval);\n\n if (start && Date.now() - start > timeout) {\n const error = new Error(`Timed out after ${timeout} milliseconds`);\n Error.captureStackTrace(error, sleepUntil);\n throw error;\n }\n }\n}\n"],"names":["sleep","ms","Promise","resolve","setImmediate","setTimeout","sleepUntil","fn","interval","timeout","process","env","start","isFinite","Date","now","error","Error","captureStackTrace"],"mappings":"AAAA,OAAO,SAASA,MAAMC,KAAK,CAAC;IAC1B,OAAO,IAAIC,QAAQ,CAACC,UAAaF,MAAM,IAAIG,aAAaD,WAAWE,WAAWF,SAASF;AACzF;AAEA,OAAO,eAAeK,WAAWC,EAAiB,EAAE,EAAEC,WAAW,CAAC,EAAEC,UAAU,KAAK,EAAE,GAAG,CAAC,CAAC;IACxF,IAAIC,QAAQC,GAAG,CAAC,KAAK,EAAE;QACrB,0DAA0D;QAC1DF,WAAW;IACb;IAEA,MAAMG,QAAQC,SAASJ,YAAYK,KAAKC,GAAG;IAE3C,8FAA8F;IAC9F,MAAO,KAAM;QACX,IAAIR,MAAM;QACV,MAAMP,MAAMQ;QAEZ,IAAII,SAASE,KAAKC,GAAG,KAAKH,QAAQH,SAAS;YACzC,MAAMO,QAAQ,IAAIC,MAAM,CAAC,gBAAgB,EAAER,QAAQ,aAAa,CAAC;YACjEQ,MAAMC,iBAAiB,CAACF,OAAOV;YAC/B,MAAMU;QACR;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/services/sleep.ts"],"sourcesContent":["import { timeoutMs } from \"./timeout.js\";\n\nexport function sleep(ms = 0): Promise<void> {\n return new Promise((resolve) => (ms == 0 ? setImmediate(resolve) : setTimeout(resolve, ms)));\n}\n\nexport async function sleepUntil(fn: () => boolean, { interval = 0, timeout = timeoutMs(\"5s\") } = {}): Promise<void> {\n const start = isFinite(timeout) && Date.now();\n\n // eslint-disable-next-line no-constant-condition, @typescript-eslint/no-unnecessary-condition\n while (true) {\n if (fn()) return;\n await sleep(interval);\n\n if (start && Date.now() - start > timeout) {\n const error = new Error(`Timed out after ${timeout} milliseconds`);\n Error.captureStackTrace(error, sleepUntil);\n throw error;\n }\n }\n}\n"],"names":["timeoutMs","sleep","ms","Promise","resolve","setImmediate","setTimeout","sleepUntil","fn","interval","timeout","start","isFinite","Date","now","error","Error","captureStackTrace"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAe;AAEzC,OAAO,SAASC,MAAMC,KAAK,CAAC;IAC1B,OAAO,IAAIC,QAAQ,CAACC,UAAaF,MAAM,IAAIG,aAAaD,WAAWE,WAAWF,SAASF;AACzF;AAEA,OAAO,eAAeK,WAAWC,EAAiB,EAAE,EAAEC,WAAW,CAAC,EAAEC,UAAUV,UAAU,KAAK,EAAE,GAAG,CAAC,CAAC;IAClG,MAAMW,QAAQC,SAASF,YAAYG,KAAKC,GAAG;IAE3C,8FAA8F;IAC9F,MAAO,KAAM;QACX,IAAIN,MAAM;QACV,MAAMP,MAAMQ;QAEZ,IAAIE,SAASE,KAAKC,GAAG,KAAKH,QAAQD,SAAS;YACzC,MAAMK,QAAQ,IAAIC,MAAM,CAAC,gBAAgB,EAAEN,QAAQ,aAAa,CAAC;YACjEM,MAAMC,iBAAiB,CAACF,OAAOR;YAC/B,MAAMQ;QACR;IACF;AACF"}
@@ -0,0 +1,8 @@
1
+ import ms from "ms";
2
+ import process from "node:process";
3
+ export const timeoutMs = (duration)=>{
4
+ const milliseconds = ms(duration);
5
+ return process.env["CI"] ? milliseconds * 2 : milliseconds;
6
+ };
7
+
8
+ //# sourceMappingURL=timeout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/timeout.ts"],"sourcesContent":["import ms from \"ms\";\nimport process from \"node:process\";\n\nexport const timeoutMs = (duration: string) => {\n const milliseconds = ms(duration);\n return process.env[\"CI\"] ? milliseconds * 2 : milliseconds;\n};\n"],"names":["ms","process","timeoutMs","duration","milliseconds","env"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,OAAOC,aAAa,eAAe;AAEnC,OAAO,MAAMC,YAAY,CAACC;IACxB,MAAMC,eAAeJ,GAAGG;IACxB,OAAOF,QAAQI,GAAG,CAAC,KAAK,GAAGD,eAAe,IAAIA;AAChD,EAAE"}
@@ -0,0 +1,70 @@
1
+ import inquirer from "inquirer";
2
+ import _ from "lodash";
3
+ import assert from "node:assert";
4
+ import z from "zod";
5
+ import { run as login } from "../commands/login.js";
6
+ import { config } from "./config.js";
7
+ import { setUser } from "./errors.js";
8
+ import { http, loadCookie, swallowUnauthorized } from "./http.js";
9
+ import { createLogger } from "./log.js";
10
+ const log = createLogger("user");
11
+ const User = z.object({
12
+ id: z.union([
13
+ z.string(),
14
+ z.number()
15
+ ]).transform(Number),
16
+ name: z.string().nullish(),
17
+ email: z.string()
18
+ });
19
+ /**
20
+ * @returns The current user.
21
+ */ export const getUser = async ()=>{
22
+ const cookie = loadCookie();
23
+ if (!cookie) {
24
+ return undefined;
25
+ }
26
+ try {
27
+ const json = await http({
28
+ url: `https://${config.domains.services}/auth/api/current-user`,
29
+ headers: {
30
+ cookie
31
+ },
32
+ responseType: "json",
33
+ resolveBodyOnly: true
34
+ });
35
+ const user = User.parse(json);
36
+ setUser(user);
37
+ log.info("loaded current user", {
38
+ user: _.pick(user, [
39
+ "id",
40
+ "name",
41
+ "email"
42
+ ])
43
+ });
44
+ return user;
45
+ } catch (error) {
46
+ swallowUnauthorized(error);
47
+ return undefined;
48
+ }
49
+ };
50
+ export const getUserOrLogin = async (message = "You must be logged in to use this command. Would you like to log in?")=>{
51
+ let user = await getUser();
52
+ if (user) {
53
+ return user;
54
+ }
55
+ log.info("prompting user to log in");
56
+ const { yes } = await inquirer.prompt({
57
+ type: "confirm",
58
+ name: "yes",
59
+ message
60
+ });
61
+ if (!yes) {
62
+ process.exit(0);
63
+ }
64
+ await login();
65
+ user = await getUser();
66
+ assert(user, "missing user after successful login");
67
+ return user;
68
+ };
69
+
70
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/user.ts"],"sourcesContent":["import inquirer from \"inquirer\";\nimport _ from \"lodash\";\nimport assert from \"node:assert\";\nimport z from \"zod\";\nimport { run as login } from \"../commands/login.js\";\nimport { config } from \"./config.js\";\nimport { setUser } from \"./errors.js\";\nimport { http, loadCookie, swallowUnauthorized } from \"./http.js\";\nimport { createLogger } from \"./log.js\";\n\nconst log = createLogger(\"user\");\n\nconst User = z.object({\n id: z.union([z.string(), z.number()]).transform(Number),\n name: z.string().nullish(),\n email: z.string(),\n});\n\nexport type User = z.infer<typeof User>;\n\n/**\n * @returns The current user.\n */\nexport const getUser = async (): Promise<User | undefined> => {\n const cookie = loadCookie();\n if (!cookie) {\n return undefined;\n }\n\n try {\n const json = await http({\n url: `https://${config.domains.services}/auth/api/current-user`,\n headers: { cookie },\n responseType: \"json\",\n resolveBodyOnly: true,\n });\n\n const user = User.parse(json);\n setUser(user);\n log.info(\"loaded current user\", { user: _.pick(user, [\"id\", \"name\", \"email\"]) });\n\n return user;\n } catch (error) {\n swallowUnauthorized(error);\n return undefined;\n }\n};\n\nexport const getUserOrLogin = async (message = \"You must be logged in to use this command. Would you like to log in?\"): Promise<User> => {\n let user = await getUser();\n if (user) {\n return user;\n }\n\n log.info(\"prompting user to log in\");\n const { yes } = await inquirer.prompt<{ yes: boolean }>({\n type: \"confirm\",\n name: \"yes\",\n message,\n });\n\n if (!yes) {\n process.exit(0);\n }\n\n await login();\n\n user = await getUser();\n assert(user, \"missing user after successful login\");\n\n return user;\n};\n"],"names":["inquirer","_","assert","z","run","login","config","setUser","http","loadCookie","swallowUnauthorized","createLogger","log","User","object","id","union","string","number","transform","Number","name","nullish","email","getUser","cookie","undefined","json","url","domains","services","headers","responseType","resolveBodyOnly","user","parse","info","pick","error","getUserOrLogin","message","yes","prompt","type","process","exit"],"mappings":"AAAA,OAAOA,cAAc,WAAW;AAChC,OAAOC,OAAO,SAAS;AACvB,OAAOC,YAAY,cAAc;AACjC,OAAOC,OAAO,MAAM;AACpB,SAASC,OAAOC,KAAK,QAAQ,uBAAuB;AACpD,SAASC,MAAM,QAAQ,cAAc;AACrC,SAASC,OAAO,QAAQ,cAAc;AACtC,SAASC,IAAI,EAAEC,UAAU,EAAEC,mBAAmB,QAAQ,YAAY;AAClE,SAASC,YAAY,QAAQ,WAAW;AAExC,MAAMC,MAAMD,aAAa;AAEzB,MAAME,OAAOV,EAAEW,MAAM,CAAC;IACpBC,IAAIZ,EAAEa,KAAK,CAAC;QAACb,EAAEc,MAAM;QAAId,EAAEe,MAAM;KAAG,EAAEC,SAAS,CAACC;IAChDC,MAAMlB,EAAEc,MAAM,GAAGK,OAAO;IACxBC,OAAOpB,EAAEc,MAAM;AACjB;AAIA;;CAEC,GACD,OAAO,MAAMO,UAAU;IACrB,MAAMC,SAAShB;IACf,IAAI,CAACgB,QAAQ;QACX,OAAOC;IACT;IAEA,IAAI;QACF,MAAMC,OAAO,MAAMnB,KAAK;YACtBoB,KAAK,CAAC,QAAQ,EAAEtB,OAAOuB,OAAO,CAACC,QAAQ,CAAC,sBAAsB,CAAC;YAC/DC,SAAS;gBAAEN;YAAO;YAClBO,cAAc;YACdC,iBAAiB;QACnB;QAEA,MAAMC,OAAOrB,KAAKsB,KAAK,CAACR;QACxBpB,QAAQ2B;QACRtB,IAAIwB,IAAI,CAAC,uBAAuB;YAAEF,MAAMjC,EAAEoC,IAAI,CAACH,MAAM;gBAAC;gBAAM;gBAAQ;aAAQ;QAAE;QAE9E,OAAOA;IACT,EAAE,OAAOI,OAAO;QACd5B,oBAAoB4B;QACpB,OAAOZ;IACT;AACF,EAAE;AAEF,OAAO,MAAMa,iBAAiB,OAAOC,UAAU,sEAAsE;IACnH,IAAIN,OAAO,MAAMV;IACjB,IAAIU,MAAM;QACR,OAAOA;IACT;IAEAtB,IAAIwB,IAAI,CAAC;IACT,MAAM,EAAEK,GAAG,EAAE,GAAG,MAAMzC,SAAS0C,MAAM,CAAmB;QACtDC,MAAM;QACNtB,MAAM;QACNmB;IACF;IAEA,IAAI,CAACC,KAAK;QACRG,QAAQC,IAAI,CAAC;IACf;IAEA,MAAMxC;IAEN6B,OAAO,MAAMV;IACbtB,OAAOgC,MAAM;IAEb,OAAOA;AACT,EAAE"}
@@ -0,0 +1,72 @@
1
+ import boxen from "boxen";
2
+ import { isAfter } from "date-fns";
3
+ import fs from "fs-extra";
4
+ import ms from "ms";
5
+ import assert from "node:assert";
6
+ import path from "node:path";
7
+ import semver from "semver";
8
+ import { z } from "zod";
9
+ import { config } from "./config.js";
10
+ import { http } from "./http.js";
11
+ import { createLogger } from "./log.js";
12
+ import { println, sprint } from "./output.js";
13
+ const log = createLogger("version");
14
+ const UPDATE_CHECK_FREQUENCY = ms("12 hours");
15
+ export const getDistTags = async ()=>{
16
+ const json = await http({
17
+ method: "GET",
18
+ url: "https://registry.npmjs.org/ggt",
19
+ responseType: "json",
20
+ resolveBodyOnly: true,
21
+ timeout: {
22
+ request: ms("5s")
23
+ }
24
+ });
25
+ const parsed = z.object({
26
+ name: z.literal("ggt"),
27
+ "dist-tags": z.object({
28
+ latest: z.string()
29
+ })
30
+ }).parse(json);
31
+ return parsed["dist-tags"];
32
+ };
33
+ export const shouldCheckForUpdate = async ()=>{
34
+ try {
35
+ const lastCheck = Number(await fs.readFile(path.join(config.cacheDir, "last-update-check"), "utf-8"));
36
+ assert(!Number.isNaN(lastCheck));
37
+ return isAfter(Date.now(), lastCheck + UPDATE_CHECK_FREQUENCY);
38
+ } catch (error) {
39
+ return true;
40
+ }
41
+ };
42
+ export const warnIfUpdateAvailable = async ()=>{
43
+ try {
44
+ const shouldCheck = await shouldCheckForUpdate();
45
+ if (!shouldCheck) {
46
+ return;
47
+ }
48
+ await fs.outputFile(path.join(config.cacheDir, "last-update-check"), String(Date.now()));
49
+ const tags = await getDistTags();
50
+ if (semver.lt(config.version, tags.latest)) {
51
+ log.info("update available", {
52
+ current: config.version,
53
+ latest: tags.latest
54
+ });
55
+ println(boxen(sprint`
56
+ Update available! {red ${config.version}} -> {green ${tags.latest}}.
57
+ Changelog: https://github.com/gadget-inc/ggt/releases/tag/v${tags.latest}
58
+ Run "npm install -g ${config.name}" to update.
59
+ `, {
60
+ padding: 1,
61
+ borderStyle: "round",
62
+ textAlignment: "center"
63
+ }));
64
+ }
65
+ } catch (error) {
66
+ log.error("failed to check for updates", {
67
+ error
68
+ });
69
+ }
70
+ };
71
+
72
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/version.ts"],"sourcesContent":["import boxen from \"boxen\";\nimport { isAfter } from \"date-fns\";\nimport fs from \"fs-extra\";\nimport ms from \"ms\";\nimport assert from \"node:assert\";\nimport path from \"node:path\";\nimport semver from \"semver\";\nimport { z } from \"zod\";\nimport { config } from \"./config.js\";\nimport { http } from \"./http.js\";\nimport { createLogger } from \"./log.js\";\nimport { println, sprint } from \"./output.js\";\n\nconst log = createLogger(\"version\");\n\nconst UPDATE_CHECK_FREQUENCY = ms(\"12 hours\");\n\nexport const getDistTags = async () => {\n const json = await http({\n method: \"GET\",\n url: \"https://registry.npmjs.org/ggt\",\n responseType: \"json\",\n resolveBodyOnly: true,\n timeout: {\n request: ms(\"5s\"),\n },\n });\n\n const parsed = z\n .object({\n name: z.literal(\"ggt\"),\n \"dist-tags\": z.object({\n latest: z.string(),\n }),\n })\n .parse(json);\n\n return parsed[\"dist-tags\"];\n};\n\nexport const shouldCheckForUpdate = async () => {\n try {\n const lastCheck = Number(await fs.readFile(path.join(config.cacheDir, \"last-update-check\"), \"utf-8\"));\n assert(!Number.isNaN(lastCheck));\n return isAfter(Date.now(), lastCheck + UPDATE_CHECK_FREQUENCY);\n } catch (error) {\n return true;\n }\n};\n\nexport const warnIfUpdateAvailable = async () => {\n try {\n const shouldCheck = await shouldCheckForUpdate();\n if (!shouldCheck) {\n return;\n }\n\n await fs.outputFile(path.join(config.cacheDir, \"last-update-check\"), String(Date.now()));\n\n const tags = await getDistTags();\n\n if (semver.lt(config.version, tags.latest)) {\n log.info(\"update available\", { current: config.version, latest: tags.latest });\n println(\n boxen(\n sprint`\n Update available! {red ${config.version}} -> {green ${tags.latest}}.\n Changelog: https://github.com/gadget-inc/ggt/releases/tag/v${tags.latest}\n Run \"npm install -g ${config.name}\" to update.\n `,\n {\n padding: 1,\n borderStyle: \"round\",\n textAlignment: \"center\",\n },\n ),\n );\n }\n } catch (error) {\n log.error(\"failed to check for updates\", { error });\n }\n};\n"],"names":["boxen","isAfter","fs","ms","assert","path","semver","z","config","http","createLogger","println","sprint","log","UPDATE_CHECK_FREQUENCY","getDistTags","json","method","url","responseType","resolveBodyOnly","timeout","request","parsed","object","name","literal","latest","string","parse","shouldCheckForUpdate","lastCheck","Number","readFile","join","cacheDir","isNaN","Date","now","error","warnIfUpdateAvailable","shouldCheck","outputFile","String","tags","lt","version","info","current","padding","borderStyle","textAlignment"],"mappings":"AAAA,OAAOA,WAAW,QAAQ;AAC1B,SAASC,OAAO,QAAQ,WAAW;AACnC,OAAOC,QAAQ,WAAW;AAC1B,OAAOC,QAAQ,KAAK;AACpB,OAAOC,YAAY,cAAc;AACjC,OAAOC,UAAU,YAAY;AAC7B,OAAOC,YAAY,SAAS;AAC5B,SAASC,CAAC,QAAQ,MAAM;AACxB,SAASC,MAAM,QAAQ,cAAc;AACrC,SAASC,IAAI,QAAQ,YAAY;AACjC,SAASC,YAAY,QAAQ,WAAW;AACxC,SAASC,OAAO,EAAEC,MAAM,QAAQ,cAAc;AAE9C,MAAMC,MAAMH,aAAa;AAEzB,MAAMI,yBAAyBX,GAAG;AAElC,OAAO,MAAMY,cAAc;IACzB,MAAMC,OAAO,MAAMP,KAAK;QACtBQ,QAAQ;QACRC,KAAK;QACLC,cAAc;QACdC,iBAAiB;QACjBC,SAAS;YACPC,SAASnB,GAAG;QACd;IACF;IAEA,MAAMoB,SAAShB,EACZiB,MAAM,CAAC;QACNC,MAAMlB,EAAEmB,OAAO,CAAC;QAChB,aAAanB,EAAEiB,MAAM,CAAC;YACpBG,QAAQpB,EAAEqB,MAAM;QAClB;IACF,GACCC,KAAK,CAACb;IAET,OAAOO,MAAM,CAAC,YAAY;AAC5B,EAAE;AAEF,OAAO,MAAMO,uBAAuB;IAClC,IAAI;QACF,MAAMC,YAAYC,OAAO,MAAM9B,GAAG+B,QAAQ,CAAC5B,KAAK6B,IAAI,CAAC1B,OAAO2B,QAAQ,EAAE,sBAAsB;QAC5F/B,OAAO,CAAC4B,OAAOI,KAAK,CAACL;QACrB,OAAO9B,QAAQoC,KAAKC,GAAG,IAAIP,YAAYjB;IACzC,EAAE,OAAOyB,OAAO;QACd,OAAO;IACT;AACF,EAAE;AAEF,OAAO,MAAMC,wBAAwB;IACnC,IAAI;QACF,MAAMC,cAAc,MAAMX;QAC1B,IAAI,CAACW,aAAa;YAChB;QACF;QAEA,MAAMvC,GAAGwC,UAAU,CAACrC,KAAK6B,IAAI,CAAC1B,OAAO2B,QAAQ,EAAE,sBAAsBQ,OAAON,KAAKC,GAAG;QAEpF,MAAMM,OAAO,MAAM7B;QAEnB,IAAIT,OAAOuC,EAAE,CAACrC,OAAOsC,OAAO,EAAEF,KAAKjB,MAAM,GAAG;YAC1Cd,IAAIkC,IAAI,CAAC,oBAAoB;gBAAEC,SAASxC,OAAOsC,OAAO;gBAAEnB,QAAQiB,KAAKjB,MAAM;YAAC;YAC5EhB,QACEX,MACEY,MAAM,CAAC;mCACkB,EAAEJ,OAAOsC,OAAO,CAAC,YAAY,EAAEF,KAAKjB,MAAM,CAAC;uEACP,EAAEiB,KAAKjB,MAAM,CAAC;gCACrD,EAAEnB,OAAOiB,IAAI,CAAC;UACpC,CAAC,EACD;gBACEwB,SAAS;gBACTC,aAAa;gBACbC,eAAe;YACjB;QAGN;IACF,EAAE,OAAOZ,OAAO;QACd1B,IAAI0B,KAAK,CAAC,+BAA+B;YAAEA;QAAM;IACnD;AACF,EAAE"}