import {
listUserSecretNames,
ADMIN_ACCESS_TOKEN_SECRET,
CLIENT_ID_SECRET,
CLIENT_SECRET_SECRET,
resolveAuthMode,
resolveShop,
} from './lib/client.ts'
import { runShopHelperSelfCheck } from './lib/shop.ts'
import { getShop } from './shop.ts'
import type { ShopifyClientOptions } from './types.ts'
export type ShopifySmokeTestResult = {
ok: boolean
selfCheck: { ok: true; checks: number }
live: boolean
authMode: 'admin-token' | 'client-credentials' | null
shop: string | null
shopName: string | null
setup: {
secrets: {
shopifyAdminAccessToken: boolean
shopifyClientId: boolean
shopifyClientSecret: boolean
}
nextSteps: Array<string>
}
}
/**
* Local helper checks, plus an optional live `shop { name }` read.
*
* Pass `shop` (and have secrets saved) to exercise credentials. Without
* them this still returns `{ ok: true, live: false }` and setup URLs so
* the package is forkable before anyone connects a store.
*
* @example
* import smokeTest from 'kody:@kody/shopify/smoke-test'
* const result = await smokeTest({ shop: 'acme' })
*/
export async function smokeTest(
params: ShopifyClientOptions = {},
): Promise<ShopifySmokeTestResult> {
const selfCheck = runShopHelperSelfCheck()
const names = await listUserSecretNames()
const secrets = {
shopifyAdminAccessToken: names.has(ADMIN_ACCESS_TOKEN_SECRET),
shopifyClientId: names.has(CLIENT_ID_SECRET),
shopifyClientSecret: names.has(CLIENT_SECRET_SECRET),
}
const nextSteps: Array<string> = []
if (!secrets.shopifyAdminAccessToken && !(secrets.shopifyClientId && secrets.shopifyClientSecret)) {
nextSteps.push(
'Save shopifyClientId and shopifyClientSecret from the Shopify Dev Dashboard, or shopifyAdminAccessToken from a legacy custom app.',
)
nextSteps.push(
'https://kody.codes/account/secrets/new?name=shopifyClientId&description=Shopify%20Dev%20Dashboard%20client%20id&scope=user',
)
nextSteps.push(
'https://kody.codes/account/secrets/new?name=shopifyClientSecret&description=Shopify%20Dev%20Dashboard%20client%20secret&scope=user',
)
}
let shop: string | null = null
try {
shop = await resolveShop(params.shop)
} catch {
shop = null
nextSteps.push(
'Pass shop: "your-store" (the *.myshopify.com handle) or set a default after forking via kody:@kody/shopify/config.',
)
}
if (shop) {
nextSteps.push(
`Approve host ${shop}.myshopify.com in the account secrets UI after the secret is saved.`,
)
}
const canLive =
Boolean(shop) &&
(secrets.shopifyAdminAccessToken ||
(secrets.shopifyClientId && secrets.shopifyClientSecret))
if (!canLive) {
return {
ok: true,
selfCheck,
live: false,
authMode: null,
shop,
shopName: null,
setup: { secrets, nextSteps },
}
}
const authMode = await resolveAuthMode()
const profile = await getShop({ shop: shop || undefined, apiVersion: params.apiVersion })
return {
ok: true,
selfCheck,
live: true,
authMode,
shop: profile.myshopifyDomain,
shopName: profile.name,
setup: { secrets, nextSteps: [] },
}
}
/** Default export: smoke test. */
export default smokeTest