@stacksjs/defaults 0.70.207 → 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,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-routes
|
|
3
|
+
description: Use when defining or organizing route files in a Stacks application — creating route files in routes/, registering them in app/Routes.ts, using route prefixes and middleware groups, or the default API routes structure. For the router API itself (request helpers, response helpers, middleware classes), see stacks-router.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Stacks Route Definitions
|
|
10
|
+
|
|
11
|
+
How to define and organize routes in a Stacks application.
|
|
12
|
+
|
|
13
|
+
## Key Paths
|
|
14
|
+
- Route files: `routes/` (api.ts, v1.ts, buddy.ts, users.ts)
|
|
15
|
+
- Route registry: `app/Routes.ts`
|
|
16
|
+
|
|
17
|
+
## Route Registry (app/Routes.ts)
|
|
18
|
+
|
|
19
|
+
Maps route files to URL prefixes:
|
|
20
|
+
```typescript
|
|
21
|
+
export default {
|
|
22
|
+
'api': 'api', // routes/api.ts → /api/* (auto-prefixed; see #1835)
|
|
23
|
+
'v1': { path: 'v1', prefix: 'v1' }, // routes/v1.ts → /v1/*
|
|
24
|
+
'admin': { path: 'admin', prefix: 'admin', middleware: ['auth'] }
|
|
25
|
+
} satisfies Record<string, string | RouteDefinition>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Creating a Route File
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// routes/api.ts
|
|
32
|
+
import { route } from '@stacksjs/router'
|
|
33
|
+
|
|
34
|
+
route.get('/users', 'Actions/ListUsers')
|
|
35
|
+
route.post('/users', 'Actions/CreateUser')
|
|
36
|
+
route.get('/users/{id}', 'Actions/ShowUser')
|
|
37
|
+
route.put('/users/{id}', 'Actions/UpdateUser')
|
|
38
|
+
route.delete('/users/{id}', 'Actions/DeleteUser')
|
|
39
|
+
|
|
40
|
+
// With inline handler
|
|
41
|
+
route.get('/health', (req) => Response.json({ status: 'ok' }))
|
|
42
|
+
|
|
43
|
+
// Groups
|
|
44
|
+
route.group({ prefix: '/admin', middleware: ['auth'] }, () => {
|
|
45
|
+
route.get('/dashboard', 'Actions/Dashboard')
|
|
46
|
+
route.get('/settings', 'Actions/Settings')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// Health check
|
|
50
|
+
route.health()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Default API Routes (routes/api.ts)
|
|
54
|
+
|
|
55
|
+
### Authentication
|
|
56
|
+
- `POST /login` → LoginAction
|
|
57
|
+
- `POST /register` → RegisterAction
|
|
58
|
+
- `POST /auth/refresh` → RefreshTokenAction
|
|
59
|
+
- `GET /me` → GetMeAction (auth)
|
|
60
|
+
- `POST /logout` → LogoutAction (auth)
|
|
61
|
+
|
|
62
|
+
### Email
|
|
63
|
+
- `POST /api/email/subscribe`
|
|
64
|
+
- `GET /api/email/unsubscribe`
|
|
65
|
+
|
|
66
|
+
### AI
|
|
67
|
+
- `POST /ai/ask`, `POST /ai/summary`
|
|
68
|
+
|
|
69
|
+
### CMS & Commerce
|
|
70
|
+
- `/cms/posts/*`, `/cms/authors/*`, `/cms/categories/*`, `/cms/tags/*`
|
|
71
|
+
- `/commerce/products/*`, `/commerce/orders/*`, `/commerce/customers/*`
|
|
72
|
+
|
|
73
|
+
### Health
|
|
74
|
+
- `GET /health` — status, uptime, memory, PID, Bun version
|
|
75
|
+
|
|
76
|
+
## Versioned Routes (routes/v1.ts)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// routes/v1.ts — prefixed with /v1
|
|
80
|
+
route.get('/users', 'Actions/V1/ListUsers')
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Handler Types
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// 1. Action string (auto-loaded from app/Actions/)
|
|
87
|
+
route.get('/users', 'Actions/ListUsers')
|
|
88
|
+
|
|
89
|
+
// 2. Controller method
|
|
90
|
+
route.get('/users', 'Controllers/UserController@index')
|
|
91
|
+
|
|
92
|
+
// 3. Inline function
|
|
93
|
+
route.get('/ping', (req) => Response.json({ pong: true }))
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## CLI Commands
|
|
97
|
+
- `buddy route:list` — list all registered routes
|
|
98
|
+
|
|
99
|
+
## Gotchas
|
|
100
|
+
- Route files must be registered in `app/Routes.ts` to be loaded
|
|
101
|
+
- String handlers (Actions/X) are dynamically imported at request time
|
|
102
|
+
- Route order matters — first match wins
|
|
103
|
+
- Use groups for shared middleware instead of repeating on each route
|
|
104
|
+
- The `health()` helper registers `GET /health` automatically
|
|
105
|
+
- For the router API (request helpers, middleware, responses), see the `stacks-router` skill
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-scaffolding
|
|
3
|
+
description: Use when generating new code with Stacks — buddy make commands, project scaffolding, component/page/store/layout generation, or project templates. Covers buddy make:* commands and STX scaffolding utilities.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Stacks Scaffolding
|
|
10
|
+
|
|
11
|
+
## Key Paths
|
|
12
|
+
- Buddy commands: `storage/framework/core/buddy/src/commands/make.ts`
|
|
13
|
+
- Default templates: `storage/framework/defaults/`
|
|
14
|
+
- STX scaffolding: `@stacksjs/stx` (scaffolding module)
|
|
15
|
+
|
|
16
|
+
## CLI Make Commands
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
buddy make:component <name> # Create a new STX component
|
|
20
|
+
buddy make:function <name> # Create a new function/composable
|
|
21
|
+
buddy make:migration <name> # Create a new database migration
|
|
22
|
+
buddy make:notification <name> # Create a notification class
|
|
23
|
+
buddy make:factory <name> # Create a model factory
|
|
24
|
+
buddy make:lang <name> # Create a language/locale file
|
|
25
|
+
buddy make:stack <name> # Create a new stack
|
|
26
|
+
buddy extension:init # Create a Chrome + Firefox + Safari extension
|
|
27
|
+
buddy extension:init --target safari --bundle-id com.example.Extension
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## STX Scaffolding API
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createProject, addComponent, addPage, addStore, addLayout } from '@stacksjs/stx'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Create Project
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
async function createProject(name: string, options?: CreateProjectOptions): Promise<ScaffoldResult>
|
|
40
|
+
|
|
41
|
+
interface CreateProjectOptions {
|
|
42
|
+
template?: 'default' | 'minimal' | 'full' | 'blog' | 'dashboard' | 'landing'
|
|
43
|
+
skipGit?: boolean
|
|
44
|
+
skipInstall?: boolean
|
|
45
|
+
packageManager?: 'bun' | 'npm' | 'pnpm' | 'yarn'
|
|
46
|
+
typescript?: boolean
|
|
47
|
+
examples?: boolean
|
|
48
|
+
pwa?: boolean
|
|
49
|
+
tailwind?: boolean
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Add Component
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
async function addComponent(name: string, options?: AddComponentOptions): Promise<ScaffoldResult>
|
|
57
|
+
|
|
58
|
+
interface AddComponentOptions {
|
|
59
|
+
dir?: string // Custom directory (default: componentsDir)
|
|
60
|
+
props?: boolean // Include props section
|
|
61
|
+
styles?: boolean // Include style block
|
|
62
|
+
script?: boolean // Include script block
|
|
63
|
+
force?: boolean // Overwrite existing
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Add Page
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
async function addPage(name: string, options?: AddPageOptions): Promise<ScaffoldResult>
|
|
71
|
+
|
|
72
|
+
interface AddPageOptions {
|
|
73
|
+
dir?: string // Custom directory
|
|
74
|
+
layout?: string // Layout to use
|
|
75
|
+
dynamic?: boolean // Dynamic route parameter
|
|
76
|
+
loader?: boolean // Include data loader
|
|
77
|
+
force?: boolean
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Add Store
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
async function addStore(name: string, options?: AddStoreOptions): Promise<ScaffoldResult>
|
|
85
|
+
|
|
86
|
+
interface AddStoreOptions {
|
|
87
|
+
dir?: string
|
|
88
|
+
persist?: boolean // Persist state to storage
|
|
89
|
+
actions?: boolean // Include action methods
|
|
90
|
+
force?: boolean
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Add Layout
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
async function addLayout(name: string, options?: AddLayoutOptions): Promise<ScaffoldResult>
|
|
98
|
+
|
|
99
|
+
interface AddLayoutOptions {
|
|
100
|
+
dir?: string
|
|
101
|
+
nav?: boolean // Include navigation
|
|
102
|
+
footer?: boolean // Include footer
|
|
103
|
+
force?: boolean
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Scaffold Result
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
interface ScaffoldResult {
|
|
111
|
+
success: boolean
|
|
112
|
+
message: string
|
|
113
|
+
files: string[] // Created file paths
|
|
114
|
+
errors: string[]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Project Templates
|
|
119
|
+
|
|
120
|
+
| Template | Description |
|
|
121
|
+
|----------|-------------|
|
|
122
|
+
| `default` | Standard project with common features |
|
|
123
|
+
| `minimal` | Bare minimum setup |
|
|
124
|
+
| `full` | All features enabled |
|
|
125
|
+
| `blog` | Blog-focused with CMS |
|
|
126
|
+
| `dashboard` | Admin dashboard |
|
|
127
|
+
| `landing` | Marketing landing page |
|
|
128
|
+
|
|
129
|
+
## Generated File Locations
|
|
130
|
+
|
|
131
|
+
| Type | Location |
|
|
132
|
+
|------|----------|
|
|
133
|
+
| Components | `resources/components/` |
|
|
134
|
+
| Functions | `resources/functions/` |
|
|
135
|
+
| Migrations | `database/migrations/` |
|
|
136
|
+
| Notifications | `app/Notifications/` |
|
|
137
|
+
| Language files | `locales/` |
|
|
138
|
+
| Layouts | `resources/layouts/` |
|
|
139
|
+
| Pages | `resources/views/` |
|
|
140
|
+
| Stores | `storage/framework/defaults/stores/` |
|
|
141
|
+
| Partials | `resources/partials/` |
|
|
142
|
+
|
|
143
|
+
Browser-extension scaffolding also follows this resource layout: popup pages
|
|
144
|
+
live in `resources/views/`, browser scripts in `resources/scripts/`, and shared
|
|
145
|
+
includes in `resources/partials/`. Safari scaffolding creates the Xcode
|
|
146
|
+
container app alongside the web-extension starter.
|
|
147
|
+
|
|
148
|
+
## Default Templates
|
|
149
|
+
|
|
150
|
+
Templates for generated code are in `storage/framework/defaults/`:
|
|
151
|
+
- `defaults/components/` — component templates
|
|
152
|
+
- `defaults/models/` — model templates
|
|
153
|
+
- `defaults/app/Middleware/` — middleware templates
|
|
154
|
+
- `defaults/layouts/` — layout templates
|
|
155
|
+
- `defaults/views/` — view templates
|
|
156
|
+
|
|
157
|
+
## Gotchas
|
|
158
|
+
- **Always use make commands** — ensures consistent file structure and naming
|
|
159
|
+
- **Templates are customizable** — modify files in `storage/framework/defaults/` to change scaffolding output
|
|
160
|
+
- **Run pickier after generating** — `bunx --bun pickier . --fix` to format generated code
|
|
161
|
+
- **`force` flag overwrites** — without it, existing files are not overwritten
|
|
162
|
+
- **STX scaffolding vs buddy make** — `addComponent()` is the programmatic API, `buddy make:component` is the CLI equivalent
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-scheduler
|
|
3
|
+
description: Use when scheduling tasks in a Stacks application — defining scheduled tasks, cron-like scheduling, or task automation. Covers @stacksjs/scheduler, @stacksjs/cron, and app/Scheduler.ts.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Stacks Scheduler
|
|
10
|
+
|
|
11
|
+
The `@stacksjs/scheduler` package provides fluent, chainable task scheduling for Stacks applications. It wraps `@stacksjs/cron` for cron expression parsing and supports scheduling jobs, actions, and shell commands with timezone awareness, overlap prevention, and background execution.
|
|
12
|
+
|
|
13
|
+
## Key Paths
|
|
14
|
+
- Scheduler package: `storage/framework/core/scheduler/src/`
|
|
15
|
+
- Cron package: `storage/framework/core/cron/src/`
|
|
16
|
+
- Application scheduler: `app/Scheduler.ts`
|
|
17
|
+
- CLI command: `storage/framework/core/buddy/src/commands/schedule.ts`
|
|
18
|
+
- Run action: `storage/framework/core/actions/src/schedule/run.ts`
|
|
19
|
+
- Queue-based scheduler: `storage/framework/core/queue/src/scheduler.ts`
|
|
20
|
+
- Job types / `Every` enum: `storage/framework/core/types/src/cron-jobs.ts`
|
|
21
|
+
- Lock files: `storage/framework/locks/` (created at runtime)
|
|
22
|
+
|
|
23
|
+
## Source Files
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
scheduler/src/
|
|
27
|
+
├── index.ts # Re-exports everything from run, schedule, types
|
|
28
|
+
├── schedule.ts # Schedule class, Queue alias, sendAt(), timeout()
|
|
29
|
+
├── run.ts # runScheduler() — loads Jobs/*.ts + app/Scheduler.ts
|
|
30
|
+
└── types.ts # Timezone union, ScheduledJob, UntimedSchedule, TimedSchedule, BaseSchedule
|
|
31
|
+
|
|
32
|
+
cron/src/
|
|
33
|
+
├── index.ts # parse(), register(), remove() — delegates to Bun.cron or parseCron
|
|
34
|
+
├── parser.ts # parseCron() — native 5-field cron parser with POSIX OR logic
|
|
35
|
+
├── types.ts # CatchCallbackFn, ProtectCallbackFn, IntRange
|
|
36
|
+
└── bun-cron.d.ts # Bun.cron type declarations
|
|
37
|
+
|
|
38
|
+
queue/src/
|
|
39
|
+
└── scheduler.ts # startScheduler(), stopScheduler(), getSchedulerStatus() — queue-level scheduler
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Schedule Class (schedule.ts)
|
|
43
|
+
|
|
44
|
+
The `Schedule` class is the core scheduling API. The lowercase `schedule` export is an alias for the class itself (used as a static-method namespace).
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { schedule } from '@stacksjs/scheduler'
|
|
48
|
+
|
|
49
|
+
// Static factory methods — each returns UntimedSchedule
|
|
50
|
+
schedule.job(name: string): UntimedSchedule // Runs a job by name via runJob()
|
|
51
|
+
schedule.action(name: string): UntimedSchedule // Runs an action by name via runAction()
|
|
52
|
+
schedule.command(cmd: string): UntimedSchedule // Runs a shell command via runCommand()
|
|
53
|
+
|
|
54
|
+
// Graceful shutdown — stops all tracked jobs
|
|
55
|
+
schedule.gracefulShutdown(): Promise<void>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Constructor
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
new Schedule(task: () => void)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The constructor accepts a task function and auto-starts the schedule via `setTimeout(() => this.start(), 0)` after all chained methods have been called in the current tick.
|
|
65
|
+
|
|
66
|
+
### Timing Methods (returns TimedSchedule)
|
|
67
|
+
|
|
68
|
+
Each sets an internal cron pattern. Once a timing method is called, the schedule is "timed" and only configuration methods remain available.
|
|
69
|
+
|
|
70
|
+
| Method | Cron Pattern | Notes |
|
|
71
|
+
|------------------------|--------------------|-----------------------------|
|
|
72
|
+
| `everySecond()` | `@every_second` | Uses `setInterval(1000)`, not cron |
|
|
73
|
+
| `everyMinute()` | `* * * * *` | |
|
|
74
|
+
| `everyTwoMinutes()` | `*/2 * * * *` | |
|
|
75
|
+
| `everyFiveMinutes()` | `*/5 * * * *` | |
|
|
76
|
+
| `everyTenMinutes()` | `*/10 * * * *` | |
|
|
77
|
+
| `everyThirtyMinutes()` | `*/30 * * * *` | |
|
|
78
|
+
| `everyHour()` / `hourly()` | `0 * * * *` | |
|
|
79
|
+
| `everyDay()` / `daily()` | `0 0 * * *` | |
|
|
80
|
+
| `weekly()` | `0 0 * * 0` | Sunday at midnight |
|
|
81
|
+
| `monthly()` | `0 0 1 * *` | 1st of month at midnight |
|
|
82
|
+
| `yearly()` / `annually()` | `0 0 1 1 *` | Jan 1 at midnight |
|
|
83
|
+
| `onDays(days: number[])` | `0 0 * * {days}` | e.g. `onDays([1,3,5])` => `0 0 * * 1,3,5` |
|
|
84
|
+
| `at(time: string)` | `{min} {hr} * * *` | e.g. `at('14:30')` => `30 14 * * *` |
|
|
85
|
+
|
|
86
|
+
### Configuration Methods (chainable, returns `this`)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
setTimeZone(timezone: Timezone): this
|
|
90
|
+
withErrorHandler(handler: CatchCallbackFn): this
|
|
91
|
+
withMaxRuns(runs: number): this
|
|
92
|
+
withProtection(callback?: (job: ScheduledJob) => void): this
|
|
93
|
+
withName(name: string): this
|
|
94
|
+
withContext(context: any): this
|
|
95
|
+
withInterval(seconds: number): this
|
|
96
|
+
between(startAt: string | Date, stopAt: string | Date): this
|
|
97
|
+
withoutOverlapping(expiresAfterMinutes?: number): this
|
|
98
|
+
onOneServer(): this
|
|
99
|
+
runInBackground(): this
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### ScheduledJob Interface
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
interface ScheduledJob {
|
|
106
|
+
stop: () => void
|
|
107
|
+
nextRun: () => Date | null
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Timezone Type
|
|
112
|
+
|
|
113
|
+
The `Timezone` type is a string union of ~70 IANA timezone identifiers (e.g., `'America/New_York'`, `'Europe/Berlin'`, `'Asia/Tokyo'`, `'UTC'`). Default is `'America/Los_Angeles'`.
|
|
114
|
+
|
|
115
|
+
### Internal Scheduling Engine
|
|
116
|
+
|
|
117
|
+
- **Sub-minute** (`everySecond`): Uses `setInterval` with the configured `intervalMs`.
|
|
118
|
+
- **Minute+**: Uses `parse()` from `@stacksjs/cron` to compute the next run time, then `setTimeout` to fire at the right moment. When the delay exceeds `2^31-1 ms` (~24.8 days), it chains shorter timeouts.
|
|
119
|
+
- **Timezone-aware**: Converts "now" to the configured timezone via `toLocaleString()`, parses the cron pattern from that local time, then computes the real-world delay.
|
|
120
|
+
- **maxRuns**: Tracks `runCount` and calls `stop()` when the limit is reached.
|
|
121
|
+
- **Error handling**: If `options.catch` is set, errors are caught and passed to the handler instead of propagating.
|
|
122
|
+
|
|
123
|
+
### Overlap Prevention and Locking
|
|
124
|
+
|
|
125
|
+
When `withoutOverlapping()` or `onOneServer()` is called:
|
|
126
|
+
1. Lock files are created in `storage/framework/locks/{taskName}.lock`
|
|
127
|
+
2. The lock directory is created automatically if missing
|
|
128
|
+
3. Lock files use exclusive write (`flag: 'wx'`) for atomicity
|
|
129
|
+
4. Stale locks expire after `overlapExpiresAfterMinutes` (default: 1440 = 24 hours)
|
|
130
|
+
5. Lock age is checked via file `mtime`
|
|
131
|
+
6. Locks are released in a `finally` block (or `.finally()` for async tasks)
|
|
132
|
+
|
|
133
|
+
### Background Execution
|
|
134
|
+
|
|
135
|
+
When `runInBackground()` is called, the task is spawned as a detached child process via `node:child_process.spawn`. The child is `unref()`'d so it does not keep the parent alive.
|
|
136
|
+
|
|
137
|
+
## Helper Functions
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { sendAt, timeout } from '@stacksjs/scheduler'
|
|
141
|
+
|
|
142
|
+
// Get the next Date a cron expression will fire
|
|
143
|
+
sendAt(cronExpression: string | Date): Date | null
|
|
144
|
+
// - String: delegates to parse() from @stacksjs/cron
|
|
145
|
+
// - Date: returns the date if it's in the future, null otherwise
|
|
146
|
+
|
|
147
|
+
// Get milliseconds until the next fire time
|
|
148
|
+
timeout(cronExpression: string | Date): number
|
|
149
|
+
// Returns -1 if no upcoming run
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Cron Parser (@stacksjs/cron)
|
|
153
|
+
|
|
154
|
+
### parse()
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { parse } from '@stacksjs/cron'
|
|
158
|
+
|
|
159
|
+
parse(expression: string, relativeDate?: Date | number): Date | null
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- Uses `Bun.cron.parse()` when available (native Bun cron support), otherwise falls back to the built-in `parseCron()` implementation.
|
|
163
|
+
- Returns the next matching UTC `Date`, or `null` if no match within ~4 years.
|
|
164
|
+
- Throws on invalid expressions (wrong field count, out-of-range values).
|
|
165
|
+
|
|
166
|
+
### parseCron() (built-in parser)
|
|
167
|
+
|
|
168
|
+
Supports the standard 5-field format: `minute hour dayOfMonth month dayOfWeek`
|
|
169
|
+
|
|
170
|
+
**Operators**: `*` (all), `,` (list), `-` (range), `/` (step)
|
|
171
|
+
**Named values**: `JAN`-`DEC`, `SUN`-`SAT` (case-insensitive, full names also accepted)
|
|
172
|
+
**Nicknames**: `@yearly`, `@annually`, `@monthly`, `@weekly`, `@daily`, `@midnight`, `@hourly`
|
|
173
|
+
**POSIX OR logic**: When both dayOfMonth and dayOfWeek are specified (neither is `*`), the expression matches when *either* condition is true.
|
|
174
|
+
|
|
175
|
+
### OS-Level Cron Registration
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { register, remove } from '@stacksjs/cron'
|
|
179
|
+
|
|
180
|
+
// Register a persistent OS-level cron job (requires Bun.cron native support)
|
|
181
|
+
await register(path: string, schedule: string, title: string)
|
|
182
|
+
|
|
183
|
+
// Remove a registered cron job by title
|
|
184
|
+
await remove(title: string)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
These require Bun's native cron support (crontab on Linux, launchd on macOS, schtasks on Windows). The target script must export a `scheduled(controller)` handler.
|
|
188
|
+
|
|
189
|
+
## Every Enum (cron-jobs.ts)
|
|
190
|
+
|
|
191
|
+
The `Every` enum maps human-readable intervals to cron expressions. Used in Job `rate` fields.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { Every } from '@stacksjs/types'
|
|
195
|
+
|
|
196
|
+
Every.Second // '* * * * * *' (6-field, sub-minute)
|
|
197
|
+
Every.FiveSeconds // '*/5 * * * * *'
|
|
198
|
+
Every.TenSeconds // '*/10 * * * * *'
|
|
199
|
+
Every.ThirtySeconds // '*/30 * * * * *'
|
|
200
|
+
Every.Minute // '* * * * *'
|
|
201
|
+
Every.TwoMinutes // '*/2 * * * *'
|
|
202
|
+
Every.FiveMinutes // '*/5 * * * *'
|
|
203
|
+
Every.TenMinutes // '*/10 * * * *'
|
|
204
|
+
Every.FifteenMinutes // '*/15 * * * *'
|
|
205
|
+
Every.ThirtyMinutes // '*/30 * * * *'
|
|
206
|
+
Every.Hour // '0 * * * *'
|
|
207
|
+
Every.HalfHour // '0,30 * * * *'
|
|
208
|
+
Every.Day // '0 0 * * *'
|
|
209
|
+
Every.Week // '0 0 * * 0'
|
|
210
|
+
Every.Weekday // '0 0 * * 1-5'
|
|
211
|
+
Every.Weekend // '0 0 * * 0,6'
|
|
212
|
+
Every.Month // '0 0 1 * *'
|
|
213
|
+
Every.Year // '0 0 1 1 *'
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## runScheduler() (run.ts)
|
|
217
|
+
|
|
218
|
+
The entry point for starting the scheduler process:
|
|
219
|
+
|
|
220
|
+
1. Globs `app/Jobs/*.ts` for job files
|
|
221
|
+
2. For each job with a `rate` property, maps the rate to a schedule method via `executeJobRate()` (switch on `Every.*` values)
|
|
222
|
+
3. Job names are derived from `job.name` or the filename, then `snakeCase()`'d
|
|
223
|
+
4. Imports and calls the default export from `app/Scheduler.ts`
|
|
224
|
+
5. Returns `Ok<string>` on success
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { runScheduler } from '@stacksjs/scheduler'
|
|
228
|
+
const result = await runScheduler()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Queue-Level Scheduler (queue/src/scheduler.ts)
|
|
232
|
+
|
|
233
|
+
A separate, queue-integrated scheduler that discovers jobs and dispatches them to the queue system:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { startScheduler, stopScheduler, getSchedulerStatus, triggerJob } from '@stacksjs/queue'
|
|
237
|
+
|
|
238
|
+
await startScheduler(config?: Partial<SchedulerConfig>)
|
|
239
|
+
await stopScheduler()
|
|
240
|
+
getSchedulerStatus(): { isRunning, jobCount, jobs[] }
|
|
241
|
+
isSchedulerRunning(): boolean
|
|
242
|
+
getRegisteredJobs(): Map<string, ScheduledJobState>
|
|
243
|
+
await triggerJob(name: string) // Manually dispatch a scheduled job
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### SchedulerConfig
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
interface SchedulerConfig {
|
|
250
|
+
checkInterval: number // ms between checks (default: 60000)
|
|
251
|
+
timezone?: string
|
|
252
|
+
preventOverlapping: boolean // default: true
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
This scheduler polls on `checkInterval`, uses its own `shouldRunNow()` cron matcher (supports 5- and 6-field expressions), and dispatches jobs to the queue via `storeJob()` and `emitQueueEvent()`.
|
|
257
|
+
|
|
258
|
+
## app/Scheduler.ts
|
|
259
|
+
|
|
260
|
+
User-defined scheduled tasks live here. Must export a default function:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { schedule } from '@stacksjs/scheduler'
|
|
264
|
+
|
|
265
|
+
export default function () {
|
|
266
|
+
schedule.job('Inspire').hourly().setTimeZone('America/Los_Angeles')
|
|
267
|
+
schedule.action('CleanupTempFiles').everyFiveMinutes()
|
|
268
|
+
schedule.command('echo "maintenance"').daily()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Graceful shutdown on SIGINT
|
|
272
|
+
process.on('SIGINT', () => {
|
|
273
|
+
schedule.gracefulShutdown().then(() => process.exit(0))
|
|
274
|
+
})
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## CLI Commands
|
|
278
|
+
|
|
279
|
+
- `buddy schedule:run` -- Runs `Action.ScheduleRun`, which calls `runScheduler()`
|
|
280
|
+
- Options: `-p, --project [project]`, `--verbose`
|
|
281
|
+
|
|
282
|
+
## Code Examples
|
|
283
|
+
|
|
284
|
+
### Schedule a job with overlap prevention
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
schedule
|
|
288
|
+
.job('ProcessPayments')
|
|
289
|
+
.everyFiveMinutes()
|
|
290
|
+
.withoutOverlapping(30) // Lock expires after 30 minutes
|
|
291
|
+
.setTimeZone('America/New_York')
|
|
292
|
+
.withErrorHandler((err) => console.error('Payment processing failed:', err))
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Schedule a command with max runs
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
schedule
|
|
299
|
+
.command('bun run cleanup')
|
|
300
|
+
.daily()
|
|
301
|
+
.withMaxRuns(7) // Stop after 7 executions
|
|
302
|
+
.withName('weekly-cleanup')
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Schedule on specific days
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
schedule
|
|
309
|
+
.action('SendWeeklyReport')
|
|
310
|
+
.onDays([1, 3, 5]) // Mon, Wed, Fri at midnight
|
|
311
|
+
.setTimeZone('Europe/London')
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Schedule at a specific time
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
schedule
|
|
318
|
+
.job('DailyDigest')
|
|
319
|
+
.at('09:00') // 9 AM daily
|
|
320
|
+
.setTimeZone('Asia/Tokyo')
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Query next run time
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { sendAt, timeout } from '@stacksjs/scheduler'
|
|
327
|
+
|
|
328
|
+
const nextRun = sendAt('*/15 * * * *') // Next 15-min mark
|
|
329
|
+
const msUntil = timeout('0 0 * * *') // ms until next midnight
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Job with rate-based scheduling
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
// app/Jobs/CleanupExpiredSessions.ts
|
|
336
|
+
import { Every } from '@stacksjs/types'
|
|
337
|
+
|
|
338
|
+
export default {
|
|
339
|
+
name: 'CleanupExpiredSessions',
|
|
340
|
+
rate: Every.Hour,
|
|
341
|
+
handle: async () => {
|
|
342
|
+
// cleanup logic
|
|
343
|
+
},
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Gotchas
|
|
348
|
+
- The `Schedule` constructor auto-starts via `setTimeout(0)` -- all chained methods must be called synchronously in the same tick, or the schedule starts with incomplete configuration
|
|
349
|
+
- Default timezone is `'America/Los_Angeles'`, not UTC
|
|
350
|
+
- `everySecond()` uses `setInterval`, not cron -- it sets `intervalMs = 1000` and bypasses the cron parser entirely
|
|
351
|
+
- The `Queue` class in `schedule.ts` is just an empty subclass of `Schedule` (`export class Queue extends Schedule {}`) -- it adds no functionality
|
|
352
|
+
- `withoutOverlapping()` uses file-based locks in `storage/framework/locks/` -- this only prevents overlap within a single machine, not across a cluster
|
|
353
|
+
- `onOneServer()` also uses file-based locks (same as `withoutOverlapping`), so it does not actually coordinate across multiple servers
|
|
354
|
+
- `runInBackground()` spawns a detached child process with `spawn(process.execPath, ['-e', ...])` -- the task function is `.toString()`'d and eval'd, so closures over external variables will not work
|
|
355
|
+
- There are TWO scheduler systems: `@stacksjs/scheduler` (fluent API in `schedule.ts`) and the queue-level scheduler in `@stacksjs/queue` (`queue/src/scheduler.ts`). The former runs tasks in-process; the latter dispatches to the queue
|
|
356
|
+
- `sendAt()` throws on invalid cron expressions (it delegates to `parse()` which throws)
|
|
357
|
+
- `timeout()` returns `-1` (not `0` or `Infinity`) when there is no upcoming run
|
|
358
|
+
- The `Every.Second/FiveSeconds/TenSeconds/ThirtySeconds` enum values use 6-field cron (with seconds), but the `@stacksjs/cron` parser only supports 5-field expressions -- the queue scheduler's `parseScheduleString()` maps sub-minute intervals to `'* * * * *'` (every minute)
|
|
359
|
+
- `runScheduler()` silently catches and logs errors when individual job files fail to import -- a broken job file does not prevent other jobs from being scheduled
|
|
360
|
+
- Named jobs via `withName()` are tracked in a static `Map<string, ScheduledJob>` on the `Schedule` class -- `gracefulShutdown()` iterates and stops all of them
|
|
361
|
+
- The cron parser uses POSIX OR logic when both day-of-month and day-of-week are specified (neither `*`) -- this means `0 0 15 * FRI` matches the 15th OR every Friday, not only Fridays that fall on the 15th
|
|
362
|
+
- Lock files are written with `{ flag: 'wx' }` for atomic creation, but this is not NFS-safe
|
|
363
|
+
- `parse()` returns `null` for impossible patterns (e.g., `0 0 30 2 *` -- Feb 30 never exists) rather than throwing
|