@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,475 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Serverless')
|
|
5
|
+
<div class="py-4 lg:py-8 min-h-screen dark:bg-neutral-800">
|
|
6
|
+
<div class="px-4 sm:px-6 lg:px-8">
|
|
7
|
+
<PageHeader title="Serverless Infrastructure" description="Visualize and manage your serverless AWS services and their relationships." />
|
|
8
|
+
|
|
9
|
+
<dl class="grid gap-5 grid-cols-2 sm:grid-cols-4 mt-8">
|
|
10
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-700 rounded-lg shadow">
|
|
11
|
+
<dt class="font-medium text-gray-500 text-sm dark:text-neutral-400">Total Services</dt>
|
|
12
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 dark:text-white">{{ services.length }}</dd>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-700 rounded-lg shadow">
|
|
15
|
+
<dt class="font-medium text-gray-500 text-sm dark:text-neutral-400">Connections</dt>
|
|
16
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 dark:text-white">{{ links.length }}</dd>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-700 rounded-lg shadow">
|
|
19
|
+
<dt class="font-medium text-gray-500 text-sm dark:text-neutral-400">Service Types</dt>
|
|
20
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 dark:text-white">{{ servicesByType.length }}</dd>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-700 rounded-lg shadow">
|
|
23
|
+
<dt class="font-medium text-gray-500 text-sm dark:text-neutral-400">Recent Events</dt>
|
|
24
|
+
<dd class="mt-1 font-semibold text-3xl text-gray-900 dark:text-white">{{ serverEventsRaw.length }}</dd>
|
|
25
|
+
</div>
|
|
26
|
+
</dl>
|
|
27
|
+
|
|
28
|
+
<div class="mt-8 bg-white dark:bg-neutral-700 rounded-lg shadow">
|
|
29
|
+
<div class="p-6">
|
|
30
|
+
<div class="flex items-center justify-between mb-4">
|
|
31
|
+
<h4 class="font-medium text-base text-gray-900 dark:text-neutral-100">Service topology</h4>
|
|
32
|
+
<p class="text-gray-500 text-xs dark:text-neutral-400">Drag nodes · scroll to zoom</p>
|
|
33
|
+
</div>
|
|
34
|
+
<div id="serverless_topology" class="h-[500px] w-full bg-neutral-50 dark:bg-neutral-800 rounded-lg"></div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div class="mt-8 space-y-8">
|
|
39
|
+
<template :for="group in servicesByType">
|
|
40
|
+
<div>
|
|
41
|
+
<h4 class="font-medium text-base text-gray-900 dark:text-white">{{ group.label }}</h4>
|
|
42
|
+
<div class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 mt-3">
|
|
43
|
+
<template :for="service in group.services">
|
|
44
|
+
<div @click="selectService(service.id)" class="overflow-hidden p-4 bg-white dark:bg-neutral-700 rounded-lg hover:ring-2 hover:ring-blue-500 shadow cursor-pointer">
|
|
45
|
+
<div class="flex gap-3 items-center">
|
|
46
|
+
<div class="flex items-center justify-center h-10 w-10 rounded-lg" :style="'background-color: ' + service.color + '20; color: ' + service.color">
|
|
47
|
+
<div :class="service.icon" class="h-6 w-6"></div>
|
|
48
|
+
</div>
|
|
49
|
+
<div>
|
|
50
|
+
<p class="font-medium text-gray-900 text-sm dark:text-white">{{ service.name }}</p>
|
|
51
|
+
<p class="capitalize text-gray-500 text-xs dark:text-neutral-400">{{ service.type }}</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<p class="mt-3 leading-relaxed text-gray-500 text-xs dark:text-neutral-400">{{ service.description }}</p>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div :show="selectedService() !== null" @click.self="closeService()" class="flex fixed inset-0 z-50 items-center justify-center p-4 bg-black bg-opacity-50">
|
|
63
|
+
<div class="overflow-y-auto p-6 max-h-[90vh] max-w-2xl w-full bg-white dark:bg-neutral-800 rounded-lg shadow-xl">
|
|
64
|
+
<div class="flex items-start justify-between">
|
|
65
|
+
<div class="flex gap-3 items-center">
|
|
66
|
+
<div class="flex items-center justify-center h-12 w-12 rounded-lg" :style="selectedServiceStyle()">
|
|
67
|
+
<div :class="selectedServiceIconClass()"></div>
|
|
68
|
+
</div>
|
|
69
|
+
<div>
|
|
70
|
+
<h3 class="font-semibold text-gray-900 text-lg dark:text-white">{{ selectedService()?.name }}</h3>
|
|
71
|
+
<p class="capitalize text-gray-500 text-sm dark:text-neutral-400">{{ selectedService()?.type }}</p>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<button @click="closeService()" class="text-gray-400 dark:text-neutral-300 hover:text-gray-600 dark:hover:text-white">
|
|
75
|
+
<i class="h-5 w-5 i-hugeicons-cancel-01"></i>
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<p class="mt-4 text-gray-700 text-sm dark:text-neutral-300">{{ selectedService()?.description }}</p>
|
|
80
|
+
|
|
81
|
+
<div :show="selectedOutgoing().length > 0" class="mt-6">
|
|
82
|
+
<h4 class="font-medium text-gray-900 text-sm dark:text-white">Outgoing connections</h4>
|
|
83
|
+
<ul class="mt-2 space-y-2">
|
|
84
|
+
<template :for="conn in selectedOutgoing">
|
|
85
|
+
<li class="flex items-center justify-between p-2 bg-gray-50 dark:bg-neutral-700 rounded">
|
|
86
|
+
<span class="text-gray-900 text-sm dark:text-white">{{ conn.target?.name }}</span>
|
|
87
|
+
<span class="{{ linkTypeBadge(conn.type) }}">{{ conn.type }}</span>
|
|
88
|
+
</li>
|
|
89
|
+
</template>
|
|
90
|
+
</ul>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div :show="selectedIncoming().length > 0" class="mt-6">
|
|
94
|
+
<h4 class="font-medium text-gray-900 text-sm dark:text-white">Incoming connections</h4>
|
|
95
|
+
<ul class="mt-2 space-y-2">
|
|
96
|
+
<template :for="conn in selectedIncoming">
|
|
97
|
+
<li class="flex items-center justify-between p-2 bg-gray-50 dark:bg-neutral-700 rounded">
|
|
98
|
+
<span class="text-gray-900 text-sm dark:text-white">{{ conn.source?.name }}</span>
|
|
99
|
+
<span class="{{ linkTypeBadge(conn.type) }}">{{ conn.type }}</span>
|
|
100
|
+
</li>
|
|
101
|
+
</template>
|
|
102
|
+
</ul>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="mt-12">
|
|
108
|
+
<div class="flex items-center justify-between mb-4">
|
|
109
|
+
<div>
|
|
110
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-neutral-100">Recent Events</h3>
|
|
111
|
+
<p class="mt-2 text-gray-700 text-sm dark:text-neutral-400">Latest server events and notifications from your AWS services.</p>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="inline-block min-w-full align-middle">
|
|
116
|
+
<div class="overflow-hidden ring-1 ring-black ring-opacity-5 sm:rounded-lg shadow">
|
|
117
|
+
<table class="min-w-full divide-gray-300 divide-y dark:divide-neutral-600">
|
|
118
|
+
<thead class="bg-gray-50 dark:bg-neutral-600">
|
|
119
|
+
<tr>
|
|
120
|
+
<th scope="col" class="pl-4 pr-3 py-3.5 sm:pl-6 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Type</th>
|
|
121
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Service</th>
|
|
122
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Message</th>
|
|
123
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-right text-sm dark:text-neutral-100">Timestamp</th>
|
|
124
|
+
</tr>
|
|
125
|
+
</thead>
|
|
126
|
+
<tbody class="bg-white dark:bg-neutral-700 divide-gray-200 divide-y dark:divide-neutral-700">
|
|
127
|
+
<template :for="event in serverEventsRaw">
|
|
128
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-neutral-600">
|
|
129
|
+
<td class="pl-4 pr-3 py-4 sm:pl-6 text-sm whitespace-nowrap">
|
|
130
|
+
<div :class="eventTypeIcon(event.type) + ' ' + eventTypeColor(event.type)" class="h-5 w-5"></div>
|
|
131
|
+
</td>
|
|
132
|
+
<td class="px-3 py-4 text-gray-900 text-sm whitespace-nowrap dark:text-neutral-100">{{ event.service }}</td>
|
|
133
|
+
<td class="px-3 py-4 text-gray-500 text-sm dark:text-neutral-400">{{ event.message }}</td>
|
|
134
|
+
<td class="px-3 py-4 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-400">{{ event.timestamp }}</td>
|
|
135
|
+
</tr>
|
|
136
|
+
</template>
|
|
137
|
+
</tbody>
|
|
138
|
+
</table>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<script client>
|
|
146
|
+
// Static topology data + view helpers — moved out of the former
|
|
147
|
+
// `<script server>` block (stacksjs/stacks#1838).
|
|
148
|
+
const services = [
|
|
149
|
+
{ id: 'lambda', name: 'Lambda', type: 'compute', description: 'Serverless compute service', icon: 'i-hugeicons-cloud', color: '#F90F71' },
|
|
150
|
+
{ id: 's3', name: 'S3', type: 'storage', description: 'Object storage service', icon: 'i-hugeicons-database', color: '#6CAE3E' },
|
|
151
|
+
{ id: 'dynamodb', name: 'DynamoDB', type: 'database', description: 'NoSQL database service', icon: 'i-hugeicons-database-02', color: '#527FFF' },
|
|
152
|
+
{ id: 'sqs', name: 'SQS', type: 'queue', description: 'Message queue service', icon: 'i-hugeicons-message-multiple-02', color: '#FF4F8B' },
|
|
153
|
+
{ id: 'apigateway', name: 'API Gateway', type: 'api', description: 'API management service', icon: 'i-hugeicons-globe', color: '#A166FF' },
|
|
154
|
+
{ id: 'cloudfront', name: 'CloudFront', type: 'cdn', description: 'Content delivery network', icon: 'i-hugeicons-cloud-fast-wind', color: '#A166FF' },
|
|
155
|
+
{ id: 'route53', name: 'Route 53', type: 'dns', description: 'DNS and domain management service', icon: 'i-hugeicons-route-01', color: '#C77DFF' },
|
|
156
|
+
{ id: 'ses', name: 'SES', type: 'email', description: 'Email sending and receiving service', icon: 'i-hugeicons-mail-01', color: '#FF8E8E' },
|
|
157
|
+
{ id: 'vpc', name: 'VPC', type: 'network', description: 'Virtual Private Cloud networking', icon: 'i-hugeicons-network', color: '#64B5FF' },
|
|
158
|
+
{ id: 'efs', name: 'EFS', type: 'storage', description: 'Elastic File System', icon: 'i-hugeicons-folder-01', color: '#00D1B2' },
|
|
159
|
+
{ id: 'ecs', name: 'ECS', type: 'compute', description: 'Elastic Container Service', icon: 'i-hugeicons-package', color: '#FFC300' },
|
|
160
|
+
{ id: 'acm', name: 'ACM', type: 'security', description: 'Certificate Manager', icon: 'i-hugeicons-certificate-01', color: '#A166FF' },
|
|
161
|
+
{ id: 'waf', name: 'WAF', type: 'security', description: 'Web Application Firewall', icon: 'i-hugeicons-shield-01', color: '#FF6B6B' },
|
|
162
|
+
{ id: 'kms', name: 'KMS', type: 'security', description: 'Key Management Service', icon: 'i-hugeicons-key-01', color: '#7F6B99' },
|
|
163
|
+
{ id: 'iam', name: 'IAM', type: 'security', description: 'Identity and Access Management', icon: 'i-hugeicons-user-shield-01', color: '#DD344C' },
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
const links = [
|
|
167
|
+
{ source: 'apigateway', target: 'lambda', type: 'triggers' },
|
|
168
|
+
{ source: 'lambda', target: 's3', type: 'uses' },
|
|
169
|
+
{ source: 'lambda', target: 'dynamodb', type: 'uses' },
|
|
170
|
+
{ source: 'lambda', target: 'sqs', type: 'processes' },
|
|
171
|
+
{ source: 'cloudfront', target: 's3', type: 'connects' },
|
|
172
|
+
{ source: 'route53', target: 'cloudfront', type: 'connects' },
|
|
173
|
+
{ source: 'route53', target: 'apigateway', type: 'connects' },
|
|
174
|
+
{ source: 'route53', target: 'ecs', type: 'connects' },
|
|
175
|
+
{ source: 'lambda', target: 'ses', type: 'uses' },
|
|
176
|
+
{ source: 'lambda', target: 'vpc', type: 'uses' },
|
|
177
|
+
{ source: 'ecs', target: 'vpc', type: 'uses' },
|
|
178
|
+
{ source: 'ecs', target: 'efs', type: 'uses' },
|
|
179
|
+
{ source: 'waf', target: 'cloudfront', type: 'protects' },
|
|
180
|
+
{ source: 'waf', target: 'apigateway', type: 'protects' },
|
|
181
|
+
{ source: 'kms', target: 's3', type: 'protects' },
|
|
182
|
+
{ source: 'kms', target: 'efs', type: 'protects' },
|
|
183
|
+
{ source: 'acm', target: 'cloudfront', type: 'protects' },
|
|
184
|
+
{ source: 'acm', target: 'apigateway', type: 'protects' },
|
|
185
|
+
{ source: 'acm', target: 'ecs', type: 'protects' },
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
const serviceById = Object.fromEntries(services.map(s => [s.id, s]))
|
|
189
|
+
|
|
190
|
+
const servicesWithConnections = services.map((service) => {
|
|
191
|
+
const outgoing = links.filter(l => l.source === service.id).map(l => ({ type: l.type, target: serviceById[l.target] }))
|
|
192
|
+
const incoming = links.filter(l => l.target === service.id).map(l => ({ type: l.type, source: serviceById[l.source] }))
|
|
193
|
+
return { ...service, outgoing, incoming, connectionCount: outgoing.length + incoming.length }
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
const servicesByType = ['compute', 'storage', 'database', 'queue', 'api', 'cdn', 'dns', 'email', 'network', 'security'].map(type => ({
|
|
197
|
+
type,
|
|
198
|
+
label: type.charAt(0).toUpperCase() + type.slice(1),
|
|
199
|
+
services: services.filter(s => s.type === type),
|
|
200
|
+
})).filter(group => group.services.length > 0)
|
|
201
|
+
|
|
202
|
+
const serverEventsRaw = [
|
|
203
|
+
{ id: '1', service: 'Lambda', type: 'success', message: 'Function execution completed successfully', timestamp: '2024-03-21 14:23:45' },
|
|
204
|
+
{ id: '2', service: 'API Gateway', type: 'info', message: 'New API endpoint deployed', timestamp: '2024-03-21 14:20:12' },
|
|
205
|
+
{ id: '3', service: 'DynamoDB', type: 'warning', message: 'High read capacity utilization', timestamp: '2024-03-21 14:15:30' },
|
|
206
|
+
{ id: '4', service: 'CloudFront', type: 'error', message: 'Cache invalidation failed', timestamp: '2024-03-21 14:10:55' },
|
|
207
|
+
{ id: '5', service: 'S3', type: 'success', message: 'Bucket policy updated successfully', timestamp: '2024-03-21 14:05:22' },
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
function eventTypeColor(type: string): string {
|
|
211
|
+
switch (type) {
|
|
212
|
+
case 'success': return 'text-green-500'
|
|
213
|
+
case 'error': return 'text-red-500'
|
|
214
|
+
case 'warning': return 'text-yellow-500'
|
|
215
|
+
default: return 'text-blue-500'
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function eventTypeIcon(type: string): string {
|
|
220
|
+
switch (type) {
|
|
221
|
+
case 'success': return 'i-hugeicons-checkmark-circle-02'
|
|
222
|
+
case 'error': return 'i-hugeicons-cancel-circle'
|
|
223
|
+
case 'warning': return 'i-hugeicons-alert-02'
|
|
224
|
+
default: return 'i-hugeicons-information-circle'
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function linkTypeBadge(type: string): string {
|
|
229
|
+
const base = 'inline-flex items-center px-1.5 py-0.5 font-medium text-xs rounded'
|
|
230
|
+
switch (type) {
|
|
231
|
+
case 'triggers': return `${base} bg-pink-100 dark:bg-pink-900 text-pink-700 dark:text-pink-200`
|
|
232
|
+
case 'uses': return `${base} bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-200`
|
|
233
|
+
case 'connects': return `${base} bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-200`
|
|
234
|
+
case 'processes': return `${base} bg-yellow-100 dark:bg-yellow-900 text-yellow-700 dark:text-yellow-200`
|
|
235
|
+
case 'protects': return `${base} bg-purple-100 dark:bg-purple-900 text-purple-700 dark:text-purple-200`
|
|
236
|
+
default: return `${base} bg-gray-100 dark:bg-neutral-700 text-gray-700 dark:text-neutral-200`
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
interface Service {
|
|
241
|
+
id: string
|
|
242
|
+
name: string
|
|
243
|
+
type: string
|
|
244
|
+
description: string
|
|
245
|
+
icon: string
|
|
246
|
+
color: string
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
interface Connection {
|
|
250
|
+
type: string
|
|
251
|
+
source?: Service
|
|
252
|
+
target?: Service
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const servicesData: Service[] = [
|
|
256
|
+
{ id: 'lambda', name: 'Lambda', type: 'compute', description: 'Serverless compute service', icon: 'i-hugeicons-cloud', color: '#F90F71' },
|
|
257
|
+
{ id: 's3', name: 'S3', type: 'storage', description: 'Object storage service', icon: 'i-hugeicons-database', color: '#6CAE3E' },
|
|
258
|
+
{ id: 'dynamodb', name: 'DynamoDB', type: 'database', description: 'NoSQL database service', icon: 'i-hugeicons-database-02', color: '#527FFF' },
|
|
259
|
+
{ id: 'sqs', name: 'SQS', type: 'queue', description: 'Message queue service', icon: 'i-hugeicons-message-multiple-02', color: '#FF4F8B' },
|
|
260
|
+
{ id: 'apigateway', name: 'API Gateway', type: 'api', description: 'API management service', icon: 'i-hugeicons-globe', color: '#A166FF' },
|
|
261
|
+
{ id: 'cloudfront', name: 'CloudFront', type: 'cdn', description: 'Content delivery network', icon: 'i-hugeicons-cloud-fast-wind', color: '#A166FF' },
|
|
262
|
+
{ id: 'route53', name: 'Route 53', type: 'dns', description: 'DNS and domain management service', icon: 'i-hugeicons-route-01', color: '#C77DFF' },
|
|
263
|
+
{ id: 'ses', name: 'SES', type: 'email', description: 'Email sending and receiving service', icon: 'i-hugeicons-mail-01', color: '#FF8E8E' },
|
|
264
|
+
{ id: 'vpc', name: 'VPC', type: 'network', description: 'Virtual Private Cloud networking', icon: 'i-hugeicons-network', color: '#64B5FF' },
|
|
265
|
+
{ id: 'efs', name: 'EFS', type: 'storage', description: 'Elastic File System', icon: 'i-hugeicons-folder-01', color: '#00D1B2' },
|
|
266
|
+
{ id: 'ecs', name: 'ECS', type: 'compute', description: 'Elastic Container Service', icon: 'i-hugeicons-package', color: '#FFC300' },
|
|
267
|
+
{ id: 'acm', name: 'ACM', type: 'security', description: 'Certificate Manager', icon: 'i-hugeicons-certificate-01', color: '#A166FF' },
|
|
268
|
+
{ id: 'waf', name: 'WAF', type: 'security', description: 'Web Application Firewall', icon: 'i-hugeicons-shield-01', color: '#FF6B6B' },
|
|
269
|
+
{ id: 'kms', name: 'KMS', type: 'security', description: 'Key Management Service', icon: 'i-hugeicons-key-01', color: '#7F6B99' },
|
|
270
|
+
{ id: 'iam', name: 'IAM', type: 'security', description: 'Identity and Access Management', icon: 'i-hugeicons-user-shield-01', color: '#DD344C' },
|
|
271
|
+
]
|
|
272
|
+
|
|
273
|
+
const linksData = [
|
|
274
|
+
{ source: 'apigateway', target: 'lambda', type: 'triggers' },
|
|
275
|
+
{ source: 'lambda', target: 's3', type: 'uses' },
|
|
276
|
+
{ source: 'lambda', target: 'dynamodb', type: 'uses' },
|
|
277
|
+
{ source: 'lambda', target: 'sqs', type: 'processes' },
|
|
278
|
+
{ source: 'cloudfront', target: 's3', type: 'connects' },
|
|
279
|
+
{ source: 'route53', target: 'cloudfront', type: 'connects' },
|
|
280
|
+
{ source: 'route53', target: 'apigateway', type: 'connects' },
|
|
281
|
+
{ source: 'route53', target: 'ecs', type: 'connects' },
|
|
282
|
+
{ source: 'lambda', target: 'ses', type: 'uses' },
|
|
283
|
+
{ source: 'lambda', target: 'vpc', type: 'uses' },
|
|
284
|
+
{ source: 'ecs', target: 'vpc', type: 'uses' },
|
|
285
|
+
{ source: 'ecs', target: 'efs', type: 'uses' },
|
|
286
|
+
{ source: 'waf', target: 'cloudfront', type: 'protects' },
|
|
287
|
+
{ source: 'waf', target: 'apigateway', type: 'protects' },
|
|
288
|
+
{ source: 'kms', target: 's3', type: 'protects' },
|
|
289
|
+
{ source: 'kms', target: 'efs', type: 'protects' },
|
|
290
|
+
{ source: 'acm', target: 'cloudfront', type: 'protects' },
|
|
291
|
+
{ source: 'acm', target: 'apigateway', type: 'protects' },
|
|
292
|
+
{ source: 'acm', target: 'ecs', type: 'protects' },
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
const serviceById: Record<string, Service> = Object.fromEntries(servicesData.map(s => [s.id, s]))
|
|
296
|
+
|
|
297
|
+
const selectedServiceId = state<string | null>(null)
|
|
298
|
+
|
|
299
|
+
const selectedService = derived(() => selectedServiceId() ? serviceById[selectedServiceId()!] ?? null : null)
|
|
300
|
+
|
|
301
|
+
const selectedOutgoing = derived<Connection[]>(() => {
|
|
302
|
+
const id = selectedServiceId()
|
|
303
|
+
if (!id)
|
|
304
|
+
return []
|
|
305
|
+
return linksData.filter(l => l.source === id).map(l => ({ type: l.type, target: serviceById[l.target] }))
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const selectedIncoming = derived<Connection[]>(() => {
|
|
309
|
+
const id = selectedServiceId()
|
|
310
|
+
if (!id)
|
|
311
|
+
return []
|
|
312
|
+
return linksData.filter(l => l.target === id).map(l => ({ type: l.type, source: serviceById[l.source] }))
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
const selectedServiceStyle = derived(() => {
|
|
316
|
+
const s = selectedService()
|
|
317
|
+
return s ? `background-color: ${s.color}20; color: ${s.color}` : ''
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
const selectedServiceIconClass = derived(() => {
|
|
321
|
+
const s = selectedService()
|
|
322
|
+
return s ? `${s.icon} h-7 w-7` : ''
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
function selectService(id: string) {
|
|
326
|
+
selectedServiceId.set(id)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function closeService() {
|
|
330
|
+
selectedServiceId.set(null)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function linkTypeBadge(type: string): string {
|
|
334
|
+
const base = 'inline-flex items-center px-1.5 py-0.5 font-medium text-xs rounded'
|
|
335
|
+
switch (type) {
|
|
336
|
+
case 'triggers': return `${base} bg-pink-100 dark:bg-pink-900 text-pink-700 dark:text-pink-200`
|
|
337
|
+
case 'uses': return `${base} bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-200`
|
|
338
|
+
case 'connects': return `${base} bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-200`
|
|
339
|
+
case 'processes': return `${base} bg-yellow-100 dark:bg-yellow-900 text-yellow-700 dark:text-yellow-200`
|
|
340
|
+
case 'protects': return `${base} bg-purple-100 dark:bg-purple-900 text-purple-700 dark:text-purple-200`
|
|
341
|
+
default: return `${base} bg-gray-100 dark:bg-neutral-700 text-gray-700 dark:text-neutral-200`
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function linkColor(type: string): string {
|
|
346
|
+
switch (type) {
|
|
347
|
+
case 'triggers': return '#FF4F8B'
|
|
348
|
+
case 'uses': return '#4053D6'
|
|
349
|
+
case 'connects': return '#569A31'
|
|
350
|
+
case 'processes': return '#FFC300'
|
|
351
|
+
case 'protects': return '#A166FF'
|
|
352
|
+
default: return '#6B7280'
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
let topologyCleanup: (() => void) | null = null
|
|
357
|
+
|
|
358
|
+
async function renderTopology() {
|
|
359
|
+
const container = document.getElementById('serverless_topology')
|
|
360
|
+
if (!container)
|
|
361
|
+
return
|
|
362
|
+
topologyCleanup?.()
|
|
363
|
+
container.innerHTML = ''
|
|
364
|
+
|
|
365
|
+
const d3 = await import('d3')
|
|
366
|
+
const width = container.clientWidth || 800
|
|
367
|
+
const height = container.clientHeight || 500
|
|
368
|
+
|
|
369
|
+
type SimNode = Service & { x?: number, y?: number, fx?: number | null, fy?: number | null }
|
|
370
|
+
type SimLink = { source: string | SimNode, target: string | SimNode, type: string }
|
|
371
|
+
|
|
372
|
+
const nodes: SimNode[] = servicesData.map(s => ({ ...s }))
|
|
373
|
+
const links: SimLink[] = linksData.map(l => ({ source: l.source, target: l.target, type: l.type }))
|
|
374
|
+
|
|
375
|
+
const svg = d3.select(container)
|
|
376
|
+
.append('svg')
|
|
377
|
+
.attr('width', width)
|
|
378
|
+
.attr('height', height)
|
|
379
|
+
.attr('viewBox', [0, 0, width, height])
|
|
380
|
+
.attr('style', 'max-width: 100%; height: auto;')
|
|
381
|
+
|
|
382
|
+
const zoomGroup = svg.append('g')
|
|
383
|
+
const zoom = d3.zoom<SVGSVGElement, unknown>()
|
|
384
|
+
.scaleExtent([0.3, 3])
|
|
385
|
+
.on('zoom', (event) => {
|
|
386
|
+
zoomGroup.attr('transform', event.transform.toString())
|
|
387
|
+
})
|
|
388
|
+
svg.call(zoom as any)
|
|
389
|
+
|
|
390
|
+
const link = zoomGroup.append('g')
|
|
391
|
+
.attr('stroke-opacity', 0.7)
|
|
392
|
+
.selectAll('line')
|
|
393
|
+
.data(links)
|
|
394
|
+
.join('line')
|
|
395
|
+
.attr('stroke', d => linkColor(d.type))
|
|
396
|
+
.attr('stroke-width', 2)
|
|
397
|
+
|
|
398
|
+
const node = zoomGroup.append('g')
|
|
399
|
+
.selectAll<SVGGElement, SimNode>('g')
|
|
400
|
+
.data(nodes)
|
|
401
|
+
.join('g')
|
|
402
|
+
.attr('cursor', 'pointer')
|
|
403
|
+
.on('click', (_event, d) => selectService(d.id))
|
|
404
|
+
|
|
405
|
+
node.append('circle')
|
|
406
|
+
.attr('r', 26)
|
|
407
|
+
.attr('fill', '#1E293B')
|
|
408
|
+
.attr('stroke', d => d.color)
|
|
409
|
+
.attr('stroke-width', 3)
|
|
410
|
+
|
|
411
|
+
node.append('circle')
|
|
412
|
+
.attr('r', 18)
|
|
413
|
+
.attr('fill', d => d.color)
|
|
414
|
+
.attr('fill-opacity', 0.85)
|
|
415
|
+
|
|
416
|
+
node.append('text')
|
|
417
|
+
.text(d => d.name)
|
|
418
|
+
.attr('text-anchor', 'middle')
|
|
419
|
+
.attr('dy', 44)
|
|
420
|
+
.attr('fill', 'currentColor')
|
|
421
|
+
.attr('font-size', '11px')
|
|
422
|
+
.attr('font-weight', '500')
|
|
423
|
+
.attr('class', 'text-gray-700 dark:text-neutral-200')
|
|
424
|
+
.attr('pointer-events', 'none')
|
|
425
|
+
|
|
426
|
+
const drag = d3.drag<SVGGElement, SimNode>()
|
|
427
|
+
.on('start', (event, d) => {
|
|
428
|
+
if (!event.active)
|
|
429
|
+
simulation.alphaTarget(0.3).restart()
|
|
430
|
+
d.fx = d.x
|
|
431
|
+
d.fy = d.y
|
|
432
|
+
})
|
|
433
|
+
.on('drag', (event, d) => {
|
|
434
|
+
d.fx = event.x
|
|
435
|
+
d.fy = event.y
|
|
436
|
+
})
|
|
437
|
+
.on('end', (event, d) => {
|
|
438
|
+
if (!event.active)
|
|
439
|
+
simulation.alphaTarget(0)
|
|
440
|
+
d.fx = null
|
|
441
|
+
d.fy = null
|
|
442
|
+
})
|
|
443
|
+
node.call(drag as any)
|
|
444
|
+
|
|
445
|
+
const simulation = d3.forceSimulation<SimNode>(nodes)
|
|
446
|
+
.force('link', d3.forceLink<SimNode, SimLink>(links).id(d => d.id).distance(140))
|
|
447
|
+
.force('charge', d3.forceManyBody().strength(-450))
|
|
448
|
+
.force('center', d3.forceCenter(width / 2, height / 2))
|
|
449
|
+
.force('collide', d3.forceCollide<SimNode>().radius(40))
|
|
450
|
+
.on('tick', () => {
|
|
451
|
+
link
|
|
452
|
+
.attr('x1', d => (d.source as SimNode).x ?? 0)
|
|
453
|
+
.attr('y1', d => (d.source as SimNode).y ?? 0)
|
|
454
|
+
.attr('x2', d => (d.target as SimNode).x ?? 0)
|
|
455
|
+
.attr('y2', d => (d.target as SimNode).y ?? 0)
|
|
456
|
+
node.attr('transform', d => `translate(${d.x ?? 0},${d.y ?? 0})`)
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
topologyCleanup = () => {
|
|
460
|
+
simulation.stop()
|
|
461
|
+
container.innerHTML = ''
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
onMount(() => {
|
|
466
|
+
void renderTopology()
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
onDestroy(() => {
|
|
470
|
+
topologyCleanup?.()
|
|
471
|
+
topologyCleanup = null
|
|
472
|
+
})
|
|
473
|
+
</script>
|
|
474
|
+
|
|
475
|
+
@endsection
|