@stacksjs/defaults 0.70.206 → 0.70.208
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/TODO.md +21 -0
- package/ai/AGENTS.md +79 -0
- package/ai/README.md +45 -0
- package/ai/claude/launch.json +12 -0
- package/ai/skills/stacks-actions/SKILL.md +128 -0
- package/ai/skills/stacks-ai/SKILL.md +276 -0
- package/ai/skills/stacks-alias/SKILL.md +94 -0
- package/ai/skills/stacks-analytics/SKILL.md +91 -0
- package/ai/skills/stacks-api/SKILL.md +738 -0
- package/ai/skills/stacks-arrays/SKILL.md +277 -0
- package/ai/skills/stacks-auth/SKILL.md +422 -0
- package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
- package/ai/skills/stacks-brandkit/SKILL.md +811 -0
- package/ai/skills/stacks-browse/SKILL.md +127 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
- package/ai/skills/stacks-browser/SKILL.md +145 -0
- package/ai/skills/stacks-buddy/SKILL.md +676 -0
- package/ai/skills/stacks-build/SKILL.md +163 -0
- package/ai/skills/stacks-cache/SKILL.md +125 -0
- package/ai/skills/stacks-calendar/SKILL.md +113 -0
- package/ai/skills/stacks-chat/SKILL.md +371 -0
- package/ai/skills/stacks-cli/SKILL.md +112 -0
- package/ai/skills/stacks-cloud/SKILL.md +192 -0
- package/ai/skills/stacks-cms/SKILL.md +217 -0
- package/ai/skills/stacks-collections/SKILL.md +82 -0
- package/ai/skills/stacks-commerce/SKILL.md +114 -0
- package/ai/skills/stacks-composables/SKILL.md +161 -0
- package/ai/skills/stacks-config/SKILL.md +144 -0
- package/ai/skills/stacks-configuration/SKILL.md +154 -0
- package/ai/skills/stacks-cron/SKILL.md +123 -0
- package/ai/skills/stacks-crosswind/SKILL.md +190 -0
- package/ai/skills/stacks-dashboard/SKILL.md +173 -0
- package/ai/skills/stacks-database/SKILL.md +286 -0
- package/ai/skills/stacks-datetime/SKILL.md +269 -0
- package/ai/skills/stacks-dependencies/SKILL.md +111 -0
- package/ai/skills/stacks-deploy/SKILL.md +102 -0
- package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
- package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
- package/ai/skills/stacks-design-output/SKILL.md +55 -0
- package/ai/skills/stacks-design-soft/SKILL.md +156 -0
- package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
- package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
- package/ai/skills/stacks-desktop/SKILL.md +78 -0
- package/ai/skills/stacks-development/SKILL.md +298 -0
- package/ai/skills/stacks-dns/SKILL.md +149 -0
- package/ai/skills/stacks-docs/SKILL.md +109 -0
- package/ai/skills/stacks-email/SKILL.md +236 -0
- package/ai/skills/stacks-enums/SKILL.md +100 -0
- package/ai/skills/stacks-env/SKILL.md +181 -0
- package/ai/skills/stacks-error-handling/SKILL.md +137 -0
- package/ai/skills/stacks-events/SKILL.md +228 -0
- package/ai/skills/stacks-faker/SKILL.md +158 -0
- package/ai/skills/stacks-git/SKILL.md +158 -0
- package/ai/skills/stacks-guard/SKILL.md +98 -0
- package/ai/skills/stacks-health/SKILL.md +75 -0
- package/ai/skills/stacks-http/SKILL.md +316 -0
- package/ai/skills/stacks-i18n/SKILL.md +198 -0
- package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
- package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
- package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
- package/ai/skills/stacks-investigate/SKILL.md +119 -0
- package/ai/skills/stacks-jobs/SKILL.md +136 -0
- package/ai/skills/stacks-lint/SKILL.md +184 -0
- package/ai/skills/stacks-listeners/SKILL.md +99 -0
- package/ai/skills/stacks-logging/SKILL.md +78 -0
- package/ai/skills/stacks-mail/SKILL.md +120 -0
- package/ai/skills/stacks-middleware/SKILL.md +249 -0
- package/ai/skills/stacks-migrations/SKILL.md +105 -0
- package/ai/skills/stacks-models/SKILL.md +267 -0
- package/ai/skills/stacks-new-feature/SKILL.md +206 -0
- package/ai/skills/stacks-notifications/SKILL.md +210 -0
- package/ai/skills/stacks-objects/SKILL.md +205 -0
- package/ai/skills/stacks-office-hours/SKILL.md +134 -0
- package/ai/skills/stacks-orm/SKILL.md +342 -0
- package/ai/skills/stacks-path/SKILL.md +118 -0
- package/ai/skills/stacks-payments/SKILL.md +373 -0
- package/ai/skills/stacks-plan-review/SKILL.md +152 -0
- package/ai/skills/stacks-plugins/SKILL.md +149 -0
- package/ai/skills/stacks-push/SKILL.md +376 -0
- package/ai/skills/stacks-query-builder/SKILL.md +128 -0
- package/ai/skills/stacks-queue/SKILL.md +559 -0
- package/ai/skills/stacks-realtime/SKILL.md +442 -0
- package/ai/skills/stacks-redesign/SKILL.md +182 -0
- package/ai/skills/stacks-registry/SKILL.md +58 -0
- package/ai/skills/stacks-repl/SKILL.md +80 -0
- package/ai/skills/stacks-retro/SKILL.md +122 -0
- package/ai/skills/stacks-review/SKILL.md +135 -0
- package/ai/skills/stacks-router/SKILL.md +231 -0
- package/ai/skills/stacks-routes/SKILL.md +105 -0
- package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
- package/ai/skills/stacks-scheduler/SKILL.md +363 -0
- package/ai/skills/stacks-search-engine/SKILL.md +112 -0
- package/ai/skills/stacks-security/SKILL.md +129 -0
- package/ai/skills/stacks-security-audit/SKILL.md +128 -0
- package/ai/skills/stacks-server/SKILL.md +458 -0
- package/ai/skills/stacks-shell/SKILL.md +62 -0
- package/ai/skills/stacks-slug/SKILL.md +87 -0
- package/ai/skills/stacks-sms/SKILL.md +385 -0
- package/ai/skills/stacks-socials/SKILL.md +303 -0
- package/ai/skills/stacks-storage/SKILL.md +576 -0
- package/ai/skills/stacks-strings/SKILL.md +416 -0
- package/ai/skills/stacks-stx/SKILL.md +176 -0
- package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
- package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
- package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
- package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
- package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
- package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
- package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
- package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
- package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
- package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
- package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
- package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
- package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
- package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
- package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
- package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
- package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
- package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
- package/ai/skills/stacks-testing/SKILL.md +129 -0
- package/ai/skills/stacks-tunnel/SKILL.md +125 -0
- package/ai/skills/stacks-types/SKILL.md +178 -0
- package/ai/skills/stacks-ui/SKILL.md +246 -0
- package/ai/skills/stacks-utils/SKILL.md +444 -0
- package/ai/skills/stacks-validation/SKILL.md +371 -0
- package/ai/skills/stacks-whois/SKILL.md +315 -0
- package/assets/world-map-data.ts +121 -0
- package/bootstrap.ts +114 -0
- package/docs/api-examples.md +46 -0
- package/docs/index.md +24 -0
- package/docs/markdown-examples.md +87 -0
- package/functions/analytics.ts +97 -0
- package/functions/api.ts +143 -0
- package/functions/auth.ts +208 -0
- package/functions/billing/payments.ts +149 -0
- package/functions/blog.ts +120 -0
- package/functions/cms/categorizables.ts +107 -0
- package/functions/cms/pages.ts +108 -0
- package/functions/cms/posts.ts +100 -0
- package/functions/cms/taggables.ts +102 -0
- package/functions/commerce/coupons.ts +128 -0
- package/functions/commerce/customers.ts +128 -0
- package/functions/commerce/gift-cards.ts +119 -0
- package/functions/commerce/orders.ts +112 -0
- package/functions/commerce/payments.ts +119 -0
- package/functions/commerce/products/categories.ts +123 -0
- package/functions/commerce/products/manufacturers.ts +123 -0
- package/functions/commerce/products/products.ts +123 -0
- package/functions/commerce/products/reviews.ts +123 -0
- package/functions/commerce/products/units.ts +123 -0
- package/functions/commerce/products/variants.ts +123 -0
- package/functions/commerce/shippings/delivery-routes.ts +123 -0
- package/functions/commerce/shippings/digital-deliveries.ts +119 -0
- package/functions/commerce/shippings/drivers.ts +123 -0
- package/functions/commerce/shippings/license-keys.ts +123 -0
- package/functions/commerce/shippings/shipping-methods.ts +123 -0
- package/functions/commerce/shippings/shipping-rates.ts +119 -0
- package/functions/commerce/shippings/shipping-zones.ts +119 -0
- package/functions/commerce/taxes.ts +119 -0
- package/functions/commerce/waitlist/products.ts +123 -0
- package/functions/commerce/waitlist/restaurants.ts +123 -0
- package/functions/craft.ts +107 -0
- package/functions/dashboard.ts +153 -0
- package/functions/inbox.ts +95 -0
- package/functions/jobs.ts +86 -0
- package/functions/monitoring/errors.ts +295 -0
- package/functions/queue.ts +111 -0
- package/functions/realtime/websockets.ts +96 -0
- package/functions/realtime.ts +52 -0
- package/functions/releases.ts +49 -0
- package/functions/search.ts +126 -0
- package/functions/toasts.ts +95 -0
- package/functions/uploads.ts +216 -0
- package/ide/.gitignore +4 -0
- package/ide/cursor/rules/auto-imports.mdc +574 -0
- package/ide/cursor/rules/code-style.mdc +12 -0
- package/ide/cursor/rules/documentation.mdc +9 -0
- package/ide/cursor/rules/error-handling-validation.mdc +11 -0
- package/ide/cursor/rules/key-conventions.mdc +11 -0
- package/ide/cursor/rules/project-structure.mdc +169 -0
- package/ide/cursor/rules/readme.mdc +318 -0
- package/ide/cursor/rules/syntax-formatting.mdc +9 -0
- package/ide/cursor/rules/testing.mdc +10 -0
- package/ide/cursor/rules/typescript.mdc +9 -0
- package/ide/cursor/rules/ui-styling.mdc +0 -0
- package/ide/dictionary.txt +397 -0
- package/ide/jetbrains/.fleet/settings.json +4 -0
- package/ide/jetbrains/.idea/.gitignore +5 -0
- package/ide/jetbrains/.idea/.name +1 -0
- package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
- package/ide/jetbrains/.idea/modules.xml +8 -0
- package/ide/jetbrains/.idea/stacks.iml +22 -0
- package/ide/jetbrains/.idea/vcs.xml +6 -0
- package/ide/jetbrains/.idea/webResources.xml +14 -0
- package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
- package/ide/jetbrains/installed.txt +4 -0
- package/ide/jetbrains/options/github-copilot.xml +5 -0
- package/ide/jetbrains/options/nodejs.xml +7 -0
- package/ide/jetbrains/options/templates.xml +124 -0
- package/ide/jetbrains/templates/JavaScript.xml +6 -0
- package/ide/jetbrains/templates/Stacks.xml +8 -0
- package/ide/vscode/.vscode/README.md +23 -0
- package/ide/vscode/.vscode/extensions.json +5 -0
- package/ide/vscode/.vscode/settings.json +176 -0
- package/ide/vscode/.vscode/stacks.code-snippets +181 -0
- package/ide/vscode/LICENSE.md +21 -0
- package/ide/vscode/README.md +36 -0
- package/ide/vscode/logo.png +0 -0
- package/ide/vscode/package.json +79 -0
- package/ide/zed/.zed/settings.json +139 -0
- package/lang/README.md +28 -0
- package/lang/de.yml +14 -0
- package/lang/en.yml +15 -0
- package/package.json +19 -3
- package/project/bootstrap +161 -0
- package/project/buddy +175 -0
- package/project/storage/framework/tsconfig.app.json +50 -0
- package/project/storage/framework/tsconfig.base.json +58 -0
- package/routes/core.ts +78 -0
- package/routes/dashboard-api.ts +233 -0
- package/routes/dashboard.ts +739 -0
- package/routes/email.ts +129 -0
- package/stores/[name].stx +16 -0
- package/stores/git.ts +71 -0
- package/stores/payment.ts +474 -0
- package/stores/queue.ts +43 -0
- package/stores/user.ts +29 -0
- package/stx-components-plugin.ts +25 -0
- package/styles/design-tokens.css +597 -0
- package/types/dashboard.ts +70 -0
- package/types/defaults.ts +438 -0
- package/vcs/github/CODE_OF_CONDUCT.md +83 -0
- package/vcs/github/CONTRIBUTING.md +187 -0
- package/vcs/github/EXPLANATIONS.md +41 -0
- package/vcs/github/FUNDING.yml +1 -0
- package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
- package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
- package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- package/vcs/github/SECURITY.md +70 -0
- package/vcs/github/renovate.json +5 -0
- package/vcs/github/stale.yml +14 -0
- package/vcs/github/workflows/README.md +16 -0
- package/vcs/github/workflows/ci.yml +114 -0
- package/vcs/github/workflows/export-size.yml +25 -0
- package/vcs/github/workflows/labeler.yml +13 -0
- package/vcs/github/workflows/release.yml +219 -0
- package/views/[...all].stx +8 -0
- package/views/about.md +3 -0
- package/views/auth/login.stx +1 -0
- package/views/auth/signup.stx +85 -0
- package/views/dashboard/.discovered-models.json +542 -0
- package/views/dashboard/AUDIT.md +904 -0
- package/views/dashboard/[...all].stx +89 -0
- package/views/dashboard/access-tokens/index.stx +177 -0
- package/views/dashboard/actions/index.stx +129 -0
- package/views/dashboard/analytics/blog/index.stx +356 -0
- package/views/dashboard/analytics/browsers/index.stx +263 -0
- package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
- package/views/dashboard/analytics/commerce/web/index.stx +379 -0
- package/views/dashboard/analytics/countries/index.stx +289 -0
- package/views/dashboard/analytics/devices/index.stx +305 -0
- package/views/dashboard/analytics/events/index.stx +536 -0
- package/views/dashboard/analytics/index.stx +88 -0
- package/views/dashboard/analytics/marketing/index.stx +315 -0
- package/views/dashboard/analytics/pages/index.stx +271 -0
- package/views/dashboard/analytics/referrers/index.stx +319 -0
- package/views/dashboard/analytics/web/index.stx +356 -0
- package/views/dashboard/buddy/index.stx +198 -0
- package/views/dashboard/ci/index.stx +462 -0
- package/views/dashboard/cloud/index.stx +452 -0
- package/views/dashboard/commands/index.stx +295 -0
- package/views/dashboard/commerce/categories/index.stx +406 -0
- package/views/dashboard/commerce/coupons/index.stx +485 -0
- package/views/dashboard/commerce/customers/index.stx +410 -0
- package/views/dashboard/commerce/dashboard/index.stx +287 -0
- package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
- package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
- package/views/dashboard/commerce/delivery/drivers.stx +397 -0
- package/views/dashboard/commerce/delivery/index.stx +18 -0
- package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
- package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
- package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
- package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
- package/views/dashboard/commerce/delivery/tabs.ts +25 -0
- package/views/dashboard/commerce/gift-cards/index.stx +561 -0
- package/views/dashboard/commerce/manufacturers/index.stx +308 -0
- package/views/dashboard/commerce/orders/index.stx +247 -0
- package/views/dashboard/commerce/payments/index.stx +535 -0
- package/views/dashboard/commerce/pos/index.stx +653 -0
- package/views/dashboard/commerce/printers/devices/index.stx +273 -0
- package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
- package/views/dashboard/commerce/products/detail.stx +563 -0
- package/views/dashboard/commerce/products/index.stx +370 -0
- package/views/dashboard/commerce/reviews/index.stx +656 -0
- package/views/dashboard/commerce/reviews/index.ts +0 -0
- package/views/dashboard/commerce/taxes/index.stx +377 -0
- package/views/dashboard/commerce/units/index.stx +317 -0
- package/views/dashboard/commerce/variants/index.stx +319 -0
- package/views/dashboard/commerce/waitlist/products.stx +942 -0
- package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
- package/views/dashboard/components/index.stx +330 -0
- package/views/dashboard/composables/index.ts +19 -0
- package/views/dashboard/composables/useChart.ts +77 -0
- package/views/dashboard/composables/useNavigation.ts +99 -0
- package/views/dashboard/composables/useRole.ts +58 -0
- package/views/dashboard/composables/useTheme.ts +74 -0
- package/views/dashboard/content/authors/index.stx +171 -0
- package/views/dashboard/content/blog/index.stx +493 -0
- package/views/dashboard/content/categories/index.stx +169 -0
- package/views/dashboard/content/comments/index.stx +189 -0
- package/views/dashboard/content/dashboard.stx +383 -0
- package/views/dashboard/content/files/index.stx +706 -0
- package/views/dashboard/content/pages/index.stx +174 -0
- package/views/dashboard/content/posts/index.stx +269 -0
- package/views/dashboard/content/seo/index.stx +240 -0
- package/views/dashboard/content/tags/index.stx +167 -0
- package/views/dashboard/data/activity/index.stx +261 -0
- package/views/dashboard/data/dashboard/index.stx +116 -0
- package/views/dashboard/data/subscribers.stx +270 -0
- package/views/dashboard/data/teams.stx +275 -0
- package/views/dashboard/data/users.stx +279 -0
- package/views/dashboard/dependencies/index.stx +178 -0
- package/views/dashboard/deployments/[id].stx +234 -0
- package/views/dashboard/deployments/index.stx +9 -0
- package/views/dashboard/dns/index.stx +163 -0
- package/views/dashboard/environment/index.stx +283 -0
- package/views/dashboard/errors/index.stx +274 -0
- package/views/dashboard/forgot-password.stx +57 -0
- package/views/dashboard/functions/index.stx +159 -0
- package/views/dashboard/health/index.stx +248 -0
- package/views/dashboard/inbox/activity.stx +350 -0
- package/views/dashboard/inbox/index.stx +452 -0
- package/views/dashboard/inbox/settings.stx +290 -0
- package/views/dashboard/index.stx +252 -0
- package/views/dashboard/insights/index.stx +529 -0
- package/views/dashboard/jobs/[id].stx +430 -0
- package/views/dashboard/jobs/history.stx +222 -0
- package/views/dashboard/jobs/index.stx +214 -0
- package/views/dashboard/kanban/[id].stx +899 -0
- package/views/dashboard/kanban/index.stx +260 -0
- package/views/dashboard/layouts/default.stx +565 -0
- package/views/dashboard/layouts/guest.stx +10 -0
- package/views/dashboard/login.stx +48 -0
- package/views/dashboard/logs/index.stx +540 -0
- package/views/dashboard/mailboxes/index.stx +149 -0
- package/views/dashboard/management/permissions/index.stx +490 -0
- package/views/dashboard/marketing/campaigns/index.stx +604 -0
- package/views/dashboard/marketing/lists/index.stx +514 -0
- package/views/dashboard/marketing/reviews/index.stx +475 -0
- package/views/dashboard/marketing/social-posts/index.stx +560 -0
- package/views/dashboard/models/[model].stx +195 -0
- package/views/dashboard/models/index.stx +159 -0
- package/views/dashboard/monitoring/errors/index.stx +415 -0
- package/views/dashboard/notifications/dashboard.stx +383 -0
- package/views/dashboard/notifications/email.stx +336 -0
- package/views/dashboard/notifications/history.stx +373 -0
- package/views/dashboard/notifications/sms.stx +332 -0
- package/views/dashboard/packages/index.stx +195 -0
- package/views/dashboard/queries/[id].stx +381 -0
- package/views/dashboard/queries/history.stx +227 -0
- package/views/dashboard/queries/index.stx +335 -0
- package/views/dashboard/queries/slow.stx +318 -0
- package/views/dashboard/queue/index.stx +427 -0
- package/views/dashboard/realtime/index.stx +429 -0
- package/views/dashboard/register.stx +46 -0
- package/views/dashboard/releases/index.stx +389 -0
- package/views/dashboard/requests/index.stx +462 -0
- package/views/dashboard/serverless/index.stx +475 -0
- package/views/dashboard/servers/[id].stx +299 -0
- package/views/dashboard/servers/index.stx +483 -0
- package/views/dashboard/settings/billing.stx +50 -0
- package/views/dashboard/settings/index.stx +256 -0
- package/views/dashboard/settings/mail.stx +252 -0
- package/views/dashboard/stores/auth.ts +123 -0
- package/views/dashboard/stores/ci.ts +342 -0
- package/views/dashboard/stores/index.ts +129 -0
- package/views/dashboard/stores/kanban.ts +723 -0
- package/views/dashboard/stores/rbac.ts +350 -0
- package/views/dashboard/stx.config.ts +34 -0
- package/views/dashboard/teams/[id].stx +170 -0
- package/views/forum/category.stx +92 -0
- package/views/forum/index.stx +209 -0
- package/views/forum/new-topic.stx +113 -0
- package/views/forum/profile.stx +1 -0
- package/views/forum/topic.stx +143 -0
- package/views/hello-world/[name].stx +47 -0
- package/views/index.stx +21 -0
- package/views/system-tray/index.stx +147 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-objects
|
|
3
|
+
description: Use when working with object manipulation in Stacks — deep merging with type safety, object mapping/transformation, strict key checking, typed entries/keys, property picking, clearing undefined values, or the DeepMerge utility type. Covers @stacksjs/objects.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Stacks Object Utilities
|
|
10
|
+
|
|
11
|
+
Type-safe object manipulation helpers. All functions are exported from a single file.
|
|
12
|
+
|
|
13
|
+
## Key Path
|
|
14
|
+
- Core package: `storage/framework/core/objects/src/index.ts` (single file, all functions)
|
|
15
|
+
|
|
16
|
+
## Dependencies
|
|
17
|
+
- `@stacksjs/types` -- `DeepMerge` type
|
|
18
|
+
- `@stacksjs/utils` -- `notNullish` filter function
|
|
19
|
+
- `@stacksjs/validation` -- `isObject` type guard
|
|
20
|
+
|
|
21
|
+
## Functions
|
|
22
|
+
|
|
23
|
+
### objectMap -- Transform Object Key/Value Pairs
|
|
24
|
+
```typescript
|
|
25
|
+
function objectMap<K extends string, V, NK = K, NV = V>(
|
|
26
|
+
obj: Record<K, V>,
|
|
27
|
+
fn: (key: K, value: V) => [NK, NV] | undefined,
|
|
28
|
+
): Record<K, V>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The callback receives `(key, value)` and must return either:
|
|
32
|
+
- `[newKey, newValue]` tuple to include the entry
|
|
33
|
+
- `undefined` to filter out the entry
|
|
34
|
+
|
|
35
|
+
Implementation uses `Object.fromEntries(Object.entries(obj).map(...).filter(notNullish))`.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// Transform values
|
|
39
|
+
objectMap({ a: 1, b: 2 }, (k, v) => [k, v * 2])
|
|
40
|
+
// { a: 2, b: 4 }
|
|
41
|
+
|
|
42
|
+
// Rename keys
|
|
43
|
+
objectMap({ a: 1, b: 2 }, (k, v) => [`prefix_${k}`, v])
|
|
44
|
+
// { prefix_a: 1, prefix_b: 2 }
|
|
45
|
+
|
|
46
|
+
// Swap key/value
|
|
47
|
+
objectMap({ a: 1, b: 2 }, (k, v) => [v, k])
|
|
48
|
+
// { 1: 'a', 2: 'b' }
|
|
49
|
+
|
|
50
|
+
// Filter entries (return undefined to exclude)
|
|
51
|
+
objectMap({ a: 1, b: 2, c: 3 }, (k, v) => k === 'b' ? undefined : [k, v])
|
|
52
|
+
// { a: 1, c: 3 }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### deepMerge -- Deep Merge Objects
|
|
56
|
+
```typescript
|
|
57
|
+
function deepMerge<T extends object = object, S extends object = T>(
|
|
58
|
+
target: T,
|
|
59
|
+
...sources: S[]
|
|
60
|
+
): DeepMerge<T, S>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Recursively merges source objects into target. Handles multiple sources via recursive spread.
|
|
64
|
+
|
|
65
|
+
Key behaviors:
|
|
66
|
+
- Only merges "mergeable objects" (objects that are not arrays, checked via `isObject()` and `!Array.isArray()`)
|
|
67
|
+
- Arrays are NOT deeply merged -- they are replaced entirely
|
|
68
|
+
- Missing keys in target are created as empty objects `{}` before recursive merge
|
|
69
|
+
- **Mutates the target object** -- the return value IS the modified target
|
|
70
|
+
- Processes sources left to right
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const target = { a: 1, nested: { x: 1, y: 2 } }
|
|
74
|
+
const source = { b: 2, nested: { y: 3, z: 4 } }
|
|
75
|
+
const result = deepMerge(target, source)
|
|
76
|
+
// result === target (same reference, mutated)
|
|
77
|
+
// { a: 1, b: 2, nested: { x: 1, y: 3, z: 4 } }
|
|
78
|
+
|
|
79
|
+
// Multiple sources
|
|
80
|
+
const merged = deepMerge(defaults, userConfig, overrides)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The `DeepMerge<T, S>` type (from `@stacksjs/types`) provides full type inference:
|
|
84
|
+
```typescript
|
|
85
|
+
type DeepMerge<F, S> = MergeInsertions<{
|
|
86
|
+
[K in keyof F | keyof S]: K extends keyof S & keyof F
|
|
87
|
+
? DeepMerge<F[K], S[K]>
|
|
88
|
+
: K extends keyof S ? S[K]
|
|
89
|
+
: K extends keyof F ? F[K]
|
|
90
|
+
: never
|
|
91
|
+
}>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### objectPick -- Pick Properties by Key
|
|
95
|
+
```typescript
|
|
96
|
+
function objectPick<O extends object, T extends keyof O>(
|
|
97
|
+
obj: O,
|
|
98
|
+
keys: T[],
|
|
99
|
+
omitUndefined?: boolean, // default: false
|
|
100
|
+
): Pick<O, T>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Creates a new object with only the specified keys. Uses `reduce` internally.
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const user = { id: 1, name: 'John', email: 'john@test.com', password: 'secret' }
|
|
107
|
+
objectPick(user, ['id', 'name', 'email'])
|
|
108
|
+
// { id: 1, name: 'John', email: 'john@test.com' }
|
|
109
|
+
|
|
110
|
+
// With omitUndefined=true, skips keys whose values are undefined
|
|
111
|
+
const partial = { id: 1, name: 'John', bio: undefined }
|
|
112
|
+
objectPick(partial, ['id', 'name', 'bio'], true)
|
|
113
|
+
// { id: 1, name: 'John' } (bio omitted)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- Only includes keys that exist in the object (`k in obj` check)
|
|
117
|
+
- With `omitUndefined=true`, additionally skips keys where `obj[k] === undefined`
|
|
118
|
+
|
|
119
|
+
### clearUndefined -- Remove Undefined Fields
|
|
120
|
+
```typescript
|
|
121
|
+
function clearUndefined<T extends object>(obj: T): T
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Mutates the object** by deleting keys whose values are `undefined`. Returns the same object reference.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const data = { name: 'John', age: undefined, email: 'john@test.com' }
|
|
128
|
+
clearUndefined(data)
|
|
129
|
+
// data is now { name: 'John', email: 'john@test.com' }
|
|
130
|
+
// Returns same reference as input
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- Only removes `undefined` values -- `null`, `0`, `''`, `false` are preserved
|
|
134
|
+
- Uses `delete obj[key]` for removal
|
|
135
|
+
|
|
136
|
+
### isKeyOf -- Type Guard for Object Keys
|
|
137
|
+
```typescript
|
|
138
|
+
function isKeyOf<T extends object>(obj: T, k: keyof any): k is keyof T
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Type guard that narrows `k` to `keyof T` if the key exists in `obj`. Uses `k in obj`.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const config = { debug: true, verbose: false }
|
|
145
|
+
const key: string = 'debug'
|
|
146
|
+
|
|
147
|
+
if (isKeyOf(config, key)) {
|
|
148
|
+
// TypeScript knows: key is 'debug' | 'verbose'
|
|
149
|
+
console.log(config[key]) // type-safe access
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### objectKeys -- Strictly Typed Object.keys
|
|
154
|
+
```typescript
|
|
155
|
+
function objectKeys<T extends object>(obj: T): Array<`${keyof T & (string | number | boolean | null | undefined)}`>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Returns `Object.keys(obj)` with a stricter return type than the built-in `Object.keys()` (which returns `string[]`).
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const user = { name: 'John', age: 30 }
|
|
162
|
+
const keys = objectKeys(user)
|
|
163
|
+
// Type: ('name' | 'age')[] (not string[])
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### objectEntries -- Strictly Typed Object.entries
|
|
167
|
+
```typescript
|
|
168
|
+
function objectEntries<T extends object>(obj: T): Array<[keyof T, T[keyof T]]>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Returns `Object.entries(obj)` with a stricter return type than the built-in `Object.entries()` (which returns `[string, any][]`).
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const user = { name: 'John', age: 30 }
|
|
175
|
+
const entries = objectEntries(user)
|
|
176
|
+
// Type: ['name' | 'age', string | number][]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### hasOwnProperty -- Safe Property Check
|
|
180
|
+
```typescript
|
|
181
|
+
function hasOwnProperty<T>(obj: T, v: PropertyKey): boolean
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Null-safe wrapper around `Object.prototype.hasOwnProperty.call()`. Returns `false` if `obj` is `null` or `undefined`.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
hasOwnProperty({ a: 1 }, 'a') // true
|
|
188
|
+
hasOwnProperty({ a: 1 }, 'b') // false
|
|
189
|
+
hasOwnProperty(null, 'a') // false (no throw)
|
|
190
|
+
hasOwnProperty(undefined, 'a') // false (no throw)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Gotchas
|
|
194
|
+
- `deepMerge` **mutates the target object** -- it does not create a new object. The return value is the same reference as `target`.
|
|
195
|
+
- `clearUndefined` **mutates the input object** -- it deletes properties in place.
|
|
196
|
+
- `objectPick` creates a NEW object -- original is not affected.
|
|
197
|
+
- `objectMap` creates a NEW object via `Object.fromEntries`.
|
|
198
|
+
- `deepMerge` does NOT deeply merge arrays -- arrays from source replace arrays in target entirely.
|
|
199
|
+
- `deepMerge` uses `isObject()` from `@stacksjs/validation` combined with `!Array.isArray()` to determine mergeability.
|
|
200
|
+
- `objectMap` can filter entries by returning `undefined` from the callback -- filtered via `notNullish` from `@stacksjs/utils`.
|
|
201
|
+
- `objectKeys` return type uses a template literal type to handle non-string keys.
|
|
202
|
+
- `clearUndefined` only removes `undefined` -- `null` values are preserved.
|
|
203
|
+
- `hasOwnProperty` accepts `null`/`undefined` objects without throwing.
|
|
204
|
+
- `objectPick` with `omitUndefined=false` (default) includes keys even if their values are `undefined`, as long as the key exists in the object.
|
|
205
|
+
- These utilities are also re-exported through `@stacksjs/utils`.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-office-hours
|
|
3
|
+
description: Use for structured product brainstorming about Stacks features — two modes (startup diagnostic for new ideas, builder generative for existing features). Produces design documents, never code. Invoke with /stacks-office-hours.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /stacks-office-hours — Product Brainstorming
|
|
10
|
+
|
|
11
|
+
You are a product thinking partner for the Stacks ecosystem. You produce **design documents and strategic analysis**, never code.
|
|
12
|
+
|
|
13
|
+
## Determine Mode
|
|
14
|
+
|
|
15
|
+
- **New idea** → Startup Mode (diagnostic)
|
|
16
|
+
- **Existing feature/package** → Builder Mode (generative)
|
|
17
|
+
|
|
18
|
+
If context makes it obvious (e.g., a feature for an existing Stacks package), skip the question.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Startup Mode: Diagnostic
|
|
23
|
+
|
|
24
|
+
Work through 6 questions. Push back on vague answers.
|
|
25
|
+
|
|
26
|
+
### 1. Demand Signal
|
|
27
|
+
> "What evidence do you have that people want this?"
|
|
28
|
+
Red flags: "Everyone needs this", no concrete evidence
|
|
29
|
+
Green flags: GitHub issues, users building workarounds, measurable pain
|
|
30
|
+
|
|
31
|
+
### 2. Existing Alternatives
|
|
32
|
+
> "What do people use today? Why isn't that good enough?"
|
|
33
|
+
|
|
34
|
+
### 3. Target User
|
|
35
|
+
> "Describe the specific person who would use this."
|
|
36
|
+
Red flags: "All developers"
|
|
37
|
+
Green flags: Named personas, specific workflows
|
|
38
|
+
|
|
39
|
+
### 4. Scope Trap
|
|
40
|
+
> "What's the smallest version that would be useful?"
|
|
41
|
+
|
|
42
|
+
### 5. Stacks Ecosystem Fit
|
|
43
|
+
> "How does this interact with existing Stacks packages? Does it extend, replace, or stand alone?"
|
|
44
|
+
Check against the 39+ existing packages. Flag duplication.
|
|
45
|
+
|
|
46
|
+
### 6. Maintenance Burden
|
|
47
|
+
> "Who maintains this? What's the ongoing cost?"
|
|
48
|
+
|
|
49
|
+
### Diagnostic Output
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
## Idea Diagnostic: [name]
|
|
53
|
+
|
|
54
|
+
### Verdict: [BUILD / ITERATE / PAUSE / KILL]
|
|
55
|
+
|
|
56
|
+
### Strengths
|
|
57
|
+
- [with evidence]
|
|
58
|
+
|
|
59
|
+
### Concerns
|
|
60
|
+
- [with evidence]
|
|
61
|
+
|
|
62
|
+
### If proceeding, start with:
|
|
63
|
+
[smallest deliverable that tests the core hypothesis]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Builder Mode: Generative
|
|
69
|
+
|
|
70
|
+
### Step 1: Understand the Goal
|
|
71
|
+
> "What should the user be able to do that they can't today?"
|
|
72
|
+
|
|
73
|
+
### Step 2: Forced Alternatives
|
|
74
|
+
|
|
75
|
+
For every design decision, generate 3 approaches:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
### [Decision]
|
|
79
|
+
|
|
80
|
+
**Minimal**: [simplest thing]
|
|
81
|
+
- Pros / Cons / Build time
|
|
82
|
+
|
|
83
|
+
**Ideal**: [right solution if complexity wasn't a factor]
|
|
84
|
+
- Pros / Cons / Build time
|
|
85
|
+
|
|
86
|
+
**Creative**: [lateral approach]
|
|
87
|
+
- Pros / Cons / Build time
|
|
88
|
+
|
|
89
|
+
**Recommendation**: [which and why]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Step 3: Design Document
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
## Design: [feature name]
|
|
96
|
+
|
|
97
|
+
### Problem
|
|
98
|
+
[What user problem, specifically]
|
|
99
|
+
|
|
100
|
+
### Solution
|
|
101
|
+
[Chosen approach]
|
|
102
|
+
|
|
103
|
+
### User Experience
|
|
104
|
+
[Step-by-step: what does the user do?]
|
|
105
|
+
|
|
106
|
+
### Technical Approach
|
|
107
|
+
[How it fits into Stacks. Key data flows. Which @stacksjs/* packages involved.]
|
|
108
|
+
|
|
109
|
+
### API Surface
|
|
110
|
+
[CLI commands (buddy *), config options, package exports]
|
|
111
|
+
|
|
112
|
+
### Edge Cases
|
|
113
|
+
[Error states, empty states, invalid input]
|
|
114
|
+
|
|
115
|
+
### Non-Goals
|
|
116
|
+
[What this deliberately does NOT do]
|
|
117
|
+
|
|
118
|
+
### Open Questions
|
|
119
|
+
[Decisions needing input]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Rules
|
|
125
|
+
|
|
126
|
+
- **Never write code.** Documents and analysis only.
|
|
127
|
+
- **Push back on vague answers.** Demand evidence.
|
|
128
|
+
- **Respect the Stacks ecosystem.** Check existing packages before suggesting new ones.
|
|
129
|
+
- **Be direct about bad ideas.** A polite "KILL" saves time.
|
|
130
|
+
- **One session, one idea.**
|
|
131
|
+
|
|
132
|
+
## Downstream
|
|
133
|
+
|
|
134
|
+
> **Design document complete.** Run `/stacks-plan-review` to get architecture review and implementation plan.
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-orm
|
|
3
|
+
description: Use when working with the Stacks ORM — defining models with defineModel(), model relationships (hasOne, hasMany, belongsTo, belongsToMany, morphOne, hasManyThrough), attributes, traits, factories, computed properties, query building, transactions, or the 50+ built-in models. Covers @stacksjs/orm, storage/framework/orm/, and storage/framework/defaults/app/Models/.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript, SQLite >= 3.47.2
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Stacks ORM
|
|
10
|
+
|
|
11
|
+
## Key Paths
|
|
12
|
+
- Core ORM package: `storage/framework/core/orm/src/`
|
|
13
|
+
- ORM implementation: `storage/framework/orm/`
|
|
14
|
+
- Model definitions: `storage/framework/defaults/app/Models/` (50+ models)
|
|
15
|
+
- Application models: `app/Models/`
|
|
16
|
+
- Default model templates: `storage/framework/defaults/app/Models/`
|
|
17
|
+
- ORM type globals: `storage/framework/types/orm-globals.d.ts`
|
|
18
|
+
- Attribute types: `storage/framework/types/attributes.ts` (240+ attributes)
|
|
19
|
+
- Model events: `storage/framework/types/events.ts`
|
|
20
|
+
|
|
21
|
+
## Source Files
|
|
22
|
+
```
|
|
23
|
+
orm/src/
|
|
24
|
+
├── define-model.ts # defineModel() + buildEventHooks() + buildTraitMethods()
|
|
25
|
+
├── index.ts # Re-exports orm/src + db + subquery + transaction + types
|
|
26
|
+
├── db.ts # Database query builder bridge
|
|
27
|
+
├── subquery.ts # Subquery support
|
|
28
|
+
├── transaction.ts # transaction(), savepoint(), transactional()
|
|
29
|
+
├── model-types.ts # ModelRow<T>, NewModelData<T>, UpdateModelData<T>
|
|
30
|
+
├── types.ts # ORM type definitions
|
|
31
|
+
├── utils.ts # modelTableName, getRelations, getFillableAttributes, etc.
|
|
32
|
+
├── builder.ts # Query builder integration
|
|
33
|
+
├── generated/ # Auto-generated model types and table traits
|
|
34
|
+
│ ├── types.ts
|
|
35
|
+
│ ├── index.ts
|
|
36
|
+
│ └── table-traits.ts
|
|
37
|
+
└── traits/
|
|
38
|
+
├── index.ts # Re-exports all trait creators
|
|
39
|
+
├── taggable.ts # createTaggableMethods()
|
|
40
|
+
├── categorizable.ts # createCategorizableMethods()
|
|
41
|
+
├── commentable.ts # createCommentableMethods()
|
|
42
|
+
├── billable.ts # createBillableMethods()
|
|
43
|
+
├── likeable.ts # createLikeableMethods()
|
|
44
|
+
└── two-factor.ts # createTwoFactorMethods()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## defineModel() API (define-model.ts)
|
|
48
|
+
|
|
49
|
+
Wraps bun-query-builder's `createModel()` with Stacks-specific enhancements:
|
|
50
|
+
- Event dispatching via `traits.observe` (emits `{model}:created`, `{model}:updated`, `{model}:deleted` via `@stacksjs/events`)
|
|
51
|
+
- Trait methods (billable, taggable, categorizable, commentable, likeable, 2FA)
|
|
52
|
+
- Raw definition access for generators (`getDefinition()`, `_isStacksModel`)
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { defineModel } from '@stacksjs/orm'
|
|
56
|
+
|
|
57
|
+
export default defineModel({
|
|
58
|
+
name: 'Product',
|
|
59
|
+
table: 'products',
|
|
60
|
+
primaryKey: 'id', // default: 'id'
|
|
61
|
+
autoIncrement: true, // default: true
|
|
62
|
+
|
|
63
|
+
traits: {
|
|
64
|
+
useUuid: true, // adds uuid column
|
|
65
|
+
useTimestamps: true, // adds created_at, updated_at
|
|
66
|
+
useAuth: { usePasskey: true }, // adds auth columns + passkey support
|
|
67
|
+
useSocials: ['github'], // social login providers
|
|
68
|
+
useSearch: { // search engine indexing
|
|
69
|
+
displayable: ['name', 'email'],
|
|
70
|
+
searchable: ['name', 'email'],
|
|
71
|
+
sortable: ['name', 'created_at'],
|
|
72
|
+
filterable: ['status']
|
|
73
|
+
},
|
|
74
|
+
useSeeder: { count: 10 }, // or just `true` (defaults to 10)
|
|
75
|
+
useApi: {
|
|
76
|
+
uri: 'products',
|
|
77
|
+
routes: ['index', 'store', 'show', 'update', 'destroy']
|
|
78
|
+
},
|
|
79
|
+
categorizable: true, // adds category relations via categorizable table
|
|
80
|
+
taggable: true, // adds tag relations via taggable table
|
|
81
|
+
commentables: true, // adds comment relations (NOTE: plural 's' in key)
|
|
82
|
+
billable: true, // adds Stripe integration methods
|
|
83
|
+
likeable: true, // or { table?: string, foreignKey?: string }
|
|
84
|
+
observe: true, // emit model events (true = all, or array: ['create','update','delete'])
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// Relationships
|
|
88
|
+
hasOne: ['Subscriber'],
|
|
89
|
+
hasMany: ['Post', 'Order'],
|
|
90
|
+
belongsTo: ['User', 'Category'],
|
|
91
|
+
belongsToMany: ['Tag'],
|
|
92
|
+
hasOneThrough: ['Profile'],
|
|
93
|
+
morphOne: 'Image', // or { model, morphName?, type?, id? }
|
|
94
|
+
|
|
95
|
+
indexes: [
|
|
96
|
+
{ name: 'idx_email', columns: ['email'] },
|
|
97
|
+
{ name: 'idx_composite', columns: ['email', 'name'] }
|
|
98
|
+
],
|
|
99
|
+
|
|
100
|
+
attributes: {
|
|
101
|
+
name: {
|
|
102
|
+
order: 1,
|
|
103
|
+
fillable: true,
|
|
104
|
+
required: true,
|
|
105
|
+
unique: false,
|
|
106
|
+
validation: {
|
|
107
|
+
rule: schema.string().maxLength(100),
|
|
108
|
+
message: { maxLength: 'Name is too long' }
|
|
109
|
+
},
|
|
110
|
+
factory: (faker) => faker.lorem.word()
|
|
111
|
+
},
|
|
112
|
+
price: {
|
|
113
|
+
fillable: true,
|
|
114
|
+
required: true,
|
|
115
|
+
validation: { rule: schema.number().min(1) },
|
|
116
|
+
factory: (faker) => faker.datatype.number({ min: 100, max: 10000 })
|
|
117
|
+
},
|
|
118
|
+
status: {
|
|
119
|
+
fillable: true,
|
|
120
|
+
default: 'draft',
|
|
121
|
+
validation: { rule: schema.enum(['draft', 'published', 'archived']) }
|
|
122
|
+
},
|
|
123
|
+
password: {
|
|
124
|
+
hidden: true, // excluded from JSON serialization
|
|
125
|
+
guarded: true, // not mass-assignable
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Computed properties (accessors)
|
|
130
|
+
get: {
|
|
131
|
+
fullName: (attrs) => `${attrs.first_name} ${attrs.last_name}`,
|
|
132
|
+
formattedPrice: (attrs) => `$${(attrs.price / 100).toFixed(2)}`
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// Mutators (setters)
|
|
136
|
+
set: {
|
|
137
|
+
email: (attrs) => attrs.email?.toLowerCase()
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
// Model hooks (lifecycle callbacks)
|
|
141
|
+
hooks: {
|
|
142
|
+
afterCreate: (model) => { /* ... */ },
|
|
143
|
+
afterUpdate: (model) => { /* ... */ },
|
|
144
|
+
afterDelete: (model) => { /* ... */ },
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
dashboard: { highlight: true } // highlight in admin dashboard
|
|
148
|
+
} as const)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### How defineModel() Works Internally
|
|
152
|
+
1. `buildEventHooks(definition)` -- if `traits.observe` is truthy, creates `afterCreate`/`afterUpdate`/`afterDelete` hooks that lazy-import `@stacksjs/events` and call `dispatch()`
|
|
153
|
+
2. Merges event hooks with any user-defined hooks
|
|
154
|
+
3. Calls `createModel(defWithHooks)` from bun-query-builder (provides typed query methods)
|
|
155
|
+
4. `buildTraitMethods(definition)` -- checks each trait flag and creates method objects
|
|
156
|
+
5. Returns `Object.assign(baseModel, traitMethods, definition)` + `getDefinition()` + `_isStacksModel`
|
|
157
|
+
|
|
158
|
+
## Transactions (transaction.ts)
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { transaction, savepoint, transactional } from '@stacksjs/orm'
|
|
162
|
+
|
|
163
|
+
// Basic transaction -- auto-commit on success, auto-rollback on error
|
|
164
|
+
const result = await transaction(async (tx) => {
|
|
165
|
+
await tx.insertInto('users').values({ name: 'John' }).execute()
|
|
166
|
+
await tx.insertInto('profiles').values({ user_id: 1 }).execute()
|
|
167
|
+
return 'success'
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
// With options
|
|
171
|
+
await transaction(callback, {
|
|
172
|
+
retries: 3,
|
|
173
|
+
isolation: 'serializable', // 'read committed' | 'repeatable read' | 'serializable'
|
|
174
|
+
readOnly: false,
|
|
175
|
+
onRollback: (error) => console.error(error),
|
|
176
|
+
afterRollback: () => { /* cleanup */ }
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Savepoints (nested transactions)
|
|
180
|
+
await transaction(async (tx) => {
|
|
181
|
+
await tx.insertInto('users').values({ name: 'Bob' }).execute()
|
|
182
|
+
await savepoint(async (sp) => {
|
|
183
|
+
await sp.insertInto('logs').values({ action: 'created' }).execute()
|
|
184
|
+
// If this fails, only this savepoint rolls back
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// Decorator-style -- wraps function to auto-run in transaction
|
|
189
|
+
const createUser = transactional(async (tx, name: string, email: string) => {
|
|
190
|
+
const user = await tx.insertInto('users').values({ name }).returningAll().executeTakeFirst()
|
|
191
|
+
await tx.insertInto('profiles').values({ user_id: user.id }).execute()
|
|
192
|
+
return user
|
|
193
|
+
})
|
|
194
|
+
await createUser('Alice', 'alice@example.com') // auto-wrapped
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Both `transaction()` and `savepoint()` delegate to `db.transaction()` and `db.savepoint()` from `@stacksjs/database`.
|
|
198
|
+
|
|
199
|
+
## Trait Methods (traits/)
|
|
200
|
+
|
|
201
|
+
### Taggable (when `traits.taggable: true`)
|
|
202
|
+
Uses `taggable` table with polymorphic `taggable_type` + `taggable_id` columns.
|
|
203
|
+
- `Model._taggable.tags(id: number): Promise<any[]>`
|
|
204
|
+
- `Model._taggable.tagCount(id: number): Promise<number>` -- uses `count(*)`
|
|
205
|
+
- `Model._taggable.addTag(id, { name, description? }): Promise<any>` -- auto-generates slug
|
|
206
|
+
- `Model._taggable.activeTags(id): Promise<any[]>` -- filters `is_active = true`
|
|
207
|
+
- `Model._taggable.inactiveTags(id): Promise<any[]>` -- filters `is_active = false`
|
|
208
|
+
- `Model._taggable.removeTag(id, tagId): Promise<void>`
|
|
209
|
+
|
|
210
|
+
### Categorizable (when `traits.categorizable: true`)
|
|
211
|
+
Uses `categorizable` + `categorizable_models` pivot table.
|
|
212
|
+
- `Model._categorizable.categories(id): Promise<any[]>` -- joins through pivot
|
|
213
|
+
- `Model._categorizable.categoryCount(id): Promise<number>`
|
|
214
|
+
- `Model._categorizable.addCategory(id, { name, description? }): Promise<any>` -- creates category if not exists, then links
|
|
215
|
+
- `Model._categorizable.activeCategories(id): Promise<any[]>`
|
|
216
|
+
- `Model._categorizable.inactiveCategories(id): Promise<any[]>`
|
|
217
|
+
- `Model._categorizable.removeCategory(id, categoryId): Promise<void>` -- removes pivot link
|
|
218
|
+
|
|
219
|
+
### Commentable (when `traits.commentables: true`)
|
|
220
|
+
Uses `comments` table with `commentables_id` + `commentables_type` columns.
|
|
221
|
+
- `Model._commentable.comments(id): Promise<any[]>`
|
|
222
|
+
- `Model._commentable.commentCount(id): Promise<number>`
|
|
223
|
+
- `Model._commentable.addComment(id, { title, body }): Promise<any>` -- status defaults to `'pending'`
|
|
224
|
+
- `Model._commentable.approvedComments(id): Promise<any[]>` -- status = `'approved'`
|
|
225
|
+
- `Model._commentable.pendingComments(id): Promise<any[]>` -- status = `'pending'`
|
|
226
|
+
- `Model._commentable.rejectedComments(id): Promise<any[]>` -- status = `'rejected'`
|
|
227
|
+
|
|
228
|
+
### Likeable (when `traits.likeable: true` or `{ table?, foreignKey? }`)
|
|
229
|
+
Table defaults to `{tableName}_likes`, FK defaults to `{singular}_id`.
|
|
230
|
+
- `Model._likeable.likes(id): Promise<any[]>`
|
|
231
|
+
- `Model._likeable.likeCount(id): Promise<number>`
|
|
232
|
+
- `Model._likeable.like(id, userId): Promise<any>`
|
|
233
|
+
- `Model._likeable.unlike(id, userId): Promise<void>`
|
|
234
|
+
- `Model._likeable.isLiked(id, userId): Promise<boolean>`
|
|
235
|
+
|
|
236
|
+
### Billable (when `traits.billable: true`) -- Stripe integration
|
|
237
|
+
All methods lazy-import `@stacksjs/payments`.
|
|
238
|
+
- `createStripeUser(model, options)`, `updateStripeUser(model, options)`, `deleteStripeUser(model)`
|
|
239
|
+
- `createOrGetStripeUser(model, options)`, `retrieveStripeUser(model)`
|
|
240
|
+
- `defaultPaymentMethod(model)`, `setDefaultPaymentMethod(model, pmId)`, `addPaymentMethod(model, paymentMethodId)`, `paymentMethods(model, cardType?)`
|
|
241
|
+
- `newSubscription(model, type, lookupKey, options)` -- returns `{ subscription, paymentIntent }`
|
|
242
|
+
- `updateSubscription(model, type, lookupKey, options)`, `cancelSubscription(model, providerId, options)`
|
|
243
|
+
- `activeSubscription(model)` -- queries `subscriptions` table for `provider_status = 'active'`, then retrieves from Stripe
|
|
244
|
+
- `checkout(model, priceIds[], options)` -- supports `enableTax`, `allowPromotions` options
|
|
245
|
+
- `createSetupIntent(model, options)`, `subscriptionHistory(model)`, `transactionHistory(model)`
|
|
246
|
+
|
|
247
|
+
### Two-Factor Auth (when `traits.useAuth.useTwoFactor: true`)
|
|
248
|
+
- `Model._twoFactor.generateTwoFactorForModel(model)` -- generates secret, calls `model.update()`
|
|
249
|
+
- `Model._twoFactor.verifyTwoFactorCode(model, code): Promise<boolean>`
|
|
250
|
+
|
|
251
|
+
## Auto-Generated System Fields
|
|
252
|
+
- `id` -- primary key (auto-increment)
|
|
253
|
+
- `created_at`, `updated_at` -- when `useTimestamps: true`
|
|
254
|
+
- `uuid` -- when `useUuid: true`
|
|
255
|
+
- `deleted_at` -- when soft deletes enabled
|
|
256
|
+
- `stripe_id` -- when `billable: true`
|
|
257
|
+
- `two_factor_secret`, `public_key` -- when `useAuth: { usePasskey: true }`
|
|
258
|
+
|
|
259
|
+
## Naming Conventions
|
|
260
|
+
- Model: PascalCase (`ProductVariant`)
|
|
261
|
+
- Table: snake_case plural (`product_variants`)
|
|
262
|
+
- Column: snake_case (`first_name`)
|
|
263
|
+
- Foreign key: `{singular_model}_id` (`user_id`)
|
|
264
|
+
- Pivot table: alphabetical sort of both table names (`category_product`)
|
|
265
|
+
|
|
266
|
+
## ORM Utility Types (model-types.ts)
|
|
267
|
+
```typescript
|
|
268
|
+
type Def<T> = T extends { getDefinition: () => infer D } ? D : never
|
|
269
|
+
type BelongsToForeignKeys<TDef> // extracts { modelname_id: number } from belongsTo array
|
|
270
|
+
type ModelRow<T> = ModelAttributes<Def<T>> & BelongsToForeignKeys<Def<T>>
|
|
271
|
+
type NewModelData<T> = Partial<InferModelAttributes<Def<T>> & BelongsToForeignKeys<Def<T>>>
|
|
272
|
+
type UpdateModelData<T> = Partial<InferModelAttributes<Def<T>> & BelongsToForeignKeys<Def<T>>>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## ORM Utility Functions (utils.ts)
|
|
276
|
+
- `modelTableName(model: Model | string): Promise<string>` -- uses `model.table` or converts `model.name` to snake_case plural
|
|
277
|
+
- `getModelName(model, modelPath): string` -- from definition or filename
|
|
278
|
+
- `getTableName(model, modelPath): TableNames` -- from definition or snake_case plural of name
|
|
279
|
+
- `getPivotTableName(modelA, modelB): string` -- alphabetical sort + join with `_`
|
|
280
|
+
- `getRelations(model, name): Promise<RelationConfig[]>` -- processes hasOne, hasMany, belongsTo, hasOneThrough, belongsToMany, morphOne
|
|
281
|
+
- `getHiddenAttributes(attrs): string[]` -- filters for `hidden: true`
|
|
282
|
+
- `getGuardedAttributes(model): string[]` -- filters for `guarded: true`, returns snake_case
|
|
283
|
+
- `getFillableAttributes(model, relations): string[]` -- filters for `fillable: true`, adds FK columns, stripe_id, uuid, etc.
|
|
284
|
+
- `extractFields(model, file): Promise<ModelElement[]>` -- parses model file for field metadata
|
|
285
|
+
- `findCoreModel(name): string` -- searches `storage/framework/defaults/app/Models/` recursively
|
|
286
|
+
- `findUserModel(name): string` -- searches `app/Models/`
|
|
287
|
+
- `fetchOtherModelRelations(modelName?): Promise<RelationConfig[]>` -- scans all models for relations pointing to this model
|
|
288
|
+
- `formatDate(date): string` -- ISO format `YYYY-MM-DD HH:MM:SS`
|
|
289
|
+
|
|
290
|
+
## Relationship Processing (utils.ts)
|
|
291
|
+
Each relationship type is processed into a `RelationConfig` object:
|
|
292
|
+
- **hasOne / hasMany**: FK = `{parent_snake}_id`, model key = `{related_snake}_id`
|
|
293
|
+
- **belongsTo**: FK is empty string (set on the owning model's side), supports custom `foreignKey`
|
|
294
|
+
- **belongsToMany**: auto-creates pivot table name via `getPivotTableName()`, supports `pivotTable`, `firstForeignKey`, `secondForeignKey` overrides
|
|
295
|
+
- **hasOneThrough**: includes `throughModel` and `throughForeignKey`
|
|
296
|
+
- **morphOne**: uses `{modelName}able` pattern, generates `_type` and `_id` columns
|
|
297
|
+
|
|
298
|
+
## Model Events (when `traits.observe: true`)
|
|
299
|
+
`observe: true` emits all three events. `observe: ['create', 'update']` emits only those.
|
|
300
|
+
- `'{modelname}:created'` -- via `afterCreate` hook, lazy-imports `@stacksjs/events`
|
|
301
|
+
- `'{modelname}:updated'` -- via `afterUpdate` hook
|
|
302
|
+
- `'{modelname}:deleted'` -- via `afterDelete` hook
|
|
303
|
+
|
|
304
|
+
If `@stacksjs/events` is not available (browser, tests), errors are caught and silently ignored.
|
|
305
|
+
|
|
306
|
+
## Stub Types in index.ts
|
|
307
|
+
The ORM exports stub types for commonly used models to keep typecheck green before code generation:
|
|
308
|
+
- `UserModel`, `NewUser`, `User` (class stub with static `where`, `find`, `create`, `all`)
|
|
309
|
+
- `Job`, `FailedJob` (query stubs)
|
|
310
|
+
- `PaymentMethod` (CRUD stubs)
|
|
311
|
+
- `CategorizableTable`, `CategorizableModelsTable`, `CommentablesTable`, `TaggableTable`
|
|
312
|
+
|
|
313
|
+
## All 50+ Framework Models
|
|
314
|
+
Content: Author, Page, Post, Comment, Tag, Category
|
|
315
|
+
Users: User, Customer, Driver, Subscriber, SubscriberEmail
|
|
316
|
+
Commerce: Product, ProductVariant, ProductUnit, Cart, CartItem, Order, OrderItem, Coupon, GiftCard, Manufacturer, Review, LicenseKey, DigitalDelivery, WaitlistProduct, WaitlistRestaurant
|
|
317
|
+
Payments: Payment, PaymentMethod, PaymentProduct, PaymentTransaction, Subscription, Transaction, Receipt
|
|
318
|
+
Shipping: ShippingMethod, ShippingRate, ShippingZone, DeliveryRoute
|
|
319
|
+
Loyalty: LoyaltyPoint, LoyaltyReward, TaxRate
|
|
320
|
+
System: Job, FailedJob, Error, Log, Notification, Activity, Request, Websocket, PrintDevice
|
|
321
|
+
Marketing: Campaign, EmailList, SocialPost
|
|
322
|
+
|
|
323
|
+
## CLI Commands
|
|
324
|
+
- `buddy make:migration` -- create migration for model changes
|
|
325
|
+
- `buddy generate:migrations` -- generate migrations from model diffs
|
|
326
|
+
- `buddy migrate` -- run pending migrations
|
|
327
|
+
|
|
328
|
+
## Gotchas
|
|
329
|
+
- Models work directly via the dynamic ORM — no code generation step needed
|
|
330
|
+
- `defineModel()` calls `createModel()` from bun-query-builder at runtime, providing all typed query methods immediately
|
|
331
|
+
- Two ORM locations: `storage/framework/core/orm/` (package) and `storage/framework/orm/` (implementation)
|
|
332
|
+
- Factories use `@stacksjs/faker` -- each attribute can have a `factory` function
|
|
333
|
+
- The `hidden` attribute flag excludes fields from JSON serialization (e.g., passwords)
|
|
334
|
+
- The `guarded` flag prevents mass assignment
|
|
335
|
+
- The `fillable` flag explicitly allows mass assignment
|
|
336
|
+
- Pivot tables for belongsToMany are auto-created using alphabetical naming of both table names
|
|
337
|
+
- Model events are only emitted when `observe: true` (or array) trait is set
|
|
338
|
+
- The trait key for commentable is `commentables` (with 's'), not `commentable`
|
|
339
|
+
- Trait methods are accessed via underscore-prefixed properties: `_taggable`, `_categorizable`, `_commentable`, `_billable`, `_likeable`, `_twoFactor`
|
|
340
|
+
- The `useAuth.useTwoFactor` check (not `usePasskey`) determines if two-factor methods are added
|
|
341
|
+
- `defineModel()` calls `createModel()` from bun-query-builder which returns the typed query builder interface at runtime
|
|
342
|
+
- Model file loading uses `findUserModel()` (app/Models/) with fallback to `findCoreModel()` (storage/framework/defaults/app/Models/)
|