@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.9
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/README.md +37 -0
- package/apps/README.md +25 -0
- package/apps/cad-creator/shared/cad/package.json +1 -1
- package/apps/client-cms-editor/backend/package.json +4 -6
- package/apps/client-cms-editor/frontend/package.json +6 -8
- package/apps/client-cms-editor/frontend/tsconfig.json +27 -8
- package/apps/client-cms-editor/package.json +1 -1
- package/apps/client-cms-editor/shared/cms/package.json +4 -6
- package/docs/LOCAL_ENGINE_COMPUTE_AUDIT_PLAN.md +299 -0
- package/docs/REPO_FILE_MAP.txt +132 -0
- package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
- package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
- package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
- package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
- package/native/agentsam-machine/cli/Cargo.toml +8 -1
- package/native/agentsam-machine/cli/README.md +21 -0
- package/native/agentsam-machine/core/Cargo.toml +7 -0
- package/native/agentsam-machine/core/README.md +14 -0
- package/native/agentsam-machine/core/build.rs +33 -0
- package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
- package/native/agentsam-machine/core/src/lib.rs +6 -0
- package/native/agentsam-machine/core/src/source_types.rs +2 -2
- package/package.json +31 -10
- package/packages/agentsam-brand/package.json +1 -1
- package/packages/agentsam-contracts/package.json +71 -20
- package/packages/agentsam-contracts/scripts/build.mjs +18 -0
- package/packages/agentsam-contracts/test/contracts.test.mjs +4 -1
- package/packages/agentsam-contracts/test/repository.test.mjs +4 -1
- package/packages/agentsam-contracts/tsconfig.build.json +10 -0
- package/packages/agentsam-errors/package.json +3 -2
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/tool.js +56 -0
- package/packages/agentsam-errors/test/tool.test.mjs +58 -0
- package/packages/agentsam-goap/README.md +52 -0
- package/packages/agentsam-goap/package.json +37 -0
- package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
- package/packages/agentsam-goap/src/adapters/memory.js +199 -0
- package/packages/agentsam-goap/src/contracts.js +226 -0
- package/packages/agentsam-goap/src/control-plane.js +112 -0
- package/packages/agentsam-goap/src/errors.js +157 -0
- package/packages/agentsam-goap/src/index.js +5 -0
- package/packages/agentsam-goap/src/world.js +202 -0
- package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
- package/packages/agentsam-goap/test/world.test.mjs +79 -0
- package/packages/agentsam-knowledge/package.json +3 -2
- package/packages/agentsam-nav/package.json +1 -1
- package/packages/agentsam-queue-control/package.json +1 -1
- package/packages/agentsam-rapid-rust/src/main.rs +1 -0
- package/packages/agentsam-repository/package.json +3 -2
- package/packages/agentsam-repository/src/goap.js +13 -14
- package/packages/agentsam-repository/src/tickets.js +15 -22
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
- package/packages/agentsam-vault/package.json +8 -5
- package/packages/agentsam-workbench/package.json +44 -17
- package/packages/connectors/cloudflare/package.json +4 -2
- package/packages/heuristic-theme/package.json +1 -1
- package/packages/identity/package.json +4 -3
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +10 -2
- package/packages/providers/completeful/package.json +1 -1
- package/packages/theme-church-site/README.md +2 -2
- package/packages/theme-church-site/package.json +3 -4
- package/packages/theme-church-site/src/index.js +1 -1
- package/packages/theme-church-site/test/theme.test.mjs +1 -1
- package/packages/theme-companions-site/README.md +2 -2
- package/packages/theme-companions-site/package.json +3 -4
- package/packages/theme-companions-site/src/index.js +1 -1
- package/packages/theme-companions-site/test/theme.test.mjs +1 -1
- package/packages/theme-floors-site/README.md +2 -2
- package/packages/theme-floors-site/package.json +3 -4
- package/packages/theme-floors-site/src/index.js +1 -1
- package/packages/theme-floors-site/test/theme.test.mjs +1 -1
- package/packages/theme-fuelnfree-site/README.md +2 -2
- package/packages/theme-fuelnfree-site/package.json +3 -4
- package/packages/theme-fuelnfree-site/src/index.js +1 -1
- package/packages/theme-fuelnfree-site/test/theme.test.mjs +1 -1
- package/packages/theme-handyman-site/README.md +2 -2
- package/packages/theme-handyman-site/package.json +3 -4
- package/packages/theme-handyman-site/src/index.js +1 -1
- package/packages/theme-handyman-site/test/theme.test.mjs +1 -1
- package/packages/theme-insurance-site/README.md +2 -2
- package/packages/theme-insurance-site/package.json +3 -4
- package/packages/theme-insurance-site/src/index.js +1 -1
- package/packages/theme-insurance-site/test/theme.test.mjs +1 -1
- package/packages/theme-scenes/package.json +1 -1
- package/packages/theme-shinshu-site/README.md +2 -2
- package/packages/theme-shinshu-site/package.json +3 -4
- package/packages/theme-shinshu-site/src/index.js +1 -1
- package/packages/theme-shinshu-site/test/theme.test.mjs +1 -1
- package/packages/work-graph/package.json +3 -2
- package/protocol/local-engine/benchmark.v1.schema.json +14 -0
- package/protocol/local-engine/engine.v1.schema.json +17 -0
- package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
- package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
- package/python/tests/test_repository_intelligence.py +30 -0
- package/src/cli/command-catalog.js +3 -1
- package/src/cli.js +20 -1
- package/src/commands/app.js +10 -0
- package/src/commands/engine.js +10 -0
- package/src/commands/goap-world.js +134 -0
- package/src/commands/goap.js +11 -4
- package/src/commands/machine-binary.js +33 -27
- package/src/commands/machine-runtime.js +266 -0
- package/src/commands/machine.js +155 -51
- package/src/commands/package.js +537 -0
- package/src/commands/plan-ledger.js +370 -0
- package/src/commands/plan.js +183 -0
- package/src/commands/runtime.js +25 -10
- package/src/commands/setup.js +30 -6
- package/src/commands/skill.js +78 -17
- package/src/commands/terminal.js +20 -8
- package/src/errors/contract.js +4 -4
- package/src/errors/diagnostic.js +1 -1
- package/src/errors/index.js +1 -1
- package/src/index.js +20 -0
- package/src/indexing/ingest/materials.js +237 -30
- package/src/knowledge/source.js +1 -1
- package/src/lib/setup/runtime.js +4 -2
- package/src/lib/slash-commands.js +1 -1
- package/src/local/runtime-store.js +24 -2
- package/src/local/sqlite.js +17 -0
- package/src/local-engine/assets.js +37 -0
- package/src/local-engine/audit.js +133 -0
- package/src/local-engine/benchmark.js +26 -0
- package/src/local-engine/contracts.js +101 -0
- package/src/local-engine/engines.js +142 -0
- package/src/local-engine/index.js +18 -0
- package/src/local-engine/runtime.js +39 -0
- package/src/sam/operations/package-audit.js +41 -0
- package/src/sam/seed.js +2 -0
- package/skills/grok-auth/SKILL.md +0 -110
- package/skills/grok-auth/agentsam.skill.json +0 -25
- package/skills/grok-auth/references/grok-identity.md +0 -64
- package/skills/grok-auth/references/per-user-data.md +0 -49
- package/skills/grok-auth/references/prewired-and-env.md +0 -54
- package/skills/grok-auth/references/session-ui.md +0 -133
- package/skills/grok-auth/references/sign-in-methods.md +0 -55
- package/skills/grok-auth/references/wiring.md +0 -71
- package/skills/grok-building-games/SKILL.md +0 -213
- package/skills/grok-building-games/agentsam.skill.json +0 -25
- package/skills/grok-building-games/references/3d-libs.md +0 -64
- package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
- package/skills/grok-building-games/references/audio.md +0 -129
- package/skills/grok-building-games/references/babylon.md +0 -202
- package/skills/grok-building-games/references/collision-physics.md +0 -122
- package/skills/grok-building-games/references/ecs-architecture.md +0 -111
- package/skills/grok-building-games/references/game-feel-juice.md +0 -110
- package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
- package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
- package/skills/grok-building-games/references/genres/fps.md +0 -105
- package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
- package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
- package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
- package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
- package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
- package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
- package/skills/grok-building-games/references/input.md +0 -139
- package/skills/grok-building-games/references/phaser.md +0 -277
- package/skills/grok-building-games/references/procedural-generation.md +0 -141
- package/skills/grok-building-games/references/save-persistence.md +0 -108
- package/skills/grok-building-games/references/threejs-foundational.md +0 -148
- package/skills/grok-controls/SKILL.md +0 -274
- package/skills/grok-controls/agentsam.skill.json +0 -25
- package/skills/grok-design-ui/SKILL.md +0 -122
- package/skills/grok-design-ui/agentsam.skill.json +0 -25
- package/skills/grok-design-ui/references/animations.md +0 -379
- package/skills/grok-design-ui/references/performance.md +0 -88
- package/skills/grok-design-ui/references/refined-ui.md +0 -384
- package/skills/grok-design-ui/references/surfaces.md +0 -247
- package/skills/grok-design-ui/references/typography.md +0 -123
- package/skills/grok-game-animation-frames/SKILL.md +0 -84
- package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
- package/skills/grok-game-asset-core/SKILL.md +0 -69
- package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
- package/skills/grok-game-character-consistency/SKILL.md +0 -69
- package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
- package/skills/grok-game-tilesets/SKILL.md +0 -65
- package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
- package/skills/grok-game-ui-icons/SKILL.md +0 -56
- package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
- package/skills/grok-generate2dmap/LICENSE +0 -21
- package/skills/grok-generate2dmap/SKILL.md +0 -120
- package/skills/grok-generate2dmap/SOURCE.md +0 -6
- package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
- package/skills/grok-generate2dmap/references/deliverables.md +0 -101
- package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
- package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
- package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
- package/skills/grok-generate2dmap/references/pipeline.md +0 -149
- package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
- package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
- package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
- package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
- package/skills/grok-generate2dsprite/LICENSE +0 -21
- package/skills/grok-generate2dsprite/SKILL.md +0 -313
- package/skills/grok-generate2dsprite/SOURCE.md +0 -6
- package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
- package/skills/grok-generate2dsprite/references/modes.md +0 -124
- package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
- package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
- package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
- package/skills/grok-imagine/SKILL.md +0 -201
- package/skills/grok-imagine/agentsam.skill.json +0 -25
- package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
- package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
- package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
- package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
- package/skills/grok-neon/SKILL.md +0 -157
- package/skills/grok-neon/agentsam.skill.json +0 -25
- package/skills/grok-og/SKILL.md +0 -102
- package/skills/grok-og/agentsam.skill.json +0 -25
- package/skills/grok-og/references/brand-pass.md +0 -53
- package/skills/grok-og/references/custom-card.md +0 -107
- package/skills/grok-og/references/favicon-and-icons.md +0 -48
- package/skills/grok-og/references/og-type-contract.md +0 -18
- package/skills/grok-og/references/placeholder-card.md +0 -21
- package/skills/grok-og/references/x-banner.md +0 -41
- package/skills/grok-threejs/SKILL.md +0 -67
- package/skills/grok-threejs/agentsam.skill.json +0 -25
- package/skills/grok-threejs/references/llms-full.txt +0 -2780
- package/skills/grok-video2dsprite/LICENSE +0 -21
- package/skills/grok-video2dsprite/SKILL.md +0 -236
- package/skills/grok-video2dsprite/SOURCE.md +0 -6
- package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
- package/skills/grok-video2dsprite/references/pipeline.md +0 -90
- package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
- package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
- package/skills/grok-xai-api/SKILL.md +0 -152
- package/skills/grok-xai-api/agentsam.skill.json +0 -25
- package/test/account-session.test.mjs +0 -101
- package/test/agent-capabilities.test.mjs +0 -67
- package/test/app-authority-context.test.mjs +0 -32
- package/test/app-building-skills.test.mjs +0 -61
- package/test/apps-scaffold-contract.test.mjs +0 -115
- package/test/blender-cad.test.mjs +0 -146
- package/test/cad-docker.test.mjs +0 -96
- package/test/capabilities.test.mjs +0 -133
- package/test/cli/api-key-env-whoami.test.mjs +0 -129
- package/test/cli/catalog-authority.test.mjs +0 -64
- package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
- package/test/cli/eval-live.test.mjs +0 -219
- package/test/cli/go.test.mjs +0 -128
- package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
- package/test/cli/machine-command.test.mjs +0 -34
- package/test/cli/mcp-client.test.mjs +0 -256
- package/test/cli/preferences-runtime.test.mjs +0 -11
- package/test/cli/runtime-persist.test.mjs +0 -56
- package/test/cli/runtime-ui.test.mjs +0 -141
- package/test/cli/rust-command.test.mjs +0 -21
- package/test/cli/skill-npm-and-env.test.mjs +0 -52
- package/test/cli/status-actions.test.mjs +0 -88
- package/test/cli/wireframes-go-registry.test.mjs +0 -139
- package/test/cli-preferences.test.mjs +0 -46
- package/test/cloudflare-connector.test.mjs +0 -93
- package/test/cloudflare-runtime.test.mjs +0 -82
- package/test/context.test.mjs +0 -159
- package/test/credentials-audit.test.mjs +0 -113
- package/test/deploy-health-scan.test.mjs +0 -95
- package/test/deploy-receipt.test.mjs +0 -91
- package/test/dockerize.test.mjs +0 -93
- package/test/error-diagnostics.test.mjs +0 -124
- package/test/eval-context.test.mjs +0 -37
- package/test/execution-approvals.test.mjs +0 -27
- package/test/fixtures/cad/courtyard-house.json +0 -208
- package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
- package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
- package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
- package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
- package/test/gcloud-auth.test.mjs +0 -111
- package/test/go/build-source-identity.test.mjs +0 -31
- package/test/go/cloudflare-probe.test.mjs +0 -317
- package/test/go/distribution.test.mjs +0 -28
- package/test/google-cloud-connection.test.mjs +0 -83
- package/test/google-cloud-inventory.test.mjs +0 -64
- package/test/indexing-provider.test.mjs +0 -29
- package/test/init-options.test.mjs +0 -35
- package/test/integration/ai-access-onboarding.test.mjs +0 -47
- package/test/integration/app-command.test.mjs +0 -85
- package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
- package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
- package/test/integration/cad-discovery.test.mjs +0 -158
- package/test/integration/cad-docker-executor.test.mjs +0 -249
- package/test/integration/cad-execution.test.mjs +0 -184
- package/test/integration/cad-project-app.test.mjs +0 -31
- package/test/integration/cad-project-d1.test.mjs +0 -25
- package/test/integration/cad-project-native.test.mjs +0 -24
- package/test/integration/cad-project-workflow.test.mjs +0 -9
- package/test/integration/cad-project.test.mjs +0 -85
- package/test/integration/cli-help.test.mjs +0 -41
- package/test/integration/cms-app-scaffold.test.mjs +0 -77
- package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
- package/test/integration/codebaseindex-ingest.test.mjs +0 -255
- package/test/integration/core-client.integration.test.mjs +0 -55
- package/test/integration/database-hosted-honesty.test.mjs +0 -49
- package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
- package/test/integration/error-runtime-rpc.test.mjs +0 -71
- package/test/integration/features-resolve.test.mjs +0 -147
- package/test/integration/hosted-work-host-authority.test.mjs +0 -47
- package/test/integration/icon-registry.test.mjs +0 -67
- package/test/integration/ingest-discover-models.test.mjs +0 -30
- package/test/integration/inspect-path-cli.test.mjs +0 -46
- package/test/integration/install-script.test.mjs +0 -110
- package/test/integration/inventory-core.test.mjs +0 -53
- package/test/integration/inventory-eligibility.test.mjs +0 -59
- package/test/integration/inventory-evidence.test.mjs +0 -125
- package/test/integration/knowledge-rpc.test.mjs +0 -112
- package/test/integration/local-fs.test.mjs +0 -113
- package/test/integration/local-provider-bridge.test.mjs +0 -65
- package/test/integration/local-studio-settings-production.test.mjs +0 -40
- package/test/integration/lockfile-sync.test.mjs +0 -26
- package/test/integration/merkle-cli.test.mjs +0 -61
- package/test/integration/merkle-persistence-identity.test.mjs +0 -48
- package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
- package/test/integration/provider-env-cli.test.mjs +0 -60
- package/test/integration/provider-factory.test.mjs +0 -197
- package/test/integration/repository-company-graph.test.mjs +0 -90
- package/test/integration/runtime-migrations.test.mjs +0 -87
- package/test/integration/runtime-status.integration.test.mjs +0 -227
- package/test/integration/sam-activity-recovery.test.mjs +0 -147
- package/test/integration/sam-decision.test.mjs +0 -584
- package/test/integration/sam-kernel.test.mjs +0 -99
- package/test/integration/sam-planning-astar.test.mjs +0 -279
- package/test/integration/scaffold-cloudflare.test.mjs +0 -46
- package/test/integration/skill-runtime.test.mjs +0 -240
- package/test/integration/storage-architecture.test.mjs +0 -154
- package/test/integration/store-discovery.test.mjs +0 -44
- package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
- package/test/integration/terminal-exec.integration.test.mjs +0 -86
- package/test/integration/theme-package-registry.test.mjs +0 -31
- package/test/integration/tool-runtime.test.mjs +0 -124
- package/test/integration/tool-schema.test.mjs +0 -59
- package/test/jr-dev-skill.test.mjs +0 -26
- package/test/knowledge-context-pack.test.mjs +0 -19
- package/test/knowledge-postgres.test.mjs +0 -40
- package/test/knowledge-service.test.mjs +0 -110
- package/test/knowledge.test.mjs +0 -206
- package/test/live/terminal-transport.live.test.mjs +0 -24
- package/test/local-sessions.test.mjs +0 -57
- package/test/local-studio-deploy.test.mjs +0 -83
- package/test/loopback-oauth.test.mjs +0 -53
- package/test/merkle-render.test.mjs +0 -31
- package/test/mini.test.mjs +0 -140
- package/test/model-catalog.test.mjs +0 -70
- package/test/models.test.mjs +0 -309
- package/test/npm10-lock.test.mjs +0 -29
- package/test/ollama.test.mjs +0 -137
- package/test/open-url.test.mjs +0 -64
- package/test/openai-responses.test.mjs +0 -155
- package/test/portable-context.test.mjs +0 -94
- package/test/project-config.test.mjs +0 -81
- package/test/project-rules.test.mjs +0 -44
- package/test/provider-credentials.test.mjs +0 -106
- package/test/rehydrate.test.mjs +0 -25
- package/test/release-hygiene.test.mjs +0 -42
- package/test/repository-snapshot-view.test.mjs +0 -112
- package/test/responses-runner.test.mjs +0 -465
- package/test/runtime-activity.test.mjs +0 -98
- package/test/sdk-worker-contract.test.mjs +0 -72
- package/test/security.test.mjs +0 -266
- package/test/setup-planner.test.mjs +0 -74
- package/test/setup-runtime.test.mjs +0 -51
- package/test/shell.test.mjs +0 -281
- package/test/skills.test.mjs +0 -22
- package/test/smoke.mjs +0 -122
- package/test/telemetry.test.mjs +0 -79
- package/test/terminal/local-pty.mock.test.mjs +0 -153
- package/test/terminal-machine-identity.test.mjs +0 -88
- package/test/theme-portability.test.mjs +0 -14
- package/test/tools-search.test.mjs +0 -73
- package/test/unit/website-assets-bindings.test.mjs +0 -60
- package/test/whoami-resume.test.mjs +0 -157
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: auth
|
|
3
|
-
description: >
|
|
4
|
-
Add user accounts and sign-in to this TanStack Start app. Use when the app
|
|
5
|
-
needs authentication, sign-in, user accounts, protected routes, or per-user
|
|
6
|
-
data. Triggers on "auth", "login", "log in", "sign in", "sign up", "account",
|
|
7
|
-
"users", "authentication", "protected", "who is logged in", "current user",
|
|
8
|
-
"per-user".
|
|
9
|
-
metadata:
|
|
10
|
-
short-description: "Auth via the Grok broker (Google, X) or local email/password — no other methods supported"
|
|
11
|
-
user-invocable: false
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# Auth
|
|
15
|
-
|
|
16
|
-
This app runs its **own** [Better Auth](https://better-auth.com) at
|
|
17
|
-
`/api/auth/*`, federating to the shared **Grok auth broker** (`auth.grok.me`)
|
|
18
|
-
via the `genericOAuth` plugin. This template wires **Google** and **X**.
|
|
19
|
-
|
|
20
|
-
**Supported sign-in methods — use ONLY these three; nothing else is supported:
|
|
21
|
-
Google, X, and email/password.** No other social/OAuth provider (GitHub, Apple,
|
|
22
|
-
Discord, …), no magic links, passkeys, OTP, phone/SMS, or anonymous sign-in. Do
|
|
23
|
-
not add entries to `GROK_PROVIDERS`. Method detail and the email/password switch
|
|
24
|
-
(edit **only** `src/lib/auth/email-password.ts`): `references/sign-in-methods.md`.
|
|
25
|
-
**Exception — gate viewers are signed in already; NEVER render login/re-auth
|
|
26
|
-
buttons for them. Connector / app-data apps: ONLY gate "Continue with Grok",
|
|
27
|
-
no Google/X buttons**: `references/grok-identity.md`.
|
|
28
|
-
|
|
29
|
-
**Sign-in is OFF by default** — the template ships `.grok/app-env.json` with
|
|
30
|
-
`{"VITE_AUTH_ENABLED": "false"}`, so only add accounts when the ask calls for
|
|
31
|
-
them (AGENTS.md §0.5). Switching it on is "Turning sign-in on" below.
|
|
32
|
-
|
|
33
|
-
**Once on, sign-in is REAL — including in the sandbox live preview.** Do **NOT**
|
|
34
|
-
scaffold demo/mock/hardcoded users. Preview: popup + baked preview client;
|
|
35
|
-
deployed: per-app client + `DATABASE_URL` + zero-click gate sign-in
|
|
36
|
-
(`references/prewired-and-env.md`).
|
|
37
|
-
|
|
38
|
-
**While OFF** (`VITE_AUTH_ENABLED=false`) a **dev user** is returned so a
|
|
39
|
-
non-auth app renders without a signed-in visitor — dev and preview only.
|
|
40
|
-
Deployed, the flag is the platform's (always `"true"`), so `requireUserId`
|
|
41
|
-
rejects every visitor — auth-off apps use neither it nor `authMiddleware`.
|
|
42
|
-
|
|
43
|
-
Everything is **preinstalled and pre-wired in `src/lib/auth/`** — do not
|
|
44
|
-
`npm install` anything; `better-auth` is the only auth package (never
|
|
45
|
-
`@neondatabase/*`, `@stackframe/*`, or `@clerk/*`). **Do not edit or rewrite any
|
|
46
|
-
file under `src/lib/auth/`** — `server.ts` least of all — except
|
|
47
|
-
`email-password.ts` for its one flag. Per-file map:
|
|
48
|
-
`references/prewired-and-env.md`.
|
|
49
|
-
|
|
50
|
-
**`/auth/popup` is already handled by the template Vite plugin**
|
|
51
|
-
(`vite.config.ts` → `popup.server.ts`): it never paints the React app. **Do NOT
|
|
52
|
-
create `src/routes/auth/popup.tsx`** (or any React page / client OAuth at that
|
|
53
|
-
path) — that shows the full app inside the popup, the common failure mode.
|
|
54
|
-
|
|
55
|
-
**Never write a `.env` / `.env.local` / `.env.example`** in this sandbox: live
|
|
56
|
-
preview needs **zero** env configuration and a deployed app gets its vars
|
|
57
|
-
injected by the platform. The knobs that exist are in
|
|
58
|
-
`references/prewired-and-env.md` — never expose a non-`VITE_` var to the client.
|
|
59
|
-
|
|
60
|
-
`migrations/auth/0001_auth.sql` is the Better Auth schema — **do not edit**. It
|
|
61
|
-
sits outside the globbed `migrations/` directory (neither applier descends), so
|
|
62
|
-
it is not applied to apps without sign-in; "Turning sign-in on" copies it up.
|
|
63
|
-
|
|
64
|
-
## Turning sign-in on
|
|
65
|
-
|
|
66
|
-
Do all of this — the routes alone render the disabled branch:
|
|
67
|
-
|
|
68
|
-
1. **Flag:** delete the `VITE_AUTH_ENABLED` key from `.grok/app-env.json` and
|
|
69
|
-
**restart the dev server**. Vite reads env at startup, so HMR will not pick
|
|
70
|
-
it up. `npm run dev`, `npm run build` and `npm run preview` all read that
|
|
71
|
-
file through `scripts/with-app-env.mjs`, so preview and the built output flip
|
|
72
|
-
together — never start Vite directly.
|
|
73
|
-
2. **Schema:** `cp migrations/auth/0001_auth.sql migrations/0001_auth.sql`, then
|
|
74
|
-
restart so it applies. It is tracked by basename in `_migrations`, so a
|
|
75
|
-
database that already has it will not re-run it.
|
|
76
|
-
3. **Routes:** add `src/routes/api/auth/$.ts` + `src/routes/login.tsx` — copy
|
|
77
|
-
both from `references/wiring.md` (the catch-all API route is what makes
|
|
78
|
-
`/api/auth/*` and the broker callback work).
|
|
79
|
-
4. **Sign out:** a login with no way out is not done — render `<UserButton />`
|
|
80
|
-
from `@/lib/auth/gates` (wires `signOut()`; hides sign-out for gate sessions).
|
|
81
|
-
5. **Existing data:** wrap the app's server functions in `authMiddleware` (an
|
|
82
|
-
auth-off app must not have been using it — see the `neon` skill). Rows from
|
|
83
|
-
before sign-in existed are **development data**: drop and recreate them
|
|
84
|
-
unless the user says otherwise — don't hand them to whoever signs in first.
|
|
85
|
-
|
|
86
|
-
## Building on it once it's on
|
|
87
|
-
|
|
88
|
-
- **Sign in / out:** `signIn(providerId)` and `signOut()` from
|
|
89
|
-
`@/lib/auth/client`; `GROK_PROVIDERS` renders the buttons. The popup,
|
|
90
|
-
bearer-token hand-off, and request attachment are internal — leave them alone.
|
|
91
|
-
Prefer `<UserButton />` (it handles the pending and failure states); `signOut()`
|
|
92
|
-
rejects when deployed if the server never confirms — catch it. Never
|
|
93
|
-
`authClient.signOut()`: it leaves the preview bearer token attached to every
|
|
94
|
-
later request, so the visitor stays signed in.
|
|
95
|
-
- **Reading the user:** `useCurrentUser()` is display-only (`null` means
|
|
96
|
-
*loading OR signed out*, so never redirect on it alone); guard on
|
|
97
|
-
`useCurrentUserState()`'s `isPending` instead. Gates (`SignedIn`, `SignedOut`,
|
|
98
|
-
`SignInGate`, `RedirectToSignIn`, `UserButton`) live in `@/lib/auth/gates`.
|
|
99
|
-
CTA hard rules, skeleton, and cookie-SSR zero-flash: `references/session-ui.md`.
|
|
100
|
-
- **Per-user data (mandatory):** every server function that touches per-user data
|
|
101
|
-
must use the prewired `authMiddleware` and scope every read **and** write to
|
|
102
|
-
`context.userId` — a Postgres driver has full DB access, so nothing else limits
|
|
103
|
-
the query. Keep `user_id` columns `TEXT`; never trust a client-supplied user id;
|
|
104
|
-
signed out, the middleware throws `UnauthorizedError` (401). Code and
|
|
105
|
-
disabled-mode semantics: `references/per-user-data.md`.
|
|
106
|
-
- **Security model:** headless broker, `__Host-` cookies + `trustedOrigins`, and
|
|
107
|
-
Fetch-Metadata sibling isolation are already wired — never weaken them to make
|
|
108
|
-
an error go away (`references/sign-in-methods.md` covers the model and the
|
|
109
|
-
"Invalid origin" fix).
|
|
110
|
-
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schema": "agentsam.skill.v1",
|
|
3
|
-
"id": "grok-auth",
|
|
4
|
-
"name": "Grok \u00b7 auth",
|
|
5
|
-
"description": "Auth via the Grok broker (Google, X) or local email/password \u2014 no other methods supported",
|
|
6
|
-
"icon": "skill",
|
|
7
|
-
"slash": {
|
|
8
|
-
"suggested": "/grok-auth"
|
|
9
|
-
},
|
|
10
|
-
"instructions": {
|
|
11
|
-
"source": "local_file",
|
|
12
|
-
"ref": "SKILL.md"
|
|
13
|
-
},
|
|
14
|
-
"execution": {
|
|
15
|
-
"mode": "turn",
|
|
16
|
-
"tools": [],
|
|
17
|
-
"operations": [],
|
|
18
|
-
"capabilities": []
|
|
19
|
-
},
|
|
20
|
-
"provenance": {
|
|
21
|
-
"source": "apps/local-studio/.grok/skills",
|
|
22
|
-
"vendor": "grok",
|
|
23
|
-
"status": "imported"
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Sign in with Grok (deployed apps — zero clicks)
|
|
2
|
-
|
|
3
|
-
Behind the edge gate, every proxied request from a signed-in Grok viewer
|
|
4
|
-
carries an unforgeable `x-grok-identity` JWT (EdDSA, minted per request; the
|
|
5
|
-
gate strips any client-supplied copy). The pre-wired `gateIdentitySessions`
|
|
6
|
-
plugin (`src/lib/auth/gate-session.server.ts`) verifies it against the gate's
|
|
7
|
-
JWKS (`/__gate/identity-key`, via `src/lib/auth/gate-identity.server.ts`) and,
|
|
8
|
-
when the app has no session yet, materializes the Better Auth session for that
|
|
9
|
-
viewer automatically — no sign-in button, no redirect, no broker round-trip.
|
|
10
|
-
`useSession` / `useCurrentUser` simply return the Grok user.
|
|
11
|
-
|
|
12
|
-
The broker OAuth flow is the **fallback** for anonymous/public viewers and for
|
|
13
|
-
contexts without the gate. The live preview gets the same zero-click identity
|
|
14
|
-
from the in-VM preview proxy at `http://127.0.0.1:6014` (preview tokens carry
|
|
15
|
-
audience `preview`); the popup mechanism remains the fallback there.
|
|
16
|
-
|
|
17
|
-
## Never render sign-in or re-auth UI to a gate viewer
|
|
18
|
-
|
|
19
|
-
A gate-authenticated viewer is **already signed in**, and the gate refreshes
|
|
20
|
-
connector tokens on every proxied request — **the platform has no re-auth
|
|
21
|
-
concept**. Never render "Re-auth with Grok", "Sign in again", "Refresh
|
|
22
|
-
session", or a standing "Continue with Grok" button: sign-in UI may appear
|
|
23
|
-
only in the `app-data` skill's `login` error state, after a connector call
|
|
24
|
-
actually returned `loginRequired: true`.
|
|
25
|
-
|
|
26
|
-
The live preview gets the same zero-click session, so a sign-in button visible
|
|
27
|
-
to the owner in the preview indicates a bug (a CTA rendered while the session
|
|
28
|
-
check was still pending, or rendered in reaction to a data error) — fix it,
|
|
29
|
-
don't restyle it. For any fallback sign-in surface use `<SignInGate>` from
|
|
30
|
-
`@/lib/auth/gates`: it renders sign-in UI only after the session check resolved
|
|
31
|
-
to no user, never during loading and never from a data error.
|
|
32
|
-
|
|
33
|
-
Sign-out is also a no-op for a gate session — the next request re-materializes
|
|
34
|
-
it from `x-grok-identity`, an instant sign-back-in loop. `<UserButton />`
|
|
35
|
-
already hides its sign-out control for gate sessions; never build a custom
|
|
36
|
-
sign-out (or any sign-out route/handler) for gate viewers.
|
|
37
|
-
|
|
38
|
-
## Files (pre-wired — do not edit)
|
|
39
|
-
|
|
40
|
-
| File | Role |
|
|
41
|
-
|---|---|
|
|
42
|
-
| `gate-identity.server.ts` | Verifies the gate's `x-grok-identity` viewer JWT (EdDSA vs the gate JWKS; fail-closed). Server-only. |
|
|
43
|
-
| `gate-session.server.ts` | Better Auth plugin that turns a verified gate identity into the app session with zero clicks. Already registered in `server.ts`. |
|
|
44
|
-
|
|
45
|
-
## Env (deployer-injected)
|
|
46
|
-
|
|
47
|
-
| Var | Scope | Meaning |
|
|
48
|
-
|---|---|---|
|
|
49
|
-
| `GROK_PROJECT_ID` | server | deployed apps: enables "Sign in with Grok" (`x-grok-identity` audience check `app:<project_id>`) |
|
|
50
|
-
| `GROK_GATE_ORIGIN` | server | gate public origin override (JWKS + issuer pin); unset → preview mode (no `GROK_PROJECT_ID`) defaults to the in-VM proxy `http://127.0.0.1:6014` (audience `preview`), deployed mode derives it from the inbound host |
|
|
51
|
-
|
|
52
|
-
Deployed behavior: gate-authenticated viewers are signed in automatically from
|
|
53
|
-
`x-grok-identity`; the deployer also injects a per-app broker client +
|
|
54
|
-
`DATABASE_URL`, so the fallback sign-in persists identities in Postgres.
|
|
55
|
-
|
|
56
|
-
## Connector / app-data apps: gate sign-in only
|
|
57
|
-
|
|
58
|
-
When the `app-data` skill applies, the login page offers ONLY "Continue with
|
|
59
|
-
Grok" via the gate sign-in — the zero-click `x-grok-identity` session above, or
|
|
60
|
-
the gate-built `loginUrl` returned by a connector call. Do not wire Google/X
|
|
61
|
-
buttons for these apps: a broker login can mint an identity that is not the
|
|
62
|
-
gate viewer the connector data belongs to. The three-method rule applies to
|
|
63
|
-
apps without connector data. Still no new `GROK_PROVIDERS` entries, still never
|
|
64
|
-
edit `src/lib/auth/`.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Per-user data (server-side — mandatory)
|
|
2
|
-
|
|
3
|
-
Pair auth with the DB (see the `neon` skill). A regular Postgres driver has full
|
|
4
|
-
DB access, so **every** server function that touches per-user data must verify
|
|
5
|
-
the caller and scope rows to them. Use the prewired **`authMiddleware`**: it
|
|
6
|
-
resolves the same-origin session to a verified `context.userId` (and rejects
|
|
7
|
-
scripted cross-site/sibling requests) — no token threading:
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import { createServerFn } from "@tanstack/react-start";
|
|
11
|
-
import { getSql } from "@/lib/db";
|
|
12
|
-
import { authMiddleware } from "@/lib/auth/middleware";
|
|
13
|
-
|
|
14
|
-
export const listTodos = createServerFn({ method: "GET" })
|
|
15
|
-
.middleware([authMiddleware])
|
|
16
|
-
.handler(async ({ context }) => {
|
|
17
|
-
const sql = await getSql();
|
|
18
|
-
// Type the row shape — a server fn's return must be provably serializable.
|
|
19
|
-
return sql<{ id: number; title: string; done: boolean }>`select id, title, done from todos where user_id = ${context.userId} order by id desc`;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Inputs go through `.validator()` (the current API); the client passes `{ data }`:
|
|
23
|
-
export const addTodo = createServerFn({ method: "POST" })
|
|
24
|
-
.validator((title: string) => title.trim())
|
|
25
|
-
.middleware([authMiddleware])
|
|
26
|
-
.handler(async ({ context, data: title }) => {
|
|
27
|
-
if (!title) return;
|
|
28
|
-
const sql = await getSql();
|
|
29
|
-
await sql`insert into todos (user_id, title) values (${context.userId}, ${title})`;
|
|
30
|
-
});
|
|
31
|
-
// mutations must scope writes too: `... where id = ${id} and user_id = ${context.userId}`
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Call these from **client code** (effects, event handlers, React Query) — that's
|
|
35
|
-
where `Sec-Fetch-Site: same-origin` holds:
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
useEffect(() => { listTodos().then(setTodos).catch(() => setTodos([])); }, []);
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Semantics: signed out → the middleware throws `UnauthorizedError` (message
|
|
42
|
-
`"Unauthorized"`, `status` 401 — match it to send the visitor to sign-in), in the
|
|
43
|
-
live preview too (real auth). With auth disabled (`VITE_AUTH_ENABLED=false`) it
|
|
44
|
-
resolves the dev user (`"dev-user"`) in dev and preview only — the deployed flag
|
|
45
|
-
comes from the deployer (today always `"true"`), so deployed it rejects every
|
|
46
|
-
visitor — which is why an app without sign-in must not use the middleware at all
|
|
47
|
-
(see the `neon` skill). Keep `user_id` columns
|
|
48
|
-
`TEXT` (Better Auth uses text ids; the disabled dev user is `'dev-user'`). Never
|
|
49
|
-
trust a client-supplied user id — only the middleware / `requireUserId()` result.
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# What's pre-wired, and the env vars
|
|
2
|
-
|
|
3
|
-
## `src/lib/auth/`
|
|
4
|
-
|
|
5
|
-
| File | Use it for |
|
|
6
|
-
|---|---|
|
|
7
|
-
| `client.ts` | Browser client. `signIn(providerId)`, `signOut()`, `authEnabled`, `GROK_PROVIDERS`. |
|
|
8
|
-
| `server.ts` | The Better Auth instance (server-only). **Do not edit or rewrite.** Import only from `/api/auth/$`. |
|
|
9
|
-
| `email-password.ts` | **Only** place to enable local email/password (`emailAndPasswordEnabled = true`). |
|
|
10
|
-
| `popup.server.ts` | Live-preview popup handler (server-only). Already wired by the Vite plugin — do not create a route for it. |
|
|
11
|
-
| `providers.ts` | `GROK_PROVIDERS` — the fixed broker upstream list (Google and X only; don't add others). |
|
|
12
|
-
| `use-current-user.ts` | `useCurrentUser()` / `useCurrentUserState()` React hooks. |
|
|
13
|
-
| `gates.tsx` | `SignedIn`, `SignedOut`, `RedirectToSignIn`, `UserButton`. |
|
|
14
|
-
| `middleware.ts` | `authMiddleware` for server functions → verified `context.userId`. |
|
|
15
|
-
| `verify.server.ts` | `requireUserId()` / `getSessionUser()` (server-only) for manual wiring. |
|
|
16
|
-
|
|
17
|
-
## How each mode gets its credentials
|
|
18
|
-
|
|
19
|
-
- **Live preview** (`*.grok-sandbox.com`): the app is an embedded iframe, so
|
|
20
|
-
sign-in opens a **popup** (a top-level redirect to the broker can't work inside
|
|
21
|
-
the iframe) and federates via a baked shared **preview client**
|
|
22
|
-
(`src/lib/auth/preview.ts`). The handler 302s straight to the broker/upstream
|
|
23
|
-
login; on return the popup posts the session bearer back in a tiny HTML page.
|
|
24
|
-
Sessions (and email/password users) persist in the app's embedded PGLite DB —
|
|
25
|
-
the SAME DB as app data — and, since the iframe's cookies are partitioned,
|
|
26
|
-
ride that bearer token; all of it lives in `src/lib/auth`.
|
|
27
|
-
Restarting the preview resets the DB.
|
|
28
|
-
- **Deployed**: the deployer injects a per-app client + `DATABASE_URL`, so
|
|
29
|
-
sign-in persists identities in Postgres.
|
|
30
|
-
|
|
31
|
-
## Env vars — do **not** create a `.env` file
|
|
32
|
-
|
|
33
|
-
**Never write a `.env` / `.env.local` / `.env.example` for auth (or anything
|
|
34
|
-
else) in this sandbox.** Live preview sign-in works out of the box with **zero**
|
|
35
|
-
env configuration: the server falls back to the baked preview client in
|
|
36
|
-
`src/lib/auth/preview.ts`, derives the `*.grok-sandbox.com` origin per-request,
|
|
37
|
-
mints a process-stable session secret, and persists sessions in embedded
|
|
38
|
-
PGLite. Deployed apps get `GROK_AUTH_*` / `BETTER_AUTH_*` / `DATABASE_URL`
|
|
39
|
-
injected by the platform — still not something you write into a file.
|
|
40
|
-
|
|
41
|
-
Optional process-env knobs (platform / rare overrides only — **do not** put
|
|
42
|
-
these in a file you create):
|
|
43
|
-
|
|
44
|
-
| Var | Where | Purpose |
|
|
45
|
-
|---|---|---|
|
|
46
|
-
| `VITE_AUTH_ENABLED` | client | `"false"` in the shipped `.grok/app-env.json` (dev user); drop the key to turn sign-in ON. Only client-visible auth flag |
|
|
47
|
-
| `BETTER_AUTH_URL` | server | app's own public origin; unset in preview (origin is derived per-request) |
|
|
48
|
-
| `BETTER_AUTH_SECRET` | server | signs this app's own sessions (process-stable fallback in preview; survives HMR) |
|
|
49
|
-
| `GROK_AUTH_ISSUER` | server | the shared broker (defaults to `https://auth.grok.me`) |
|
|
50
|
-
| `GROK_AUTH_CLIENT_ID` / `GROK_AUTH_CLIENT_SECRET` | server | per-app client (falls back to the preview client) |
|
|
51
|
-
| `DATABASE_URL` | server | when deployed, Better Auth persists here (preview persists to the embedded PGLite — same DB as app data) |
|
|
52
|
-
|
|
53
|
-
Never expose a non-`VITE_` var to the client. The preview client id/secret live
|
|
54
|
-
server-only in `src/lib/auth/preview.ts`.
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
# Reading the user, protecting routes, and preventing flicker
|
|
2
|
-
|
|
3
|
-
## When sign-in UI may render (hard rules)
|
|
4
|
-
|
|
5
|
-
- **Connector / owner-data apps: never gate the data fetch behind a session.**
|
|
6
|
-
When the data comes from the app's connector grants, the fetch runs on the
|
|
7
|
-
gate-injected connector token — a chain that does not involve the app
|
|
8
|
-
session. Fetch first; use the session for personalization only (greeting,
|
|
9
|
-
per-user rows). Requiring sign-in before fetching adds a click that changes
|
|
10
|
-
nothing.
|
|
11
|
-
- **A sign-in CTA may render only after the session check has RESOLVED to no
|
|
12
|
-
user** — never while `isPending` is true (no CTA flash on load), and never
|
|
13
|
-
as a reaction to a data error (the `app-data` skill's error mapping owns
|
|
14
|
-
those states; only its `login` kind ever shows "Continue with Grok").
|
|
15
|
-
- **In preview, gate identity signs the owner in with zero clicks** — a
|
|
16
|
-
visible sign-in button for the owner in the preview is a bug to fix, not a
|
|
17
|
-
style choice (`grok-identity.md`).
|
|
18
|
-
- **Use `<SignInGate>` from `@/lib/auth/gates`** — `{ children, fallback? }`:
|
|
19
|
-
nothing while pending, `children` when signed in, `fallback` (or the
|
|
20
|
-
standard provider buttons) only once signed out is known. Do not hand-roll
|
|
21
|
-
sign-in CTAs from `useCurrentUser()`.
|
|
22
|
-
|
|
23
|
-
## Reading the user / protecting routes
|
|
24
|
-
|
|
25
|
-
`@/lib/auth/use-current-user` (with auth on these reflect the REAL session, so a
|
|
26
|
-
preview visitor is signed out until they sign in):
|
|
27
|
-
|
|
28
|
-
- `useCurrentUser()` → `AppUser | null` — for display. `null` means *loading OR
|
|
29
|
-
signed out*, so never redirect on it alone.
|
|
30
|
-
- `useCurrentUserState()` → `{ user, isPending }` — for guards: wait for
|
|
31
|
-
`isPending` to clear before treating `user: null` as signed out, or a hard
|
|
32
|
-
reload bounces signed-in users to sign-in.
|
|
33
|
-
|
|
34
|
-
**State components** from `@/lib/auth/gates`: `SignedIn`, `SignedOut`,
|
|
35
|
-
`SignInGate` (`{ children, fallback? }` — nothing while pending, `children`
|
|
36
|
-
signed in, `fallback` or the standard provider buttons only once signed out is
|
|
37
|
-
known; prefer it over hand-rolled sign-in CTAs), `RedirectToSignIn`,
|
|
38
|
-
`UserButton`. (When auth is disabled via `VITE_AUTH_ENABLED=false` they apply
|
|
39
|
-
dev-user semantics so a non-auth app still renders.)
|
|
40
|
-
|
|
41
|
-
```tsx
|
|
42
|
-
import { useCurrentUser, useCurrentUserState } from "@/lib/auth/use-current-user";
|
|
43
|
-
import { RedirectToSignIn, SignedIn, SignedOut, UserButton } from "@/lib/auth/gates";
|
|
44
|
-
|
|
45
|
-
function Navbar() {
|
|
46
|
-
const user = useCurrentUser(); // display only — null may just mean "loading"
|
|
47
|
-
return (
|
|
48
|
-
<>
|
|
49
|
-
<span>{user?.displayName ?? "Guest"}</span>
|
|
50
|
-
<SignedOut><a href="/login">Sign in</a></SignedOut>
|
|
51
|
-
<SignedIn><UserButton /></SignedIn>
|
|
52
|
-
</>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function AccountPage() {
|
|
57
|
-
const { user, isPending } = useCurrentUserState();
|
|
58
|
-
if (isPending) return null; // session still resolving
|
|
59
|
-
if (!user) return <RedirectToSignIn />; // client-side Navigate — not window.location
|
|
60
|
-
return <h1>Welcome, {user.displayName}</h1>;
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Sign out with `<UserButton />` or `signOut()` from `@/lib/auth/client`.
|
|
65
|
-
|
|
66
|
-
Session loading is the **same in live preview and when deployed**: wait for
|
|
67
|
-
`isPending` from `useCurrentUserState()` (backed by `/api/auth/get-session`).
|
|
68
|
-
The only live-preview difference is **how sign-in starts** (popup + bearer hand-off
|
|
69
|
-
instead of a full-page OAuth redirect) — not how guests vs signed-in users are
|
|
70
|
-
detected. Prefer `<RedirectToSignIn />` (TanStack `<Navigate>`) over
|
|
71
|
-
`window.location.href = "/login"` so a signed-out redirect does not full-reload
|
|
72
|
-
the SPA.
|
|
73
|
-
|
|
74
|
-
## Preventing auth flicker
|
|
75
|
-
|
|
76
|
-
`useSession()` resolves on the client, so a naive UI flashes signed-out →
|
|
77
|
-
signed-in on load. Rules:
|
|
78
|
-
|
|
79
|
-
1. **Gate on `isPending`, not `user` alone — and render a same-sized skeleton.**
|
|
80
|
-
Showing the SAME placeholder while `isPending` (server render + first client
|
|
81
|
-
paint) makes it one clean swap (skeleton → content) with no flash and no SSR
|
|
82
|
-
hydration mismatch. Don't return `null` in a slot that then grows — reserve the
|
|
83
|
-
space:
|
|
84
|
-
|
|
85
|
-
```tsx
|
|
86
|
-
import { useCurrentUserState } from "@/lib/auth/use-current-user";
|
|
87
|
-
import { UserButton } from "@/lib/auth/gates";
|
|
88
|
-
|
|
89
|
-
function AuthSlot() {
|
|
90
|
-
const { user, isPending } = useCurrentUserState();
|
|
91
|
-
if (isPending) return <div className="h-8 w-8 animate-pulse rounded-full bg-black/10" />;
|
|
92
|
-
return user ? <UserButton /> : <a href="/login">Sign in</a>;
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
2. **Guard at a layout boundary** (nav / page shell), not in leaf components that
|
|
97
|
-
mount/unmount — `useSession` is one shared store, so keep one stable consumer
|
|
98
|
-
per region instead of re-gating everywhere.
|
|
99
|
-
|
|
100
|
-
3. **Zero-flash when deployed: SSR the session from the cookie.** On a deployed
|
|
101
|
-
app (and top-level navigations) the session cookie is same-origin, so the server
|
|
102
|
-
already knows the user on the first request — resolve it in the root route and
|
|
103
|
-
render the authed shell immediately:
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
// src/routes/__root.tsx (excerpt)
|
|
107
|
-
import { createServerFn } from "@tanstack/react-start";
|
|
108
|
-
import { createRootRoute } from "@tanstack/react-router";
|
|
109
|
-
|
|
110
|
-
const fetchSessionUser = createServerFn({ method: "GET" }).handler(async () => {
|
|
111
|
-
// Cookie path only — works when deployed / on top-level loads.
|
|
112
|
-
const { getSessionUser } = await import("@/lib/auth/verify.server");
|
|
113
|
-
const u = await getSessionUser();
|
|
114
|
-
return u ? { id: u.id, email: u.email } : null;
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
export const Route = createRootRoute({
|
|
118
|
-
beforeLoad: async () => ({ sessionUser: await fetchSessionUser() }),
|
|
119
|
-
// Merge into the existing root — keep the existing head().
|
|
120
|
-
// component: prefer `sessionUser` for the FIRST paint when deployed, then
|
|
121
|
-
// `useCurrentUserState()` for live in-page updates.
|
|
122
|
-
});
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Sign-in/out navigate, so `beforeLoad` re-runs and the context stays fresh; call
|
|
126
|
-
`router.invalidate()` if you change auth state without navigating.
|
|
127
|
-
|
|
128
|
-
In live preview the session often rides a bearer after popup sign-in, so cookie
|
|
129
|
-
SSR may still return null until the client `useSession()` runs with the bearer
|
|
130
|
-
attached — still gate on `isPending`, same as when deployed.
|
|
131
|
-
|
|
132
|
-
The template already enables Better Auth's `session.cookieCache`, so `/get-session`
|
|
133
|
-
answers from a cookie when one is present (no DB round-trip).
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Supported sign-in methods (Google, X, email/password — and nothing else)
|
|
2
|
-
|
|
3
|
-
Use **only** these three — no other method is supported:
|
|
4
|
-
|
|
5
|
-
- **Google** and **X** — federated through the Grok broker (pre-wired here). The
|
|
6
|
-
broker federates these two upstreams and nothing else, so do **not** add entries
|
|
7
|
-
to `GROK_PROVIDERS` beyond them (the broker rejects an unknown `idp`).
|
|
8
|
-
- **Email + password** — this app's OWN Better Auth, persisted in your database
|
|
9
|
-
(never the broker, never mocked). Better Auth is DB-backed in BOTH modes — real
|
|
10
|
-
Postgres when deployed and the embedded PGLite in the sandbox preview — so
|
|
11
|
-
email/password accounts are stored and survive across requests, **in preview
|
|
12
|
-
too**. It's off by default. Enable it by editing **only**
|
|
13
|
-
`src/lib/auth/email-password.ts`:
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
// src/lib/auth/email-password.ts
|
|
17
|
-
export const emailAndPasswordEnabled = true; // was false
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Do not edit or rewrite `src/lib/auth/server.ts`** (or any other file under
|
|
21
|
-
`src/lib/auth/` except `email-password.ts` for this flag). That file is
|
|
22
|
-
pre-wired; "fixing" it by regenerating Better Auth config breaks live-preview
|
|
23
|
-
sign-in.
|
|
24
|
-
|
|
25
|
-
The pre-applied schema already has the `account.password` column — no migration
|
|
26
|
-
needed. Then build sign-up / sign-in forms with `authClient.signUp.email(...)`
|
|
27
|
-
and `authClient.signIn.email(...)` from `@/lib/auth/client`.
|
|
28
|
-
|
|
29
|
-
**Do not** add `emailAndPassword` as a plugin entry (that is a syntax/type
|
|
30
|
-
error). **Do not** invent a new Better Auth config.
|
|
31
|
-
|
|
32
|
-
If sign-up/sign-in returns **"Invalid origin"**, do **not** disable CSRF and
|
|
33
|
-
do **not** edit `server.ts`. The template's `trustedOrigins` already covers
|
|
34
|
-
`*.grok-sandbox.com` and local loopback on port 8080 (`localhost` /
|
|
35
|
-
`127.0.0.1` / `[::1]`). Open the app at one of those origins (not a random
|
|
36
|
-
host/port).
|
|
37
|
-
|
|
38
|
-
Do **NOT** add or use anything else: no other social / OAuth providers (GitHub,
|
|
39
|
-
Apple, Discord, Microsoft, Facebook, …), and no magic links, passkeys, one-time
|
|
40
|
-
codes / OTP, phone / SMS, or anonymous sign-in.
|
|
41
|
-
|
|
42
|
-
## Security model (already handled — don't undo it)
|
|
43
|
-
|
|
44
|
-
- **Headless broker**: the broker offers the upstream sign-in methods
|
|
45
|
-
and holds their shared secrets; this app only holds its own per-app client
|
|
46
|
-
id/secret and names the upstream it wants via each provider's `idp` hint. The
|
|
47
|
-
broker forwards straight to Google/X. Users never see the broker.
|
|
48
|
-
- **`__Host-` cookies + `trustedOrigins`**: a sibling `*.grok.me` app can't toss a
|
|
49
|
-
`Domain=.grok.me` cookie, and Better Auth rejects cross-origin `/api/auth`
|
|
50
|
-
calls.
|
|
51
|
-
- **Sibling isolation**: `authMiddleware` rejects scripted cross-site/same-site
|
|
52
|
-
requests (Fetch-Metadata), so a sibling can't ride this app's session cookie
|
|
53
|
-
into its server functions.
|
|
54
|
-
- The upstream Google/X tokens live only on the broker; this app only ever gets a
|
|
55
|
-
broker-issued identity and mints its own local session.
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Wiring the routes (do this once)
|
|
2
|
-
|
|
3
|
-
**Live-preview popup is PRE-WIRED — do not create it.**
|
|
4
|
-
`signIn` opens `/auth/popup`; the template Vite plugin
|
|
5
|
-
(`authPopupPlugin` in `vite.config.ts`) serves it via `popup.server.ts`.
|
|
6
|
-
**Never** add `src/routes/auth/popup.tsx` (or any React page / client OAuth at
|
|
7
|
-
that path). Doing so loads the full app shell in the popup ("the app opened
|
|
8
|
-
instead of Google") — that is always wrong.
|
|
9
|
-
|
|
10
|
-
**1. Mount Better Auth** — create the catch-all API route (this is what makes
|
|
11
|
-
`/api/auth/*` work; the broker's OAuth callback lands here):
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
// src/routes/api/auth/$.ts
|
|
15
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
16
|
-
import { auth } from "@/lib/auth/server";
|
|
17
|
-
|
|
18
|
-
export const Route = createFileRoute("/api/auth/$")({
|
|
19
|
-
server: {
|
|
20
|
-
handlers: {
|
|
21
|
-
GET: ({ request }) => auth.handler(request),
|
|
22
|
-
POST: ({ request }) => auth.handler(request),
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**2. Add a sign-in page** — buttons that kick off the broker flow. Import from
|
|
29
|
-
`@/lib/auth/client`. With the flag on, `authEnabled` is true in preview and
|
|
30
|
-
deployed, so the buttons show and work in the live preview; the `else` branch
|
|
31
|
-
shows while auth is still disabled (`VITE_AUTH_ENABLED=false`):
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
// src/routes/login.tsx
|
|
35
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
36
|
-
import { GROK_PROVIDERS, authEnabled, signIn } from "@/lib/auth/client";
|
|
37
|
-
|
|
38
|
-
export const Route = createFileRoute("/login")({ component: Login });
|
|
39
|
-
|
|
40
|
-
function Login() {
|
|
41
|
-
return (
|
|
42
|
-
<main className="grid min-h-screen place-items-center p-6">
|
|
43
|
-
<div className="w-full max-w-sm space-y-3">
|
|
44
|
-
<h1 className="text-xl font-semibold">Sign in</h1>
|
|
45
|
-
{authEnabled ? (
|
|
46
|
-
GROK_PROVIDERS.map((p) => (
|
|
47
|
-
<button
|
|
48
|
-
key={p.providerId}
|
|
49
|
-
type="button"
|
|
50
|
-
onClick={() => signIn(p.providerId, { callbackURL: "/" })}
|
|
51
|
-
className="w-full cursor-pointer rounded-md border border-neutral-300 px-4 py-2 hover:bg-neutral-100 dark:border-neutral-700 dark:hover:bg-neutral-900"
|
|
52
|
-
>
|
|
53
|
-
Continue with {p.label}
|
|
54
|
-
</button>
|
|
55
|
-
))
|
|
56
|
-
) : (
|
|
57
|
-
<p className="text-sm text-neutral-500">Sign-in is disabled.</p>
|
|
58
|
-
)}
|
|
59
|
-
</div>
|
|
60
|
-
</main>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`RedirectToSignIn` sends signed-out users to `/login` by default (override with
|
|
66
|
-
`<RedirectToSignIn to="/somewhere" />`). Style the page however you like — see
|
|
67
|
-
the `design-ui` skill.
|
|
68
|
-
|
|
69
|
-
That's it — call `signIn(providerId)` from your sign-in buttons. The popup,
|
|
70
|
-
bearer-token hand-off, and request attachment are all inside `src/lib/auth` +
|
|
71
|
-
the Vite plugin; leave them alone.
|