@shopify/cli-kit 4.7.1 → 4.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/private/node/ui/components/AutocompletePrompt.js +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +14 -0
- package/dist/private/node/ui/components/AutocompletePrompt.test.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 +9 -3
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/error.js +4 -3
- package/dist/public/node/error.js.map +1 -1
- package/dist/public/node/git.js +4 -0
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/notifications-system.js +19 -3
- package/dist/public/node/notifications-system.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/public/node/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,WAAW,CAAA;AACvC,OAAO,EAAgB,gBAAgB,EAAE,eAAe,EAAC,MAAM,aAAa,CAAA;AAC5E,OAAO,EAAC,iBAAiB,EAAmC,MAAM,gDAAgD,CAAA;AAClH,OAAO,EAAC,gBAAgB,EAAC,MAAM,qDAAqD,CAAA;AAEpF,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAA;AAIlC,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,qDAAK,CAAA;IACL,iEAAW,CAAA;IACX,iDAAG,CAAA;AACL,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;CAAG;AAE7C;;;GAGG;AACH,MAAM,OAAgB,UAAW,SAAQ,KAAK;IAC5C,UAAU,CAAkB;IAC5B,IAAI,CAAgB;IACpB,SAAS,CAA2B;IACpC,gBAAgB,CAAY;IAC5B,cAAc,CAAuB;IACrC,sBAAsB,CAAS;IAC/B;;;;;;;;;;OAUG;IACH,YACE,OAAkC,EAClC,IAAoB,EACpB,aAA+C,IAAI,EACnD,SAAoC,EACpC,cAAqC;QAErC,MAAM,sBAAsB,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,OAAO,CAAA;QAChF,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;QAEtF,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,UAAU,YAAY,eAAe,EAAE,CAAC;gBAC1C,IAAI,CAAC,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;YAChD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;YAC9B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA;QACxB,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAA;QAElC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC5B,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAA;QACjC,CAAC;IACH,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,UAAW,SAAQ,UAAU;IACxC,YACE,OAAkC,EAClC,aAA+C,IAAI,EACnD,SAAoC,EACpC,cAAqC;QAErC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,CAAC,CAAA;IAC7E,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3C,OAAO,CAAQ;IACf,IAAI,CAAU;IAEd,YACE,OAAsB,EACtB,OAAe,EACf,IAAc,EACd,aAA+C,IAAI;QAEnD,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;QAChD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC9C;QACE,KAAK,CAAC,EAAE,EAAE,cAAc,CAAC,WAAW,CAAC,CAAA;IACvC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,UAAU;IACtC,YAAY,OAAkC,EAAE,aAA+C,IAAI;QACjG,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;IAChD,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAc;IAC1C,IAAI,KAAiB,CAAA;IACrB,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,KAAK,GAAG,KAAK,CAAA;IACf,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACrC,KAAK,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7B,CAAC;SAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAClC,KAAK,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACnC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;IAC3B,CAAC;SAAM,CAAC;QACN,6CAA6C;QAC7C,8DAA8D;QAC9D,MAAM,UAAU,GAAG,KAAY,CAAA;QAC/B,KAAK,GAAG,IAAI,QAAQ,CAAC,UAAU,EAAE,OAAO,IAAI,eAAe,CAAC,CAAA;QAC5D,IAAI,UAAU,EAAE,KAAK,EAAE,CAAC;YACtB,KAAK,CAAC,KAAK,GAAG,UAAU,EAAE,KAAK,CAAA;QACjC,CAAC;IACH,CAAC;IAED,MAAM,EAAC,gBAAgB,EAAC,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;IAClD,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACvB,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACjD,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;QAC/B,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACrC,CAAC;SAAM,CAAC;QACN,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC/B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,KAAc;IAC7B,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QAC1D,qDAAqD;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,KAAc;IAC1D,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,mDAAmD;QACnD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,6FAA6F;YAC7F,6FAA6F;YAC7F,aAAa;YACb,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAA;YACd,CAAC;YACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;YAC7B,OAAO,CAAC,mCAAmC,CAAC,OAAO,CAAC,CAAA;QACtD,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,GAAG,EAAE,CAAC;QACtC,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAS,kBAAkB,CAAC,KAAY;IACtC,MAAM,SAAS,GAAG,KAGjB,CAAA;IACD,IAAI,OAAO,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,SAAS,CAAC,QAAQ,KAAK,IAAI,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC7G,OAAO,KAAK,CAAA;IACd,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAA;IACxC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACrC,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,OAAO,aAAa,CAAC,QAAQ,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,SAAS,mCAAmC,CAAC,OAAe;IAC1D,MAAM,wBAAwB,GAAG;QAC/B,yCAAyC;QACzC,wCAAwC;QACxC,2BAA2B;QAC3B,yCAAyC;QACzC,0DAA0D;QAC1D,gCAAgC;QAChC,gCAAgC;QAChC,uBAAuB;QACvB,iFAAiF;QACjF,aAAa;QACb,gBAAgB;QAChB,6BAA6B;QAC7B,aAAa;QACb,sBAAsB;KACvB,CAAA;IACD,MAAM,UAAU,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAA;IAClG,OAAO,UAAU,CAAA;AACnB,CAAC","sourcesContent":["import {normalizePath} from './path.js'\nimport {OutputMessage, stringifyMessage, TokenizedString} from './output.js'\nimport {tokenItemToString, type InlineToken, type TokenItem} from '../../private/node/ui/components/token-item.js'\nimport {hasRateLimitCode} from '../../private/node/analytics/graphql-error-codes.js'\n\nimport {Errors} from '@oclif/core'\n\nimport type {AlertCustomSection} from './ui.js'\n\nexport enum FatalErrorType {\n Abort,\n AbortSilent,\n Bug,\n}\n\nexport class CancelExecution extends Error {}\n\n/**\n * A fatal error represents an error shouldn't be rescued and that causes the execution to terminate.\n * There shouldn't be code that catches fatal errors.\n */\nexport abstract class FatalError extends Error {\n tryMessage: TokenItem | null\n type: FatalErrorType\n nextSteps?: TokenItem<InlineToken>[]\n formattedMessage?: TokenItem\n customSections?: AlertCustomSection[]\n skipOclifErrorHandling: boolean\n /**\n * Creates a new FatalError error.\n *\n * @param message - The error message.\n * @param type - The type of fatal error.\n * @param tryMessage - The message that recommends next steps to the user.\n * You can pass a string a {@link TokenizedString} or a {@link TokenItem}\n * if you need to style the message inside the error Banner component.\n * @param nextSteps - Message to show as \"next steps\" with suggestions to solve the issue.\n * @param customSections - Custom sections to show in the error banner. To be used if nextSteps is not enough.\n */\n constructor(\n message: TokenItem | OutputMessage,\n type: FatalErrorType,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n const messageIsOutputMessage = typeof message === 'string' || 'value' in message\n super(messageIsOutputMessage ? stringifyMessage(message) : tokenItemToString(message))\n\n if (tryMessage) {\n if (tryMessage instanceof TokenizedString) {\n this.tryMessage = stringifyMessage(tryMessage)\n } else {\n this.tryMessage = tryMessage\n }\n } else {\n this.tryMessage = null\n }\n\n this.type = type\n this.nextSteps = nextSteps\n this.customSections = customSections\n this.skipOclifErrorHandling = true\n\n if (!messageIsOutputMessage) {\n this.formattedMessage = message\n }\n }\n}\n\n/**\n * An abort error is a fatal error that shouldn't be reported as a bug.\n * Those usually represent unexpected scenarios that we can't handle and that usually require some action from the developer.\n */\nexport class AbortError extends FatalError {\n constructor(\n message: TokenItem | OutputMessage,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n super(message, FatalErrorType.Abort, tryMessage, nextSteps, customSections)\n }\n}\n\n/**\n * An external error is similar to Abort but has extra command and args attributes.\n * This is useful to represent errors coming from external commands, usually executed by execa.\n */\nexport class ExternalError extends FatalError {\n command: string\n args: string[]\n\n constructor(\n message: OutputMessage,\n command: string,\n args: string[],\n tryMessage: TokenItem | OutputMessage | null = null,\n ) {\n super(message, FatalErrorType.Abort, tryMessage)\n this.command = command\n this.args = args\n }\n}\n\nexport class AbortSilentError extends FatalError {\n constructor() {\n super('', FatalErrorType.AbortSilent)\n }\n}\n\n/**\n * A bug error is an error that represents a bug and therefore should be reported.\n */\nexport class BugError extends FatalError {\n constructor(message: TokenItem | OutputMessage, tryMessage: TokenItem | OutputMessage | null = null) {\n super(message, FatalErrorType.Bug, tryMessage)\n }\n}\n\n/**\n * A function that handles errors that blow up in the CLI.\n *\n * @param error - Error to be handled.\n * @returns A promise that resolves with the error passed.\n */\nexport async function handler(error: unknown): Promise<unknown> {\n let fatal: FatalError\n if (isFatal(error)) {\n fatal = error\n } else if (typeof error === 'string') {\n fatal = new BugError(error)\n } else if (error instanceof Error) {\n fatal = new BugError(error.message)\n fatal.stack = error.stack\n } else {\n // errors can come in all shapes and sizes...\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const maybeError = error as any\n fatal = new BugError(maybeError?.message ?? 'Unknown error')\n if (maybeError?.stack) {\n fatal.stack = maybeError?.stack\n }\n }\n\n const {renderFatalError} = await import('./ui.js')\n renderFatalError(fatal)\n return Promise.resolve(error)\n}\n\n/**\n * A function that maps an error to an Abort with the stack trace when coming from the CLI.\n *\n * @param error - Error to be mapped.\n * @returns A promise that resolves with the new error object.\n */\nexport function errorMapper(error: unknown): Promise<unknown> {\n if (error instanceof Errors.CLIError) {\n const mappedError = new AbortError(error.message)\n mappedError.stack = error.stack\n return Promise.resolve(mappedError)\n } else {\n return Promise.resolve(error)\n }\n}\n\n/**\n * A function that checks if an error is a fatal one.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a fatal one.\n */\nfunction isFatal(error: unknown): error is FatalError {\n try {\n return Object.prototype.hasOwnProperty.call(error, 'type')\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * A function that checks if an error should be reported as unexpected.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error should be reported as unexpected.\n */\nexport function shouldReportErrorAsUnexpected(error: unknown): boolean {\n if (!isFatal(error)) {\n // this means its not one of the CLI wrapped errors\n if (error instanceof Error) {\n // Raw API errors that slip through unwrapped (e.g. the handleErrors:false path) are expected\n // environmental conditions, not CLI bugs. Treat them as expected so they don't pollute crash\n // reporting.\n if (isExpectedApiError(error)) {\n return false\n }\n const message = error.message\n return !errorMessageImpliesEnvironmentIssue(message)\n }\n return true\n }\n if (error.type === FatalErrorType.Bug) {\n return true\n }\n return false\n}\n\n/**\n * Detects raw graphql-request `ClientError`s that are expected environmental conditions rather than\n * CLI bugs. These reach the reporter as plain `Error`s (not `FatalError`s) and would otherwise be\n * reported as unexpected. Two distinct cases, both kept out of crash reporting:\n *\n * HTTP 401 (unauthenticated) is not \"transient\" in the retry sense — it means the user's session\n * token is expired or invalid, a credential/environment condition (see issue #7891). Rate limiting\n * (HTTP 429, or a `THROTTLED`/`429` GraphQL code on any error in the response) matches the shape\n * detected by `errorsIncludeStatus429` in `private/node/api.ts`.\n *\n * Scoped to the external `ClientError` shape only — importing the cli-kit `GraphQLClientError`\n * wrapper here would create an `error.ts → headers.ts → error.ts` import cycle.\n *\n * Matched structurally rather than with `instanceof ClientError`, because importing the class\n * pulls `graphql-request` — and through it `graphql`, `tr46` and `whatwg-url` — into the module\n * graph of every command, for one type check on an error path. `ClientError` is the only error\n * reaching here that carries both `response` and `request`; the cli-kit wrapper carries\n * `statusCode` instead (see `private/node/api/headers.ts`).\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a known expected API error.\n */\nfunction isExpectedApiError(error: Error): boolean {\n const candidate = error as Error & {\n response?: {status?: number; errors?: unknown}\n request?: unknown\n }\n if (typeof candidate.response !== 'object' || candidate.response === null || candidate.request === undefined) {\n return false\n }\n const status = candidate.response.status\n if (status === 401 || status === 429) {\n return true\n }\n return hasRateLimitCode(candidate.response.errors)\n}\n\n/**\n * Stack traces usually have file:// - we strip that and also remove the Windows drive designation.\n *\n * @param filePath - Path to be cleaned.\n * @returns The cleaned path.\n */\nexport function cleanSingleStackTracePath(filePath: string): string {\n return normalizePath(filePath)\n .replace('file:/', '/')\n .replace(/^\\/?[A-Z]:/, '')\n}\n\n/**\n * There are certain errors that we know are not due to a CLI bug, but are environmental/user error.\n *\n * @param message - The error message to check.\n * @returns A boolean indicating if the error message implies an environment issue.\n */\nfunction errorMessageImpliesEnvironmentIssue(message: string): boolean {\n const environmentIssueMessages = [\n 'EPERM: operation not permitted, scandir',\n 'EPERM: operation not permitted, rename',\n 'EACCES: permission denied',\n 'EPERM: operation not permitted, symlink',\n 'This version of npm supports the following node versions',\n 'EBUSY: resource busy or locked',\n 'ENOTEMPTY: directory not empty',\n 'getaddrinfo ENOTFOUND',\n 'Client network socket disconnected before secure TLS connection was established',\n 'spawn EPERM',\n 'socket hang up',\n 'The user aborted a request.',\n 'write EPIPE',\n 'Unsupported platform',\n ]\n const anyMatches = environmentIssueMessages.some((issueMessage) => message.includes(issueMessage))\n return anyMatches\n}\n"]}
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/public/node/error.ts"],"names":[],"mappings":"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","sourcesContent":["import {normalizePath} from './path.js'\nimport {OutputMessage, stringifyMessage, TokenizedString} from './output.js'\nimport {tokenItemToString, type InlineToken, type TokenItem} from '../../private/node/ui/components/token-item.js'\nimport {hasRateLimitCode} from '../../private/node/analytics/graphql-error-codes.js'\n\nimport {Errors} from '@oclif/core'\n\nimport type {AlertCustomSection} from './ui.js'\n\nexport enum FatalErrorType {\n Abort,\n AbortSilent,\n Bug,\n}\n\nexport class CancelExecution extends Error {}\n\n/**\n * A fatal error represents an error shouldn't be rescued and that causes the execution to terminate.\n * There shouldn't be code that catches fatal errors.\n */\nexport abstract class FatalError extends Error {\n tryMessage: TokenItem | null\n type: FatalErrorType\n nextSteps?: TokenItem<InlineToken>[]\n formattedMessage?: TokenItem\n customSections?: AlertCustomSection[]\n skipOclifErrorHandling: boolean\n /**\n * Creates a new FatalError error.\n *\n * @param message - The error message.\n * @param type - The type of fatal error.\n * @param tryMessage - The message that recommends next steps to the user.\n * You can pass a string a {@link TokenizedString} or a {@link TokenItem}\n * if you need to style the message inside the error Banner component.\n * @param nextSteps - Message to show as \"next steps\" with suggestions to solve the issue.\n * @param customSections - Custom sections to show in the error banner. To be used if nextSteps is not enough.\n */\n constructor(\n message: TokenItem | OutputMessage,\n type: FatalErrorType,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n const messageIsOutputMessage = typeof message === 'string' || 'value' in message\n super(messageIsOutputMessage ? stringifyMessage(message) : tokenItemToString(message))\n\n if (tryMessage) {\n if (tryMessage instanceof TokenizedString) {\n this.tryMessage = stringifyMessage(tryMessage)\n } else {\n this.tryMessage = tryMessage\n }\n } else {\n this.tryMessage = null\n }\n\n this.type = type\n this.nextSteps = nextSteps\n this.customSections = customSections\n this.skipOclifErrorHandling = true\n\n if (!messageIsOutputMessage) {\n this.formattedMessage = message\n }\n }\n}\n\n/**\n * An abort error is a fatal error that shouldn't be reported as a bug.\n * Those usually represent unexpected scenarios that we can't handle and that usually require some action from the developer.\n */\nexport class AbortError extends FatalError {\n constructor(\n message: TokenItem | OutputMessage,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n super(message, FatalErrorType.Abort, tryMessage, nextSteps, customSections)\n }\n}\n\n/**\n * An external error is similar to Abort but has extra command and args attributes.\n * This is useful to represent errors coming from external commands, usually executed by execa.\n */\nexport class ExternalError extends FatalError {\n command: string\n args: string[]\n\n constructor(\n message: OutputMessage,\n command: string,\n args: string[],\n tryMessage: TokenItem | OutputMessage | null = null,\n ) {\n super(message, FatalErrorType.Abort, tryMessage)\n this.command = command\n this.args = args\n }\n}\n\nexport class AbortSilentError extends FatalError {\n constructor() {\n super('', FatalErrorType.AbortSilent)\n }\n}\n\n/**\n * A bug error is an error that represents a bug and therefore should be reported.\n */\nexport class BugError extends FatalError {\n constructor(message: TokenItem | OutputMessage, tryMessage: TokenItem | OutputMessage | null = null) {\n super(message, FatalErrorType.Bug, tryMessage)\n }\n}\n\n/**\n * A function that handles errors that blow up in the CLI.\n *\n * @param error - Error to be handled.\n * @returns A promise that resolves with the error passed.\n */\nexport async function handler(error: unknown): Promise<unknown> {\n let fatal: FatalError\n if (isFatal(error)) {\n fatal = error\n } else if (typeof error === 'string') {\n fatal = new BugError(error)\n } else if (error instanceof Error) {\n fatal = new BugError(error.message)\n fatal.stack = error.stack\n } else {\n // errors can come in all shapes and sizes...\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const maybeError = error as any\n fatal = new BugError(maybeError?.message ?? 'Unknown error')\n if (maybeError?.stack) {\n fatal.stack = maybeError?.stack\n }\n }\n\n const {renderFatalError} = await import('./ui.js')\n renderFatalError(fatal)\n return Promise.resolve(error)\n}\n\n/**\n * A function that maps an error to an Abort with the stack trace when coming from the CLI.\n *\n * @param error - Error to be mapped.\n * @returns A promise that resolves with the new error object.\n */\nexport function errorMapper(error: unknown): Promise<unknown> {\n if (error instanceof Errors.CLIError) {\n const mappedError = new AbortError(error.message)\n mappedError.stack = error.stack\n return Promise.resolve(mappedError)\n } else {\n return Promise.resolve(error)\n }\n}\n\n/**\n * A function that checks if an error is a fatal one.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a fatal one.\n */\nfunction isFatal(error: unknown): error is FatalError {\n try {\n return Object.prototype.hasOwnProperty.call(error, 'type')\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * A function that checks if an error should be reported as unexpected.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error should be reported as unexpected.\n */\nexport function shouldReportErrorAsUnexpected(error: unknown): boolean {\n if (!isFatal(error)) {\n // this means its not one of the CLI wrapped errors\n if (error instanceof Error) {\n // Raw API errors that slip through unwrapped (e.g. the handleErrors:false path) are expected\n // environmental conditions, not CLI bugs. Treat them as expected so they don't pollute crash\n // reporting.\n if (isExpectedApiError(error)) {\n return false\n }\n const message = error.message\n return !errorMessageImpliesEnvironmentIssue(message)\n }\n return true\n }\n if (error.type === FatalErrorType.Bug) {\n return true\n }\n return false\n}\n\n/**\n * Detects raw graphql-request `ClientError`s that are expected environmental conditions rather than\n * CLI bugs. These reach the reporter as plain `Error`s (not `FatalError`s) and would otherwise be\n * reported as unexpected.\n *\n * HTTP 401 (unauthenticated) is not \"transient\" in the retry sense — it means the user's session\n * token is expired or invalid, a credential/environment condition (see issue #7891). Rate limiting\n * (HTTP 429, or a `THROTTLED`/`429` GraphQL code on any error in the response) matches the shape\n * detected by `errorsIncludeStatus429` in `private/node/api.ts`. Gateway errors (502/503/504) are\n * also expected infrastructure failures.\n *\n * Scoped to the external `ClientError` shape only — importing the cli-kit `GraphQLClientError`\n * wrapper here would create an `error.ts → headers.ts → error.ts` import cycle.\n *\n * Matched structurally rather than with `instanceof ClientError`, because importing the class\n * pulls `graphql-request` — and through it `graphql`, `tr46` and `whatwg-url` — into the module\n * graph of every command, for one type check on an error path. `ClientError` is the only error\n * reaching here that carries both `response` and `request`; the cli-kit wrapper carries\n * `statusCode` instead (see `private/node/api/headers.ts`).\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a known expected API error.\n */\nfunction isExpectedApiError(error: Error): boolean {\n const candidate = error as Error & {\n response?: {status?: number; errors?: unknown}\n request?: unknown\n }\n if (typeof candidate.response !== 'object' || candidate.response === null || candidate.request === undefined) {\n return false\n }\n const status = candidate.response.status\n if (status === 401 || status === 429 || status === 502 || status === 503 || status === 504) {\n return true\n }\n return hasRateLimitCode(candidate.response.errors)\n}\n\n/**\n * Stack traces usually have file:// - we strip that and also remove the Windows drive designation.\n *\n * @param filePath - Path to be cleaned.\n * @returns The cleaned path.\n */\nexport function cleanSingleStackTracePath(filePath: string): string {\n return normalizePath(filePath)\n .replace('file:/', '/')\n .replace(/^\\/?[A-Z]:/, '')\n}\n\n/**\n * There are certain errors that we know are not due to a CLI bug, but are environmental/user error.\n *\n * @param message - The error message to check.\n * @returns A boolean indicating if the error message implies an environment issue.\n */\nfunction errorMessageImpliesEnvironmentIssue(message: string): boolean {\n const environmentIssueMessages = [\n 'EPERM: operation not permitted, scandir',\n 'EPERM: operation not permitted, rename',\n 'EACCES: permission denied',\n 'EPERM: operation not permitted, symlink',\n 'This version of npm supports the following node versions',\n 'EBUSY: resource busy or locked',\n 'ENOTEMPTY: directory not empty',\n 'getaddrinfo ENOTFOUND',\n 'Client network socket disconnected before secure TLS connection was established',\n 'spawn EPERM',\n 'socket hang up',\n 'The user aborted a request.',\n 'write EPIPE',\n 'Unsupported platform',\n ]\n const anyMatches = environmentIssueMessages.some((issueMessage) => message.includes(issueMessage))\n return anyMatches\n}\n"]}
|
package/dist/public/node/git.js
CHANGED
|
@@ -222,6 +222,10 @@ export async function addAllToGitFromDirectory(directory) {
|
|
|
222
222
|
export async function createGitCommit(message, options) {
|
|
223
223
|
const args = ['commit', '-m', message];
|
|
224
224
|
if (options?.author) {
|
|
225
|
+
// Guard against option injection attacks if author starts with '-'
|
|
226
|
+
if (options.author.startsWith('-')) {
|
|
227
|
+
throw new AbortError(`Invalid commit author: ${options.author}. Author name/email can't start with a hyphen.`);
|
|
228
|
+
}
|
|
225
229
|
args.push('--author', options.author);
|
|
226
230
|
}
|
|
227
231
|
await gitCommand(args, options?.directory);
|
|
@@ -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 // Guard against command/argument injection attacks if initialBranch starts with '-'\n if (initialBranch.startsWith('-')) {\n throw new AbortError(`Invalid initial branch name: ${initialBranch}. Branch names can't start with a hyphen.`)\n }\n\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 const fileContent = Object.entries(template)\n .map(([section, lines]) => `# ${section}\\n${lines.join('\\n')}\\n\\n`)\n .join('')\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"]}
|
|
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 // Guard against command/argument injection attacks if initialBranch starts with '-'\n if (initialBranch.startsWith('-')) {\n throw new AbortError(`Invalid initial branch name: ${initialBranch}. Branch names can't start with a hyphen.`)\n }\n\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 const fileContent = Object.entries(template)\n .map(([section, lines]) => `# ${section}\\n${lines.join('\\n')}\\n\\n`)\n .join('')\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 // Guard against option injection attacks if author starts with '-'\n if (options.author.startsWith('-')) {\n throw new AbortError(`Invalid commit author: ${options.author}. Author name/email can't start with a hyphen.`)\n }\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"]}
|
|
@@ -22,16 +22,20 @@ const COMMANDS_TO_SKIP = [
|
|
|
22
22
|
'cache:clear',
|
|
23
23
|
'send-analytics',
|
|
24
24
|
];
|
|
25
|
+
// Hostnames whose traffic never leaves the machine, so it can't be intercepted or tampered with.
|
|
26
|
+
const LOOPBACK_HOSTNAMES = ['127.0.0.1', 'localhost', '::1', '[::1]'];
|
|
25
27
|
function url() {
|
|
26
28
|
const envUrl = process.env.SHOPIFY_CLI_NOTIFICATIONS_URL;
|
|
27
29
|
if (envUrl) {
|
|
28
30
|
try {
|
|
29
31
|
const parsedUrl = new globalThis.URL(envUrl);
|
|
30
|
-
// We only allow https for notifications to prevent loading malicious content from insecure
|
|
31
|
-
|
|
32
|
+
// We only allow https for notifications to prevent loading malicious content from insecure
|
|
33
|
+
// sources. Plain http is allowed for loopback hosts so that notifications can be tested
|
|
34
|
+
// against a local server, where there is no network for an attacker to sit on.
|
|
35
|
+
if (isAllowedNotificationsUrl(parsedUrl)) {
|
|
32
36
|
return envUrl;
|
|
33
37
|
}
|
|
34
|
-
outputDebug(`The notifications URL provided via SHOPIFY_CLI_NOTIFICATIONS_URL (${envUrl})
|
|
38
|
+
outputDebug(`The notifications URL provided via SHOPIFY_CLI_NOTIFICATIONS_URL (${envUrl}) must use https, or http with a loopback host. Falling back to default.`);
|
|
35
39
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
36
40
|
}
|
|
37
41
|
catch {
|
|
@@ -40,6 +44,18 @@ function url() {
|
|
|
40
44
|
}
|
|
41
45
|
return URL;
|
|
42
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Checks whether a notifications URL is safe to load from.
|
|
49
|
+
*
|
|
50
|
+
* @param parsedUrl - The parsed notifications URL.
|
|
51
|
+
* @returns - A boolean indicating whether the URL may be used.
|
|
52
|
+
*/
|
|
53
|
+
function isAllowedNotificationsUrl(parsedUrl) {
|
|
54
|
+
if (parsedUrl.protocol === 'https:')
|
|
55
|
+
return true;
|
|
56
|
+
// `hostname` is the parsed authority, so lookalikes such as `127.0.0.1.example.com` don't match.
|
|
57
|
+
return parsedUrl.protocol === 'http:' && LOOPBACK_HOSTNAMES.includes(parsedUrl.hostname);
|
|
58
|
+
}
|
|
43
59
|
const NotificationSchema = zod.object({
|
|
44
60
|
id: zod.string(),
|
|
45
61
|
message: zod.string(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications-system.js","sourceRoot":"","sources":["../../../src/public/node/notifications-system.ts"],"names":[],"mappings":"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","sourcesContent":["import {versionSatisfies} from './node-package-manager.js'\nimport {renderError, renderInfo, renderWarning} from './ui.js'\nimport {getCurrentCommandId} from './global-context.js'\nimport {outputDebug} from './output.js'\nimport {zod} from './schema.js'\nimport {AbortSilentError} from './error.js'\nimport {isTruthy} from './context/utilities.js'\nimport {exec} from './system.js'\nimport {jsonOutputEnabled} from './environment.js'\nimport {fetch} from './http.js'\nimport {CLI_KIT_VERSION} from '../common/version.js'\nimport {NotificationKey, NotificationsKey, cacheRetrieve, cacheStore} from '../../private/node/conf-store.js'\n\nconst URL = 'https://cdn.shopify.com/static/cli/notifications.json'\nconst EMPTY_CACHE_MESSAGE = 'Cache is empty'\nconst COMMANDS_TO_SKIP = [\n 'notifications:list',\n 'notifications:generate',\n 'init',\n 'app:init',\n 'theme:init',\n 'hydrogen:init',\n 'cache:clear',\n 'send-analytics',\n]\n\nfunction url(): string {\n const envUrl = process.env.SHOPIFY_CLI_NOTIFICATIONS_URL\n if (envUrl) {\n try {\n const parsedUrl = new globalThis.URL(envUrl)\n // We only allow https for notifications to prevent loading malicious content from insecure sources.\n if (parsedUrl.protocol === 'https:') {\n return envUrl\n }\n outputDebug(\n `The notifications URL provided via SHOPIFY_CLI_NOTIFICATIONS_URL (${envUrl}) is not secure (https). Falling back to default.`,\n )\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n outputDebug(\n `The notifications URL provided via SHOPIFY_CLI_NOTIFICATIONS_URL (${envUrl}) is not a valid URL. Falling back to default.`,\n )\n }\n }\n return URL\n}\n\nconst NotificationSchema = zod.object({\n id: zod.string(),\n message: zod.string(),\n type: zod.enum(['info', 'warning', 'error']),\n frequency: zod.enum(['always', 'once', 'once_a_day', 'once_a_week']),\n ownerChannel: zod.string(),\n cta: zod\n .object({\n label: zod.string(),\n url: zod.string().url(),\n })\n .optional(),\n title: zod.string().optional(),\n minVersion: zod.string().optional(),\n maxVersion: zod.string().optional(),\n minDate: zod.string().optional(),\n maxDate: zod.string().optional(),\n commands: zod.array(zod.string()).optional(),\n surface: zod.string().optional(),\n})\nexport type Notification = zod.infer<typeof NotificationSchema>\n\nconst NotificationsSchema = zod.object({notifications: zod.array(NotificationSchema)})\nexport type Notifications = zod.infer<typeof NotificationsSchema>\n\n/**\n * Shows notifications to the user if they meet the criteria specified in the notifications.json file.\n *\n * @param currentSurfaces - The surfaces present in the current project (usually for app extensions).\n * @param environment - Process environment variables.\n * @returns - A promise that resolves when the notifications have been shown.\n */\nexport async function showNotificationsIfNeeded(\n currentSurfaces?: string[],\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n try {\n const commandId = getCurrentCommandId()\n if (skipNotifications(commandId, environment) || jsonOutputEnabled(environment)) return\n\n const notifications = await getNotifications()\n const notificationsToShow = filterNotifications(notifications.notifications, commandId, currentSurfaces)\n outputDebug(`Notifications to show: ${notificationsToShow.length}`)\n await renderNotifications(notificationsToShow)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message === EMPTY_CACHE_MESSAGE) {\n outputDebug('Notifications to show: 0 (Cache is empty)')\n return\n }\n if (error.message === 'abort') throw new AbortSilentError()\n const errorMessage = `Error showing notifications: ${error.message}`\n outputDebug(errorMessage)\n // This is very prone to becoming a circular dependency, so we import it dynamically\n const {sendErrorToBugsnag} = await import('./error-handler.js')\n await sendErrorToBugsnag(errorMessage, 'unexpected_error')\n }\n}\n\nfunction skipNotifications(currentCommand: string, environment: NodeJS.ProcessEnv = process.env): boolean {\n return (\n isTruthy(environment.CI) || isTruthy(environment.SHOPIFY_UNIT_TEST) || COMMANDS_TO_SKIP.includes(currentCommand)\n )\n}\n\n/**\n * Renders the first 2 notifications to the user.\n *\n * @param notifications - The notifications to render.\n */\nasync function renderNotifications(notifications: Notification[]) {\n notifications.slice(0, 2).forEach((notification) => {\n const content = {\n headline: notification.title,\n body: notification.message.replace(/\\\\n/g, '\\n'),\n link: notification.cta,\n }\n switch (notification.type) {\n case 'info': {\n renderInfo(content)\n break\n }\n case 'warning': {\n renderWarning(content)\n break\n }\n case 'error': {\n renderError(content)\n throw new Error('abort')\n }\n }\n cacheStore(`notification-${notification.id}`, new Date().getTime().toString())\n })\n}\n\n/**\n * Get notifications list from cache, that is updated in the background from bin/fetch-notifications.json.\n *\n * @returns A Notifications object.\n */\nexport async function getNotifications(): Promise<Notifications> {\n const cacheKey: NotificationsKey = `notifications-${url()}`\n const rawNotifications = cacheRetrieve(cacheKey)?.value as unknown as string\n if (!rawNotifications) throw new Error(EMPTY_CACHE_MESSAGE)\n const notifications: object = JSON.parse(rawNotifications)\n return NotificationsSchema.parse(notifications)\n}\n\n/**\n * Fetch notifications from the CDN and chache them.\n *\n * @returns A string with the notifications.\n */\nexport async function fetchNotifications(): Promise<Notifications> {\n outputDebug(`Fetching notifications...`)\n const response = await fetch(url(), undefined, {\n useNetworkLevelRetry: false,\n useAbortSignal: true,\n timeoutMs: 3 * 1000,\n })\n if (response.status !== 200) throw new Error(`Failed to fetch notifications: ${response.statusText}`)\n const rawNotifications = await response.text()\n const notifications: object = JSON.parse(rawNotifications)\n const result = NotificationsSchema.parse(notifications)\n await cacheNotifications(rawNotifications)\n return result\n}\n\n/**\n * Store the notifications in the cache.\n *\n * @param notifications - String with the notifications to cache.\n * @returns A Notifications object.\n */\nasync function cacheNotifications(notifications: string): Promise<void> {\n cacheStore(`notifications-${url()}`, notifications)\n outputDebug(`Notifications from ${url()} stored in the cache`)\n}\n\n/**\n * Fetch notifications in background as a detached process.\n *\n * @param currentCommand - The current Shopify command being run.\n * @param argv - The arguments passed to the current process.\n * @param environment - Process environment variables.\n */\nexport function fetchNotificationsInBackground(\n currentCommand: string,\n argv = process.argv,\n environment: NodeJS.ProcessEnv = process.env,\n): void {\n if (skipNotifications(currentCommand, environment)) return\n if (!argv[1]) return\n\n // Run the Shopify command the same way as the current execution\n const nodeBinary = process.execPath\n const shopifyBinary = argv[1]\n const args = [shopifyBinary, 'notifications', 'list', '--ignore-errors']\n\n // eslint-disable-next-line no-void\n void exec(nodeBinary, args, {\n background: true,\n env: {...process.env, SHOPIFY_CLI_NO_ANALYTICS: '1'},\n externalErrorHandler: async (error: unknown) => {\n outputDebug(`Failed to fetch notifications in background: ${(error as Error).message}`)\n },\n })\n}\n\n/**\n * Filters notifications based on the version of the CLI.\n *\n * @param notifications - The notifications to filter.\n * @param commandId - The command ID to filter by.\n * @param currentSurfaces - The surfaces present in the current project (usually for app extensions).\n * @param today - The current date.\n * @param currentVersion - The current version of the CLI.\n * @returns - The filtered notifications.\n */\nexport function filterNotifications(\n notifications: Notification[],\n commandId: string,\n currentSurfaces?: string[],\n today: Date = new Date(new Date().setUTCHours(0, 0, 0, 0)),\n currentVersion: string = CLI_KIT_VERSION,\n): Notification[] {\n return notifications\n .filter((notification) => filterByVersion(notification, currentVersion))\n .filter((notifications) => filterByDate(notifications, today))\n .filter((notification) => filterByCommand(notification, commandId))\n .filter((notification) => filterBySurface(notification, commandId, currentSurfaces))\n .filter((notification) => filterByFrequency(notification))\n}\n\n/**\n * Filters notifications based on the version of the CLI.\n *\n * @param notification - The notification to filter.\n * @param currentVersion - The current version of the CLI.\n */\nfunction filterByVersion(notification: Notification, currentVersion: string) {\n const minVersion = !notification.minVersion || versionSatisfies(currentVersion, `>=${notification.minVersion}`)\n const maxVersion = !notification.maxVersion || versionSatisfies(currentVersion, `<=${notification.maxVersion}`)\n return minVersion && maxVersion\n}\n\n/**\n * Filters notifications based on the date.\n *\n * @param notification - The notification to filter.\n * @param today - The current date.\n */\nfunction filterByDate(notification: Notification, today: Date) {\n const minDate = !notification.minDate || new Date(notification.minDate) <= today\n const maxDate = !notification.maxDate || new Date(notification.maxDate) >= today\n return minDate && maxDate\n}\n\n/**\n * Filters notifications based on the command ID.\n *\n * @param notification - The notification to filter.\n * @param commandId - The command ID to filter by.\n * @returns - A boolean indicating whether the notification should be shown.\n */\nfunction filterByCommand(notification: Notification, commandId: string) {\n if (commandId === '') return true\n return !notification.commands || notification.commands.includes(commandId)\n}\n\n/**\n * Filters notifications based on the surface.\n *\n * @param notification - The notification to filter.\n * @param commandId - The command id.\n * @param surfacesFromContext - The surfaces present in the current project (usually for app extensions).\n * @returns - A boolean indicating whether the notification should be shown.\n */\nfunction filterBySurface(notification: Notification, commandId: string, surfacesFromContext?: string[]) {\n const surfaceFromCommand = commandId.split(':')[0] ?? 'all'\n const notificationSurface = notification.surface ?? 'all'\n\n if (surfacesFromContext) return surfacesFromContext.includes(notificationSurface)\n\n return notificationSurface === surfaceFromCommand || notificationSurface === 'all'\n}\n\n/**\n * Filters notifications based on the frequency.\n *\n * @param notification - The notification to filter.\n * @returns - A boolean indicating whether the notification should be shown.\n */\nfunction filterByFrequency(notification: Notification): boolean {\n if (!notification.frequency) return true\n const cacheKey: NotificationKey = `notification-${notification.id}`\n const lastShown = cacheRetrieve(cacheKey)?.value as unknown as string\n if (!lastShown) return true\n\n switch (notification.frequency) {\n case 'always': {\n return true\n }\n case 'once': {\n return false\n }\n case 'once_a_day': {\n return new Date().getTime() - Number(lastShown) > 24 * 3600 * 1000\n }\n case 'once_a_week': {\n return new Date().getTime() - Number(lastShown) > 7 * 24 * 3600 * 1000\n }\n }\n}\n\n/**\n * Returns a string with the filters from a notification, one by line.\n *\n * @param notification - The notification to get the filters from.\n * @returns A string with human-readable filters from the notification.\n */\nexport function stringifyFilters(notification: Notification): string {\n const filters = []\n if (notification.minDate) filters.push(`from ${notification.minDate}`)\n if (notification.maxDate) filters.push(`to ${notification.maxDate}`)\n if (notification.minVersion) filters.push(`from v${notification.minVersion}`)\n if (notification.maxVersion) filters.push(`to v${notification.maxVersion}`)\n if (notification.frequency === 'once') filters.push('show only once')\n if (notification.frequency === 'once_a_day') filters.push('show once a day')\n if (notification.frequency === 'once_a_week') filters.push('show once a week')\n if (notification.surface) filters.push(`surface = ${notification.surface}`)\n if (notification.commands) filters.push(`commands = ${notification.commands.join(', ')}`)\n return filters.join('\\n')\n}\n"]}
|
|
1
|
+
{"version":3,"file":"notifications-system.js","sourceRoot":"","sources":["../../../src/public/node/notifications-system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAC,WAAW,EAAE,UAAU,EAAE,aAAa,EAAC,MAAM,SAAS,CAAA;AAC9D,OAAO,EAAC,mBAAmB,EAAC,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA;AAC/B,OAAO,EAAC,gBAAgB,EAAC,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAC,IAAI,EAAC,MAAM,aAAa,CAAA;AAChC,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAC,KAAK,EAAC,MAAM,WAAW,CAAA;AAC/B,OAAO,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAoC,aAAa,EAAE,UAAU,EAAC,MAAM,kCAAkC,CAAA;AAE7G,MAAM,GAAG,GAAG,uDAAuD,CAAA;AACnE,MAAM,mBAAmB,GAAG,gBAAgB,CAAA;AAC5C,MAAM,gBAAgB,GAAG;IACvB,oBAAoB;IACpB,wBAAwB;IACxB,MAAM;IACN,UAAU;IACV,YAAY;IACZ,eAAe;IACf,aAAa;IACb,gBAAgB;CACjB,CAAA;AAED,iGAAiG;AACjG,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;AAErE,SAAS,GAAG;IACV,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAA;IACxD,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAC5C,2FAA2F;YAC3F,wFAAwF;YACxF,+EAA+E;YAC/E,IAAI,yBAAyB,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzC,OAAO,MAAM,CAAA;YACf,CAAC;YACD,WAAW,CACT,qEAAqE,MAAM,0EAA0E,CACtJ,CAAA;YACD,qDAAqD;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CACT,qEAAqE,MAAM,gDAAgD,CAC5H,CAAA;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,SAAS,yBAAyB,CAAC,SAAyB;IAC1D,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAChD,iGAAiG;IACjG,OAAO,SAAS,CAAC,QAAQ,KAAK,OAAO,IAAI,kBAAkB,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC1F,CAAC;AAED,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,CAAC;IACpC,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC5C,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;IACpE,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE;IAC1B,GAAG,EAAE,GAAG;SACL,MAAM,CAAC;QACN,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QACnB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;KACxB,CAAC;SACD,QAAQ,EAAE;IACb,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC5C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAA;AAGF,MAAM,mBAAmB,GAAG,GAAG,CAAC,MAAM,CAAC,EAAC,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAC,CAAC,CAAA;AAGtF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,eAA0B,EAC1B,cAAiC,OAAO,CAAC,GAAG;IAE5C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAA;QACvC,IAAI,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC;YAAE,OAAM;QAEvF,MAAM,aAAa,GAAG,MAAM,gBAAgB,EAAE,CAAA;QAC9C,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,aAAa,CAAC,aAAa,EAAE,SAAS,EAAE,eAAe,CAAC,CAAA;QACxG,WAAW,CAAC,0BAA0B,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAA;QACnE,MAAM,mBAAmB,CAAC,mBAAmB,CAAC,CAAA;QAC9C,8DAA8D;IAChE,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,IAAI,KAAK,CAAC,OAAO,KAAK,mBAAmB,EAAE,CAAC;YAC1C,WAAW,CAAC,2CAA2C,CAAC,CAAA;YACxD,OAAM;QACR,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO;YAAE,MAAM,IAAI,gBAAgB,EAAE,CAAA;QAC3D,MAAM,YAAY,GAAG,gCAAgC,KAAK,CAAC,OAAO,EAAE,CAAA;QACpE,WAAW,CAAC,YAAY,CAAC,CAAA;QACzB,oFAAoF;QACpF,MAAM,EAAC,kBAAkB,EAAC,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;QAC/D,MAAM,kBAAkB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,cAAsB,EAAE,cAAiC,OAAO,CAAC,GAAG;IAC7F,OAAO,CACL,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,cAAc,CAAC,CACjH,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,mBAAmB,CAAC,aAA6B;IAC9D,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG;YACd,QAAQ,EAAE,YAAY,CAAC,KAAK;YAC5B,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;YAChD,IAAI,EAAE,YAAY,CAAC,GAAG;SACvB,CAAA;QACD,QAAQ,YAAY,CAAC,IAAI,EAAE,CAAC;YAC1B,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,UAAU,CAAC,OAAO,CAAC,CAAA;gBACnB,MAAK;YACP,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,aAAa,CAAC,OAAO,CAAC,CAAA;gBACtB,MAAK;YACP,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,WAAW,CAAC,OAAO,CAAC,CAAA;gBACpB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;YAC1B,CAAC;QACH,CAAC;QACD,UAAU,CAAC,gBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAA;IAChF,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,QAAQ,GAAqB,iBAAiB,GAAG,EAAE,EAAE,CAAA;IAC3D,MAAM,gBAAgB,GAAG,aAAa,CAAC,QAAQ,CAAC,EAAE,KAA0B,CAAA;IAC5E,IAAI,CAAC,gBAAgB;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;IAC3D,MAAM,aAAa,GAAW,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IAC1D,OAAO,mBAAmB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,WAAW,CAAC,2BAA2B,CAAC,CAAA;IACxC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE;QAC7C,oBAAoB,EAAE,KAAK;QAC3B,cAAc,EAAE,IAAI;QACpB,SAAS,EAAE,CAAC,GAAG,IAAI;KACpB,CAAC,CAAA;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;IACrG,MAAM,gBAAgB,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC9C,MAAM,aAAa,GAAW,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;IACvD,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,CAAA;IAC1C,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,kBAAkB,CAAC,aAAqB;IACrD,UAAU,CAAC,iBAAiB,GAAG,EAAE,EAAE,EAAE,aAAa,CAAC,CAAA;IACnD,WAAW,CAAC,sBAAsB,GAAG,EAAE,sBAAsB,CAAC,CAAA;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAC5C,cAAsB,EACtB,IAAI,GAAG,OAAO,CAAC,IAAI,EACnB,cAAiC,OAAO,CAAC,GAAG;IAE5C,IAAI,iBAAiB,CAAC,cAAc,EAAE,WAAW,CAAC;QAAE,OAAM;IAC1D,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAM;IAEpB,gEAAgE;IAChE,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAA;IACnC,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAA;IAExE,mCAAmC;IACnC,KAAK,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE;QAC1B,UAAU,EAAE,IAAI;QAChB,GAAG,EAAE,EAAC,GAAG,OAAO,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG,EAAC;QACpD,oBAAoB,EAAE,KAAK,EAAE,KAAc,EAAE,EAAE;YAC7C,WAAW,CAAC,gDAAiD,KAAe,CAAC,OAAO,EAAE,CAAC,CAAA;QACzF,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CACjC,aAA6B,EAC7B,SAAiB,EACjB,eAA0B,EAC1B,QAAc,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAC1D,iBAAyB,eAAe;IAExC,OAAO,aAAa;SACjB,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;SACvE,MAAM,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;SAC7D,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;SAClE,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC,YAAY,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;SACnF,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAA;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,YAA0B,EAAE,cAAsB;IACzE,MAAM,UAAU,GAAG,CAAC,YAAY,CAAC,UAAU,IAAI,gBAAgB,CAAC,cAAc,EAAE,KAAK,YAAY,CAAC,UAAU,EAAE,CAAC,CAAA;IAC/G,MAAM,UAAU,GAAG,CAAC,YAAY,CAAC,UAAU,IAAI,gBAAgB,CAAC,cAAc,EAAE,KAAK,YAAY,CAAC,UAAU,EAAE,CAAC,CAAA;IAC/G,OAAO,UAAU,IAAI,UAAU,CAAA;AACjC,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,YAA0B,EAAE,KAAW;IAC3D,MAAM,OAAO,GAAG,CAAC,YAAY,CAAC,OAAO,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,KAAK,CAAA;IAChF,MAAM,OAAO,GAAG,CAAC,YAAY,CAAC,OAAO,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,KAAK,CAAA;IAChF,OAAO,OAAO,IAAI,OAAO,CAAA;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,YAA0B,EAAE,SAAiB;IACpE,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IACjC,OAAO,CAAC,YAAY,CAAC,QAAQ,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;AAC5E,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,YAA0B,EAAE,SAAiB,EAAE,mBAA8B;IACpG,MAAM,kBAAkB,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;IAC3D,MAAM,mBAAmB,GAAG,YAAY,CAAC,OAAO,IAAI,KAAK,CAAA;IAEzD,IAAI,mBAAmB;QAAE,OAAO,mBAAmB,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAA;IAEjF,OAAO,mBAAmB,KAAK,kBAAkB,IAAI,mBAAmB,KAAK,KAAK,CAAA;AACpF,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,YAA0B;IACnD,IAAI,CAAC,YAAY,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA;IACxC,MAAM,QAAQ,GAAoB,gBAAgB,YAAY,CAAC,EAAE,EAAE,CAAA;IACnE,MAAM,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,EAAE,KAA0B,CAAA;IACrE,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA;IAE3B,QAAQ,YAAY,CAAC,SAAS,EAAE,CAAC;QAC/B,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO,IAAI,CAAA;QACb,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO,KAAK,CAAA;QACd,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,OAAO,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;QACpE,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,OAAO,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;QACxE,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAA0B;IACzD,MAAM,OAAO,GAAG,EAAE,CAAA;IAClB,IAAI,YAAY,CAAC,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,YAAY,CAAC,OAAO,EAAE,CAAC,CAAA;IACtE,IAAI,YAAY,CAAC,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,OAAO,EAAE,CAAC,CAAA;IACpE,IAAI,YAAY,CAAC,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,SAAS,YAAY,CAAC,UAAU,EAAE,CAAC,CAAA;IAC7E,IAAI,YAAY,CAAC,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,YAAY,CAAC,UAAU,EAAE,CAAC,CAAA;IAC3E,IAAI,YAAY,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACrE,IAAI,YAAY,CAAC,SAAS,KAAK,YAAY;QAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAC5E,IAAI,YAAY,CAAC,SAAS,KAAK,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAC9E,IAAI,YAAY,CAAC,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,aAAa,YAAY,CAAC,OAAO,EAAE,CAAC,CAAA;IAC3E,IAAI,YAAY,CAAC,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,cAAc,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACzF,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC","sourcesContent":["import {versionSatisfies} from './node-package-manager.js'\nimport {renderError, renderInfo, renderWarning} from './ui.js'\nimport {getCurrentCommandId} from './global-context.js'\nimport {outputDebug} from './output.js'\nimport {zod} from './schema.js'\nimport {AbortSilentError} from './error.js'\nimport {isTruthy} from './context/utilities.js'\nimport {exec} from './system.js'\nimport {jsonOutputEnabled} from './environment.js'\nimport {fetch} from './http.js'\nimport {CLI_KIT_VERSION} from '../common/version.js'\nimport {NotificationKey, NotificationsKey, cacheRetrieve, cacheStore} from '../../private/node/conf-store.js'\n\nconst URL = 'https://cdn.shopify.com/static/cli/notifications.json'\nconst EMPTY_CACHE_MESSAGE = 'Cache is empty'\nconst COMMANDS_TO_SKIP = [\n 'notifications:list',\n 'notifications:generate',\n 'init',\n 'app:init',\n 'theme:init',\n 'hydrogen:init',\n 'cache:clear',\n 'send-analytics',\n]\n\n// Hostnames whose traffic never leaves the machine, so it can't be intercepted or tampered with.\nconst LOOPBACK_HOSTNAMES = ['127.0.0.1', 'localhost', '::1', '[::1]']\n\nfunction url(): string {\n const envUrl = process.env.SHOPIFY_CLI_NOTIFICATIONS_URL\n if (envUrl) {\n try {\n const parsedUrl = new globalThis.URL(envUrl)\n // We only allow https for notifications to prevent loading malicious content from insecure\n // sources. Plain http is allowed for loopback hosts so that notifications can be tested\n // against a local server, where there is no network for an attacker to sit on.\n if (isAllowedNotificationsUrl(parsedUrl)) {\n return envUrl\n }\n outputDebug(\n `The notifications URL provided via SHOPIFY_CLI_NOTIFICATIONS_URL (${envUrl}) must use https, or http with a loopback host. Falling back to default.`,\n )\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n outputDebug(\n `The notifications URL provided via SHOPIFY_CLI_NOTIFICATIONS_URL (${envUrl}) is not a valid URL. Falling back to default.`,\n )\n }\n }\n return URL\n}\n\n/**\n * Checks whether a notifications URL is safe to load from.\n *\n * @param parsedUrl - The parsed notifications URL.\n * @returns - A boolean indicating whether the URL may be used.\n */\nfunction isAllowedNotificationsUrl(parsedUrl: globalThis.URL): boolean {\n if (parsedUrl.protocol === 'https:') return true\n // `hostname` is the parsed authority, so lookalikes such as `127.0.0.1.example.com` don't match.\n return parsedUrl.protocol === 'http:' && LOOPBACK_HOSTNAMES.includes(parsedUrl.hostname)\n}\n\nconst NotificationSchema = zod.object({\n id: zod.string(),\n message: zod.string(),\n type: zod.enum(['info', 'warning', 'error']),\n frequency: zod.enum(['always', 'once', 'once_a_day', 'once_a_week']),\n ownerChannel: zod.string(),\n cta: zod\n .object({\n label: zod.string(),\n url: zod.string().url(),\n })\n .optional(),\n title: zod.string().optional(),\n minVersion: zod.string().optional(),\n maxVersion: zod.string().optional(),\n minDate: zod.string().optional(),\n maxDate: zod.string().optional(),\n commands: zod.array(zod.string()).optional(),\n surface: zod.string().optional(),\n})\nexport type Notification = zod.infer<typeof NotificationSchema>\n\nconst NotificationsSchema = zod.object({notifications: zod.array(NotificationSchema)})\nexport type Notifications = zod.infer<typeof NotificationsSchema>\n\n/**\n * Shows notifications to the user if they meet the criteria specified in the notifications.json file.\n *\n * @param currentSurfaces - The surfaces present in the current project (usually for app extensions).\n * @param environment - Process environment variables.\n * @returns - A promise that resolves when the notifications have been shown.\n */\nexport async function showNotificationsIfNeeded(\n currentSurfaces?: string[],\n environment: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n try {\n const commandId = getCurrentCommandId()\n if (skipNotifications(commandId, environment) || jsonOutputEnabled(environment)) return\n\n const notifications = await getNotifications()\n const notificationsToShow = filterNotifications(notifications.notifications, commandId, currentSurfaces)\n outputDebug(`Notifications to show: ${notificationsToShow.length}`)\n await renderNotifications(notificationsToShow)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message === EMPTY_CACHE_MESSAGE) {\n outputDebug('Notifications to show: 0 (Cache is empty)')\n return\n }\n if (error.message === 'abort') throw new AbortSilentError()\n const errorMessage = `Error showing notifications: ${error.message}`\n outputDebug(errorMessage)\n // This is very prone to becoming a circular dependency, so we import it dynamically\n const {sendErrorToBugsnag} = await import('./error-handler.js')\n await sendErrorToBugsnag(errorMessage, 'unexpected_error')\n }\n}\n\nfunction skipNotifications(currentCommand: string, environment: NodeJS.ProcessEnv = process.env): boolean {\n return (\n isTruthy(environment.CI) || isTruthy(environment.SHOPIFY_UNIT_TEST) || COMMANDS_TO_SKIP.includes(currentCommand)\n )\n}\n\n/**\n * Renders the first 2 notifications to the user.\n *\n * @param notifications - The notifications to render.\n */\nasync function renderNotifications(notifications: Notification[]) {\n notifications.slice(0, 2).forEach((notification) => {\n const content = {\n headline: notification.title,\n body: notification.message.replace(/\\\\n/g, '\\n'),\n link: notification.cta,\n }\n switch (notification.type) {\n case 'info': {\n renderInfo(content)\n break\n }\n case 'warning': {\n renderWarning(content)\n break\n }\n case 'error': {\n renderError(content)\n throw new Error('abort')\n }\n }\n cacheStore(`notification-${notification.id}`, new Date().getTime().toString())\n })\n}\n\n/**\n * Get notifications list from cache, that is updated in the background from bin/fetch-notifications.json.\n *\n * @returns A Notifications object.\n */\nexport async function getNotifications(): Promise<Notifications> {\n const cacheKey: NotificationsKey = `notifications-${url()}`\n const rawNotifications = cacheRetrieve(cacheKey)?.value as unknown as string\n if (!rawNotifications) throw new Error(EMPTY_CACHE_MESSAGE)\n const notifications: object = JSON.parse(rawNotifications)\n return NotificationsSchema.parse(notifications)\n}\n\n/**\n * Fetch notifications from the CDN and chache them.\n *\n * @returns A string with the notifications.\n */\nexport async function fetchNotifications(): Promise<Notifications> {\n outputDebug(`Fetching notifications...`)\n const response = await fetch(url(), undefined, {\n useNetworkLevelRetry: false,\n useAbortSignal: true,\n timeoutMs: 3 * 1000,\n })\n if (response.status !== 200) throw new Error(`Failed to fetch notifications: ${response.statusText}`)\n const rawNotifications = await response.text()\n const notifications: object = JSON.parse(rawNotifications)\n const result = NotificationsSchema.parse(notifications)\n await cacheNotifications(rawNotifications)\n return result\n}\n\n/**\n * Store the notifications in the cache.\n *\n * @param notifications - String with the notifications to cache.\n * @returns A Notifications object.\n */\nasync function cacheNotifications(notifications: string): Promise<void> {\n cacheStore(`notifications-${url()}`, notifications)\n outputDebug(`Notifications from ${url()} stored in the cache`)\n}\n\n/**\n * Fetch notifications in background as a detached process.\n *\n * @param currentCommand - The current Shopify command being run.\n * @param argv - The arguments passed to the current process.\n * @param environment - Process environment variables.\n */\nexport function fetchNotificationsInBackground(\n currentCommand: string,\n argv = process.argv,\n environment: NodeJS.ProcessEnv = process.env,\n): void {\n if (skipNotifications(currentCommand, environment)) return\n if (!argv[1]) return\n\n // Run the Shopify command the same way as the current execution\n const nodeBinary = process.execPath\n const shopifyBinary = argv[1]\n const args = [shopifyBinary, 'notifications', 'list', '--ignore-errors']\n\n // eslint-disable-next-line no-void\n void exec(nodeBinary, args, {\n background: true,\n env: {...process.env, SHOPIFY_CLI_NO_ANALYTICS: '1'},\n externalErrorHandler: async (error: unknown) => {\n outputDebug(`Failed to fetch notifications in background: ${(error as Error).message}`)\n },\n })\n}\n\n/**\n * Filters notifications based on the version of the CLI.\n *\n * @param notifications - The notifications to filter.\n * @param commandId - The command ID to filter by.\n * @param currentSurfaces - The surfaces present in the current project (usually for app extensions).\n * @param today - The current date.\n * @param currentVersion - The current version of the CLI.\n * @returns - The filtered notifications.\n */\nexport function filterNotifications(\n notifications: Notification[],\n commandId: string,\n currentSurfaces?: string[],\n today: Date = new Date(new Date().setUTCHours(0, 0, 0, 0)),\n currentVersion: string = CLI_KIT_VERSION,\n): Notification[] {\n return notifications\n .filter((notification) => filterByVersion(notification, currentVersion))\n .filter((notifications) => filterByDate(notifications, today))\n .filter((notification) => filterByCommand(notification, commandId))\n .filter((notification) => filterBySurface(notification, commandId, currentSurfaces))\n .filter((notification) => filterByFrequency(notification))\n}\n\n/**\n * Filters notifications based on the version of the CLI.\n *\n * @param notification - The notification to filter.\n * @param currentVersion - The current version of the CLI.\n */\nfunction filterByVersion(notification: Notification, currentVersion: string) {\n const minVersion = !notification.minVersion || versionSatisfies(currentVersion, `>=${notification.minVersion}`)\n const maxVersion = !notification.maxVersion || versionSatisfies(currentVersion, `<=${notification.maxVersion}`)\n return minVersion && maxVersion\n}\n\n/**\n * Filters notifications based on the date.\n *\n * @param notification - The notification to filter.\n * @param today - The current date.\n */\nfunction filterByDate(notification: Notification, today: Date) {\n const minDate = !notification.minDate || new Date(notification.minDate) <= today\n const maxDate = !notification.maxDate || new Date(notification.maxDate) >= today\n return minDate && maxDate\n}\n\n/**\n * Filters notifications based on the command ID.\n *\n * @param notification - The notification to filter.\n * @param commandId - The command ID to filter by.\n * @returns - A boolean indicating whether the notification should be shown.\n */\nfunction filterByCommand(notification: Notification, commandId: string) {\n if (commandId === '') return true\n return !notification.commands || notification.commands.includes(commandId)\n}\n\n/**\n * Filters notifications based on the surface.\n *\n * @param notification - The notification to filter.\n * @param commandId - The command id.\n * @param surfacesFromContext - The surfaces present in the current project (usually for app extensions).\n * @returns - A boolean indicating whether the notification should be shown.\n */\nfunction filterBySurface(notification: Notification, commandId: string, surfacesFromContext?: string[]) {\n const surfaceFromCommand = commandId.split(':')[0] ?? 'all'\n const notificationSurface = notification.surface ?? 'all'\n\n if (surfacesFromContext) return surfacesFromContext.includes(notificationSurface)\n\n return notificationSurface === surfaceFromCommand || notificationSurface === 'all'\n}\n\n/**\n * Filters notifications based on the frequency.\n *\n * @param notification - The notification to filter.\n * @returns - A boolean indicating whether the notification should be shown.\n */\nfunction filterByFrequency(notification: Notification): boolean {\n if (!notification.frequency) return true\n const cacheKey: NotificationKey = `notification-${notification.id}`\n const lastShown = cacheRetrieve(cacheKey)?.value as unknown as string\n if (!lastShown) return true\n\n switch (notification.frequency) {\n case 'always': {\n return true\n }\n case 'once': {\n return false\n }\n case 'once_a_day': {\n return new Date().getTime() - Number(lastShown) > 24 * 3600 * 1000\n }\n case 'once_a_week': {\n return new Date().getTime() - Number(lastShown) > 7 * 24 * 3600 * 1000\n }\n }\n}\n\n/**\n * Returns a string with the filters from a notification, one by line.\n *\n * @param notification - The notification to get the filters from.\n * @returns A string with human-readable filters from the notification.\n */\nexport function stringifyFilters(notification: Notification): string {\n const filters = []\n if (notification.minDate) filters.push(`from ${notification.minDate}`)\n if (notification.maxDate) filters.push(`to ${notification.maxDate}`)\n if (notification.minVersion) filters.push(`from v${notification.minVersion}`)\n if (notification.maxVersion) filters.push(`to v${notification.maxVersion}`)\n if (notification.frequency === 'once') filters.push('show only once')\n if (notification.frequency === 'once_a_day') filters.push('show once a day')\n if (notification.frequency === 'once_a_week') filters.push('show once a week')\n if (notification.surface) filters.push(`surface = ${notification.surface}`)\n if (notification.commands) filters.push(`commands = ${notification.commands.join(', ')}`)\n return filters.join('\\n')\n}\n"]}
|