import { kody } from 'kody:runtime'
import { smokeTest, tryDefaultHandle } from './client.ts'
import {
APP_PASSWORD_DOCS_URL,
APP_PASSWORD_SECRET,
APP_PASSWORD_SETUP_URL,
AUTH_HOST,
DEFAULT_AUTH_SERVICE,
DEFAULT_PUBLIC_APPVIEW,
HANDLE_STORAGE_KEY,
PDS_HOST_PATTERN,
} from './setup.ts'
function secretEntries(result: unknown): Array<{ name?: string; scope?: string }> {
if (result && typeof result === 'object' && Array.isArray((result as { secrets?: unknown }).secrets)) {
return (result as { secrets: Array<{ name?: string; scope?: string }> }).secrets
}
return Array.isArray(result) ? result : []
}
/**
* Verify Bluesky auth and read the default profile without returning session tokens.
* Without a saved app password or handle this still returns `{ ok: true, live: false }`
* plus the prefilled secret URL so the package is forkable before anyone connects.
* @example
* import smokeTest from 'kody:@kody/bluesky/smoke-test'
* const result = await smokeTest()
* // => { ok: true, live: false, setup: { ... } }
*/
export default async function smokeTestEntrypoint(params: Record<string, unknown> = {}) {
const listed = await kody.secret_list({ scope: 'user' })
const names = new Set<string>()
for (const entry of secretEntries(listed)) {
if (entry?.name && (entry.scope === 'user' || !entry.scope)) {
names.add(entry.name)
}
}
const identifier =
(typeof params.identifier === 'string' && params.identifier.trim()) ||
(typeof params.handle === 'string' && params.handle.trim()) ||
(await tryDefaultHandle())
const hasSecret = names.has(APP_PASSWORD_SECRET)
const setup = {
secretUrl: APP_PASSWORD_SETUP_URL,
appPasswordDocs: APP_PASSWORD_DOCS_URL,
hosts: [AUTH_HOST, PDS_HOST_PATTERN],
handleStorageKey: HANDLE_STORAGE_KEY,
defaultAuthService: DEFAULT_AUTH_SERVICE,
defaultPublicAppview: DEFAULT_PUBLIC_APPVIEW,
secrets: { [APP_PASSWORD_SECRET]: hasSecret },
hasHandle: Boolean(identifier),
nextSteps: [
'Create an app password at ' + APP_PASSWORD_DOCS_URL + '. Do not paste it into chat.',
APP_PASSWORD_SETUP_URL,
'Approve hosts bsky.social and *.bsky.network after the secret is saved.',
'Fork this package, then packageStorage().set("blueskyHandle", "yourhandle.bsky.social").',
],
}
if (!hasSecret || !identifier || params.setupOnly === true) {
return {
ok: true,
live: false,
method: 'com.atproto.server.createSession',
host: AUTH_HOST,
handle: identifier || null,
setup,
}
}
const live = await smokeTest({ ...params, identifier })
return { ...live, setup: { ...setup, nextSteps: [] } }
}