@shopify/cli-kit 4.0.0 → 4.2.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 +2 -2
- package/assets/graphiql/favicon.ico +0 -0
- package/assets/graphiql/style.css +58 -0
- package/dist/private/common/array.js +2 -1
- package/dist/private/common/array.js.map +1 -1
- package/dist/private/node/api/headers.js +6 -3
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/constants.d.ts +0 -1
- package/dist/private/node/constants.js +0 -1
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/session/device-authorization.js +4 -16
- package/dist/private/node/session/device-authorization.js.map +1 -1
- package/dist/private/node/ui.js +4 -1
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/gid.d.ts +24 -0
- package/dist/public/common/gid.js +32 -0
- package/dist/public/common/gid.js.map +1 -0
- package/dist/public/common/string.js +7 -6
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/url.d.ts +16 -0
- package/dist/public/common/url.js +30 -0
- package/dist/public/common/url.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/analytics.js +3 -5
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/cli.d.ts +13 -0
- package/dist/public/node/cli.js +12 -0
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/context/local.d.ts +0 -7
- package/dist/public/node/context/local.js +18 -9
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/error-handler.js +1 -1
- package/dist/public/node/error-handler.js.map +1 -1
- package/dist/public/node/git.js +8 -1
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/graphiql/server.d.ts +80 -0
- package/dist/public/node/graphiql/server.js +234 -0
- package/dist/public/node/graphiql/server.js.map +1 -0
- package/dist/public/node/graphiql/templates/graphiql.d.ts +12 -0
- package/dist/public/node/graphiql/templates/graphiql.js +314 -0
- package/dist/public/node/graphiql/templates/graphiql.js.map +1 -0
- package/dist/public/node/graphiql/templates/unauthorized.d.ts +5 -0
- package/dist/public/node/graphiql/templates/unauthorized.js +111 -0
- package/dist/public/node/graphiql/templates/unauthorized.js.map +1 -0
- package/dist/public/node/graphiql/utilities.d.ts +12 -0
- package/dist/public/node/graphiql/utilities.js +44 -0
- package/dist/public/node/graphiql/utilities.js.map +1 -0
- package/dist/public/node/graphql.d.ts +19 -0
- package/dist/public/node/graphql.js +41 -0
- package/dist/public/node/graphql.js.map +1 -0
- package/dist/public/node/hooks/postrun.js +12 -2
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/http.js +27 -31
- package/dist/public/node/http.js.map +1 -1
- package/dist/public/node/import-extractor.js +4 -3
- package/dist/public/node/import-extractor.js.map +1 -1
- package/dist/public/node/metadata.d.ts +3 -0
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/monorail.d.ts +2 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/output.js +22 -11
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/system.js +5 -42
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/tcp.js +11 -3
- package/dist/public/node/tcp.js.map +1 -1
- package/dist/public/node/themes/api.js +76 -4
- package/dist/public/node/themes/api.js.map +1 -1
- package/dist/public/node/toml/toml-file.d.ts +3 -2
- package/dist/public/node/toml/toml-file.js +3 -2
- package/dist/public/node/toml/toml-file.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +34 -29
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/public/node/git.ts"],"names":[],"mappings":"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","sourcesContent":["import {outputContent, outputToken, outputDebug} from './output.js'\nimport {hasGit, isTerminalInteractive} from './context/local.js'\nimport {\n appendFileSync,\n detectEOL,\n fileExists,\n fileExistsSync,\n glob,\n isDirectory,\n readFileSync,\n writeFileSync,\n} from './fs.js'\nimport {AbortError} from './error.js'\nimport {cwd, joinPath} from './path.js'\nimport {runWithTimer} from './metadata.js'\nimport {execa} from 'execa'\n\nimport ignore from 'ignore'\n\nexport interface GitLogEntry {\n hash: string\n date: string\n message: string\n refs: string\n body: string\n author_name: string\n author_email: string\n}\n\nasync function gitCommand(args: string[], directory?: string): Promise<string> {\n try {\n const result = await execa('git', args, {cwd: directory})\n return result.stdout\n } catch (err) {\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n if ('exitCode' in err) {\n Object.assign(abortError, {exitCode: err.exitCode})\n }\n throw abortError\n }\n throw err\n }\n}\n\n/**\n * Initialize a git repository at the given directory.\n *\n * @param directory - The directory where the git repository will be initialized.\n * @param initialBranch - The name of the initial branch.\n */\nexport async function initializeGitRepository(directory: string, initialBranch = 'main'): Promise<void> {\n outputDebug(outputContent`Initializing git repository at ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n // We use init and checkout instead of `init --initial-branch` because the latter is only supported in git 2.28+\n await gitCommand(['init'], directory)\n await gitCommand(['checkout', '-b', initialBranch], directory)\n}\n\n/**\n * Given a Git repository and a list of absolute paths to files contained\n * in the repository, it filters and returns the files that are ignored\n * by the .gitignore.\n *\n * @param directory - The absolute path to the directory containing the files.\n * @param files - The list of files to check against.\n * @returns Files ignored by the lockfile.\n */\nexport async function checkIfIgnoredInGitRepository(directory: string, files: string[]): Promise<string[]> {\n try {\n const stdout = await gitCommand(['check-ignore', ...files], directory)\n return stdout.split('\\n').filter(Boolean)\n } catch (error) {\n // git check-ignore exits with code 1 when no files are ignored\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 1) return []\n throw error\n }\n}\n\nexport type GitIgnoreTemplate = Record<string, string[]>\n/**\n * Create a .gitignore file in the given directory.\n *\n * @param directory - The directory where the .gitignore file will be created.\n * @param template - The template to use to create the .gitignore file.\n */\nexport function createGitIgnore(directory: string, template: GitIgnoreTemplate): void {\n outputDebug(outputContent`Creating .gitignore at ${outputToken.path(directory)}...`)\n const filePath = `${directory}/.gitignore`\n\n let fileContent = ''\n for (const [section, lines] of Object.entries(template)) {\n fileContent += `# ${section}\\n`\n fileContent += `${lines.join('\\n')}\\n\\n`\n }\n\n appendFileSync(filePath, fileContent)\n}\n\n/**\n * Add an entry to an existing .gitignore file.\n *\n * If the .gitignore file doesn't exist, or if the entry is already present,\n * no changes will be made.\n *\n * @param root - The directory containing the .gitignore file.\n * @param entry - The entry to add to the .gitignore file.\n */\nexport function addToGitIgnore(root: string, entry: string): void {\n const gitIgnorePath = joinPath(root, '.gitignore')\n\n if (!fileExistsSync(gitIgnorePath)) {\n // When the .gitignore file does not exist, the CLI should not be opinionated about creating it\n return\n }\n\n const gitIgnoreContent = readFileSync(gitIgnorePath).toString()\n const eol = detectEOL(gitIgnoreContent)\n\n const lines = gitIgnoreContent.split(eol).map((line) => line.trim())\n const ignoreManager = ignore.default({allowRelativePaths: true}).add(lines)\n\n const isIgnoredEntry = ignoreManager.ignores(joinPath(entry))\n const isIgnoredEntryAsDir = ignoreManager.ignores(joinPath(entry, 'ignored.txt'))\n const isAlreadyIgnored = isIgnoredEntry || isIgnoredEntryAsDir\n if (isAlreadyIgnored) {\n // The file is already ignored by an existing pattern\n return\n }\n\n if (gitIgnoreContent.endsWith(eol)) {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${entry}${eol}`)\n } else {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${eol}${entry}${eol}`)\n }\n}\n\n/**\n * Options to use when cloning a git repository.\n *\n * @param repoUrl - The URL of the repository to clone.\n * @param destination - The directory where the repository will be cloned.\n * @param shallow - Whether to clone the repository shallowly.\n * @param latestTag - Whether to clone the latest tag instead of the default branch.\n */\nexport interface GitCloneOptions {\n repoUrl: string\n destination: string\n shallow?: boolean\n latestTag?: boolean\n}\n/**\n * Clone a git repository.\n *\n * @param cloneOptions - The options to use to clone the repository.\n * @returns A promise that resolves when the clone is complete.\n */\nexport async function downloadGitRepository(cloneOptions: GitCloneOptions): Promise<void> {\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n const {repoUrl, destination, shallow, latestTag} = cloneOptions\n outputDebug(outputContent`Git-cloning repository ${repoUrl} into ${outputToken.path(destination)}...`)\n await ensureGitIsPresentOrAbort()\n\n // Validate destination directory before attempting to clone\n if (await fileExists(destination)) {\n // Check if it's a directory\n if (!(await isDirectory(destination))) {\n throw new AbortError(\n outputContent`Can't clone to ${outputToken.path(destination)}`,\n \"The path exists but isn't a directory.\",\n )\n }\n\n // Check if directory is empty\n const entries = await glob(['*', '.*'], {\n cwd: destination,\n deep: 1,\n onlyFiles: false,\n })\n\n if (entries.length > 0) {\n throw new AbortError(\n outputContent`Directory ${outputToken.path(destination)} already exists and is not empty`,\n outputContent`Choose a different name or remove the existing directory first.`,\n )\n }\n }\n\n const [repository, branch] = repoUrl.split('#')\n\n if (branch && latestTag) {\n throw new AbortError(\"Error cloning the repository. Git can't clone the latest release with a 'branch'.\")\n }\n\n if (shallow && latestTag) {\n throw new AbortError(\n \"Error cloning the repository. Git can't clone the latest release with the 'shallow' property.\",\n )\n }\n\n const args = ['clone', '--recurse-submodules']\n if (branch) {\n args.push('--branch', branch)\n }\n if (shallow) {\n args.push('--depth', '1')\n }\n if (!isTerminalInteractive()) {\n args.push('-c', 'core.askpass=true')\n }\n args.push(repository!, destination)\n\n try {\n await execa('git', args)\n\n if (latestTag) {\n const tag = await getLatestTagFromDirectory(destination, repoUrl)\n await gitCommand(['checkout', tag], destination)\n }\n } catch (err) {\n if (err instanceof AbortError) {\n throw err\n }\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n throw abortError\n }\n throw err\n }\n })\n}\n\nasync function getLatestTagFromDirectory(directory: string, repoUrl: string): Promise<string> {\n const tag = await getLatestTag(directory)\n\n if (!tag) {\n throw new AbortError(`Couldn't obtain the most recent tag of the repository ${repoUrl}`)\n }\n\n return tag\n}\n\n/**\n * Get the latest commit of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The latest commit of the repository.\n */\nexport async function getLatestGitCommit(directory?: string): Promise<GitLogEntry> {\n const format = '%H%x00%ai%x00%s%x00%D%x00%b%x00%an%x00%ae'\n const stdout = await gitCommand(['log', '-1', `--format=${format}`], directory)\n if (!stdout.trim()) {\n throw new AbortError(\n 'Must have at least one commit to run command',\n outputContent`Run ${outputToken.genericShellCommand(\n \"git commit -m 'Initial commit'\",\n )} to create your first commit.`,\n )\n }\n const parts = stdout.split('\\x00')\n return {\n hash: parts[0]!,\n date: parts[1]!,\n message: parts[2]!,\n refs: parts[3]!,\n body: parts[4]!,\n author_name: parts[5]!,\n author_email: parts[6]!,\n }\n}\n\n/**\n * Add all files to the git index from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @returns A promise that resolves when the files are added to the index.\n */\nexport async function addAllToGitFromDirectory(directory?: string): Promise<void> {\n await gitCommand(['add', '--all'], directory)\n}\n\nexport interface CreateGitCommitOptions {\n directory?: string\n author?: string\n}\n\n/**\n * Create a git commit.\n *\n * @param message - The message of the commit.\n * @param options - The options to use to create the commit.\n * @returns The hash of the created commit.\n */\nexport async function createGitCommit(message: string, options?: CreateGitCommitOptions): Promise<string> {\n const args = ['commit', '-m', message]\n if (options?.author) {\n args.push('--author', options.author)\n }\n await gitCommand(args, options?.directory)\n const stdout = await gitCommand(['rev-parse', 'HEAD'], options?.directory)\n return stdout.trim()\n}\n\n/**\n * Get the HEAD symbolic reference of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The HEAD symbolic reference of the repository.\n */\nexport async function getHeadSymbolicRef(directory?: string): Promise<string> {\n const ref = await gitCommand(['symbolic-ref', '-q', 'HEAD'], directory)\n if (!ref) {\n throw new AbortError(\n \"Git HEAD can't be detached to run command\",\n outputContent`Run ${outputToken.genericShellCommand(\n 'git checkout [branchName]',\n )} to reattach HEAD or see git ${outputToken.link(\n 'documentation',\n 'https://git-scm.com/book/en/v2/Git-Internals-Git-References',\n )} for more details`,\n )\n }\n return ref.trim()\n}\n\n/**\n * If \"git\" is not present in the environment it throws\n * an abort error.\n */\nexport async function ensureGitIsPresentOrAbort(): Promise<void> {\n if (!(await hasGit())) {\n throw new AbortError(\n `Git is necessary in the environment to continue`,\n outputContent`Install ${outputToken.link(\n 'git',\n 'https://git-scm.com/book/en/v2/Getting-Started-Installing-Git',\n )}`,\n )\n }\n}\n\nexport class OutsideGitDirectoryError extends AbortError {}\n/**\n * If command run from outside a .git directory tree\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureInsideGitDirectory(directory?: string): Promise<void> {\n if (!(await insideGitDirectory(directory))) {\n throw new OutsideGitDirectoryError(`${outputToken.path(directory ?? cwd())} is not a Git directory`)\n }\n}\n\n/**\n * Returns true if the given directory is inside a .git directory tree.\n *\n * @param directory - The directory to check.\n * @returns True if the directory is inside a .git directory tree.\n */\nexport async function insideGitDirectory(directory?: string): Promise<boolean> {\n try {\n await execa('git', ['rev-parse', '--git-dir'], {cwd: directory})\n return true\n } catch (error) {\n if (error instanceof Error && 'exitCode' in error && error.exitCode === 128) return false\n throw error\n }\n}\n\nexport class GitDirectoryNotCleanError extends AbortError {}\n/**\n * If the .git directory tree is not clean (has uncommitted changes)\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureIsClean(directory?: string): Promise<void> {\n if (!(await isClean(directory))) {\n throw new GitDirectoryNotCleanError(`${outputToken.path(directory ?? cwd())} is not a clean Git directory`)\n }\n}\n\n/**\n * Returns true if the .git directory tree is clean (no uncommitted changes).\n *\n * @param directory - The directory to check.\n * @returns True is the .git directory is clean.\n */\nexport async function isClean(directory?: string): Promise<boolean> {\n const stdout = await gitCommand(['status', '--porcelain'], directory)\n return stdout.trim() === ''\n}\n\n/**\n * Returns the latest tag of a git repository.\n *\n * @param directory - The directory to check.\n * @returns String with the latest tag or undefined if no tags are found.\n */\nexport async function getLatestTag(directory?: string): Promise<string | undefined> {\n try {\n const stdout = await gitCommand(['describe', '--tags', '--abbrev=0'], directory)\n return stdout.trim() || undefined\n } catch (error) {\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 128) return undefined\n throw error\n }\n}\n\n/**\n * Remove a git remote from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @param remoteName - The name of the remote to remove (defaults to 'origin').\n * @returns A promise that resolves when the remote is removed.\n */\nexport async function removeGitRemote(directory: string, remoteName = 'origin'): Promise<void> {\n outputDebug(outputContent`Removing git remote ${remoteName} from ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n\n const stdout = await gitCommand(['remote'], directory)\n const remotes = stdout.split('\\n').filter(Boolean)\n\n if (!remotes.includes(remoteName)) {\n outputDebug(outputContent`Remote ${remoteName} does not exist, no action needed`)\n return\n }\n\n await gitCommand(['remote', 'remove', remoteName], directory)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/public/node/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AACnE,OAAO,EAAC,MAAM,EAAE,qBAAqB,EAAC,MAAM,oBAAoB,CAAA;AAChE,OAAO,EACL,cAAc,EACd,SAAS,EACT,UAAU,EACV,cAAc,EACd,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAA;AAChB,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AACrC,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAC,MAAM,WAAW,CAAA;AACvC,OAAO,EAAC,YAAY,EAAC,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAC,KAAK,EAAC,MAAM,OAAO,CAAA;AAE3B,OAAO,MAAM,MAAM,QAAQ,CAAA;AAY3B,KAAK,UAAU,UAAU,CAAC,IAAc,EAAE,SAAkB;IAC1D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,EAAC,GAAG,EAAE,SAAS,EAAC,CAAC,CAAA;QACzD,OAAO,MAAM,CAAC,MAAM,CAAA;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC9C,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;YAC5B,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;gBACtB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,EAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAC,CAAC,CAAA;YACrD,CAAC;YACD,MAAM,UAAU,CAAA;QAClB,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,SAAiB,EAAE,aAAa,GAAG,MAAM;IACrF,WAAW,CAAC,aAAa,CAAA,kCAAkC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC5F,MAAM,yBAAyB,EAAE,CAAA;IACjC,gHAAgH;IAChH,MAAM,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAA;IACrC,MAAM,UAAU,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE,SAAS,CAAC,CAAA;AAChE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,SAAiB,EAAE,KAAe;IACpF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,cAAc,EAAE,GAAG,KAAK,CAAC,EAAE,SAAS,CAAC,CAAA;QACtE,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+DAA+D;QAC/D,IAAI,KAAK,YAAY,UAAU,IAAI,UAAU,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QACzF,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAGD;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,QAA2B;IAC5E,WAAW,CAAC,aAAa,CAAA,0BAA0B,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACpF,MAAM,QAAQ,GAAG,GAAG,SAAS,aAAa,CAAA;IAE1C,IAAI,WAAW,GAAG,EAAE,CAAA;IACpB,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,WAAW,IAAI,KAAK,OAAO,IAAI,CAAA;QAC/B,WAAW,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA;IAC1C,CAAC;IAED,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;AACvC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAa;IACxD,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;IAElD,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;QACnC,+FAA+F;QAC/F,OAAM;IACR,CAAC;IAED,MAAM,gBAAgB,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC/D,MAAM,GAAG,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAA;IAEvC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACpE,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,EAAC,kBAAkB,EAAE,IAAI,EAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAE3E,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7D,MAAM,mBAAmB,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAA;IACjF,MAAM,gBAAgB,GAAG,cAAc,IAAI,mBAAmB,CAAA;IAC9D,IAAI,gBAAgB,EAAE,CAAC;QACrB,qDAAqD;QACrD,OAAM;IACR,CAAC;IAED,IAAI,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,aAAa,CAAC,aAAa,EAAE,GAAG,gBAAgB,GAAG,KAAK,GAAG,GAAG,EAAE,CAAC,CAAA;IACnE,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,aAAa,EAAE,GAAG,gBAAgB,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,EAAE,CAAC,CAAA;IACzE,CAAC;AACH,CAAC;AAgBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,YAA6B;IACvE,OAAO,YAAY,CAAC,2BAA2B,CAAC,CAAC,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAC,GAAG,YAAY,CAAA;QAC/D,WAAW,CAAC,aAAa,CAAA,0BAA0B,OAAO,SAAS,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;QACtG,MAAM,yBAAyB,EAAE,CAAA;QAEjC,4DAA4D;QAC5D,IAAI,MAAM,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAClC,4BAA4B;YAC5B,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;gBACtC,MAAM,IAAI,UAAU,CAClB,aAAa,CAAA,kBAAkB,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAC9D,wCAAwC,CACzC,CAAA;YACH,CAAC;YAED,8BAA8B;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE;gBACtC,GAAG,EAAE,WAAW;gBAChB,IAAI,EAAE,CAAC;gBACP,SAAS,EAAE,KAAK;aACjB,CAAC,CAAA;YAEF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,UAAU,CAClB,aAAa,CAAA,aAAa,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,kCAAkC,EACzF,aAAa,CAAA,iEAAiE,CAC/E,CAAA;YACH,CAAC;QACH,CAAC;QAED,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAE/C,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,UAAU,CAAC,mFAAmF,CAAC,CAAA;QAC3G,CAAC;QAED,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,UAAU,CAClB,+FAA+F,CAChG,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAA;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;QAC/B,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QAC3B,CAAC;QACD,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,UAAW,EAAE,WAAW,CAAC,CAAA;QAEnC,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YAExB,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,MAAM,yBAAyB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;gBACjE,MAAM,UAAU,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,WAAW,CAAC,CAAA;YAClD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;gBAC9B,MAAM,GAAG,CAAA;YACX,CAAC;YACD,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAC9C,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;gBAC5B,MAAM,UAAU,CAAA;YAClB,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,SAAiB,EAAE,OAAe;IACzE,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAA;IAEzC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,UAAU,CAAC,yDAAyD,OAAO,EAAE,CAAC,CAAA;IAC1F,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAkB;IACzD,MAAM,MAAM,GAAG,2CAA2C,CAAA;IAC1D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,MAAM,EAAE,CAAC,EAAE,SAAS,CAAC,CAAA;IAC/E,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,UAAU,CAClB,8CAA8C,EAC9C,aAAa,CAAA,OAAO,WAAW,CAAC,mBAAmB,CACjD,gCAAgC,CACjC,+BAA+B,CACjC,CAAA;IACH,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAClC,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE;QACf,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE;QACf,OAAO,EAAE,KAAK,CAAC,CAAC,CAAE;QAClB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE;QACf,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE;QACf,WAAW,EAAE,KAAK,CAAC,CAAC,CAAE;QACtB,YAAY,EAAE,KAAK,CAAC,CAAC,CAAE;KACxB,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,SAAkB;IAC/D,MAAM,UAAU,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAA;AAC/C,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe,EAAE,OAAgC;IACrF,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACtC,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC;IACD,MAAM,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;IAC1E,OAAO,MAAM,CAAC,IAAI,EAAE,CAAA;AACtB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAkB;IACzD,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,CAAA;IACvE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,UAAU,CAClB,2CAA2C,EAC3C,aAAa,CAAA,OAAO,WAAW,CAAC,mBAAmB,CACjD,2BAA2B,CAC5B,gCAAgC,WAAW,CAAC,IAAI,CAC/C,eAAe,EACf,6DAA6D,CAC9D,mBAAmB,CACrB,CAAA;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAC7C,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAClB,iDAAiD,EACjD,aAAa,CAAA,WAAW,WAAW,CAAC,IAAI,CACtC,KAAK,EACL,+DAA+D,CAChE,EAAE,CACJ,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,OAAO,wBAAyB,SAAQ,UAAU;CAAG;AAC3D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,SAAkB;IAC/D,MAAM,yBAAyB,EAAE,CAAA;IAEjC,IAAI,CAAC,CAAC,MAAM,yBAAyB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,wBAAwB,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC,yBAAyB,CAAC,CAAA;IACtG,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAkB;IACzD,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,yBAAyB,CAAC,SAAS,CAAC,CAAA;AAC7C,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,SAAkB;IACzD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAC,GAAG,EAAE,SAAS,EAAC,CAAC,CAAA;QAChE,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,UAAU,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,GAAG;YAAE,OAAO,KAAK,CAAA;QACzF,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,OAAO,yBAA0B,SAAQ,UAAU;CAAG;AAC5D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAkB;IACpD,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,yBAAyB,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC,+BAA+B,CAAC,CAAA;IAC7G,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,SAAkB;IAC9C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,SAAS,CAAC,CAAA;IACrE,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAkB;IACnD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,SAAS,CAAC,CAAA;QAChF,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,CAAA;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,UAAU,IAAI,UAAU,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,GAAG;YAAE,OAAO,SAAS,CAAA;QAClG,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB,EAAE,UAAU,GAAG,QAAQ;IAC5E,WAAW,CAAC,aAAa,CAAA,uBAAuB,UAAU,SAAS,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACpG,MAAM,yBAAyB,EAAE,CAAA;IAEjC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAA;IACtD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAElD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,WAAW,CAAC,aAAa,CAAA,UAAU,UAAU,mCAAmC,CAAC,CAAA;QACjF,OAAM;IACR,CAAC;IAED,MAAM,UAAU,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,SAAS,CAAC,CAAA;AAC/D,CAAC","sourcesContent":["import {outputContent, outputToken, outputDebug} from './output.js'\nimport {hasGit, isTerminalInteractive} from './context/local.js'\nimport {\n appendFileSync,\n detectEOL,\n fileExists,\n fileExistsSync,\n glob,\n isDirectory,\n readFileSync,\n writeFileSync,\n} from './fs.js'\nimport {AbortError} from './error.js'\nimport {cwd, joinPath} from './path.js'\nimport {runWithTimer} from './metadata.js'\nimport {execa} from 'execa'\n\nimport ignore from 'ignore'\n\nexport interface GitLogEntry {\n hash: string\n date: string\n message: string\n refs: string\n body: string\n author_name: string\n author_email: string\n}\n\nasync function gitCommand(args: string[], directory?: string): Promise<string> {\n try {\n const result = await execa('git', args, {cwd: directory})\n return result.stdout\n } catch (err) {\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n if ('exitCode' in err) {\n Object.assign(abortError, {exitCode: err.exitCode})\n }\n throw abortError\n }\n throw err\n }\n}\n\n/**\n * Initialize a git repository at the given directory.\n *\n * @param directory - The directory where the git repository will be initialized.\n * @param initialBranch - The name of the initial branch.\n */\nexport async function initializeGitRepository(directory: string, initialBranch = 'main'): Promise<void> {\n outputDebug(outputContent`Initializing git repository at ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n // We use init and checkout instead of `init --initial-branch` because the latter is only supported in git 2.28+\n await gitCommand(['init'], directory)\n await gitCommand(['checkout', '-b', initialBranch], directory)\n}\n\n/**\n * Given a Git repository and a list of absolute paths to files contained\n * in the repository, it filters and returns the files that are ignored\n * by the .gitignore.\n *\n * @param directory - The absolute path to the directory containing the files.\n * @param files - The list of files to check against.\n * @returns Files ignored by the lockfile.\n */\nexport async function checkIfIgnoredInGitRepository(directory: string, files: string[]): Promise<string[]> {\n try {\n const stdout = await gitCommand(['check-ignore', ...files], directory)\n return stdout.split('\\n').filter(Boolean)\n } catch (error) {\n // git check-ignore exits with code 1 when no files are ignored\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 1) return []\n throw error\n }\n}\n\nexport type GitIgnoreTemplate = Record<string, string[]>\n/**\n * Create a .gitignore file in the given directory.\n *\n * @param directory - The directory where the .gitignore file will be created.\n * @param template - The template to use to create the .gitignore file.\n */\nexport function createGitIgnore(directory: string, template: GitIgnoreTemplate): void {\n outputDebug(outputContent`Creating .gitignore at ${outputToken.path(directory)}...`)\n const filePath = `${directory}/.gitignore`\n\n let fileContent = ''\n for (const [section, lines] of Object.entries(template)) {\n fileContent += `# ${section}\\n`\n fileContent += `${lines.join('\\n')}\\n\\n`\n }\n\n appendFileSync(filePath, fileContent)\n}\n\n/**\n * Add an entry to an existing .gitignore file.\n *\n * If the .gitignore file doesn't exist, or if the entry is already present,\n * no changes will be made.\n *\n * @param root - The directory containing the .gitignore file.\n * @param entry - The entry to add to the .gitignore file.\n */\nexport function addToGitIgnore(root: string, entry: string): void {\n const gitIgnorePath = joinPath(root, '.gitignore')\n\n if (!fileExistsSync(gitIgnorePath)) {\n // When the .gitignore file does not exist, the CLI should not be opinionated about creating it\n return\n }\n\n const gitIgnoreContent = readFileSync(gitIgnorePath).toString()\n const eol = detectEOL(gitIgnoreContent)\n\n const lines = gitIgnoreContent.split(eol).map((line) => line.trim())\n const ignoreManager = ignore.default({allowRelativePaths: true}).add(lines)\n\n const isIgnoredEntry = ignoreManager.ignores(joinPath(entry))\n const isIgnoredEntryAsDir = ignoreManager.ignores(joinPath(entry, 'ignored.txt'))\n const isAlreadyIgnored = isIgnoredEntry || isIgnoredEntryAsDir\n if (isAlreadyIgnored) {\n // The file is already ignored by an existing pattern\n return\n }\n\n if (gitIgnoreContent.endsWith(eol)) {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${entry}${eol}`)\n } else {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${eol}${entry}${eol}`)\n }\n}\n\n/**\n * Options to use when cloning a git repository.\n *\n * @param repoUrl - The URL of the repository to clone.\n * @param destination - The directory where the repository will be cloned.\n * @param shallow - Whether to clone the repository shallowly.\n * @param latestTag - Whether to clone the latest tag instead of the default branch.\n */\nexport interface GitCloneOptions {\n repoUrl: string\n destination: string\n shallow?: boolean\n latestTag?: boolean\n}\n/**\n * Clone a git repository.\n *\n * @param cloneOptions - The options to use to clone the repository.\n * @returns A promise that resolves when the clone is complete.\n */\nexport async function downloadGitRepository(cloneOptions: GitCloneOptions): Promise<void> {\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n const {repoUrl, destination, shallow, latestTag} = cloneOptions\n outputDebug(outputContent`Git-cloning repository ${repoUrl} into ${outputToken.path(destination)}...`)\n await ensureGitIsPresentOrAbort()\n\n // Validate destination directory before attempting to clone\n if (await fileExists(destination)) {\n // Check if it's a directory\n if (!(await isDirectory(destination))) {\n throw new AbortError(\n outputContent`Can't clone to ${outputToken.path(destination)}`,\n \"The path exists but isn't a directory.\",\n )\n }\n\n // Check if directory is empty\n const entries = await glob(['*', '.*'], {\n cwd: destination,\n deep: 1,\n onlyFiles: false,\n })\n\n if (entries.length > 0) {\n throw new AbortError(\n outputContent`Directory ${outputToken.path(destination)} already exists and is not empty`,\n outputContent`Choose a different name or remove the existing directory first.`,\n )\n }\n }\n\n const [repository, branch] = repoUrl.split('#')\n\n if (branch && latestTag) {\n throw new AbortError(\"Error cloning the repository. Git can't clone the latest release with a 'branch'.\")\n }\n\n if (shallow && latestTag) {\n throw new AbortError(\n \"Error cloning the repository. Git can't clone the latest release with the 'shallow' property.\",\n )\n }\n\n const args = ['clone', '--recurse-submodules']\n if (branch) {\n args.push('--branch', branch)\n }\n if (shallow) {\n args.push('--depth', '1')\n }\n if (!isTerminalInteractive()) {\n args.push('-c', 'core.askpass=true')\n }\n args.push(repository!, destination)\n\n try {\n await execa('git', args)\n\n if (latestTag) {\n const tag = await getLatestTagFromDirectory(destination, repoUrl)\n await gitCommand(['checkout', tag], destination)\n }\n } catch (err) {\n if (err instanceof AbortError) {\n throw err\n }\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n throw abortError\n }\n throw err\n }\n })\n}\n\nasync function getLatestTagFromDirectory(directory: string, repoUrl: string): Promise<string> {\n const tag = await getLatestTag(directory)\n\n if (!tag) {\n throw new AbortError(`Couldn't obtain the most recent tag of the repository ${repoUrl}`)\n }\n\n return tag\n}\n\n/**\n * Get the latest commit of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The latest commit of the repository.\n */\nexport async function getLatestGitCommit(directory?: string): Promise<GitLogEntry> {\n const format = '%H%x00%ai%x00%s%x00%D%x00%b%x00%an%x00%ae'\n const stdout = await gitCommand(['log', '-1', `--format=${format}`], directory)\n if (!stdout.trim()) {\n throw new AbortError(\n 'Must have at least one commit to run command',\n outputContent`Run ${outputToken.genericShellCommand(\n \"git commit -m 'Initial commit'\",\n )} to create your first commit.`,\n )\n }\n const parts = stdout.split('\\x00')\n return {\n hash: parts[0]!,\n date: parts[1]!,\n message: parts[2]!,\n refs: parts[3]!,\n body: parts[4]!,\n author_name: parts[5]!,\n author_email: parts[6]!,\n }\n}\n\n/**\n * Add all files to the git index from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @returns A promise that resolves when the files are added to the index.\n */\nexport async function addAllToGitFromDirectory(directory?: string): Promise<void> {\n await gitCommand(['add', '--all'], directory)\n}\n\nexport interface CreateGitCommitOptions {\n directory?: string\n author?: string\n}\n\n/**\n * Create a git commit.\n *\n * @param message - The message of the commit.\n * @param options - The options to use to create the commit.\n * @returns The hash of the created commit.\n */\nexport async function createGitCommit(message: string, options?: CreateGitCommitOptions): Promise<string> {\n const args = ['commit', '-m', message]\n if (options?.author) {\n args.push('--author', options.author)\n }\n await gitCommand(args, options?.directory)\n const stdout = await gitCommand(['rev-parse', 'HEAD'], options?.directory)\n return stdout.trim()\n}\n\n/**\n * Get the HEAD symbolic reference of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The HEAD symbolic reference of the repository.\n */\nexport async function getHeadSymbolicRef(directory?: string): Promise<string> {\n const ref = await gitCommand(['symbolic-ref', '-q', 'HEAD'], directory)\n if (!ref) {\n throw new AbortError(\n \"Git HEAD can't be detached to run command\",\n outputContent`Run ${outputToken.genericShellCommand(\n 'git checkout [branchName]',\n )} to reattach HEAD or see git ${outputToken.link(\n 'documentation',\n 'https://git-scm.com/book/en/v2/Git-Internals-Git-References',\n )} for more details`,\n )\n }\n return ref.trim()\n}\n\n/**\n * If \"git\" is not present in the environment it throws\n * an abort error.\n */\nexport async function ensureGitIsPresentOrAbort(): Promise<void> {\n if (!(await hasGit())) {\n throw new AbortError(\n `Git is necessary in the environment to continue`,\n outputContent`Install ${outputToken.link(\n 'git',\n 'https://git-scm.com/book/en/v2/Getting-Started-Installing-Git',\n )}`,\n )\n }\n}\n\nexport class OutsideGitDirectoryError extends AbortError {}\n/**\n * If command run from outside a .git directory tree\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureInsideGitDirectory(directory?: string): Promise<void> {\n await ensureGitIsPresentOrAbort()\n\n if (!(await checkIfInsideGitDirectory(directory))) {\n throw new OutsideGitDirectoryError(`${outputToken.path(directory ?? cwd())} is not a Git directory`)\n }\n}\n\n/**\n * Returns true if the given directory is inside a .git directory tree.\n *\n * @param directory - The directory to check.\n * @returns True if the directory is inside a .git directory tree.\n */\nexport async function insideGitDirectory(directory?: string): Promise<boolean> {\n if (!(await hasGit())) {\n return false\n }\n\n return checkIfInsideGitDirectory(directory)\n}\n\nasync function checkIfInsideGitDirectory(directory?: string): Promise<boolean> {\n try {\n await execa('git', ['rev-parse', '--git-dir'], {cwd: directory})\n return true\n } catch (error) {\n if (error instanceof Error && 'exitCode' in error && error.exitCode === 128) return false\n throw error\n }\n}\n\nexport class GitDirectoryNotCleanError extends AbortError {}\n/**\n * If the .git directory tree is not clean (has uncommitted changes)\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureIsClean(directory?: string): Promise<void> {\n if (!(await isClean(directory))) {\n throw new GitDirectoryNotCleanError(`${outputToken.path(directory ?? cwd())} is not a clean Git directory`)\n }\n}\n\n/**\n * Returns true if the .git directory tree is clean (no uncommitted changes).\n *\n * @param directory - The directory to check.\n * @returns True is the .git directory is clean.\n */\nexport async function isClean(directory?: string): Promise<boolean> {\n const stdout = await gitCommand(['status', '--porcelain'], directory)\n return stdout.trim() === ''\n}\n\n/**\n * Returns the latest tag of a git repository.\n *\n * @param directory - The directory to check.\n * @returns String with the latest tag or undefined if no tags are found.\n */\nexport async function getLatestTag(directory?: string): Promise<string | undefined> {\n try {\n const stdout = await gitCommand(['describe', '--tags', '--abbrev=0'], directory)\n return stdout.trim() || undefined\n } catch (error) {\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 128) return undefined\n throw error\n }\n}\n\n/**\n * Remove a git remote from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @param remoteName - The name of the remote to remove (defaults to 'origin').\n * @returns A promise that resolves when the remote is removed.\n */\nexport async function removeGitRemote(directory: string, remoteName = 'origin'): Promise<void> {\n outputDebug(outputContent`Removing git remote ${remoteName} from ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n\n const stdout = await gitCommand(['remote'], directory)\n const remotes = stdout.split('\\n').filter(Boolean)\n\n if (!remotes.includes(remoteName)) {\n outputDebug(outputContent`Remote ${remoteName} does not exist, no action needed`)\n return\n }\n\n await gitCommand(['remote', 'remove', remoteName], directory)\n}\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Server } from 'http';
|
|
2
|
+
import { Writable } from 'stream';
|
|
3
|
+
/**
|
|
4
|
+
* Derives a deterministic GraphiQL authentication key from the app's API secret and store FQDN.
|
|
5
|
+
* The key is stable across dev server restarts (so browser tabs survive restarts)
|
|
6
|
+
* but is not guessable without the app secret.
|
|
7
|
+
*
|
|
8
|
+
* @param apiSecret - The Partners app's client secret used as the HMAC key.
|
|
9
|
+
* @param storeFqdn - The myshopify.com domain the GraphiQL session targets.
|
|
10
|
+
* @returns A 64-character hex string suitable for use as the `?key=` query param.
|
|
11
|
+
*/
|
|
12
|
+
export declare function deriveGraphiQLKey(apiSecret: string, storeFqdn: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the GraphiQL authentication key. Uses the explicitly provided key
|
|
15
|
+
* if non-empty, otherwise derives one deterministically from the app secret.
|
|
16
|
+
*
|
|
17
|
+
* @param providedKey - An explicit key supplied by the caller; takes precedence when non-empty.
|
|
18
|
+
* @param apiSecret - The Partners app's client secret, used to derive a stable key as a fallback.
|
|
19
|
+
* @param storeFqdn - The myshopify.com domain the GraphiQL session targets.
|
|
20
|
+
* @returns The resolved key.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveGraphiQLKey(providedKey: string | undefined, apiSecret: string, storeFqdn: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Pluggable strategy for obtaining and refreshing the Admin API access token
|
|
25
|
+
* that the GraphiQL proxy injects into every request.
|
|
26
|
+
*
|
|
27
|
+
* - `getToken` may return a cached token; the proxy calls it for every request.
|
|
28
|
+
* - `refreshToken` (optional) is invoked when the upstream Admin API returns 401.
|
|
29
|
+
* When omitted, the proxy falls back to calling `getToken` again on 401.
|
|
30
|
+
*
|
|
31
|
+
* Implementations must throw `TokenRefreshError` (or any thrown error) when the
|
|
32
|
+
* token cannot be obtained; the proxy renders the unauthorized template in that case.
|
|
33
|
+
*/
|
|
34
|
+
export interface TokenProvider {
|
|
35
|
+
getToken: () => Promise<string>;
|
|
36
|
+
refreshToken?: () => Promise<string>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Optional app-specific context, used to render the app pill and scopes note in the
|
|
40
|
+
* GraphiQL header and to drive the deterministic key derivation. Pass when the GraphiQL
|
|
41
|
+
* server is hosted as part of `shopify app dev`; omit for app-less use cases such as
|
|
42
|
+
* `shopify store execute`.
|
|
43
|
+
*/
|
|
44
|
+
export interface GraphiQLAppContext {
|
|
45
|
+
appName: string;
|
|
46
|
+
appUrl: string;
|
|
47
|
+
apiSecret: string;
|
|
48
|
+
}
|
|
49
|
+
export interface SetupGraphiQLServerOptions {
|
|
50
|
+
stdout: Writable;
|
|
51
|
+
port: number;
|
|
52
|
+
storeFqdn: string;
|
|
53
|
+
tokenProvider: TokenProvider;
|
|
54
|
+
/**
|
|
55
|
+
* Authentication key required as a `?key=` query string on every request. When omitted:
|
|
56
|
+
* - if `appContext` is provided, derived deterministically from `apiSecret` + `storeFqdn`
|
|
57
|
+
* so browser tabs survive dev server restarts.
|
|
58
|
+
* - otherwise, generated randomly per process.
|
|
59
|
+
*/
|
|
60
|
+
key?: string;
|
|
61
|
+
appContext?: GraphiQLAppContext;
|
|
62
|
+
/**
|
|
63
|
+
* When true, the proxy rejects mutation operations with HTTP 400 before forwarding
|
|
64
|
+
* them to the Admin API. Use this to mirror non-interactive safety guarantees in the
|
|
65
|
+
* interactive UI.
|
|
66
|
+
*/
|
|
67
|
+
protectMutations?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export declare const MUTATIONS_BLOCKED_MESSAGE = "Mutations are disabled. Re-run with --allow-mutations to enable mutations.";
|
|
70
|
+
/**
|
|
71
|
+
* Starts a local HTTP server that hosts the GraphiQL UI and proxies requests to the
|
|
72
|
+
* Admin API for the configured store. Authentication is delegated to the supplied
|
|
73
|
+
* `tokenProvider`, so the same server can serve both `shopify app dev` and stored-session
|
|
74
|
+
* use cases.
|
|
75
|
+
*
|
|
76
|
+
* @param options - Configuration for the server, including the target store, the
|
|
77
|
+
* pluggable token provider, and the local port to bind to.
|
|
78
|
+
* @returns The underlying Node `http.Server` instance, already listening on `options.port`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function setupGraphiQLServer(options: SetupGraphiQLServerOptions): Server;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { defaultQuery, graphiqlTemplate } from './templates/graphiql.js';
|
|
2
|
+
import { unauthorizedTemplate } from './templates/unauthorized.js';
|
|
3
|
+
import { filterCustomHeaders } from './utilities.js';
|
|
4
|
+
import { performActionWithRetryAfterRecovery } from '../../common/retry.js';
|
|
5
|
+
import { CLI_KIT_VERSION } from '../../common/version.js';
|
|
6
|
+
import { AbortError } from '../error.js';
|
|
7
|
+
import { adminUrl, supportedApiVersions } from '../api/admin.js';
|
|
8
|
+
import { fetch } from '../http.js';
|
|
9
|
+
import { renderLiquidTemplate } from '../liquid.js';
|
|
10
|
+
import { outputDebug } from '../output.js';
|
|
11
|
+
import { containsMutation } from '../graphql.js';
|
|
12
|
+
import { createApp, createRouter, defineEventHandler, getQuery, getRequestHeader, getRequestHeaders, readBody, setResponseHeader, setResponseStatus, toNodeListener, } from 'h3';
|
|
13
|
+
import { createHmac, randomBytes } from 'crypto';
|
|
14
|
+
import { createServer } from 'http';
|
|
15
|
+
import { readFileSync } from 'fs';
|
|
16
|
+
import { createRequire } from 'module';
|
|
17
|
+
/**
|
|
18
|
+
* Derives a deterministic GraphiQL authentication key from the app's API secret and store FQDN.
|
|
19
|
+
* The key is stable across dev server restarts (so browser tabs survive restarts)
|
|
20
|
+
* but is not guessable without the app secret.
|
|
21
|
+
*
|
|
22
|
+
* @param apiSecret - The Partners app's client secret used as the HMAC key.
|
|
23
|
+
* @param storeFqdn - The myshopify.com domain the GraphiQL session targets.
|
|
24
|
+
* @returns A 64-character hex string suitable for use as the `?key=` query param.
|
|
25
|
+
*/
|
|
26
|
+
export function deriveGraphiQLKey(apiSecret, storeFqdn) {
|
|
27
|
+
return createHmac('sha256', apiSecret).update(`graphiql:${storeFqdn}`).digest('hex');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolves the GraphiQL authentication key. Uses the explicitly provided key
|
|
31
|
+
* if non-empty, otherwise derives one deterministically from the app secret.
|
|
32
|
+
*
|
|
33
|
+
* @param providedKey - An explicit key supplied by the caller; takes precedence when non-empty.
|
|
34
|
+
* @param apiSecret - The Partners app's client secret, used to derive a stable key as a fallback.
|
|
35
|
+
* @param storeFqdn - The myshopify.com domain the GraphiQL session targets.
|
|
36
|
+
* @returns The resolved key.
|
|
37
|
+
*/
|
|
38
|
+
export function resolveGraphiQLKey(providedKey, apiSecret, storeFqdn) {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- intentional: empty string after trim should fall through to deriveGraphiQLKey
|
|
40
|
+
return providedKey?.trim() || deriveGraphiQLKey(apiSecret, storeFqdn);
|
|
41
|
+
}
|
|
42
|
+
const require = createRequire(import.meta.url);
|
|
43
|
+
class TokenRefreshError extends AbortError {
|
|
44
|
+
constructor() {
|
|
45
|
+
super('Failed to refresh credentials. Check that your app is installed, and try again.');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export const MUTATIONS_BLOCKED_MESSAGE = 'Mutations are disabled. Re-run with --allow-mutations to enable mutations.';
|
|
49
|
+
/**
|
|
50
|
+
* Starts a local HTTP server that hosts the GraphiQL UI and proxies requests to the
|
|
51
|
+
* Admin API for the configured store. Authentication is delegated to the supplied
|
|
52
|
+
* `tokenProvider`, so the same server can serve both `shopify app dev` and stored-session
|
|
53
|
+
* use cases.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Configuration for the server, including the target store, the
|
|
56
|
+
* pluggable token provider, and the local port to bind to.
|
|
57
|
+
* @returns The underlying Node `http.Server` instance, already listening on `options.port`.
|
|
58
|
+
*/
|
|
59
|
+
export function setupGraphiQLServer(options) {
|
|
60
|
+
const { stdout, port, storeFqdn, tokenProvider, key: providedKey, appContext, protectMutations = false } = options;
|
|
61
|
+
const key = resolveGraphiQLServerKey(providedKey, appContext, storeFqdn);
|
|
62
|
+
outputDebug(`Setting up GraphiQL HTTP server on port ${port}...`, stdout);
|
|
63
|
+
const app = createApp();
|
|
64
|
+
const router = createRouter();
|
|
65
|
+
const refreshUpstreamToken = async () => {
|
|
66
|
+
try {
|
|
67
|
+
outputDebug('refreshing token', stdout);
|
|
68
|
+
return await (tokenProvider.refreshToken ?? tokenProvider.getToken)();
|
|
69
|
+
}
|
|
70
|
+
catch (_error) {
|
|
71
|
+
throw new TokenRefreshError();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const currentToken = async () => {
|
|
75
|
+
try {
|
|
76
|
+
return await tokenProvider.getToken();
|
|
77
|
+
}
|
|
78
|
+
catch (_error) {
|
|
79
|
+
throw new TokenRefreshError();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
async function fetchApiVersionsWithTokenRefresh() {
|
|
83
|
+
return performActionWithRetryAfterRecovery(async () => supportedApiVersions({ storeFqdn, token: await currentToken() }), refreshUpstreamToken);
|
|
84
|
+
}
|
|
85
|
+
const faviconPath = require.resolve('@shopify/cli-kit/assets/graphiql/favicon.ico');
|
|
86
|
+
const faviconContent = readFileSync(faviconPath);
|
|
87
|
+
const stylePath = require.resolve('@shopify/cli-kit/assets/graphiql/style.css');
|
|
88
|
+
const styleContent = readFileSync(stylePath, 'utf8');
|
|
89
|
+
app.use(defineEventHandler((event) => {
|
|
90
|
+
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
|
|
91
|
+
setResponseHeader(event, 'Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
92
|
+
setResponseHeader(event, 'Access-Control-Allow-Headers', 'Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, ngrok-skip-browser-warning');
|
|
93
|
+
}));
|
|
94
|
+
router.get('/graphiql/ping', defineEventHandler(() => 'pong'));
|
|
95
|
+
router.get('/graphiql/favicon.ico', defineEventHandler((event) => {
|
|
96
|
+
setResponseHeader(event, 'Content-Type', 'image/x-icon');
|
|
97
|
+
return faviconContent;
|
|
98
|
+
}));
|
|
99
|
+
router.get('/graphiql/simple.css', defineEventHandler((event) => {
|
|
100
|
+
setResponseHeader(event, 'Content-Type', 'text/css');
|
|
101
|
+
return styleContent;
|
|
102
|
+
}));
|
|
103
|
+
router.get('/graphiql/status', defineEventHandler(async () => {
|
|
104
|
+
try {
|
|
105
|
+
await fetchApiVersionsWithTokenRefresh();
|
|
106
|
+
return { status: 'OK', storeFqdn, appName: appContext?.appName, appUrl: appContext?.appUrl };
|
|
107
|
+
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return { status: 'UNAUTHENTICATED' };
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
113
|
+
router.get('/graphiql', defineEventHandler(async (event) => {
|
|
114
|
+
outputDebug('Handling /graphiql request', stdout);
|
|
115
|
+
const query = getQuery(event);
|
|
116
|
+
if (key && query.key !== key) {
|
|
117
|
+
setResponseStatus(event, 404);
|
|
118
|
+
return `Invalid path ${event.path}`;
|
|
119
|
+
}
|
|
120
|
+
const forwardedProto = getRequestHeader(event, 'x-forwarded-proto');
|
|
121
|
+
const usesHttps = forwardedProto === 'https';
|
|
122
|
+
const host = getRequestHeader(event, 'host');
|
|
123
|
+
const url = `http${usesHttps ? 's' : ''}://${host}`;
|
|
124
|
+
let apiVersions;
|
|
125
|
+
try {
|
|
126
|
+
apiVersions = await fetchApiVersionsWithTokenRefresh();
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (err instanceof TokenRefreshError) {
|
|
130
|
+
return renderLiquidTemplate(unauthorizedTemplate({ hasAppContext: Boolean(appContext) }), {
|
|
131
|
+
previewUrl: appContext?.appUrl ?? '',
|
|
132
|
+
storeFqdn,
|
|
133
|
+
url,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
const apiVersion = apiVersions.sort().reverse()[0];
|
|
139
|
+
function decodeQueryString(input) {
|
|
140
|
+
return input ? decodeURIComponent(input).replace(/\n/g, '\\n') : undefined;
|
|
141
|
+
}
|
|
142
|
+
const queryParam = decodeQueryString(query.query);
|
|
143
|
+
const variables = decodeQueryString(query.variables);
|
|
144
|
+
return renderLiquidTemplate(graphiqlTemplate({
|
|
145
|
+
apiVersion,
|
|
146
|
+
apiVersions: [...apiVersions, 'unstable'],
|
|
147
|
+
appName: appContext?.appName,
|
|
148
|
+
appUrl: appContext?.appUrl,
|
|
149
|
+
key,
|
|
150
|
+
storeFqdn,
|
|
151
|
+
protectMutations,
|
|
152
|
+
}), {
|
|
153
|
+
url,
|
|
154
|
+
defaultQueries: [{ query: defaultQuery }],
|
|
155
|
+
query: queryParam ? JSON.stringify(queryParam) : undefined,
|
|
156
|
+
variables: variables ? JSON.stringify(variables) : undefined,
|
|
157
|
+
});
|
|
158
|
+
}));
|
|
159
|
+
router.post('/graphiql/graphql.json', defineEventHandler(async (event) => {
|
|
160
|
+
outputDebug('Handling /graphiql/graphql.json request', stdout);
|
|
161
|
+
const query = getQuery(event);
|
|
162
|
+
if (key && query.key !== key) {
|
|
163
|
+
setResponseStatus(event, 404);
|
|
164
|
+
return `Invalid path ${event.path}`;
|
|
165
|
+
}
|
|
166
|
+
const graphqlUrl = adminUrl(storeFqdn, query.api_version);
|
|
167
|
+
try {
|
|
168
|
+
const body = await readBody(event);
|
|
169
|
+
if (protectMutations && isMutationRequestBody(body)) {
|
|
170
|
+
setResponseStatus(event, 400);
|
|
171
|
+
return { errors: [{ message: MUTATIONS_BLOCKED_MESSAGE }] };
|
|
172
|
+
}
|
|
173
|
+
const reqBody = JSON.stringify(body);
|
|
174
|
+
const reqHeaders = getRequestHeaders(event);
|
|
175
|
+
const customHeaders = filterCustomHeaders(reqHeaders);
|
|
176
|
+
const runRequest = async (token) => {
|
|
177
|
+
const headers = {
|
|
178
|
+
...customHeaders,
|
|
179
|
+
Accept: 'application/json',
|
|
180
|
+
'Content-Type': 'application/json',
|
|
181
|
+
'X-Shopify-Access-Token': token,
|
|
182
|
+
'User-Agent': `ShopifyCLIGraphiQL/${CLI_KIT_VERSION}`,
|
|
183
|
+
};
|
|
184
|
+
return fetch(graphqlUrl, {
|
|
185
|
+
method: 'POST',
|
|
186
|
+
headers,
|
|
187
|
+
body: reqBody,
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
let result = await runRequest(await currentToken());
|
|
191
|
+
if (result.status === 401) {
|
|
192
|
+
outputDebug('Token expired, fetching new token', stdout);
|
|
193
|
+
result = await runRequest(await refreshUpstreamToken());
|
|
194
|
+
}
|
|
195
|
+
setResponseHeader(event, 'Content-Type', 'application/json');
|
|
196
|
+
setResponseStatus(event, result.status);
|
|
197
|
+
return result.json();
|
|
198
|
+
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
setResponseStatus(event, 500);
|
|
202
|
+
if (error instanceof Error) {
|
|
203
|
+
return { errors: [error.message] };
|
|
204
|
+
}
|
|
205
|
+
return { errors: ['Unknown error'] };
|
|
206
|
+
}
|
|
207
|
+
}));
|
|
208
|
+
app.use(router);
|
|
209
|
+
const server = createServer(toNodeListener(app));
|
|
210
|
+
server.listen(port, 'localhost', () => stdout.write(`GraphiQL server started on port ${port}`));
|
|
211
|
+
return server;
|
|
212
|
+
}
|
|
213
|
+
// Picks the right key based on what the caller supplied:
|
|
214
|
+
// - explicit non-empty key → use it
|
|
215
|
+
// - app context with apiSecret → derive deterministically (stable across restarts)
|
|
216
|
+
// - otherwise → random per-process key (browser tabs won't survive restarts, which is
|
|
217
|
+
// the right tradeoff when there's no stable secret to derive from).
|
|
218
|
+
function resolveGraphiQLServerKey(providedKey, appContext, storeFqdn) {
|
|
219
|
+
const trimmed = providedKey?.trim();
|
|
220
|
+
if (trimmed)
|
|
221
|
+
return trimmed;
|
|
222
|
+
if (appContext)
|
|
223
|
+
return deriveGraphiQLKey(appContext.apiSecret, storeFqdn);
|
|
224
|
+
return randomBytes(32).toString('hex');
|
|
225
|
+
}
|
|
226
|
+
function isMutationRequestBody(body) {
|
|
227
|
+
if (typeof body !== 'object' || body === null)
|
|
228
|
+
return false;
|
|
229
|
+
const { query, operationName } = body;
|
|
230
|
+
if (typeof query !== 'string')
|
|
231
|
+
return false;
|
|
232
|
+
return containsMutation(query, typeof operationName === 'string' ? operationName : undefined);
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../src/public/node/graphiql/server.ts"],"names":[],"mappings":"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","sourcesContent":["import {defaultQuery, graphiqlTemplate} from './templates/graphiql.js'\nimport {unauthorizedTemplate} from './templates/unauthorized.js'\nimport {filterCustomHeaders} from './utilities.js'\nimport {performActionWithRetryAfterRecovery} from '../../common/retry.js'\nimport {CLI_KIT_VERSION} from '../../common/version.js'\nimport {AbortError} from '../error.js'\nimport {adminUrl, supportedApiVersions} from '../api/admin.js'\nimport {fetch} from '../http.js'\nimport {renderLiquidTemplate} from '../liquid.js'\nimport {outputDebug} from '../output.js'\nimport {containsMutation} from '../graphql.js'\nimport {\n createApp,\n createRouter,\n defineEventHandler,\n getQuery,\n getRequestHeader,\n getRequestHeaders,\n readBody,\n setResponseHeader,\n setResponseStatus,\n toNodeListener,\n} from 'h3'\nimport {createHmac, randomBytes} from 'crypto'\nimport {createServer, Server} from 'http'\nimport {readFileSync} from 'fs'\nimport {Writable} from 'stream'\nimport {createRequire} from 'module'\n\n/**\n * Derives a deterministic GraphiQL authentication key from the app's API secret and store FQDN.\n * The key is stable across dev server restarts (so browser tabs survive restarts)\n * but is not guessable without the app secret.\n *\n * @param apiSecret - The Partners app's client secret used as the HMAC key.\n * @param storeFqdn - The myshopify.com domain the GraphiQL session targets.\n * @returns A 64-character hex string suitable for use as the `?key=` query param.\n */\nexport function deriveGraphiQLKey(apiSecret: string, storeFqdn: string): string {\n return createHmac('sha256', apiSecret).update(`graphiql:${storeFqdn}`).digest('hex')\n}\n\n/**\n * Resolves the GraphiQL authentication key. Uses the explicitly provided key\n * if non-empty, otherwise derives one deterministically from the app secret.\n *\n * @param providedKey - An explicit key supplied by the caller; takes precedence when non-empty.\n * @param apiSecret - The Partners app's client secret, used to derive a stable key as a fallback.\n * @param storeFqdn - The myshopify.com domain the GraphiQL session targets.\n * @returns The resolved key.\n */\nexport function resolveGraphiQLKey(providedKey: string | undefined, apiSecret: string, storeFqdn: string): string {\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- intentional: empty string after trim should fall through to deriveGraphiQLKey\n return providedKey?.trim() || deriveGraphiQLKey(apiSecret, storeFqdn)\n}\n\nconst require = createRequire(import.meta.url)\n\nclass TokenRefreshError extends AbortError {\n constructor() {\n super('Failed to refresh credentials. Check that your app is installed, and try again.')\n }\n}\n\n/**\n * Pluggable strategy for obtaining and refreshing the Admin API access token\n * that the GraphiQL proxy injects into every request.\n *\n * - `getToken` may return a cached token; the proxy calls it for every request.\n * - `refreshToken` (optional) is invoked when the upstream Admin API returns 401.\n * When omitted, the proxy falls back to calling `getToken` again on 401.\n *\n * Implementations must throw `TokenRefreshError` (or any thrown error) when the\n * token cannot be obtained; the proxy renders the unauthorized template in that case.\n */\nexport interface TokenProvider {\n getToken: () => Promise<string>\n refreshToken?: () => Promise<string>\n}\n\n/**\n * Optional app-specific context, used to render the app pill and scopes note in the\n * GraphiQL header and to drive the deterministic key derivation. Pass when the GraphiQL\n * server is hosted as part of `shopify app dev`; omit for app-less use cases such as\n * `shopify store execute`.\n */\nexport interface GraphiQLAppContext {\n appName: string\n appUrl: string\n apiSecret: string\n}\n\nexport interface SetupGraphiQLServerOptions {\n stdout: Writable\n port: number\n storeFqdn: string\n tokenProvider: TokenProvider\n /**\n * Authentication key required as a `?key=` query string on every request. When omitted:\n * - if `appContext` is provided, derived deterministically from `apiSecret` + `storeFqdn`\n * so browser tabs survive dev server restarts.\n * - otherwise, generated randomly per process.\n */\n key?: string\n appContext?: GraphiQLAppContext\n /**\n * When true, the proxy rejects mutation operations with HTTP 400 before forwarding\n * them to the Admin API. Use this to mirror non-interactive safety guarantees in the\n * interactive UI.\n */\n protectMutations?: boolean\n}\n\nexport const MUTATIONS_BLOCKED_MESSAGE = 'Mutations are disabled. Re-run with --allow-mutations to enable mutations.'\n\n/**\n * Starts a local HTTP server that hosts the GraphiQL UI and proxies requests to the\n * Admin API for the configured store. Authentication is delegated to the supplied\n * `tokenProvider`, so the same server can serve both `shopify app dev` and stored-session\n * use cases.\n *\n * @param options - Configuration for the server, including the target store, the\n * pluggable token provider, and the local port to bind to.\n * @returns The underlying Node `http.Server` instance, already listening on `options.port`.\n */\nexport function setupGraphiQLServer(options: SetupGraphiQLServerOptions): Server {\n const {stdout, port, storeFqdn, tokenProvider, key: providedKey, appContext, protectMutations = false} = options\n const key = resolveGraphiQLServerKey(providedKey, appContext, storeFqdn)\n outputDebug(`Setting up GraphiQL HTTP server on port ${port}...`, stdout)\n\n const app = createApp()\n const router = createRouter()\n\n const refreshUpstreamToken = async (): Promise<string> => {\n try {\n outputDebug('refreshing token', stdout)\n return await (tokenProvider.refreshToken ?? tokenProvider.getToken)()\n } catch (_error) {\n throw new TokenRefreshError()\n }\n }\n\n const currentToken = async (): Promise<string> => {\n try {\n return await tokenProvider.getToken()\n } catch (_error) {\n throw new TokenRefreshError()\n }\n }\n\n async function fetchApiVersionsWithTokenRefresh(): Promise<string[]> {\n return performActionWithRetryAfterRecovery(\n async () => supportedApiVersions({storeFqdn, token: await currentToken()}),\n refreshUpstreamToken,\n )\n }\n\n const faviconPath = require.resolve('@shopify/cli-kit/assets/graphiql/favicon.ico')\n const faviconContent = readFileSync(faviconPath)\n const stylePath = require.resolve('@shopify/cli-kit/assets/graphiql/style.css')\n const styleContent = readFileSync(stylePath, 'utf8')\n\n app.use(\n defineEventHandler((event) => {\n setResponseHeader(event, 'Access-Control-Allow-Origin', '*')\n setResponseHeader(event, 'Access-Control-Allow-Methods', 'GET, OPTIONS')\n setResponseHeader(\n event,\n 'Access-Control-Allow-Headers',\n 'Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, ngrok-skip-browser-warning',\n )\n }),\n )\n\n router.get(\n '/graphiql/ping',\n defineEventHandler(() => 'pong'),\n )\n\n router.get(\n '/graphiql/favicon.ico',\n defineEventHandler((event) => {\n setResponseHeader(event, 'Content-Type', 'image/x-icon')\n return faviconContent\n }),\n )\n\n router.get(\n '/graphiql/simple.css',\n defineEventHandler((event) => {\n setResponseHeader(event, 'Content-Type', 'text/css')\n return styleContent\n }),\n )\n\n router.get(\n '/graphiql/status',\n defineEventHandler(async () => {\n try {\n await fetchApiVersionsWithTokenRefresh()\n return {status: 'OK', storeFqdn, appName: appContext?.appName, appUrl: appContext?.appUrl}\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return {status: 'UNAUTHENTICATED'}\n }\n }),\n )\n\n router.get(\n '/graphiql',\n defineEventHandler(async (event) => {\n outputDebug('Handling /graphiql request', stdout)\n\n const query = getQuery(event)\n\n if (key && query.key !== key) {\n setResponseStatus(event, 404)\n return `Invalid path ${event.path}`\n }\n\n const forwardedProto = getRequestHeader(event, 'x-forwarded-proto')\n const usesHttps = forwardedProto === 'https'\n const host = getRequestHeader(event, 'host')\n const url = `http${usesHttps ? 's' : ''}://${host}`\n\n let apiVersions: string[]\n try {\n apiVersions = await fetchApiVersionsWithTokenRefresh()\n } catch (err) {\n if (err instanceof TokenRefreshError) {\n return renderLiquidTemplate(unauthorizedTemplate({hasAppContext: Boolean(appContext)}), {\n previewUrl: appContext?.appUrl ?? '',\n storeFqdn,\n url,\n })\n }\n throw err\n }\n\n const apiVersion = apiVersions.sort().reverse()[0]!\n\n function decodeQueryString(input: string | undefined) {\n return input ? decodeURIComponent(input).replace(/\\n/g, '\\\\n') : undefined\n }\n\n const queryParam = decodeQueryString(query.query as string | undefined)\n const variables = decodeQueryString(query.variables as string | undefined)\n\n return renderLiquidTemplate(\n graphiqlTemplate({\n apiVersion,\n apiVersions: [...apiVersions, 'unstable'],\n appName: appContext?.appName,\n appUrl: appContext?.appUrl,\n key,\n storeFqdn,\n protectMutations,\n }),\n {\n url,\n defaultQueries: [{query: defaultQuery}],\n query: queryParam ? JSON.stringify(queryParam) : undefined,\n variables: variables ? JSON.stringify(variables) : undefined,\n },\n )\n }),\n )\n\n router.post(\n '/graphiql/graphql.json',\n defineEventHandler(async (event) => {\n outputDebug('Handling /graphiql/graphql.json request', stdout)\n\n const query = getQuery(event)\n\n if (key && query.key !== key) {\n setResponseStatus(event, 404)\n return `Invalid path ${event.path}`\n }\n\n const graphqlUrl = adminUrl(storeFqdn, query.api_version as string)\n try {\n const body = await readBody(event)\n\n if (protectMutations && isMutationRequestBody(body)) {\n setResponseStatus(event, 400)\n return {errors: [{message: MUTATIONS_BLOCKED_MESSAGE}]}\n }\n\n const reqBody = JSON.stringify(body)\n\n const reqHeaders = getRequestHeaders(event)\n const customHeaders = filterCustomHeaders(reqHeaders)\n\n const runRequest = async (token: string) => {\n const headers = {\n ...customHeaders,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n 'X-Shopify-Access-Token': token,\n 'User-Agent': `ShopifyCLIGraphiQL/${CLI_KIT_VERSION}`,\n }\n\n return fetch(graphqlUrl, {\n method: 'POST',\n headers,\n body: reqBody,\n })\n }\n\n let result = await runRequest(await currentToken())\n if (result.status === 401) {\n outputDebug('Token expired, fetching new token', stdout)\n result = await runRequest(await refreshUpstreamToken())\n }\n\n setResponseHeader(event, 'Content-Type', 'application/json')\n setResponseStatus(event, result.status)\n return result.json()\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error: unknown) {\n setResponseStatus(event, 500)\n if (error instanceof Error) {\n return {errors: [error.message]}\n }\n return {errors: ['Unknown error']}\n }\n }),\n )\n\n app.use(router)\n\n const server = createServer(toNodeListener(app))\n server.listen(port, 'localhost', () => stdout.write(`GraphiQL server started on port ${port}`))\n return server\n}\n\n// Picks the right key based on what the caller supplied:\n// - explicit non-empty key → use it\n// - app context with apiSecret → derive deterministically (stable across restarts)\n// - otherwise → random per-process key (browser tabs won't survive restarts, which is\n// the right tradeoff when there's no stable secret to derive from).\nfunction resolveGraphiQLServerKey(\n providedKey: string | undefined,\n appContext: GraphiQLAppContext | undefined,\n storeFqdn: string,\n): string {\n const trimmed = providedKey?.trim()\n if (trimmed) return trimmed\n if (appContext) return deriveGraphiQLKey(appContext.apiSecret, storeFqdn)\n return randomBytes(32).toString('hex')\n}\n\nfunction isMutationRequestBody(body: unknown): boolean {\n if (typeof body !== 'object' || body === null) return false\n const {query, operationName} = body as {query?: unknown; operationName?: unknown}\n if (typeof query !== 'string') return false\n return containsMutation(query, typeof operationName === 'string' ? operationName : undefined)\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const defaultQuery: string;
|
|
2
|
+
interface GraphiQLTemplateOptions {
|
|
3
|
+
apiVersion: string;
|
|
4
|
+
apiVersions: string[];
|
|
5
|
+
appName?: string;
|
|
6
|
+
appUrl?: string;
|
|
7
|
+
key: string;
|
|
8
|
+
storeFqdn: string;
|
|
9
|
+
protectMutations?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function graphiqlTemplate({ apiVersion, apiVersions, appName, appUrl, key, storeFqdn, protectMutations, }: GraphiQLTemplateOptions): string;
|
|
12
|
+
export {};
|