@gadgetinc/ggt 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -76
- package/bin/dev.js +4 -7
- package/lib/__generated__/graphql.js.map +1 -1
- package/lib/commands/deploy.js +227 -0
- package/lib/commands/deploy.js.map +1 -0
- package/lib/commands/list.js +20 -16
- package/lib/commands/list.js.map +1 -1
- package/lib/commands/login.js +22 -20
- package/lib/commands/login.js.map +1 -1
- package/lib/commands/logout.js +13 -9
- package/lib/commands/logout.js.map +1 -1
- package/lib/commands/root.js +89 -56
- package/lib/commands/root.js.map +1 -1
- package/lib/commands/sync.js +253 -496
- package/lib/commands/sync.js.map +1 -1
- package/lib/commands/version.js +21 -0
- package/lib/commands/version.js.map +1 -0
- package/lib/commands/whoami.js +15 -11
- package/lib/commands/whoami.js.map +1 -1
- package/lib/main.js +4 -10
- package/lib/main.js.map +1 -1
- package/lib/services/{app.js → app/app.js} +8 -3
- package/lib/services/app/app.js.map +1 -0
- package/lib/services/app/arg.js +28 -0
- package/lib/services/app/arg.js.map +1 -0
- package/lib/services/app/edit-graphql.js +389 -0
- package/lib/services/app/edit-graphql.js.map +1 -0
- package/lib/services/command/arg.js +53 -0
- package/lib/services/command/arg.js.map +1 -0
- package/lib/services/command/command.js +27 -0
- package/lib/services/command/command.js.map +1 -0
- package/lib/services/command/context.js +60 -0
- package/lib/services/command/context.js.map +1 -0
- package/lib/services/{config.js → config/config.js} +29 -31
- package/lib/services/config/config.js.map +1 -0
- package/lib/services/config/env.js +22 -0
- package/lib/services/config/env.js.map +1 -0
- package/lib/services/config/package-json.js +9 -0
- package/lib/services/config/package-json.js.map +1 -0
- package/lib/services/filesync/changes.js +97 -0
- package/lib/services/filesync/changes.js.map +1 -0
- package/lib/services/filesync/conflicts.js +137 -0
- package/lib/services/filesync/conflicts.js.map +1 -0
- package/lib/services/filesync/directory.js +253 -0
- package/lib/services/filesync/directory.js.map +1 -0
- package/lib/services/filesync/error.js +67 -0
- package/lib/services/filesync/error.js.map +1 -0
- package/lib/services/filesync/file.js +3 -0
- package/lib/services/filesync/file.js.map +1 -0
- package/lib/services/filesync/filesync.js +675 -0
- package/lib/services/filesync/filesync.js.map +1 -0
- package/lib/services/filesync/hashes.js +150 -0
- package/lib/services/filesync/hashes.js.map +1 -0
- package/lib/services/http/auth.js +41 -0
- package/lib/services/http/auth.js.map +1 -0
- package/lib/services/http/http.js +64 -0
- package/lib/services/http/http.js.map +1 -0
- package/lib/services/output/log/field.js +3 -0
- package/lib/services/output/log/field.js.map +1 -0
- package/lib/services/output/log/format/format.js +8 -0
- package/lib/services/output/log/format/format.js.map +1 -0
- package/lib/services/output/log/format/json.js +45 -0
- package/lib/services/output/log/format/json.js.map +1 -0
- package/lib/services/output/log/format/pretty.js +147 -0
- package/lib/services/output/log/format/pretty.js.map +1 -0
- package/lib/services/output/log/level.js +41 -0
- package/lib/services/output/log/level.js.map +1 -0
- package/lib/services/output/log/logger.js +40 -0
- package/lib/services/output/log/logger.js.map +1 -0
- package/lib/services/output/log/printer.js +120 -0
- package/lib/services/output/log/printer.js.map +1 -0
- package/lib/services/output/log/structured.js +52 -0
- package/lib/services/output/log/structured.js.map +1 -0
- package/lib/services/{notify.js → output/notify.js} +7 -6
- package/lib/services/output/notify.js.map +1 -0
- package/lib/services/output/prompt.js +52 -0
- package/lib/services/output/prompt.js.map +1 -0
- package/lib/services/output/report.js +162 -0
- package/lib/services/output/report.js.map +1 -0
- package/lib/services/output/sprint.js +21 -0
- package/lib/services/output/sprint.js.map +1 -0
- package/lib/services/output/stream.js +54 -0
- package/lib/services/output/stream.js.map +1 -0
- package/lib/services/{version.js → output/update.js} +24 -16
- package/lib/services/output/update.js.map +1 -0
- package/lib/services/user/session.js +50 -0
- package/lib/services/user/session.js.map +1 -0
- package/lib/services/{user.js → user/user.js} +23 -14
- package/lib/services/user/user.js.map +1 -0
- package/lib/services/util/boolean.js +15 -0
- package/lib/services/util/boolean.js.map +1 -0
- package/lib/services/util/collection.js +38 -0
- package/lib/services/util/collection.js.map +1 -0
- package/lib/services/util/function.js +97 -0
- package/lib/services/util/function.js.map +1 -0
- package/lib/services/{is.js → util/is.js} +7 -0
- package/lib/services/util/is.js.map +1 -0
- package/lib/services/util/number.js +27 -0
- package/lib/services/util/number.js.map +1 -0
- package/lib/services/util/object.js +101 -0
- package/lib/services/util/object.js.map +1 -0
- package/lib/services/util/paths.js +36 -0
- package/lib/services/util/paths.js.map +1 -0
- package/lib/services/{promise.js → util/promise.js} +5 -7
- package/lib/services/util/promise.js.map +1 -0
- package/npm-shrinkwrap.json +2143 -1304
- package/package.json +50 -42
- package/lib/commands/index.js +0 -9
- package/lib/commands/index.js.map +0 -1
- package/lib/services/app.js.map +0 -1
- package/lib/services/args.js +0 -28
- package/lib/services/args.js.map +0 -1
- package/lib/services/collections.js +0 -17
- package/lib/services/collections.js.map +0 -1
- package/lib/services/config.js.map +0 -1
- package/lib/services/debounce.js +0 -21
- package/lib/services/debounce.js.map +0 -1
- package/lib/services/defaults.js +0 -8
- package/lib/services/defaults.js.map +0 -1
- package/lib/services/edit-graphql.js +0 -202
- package/lib/services/edit-graphql.js.map +0 -1
- package/lib/services/errors.js +0 -277
- package/lib/services/errors.js.map +0 -1
- package/lib/services/filesync.js +0 -404
- package/lib/services/filesync.js.map +0 -1
- package/lib/services/fs.js +0 -35
- package/lib/services/fs.js.map +0 -1
- package/lib/services/http.js +0 -53
- package/lib/services/http.js.map +0 -1
- package/lib/services/is.js.map +0 -1
- package/lib/services/log.js +0 -45
- package/lib/services/log.js.map +0 -1
- package/lib/services/noop.js +0 -4
- package/lib/services/noop.js.map +0 -1
- package/lib/services/notify.js.map +0 -1
- package/lib/services/output.js +0 -74
- package/lib/services/output.js.map +0 -1
- package/lib/services/promise.js.map +0 -1
- package/lib/services/prompt.js +0 -22
- package/lib/services/prompt.js.map +0 -1
- package/lib/services/session.js +0 -31
- package/lib/services/session.js.map +0 -1
- package/lib/services/sleep.js +0 -21
- package/lib/services/sleep.js.map +0 -1
- package/lib/services/timeout.js +0 -8
- package/lib/services/timeout.js.map +0 -1
- package/lib/services/user.js.map +0 -1
- package/lib/services/version.js.map +0 -1
package/lib/commands/sync.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/sync.ts"],"sourcesContent":["import arg from \"arg\";\nimport dayjs from \"dayjs\";\nimport { execa } from \"execa\";\nimport type { Stats } from \"fs-extra\";\nimport fs from \"fs-extra\";\nimport ms from \"ms\";\nimport path from \"node:path\";\nimport pMap from \"p-map\";\nimport PQueue from \"p-queue\";\nimport type { SetRequired } from \"type-fest\";\nimport FSWatcher from \"watcher\";\nimport which from \"which\";\nimport { FileSyncEncoding, type FileSyncChangedEventInput, type FileSyncDeletedEventInput } from \"../__generated__/graphql.js\";\nimport { AppArg } from \"../services/args.js\";\nimport { config } from \"../services/config.js\";\nimport { debounce, type DebouncedFunc } from \"../services/debounce.js\";\nimport { defaults } from \"../services/defaults.js\";\nimport { EditGraphQL } from \"../services/edit-graphql.js\";\nimport { YarnNotFoundError } from \"../services/errors.js\";\nimport {\n FileSync,\n PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n REMOTE_FILES_VERSION_QUERY,\n REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION,\n printPaths,\n} from \"../services/filesync.js\";\nimport { swallowEnoent } from \"../services/fs.js\";\nimport { createLogger } from \"../services/log.js\";\nimport { noop } from \"../services/noop.js\";\nimport { notify } from \"../services/notify.js\";\nimport { println, sprint } from \"../services/output.js\";\nimport { PromiseSignal } from \"../services/promise.js\";\nimport { select } from \"../services/prompt.js\";\nimport { getUserOrLogin } from \"../services/user.js\";\nimport { type RootArgs } from \"./root.js\";\n\nexport const usage = sprint`\n Sync your Gadget application's source code to and from\n your local filesystem.\n\n {bold USAGE}\n $ ggt sync [DIRECTORY] [--app <name>]\n\n {bold ARGUMENTS}\n DIRECTORY {dim [default: .] The directory to sync files to.\n\n If the directory doesn't exist, it will be created.}\n\n {bold FLAGS}\n -a, --app=<name> {dim The Gadget application to sync files to.}\n\n --force {dim Whether to sync even if we can't determine\n the state of your local files relative to\n your remote ones.}\n\n {bold DESCRIPTION}\n Sync provides the ability to sync your Gadget application's source\n code to and from your local filesystem.\n\n While ggt sync is running, local file changes are immediately\n reflected within Gadget, while files that are changed remotely are\n immediately saved to your local filesystem.\n\n Use cases for this include:\n • Developing locally with your own editor like VSCode\n • Storing your source code in a Git repository like GitHub\n\n Sync includes the concept of a {dim .ignore} file. This file may\n contain a list of files and directories that won't be received or\n sent to Gadget when syncing. The format of this file is identical\n to the one used by Git {dim (https://git-scm.com/docs/gitignore)}.\n\n The following files and directories are always ignored:\n • .DS_Store\n • .gadget\n • .git\n • node_modules\n\n Note:\n • If you have separate development and production environments,\n {dim ggt sync} will only sync with your development environment\n • Gadget applications only support installing dependencies\n with Yarn 1 {dim (https://classic.yarnpkg.com/lang/en/)}\n • Since file changes are immediately reflected in Gadget,\n avoid the following while {dim ggt sync} is running:\n • Deleting all your files\n • Moving all your files to a different directory\n\n {bold EXAMPLES}\n {dim $ ggt sync --app my-app ~/gadget/my-app}\n\n App my-app\n Editor https://my-app.gadget.app/edit\n Playground https://my-app.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/my-app\n\n Endpoints\n • https://my-app.gadget.app\n • https://my-app--development.gadget.app\n\n Watching for file changes... {dim Press Ctrl+C to stop}\n\n Received {dim 12:00:00 PM}\n {green ←} routes/GET.js {dim (changed)}\n {green ←} user/signUp/signIn.js {dim (changed)}\n {dim 2 files in total. 2 changed, 0 deleted.}\n\n Sent {dim 12:00:03 PM}\n {green →} routes/GET.ts {dim (changed)}\n {dim 1 file in total. 1 changed, 0 deleted.}\n\n ^C Stopping... {dim (press Ctrl+C again to force)}\n Goodbye!\n`;\n\nexport enum SyncStatus {\n STARTING,\n RUNNING,\n STOPPING,\n STOPPED,\n}\n\nexport enum Action {\n CANCEL = \"Cancel (Ctrl+C)\",\n MERGE = \"Merge local files with remote ones\",\n RESET = \"Reset local files to remote ones\",\n}\n\nconst argSpec = {\n \"-a\": \"--app\",\n \"--app\": AppArg,\n \"--force\": Boolean,\n \"--file-push-delay\": Number,\n \"--file-watch-debounce\": Number,\n \"--file-watch-poll-interval\": Number,\n \"--file-watch-poll-timeout\": Number,\n \"--file-watch-rename-timeout\": Number,\n};\n\nexport class Sync {\n args!: SetRequired<arg.Result<typeof argSpec>, \"--file-push-delay\">;\n\n /**\n * The current status of the sync process.\n */\n status = SyncStatus.STARTING;\n\n /**\n * A list of filepaths that have changed because of a remote file-sync\n * event. This is used to avoid sending files that we recently\n * received from a remote file-sync event.\n */\n recentRemoteChanges = new Map<string, number>();\n\n /**\n * A FIFO async callback queue that ensures we process file-sync events in the order they occurred.\n */\n queue = new PQueue({ concurrency: 1 });\n\n /**\n * A GraphQL client connected to the app's /edit/api/graphql-ws endpoint\n */\n graphql!: EditGraphQL;\n\n /**\n * Watches the local filesystem for changes.\n */\n watcher!: FSWatcher;\n\n /**\n * Handles writing files to the local filesystem.\n */\n filesync!: FileSync;\n\n /**\n * A debounced function that enqueue's local file changes to be sent to Gadget.\n */\n publish!: DebouncedFunc<() => void>;\n\n /**\n * Gracefully stops the sync.\n */\n stop!: (error?: unknown) => Promise<void>;\n\n /**\n * A logger for the sync command.\n */\n log = createLogger(\"sync\", () => {\n return {\n app: this.filesync.app.slug,\n filesVersion: String(this.filesync.filesVersion),\n mtime: this.filesync.mtime,\n };\n });\n\n /**\n * Initializes the sync process.\n * - Ensures the directory exists.\n * - Ensures the directory is empty or contains a `.gadget/sync.json` file.\n * - Ensures an app is selected and that it matches the app the directory was previously synced to.\n * - Ensures yarn v1 is installed.\n * - Prompts the user how to resolve conflicts if the local filesystem has changed since the last sync.\n */\n async init(rootArgs: RootArgs): Promise<void> {\n this.args = defaults(arg(argSpec, { argv: rootArgs._ }), {\n \"--file-push-delay\": 100,\n \"--file-watch-debounce\": 300,\n \"--file-watch-poll-interval\": 3_000,\n \"--file-watch-poll-timeout\": 20_000,\n \"--file-watch-rename-timeout\": 1_250,\n });\n\n if (!which.sync(\"yarn\", { nothrow: true })) {\n throw new YarnNotFoundError();\n }\n\n const user = await getUserOrLogin();\n\n this.filesync = await FileSync.init(user, {\n dir: this.args._[0],\n app: this.args[\"--app\"],\n force: this.args[\"--force\"],\n extraIgnorePaths: [\".gadget\"],\n });\n\n this.graphql = new EditGraphQL(this.filesync.app);\n\n const { remoteFilesVersion } = await this.graphql.query({ query: REMOTE_FILES_VERSION_QUERY });\n const hasRemoteChanges = BigInt(remoteFilesVersion) > this.filesync.filesVersion;\n\n const getChangedFiles = async (): Promise<Map<string, Stats>> => {\n const files = new Map();\n for await (const [absolutePath, stats] of this.filesync.walkDir()) {\n if (stats.mtime.getTime() > this.filesync.mtime) {\n files.set(this.filesync.normalize(absolutePath, stats.isDirectory()), stats);\n }\n }\n\n // never include the root directory\n files.delete(\"/\");\n\n return files;\n };\n\n let changedFiles = await getChangedFiles();\n const hasLocalChanges = changedFiles.size > 0;\n if (hasLocalChanges) {\n this.log.info(\"local files have changed\", {\n remoteFilesVersion,\n hasRemoteChanges,\n hasLocalChanges,\n changed: Array.from(changedFiles.keys()),\n });\n\n println(\"Local files have changed since you last synced\");\n printPaths(\"-\", Array.from(changedFiles.keys()), [], { limit: changedFiles.size });\n println();\n }\n\n let action: Action | undefined;\n if (hasLocalChanges) {\n action = await select({\n message: hasRemoteChanges ? \"Remote files have also changed. How would you like to proceed?\" : \"How would you like to proceed?\",\n choices: [Action.CANCEL, Action.MERGE, Action.RESET],\n });\n }\n\n // get all the changed files again in case more changed\n changedFiles = await getChangedFiles();\n\n switch (action) {\n case Action.MERGE: {\n this.log.info(\"merging local changes\", {\n remoteFilesVersion,\n hasRemoteChanges,\n hasLocalChanges,\n changed: Array.from(changedFiles.keys()),\n });\n\n // We purposefully don't write the returned files version here\n // because we haven't received its associated files yet. This\n // will cause us to receive the remote files that have changed\n // since the last sync (+ the local files that we just\n // published)\n await this.graphql.query({\n query: PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n variables: {\n input: {\n expectedRemoteFilesVersion: remoteFilesVersion,\n changed: await pMap(changedFiles, async ([normalizedPath, stats]) => ({\n path: normalizedPath,\n mode: stats.mode,\n content: stats.isDirectory() ? \"\" : await fs.readFile(this.filesync.absolute(normalizedPath), \"base64\"),\n encoding: FileSyncEncoding.Base64,\n })),\n deleted: [],\n },\n },\n });\n break;\n }\n case Action.RESET: {\n this.log.info(\"resetting local changes\", {\n remoteFilesVersion,\n hasRemoteChanges,\n hasLocalChanges,\n changed: Array.from(changedFiles.keys()),\n });\n\n // delete all the local files that have changed since the last\n // sync and set the files version to 0 so we receive all the\n // remote files again, including any files that we just deleted\n // that still exist\n await this.filesync.write(0n, [], changedFiles.keys(), true);\n break;\n }\n case Action.CANCEL: {\n process.exit(0);\n }\n }\n }\n\n /**\n * Runs the sync process until it is stopped or an error occurs.\n */\n async run(): Promise<void> {\n let error: unknown;\n const stopped = new PromiseSignal();\n\n const recentRemoteChangesInterval = setInterval(() => {\n for (const [path, timestamp] of this.recentRemoteChanges) {\n if (dayjs().isAfter(timestamp + ms(\"5s\"))) {\n // this change should have been seen by now, so remove it\n this.recentRemoteChanges.delete(path);\n }\n }\n }, ms(\"1s\")).unref();\n\n this.stop = async (e?: unknown) => {\n if (this.status !== SyncStatus.RUNNING) {\n return;\n }\n\n this.status = SyncStatus.STOPPING;\n error = e;\n\n this.log.info(\"stopping\", { error });\n\n try {\n clearInterval(recentRemoteChangesInterval);\n unsubscribe();\n this.watcher.removeAllListeners();\n this.publish.flush();\n await this.queue.onIdle();\n } finally {\n await Promise.allSettled([this.watcher.close(), this.graphql.dispose()]);\n\n this.status = SyncStatus.STOPPED;\n stopped.resolve();\n this.log.info(\"stopped\");\n }\n };\n\n for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) {\n process.on(signal, () => {\n if (this.status !== SyncStatus.RUNNING) {\n return;\n }\n\n println` Stopping... {gray (press Ctrl+C again to force)}`;\n void this.stop();\n\n // When ggt is run via npx, and the user presses Ctrl+C, npx sends SIGINT twice in quick succession. In order to prevent the second\n // SIGINT from triggering the force exit listener, we wait a bit before registering it. This is a bit of a hack, but it works.\n setTimeout(() => {\n process.once(signal, () => {\n println(\" Exiting immediately. Note that files may not have finished syncing.\");\n process.exit(1);\n });\n }, 100).unref();\n });\n }\n\n const unsubscribe = this.graphql.subscribe(\n {\n query: REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION,\n variables: () => ({ localFilesVersion: String(this.filesync.filesVersion) }),\n },\n {\n error: (error) => void this.stop(error),\n next: ({ remoteFileSyncEvents }) => {\n const remoteFilesVersion = remoteFileSyncEvents.remoteFilesVersion;\n\n // we always ignore .gadget/ files so that we don't publish them (they're managed by gadget), but we still want to receive them\n const filterIgnored = (event: { path: string }) => event.path.startsWith(\".gadget/\") || !this.filesync.ignores(event.path);\n const changed = remoteFileSyncEvents.changed.filter(filterIgnored);\n const deleted = remoteFileSyncEvents.deleted.filter(filterIgnored);\n\n this.log.info(\"received files\", {\n remoteFilesVersion,\n changed: changed.map((x) => x.path),\n deleted: deleted.map((x) => x.path),\n });\n\n this._enqueue(async () => {\n // add all the non-ignored files and directories we're about\n // to touch to recentRemoteChanges so that we don't send\n // them back\n for (const file of [...changed, ...deleted].filter((file) => !this.filesync.ignores(file.path))) {\n this.recentRemoteChanges.set(file.path, Date.now());\n\n let dir = path.dirname(file.path);\n while (dir !== \".\") {\n this.recentRemoteChanges.set(dir + \"/\", Date.now());\n dir = path.dirname(dir);\n }\n }\n\n if (changed.length > 0 || deleted.length > 0) {\n println`Received {gray ${dayjs().format(\"hh:mm:ss A\")}}`;\n printPaths(\n \"←\",\n changed.map((x) => x.path),\n deleted.map((x) => x.path),\n );\n }\n\n await this.filesync.write(\n remoteFilesVersion,\n changed,\n deleted.map((x) => x.path),\n );\n\n if (changed.some((x) => x.path === \"yarn.lock\")) {\n await execa(\"yarn\", [\"install\"], { cwd: this.filesync.dir }).catch(noop);\n }\n });\n },\n },\n );\n\n const localFilesBuffer = new Map<\n string,\n | { mode: number; isDirectory: boolean }\n | { isDeleted: true; isDirectory: boolean }\n | { mode: number; oldPath: string; newPath: string; isDirectory: boolean }\n >();\n\n this.publish = debounce(this.args[\"--file-push-delay\"], () => {\n const localFiles = new Map(localFilesBuffer.entries());\n localFilesBuffer.clear();\n\n this._enqueue(async () => {\n const changed: FileSyncChangedEventInput[] = [];\n const deleted: FileSyncDeletedEventInput[] = [];\n\n await pMap(localFiles, async ([normalizedPath, file]) => {\n if (\"isDeleted\" in file) {\n deleted.push({ path: normalizedPath });\n return;\n }\n\n try {\n changed.push({\n path: normalizedPath,\n oldPath: \"oldPath\" in file ? file.oldPath : undefined,\n mode: file.mode,\n content: file.isDirectory ? \"\" : await fs.readFile(this.filesync.absolute(normalizedPath), FileSyncEncoding.Base64),\n encoding: FileSyncEncoding.Base64,\n });\n } catch (error) {\n // A file could have been changed and then deleted before we process the change event, so the readFile\n // above will raise an ENOENT. This is normal operation, so just ignore this event.\n swallowEnoent(error);\n }\n });\n\n if (changed.length === 0 && deleted.length === 0) {\n return;\n }\n\n const { publishFileSyncEvents } = await this.graphql.query({\n query: PUBLISH_FILE_SYNC_EVENTS_MUTATION,\n variables: { input: { expectedRemoteFilesVersion: String(this.filesync.filesVersion), changed, deleted } },\n });\n\n await this.filesync.write(publishFileSyncEvents.remoteFilesVersion, [], []);\n\n println`Sent {gray ${dayjs().format(\"hh:mm:ss A\")}}`;\n printPaths(\n \"→\",\n changed.map((x) => x.path),\n deleted.map((x) => x.path),\n );\n });\n });\n\n this.watcher = new FSWatcher(this.filesync.dir, {\n // don't emit an event for every watched file on boot\n ignoreInitial: true,\n ignore: (path: string) => this.filesync.ignores(path),\n renameDetection: true,\n recursive: true,\n debounce: this.args[\"--file-watch-debounce\"],\n pollingInterval: this.args[\"--file-watch-poll-interval\"],\n pollingTimeout: this.args[\"--file-watch-poll-timeout\"],\n renameTimeout: this.args[\"--file-watch-rename-timeout\"],\n });\n\n this.watcher.once(\"error\", (error) => void this.stop(error));\n\n this.watcher.on(\"all\", (event: string, absolutePath: string, renamedPath: string) => {\n const filepath = event === \"rename\" || event === \"renameDir\" ? renamedPath : absolutePath;\n const isDirectory = event === \"renameDir\" || event === \"addDir\" || event === \"unlinkDir\";\n const normalizedPath = this.filesync.normalize(filepath, isDirectory);\n\n this.log.debug(\"file event\", {\n event,\n path: normalizedPath,\n isDirectory,\n recentRemoteChanges: Array.from(this.recentRemoteChanges.keys()),\n });\n\n if (filepath === this.filesync.absolute(\".ignore\")) {\n this.filesync.reloadIgnorePaths();\n } else if (this.filesync.ignores(filepath)) {\n return;\n }\n\n if (this.recentRemoteChanges.delete(normalizedPath)) {\n return;\n }\n\n switch (event) {\n case \"add\":\n case \"addDir\":\n case \"change\": {\n const stats = fs.statSync(filepath);\n localFilesBuffer.set(normalizedPath, { mode: stats.mode, isDirectory });\n break;\n }\n case \"unlink\":\n case \"unlinkDir\": {\n localFilesBuffer.set(normalizedPath, { isDeleted: true, isDirectory });\n break;\n }\n case \"rename\":\n case \"renameDir\": {\n const stats = fs.statSync(filepath);\n localFilesBuffer.set(normalizedPath, {\n oldPath: this.filesync.normalize(absolutePath, isDirectory),\n newPath: normalizedPath,\n isDirectory,\n mode: stats.mode,\n });\n break;\n }\n }\n\n this.publish();\n });\n\n this.status = SyncStatus.RUNNING;\n\n println();\n println`\n {bold ggt v${config.version}}\n\n App ${this.filesync.app.slug}\n Editor https://${this.filesync.app.slug}.gadget.app/edit\n Playground https://${this.filesync.app.slug}.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/${this.filesync.app.slug}\n\n {underline Endpoints} ${\n this.filesync.app.hasSplitEnvironments\n ? `\n • https://${this.filesync.app.primaryDomain}\n • https://${this.filesync.app.slug}--development.gadget.app`\n : `\n • https://${this.filesync.app.primaryDomain}`\n }\n\n Watching for file changes... {gray Press Ctrl+C to stop}\n `;\n println();\n\n await stopped;\n\n if (error) {\n notify({ subtitle: \"Uh oh!\", message: \"An error occurred while syncing files\" });\n throw error as Error;\n } else {\n println(\"Goodbye!\");\n }\n }\n\n /**\n * Enqueues a function that handles file-sync events onto the {@linkcode queue}.\n *\n * @param fn The function to enqueue.\n */\n private _enqueue(fn: () => Promise<unknown>): void {\n void this.queue.add(fn).catch(this.stop);\n }\n}\n\nconst sync = new Sync();\nexport const init = sync.init.bind(sync);\nexport const run = sync.run.bind(sync);\n"],"names":["arg","dayjs","execa","fs","ms","path","pMap","PQueue","FSWatcher","which","FileSyncEncoding","AppArg","config","debounce","defaults","EditGraphQL","YarnNotFoundError","FileSync","PUBLISH_FILE_SYNC_EVENTS_MUTATION","REMOTE_FILES_VERSION_QUERY","REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION","printPaths","swallowEnoent","createLogger","noop","notify","println","sprint","PromiseSignal","select","getUserOrLogin","usage","SyncStatus","Action","argSpec","Boolean","Number","Sync","init","rootArgs","args","argv","_","sync","nothrow","user","filesync","dir","app","force","extraIgnorePaths","graphql","remoteFilesVersion","query","hasRemoteChanges","BigInt","filesVersion","getChangedFiles","files","Map","absolutePath","stats","walkDir","mtime","getTime","set","normalize","isDirectory","delete","changedFiles","hasLocalChanges","size","log","info","changed","Array","from","keys","limit","action","message","choices","variables","input","expectedRemoteFilesVersion","normalizedPath","mode","content","readFile","absolute","encoding","Base64","deleted","write","process","exit","run","error","stopped","recentRemoteChangesInterval","setInterval","timestamp","recentRemoteChanges","isAfter","unref","stop","e","status","clearInterval","unsubscribe","watcher","removeAllListeners","publish","flush","queue","onIdle","Promise","allSettled","close","dispose","resolve","signal","on","setTimeout","once","subscribe","localFilesVersion","String","next","remoteFileSyncEvents","filterIgnored","event","startsWith","ignores","filter","map","x","_enqueue","file","Date","now","dirname","length","format","some","cwd","catch","localFilesBuffer","localFiles","entries","clear","push","oldPath","undefined","publishFileSyncEvents","ignoreInitial","ignore","renameDetection","recursive","pollingInterval","pollingTimeout","renameTimeout","renamedPath","filepath","debug","reloadIgnorePaths","statSync","isDeleted","newPath","version","slug","hasSplitEnvironments","primaryDomain","subtitle","fn","add","concurrency","bind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/sync.ts"],"sourcesContent":["import dayjs from \"dayjs\";\nimport { execa } from \"execa\";\nimport ms from \"ms\";\nimport path from \"node:path\";\nimport Watcher from \"watcher\";\nimport which from \"which\";\nimport { AppArg } from \"../services/app/arg.js\";\nimport type { ArgsSpec } from \"../services/command/arg.js\";\nimport type { Command, Usage } from \"../services/command/command.js\";\nimport { config } from \"../services/config/config.js\";\nimport { Changes } from \"../services/filesync/changes.js\";\nimport { YarnNotFoundError } from \"../services/filesync/error.js\";\nimport { ConflictPreferenceArg, FileSync } from \"../services/filesync/filesync.js\";\nimport { notify } from \"../services/output/notify.js\";\nimport { reportErrorAndExit } from \"../services/output/report.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUserOrLogin } from \"../services/user/user.js\";\nimport { debounce } from \"../services/util/function.js\";\nimport { isAbortError } from \"../services/util/is.js\";\n\nexport const usage: Usage = () => sprint`\n Sync your Gadget environment's source code with your local filesystem.\n\n {bold USAGE}\n ggt sync [DIRECTORY]\n\n {bold ARGUMENTS}\n DIRECTORY The directory to sync files to (default: \".\")\n\n {bold FLAGS}\n -a, --app=<name> The Gadget application to sync files to\n --prefer=<filesystem> Prefer \"local\" or \"gadget\" conflicting changes\n --once Sync once and exit\n --force Sync regardless of local filesystem state\n\n {bold DESCRIPTION}\n Sync allows you to synchronize your Gadget application's source\n code with your local filesystem.\n\n While ggt sync is running, local file changes are immediately\n reflected within Gadget, while files that are changed in Gadget are\n immediately saved to your local filesystem.\n\n Ideal for:\n • Local development with editors like VSCode\n • Storing source code in a Git repository like GitHub\n\n Sync looks for a \".ignore\" file to exclude certain files/directories\n from being synced. The format is identical to Git's.\n\n These files are always ignored:\n • .DS_Store\n • .gadget\n • .git\n • node_modules\n\n Note:\n • Sync only works with your development environment\n • Avoid deleting/moving all your files while sync is running\n • Gadget only supports Yarn v1 for dependency installation\n\n {bold EXAMPLE}\n $ ggt sync ~/gadget/example --app example\n\n App example\n Editor https://example.gadget.app/edit\n Playground https://example.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/example\n\n Endpoints\n • https://example.gadget.app\n • https://example--development.gadget.app\n\n Watching for file changes... {gray Press Ctrl+C to stop}\n\n → Sent {gray 09:06:25 AM}\n {greenBright routes/GET-hello.js + created}\n\n → Sent {gray 09:06:49 AM}\n {blueBright routes/GET-hello.js ± updated}\n\n ← Received {gray 09:06:54 AM}\n {blueBright routes/GET-hello.js ± updated}\n\n ← Received {gray 09:06:56 AM}\n {redBright routes/GET-hello.js - deleted}\n ^C Stopping... {gray press Ctrl+C again to force}\n\n Goodbye!\n`;\n\nexport const args = {\n \"--app\": { type: AppArg, alias: \"-a\" },\n \"--force\": Boolean,\n \"--once\": Boolean,\n \"--prefer\": ConflictPreferenceArg,\n \"--file-push-delay\": { type: Number, default: ms(\"100ms\") },\n \"--file-watch-debounce\": { type: Number, default: ms(\"300ms\") },\n \"--file-watch-poll-interval\": { type: Number, default: ms(\"3s\") },\n \"--file-watch-poll-timeout\": { type: Number, default: ms(\"20s\") },\n \"--file-watch-rename-timeout\": { type: Number, default: ms(\"1.25s\") },\n} satisfies ArgsSpec;\n\n/**\n * Runs the sync process until it is stopped or an error occurs.\n */\nexport const command: Command<typeof args> = async (ctx) => {\n const filesync = await FileSync.init({\n user: await getUserOrLogin(),\n dir: ctx.args._[0],\n app: ctx.args[\"--app\"],\n force: ctx.args[\"--force\"],\n });\n\n await filesync.sync({ preference: ctx.args[\"--prefer\"] });\n\n if (ctx.args[\"--once\"]) {\n ctx.log.println(\"Done!\");\n return;\n }\n\n if (!which.sync(\"yarn\", { nothrow: true })) {\n throw new YarnNotFoundError();\n }\n\n /**\n * A list of filepaths that have changed because we (this ggt process)\n * modified them. This is used to avoid reacting to filesystem events\n * that we caused, which would cause an infinite loop.\n */\n const recentWritesToLocalFilesystem = new Map<string, number>();\n\n const clearRecentWritesInterval = setInterval(() => {\n for (const [path, timestamp] of recentWritesToLocalFilesystem) {\n if (dayjs().isAfter(timestamp + ms(\"5s\"))) {\n // this change should have been seen by now\n recentWritesToLocalFilesystem.delete(path);\n }\n }\n }, ms(\"1s\")).unref();\n\n /**\n * Subscribe to file changes on Gadget and apply them to the local\n * filesystem.\n */\n const unsubscribeFromGadgetChanges = filesync.subscribeToGadgetChanges({\n onError: (error) => ctx.abort(error),\n beforeChanges: ({ changed, deleted }) => {\n // add all the files and directories we're about to touch to\n // recentWritesToLocalFilesystem so that we don't send them back\n // to Gadget\n for (const filepath of [...changed, ...deleted]) {\n recentWritesToLocalFilesystem.set(filepath, Date.now());\n\n let dir = path.dirname(filepath);\n while (dir !== \".\") {\n recentWritesToLocalFilesystem.set(dir + \"/\", Date.now());\n dir = path.dirname(dir);\n }\n }\n },\n afterChanges: async ({ changes }) => {\n if (changes.has(\"yarn.lock\")) {\n await execa(\"yarn\", [\"install\", \"--check-files\"], { cwd: filesync.directory.path }).catch((error) => {\n ctx.log.error(\"yarn install failed\", { error });\n });\n }\n },\n });\n\n /**\n * A buffer of local file changes to send to Gadget.\n */\n const localChangesBuffer = new Changes();\n\n /**\n * A debounced function that sends the local file changes to Gadget.\n */\n const sendChangesToGadget = debounce(ctx.args[\"--file-push-delay\"], () => {\n const changes = new Changes(localChangesBuffer.entries());\n localChangesBuffer.clear();\n filesync.sendChangesToGadget({ changes }).catch((error) => ctx.abort(error));\n });\n\n ctx.log.debug(\"watching\", { path: filesync.directory.path });\n\n /**\n * Watches the local filesystem for changes.\n */\n const fileWatcher = new Watcher(\n filesync.directory.path,\n {\n // don't emit an event for every watched file on boot\n ignoreInitial: true,\n // don't emit changes to .gadget/ files because they're readonly (Gadget manages them)\n ignore: (path: string) => filesync.directory.relative(path).startsWith(\".gadget\") || filesync.directory.ignores(path),\n renameDetection: true,\n recursive: true,\n debounce: ctx.args[\"--file-watch-debounce\"],\n pollingInterval: ctx.args[\"--file-watch-poll-interval\"],\n pollingTimeout: ctx.args[\"--file-watch-poll-timeout\"],\n renameTimeout: ctx.args[\"--file-watch-rename-timeout\"],\n },\n (event: string, absolutePath: string, renamedPath: string) => {\n const filepath = event === \"rename\" || event === \"renameDir\" ? renamedPath : absolutePath;\n const isDirectory = event === \"renameDir\" || event === \"addDir\" || event === \"unlinkDir\";\n const normalizedPath = filesync.directory.normalize(filepath, isDirectory);\n\n ctx.log.trace(\"file event\", { event, isDirectory, path: normalizedPath });\n\n if (filepath === filesync.directory.absolute(\".ignore\")) {\n filesync.directory.loadIgnoreFile().catch((error) => ctx.abort(error));\n } else if (filesync.directory.ignores(filepath)) {\n return;\n }\n\n if (recentWritesToLocalFilesystem.delete(normalizedPath)) {\n ctx.log.trace(\"ignoring event because we caused it\", { event, path: normalizedPath });\n return;\n }\n\n switch (event) {\n case \"add\":\n case \"addDir\":\n localChangesBuffer.set(normalizedPath, { type: \"create\" });\n break;\n case \"rename\":\n case \"renameDir\": {\n const oldNormalizedPath = filesync.directory.normalize(absolutePath, isDirectory);\n localChangesBuffer.set(normalizedPath, { type: \"create\", oldPath: oldNormalizedPath });\n break;\n }\n case \"change\": {\n localChangesBuffer.set(normalizedPath, { type: \"update\" });\n break;\n }\n case \"unlink\":\n case \"unlinkDir\": {\n localChangesBuffer.set(normalizedPath, { type: \"delete\" });\n break;\n }\n }\n\n sendChangesToGadget();\n },\n ).once(\"error\", (error) => ctx.abort(error));\n\n ctx.log.printlns`\n ggt v${config.version}\n\n App ${filesync.app.slug}\n Editor https://${filesync.app.slug}.gadget.app/edit\n Playground https://${filesync.app.slug}.gadget.app/api/graphql/playground\n Docs https://docs.gadget.dev/api/${filesync.app.slug}\n\n Endpoints ${\n filesync.app.hasSplitEnvironments\n ? `\n • https://${filesync.app.primaryDomain}\n • https://${filesync.app.slug}--development.gadget.app`\n : `\n • https://${filesync.app.primaryDomain}`\n }\n\n Watching for file changes... {gray Press Ctrl+C to stop}\n `;\n\n ctx.onAbort(async (reason) => {\n ctx.log.info(\"stopping\", { reason });\n\n unsubscribeFromGadgetChanges();\n fileWatcher.close();\n clearInterval(clearRecentWritesInterval);\n sendChangesToGadget.flush();\n\n try {\n await filesync.idle();\n } catch (error) {\n ctx.log.error(\"error while waiting for idle\", { error });\n }\n\n if (isAbortError(reason)) {\n ctx.log.printlns(\"Goodbye!\");\n return;\n }\n\n notify({ subtitle: \"Uh oh!\", message: \"An error occurred while syncing files\" });\n await reportErrorAndExit(reason);\n });\n};\n"],"names":["dayjs","execa","ms","path","Watcher","which","AppArg","config","Changes","YarnNotFoundError","ConflictPreferenceArg","FileSync","notify","reportErrorAndExit","sprint","getUserOrLogin","debounce","isAbortError","usage","args","type","alias","Boolean","Number","default","command","ctx","filesync","init","user","dir","_","app","force","sync","preference","log","println","nothrow","recentWritesToLocalFilesystem","Map","clearRecentWritesInterval","setInterval","timestamp","isAfter","delete","unref","unsubscribeFromGadgetChanges","subscribeToGadgetChanges","onError","error","abort","beforeChanges","changed","deleted","filepath","set","Date","now","dirname","afterChanges","changes","has","cwd","directory","catch","localChangesBuffer","sendChangesToGadget","entries","clear","debug","fileWatcher","ignoreInitial","ignore","relative","startsWith","ignores","renameDetection","recursive","pollingInterval","pollingTimeout","renameTimeout","event","absolutePath","renamedPath","isDirectory","normalizedPath","normalize","trace","absolute","loadIgnoreFile","oldNormalizedPath","oldPath","once","printlns","version","slug","hasSplitEnvironments","primaryDomain","onAbort","reason","info","close","clearInterval","flush","idle","subtitle","message"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { config } from "../services/config/config.js";
|
|
2
|
+
import { createLogger } from "../services/output/log/logger.js";
|
|
3
|
+
import { sprint } from "../services/output/sprint.js";
|
|
4
|
+
const log = createLogger({
|
|
5
|
+
name: "version"
|
|
6
|
+
});
|
|
7
|
+
export const usage = ()=>sprint`
|
|
8
|
+
Print the version of ggt
|
|
9
|
+
|
|
10
|
+
{bold USAGE}
|
|
11
|
+
ggt version
|
|
12
|
+
|
|
13
|
+
{bold EXAMPLES}
|
|
14
|
+
$ ggt version
|
|
15
|
+
${config.version}
|
|
16
|
+
`;
|
|
17
|
+
export const command = ()=>{
|
|
18
|
+
log.println(config.version);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/version.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { config } from \"../services/config/config.js\";\nimport { createLogger } from \"../services/output/log/logger.js\";\nimport { sprint } from \"../services/output/sprint.js\";\n\nconst log = createLogger({ name: \"version\" });\n\nexport const usage: Usage = () => sprint`\n Print the version of ggt\n\n {bold USAGE}\n ggt version\n\n {bold EXAMPLES}\n $ ggt version\n ${config.version}\n`;\n\nexport const command: Command = () => {\n log.println(config.version);\n};\n"],"names":["config","createLogger","sprint","log","name","usage","version","command","println"],"mappings":"AACA,SAASA,MAAM,QAAQ,+BAA+B;AACtD,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AAEtD,MAAMC,MAAMF,aAAa;IAAEG,MAAM;AAAU;AAE3C,OAAO,MAAMC,QAAe,IAAMH,MAAM,CAAC;;;;;;;;MAQnC,EAAEF,OAAOM,OAAO,CAAC;AACvB,CAAC,CAAC;AAEF,OAAO,MAAMC,UAAmB;IAC9BJ,IAAIK,OAAO,CAACR,OAAOM,OAAO;AAC5B,EAAE"}
|
package/lib/commands/whoami.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { createLogger } from "../services/output/log/logger.js";
|
|
2
|
+
import { sprint } from "../services/output/sprint.js";
|
|
3
|
+
import { getUser } from "../services/user/user.js";
|
|
4
|
+
const log = createLogger({
|
|
5
|
+
name: "whoami"
|
|
6
|
+
});
|
|
7
|
+
export const usage = ()=>sprint`
|
|
8
|
+
Show the name and email address of the currently logged in user
|
|
5
9
|
|
|
6
10
|
{bold USAGE}
|
|
7
|
-
|
|
11
|
+
ggt whoami
|
|
8
12
|
|
|
9
13
|
{bold EXAMPLES}
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
$ ggt whoami
|
|
15
|
+
You are logged in as Jane Doe (jane@example.com)
|
|
12
16
|
`;
|
|
13
|
-
export const
|
|
17
|
+
export const command = async ()=>{
|
|
14
18
|
const user = await getUser();
|
|
15
19
|
if (!user) {
|
|
16
|
-
println`You are not logged in`;
|
|
20
|
+
log.println`You are not logged in`;
|
|
17
21
|
return;
|
|
18
22
|
}
|
|
19
23
|
if (user.name) {
|
|
20
|
-
println`You are logged in as ${user.name} {gray (${user.email})}`;
|
|
24
|
+
log.println`You are logged in as ${user.name} {gray (${user.email})}`;
|
|
21
25
|
} else {
|
|
22
|
-
println`You are logged in as ${user.email}`;
|
|
26
|
+
log.println`You are logged in as ${user.email}`;
|
|
23
27
|
}
|
|
24
28
|
};
|
|
25
29
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import type { Command, Usage } from \"../services/command/command.js\";\nimport { createLogger } from \"../services/output/log/logger.js\";\nimport { sprint } from \"../services/output/sprint.js\";\nimport { getUser } from \"../services/user/user.js\";\n\nconst log = createLogger({ name: \"whoami\" });\n\nexport const usage: Usage = () => sprint`\n Show the name and email address of the currently logged in user\n\n {bold USAGE}\n ggt whoami\n\n {bold EXAMPLES}\n $ ggt whoami\n You are logged in as Jane Doe (jane@example.com)\n`;\n\nexport const command: Command = async () => {\n const user = await getUser();\n if (!user) {\n log.println`You are not logged in`;\n return;\n }\n\n if (user.name) {\n log.println`You are logged in as ${user.name} {gray (${user.email})}`;\n } else {\n log.println`You are logged in as ${user.email}`;\n }\n};\n"],"names":["createLogger","sprint","getUser","log","name","usage","command","user","println","email"],"mappings":"AACA,SAASA,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,+BAA+B;AACtD,SAASC,OAAO,QAAQ,2BAA2B;AAEnD,MAAMC,MAAMH,aAAa;IAAEI,MAAM;AAAS;AAE1C,OAAO,MAAMC,QAAe,IAAMJ,MAAM,CAAC;;;;;;;;;AASzC,CAAC,CAAC;AAEF,OAAO,MAAMK,UAAmB;IAC9B,MAAMC,OAAO,MAAML;IACnB,IAAI,CAACK,MAAM;QACTJ,IAAIK,OAAO,CAAC,qBAAqB,CAAC;QAClC;IACF;IAEA,IAAID,KAAKH,IAAI,EAAE;QACbD,IAAIK,OAAO,CAAC,qBAAqB,EAAED,KAAKH,IAAI,CAAC,QAAQ,EAAEG,KAAKE,KAAK,CAAC,EAAE,CAAC;IACvE,OAAO;QACLN,IAAIK,OAAO,CAAC,qBAAqB,EAAED,KAAKE,KAAK,CAAC,CAAC;IACjD;AACF,EAAE"}
|
package/lib/main.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
init({
|
|
6
|
-
dsn: "https://0c26e0d8afd94e77a88ee1c3aa9e7065@o250689.ingest.sentry.io/6703266",
|
|
7
|
-
release: config.version,
|
|
8
|
-
enabled: env.productionLike && parseBoolean(process.env["GGT_SENTRY_ENABLED"] ?? "true")
|
|
9
|
-
});
|
|
10
|
-
await run();
|
|
1
|
+
import { command as root } from "./commands/root.js";
|
|
2
|
+
import { installErrorHandlers } from "./services/output/report.js";
|
|
3
|
+
installErrorHandlers();
|
|
4
|
+
await root();
|
|
11
5
|
|
|
12
6
|
//# sourceMappingURL=main.js.map
|
package/lib/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/main.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/main.ts"],"sourcesContent":["import { command as root } from \"./commands/root.js\";\nimport { installErrorHandlers } from \"./services/output/report.js\";\n\ninstallErrorHandlers();\n\nawait root();\n"],"names":["command","root","installErrorHandlers"],"mappings":"AAAA,SAASA,WAAWC,IAAI,QAAQ,qBAAqB;AACrD,SAASC,oBAAoB,QAAQ,8BAA8B;AAEnEA;AAEA,MAAMD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { config } from "
|
|
3
|
-
import {
|
|
2
|
+
import { config } from "../config/config.js";
|
|
3
|
+
import { loadCookie } from "../http/auth.js";
|
|
4
|
+
import { http } from "../http/http.js";
|
|
4
5
|
export const App = z.object({
|
|
5
6
|
id: z.union([
|
|
6
7
|
z.string(),
|
|
@@ -12,7 +13,11 @@ export const App = z.object({
|
|
|
12
13
|
hasSplitEnvironments: z.boolean()
|
|
13
14
|
});
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
+
* Retrieves a list of apps for the given user. If the user is not
|
|
17
|
+
* logged in, an empty array is returned instead.
|
|
18
|
+
*
|
|
19
|
+
* @param user The user for whom to retrieve the apps.
|
|
20
|
+
* @returns A promise that resolves to an array of App objects.
|
|
16
21
|
*/ export const getApps = async (user)=>{
|
|
17
22
|
const cookie = loadCookie();
|
|
18
23
|
if (!cookie) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/app/app.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { config } from \"../config/config.js\";\nimport { loadCookie } from \"../http/auth.js\";\nimport { http } from \"../http/http.js\";\nimport type { User } from \"../user/user.js\";\n\nexport const App = z.object({\n id: z.union([z.string(), z.number(), z.bigint()]),\n slug: z.string(),\n primaryDomain: z.string(),\n hasSplitEnvironments: z.boolean(),\n});\n\nexport type App = z.infer<typeof App> & { user: User };\n\n/**\n * Retrieves a list of apps for the given user. If the user is not\n * logged in, an empty array is returned instead.\n *\n * @param user The user for whom to retrieve the apps.\n * @returns A promise that resolves to an array of App objects.\n */\nexport const getApps = async (user: User): Promise<App[]> => {\n const cookie = loadCookie();\n if (!cookie) {\n return [];\n }\n\n const json = await http({\n url: `https://${config.domains.services}/auth/api/apps`,\n headers: { cookie },\n responseType: \"json\",\n resolveBodyOnly: true,\n });\n\n return z\n .array(App)\n .parse(json)\n .map((app) => ({ ...app, user }));\n};\n"],"names":["z","config","loadCookie","http","App","object","id","union","string","number","bigint","slug","primaryDomain","hasSplitEnvironments","boolean","getApps","user","cookie","json","url","domains","services","headers","responseType","resolveBodyOnly","array","parse","map","app"],"mappings":"AAAA,SAASA,CAAC,QAAQ,MAAM;AACxB,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,IAAI,QAAQ,kBAAkB;AAGvC,OAAO,MAAMC,MAAMJ,EAAEK,MAAM,CAAC;IAC1BC,IAAIN,EAAEO,KAAK,CAAC;QAACP,EAAEQ,MAAM;QAAIR,EAAES,MAAM;QAAIT,EAAEU,MAAM;KAAG;IAChDC,MAAMX,EAAEQ,MAAM;IACdI,eAAeZ,EAAEQ,MAAM;IACvBK,sBAAsBb,EAAEc,OAAO;AACjC,GAAG;AAIH;;;;;;CAMC,GACD,OAAO,MAAMC,UAAU,OAAOC;IAC5B,MAAMC,SAASf;IACf,IAAI,CAACe,QAAQ;QACX,OAAO,EAAE;IACX;IAEA,MAAMC,OAAO,MAAMf,KAAK;QACtBgB,KAAK,CAAC,QAAQ,EAAElB,OAAOmB,OAAO,CAACC,QAAQ,CAAC,cAAc,CAAC;QACvDC,SAAS;YAAEL;QAAO;QAClBM,cAAc;QACdC,iBAAiB;IACnB;IAEA,OAAOxB,EACJyB,KAAK,CAACrB,KACNsB,KAAK,CAACR,MACNS,GAAG,CAAC,CAACC,MAAS,CAAA;YAAE,GAAGA,GAAG;YAAEZ;QAAK,CAAA;AAClC,EAAE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ArgError } from "../command/arg.js";
|
|
2
|
+
import { sprint } from "../output/sprint.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parses the value of an application argument (-a/--app) and returns
|
|
5
|
+
* the application's slug.
|
|
6
|
+
*
|
|
7
|
+
* @param value - The value of the argument.
|
|
8
|
+
* @param name - The name of the argument. e.g. "-a" or "--app".
|
|
9
|
+
* @returns The application's slug.
|
|
10
|
+
* @throws {ArgError} If the value is not a valid slug or URL.
|
|
11
|
+
*/ export const AppArg = (value, name)=>{
|
|
12
|
+
const slug = RegExp("^(https:\\/\\/)?(?<slug>[\\w-]+?)(--development)?(\\..*)?$").exec(value)?.groups?.["slug"];
|
|
13
|
+
if (slug) {
|
|
14
|
+
return slug;
|
|
15
|
+
}
|
|
16
|
+
throw new ArgError(sprint`
|
|
17
|
+
${name} must be the application's {bold slug} or {bold URL}
|
|
18
|
+
|
|
19
|
+
{bold EXAMPLES:}
|
|
20
|
+
${name} my-app
|
|
21
|
+
${name} my-app.gadget.app
|
|
22
|
+
${name} https://my-app.gadget.app
|
|
23
|
+
${name} https://my-app.gadget.app/edit
|
|
24
|
+
${name} https://my-app--development.gadget.app/edit
|
|
25
|
+
`);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=arg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/app/arg.ts"],"sourcesContent":["import { ArgError } from \"../command/arg.js\";\nimport { sprint } from \"../output/sprint.js\";\n\n/**\n * Parses the value of an application argument (-a/--app) and returns\n * the application's slug.\n *\n * @param value - The value of the argument.\n * @param name - The name of the argument. e.g. \"-a\" or \"--app\".\n * @returns The application's slug.\n * @throws {ArgError} If the value is not a valid slug or URL.\n */\nexport const AppArg = (value: string, name: string): string => {\n const slug = /^(https:\\/\\/)?(?<slug>[\\w-]+?)(--development)?(\\..*)?$/.exec(value)?.groups?.[\"slug\"];\n if (slug) {\n return slug;\n }\n\n throw new ArgError(\n sprint`\n ${name} must be the application's {bold slug} or {bold URL}\n\n {bold EXAMPLES:}\n ${name} my-app\n ${name} my-app.gadget.app\n ${name} https://my-app.gadget.app\n ${name} https://my-app.gadget.app/edit\n ${name} https://my-app--development.gadget.app/edit\n `,\n );\n};\n"],"names":["ArgError","sprint","AppArg","value","name","slug","exec","groups"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,oBAAoB;AAC7C,SAASC,MAAM,QAAQ,sBAAsB;AAE7C;;;;;;;;CAQC,GACD,OAAO,MAAMC,SAAS,CAACC,OAAeC;IACpC,MAAMC,OAAO,qEAAyDC,IAAI,CAACH,QAAQI,QAAQ,CAAC,OAAO;IACnG,IAAIF,MAAM;QACR,OAAOA;IACT;IAEA,MAAM,IAAIL,SACRC,MAAM,CAAC;MACL,EAAEG,KAAK;;;QAGL,EAAEA,KAAK;QACP,EAAEA,KAAK;QACP,EAAEA,KAAK;QACP,EAAEA,KAAK;QACP,EAAEA,KAAK;IACX,CAAC;AAEL,EAAE"}
|