cfsa-antigravity 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spacetimedb
|
|
3
|
+
description: "Expert SpacetimeDB guide covering server module design, table schema with the function-builder API, reducer patterns (atomicity, validation, authorization), subscription optimization, client SDK connection lifecycle, React integration hooks, TypeScript patterns, and real-time sync strategies. Use when building real-time multiplayer apps, collaborative tools, or any application using SpacetimeDB as the primary data store and backend runtime."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# SpacetimeDB Expert Guide
|
|
8
|
+
|
|
9
|
+
> Use this skill when designing SpacetimeDB modules, writing table schemas, implementing reducers, managing client subscriptions, integrating with React, or optimizing real-time sync. This skill targets SpacetimeDB TypeScript SDK v1.4.0+ with the function-builder API.
|
|
10
|
+
|
|
11
|
+
## When to Use This Skill
|
|
12
|
+
|
|
13
|
+
- Building real-time multiplayer games with server-authoritative state
|
|
14
|
+
- Implementing collaborative apps with live sync (whiteboards, editors, dashboards)
|
|
15
|
+
- Designing chat/messaging systems with persistent history
|
|
16
|
+
- Projects that need a **combined database + backend runtime** — no separate API layer
|
|
17
|
+
- Integrating SpacetimeDB as the `DATABASE_PRIMARY` store with WebSocket-based clients
|
|
18
|
+
|
|
19
|
+
## When NOT to Use This Skill
|
|
20
|
+
|
|
21
|
+
- Traditional REST/GraphQL APIs → use a backend framework (Hono, NestJS, FastAPI)
|
|
22
|
+
- Relational analytics with complex JOINs → use PostgreSQL
|
|
23
|
+
- Vector/embedding search → use LanceDB, Qdrant, or pgvector
|
|
24
|
+
- Existing backend + separate database → use a traditional DB skill
|
|
25
|
+
- Offline-first mobile apps without WebSocket → use SQLite or Supabase
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Module Design (CRITICAL)
|
|
30
|
+
|
|
31
|
+
SpacetimeDB modules are server-side programs. Each module is a self-contained unit of tables + reducers.
|
|
32
|
+
|
|
33
|
+
### Module Structure
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { spacetimedb, table, t, ReducerContext } from 'spacetimedb';
|
|
37
|
+
|
|
38
|
+
// 1. Define tables
|
|
39
|
+
const Player = table(
|
|
40
|
+
{ name: 'player', public: true },
|
|
41
|
+
{
|
|
42
|
+
identity: t.identity().primaryKey(),
|
|
43
|
+
name: t.string(),
|
|
44
|
+
score: t.u64().index(),
|
|
45
|
+
isOnline: t.bool().index(),
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// 2. Define reducers
|
|
50
|
+
spacetimedb.reducer('create_player', { name: t.string() }, (ctx: ReducerContext, { name }) => {
|
|
51
|
+
ctx.db.player.insert({
|
|
52
|
+
identity: ctx.sender,
|
|
53
|
+
name,
|
|
54
|
+
score: 0n,
|
|
55
|
+
isOnline: true,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 3. Lifecycle hooks
|
|
60
|
+
spacetimedb.init((ctx: ReducerContext) => { /* module initialization */ });
|
|
61
|
+
spacetimedb.clientConnected((ctx: ReducerContext) => { /* mark player online */ });
|
|
62
|
+
spacetimedb.clientDisconnected((ctx: ReducerContext) => { /* mark player offline */ });
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Module Design Rules
|
|
66
|
+
|
|
67
|
+
- **One module per domain** — keep modules focused on a single bounded context
|
|
68
|
+
- **Use lifecycle hooks** — `init` for setup, `clientConnected`/`clientDisconnected` for presence
|
|
69
|
+
- **Handle errors in modules** — throw descriptive errors; reducers are transactional and auto-rollback
|
|
70
|
+
- **Export types** — client SDK generates types from your module schema
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 2. Table Schema & Indexing (CRITICAL)
|
|
75
|
+
|
|
76
|
+
### Primary Key Strategies
|
|
77
|
+
|
|
78
|
+
Every SpacetimeDB table requires a primary key. Choose based on use case:
|
|
79
|
+
|
|
80
|
+
| Strategy | When to Use | Example |
|
|
81
|
+
|----------|------------|---------|
|
|
82
|
+
| `t.identity().primaryKey()` | User-owned data | Player profiles, settings |
|
|
83
|
+
| `t.string().primaryKey()` | UUID-based entities | Messages, items, rooms |
|
|
84
|
+
| `t.u64().primaryKey().autoInc()` | Sequential data | Game rounds, log entries |
|
|
85
|
+
| Composite keys | Junction/relationship tables | Friendships, room membership |
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// ✅ Identity as primary key for user-owned data
|
|
89
|
+
const Player = table(
|
|
90
|
+
{ name: 'player', public: true },
|
|
91
|
+
{
|
|
92
|
+
identity: t.identity().primaryKey(),
|
|
93
|
+
username: t.string(),
|
|
94
|
+
score: t.u64(),
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// ✅ UUID for entity tables
|
|
99
|
+
const Message = table(
|
|
100
|
+
{ name: 'message', public: true },
|
|
101
|
+
{
|
|
102
|
+
id: t.string().primaryKey(), // UUID generated at insert
|
|
103
|
+
senderId: t.identity(),
|
|
104
|
+
content: t.string(),
|
|
105
|
+
timestamp: t.u64(),
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// ✅ Auto-increment for sequential data
|
|
110
|
+
const GameRound = table(
|
|
111
|
+
{ name: 'game_round', public: true },
|
|
112
|
+
{
|
|
113
|
+
roundNumber: t.u64().primaryKey().autoInc(),
|
|
114
|
+
startedAt: t.u64(),
|
|
115
|
+
endedAt: t.u64().optional(),
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Indexing
|
|
121
|
+
|
|
122
|
+
Add `.index()` to columns used in subscription filters or frequent queries:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const Player = table(
|
|
126
|
+
{ name: 'player', public: true },
|
|
127
|
+
{
|
|
128
|
+
identity: t.identity().primaryKey(),
|
|
129
|
+
name: t.string(),
|
|
130
|
+
score: t.u64().index(), // Indexed: leaderboard queries
|
|
131
|
+
isOnline: t.bool().index(), // Indexed: online players filter
|
|
132
|
+
roomId: t.string().index(), // Indexed: room membership queries
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> Index every column that appears in a `WHERE` clause in subscriptions — unindexed filters are expensive.
|
|
138
|
+
|
|
139
|
+
### Column Types
|
|
140
|
+
|
|
141
|
+
| Type Builder | TypeScript Type | When to Use |
|
|
142
|
+
|-------------|----------------|------------|
|
|
143
|
+
| `t.string()` | `string` | Text, UUIDs |
|
|
144
|
+
| `t.u32()`, `t.u64()` | `number`, `bigint` | Counts, timestamps |
|
|
145
|
+
| `t.i32()`, `t.i64()` | `number`, `bigint` | Signed integers |
|
|
146
|
+
| `t.f32()`, `t.f64()` | `number` | Floating point |
|
|
147
|
+
| `t.bool()` | `boolean` | Flags |
|
|
148
|
+
| `t.identity()` | `Identity` | User identifiers |
|
|
149
|
+
| `.optional()` | `T \| undefined` | Nullable fields |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 3. Reducer Patterns (HIGH)
|
|
154
|
+
|
|
155
|
+
Reducers are transactional server-side functions. They either complete entirely or roll back.
|
|
156
|
+
|
|
157
|
+
### Atomicity — One Reducer, One Job
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// ✅ Focused reducer — does one thing
|
|
161
|
+
spacetimedb.reducer(
|
|
162
|
+
'move_player',
|
|
163
|
+
{ direction: t.string() },
|
|
164
|
+
(ctx: ReducerContext, { direction }) => {
|
|
165
|
+
const player = ctx.db.player.identity.find(ctx.sender);
|
|
166
|
+
if (!player) throw new Error('Player not found');
|
|
167
|
+
|
|
168
|
+
const newPosition = calculateNewPosition(player.position, direction);
|
|
169
|
+
if (!isValidPosition(newPosition)) throw new Error('Invalid move');
|
|
170
|
+
|
|
171
|
+
ctx.db.player.identity.update({
|
|
172
|
+
...player,
|
|
173
|
+
position: newPosition,
|
|
174
|
+
lastMoveAt: ctx.timestamp,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// ❌ Avoid: one reducer that moves, checks collisions, awards achievements, and updates leaderboard
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Input Validation
|
|
183
|
+
|
|
184
|
+
Always validate at reducer entry:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
spacetimedb.reducer(
|
|
188
|
+
'send_message',
|
|
189
|
+
{ channelId: t.string(), content: t.string() },
|
|
190
|
+
(ctx: ReducerContext, { channelId, content }) => {
|
|
191
|
+
// Validate input
|
|
192
|
+
if (!content || content.trim().length === 0) {
|
|
193
|
+
throw new Error('Message content cannot be empty');
|
|
194
|
+
}
|
|
195
|
+
if (content.length > 2000) {
|
|
196
|
+
throw new Error('Message too long (max 2000 characters)');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Verify channel exists
|
|
200
|
+
const channel = ctx.db.channel.id.find(channelId);
|
|
201
|
+
if (!channel) throw new Error('Channel not found');
|
|
202
|
+
|
|
203
|
+
ctx.db.message.insert({
|
|
204
|
+
id: crypto.randomUUID(),
|
|
205
|
+
senderId: ctx.sender,
|
|
206
|
+
channelId,
|
|
207
|
+
content: content.trim(),
|
|
208
|
+
timestamp: ctx.timestamp,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Authorization
|
|
215
|
+
|
|
216
|
+
Check caller identity for sensitive operations:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
spacetimedb.reducer(
|
|
220
|
+
'delete_message',
|
|
221
|
+
{ messageId: t.string() },
|
|
222
|
+
(ctx: ReducerContext, { messageId }) => {
|
|
223
|
+
const message = ctx.db.message.id.find(messageId);
|
|
224
|
+
if (!message) throw new Error('Message not found');
|
|
225
|
+
|
|
226
|
+
// Only the sender can delete their own message
|
|
227
|
+
if (!message.senderId.isEqual(ctx.sender)) {
|
|
228
|
+
throw new Error('Unauthorized: can only delete your own messages');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
ctx.db.message.id.delete(messageId);
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 4. Subscription Optimization (HIGH)
|
|
239
|
+
|
|
240
|
+
### Selective Subscriptions
|
|
241
|
+
|
|
242
|
+
Subscribe only to the data your client needs. Use `WHERE` clauses to filter server-side:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { DbConnection } from './generated';
|
|
246
|
+
|
|
247
|
+
const conn = DbConnection.builder()
|
|
248
|
+
.withUri('ws://localhost:3000')
|
|
249
|
+
.withModuleName('game-module')
|
|
250
|
+
.onConnect((ctx, identity, token) => {
|
|
251
|
+
const myId = identity.toHexString();
|
|
252
|
+
|
|
253
|
+
// ✅ Only online players
|
|
254
|
+
conn.subscription(['SELECT * FROM player WHERE isOnline = true']);
|
|
255
|
+
|
|
256
|
+
// ✅ Only my inventory
|
|
257
|
+
conn.subscription(['SELECT * FROM inventory WHERE ownerId = ?', myId]);
|
|
258
|
+
|
|
259
|
+
// ✅ Leaderboard top 100
|
|
260
|
+
conn.subscription(['SELECT * FROM player ORDER BY score DESC LIMIT 100']);
|
|
261
|
+
})
|
|
262
|
+
.build();
|
|
263
|
+
|
|
264
|
+
// ✅ Dynamic subscriptions with cleanup
|
|
265
|
+
function subscribeToChannel(channelId: string) {
|
|
266
|
+
return conn.subscription([
|
|
267
|
+
'SELECT * FROM message WHERE channelId = ?',
|
|
268
|
+
channelId,
|
|
269
|
+
]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Unsubscribe when leaving channel
|
|
273
|
+
function leaveChannel(sub: any) {
|
|
274
|
+
sub?.unsubscribe();
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
> **Rule**: Never `SELECT * FROM table` without filters — this downloads the entire table to every client.
|
|
279
|
+
|
|
280
|
+
### Subscription Batching
|
|
281
|
+
|
|
282
|
+
Batch subscription setup on client connect to reduce round trips:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
.onConnect((ctx, identity, token) => {
|
|
286
|
+
// Batch multiple subscriptions in one connect handler
|
|
287
|
+
conn.subscription([
|
|
288
|
+
'SELECT * FROM player WHERE isOnline = true',
|
|
289
|
+
'SELECT * FROM player WHERE identity = ?', identity.toHexString(),
|
|
290
|
+
'SELECT * FROM config',
|
|
291
|
+
]);
|
|
292
|
+
})
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## 5. Client SDK Integration
|
|
298
|
+
|
|
299
|
+
### Connection Lifecycle
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { DbConnection } from './generated';
|
|
303
|
+
|
|
304
|
+
const conn = DbConnection.builder()
|
|
305
|
+
.withUri('ws://localhost:3000')
|
|
306
|
+
.withModuleName('my-module')
|
|
307
|
+
.onConnect((ctx, identity, token) => {
|
|
308
|
+
console.log('Connected as', identity.toHexString());
|
|
309
|
+
// Store token for reconnection
|
|
310
|
+
localStorage.setItem('spacetimedb_token', token);
|
|
311
|
+
// Set up subscriptions
|
|
312
|
+
conn.subscription(['SELECT * FROM player WHERE isOnline = true']);
|
|
313
|
+
})
|
|
314
|
+
.onDisconnect((ctx, error) => {
|
|
315
|
+
console.error('Disconnected:', error);
|
|
316
|
+
// Implement reconnection logic
|
|
317
|
+
})
|
|
318
|
+
.build();
|
|
319
|
+
|
|
320
|
+
// Call reducers
|
|
321
|
+
await conn.reducers.createPlayer('Alice');
|
|
322
|
+
|
|
323
|
+
// Access tables
|
|
324
|
+
const player = conn.db.player.identity.find(identity);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Reconnection Pattern
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
function connectWithRetry(maxRetries = 5, delayMs = 1000) {
|
|
331
|
+
let attempt = 0;
|
|
332
|
+
|
|
333
|
+
function connect() {
|
|
334
|
+
return DbConnection.builder()
|
|
335
|
+
.withUri('ws://localhost:3000')
|
|
336
|
+
.withModuleName('my-module')
|
|
337
|
+
.withToken(localStorage.getItem('spacetimedb_token') ?? undefined)
|
|
338
|
+
.onConnect((ctx, identity, token) => {
|
|
339
|
+
attempt = 0; // Reset on success
|
|
340
|
+
localStorage.setItem('spacetimedb_token', token);
|
|
341
|
+
})
|
|
342
|
+
.onDisconnect((ctx, error) => {
|
|
343
|
+
if (attempt < maxRetries) {
|
|
344
|
+
attempt++;
|
|
345
|
+
setTimeout(connect, delayMs * Math.pow(2, attempt));
|
|
346
|
+
}
|
|
347
|
+
})
|
|
348
|
+
.build();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return connect();
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 6. React Integration
|
|
358
|
+
|
|
359
|
+
### Table Hooks
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import { useTable, where, eq } from 'spacetimedb/react';
|
|
363
|
+
import { DbConnection, Player, Message } from './generated';
|
|
364
|
+
|
|
365
|
+
function OnlinePlayers() {
|
|
366
|
+
const { rows: players } = useTable<DbConnection, Player>(
|
|
367
|
+
'player',
|
|
368
|
+
where(eq('isOnline', true))
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<div>
|
|
373
|
+
{players.map(p => (
|
|
374
|
+
<div key={p.identity.toHexString()}>{p.name} — Score: {p.score}</div>
|
|
375
|
+
))}
|
|
376
|
+
</div>
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function ChatMessages({ channelId }: { channelId: string }) {
|
|
381
|
+
const { rows: messages } = useTable<DbConnection, Message>(
|
|
382
|
+
'message',
|
|
383
|
+
where(eq('channelId', channelId))
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<div>
|
|
388
|
+
{messages.map(m => (
|
|
389
|
+
<div key={m.id}>{m.content}</div>
|
|
390
|
+
))}
|
|
391
|
+
</div>
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Reducer Calls with Error Handling
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
function SendMessageForm({ conn, channelId }: { conn: DbConnection; channelId: string }) {
|
|
400
|
+
const [content, setContent] = useState('');
|
|
401
|
+
const [error, setError] = useState<string | null>(null);
|
|
402
|
+
|
|
403
|
+
const handleSend = async () => {
|
|
404
|
+
try {
|
|
405
|
+
setError(null);
|
|
406
|
+
await conn.reducers.sendMessage(channelId, content);
|
|
407
|
+
setContent('');
|
|
408
|
+
} catch (err) {
|
|
409
|
+
setError(err instanceof Error ? err.message : 'Failed to send');
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<form onSubmit={e => { e.preventDefault(); handleSend(); }}>
|
|
415
|
+
<input value={content} onChange={e => setContent(e.target.value)} />
|
|
416
|
+
<button type="submit">Send</button>
|
|
417
|
+
{error && <p className="error">{error}</p>}
|
|
418
|
+
</form>
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Subscription Lifecycle in Components
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
import { useEffect, useState } from 'react';
|
|
427
|
+
|
|
428
|
+
function ChatRoom({ channelId, conn }: { channelId: string; conn: DbConnection }) {
|
|
429
|
+
useEffect(() => {
|
|
430
|
+
const sub = conn.subscription([
|
|
431
|
+
'SELECT * FROM message WHERE channelId = ?',
|
|
432
|
+
channelId,
|
|
433
|
+
]);
|
|
434
|
+
|
|
435
|
+
return () => { sub?.unsubscribe(); };
|
|
436
|
+
}, [channelId, conn]);
|
|
437
|
+
|
|
438
|
+
const { rows: messages } = useTable<DbConnection, Message>(
|
|
439
|
+
'message',
|
|
440
|
+
where(eq('channelId', channelId))
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
return <div>{messages.map(m => <div key={m.id}>{m.content}</div>)}</div>;
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## 7. TypeScript Patterns
|
|
450
|
+
|
|
451
|
+
- **Use generated types** — run `spacetimedb generate` and import from `./generated`
|
|
452
|
+
- **Enable strict mode** — `"strict": true` in tsconfig for better type safety
|
|
453
|
+
- **Use `bigint` for u64** — SpacetimeDB `u64` maps to TypeScript `bigint` (e.g., `0n`, `ctx.timestamp`)
|
|
454
|
+
- **Type guards for runtime validation** — validate data shapes at module boundaries
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
// ✅ Use generated types
|
|
458
|
+
import { Player, Message, DbConnection } from './generated';
|
|
459
|
+
|
|
460
|
+
// ✅ Use bigint for u64 fields
|
|
461
|
+
const score: bigint = 100n;
|
|
462
|
+
|
|
463
|
+
// ✅ Type guard example
|
|
464
|
+
function isValidDirection(dir: string): dir is 'up' | 'down' | 'left' | 'right' {
|
|
465
|
+
return ['up', 'down', 'left', 'right'].includes(dir);
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## 8. Real-time Sync Patterns
|
|
472
|
+
|
|
473
|
+
### Debounce Rapid Updates
|
|
474
|
+
|
|
475
|
+
For high-frequency state changes (mouse position, typing indicators), debounce on the client:
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
function useDebouncedReducer(conn: DbConnection, intervalMs = 50) {
|
|
479
|
+
const lastSent = useRef(0);
|
|
480
|
+
|
|
481
|
+
return (x: number, y: number) => {
|
|
482
|
+
const now = Date.now();
|
|
483
|
+
if (now - lastSent.current > intervalMs) {
|
|
484
|
+
lastSent.current = now;
|
|
485
|
+
conn.reducers.updateCursor(x, y);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Presence
|
|
492
|
+
|
|
493
|
+
Use `clientConnected`/`clientDisconnected` lifecycle hooks for user presence:
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
// Server module
|
|
497
|
+
spacetimedb.clientConnected((ctx: ReducerContext) => {
|
|
498
|
+
const player = ctx.db.player.identity.find(ctx.sender);
|
|
499
|
+
if (player) {
|
|
500
|
+
ctx.db.player.identity.update({ ...player, isOnline: true, lastSeen: ctx.timestamp });
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
spacetimedb.clientDisconnected((ctx: ReducerContext) => {
|
|
505
|
+
const player = ctx.db.player.identity.find(ctx.sender);
|
|
506
|
+
if (player) {
|
|
507
|
+
ctx.db.player.identity.update({ ...player, isOnline: false, lastSeen: ctx.timestamp });
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## 9. Common Anti-Patterns
|
|
515
|
+
|
|
516
|
+
1. **God reducer** — one reducer doing everything; break into focused, atomic reducers
|
|
517
|
+
2. **Unfiltered subscriptions** — `SELECT * FROM table` with no WHERE clause wastes bandwidth
|
|
518
|
+
3. **Mutable primary keys** — using `username` as PK when it can change; use `identity` or UUID
|
|
519
|
+
4. **No input validation** — always validate at reducer entry; never trust client input
|
|
520
|
+
5. **Missing indexes** — subscription WHERE columns without `.index()` are slow
|
|
521
|
+
6. **Storing secrets in tables** — SpacetimeDB tables marked `public: true` are visible to subscribers
|
|
522
|
+
7. **Ignoring `ctx.sender`** — always verify the caller's identity for mutations on user-owned data
|
|
523
|
+
8. **No reconnection logic** — WebSocket connections drop; implement exponential backoff
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## References
|
|
528
|
+
|
|
529
|
+
- [SpacetimeDB Documentation](https://spacetimedb.com/docs)
|
|
530
|
+
- [TypeScript Module Quickstart](https://spacetimedb.com/docs/modules/typescript/quickstart/)
|
|
531
|
+
- [TypeScript SDK Reference](https://spacetimedb.com/docs/sdks/typescript/)
|
|
532
|
+
- Source patterns adapted from [iSyn/stdb-skills](https://github.com/iSyn/stdb-skills) (MIT)
|