@voltro/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/LICENSE +57 -0
- package/README.md +26 -0
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +20236 -0
- package/bin/voltro.mjs +43 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +9 -0
- package/dist/commands-CfPH2Wf4.js +18061 -0
- package/dist/frameworkInspectState-CX2250XB.js +86 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +5 -0
- package/dist/inspectState.d.ts +116 -0
- package/dist/inspectState.js +2 -0
- package/dist/startup.d.ts +26 -0
- package/dist/startup.js +2 -0
- package/dist/startupRunner-CRhuUl91.js +71 -0
- package/package.json +88 -0
- package/templates/AGENTS.core.md +258 -0
- package/templates/AGENTS.md +351 -0
- package/templates/agent-docs/_index.md +93 -0
- package/templates/agent-docs/_manifest.json +655 -0
- package/templates/agent-docs/ai.md +1845 -0
- package/templates/agent-docs/authentication.md +1788 -0
- package/templates/agent-docs/caching.md +624 -0
- package/templates/agent-docs/cli.md +1650 -0
- package/templates/agent-docs/configuration.md +295 -0
- package/templates/agent-docs/data.md +2172 -0
- package/templates/agent-docs/database/advancedqueries.md +1583 -0
- package/templates/agent-docs/database/columntypes.md +1200 -0
- package/templates/agent-docs/database/hosting.md +881 -0
- package/templates/agent-docs/database/migrations.md +2938 -0
- package/templates/agent-docs/database/misc.md +270 -0
- package/templates/agent-docs/database/overview.md +108 -0
- package/templates/agent-docs/database/querying.md +1622 -0
- package/templates/agent-docs/database/scaling.md +331 -0
- package/templates/agent-docs/database/schema.md +1458 -0
- package/templates/agent-docs/database/seedsdialects.md +1235 -0
- package/templates/agent-docs/database/transactions.md +285 -0
- package/templates/agent-docs/deployment.md +999 -0
- package/templates/agent-docs/internationalization.md +359 -0
- package/templates/agent-docs/introduction.md +438 -0
- package/templates/agent-docs/multi-tenancy.md +610 -0
- package/templates/agent-docs/observability.md +350 -0
- package/templates/agent-docs/plugins.md +1273 -0
- package/templates/agent-docs/reference.md +978 -0
- package/templates/agent-docs/routing.md +1553 -0
- package/templates/agent-docs/scheduling.md +666 -0
- package/templates/agent-docs/schema-driven-ui.md +607 -0
- package/templates/agent-docs/security.md +42 -0
- package/templates/agent-docs/templates/apibackends.md +3214 -0
- package/templates/agent-docs/templates/appshells.md +2062 -0
- package/templates/agent-docs/templates/custom.md +128 -0
- package/templates/agent-docs/templates/overview.md +122 -0
- package/templates/agent-docs/templates/serverless.md +315 -0
- package/templates/agent-docs/testing.md +376 -0
- package/templates/agent-docs/workflows.md +1351 -0
- package/templates/apps/api-ai/README.md +105 -0
- package/templates/apps/api-ai/actions/summarize.action.server.tsx +32 -0
- package/templates/apps/api-ai/actions/summarize.action.ts +33 -0
- package/templates/apps/api-ai/agents/support.agent.server.tsx +31 -0
- package/templates/apps/api-ai/agents/support.agent.tsx +27 -0
- package/templates/apps/api-ai/app.config.ts +57 -0
- package/templates/apps/api-ai/database/schema.ts +67 -0
- package/templates/apps/api-ai/package.json +27 -0
- package/templates/apps/api-ai/seeds/docs.seed.ts +67 -0
- package/templates/apps/api-ai/template.json +6 -0
- package/templates/apps/api-ai/tests/summarize.test.ts +50 -0
- package/templates/apps/api-ai/tools/searchDocs.tool.tsx +60 -0
- package/templates/apps/api-ai/tsconfig.json +5 -0
- package/templates/apps/api-auth/.env +17 -0
- package/templates/apps/api-auth/README.md +109 -0
- package/templates/apps/api-auth/actions/me.action.server.ts +20 -0
- package/templates/apps/api-auth/actions/me.action.ts +19 -0
- package/templates/apps/api-auth/app.config.ts +59 -0
- package/templates/apps/api-auth/database/schema.ts +26 -0
- package/templates/apps/api-auth/package.json +28 -0
- package/templates/apps/api-auth/template.json +6 -0
- package/templates/apps/api-auth/tests/me.test.ts +37 -0
- package/templates/apps/api-auth/tsconfig.json +5 -0
- package/templates/apps/api-backend/README.md +25 -0
- package/templates/apps/api-backend/app.config.ts +39 -0
- package/templates/apps/api-backend/database/schema.ts +57 -0
- package/templates/apps/api-backend/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend/package.json +28 -0
- package/templates/apps/api-backend/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend/template.json +6 -0
- package/templates/apps/api-backend/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend/tsconfig.json +5 -0
- package/templates/apps/api-backend-deactivation/README.md +49 -0
- package/templates/apps/api-backend-deactivation/actions/users.get.action.server.ts +17 -0
- package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +18 -0
- package/templates/apps/api-backend-deactivation/app.config.ts +20 -0
- package/templates/apps/api-backend-deactivation/database/schema.ts +41 -0
- package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.server.ts +6 -0
- package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +16 -0
- package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.server.ts +10 -0
- package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +19 -0
- package/templates/apps/api-backend-deactivation/package.json +28 -0
- package/templates/apps/api-backend-deactivation/template.json +6 -0
- package/templates/apps/api-backend-deactivation/tests/users.deactivate.test.ts +47 -0
- package/templates/apps/api-backend-deactivation/tsconfig.json +5 -0
- package/templates/apps/api-backend-mail/README.md +39 -0
- package/templates/apps/api-backend-mail/actions/sendWelcome.action.server.ts +15 -0
- package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +21 -0
- package/templates/apps/api-backend-mail/app.config.ts +34 -0
- package/templates/apps/api-backend-mail/database/schema.ts +57 -0
- package/templates/apps/api-backend-mail/emails/welcome.email.tsx +106 -0
- package/templates/apps/api-backend-mail/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend-mail/package.json +30 -0
- package/templates/apps/api-backend-mail/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend-mail/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend-mail/template.json +6 -0
- package/templates/apps/api-backend-mail/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend-mail/tsconfig.json +5 -0
- package/templates/apps/api-backend-mariadb/.env.example +35 -0
- package/templates/apps/api-backend-mariadb/README.md +31 -0
- package/templates/apps/api-backend-mariadb/app.config.ts +68 -0
- package/templates/apps/api-backend-mariadb/database/schema.ts +57 -0
- package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend-mariadb/package.json +30 -0
- package/templates/apps/api-backend-mariadb/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend-mariadb/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend-mariadb/template.json +6 -0
- package/templates/apps/api-backend-mariadb/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend-mariadb/tsconfig.json +5 -0
- package/templates/apps/api-backend-storage/README.md +86 -0
- package/templates/apps/api-backend-storage/actions/uploadAvatar.action.server.ts +21 -0
- package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +21 -0
- package/templates/apps/api-backend-storage/actions/uploadDocument.action.server.ts +21 -0
- package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +20 -0
- package/templates/apps/api-backend-storage/app.config.ts +38 -0
- package/templates/apps/api-backend-storage/database/schema.ts +57 -0
- package/templates/apps/api-backend-storage/mutations/notes.create.mutation.server.ts +19 -0
- package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +37 -0
- package/templates/apps/api-backend-storage/package.json +27 -0
- package/templates/apps/api-backend-storage/queries/notes.query.server.ts +14 -0
- package/templates/apps/api-backend-storage/queries/notes.query.ts +20 -0
- package/templates/apps/api-backend-storage/template.json +6 -0
- package/templates/apps/api-backend-storage/tests/notes.create.test.ts +50 -0
- package/templates/apps/api-backend-storage/tsconfig.json +5 -0
- package/templates/apps/api-data-advanced/.env +17 -0
- package/templates/apps/api-data-advanced/README.md +88 -0
- package/templates/apps/api-data-advanced/app.config.ts +56 -0
- package/templates/apps/api-data-advanced/database/actors.entity.ts +14 -0
- package/templates/apps/api-data-advanced/database/authors.entity.ts +30 -0
- package/templates/apps/api-data-advanced/database/authors.relations.ts +15 -0
- package/templates/apps/api-data-advanced/database/books.entity.ts +59 -0
- package/templates/apps/api-data-advanced/database/books.relations.ts +10 -0
- package/templates/apps/api-data-advanced/database/index.ts +23 -0
- package/templates/apps/api-data-advanced/database/tenants.entity.ts +11 -0
- package/templates/apps/api-data-advanced/package.json +28 -0
- package/templates/apps/api-data-advanced/queries/authors.withBooks.query.server.ts +18 -0
- package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +40 -0
- package/templates/apps/api-data-advanced/queries/books.search.query.server.ts +17 -0
- package/templates/apps/api-data-advanced/queries/books.search.query.ts +39 -0
- package/templates/apps/api-data-advanced/seeds/catalog.seed.ts +101 -0
- package/templates/apps/api-data-advanced/template.json +6 -0
- package/templates/apps/api-data-advanced/tests/queries.test.ts +124 -0
- package/templates/apps/api-data-advanced/tsconfig.json +5 -0
- package/templates/apps/api-durable/README.md +81 -0
- package/templates/apps/api-durable/aggregates/orderStats.aggregate.ts +49 -0
- package/templates/apps/api-durable/app.config.ts +41 -0
- package/templates/apps/api-durable/database/schema.ts +65 -0
- package/templates/apps/api-durable/mutations/orders.approve.mutation.server.ts +43 -0
- package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +23 -0
- package/templates/apps/api-durable/mutations/orders.place.mutation.server.ts +45 -0
- package/templates/apps/api-durable/mutations/orders.place.mutation.ts +40 -0
- package/templates/apps/api-durable/package.json +28 -0
- package/templates/apps/api-durable/schedules/nightlyReport.cron.tsx +37 -0
- package/templates/apps/api-durable/startup/warm.startup.tsx +33 -0
- package/templates/apps/api-durable/subscribers/orderChanges.subscribe.ts +27 -0
- package/templates/apps/api-durable/template.json +6 -0
- package/templates/apps/api-durable/tests/orders.place.test.ts +91 -0
- package/templates/apps/api-durable/triggers/order.placed.trigger.tsx +21 -0
- package/templates/apps/api-durable/tsconfig.json +5 -0
- package/templates/apps/api-durable/workflows/order.fulfill.workflow.server.tsx +103 -0
- package/templates/apps/api-durable/workflows/order.fulfill.workflow.tsx +25 -0
- package/templates/apps/api-feature-flags/README.md +63 -0
- package/templates/apps/api-feature-flags/actions/notes.export.action.server.ts +11 -0
- package/templates/apps/api-feature-flags/actions/notes.export.action.ts +18 -0
- package/templates/apps/api-feature-flags/app.config.ts +41 -0
- package/templates/apps/api-feature-flags/database/schema.ts +37 -0
- package/templates/apps/api-feature-flags/mutations/notes.create.mutation.server.ts +29 -0
- package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +28 -0
- package/templates/apps/api-feature-flags/package.json +29 -0
- package/templates/apps/api-feature-flags/template.json +6 -0
- package/templates/apps/api-feature-flags/tests/notes.create.test.ts +67 -0
- package/templates/apps/api-feature-flags/tsconfig.json +5 -0
- package/templates/apps/api-governance/.env +4 -0
- package/templates/apps/api-governance/README.md +61 -0
- package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -0
- package/templates/apps/api-governance/actions/profiles.get.action.ts +17 -0
- package/templates/apps/api-governance/app.config.ts +35 -0
- package/templates/apps/api-governance/database/schema.ts +41 -0
- package/templates/apps/api-governance/mutations/profiles.create.mutation.server.ts +17 -0
- package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +21 -0
- package/templates/apps/api-governance/package.json +29 -0
- package/templates/apps/api-governance/template.json +6 -0
- package/templates/apps/api-governance/tests/profiles.create.test.ts +59 -0
- package/templates/apps/api-governance/tsconfig.json +5 -0
- package/templates/apps/api-kv/README.md +100 -0
- package/templates/apps/api-kv/actions/sync.pull.action.server.ts +75 -0
- package/templates/apps/api-kv/actions/sync.pull.action.ts +25 -0
- package/templates/apps/api-kv/actions/sync.reset.action.server.ts +25 -0
- package/templates/apps/api-kv/actions/sync.reset.action.ts +22 -0
- package/templates/apps/api-kv/actions/sync.status.action.server.ts +28 -0
- package/templates/apps/api-kv/actions/sync.status.action.ts +17 -0
- package/templates/apps/api-kv/app.config.ts +48 -0
- package/templates/apps/api-kv/database/schema.ts +62 -0
- package/templates/apps/api-kv/package.json +28 -0
- package/templates/apps/api-kv/queries/events.list.query.server.ts +14 -0
- package/templates/apps/api-kv/queries/events.list.query.ts +23 -0
- package/templates/apps/api-kv/template.json +6 -0
- package/templates/apps/api-kv/tests/sync.test.ts +103 -0
- package/templates/apps/api-kv/tsconfig.json +5 -0
- package/templates/apps/api-moderation/README.md +46 -0
- package/templates/apps/api-moderation/app.config.ts +33 -0
- package/templates/apps/api-moderation/database/schema.ts +45 -0
- package/templates/apps/api-moderation/mutations/comments.create.mutation.server.ts +8 -0
- package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +20 -0
- package/templates/apps/api-moderation/mutations/posts.create.mutation.server.ts +9 -0
- package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +25 -0
- package/templates/apps/api-moderation/package.json +29 -0
- package/templates/apps/api-moderation/template.json +6 -0
- package/templates/apps/api-moderation/tests/posts.create.test.ts +79 -0
- package/templates/apps/api-moderation/tsconfig.json +5 -0
- package/templates/apps/api-observability/README.md +106 -0
- package/templates/apps/api-observability/app.config.ts +32 -0
- package/templates/apps/api-observability/database/schema.ts +38 -0
- package/templates/apps/api-observability/mutations/notes.create.mutation.server.ts +33 -0
- package/templates/apps/api-observability/mutations/notes.create.mutation.ts +15 -0
- package/templates/apps/api-observability/package.json +29 -0
- package/templates/apps/api-observability/queries/notes.list.query.server.ts +7 -0
- package/templates/apps/api-observability/queries/notes.list.query.ts +14 -0
- package/templates/apps/api-observability/template.json +6 -0
- package/templates/apps/api-observability/tests/notes.create.test.ts +36 -0
- package/templates/apps/api-observability/tsconfig.json +5 -0
- package/templates/apps/api-ratelimit/README.md +49 -0
- package/templates/apps/api-ratelimit/app.config.ts +42 -0
- package/templates/apps/api-ratelimit/database/schema.ts +37 -0
- package/templates/apps/api-ratelimit/mutations/notes.create.mutation.server.ts +16 -0
- package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +34 -0
- package/templates/apps/api-ratelimit/package.json +29 -0
- package/templates/apps/api-ratelimit/template.json +6 -0
- package/templates/apps/api-ratelimit/tests/notes.create.test.ts +69 -0
- package/templates/apps/api-ratelimit/tsconfig.json +5 -0
- package/templates/apps/api-rbac/README.md +59 -0
- package/templates/apps/api-rbac/app.config.ts +48 -0
- package/templates/apps/api-rbac/database/schema.ts +37 -0
- package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +22 -0
- package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +26 -0
- package/templates/apps/api-rbac/package.json +29 -0
- package/templates/apps/api-rbac/template.json +6 -0
- package/templates/apps/api-rbac/tests/notes.create.test.ts +80 -0
- package/templates/apps/api-rbac/tsconfig.json +5 -0
- package/templates/apps/api-rest/README.md +85 -0
- package/templates/apps/api-rest/app.config.ts +70 -0
- package/templates/apps/api-rest/database/schema.ts +52 -0
- package/templates/apps/api-rest/lib/product.ts +30 -0
- package/templates/apps/api-rest/package.json +27 -0
- package/templates/apps/api-rest/routes/v1/products.create.route.tsx +45 -0
- package/templates/apps/api-rest/routes/v1/products.delete.route.tsx +25 -0
- package/templates/apps/api-rest/routes/v1/products.get.route.tsx +29 -0
- package/templates/apps/api-rest/routes/v1/products.list.route.tsx +43 -0
- package/templates/apps/api-rest/template.json +6 -0
- package/templates/apps/api-rest/tests/products.create.test.ts +53 -0
- package/templates/apps/api-rest/tsconfig.json +5 -0
- package/templates/apps/api-saas/README.md +106 -0
- package/templates/apps/api-saas/app.config.ts +51 -0
- package/templates/apps/api-saas/database/schema.ts +50 -0
- package/templates/apps/api-saas/mutations/projects.create.mutation.server.ts +52 -0
- package/templates/apps/api-saas/mutations/projects.create.mutation.ts +18 -0
- package/templates/apps/api-saas/package.json +31 -0
- package/templates/apps/api-saas/queries/projects.list.query.server.ts +7 -0
- package/templates/apps/api-saas/queries/projects.list.query.ts +18 -0
- package/templates/apps/api-saas/template.json +6 -0
- package/templates/apps/api-saas/tests/projects.create.test.ts +47 -0
- package/templates/apps/api-saas/tsconfig.json +5 -0
- package/templates/apps/api-search/README.md +68 -0
- package/templates/apps/api-search/app.config.ts +31 -0
- package/templates/apps/api-search/database/schema.ts +47 -0
- package/templates/apps/api-search/lib/search.ts +27 -0
- package/templates/apps/api-search/mutations/articles.create.mutation.server.ts +19 -0
- package/templates/apps/api-search/mutations/articles.create.mutation.ts +35 -0
- package/templates/apps/api-search/package.json +29 -0
- package/templates/apps/api-search/queries/articles.list.query.server.ts +14 -0
- package/templates/apps/api-search/queries/articles.list.query.ts +19 -0
- package/templates/apps/api-search/seeds/articles.seed.ts +41 -0
- package/templates/apps/api-search/startup/searchBackfill.startup.tsx +24 -0
- package/templates/apps/api-search/template.json +6 -0
- package/templates/apps/api-search/tests/articles.create.test.ts +69 -0
- package/templates/apps/api-search/tsconfig.json +5 -0
- package/templates/apps/api-versioning/README.md +51 -0
- package/templates/apps/api-versioning/actions/documents.asOf.action.server.ts +13 -0
- package/templates/apps/api-versioning/actions/documents.asOf.action.ts +14 -0
- package/templates/apps/api-versioning/actions/documents.history.action.server.ts +15 -0
- package/templates/apps/api-versioning/actions/documents.history.action.ts +17 -0
- package/templates/apps/api-versioning/app.config.ts +24 -0
- package/templates/apps/api-versioning/database/schema.ts +38 -0
- package/templates/apps/api-versioning/mutations/documents.create.mutation.server.ts +8 -0
- package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +21 -0
- package/templates/apps/api-versioning/mutations/documents.update.mutation.server.ts +9 -0
- package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +21 -0
- package/templates/apps/api-versioning/package.json +29 -0
- package/templates/apps/api-versioning/template.json +6 -0
- package/templates/apps/api-versioning/tests/documents.create.test.ts +37 -0
- package/templates/apps/api-versioning/tsconfig.json +5 -0
- package/templates/apps/api-webhooks/.env +6 -0
- package/templates/apps/api-webhooks/README.md +106 -0
- package/templates/apps/api-webhooks/app.config.ts +16 -0
- package/templates/apps/api-webhooks/database/schema.ts +49 -0
- package/templates/apps/api-webhooks/events/order.completed.webhook.tsx +22 -0
- package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.server.ts +37 -0
- package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +15 -0
- package/templates/apps/api-webhooks/package.json +28 -0
- package/templates/apps/api-webhooks/queries/orders.list.query.server.ts +7 -0
- package/templates/apps/api-webhooks/queries/orders.list.query.ts +15 -0
- package/templates/apps/api-webhooks/template.json +6 -0
- package/templates/apps/api-webhooks/tests/orders.fulfill.test.ts +51 -0
- package/templates/apps/api-webhooks/tsconfig.json +5 -0
- package/templates/apps/api-webhooks/webhooks/orders.webhook.tsx +35 -0
- package/templates/apps/changelog/README.md +77 -0
- package/templates/apps/changelog/app.config.ts +27 -0
- package/templates/apps/changelog/content/releases/0.1.0.mdx +19 -0
- package/templates/apps/changelog/content/releases/0.2.0.mdx +28 -0
- package/templates/apps/changelog/package.json +30 -0
- package/templates/apps/changelog/scripts/generate-rss.mjs +38 -0
- package/templates/apps/changelog/src/globals.css +66 -0
- package/templates/apps/changelog/src/globals.d.ts +16 -0
- package/templates/apps/changelog/src/lib/locale.test.ts +72 -0
- package/templates/apps/changelog/src/lib/locale.ts +55 -0
- package/templates/apps/changelog/src/lib/releases.ts +21 -0
- package/templates/apps/changelog/src/locales/de.ts +22 -0
- package/templates/apps/changelog/src/locales/en.ts +30 -0
- package/templates/apps/changelog/src/pages/[locale]/[slug].tsx +24 -0
- package/templates/apps/changelog/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +95 -0
- package/templates/apps/changelog/src/pages/[slug].test.tsx +127 -0
- package/templates/apps/changelog/src/pages/[slug].tsx +52 -0
- package/templates/apps/changelog/src/pages/index.test.tsx +112 -0
- package/templates/apps/changelog/src/pages/index.tsx +55 -0
- package/templates/apps/changelog/src/pages/layout.tsx +84 -0
- package/templates/apps/changelog/template.json +6 -0
- package/templates/apps/changelog/tsconfig.json +11 -0
- package/templates/apps/edge-functions/README.md +55 -0
- package/templates/apps/edge-functions/functions/aiComplete.serverless.ts +58 -0
- package/templates/apps/edge-functions/functions/currencyConvert.serverless.ts +47 -0
- package/templates/apps/edge-functions/functions/geoGreeting.serverless.ts +44 -0
- package/templates/apps/edge-functions/functions/health.serverless.ts +29 -0
- package/templates/apps/edge-functions/functions/resolveLink.serverless.ts +32 -0
- package/templates/apps/edge-functions/functions/shareLink.serverless.ts +30 -0
- package/templates/apps/edge-functions/functions/slackNotify.serverless.ts +40 -0
- package/templates/apps/edge-functions/functions/verifySignature.serverless.ts +52 -0
- package/templates/apps/edge-functions/package.json +21 -0
- package/templates/apps/edge-functions/template.json +6 -0
- package/templates/apps/edge-functions/tsconfig.json +10 -0
- package/templates/apps/frontend-admin/README.md +40 -0
- package/templates/apps/frontend-admin/app.config.ts +37 -0
- package/templates/apps/frontend-admin/package.json +30 -0
- package/templates/apps/frontend-admin/src/config.ts +8 -0
- package/templates/apps/frontend-admin/src/globals.css +76 -0
- package/templates/apps/frontend-admin/src/globals.d.ts +6 -0
- package/templates/apps/frontend-admin/src/lib/admin.ts +16 -0
- package/templates/apps/frontend-admin/src/lib/auth.ts +24 -0
- package/templates/apps/frontend-admin/src/locales/de.ts +67 -0
- package/templates/apps/frontend-admin/src/locales/en.ts +79 -0
- package/templates/apps/frontend-admin/src/locales/index.ts +15 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/index.test.tsx +55 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/index.tsx +32 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/layout.tsx +29 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/login.test.tsx +73 -0
- package/templates/apps/frontend-admin/src/pages/(marketing)/login.tsx +35 -0
- package/templates/apps/frontend-admin/src/pages/admin/[entity].tsx +121 -0
- package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +119 -0
- package/templates/apps/frontend-admin/src/pages/admin/error.tsx +20 -0
- package/templates/apps/frontend-admin/src/pages/admin/fallbacks.test.tsx +68 -0
- package/templates/apps/frontend-admin/src/pages/admin/index.test.tsx +88 -0
- package/templates/apps/frontend-admin/src/pages/admin/index.tsx +65 -0
- package/templates/apps/frontend-admin/src/pages/admin/layout.test.tsx +114 -0
- package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +97 -0
- package/templates/apps/frontend-admin/src/pages/admin/loading.tsx +15 -0
- package/templates/apps/frontend-admin/src/pages/admin/not-found.tsx +15 -0
- package/templates/apps/frontend-admin/src/pages/layout.tsx +12 -0
- package/templates/apps/frontend-admin/src/pages/layouts.test.tsx +54 -0
- package/templates/apps/frontend-admin/template.json +6 -0
- package/templates/apps/frontend-admin/tsconfig.json +11 -0
- package/templates/apps/frontend-app/README.md +98 -0
- package/templates/apps/frontend-app/app.config.ts +43 -0
- package/templates/apps/frontend-app/package.json +30 -0
- package/templates/apps/frontend-app/src/locales/de.ts +36 -0
- package/templates/apps/frontend-app/src/locales/en.ts +43 -0
- package/templates/apps/frontend-app/src/locales/index.ts +15 -0
- package/templates/apps/frontend-app/src/pages/index.test.tsx +167 -0
- package/templates/apps/frontend-app/src/pages/index.tsx +136 -0
- package/templates/apps/frontend-app/src/pages/layout.tsx +41 -0
- package/templates/apps/frontend-app/src/pages/schema-ui.test.tsx +99 -0
- package/templates/apps/frontend-app/src/pages/schema-ui.tsx +74 -0
- package/templates/apps/frontend-app/template.json +6 -0
- package/templates/apps/frontend-app/tsconfig.json +11 -0
- package/templates/apps/frontend-blank/README.md +18 -0
- package/templates/apps/frontend-blank/app.config.ts +29 -0
- package/templates/apps/frontend-blank/package.json +29 -0
- package/templates/apps/frontend-blank/src/locales/de.ts +15 -0
- package/templates/apps/frontend-blank/src/locales/en.ts +22 -0
- package/templates/apps/frontend-blank/src/locales/index.ts +15 -0
- package/templates/apps/frontend-blank/src/pages/index.test.tsx +55 -0
- package/templates/apps/frontend-blank/src/pages/index.tsx +27 -0
- package/templates/apps/frontend-blank/src/pages/layout.test.tsx +54 -0
- package/templates/apps/frontend-blank/src/pages/layout.tsx +35 -0
- package/templates/apps/frontend-blank/template.json +6 -0
- package/templates/apps/frontend-blank/tsconfig.json +11 -0
- package/templates/apps/frontend-contact/README.md +65 -0
- package/templates/apps/frontend-contact/app.config.ts +25 -0
- package/templates/apps/frontend-contact/functions/sendMessage.serverless.ts +69 -0
- package/templates/apps/frontend-contact/package.json +33 -0
- package/templates/apps/frontend-contact/src/components/ContactForm.island.test.tsx +142 -0
- package/templates/apps/frontend-contact/src/components/ContactForm.island.tsx +104 -0
- package/templates/apps/frontend-contact/src/config.ts +12 -0
- package/templates/apps/frontend-contact/src/globals.css +84 -0
- package/templates/apps/frontend-contact/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-contact/src/locales/de.ts +26 -0
- package/templates/apps/frontend-contact/src/locales/en.ts +29 -0
- package/templates/apps/frontend-contact/src/pages/[locale]/index.tsx +14 -0
- package/templates/apps/frontend-contact/src/pages/index.test.tsx +70 -0
- package/templates/apps/frontend-contact/src/pages/index.tsx +63 -0
- package/templates/apps/frontend-contact/src/pages/layout.tsx +65 -0
- package/templates/apps/frontend-contact/template.json +6 -0
- package/templates/apps/frontend-contact/tsconfig.json +11 -0
- package/templates/apps/frontend-dashboard/README.md +54 -0
- package/templates/apps/frontend-dashboard/app.config.ts +39 -0
- package/templates/apps/frontend-dashboard/package.json +29 -0
- package/templates/apps/frontend-dashboard/src/config.ts +8 -0
- package/templates/apps/frontend-dashboard/src/globals.css +72 -0
- package/templates/apps/frontend-dashboard/src/globals.d.ts +6 -0
- package/templates/apps/frontend-dashboard/src/lib/auth.ts +27 -0
- package/templates/apps/frontend-dashboard/src/locales/de.ts +49 -0
- package/templates/apps/frontend-dashboard/src/locales/en.ts +60 -0
- package/templates/apps/frontend-dashboard/src/locales/index.ts +15 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.test.tsx +55 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.tsx +34 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/layout.tsx +32 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.test.tsx +74 -0
- package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.tsx +40 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/error.tsx +21 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/fallbacks.test.tsx +68 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/index.test.tsx +55 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/index.tsx +38 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.test.tsx +88 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.tsx +69 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/loading.tsx +21 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/not-found.tsx +19 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.test.tsx +69 -0
- package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.tsx +35 -0
- package/templates/apps/frontend-dashboard/src/pages/layout.tsx +12 -0
- package/templates/apps/frontend-dashboard/src/pages/layouts.test.tsx +54 -0
- package/templates/apps/frontend-dashboard/template.json +6 -0
- package/templates/apps/frontend-dashboard/tsconfig.json +11 -0
- package/templates/apps/frontend-docs/README.md +19 -0
- package/templates/apps/frontend-docs/app.config.ts +25 -0
- package/templates/apps/frontend-docs/package.json +29 -0
- package/templates/apps/frontend-docs/src/globals.css +32 -0
- package/templates/apps/frontend-docs/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-docs/src/lib/locale.ts +56 -0
- package/templates/apps/frontend-docs/src/locales/de.ts +24 -0
- package/templates/apps/frontend-docs/src/locales/en.ts +28 -0
- package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug].tsx +18 -0
- package/templates/apps/frontend-docs/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +67 -0
- package/templates/apps/frontend-docs/src/pages/docs/[...slug].test.tsx +115 -0
- package/templates/apps/frontend-docs/src/pages/docs/[...slug].tsx +82 -0
- package/templates/apps/frontend-docs/src/pages/index.test.tsx +90 -0
- package/templates/apps/frontend-docs/src/pages/index.tsx +45 -0
- package/templates/apps/frontend-docs/src/pages/layout.test.tsx +84 -0
- package/templates/apps/frontend-docs/src/pages/layout.tsx +66 -0
- package/templates/apps/frontend-docs/template.json +6 -0
- package/templates/apps/frontend-docs/tsconfig.json +11 -0
- package/templates/apps/frontend-i18n/README.md +61 -0
- package/templates/apps/frontend-i18n/app.config.ts +33 -0
- package/templates/apps/frontend-i18n/package.json +28 -0
- package/templates/apps/frontend-i18n/src/globals.css +46 -0
- package/templates/apps/frontend-i18n/src/globals.d.ts +6 -0
- package/templates/apps/frontend-i18n/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-i18n/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-i18n/src/locales/de.ts +24 -0
- package/templates/apps/frontend-i18n/src/locales/en.ts +25 -0
- package/templates/apps/frontend-i18n/src/pages/[locale]/about.tsx +11 -0
- package/templates/apps/frontend-i18n/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-i18n/src/pages/[locale]/mirrors.test.tsx +50 -0
- package/templates/apps/frontend-i18n/src/pages/about.test.tsx +75 -0
- package/templates/apps/frontend-i18n/src/pages/about.tsx +31 -0
- package/templates/apps/frontend-i18n/src/pages/index.test.tsx +102 -0
- package/templates/apps/frontend-i18n/src/pages/index.tsx +43 -0
- package/templates/apps/frontend-i18n/src/pages/layout.test.tsx +86 -0
- package/templates/apps/frontend-i18n/src/pages/layout.tsx +70 -0
- package/templates/apps/frontend-i18n/template.json +6 -0
- package/templates/apps/frontend-i18n/tsconfig.json +11 -0
- package/templates/apps/frontend-landing/README.md +17 -0
- package/templates/apps/frontend-landing/app.config.ts +25 -0
- package/templates/apps/frontend-landing/package.json +29 -0
- package/templates/apps/frontend-landing/src/globals.css +23 -0
- package/templates/apps/frontend-landing/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-landing/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-landing/src/locales/de.ts +24 -0
- package/templates/apps/frontend-landing/src/locales/en.ts +26 -0
- package/templates/apps/frontend-landing/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-landing/src/pages/[locale]/mirrors.test.tsx +37 -0
- package/templates/apps/frontend-landing/src/pages/index.test.tsx +110 -0
- package/templates/apps/frontend-landing/src/pages/index.tsx +75 -0
- package/templates/apps/frontend-landing/src/pages/layout.test.tsx +84 -0
- package/templates/apps/frontend-landing/src/pages/layout.tsx +66 -0
- package/templates/apps/frontend-landing/template.json +6 -0
- package/templates/apps/frontend-landing/tsconfig.json +11 -0
- package/templates/apps/frontend-spa/README.md +45 -0
- package/templates/apps/frontend-spa/app.config.ts +27 -0
- package/templates/apps/frontend-spa/package.json +29 -0
- package/templates/apps/frontend-spa/src/globals.css +84 -0
- package/templates/apps/frontend-spa/src/locales/de.ts +22 -0
- package/templates/apps/frontend-spa/src/locales/en.ts +29 -0
- package/templates/apps/frontend-spa/src/locales/index.ts +15 -0
- package/templates/apps/frontend-spa/src/pages/index.test.tsx +137 -0
- package/templates/apps/frontend-spa/src/pages/index.tsx +123 -0
- package/templates/apps/frontend-spa/src/pages/layout.tsx +27 -0
- package/templates/apps/frontend-spa/template.json +6 -0
- package/templates/apps/frontend-spa/tsconfig.json +11 -0
- package/templates/apps/frontend-ssr/README.md +68 -0
- package/templates/apps/frontend-ssr/app.config.ts +32 -0
- package/templates/apps/frontend-ssr/package.json +29 -0
- package/templates/apps/frontend-ssr/src/globals.css +67 -0
- package/templates/apps/frontend-ssr/src/locales/de.ts +41 -0
- package/templates/apps/frontend-ssr/src/locales/en.ts +54 -0
- package/templates/apps/frontend-ssr/src/locales/index.ts +16 -0
- package/templates/apps/frontend-ssr/src/pages/feed-swr.test.tsx +69 -0
- package/templates/apps/frontend-ssr/src/pages/feed-swr.tsx +54 -0
- package/templates/apps/frontend-ssr/src/pages/feed.test.tsx +73 -0
- package/templates/apps/frontend-ssr/src/pages/feed.tsx +64 -0
- package/templates/apps/frontend-ssr/src/pages/index.test.tsx +89 -0
- package/templates/apps/frontend-ssr/src/pages/index.tsx +72 -0
- package/templates/apps/frontend-ssr/src/pages/layout.tsx +37 -0
- package/templates/apps/frontend-ssr/template.json +6 -0
- package/templates/apps/frontend-ssr/tsconfig.json +11 -0
- package/templates/apps/frontend-ssr-api/README.md +50 -0
- package/templates/apps/frontend-ssr-api/app.config.ts +43 -0
- package/templates/apps/frontend-ssr-api/package.json +30 -0
- package/templates/apps/frontend-ssr-api/src/globals.css +38 -0
- package/templates/apps/frontend-ssr-api/src/globals.d.ts +6 -0
- package/templates/apps/frontend-ssr-api/src/locales/de.ts +20 -0
- package/templates/apps/frontend-ssr-api/src/locales/en.ts +31 -0
- package/templates/apps/frontend-ssr-api/src/locales/index.ts +16 -0
- package/templates/apps/frontend-ssr-api/src/pages/index.test.tsx +105 -0
- package/templates/apps/frontend-ssr-api/src/pages/index.tsx +83 -0
- package/templates/apps/frontend-ssr-api/src/pages/layout.tsx +28 -0
- package/templates/apps/frontend-ssr-api/template.json +6 -0
- package/templates/apps/frontend-ssr-api/tsconfig.json +11 -0
- package/templates/apps/frontend-static-blog/README.md +49 -0
- package/templates/apps/frontend-static-blog/app.config.ts +34 -0
- package/templates/apps/frontend-static-blog/package.json +28 -0
- package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.test.tsx +65 -0
- package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.tsx +35 -0
- package/templates/apps/frontend-static-blog/src/content/posts.ts +64 -0
- package/templates/apps/frontend-static-blog/src/globals.css +75 -0
- package/templates/apps/frontend-static-blog/src/lib/locale.test.ts +72 -0
- package/templates/apps/frontend-static-blog/src/lib/locale.ts +55 -0
- package/templates/apps/frontend-static-blog/src/locales/de.ts +19 -0
- package/templates/apps/frontend-static-blog/src/locales/en.ts +26 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug].tsx +20 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/index.tsx +13 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +62 -0
- package/templates/apps/frontend-static-blog/src/pages/blog/[slug].test.tsx +116 -0
- package/templates/apps/frontend-static-blog/src/pages/blog/[slug].tsx +69 -0
- package/templates/apps/frontend-static-blog/src/pages/index.test.tsx +100 -0
- package/templates/apps/frontend-static-blog/src/pages/index.tsx +58 -0
- package/templates/apps/frontend-static-blog/src/pages/layout.tsx +63 -0
- package/templates/apps/frontend-static-blog/template.json +6 -0
- package/templates/apps/frontend-static-blog/tsconfig.json +11 -0
- package/templates/baselines/bare/.env.example +37 -0
- package/templates/baselines/bare/README.md +47 -0
- package/templates/baselines/bare/baseline.json +31 -0
- package/templates/baselines/bare/deploy/README.md +43 -0
- package/templates/baselines/bare/deploy/voltro.service.example +36 -0
- package/templates/baselines/compose/.env.example +46 -0
- package/templates/baselines/compose/README.md +69 -0
- package/templates/baselines/compose/baseline.json +51 -0
- package/templates/baselines/compose/docker/.dockerignore +38 -0
- package/templates/baselines/compose/docker/api.Dockerfile +57 -0
- package/templates/baselines/compose/docker/dev.Dockerfile +35 -0
- package/templates/baselines/compose/docker/web.Dockerfile +59 -0
- package/templates/baselines/compose/docker-compose.dev.yml +89 -0
- package/templates/baselines/compose/docker-compose.prod.yml +87 -0
- package/templates/baselines/compose/docker-compose.yml +41 -0
- package/templates/baselines/compose-mariadb/.env.example +57 -0
- package/templates/baselines/compose-mariadb/README.md +78 -0
- package/templates/baselines/compose-mariadb/baseline.json +51 -0
- package/templates/baselines/compose-mariadb/docker/.dockerignore +38 -0
- package/templates/baselines/compose-mariadb/docker/api.Dockerfile +57 -0
- package/templates/baselines/compose-mariadb/docker/dev.Dockerfile +35 -0
- package/templates/baselines/compose-mariadb/docker/mariadb-init.sql +6 -0
- package/templates/baselines/compose-mariadb/docker/web.Dockerfile +59 -0
- package/templates/baselines/compose-mariadb/docker-compose.dev.yml +117 -0
- package/templates/baselines/compose-mariadb/docker-compose.prod.yml +114 -0
- package/templates/baselines/compose-mariadb/docker-compose.yml +79 -0
- package/templates/baselines/helm/.env.example +39 -0
- package/templates/baselines/helm/README.md +98 -0
- package/templates/baselines/helm/baseline.json +53 -0
- package/templates/baselines/helm/charts/voltro-app/.helmignore +10 -0
- package/templates/baselines/helm/charts/voltro-app/Chart.yaml +10 -0
- package/templates/baselines/helm/charts/voltro-app/templates/_helpers.tpl +36 -0
- package/templates/baselines/helm/charts/voltro-app/templates/configmap.yaml +13 -0
- package/templates/baselines/helm/charts/voltro-app/templates/deployment-api.yaml +120 -0
- package/templates/baselines/helm/charts/voltro-app/templates/deployment-web.yaml +45 -0
- package/templates/baselines/helm/charts/voltro-app/templates/ingress.yaml +37 -0
- package/templates/baselines/helm/charts/voltro-app/templates/postgres-service.yaml +19 -0
- package/templates/baselines/helm/charts/voltro-app/templates/postgres-statefulset.yaml +73 -0
- package/templates/baselines/helm/charts/voltro-app/templates/secret.yaml +33 -0
- package/templates/baselines/helm/charts/voltro-app/templates/service-api.yaml +19 -0
- package/templates/baselines/helm/charts/voltro-app/templates/service-web.yaml +19 -0
- package/templates/baselines/helm/charts/voltro-app/values-dev.yaml +21 -0
- package/templates/baselines/helm/charts/voltro-app/values-prod.yaml +58 -0
- package/templates/baselines/helm/charts/voltro-app/values-staging.yaml +25 -0
- package/templates/baselines/helm/charts/voltro-app/values.yaml +109 -0
- package/templates/baselines/helm/deploy/README.md +94 -0
- package/templates/patches/@effect__cluster@0.59.0.patch +262 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
> Voltro's test story — the @voltro/testing package, the test pyramid (unit handlers/tools → workflow runner → e2e), and the voltro test / voltro e2e CLI commands.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- source: en/testing/overview.md -->
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
_Voltro's test story — the @voltro/testing package, the test pyramid (unit handlers/tools → workflow runner → e2e), and the voltro test / voltro e2e CLI commands._
|
|
13
|
+
|
|
14
|
+
## The package
|
|
15
|
+
|
|
16
|
+
Test utilities live in **`@voltro/testing`** — a separate, public package. It is **not** bundled into a scaffolded project, so the moment you write your first test, add it (and `vitest`) as a **devDependency** of the app you're testing:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm --filter @my-app/api add -D @voltro/testing vitest
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Everything in it is in-memory and synchronous-friendly — no docker, no running server, no real model calls. A handler test boots in milliseconds.
|
|
23
|
+
|
|
24
|
+
| Export | Use |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `makeTestContext(options?)` | The request `ctx` a handler/tool sees at runtime — subject-scoped `ctx.store`, `clock`, `email`, optional `ai`. → [Unit testing](/docs/testing/unit-testing) |
|
|
27
|
+
| `mockStore(seed)` | Seed rows: `makeTestContext({ store: mockStore({ todos: [...] }) })`. |
|
|
28
|
+
| `MockClock` / `MockEmail` / `MockLLM` | Deterministic clock, captured email, queued LLM responses. |
|
|
29
|
+
| `makeWorkflowRunner({ ctx, workflows })` | Drive a workflow in-process and assert on its steps. → [Workflows](/docs/testing/workflows) |
|
|
30
|
+
| `runDialectParity(fixture)` | Run one fixture across a SQL dialect for portability — from the `@voltro/testing/dialect` subpath. → [Dialect parity](/docs/testing/dialect-parity) |
|
|
31
|
+
|
|
32
|
+
## The test pyramid
|
|
33
|
+
|
|
34
|
+
Voltro's primitives are designed so the cheapest test covers the most surface. Reach for the lowest layer that proves what you need:
|
|
35
|
+
|
|
36
|
+
1. **Unit — handlers, tools, mutations, queries.** Call the executor directly with a `makeTestContext()` ctx. The store is the real mixin-wrapped store, so tenant scoping, soft-delete, and audit auto-fill all behave as in production — without a database. This is 90% of your tests. See [Unit testing](/docs/testing/unit-testing).
|
|
37
|
+
2. **Workflow — durable, multi-step logic.** `makeWorkflowRunner` drives a workflow end-to-end in-process and hands back the same step log the dashboard shows, including real retry counts. See [Workflows](/docs/testing/workflows).
|
|
38
|
+
3. **Parity — hand-written SQL that must stay portable.** `runDialectParity` runs a fixed scenario suite against a dialect you stand up. Mostly for dialect-package authors and apps with `unsafe()` SQL. See [Dialect parity](/docs/testing/dialect-parity).
|
|
39
|
+
4. **End-to-end — the running stack.** `voltro e2e` boots the api + web siblings, runs your tests against the live processes, and tears them down.
|
|
40
|
+
|
|
41
|
+
Agents are integration tests; tools are unit tests. Don't reach for an e2e harness to assert logic a `makeTestContext` test can prove.
|
|
42
|
+
|
|
43
|
+
## The CLI
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
voltro test # vitest against the current app
|
|
47
|
+
voltro e2e # boot api + web siblings, run tests, tear down
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`voltro test` is a thin wrapper over vitest — it runs the app's test files with the framework's config. Everything `@voltro/testing` exports is plain TypeScript you import inside those files; there's no special test runner.
|
|
51
|
+
|
|
52
|
+
## What NOT to do
|
|
53
|
+
|
|
54
|
+
- **Don't spin up Postgres for a handler test.** `makeTestContext`'s in-memory store enforces the same mixin behaviour — tenant scoping, soft-delete, audit — so a unit test catches the same class of bug far faster. Save a real database for [dialect parity](/docs/testing/dialect-parity) and e2e.
|
|
55
|
+
- **Don't call a real model in agent tests.** Queue deterministic responses with `mockAi` / `useMockAi` (see [Unit testing → agents](/docs/testing/unit-testing#testing-agents-and-the-model-loop)). A flaky test that hits the network on every run is worse than no test.
|
|
56
|
+
- **Don't assert on wall-clock time.** Inject `MockClock` and `advance(...)` deterministically — never `setTimeout` + real sleeps.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
<!-- source: en/testing/unit-testing.md -->
|
|
63
|
+
## Unit testing
|
|
64
|
+
|
|
65
|
+
_makeTestContext — the in-memory request ctx for handler and tool tests. The real mixin-wrapped store, mockStore seeding, subject/tenant re-scoping, and the deterministic clock / email / LLM mocks._
|
|
66
|
+
|
|
67
|
+
## `makeTestContext`
|
|
68
|
+
|
|
69
|
+
`makeTestContext(options?)` returns an **`AppContext`** — the exact `ctx` a mutation / query / action / tool executor receives at runtime — with the deterministic test doubles added on top. Because it *is* an `AppContext`, you pass it straight into a handler: `await myHandler(input, makeTestContext({ … }))`. The acting subject is at `ctx.request.subject`; `ctx.store` is the **real** mixin-wrapped store backed by an in-memory data store (so tenant auto-scoping, soft-delete filtering, audit auto-fill, and the fluent `select` / `update` / `delete` builders behave exactly as in production); `ctx.cache` is a real in-memory cache whose TTLs honour `ctx.clock`.
|
|
70
|
+
|
|
71
|
+
Tables are auto-wired from whatever the test imported (the globally-registered tables), so you never re-declare schema. Seed rows with `mockStore`.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { makeTestContext, mockStore } from '@voltro/testing'
|
|
75
|
+
import createTodo from '../mutations/todos.create.mutation.server'
|
|
76
|
+
|
|
77
|
+
test('createTodo inserts a row for the caller’s tenant', async () => {
|
|
78
|
+
const ctx = makeTestContext({
|
|
79
|
+
subject: { type: 'user', id: 'user_1', tenantId: 't1' },
|
|
80
|
+
store: mockStore({ todos: [] }),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const row = await createTodo({ tenantId: 't1', title: 'buy milk' }, ctx)
|
|
84
|
+
|
|
85
|
+
expect(row.title).toBe('buy milk')
|
|
86
|
+
// The real store middleware auto-stamped audit + tenant columns —
|
|
87
|
+
// no different from a live mutation.
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The same call tests a tool — a tool's `execute` / handler takes `(input, ctx)`:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { makeTestContext, mockStore } from '@voltro/testing'
|
|
95
|
+
import searchDocs from '../tools/searchDocs.tool'
|
|
96
|
+
|
|
97
|
+
test('searchDocs returns matching rows', async () => {
|
|
98
|
+
const ctx = makeTestContext({ store: mockStore({ docs: [{ id: 'd1', body: 'hello world' }] }) })
|
|
99
|
+
const out = await searchDocs({ query: 'hello' }, ctx)
|
|
100
|
+
expect(out).toHaveLength(1)
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Options
|
|
105
|
+
|
|
106
|
+
`MakeTestContextOptions`:
|
|
107
|
+
|
|
108
|
+
| Field | Default | Meaning |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| `subject` | anonymous, no tenant | The acting `Subject`. |
|
|
111
|
+
| `tables` | all registered | Tables to wire into the store's schema. |
|
|
112
|
+
| `store` | `{}` | Seed rows keyed by table name — use `mockStore({...})`. |
|
|
113
|
+
| `clockStart` | `2026-01-01T00:00:00Z` | Frozen start instant for `ctx.clock`. |
|
|
114
|
+
| `ai` | — | Injected AI mock (a `mockAi({...})` value). |
|
|
115
|
+
| `llmResponses` | `[]` | Queued responses for the bundled `ctx.llm` (`MockLLM`). |
|
|
116
|
+
| `env` | ambient `process.env` | Env values sealed into the boot snapshot so handler code reading `getSecret('X')` / `serverEnv.X` resolves under test. Merged over `process.env` (these win). |
|
|
117
|
+
|
|
118
|
+
The returned `TestContext` carries `{ clock, email, llm, ai?, request, cache, store, withSubject, withTenant }` — read the acting subject at `ctx.request.subject` and the in-memory cache at `ctx.cache`.
|
|
119
|
+
|
|
120
|
+
## `invoke` — run a handler through its input Schema
|
|
121
|
+
|
|
122
|
+
Calling an executor directly skips the input-Schema **decode** the real dispatcher runs first, so a test can feed the handler a value the wire would reject. `invoke(descriptor, executor, rawInput, ctx)` decodes `rawInput` through `descriptor.input` (throwing a `ParseError` on invalid input — the same validation that would 400 in production) and only then calls the executor with the decoded value.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { invoke, makeTestContext } from '@voltro/testing'
|
|
126
|
+
import { createNote } from './notes.mutation' // the descriptor
|
|
127
|
+
import { createNoteHandler } from './notes.mutation.server' // the executor
|
|
128
|
+
|
|
129
|
+
const ctx = makeTestContext({ subject: { type: 'user', id: 'u1', tenantId: 't1' } })
|
|
130
|
+
|
|
131
|
+
// valid input decodes, then the handler runs
|
|
132
|
+
const note = await invoke(createNote, createNoteHandler, { title: 'hi' }, ctx)
|
|
133
|
+
|
|
134
|
+
// a bad shape rejects at the decode — the handler never runs
|
|
135
|
+
await expect(invoke(createNote, createNoteHandler, { title: 42 }, ctx)).rejects.toThrow()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`invoke` reproduces the **input-Schema validation** hop only. RBAC / tenant / auth **guards** are rpc middleware wired at dispatch time — not carried on the descriptor — so to assert a guard, run the real handler under a scoped `ctx.request.subject` (via `makeTestContext({ subject })` / `ctx.withSubject`) and let the handler's own `requireScope(...)` execute.
|
|
139
|
+
|
|
140
|
+
## Subject + tenant re-scoping
|
|
141
|
+
|
|
142
|
+
`withSubject` and `withTenant` re-scope to a different principal for one block, sharing the **same** underlying data — so cross-subject reads exercise real tenant scoping, not a closure stub. This is how you prove isolation: write as one tenant, then assert another tenant can't see the row.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const ctx = makeTestContext({
|
|
146
|
+
subject: { type: 'user', id: 'u1', tenantId: 't1' },
|
|
147
|
+
store: mockStore({ todos: [] }),
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
await ctx.store.insert('todos', { title: 'private to t1' })
|
|
151
|
+
|
|
152
|
+
await ctx.withTenant('t2', async (ctx2) => {
|
|
153
|
+
const rows = await ctx2.store.select('todos').all()
|
|
154
|
+
expect(rows).toHaveLength(0) // t2 sees none of t1's rows
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`withSubject(subject, fn)` swaps the full identity; `withTenant(tenantId, fn)` keeps the current subject and only changes the tenant. Both return a `Promise` of whatever `fn` returns.
|
|
159
|
+
|
|
160
|
+
## Asserting on hidden rows
|
|
161
|
+
|
|
162
|
+
`ctx.store` applies the same scoping a handler gets — the tenant filter plus `deletedAt IS NULL`. To assert on rows the scope hides (that a mutation soft-deleted a row, or wrote into another tenant), read **past** the scope with `.unscoped()` (drops the tenant filter) and `.withDeleted()` (includes soft-deleted rows) — both typed, no cast:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
await deleteNote({ id: 'n1' }, ctx) // soft-delete
|
|
166
|
+
expect(await ctx.store.select('notes').all()).toHaveLength(0) // hidden from normal reads
|
|
167
|
+
|
|
168
|
+
const raw = await ctx.store.select('notes').unscoped().withDeleted().all()
|
|
169
|
+
expect(raw[0]?.deletedAt).not.toBeNull() // …but still there, tombstoned
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## The deterministic mocks
|
|
173
|
+
|
|
174
|
+
### `ctx.clock` — `MockClock`
|
|
175
|
+
|
|
176
|
+
A frozen clock you advance by hand. No real sleeping.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
ctx.clock.now() // current instant in ms
|
|
180
|
+
ctx.clock.date() // current instant as a Date
|
|
181
|
+
ctx.clock.advance('15m') // jump forward — ms | s | m | h | d, or a number of ms
|
|
182
|
+
ctx.clock.advance(900_000) // same, in milliseconds
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### `ctx.email` — `MockEmail`
|
|
186
|
+
|
|
187
|
+
Captures outgoing email for assertion.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
ctx.email.sent // SentEmail[] — every send, in order
|
|
191
|
+
ctx.email.lastTo('a@b.com') // the most recent email to that address, or undefined
|
|
192
|
+
ctx.email.clear() // reset between cases
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `ctx.llm` — `MockLLM`
|
|
196
|
+
|
|
197
|
+
A queue of canned model responses plus a record of every call. Each `MockResponse` is one of `{ text }`, `{ toolCall: { name, input } }`, or `{ error: { code, message? } }`.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const ctx = makeTestContext({
|
|
201
|
+
llmResponses: [{ text: 'first' }, { toolCall: { name: 'search', input: { q: 'x' } } }],
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
// inside the handler under test, the model consumes the queue in order;
|
|
205
|
+
// afterwards:
|
|
206
|
+
expect(ctx.llm.calls).toHaveLength(2) // each prompt that triggered a call
|
|
207
|
+
expect(ctx.llm.remaining()).toBe(0) // queue drained
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`MockLLM` throws `MockLLM: no more responses queued` if the code under test asks for one more response than you queued — a useful assertion that the loop ran exactly as many turns as expected.
|
|
211
|
+
|
|
212
|
+
## Testing agents and the model loop
|
|
213
|
+
|
|
214
|
+
`ctx.llm` is the low-level queue. For a full agent / model-loop test, install a deterministic provider with `mockAi` / `useMockAi` from `@voltro/ai/test` — the AI package owns the full mock; `@voltro/testing` only types the injected `MockAi` slot on `makeTestContext({ ai })`.
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
import { useMockAi } from '@voltro/ai/test'
|
|
218
|
+
|
|
219
|
+
const mock = useMockAi({
|
|
220
|
+
stream: ['Hello, ', 'world.'], // token deltas
|
|
221
|
+
turns: [ // scripted tool loop
|
|
222
|
+
{ toolCalls: [{ name: 'searchDocs', input: { query: 'x' } }] },
|
|
223
|
+
{ text: 'Based on the docs.' },
|
|
224
|
+
],
|
|
225
|
+
})
|
|
226
|
+
// … run the agent …
|
|
227
|
+
mock.reset()
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`mockAi({...})` returns a `MockAi` value you pass as `makeTestContext({ ai: mockAi({...}) })`; `throwNTimes(n, value)` exercises retry paths. See [AI → Providers](/docs/ai/providers#mock-for-tests) for the full surface.
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
<!-- source: en/testing/workflows.md -->
|
|
237
|
+
## Testing workflows
|
|
238
|
+
|
|
239
|
+
_makeWorkflowRunner — drive a workflow end-to-end in-process and assert on the same step log the dashboard reads, including real retry counts._
|
|
240
|
+
|
|
241
|
+
## `makeWorkflowRunner`
|
|
242
|
+
|
|
243
|
+
A workflow's logic — steps, retries, branching on a signal — deserves a test that doesn't boot the cluster engine. `makeWorkflowRunner({ ctx, workflows })` runs a workflow end-to-end in-process on an in-memory engine and hands back the same step log the [workflow dashboard](/docs/workflows/debugging) reads, so a test can assert on attempts, durations, and intermediate values.
|
|
244
|
+
|
|
245
|
+
Discovery is explicit: pass each workflow under test as a `{ workflow, execute }` entry. The `workflow` is the value from `workflow({ name, ... })` (the descriptor); the `execute` is the same `(payload, executionId) => Effect` the framework hands to `workflow.toLayer(...)` at registration time — i.e. `buildExecute(ctx)` from your `*.workflow.server.tsx`. The runner matches `start(name, …)` against `entry.workflow.name`.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import { makeTestContext, mockStore, makeWorkflowRunner } from '@voltro/testing'
|
|
249
|
+
import { SummarizeTodos } from '../workflows/todos.summarize.workflow'
|
|
250
|
+
import buildExecute from '../workflows/todos.summarize.workflow.server'
|
|
251
|
+
|
|
252
|
+
test('summarize walks fetch → summarize and succeeds', async () => {
|
|
253
|
+
const ctx = makeTestContext({ store: mockStore({ todos: [{ id: 't1', title: 'x' }] }) })
|
|
254
|
+
|
|
255
|
+
const runner = makeWorkflowRunner({
|
|
256
|
+
ctx,
|
|
257
|
+
workflows: [
|
|
258
|
+
{ workflow: SummarizeTodos as never, execute: buildExecute(ctx) as never },
|
|
259
|
+
],
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
const result = await runner.start('todos.summarize', { tenantId: 't1' })
|
|
263
|
+
|
|
264
|
+
expect(result.status).toBe('succeeded')
|
|
265
|
+
expect(result.steps.map((s) => s.name)).toEqual(['fetch-todos', 'summarize'])
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
The `as never` casts keep the call-site ergonomic — the runner is type-erased over each workflow's payload / success / error shapes (it provides the engine layer itself), and `never` assigns to any field type without an `any` leaking into the public type.
|
|
270
|
+
|
|
271
|
+
## The result
|
|
272
|
+
|
|
273
|
+
`start(name, payload)` blocks until the run is terminal and resolves a `WorkflowRunResult`:
|
|
274
|
+
|
|
275
|
+
| Field | Meaning |
|
|
276
|
+
|---|---|
|
|
277
|
+
| `status` | `'succeeded'` or `'failed'`. |
|
|
278
|
+
| `output` | The workflow's success value (`null` on failure). |
|
|
279
|
+
| `error` | `{ tag, message }` on failure (`null` on success). `tag` is the typed error's `_tag` when there is one. |
|
|
280
|
+
| `steps` | One `InspectedStep` per step name — `{ name, attempt, attempts, status, input, output, error, durationMs }`. |
|
|
281
|
+
| `runId` | The synthetic run id, for `inspect(...)`. |
|
|
282
|
+
|
|
283
|
+
### Asserting on retries
|
|
284
|
+
|
|
285
|
+
`steps[i].attempts` reflects the **real** retry count: a step that throws twice then succeeds records three attempt rows, so `attempts === 3`. This is the cleanest way to prove a step's retry policy actually fired.
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
const charge = result.steps.find((s) => s.name === 'charge-card')
|
|
289
|
+
expect(charge?.status).toBe('completed')
|
|
290
|
+
expect(charge?.attempts).toBe(3) // failed twice, succeeded on the third
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Inspecting a finished run
|
|
294
|
+
|
|
295
|
+
`inspect(runId)` returns the recorded `InspectedWorkflow` for a previously-started run **without re-running it**, or `null` for an unknown id — the same shape the dashboard renders (`{ id, name, status, input, output, subject, source: 'test-runner', steps, startedAt, finishedAt, … }`).
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
const run = await runner.inspect(result.runId)
|
|
299
|
+
expect(run?.source).toBe('test-runner')
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Notes
|
|
303
|
+
|
|
304
|
+
- The runner uses the in-memory workflow engine and an in-memory recorder — nothing persists, nothing schedules on the real clock. Pair it with [the mock clock](/docs/testing/unit-testing#the-deterministic-mocks) for any time-dependent step.
|
|
305
|
+
- Starting a workflow the runner doesn't know about throws a clear error naming the missing workflow — register it in the `workflows` array.
|
|
306
|
+
- This tests the workflow's **logic**. To exercise the durable engine itself (crash/resume, cluster handoff), that's an integration concern beyond the in-process runner.
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
<!-- source: en/testing/dialect-parity.md -->
|
|
313
|
+
## Dialect parity
|
|
314
|
+
|
|
315
|
+
_runDialectParity — a fixed scenario suite that proves a SQL backend behaves identically to the others. For dialect-package authors and apps with hand-written portable SQL._
|
|
316
|
+
|
|
317
|
+
## When you need this
|
|
318
|
+
|
|
319
|
+
Most apps never touch this page. The framework's DSL already hides every cross-dialect difference, and a [unit test](/docs/testing/unit-testing) on the in-memory store proves your handler logic. Reach for `runDialectParity` only when you have code that talks to a real database in a dialect-specific way:
|
|
320
|
+
|
|
321
|
+
- You're authoring a new `@voltro/sql-*` dialect package and need to prove it before plugging it into `loadDialect()`.
|
|
322
|
+
- Your app drops to `unsafe()` SQL or custom store logic that must stay portable across the backends you ship on.
|
|
323
|
+
|
|
324
|
+
## `runDialectParity`
|
|
325
|
+
|
|
326
|
+
`runDialectParity(fixture)` registers a vitest suite (`describe('dialect parity: <name>')`) that runs a fixed scenario set against the database your fixture stands up — and asserts identical behaviour on each. It's exported from the **`@voltro/testing/dialect`** subpath — the only part of `@voltro/testing` that imports `vitest`, so `makeTestContext` consumers carry no `vitest` peer. The scenarios cover the contract the DSL relies on:
|
|
327
|
+
|
|
328
|
+
- DDL idempotency (re-applying the schema is a no-op)
|
|
329
|
+
- insert / query round-trip, update post-image, delete
|
|
330
|
+
- `onChange` fires insert + update + delete events
|
|
331
|
+
- `transactional` rolls back on throw (and drops queued change events) / commits and drains events in order
|
|
332
|
+
- `upsert` (insert then update-on-conflict, no duplicate)
|
|
333
|
+
- `updateMany` with a predicate, and the atomic compare-and-set (the wakeup-claim pattern)
|
|
334
|
+
- `retryFilter` returns a stable `'retry' | 'noRetry'` decision
|
|
335
|
+
|
|
336
|
+
The harness intentionally does **not** bundle docker setup — that lives next to the dialect, so the parity packages' devDeps stay minimal. Your fixture owns the lifecycle (scratch docker Postgres, temp-file SQLite, …).
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
// sql-postgres/__tests__/parity.test.ts
|
|
340
|
+
import { runDialectParity, applySchema } from '@voltro/testing/dialect'
|
|
341
|
+
import { postgresDialect } from '../src/index'
|
|
342
|
+
|
|
343
|
+
runDialectParity({
|
|
344
|
+
dialect: postgresDialect,
|
|
345
|
+
name: 'postgres (scratch docker)',
|
|
346
|
+
setup: async () => { /* stand up a clean scratch database */ },
|
|
347
|
+
teardown: async () => { /* drop it */ },
|
|
348
|
+
make: async () => ({
|
|
349
|
+
store: /* the live DataStore for this scenario */,
|
|
350
|
+
migrate: (tables) => /* applySchema(tables, dialect.id) against the same runtime */,
|
|
351
|
+
dispose: async () => { /* close store, drop scratch state */ },
|
|
352
|
+
}),
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## The fixture contract
|
|
357
|
+
|
|
358
|
+
`DialectFixture`:
|
|
359
|
+
|
|
360
|
+
| Field | Meaning |
|
|
361
|
+
|---|---|
|
|
362
|
+
| `dialect` | The `SqlDialect` under test (its `id`, `retryFilter`, etc.). |
|
|
363
|
+
| `name?` | Label for the test output (defaults to `dialect.id`). |
|
|
364
|
+
| `setup` | Runs before each scenario — give it a clean slate. |
|
|
365
|
+
| `teardown` | Runs after each scenario. |
|
|
366
|
+
| `make` | Returns a `DialectFixtureSession` for the scenario. |
|
|
367
|
+
|
|
368
|
+
`DialectFixtureSession`:
|
|
369
|
+
|
|
370
|
+
| Field | Meaning |
|
|
371
|
+
|---|---|
|
|
372
|
+
| `store` | The live `DataStore` the scenarios drive. |
|
|
373
|
+
| `migrate(tables)` | Apply `applySchema(tables, dialect.id)` against the same runtime the store uses, so DDL and DML hit the same database. |
|
|
374
|
+
| `dispose()` | Tear the session down (close store, drop scratch DB). |
|
|
375
|
+
|
|
376
|
+
`applySchema` is re-exported from `@voltro/testing/dialect` (the same subpath as `runDialectParity`, not the root entry) so a fixture can build its `migrate` without pulling `@voltro/database/sql` separately. Once a dialect green-checks the harness, it's ready for `loadDialect()`.
|