Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
"octokit-plugin-create-pull-request": "^3.12.2",
"pathe": "1.1.1",
"pin-github-action": "^3.3.1",
"react": "17.0.2",
"rimraf": "^3.0.2",
"tmp": "^0.2.5",
"ts-node": "^10.9.1",
Expand All @@ -98,7 +97,7 @@
},
"version": "0.0.0",
"resolutions": {
"@types/react": "17.0.2",
"@types/react": "18.3.12",
"vite": "6.4.1",
"whatwg-url": "14.0.0",
"supports-hyperlinks": "3.1.0",
Expand Down Expand Up @@ -162,7 +161,6 @@
"@nx/workspace",
"graphql-tag",
"pin-github-action",
"react",
"esbuild"
],
"ignore": [
Expand Down
6 changes: 3 additions & 3 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"ignore": "6.0.2",
"proper-lockfile": "4.1.2",
"react": "^18.2.0",
"react-dom": "18.3.1",
"react-dom": "^18.2.0",
"which": "4.0.0",
"ws": "8.18.0"
},
Expand All @@ -79,8 +79,8 @@
"@types/diff": "^5.0.3",
"@types/express": "^4.17.17",
"@types/proper-lockfile": "4.1.4",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/which": "3.0.4",
"@types/ws": "^8.5.13",
"@vitest/coverage-istanbul": "^3.1.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ const Logs: FunctionComponent<LogsProps> = ({
</Box>
<Box flexDirection="column" marginLeft={4}>
{appLog instanceof FunctionRunLog && (
<>
<Box flexDirection="column">
<Text>{appLog.logs}</Text>
{appLog.inputQueryVariablesMetafieldKey && appLog.inputQueryVariablesMetafieldNamespace && (
{appLog.inputQueryVariablesMetafieldKey && appLog.inputQueryVariablesMetafieldNamespace ? (
<Box flexDirection="column" marginTop={1}>
<Text bold>Input Query Variables:</Text>
<Box flexDirection="row" marginLeft={1} marginTop={1}>
Expand All @@ -98,8 +98,8 @@ const Logs: FunctionComponent<LogsProps> = ({
</Text>
</Box>
</Box>
)}
{appLog.input && (
) : null}
{appLog.input ? (
<Box flexDirection="column" marginTop={1}>
<Text bold>
Input <Text dimColor>({appLog.inputBytes} bytes):</Text>
Expand All @@ -108,8 +108,8 @@ const Logs: FunctionComponent<LogsProps> = ({
<Text>{prettyPrintJsonIfPossible(appLog.input)}</Text>
</Box>
</Box>
)}
{appLog.output && (
) : null}
{appLog.output ? (
<Box flexDirection="column" marginTop={1}>
<Text bold>
Output <Text dimColor>({appLog.outputBytes} bytes):</Text>
Expand All @@ -118,41 +118,41 @@ const Logs: FunctionComponent<LogsProps> = ({
<Text>{prettyPrintJsonIfPossible(appLog.output)}</Text>
</Box>
</Box>
)}
</>
) : null}
</Box>
)}
{appLog instanceof NetworkAccessResponseFromCacheLog && (
<>
<Box flexDirection="column">
<Text>Cache write time: {new Date(appLog.cacheEntryEpochMs).toISOString()}</Text>
<Text>Cache TTL: {appLog.cacheTtlMs / 1000} s</Text>
<Text>HTTP request:</Text>
<Text>{prettyPrintJsonIfPossible(appLog.httpRequest)}</Text>
<Text>HTTP response:</Text>
<Text>{prettyPrintJsonIfPossible(appLog.httpResponse)}</Text>
</>
</Box>
)}
{appLog instanceof NetworkAccessRequestExecutionInBackgroundLog && (
<>
<Box flexDirection="column">
<Text>Reason: {getBackgroundExecutionReasonMessage(appLog.reason)}</Text>
<Text>HTTP request:</Text>
<Text>{prettyPrintJsonIfPossible(appLog.httpRequest)}</Text>
</>
</Box>
)}
{appLog instanceof NetworkAccessRequestExecutedLog && (
<>
<Box flexDirection="column">
<Text>Attempt: {appLog.attempt}</Text>
{appLog.connectTimeMs && <Text>Connect time: {appLog.connectTimeMs} ms</Text>}
{appLog.writeReadTimeMs && <Text>Write read time: {appLog.writeReadTimeMs} ms</Text>}
{appLog.connectTimeMs ? <Text>Connect time: {appLog.connectTimeMs} ms</Text> : null}
{appLog.writeReadTimeMs ? <Text>Write read time: {appLog.writeReadTimeMs} ms</Text> : null}
<Text>HTTP request:</Text>
<Text>{prettyPrintJsonIfPossible(appLog.httpRequest)}</Text>
{appLog.httpResponse && (
<>
{appLog.httpResponse ? (
<Box flexDirection="column">
<Text>HTTP response:</Text>
<Text>{prettyPrintJsonIfPossible(appLog.httpResponse)}</Text>
</>
)}
{appLog.error && <Text>Error: {appLog.error}</Text>}
</>
</Box>
) : null}
{appLog.error ? <Text>Error: {appLog.error}</Text> : null}
</Box>
)}
</Box>
</Box>
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/cli/services/app-logs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,15 @@ export const subscribeToAppLogs = async (
return jwtToken
}

export function prettyPrintJsonIfPossible(json: unknown) {
export function prettyPrintJsonIfPossible(json: unknown): string | undefined {
try {
if (typeof json === 'string') {
const jsonObject = JSON.parse(json)
return JSON.stringify(jsonObject, null, 2)
} else if (typeof json === 'object' && json !== null) {
return JSON.stringify(json, null, 2)
} else {
return json
return undefined
}
} catch (error) {
throw new Error(`Error parsing JSON: ${error as string}`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ async function reload(app: AppLinkedInterface): Promise<AppLinkedInterface> {
return newApp
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
throw new Error(`Error reloading app: ${error.message}`, {cause: 'validation-error'})
const err = new Error(`Error reloading app: ${error.message}`)
;(err as Error & {cause: string}).cause = 'validation-error'
throw err
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ export class DevSession {
await this.logger.debug('❌ Dev preview update aborted (new change detected or error during update)')
} else if (result.status === 'remote-error' || result.status === 'unknown-error') {
await this.logger.logUserErrors(result.error, event?.app.allExtensions ?? [])
if (result.error instanceof Error && result.error.cause === 'validation-error') {
if (
result.error instanceof Error &&
(result.error as Error & {cause?: string}).cause === 'validation-error'
) {
this.statusManager.setMessage('VALIDATION_ERROR')
} else {
if (event) this.failedEvents.push(event)
Expand Down
8 changes: 6 additions & 2 deletions packages/app/src/cli/utilities/app/http-reverse-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import * as https from 'https'
import {Writable} from 'stream'
import type Server from 'http-proxy-node16'

function isAggregateError(err: Error): err is Error & {errors: Error[]} {
return 'errors' in err && Array.isArray((err as {errors?: unknown}).errors)
}

export interface LocalhostCert {
key: string
cert: string
Expand Down Expand Up @@ -47,7 +51,7 @@ function getProxyServerWebsocketUpgradeListener(
if (target) {
return proxy.ws(req, socket, head, {target}, (err) => {
useConcurrentOutputContext({outputPrefix: 'proxy', stripAnsi: false}, () => {
const error = err instanceof AggregateError && err.errors.length > 0 ? err.errors[err.errors.length - 1] : err
const error = isAggregateError(err) && err.errors.length > 0 ? err.errors[err.errors.length - 1]! : err
outputWarn(`Error forwarding websocket request: ${error.message}`, stdout)
outputWarn(`└ Unreachable target "${target}" for path: "${req.url}"`, stdout)
})
Expand All @@ -67,7 +71,7 @@ function getProxyServerRequestListener(
if (target) {
return proxy.web(req, res, {target}, (err) => {
useConcurrentOutputContext({outputPrefix: 'proxy', stripAnsi: false}, () => {
const error = err instanceof AggregateError && err.errors.length > 0 ? err.errors[err.errors.length - 1] : err
const error = isAggregateError(err) && err.errors.length > 0 ? err.errors[err.errors.length - 1]! : err
outputWarn(`Error forwarding web request: ${error.message}`, stdout)
outputWarn(`└ Unreachable target "${target}" for path: "${req.url}"`, stdout)
})
Expand Down
4 changes: 2 additions & 2 deletions packages/cli-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
"graphql": "16.10.0",
"graphql-request": "6.1.0",
"ignore": "6.0.2",
"ink": "4.4.1",
"ink": "5.2.1",
"is-executable": "2.0.1",
"is-interactive": "2.0.0",
"is-wsl": "3.1.0",
Expand Down Expand Up @@ -171,7 +171,7 @@
"@types/fs-extra": "9.0.13",
"@types/gradient-string": "^1.1.2",
"@types/lodash": "4.17.19",
"@types/react": "18.2.0",
"@types/react": "^18.2.0",
"@types/semver": "^7.5.2",
"@types/which": "3.0.4",
"@vitest/coverage-istanbul": "^3.1.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type BannerType = 'success' | 'error' | 'warning' | 'info' | 'external_er

interface BannerProps {
type: BannerType
children?: React.ReactNode
}

function typeToColor(type: BannerProps['type']) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ interface CompletedPromptProps {

const CompletedPrompt: FunctionComponent<CompletedPromptProps> = ({cancelled}) => (
<Box>
<Box marginRight={2}>
<Box width={3}>
{cancelled ? <Text color="red">{figures.cross}</Text> : <Text color="cyan">{figures.tick}</Text>}
</Box>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {AbortSignal} from '../../../../../public/node/abort.js'
import useAbortSignal from '../../hooks/use-abort-signal.js'
import {PromptState} from '../../hooks/use-prompt.js'
import React, {ReactElement, cloneElement, useCallback, useLayoutEffect, useState} from 'react'
import {Box, measureElement, Text, useStdout} from 'ink'
import {Box, measureElement, Text, useStdout, DOMElement} from 'ink'
import figures from 'figures'

export type Message = TokenItem<Exclude<InlineToken, LinkToken>>
Expand Down Expand Up @@ -40,7 +40,7 @@ const PromptLayout = ({
const [availableLines, setAvailableLines] = useState(currentAvailableLines)

const wrapperRef = useCallback(
(node) => {
(node: DOMElement | null) => {
if (node !== null) {
const {height} = measureElement(node)
if (wrapperHeight !== height) {
Expand All @@ -51,14 +51,14 @@ const PromptLayout = ({
[wrapperHeight],
)

const promptAreaRef = useCallback((node) => {
const promptAreaRef = useCallback((node: DOMElement | null) => {
if (node !== null) {
const {height} = measureElement(node)
setPromptAreaHeight(height)
}
}, [])

const inputFixedAreaRef = useCallback((node) => {
const inputFixedAreaRef = useCallback((node: DOMElement | null) => {
if (node !== null) {
const {height} = measureElement(node)
// + 3 accounts for the margins inside the input elements and the last empty line of the terminal
Expand Down Expand Up @@ -120,7 +120,7 @@ const PromptLayout = ({

{state === PromptState.Submitted && submittedAnswerLabel ? (
<Box>
<Box marginRight={2}>
<Box width={3}>
<Text color="cyan">{figures.tick}</Text>
</Box>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import sortBy from 'lodash/sortBy.js'

declare module 'react' {
function forwardRef<T, P>(
render: (props: P, ref: React.Ref<T>) => JSX.Element | null,
): (props: P & React.RefAttributes<T>) => JSX.Element | null
render: (props: P, ref: React.Ref<T>) => React.ReactElement | null,
): (props: P & React.RefAttributes<T>) => React.ReactElement | null
}
export interface SelectInputProps<T> {
items: Item<T>[]
Expand Down Expand Up @@ -90,7 +90,7 @@ function Item<T>({
items,
hasAnyGroup,
index,
}: ItemProps<T>): JSX.Element {
}: ItemProps<T>): React.ReactElement {
const label = highlightedLabel(item.label, highlightedTerm)
let title: string | undefined
let labelColor
Expand Down Expand Up @@ -153,7 +153,7 @@ function SelectInputInner<T>(
groupOrder,
}: SelectInputProps<T>,
ref: React.ForwardedRef<DOMElement>,
): JSX.Element | null {
): React.ReactElement | null {
let noItems = false

if (rawItems.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const TextPrompt: FunctionComponent<TextPromptProps> = ({
</Box>
{promptState === PromptState.Submitted ? (
<Box>
<Box marginRight={2}>
<Box width={3}>
<Text color="cyan">{figures.tick}</Text>
</Box>

Expand Down
2 changes: 1 addition & 1 deletion packages/cli-kit/src/public/node/notifications-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async function renderNotifications(notifications: Notification[]) {
notifications.slice(0, 2).forEach((notification) => {
const content = {
headline: notification.title,
body: notification.message.replaceAll('\\n', '\n'),
body: notification.message.replace(/\\n/g, '\n'),
link: notification.cta,
}
switch (notification.type) {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cli/commands/docs/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const data: ReferenceEntityTemplateSchema = {

export default data`

const updatedDocString = docString.replaceAll('<%= config.bin %>', 'shopify')
const updatedDocString = docString.replace(/<%= config\.bin %>/g, 'shopify')

await writeFile(`${docsPath}/${fileName}.doc.ts`, updatedDocString)
outputInfo(`Generated docs for ${commandName}`)
Expand Down
8 changes: 7 additions & 1 deletion packages/theme/src/cli/polyfills/promiseWithResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ interface PromiseWithResolvers<T> {
reject: (reason?: unknown) => void
}

declare global {
interface PromiseConstructor {
withResolvers?<T>(): PromiseWithResolvers<T>
}
}

// Polyfill for Promise.withResolvers
// Can remove once our minimum supported Node version is 22
export function promiseWithResolvers<T>(): PromiseWithResolvers<T> {
if (typeof Promise.withResolvers === 'function') {
if (Promise.withResolvers) {
return Promise.withResolvers<T>()
}

Expand Down
4 changes: 2 additions & 2 deletions packages/theme/src/cli/utilities/theme-environment/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
}

function getStoreFqdnForRegEx(ctx: DevServerContext) {
return ctx.session.storeFqdn.replaceAll('.', '\\.')
return ctx.session.storeFqdn.replace(/\./g, '\\.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎩 'd and didn't run into any issues. I'm not sure if there are edge cases that would cause a problem here when the old code was essentially doing the same.

}

/**
Expand Down Expand Up @@ -289,7 +289,7 @@
}

export function proxyStorefrontRequest(event: H3Event, ctx: DevServerContext): Promise<Response> {
const path = event.path.replaceAll(EXTENSION_CDN_PREFIX, '/')
const path = event.path.replace(new RegExp(EXTENSION_CDN_PREFIX, 'g'), '/')
const host = event.path.startsWith(EXTENSION_CDN_PREFIX) ? 'cdn.shopify.com' : ctx.session.storeFqdn
const url = new URL(path, `https://${host}`)

Expand Down
2 changes: 1 addition & 1 deletion packages/ui-extensions-test-utils/src/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {mount} from '@shopify/react-testing'

export function render<TProps, TProviderProps>(
element: React.ReactElement<TProps>,
Providers: React.ComponentType<TProviderProps> = ({children}) => <>{children}</>,
Providers: React.ComponentType<React.PropsWithChildren<TProviderProps>> = ({children}) => <>{children}</>,
options: Omit<TProviderProps, 'children'> = {} as TProviderProps,
) {
return mount(<Providers {...(options as TProviderProps)}>{element}</Providers>)
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-extensions-test-utils/src/renderHook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function MountHook({callback}: {callback(): void}) {

export function renderHook<T, TP>(
hook: () => T,
Providers: React.ComponentType<TP> = ({children}) => <>{children}</>,
Providers: React.ComponentType<React.PropsWithChildren<TP>> = ({children}) => <>{children}</>,
options: Omit<TP, 'children'> = {} as TP,
) {
const hookResult: HookWrapper<T> = {} as any
Expand Down
Loading
Loading