@gadgetinc/ggt 1.0.0 → 1.0.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.
@@ -3,6 +3,7 @@ import { execa } from "execa";
3
3
  import fs from "fs-extra";
4
4
  import ms from "ms";
5
5
  import assert from "node:assert";
6
+ import path from "node:path";
6
7
  import process from "node:process";
7
8
  import pMap from "p-map";
8
9
  import PQueue from "p-queue";
@@ -21,6 +22,7 @@ import { sprint, sprintln } from "../output/sprint.js";
21
22
  import { symbol } from "../output/symbols.js";
22
23
  import { ts } from "../output/timestamp.js";
23
24
  import { noop } from "../util/function.js";
25
+ import { isEEXISTError, isENOENTError, isENOTDIRError, isENOTEMPTYError } from "../util/is.js";
24
26
  import { serializeError } from "../util/object.js";
25
27
  import { Changes, printChanges, sprintChanges } from "./changes.js";
26
28
  import { getConflicts, printConflicts, withoutConflictingChanges } from "./conflicts.js";
@@ -617,11 +619,18 @@ export class FileSync {
617
619
  files: options.files.map((file)=>file.path),
618
620
  delete: options.delete
619
621
  });
620
- const created = [];
621
- const updated = [];
622
- await pMap(options.delete, async (filepath)=>{
623
- const currentPath = this.syncJson.directory.absolute(filepath);
624
- const backupPath = this.syncJson.directory.absolute(".gadget/backup", this.syncJson.directory.relative(filepath));
622
+ const changes = new Changes();
623
+ const directoriesWithDeletedFiles = new Set();
624
+ await pMap(options.delete, async (pathToDelete)=>{
625
+ // add all the directories that contain this file to
626
+ // directoriesWithDeletedFiles so we can clean them up later
627
+ let dir = path.dirname(pathToDelete);
628
+ while(dir !== "."){
629
+ directoriesWithDeletedFiles.add(this.syncJson.directory.normalize(dir, true));
630
+ dir = path.dirname(dir);
631
+ }
632
+ const currentPath = this.syncJson.directory.absolute(pathToDelete);
633
+ const backupPath = this.syncJson.directory.absolute(".gadget/backup", this.syncJson.directory.relative(pathToDelete));
625
634
  // rather than `rm -rf`ing files, we move them to
626
635
  // `.gadget/backup/` so that users can recover them if something
627
636
  // goes wrong. We've seen a lot of EBUSY/EINVAL errors when moving
@@ -632,9 +641,36 @@ export class FileSync {
632
641
  // different type (file vs directory)
633
642
  await fs.remove(backupPath);
634
643
  await fs.move(currentPath, backupPath);
644
+ changes.set(pathToDelete, {
645
+ type: "delete"
646
+ });
635
647
  } catch (error) {
636
- // replicate the behavior of `rm -rf` and ignore ENOENT
637
- swallowEnoent(error);
648
+ if (isENOENTError(error)) {
649
+ // replicate the behavior of `rm -rf` and ignore ENOENT
650
+ return;
651
+ }
652
+ if (isENOTDIRError(error) || isEEXISTError(error)) {
653
+ // the backup path already exists and ends in a file
654
+ // rather than a directory, so we have to remove the file
655
+ // before we can move the current path to the backup path
656
+ let dir = path.dirname(backupPath);
657
+ while(dir !== this.syncJson.directory.absolute(".gadget/backup")){
658
+ const stats = await fs.stat(dir);
659
+ // eslint-disable-next-line max-depth
660
+ if (!stats.isDirectory()) {
661
+ // this file is in the way, so remove it
662
+ ctx.log.debug("removing file in the way of backup path", {
663
+ currentPath,
664
+ backupPath,
665
+ file: dir
666
+ });
667
+ await fs.remove(dir);
668
+ }
669
+ dir = path.dirname(dir);
670
+ }
671
+ // still throw the error so we retry
672
+ }
673
+ throw error;
638
674
  }
639
675
  }, {
640
676
  // windows tends to run into these issues way more often than
@@ -650,12 +686,38 @@ export class FileSync {
650
686
  }
651
687
  });
652
688
  });
