import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import test from 'node:test' import { fileURLToPath } from 'node:url' import { resolveIntegrationName, resolveSecretName } from './setup.ts' import { kitUrl, mutationPreview, normalizeKitPath, rejectBroadcastSend } from './safety.ts' import { API_KEY_SETUP_URL, DEFAULT_API_KEY_SECRET, KIT_CALLBACK_URL, OAUTH_CONNECT_URL, apiKeySetupUrl, oauthConnectUrl, } from './setup.ts' import { buildLiquidGreeting, joinEmailBlocks } from './html.ts' const here = dirname(fileURLToPath(import.meta.url)) const root = join(here, '..') test('secret and integration names default and suffix accounts', () => { assert.equal(resolveIntegrationName(), 'kit') assert.equal(resolveSecretName(), DEFAULT_API_KEY_SECRET) assert.equal(resolveIntegrationName({ account: 'default' }), 'kit') assert.equal(resolveIntegrationName({ account: 'work' }), 'kit-work') assert.equal(resolveSecretName({ account: 'work' }), 'kitApiKey-work') assert.equal(resolveIntegrationName({ integrationName: 'kit-brand' }), 'kit-brand') assert.equal(resolveSecretName({ secretName: 'kitApiKey-brand' }), 'kitApiKey-brand') }) test('setup URLs are prefilled for OAuth and API key', () => { assert.match(OAUTH_CONNECT_URL, /provider=kit/) assert.match(OAUTH_CONNECT_URL, /authorizeUrl=https%3A%2F%2Fapi\.kit\.com%2Fv4%2Foauth%2Fauthorize/) assert.match(OAUTH_CONNECT_URL, /tokenUrl=https%3A%2F%2Fapi\.kit\.com%2Fv4%2Foauth%2Ftoken/) assert.match(OAUTH_CONNECT_URL, /allowedHosts=api\.kit\.com/) assert.equal(KIT_CALLBACK_URL, 'https://kody.codes/connect/oauth') assert.match(API_KEY_SETUP_URL, /name=kitApiKey/) assert.match(API_KEY_SETUP_URL, /allowedHosts=api\.kit\.com/) assert.match(API_KEY_SETUP_URL, /scope=user/) assert.match(oauthConnectUrl('kit-work'), /provider=kit-work/) assert.match(apiKeySetupUrl('kitApiKey-work'), /name=kitApiKey-work/) }) test('mutationPreview dryRun skips confirm', () => { const preview = mutationPreview( { dryRun: true }, { method: 'POST', path: '/subscribers', body: { email_address: 'ada@example.com' }, }, ) assert.deepEqual(preview, { dryRun: true, method: 'POST', path: '/subscribers', body: { email_address: 'ada@example.com' }, }) }) test('mutationPreview requires confirm for live writes', () => { assert.throws( () => mutationPreview( {}, { method: 'POST', path: '/broadcasts', body: { subject: 'Hi' } }, ), /confirm: true/, ) assert.equal( mutationPreview( { confirm: true }, { method: 'POST', path: '/broadcasts', body: { subject: 'Hi' } }, ), null, ) }) test('broadcast helpers refuse send_at and send statuses', () => { assert.throws( () => rejectBroadcastSend({ send_at: '2026-01-01T00:00:00Z' }, 'createBroadcastDraft'), /draft-only/, ) assert.throws( () => rejectBroadcastSend({ status: 'published' }, 'updateBroadcast'), /draft-only/, ) rejectBroadcastSend({ subject: 'Hello' }, 'createBroadcastDraft') }) test('kitUrl stays on api.kit.com/v4', () => { assert.equal(normalizeKitPath('/subscribers'), '/subscribers') assert.match(kitUrl('/account'), /^https:\/\/api\.kit\.com\/v4\/account$/) assert.match(kitUrl('/broadcasts', { per_page: 5 }), /per_page=5/) assert.throws(() => normalizeKitPath('https://example.com/v4/account'), /api\.kit\.com/) }) test('html builders stay generic', () => { const greeting = buildLiquidGreeting({ withName: 'Hey {{ subscriber.first_name }}', withoutName: 'Hey there', }) assert.match(greeting, /subscriber\.first_name/) assert.equal(joinEmailBlocks(['
A
', 'B
']), 'A
\n\nB
') }) test('package is public MIT official kit with disabled job', () => { const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) assert.equal(manifest.name, '@kody/kit') assert.equal(manifest.license, 'MIT') assert.equal(manifest.private, false) assert.equal(manifest.kody.id, 'kit') assert.equal(manifest.kody.jobs['account-health'].enabled, false) const readme = readFileSync(join(root, 'README.md'), 'utf8') assert.match(readme, /## Intent/) assert.match(readme, /https:\/\/kody\.codes\/@kody\/kit/) assert.doesNotMatch(readme, /\/community\/[0-9a-f-]{36}/) assert.doesNotMatch(readme, /hello@kentcdodds\.com/) assert.doesNotMatch(readme, /betterWithKent/) assert.doesNotMatch(readme, /KIT_TEMPLATES/) const icon = readFileSync(join(root, 'community-icon.svg'), 'utf8') assert.match(icon, /#44B1FF/) assert.match(icon, /Official Kit wordmark/) })