ConusAI vendor v0.1.0-dev.20261013+85463d22

This commit is contained in:
ConusAI vendor v0.1.0-dev.20261013+85463d22
2026-10-13 20:45:57 +00:00
parent c3c6526952
commit 0da8a2a81b
67 changed files with 1510 additions and 10153 deletions
+13
View File
@@ -0,0 +1,13 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
// The deployer's default health probe is "/" (deploy_image.rs), which renders
// this app's dashboard; the template must ship its real health route in
// .conusai.yaml (schema: crates/conusai-repo-config, `health.path`).
describe('.conusai.yaml', () => {
const yaml = readFileSync(new URL('../.conusai.yaml', import.meta.url), 'utf8')
it('declares the health check path the app actually serves', () => {
expect(yaml).toMatch(/^health:\n(\s{2}.*\n)*\s{2}path: \/api\/health\s*$/m)
})
})
+36
View File
@@ -0,0 +1,36 @@
import { existsSync, readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
// Every showcase visit 404'd on both /favicon.ico and /favicon.svg (stage sweep,
// 2026-10-11) because the template shipped no favicon at all. `app/favicon.ico` is
// Next's own file convention for /favicon.ico; `public/favicon.svg` is a plain static
// file for /favicon.svg, which Next's convention does not cover (it only serves
// `icon.svg` at /icon.svg). The root layout's `metadata.icons` must name both, so the
// rendered <link> tags match what is actually shipped.
describe('favicon', () => {
it('ships a valid favicon.ico for Next’s /favicon.ico convention', () => {
const path = fileURLToPath(new URL('../app/favicon.ico', import.meta.url))
expect(existsSync(path)).toBe(true)
const bytes = readFileSync(path)
// ICO header: reserved=0, type=1 (icon), at least one image.
expect(bytes.readUInt16LE(0)).toBe(0)
expect(bytes.readUInt16LE(2)).toBe(1)
expect(bytes.readUInt16LE(4)).toBeGreaterThan(0)
})
it('ships public/favicon.svg, served verbatim at /favicon.svg', () => {
const path = fileURLToPath(new URL('../public/favicon.svg', import.meta.url))
expect(existsSync(path)).toBe(true)
expect(readFileSync(path, 'utf8')).toContain('<svg')
})
it('names both favicons in the root layout’s metadata', () => {
const layout = readFileSync(
new URL('../src/app/layouts/root.tsx', import.meta.url),
'utf8',
)
expect(layout).toMatch(/\/favicon\.svg/)
expect(layout).toMatch(/\/favicon\.ico/)
})
})
+24
View File
@@ -0,0 +1,24 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
// The template renders with browser-default styling unless the root layout
// imports the global stylesheet (seen on stage 2026-10-10: the deployed
// dashboard answered 200 with zero CSS linked). The layout is the one module
// every page passes through, so its import is the whole contract.
describe('global stylesheet', () => {
const layout = readFileSync(
new URL('../src/app/layouts/root.tsx', import.meta.url),
'utf8',
)
it('is imported by the root layout', () => {
expect(layout).toMatch(/import\s+['"]\.\.\/globals\.css['"]/)
})
it('exists and carries the design tokens', () => {
const css = readFileSync(new URL('../src/app/globals.css', import.meta.url), 'utf8')
expect(css).toContain(':root')
expect(css).toContain('--accent')
expect(css).toContain('main')
})
})
+53
View File
@@ -0,0 +1,53 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
// @conusai-sdk/observe's replay module is off unless modules.replay is `true` or a
// ReplayOptions object (sdks/node/packages/observe/src/index.ts). The default mode,
// 'onError', only uploads a replay when an error is captured, so a plain showcase visit
// produced nothing on Analytics > Session Replays (showcase plan D22). The shipped
// instrumentation-client.ts must enable replay in a mode that records from page start.
//
// mode: 'always' alone is not enough (showcase plan D24): replay is a 'consented' item
// (core/consent.ts verdict()), and the default consent mode 'anonymous' never sends
// consented items, so the recorder never starts regardless of mode. Verified live on
// stage 2026-10-11: 'always' with no consent option produced zero /api/_conusai/envelope
// requests in 40+ seconds of interaction. The shipped file must also opt out of consent.
//
// @conusai-sdk/observe enables only `errors` by default (sdks/node/packages/observe/src/index.ts):
// every other module — analytics, vitals, traces, replay, logs — is off unless named truthy under
// `modules`. The showcase exists to exercise every SDK module, so this test fails whenever the
// shipped instrumentation-client.ts leaves one off or sets it to a bare `false` (showcase plan D25).
describe('instrumentation-client.ts', () => {
const source = readFileSync(new URL('../instrumentation-client.ts', import.meta.url), 'utf8')
// A tiny parser rather than one regex per module: a module switch can be `true` or an options
// object (replay's `{ mode: 'always' }`), and a regex permissive enough for both shapes would
// also match a module spelled out in a comment, which defeats the point of this test.
function moduleSwitches(src: string): Record<string, unknown> {
const match = src.match(/modules:\s*{([\s\S]*?)}\s*,?\s*}\)/)
const body = match?.[1]
if (!body) throw new Error('no modules: {...} block found in instrumentation-client.ts')
const result: Record<string, unknown> = {}
for (const entry of body.matchAll(/(\w+):\s*(true|false|\{[^}]*\})/g)) {
const name = entry[1]
const value = entry[2]
if (!name || !value) continue
result[name] = value === 'true' ? true : value === 'false' ? false : value
}
return result
}
it.each(['analytics', 'vitals', 'traces', 'replay', 'logs'])('enables the %s module', (name) => {
const switches = moduleSwitches(source)
expect(switches, `modules.${name} is missing`).toHaveProperty(name)
expect(switches[name], `modules.${name} must not be false`).not.toBe(false)
})
it('enables replay in a mode that records every visit, not only on error', () => {
expect(source).toMatch(/modules:\s*{[\s\S]*?replay:\s*{\s*mode:\s*['"]always['"]/)
})
it('opts consent out, so replay (a consented item) is actually allowed to send', () => {
expect(source).toMatch(/consent:\s*['"]opt-out['"]/)
})
})
+19
View File
@@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest'
import { MAX_UPLOAD_BYTES } from '@/entities/file'
import nextConfig from '../next.config'
// The upload form posts to a server action, whose body Next caps at 1 MB unless
// configured (next.config `experimental.serverActions.bodySizeLimit`). The cap must
// admit the largest attachment the app accepts, plus multipart overhead.
function parseLimit(limit: string | number | undefined): number | undefined {
if (typeof limit === 'number') return limit
const match = /^(\d+)mb$/.exec(limit ?? '')
return match ? Number(match[1]) * 1024 * 1024 : undefined
}
describe('next.config server action body limit', () => {
it('admits the largest attachment the app accepts', () => {
const limit = parseLimit(nextConfig.experimental?.serverActions?.bodySizeLimit)
expect(limit).toBeGreaterThanOrEqual(MAX_UPLOAD_BYTES)
})
})
+95
View File
@@ -0,0 +1,95 @@
import { existsSync, readFileSync, readdirSync } from 'node:fs'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
// Every @conusai-sdk/* package the template imports must be pinned in the
// shipped package.json at the version the SDK source tree carries at the same
// commit (showcase plan §2.7 "Pin versions", D19). An import the manifest does
// not declare builds nowhere: `npm install` cannot know it and `next build`
// fails with "Module not found" (KI-55; stage deployment #5, 2026-10-09).
//
// The pin comparison needs the monorepo: CONUSAI_REPO_ROOT when set
// (test-template.sh exports it), else the nearest ancestor holding
// sdks/node/packages. A standalone project created from the template has
// neither — no source tree exists there to compare against, so only the
// presence check runs.
const templateRoot = fileURLToPath(new URL('..', import.meta.url))
const thisFile = fileURLToPath(import.meta.url)
const IMPORT_PATTERN = /@conusai-sdk\/[a-z0-9-]+/g
const SOURCE_PATTERN = /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/
const SKIP_DIRS = new Set(['node_modules', '.next'])
function collectSdkImports(dir: string, found = new Set<string>()): Set<string> {
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const path = join(dir, entry.name)
if (entry.isDirectory()) {
if (!SKIP_DIRS.has(entry.name)) collectSdkImports(path, found)
} else if (SOURCE_PATTERN.test(entry.name) && path !== thisFile) {
for (const match of readFileSync(path, 'utf8').matchAll(IMPORT_PATTERN)) found.add(match[0])
}
}
return found
}
const sdkImports = [...collectSdkImports(templateRoot)].sort()
const manifest = JSON.parse(readFileSync(join(templateRoot, 'package.json'), 'utf8')) as {
dependencies?: Record<string, string>
devDependencies?: Record<string, string>
}
const declared: Record<string, string> = { ...manifest.dependencies, ...manifest.devDependencies }
function monorepoRoot(): string | undefined {
const candidates = process.env.CONUSAI_REPO_ROOT ? [process.env.CONUSAI_REPO_ROOT] : []
let dir = templateRoot
for (let depth = 0; depth <= 4; depth += 1) {
candidates.push(dir)
dir = join(dir, '..')
}
return candidates.find((candidate) => existsSync(join(candidate, 'sdks/node/packages')))
}
function sdkSourceVersions(root: string): Map<string, string> {
const versions = new Map<string, string>()
for (const group of ['sdks/node/packages', 'packages']) {
for (const entry of readdirSync(join(root, group), { withFileTypes: true })) {
const manifestPath = join(root, group, entry.name, 'package.json')
if (!entry.isDirectory() || !existsSync(manifestPath)) continue
const source = JSON.parse(readFileSync(manifestPath, 'utf8')) as { name?: string; version?: string }
if (source.name?.startsWith('@conusai-sdk/') && source.version) versions.set(source.name, source.version)
}
}
return versions
}
// A dev vendor bundle rewrites every package's own version and the template's
// @conusai-sdk/* pins with the same `-dev.<yyyymmdd>.<sha8>` suffix, inside the
// bundle only (scripts/vendor/build-bundle.sh, scripts/vendor/rewrite-version.py;
// showcase plan D29). test-template.sh now builds this file's package.json from
// the bundle's own rewritten template archive, so a dev build's declared pin
// carries that suffix; strip it before comparing against this commit's plain
// SDK source version. A release build's pin carries no suffix, so the strip is
// a no-op there.
const DEV_SUFFIX = /[-.]dev\.\d{8}\.[0-9a-f]+$/
describe('the shipped package.json pins every imported @conusai-sdk package (D19)', () => {
it('finds @conusai-sdk imports in the template (negative control)', () => {
expect(sdkImports.length).toBeGreaterThan(0)
})
it.each(sdkImports)('declares %s', (name) => {
expect(declared, `${name} is imported but missing from package.json`).toHaveProperty(name)
})
it('pins each at the version the SDK source tree carries at this commit (plain, or dev-bundle-suffixed)', () => {
const root = monorepoRoot()
if (!root) return // standalone checkout: no SDK source tree to compare against
const versions = sdkSourceVersions(root)
for (const name of sdkImports) {
expect(versions.has(name), `${name} has no source package under sdks/node/packages or packages`).toBe(true)
const pinnedBase = (declared[name] ?? '').replace(DEV_SUFFIX, '')
expect(pinnedBase, `${name} pin differs from the SDK source version at this commit`).toBe(versions.get(name))
}
})
})
+20
View File
@@ -0,0 +1,20 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
// `next build` rewrites tsconfig.json when the values differ from what Next 16
// mandates (jsx: react-jsx, .next/dev/types in include), dirtying the checkout on
// every build. The shipped file must already hold them.
const tsconfig = JSON.parse(readFileSync(new URL('../tsconfig.json', import.meta.url), 'utf8')) as {
compilerOptions: { jsx?: string }
include: string[]
}
describe('tsconfig holds the values Next 16 mandates', () => {
it('uses the React automatic runtime jsx setting', () => {
expect(tsconfig.compilerOptions.jsx).toBe('react-jsx')
})
it('includes the dev types directory', () => {
expect(tsconfig.include).toContain('.next/dev/types/**/*.ts')
})
})