689
+ for (const directoryWithDeletedFile of Array.from(directoriesWithDeletedFiles.values()).sort().reverse()){
690
+ if (options.files.some((file)=>file.path === directoryWithDeletedFile)) {
691
+ continue;
692
+ }
693
+ try {
694
+ // delete any empty directories that contained a deleted file.
695
+ // if the empty directory should continue to exist, we would
696
+ // have received an event to create it above
697
+ await fs.rmdir(this.syncJson.directory.absolute(directoryWithDeletedFile));
698
+ changes.set(directoryWithDeletedFile, {
699
+ type: "delete"
700
+ });
701
+ } catch (error) {
702
+ if (isENOENTError(error) || isENOTEMPTYError(error)) {
703
+ continue;
704
+ }
705
+ throw error;
706
+ }
707
+ }
653
708
  await pMap(options.files, async (file)=>{
654
709
  const absolutePath = this.syncJson.directory.absolute(file.path);
655
710
  if (await fs.pathExists(absolutePath)) {
656
- updated.push(file.path);
711
+ if (!file.path.endsWith("/")) {
712
+ // only track file updates, not directory updates
713
+ changes.set(file.path, {
714
+ type: "update"
715
+ });
716
+ }
657
717
  } else {
658
- created.push(file.path);
718
+ changes.set(file.path, {
719
+ type: "create"
720
+ });
659
721
  }
660
722
  if (file.path.endsWith("/")) {
661
723
  await fs.ensureDir(absolutePath);
@@ -673,26 +735,6 @@ export class FileSync {
673
735
  }
674
736
  });
675
737
  await this.syncJson.save(String(filesVersion));
676
- const changes = new Changes([
677
- ...created.map((path)=>[
678
- path,
679
- {
680
- type: "create"
681
- }
682
- ]),
683
- ...updated.map((path)=>[
684
- path,
685
- {
686
- type: "update"
687
- }
688
- ]),
689
- ...options.delete.map((path)=>[
690
- path,
691
- {
692
- type: "delete"
693
- }
694
- ])
695
- ]);
696
738
  options.spinner?.clear();
697
739
  printChanges(ctx, {
698
740
  changes,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/filesync/filesync.ts"],"sourcesContent":["import { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport ms from \"ms\";\nimport assert from \"node:assert\";\nimport process from \"node:process\";\nimport pMap from \"p-map\";\nimport PQueue from \"p-queue\";\nimport pRetry from \"p-retry\";\nimport pluralize from \"pluralize\";\nimport type { Promisable } from \"type-fest\";\nimport { FileSyncEncoding, type FileSyncChangedEventInput, type FileSyncDeletedEventInput } from \"../../__generated__/graphql.js\";\nimport type { DevArgs } from \"../../commands/dev.js\";\nimport type { PullArgs } from \"../../commands/pull.js\";\nimport { type EditSubscription } from \"../app/edit/edit.js\";\nimport {\n FILE_SYNC_COMPARISON_HASHES_QUERY,\n FILE_SYNC_FILES_QUERY,\n FILE_SYNC_HASHES_QUERY,\n PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION,\n} from \"../app/edit/operation.js\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { confirm } from \"../output/confirm.js\";\nimport { println } from \"../output/print.js\";\nimport { filesyncProblemsToProblems, sprintProblems } from \"../output/problems.js\";\nimport { EdgeCaseError } from \"../output/report.js\";\nimport { select } from \"../output/select.js\";\nimport { spin, type spinner } from \"../output/spinner.js\";\nimport { sprint, sprintln } from \"../output/sprint.js\";\nimport { symbol } from \"../output/symbols.js\";\nimport { ts } from \"../output/timestamp.js\";\nimport { noop } from \"../util/function.js\";\nimport { serializeError } from \"../util/object.js\";\nimport { Changes, printChanges, sprintChanges, type PrintChangesOptions } from \"./changes.js\";\nimport { getConflicts, printConflicts, withoutConflictingChanges } from \"./conflicts.js\";\nimport { supportsPermissions, swallowEnoent, type Hashes } from \"./directory.js\";\nimport { TooManyMergeAttemptsError, isFilesVersionMismatchError, swallowFilesVersionMismatch } from \"./error.js\";\nimport type { File } from \"./file.js\";\nimport { getNecessaryChanges, isEqualHashes, type ChangesWithHash } from \"./hashes.js\";\nimport { MergeConflictPreference } from \"./strategy.js\";\nimport { type SyncJson, type SyncJsonArgs } from \"./sync-json.js\";\n\n/**\n * The maximum attempts to automatically merge local and environment\n * file changes when a FilesVersionMismatchError is encountered before\n * throwing a {@linkcode TooManyMergeAttemptsError}.\n */\nexport const MAX_MERGE_ATTEMPTS = 10;\n\n/**\n * The maximum length of file content that can be pushed to Gadget in a\n * single request.\n */\nexport const MAX_PUSH_CONTENT_LENGTH = 50 * 1024 * 1024; // 50mb\n\nexport type FileSyncHashes = {\n /**\n * Whether the local filesystem is in sync with the environment's\n * filesystem.\n */\n inSync: boolean;\n\n /**\n * Whether the local filesystem and the environment's filesystem have\n * both changed since the last sync.\n */\n bothChanged: boolean;\n\n /**\n * Whether only .gadget/ files have changed on the environment's\n * filesystem.\n */\n onlyDotGadgetFilesChanged: boolean;\n\n /**\n * The hashes of the files at the local filesVersion.\n */\n localFilesVersionHashes: Hashes;\n\n /**\n * The hashes of the files on the local filesystem.\n */\n localHashes: Hashes;\n\n /**\n * The changes the local filesystem has made since the last sync.\n */\n localChanges: ChangesWithHash;\n\n /**\n * The changes the local filesystem needs to push to make the\n * environment's filesystem in sync with the local filesystem.\n *\n * NOTE: If the environment's filesystem has changed since the last\n * sync, these changes will undo those changes.\n */\n localChangesToPush: Changes | ChangesWithHash;\n\n /**\n * The filesVersion of the environment's filesystem.\n */\n environmentFilesVersion: bigint;\n\n /**\n * The hashes of the files on the environment's filesystem.\n */\n environmentHashes: Hashes;\n\n /**\n * The changes the environment's filesystem has made since the last\n * sync.\n */\n environmentChanges: ChangesWithHash;\n\n /**\n * The changes the local filesystem needs to pull from the\n * environment's filesystem to be in sync with the environment's\n * filesystem.\n *\n * NOTE: If the local filesystem has changed since the last sync,\n * these changes will undo those changes.\n */\n environmentChangesToPull: Changes | ChangesWithHash;\n};\n\nexport class FileSync {\n /**\n * A FIFO async callback queue that ensures we process filesync events\n * in the order we receive them.\n */\n private _syncOperations = new PQueue({ concurrency: 1 });\n\n constructor(readonly syncJson: SyncJson) {}\n\n async hashes(ctx: Context<SyncJsonArgs>): Promise<FileSyncHashes> {\n const spinner = spin({ ensureEmptyLineAbove: true })`\n Calculating file changes.\n `;\n\n try {\n const [localHashes, { localFilesVersionHashes, environmentHashes, environmentFilesVersion }] = await Promise.all([\n // get the hashes of our local files\n this.syncJson.directory.hashes(),\n // get the hashes of our local filesVersion and the latest filesVersion\n (async () => {\n let localFilesVersionHashes: Hashes;\n let environmentHashes: Hashes;\n let environmentFilesVersion: bigint;\n\n if (this.syncJson.filesVersion === 0n) {\n // we're either syncing for the first time or we're syncing a\n // non-empty directory without a `.gadget/sync.json` file,\n // regardless get the hashes of the latest filesVersion\n const { fileSyncHashes } = await this.syncJson.edit.query({ query: FILE_SYNC_HASHES_QUERY });\n environmentFilesVersion = BigInt(fileSyncHashes.filesVersion);\n environmentHashes = fileSyncHashes.hashes;\n localFilesVersionHashes = {}; // represents an empty directory\n } else {\n // this isn't the first time we're syncing, so get the\n // hashes of the files at our local filesVersion and the\n // latest filesVersion\n const { fileSyncComparisonHashes } = await this.syncJson.edit.query({\n query: FILE_SYNC_COMPARISON_HASHES_QUERY,\n variables: { filesVersion: String(this.syncJson.filesVersion) },\n });\n\n localFilesVersionHashes = fileSyncComparisonHashes.filesVersionHashes.hashes;\n environmentHashes = fileSyncComparisonHashes.latestFilesVersionHashes.hashes;\n environmentFilesVersion = BigInt(fileSyncComparisonHashes.latestFilesVersionHashes.filesVersion);\n }\n\n return { localFilesVersionHashes, environmentHashes, environmentFilesVersion };\n })(),\n ]);\n\n const inSync = isEqualHashes(ctx, localHashes, environmentHashes);\n\n const localChanges = getNecessaryChanges(ctx, {\n from: localFilesVersionHashes,\n to: localHashes,\n existing: environmentHashes,\n ignore: [\".gadget/\"], // gadget manages these files\n });\n\n let environmentChanges = getNecessaryChanges(ctx, {\n from: localFilesVersionHashes,\n to: environmentHashes,\n existing: localHashes,\n });\n\n if (!inSync && localChanges.size === 0 && environmentChanges.size === 0) {\n // we're not in sync, but neither the local filesystem nor the\n // environment's filesystem have any changes; this is only\n // possible if the local filesystem has modified .gadget/ files\n environmentChanges = getNecessaryChanges(ctx, { from: localHashes, to: environmentHashes });\n assert(environmentChanges.size > 0, \"expected environmentChanges to have changes\");\n assert(\n Array.from(environmentChanges.keys()).every((path) => path.startsWith(\".gadget/\")),\n \"expected all environmentChanges to be .gadget/ files\",\n );\n }\n\n assert(inSync || localChanges.size > 0 || environmentChanges.size > 0, \"there must be changes if hashes don't match\");\n\n const localChangesToPush = getNecessaryChanges(ctx, { from: environmentHashes, to: localHashes, ignore: [\".gadget/\"] });\n const environmentChangesToPull = getNecessaryChanges(ctx, { from: localHashes, to: environmentHashes });\n\n const onlyDotGadgetFilesChanged = Array.from(environmentChangesToPull.keys()).every((filepath) => filepath.startsWith(\".gadget/\"));\n const bothChanged = localChanges.size > 0 && environmentChanges.size > 0 && !onlyDotGadgetFilesChanged;\n\n if (inSync) {\n spinner.succeed`Your files are up to date. ${ts()}`;\n } else {\n spinner.succeed`Calculated file changes. ${ts()}`;\n }\n\n return {\n inSync,\n localFilesVersionHashes,\n localHashes,\n localChanges,\n localChangesToPush,\n environmentHashes,\n environmentChanges,\n environmentChangesToPull,\n environmentFilesVersion,\n onlyDotGadgetFilesChanged,\n bothChanged,\n };\n } catch (error) {\n spinner.fail();\n throw error;\n }\n }\n\n async print(ctx: Context<SyncJsonArgs>, { hashes }: { hashes?: FileSyncHashes } = {}): Promise<void> {\n const { inSync, localChanges, environmentChanges, onlyDotGadgetFilesChanged, bothChanged } = hashes ?? (await this.hashes(ctx));\n if (inSync) {\n // the spinner in hashes will have already printed that we're in sync\n return;\n }\n\n if (localChanges.size > 0) {\n printChanges(ctx, {\n changes: localChanges,\n tense: \"past\",\n title: sprint`Your local files {underline have} changed.`,\n });\n } else {\n println({ ensureEmptyLineAbove: true })`\n Your local files {underline have not} changed.\n `;\n }\n\n if (environmentChanges.size > 0 && !onlyDotGadgetFilesChanged) {\n printChanges(ctx, {\n changes: environmentChanges,\n tense: \"past\",\n title: sprint`Your environment's files {underline have}${bothChanged ? \" also\" : \"\"} changed.`,\n });\n } else {\n println({ ensureEmptyLineAbove: true })`\n Your environment's files {underline have not} changed.\n `;\n }\n }\n\n /**\n * Waits for all pending and ongoing filesync operations to complete.\n */\n async idle(): Promise<void> {\n await this._syncOperations.onIdle();\n }\n\n /**\n * Attempts to send file changes to the Gadget. If a files version\n * mismatch error occurs, this function will merge the changes with\n * Gadget instead.\n *\n * @param ctx - The context to use.\n * @param options - The options to use.\n * @param options.changes - The changes to send.\n * @param options.printLocalChangesOptions - The options to use when printing the local changes.\n * @param options.printEnvironmentChangesOptions - The options to use when printing the changes from Gadget.\n * @returns A promise that resolves when the changes have been sent.\n */\n async mergeChangesWithEnvironment(\n ctx: Context<DevArgs>,\n {\n changes,\n printLocalChangesOptions,\n printEnvironmentChangesOptions,\n }: {\n changes: Changes;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n await this._syncOperations.add(async () => {\n try {\n await this._sendChangesToEnvironment(ctx, { changes, printLocalChangesOptions });\n } catch (error) {\n swallowFilesVersionMismatch(ctx, error);\n // we either sent the wrong expectedFilesVersion or we received\n // a filesVersion that is greater than the expectedFilesVersion\n // + 1, so we need to stop what we're doing and get in sync\n await this.merge(ctx, { printEnvironmentChangesOptions });\n }\n });\n }\n\n /**\n * Subscribes to file changes on Gadget and executes the provided\n * callbacks before and after the changes occur.\n *\n * @param ctx - The context to use.\n * @param options - The options to use.\n * @param options.beforeChanges - A callback that is called before the changes occur.\n * @param options.afterChanges - A callback that is called after the changes occur.\n * @param options.onError - A callback that is called if an error occurs.\n * @param options.printEnvironmentChangesOptions - The options to use when printing the changes from Gadget.\n * @returns A function that unsubscribes from changes on Gadget.\n */\n subscribeToEnvironmentChanges(\n ctx: Context<DevArgs>,\n {\n beforeChanges = noop,\n printEnvironmentChangesOptions,\n afterChanges = noop,\n onError,\n }: {\n beforeChanges?: (data: { changed: string[]; deleted: string[] }) => Promisable<void>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n afterChanges?: (data: { changes: Changes }) => Promisable<void>;\n onError: (error: unknown) => void;\n },\n ): EditSubscription<REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION> {\n return this.syncJson.edit.subscribe({\n subscription: REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION,\n // the reason this is a function rather than a static value is\n // so that it will be re-evaluated if the connection is lost and\n // then re-established. this ensures that we send our current\n // filesVersion rather than the one that was sent when we first\n // subscribed\n variables: () => ({ localFilesVersion: String(this.syncJson.filesVersion) }),\n onError,\n onData: ({ remoteFileSyncEvents: { changed, deleted, remoteFilesVersion } }) => {\n this._syncOperations\n .add(async () => {\n if (BigInt(remoteFilesVersion) < this.syncJson.filesVersion) {\n ctx.log.warn(\"skipping received changes because files version is outdated\", { filesVersion: remoteFilesVersion });\n return;\n }\n\n ctx.log.debug(\"received files\", {\n remoteFilesVersion,\n changed: changed.map((change) => change.path),\n deleted: deleted.map((change) => change.path),\n });\n\n const filterIgnoredFiles = (file: { path: string }): boolean => {\n const ignored = this.syncJson.directory.ignores(file.path);\n if (ignored) {\n ctx.log.warn(\"skipping received change because file is ignored\", { path: file.path });\n }\n return !ignored;\n };\n\n changed = changed.filter(filterIgnoredFiles);\n deleted = deleted.filter(filterIgnoredFiles);\n\n if (changed.length === 0 && deleted.length === 0) {\n await this.syncJson.save(remoteFilesVersion);\n return;\n }\n\n await beforeChanges({\n changed: changed.map((file) => file.path),\n deleted: deleted.map((file) => file.path),\n });\n\n const changes = await this._writeToLocalFilesystem(ctx, {\n filesVersion: remoteFilesVersion,\n files: changed,\n delete: deleted.map((file) => file.path),\n printEnvironmentChangesOptions: {\n tense: \"past\",\n ensureEmptyLineAbove: true,\n title: sprintln`{green ${symbol.tick}} Pulled ${pluralize(\"file\", changed.length + deleted.length)}. ${symbol.arrowLeft} ${ts()}`,\n limit: 5,\n ...printEnvironmentChangesOptions,\n },\n });\n\n await afterChanges({ changes });\n })\n .catch(onError);\n },\n });\n }\n\n /**\n * Ensures the local filesystem is in sync with Gadget's filesystem.\n * - All non-conflicting changes are automatically merged.\n * - Conflicts are resolved by prompting the user to either keep their local changes or keep Gadget's changes.\n * - This function will not return until the filesystem is in sync.\n */\n async merge(\n ctx: Context<DevArgs>,\n {\n hashes,\n maxAttempts = 10,\n printLocalChangesOptions,\n printEnvironmentChangesOptions,\n }: {\n hashes?: FileSyncHashes;\n maxAttempts?: number;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n } = {},\n ): Promise<void> {\n let attempt = 0;\n\n do {\n if (attempt === 0) {\n hashes ??= await this.hashes(ctx);\n } else {\n hashes = await this.hashes(ctx);\n }\n\n if (hashes.inSync) {\n this._syncOperations.clear();\n ctx.log.info(\"filesystem in sync\");\n await this.syncJson.save(hashes.environmentFilesVersion);\n return;\n }\n\n attempt += 1;\n ctx.log.info(\"merging\", { attempt, ...hashes });\n\n try {\n await this._merge(ctx, { hashes, printLocalChangesOptions, printEnvironmentChangesOptions });\n } catch (error) {\n swallowFilesVersionMismatch(ctx, error);\n // we either sent the wrong expectedFilesVersion or we received\n // a filesVersion that is greater than the expectedFilesVersion\n // + 1, so try again\n }\n } while (attempt < maxAttempts);\n\n throw new TooManyMergeAttemptsError(maxAttempts);\n }\n\n /**\n * Pushes any changes made to the local filesystem since the last sync\n * to Gadget.\n *\n * If Gadget has also made changes since the last sync, and --force\n * was not passed, the user will be prompted to discard them.\n */\n async push(\n ctx: Context<PullArgs>,\n {\n hashes,\n force,\n printLocalChangesOptions,\n }: {\n hashes?: FileSyncHashes;\n force?: boolean;\n printLocalChangesOptions?: PrintChangesOptions;\n } = {},\n ): Promise<void> {\n const { localChangesToPush, environmentChanges, environmentFilesVersion, onlyDotGadgetFilesChanged } =\n hashes ?? (await this.hashes(ctx));\n assert(localChangesToPush.size > 0, \"cannot push if there are no changes\");\n\n // TODO: lift this check up to the push command\n if (\n // they didn't pass --force\n !(force ?? ctx.args[\"--force\"]) &&\n // their environment's files have changed\n environmentChanges.size > 0 &&\n // some of the changes aren't .gadget/ files\n !onlyDotGadgetFilesChanged\n ) {\n await confirm({ ensureEmptyLineAbove: true })`\n Are you sure you want to {underline discard} your environment's changes?\n `;\n }\n\n try {\n await this._sendChangesToEnvironment(ctx, {\n // what changes need to be made to your local files to make\n // them match the environment's files\n changes: localChangesToPush,\n expectedFilesVersion: environmentFilesVersion,\n printLocalChangesOptions,\n });\n } catch (error) {\n swallowFilesVersionMismatch(ctx, error);\n // we were told to push their local changes, but their\n // environment's files have changed since we last checked, so\n // throw a nicer error message\n // TODO: we don't have to do this if only .gadget/ files changed\n throw new EdgeCaseError(sprint`\n Your environment's files have changed since we last checked.\n\n Please re-run \"ggt ${ctx.command}\" to see the changes and try again.\n `);\n }\n }\n\n async pull(\n ctx: Context<PullArgs>,\n {\n hashes,\n force,\n printEnvironmentChangesOptions,\n }: {\n hashes?: FileSyncHashes;\n force?: boolean;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n } = {},\n ): Promise<void> {\n const { localChanges, environmentChangesToPull, environmentFilesVersion } = hashes ?? (await this.hashes(ctx));\n assert(environmentChangesToPull.size > 0, \"cannot push if there are no changes\");\n\n // TODO: lift this check up to the pull command\n if (localChanges.size > 0 && !(force ?? ctx.args[\"--force\"])) {\n await confirm`\n Are you sure you want to {underline discard} your local changes?\n `;\n }\n\n await this._getChangesFromEnvironment(ctx, {\n changes: environmentChangesToPull,\n filesVersion: environmentFilesVersion,\n printEnvironmentChangesOptions,\n });\n }\n\n private async _merge(\n ctx: Context<DevArgs>,\n {\n hashes: { localChanges, environmentChanges, environmentFilesVersion },\n printLocalChangesOptions,\n printEnvironmentChangesOptions,\n }: {\n hashes: FileSyncHashes;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n const conflicts = getConflicts({ localChanges, environmentChanges });\n if (conflicts.size > 0) {\n ctx.log.debug(\"conflicts detected\", { conflicts });\n\n let preference = ctx.args[\"--prefer\"];\n if (!preference) {\n printConflicts({ conflicts });\n preference = await select({ choices: Object.values(MergeConflictPreference) })`\n {bold How should we resolve these conflicts?}\n `;\n }\n\n switch (preference) {\n case MergeConflictPreference.CANCEL: {\n process.exit(0);\n break;\n }\n case MergeConflictPreference.LOCAL: {\n environmentChanges = withoutConflictingChanges({ conflicts, changes: environmentChanges });\n break;\n }\n case MergeConflictPreference.ENVIRONMENT: {\n localChanges = withoutConflictingChanges({ conflicts, changes: localChanges });\n break;\n }\n }\n }\n\n if (environmentChanges.size > 0) {\n await this._getChangesFromEnvironment(ctx, {\n changes: environmentChanges,\n filesVersion: environmentFilesVersion,\n printEnvironmentChangesOptions,\n });\n }\n\n if (localChanges.size > 0) {\n await this._sendChangesToEnvironment(ctx, {\n changes: localChanges,\n expectedFilesVersion: environmentFilesVersion,\n printLocalChangesOptions,\n });\n }\n }\n\n private async _getChangesFromEnvironment(\n ctx: Context<SyncJsonArgs>,\n {\n filesVersion,\n changes,\n printEnvironmentChangesOptions,\n }: {\n filesVersion: bigint;\n changes: Changes | ChangesWithHash;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n ctx.log.debug(\"getting changes from gadget\", { filesVersion, changes });\n const created = changes.created();\n const updated = changes.updated();\n\n const spinner = spin({ ensureEmptyLineAbove: true })(\n sprintChanges(ctx, {\n changes,\n tense: \"present\",\n title: sprint`Pulling ${pluralize(\"file\", changes.size)}. ${symbol.arrowLeft}`,\n ...printEnvironmentChangesOptions,\n }),\n );\n\n try {\n let files: File[] = [];\n if (created.length > 0 || updated.length > 0) {\n const { fileSyncFiles } = await this.syncJson.edit.query({\n query: FILE_SYNC_FILES_QUERY,\n variables: {\n paths: [...created, ...updated],\n filesVersion: String(filesVersion),\n encoding: FileSyncEncoding.Base64,\n },\n });\n\n files = fileSyncFiles.files;\n }\n\n await this._writeToLocalFilesystem(ctx, {\n filesVersion,\n files,\n delete: changes.deleted(),\n spinner,\n printEnvironmentChangesOptions,\n });\n } catch (error) {\n spinner.fail();\n throw error;\n }\n }\n\n private async _sendChangesToEnvironment(\n ctx: Context<SyncJsonArgs>,\n {\n changes,\n expectedFilesVersion = this.syncJson.filesVersion,\n printLocalChangesOptions,\n }: {\n changes: Changes | ChangesWithHash;\n expectedFilesVersion?: bigint;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n ctx.log.debug(\"sending changes to gadget\", { expectedFilesVersion, changes });\n const changed: FileSyncChangedEventInput[] = [];\n const deleted: FileSyncDeletedEventInput[] = [];\n\n await pMap(changes, async ([normalizedPath, change]) => {\n if (change.type === \"delete\") {\n deleted.push({ path: normalizedPath });\n return;\n }\n\n const absolutePath = this.syncJson.directory.absolute(normalizedPath);\n\n let stats;\n try {\n stats = await fs.stat(absolutePath);\n } catch (error) {\n swallowEnoent(error);\n ctx.log.debug(\"skipping change because file doesn't exist\", { path: normalizedPath });\n return;\n }\n\n let content = \"\";\n if (stats.isFile()) {\n content = await fs.readFile(absolutePath, FileSyncEncoding.Base64);\n }\n\n let oldPath;\n if (change.type === \"create\" && change.oldPath) {\n oldPath = change.oldPath;\n }\n\n changed.push({\n content,\n oldPath,\n path: normalizedPath,\n mode: stats.mode,\n encoding: FileSyncEncoding.Base64,\n });\n });\n\n if (changed.length === 0 && deleted.length === 0) {\n ctx.log.debug(\"skipping send because there are no changes\");\n return;\n }\n\n const contentLength = changed.map((change) => change.content.length).reduce((a, b) => a + b, 0);\n if (contentLength > MAX_PUSH_CONTENT_LENGTH) {\n throw new EdgeCaseError(sprint`\n {underline Your file changes are too large to push.}\n\n Run \"ggt status\" to see your changes and consider\n ignoring some files or pushing in smaller batches.\n `);\n }\n\n const spinner = spin({ ensureEmptyLineAbove: true })(\n sprintChanges(ctx, {\n changes,\n tense: \"present\",\n title: sprintln`Pushing ${pluralize(\"file\", changed.length + deleted.length)}. ${symbol.arrowRight}`,\n ...printLocalChangesOptions,\n }),\n );\n\n try {\n const {\n publishFileSyncEvents: { remoteFilesVersion, problems: filesyncProblems },\n } = await this.syncJson.edit.mutate({\n mutation: PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n variables: {\n input: {\n expectedRemoteFilesVersion: String(expectedFilesVersion),\n changed,\n deleted,\n },\n },\n http: {\n retry: {\n // we can retry this request because\n // expectedRemoteFilesVersion makes it idempotent\n methods: [\"POST\"],\n calculateDelay: ({ error, computedValue }) => {\n if (isFilesVersionMismatchError(error.response?.body)) {\n // don't retry if we get a files version mismatch error\n return 0;\n }\n return computedValue;\n },\n },\n },\n });\n\n if (BigInt(remoteFilesVersion) > expectedFilesVersion + 1n) {\n // we can't save the remoteFilesVersion because we haven't\n // received the intermediate filesVersions yet\n throw new Error(\"Files version mismatch\");\n }\n\n await this.syncJson.save(remoteFilesVersion);\n\n spinner.succeed(\n sprintChanges(ctx, {\n changes,\n tense: \"past\",\n title: sprintln`Pushed ${pluralize(\"file\", changed.length + deleted.length)}. ${symbol.arrowRight} ${ts()}`,\n ...printLocalChangesOptions,\n }),\n );\n\n if (filesyncProblems.length > 0) {\n println({ ensureEmptyLineAbove: true })`\n {red Gadget has detected the following fatal errors with your files:}\n\n ${sprintProblems({\n problems: filesyncProblemsToProblems(filesyncProblems),\n showFileTypes: false,\n indent: 10,\n })}\n\n {red Your app will not be operational until all fatal errors are fixed.}\n `;\n }\n } catch (error) {\n if (isFilesVersionMismatchError(error)) {\n spinner.clear();\n } else {\n spinner.fail();\n }\n\n throw error;\n }\n }\n\n private async _writeToLocalFilesystem(\n ctx: Context<SyncJsonArgs>,\n options: {\n filesVersion: bigint | string;\n files: File[];\n delete: string[];\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n spinner?: spinner;\n },\n ): Promise<Changes> {\n const filesVersion = BigInt(options.filesVersion);\n assert(filesVersion >= this.syncJson.filesVersion, \"filesVersion must be greater than or equal to current filesVersion\");\n\n ctx.log.debug(\"writing to local filesystem\", {\n filesVersion,\n files: options.files.map((file) => file.path),\n delete: options.delete,\n });\n\n const created: string[] = [];\n const updated: string[] = [];\n\n await pMap(options.delete, async (filepath) => {\n const currentPath = this.syncJson.directory.absolute(filepath);\n const backupPath = this.syncJson.directory.absolute(\".gadget/backup\", this.syncJson.directory.relative(filepath));\n\n // rather than `rm -rf`ing files, we move them to\n // `.gadget/backup/` so that users can recover them if something\n // goes wrong. We've seen a lot of EBUSY/EINVAL errors when moving\n // files so we retry a few times.\n await pRetry(\n async () => {\n try {\n // remove the current backup file in case it exists and is a\n // different type (file vs directory)\n await fs.remove(backupPath);\n await fs.move(currentPath, backupPath);\n } catch (error) {\n // replicate the behavior of `rm -rf` and ignore ENOENT\n swallowEnoent(error);\n }\n },\n {\n // windows tends to run into these issues way more often than\n // mac/linux, so we retry more times\n retries: config.windows ? 4 : 2,\n minTimeout: ms(\"100ms\"),\n onFailedAttempt: (error) => {\n ctx.log.warn(\"failed to move file to backup\", { error, currentPath, backupPath });\n },\n },\n );\n });\n\n await pMap(options.files, async (file) => {\n const absolutePath = this.syncJson.directory.absolute(file.path);\n if (await fs.pathExists(absolutePath)) {\n updated.push(file.path);\n } else {\n created.push(file.path);\n }\n\n if (file.path.endsWith(\"/\")) {\n await fs.ensureDir(absolutePath);\n } else {\n await fs.outputFile(absolutePath, Buffer.from(file.content, file.encoding));\n }\n\n if (supportsPermissions) {\n // the os's default umask makes setting the mode during creation\n // not work, so an additional fs.chmod call is necessary to\n // ensure the file has the correct mode\n await fs.chmod(absolutePath, file.mode & 0o777);\n }\n\n if (absolutePath === this.syncJson.directory.absolute(\".ignore\")) {\n await this.syncJson.directory.loadIgnoreFile();\n }\n });\n\n await this.syncJson.save(String(filesVersion));\n\n const changes = new Changes([\n ...created.map((path) => [path, { type: \"create\" }] as const),\n ...updated.map((path) => [path, { type: \"update\" }] as const),\n ...options.delete.map((path) => [path, { type: \"delete\" }] as const),\n ]);\n\n options.spinner?.clear();\n\n printChanges(ctx, {\n changes,\n tense: \"past\",\n title: sprint`{green ${symbol.tick}} Pulled ${pluralize(\"file\", changes.size)}. ${symbol.arrowLeft} ${ts()}`,\n ...options.printEnvironmentChangesOptions,\n });\n\n if (changes.has(\"yarn.lock\")) {\n const spinner = spin({ ensureEmptyLineAbove: true })('Running \"yarn install --check-files\"');\n\n try {\n await execa(\"yarn\", [\"install\", \"--check-files\"], { cwd: this.syncJson.directory.path });\n spinner.succeed`Ran \"yarn install --check-files\" ${ts()}`;\n } catch (error) {\n spinner.fail();\n ctx.log.error(\"yarn install failed\", { error });\n\n const message = serializeError(error).message;\n if (message) {\n println({ ensureEmptyLineAbove: true, indent: 2 })(message);\n }\n }\n }\n\n return changes;\n }\n}\n"],"names":["execa","fs","ms","assert","process","pMap","PQueue","pRetry","pluralize","FileSyncEncoding","FILE_SYNC_COMPARISON_HASHES_QUERY","FILE_SYNC_FILES_QUERY","FILE_SYNC_HASHES_QUERY","PUBLISH_FILE_SYNC_EVENTS_MUTATION","REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION","config","confirm","println","filesyncProblemsToProblems","sprintProblems","EdgeCaseError","select","spin","sprint","sprintln","symbol","ts","noop","serializeError","Changes","printChanges","sprintChanges","getConflicts","printConflicts","withoutConflictingChanges","supportsPermissions","swallowEnoent","TooManyMergeAttemptsError","isFilesVersionMismatchError","swallowFilesVersionMismatch","getNecessaryChanges","isEqualHashes","MergeConflictPreference","MAX_MERGE_ATTEMPTS","MAX_PUSH_CONTENT_LENGTH","FileSync","hashes","ctx","spinner","ensureEmptyLineAbove","localHashes","localFilesVersionHashes","environmentHashes","environmentFilesVersion","Promise","all","syncJson","directory","filesVersion","fileSyncHashes","edit","query","BigInt","fileSyncComparisonHashes","variables","String","filesVersionHashes","latestFilesVersionHashes","inSync","localChanges","from","to","existing","ignore","environmentChanges","size","Array","keys","every","path","startsWith","localChangesToPush","environmentChangesToPull","onlyDotGadgetFilesChanged","filepath","bothChanged","succeed","error","fail","print","changes","tense","title","idle","_syncOperations","onIdle","mergeChangesWithEnvironment","printLocalChangesOptions","printEnvironmentChangesOptions","add","_sendChangesToEnvironment","merge","subscribeToEnvironmentChanges","beforeChanges","afterChanges","onError","subscribe","subscription","localFilesVersion","onData","remoteFileSyncEvents","changed","deleted","remoteFilesVersion","log","warn","debug","map","change","filterIgnoredFiles","file","ignored","ignores","filter","length","save","_writeToLocalFilesystem","files","delete","tick","arrowLeft","limit","catch","maxAttempts","attempt","clear","info","_merge","push","force","args","expectedFilesVersion","command","pull","_getChangesFromEnvironment","conflicts","preference","choices","Object","values","CANCEL","exit","LOCAL","ENVIRONMENT","created","updated","fileSyncFiles","paths","encoding","Base64","normalizedPath","type","absolutePath","absolute","stats","stat","content","isFile","readFile","oldPath","mode","contentLength","reduce","a","b","arrowRight","publishFileSyncEvents","problems","filesyncProblems","mutate","mutation","input","expectedRemoteFilesVersion","http","retry","methods","calculateDelay","computedValue","response","body","Error","showFileTypes","indent","options","currentPath","backupPath","relative","remove","move","retries","windows","minTimeout","onFailedAttempt","pathExists","endsWith","ensureDir","outputFile","Buffer","chmod","loadIgnoreFile","has","cwd","message","constructor","concurrency"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/services/filesync/filesync.ts"],"sourcesContent":["import { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport ms from \"ms\";\nimport assert from \"node:assert\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport pMap from \"p-map\";\nimport PQueue from \"p-queue\";\nimport pRetry from \"p-retry\";\nimport pluralize from \"pluralize\";\nimport type { Promisable } from \"type-fest\";\nimport { FileSyncEncoding, type FileSyncChangedEventInput, type FileSyncDeletedEventInput } from \"../../__generated__/graphql.js\";\nimport type { DevArgs } from \"../../commands/dev.js\";\nimport type { PullArgs } from \"../../commands/pull.js\";\nimport { type EditSubscription } from \"../app/edit/edit.js\";\nimport {\n FILE_SYNC_COMPARISON_HASHES_QUERY,\n FILE_SYNC_FILES_QUERY,\n FILE_SYNC_HASHES_QUERY,\n PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION,\n} from \"../app/edit/operation.js\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { confirm } from \"../output/confirm.js\";\nimport { println } from \"../output/print.js\";\nimport { filesyncProblemsToProblems, sprintProblems } from \"../output/problems.js\";\nimport { EdgeCaseError } from \"../output/report.js\";\nimport { select } from \"../output/select.js\";\nimport { spin, type spinner } from \"../output/spinner.js\";\nimport { sprint, sprintln } from \"../output/sprint.js\";\nimport { symbol } from \"../output/symbols.js\";\nimport { ts } from \"../output/timestamp.js\";\nimport { noop } from \"../util/function.js\";\nimport { isEEXISTError, isENOENTError, isENOTDIRError, isENOTEMPTYError } from \"../util/is.js\";\nimport { serializeError } from \"../util/object.js\";\nimport { Changes, printChanges, sprintChanges, type PrintChangesOptions } from \"./changes.js\";\nimport { getConflicts, printConflicts, withoutConflictingChanges } from \"./conflicts.js\";\nimport { supportsPermissions, swallowEnoent, type Hashes } from \"./directory.js\";\nimport { TooManyMergeAttemptsError, isFilesVersionMismatchError, swallowFilesVersionMismatch } from \"./error.js\";\nimport type { File } from \"./file.js\";\nimport { getNecessaryChanges, isEqualHashes, type ChangesWithHash } from \"./hashes.js\";\nimport { MergeConflictPreference } from \"./strategy.js\";\nimport { type SyncJson, type SyncJsonArgs } from \"./sync-json.js\";\n\n/**\n * The maximum attempts to automatically merge local and environment\n * file changes when a FilesVersionMismatchError is encountered before\n * throwing a {@linkcode TooManyMergeAttemptsError}.\n */\nexport const MAX_MERGE_ATTEMPTS = 10;\n\n/**\n * The maximum length of file content that can be pushed to Gadget in a\n * single request.\n */\nexport const MAX_PUSH_CONTENT_LENGTH = 50 * 1024 * 1024; // 50mb\n\nexport type FileSyncHashes = {\n /**\n * Whether the local filesystem is in sync with the environment's\n * filesystem.\n */\n inSync: boolean;\n\n /**\n * Whether the local filesystem and the environment's filesystem have\n * both changed since the last sync.\n */\n bothChanged: boolean;\n\n /**\n * Whether only .gadget/ files have changed on the environment's\n * filesystem.\n */\n onlyDotGadgetFilesChanged: boolean;\n\n /**\n * The hashes of the files at the local filesVersion.\n */\n localFilesVersionHashes: Hashes;\n\n /**\n * The hashes of the files on the local filesystem.\n */\n localHashes: Hashes;\n\n /**\n * The changes the local filesystem has made since the last sync.\n */\n localChanges: ChangesWithHash;\n\n /**\n * The changes the local filesystem needs to push to make the\n * environment's filesystem in sync with the local filesystem.\n *\n * NOTE: If the environment's filesystem has changed since the last\n * sync, these changes will undo those changes.\n */\n localChangesToPush: Changes | ChangesWithHash;\n\n /**\n * The filesVersion of the environment's filesystem.\n */\n environmentFilesVersion: bigint;\n\n /**\n * The hashes of the files on the environment's filesystem.\n */\n environmentHashes: Hashes;\n\n /**\n * The changes the environment's filesystem has made since the last\n * sync.\n */\n environmentChanges: ChangesWithHash;\n\n /**\n * The changes the local filesystem needs to pull from the\n * environment's filesystem to be in sync with the environment's\n * filesystem.\n *\n * NOTE: If the local filesystem has changed since the last sync,\n * these changes will undo those changes.\n */\n environmentChangesToPull: Changes | ChangesWithHash;\n};\n\nexport class FileSync {\n /**\n * A FIFO async callback queue that ensures we process filesync events\n * in the order we receive them.\n */\n private _syncOperations = new PQueue({ concurrency: 1 });\n\n constructor(readonly syncJson: SyncJson) {}\n\n async hashes(ctx: Context<SyncJsonArgs>): Promise<FileSyncHashes> {\n const spinner = spin({ ensureEmptyLineAbove: true })`\n Calculating file changes.\n `;\n\n try {\n const [localHashes, { localFilesVersionHashes, environmentHashes, environmentFilesVersion }] = await Promise.all([\n // get the hashes of our local files\n this.syncJson.directory.hashes(),\n // get the hashes of our local filesVersion and the latest filesVersion\n (async () => {\n let localFilesVersionHashes: Hashes;\n let environmentHashes: Hashes;\n let environmentFilesVersion: bigint;\n\n if (this.syncJson.filesVersion === 0n) {\n // we're either syncing for the first time or we're syncing a\n // non-empty directory without a `.gadget/sync.json` file,\n // regardless get the hashes of the latest filesVersion\n const { fileSyncHashes } = await this.syncJson.edit.query({ query: FILE_SYNC_HASHES_QUERY });\n environmentFilesVersion = BigInt(fileSyncHashes.filesVersion);\n environmentHashes = fileSyncHashes.hashes;\n localFilesVersionHashes = {}; // represents an empty directory\n } else {\n // this isn't the first time we're syncing, so get the\n // hashes of the files at our local filesVersion and the\n // latest filesVersion\n const { fileSyncComparisonHashes } = await this.syncJson.edit.query({\n query: FILE_SYNC_COMPARISON_HASHES_QUERY,\n variables: { filesVersion: String(this.syncJson.filesVersion) },\n });\n\n localFilesVersionHashes = fileSyncComparisonHashes.filesVersionHashes.hashes;\n environmentHashes = fileSyncComparisonHashes.latestFilesVersionHashes.hashes;\n environmentFilesVersion = BigInt(fileSyncComparisonHashes.latestFilesVersionHashes.filesVersion);\n }\n\n return { localFilesVersionHashes, environmentHashes, environmentFilesVersion };\n })(),\n ]);\n\n const inSync = isEqualHashes(ctx, localHashes, environmentHashes);\n\n const localChanges = getNecessaryChanges(ctx, {\n from: localFilesVersionHashes,\n to: localHashes,\n existing: environmentHashes,\n ignore: [\".gadget/\"], // gadget manages these files\n });\n\n let environmentChanges = getNecessaryChanges(ctx, {\n from: localFilesVersionHashes,\n to: environmentHashes,\n existing: localHashes,\n });\n\n if (!inSync && localChanges.size === 0 && environmentChanges.size === 0) {\n // we're not in sync, but neither the local filesystem nor the\n // environment's filesystem have any changes; this is only\n // possible if the local filesystem has modified .gadget/ files\n environmentChanges = getNecessaryChanges(ctx, { from: localHashes, to: environmentHashes });\n assert(environmentChanges.size > 0, \"expected environmentChanges to have changes\");\n assert(\n Array.from(environmentChanges.keys()).every((path) => path.startsWith(\".gadget/\")),\n \"expected all environmentChanges to be .gadget/ files\",\n );\n }\n\n assert(inSync || localChanges.size > 0 || environmentChanges.size > 0, \"there must be changes if hashes don't match\");\n\n const localChangesToPush = getNecessaryChanges(ctx, { from: environmentHashes, to: localHashes, ignore: [\".gadget/\"] });\n const environmentChangesToPull = getNecessaryChanges(ctx, { from: localHashes, to: environmentHashes });\n\n const onlyDotGadgetFilesChanged = Array.from(environmentChangesToPull.keys()).every((filepath) => filepath.startsWith(\".gadget/\"));\n const bothChanged = localChanges.size > 0 && environmentChanges.size > 0 && !onlyDotGadgetFilesChanged;\n\n if (inSync) {\n spinner.succeed`Your files are up to date. ${ts()}`;\n } else {\n spinner.succeed`Calculated file changes. ${ts()}`;\n }\n\n return {\n inSync,\n localFilesVersionHashes,\n localHashes,\n localChanges,\n localChangesToPush,\n environmentHashes,\n environmentChanges,\n environmentChangesToPull,\n environmentFilesVersion,\n onlyDotGadgetFilesChanged,\n bothChanged,\n };\n } catch (error) {\n spinner.fail();\n throw error;\n }\n }\n\n async print(ctx: Context<SyncJsonArgs>, { hashes }: { hashes?: FileSyncHashes } = {}): Promise<void> {\n const { inSync, localChanges, environmentChanges, onlyDotGadgetFilesChanged, bothChanged } = hashes ?? (await this.hashes(ctx));\n if (inSync) {\n // the spinner in hashes will have already printed that we're in sync\n return;\n }\n\n if (localChanges.size > 0) {\n printChanges(ctx, {\n changes: localChanges,\n tense: \"past\",\n title: sprint`Your local files {underline have} changed.`,\n });\n } else {\n println({ ensureEmptyLineAbove: true })`\n Your local files {underline have not} changed.\n `;\n }\n\n if (environmentChanges.size > 0 && !onlyDotGadgetFilesChanged) {\n printChanges(ctx, {\n changes: environmentChanges,\n tense: \"past\",\n title: sprint`Your environment's files {underline have}${bothChanged ? \" also\" : \"\"} changed.`,\n });\n } else {\n println({ ensureEmptyLineAbove: true })`\n Your environment's files {underline have not} changed.\n `;\n }\n }\n\n /**\n * Waits for all pending and ongoing filesync operations to complete.\n */\n async idle(): Promise<void> {\n await this._syncOperations.onIdle();\n }\n\n /**\n * Attempts to send file changes to the Gadget. If a files version\n * mismatch error occurs, this function will merge the changes with\n * Gadget instead.\n *\n * @param ctx - The context to use.\n * @param options - The options to use.\n * @param options.changes - The changes to send.\n * @param options.printLocalChangesOptions - The options to use when printing the local changes.\n * @param options.printEnvironmentChangesOptions - The options to use when printing the changes from Gadget.\n * @returns A promise that resolves when the changes have been sent.\n */\n async mergeChangesWithEnvironment(\n ctx: Context<DevArgs>,\n {\n changes,\n printLocalChangesOptions,\n printEnvironmentChangesOptions,\n }: {\n changes: Changes;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n await this._syncOperations.add(async () => {\n try {\n await this._sendChangesToEnvironment(ctx, { changes, printLocalChangesOptions });\n } catch (error) {\n swallowFilesVersionMismatch(ctx, error);\n // we either sent the wrong expectedFilesVersion or we received\n // a filesVersion that is greater than the expectedFilesVersion\n // + 1, so we need to stop what we're doing and get in sync\n await this.merge(ctx, { printEnvironmentChangesOptions });\n }\n });\n }\n\n /**\n * Subscribes to file changes on Gadget and executes the provided\n * callbacks before and after the changes occur.\n *\n * @param ctx - The context to use.\n * @param options - The options to use.\n * @param options.beforeChanges - A callback that is called before the changes occur.\n * @param options.afterChanges - A callback that is called after the changes occur.\n * @param options.onError - A callback that is called if an error occurs.\n * @param options.printEnvironmentChangesOptions - The options to use when printing the changes from Gadget.\n * @returns A function that unsubscribes from changes on Gadget.\n */\n subscribeToEnvironmentChanges(\n ctx: Context<DevArgs>,\n {\n beforeChanges = noop,\n printEnvironmentChangesOptions,\n afterChanges = noop,\n onError,\n }: {\n beforeChanges?: (data: { changed: string[]; deleted: string[] }) => Promisable<void>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n afterChanges?: (data: { changes: Changes }) => Promisable<void>;\n onError: (error: unknown) => void;\n },\n ): EditSubscription<REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION> {\n return this.syncJson.edit.subscribe({\n subscription: REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION,\n // the reason this is a function rather than a static value is\n // so that it will be re-evaluated if the connection is lost and\n // then re-established. this ensures that we send our current\n // filesVersion rather than the one that was sent when we first\n // subscribed\n variables: () => ({ localFilesVersion: String(this.syncJson.filesVersion) }),\n onError,\n onData: ({ remoteFileSyncEvents: { changed, deleted, remoteFilesVersion } }) => {\n this._syncOperations\n .add(async () => {\n if (BigInt(remoteFilesVersion) < this.syncJson.filesVersion) {\n ctx.log.warn(\"skipping received changes because files version is outdated\", { filesVersion: remoteFilesVersion });\n return;\n }\n\n ctx.log.debug(\"received files\", {\n remoteFilesVersion,\n changed: changed.map((change) => change.path),\n deleted: deleted.map((change) => change.path),\n });\n\n const filterIgnoredFiles = (file: { path: string }): boolean => {\n const ignored = this.syncJson.directory.ignores(file.path);\n if (ignored) {\n ctx.log.warn(\"skipping received change because file is ignored\", { path: file.path });\n }\n return !ignored;\n };\n\n changed = changed.filter(filterIgnoredFiles);\n deleted = deleted.filter(filterIgnoredFiles);\n\n if (changed.length === 0 && deleted.length === 0) {\n await this.syncJson.save(remoteFilesVersion);\n return;\n }\n\n await beforeChanges({\n changed: changed.map((file) => file.path),\n deleted: deleted.map((file) => file.path),\n });\n\n const changes = await this._writeToLocalFilesystem(ctx, {\n filesVersion: remoteFilesVersion,\n files: changed,\n delete: deleted.map((file) => file.path),\n printEnvironmentChangesOptions: {\n tense: \"past\",\n ensureEmptyLineAbove: true,\n title: sprintln`{green ${symbol.tick}} Pulled ${pluralize(\"file\", changed.length + deleted.length)}. ${symbol.arrowLeft} ${ts()}`,\n limit: 5,\n ...printEnvironmentChangesOptions,\n },\n });\n\n await afterChanges({ changes });\n })\n .catch(onError);\n },\n });\n }\n\n /**\n * Ensures the local filesystem is in sync with Gadget's filesystem.\n * - All non-conflicting changes are automatically merged.\n * - Conflicts are resolved by prompting the user to either keep their local changes or keep Gadget's changes.\n * - This function will not return until the filesystem is in sync.\n */\n async merge(\n ctx: Context<DevArgs>,\n {\n hashes,\n maxAttempts = 10,\n printLocalChangesOptions,\n printEnvironmentChangesOptions,\n }: {\n hashes?: FileSyncHashes;\n maxAttempts?: number;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n } = {},\n ): Promise<void> {\n let attempt = 0;\n\n do {\n if (attempt === 0) {\n hashes ??= await this.hashes(ctx);\n } else {\n hashes = await this.hashes(ctx);\n }\n\n if (hashes.inSync) {\n this._syncOperations.clear();\n ctx.log.info(\"filesystem in sync\");\n await this.syncJson.save(hashes.environmentFilesVersion);\n return;\n }\n\n attempt += 1;\n ctx.log.info(\"merging\", { attempt, ...hashes });\n\n try {\n await this._merge(ctx, { hashes, printLocalChangesOptions, printEnvironmentChangesOptions });\n } catch (error) {\n swallowFilesVersionMismatch(ctx, error);\n // we either sent the wrong expectedFilesVersion or we received\n // a filesVersion that is greater than the expectedFilesVersion\n // + 1, so try again\n }\n } while (attempt < maxAttempts);\n\n throw new TooManyMergeAttemptsError(maxAttempts);\n }\n\n /**\n * Pushes any changes made to the local filesystem since the last sync\n * to Gadget.\n *\n * If Gadget has also made changes since the last sync, and --force\n * was not passed, the user will be prompted to discard them.\n */\n async push(\n ctx: Context<PullArgs>,\n {\n hashes,\n force,\n printLocalChangesOptions,\n }: {\n hashes?: FileSyncHashes;\n force?: boolean;\n printLocalChangesOptions?: PrintChangesOptions;\n } = {},\n ): Promise<void> {\n const { localChangesToPush, environmentChanges, environmentFilesVersion, onlyDotGadgetFilesChanged } =\n hashes ?? (await this.hashes(ctx));\n assert(localChangesToPush.size > 0, \"cannot push if there are no changes\");\n\n // TODO: lift this check up to the push command\n if (\n // they didn't pass --force\n !(force ?? ctx.args[\"--force\"]) &&\n // their environment's files have changed\n environmentChanges.size > 0 &&\n // some of the changes aren't .gadget/ files\n !onlyDotGadgetFilesChanged\n ) {\n await confirm({ ensureEmptyLineAbove: true })`\n Are you sure you want to {underline discard} your environment's changes?\n `;\n }\n\n try {\n await this._sendChangesToEnvironment(ctx, {\n // what changes need to be made to your local files to make\n // them match the environment's files\n changes: localChangesToPush,\n expectedFilesVersion: environmentFilesVersion,\n printLocalChangesOptions,\n });\n } catch (error) {\n swallowFilesVersionMismatch(ctx, error);\n // we were told to push their local changes, but their\n // environment's files have changed since we last checked, so\n // throw a nicer error message\n // TODO: we don't have to do this if only .gadget/ files changed\n throw new EdgeCaseError(sprint`\n Your environment's files have changed since we last checked.\n\n Please re-run \"ggt ${ctx.command}\" to see the changes and try again.\n `);\n }\n }\n\n async pull(\n ctx: Context<PullArgs>,\n {\n hashes,\n force,\n printEnvironmentChangesOptions,\n }: {\n hashes?: FileSyncHashes;\n force?: boolean;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n } = {},\n ): Promise<void> {\n const { localChanges, environmentChangesToPull, environmentFilesVersion } = hashes ?? (await this.hashes(ctx));\n assert(environmentChangesToPull.size > 0, \"cannot push if there are no changes\");\n\n // TODO: lift this check up to the pull command\n if (localChanges.size > 0 && !(force ?? ctx.args[\"--force\"])) {\n await confirm`\n Are you sure you want to {underline discard} your local changes?\n `;\n }\n\n await this._getChangesFromEnvironment(ctx, {\n changes: environmentChangesToPull,\n filesVersion: environmentFilesVersion,\n printEnvironmentChangesOptions,\n });\n }\n\n private async _merge(\n ctx: Context<DevArgs>,\n {\n hashes: { localChanges, environmentChanges, environmentFilesVersion },\n printLocalChangesOptions,\n printEnvironmentChangesOptions,\n }: {\n hashes: FileSyncHashes;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n const conflicts = getConflicts({ localChanges, environmentChanges });\n if (conflicts.size > 0) {\n ctx.log.debug(\"conflicts detected\", { conflicts });\n\n let preference = ctx.args[\"--prefer\"];\n if (!preference) {\n printConflicts({ conflicts });\n preference = await select({ choices: Object.values(MergeConflictPreference) })`\n {bold How should we resolve these conflicts?}\n `;\n }\n\n switch (preference) {\n case MergeConflictPreference.CANCEL: {\n process.exit(0);\n break;\n }\n case MergeConflictPreference.LOCAL: {\n environmentChanges = withoutConflictingChanges({ conflicts, changes: environmentChanges });\n break;\n }\n case MergeConflictPreference.ENVIRONMENT: {\n localChanges = withoutConflictingChanges({ conflicts, changes: localChanges });\n break;\n }\n }\n }\n\n if (environmentChanges.size > 0) {\n await this._getChangesFromEnvironment(ctx, {\n changes: environmentChanges,\n filesVersion: environmentFilesVersion,\n printEnvironmentChangesOptions,\n });\n }\n\n if (localChanges.size > 0) {\n await this._sendChangesToEnvironment(ctx, {\n changes: localChanges,\n expectedFilesVersion: environmentFilesVersion,\n printLocalChangesOptions,\n });\n }\n }\n\n private async _getChangesFromEnvironment(\n ctx: Context<SyncJsonArgs>,\n {\n filesVersion,\n changes,\n printEnvironmentChangesOptions,\n }: {\n filesVersion: bigint;\n changes: Changes | ChangesWithHash;\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n ctx.log.debug(\"getting changes from gadget\", { filesVersion, changes });\n const created = changes.created();\n const updated = changes.updated();\n\n const spinner = spin({ ensureEmptyLineAbove: true })(\n sprintChanges(ctx, {\n changes,\n tense: \"present\",\n title: sprint`Pulling ${pluralize(\"file\", changes.size)}. ${symbol.arrowLeft}`,\n ...printEnvironmentChangesOptions,\n }),\n );\n\n try {\n let files: File[] = [];\n if (created.length > 0 || updated.length > 0) {\n const { fileSyncFiles } = await this.syncJson.edit.query({\n query: FILE_SYNC_FILES_QUERY,\n variables: {\n paths: [...created, ...updated],\n filesVersion: String(filesVersion),\n encoding: FileSyncEncoding.Base64,\n },\n });\n\n files = fileSyncFiles.files;\n }\n\n await this._writeToLocalFilesystem(ctx, {\n filesVersion,\n files,\n delete: changes.deleted(),\n spinner,\n printEnvironmentChangesOptions,\n });\n } catch (error) {\n spinner.fail();\n throw error;\n }\n }\n\n private async _sendChangesToEnvironment(\n ctx: Context<SyncJsonArgs>,\n {\n changes,\n expectedFilesVersion = this.syncJson.filesVersion,\n printLocalChangesOptions,\n }: {\n changes: Changes | ChangesWithHash;\n expectedFilesVersion?: bigint;\n printLocalChangesOptions?: Partial<PrintChangesOptions>;\n },\n ): Promise<void> {\n ctx.log.debug(\"sending changes to gadget\", { expectedFilesVersion, changes });\n const changed: FileSyncChangedEventInput[] = [];\n const deleted: FileSyncDeletedEventInput[] = [];\n\n await pMap(changes, async ([normalizedPath, change]) => {\n if (change.type === \"delete\") {\n deleted.push({ path: normalizedPath });\n return;\n }\n\n const absolutePath = this.syncJson.directory.absolute(normalizedPath);\n\n let stats;\n try {\n stats = await fs.stat(absolutePath);\n } catch (error) {\n swallowEnoent(error);\n ctx.log.debug(\"skipping change because file doesn't exist\", { path: normalizedPath });\n return;\n }\n\n let content = \"\";\n if (stats.isFile()) {\n content = await fs.readFile(absolutePath, FileSyncEncoding.Base64);\n }\n\n let oldPath;\n if (change.type === \"create\" && change.oldPath) {\n oldPath = change.oldPath;\n }\n\n changed.push({\n content,\n oldPath,\n path: normalizedPath,\n mode: stats.mode,\n encoding: FileSyncEncoding.Base64,\n });\n });\n\n if (changed.length === 0 && deleted.length === 0) {\n ctx.log.debug(\"skipping send because there are no changes\");\n return;\n }\n\n const contentLength = changed.map((change) => change.content.length).reduce((a, b) => a + b, 0);\n if (contentLength > MAX_PUSH_CONTENT_LENGTH) {\n throw new EdgeCaseError(sprint`\n {underline Your file changes are too large to push.}\n\n Run \"ggt status\" to see your changes and consider\n ignoring some files or pushing in smaller batches.\n `);\n }\n\n const spinner = spin({ ensureEmptyLineAbove: true })(\n sprintChanges(ctx, {\n changes,\n tense: \"present\",\n title: sprintln`Pushing ${pluralize(\"file\", changed.length + deleted.length)}. ${symbol.arrowRight}`,\n ...printLocalChangesOptions,\n }),\n );\n\n try {\n const {\n publishFileSyncEvents: { remoteFilesVersion, problems: filesyncProblems },\n } = await this.syncJson.edit.mutate({\n mutation: PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n variables: {\n input: {\n expectedRemoteFilesVersion: String(expectedFilesVersion),\n changed,\n deleted,\n },\n },\n http: {\n retry: {\n // we can retry this request because\n // expectedRemoteFilesVersion makes it idempotent\n methods: [\"POST\"],\n calculateDelay: ({ error, computedValue }) => {\n if (isFilesVersionMismatchError(error.response?.body)) {\n // don't retry if we get a files version mismatch error\n return 0;\n }\n return computedValue;\n },\n },\n },\n });\n\n if (BigInt(remoteFilesVersion) > expectedFilesVersion + 1n) {\n // we can't save the remoteFilesVersion because we haven't\n // received the intermediate filesVersions yet\n throw new Error(\"Files version mismatch\");\n }\n\n await this.syncJson.save(remoteFilesVersion);\n\n spinner.succeed(\n sprintChanges(ctx, {\n changes,\n tense: \"past\",\n title: sprintln`Pushed ${pluralize(\"file\", changed.length + deleted.length)}. ${symbol.arrowRight} ${ts()}`,\n ...printLocalChangesOptions,\n }),\n );\n\n if (filesyncProblems.length > 0) {\n println({ ensureEmptyLineAbove: true })`\n {red Gadget has detected the following fatal errors with your files:}\n\n ${sprintProblems({\n problems: filesyncProblemsToProblems(filesyncProblems),\n showFileTypes: false,\n indent: 10,\n })}\n\n {red Your app will not be operational until all fatal errors are fixed.}\n `;\n }\n } catch (error) {\n if (isFilesVersionMismatchError(error)) {\n spinner.clear();\n } else {\n spinner.fail();\n }\n\n throw error;\n }\n }\n\n private async _writeToLocalFilesystem(\n ctx: Context<SyncJsonArgs>,\n options: {\n filesVersion: bigint | string;\n files: File[];\n delete: string[];\n printEnvironmentChangesOptions?: Partial<PrintChangesOptions>;\n spinner?: spinner;\n },\n ): Promise<Changes> {\n const filesVersion = BigInt(options.filesVersion);\n assert(filesVersion >= this.syncJson.filesVersion, \"filesVersion must be greater than or equal to current filesVersion\");\n\n ctx.log.debug(\"writing to local filesystem\", {\n filesVersion,\n files: options.files.map((file) => file.path),\n delete: options.delete,\n });\n\n const changes = new Changes();\n const directoriesWithDeletedFiles = new Set<string>();\n\n await pMap(options.delete, async (pathToDelete) => {\n // add all the directories that contain this file to\n // directoriesWithDeletedFiles so we can clean them up later\n let dir = path.dirname(pathToDelete);\n while (dir !== \".\") {\n directoriesWithDeletedFiles.add(this.syncJson.directory.normalize(dir, true));\n dir = path.dirname(dir);\n }\n\n const currentPath = this.syncJson.directory.absolute(pathToDelete);\n const backupPath = this.syncJson.directory.absolute(\".gadget/backup\", this.syncJson.directory.relative(pathToDelete));\n\n // rather than `rm -rf`ing files, we move them to\n // `.gadget/backup/` so that users can recover them if something\n // goes wrong. We've seen a lot of EBUSY/EINVAL errors when moving\n // files so we retry a few times.\n await pRetry(\n async () => {\n try {\n // remove the current backup file in case it exists and is a\n // different type (file vs directory)\n await fs.remove(backupPath);\n await fs.move(currentPath, backupPath);\n changes.set(pathToDelete, { type: \"delete\" });\n } catch (error) {\n if (isENOENTError(error)) {\n // replicate the behavior of `rm -rf` and ignore ENOENT\n return;\n }\n\n if (isENOTDIRError(error) || isEEXISTError(error)) {\n // the backup path already exists and ends in a file\n // rather than a directory, so we have to remove the file\n // before we can move the current path to the backup path\n let dir = path.dirname(backupPath);\n while (dir !== this.syncJson.directory.absolute(\".gadget/backup\")) {\n const stats = await fs.stat(dir);\n // eslint-disable-next-line max-depth\n if (!stats.isDirectory()) {\n // this file is in the way, so remove it\n ctx.log.debug(\"removing file in the way of backup path\", { currentPath, backupPath, file: dir });\n await fs.remove(dir);\n }\n dir = path.dirname(dir);\n }\n // still throw the error so we retry\n }\n\n throw error;\n }\n },\n {\n // windows tends to run into these issues way more often than\n // mac/linux, so we retry more times\n retries: config.windows ? 4 : 2,\n minTimeout: ms(\"100ms\"),\n onFailedAttempt: (error) => {\n ctx.log.warn(\"failed to move file to backup\", { error, currentPath, backupPath });\n },\n },\n );\n });\n\n for (const directoryWithDeletedFile of Array.from(directoriesWithDeletedFiles.values()).sort().reverse()) {\n if (options.files.some((file) => file.path === directoryWithDeletedFile)) {\n // we're about to create this directory, so we don't need to\n // clean it up\n continue;\n }\n\n try {\n // delete any empty directories that contained a deleted file.\n // if the empty directory should continue to exist, we would\n // have received an event to create it above\n await fs.rmdir(this.syncJson.directory.absolute(directoryWithDeletedFile));\n changes.set(directoryWithDeletedFile, { type: \"delete\" });\n } catch (error) {\n if (isENOENTError(error) || isENOTEMPTYError(error)) {\n // noop if the directory doesn't exist or isn't empty\n continue;\n }\n throw error;\n }\n }\n\n await pMap(options.files, async (file) => {\n const absolutePath = this.syncJson.directory.absolute(file.path);\n if (await fs.pathExists(absolutePath)) {\n if (!file.path.endsWith(\"/\")) {\n // only track file updates, not directory updates\n changes.set(file.path, { type: \"update\" });\n }\n } else {\n changes.set(file.path, { type: \"create\" });\n }\n\n if (file.path.endsWith(\"/\")) {\n await fs.ensureDir(absolutePath);\n } else {\n await fs.outputFile(absolutePath, Buffer.from(file.content, file.encoding));\n }\n\n if (supportsPermissions) {\n // the os's default umask makes setting the mode during creation\n // not work, so an additional fs.chmod call is necessary to\n // ensure the file has the correct mode\n await fs.chmod(absolutePath, file.mode & 0o777);\n }\n\n if (absolutePath === this.syncJson.directory.absolute(\".ignore\")) {\n await this.syncJson.directory.loadIgnoreFile();\n }\n });\n\n await this.syncJson.save(String(filesVersion));\n\n options.spinner?.clear();\n\n printChanges(ctx, {\n changes,\n tense: \"past\",\n title: sprint`{green ${symbol.tick}} Pulled ${pluralize(\"file\", changes.size)}. ${symbol.arrowLeft} ${ts()}`,\n ...options.printEnvironmentChangesOptions,\n });\n\n if (changes.has(\"yarn.lock\")) {\n const spinner = spin({ ensureEmptyLineAbove: true })('Running \"yarn install --check-files\"');\n\n try {\n await execa(\"yarn\", [\"install\", \"--check-files\"], { cwd: this.syncJson.directory.path });\n spinner.succeed`Ran \"yarn install --check-files\" ${ts()}`;\n } catch (error) {\n spinner.fail();\n ctx.log.error(\"yarn install failed\", { error });\n\n const message = serializeError(error).message;\n if (message) {\n println({ ensureEmptyLineAbove: true, indent: 2 })(message);\n }\n }\n }\n\n return changes;\n }\n}\n"],"names":["execa","fs","ms","assert","path","process","pMap","PQueue","pRetry","pluralize","FileSyncEncoding","FILE_SYNC_COMPARISON_HASHES_QUERY","FILE_SYNC_FILES_QUERY","FILE_SYNC_HASHES_QUERY","PUBLISH_FILE_SYNC_EVENTS_MUTATION","REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION","config","confirm","println","filesyncProblemsToProblems","sprintProblems","EdgeCaseError","select","spin","sprint","sprintln","symbol","ts","noop","isEEXISTError","isENOENTError","isENOTDIRError","isENOTEMPTYError","serializeError","Changes","printChanges","sprintChanges","getConflicts","printConflicts","withoutConflictingChanges","supportsPermissions","swallowEnoent","TooManyMergeAttemptsError","isFilesVersionMismatchError","swallowFilesVersionMismatch","getNecessaryChanges","isEqualHashes","MergeConflictPreference","MAX_MERGE_ATTEMPTS","MAX_PUSH_CONTENT_LENGTH","FileSync","hashes","ctx","spinner","ensureEmptyLineAbove","localHashes","localFilesVersionHashes","environmentHashes","environmentFilesVersion","Promise","all","syncJson","directory","filesVersion","fileSyncHashes","edit","query","BigInt","fileSyncComparisonHashes","variables","String","filesVersionHashes","latestFilesVersionHashes","inSync","localChanges","from","to","existing","ignore","environmentChanges","size","Array","keys","every","startsWith","localChangesToPush","environmentChangesToPull","onlyDotGadgetFilesChanged","filepath","bothChanged","succeed","error","fail","print","changes","tense","title","idle","_syncOperations","onIdle","mergeChangesWithEnvironment","printLocalChangesOptions","printEnvironmentChangesOptions","add","_sendChangesToEnvironment","merge","subscribeToEnvironmentChanges","beforeChanges","afterChanges","onError","subscribe","subscription","localFilesVersion","onData","remoteFileSyncEvents","changed","deleted","remoteFilesVersion","log","warn","debug","map","change","filterIgnoredFiles","file","ignored","ignores","filter","length","save","_writeToLocalFilesystem","files","delete","tick","arrowLeft","limit","catch","maxAttempts","attempt","clear","info","_merge","push","force","args","expectedFilesVersion","command","pull","_getChangesFromEnvironment","conflicts","preference","choices","Object","values","CANCEL","exit","LOCAL","ENVIRONMENT","created","updated","fileSyncFiles","paths","encoding","Base64","normalizedPath","type","absolutePath","absolute","stats","stat","content","isFile","readFile","oldPath","mode","contentLength","reduce","a","b","arrowRight","publishFileSyncEvents","problems","filesyncProblems","mutate","mutation","input","expectedRemoteFilesVersion","http","retry","methods","calculateDelay","computedValue","response","body","Error","showFileTypes","indent","options","directoriesWithDeletedFiles","Set","pathToDelete","dir","dirname","normalize","currentPath","backupPath","relative","remove","move","set","isDirectory","retries","windows","minTimeout","onFailedAttempt","directoryWithDeletedFile","sort","reverse","some","rmdir","pathExists","endsWith","ensureDir","outputFile","Buffer","chmod","loadIgnoreFile","has","cwd","message","constructor","concurrency"],"mappings":"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"}
@@ -77,7 +77,7 @@ export const installErrorHandlers = (ctx)=>{
77
77
  ctx.log.debug("installing error handlers");
78
78
  Sentry.init({
79
79
  dsn: "https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266",
80
- enabled: env.productionLike && ctx.args["--telemetry"],
80
+ enabled: env.productionLike && (ctx.args["--telemetry"] ?? false),
81
81
  release: packageJson.version,
82
82
  environment: packageJson.version.includes("experimental") ? "experimental" : "production"
83
83
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/output/report.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport cleanStack from \"clean-stack\";\nimport ms from \"ms\";\nimport { randomUUID } from \"node:crypto\";\nimport os from \"node:os\";\nimport terminalLink from \"terminal-link\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { env } from \"../config/env.js\";\nimport { packageJson } from \"../config/package-json.js\";\nimport { isAbortError } from \"../util/is.js\";\nimport { serializeError } from \"../util/object.js\";\nimport { workspaceRoot } from \"../util/paths.js\";\nimport { println } from \"./print.js\";\nimport { sprintln, type SprintOptions } from \"./sprint.js\";\n\nexport const reportErrorAndExit = async (ctx: Context, cause: unknown): Promise<never> => {\n if (isAbortError(cause)) {\n ctx.log.debug(\"aborting without reporting error\", { error: cause });\n return process.exit(1);\n }\n\n ctx.log.error(\"reporting error and exiting\", { error: cause });\n\n try {\n const error = GGTError.from(cause);\n error.print();\n\n if (error.isBug === IsBug.NO) {\n return undefined as never;\n }\n\n Sentry.captureException(error, {\n event_id: error.id,\n captureContext: {\n user: ctx.user && {\n id: String(ctx.user.id),\n email: ctx.user.email,\n username: ctx.user.name ?? undefined,\n },\n tags: {\n application_id: ctx.app?.id,\n arch: config.arch,\n bug: error.isBug,\n environment: env.value,\n platform: config.platform,\n shell: config.shell,\n version: packageJson.version,\n },\n contexts: {\n ctx: {\n argv: process.argv,\n args: ctx.args,\n },\n cause: error.cause ? serializeError(error.cause) : undefined,\n app: {\n app_name: packageJson.name,\n app_version: packageJson.version,\n },\n device: {\n name: os.hostname(),\n family: os.type(),\n arch: os.arch(),\n },\n runtime: {\n name: process.release.name,\n version: process.version,\n },\n },\n },\n });\n\n await Sentry.flush(ms(\"2s\"));\n } finally {\n process.exit(1);\n }\n};\n\nexport const installErrorHandlers = (ctx: Context): void => {\n ctx.log.debug(\"installing error handlers\");\n\n Sentry.init({\n dsn: \"https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266\",\n enabled: env.productionLike && ctx.args[\"--telemetry\"],\n release: packageJson.version,\n environment: packageJson.version.includes(\"experimental\") ? \"experimental\" : \"production\",\n });\n\n const handleError = (error: unknown) => void reportErrorAndExit(ctx, error);\n process.once(\"uncaughtException\", handleError);\n process.once(\"unhandledRejection\", handleError);\n};\n\nexport const IsBug = Object.freeze({\n YES: \"yes\",\n NO: \"no\",\n MAYBE: \"maybe\",\n});\n\nexport type IsBug = (typeof IsBug)[keyof typeof IsBug];\n\n/**\n * Base class for all errors.\n */\nexport abstract class GGTError extends Error {\n /**\n * The ID for this error.\n */\n id = env.testLike ? \"00000000-0000-0000-0000-000000000000\" : randomUUID();\n\n /**\n * The underlying *thing* that caused this error.\n */\n cause?: unknown;\n\n /**\n * Assume the stack trace exists.\n */\n override stack!: string;\n\n /**\n * Indicates whether this error is considered a bug or not.\n */\n abstract isBug: IsBug;\n\n constructor(message: string) {\n super(message);\n Error.captureStackTrace(this, this.constructor);\n this.stack = cleanStack(this.stack, { pretty: true, basePath: workspaceRoot });\n }\n\n /**\n * Constructs a GGTError from an unknown cause.\n *\n * @param cause - The cause of the error.\n */\n static from(cause: unknown): GGTError {\n if (cause instanceof GGTError) {\n return cause;\n }\n return new UnexpectedError(cause);\n }\n\n sprint(): string {\n let rendered = this.render();\n\n if (this.isBug !== IsBug.NO) {\n // ensure the rendered message ends with a newline\n rendered = sprintln(rendered);\n\n const thisIsABug = this.isBug === IsBug.YES ? \"This is a bug\" : \"If you think this is a bug\";\n const issueLink = `https://github.com/gadget-inc/ggt/issues/new?template=bug_report.yml&error-id=${this.id}`;\n\n if (terminalLink.isSupported) {\n rendered += sprintln({ ensureEmptyLineAbove: true })`\n ${thisIsABug}, ${terminalLink(\"click here\", issueLink)} to create an issue on GitHub.\n `;\n } else {\n rendered += sprintln({ ensureEmptyLineAbove: true })`\n ${thisIsABug}, use the link below to create an issue on GitHub.\n\n ${issueLink}\n `;\n }\n }\n\n return rendered;\n }\n\n print(options?: SprintOptions): void {\n println({ ensureEmptyLineAbove: true, ...options })(this.sprint());\n }\n\n /**\n * Turns this error into a user-friendly message that explains what\n * went wrong and how to fix it. A good write up of what an error\n * should look like can be found here:\n * {@link https://clig.dev/#errors}\n */\n protected abstract render(): string;\n}\n\n/**\n * Our \"catch all\" error.\n *\n * If this error is thrown, we almost certainly have a bug, and should\n * either fix it or add a more specific error so that we can provide\n * more useful information.\n */\nexport class UnexpectedError extends GGTError {\n isBug = IsBug.YES;\n\n constructor(override cause: unknown) {\n super(\"An unexpected error occurred\");\n }\n\n protected render(): string {\n const serialized = serializeError(this.cause);\n const body = serialized.stack || serialized.message || this.stack;\n return this.message + \".\\n\\n\" + body;\n }\n}\n\n/**\n * An error that is expected to happen sometimes.\n */\nexport class EdgeCaseError extends GGTError {\n isBug = IsBug.MAYBE;\n\n constructor(\n message: string,\n override cause?: unknown,\n ) {\n super(message);\n }\n\n protected render(): string {\n return this.message;\n }\n}\n"],"names":["Sentry","cleanStack","ms","randomUUID","os","terminalLink","config","env","packageJson","isAbortError","serializeError","workspaceRoot","println","sprintln","reportErrorAndExit","ctx","cause","log","debug","error","process","exit","GGTError","from","print","isBug","IsBug","NO","undefined","captureException","event_id","id","captureContext","user","String","email","username","name","tags","application_id","app","arch","bug","environment","value","platform","shell","version","contexts","argv","args","app_name","app_version","device","hostname","family","type","runtime","release","flush","installErrorHandlers","init","dsn","enabled","productionLike","includes","handleError","once","Object","freeze","YES","MAYBE","Error","UnexpectedError","sprint","rendered","render","thisIsABug","issueLink","isSupported","ensureEmptyLineAbove","options","constructor","message","testLike","stack","captureStackTrace","pretty","basePath","serialized","body","EdgeCaseError"],"mappings":";AAAA,YAAYA,YAAY,eAAe;AACvC,OAAOC,gBAAgB,cAAc;AACrC,OAAOC,QAAQ,KAAK;AACpB,SAASC,UAAU,QAAQ,cAAc;AACzC,OAAOC,QAAQ,UAAU;AACzB,OAAOC,kBAAkB,gBAAgB;AAEzC,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,GAAG,QAAQ,mBAAmB;AACvC,SAASC,WAAW,QAAQ,4BAA4B;AACxD,SAASC,YAAY,QAAQ,gBAAgB;AAC7C,SAASC,cAAc,QAAQ,oBAAoB;AACnD,SAASC,aAAa,QAAQ,mBAAmB;AACjD,SAASC,OAAO,QAAQ,aAAa;AACrC,SAASC,QAAQ,QAA4B,cAAc;AAE3D,OAAO,MAAMC,qBAAqB,OAAOC,KAAcC;IACrD,IAAIP,aAAaO,QAAQ;QACvBD,IAAIE,GAAG,CAACC,KAAK,CAAC,oCAAoC;YAAEC,OAAOH;QAAM;QACjE,OAAOI,QAAQC,IAAI,CAAC;IACtB;IAEAN,IAAIE,GAAG,CAACE,KAAK,CAAC,+BAA+B;QAAEA,OAAOH;IAAM;IAE5D,IAAI;QACF,MAAMG,QAAQG,SAASC,IAAI,CAACP;QAC5BG,MAAMK,KAAK;QAEX,IAAIL,MAAMM,KAAK,KAAKC,MAAMC,EAAE,EAAE;YAC5B,OAAOC;QACT;QAEA5B,OAAO6B,gBAAgB,CAACV,OAAO;YAC7BW,UAAUX,MAAMY,EAAE;YAClBC,gBAAgB;gBACdC,MAAMlB,IAAIkB,IAAI,IAAI;oBAChBF,IAAIG,OAAOnB,IAAIkB,IAAI,CAACF,EAAE;oBACtBI,OAAOpB,IAAIkB,IAAI,CAACE,KAAK;oBACrBC,UAAUrB,IAAIkB,IAAI,CAACI,IAAI,IAAIT;gBAC7B;gBACAU,MAAM;oBACJC,gBAAgBxB,IAAIyB,GAAG,EAAET;oBACzBU,MAAMnC,OAAOmC,IAAI;oBACjBC,KAAKvB,MAAMM,KAAK;oBAChBkB,aAAapC,IAAIqC,KAAK;oBACtBC,UAAUvC,OAAOuC,QAAQ;oBACzBC,OAAOxC,OAAOwC,KAAK;oBACnBC,SAASvC,YAAYuC,OAAO;gBAC9B;gBACAC,UAAU;oBACRjC,KAAK;wBACHkC,MAAM7B,QAAQ6B,IAAI;wBAClBC,MAAMnC,IAAImC,IAAI;oBAChB;oBACAlC,OAAOG,MAAMH,KAAK,GAAGN,eAAeS,MAAMH,KAAK,IAAIY;oBACnDY,KAAK;wBACHW,UAAU3C,YAAY6B,IAAI;wBAC1Be,aAAa5C,YAAYuC,OAAO;oBAClC;oBACAM,QAAQ;wBACNhB,MAAMjC,GAAGkD,QAAQ;wBACjBC,QAAQnD,GAAGoD,IAAI;wBACff,MAAMrC,GAAGqC,IAAI;oBACf;oBACAgB,SAAS;wBACPpB,MAAMjB,QAAQsC,OAAO,CAACrB,IAAI;wBAC1BU,SAAS3B,QAAQ2B,OAAO;oBAC1B;gBACF;YACF;QACF;QAEA,MAAM/C,OAAO2D,KAAK,CAACzD,GAAG;IACxB,SAAU;QACRkB,QAAQC,IAAI,CAAC;IACf;AACF,EAAE;AAEF,OAAO,MAAMuC,uBAAuB,CAAC7C;IACnCA,IAAIE,GAAG,CAACC,KAAK,CAAC;IAEdlB,OAAO6D,IAAI,CAAC;QACVC,KAAK;QACLC,SAASxD,IAAIyD,cAAc,IAAIjD,IAAImC,IAAI,CAAC,cAAc;QACtDQ,SAASlD,YAAYuC,OAAO;QAC5BJ,aAAanC,YAAYuC,OAAO,CAACkB,QAAQ,CAAC,kBAAkB,iBAAiB;IAC/E;IAEA,MAAMC,cAAc,CAAC/C,QAAmB,KAAKL,mBAAmBC,KAAKI;IACrEC,QAAQ+C,IAAI,CAAC,qBAAqBD;IAClC9C,QAAQ+C,IAAI,CAAC,sBAAsBD;AACrC,EAAE;AAEF,OAAO,MAAMxC,QAAQ0C,OAAOC,MAAM,CAAC;IACjCC,KAAK;IACL3C,IAAI;IACJ4C,OAAO;AACT,GAAG;AAIH;;CAEC,GACD,OAAO,MAAejD,iBAAiBkD;IA2BrC;;;;GAIC,GACD,OAAOjD,KAAKP,KAAc,EAAY;QACpC,IAAIA,iBAAiBM,UAAU;YAC7B,OAAON;QACT;QACA,OAAO,IAAIyD,gBAAgBzD;IAC7B;IAEA0D,SAAiB;QACf,IAAIC,WAAW,IAAI,CAACC,MAAM;QAE1B,IAAI,IAAI,CAACnD,KAAK,KAAKC,MAAMC,EAAE,EAAE;YAC3B,kDAAkD;YAClDgD,WAAW9D,SAAS8D;YAEpB,MAAME,aAAa,IAAI,CAACpD,KAAK,KAAKC,MAAM4C,GAAG,GAAG,kBAAkB;YAChE,MAAMQ,YAAY,CAAC,8EAA8E,EAAE,IAAI,CAAC/C,EAAE,CAAC,CAAC;YAE5G,IAAI1B,aAAa0E,WAAW,EAAE;gBAC5BJ,YAAY9D,SAAS;oBAAEmE,sBAAsB;gBAAK,EAAE,CAAC;UACnD,EAAEH,WAAW,EAAE,EAAExE,aAAa,cAAcyE,WAAW;QACzD,CAAC;YACH,OAAO;gBACLH,YAAY9D,SAAS;oBAAEmE,sBAAsB;gBAAK,EAAE,CAAC;UACnD,EAAEH,WAAW;;UAEb,EAAEC,UAAU;QACd,CAAC;YACH;QACF;QAEA,OAAOH;IACT;IAEAnD,MAAMyD,OAAuB,EAAQ;QACnCrE,QAAQ;YAAEoE,sBAAsB;YAAM,GAAGC,OAAO;QAAC,GAAG,IAAI,CAACP,MAAM;IACjE;IA9CAQ,YAAYC,OAAe,CAAE;QAC3B,KAAK,CAACA;QArBR;;GAEC,GACDpD,uBAAAA,MAAKxB,IAAI6E,QAAQ,GAAG,yCAAyCjF;QAE7D;;GAEC,GACDa,uBAAAA,SAAAA,KAAAA;QAEA;;GAEC,GACD,uBAASqE,SAAT,KAAA;QASEb,MAAMc,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAACJ,WAAW;QAC9C,IAAI,CAACG,KAAK,GAAGpF,WAAW,IAAI,CAACoF,KAAK,EAAE;YAAEE,QAAQ;YAAMC,UAAU7E;QAAc;IAC9E;AAmDF;AAEA;;;;;;CAMC,GACD,OAAO,MAAM8D,wBAAwBnD;IAOzBsD,SAAiB;QACzB,MAAMa,aAAa/E,eAAe,IAAI,CAACM,KAAK;QAC5C,MAAM0E,OAAOD,WAAWJ,KAAK,IAAII,WAAWN,OAAO,IAAI,IAAI,CAACE,KAAK;QACjE,OAAO,IAAI,CAACF,OAAO,GAAG,UAAUO;IAClC;IARAR,YAAY,AAASlE,KAAc,CAAE;QACnC,KAAK,CAAC;;QAHRS,uBAAAA,SAAAA,KAAAA;aAEqBT,QAAAA;aAFrBS,QAAQC,MAAM4C,GAAG;IAIjB;AAOF;AAEA;;CAEC,GACD,OAAO,MAAMqB,sBAAsBrE;IAUvBsD,SAAiB;QACzB,OAAO,IAAI,CAACO,OAAO;IACrB;IATAD,YACEC,OAAe,EACf,AAASnE,KAAe,CACxB;QACA,KAAK,CAACmE;;QANR1D,uBAAAA,SAAAA,KAAAA;aAIWT,QAAAA;aAJXS,QAAQC,MAAM6C,KAAK;IAOnB;AAKF"}
1
+ {"version":3,"sources":["../../../src/services/output/report.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport cleanStack from \"clean-stack\";\nimport ms from \"ms\";\nimport { randomUUID } from \"node:crypto\";\nimport os from \"node:os\";\nimport terminalLink from \"terminal-link\";\nimport type { Context } from \"../command/context.js\";\nimport { config } from \"../config/config.js\";\nimport { env } from \"../config/env.js\";\nimport { packageJson } from \"../config/package-json.js\";\nimport { isAbortError } from \"../util/is.js\";\nimport { serializeError } from \"../util/object.js\";\nimport { workspaceRoot } from \"../util/paths.js\";\nimport { println } from \"./print.js\";\nimport { sprintln, type SprintOptions } from \"./sprint.js\";\n\nexport const reportErrorAndExit = async (ctx: Context, cause: unknown): Promise<never> => {\n if (isAbortError(cause)) {\n ctx.log.debug(\"aborting without reporting error\", { error: cause });\n return process.exit(1);\n }\n\n ctx.log.error(\"reporting error and exiting\", { error: cause });\n\n try {\n const error = GGTError.from(cause);\n error.print();\n\n if (error.isBug === IsBug.NO) {\n return undefined as never;\n }\n\n Sentry.captureException(error, {\n event_id: error.id,\n captureContext: {\n user: ctx.user && {\n id: String(ctx.user.id),\n email: ctx.user.email,\n username: ctx.user.name ?? undefined,\n },\n tags: {\n application_id: ctx.app?.id,\n arch: config.arch,\n bug: error.isBug,\n environment: env.value,\n platform: config.platform,\n shell: config.shell,\n version: packageJson.version,\n },\n contexts: {\n ctx: {\n argv: process.argv,\n args: ctx.args,\n },\n cause: error.cause ? serializeError(error.cause) : undefined,\n app: {\n app_name: packageJson.name,\n app_version: packageJson.version,\n },\n device: {\n name: os.hostname(),\n family: os.type(),\n arch: os.arch(),\n },\n runtime: {\n name: process.release.name,\n version: process.version,\n },\n },\n },\n });\n\n await Sentry.flush(ms(\"2s\"));\n } finally {\n process.exit(1);\n }\n};\n\nexport const installErrorHandlers = (ctx: Context): void => {\n ctx.log.debug(\"installing error handlers\");\n\n Sentry.init({\n dsn: \"https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266\",\n enabled: env.productionLike && (ctx.args[\"--telemetry\"] ?? false),\n release: packageJson.version,\n environment: packageJson.version.includes(\"experimental\") ? \"experimental\" : \"production\",\n });\n\n const handleError = (error: unknown) => void reportErrorAndExit(ctx, error);\n process.once(\"uncaughtException\", handleError);\n process.once(\"unhandledRejection\", handleError);\n};\n\nexport const IsBug = Object.freeze({\n YES: \"yes\",\n NO: \"no\",\n MAYBE: \"maybe\",\n});\n\nexport type IsBug = (typeof IsBug)[keyof typeof IsBug];\n\n/**\n * Base class for all errors.\n */\nexport abstract class GGTError extends Error {\n /**\n * The ID for this error.\n */\n id = env.testLike ? \"00000000-0000-0000-0000-000000000000\" : randomUUID();\n\n /**\n * The underlying *thing* that caused this error.\n */\n cause?: unknown;\n\n /**\n * Assume the stack trace exists.\n */\n override stack!: string;\n\n /**\n * Indicates whether this error is considered a bug or not.\n */\n abstract isBug: IsBug;\n\n constructor(message: string) {\n super(message);\n Error.captureStackTrace(this, this.constructor);\n this.stack = cleanStack(this.stack, { pretty: true, basePath: workspaceRoot });\n }\n\n /**\n * Constructs a GGTError from an unknown cause.\n *\n * @param cause - The cause of the error.\n */\n static from(cause: unknown): GGTError {\n if (cause instanceof GGTError) {\n return cause;\n }\n return new UnexpectedError(cause);\n }\n\n sprint(): string {\n let rendered = this.render();\n\n if (this.isBug !== IsBug.NO) {\n // ensure the rendered message ends with a newline\n rendered = sprintln(rendered);\n\n const thisIsABug = this.isBug === IsBug.YES ? \"This is a bug\" : \"If you think this is a bug\";\n const issueLink = `https://github.com/gadget-inc/ggt/issues/new?template=bug_report.yml&error-id=${this.id}`;\n\n if (terminalLink.isSupported) {\n rendered += sprintln({ ensureEmptyLineAbove: true })`\n ${thisIsABug}, ${terminalLink(\"click here\", issueLink)} to create an issue on GitHub.\n `;\n } else {\n rendered += sprintln({ ensureEmptyLineAbove: true })`\n ${thisIsABug}, use the link below to create an issue on GitHub.\n\n ${issueLink}\n `;\n }\n }\n\n return rendered;\n }\n\n print(options?: SprintOptions): void {\n println({ ensureEmptyLineAbove: true, ...options })(this.sprint());\n }\n\n /**\n * Turns this error into a user-friendly message that explains what\n * went wrong and how to fix it. A good write up of what an error\n * should look like can be found here:\n * {@link https://clig.dev/#errors}\n */\n protected abstract render(): string;\n}\n\n/**\n * Our \"catch all\" error.\n *\n * If this error is thrown, we almost certainly have a bug, and should\n * either fix it or add a more specific error so that we can provide\n * more useful information.\n */\nexport class UnexpectedError extends GGTError {\n isBug = IsBug.YES;\n\n constructor(override cause: unknown) {\n super(\"An unexpected error occurred\");\n }\n\n protected render(): string {\n const serialized = serializeError(this.cause);\n const body = serialized.stack || serialized.message || this.stack;\n return this.message + \".\\n\\n\" + body;\n }\n}\n\n/**\n * An error that is expected to happen sometimes.\n */\nexport class EdgeCaseError extends GGTError {\n isBug = IsBug.MAYBE;\n\n constructor(\n message: string,\n override cause?: unknown,\n ) {\n super(message);\n }\n\n protected render(): string {\n return this.message;\n }\n}\n"],"names":["Sentry","cleanStack","ms","randomUUID","os","terminalLink","config","env","packageJson","isAbortError","serializeError","workspaceRoot","println","sprintln","reportErrorAndExit","ctx","cause","log","debug","error","process","exit","GGTError","from","print","isBug","IsBug","NO","undefined","captureException","event_id","id","captureContext","user","String","email","username","name","tags","application_id","app","arch","bug","environment","value","platform","shell","version","contexts","argv","args","app_name","app_version","device","hostname","family","type","runtime","release","flush","installErrorHandlers","init","dsn","enabled","productionLike","includes","handleError","once","Object","freeze","YES","MAYBE","Error","UnexpectedError","sprint","rendered","render","thisIsABug","issueLink","isSupported","ensureEmptyLineAbove","options","constructor","message","testLike","stack","captureStackTrace","pretty","basePath","serialized","body","EdgeCaseError"],"mappings":"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"}
@@ -62,6 +62,18 @@ export const isNever = (value)=>{
62
62
  export const isAbortError = (error)=>{
63
63
  return error instanceof Error && error.name === "AbortError" || error instanceof Event && error.type === "abort";
64
64
  };
65
+ export const isENOENTError = (error)=>{
66
+ return isObject(error) && "code" in error && error.code === "ENOENT";
67
+ };
68
+ export const isENOTEMPTYError = (error)=>{
69
+ return isObject(error) && "code" in error && error.code === "ENOTEMPTY";
70
+ };
71
+ export const isENOTDIRError = (error)=>{
72
+ return isObject(error) && "code" in error && error.code === "ENOTDIR";
73
+ };
74
+ export const isEEXISTError = (error)=>{
75
+ return isObject(error) && "code" in error && error.code === "EEXIST";
76
+ };
65
77
  export const isJavaScriptFile = (filepath)=>{
66
78
  return [
67
79
  ".js",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/util/is.ts"],"sourcesContent":["import type { ExecutionResult, GraphQLError } from \"graphql\";\nimport type { SetOptional } from \"type-fest\";\nimport type { CloseEvent, ErrorEvent } from \"ws\";\nimport { z } from \"zod\";\n\nexport const isNil = (val: unknown): val is null | undefined => {\n return val === null || val === undefined;\n};\n\nexport const isString = (val: unknown): val is string => {\n return typeof val === \"string\";\n};\n\nexport const isObject = (val: unknown): val is object => {\n return typeof val === \"object\" && val !== null;\n};\n\nexport const isArray = Array.isArray;\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport const isFunction = (val: unknown): val is Function => {\n return typeof val === \"function\";\n};\n\nexport const isError = (val: unknown): val is Error => {\n return val instanceof Error;\n};\n\nexport const isCloseEvent = (e: unknown): e is SetOptional<CloseEvent, \"target\"> => {\n return z.object({ type: z.string(), code: z.number(), reason: z.string(), wasClean: z.boolean() }).safeParse(e).success;\n};\n\nexport const isErrorEvent = (e: unknown): e is SetOptional<ErrorEvent, \"target\"> => {\n return z.object({ type: z.string(), message: z.string(), error: z.any() }).safeParse(e).success;\n};\n\nexport const isGraphQLResult = (val: unknown): val is ExecutionResult => {\n return z\n .union([\n z.object({ data: z.record(z.unknown()) }),\n z.object({ errors: z.array(z.object({ message: z.string() })) }),\n z.object({\n data: z.record(z.unknown()),\n errors: z.array(z.object({ message: z.string() })),\n }),\n ])\n .safeParse(val).success;\n};\n\nexport const isGraphQLErrors = (e: unknown): e is readonly GraphQLError[] => {\n return z\n .array(\n z.object({\n message: z.string(),\n extensions: z\n .record(z.unknown())\n .nullish()\n .transform((ext) => ext ?? {}),\n }),\n )\n .min(1)\n .safeParse(e).success;\n};\n\nexport const isNever = (value: never): never => {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unexpected value: ${value}`);\n};\n\nexport const isAbortError = (error: unknown): error is Error | Event => {\n return (error instanceof Error && error.name === \"AbortError\") || (error instanceof Event && error.type === \"abort\");\n};\n\nexport const isJavaScriptFile = (filepath: string): boolean => {\n return [\".js\", \".jsx\", \".cjs\", \".mjs\"].some((ext) => filepath.endsWith(ext));\n};\n\nexport const isTypeScriptFile = (filepath: string): boolean => {\n return [\".ts\", \".tsx\", \".cts\", \".mts\"].some((ext) => filepath.endsWith(ext) && !filepath.endsWith(\".d.ts\"));\n};\n\nexport const isGellyFile = (filepath: string): boolean => {\n return filepath.endsWith(\".gelly\");\n};\n"],"names":["z","isNil","val","undefined","isString","isObject","isArray","Array","isFunction","isError","Error","isCloseEvent","e","object","type","string","code","number","reason","wasClean","boolean","safeParse","success","isErrorEvent","message","error","any","isGraphQLResult","union","data","record","unknown","errors","array","isGraphQLErrors","extensions","nullish","transform","ext","min","isNever","value","isAbortError","name","Event","isJavaScriptFile","filepath","some","endsWith","isTypeScriptFile","isGellyFile"],"mappings":"AAGA,SAASA,CAAC,QAAQ,MAAM;AAExB,OAAO,MAAMC,QAAQ,CAACC;IACpB,OAAOA,QAAQ,QAAQA,QAAQC;AACjC,EAAE;AAEF,OAAO,MAAMC,WAAW,CAACF;IACvB,OAAO,OAAOA,QAAQ;AACxB,EAAE;AAEF,OAAO,MAAMG,WAAW,CAACH;IACvB,OAAO,OAAOA,QAAQ,YAAYA,QAAQ;AAC5C,EAAE;AAEF,OAAO,MAAMI,UAAUC,MAAMD,OAAO,CAAC;AAErC,wDAAwD;AACxD,OAAO,MAAME,aAAa,CAACN;IACzB,OAAO,OAAOA,QAAQ;AACxB,EAAE;AAEF,OAAO,MAAMO,UAAU,CAACP;IACtB,OAAOA,eAAeQ;AACxB,EAAE;AAEF,OAAO,MAAMC,eAAe,CAACC;IAC3B,OAAOZ,EAAEa,MAAM,CAAC;QAAEC,MAAMd,EAAEe,MAAM;QAAIC,MAAMhB,EAAEiB,MAAM;QAAIC,QAAQlB,EAAEe,MAAM;QAAII,UAAUnB,EAAEoB,OAAO;IAAG,GAAGC,SAAS,CAACT,GAAGU,OAAO;AACzH,EAAE;AAEF,OAAO,MAAMC,eAAe,CAACX;IAC3B,OAAOZ,EAAEa,MAAM,CAAC;QAAEC,MAAMd,EAAEe,MAAM;QAAIS,SAASxB,EAAEe,MAAM;QAAIU,OAAOzB,EAAE0B,GAAG;IAAG,GAAGL,SAAS,CAACT,GAAGU,OAAO;AACjG,EAAE;AAEF,OAAO,MAAMK,kBAAkB,CAACzB;IAC9B,OAAOF,EACJ4B,KAAK,CAAC;QACL5B,EAAEa,MAAM,CAAC;YAAEgB,MAAM7B,EAAE8B,MAAM,CAAC9B,EAAE+B,OAAO;QAAI;QACvC/B,EAAEa,MAAM,CAAC;YAAEmB,QAAQhC,EAAEiC,KAAK,CAACjC,EAAEa,MAAM,CAAC;gBAAEW,SAASxB,EAAEe,MAAM;YAAG;QAAI;QAC9Df,EAAEa,MAAM,CAAC;YACPgB,MAAM7B,EAAE8B,MAAM,CAAC9B,EAAE+B,OAAO;YACxBC,QAAQhC,EAAEiC,KAAK,CAACjC,EAAEa,MAAM,CAAC;gBAAEW,SAASxB,EAAEe,MAAM;YAAG;QACjD;KACD,EACAM,SAAS,CAACnB,KAAKoB,OAAO;AAC3B,EAAE;AAEF,OAAO,MAAMY,kBAAkB,CAACtB;IAC9B,OAAOZ,EACJiC,KAAK,CACJjC,EAAEa,MAAM,CAAC;QACPW,SAASxB,EAAEe,MAAM;QACjBoB,YAAYnC,EACT8B,MAAM,CAAC9B,EAAE+B,OAAO,IAChBK,OAAO,GACPC,SAAS,CAAC,CAACC,MAAQA,OAAO,CAAC;IAChC,IAEDC,GAAG,CAAC,GACJlB,SAAS,CAACT,GAAGU,OAAO;AACzB,EAAE;AAEF,OAAO,MAAMkB,UAAU,CAACC;IACtB,4EAA4E;IAC5E,MAAM,IAAI/B,MAAM,CAAC,kBAAkB,EAAE+B,MAAM,CAAC;AAC9C,EAAE;AAEF,OAAO,MAAMC,eAAe,CAACjB;IAC3B,OAAO,AAACA,iBAAiBf,SAASe,MAAMkB,IAAI,KAAK,gBAAkBlB,iBAAiBmB,SAASnB,MAAMX,IAAI,KAAK;AAC9G,EAAE;AAEF,OAAO,MAAM+B,mBAAmB,CAACC;IAC/B,OAAO;QAAC;QAAO;QAAQ;QAAQ;KAAO,CAACC,IAAI,CAAC,CAACT,MAAQQ,SAASE,QAAQ,CAACV;AACzE,EAAE;AAEF,OAAO,MAAMW,mBAAmB,CAACH;IAC/B,OAAO;QAAC;QAAO;QAAQ;QAAQ;KAAO,CAACC,IAAI,CAAC,CAACT,MAAQQ,SAASE,QAAQ,CAACV,QAAQ,CAACQ,SAASE,QAAQ,CAAC;AACpG,EAAE;AAEF,OAAO,MAAME,cAAc,CAACJ;IAC1B,OAAOA,SAASE,QAAQ,CAAC;AAC3B,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/util/is.ts"],"sourcesContent":["import type { ExecutionResult, GraphQLError } from \"graphql\";\nimport type { SetOptional } from \"type-fest\";\nimport type { CloseEvent, ErrorEvent } from \"ws\";\nimport { z } from \"zod\";\n\nexport const isNil = (val: unknown): val is null | undefined => {\n return val === null || val === undefined;\n};\n\nexport const isString = (val: unknown): val is string => {\n return typeof val === \"string\";\n};\n\nexport const isObject = (val: unknown): val is object => {\n return typeof val === \"object\" && val !== null;\n};\n\nexport const isArray = Array.isArray;\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport const isFunction = (val: unknown): val is Function => {\n return typeof val === \"function\";\n};\n\nexport const isError = (val: unknown): val is Error => {\n return val instanceof Error;\n};\n\nexport const isCloseEvent = (e: unknown): e is SetOptional<CloseEvent, \"target\"> => {\n return z.object({ type: z.string(), code: z.number(), reason: z.string(), wasClean: z.boolean() }).safeParse(e).success;\n};\n\nexport const isErrorEvent = (e: unknown): e is SetOptional<ErrorEvent, \"target\"> => {\n return z.object({ type: z.string(), message: z.string(), error: z.any() }).safeParse(e).success;\n};\n\nexport const isGraphQLResult = (val: unknown): val is ExecutionResult => {\n return z\n .union([\n z.object({ data: z.record(z.unknown()) }),\n z.object({ errors: z.array(z.object({ message: z.string() })) }),\n z.object({\n data: z.record(z.unknown()),\n errors: z.array(z.object({ message: z.string() })),\n }),\n ])\n .safeParse(val).success;\n};\n\nexport const isGraphQLErrors = (e: unknown): e is readonly GraphQLError[] => {\n return z\n .array(\n z.object({\n message: z.string(),\n extensions: z\n .record(z.unknown())\n .nullish()\n .transform((ext) => ext ?? {}),\n }),\n )\n .min(1)\n .safeParse(e).success;\n};\n\nexport const isNever = (value: never): never => {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unexpected value: ${value}`);\n};\n\nexport const isAbortError = (error: unknown): error is Error | Event => {\n return (error instanceof Error && error.name === \"AbortError\") || (error instanceof Event && error.type === \"abort\");\n};\n\nexport const isENOENTError = (error: unknown): error is { code: \"ENOENT\" } => {\n return isObject(error) && \"code\" in error && error.code === \"ENOENT\";\n};\n\nexport const isENOTEMPTYError = (error: unknown): error is { code: \"ENOTEMPTY\" } => {\n return isObject(error) && \"code\" in error && error.code === \"ENOTEMPTY\";\n};\n\nexport const isENOTDIRError = (error: unknown): error is { code: \"ENOTDIR\" } => {\n return isObject(error) && \"code\" in error && error.code === \"ENOTDIR\";\n};\n\nexport const isEEXISTError = (error: unknown): error is { code: \"EEXIST\" } => {\n return isObject(error) && \"code\" in error && error.code === \"EEXIST\";\n};\n\nexport const isJavaScriptFile = (filepath: string): boolean => {\n return [\".js\", \".jsx\", \".cjs\", \".mjs\"].some((ext) => filepath.endsWith(ext));\n};\n\nexport const isTypeScriptFile = (filepath: string): boolean => {\n return [\".ts\", \".tsx\", \".cts\", \".mts\"].some((ext) => filepath.endsWith(ext) && !filepath.endsWith(\".d.ts\"));\n};\n\nexport const isGellyFile = (filepath: string): boolean => {\n return filepath.endsWith(\".gelly\");\n};\n"],"names":["z","isNil","val","undefined","isString","isObject","isArray","Array","isFunction","isError","Error","isCloseEvent","e","object","type","string","code","number","reason","wasClean","boolean","safeParse","success","isErrorEvent","message","error","any","isGraphQLResult","union","data","record","unknown","errors","array","isGraphQLErrors","extensions","nullish","transform","ext","min","isNever","value","isAbortError","name","Event","isENOENTError","isENOTEMPTYError","isENOTDIRError","isEEXISTError","isJavaScriptFile","filepath","some","endsWith","isTypeScriptFile","isGellyFile"],"mappings":"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"}