diff --git a/.env.example b/.env.example index 1f3da0e..f044d44 100644 --- a/.env.example +++ b/.env.example @@ -2,6 +2,8 @@ # Never place database credentials, ML service keys, object-storage secrets, # or other privileged values in a client-visible variable. PUBLIC_API_BASE_URL=http://localhost:8000 +# The deployed Better Auth service. Override this only when running auth locally. +PUBLIC_AUTH_BASE_URL=https://api.ifyousmellityouwilleventuallydie.tech # The native Tauri process reads these values. Since they do not use the # PUBLIC_ prefix, Vite does not expose them to the Svelte webview. diff --git a/api_server/.env.example b/api_server/.env.example new file mode 100644 index 0000000..f0b0bdf --- /dev/null +++ b/api_server/.env.example @@ -0,0 +1,18 @@ +# PostgreSQL connection used only by the server. Never expose this through Vite. +DATABASE_URL=postgresql://holotrace:change-me@localhost:5432/holotrace + +# Public URL at which Caddy exposes the Better Auth routes. +BETTER_AUTH_URL=http://localhost:8001 + +# Generate a high-entropy value of at least 32 characters. +BETTER_AUTH_SECRET=replace-with-a-random-value-of-at-least-32-characters + +# Comma-separated client origins allowed to make credentialed auth requests. +AUTH_TRUSTED_ORIGINS=http://localhost:5173 + +# Optional defense in depth for Caddy's private forward_auth request. +INTERNAL_AUTH_TOKEN=replace-with-a-separate-random-value + +# The Bun service's private listening port. +BIND_HOST=127.0.0.1 +PORT=8001 diff --git a/api_server/README.md b/api_server/README.md index 6579bc9..9722790 100644 --- a/api_server/README.md +++ b/api_server/README.md @@ -1,23 +1,95 @@ -# Holotrace API server +# Holotrace authentication API -To install dependencies: +This Bun service owns Holotrace authentication. Better Auth provides the HTTP routes and session cookies, while its +Drizzle adapter stores authentication data in the PostgreSQL `auth` schema. The service also owns authenticated +saved-circuit requests backed by the public-schema `projects` table. The existing Python model API remains separate. + +## Local setup ```bash bun install +cp .env.example .env +bun run db:migrate +bun run dev ``` -To run the current scaffold: +Set real values in `.env` before running the server. `BETTER_AUTH_SECRET` must be a high-entropy value with at least +32 characters. Do not expose `DATABASE_URL`, `BETTER_AUTH_SECRET`, or `INTERNAL_AUTH_TOKEN` to the Svelte client. + +Useful commands: ```bash -bun run index.ts +bun run check +bun run db:generate +bun run db:migrate +bun run start ``` -## Source layout +## Routes + +Better Auth is mounted below `/api/auth`. The username plugin adds username login to its standard email-and-password +account flow. + +```text +POST /api/auth/sign-up/email +POST /api/auth/sign-in/username +POST /api/auth/sign-out +GET /api/auth/get-session +GET /api/circuits +POST /api/circuits +GET /api/circuits/:id +POST /api/circuits/:id/open +PUT /api/circuits/:id +DELETE /api/circuits/:id +GET /health +GET /internal/authorize +``` + +Signup requires a display name, email, username, and password. Login requires only the username and password. +Passwords are owned and hashed by Better Auth in `auth.account`; they must never be copied into the legacy `users` +table or sent to the model service. + +The auth cookie is `Secure`, `HttpOnly`, and `SameSite=None` so the Tauri webview and local Svelte development origin +can retain a session while calling the deployed HTTPS API. Better Auth's origin checks and the credentialed CORS +allowlist remain enabled; every client origin must be listed in `AUTH_TRUSTED_ORIGINS`. + +Circuit routes require a valid Better Auth session. `public.projects.owner` references `auth.user.id`, and every read, +update, or delete includes that owner in its database predicate. Circuit JSON is limited to 12 MB per saved project +to accommodate the captured source image currently embedded in the circuit state. Listing returns lightweight +summaries ordered by `lastOpenedAt`; opening one circuit updates that timestamp before returning its full data. +The app opens a circuit through `POST /api/circuits/:id/open`, keeping the timestamp mutation off the read-only GET +route. + +`/internal/authorize` is intended for a reverse proxy's private authentication subrequest. It validates the Better +Auth session cookie and returns `X-Holotrace-User-Id` on success. When `INTERNAL_AUTH_TOKEN` is configured, the proxy +must supply the same value in `X-Internal-Auth-Token`. Do not expose this route directly through the public proxy. + +## Keeping the Python API unchanged + +In production, route `/api/auth/*` to this service and leave the remaining paths pointed at the Python model API: ```text -src/db/ Drizzle schema -src/circuit/ recognition, OpenCV wire-graph, normalization, and Circuit IR contracts +api.ifyousmellityouwilleventuallydie.tech + /api/auth/* -> Holotrace Bun API + /api/circuits* -> Holotrace Bun API + everything else -> existing Python model API ``` -The circuit normalizer belongs to the server boundary. It combines the OpenCV analysis and classifier result, then -returns canonical Circuit IR, source-image layout, and structured review issues to the user-facing application. +This preserves the Python implementation and its existing authorization behavior. To require Better Auth sessions +for the Python routes later, configure Caddy `forward_auth` to call the private `/internal/authorize` endpoint before +proxying a request to Python. Authentication at the proxy only proves who the caller is; project- and +workspace-specific authorization still belongs in an application API boundary. + +## Source layout + +```text +src/auth.ts Better Auth and username/password configuration +src/authorize.ts Private reverse-proxy authentication endpoint +src/circuits.ts Authenticated saved-circuit CRUD +src/config.ts Runtime environment validation +src/cors.ts Credentialed browser-request CORS handling +src/db/auth-schema.ts Better Auth's isolated Drizzle schema +src/db/index.ts PostgreSQL pool and Drizzle client +src/db/schema.ts Simplified saved-project schema linked to Better Auth users +deploy/ User service and Caddy routing examples +``` diff --git a/api_server/bun.lock b/api_server/bun.lock index 1427393..f396f28 100644 --- a/api_server/bun.lock +++ b/api_server/bun.lock @@ -4,23 +4,323 @@ "workspaces": { "": { "name": "y", + "dependencies": { + "@better-auth/drizzle-adapter": "^1.7.5", + "better-auth": "^1.7.5", + "drizzle-orm": "^0.45.2", + "pg": "^8.23.0", + }, "devDependencies": { "@types/bun": "latest", - }, - "peerDependencies": { - "typescript": "^5", + "@types/pg": "^8.23.1", + "drizzle-kit": "^0.31.10", + "typescript": "^7.0.2", }, }, }, "packages": { + "@better-auth/core": ["@better-auth/core@1.7.5", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.41.1", "@standard-schema/spec": "^1.1.0", "zod": "^4.5.4" }, "peerDependencies": { "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2", "@opentelemetry/api": "^1.9.0", "better-call": "1.4.0", "jose": "^6.1.0", "kysely": "^0.28.5 || ^0.29.0", "nanostores": "^1.0.1" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-kVlSu4H8OKQfjg4b/Zj5MOaospt83N0JbX38wsDzE58Yw95jzovFkU3pxzB1eUFYc4mkuhUMZD8iT1gpUjNMcQ=="], + + "@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0" }, "optionalPeers": ["drizzle-orm"] }, "sha512-9SM7v1735SoaedRDcDbHc5ULgXEd2vUlEJkvRHpMF2Q9qf59TRh1b5A9hryyecyi56bm/0CNUDU3nY0uVWj5/Q=="], + + "@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "kysely": "^0.28.17 || ^0.29.0" }, "optionalPeers": ["kysely"] }, "sha512-1wE5gvnjW+c1i4GrLtL9HLn3s0Xrq4YneCDan1NO1dpz0mEguLFNlzfnUGykTFrDwvFh2X5rkIbA8ALCj6WzXQ=="], + + "@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2" } }, "sha512-YDmnfR9zOXbn5SNYYwfHBPuc19hg1d1C1vUXb+Hm8Q91pTsstFNX5OTlZbo7f28q06FpogAEfGGCN/2QV39cig=="], + + "@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "mongodb": "^6.0.0 || ^7.0.0" }, "optionalPeers": ["mongodb"] }, "sha512-Yq0LfF0VlA9Kfjcjp/v43MSsChv7vKd1ct0Mt15px4zlqaCPIGfPbjw9YNM6jTo0fGpqLR0n15PllSWmLLRp9g=="], + + "@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@prisma/client", "prisma"] }, "sha512-QfW6HS9vK0FMcbI/GsQLdplICxOz0EPzYWGONZT4ovL3cSItd4YH/09USbPPVl+VUQCdznAQIk+n+NKvHdmSag=="], + + "@better-auth/telemetry": ["@better-auth/telemetry@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2" } }, "sha512-e/REPqMy9Em+gC6G0xWBikiMLRuy532Er7jqdoNkPBa65FbywgWcm1cZbgdW5CnHsrM3OLZsmKn14yeGoDISeg=="], + + "@better-auth/utils": ["@better-auth/utils@0.4.2", "", { "dependencies": { "@noble/hashes": "^2.0.1" } }, "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A=="], + + "@better-fetch/fetch": ["@better-fetch/fetch@1.3.2", "", {}, "sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow=="], + + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], + + "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], + + "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + + "@noble/ciphers": ["@noble/ciphers@2.4.0", "", {}, "sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw=="], + + "@noble/hashes": ["@noble/hashes@2.4.0", "", {}, "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA=="], + + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="], "@types/node": ["@types/node@26.6.2", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g=="], + "@types/pg": ["@types/pg@8.23.1", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A=="], + + "@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="], + + "@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA=="], + + "@typescript/typescript-darwin-x64": ["@typescript/typescript-darwin-x64@7.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA=="], + + "@typescript/typescript-freebsd-arm64": ["@typescript/typescript-freebsd-arm64@7.0.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ=="], + + "@typescript/typescript-freebsd-x64": ["@typescript/typescript-freebsd-x64@7.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw=="], + + "@typescript/typescript-linux-arm": ["@typescript/typescript-linux-arm@7.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ=="], + + "@typescript/typescript-linux-arm64": ["@typescript/typescript-linux-arm64@7.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ=="], + + "@typescript/typescript-linux-loong64": ["@typescript/typescript-linux-loong64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ=="], + + "@typescript/typescript-linux-mips64el": ["@typescript/typescript-linux-mips64el@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA=="], + + "@typescript/typescript-linux-ppc64": ["@typescript/typescript-linux-ppc64@7.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA=="], + + "@typescript/typescript-linux-riscv64": ["@typescript/typescript-linux-riscv64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ=="], + + "@typescript/typescript-linux-s390x": ["@typescript/typescript-linux-s390x@7.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw=="], + + "@typescript/typescript-linux-x64": ["@typescript/typescript-linux-x64@7.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A=="], + + "@typescript/typescript-netbsd-arm64": ["@typescript/typescript-netbsd-arm64@7.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA=="], + + "@typescript/typescript-netbsd-x64": ["@typescript/typescript-netbsd-x64@7.0.2", "", { "os": "none", "cpu": "x64" }, "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA=="], + + "@typescript/typescript-openbsd-arm64": ["@typescript/typescript-openbsd-arm64@7.0.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ=="], + + "@typescript/typescript-openbsd-x64": ["@typescript/typescript-openbsd-x64@7.0.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg=="], + + "@typescript/typescript-sunos-x64": ["@typescript/typescript-sunos-x64@7.0.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g=="], + + "@typescript/typescript-win32-arm64": ["@typescript/typescript-win32-arm64@7.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ=="], + + "@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g=="], + + "better-auth": ["better-auth@1.7.5", "", { "dependencies": { "@better-auth/core": "1.7.5", "@better-auth/drizzle-adapter": "1.7.5", "@better-auth/kysely-adapter": "1.7.5", "@better-auth/memory-adapter": "1.7.5", "@better-auth/mongo-adapter": "1.7.5", "@better-auth/prisma-adapter": "1.7.5", "@better-auth/telemetry": "1.7.5", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2", "@noble/ciphers": "^2.2.0", "@noble/hashes": "^2.2.0", "better-call": "1.4.0", "defu": "^6.1.4", "jose": "^6.2.3", "kysely": "^0.28.17 || ^0.29.0", "nanostores": "^1.3.0", "zod": "^4.5.4" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "drizzle-kit": ">=0.31.4 || >=1.0.0-beta.1", "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-aKE0Zt2EPTpFvmq4/oATNyG/mAfc6JUqWkW9pzGlrVnzUb0lso7GJ9BPxD6JPhLqYV1a9zOAb0uAz1Q5fm+eHA=="], + + "better-call": ["better-call@1.4.0", "", { "dependencies": { "@better-auth/utils": "^0.5.0", "@better-fetch/fetch": "^1.3.1", "rou3": "^0.9.1", "set-cookie-parser": "^3.1.2" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + "bun-types": ["bun-types@1.4.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], + + "drizzle-kit": ["drizzle-kit@0.31.10", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "tsx": "^4.21.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw=="], + + "drizzle-orm": ["drizzle-orm@0.45.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "prisma": "*", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "prisma", "sql.js", "sqlite3"] }, "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q=="], + + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "get-tsconfig": ["get-tsconfig@4.14.3", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA=="], + + "jose": ["jose@6.2.12", "", {}, "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw=="], + + "kysely": ["kysely@0.29.6", "", {}, "sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg=="], + + "nanostores": ["nanostores@1.5.3", "", {}, "sha512-rQLB6eV4f2AW/n3L0JmwCROpaisYy9EDEADvEFSd1C/qG8hB6O5TPlh9A791JRbJr4CnMQBzptDcvD9OR1+6WA=="], + + "pg": ["pg@8.23.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.16.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg=="], + + "pg-cloudflare": ["pg-cloudflare@1.4.0", "", {}, "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A=="], + + "pg-connection-string": ["pg-connection-string@2.14.0", "", {}, "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-pool": ["pg-pool@3.14.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw=="], + + "pg-protocol": ["pg-protocol@1.16.0", "", {}, "sha512-sILXutLVjCLjcDuOmvhX5e2Z4cS5qG/6Bu3VkpFwdf/633ElGLpEh9bgmuI5I4sqKqkifQiGyiCcx1HdtrK7tg=="], + + "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + + "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], + + "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "rou3": ["rou3@0.9.2", "", {}, "sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ=="], + + "set-cookie-parser": ["set-cookie-parser@3.1.2", "", {}, "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "tsx": ["tsx@4.23.14", "", { "dependencies": { "esbuild": "~0.28.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-yFwMnbAsUFz/T3kR8P2ENc/DDUaYd9tKg4oVYo0lhkX0LlK4UuqYAO6mpQ2y6lmcyip1uPJ34C2kPACopDwG4w=="], + + "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], "undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="], + + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + + "better-call/@better-auth/utils": ["@better-auth/utils@0.5.0", "", { "dependencies": { "@noble/hashes": "^2.0.1" } }, "sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA=="], + + "tsx/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], + + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], + + "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], + + "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], + + "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], + + "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], + + "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], + + "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], + + "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], + + "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], + + "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], + + "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], + + "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], + + "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], + + "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], + + "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], + + "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], + + "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], + + "tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], + + "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], + + "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], + + "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], + + "tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], + + "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], + + "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], + + "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], + + "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], } } diff --git a/api_server/deploy/Caddyfile.example b/api_server/deploy/Caddyfile.example new file mode 100644 index 0000000..2f9e8ff --- /dev/null +++ b/api_server/deploy/Caddyfile.example @@ -0,0 +1,20 @@ +{ + auto_https disable_redirects +} + +https://api.ifyousmellityouwilleventuallydie.tech:8000 { + tls internal + + handle /api/auth/* { + reverse_proxy 127.0.0.1:8002 + } + + @saved_circuits path /api/circuits /api/circuits/* + handle @saved_circuits { + reverse_proxy 127.0.0.1:8002 + } + + handle { + reverse_proxy 127.0.0.1:8001 + } +} diff --git a/api_server/deploy/holotrace-auth.service b/api_server/deploy/holotrace-auth.service new file mode 100644 index 0000000..86ca1b4 --- /dev/null +++ b/api_server/deploy/holotrace-auth.service @@ -0,0 +1,20 @@ +[Unit] +Description=Holotrace Better Auth API +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +WorkingDirectory=%h/services/auth/current +EnvironmentFile=%h/.config/holotrace/auth.env +ExecStart=%h/.bun/bin/bun run start +Restart=on-failure +RestartSec=5 +TimeoutStopSec=15 +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=full +ProtectHome=read-only + +[Install] +WantedBy=default.target diff --git a/api_server/drizzle.config.ts b/api_server/drizzle.config.ts index 2db8fc0..15a739d 100644 --- a/api_server/drizzle.config.ts +++ b/api_server/drizzle.config.ts @@ -1,16 +1,11 @@ import { defineConfig } from "drizzle-kit"; -console.log("[*] Starting Drizzle Configuration Defining...") export default defineConfig({ - schema: "./src/db/schema.ts", + schema: ["./src/db/schema.ts", "./src/db/auth-schema.ts"], out: "./drizzle", dialect: "postgresql", dbCredentials: { - host: process.env.PG_HOST!, - port: 5432, - user: process.env.PG_USER!, - password: process.env.PG_PASSWORD!, - database: process.env.PG_DATABASE!, + url: process.env.DATABASE_URL!, ssl: false } -}); \ No newline at end of file +}); diff --git a/api_server/drizzle/0000_fancy_madelyne_pryor.sql b/api_server/drizzle/0000_fancy_madelyne_pryor.sql new file mode 100644 index 0000000..c4661f2 --- /dev/null +++ b/api_server/drizzle/0000_fancy_madelyne_pryor.sql @@ -0,0 +1,17 @@ +CREATE TABLE "projects" ( + "id" serial PRIMARY KEY NOT NULL, + "owner" integer NOT NULL, + "data" text DEFAULT '' NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + "modifiedAt" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "users" ( + "id" serial PRIMARY KEY NOT NULL, + "username" varchar(18) NOT NULL, + "password" varchar(64) NOT NULL, + "createdAt" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "users_username_unique" UNIQUE("username") +); +--> statement-breakpoint +ALTER TABLE "projects" ADD CONSTRAINT "projects_owner_users_id_fk" FOREIGN KEY ("owner") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/api_server/drizzle/0000_spicy_psylocke.sql b/api_server/drizzle/0000_spicy_psylocke.sql deleted file mode 100644 index acbb7dd..0000000 --- a/api_server/drizzle/0000_spicy_psylocke.sql +++ /dev/null @@ -1,469 +0,0 @@ -CREATE SCHEMA "holotrace"; ---> statement-breakpoint -CREATE TABLE "holotrace"."app_user" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "auth_subject" text NOT NULL, - "display_name" text, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "app_user_auth_subject_unique" UNIQUE("auth_subject") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."artifact" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid, - "kind" text NOT NULL, - "object_key" text NOT NULL, - "mime_type" text NOT NULL, - "byte_size" bigint NOT NULL, - "sha256" text NOT NULL, - "license_id" text, - "source_uri" text, - "provenance" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_by" uuid, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "artifact_object_key_unique" UNIQUE("object_key"), - CONSTRAINT "artifact_kind_check" CHECK ("holotrace"."artifact"."kind" IN ('source_image', 'processed_image', 'schematic_svg', 'physical_2d', 'model_3d', 'texture', 'firmware', 'waveform', 'other')), - CONSTRAINT "artifact_byte_size_check" CHECK ("holotrace"."artifact"."byte_size" >= 0), - CONSTRAINT "artifact_sha256_check" CHECK ("holotrace"."artifact"."sha256" ~ '^[0-9a-f]{64}$') -); ---> statement-breakpoint -CREATE TABLE "holotrace"."circuit" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "project_id" uuid NOT NULL, - "name" text NOT NULL, - "created_by" uuid NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL -); ---> statement-breakpoint -CREATE TABLE "holotrace"."circuit_layout" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_version_id" uuid NOT NULL, - "layout_kind" text NOT NULL, - "revision" integer NOT NULL, - "generator" text, - "generator_version" text, - "viewport" jsonb DEFAULT '{}'::jsonb NOT NULL, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_by" uuid, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "circuit_layout_circuit_version_id_layout_kind_revision_uq" UNIQUE("circuit_version_id","layout_kind","revision"), - CONSTRAINT "circuit_layout_id_circuit_version_id_uq" UNIQUE("id","circuit_version_id"), - CONSTRAINT "circuit_layout_kind_check" CHECK ("holotrace"."circuit_layout"."layout_kind" IN ('schematic_2d', 'physical_2d', 'physical_3d')), - CONSTRAINT "circuit_layout_revision_check" CHECK ("holotrace"."circuit_layout"."revision" > 0) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."circuit_version" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_id" uuid NOT NULL, - "version_number" integer NOT NULL, - "parent_version_id" uuid, - "recognition_job_id" uuid, - "schema_version" integer DEFAULT 1 NOT NULL, - "status" text NOT NULL, - "change_summary" text, - "created_by" uuid NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "circuit_version_circuit_id_version_number_uq" UNIQUE("circuit_id","version_number"), - CONSTRAINT "circuit_version_id_circuit_id_uq" UNIQUE("id","circuit_id"), - CONSTRAINT "circuit_version_number_check" CHECK ("holotrace"."circuit_version"."version_number" > 0), - CONSTRAINT "circuit_version_schema_version_check" CHECK ("holotrace"."circuit_version"."schema_version" > 0), - CONSTRAINT "circuit_version_status_check" CHECK ("holotrace"."circuit_version"."status" IN ('recognized', 'needs_review', 'electrically_valid', 'simulatable', 'archived')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_definition" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid, - "slug" text NOT NULL, - "name" text NOT NULL, - "category" text NOT NULL, - "manufacturer" text, - "manufacturer_part" text, - "description" text, - "properties" jsonb DEFAULT '{}'::jsonb NOT NULL, - "catalog_version" integer DEFAULT 1 NOT NULL, - "is_active" boolean DEFAULT true NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "component_definition_catalog_version_check" CHECK ("holotrace"."component_definition"."catalog_version" > 0) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_instance" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_version_id" uuid NOT NULL, - "component_id" uuid, - "package_id" uuid, - "source_detection_id" uuid, - "reference_designator" text NOT NULL, - "display_name" text, - "properties" jsonb DEFAULT '{}'::jsonb NOT NULL, - "recognition_confidence" double precision, - "resolution_state" text DEFAULT 'resolved' NOT NULL, - CONSTRAINT "component_instance_circuit_version_id_reference_designator_uq" UNIQUE("circuit_version_id","reference_designator"), - CONSTRAINT "component_instance_id_circuit_version_id_uq" UNIQUE("id","circuit_version_id"), - CONSTRAINT "component_instance_recognition_confidence_check" CHECK ("holotrace"."component_instance"."recognition_confidence" BETWEEN 0.0 AND 1.0), - CONSTRAINT "component_instance_resolution_state_check" CHECK ("holotrace"."component_instance"."resolution_state" IN ('resolved', 'inferred', 'ambiguous', 'unknown')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_instance_pin" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_version_id" uuid NOT NULL, - "component_instance_id" uuid NOT NULL, - "component_pin_id" uuid, - "package_pin_id" uuid, - "pin_key" text NOT NULL, - "display_name" text, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "component_instance_pin_instance_id_pin_key_uq" UNIQUE("component_instance_id","pin_key"), - CONSTRAINT "component_instance_pin_id_circuit_version_id_uq" UNIQUE("id","circuit_version_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_package" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "component_id" uuid NOT NULL, - "package_key" text NOT NULL, - "name" text NOT NULL, - "dimensions_mm" jsonb DEFAULT '{}'::jsonb NOT NULL, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "component_package_component_id_package_key_uq" UNIQUE("component_id","package_key"), - CONSTRAINT "component_package_id_component_id_uq" UNIQUE("id","component_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_pin" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "component_id" uuid NOT NULL, - "pin_key" text NOT NULL, - "name" text NOT NULL, - "electrical_role" text, - "ordinal" integer NOT NULL, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "component_pin_component_id_pin_key_uq" UNIQUE("component_id","pin_key"), - CONSTRAINT "component_pin_component_id_ordinal_uq" UNIQUE("component_id","ordinal"), - CONSTRAINT "component_pin_ordinal_check" CHECK ("holotrace"."component_pin"."ordinal" >= 0) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_placement" ( - "circuit_version_id" uuid NOT NULL, - "layout_id" uuid NOT NULL, - "component_instance_id" uuid NOT NULL, - "position_x" double precision DEFAULT 0 NOT NULL, - "position_y" double precision DEFAULT 0 NOT NULL, - "position_z" double precision DEFAULT 0 NOT NULL, - "rotation_x" double precision DEFAULT 0 NOT NULL, - "rotation_y" double precision DEFAULT 0 NOT NULL, - "rotation_z" double precision DEFAULT 0 NOT NULL, - "rotation_w" double precision DEFAULT 1 NOT NULL, - "scale_x" double precision DEFAULT 1 NOT NULL, - "scale_y" double precision DEFAULT 1 NOT NULL, - "scale_z" double precision DEFAULT 1 NOT NULL, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "component_placement_layout_id_component_instance_id_pk" PRIMARY KEY("layout_id","component_instance_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_representation" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "component_id" uuid NOT NULL, - "package_id" uuid, - "representation_kind" text NOT NULL, - "artifact_id" uuid NOT NULL, - "detail_level" integer DEFAULT 0 NOT NULL, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "component_representation_uq" UNIQUE NULLS NOT DISTINCT("component_id","package_id","representation_kind","detail_level"), - CONSTRAINT "component_representation_kind_check" CHECK ("holotrace"."component_representation"."representation_kind" IN ('schematic_svg', 'physical_2d', 'model_3d')), - CONSTRAINT "component_representation_detail_level_check" CHECK ("holotrace"."component_representation"."detail_level" >= 0) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."component_simulation_model" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "component_id" uuid NOT NULL, - "package_id" uuid, - "engine_id" uuid NOT NULL, - "model_id" uuid NOT NULL, - "pin_mapping" jsonb NOT NULL, - "parameter_mapping" jsonb DEFAULT '{}'::jsonb NOT NULL, - "interaction_mapping" jsonb DEFAULT '{}'::jsonb NOT NULL, - "is_default" boolean DEFAULT false NOT NULL, - CONSTRAINT "component_simulation_model_uq" UNIQUE NULLS NOT DISTINCT("component_id","package_id","model_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."ml_model_version" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "model_key" text NOT NULL, - "version" text NOT NULL, - "artifact_id" uuid, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "ml_model_version_model_key_version_uq" UNIQUE("model_key","version") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."net" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_version_id" uuid NOT NULL, - "net_key" text NOT NULL, - "name" text, - "kind" text DEFAULT 'signal' NOT NULL, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "net_circuit_version_id_net_key_uq" UNIQUE("circuit_version_id","net_key"), - CONSTRAINT "net_id_circuit_version_id_uq" UNIQUE("id","circuit_version_id"), - CONSTRAINT "net_kind_check" CHECK ("holotrace"."net"."kind" IN ('signal', 'power', 'ground', 'unresolved')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."net_member" ( - "circuit_version_id" uuid NOT NULL, - "net_id" uuid NOT NULL, - "instance_pin_id" uuid NOT NULL, - CONSTRAINT "net_member_net_id_instance_pin_id_pk" PRIMARY KEY("net_id","instance_pin_id"), - CONSTRAINT "net_member_circuit_version_id_instance_pin_id_uq" UNIQUE("circuit_version_id","instance_pin_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."package_pin" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "package_id" uuid NOT NULL, - "component_pin_id" uuid NOT NULL, - "physical_label" text NOT NULL, - "anchor_2d" jsonb, - "anchor_3d" jsonb, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "package_pin_package_id_component_pin_id_uq" UNIQUE("package_id","component_pin_id"), - CONSTRAINT "package_pin_package_id_physical_label_uq" UNIQUE("package_id","physical_label") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."project" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid NOT NULL, - "name" text NOT NULL, - "description" text, - "created_by" uuid NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL -); ---> statement-breakpoint -CREATE TABLE "holotrace"."recognition_detection" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "recognition_job_id" uuid NOT NULL, - "detection_kind" text NOT NULL, - "source_region" jsonb NOT NULL, - "recognized_text" text, - "confidence" double precision, - "candidates" jsonb DEFAULT '[]'::jsonb NOT NULL, - "selected_component_id" uuid, - "review_state" text DEFAULT 'unreviewed' NOT NULL, - "reviewed_by" uuid, - "reviewed_at" timestamp with time zone, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "recognition_detection_kind_check" CHECK ("holotrace"."recognition_detection"."detection_kind" IN ('component', 'pin', 'wire', 'junction', 'crossing', 'label', 'other')), - CONSTRAINT "recognition_detection_confidence_check" CHECK ("holotrace"."recognition_detection"."confidence" BETWEEN 0.0 AND 1.0), - CONSTRAINT "recognition_detection_review_state_check" CHECK ("holotrace"."recognition_detection"."review_state" IN ('unreviewed', 'accepted', 'corrected', 'rejected')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."recognition_job" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "project_id" uuid NOT NULL, - "source_artifact_id" uuid NOT NULL, - "processed_artifact_id" uuid, - "model_version_id" uuid, - "status" text NOT NULL, - "preprocessing" jsonb DEFAULT '{}'::jsonb NOT NULL, - "raw_result" jsonb, - "error" jsonb, - "requested_by" uuid NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "started_at" timestamp with time zone, - "completed_at" timestamp with time zone, - CONSTRAINT "recognition_job_status_check" CHECK ("holotrace"."recognition_job"."status" IN ('queued', 'preprocessing', 'running', 'succeeded', 'failed', 'cancelled')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."simulation_artifact" ( - "session_id" uuid NOT NULL, - "artifact_id" uuid NOT NULL, - "purpose" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "simulation_artifact_session_id_artifact_id_pk" PRIMARY KEY("session_id","artifact_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."simulation_engine" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "engine_key" text NOT NULL, - "name" text NOT NULL, - "version" text NOT NULL, - "capabilities" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "simulation_engine_engine_key_version_uq" UNIQUE("engine_key","version") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."simulation_model" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "engine_id" uuid NOT NULL, - "model_key" text NOT NULL, - "version" integer DEFAULT 1 NOT NULL, - "definition" text, - "artifact_id" uuid, - "parameters" jsonb DEFAULT '{}'::jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "simulation_model_engine_id_model_key_version_uq" UNIQUE("engine_id","model_key","version"), - CONSTRAINT "simulation_model_id_engine_id_uq" UNIQUE("id","engine_id"), - CONSTRAINT "simulation_model_version_check" CHECK ("holotrace"."simulation_model"."version" > 0), - CONSTRAINT "simulation_model_definition_or_artifact_check" CHECK ("holotrace"."simulation_model"."definition" IS NOT NULL OR "holotrace"."simulation_model"."artifact_id" IS NOT NULL) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."simulation_sample" ( - "sampled_at" timestamp with time zone NOT NULL, - "session_id" uuid NOT NULL, - "signal_id" uuid NOT NULL, - "value" double precision NOT NULL, - "quality" smallint, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "simulation_sample_sampled_at_session_id_signal_id_pk" PRIMARY KEY("sampled_at","session_id","signal_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."simulation_session" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_version_id" uuid NOT NULL, - "engine_id" uuid NOT NULL, - "status" text NOT NULL, - "configuration" jsonb DEFAULT '{}'::jsonb NOT NULL, - "model_manifest" jsonb DEFAULT '{}'::jsonb NOT NULL, - "summary" jsonb, - "error" jsonb, - "created_by" uuid NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "started_at" timestamp with time zone, - "completed_at" timestamp with time zone, - CONSTRAINT "simulation_session_status_check" CHECK ("holotrace"."simulation_session"."status" IN ('created', 'running', 'paused', 'completed', 'failed', 'cancelled')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."simulation_signal" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "session_id" uuid NOT NULL, - "signal_key" text NOT NULL, - "name" text NOT NULL, - "quantity" text NOT NULL, - "unit" text NOT NULL, - "source_kind" text, - "source_id" uuid, - "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "simulation_signal_session_id_signal_key_uq" UNIQUE("session_id","signal_key"), - CONSTRAINT "simulation_signal_id_session_id_uq" UNIQUE("id","session_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."validation_issue" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "circuit_version_id" uuid NOT NULL, - "severity" text NOT NULL, - "issue_code" text NOT NULL, - "message" text NOT NULL, - "target_kind" text, - "target_id" uuid, - "details" jsonb DEFAULT '{}'::jsonb NOT NULL, - "resolved_at" timestamp with time zone, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "validation_issue_severity_check" CHECK ("holotrace"."validation_issue"."severity" IN ('info', 'warning', 'error')) -); ---> statement-breakpoint -CREATE TABLE "holotrace"."wire_route" ( - "circuit_version_id" uuid NOT NULL, - "layout_id" uuid NOT NULL, - "net_id" uuid NOT NULL, - "route" jsonb NOT NULL, - "style" jsonb DEFAULT '{}'::jsonb NOT NULL, - CONSTRAINT "wire_route_layout_id_net_id_pk" PRIMARY KEY("layout_id","net_id") -); ---> statement-breakpoint -CREATE TABLE "holotrace"."workspace" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "name" text NOT NULL, - "created_by" uuid NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL -); ---> statement-breakpoint -CREATE TABLE "holotrace"."workspace_member" ( - "workspace_id" uuid NOT NULL, - "user_id" uuid NOT NULL, - "role" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "workspace_member_workspace_id_user_id_pk" PRIMARY KEY("workspace_id","user_id"), - CONSTRAINT "workspace_member_role_check" CHECK ("holotrace"."workspace_member"."role" IN ('owner', 'editor', 'viewer')) -); ---> statement-breakpoint -ALTER TABLE "holotrace"."artifact" ADD CONSTRAINT "artifact_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "holotrace"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."artifact" ADD CONSTRAINT "artifact_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit" ADD CONSTRAINT "circuit_project_id_project_id_fk" FOREIGN KEY ("project_id") REFERENCES "holotrace"."project"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit" ADD CONSTRAINT "circuit_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_layout" ADD CONSTRAINT "circuit_layout_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_layout" ADD CONSTRAINT "circuit_layout_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_version" ADD CONSTRAINT "circuit_version_circuit_id_circuit_id_fk" FOREIGN KEY ("circuit_id") REFERENCES "holotrace"."circuit"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_version" ADD CONSTRAINT "circuit_version_recognition_job_id_recognition_job_id_fk" FOREIGN KEY ("recognition_job_id") REFERENCES "holotrace"."recognition_job"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_version" ADD CONSTRAINT "circuit_version_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_version" ADD CONSTRAINT "circuit_version_parent_circuit_fk" FOREIGN KEY ("parent_version_id","circuit_id") REFERENCES "holotrace"."circuit_version"("id","circuit_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_definition" ADD CONSTRAINT "component_definition_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "holotrace"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance" ADD CONSTRAINT "component_instance_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance" ADD CONSTRAINT "component_instance_component_id_component_definition_id_fk" FOREIGN KEY ("component_id") REFERENCES "holotrace"."component_definition"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance" ADD CONSTRAINT "component_instance_package_id_component_package_id_fk" FOREIGN KEY ("package_id") REFERENCES "holotrace"."component_package"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance" ADD CONSTRAINT "component_instance_source_detection_id_recognition_detection_id_fk" FOREIGN KEY ("source_detection_id") REFERENCES "holotrace"."recognition_detection"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance_pin" ADD CONSTRAINT "component_instance_pin_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance_pin" ADD CONSTRAINT "component_instance_pin_component_pin_id_component_pin_id_fk" FOREIGN KEY ("component_pin_id") REFERENCES "holotrace"."component_pin"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance_pin" ADD CONSTRAINT "component_instance_pin_package_pin_id_package_pin_id_fk" FOREIGN KEY ("package_pin_id") REFERENCES "holotrace"."package_pin"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance_pin" ADD CONSTRAINT "component_instance_pin_instance_circuit_fk" FOREIGN KEY ("component_instance_id","circuit_version_id") REFERENCES "holotrace"."component_instance"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_package" ADD CONSTRAINT "component_package_component_id_component_definition_id_fk" FOREIGN KEY ("component_id") REFERENCES "holotrace"."component_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_pin" ADD CONSTRAINT "component_pin_component_id_component_definition_id_fk" FOREIGN KEY ("component_id") REFERENCES "holotrace"."component_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_placement" ADD CONSTRAINT "component_placement_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_placement" ADD CONSTRAINT "component_placement_layout_circuit_fk" FOREIGN KEY ("layout_id","circuit_version_id") REFERENCES "holotrace"."circuit_layout"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_placement" ADD CONSTRAINT "component_placement_instance_circuit_fk" FOREIGN KEY ("component_instance_id","circuit_version_id") REFERENCES "holotrace"."component_instance"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_representation" ADD CONSTRAINT "component_representation_component_id_component_definition_id_fk" FOREIGN KEY ("component_id") REFERENCES "holotrace"."component_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_representation" ADD CONSTRAINT "component_representation_package_id_component_package_id_fk" FOREIGN KEY ("package_id") REFERENCES "holotrace"."component_package"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_representation" ADD CONSTRAINT "component_representation_artifact_id_artifact_id_fk" FOREIGN KEY ("artifact_id") REFERENCES "holotrace"."artifact"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_representation" ADD CONSTRAINT "component_representation_package_component_fk" FOREIGN KEY ("package_id","component_id") REFERENCES "holotrace"."component_package"("id","component_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_simulation_model" ADD CONSTRAINT "component_simulation_model_component_id_component_definition_id_fk" FOREIGN KEY ("component_id") REFERENCES "holotrace"."component_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_simulation_model" ADD CONSTRAINT "component_simulation_model_package_id_component_package_id_fk" FOREIGN KEY ("package_id") REFERENCES "holotrace"."component_package"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_simulation_model" ADD CONSTRAINT "component_simulation_model_engine_id_simulation_engine_id_fk" FOREIGN KEY ("engine_id") REFERENCES "holotrace"."simulation_engine"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_simulation_model" ADD CONSTRAINT "component_simulation_model_model_engine_fk" FOREIGN KEY ("model_id","engine_id") REFERENCES "holotrace"."simulation_model"("id","engine_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."ml_model_version" ADD CONSTRAINT "ml_model_version_artifact_id_artifact_id_fk" FOREIGN KEY ("artifact_id") REFERENCES "holotrace"."artifact"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."net" ADD CONSTRAINT "net_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."net_member" ADD CONSTRAINT "net_member_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."net_member" ADD CONSTRAINT "net_member_net_circuit_fk" FOREIGN KEY ("net_id","circuit_version_id") REFERENCES "holotrace"."net"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."net_member" ADD CONSTRAINT "net_member_instance_pin_circuit_fk" FOREIGN KEY ("instance_pin_id","circuit_version_id") REFERENCES "holotrace"."component_instance_pin"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."package_pin" ADD CONSTRAINT "package_pin_package_id_component_package_id_fk" FOREIGN KEY ("package_id") REFERENCES "holotrace"."component_package"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."package_pin" ADD CONSTRAINT "package_pin_component_pin_id_component_pin_id_fk" FOREIGN KEY ("component_pin_id") REFERENCES "holotrace"."component_pin"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."project" ADD CONSTRAINT "project_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "holotrace"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."project" ADD CONSTRAINT "project_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_detection" ADD CONSTRAINT "recognition_detection_recognition_job_id_recognition_job_id_fk" FOREIGN KEY ("recognition_job_id") REFERENCES "holotrace"."recognition_job"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_detection" ADD CONSTRAINT "recognition_detection_selected_component_id_component_definition_id_fk" FOREIGN KEY ("selected_component_id") REFERENCES "holotrace"."component_definition"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_detection" ADD CONSTRAINT "recognition_detection_reviewed_by_app_user_id_fk" FOREIGN KEY ("reviewed_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_job" ADD CONSTRAINT "recognition_job_project_id_project_id_fk" FOREIGN KEY ("project_id") REFERENCES "holotrace"."project"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_job" ADD CONSTRAINT "recognition_job_source_artifact_id_artifact_id_fk" FOREIGN KEY ("source_artifact_id") REFERENCES "holotrace"."artifact"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_job" ADD CONSTRAINT "recognition_job_processed_artifact_id_artifact_id_fk" FOREIGN KEY ("processed_artifact_id") REFERENCES "holotrace"."artifact"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_job" ADD CONSTRAINT "recognition_job_model_version_id_ml_model_version_id_fk" FOREIGN KEY ("model_version_id") REFERENCES "holotrace"."ml_model_version"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."recognition_job" ADD CONSTRAINT "recognition_job_requested_by_app_user_id_fk" FOREIGN KEY ("requested_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_artifact" ADD CONSTRAINT "simulation_artifact_session_id_simulation_session_id_fk" FOREIGN KEY ("session_id") REFERENCES "holotrace"."simulation_session"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_artifact" ADD CONSTRAINT "simulation_artifact_artifact_id_artifact_id_fk" FOREIGN KEY ("artifact_id") REFERENCES "holotrace"."artifact"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_model" ADD CONSTRAINT "simulation_model_engine_id_simulation_engine_id_fk" FOREIGN KEY ("engine_id") REFERENCES "holotrace"."simulation_engine"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_model" ADD CONSTRAINT "simulation_model_artifact_id_artifact_id_fk" FOREIGN KEY ("artifact_id") REFERENCES "holotrace"."artifact"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_sample" ADD CONSTRAINT "simulation_sample_signal_session_fk" FOREIGN KEY ("signal_id","session_id") REFERENCES "holotrace"."simulation_signal"("id","session_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_session" ADD CONSTRAINT "simulation_session_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_session" ADD CONSTRAINT "simulation_session_engine_id_simulation_engine_id_fk" FOREIGN KEY ("engine_id") REFERENCES "holotrace"."simulation_engine"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_session" ADD CONSTRAINT "simulation_session_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."simulation_signal" ADD CONSTRAINT "simulation_signal_session_id_simulation_session_id_fk" FOREIGN KEY ("session_id") REFERENCES "holotrace"."simulation_session"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."validation_issue" ADD CONSTRAINT "validation_issue_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."wire_route" ADD CONSTRAINT "wire_route_circuit_version_id_circuit_version_id_fk" FOREIGN KEY ("circuit_version_id") REFERENCES "holotrace"."circuit_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."wire_route" ADD CONSTRAINT "wire_route_layout_circuit_fk" FOREIGN KEY ("layout_id","circuit_version_id") REFERENCES "holotrace"."circuit_layout"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."wire_route" ADD CONSTRAINT "wire_route_net_circuit_fk" FOREIGN KEY ("net_id","circuit_version_id") REFERENCES "holotrace"."net"("id","circuit_version_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."workspace" ADD CONSTRAINT "workspace_created_by_app_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "holotrace"."app_user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."workspace_member" ADD CONSTRAINT "workspace_member_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "holotrace"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."workspace_member" ADD CONSTRAINT "workspace_member_user_id_app_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "holotrace"."app_user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -CREATE INDEX "artifact_workspace_kind_idx" ON "holotrace"."artifact" USING btree ("workspace_id","kind","created_at" DESC NULLS LAST);--> statement-breakpoint -CREATE INDEX "circuit_project_idx" ON "holotrace"."circuit" USING btree ("project_id","updated_at" DESC NULLS LAST);--> statement-breakpoint -CREATE UNIQUE INDEX "component_definition_global_slug_uq" ON "holotrace"."component_definition" USING btree ("slug") WHERE "holotrace"."component_definition"."workspace_id" IS NULL;--> statement-breakpoint -CREATE UNIQUE INDEX "component_definition_workspace_slug_uq" ON "holotrace"."component_definition" USING btree ("workspace_id","slug") WHERE "holotrace"."component_definition"."workspace_id" IS NOT NULL;--> statement-breakpoint -CREATE INDEX "component_definition_properties_gin" ON "holotrace"."component_definition" USING gin ("properties" jsonb_path_ops);--> statement-breakpoint -CREATE UNIQUE INDEX "component_default_simulation_model_uq" ON "holotrace"."component_simulation_model" USING btree ("component_id","package_id","engine_id") WHERE "holotrace"."component_simulation_model"."is_default";--> statement-breakpoint -CREATE INDEX "project_workspace_idx" ON "holotrace"."project" USING btree ("workspace_id","updated_at" DESC NULLS LAST);--> statement-breakpoint -CREATE INDEX "recognition_detection_job_idx" ON "holotrace"."recognition_detection" USING btree ("recognition_job_id","detection_kind");--> statement-breakpoint -CREATE INDEX "recognition_job_project_idx" ON "holotrace"."recognition_job" USING btree ("project_id","created_at" DESC NULLS LAST);--> statement-breakpoint -CREATE INDEX "simulation_sample_signal_time_idx" ON "holotrace"."simulation_sample" USING btree ("session_id","signal_id","sampled_at" DESC NULLS LAST);--> statement-breakpoint -CREATE INDEX "simulation_session_circuit_idx" ON "holotrace"."simulation_session" USING btree ("circuit_version_id","created_at" DESC NULLS LAST);--> statement-breakpoint -CREATE INDEX "validation_issue_open_idx" ON "holotrace"."validation_issue" USING btree ("circuit_version_id","severity") WHERE "holotrace"."validation_issue"."resolved_at" IS NULL; \ No newline at end of file diff --git a/api_server/drizzle/0001_cooing_magik.sql b/api_server/drizzle/0001_cooing_magik.sql new file mode 100644 index 0000000..e050f22 --- /dev/null +++ b/api_server/drizzle/0001_cooing_magik.sql @@ -0,0 +1,58 @@ +CREATE SCHEMA "auth"; +--> statement-breakpoint +CREATE TABLE "auth"."account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE "auth"."session" ( + "id" text PRIMARY KEY NOT NULL, + "expires_at" timestamp NOT NULL, + "token" text NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp NOT NULL, + "ip_address" text, + "user_agent" text, + "user_id" text NOT NULL, + CONSTRAINT "session_token_unique" UNIQUE("token") +); +--> statement-breakpoint +CREATE TABLE "auth"."user" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "email_verified" boolean DEFAULT false NOT NULL, + "image" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "username" text, + "display_username" text, + CONSTRAINT "user_email_unique" UNIQUE("email"), + CONSTRAINT "user_username_unique" UNIQUE("username") +); +--> statement-breakpoint +CREATE TABLE "auth"."verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "auth"."account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "auth"."session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "account_userId_idx" ON "auth"."account" USING btree ("user_id");--> statement-breakpoint +CREATE INDEX "session_userId_idx" ON "auth"."session" USING btree ("user_id");--> statement-breakpoint +CREATE INDEX "verification_identifier_idx" ON "auth"."verification" USING btree ("identifier"); \ No newline at end of file diff --git a/api_server/drizzle/0001_postgres_schema_alignment.sql b/api_server/drizzle/0001_postgres_schema_alignment.sql deleted file mode 100644 index 8c08a9d..0000000 --- a/api_server/drizzle/0001_postgres_schema_alignment.sql +++ /dev/null @@ -1,10 +0,0 @@ -ALTER TABLE "holotrace"."component_instance" DROP CONSTRAINT "component_instance_package_id_component_package_id_fk"; ---> statement-breakpoint -DROP INDEX "holotrace"."component_default_simulation_model_uq";--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_version" ADD COLUMN "ir_schema_version" text DEFAULT 'circuit-ir-v0' NOT NULL;--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance" ADD CONSTRAINT "component_instance_package_component_fk" FOREIGN KEY ("package_id","component_id") REFERENCES "holotrace"."component_package"("id","component_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "holotrace"."component_simulation_model" ADD CONSTRAINT "component_simulation_model_package_component_fk" FOREIGN KEY ("package_id","component_id") REFERENCES "holotrace"."component_package"("id","component_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -CREATE UNIQUE INDEX "component_default_simulation_model_for_package_uq" ON "holotrace"."component_simulation_model" USING btree ("component_id","package_id","engine_id") WHERE "holotrace"."component_simulation_model"."is_default" AND "holotrace"."component_simulation_model"."package_id" IS NOT NULL;--> statement-breakpoint -CREATE UNIQUE INDEX "component_default_simulation_model_without_package_uq" ON "holotrace"."component_simulation_model" USING btree ("component_id","engine_id") WHERE "holotrace"."component_simulation_model"."is_default" AND "holotrace"."component_simulation_model"."package_id" IS NULL;--> statement-breakpoint -ALTER TABLE "holotrace"."circuit_version" ADD CONSTRAINT "circuit_version_ir_schema_version_check" CHECK (length("holotrace"."circuit_version"."ir_schema_version") > 0);--> statement-breakpoint -ALTER TABLE "holotrace"."component_instance" ADD CONSTRAINT "component_instance_package_requires_component_check" CHECK ("holotrace"."component_instance"."package_id" IS NULL OR "holotrace"."component_instance"."component_id" IS NOT NULL); \ No newline at end of file diff --git a/api_server/drizzle/0002_goofy_warbound.sql b/api_server/drizzle/0002_goofy_warbound.sql new file mode 100644 index 0000000..bc306f3 --- /dev/null +++ b/api_server/drizzle/0002_goofy_warbound.sql @@ -0,0 +1,6 @@ +ALTER TABLE "projects" DROP CONSTRAINT "projects_owner_users_id_fk"; +--> statement-breakpoint +ALTER TABLE "projects" ALTER COLUMN "owner" SET DATA TYPE text;--> statement-breakpoint +ALTER TABLE "projects" ALTER COLUMN "data" DROP DEFAULT;--> statement-breakpoint +ALTER TABLE "projects" ADD COLUMN "name" varchar(120) DEFAULT 'Untitled circuit' NOT NULL;--> statement-breakpoint +ALTER TABLE "projects" ADD CONSTRAINT "projects_owner_user_id_fk" FOREIGN KEY ("owner") REFERENCES "auth"."user"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/api_server/drizzle/0003_workable_silverclaw.sql b/api_server/drizzle/0003_workable_silverclaw.sql new file mode 100644 index 0000000..c4ce5c4 --- /dev/null +++ b/api_server/drizzle/0003_workable_silverclaw.sql @@ -0,0 +1 @@ +ALTER TABLE "projects" ADD COLUMN "lastOpenedAt" timestamp DEFAULT now() NOT NULL; \ No newline at end of file diff --git a/api_server/drizzle/meta/0000_snapshot.json b/api_server/drizzle/meta/0000_snapshot.json index 8bc9674..caa3f87 100644 --- a/api_server/drizzle/meta/0000_snapshot.json +++ b/api_server/drizzle/meta/0000_snapshot.json @@ -1,318 +1,55 @@ { - "id": "d03dc983-8b11-40f8-be5f-282b6d690246", + "id": "fed3c11d-c69d-4b04-9e0c-8dafefa34252", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { - "holotrace.app_user": { - "name": "app_user", - "schema": "holotrace", + "public.projects": { + "name": "projects", + "schema": "", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "serial", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "auth_subject": { - "name": "auth_subject", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "app_user_auth_subject_unique": { - "name": "app_user_auth_subject_unique", - "nullsNotDistinct": false, - "columns": [ - "auth_subject" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.artifact": { - "name": "artifact", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "kind": { - "name": "kind", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "object_key": { - "name": "object_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mime_type": { - "name": "mime_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "byte_size": { - "name": "byte_size", - "type": "bigint", - "primaryKey": false, "notNull": true }, - "sha256": { - "name": "sha256", - "type": "text", + "owner": { + "name": "owner", + "type": "integer", "primaryKey": false, "notNull": true }, - "license_id": { - "name": "license_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "source_uri": { - "name": "source_uri", + "data": { + "name": "data", "type": "text", "primaryKey": false, - "notNull": false - }, - "provenance": { - "name": "provenance", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, "notNull": true, - "default": "now()" - } - }, - "indexes": { - "artifact_workspace_kind_idx": { - "name": "artifact_workspace_kind_idx", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "kind", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "artifact_workspace_id_workspace_id_fk": { - "name": "artifact_workspace_id_workspace_id_fk", - "tableFrom": "artifact", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "artifact_created_by_app_user_id_fk": { - "name": "artifact_created_by_app_user_id_fk", - "tableFrom": "artifact", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "artifact_object_key_unique": { - "name": "artifact_object_key_unique", - "nullsNotDistinct": false, - "columns": [ - "object_key" - ] - } - }, - "policies": {}, - "checkConstraints": { - "artifact_kind_check": { - "name": "artifact_kind_check", - "value": "\"holotrace\".\"artifact\".\"kind\" IN ('source_image', 'processed_image', 'schematic_svg', 'physical_2d', 'model_3d', 'texture', 'firmware', 'waveform', 'other')" + "default": "''" }, - "artifact_byte_size_check": { - "name": "artifact_byte_size_check", - "value": "\"holotrace\".\"artifact\".\"byte_size\" >= 0" - }, - "artifact_sha256_check": { - "name": "artifact_sha256_check", - "value": "\"holotrace\".\"artifact\".\"sha256\" ~ '^[0-9a-f]{64}$'" - } - }, - "isRLSEnabled": false - }, - "holotrace.circuit": { - "name": "circuit", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "project_id": { - "name": "project_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", + "createdAt": { + "name": "createdAt", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", + "modifiedAt": { + "name": "modifiedAt", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" } }, - "indexes": { - "circuit_project_idx": { - "name": "circuit_project_idx", - "columns": [ - { - "expression": "project_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "updated_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, + "indexes": {}, "foreignKeys": { - "circuit_project_id_project_id_fk": { - "name": "circuit_project_id_project_id_fk", - "tableFrom": "circuit", - "tableTo": "project", - "schemaTo": "holotrace", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_created_by_app_user_id_fk": { - "name": "circuit_created_by_app_user_id_fk", - "tableFrom": "circuit", - "tableTo": "app_user", - "schemaTo": "holotrace", + "projects_owner_users_id_fk": { + "name": "projects_owner_users_id_fk", + "tableFrom": "projects", + "tableTo": "users", "columnsFrom": [ - "created_by" + "owner" ], "columnsTo": [ "id" @@ -327,3257 +64,55 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "holotrace.circuit_layout": { - "name": "circuit_layout", - "schema": "holotrace", + "public.users": { + "name": "users", + "schema": "", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "serial", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, "notNull": true }, - "layout_kind": { - "name": "layout_kind", - "type": "text", + "username": { + "name": "username", + "type": "varchar(18)", "primaryKey": false, "notNull": true }, - "revision": { - "name": "revision", - "type": "integer", + "password": { + "name": "password", + "type": "varchar(64)", "primaryKey": false, "notNull": true }, - "generator": { - "name": "generator", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "generator_version": { - "name": "generator_version", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "viewport": { - "name": "viewport", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", + "createdAt": { + "name": "createdAt", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" } }, "indexes": {}, - "foreignKeys": { - "circuit_layout_circuit_version_id_circuit_version_id_fk": { - "name": "circuit_layout_circuit_version_id_circuit_version_id_fk", - "tableFrom": "circuit_layout", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_layout_created_by_app_user_id_fk": { - "name": "circuit_layout_created_by_app_user_id_fk", - "tableFrom": "circuit_layout", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, + "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": { - "circuit_layout_circuit_version_id_layout_kind_revision_uq": { - "name": "circuit_layout_circuit_version_id_layout_kind_revision_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "layout_kind", - "revision" - ] - }, - "circuit_layout_id_circuit_version_id_uq": { - "name": "circuit_layout_id_circuit_version_id_uq", + "users_username_unique": { + "name": "users_username_unique", "nullsNotDistinct": false, "columns": [ - "id", - "circuit_version_id" + "username" ] } }, "policies": {}, - "checkConstraints": { - "circuit_layout_kind_check": { - "name": "circuit_layout_kind_check", - "value": "\"holotrace\".\"circuit_layout\".\"layout_kind\" IN ('schematic_2d', 'physical_2d', 'physical_3d')" - }, - "circuit_layout_revision_check": { - "name": "circuit_layout_revision_check", - "value": "\"holotrace\".\"circuit_layout\".\"revision\" > 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.circuit_version": { - "name": "circuit_version", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_id": { - "name": "circuit_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "version_number": { - "name": "version_number", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "parent_version_id": { - "name": "parent_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "recognition_job_id": { - "name": "recognition_job_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "schema_version": { - "name": "schema_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "change_summary": { - "name": "change_summary", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "circuit_version_circuit_id_circuit_id_fk": { - "name": "circuit_version_circuit_id_circuit_id_fk", - "tableFrom": "circuit_version", - "tableTo": "circuit", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_version_recognition_job_id_recognition_job_id_fk": { - "name": "circuit_version_recognition_job_id_recognition_job_id_fk", - "tableFrom": "circuit_version", - "tableTo": "recognition_job", - "schemaTo": "holotrace", - "columnsFrom": [ - "recognition_job_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "circuit_version_created_by_app_user_id_fk": { - "name": "circuit_version_created_by_app_user_id_fk", - "tableFrom": "circuit_version", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "circuit_version_parent_circuit_fk": { - "name": "circuit_version_parent_circuit_fk", - "tableFrom": "circuit_version", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "parent_version_id", - "circuit_id" - ], - "columnsTo": [ - "id", - "circuit_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "circuit_version_circuit_id_version_number_uq": { - "name": "circuit_version_circuit_id_version_number_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_id", - "version_number" - ] - }, - "circuit_version_id_circuit_id_uq": { - "name": "circuit_version_id_circuit_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "circuit_version_number_check": { - "name": "circuit_version_number_check", - "value": "\"holotrace\".\"circuit_version\".\"version_number\" > 0" - }, - "circuit_version_schema_version_check": { - "name": "circuit_version_schema_version_check", - "value": "\"holotrace\".\"circuit_version\".\"schema_version\" > 0" - }, - "circuit_version_status_check": { - "name": "circuit_version_status_check", - "value": "\"holotrace\".\"circuit_version\".\"status\" IN ('recognized', 'needs_review', 'electrically_valid', 'simulatable', 'archived')" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_definition": { - "name": "component_definition", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "slug": { - "name": "slug", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "manufacturer": { - "name": "manufacturer", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "manufacturer_part": { - "name": "manufacturer_part", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "properties": { - "name": "properties", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "catalog_version": { - "name": "catalog_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "is_active": { - "name": "is_active", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "component_definition_global_slug_uq": { - "name": "component_definition_global_slug_uq", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_definition\".\"workspace_id\" IS NULL", - "concurrently": false, - "method": "btree", - "with": {} - }, - "component_definition_workspace_slug_uq": { - "name": "component_definition_workspace_slug_uq", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_definition\".\"workspace_id\" IS NOT NULL", - "concurrently": false, - "method": "btree", - "with": {} - }, - "component_definition_properties_gin": { - "name": "component_definition_properties_gin", - "columns": [ - { - "expression": "\"properties\" jsonb_path_ops", - "asc": true, - "isExpression": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "gin", - "with": {} - } - }, - "foreignKeys": { - "component_definition_workspace_id_workspace_id_fk": { - "name": "component_definition_workspace_id_workspace_id_fk", - "tableFrom": "component_definition", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "component_definition_catalog_version_check": { - "name": "component_definition_catalog_version_check", - "value": "\"holotrace\".\"component_definition\".\"catalog_version\" > 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_instance": { - "name": "component_instance", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "source_detection_id": { - "name": "source_detection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "reference_designator": { - "name": "reference_designator", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "properties": { - "name": "properties", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "recognition_confidence": { - "name": "recognition_confidence", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "resolution_state": { - "name": "resolution_state", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'resolved'" - } - }, - "indexes": {}, - "foreignKeys": { - "component_instance_circuit_version_id_circuit_version_id_fk": { - "name": "component_instance_circuit_version_id_circuit_version_id_fk", - "tableFrom": "component_instance", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_instance_component_id_component_definition_id_fk": { - "name": "component_instance_component_id_component_definition_id_fk", - "tableFrom": "component_instance", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_package_id_component_package_id_fk": { - "name": "component_instance_package_id_component_package_id_fk", - "tableFrom": "component_instance", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_source_detection_id_recognition_detection_id_fk": { - "name": "component_instance_source_detection_id_recognition_detection_id_fk", - "tableFrom": "component_instance", - "tableTo": "recognition_detection", - "schemaTo": "holotrace", - "columnsFrom": [ - "source_detection_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_instance_circuit_version_id_reference_designator_uq": { - "name": "component_instance_circuit_version_id_reference_designator_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "reference_designator" - ] - }, - "component_instance_id_circuit_version_id_uq": { - "name": "component_instance_id_circuit_version_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_version_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "component_instance_recognition_confidence_check": { - "name": "component_instance_recognition_confidence_check", - "value": "\"holotrace\".\"component_instance\".\"recognition_confidence\" BETWEEN 0.0 AND 1.0" - }, - "component_instance_resolution_state_check": { - "name": "component_instance_resolution_state_check", - "value": "\"holotrace\".\"component_instance\".\"resolution_state\" IN ('resolved', 'inferred', 'ambiguous', 'unknown')" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_instance_pin": { - "name": "component_instance_pin", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_instance_id": { - "name": "component_instance_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_pin_id": { - "name": "component_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "package_pin_id": { - "name": "package_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "pin_key": { - "name": "pin_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "component_instance_pin_circuit_version_id_circuit_version_id_fk": { - "name": "component_instance_pin_circuit_version_id_circuit_version_id_fk", - "tableFrom": "component_instance_pin", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_instance_pin_component_pin_id_component_pin_id_fk": { - "name": "component_instance_pin_component_pin_id_component_pin_id_fk", - "tableFrom": "component_instance_pin", - "tableTo": "component_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_pin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_pin_package_pin_id_package_pin_id_fk": { - "name": "component_instance_pin_package_pin_id_package_pin_id_fk", - "tableFrom": "component_instance_pin", - "tableTo": "package_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_pin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_pin_instance_circuit_fk": { - "name": "component_instance_pin_instance_circuit_fk", - "tableFrom": "component_instance_pin", - "tableTo": "component_instance", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_instance_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_instance_pin_instance_id_pin_key_uq": { - "name": "component_instance_pin_instance_id_pin_key_uq", - "nullsNotDistinct": false, - "columns": [ - "component_instance_id", - "pin_key" - ] - }, - "component_instance_pin_id_circuit_version_id_uq": { - "name": "component_instance_pin_id_circuit_version_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_version_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.component_package": { - "name": "component_package", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "package_key": { - "name": "package_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dimensions_mm": { - "name": "dimensions_mm", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "component_package_component_id_component_definition_id_fk": { - "name": "component_package_component_id_component_definition_id_fk", - "tableFrom": "component_package", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_package_component_id_package_key_uq": { - "name": "component_package_component_id_package_key_uq", - "nullsNotDistinct": false, - "columns": [ - "component_id", - "package_key" - ] - }, - "component_package_id_component_id_uq": { - "name": "component_package_id_component_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "component_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.component_pin": { - "name": "component_pin", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "pin_key": { - "name": "pin_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "electrical_role": { - "name": "electrical_role", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "ordinal": { - "name": "ordinal", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "component_pin_component_id_component_definition_id_fk": { - "name": "component_pin_component_id_component_definition_id_fk", - "tableFrom": "component_pin", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_pin_component_id_pin_key_uq": { - "name": "component_pin_component_id_pin_key_uq", - "nullsNotDistinct": false, - "columns": [ - "component_id", - "pin_key" - ] - }, - "component_pin_component_id_ordinal_uq": { - "name": "component_pin_component_id_ordinal_uq", - "nullsNotDistinct": false, - "columns": [ - "component_id", - "ordinal" - ] - } - }, - "policies": {}, - "checkConstraints": { - "component_pin_ordinal_check": { - "name": "component_pin_ordinal_check", - "value": "\"holotrace\".\"component_pin\".\"ordinal\" >= 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_placement": { - "name": "component_placement", - "schema": "holotrace", - "columns": { - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "layout_id": { - "name": "layout_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_instance_id": { - "name": "component_instance_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "position_x": { - "name": "position_x", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "position_y": { - "name": "position_y", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "position_z": { - "name": "position_z", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_x": { - "name": "rotation_x", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_y": { - "name": "rotation_y", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_z": { - "name": "rotation_z", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_w": { - "name": "rotation_w", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "scale_x": { - "name": "scale_x", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "scale_y": { - "name": "scale_y", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "scale_z": { - "name": "scale_z", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "component_placement_circuit_version_id_circuit_version_id_fk": { - "name": "component_placement_circuit_version_id_circuit_version_id_fk", - "tableFrom": "component_placement", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_placement_layout_circuit_fk": { - "name": "component_placement_layout_circuit_fk", - "tableFrom": "component_placement", - "tableTo": "circuit_layout", - "schemaTo": "holotrace", - "columnsFrom": [ - "layout_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_placement_instance_circuit_fk": { - "name": "component_placement_instance_circuit_fk", - "tableFrom": "component_placement", - "tableTo": "component_instance", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_instance_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "component_placement_layout_id_component_instance_id_pk": { - "name": "component_placement_layout_id_component_instance_id_pk", - "columns": [ - "layout_id", - "component_instance_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.component_representation": { - "name": "component_representation", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "representation_kind": { - "name": "representation_kind", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "detail_level": { - "name": "detail_level", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "component_representation_component_id_component_definition_id_fk": { - "name": "component_representation_component_id_component_definition_id_fk", - "tableFrom": "component_representation", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_representation_package_id_component_package_id_fk": { - "name": "component_representation_package_id_component_package_id_fk", - "tableFrom": "component_representation", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_representation_artifact_id_artifact_id_fk": { - "name": "component_representation_artifact_id_artifact_id_fk", - "tableFrom": "component_representation", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_representation_package_component_fk": { - "name": "component_representation_package_component_fk", - "tableFrom": "component_representation", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id", - "component_id" - ], - "columnsTo": [ - "id", - "component_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_representation_uq": { - "name": "component_representation_uq", - "nullsNotDistinct": true, - "columns": [ - "component_id", - "package_id", - "representation_kind", - "detail_level" - ] - } - }, - "policies": {}, - "checkConstraints": { - "component_representation_kind_check": { - "name": "component_representation_kind_check", - "value": "\"holotrace\".\"component_representation\".\"representation_kind\" IN ('schematic_svg', 'physical_2d', 'model_3d')" - }, - "component_representation_detail_level_check": { - "name": "component_representation_detail_level_check", - "value": "\"holotrace\".\"component_representation\".\"detail_level\" >= 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_simulation_model": { - "name": "component_simulation_model", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "engine_id": { - "name": "engine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "model_id": { - "name": "model_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "pin_mapping": { - "name": "pin_mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "parameter_mapping": { - "name": "parameter_mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "interaction_mapping": { - "name": "interaction_mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - } - }, - "indexes": { - "component_default_simulation_model_uq": { - "name": "component_default_simulation_model_uq", - "columns": [ - { - "expression": "component_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "package_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "engine_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_simulation_model\".\"is_default\"", - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "component_simulation_model_component_id_component_definition_id_fk": { - "name": "component_simulation_model_component_id_component_definition_id_fk", - "tableFrom": "component_simulation_model", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_simulation_model_package_id_component_package_id_fk": { - "name": "component_simulation_model_package_id_component_package_id_fk", - "tableFrom": "component_simulation_model", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_simulation_model_engine_id_simulation_engine_id_fk": { - "name": "component_simulation_model_engine_id_simulation_engine_id_fk", - "tableFrom": "component_simulation_model", - "tableTo": "simulation_engine", - "schemaTo": "holotrace", - "columnsFrom": [ - "engine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_simulation_model_model_engine_fk": { - "name": "component_simulation_model_model_engine_fk", - "tableFrom": "component_simulation_model", - "tableTo": "simulation_model", - "schemaTo": "holotrace", - "columnsFrom": [ - "model_id", - "engine_id" - ], - "columnsTo": [ - "id", - "engine_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_simulation_model_uq": { - "name": "component_simulation_model_uq", - "nullsNotDistinct": true, - "columns": [ - "component_id", - "package_id", - "model_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.ml_model_version": { - "name": "ml_model_version", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "model_key": { - "name": "model_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "ml_model_version_artifact_id_artifact_id_fk": { - "name": "ml_model_version_artifact_id_artifact_id_fk", - "tableFrom": "ml_model_version", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "ml_model_version_model_key_version_uq": { - "name": "ml_model_version_model_key_version_uq", - "nullsNotDistinct": false, - "columns": [ - "model_key", - "version" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.net": { - "name": "net", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "net_key": { - "name": "net_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "kind": { - "name": "kind", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'signal'" - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "net_circuit_version_id_circuit_version_id_fk": { - "name": "net_circuit_version_id_circuit_version_id_fk", - "tableFrom": "net", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "net_circuit_version_id_net_key_uq": { - "name": "net_circuit_version_id_net_key_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "net_key" - ] - }, - "net_id_circuit_version_id_uq": { - "name": "net_id_circuit_version_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_version_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "net_kind_check": { - "name": "net_kind_check", - "value": "\"holotrace\".\"net\".\"kind\" IN ('signal', 'power', 'ground', 'unresolved')" - } - }, - "isRLSEnabled": false - }, - "holotrace.net_member": { - "name": "net_member", - "schema": "holotrace", - "columns": { - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "net_id": { - "name": "net_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "instance_pin_id": { - "name": "instance_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "net_member_circuit_version_id_circuit_version_id_fk": { - "name": "net_member_circuit_version_id_circuit_version_id_fk", - "tableFrom": "net_member", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "net_member_net_circuit_fk": { - "name": "net_member_net_circuit_fk", - "tableFrom": "net_member", - "tableTo": "net", - "schemaTo": "holotrace", - "columnsFrom": [ - "net_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "net_member_instance_pin_circuit_fk": { - "name": "net_member_instance_pin_circuit_fk", - "tableFrom": "net_member", - "tableTo": "component_instance_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "instance_pin_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "net_member_net_id_instance_pin_id_pk": { - "name": "net_member_net_id_instance_pin_id_pk", - "columns": [ - "net_id", - "instance_pin_id" - ] - } - }, - "uniqueConstraints": { - "net_member_circuit_version_id_instance_pin_id_uq": { - "name": "net_member_circuit_version_id_instance_pin_id_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "instance_pin_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.package_pin": { - "name": "package_pin", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_pin_id": { - "name": "component_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "physical_label": { - "name": "physical_label", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "anchor_2d": { - "name": "anchor_2d", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "anchor_3d": { - "name": "anchor_3d", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "package_pin_package_id_component_package_id_fk": { - "name": "package_pin_package_id_component_package_id_fk", - "tableFrom": "package_pin", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "package_pin_component_pin_id_component_pin_id_fk": { - "name": "package_pin_component_pin_id_component_pin_id_fk", - "tableFrom": "package_pin", - "tableTo": "component_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_pin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "package_pin_package_id_component_pin_id_uq": { - "name": "package_pin_package_id_component_pin_id_uq", - "nullsNotDistinct": false, - "columns": [ - "package_id", - "component_pin_id" - ] - }, - "package_pin_package_id_physical_label_uq": { - "name": "package_pin_package_id_physical_label_uq", - "nullsNotDistinct": false, - "columns": [ - "package_id", - "physical_label" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.project": { - "name": "project", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "project_workspace_idx": { - "name": "project_workspace_idx", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "updated_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "project_workspace_id_workspace_id_fk": { - "name": "project_workspace_id_workspace_id_fk", - "tableFrom": "project", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "project_created_by_app_user_id_fk": { - "name": "project_created_by_app_user_id_fk", - "tableFrom": "project", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.recognition_detection": { - "name": "recognition_detection", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "recognition_job_id": { - "name": "recognition_job_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "detection_kind": { - "name": "detection_kind", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "source_region": { - "name": "source_region", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "recognized_text": { - "name": "recognized_text", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "confidence": { - "name": "confidence", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "candidates": { - "name": "candidates", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'[]'::jsonb" - }, - "selected_component_id": { - "name": "selected_component_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "review_state": { - "name": "review_state", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'unreviewed'" - }, - "reviewed_by": { - "name": "reviewed_by", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "reviewed_at": { - "name": "reviewed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": { - "recognition_detection_job_idx": { - "name": "recognition_detection_job_idx", - "columns": [ - { - "expression": "recognition_job_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "detection_kind", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "recognition_detection_recognition_job_id_recognition_job_id_fk": { - "name": "recognition_detection_recognition_job_id_recognition_job_id_fk", - "tableFrom": "recognition_detection", - "tableTo": "recognition_job", - "schemaTo": "holotrace", - "columnsFrom": [ - "recognition_job_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "recognition_detection_selected_component_id_component_definition_id_fk": { - "name": "recognition_detection_selected_component_id_component_definition_id_fk", - "tableFrom": "recognition_detection", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "selected_component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_detection_reviewed_by_app_user_id_fk": { - "name": "recognition_detection_reviewed_by_app_user_id_fk", - "tableFrom": "recognition_detection", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "reviewed_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "recognition_detection_kind_check": { - "name": "recognition_detection_kind_check", - "value": "\"holotrace\".\"recognition_detection\".\"detection_kind\" IN ('component', 'pin', 'wire', 'junction', 'crossing', 'label', 'other')" - }, - "recognition_detection_confidence_check": { - "name": "recognition_detection_confidence_check", - "value": "\"holotrace\".\"recognition_detection\".\"confidence\" BETWEEN 0.0 AND 1.0" - }, - "recognition_detection_review_state_check": { - "name": "recognition_detection_review_state_check", - "value": "\"holotrace\".\"recognition_detection\".\"review_state\" IN ('unreviewed', 'accepted', 'corrected', 'rejected')" - } - }, - "isRLSEnabled": false - }, - "holotrace.recognition_job": { - "name": "recognition_job", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "project_id": { - "name": "project_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "source_artifact_id": { - "name": "source_artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "processed_artifact_id": { - "name": "processed_artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "model_version_id": { - "name": "model_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "preprocessing": { - "name": "preprocessing", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "raw_result": { - "name": "raw_result", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "error": { - "name": "error", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "requested_by": { - "name": "requested_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "started_at": { - "name": "started_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "completed_at": { - "name": "completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "recognition_job_project_idx": { - "name": "recognition_job_project_idx", - "columns": [ - { - "expression": "project_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "recognition_job_project_id_project_id_fk": { - "name": "recognition_job_project_id_project_id_fk", - "tableFrom": "recognition_job", - "tableTo": "project", - "schemaTo": "holotrace", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "recognition_job_source_artifact_id_artifact_id_fk": { - "name": "recognition_job_source_artifact_id_artifact_id_fk", - "tableFrom": "recognition_job", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "source_artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_job_processed_artifact_id_artifact_id_fk": { - "name": "recognition_job_processed_artifact_id_artifact_id_fk", - "tableFrom": "recognition_job", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "processed_artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_job_model_version_id_ml_model_version_id_fk": { - "name": "recognition_job_model_version_id_ml_model_version_id_fk", - "tableFrom": "recognition_job", - "tableTo": "ml_model_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "model_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_job_requested_by_app_user_id_fk": { - "name": "recognition_job_requested_by_app_user_id_fk", - "tableFrom": "recognition_job", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "requested_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "recognition_job_status_check": { - "name": "recognition_job_status_check", - "value": "\"holotrace\".\"recognition_job\".\"status\" IN ('queued', 'preprocessing', 'running', 'succeeded', 'failed', 'cancelled')" - } - }, - "isRLSEnabled": false - }, - "holotrace.simulation_artifact": { - "name": "simulation_artifact", - "schema": "holotrace", - "columns": { - "session_id": { - "name": "session_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "purpose": { - "name": "purpose", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "simulation_artifact_session_id_simulation_session_id_fk": { - "name": "simulation_artifact_session_id_simulation_session_id_fk", - "tableFrom": "simulation_artifact", - "tableTo": "simulation_session", - "schemaTo": "holotrace", - "columnsFrom": [ - "session_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "simulation_artifact_artifact_id_artifact_id_fk": { - "name": "simulation_artifact_artifact_id_artifact_id_fk", - "tableFrom": "simulation_artifact", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "simulation_artifact_session_id_artifact_id_pk": { - "name": "simulation_artifact_session_id_artifact_id_pk", - "columns": [ - "session_id", - "artifact_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.simulation_engine": { - "name": "simulation_engine", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "engine_key": { - "name": "engine_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "capabilities": { - "name": "capabilities", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "simulation_engine_engine_key_version_uq": { - "name": "simulation_engine_engine_key_version_uq", - "nullsNotDistinct": false, - "columns": [ - "engine_key", - "version" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.simulation_model": { - "name": "simulation_model", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "engine_id": { - "name": "engine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "model_key": { - "name": "model_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "definition": { - "name": "definition", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "parameters": { - "name": "parameters", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "simulation_model_engine_id_simulation_engine_id_fk": { - "name": "simulation_model_engine_id_simulation_engine_id_fk", - "tableFrom": "simulation_model", - "tableTo": "simulation_engine", - "schemaTo": "holotrace", - "columnsFrom": [ - "engine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "simulation_model_artifact_id_artifact_id_fk": { - "name": "simulation_model_artifact_id_artifact_id_fk", - "tableFrom": "simulation_model", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "simulation_model_engine_id_model_key_version_uq": { - "name": "simulation_model_engine_id_model_key_version_uq", - "nullsNotDistinct": false, - "columns": [ - "engine_id", - "model_key", - "version" - ] - }, - "simulation_model_id_engine_id_uq": { - "name": "simulation_model_id_engine_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "engine_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "simulation_model_version_check": { - "name": "simulation_model_version_check", - "value": "\"holotrace\".\"simulation_model\".\"version\" > 0" - }, - "simulation_model_definition_or_artifact_check": { - "name": "simulation_model_definition_or_artifact_check", - "value": "\"holotrace\".\"simulation_model\".\"definition\" IS NOT NULL OR \"holotrace\".\"simulation_model\".\"artifact_id\" IS NOT NULL" - } - }, - "isRLSEnabled": false - }, - "holotrace.simulation_sample": { - "name": "simulation_sample", - "schema": "holotrace", - "columns": { - "sampled_at": { - "name": "sampled_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "session_id": { - "name": "session_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "signal_id": { - "name": "signal_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "double precision", - "primaryKey": false, - "notNull": true - }, - "quality": { - "name": "quality", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": { - "simulation_sample_signal_time_idx": { - "name": "simulation_sample_signal_time_idx", - "columns": [ - { - "expression": "session_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "signal_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "sampled_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "simulation_sample_signal_session_fk": { - "name": "simulation_sample_signal_session_fk", - "tableFrom": "simulation_sample", - "tableTo": "simulation_signal", - "schemaTo": "holotrace", - "columnsFrom": [ - "signal_id", - "session_id" - ], - "columnsTo": [ - "id", - "session_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "simulation_sample_sampled_at_session_id_signal_id_pk": { - "name": "simulation_sample_sampled_at_session_id_signal_id_pk", - "columns": [ - "sampled_at", - "session_id", - "signal_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.simulation_session": { - "name": "simulation_session", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "engine_id": { - "name": "engine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "configuration": { - "name": "configuration", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "model_manifest": { - "name": "model_manifest", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "summary": { - "name": "summary", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "error": { - "name": "error", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "started_at": { - "name": "started_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "completed_at": { - "name": "completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "simulation_session_circuit_idx": { - "name": "simulation_session_circuit_idx", - "columns": [ - { - "expression": "circuit_version_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "simulation_session_circuit_version_id_circuit_version_id_fk": { - "name": "simulation_session_circuit_version_id_circuit_version_id_fk", - "tableFrom": "simulation_session", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "simulation_session_engine_id_simulation_engine_id_fk": { - "name": "simulation_session_engine_id_simulation_engine_id_fk", - "tableFrom": "simulation_session", - "tableTo": "simulation_engine", - "schemaTo": "holotrace", - "columnsFrom": [ - "engine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "simulation_session_created_by_app_user_id_fk": { - "name": "simulation_session_created_by_app_user_id_fk", - "tableFrom": "simulation_session", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "simulation_session_status_check": { - "name": "simulation_session_status_check", - "value": "\"holotrace\".\"simulation_session\".\"status\" IN ('created', 'running', 'paused', 'completed', 'failed', 'cancelled')" - } - }, - "isRLSEnabled": false - }, - "holotrace.simulation_signal": { - "name": "simulation_signal", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "session_id": { - "name": "session_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "signal_key": { - "name": "signal_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "quantity": { - "name": "quantity", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "unit": { - "name": "unit", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "source_kind": { - "name": "source_kind", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "source_id": { - "name": "source_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "simulation_signal_session_id_simulation_session_id_fk": { - "name": "simulation_signal_session_id_simulation_session_id_fk", - "tableFrom": "simulation_signal", - "tableTo": "simulation_session", - "schemaTo": "holotrace", - "columnsFrom": [ - "session_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "simulation_signal_session_id_signal_key_uq": { - "name": "simulation_signal_session_id_signal_key_uq", - "nullsNotDistinct": false, - "columns": [ - "session_id", - "signal_key" - ] - }, - "simulation_signal_id_session_id_uq": { - "name": "simulation_signal_id_session_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "session_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.validation_issue": { - "name": "validation_issue", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "severity": { - "name": "severity", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "issue_code": { - "name": "issue_code", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "message": { - "name": "message", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "target_kind": { - "name": "target_kind", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "target_id": { - "name": "target_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "details": { - "name": "details", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "resolved_at": { - "name": "resolved_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "validation_issue_open_idx": { - "name": "validation_issue_open_idx", - "columns": [ - { - "expression": "circuit_version_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "severity", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "where": "\"holotrace\".\"validation_issue\".\"resolved_at\" IS NULL", - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "validation_issue_circuit_version_id_circuit_version_id_fk": { - "name": "validation_issue_circuit_version_id_circuit_version_id_fk", - "tableFrom": "validation_issue", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "validation_issue_severity_check": { - "name": "validation_issue_severity_check", - "value": "\"holotrace\".\"validation_issue\".\"severity\" IN ('info', 'warning', 'error')" - } - }, - "isRLSEnabled": false - }, - "holotrace.wire_route": { - "name": "wire_route", - "schema": "holotrace", - "columns": { - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "layout_id": { - "name": "layout_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "net_id": { - "name": "net_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "route": { - "name": "route", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "style": { - "name": "style", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "wire_route_circuit_version_id_circuit_version_id_fk": { - "name": "wire_route_circuit_version_id_circuit_version_id_fk", - "tableFrom": "wire_route", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "wire_route_layout_circuit_fk": { - "name": "wire_route_layout_circuit_fk", - "tableFrom": "wire_route", - "tableTo": "circuit_layout", - "schemaTo": "holotrace", - "columnsFrom": [ - "layout_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "wire_route_net_circuit_fk": { - "name": "wire_route_net_circuit_fk", - "tableFrom": "wire_route", - "tableTo": "net", - "schemaTo": "holotrace", - "columnsFrom": [ - "net_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "wire_route_layout_id_net_id_pk": { - "name": "wire_route_layout_id_net_id_pk", - "columns": [ - "layout_id", - "net_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.workspace": { - "name": "workspace", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workspace_created_by_app_user_id_fk": { - "name": "workspace_created_by_app_user_id_fk", - "tableFrom": "workspace", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.workspace_member": { - "name": "workspace_member", - "schema": "holotrace", - "columns": { - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workspace_member_workspace_id_workspace_id_fk": { - "name": "workspace_member_workspace_id_workspace_id_fk", - "tableFrom": "workspace_member", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "workspace_member_user_id_app_user_id_fk": { - "name": "workspace_member_user_id_app_user_id_fk", - "tableFrom": "workspace_member", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "workspace_member_workspace_id_user_id_pk": { - "name": "workspace_member_workspace_id_user_id_pk", - "columns": [ - "workspace_id", - "user_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "workspace_member_role_check": { - "name": "workspace_member_role_check", - "value": "\"holotrace\".\"workspace_member\".\"role\" IN ('owner', 'editor', 'viewer')" - } - }, + "checkConstraints": {}, "isRLSEnabled": false } }, "enums": {}, - "schemas": { - "holotrace": "holotrace" - }, + "schemas": {}, "sequences": {}, "roles": {}, "policies": {}, diff --git a/api_server/drizzle/meta/0001_snapshot.json b/api_server/drizzle/meta/0001_snapshot.json index 6fc3d6c..bc51474 100644 --- a/api_server/drizzle/meta/0001_snapshot.json +++ b/api_server/drizzle/meta/0001_snapshot.json @@ -1,42 +1,94 @@ { - "id": "94fa7879-f248-47aa-adc8-6d33aa3d99b1", - "prevId": "d03dc983-8b11-40f8-be5f-282b6d690246", + "id": "71bcdee2-6cd9-4d83-a185-a811d3686ec3", + "prevId": "fed3c11d-c69d-4b04-9e0c-8dafefa34252", "version": "7", "dialect": "postgresql", "tables": { - "holotrace.app_user": { - "name": "app_user", - "schema": "holotrace", + "public.projects": { + "name": "projects", + "schema": "", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "serial", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" + "notNull": true }, - "auth_subject": { - "name": "auth_subject", - "type": "text", + "owner": { + "name": "owner", + "type": "integer", "primaryKey": false, "notNull": true }, - "display_name": { - "name": "display_name", + "data": { + "name": "data", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true, + "default": "''" }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", + "createdAt": { + "name": "createdAt", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", + "modifiedAt": { + "name": "modifiedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "projects_owner_users_id_fk": { + "name": "projects_owner_users_id_fk", + "tableFrom": "projects", + "tableTo": "users", + "columnsFrom": [ + "owner" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(18)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" @@ -46,11 +98,11 @@ "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": { - "app_user_auth_subject_unique": { - "name": "app_user_auth_subject_unique", + "users_username_unique": { + "name": "users_username_unique", "nullsNotDistinct": false, "columns": [ - "auth_subject" + "username" ] } }, @@ -58,107 +110,99 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "holotrace.artifact": { - "name": "artifact", - "schema": "holotrace", + "auth.account": { + "name": "account", + "schema": "auth", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "text", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": false + "notNull": true }, - "kind": { - "name": "kind", + "account_id": { + "name": "account_id", "type": "text", "primaryKey": false, "notNull": true }, - "object_key": { - "name": "object_key", + "provider_id": { + "name": "provider_id", "type": "text", "primaryKey": false, "notNull": true }, - "mime_type": { - "name": "mime_type", + "user_id": { + "name": "user_id", "type": "text", "primaryKey": false, "notNull": true }, - "byte_size": { - "name": "byte_size", - "type": "bigint", + "access_token": { + "name": "access_token", + "type": "text", "primaryKey": false, - "notNull": true + "notNull": false }, - "sha256": { - "name": "sha256", + "refresh_token": { + "name": "refresh_token", "type": "text", "primaryKey": false, - "notNull": true + "notNull": false }, - "license_id": { - "name": "license_id", + "id_token": { + "name": "id_token", "type": "text", "primaryKey": false, "notNull": false }, - "source_uri": { - "name": "source_uri", - "type": "text", + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", "primaryKey": false, "notNull": false }, - "provenance": { - "name": "provenance", - "type": "jsonb", + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false }, - "created_by": { - "name": "created_by", - "type": "uuid", + "password": { + "name": "password", + "type": "text", "primaryKey": false, "notNull": false }, "created_at": { "name": "created_at", - "type": "timestamp with time zone", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true } }, "indexes": { - "artifact_workspace_kind_idx": { - "name": "artifact_workspace_kind_idx", + "account_userId_idx": { + "name": "account_userId_idx", "columns": [ { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "kind", + "expression": "user_id", "isExpression": false, "asc": true, "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "last" } ], "isUnique": false, @@ -168,121 +212,90 @@ } }, "foreignKeys": { - "artifact_workspace_id_workspace_id_fk": { - "name": "artifact_workspace_id_workspace_id_fk", - "tableFrom": "artifact", - "tableTo": "workspace", - "schemaTo": "holotrace", + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "schemaTo": "auth", "columnsFrom": [ - "workspace_id" + "user_id" ], "columnsTo": [ "id" ], "onDelete": "cascade", "onUpdate": "no action" - }, - "artifact_created_by_app_user_id_fk": { - "name": "artifact_created_by_app_user_id_fk", - "tableFrom": "artifact", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": { - "artifact_object_key_unique": { - "name": "artifact_object_key_unique", - "nullsNotDistinct": false, - "columns": [ - "object_key" - ] - } - }, + "uniqueConstraints": {}, "policies": {}, - "checkConstraints": { - "artifact_kind_check": { - "name": "artifact_kind_check", - "value": "\"holotrace\".\"artifact\".\"kind\" IN ('source_image', 'processed_image', 'schematic_svg', 'physical_2d', 'model_3d', 'texture', 'firmware', 'waveform', 'other')" - }, - "artifact_byte_size_check": { - "name": "artifact_byte_size_check", - "value": "\"holotrace\".\"artifact\".\"byte_size\" >= 0" - }, - "artifact_sha256_check": { - "name": "artifact_sha256_check", - "value": "\"holotrace\".\"artifact\".\"sha256\" ~ '^[0-9a-f]{64}$'" - } - }, + "checkConstraints": {}, "isRLSEnabled": false }, - "holotrace.circuit": { - "name": "circuit", - "schema": "holotrace", + "auth.session": { + "name": "session", + "schema": "auth", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "text", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "project_id": { - "name": "project_id", - "type": "uuid", - "primaryKey": false, "notNull": true }, - "name": { - "name": "name", - "type": "text", + "expires_at": { + "name": "expires_at", + "type": "timestamp", "primaryKey": false, "notNull": true }, - "created_by": { - "name": "created_by", - "type": "uuid", + "token": { + "name": "token", + "type": "text", "primaryKey": false, "notNull": true }, "created_at": { "name": "created_at", - "type": "timestamp with time zone", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" }, "updated_at": { "name": "updated_at", - "type": "timestamp with time zone", + "type": "timestamp", "primaryKey": false, - "notNull": true, - "default": "now()" + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true } }, "indexes": { - "circuit_project_idx": { - "name": "circuit_project_idx", + "session_userId_idx": { + "name": "session_userId_idx", "columns": [ { - "expression": "project_id", + "expression": "user_id", "isExpression": false, "asc": true, "nulls": "last" - }, - { - "expression": "updated_at", - "isExpression": false, - "asc": false, - "nulls": "last" } ], "isUnique": false, @@ -292,3346 +305,191 @@ } }, "foreignKeys": { - "circuit_project_id_project_id_fk": { - "name": "circuit_project_id_project_id_fk", - "tableFrom": "circuit", - "tableTo": "project", - "schemaTo": "holotrace", + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "schemaTo": "auth", "columnsFrom": [ - "project_id" + "user_id" ], "columnsTo": [ "id" ], "onDelete": "cascade", "onUpdate": "no action" - }, - "circuit_created_by_app_user_id_fk": { - "name": "circuit_created_by_app_user_id_fk", - "tableFrom": "circuit", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, "policies": {}, "checkConstraints": {}, "isRLSEnabled": false }, - "holotrace.circuit_layout": { - "name": "circuit_layout", - "schema": "holotrace", + "auth.user": { + "name": "user", + "schema": "auth", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "text", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, "notNull": true }, - "layout_kind": { - "name": "layout_kind", + "name": { + "name": "name", "type": "text", "primaryKey": false, "notNull": true }, - "revision": { - "name": "revision", - "type": "integer", + "email": { + "name": "email", + "type": "text", "primaryKey": false, "notNull": true }, - "generator": { - "name": "generator", - "type": "text", + "email_verified": { + "name": "email_verified", + "type": "boolean", "primaryKey": false, - "notNull": false + "notNull": true, + "default": false }, - "generator_version": { - "name": "generator_version", + "image": { + "name": "image", "type": "text", "primaryKey": false, "notNull": false }, - "viewport": { - "name": "viewport", - "type": "jsonb", + "created_at": { + "name": "created_at", + "type": "timestamp", "primaryKey": false, "notNull": true, - "default": "'{}'::jsonb" + "default": "now()" }, - "metadata": { - "name": "metadata", - "type": "jsonb", + "updated_at": { + "name": "updated_at", + "type": "timestamp", "primaryKey": false, "notNull": true, - "default": "'{}'::jsonb" + "default": "now()" }, - "created_by": { - "name": "created_by", - "type": "uuid", + "username": { + "name": "username", + "type": "text", "primaryKey": false, "notNull": false }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", + "display_username": { + "name": "display_username", + "type": "text", "primaryKey": false, - "notNull": true, - "default": "now()" + "notNull": false } }, "indexes": {}, - "foreignKeys": { - "circuit_layout_circuit_version_id_circuit_version_id_fk": { - "name": "circuit_layout_circuit_version_id_circuit_version_id_fk", - "tableFrom": "circuit_layout", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_layout_created_by_app_user_id_fk": { - "name": "circuit_layout_created_by_app_user_id_fk", - "tableFrom": "circuit_layout", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, + "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": { - "circuit_layout_circuit_version_id_layout_kind_revision_uq": { - "name": "circuit_layout_circuit_version_id_layout_kind_revision_uq", + "user_email_unique": { + "name": "user_email_unique", "nullsNotDistinct": false, "columns": [ - "circuit_version_id", - "layout_kind", - "revision" + "email" ] }, - "circuit_layout_id_circuit_version_id_uq": { - "name": "circuit_layout_id_circuit_version_id_uq", + "user_username_unique": { + "name": "user_username_unique", "nullsNotDistinct": false, "columns": [ - "id", - "circuit_version_id" + "username" ] } }, "policies": {}, - "checkConstraints": { - "circuit_layout_kind_check": { - "name": "circuit_layout_kind_check", - "value": "\"holotrace\".\"circuit_layout\".\"layout_kind\" IN ('schematic_2d', 'physical_2d', 'physical_3d')" - }, - "circuit_layout_revision_check": { - "name": "circuit_layout_revision_check", - "value": "\"holotrace\".\"circuit_layout\".\"revision\" > 0" - } - }, + "checkConstraints": {}, "isRLSEnabled": false }, - "holotrace.circuit_version": { - "name": "circuit_version", - "schema": "holotrace", + "auth.verification": { + "name": "verification", + "schema": "auth", "columns": { "id": { "name": "id", - "type": "uuid", + "type": "text", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_id": { - "name": "circuit_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "version_number": { - "name": "version_number", - "type": "integer", - "primaryKey": false, "notNull": true }, - "parent_version_id": { - "name": "parent_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "recognition_job_id": { - "name": "recognition_job_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "schema_version": { - "name": "schema_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "ir_schema_version": { - "name": "ir_schema_version", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'circuit-ir-v0'" - }, - "status": { - "name": "status", + "identifier": { + "name": "identifier", "type": "text", "primaryKey": false, "notNull": true }, - "change_summary": { - "name": "change_summary", + "value": { + "name": "value", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true }, - "created_by": { - "name": "created_by", - "type": "uuid", + "expires_at": { + "name": "expires_at", + "type": "timestamp", "primaryKey": false, "notNull": true }, "created_at": { "name": "created_at", - "type": "timestamp with time zone", + "type": "timestamp", "primaryKey": false, "notNull": true, "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "circuit_version_circuit_id_circuit_id_fk": { - "name": "circuit_version_circuit_id_circuit_id_fk", - "tableFrom": "circuit_version", - "tableTo": "circuit", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_version_recognition_job_id_recognition_job_id_fk": { - "name": "circuit_version_recognition_job_id_recognition_job_id_fk", - "tableFrom": "circuit_version", - "tableTo": "recognition_job", - "schemaTo": "holotrace", - "columnsFrom": [ - "recognition_job_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "circuit_version_created_by_app_user_id_fk": { - "name": "circuit_version_created_by_app_user_id_fk", - "tableFrom": "circuit_version", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" }, - "circuit_version_parent_circuit_fk": { - "name": "circuit_version_parent_circuit_fk", - "tableFrom": "circuit_version", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "parent_version_id", - "circuit_id" - ], - "columnsTo": [ - "id", - "circuit_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "circuit_version_circuit_id_version_number_uq": { - "name": "circuit_version_circuit_id_version_number_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_id", - "version_number" - ] - }, - "circuit_version_id_circuit_id_uq": { - "name": "circuit_version_id_circuit_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "circuit_version_number_check": { - "name": "circuit_version_number_check", - "value": "\"holotrace\".\"circuit_version\".\"version_number\" > 0" - }, - "circuit_version_schema_version_check": { - "name": "circuit_version_schema_version_check", - "value": "\"holotrace\".\"circuit_version\".\"schema_version\" > 0" - }, - "circuit_version_ir_schema_version_check": { - "name": "circuit_version_ir_schema_version_check", - "value": "length(\"holotrace\".\"circuit_version\".\"ir_schema_version\") > 0" - }, - "circuit_version_status_check": { - "name": "circuit_version_status_check", - "value": "\"holotrace\".\"circuit_version\".\"status\" IN ('recognized', 'needs_review', 'electrically_valid', 'simulatable', 'archived')" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_definition": { - "name": "component_definition", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "slug": { - "name": "slug", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "manufacturer": { - "name": "manufacturer", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "manufacturer_part": { - "name": "manufacturer_part", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "properties": { - "name": "properties", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "catalog_version": { - "name": "catalog_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "is_active": { - "name": "is_active", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "component_definition_global_slug_uq": { - "name": "component_definition_global_slug_uq", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_definition\".\"workspace_id\" IS NULL", - "concurrently": false, - "method": "btree", - "with": {} - }, - "component_definition_workspace_slug_uq": { - "name": "component_definition_workspace_slug_uq", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_definition\".\"workspace_id\" IS NOT NULL", - "concurrently": false, - "method": "btree", - "with": {} - }, - "component_definition_properties_gin": { - "name": "component_definition_properties_gin", - "columns": [ - { - "expression": "\"properties\" jsonb_path_ops", - "asc": true, - "isExpression": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "gin", - "with": {} - } - }, - "foreignKeys": { - "component_definition_workspace_id_workspace_id_fk": { - "name": "component_definition_workspace_id_workspace_id_fk", - "tableFrom": "component_definition", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "component_definition_catalog_version_check": { - "name": "component_definition_catalog_version_check", - "value": "\"holotrace\".\"component_definition\".\"catalog_version\" > 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_instance": { - "name": "component_instance", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "source_detection_id": { - "name": "source_detection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "reference_designator": { - "name": "reference_designator", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "properties": { - "name": "properties", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "recognition_confidence": { - "name": "recognition_confidence", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "resolution_state": { - "name": "resolution_state", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'resolved'" - } - }, - "indexes": {}, - "foreignKeys": { - "component_instance_circuit_version_id_circuit_version_id_fk": { - "name": "component_instance_circuit_version_id_circuit_version_id_fk", - "tableFrom": "component_instance", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_instance_component_id_component_definition_id_fk": { - "name": "component_instance_component_id_component_definition_id_fk", - "tableFrom": "component_instance", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_source_detection_id_recognition_detection_id_fk": { - "name": "component_instance_source_detection_id_recognition_detection_id_fk", - "tableFrom": "component_instance", - "tableTo": "recognition_detection", - "schemaTo": "holotrace", - "columnsFrom": [ - "source_detection_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_package_component_fk": { - "name": "component_instance_package_component_fk", - "tableFrom": "component_instance", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id", - "component_id" - ], - "columnsTo": [ - "id", - "component_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_instance_circuit_version_id_reference_designator_uq": { - "name": "component_instance_circuit_version_id_reference_designator_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "reference_designator" - ] - }, - "component_instance_id_circuit_version_id_uq": { - "name": "component_instance_id_circuit_version_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_version_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "component_instance_recognition_confidence_check": { - "name": "component_instance_recognition_confidence_check", - "value": "\"holotrace\".\"component_instance\".\"recognition_confidence\" BETWEEN 0.0 AND 1.0" - }, - "component_instance_resolution_state_check": { - "name": "component_instance_resolution_state_check", - "value": "\"holotrace\".\"component_instance\".\"resolution_state\" IN ('resolved', 'inferred', 'ambiguous', 'unknown')" - }, - "component_instance_package_requires_component_check": { - "name": "component_instance_package_requires_component_check", - "value": "\"holotrace\".\"component_instance\".\"package_id\" IS NULL OR \"holotrace\".\"component_instance\".\"component_id\" IS NOT NULL" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_instance_pin": { - "name": "component_instance_pin", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_instance_id": { - "name": "component_instance_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_pin_id": { - "name": "component_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "package_pin_id": { - "name": "package_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "pin_key": { - "name": "pin_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "component_instance_pin_circuit_version_id_circuit_version_id_fk": { - "name": "component_instance_pin_circuit_version_id_circuit_version_id_fk", - "tableFrom": "component_instance_pin", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_instance_pin_component_pin_id_component_pin_id_fk": { - "name": "component_instance_pin_component_pin_id_component_pin_id_fk", - "tableFrom": "component_instance_pin", - "tableTo": "component_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_pin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_pin_package_pin_id_package_pin_id_fk": { - "name": "component_instance_pin_package_pin_id_package_pin_id_fk", - "tableFrom": "component_instance_pin", - "tableTo": "package_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_pin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_instance_pin_instance_circuit_fk": { - "name": "component_instance_pin_instance_circuit_fk", - "tableFrom": "component_instance_pin", - "tableTo": "component_instance", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_instance_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_instance_pin_instance_id_pin_key_uq": { - "name": "component_instance_pin_instance_id_pin_key_uq", - "nullsNotDistinct": false, - "columns": [ - "component_instance_id", - "pin_key" - ] - }, - "component_instance_pin_id_circuit_version_id_uq": { - "name": "component_instance_pin_id_circuit_version_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_version_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.component_package": { - "name": "component_package", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "package_key": { - "name": "package_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dimensions_mm": { - "name": "dimensions_mm", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "component_package_component_id_component_definition_id_fk": { - "name": "component_package_component_id_component_definition_id_fk", - "tableFrom": "component_package", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_package_component_id_package_key_uq": { - "name": "component_package_component_id_package_key_uq", - "nullsNotDistinct": false, - "columns": [ - "component_id", - "package_key" - ] - }, - "component_package_id_component_id_uq": { - "name": "component_package_id_component_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "component_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.component_pin": { - "name": "component_pin", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "pin_key": { - "name": "pin_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "electrical_role": { - "name": "electrical_role", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "ordinal": { - "name": "ordinal", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "component_pin_component_id_component_definition_id_fk": { - "name": "component_pin_component_id_component_definition_id_fk", - "tableFrom": "component_pin", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_pin_component_id_pin_key_uq": { - "name": "component_pin_component_id_pin_key_uq", - "nullsNotDistinct": false, - "columns": [ - "component_id", - "pin_key" - ] - }, - "component_pin_component_id_ordinal_uq": { - "name": "component_pin_component_id_ordinal_uq", - "nullsNotDistinct": false, - "columns": [ - "component_id", - "ordinal" - ] - } - }, - "policies": {}, - "checkConstraints": { - "component_pin_ordinal_check": { - "name": "component_pin_ordinal_check", - "value": "\"holotrace\".\"component_pin\".\"ordinal\" >= 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_placement": { - "name": "component_placement", - "schema": "holotrace", - "columns": { - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "layout_id": { - "name": "layout_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_instance_id": { - "name": "component_instance_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "position_x": { - "name": "position_x", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "position_y": { - "name": "position_y", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "position_z": { - "name": "position_z", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_x": { - "name": "rotation_x", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_y": { - "name": "rotation_y", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_z": { - "name": "rotation_z", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "rotation_w": { - "name": "rotation_w", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "scale_x": { - "name": "scale_x", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "scale_y": { - "name": "scale_y", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "scale_z": { - "name": "scale_z", - "type": "double precision", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "component_placement_circuit_version_id_circuit_version_id_fk": { - "name": "component_placement_circuit_version_id_circuit_version_id_fk", - "tableFrom": "component_placement", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_placement_layout_circuit_fk": { - "name": "component_placement_layout_circuit_fk", - "tableFrom": "component_placement", - "tableTo": "circuit_layout", - "schemaTo": "holotrace", - "columnsFrom": [ - "layout_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_placement_instance_circuit_fk": { - "name": "component_placement_instance_circuit_fk", - "tableFrom": "component_placement", - "tableTo": "component_instance", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_instance_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "component_placement_layout_id_component_instance_id_pk": { - "name": "component_placement_layout_id_component_instance_id_pk", - "columns": [ - "layout_id", - "component_instance_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.component_representation": { - "name": "component_representation", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "representation_kind": { - "name": "representation_kind", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "detail_level": { - "name": "detail_level", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "component_representation_component_id_component_definition_id_fk": { - "name": "component_representation_component_id_component_definition_id_fk", - "tableFrom": "component_representation", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_representation_package_id_component_package_id_fk": { - "name": "component_representation_package_id_component_package_id_fk", - "tableFrom": "component_representation", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_representation_artifact_id_artifact_id_fk": { - "name": "component_representation_artifact_id_artifact_id_fk", - "tableFrom": "component_representation", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_representation_package_component_fk": { - "name": "component_representation_package_component_fk", - "tableFrom": "component_representation", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id", - "component_id" - ], - "columnsTo": [ - "id", - "component_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_representation_uq": { - "name": "component_representation_uq", - "nullsNotDistinct": true, - "columns": [ - "component_id", - "package_id", - "representation_kind", - "detail_level" - ] - } - }, - "policies": {}, - "checkConstraints": { - "component_representation_kind_check": { - "name": "component_representation_kind_check", - "value": "\"holotrace\".\"component_representation\".\"representation_kind\" IN ('schematic_svg', 'physical_2d', 'model_3d')" - }, - "component_representation_detail_level_check": { - "name": "component_representation_detail_level_check", - "value": "\"holotrace\".\"component_representation\".\"detail_level\" >= 0" - } - }, - "isRLSEnabled": false - }, - "holotrace.component_simulation_model": { - "name": "component_simulation_model", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "component_id": { - "name": "component_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "engine_id": { - "name": "engine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "model_id": { - "name": "model_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "pin_mapping": { - "name": "pin_mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "parameter_mapping": { - "name": "parameter_mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "interaction_mapping": { - "name": "interaction_mapping", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - } - }, - "indexes": { - "component_default_simulation_model_for_package_uq": { - "name": "component_default_simulation_model_for_package_uq", - "columns": [ - { - "expression": "component_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "package_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "engine_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_simulation_model\".\"is_default\" AND \"holotrace\".\"component_simulation_model\".\"package_id\" IS NOT NULL", - "concurrently": false, - "method": "btree", - "with": {} - }, - "component_default_simulation_model_without_package_uq": { - "name": "component_default_simulation_model_without_package_uq", - "columns": [ - { - "expression": "component_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "engine_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "where": "\"holotrace\".\"component_simulation_model\".\"is_default\" AND \"holotrace\".\"component_simulation_model\".\"package_id\" IS NULL", - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "component_simulation_model_component_id_component_definition_id_fk": { - "name": "component_simulation_model_component_id_component_definition_id_fk", - "tableFrom": "component_simulation_model", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_simulation_model_package_id_component_package_id_fk": { - "name": "component_simulation_model_package_id_component_package_id_fk", - "tableFrom": "component_simulation_model", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "component_simulation_model_engine_id_simulation_engine_id_fk": { - "name": "component_simulation_model_engine_id_simulation_engine_id_fk", - "tableFrom": "component_simulation_model", - "tableTo": "simulation_engine", - "schemaTo": "holotrace", - "columnsFrom": [ - "engine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_simulation_model_model_engine_fk": { - "name": "component_simulation_model_model_engine_fk", - "tableFrom": "component_simulation_model", - "tableTo": "simulation_model", - "schemaTo": "holotrace", - "columnsFrom": [ - "model_id", - "engine_id" - ], - "columnsTo": [ - "id", - "engine_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "component_simulation_model_package_component_fk": { - "name": "component_simulation_model_package_component_fk", - "tableFrom": "component_simulation_model", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id", - "component_id" - ], - "columnsTo": [ - "id", - "component_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "component_simulation_model_uq": { - "name": "component_simulation_model_uq", - "nullsNotDistinct": true, - "columns": [ - "component_id", - "package_id", - "model_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.ml_model_version": { - "name": "ml_model_version", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "model_key": { - "name": "model_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "ml_model_version_artifact_id_artifact_id_fk": { - "name": "ml_model_version_artifact_id_artifact_id_fk", - "tableFrom": "ml_model_version", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "ml_model_version_model_key_version_uq": { - "name": "ml_model_version_model_key_version_uq", - "nullsNotDistinct": false, - "columns": [ - "model_key", - "version" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.net": { - "name": "net", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "net_key": { - "name": "net_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "kind": { - "name": "kind", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'signal'" - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "net_circuit_version_id_circuit_version_id_fk": { - "name": "net_circuit_version_id_circuit_version_id_fk", - "tableFrom": "net", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "net_circuit_version_id_net_key_uq": { - "name": "net_circuit_version_id_net_key_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "net_key" - ] - }, - "net_id_circuit_version_id_uq": { - "name": "net_id_circuit_version_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "circuit_version_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "net_kind_check": { - "name": "net_kind_check", - "value": "\"holotrace\".\"net\".\"kind\" IN ('signal', 'power', 'ground', 'unresolved')" - } - }, - "isRLSEnabled": false - }, - "holotrace.net_member": { - "name": "net_member", - "schema": "holotrace", - "columns": { - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "net_id": { - "name": "net_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "instance_pin_id": { - "name": "instance_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "net_member_circuit_version_id_circuit_version_id_fk": { - "name": "net_member_circuit_version_id_circuit_version_id_fk", - "tableFrom": "net_member", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "net_member_net_circuit_fk": { - "name": "net_member_net_circuit_fk", - "tableFrom": "net_member", - "tableTo": "net", - "schemaTo": "holotrace", - "columnsFrom": [ - "net_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "net_member_instance_pin_circuit_fk": { - "name": "net_member_instance_pin_circuit_fk", - "tableFrom": "net_member", - "tableTo": "component_instance_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "instance_pin_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "net_member_net_id_instance_pin_id_pk": { - "name": "net_member_net_id_instance_pin_id_pk", - "columns": [ - "net_id", - "instance_pin_id" - ] - } - }, - "uniqueConstraints": { - "net_member_circuit_version_id_instance_pin_id_uq": { - "name": "net_member_circuit_version_id_instance_pin_id_uq", - "nullsNotDistinct": false, - "columns": [ - "circuit_version_id", - "instance_pin_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.package_pin": { - "name": "package_pin", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "package_id": { - "name": "package_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "component_pin_id": { - "name": "component_pin_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "physical_label": { - "name": "physical_label", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "anchor_2d": { - "name": "anchor_2d", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "anchor_3d": { - "name": "anchor_3d", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "package_pin_package_id_component_package_id_fk": { - "name": "package_pin_package_id_component_package_id_fk", - "tableFrom": "package_pin", - "tableTo": "component_package", - "schemaTo": "holotrace", - "columnsFrom": [ - "package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "package_pin_component_pin_id_component_pin_id_fk": { - "name": "package_pin_component_pin_id_component_pin_id_fk", - "tableFrom": "package_pin", - "tableTo": "component_pin", - "schemaTo": "holotrace", - "columnsFrom": [ - "component_pin_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "package_pin_package_id_component_pin_id_uq": { - "name": "package_pin_package_id_component_pin_id_uq", - "nullsNotDistinct": false, - "columns": [ - "package_id", - "component_pin_id" - ] - }, - "package_pin_package_id_physical_label_uq": { - "name": "package_pin_package_id_physical_label_uq", - "nullsNotDistinct": false, - "columns": [ - "package_id", - "physical_label" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.project": { - "name": "project", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "project_workspace_idx": { - "name": "project_workspace_idx", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "updated_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "project_workspace_id_workspace_id_fk": { - "name": "project_workspace_id_workspace_id_fk", - "tableFrom": "project", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "project_created_by_app_user_id_fk": { - "name": "project_created_by_app_user_id_fk", - "tableFrom": "project", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.recognition_detection": { - "name": "recognition_detection", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "recognition_job_id": { - "name": "recognition_job_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "detection_kind": { - "name": "detection_kind", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "source_region": { - "name": "source_region", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "recognized_text": { - "name": "recognized_text", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "confidence": { - "name": "confidence", - "type": "double precision", - "primaryKey": false, - "notNull": false - }, - "candidates": { - "name": "candidates", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'[]'::jsonb" - }, - "selected_component_id": { - "name": "selected_component_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "review_state": { - "name": "review_state", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'unreviewed'" - }, - "reviewed_by": { - "name": "reviewed_by", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "reviewed_at": { - "name": "reviewed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": { - "recognition_detection_job_idx": { - "name": "recognition_detection_job_idx", - "columns": [ - { - "expression": "recognition_job_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "detection_kind", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "recognition_detection_recognition_job_id_recognition_job_id_fk": { - "name": "recognition_detection_recognition_job_id_recognition_job_id_fk", - "tableFrom": "recognition_detection", - "tableTo": "recognition_job", - "schemaTo": "holotrace", - "columnsFrom": [ - "recognition_job_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "recognition_detection_selected_component_id_component_definition_id_fk": { - "name": "recognition_detection_selected_component_id_component_definition_id_fk", - "tableFrom": "recognition_detection", - "tableTo": "component_definition", - "schemaTo": "holotrace", - "columnsFrom": [ - "selected_component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_detection_reviewed_by_app_user_id_fk": { - "name": "recognition_detection_reviewed_by_app_user_id_fk", - "tableFrom": "recognition_detection", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "reviewed_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "recognition_detection_kind_check": { - "name": "recognition_detection_kind_check", - "value": "\"holotrace\".\"recognition_detection\".\"detection_kind\" IN ('component', 'pin', 'wire', 'junction', 'crossing', 'label', 'other')" - }, - "recognition_detection_confidence_check": { - "name": "recognition_detection_confidence_check", - "value": "\"holotrace\".\"recognition_detection\".\"confidence\" BETWEEN 0.0 AND 1.0" - }, - "recognition_detection_review_state_check": { - "name": "recognition_detection_review_state_check", - "value": "\"holotrace\".\"recognition_detection\".\"review_state\" IN ('unreviewed', 'accepted', 'corrected', 'rejected')" - } - }, - "isRLSEnabled": false - }, - "holotrace.recognition_job": { - "name": "recognition_job", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "project_id": { - "name": "project_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "source_artifact_id": { - "name": "source_artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "processed_artifact_id": { - "name": "processed_artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "model_version_id": { - "name": "model_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "preprocessing": { - "name": "preprocessing", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "raw_result": { - "name": "raw_result", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "error": { - "name": "error", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "requested_by": { - "name": "requested_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "started_at": { - "name": "started_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "completed_at": { - "name": "completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "recognition_job_project_idx": { - "name": "recognition_job_project_idx", - "columns": [ - { - "expression": "project_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "recognition_job_project_id_project_id_fk": { - "name": "recognition_job_project_id_project_id_fk", - "tableFrom": "recognition_job", - "tableTo": "project", - "schemaTo": "holotrace", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "recognition_job_source_artifact_id_artifact_id_fk": { - "name": "recognition_job_source_artifact_id_artifact_id_fk", - "tableFrom": "recognition_job", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "source_artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_job_processed_artifact_id_artifact_id_fk": { - "name": "recognition_job_processed_artifact_id_artifact_id_fk", - "tableFrom": "recognition_job", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "processed_artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_job_model_version_id_ml_model_version_id_fk": { - "name": "recognition_job_model_version_id_ml_model_version_id_fk", - "tableFrom": "recognition_job", - "tableTo": "ml_model_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "model_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recognition_job_requested_by_app_user_id_fk": { - "name": "recognition_job_requested_by_app_user_id_fk", - "tableFrom": "recognition_job", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "requested_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "recognition_job_status_check": { - "name": "recognition_job_status_check", - "value": "\"holotrace\".\"recognition_job\".\"status\" IN ('queued', 'preprocessing', 'running', 'succeeded', 'failed', 'cancelled')" - } - }, - "isRLSEnabled": false - }, - "holotrace.simulation_artifact": { - "name": "simulation_artifact", - "schema": "holotrace", - "columns": { - "session_id": { - "name": "session_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "purpose": { - "name": "purpose", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "simulation_artifact_session_id_simulation_session_id_fk": { - "name": "simulation_artifact_session_id_simulation_session_id_fk", - "tableFrom": "simulation_artifact", - "tableTo": "simulation_session", - "schemaTo": "holotrace", - "columnsFrom": [ - "session_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "simulation_artifact_artifact_id_artifact_id_fk": { - "name": "simulation_artifact_artifact_id_artifact_id_fk", - "tableFrom": "simulation_artifact", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "simulation_artifact_session_id_artifact_id_pk": { - "name": "simulation_artifact_session_id_artifact_id_pk", - "columns": [ - "session_id", - "artifact_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.simulation_engine": { - "name": "simulation_engine", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "engine_key": { - "name": "engine_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "capabilities": { - "name": "capabilities", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "simulation_engine_engine_key_version_uq": { - "name": "simulation_engine_engine_key_version_uq", - "nullsNotDistinct": false, - "columns": [ - "engine_key", - "version" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.simulation_model": { - "name": "simulation_model", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "engine_id": { - "name": "engine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "model_key": { - "name": "model_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "definition": { - "name": "definition", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "artifact_id": { - "name": "artifact_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "parameters": { - "name": "parameters", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "simulation_model_engine_id_simulation_engine_id_fk": { - "name": "simulation_model_engine_id_simulation_engine_id_fk", - "tableFrom": "simulation_model", - "tableTo": "simulation_engine", - "schemaTo": "holotrace", - "columnsFrom": [ - "engine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "simulation_model_artifact_id_artifact_id_fk": { - "name": "simulation_model_artifact_id_artifact_id_fk", - "tableFrom": "simulation_model", - "tableTo": "artifact", - "schemaTo": "holotrace", - "columnsFrom": [ - "artifact_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "simulation_model_engine_id_model_key_version_uq": { - "name": "simulation_model_engine_id_model_key_version_uq", - "nullsNotDistinct": false, - "columns": [ - "engine_id", - "model_key", - "version" - ] - }, - "simulation_model_id_engine_id_uq": { - "name": "simulation_model_id_engine_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "engine_id" - ] - } - }, - "policies": {}, - "checkConstraints": { - "simulation_model_version_check": { - "name": "simulation_model_version_check", - "value": "\"holotrace\".\"simulation_model\".\"version\" > 0" - }, - "simulation_model_definition_or_artifact_check": { - "name": "simulation_model_definition_or_artifact_check", - "value": "\"holotrace\".\"simulation_model\".\"definition\" IS NOT NULL OR \"holotrace\".\"simulation_model\".\"artifact_id\" IS NOT NULL" - } - }, - "isRLSEnabled": false - }, - "holotrace.simulation_sample": { - "name": "simulation_sample", - "schema": "holotrace", - "columns": { - "sampled_at": { - "name": "sampled_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "session_id": { - "name": "session_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "signal_id": { - "name": "signal_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "double precision", - "primaryKey": false, - "notNull": true - }, - "quality": { - "name": "quality", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": { - "simulation_sample_signal_time_idx": { - "name": "simulation_sample_signal_time_idx", - "columns": [ - { - "expression": "session_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "signal_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "sampled_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "simulation_sample_signal_session_fk": { - "name": "simulation_sample_signal_session_fk", - "tableFrom": "simulation_sample", - "tableTo": "simulation_signal", - "schemaTo": "holotrace", - "columnsFrom": [ - "signal_id", - "session_id" - ], - "columnsTo": [ - "id", - "session_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "simulation_sample_sampled_at_session_id_signal_id_pk": { - "name": "simulation_sample_sampled_at_session_id_signal_id_pk", - "columns": [ - "sampled_at", - "session_id", - "signal_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.simulation_session": { - "name": "simulation_session", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "engine_id": { - "name": "engine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "configuration": { - "name": "configuration", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "model_manifest": { - "name": "model_manifest", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "summary": { - "name": "summary", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "error": { - "name": "error", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "started_at": { - "name": "started_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "completed_at": { - "name": "completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "simulation_session_circuit_idx": { - "name": "simulation_session_circuit_idx", - "columns": [ - { - "expression": "circuit_version_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "simulation_session_circuit_version_id_circuit_version_id_fk": { - "name": "simulation_session_circuit_version_id_circuit_version_id_fk", - "tableFrom": "simulation_session", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "simulation_session_engine_id_simulation_engine_id_fk": { - "name": "simulation_session_engine_id_simulation_engine_id_fk", - "tableFrom": "simulation_session", - "tableTo": "simulation_engine", - "schemaTo": "holotrace", - "columnsFrom": [ - "engine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "simulation_session_created_by_app_user_id_fk": { - "name": "simulation_session_created_by_app_user_id_fk", - "tableFrom": "simulation_session", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "simulation_session_status_check": { - "name": "simulation_session_status_check", - "value": "\"holotrace\".\"simulation_session\".\"status\" IN ('created', 'running', 'paused', 'completed', 'failed', 'cancelled')" - } - }, - "isRLSEnabled": false - }, - "holotrace.simulation_signal": { - "name": "simulation_signal", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "session_id": { - "name": "session_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "signal_key": { - "name": "signal_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "quantity": { - "name": "quantity", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "unit": { - "name": "unit", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "source_kind": { - "name": "source_kind", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "source_id": { - "name": "source_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "metadata": { - "name": "metadata", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "simulation_signal_session_id_simulation_session_id_fk": { - "name": "simulation_signal_session_id_simulation_session_id_fk", - "tableFrom": "simulation_signal", - "tableTo": "simulation_session", - "schemaTo": "holotrace", - "columnsFrom": [ - "session_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "simulation_signal_session_id_signal_key_uq": { - "name": "simulation_signal_session_id_signal_key_uq", - "nullsNotDistinct": false, - "columns": [ - "session_id", - "signal_key" - ] - }, - "simulation_signal_id_session_id_uq": { - "name": "simulation_signal_id_session_id_uq", - "nullsNotDistinct": false, - "columns": [ - "id", - "session_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.validation_issue": { - "name": "validation_issue", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "severity": { - "name": "severity", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "issue_code": { - "name": "issue_code", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "message": { - "name": "message", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "target_kind": { - "name": "target_kind", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "target_id": { - "name": "target_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "details": { - "name": "details", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - }, - "resolved_at": { - "name": "resolved_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" } }, "indexes": { - "validation_issue_open_idx": { - "name": "validation_issue_open_idx", + "verification_identifier_idx": { + "name": "verification_identifier_idx", "columns": [ { - "expression": "circuit_version_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "severity", + "expression": "identifier", "isExpression": false, "asc": true, "nulls": "last" } ], "isUnique": false, - "where": "\"holotrace\".\"validation_issue\".\"resolved_at\" IS NULL", "concurrently": false, "method": "btree", "with": {} } }, - "foreignKeys": { - "validation_issue_circuit_version_id_circuit_version_id_fk": { - "name": "validation_issue_circuit_version_id_circuit_version_id_fk", - "tableFrom": "validation_issue", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "validation_issue_severity_check": { - "name": "validation_issue_severity_check", - "value": "\"holotrace\".\"validation_issue\".\"severity\" IN ('info', 'warning', 'error')" - } - }, - "isRLSEnabled": false - }, - "holotrace.wire_route": { - "name": "wire_route", - "schema": "holotrace", - "columns": { - "circuit_version_id": { - "name": "circuit_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "layout_id": { - "name": "layout_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "net_id": { - "name": "net_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "route": { - "name": "route", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "style": { - "name": "style", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{}'::jsonb" - } - }, - "indexes": {}, - "foreignKeys": { - "wire_route_circuit_version_id_circuit_version_id_fk": { - "name": "wire_route_circuit_version_id_circuit_version_id_fk", - "tableFrom": "wire_route", - "tableTo": "circuit_version", - "schemaTo": "holotrace", - "columnsFrom": [ - "circuit_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "wire_route_layout_circuit_fk": { - "name": "wire_route_layout_circuit_fk", - "tableFrom": "wire_route", - "tableTo": "circuit_layout", - "schemaTo": "holotrace", - "columnsFrom": [ - "layout_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "wire_route_net_circuit_fk": { - "name": "wire_route_net_circuit_fk", - "tableFrom": "wire_route", - "tableTo": "net", - "schemaTo": "holotrace", - "columnsFrom": [ - "net_id", - "circuit_version_id" - ], - "columnsTo": [ - "id", - "circuit_version_id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "wire_route_layout_id_net_id_pk": { - "name": "wire_route_layout_id_net_id_pk", - "columns": [ - "layout_id", - "net_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "holotrace.workspace": { - "name": "workspace", - "schema": "holotrace", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_by": { - "name": "created_by", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workspace_created_by_app_user_id_fk": { - "name": "workspace_created_by_app_user_id_fk", - "tableFrom": "workspace", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, + "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": {}, "policies": {}, "checkConstraints": {}, "isRLSEnabled": false - }, - "holotrace.workspace_member": { - "name": "workspace_member", - "schema": "holotrace", - "columns": { - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workspace_member_workspace_id_workspace_id_fk": { - "name": "workspace_member_workspace_id_workspace_id_fk", - "tableFrom": "workspace_member", - "tableTo": "workspace", - "schemaTo": "holotrace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "workspace_member_user_id_app_user_id_fk": { - "name": "workspace_member_user_id_app_user_id_fk", - "tableFrom": "workspace_member", - "tableTo": "app_user", - "schemaTo": "holotrace", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "workspace_member_workspace_id_user_id_pk": { - "name": "workspace_member_workspace_id_user_id_pk", - "columns": [ - "workspace_id", - "user_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": { - "workspace_member_role_check": { - "name": "workspace_member_role_check", - "value": "\"holotrace\".\"workspace_member\".\"role\" IN ('owner', 'editor', 'viewer')" - } - }, - "isRLSEnabled": false } }, "enums": {}, "schemas": { - "holotrace": "holotrace" + "auth": "auth" }, "sequences": {}, "roles": {}, diff --git a/api_server/drizzle/meta/0002_snapshot.json b/api_server/drizzle/meta/0002_snapshot.json new file mode 100644 index 0000000..375ee6d --- /dev/null +++ b/api_server/drizzle/meta/0002_snapshot.json @@ -0,0 +1,510 @@ +{ + "id": "a5663666-791c-4b7a-984d-3f037ef10529", + "prevId": "71bcdee2-6cd9-4d83-a185-a811d3686ec3", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true, + "default": "'Untitled circuit'" + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "modifiedAt": { + "name": "modifiedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "projects_owner_user_id_fk": { + "name": "projects_owner_user_id_fk", + "tableFrom": "projects", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "owner" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(18)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.account": { + "name": "account", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.session": { + "name": "session", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.user": { + "name": "user", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.verification": { + "name": "verification", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": { + "auth": "auth" + }, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/api_server/drizzle/meta/0003_snapshot.json b/api_server/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..f923ce6 --- /dev/null +++ b/api_server/drizzle/meta/0003_snapshot.json @@ -0,0 +1,517 @@ +{ + "id": "d6ed1fef-bb41-4885-afd0-82e2c3ce3c7f", + "prevId": "a5663666-791c-4b7a-984d-3f037ef10529", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true, + "default": "'Untitled circuit'" + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "modifiedAt": { + "name": "modifiedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "lastOpenedAt": { + "name": "lastOpenedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "projects_owner_user_id_fk": { + "name": "projects_owner_user_id_fk", + "tableFrom": "projects", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "owner" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(18)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.account": { + "name": "account", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.session": { + "name": "session", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.user": { + "name": "user", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.verification": { + "name": "verification", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": { + "auth": "auth" + }, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/api_server/drizzle/meta/_journal.json b/api_server/drizzle/meta/_journal.json index 0702cc8..93d6037 100644 --- a/api_server/drizzle/meta/_journal.json +++ b/api_server/drizzle/meta/_journal.json @@ -5,15 +5,29 @@ { "idx": 0, "version": "7", - "when": 1789839245681, - "tag": "0000_spicy_psylocke", + "when": 1789886320438, + "tag": "0000_fancy_madelyne_pryor", "breakpoints": true }, { "idx": 1, "version": "7", - "when": 1789857721654, - "tag": "0001_postgres_schema_alignment", + "when": 1789892909789, + "tag": "0001_cooing_magik", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1789910198352, + "tag": "0002_goofy_warbound", + "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1789911188047, + "tag": "0003_workable_silverclaw", "breakpoints": true } ] diff --git a/api_server/index.ts b/api_server/index.ts index f67b2c6..ae166e5 100644 --- a/api_server/index.ts +++ b/api_server/index.ts @@ -1 +1,55 @@ -console.log("Hello via Bun!"); \ No newline at end of file +import { auth } from "./src/auth"; +import { authorizeRequest } from "./src/authorize"; +import { handleCircuitRequest } from "./src/circuits"; +import { getServerHost, getServerPort, validateServerConfiguration } from "./src/config"; +import { addApiCorsHeaders, apiPreflightResponse, isRequestOriginAllowed } from "./src/cors"; + +validateServerConfiguration(); + +const port = getServerPort(); + +const server = Bun.serve({ + hostname: getServerHost(), + port, + async fetch(request) { + const url = new URL(request.url); + + if (url.pathname.startsWith("/api/auth/")) { + if (request.method === "OPTIONS") { + return apiPreflightResponse(request); + } + + const response = await auth.handler(request); + return addApiCorsHeaders(response, request); + } + + if (url.pathname === "/api/circuits" || url.pathname.startsWith("/api/circuits/")) { + if (request.method === "OPTIONS") { + return apiPreflightResponse(request); + } + + if (!isRequestOriginAllowed(request)) { + return Response.json({ error: "Origin is not allowed" }, { status: 403 }); + } + + const response = await handleCircuitRequest(request, url); + return addApiCorsHeaders(response, request); + } + + if (url.pathname === "/internal/authorize" && request.method === "GET") { + return authorizeRequest(request); + } + + if (url.pathname === "/health" && request.method === "GET") { + return Response.json({ status: "ok" }, { headers: { "Cache-Control": "no-store" } }); + } + + return Response.json({ error: "Not found" }, { status: 404 }); + }, + error(error) { + console.error("Unhandled API server error", error); + return Response.json({ error: "Internal server error" }, { status: 500 }); + }, +}); + +console.log(`Holotrace auth API listening on ${server.url}`); diff --git a/api_server/package.json b/api_server/package.json index 3914b38..957d99c 100644 --- a/api_server/package.json +++ b/api_server/package.json @@ -1,12 +1,25 @@ { - "name": "y", + "name": "holotrace-api-server", "module": "index.ts", "type": "module", "private": true, + "scripts": { + "dev": "bun --watch index.ts", + "start": "bun index.ts", + "check": "tsc --noEmit", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate" + }, "devDependencies": { - "@types/bun": "latest" + "@types/bun": "latest", + "@types/pg": "^8.23.1", + "drizzle-kit": "^0.31.10", + "typescript": "^7.0.2" }, - "peerDependencies": { - "typescript": "^5" + "dependencies": { + "@better-auth/drizzle-adapter": "^1.7.5", + "better-auth": "^1.7.5", + "drizzle-orm": "^0.45.2", + "pg": "^8.23.0" } } diff --git a/api_server/src/auth.ts b/api_server/src/auth.ts new file mode 100644 index 0000000..481608b --- /dev/null +++ b/api_server/src/auth.ts @@ -0,0 +1,40 @@ +import { drizzleAdapter } from "@better-auth/drizzle-adapter"; +import { betterAuth } from "better-auth"; +import { username } from "better-auth/plugins"; + +import { getTrustedOrigins } from "./config"; +import { db } from "./db"; +import * as authSchema from "./db/auth-schema"; + +export const auth = betterAuth({ + database: drizzleAdapter(db, { + provider: "pg", + schema: authSchema, + schemaName: "auth", + }), + baseURL: process.env.BETTER_AUTH_URL, + secret: process.env.BETTER_AUTH_SECRET, + trustedOrigins: getTrustedOrigins(), + advanced: { + defaultCookieAttributes: { + httpOnly: true, + sameSite: "none", + secure: true, + }, + ipAddress: { + ipAddressHeaders: ["cf-connecting-ip", "x-forwarded-for"], + }, + }, + emailAndPassword: { + enabled: true, + requireEmailVerification: false, + minPasswordLength: 12, + revokeSessionsOnPasswordReset: true, + }, + plugins: [ + username({ + minUsernameLength: 3, + maxUsernameLength: 30, + }), + ], +}); diff --git a/api_server/src/authorize.ts b/api_server/src/authorize.ts new file mode 100644 index 0000000..f644c21 --- /dev/null +++ b/api_server/src/authorize.ts @@ -0,0 +1,41 @@ +import { timingSafeEqual } from "node:crypto"; + +import { auth } from "./auth"; + +function hasValidInternalToken(request: Request): boolean { + const expected = process.env.INTERNAL_AUTH_TOKEN; + + if (!expected) { + return true; + } + + const received = request.headers.get("x-internal-auth-token") ?? ""; + const expectedBytes = Buffer.from(expected); + const receivedBytes = Buffer.from(received); + + return ( + expectedBytes.length === receivedBytes.length && + timingSafeEqual(expectedBytes, receivedBytes) + ); +} + +export async function authorizeRequest(request: Request): Promise { + if (!hasValidInternalToken(request)) { + return Response.json({ error: "Forbidden" }, { status: 403 }); + } + + const session = await auth.api.getSession({ headers: request.headers }); + + if (!session) { + return Response.json({ error: "Unauthorized" }, { status: 401 }); + } + + return new Response(null, { + status: 204, + headers: { + "Cache-Control": "no-store", + "X-Holotrace-Auth-Subject": session.user.id, + "X-Holotrace-User-Id": session.user.id, + }, + }); +} diff --git a/api_server/src/circuit/index.ts b/api_server/src/circuit/index.ts deleted file mode 100644 index 7c5fb4c..0000000 --- a/api_server/src/circuit/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './normalize'; -export * from './pin-templates'; -export * from './recognition'; -export * from './simulation-adapter'; -export * from './types'; diff --git a/api_server/src/circuit/normalize.ts b/api_server/src/circuit/normalize.ts deleted file mode 100644 index 35398ea..0000000 --- a/api_server/src/circuit/normalize.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { getPinTemplate, isComponentLabel, type PinTemplate } from './pin-templates'; -import type { OpenCvAnalysis, RecognitionResult, WireNode } from './recognition'; -import { - CIRCUIT_IR_VERSION, - type Bounds, - type CircuitComponent, - type CircuitNet, - type NormalizationResult, - type Point, - type SourceComponentPlacement, - type ValidationIssue -} from './types'; - -export interface NormalizationOptions { - snapDistancePx?: number; - lowConfidenceThreshold?: number; -} - -class DisjointSet { - private readonly parent = new Map(); - - add(value: string): void { - if (!this.parent.has(value)) this.parent.set(value, value); - } - - find(value: string): string { - const parent = this.parent.get(value); - if (parent === undefined) throw new Error(`Unknown wire node ${value}`); - if (parent === value) return value; - const root = this.find(parent); - this.parent.set(value, root); - return root; - } - - union(left: string, right: string): void { - const leftRoot = this.find(left); - const rightRoot = this.find(right); - if (leftRoot !== rightRoot) this.parent.set(rightRoot, leftRoot); - } -} - -function distance(left: Point, right: Point): number { - return Math.hypot(left.x - right.x, left.y - right.y); -} - -function pinPoint(bounds: Bounds, rotationDegrees: number, pin: PinTemplate): Point { - const center = { x: (bounds.x0 + bounds.x1) / 2, y: (bounds.y0 + bounds.y1) / 2 }; - const local = { - x: pin.position.x * (bounds.x1 - bounds.x0), - y: pin.position.y * (bounds.y1 - bounds.y0) - }; - const radians = (rotationDegrees * Math.PI) / 180; - return { - x: center.x + local.x * Math.cos(radians) - local.y * Math.sin(radians), - y: center.y + local.x * Math.sin(radians) + local.y * Math.cos(radians) - }; -} - -export function normalizeCircuit( - analysis: OpenCvAnalysis, - recognition: RecognitionResult, - options: NormalizationOptions = {} -): NormalizationResult { - const issues: ValidationIssue[] = []; - const predictionByRegion = new Map(recognition.regions.map((prediction) => [prediction.region_id, prediction])); - const nodeById = new Map(analysis.wireGraph.nodes.map((node) => [node.id, node])); - const graph = new DisjointSet(); - - for (const node of analysis.wireGraph.nodes) graph.add(node.id); - for (const segment of analysis.wireGraph.segments) { - if (!nodeById.has(segment.fromNodeId) || !nodeById.has(segment.toNodeId)) { - issues.push({ - id: `invalid-wire-${segment.id}`, - severity: 'error', - code: 'invalid_wire_segment', - message: `Wire segment ${segment.id} refers to a missing endpoint.` - }); - continue; - } - graph.union(segment.fromNodeId, segment.toNodeId); - } - - const snapDistance = - options.snapDistancePx ?? Math.max(4, Math.min(analysis.imageWidth, analysis.imageHeight) * 0.015); - const lowConfidence = options.lowConfidenceThreshold ?? 0.65; - const components: CircuitComponent[] = []; - const placements: SourceComponentPlacement[] = []; - const pinRoots = new Map(); - - for (const region of analysis.regions) { - const prediction = predictionByRegion.get(region.id); - if (!prediction) { - issues.push({ - id: `missing-prediction-${region.id}`, - severity: 'warning', - code: 'missing_prediction', - message: `No classifier result was returned for region ${region.id}.`, - regionId: region.id - }); - continue; - } - if (!isComponentLabel(prediction.label)) continue; - - const componentId = `component-${region.id}`; - const template = getPinTemplate(prediction.label); - if (!template) { - issues.push({ - id: `unsupported-${componentId}`, - severity: 'error', - code: 'unsupported_component', - message: `No pin template is defined for ${prediction.label}.`, - componentId, - regionId: region.id - }); - } - if (prediction.confidence < lowConfidence) { - issues.push({ - id: `low-confidence-${componentId}`, - severity: 'warning', - code: 'low_confidence', - message: `${prediction.label} was recognized with ${(prediction.confidence * 100).toFixed(1)}% confidence.`, - componentId, - regionId: region.id - }); - } - - const rotationDegrees = region.rotationDegrees ?? 0; - const placementPins = (template ?? []).map((pin) => ({ - pinKey: pin.key, - point: pinPoint(region.box, rotationDegrees, pin) - })); - const component: CircuitComponent = { - id: componentId, - type: prediction.label, - properties: {}, - pins: (template ?? []).map((pin) => ({ - key: pin.key, - name: pin.name, - electricalRole: pin.electricalRole, - netId: null - })), - recognition: { - sourceRegionId: region.id, - label: prediction.label, - confidence: prediction.confidence, - alternatives: prediction.alternatives - } - }; - - for (const pin of placementPins) { - const candidates = analysis.wireGraph.nodes - .map((node) => ({ node, distance: distance(pin.point, node.point), root: graph.find(node.id) })) - .filter((candidate) => candidate.distance <= snapDistance) - .sort((left, right) => left.distance - right.distance); - const nearest = candidates[0]; - const competing = candidates.find( - (candidate) => candidate.root !== nearest?.root && candidate.distance - (nearest?.distance ?? 0) <= 1 - ); - if (nearest && !competing) { - pinRoots.set(`${componentId}:${pin.pinKey}`, nearest.root); - } else if (nearest && competing) { - issues.push({ - id: `ambiguous-${componentId}-${pin.pinKey}`, - severity: 'warning', - code: 'ambiguous_connection', - message: `${componentId}.${pin.pinKey} is equally close to multiple wire networks.`, - componentId, - pinKey: pin.pinKey - }); - } - } - - components.push(component); - placements.push({ componentId, bounds: region.box, rotationDegrees, pins: placementPins }); - } - - const rootsWithPins = [...new Set(pinRoots.values())].sort(); - const netIdByRoot = new Map(rootsWithPins.map((root, index) => [root, `net-${index + 1}`])); - const netsById = new Map(); - for (const netId of netIdByRoot.values()) netsById.set(netId, { id: netId, name: null, members: [] }); - - for (const component of components) { - for (const pin of component.pins) { - const root = pinRoots.get(`${component.id}:${pin.key}`); - const netId = root ? (netIdByRoot.get(root) ?? null) : null; - pin.netId = netId; - if (netId) { - netsById.get(netId)?.members.push({ componentId: component.id, pinKey: pin.key }); - } else { - issues.push({ - id: `unconnected-${component.id}-${pin.key}`, - severity: 'warning', - code: 'unconnected_pin', - message: `${component.id}.${pin.key} is not connected to a wire network.`, - componentId: component.id, - pinKey: pin.key - }); - } - } - } - - if (!components.some((component) => component.type === 'gnd')) { - issues.push({ - id: 'missing-ground', - severity: 'warning', - code: 'missing_ground', - message: 'No ground or reference component was recognized.' - }); - } - - const rootForNode = (node: WireNode): string => graph.find(node.id); - return { - circuit: { - schemaVersion: CIRCUIT_IR_VERSION, - components, - nets: [...netsById.values()], - provenance: { - recognitionSchemaVersion: recognition.schema_version, - classifierVersion: recognition.classifier_version, - detectorVersion: recognition.detector_version, - clientPreprocessVersion: recognition.client_preprocess_version - } - }, - sourceLayout: { - imageWidth: analysis.imageWidth, - imageHeight: analysis.imageHeight, - components: placements, - wires: analysis.wireGraph.segments.map((segment) => { - const from = nodeById.get(segment.fromNodeId); - const root = from ? rootForNode(from) : null; - return { - id: segment.id, - netId: root ? (netIdByRoot.get(root) ?? null) : null, - points: segment.points - }; - }) - }, - issues - }; -} diff --git a/api_server/src/circuit/pin-templates.ts b/api_server/src/circuit/pin-templates.ts deleted file mode 100644 index 1a5d863..0000000 --- a/api_server/src/circuit/pin-templates.ts +++ /dev/null @@ -1,89 +0,0 @@ -import type { PinRole, Point } from './types'; - -export interface PinTemplate { - key: string; - name: string; - electricalRole: PinRole; - position: Point; -} - -const twoTerminal: PinTemplate[] = [ - { key: 'a', name: 'A', electricalRole: 'passive', position: { x: -0.5, y: 0 } }, - { key: 'b', name: 'B', electricalRole: 'passive', position: { x: 0.5, y: 0 } } -]; - -const twoInputGate: PinTemplate[] = [ - { key: 'input_a', name: 'A', electricalRole: 'input', position: { x: -0.5, y: -0.24 } }, - { key: 'input_b', name: 'B', electricalRole: 'input', position: { x: -0.5, y: 0.24 } }, - { key: 'output', name: 'Y', electricalRole: 'output', position: { x: 0.5, y: 0 } } -]; - -const templates: Record = { - resistor: twoTerminal, - 'resistor.adjustable': [ - ...twoTerminal, - { key: 'wiper', name: 'Wiper', electricalRole: 'control', position: { x: 0, y: -0.5 } } - ], - 'capacitor.unpolarized': twoTerminal, - 'capacitor.polarized': [ - { key: 'positive', name: '+', electricalRole: 'passive', position: { x: -0.5, y: 0 } }, - { key: 'negative', name: '-', electricalRole: 'passive', position: { x: 0.5, y: 0 } } - ], - inductor: twoTerminal, - diode: [ - { key: 'anode', name: 'Anode', electricalRole: 'passive', position: { x: -0.5, y: 0 } }, - { key: 'cathode', name: 'Cathode', electricalRole: 'passive', position: { x: 0.5, y: 0 } } - ], - 'diode.light_emitting': twoTerminal, - 'diode.zener': twoTerminal, - switch: twoTerminal, - fuse: twoTerminal, - lamp: twoTerminal, - motor: twoTerminal, - speaker: twoTerminal, - crystal: twoTerminal, - and: twoInputGate, - nand: twoInputGate, - or: twoInputGate, - nor: twoInputGate, - xor: twoInputGate, - not: [ - { key: 'input', name: 'A', electricalRole: 'input', position: { x: -0.5, y: 0 } }, - { key: 'output', name: 'Y', electricalRole: 'output', position: { x: 0.5, y: 0 } } - ], - operational_amplifier: [ - { key: 'inverting', name: '-', electricalRole: 'input', position: { x: -0.5, y: 0.24 } }, - { key: 'non_inverting', name: '+', electricalRole: 'input', position: { x: -0.5, y: -0.24 } }, - { key: 'output', name: 'Output', electricalRole: 'output', position: { x: 0.5, y: 0 } } - ], - 'transistor.bjt': [ - { key: 'base', name: 'Base', electricalRole: 'control', position: { x: -0.5, y: 0 } }, - { key: 'collector', name: 'Collector', electricalRole: 'passive', position: { x: 0.35, y: -0.5 } }, - { key: 'emitter', name: 'Emitter', electricalRole: 'passive', position: { x: 0.35, y: 0.5 } } - ], - 'transistor.fet': [ - { key: 'gate', name: 'Gate', electricalRole: 'control', position: { x: -0.5, y: 0 } }, - { key: 'drain', name: 'Drain', electricalRole: 'passive', position: { x: 0.35, y: -0.5 } }, - { key: 'source', name: 'Source', electricalRole: 'passive', position: { x: 0.35, y: 0.5 } } - ], - 'voltage.dc': [ - { key: 'positive', name: '+', electricalRole: 'power', position: { x: 0, y: -0.5 } }, - { key: 'negative', name: '-', electricalRole: 'ground', position: { x: 0, y: 0.5 } } - ], - 'voltage.battery': [ - { key: 'positive', name: '+', electricalRole: 'power', position: { x: 0, y: -0.5 } }, - { key: 'negative', name: '-', electricalRole: 'ground', position: { x: 0, y: 0.5 } } - ], - gnd: [{ key: 'ground', name: 'Ground', electricalRole: 'ground', position: { x: 0, y: -0.5 } }], - terminal: [{ key: 'terminal', name: 'Terminal', electricalRole: 'unknown', position: { x: 0, y: 0 } }] -}; - -const nonComponentLabels = new Set(['background', 'text', 'junction', 'crossover']); - -export function isComponentLabel(label: string): boolean { - return !nonComponentLabels.has(label); -} - -export function getPinTemplate(label: string): readonly PinTemplate[] | undefined { - return templates[label]; -} diff --git a/api_server/src/circuit/recognition.ts b/api_server/src/circuit/recognition.ts deleted file mode 100644 index b410855..0000000 --- a/api_server/src/circuit/recognition.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { Bounds, Point } from './types'; - -export const OPENCV_ANALYSIS_VERSION = 'opencv-analysis-v0' as const; - -export interface OpenCvRegion { - id: string; - box: Bounds; - rotationDegrees?: number; - localLabel?: string | null; - localConfidence?: number | null; -} - -export type WireNodeKind = 'endpoint' | 'junction' | 'crossover' | 'bend'; - -export interface WireNode { - id: string; - point: Point; - kind: WireNodeKind; -} - -export interface WireSegment { - id: string; - fromNodeId: string; - toNodeId: string; - points: Point[]; -} - -export interface OpenCvAnalysis { - schemaVersion: typeof OPENCV_ANALYSIS_VERSION; - preprocessVersion: string; - imageWidth: number; - imageHeight: number; - regions: OpenCvRegion[]; - wireGraph: { - nodes: WireNode[]; - segments: WireSegment[]; - }; -} - -export interface RecognitionAlternative { - label: string; - confidence: number; -} - -export interface RegionPrediction { - region_id: string; - label: string; - confidence: number; - alternatives: RecognitionAlternative[]; - local_label: string | null; -} - -export interface RecognitionResult { - schema_version: 'recognition-v0'; - label_set_version: string; - preprocess_version: string; - client_preprocess_version: string; - classifier_version: string | null; - detector_version: string | null; - regions: RegionPrediction[]; - detections: Array<{ - box: Bounds; - label: string; - confidence: number; - }>; -} diff --git a/api_server/src/circuit/simulation-adapter.ts b/api_server/src/circuit/simulation-adapter.ts deleted file mode 100644 index 6ac762c..0000000 --- a/api_server/src/circuit/simulation-adapter.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { CircuitIr, ValidationIssue } from './types'; - -export interface AdapterCapability { - supported: boolean; - issues: ValidationIssue[]; -} - -export interface SimulationAdapter { - readonly id: string; - check(circuit: CircuitIr): AdapterCapability; - export(circuit: CircuitIr): TProject; - normalizeState(engineState: unknown): TState; -} diff --git a/api_server/src/circuit/types.ts b/api_server/src/circuit/types.ts deleted file mode 100644 index afe7138..0000000 --- a/api_server/src/circuit/types.ts +++ /dev/null @@ -1,103 +0,0 @@ -export const CIRCUIT_IR_VERSION = 'circuit-ir-v0' as const; - -export interface Point { - x: number; - y: number; -} - -export interface Bounds { - x0: number; - y0: number; - x1: number; - y1: number; -} - -export type PinRole = 'input' | 'output' | 'power' | 'ground' | 'passive' | 'control' | 'unknown'; - -export interface CircuitPin { - key: string; - name: string; - electricalRole: PinRole; - netId: string | null; -} - -export interface CircuitComponent { - id: string; - type: string; - properties: Record; - pins: CircuitPin[]; - recognition: { - sourceRegionId: string; - label: string; - confidence: number; - alternatives: Array<{ label: string; confidence: number }>; - }; -} - -export interface CircuitNetMember { - componentId: string; - pinKey: string; -} - -export interface CircuitNet { - id: string; - name: string | null; - members: CircuitNetMember[]; -} - -export interface CircuitIr { - schemaVersion: typeof CIRCUIT_IR_VERSION; - components: CircuitComponent[]; - nets: CircuitNet[]; - provenance: { - recognitionSchemaVersion: string; - classifierVersion: string | null; - detectorVersion: string | null; - clientPreprocessVersion: string; - }; -} - -export type ValidationSeverity = 'info' | 'warning' | 'error'; - -export interface ValidationIssue { - id: string; - severity: ValidationSeverity; - code: - | 'missing_prediction' - | 'unsupported_component' - | 'low_confidence' - | 'unconnected_pin' - | 'ambiguous_connection' - | 'invalid_wire_segment' - | 'missing_ground'; - message: string; - componentId?: string; - pinKey?: string; - regionId?: string; -} - -export interface SourceComponentPlacement { - componentId: string; - bounds: Bounds; - rotationDegrees: number; - pins: Array<{ pinKey: string; point: Point }>; -} - -export interface SourceWirePath { - id: string; - netId: string | null; - points: Point[]; -} - -export interface SourceCircuitLayout { - imageWidth: number; - imageHeight: number; - components: SourceComponentPlacement[]; - wires: SourceWirePath[]; -} - -export interface NormalizationResult { - circuit: CircuitIr; - sourceLayout: SourceCircuitLayout; - issues: ValidationIssue[]; -} diff --git a/api_server/src/circuits.ts b/api_server/src/circuits.ts new file mode 100644 index 0000000..4dfa71e --- /dev/null +++ b/api_server/src/circuits.ts @@ -0,0 +1,178 @@ +import { and, desc, eq } from "drizzle-orm"; + +import { auth } from "./auth"; +import { db } from "./db"; +import { projects } from "./db/schema"; + +const MAX_CIRCUIT_BYTES = 12 * 1024 * 1024; + +interface CircuitBody { + name?: unknown; + data?: unknown; +} + +function jsonError(message: string, status: number): Response { + return Response.json({ error: message }, { status }); +} + +function serializeProject(project: typeof projects.$inferSelect) { + return { + id: project.id, + name: project.name, + data: JSON.parse(project.data) as unknown, + createdAt: project.createdAt.toISOString(), + modifiedAt: project.modifiedAt.toISOString(), + lastOpenedAt: project.lastOpenedAt.toISOString(), + }; +} + +function serializeProjectSummary( + project: Pick< + typeof projects.$inferSelect, + "id" | "name" | "createdAt" | "modifiedAt" | "lastOpenedAt" + >, +) { + return { + id: project.id, + name: project.name, + createdAt: project.createdAt.toISOString(), + modifiedAt: project.modifiedAt.toISOString(), + lastOpenedAt: project.lastOpenedAt.toISOString(), + }; +} + +async function parseCircuitBody(request: Request): Promise< + | { name: string; data: string } + | Response +> { + let body: CircuitBody; + + try { + body = (await request.json()) as CircuitBody; + } catch { + return jsonError("Request body must be valid JSON", 400); + } + + const name = typeof body.name === "string" ? body.name.trim() : ""; + + if (!name || name.length > 120) { + return jsonError("Circuit name must contain between 1 and 120 characters", 400); + } + + if (!body.data || typeof body.data !== "object" || Array.isArray(body.data)) { + return jsonError("Circuit data must be a JSON object", 400); + } + + const data = JSON.stringify(body.data); + + if (Buffer.byteLength(data, "utf8") > MAX_CIRCUIT_BYTES) { + return jsonError("Circuit data exceeds the 12 MB limit", 413); + } + + return { name, data }; +} + +function parseProjectId(url: URL): number | null { + const match = /^\/api\/circuits\/(\d+)$/.exec(url.pathname); + if (!match?.[1]) return null; + + const id = Number(match[1]); + return Number.isSafeInteger(id) && id > 0 ? id : null; +} + +function parseProjectOpenId(url: URL): number | null { + const match = /^\/api\/circuits\/(\d+)\/open$/.exec(url.pathname); + if (!match?.[1]) return null; + + const id = Number(match[1]); + return Number.isSafeInteger(id) && id > 0 ? id : null; +} + +export async function handleCircuitRequest(request: Request, url: URL): Promise { + const session = await auth.api.getSession({ headers: request.headers }); + + if (!session) { + return jsonError("Unauthorized", 401); + } + + const owner = session.user.id; + const projectId = parseProjectId(url); + const projectOpenId = parseProjectOpenId(url); + + if (url.pathname === "/api/circuits" && request.method === "GET") { + const savedProjects = await db + .select({ + id: projects.id, + name: projects.name, + createdAt: projects.createdAt, + modifiedAt: projects.modifiedAt, + lastOpenedAt: projects.lastOpenedAt, + }) + .from(projects) + .where(eq(projects.owner, owner)) + .orderBy(desc(projects.lastOpenedAt), desc(projects.modifiedAt)); + + return Response.json({ circuits: savedProjects.map(serializeProjectSummary) }); + } + + if (url.pathname === "/api/circuits" && request.method === "POST") { + const body = await parseCircuitBody(request); + if (body instanceof Response) return body; + + const [created] = await db + .insert(projects) + .values({ owner, ...body }) + .returning(); + + if (!created) return jsonError("Unable to save circuit", 500); + return Response.json({ circuit: serializeProject(created) }, { status: 201 }); + } + + if (projectOpenId && request.method === "POST") { + const [savedProject] = await db + .update(projects) + .set({ lastOpenedAt: new Date() }) + .where(and(eq(projects.id, projectOpenId), eq(projects.owner, owner))) + .returning(); + + if (!savedProject) return jsonError("Circuit not found", 404); + return Response.json({ circuit: serializeProject(savedProject) }); + } + + if (projectId && request.method === "GET") { + const [savedProject] = await db + .select() + .from(projects) + .where(and(eq(projects.id, projectId), eq(projects.owner, owner))) + .limit(1); + + if (!savedProject) return jsonError("Circuit not found", 404); + return Response.json({ circuit: serializeProject(savedProject) }); + } + + if (projectId && request.method === "PUT") { + const body = await parseCircuitBody(request); + if (body instanceof Response) return body; + + const [updated] = await db + .update(projects) + .set({ ...body, modifiedAt: new Date() }) + .where(and(eq(projects.id, projectId), eq(projects.owner, owner))) + .returning(); + + if (!updated) return jsonError("Circuit not found", 404); + return Response.json({ circuit: serializeProject(updated) }); + } + + if (projectId && request.method === "DELETE") { + const [deleted] = await db + .delete(projects) + .where(and(eq(projects.id, projectId), eq(projects.owner, owner))) + .returning({ id: projects.id }); + + if (!deleted) return jsonError("Circuit not found", 404); + return new Response(null, { status: 204 }); + } + + return jsonError("Not found", 404); +} diff --git a/api_server/src/config.ts b/api_server/src/config.ts new file mode 100644 index 0000000..5fe8f32 --- /dev/null +++ b/api_server/src/config.ts @@ -0,0 +1,50 @@ +const DEFAULT_PORT = 8001; +const DEFAULT_BIND_HOST = "127.0.0.1"; + +export function getTrustedOrigins(): string[] { + return (process.env.AUTH_TRUSTED_ORIGINS ?? "") + .split(",") + .map((origin) => origin.trim()) + .filter(Boolean); +} + +export function validateServerConfiguration(): void { + const missing = ["DATABASE_URL", "BETTER_AUTH_URL", "BETTER_AUTH_SECRET"].filter( + (name) => !process.env[name], + ); + + if (missing.length > 0) { + throw new Error(`Missing required environment variables: ${missing.join(", ")}`); + } + + if ((process.env.BETTER_AUTH_SECRET?.length ?? 0) < 32) { + throw new Error("BETTER_AUTH_SECRET must contain at least 32 characters"); + } + + const baseUrl = new URL(process.env.BETTER_AUTH_URL!); + const isLocalDevelopment = ["localhost", "127.0.0.1", "[::1]"].includes(baseUrl.hostname); + + if (baseUrl.protocol !== "https:" && !isLocalDevelopment) { + throw new Error("BETTER_AUTH_URL must use HTTPS outside local development"); + } +} + +export function getServerPort(): number { + const value = process.env.PORT; + + if (!value) { + return DEFAULT_PORT; + } + + const port = Number(value); + + if (!Number.isInteger(port) || port < 1 || port > 65_535) { + throw new Error("PORT must be an integer between 1 and 65535"); + } + + return port; +} + +export function getServerHost(): string { + return process.env.BIND_HOST?.trim() || DEFAULT_BIND_HOST; +} diff --git a/api_server/src/cors.ts b/api_server/src/cors.ts new file mode 100644 index 0000000..0866718 --- /dev/null +++ b/api_server/src/cors.ts @@ -0,0 +1,51 @@ +import { getTrustedOrigins } from "./config"; + +const ALLOWED_METHODS = "GET, POST, PUT, DELETE, OPTIONS"; +const ALLOWED_HEADERS = "Authorization, Content-Type"; + +function allowedOrigin(request: Request): string | null { + const origin = request.headers.get("origin"); + + if (!origin || !getTrustedOrigins().includes(origin)) { + return null; + } + + return origin; +} + +export function isRequestOriginAllowed(request: Request): boolean { + return !request.headers.has("origin") || allowedOrigin(request) !== null; +} + +export function apiPreflightResponse(request: Request): Response { + const origin = allowedOrigin(request); + + if (!origin) { + return Response.json({ error: "Origin is not allowed" }, { status: 403 }); + } + + return new Response(null, { + status: 204, + headers: { + "Access-Control-Allow-Credentials": "true", + "Access-Control-Allow-Headers": ALLOWED_HEADERS, + "Access-Control-Allow-Methods": ALLOWED_METHODS, + "Access-Control-Allow-Origin": origin, + "Access-Control-Max-Age": "600", + Vary: "Origin", + }, + }); +} + +export function addApiCorsHeaders(response: Response, request: Request): Response { + const origin = allowedOrigin(request); + + if (!origin) { + return response; + } + + response.headers.set("Access-Control-Allow-Credentials", "true"); + response.headers.set("Access-Control-Allow-Origin", origin); + response.headers.append("Vary", "Origin"); + return response; +} diff --git a/api_server/src/db/auth-schema.ts b/api_server/src/db/auth-schema.ts new file mode 100644 index 0000000..0d55f21 --- /dev/null +++ b/api_server/src/db/auth-schema.ts @@ -0,0 +1,97 @@ +import { relations } from "drizzle-orm"; +import { pgSchema, text, timestamp, boolean, index } from "drizzle-orm/pg-core"; + +export const authSchema = pgSchema("auth"); + +export const user = authSchema.table("user", { + id: text("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified").default(false).notNull(), + image: text("image"), + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at") + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + username: text("username").unique(), + displayUsername: text("display_username"), +}); + +export const session = authSchema.table( + "session", + { + id: text("id").primaryKey(), + expiresAt: timestamp("expires_at").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at") + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + }, + (table) => [index("session_userId_idx").on(table.userId)], +); + +export const account = authSchema.table( + "account", + { + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at") + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }, + (table) => [index("account_userId_idx").on(table.userId)], +); + +export const verification = authSchema.table( + "verification", + { + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at") + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }, + (table) => [index("verification_identifier_idx").on(table.identifier)], +); + +export const userRelations = relations(user, ({ many }) => ({ + sessions: many(session), + accounts: many(account), +})); + +export const sessionRelations = relations(session, ({ one }) => ({ + user: one(user, { + fields: [session.userId], + references: [user.id], + }), +})); + +export const accountRelations = relations(account, ({ one }) => ({ + user: one(user, { + fields: [account.userId], + references: [user.id], + }), +})); diff --git a/api_server/src/db/index.ts b/api_server/src/db/index.ts new file mode 100644 index 0000000..ac997d2 --- /dev/null +++ b/api_server/src/db/index.ts @@ -0,0 +1,20 @@ +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; + +import * as applicationSchema from "./schema"; +import * as authSchema from "./auth-schema"; + +const databaseUrl = process.env.DATABASE_URL; + +if (!databaseUrl) { + throw new Error("DATABASE_URL is required"); +} + +export const pool = new Pool({ connectionString: databaseUrl }); +export const db = drizzle({ + client: pool, + schema: { + ...applicationSchema, + ...authSchema, + }, +}); diff --git a/api_server/src/db/schema.ts b/api_server/src/db/schema.ts index 2f9d039..d63a792 100644 --- a/api_server/src/db/schema.ts +++ b/api_server/src/db/schema.ts @@ -1,816 +1,30 @@ -// TypeScript — Drizzle ORM schema for Holotrace -// -// Notes on things Drizzle can't express 1:1 with the SQL doc: -// - `sha256 ~ '^[0-9a-f]{64}$'` and all enum-style `CHECK (... IN (...))` -// constraints are reproduced with `check()`. -// - `bigint` uses `{ mode: "number" }` for convenience; switch to -// `{ mode: "bigint" }` if byte sizes can exceed Number.MAX_SAFE_INTEGER. -// - Row-level security policies are a service-level/API concern per the -// doc ("do not add permissive placeholder policies") and are -// intentionally not modeled here. - -import { sql } from "drizzle-orm"; +import { relations } from "drizzle-orm"; import { - pgSchema, - uuid, - text, - integer, - bigint, - smallint, - boolean, - jsonb, - timestamp, - doublePrecision, - primaryKey, - uniqueIndex, - index, - unique, - check, - foreignKey, - type AnyPgColumn, + pgTable, serial, varchar, timestamp, text } from "drizzle-orm/pg-core"; -export const holotrace = pgSchema("holotrace"); - -// --------------------------------------------------------------------------- -// Accounts, workspaces, and projects -// --------------------------------------------------------------------------- +import { user as authUser } from "./auth-schema"; -export const appUser = holotrace.table("app_user", { - id: uuid("id").primaryKey().defaultRandom(), - authSubject: text("auth_subject").notNull().unique(), - displayName: text("display_name"), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), +export const users = pgTable("users", { + id: serial("id").primaryKey(), + username: varchar("username", { length: 18 }).unique().notNull(), + password: varchar("password", { length: 64 }).notNull(), + createdAt: timestamp("createdAt").defaultNow().notNull(), }); -export const workspace = holotrace.table("workspace", { - id: uuid("id").primaryKey().defaultRandom(), - name: text("name").notNull(), - createdBy: uuid("created_by").notNull().references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), +export const projects = pgTable("projects", { + id: serial("id").primaryKey(), + owner: text("owner").notNull().references(() => authUser.id, { onDelete: "cascade" }), + name: varchar("name", { length: 120 }).notNull().default("Untitled circuit"), + data: text("data").notNull(), + createdAt: timestamp("createdAt").defaultNow().notNull(), + modifiedAt: timestamp("modifiedAt").defaultNow().notNull(), + lastOpenedAt: timestamp("lastOpenedAt").defaultNow().notNull(), }); -export const workspaceMember = holotrace.table( - "workspace_member", - { - workspaceId: uuid("workspace_id") - .notNull() - .references(() => workspace.id, { onDelete: "cascade" }), - userId: uuid("user_id") - .notNull() - .references(() => appUser.id, { onDelete: "cascade" }), - role: text("role").notNull(), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - primaryKey({ columns: [t.workspaceId, t.userId] }), - check("workspace_member_role_check", sql`${t.role} IN ('owner', 'editor', 'viewer')`), - ], -); - -export const project = holotrace.table( - "project", - { - id: uuid("id").primaryKey().defaultRandom(), - workspaceId: uuid("workspace_id") - .notNull() - .references(() => workspace.id, { onDelete: "cascade" }), - name: text("name").notNull(), - description: text("description"), - createdBy: uuid("created_by").notNull().references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - index("project_workspace_idx").on(t.workspaceId, t.updatedAt.desc()), - ], -); - -// --------------------------------------------------------------------------- -// Stored artifacts -// --------------------------------------------------------------------------- - -export const artifact = holotrace.table( - "artifact", - { - id: uuid("id").primaryKey().defaultRandom(), - workspaceId: uuid("workspace_id").references(() => workspace.id, { onDelete: "cascade" }), - kind: text("kind").notNull(), - objectKey: text("object_key").notNull().unique(), - mimeType: text("mime_type").notNull(), - byteSize: bigint("byte_size", { mode: "number" }).notNull(), - sha256: text("sha256").notNull(), - licenseId: text("license_id"), - sourceUri: text("source_uri"), - provenance: jsonb("provenance").notNull().default({}), - createdBy: uuid("created_by").references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - index("artifact_workspace_kind_idx").on(t.workspaceId, t.kind, t.createdAt.desc()), - check( - "artifact_kind_check", - sql`${t.kind} IN ('source_image', 'processed_image', 'schematic_svg', 'physical_2d', 'model_3d', 'texture', 'firmware', 'waveform', 'other')`, - ), - check("artifact_byte_size_check", sql`${t.byteSize} >= 0`), - check("artifact_sha256_check", sql`${t.sha256} ~ '^[0-9a-f]{64}$'`), - ], -); - -// --------------------------------------------------------------------------- -// Component catalog -// --------------------------------------------------------------------------- - -export const componentDefinition = holotrace.table( - "component_definition", - { - id: uuid("id").primaryKey().defaultRandom(), - workspaceId: uuid("workspace_id").references(() => workspace.id, { onDelete: "cascade" }), - slug: text("slug").notNull(), - name: text("name").notNull(), - category: text("category").notNull(), - manufacturer: text("manufacturer"), - manufacturerPart: text("manufacturer_part"), - description: text("description"), - properties: jsonb("properties").notNull().default({}), - catalogVersion: integer("catalog_version").notNull().default(1), - isActive: boolean("is_active").notNull().default(true), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - // Partial unique indexes: one slug namespace for the shared/global - // catalog (workspace_id IS NULL), one per-workspace. - uniqueIndex("component_definition_global_slug_uq") - .on(t.slug) - .where(sql`${t.workspaceId} IS NULL`), - uniqueIndex("component_definition_workspace_slug_uq") - .on(t.workspaceId, t.slug) - .where(sql`${t.workspaceId} IS NOT NULL`), - // GIN index on properties — declared here for documentation; Drizzle's - // index builder doesn't have a typed `jsonb_path_ops` helper, so this - // still needs `.using("gin", sql`${t.properties} jsonb_path_ops`)` - // support in your drizzle-kit version, or a raw migration statement. - index("component_definition_properties_gin").using("gin", sql`${t.properties} jsonb_path_ops`), - check("component_definition_catalog_version_check", sql`${t.catalogVersion} > 0`), - ], -); - -export const componentPin = holotrace.table( - "component_pin", - { - id: uuid("id").primaryKey().defaultRandom(), - componentId: uuid("component_id") - .notNull() - .references(() => componentDefinition.id, { onDelete: "cascade" }), - pinKey: text("pin_key").notNull(), - name: text("name").notNull(), - electricalRole: text("electrical_role"), - ordinal: integer("ordinal").notNull(), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - unique("component_pin_component_id_pin_key_uq").on(t.componentId, t.pinKey), - unique("component_pin_component_id_ordinal_uq").on(t.componentId, t.ordinal), - check("component_pin_ordinal_check", sql`${t.ordinal} >= 0`), - ], -); - -export const componentPackage = holotrace.table( - "component_package", - { - id: uuid("id").primaryKey().defaultRandom(), - componentId: uuid("component_id") - .notNull() - .references(() => componentDefinition.id, { onDelete: "cascade" }), - packageKey: text("package_key").notNull(), - name: text("name").notNull(), - dimensionsMm: jsonb("dimensions_mm").notNull().default({}), - metadata: jsonb("metadata").notNull().default({}), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - unique("component_package_component_id_package_key_uq").on(t.componentId, t.packageKey), - // Needed as the referenced side of composite FKs from component_representation - // and component_simulation_model. - unique("component_package_id_component_id_uq").on(t.id, t.componentId), - ], -); - -export const packagePin = holotrace.table( - "package_pin", - { - id: uuid("id").primaryKey().defaultRandom(), - packageId: uuid("package_id") - .notNull() - .references(() => componentPackage.id, { onDelete: "cascade" }), - componentPinId: uuid("component_pin_id") - .notNull() - .references(() => componentPin.id, { onDelete: "cascade" }), - physicalLabel: text("physical_label").notNull(), - anchor2d: jsonb("anchor_2d"), - anchor3d: jsonb("anchor_3d"), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - unique("package_pin_package_id_component_pin_id_uq").on(t.packageId, t.componentPinId), - unique("package_pin_package_id_physical_label_uq").on(t.packageId, t.physicalLabel), - // The service must verify that the package and logical pin belong to - // the same component until the write model can carry a composite key. - ], -); - -export const componentRepresentation = holotrace.table( - "component_representation", - { - id: uuid("id").primaryKey().defaultRandom(), - componentId: uuid("component_id") - .notNull() - .references(() => componentDefinition.id, { onDelete: "cascade" }), - packageId: uuid("package_id").references(() => componentPackage.id, { onDelete: "cascade" }), - representationKind: text("representation_kind").notNull(), - artifactId: uuid("artifact_id").notNull().references(() => artifact.id), - detailLevel: integer("detail_level").notNull().default(0), - metadata: jsonb("metadata").notNull().default({}), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - foreignKey({ - columns: [t.packageId, t.componentId], - foreignColumns: [componentPackage.id, componentPackage.componentId], - name: "component_representation_package_component_fk", - }), - unique("component_representation_uq") - .on(t.componentId, t.packageId, t.representationKind, t.detailLevel) - .nullsNotDistinct(), - check( - "component_representation_kind_check", - sql`${t.representationKind} IN ('schematic_svg', 'physical_2d', 'model_3d')`, - ), - check("component_representation_detail_level_check", sql`${t.detailLevel} >= 0`), - ], -); - -// --------------------------------------------------------------------------- -// Simulation catalog -// --------------------------------------------------------------------------- - -export const simulationEngine = holotrace.table( - "simulation_engine", - { - id: uuid("id").primaryKey().defaultRandom(), - engineKey: text("engine_key").notNull(), - name: text("name").notNull(), - version: text("version").notNull(), - capabilities: jsonb("capabilities").notNull().default({}), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [unique("simulation_engine_engine_key_version_uq").on(t.engineKey, t.version)], -); - -export const simulationModel = holotrace.table( - "simulation_model", - { - id: uuid("id").primaryKey().defaultRandom(), - engineId: uuid("engine_id").notNull().references(() => simulationEngine.id), - modelKey: text("model_key").notNull(), - version: integer("version").notNull().default(1), - definition: text("definition"), - artifactId: uuid("artifact_id").references(() => artifact.id), - parameters: jsonb("parameters").notNull().default({}), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - unique("simulation_model_engine_id_model_key_version_uq").on(t.engineId, t.modelKey, t.version), - // Needed as the referenced side of the composite FK from - // component_simulation_model. - unique("simulation_model_id_engine_id_uq").on(t.id, t.engineId), - check("simulation_model_version_check", sql`${t.version} > 0`), - check( - "simulation_model_definition_or_artifact_check", - sql`${t.definition} IS NOT NULL OR ${t.artifactId} IS NOT NULL`, - ), - ], -); - -export const componentSimulationModel = holotrace.table( - "component_simulation_model", - { - id: uuid("id").primaryKey().defaultRandom(), - componentId: uuid("component_id") - .notNull() - .references(() => componentDefinition.id, { onDelete: "cascade" }), - packageId: uuid("package_id").references(() => componentPackage.id, { onDelete: "cascade" }), - engineId: uuid("engine_id").notNull().references(() => simulationEngine.id), - // FK target is the composite (id, engine_id) on simulation_model — see - // the foreignKey() below, so this column itself carries no single-column - // `.references()`. - modelId: uuid("model_id").notNull(), - pinMapping: jsonb("pin_mapping").notNull(), - parameterMapping: jsonb("parameter_mapping").notNull().default({}), - interactionMapping: jsonb("interaction_mapping").notNull().default({}), - isDefault: boolean("is_default").notNull().default(false), - }, - (t) => [ - foreignKey({ - columns: [t.modelId, t.engineId], - foreignColumns: [simulationModel.id, simulationModel.engineId], - name: "component_simulation_model_model_engine_fk", - }), - foreignKey({ - columns: [t.packageId, t.componentId], - foreignColumns: [componentPackage.id, componentPackage.componentId], - name: "component_simulation_model_package_component_fk", - }).onDelete("cascade"), - unique("component_simulation_model_uq") - .on(t.componentId, t.packageId, t.modelId) - .nullsNotDistinct(), - // Separate nullable and non-null package cases so PostgreSQL cannot - // accept multiple component-wide defaults because NULLs are distinct. - uniqueIndex("component_default_simulation_model_for_package_uq") - .on(t.componentId, t.packageId, t.engineId) - .where(sql`${t.isDefault} AND ${t.packageId} IS NOT NULL`), - uniqueIndex("component_default_simulation_model_without_package_uq") - .on(t.componentId, t.engineId) - .where(sql`${t.isDefault} AND ${t.packageId} IS NULL`), - ], -); - -// --------------------------------------------------------------------------- -// ML recognition -// --------------------------------------------------------------------------- - -export const mlModelVersion = holotrace.table( - "ml_model_version", - { - id: uuid("id").primaryKey().defaultRandom(), - modelKey: text("model_key").notNull(), - version: text("version").notNull(), - artifactId: uuid("artifact_id").references(() => artifact.id), - metadata: jsonb("metadata").notNull().default({}), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [unique("ml_model_version_model_key_version_uq").on(t.modelKey, t.version)], -); - -export const recognitionJob = holotrace.table( - "recognition_job", - { - id: uuid("id").primaryKey().defaultRandom(), - projectId: uuid("project_id") - .notNull() - .references(() => project.id, { onDelete: "cascade" }), - sourceArtifactId: uuid("source_artifact_id").notNull().references(() => artifact.id), - processedArtifactId: uuid("processed_artifact_id").references(() => artifact.id), - modelVersionId: uuid("model_version_id").references(() => mlModelVersion.id), - status: text("status").notNull(), - preprocessing: jsonb("preprocessing").notNull().default({}), - rawResult: jsonb("raw_result"), - error: jsonb("error"), - requestedBy: uuid("requested_by").notNull().references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - startedAt: timestamp("started_at", { withTimezone: true }), - completedAt: timestamp("completed_at", { withTimezone: true }), - }, - (t) => [ - index("recognition_job_project_idx").on(t.projectId, t.createdAt.desc()), - check( - "recognition_job_status_check", - sql`${t.status} IN ('queued', 'preprocessing', 'running', 'succeeded', 'failed', 'cancelled')`, - ), - ], -); - -export const recognitionDetection = holotrace.table( - "recognition_detection", - { - id: uuid("id").primaryKey().defaultRandom(), - recognitionJobId: uuid("recognition_job_id") - .notNull() - .references(() => recognitionJob.id, { onDelete: "cascade" }), - detectionKind: text("detection_kind").notNull(), - sourceRegion: jsonb("source_region").notNull(), - recognizedText: text("recognized_text"), - confidence: doublePrecision("confidence"), - candidates: jsonb("candidates").notNull().default([]), - selectedComponentId: uuid("selected_component_id").references(() => componentDefinition.id), - reviewState: text("review_state").notNull().default("unreviewed"), - reviewedBy: uuid("reviewed_by").references(() => appUser.id), - reviewedAt: timestamp("reviewed_at", { withTimezone: true }), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - index("recognition_detection_job_idx").on(t.recognitionJobId, t.detectionKind), - check( - "recognition_detection_kind_check", - sql`${t.detectionKind} IN ('component', 'pin', 'wire', 'junction', 'crossing', 'label', 'other')`, - ), - check("recognition_detection_confidence_check", sql`${t.confidence} BETWEEN 0.0 AND 1.0`), - check( - "recognition_detection_review_state_check", - sql`${t.reviewState} IN ('unreviewed', 'accepted', 'corrected', 'rejected')`, - ), - ], -); - -// --------------------------------------------------------------------------- -// Circuits and immutable versions -// --------------------------------------------------------------------------- - -export const circuit = holotrace.table( - "circuit", - { - id: uuid("id").primaryKey().defaultRandom(), - projectId: uuid("project_id") - .notNull() - .references(() => project.id, { onDelete: "cascade" }), - name: text("name").notNull(), - createdBy: uuid("created_by").notNull().references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [index("circuit_project_idx").on(t.projectId, t.updatedAt.desc())], -); - -export const circuitVersion = holotrace.table( - "circuit_version", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitId: uuid("circuit_id") - .notNull() - .references(() => circuit.id, { onDelete: "cascade" }), - versionNumber: integer("version_number").notNull(), - // Self-referencing composite FK (parent_version_id, circuit_id) -> - // (id, circuit_id) — typed as AnyPgColumn to allow the circular - // reference to the table currently being defined. - parentVersionId: uuid("parent_version_id"), - recognitionJobId: uuid("recognition_job_id").references(() => recognitionJob.id), - schemaVersion: integer("schema_version").notNull().default(1), - irSchemaVersion: text("ir_schema_version").notNull().default("circuit-ir-v0"), - status: text("status").notNull(), - changeSummary: text("change_summary"), - createdBy: uuid("created_by").notNull().references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - foreignKey({ - columns: [t.parentVersionId, t.circuitId], - foreignColumns: [t.id, t.circuitId], - name: "circuit_version_parent_circuit_fk", +export const projectsRelations = relations(projects, ({ one }) => ({ + owner: one(authUser, { + fields: [projects.owner], + references: [authUser.id], }), - unique("circuit_version_circuit_id_version_number_uq").on(t.circuitId, t.versionNumber), - // Needed as the referenced side of composite FKs from every - // circuit-version-scoped child table below. - unique("circuit_version_id_circuit_id_uq").on(t.id, t.circuitId), - check("circuit_version_number_check", sql`${t.versionNumber} > 0`), - check("circuit_version_schema_version_check", sql`${t.schemaVersion} > 0`), - check("circuit_version_ir_schema_version_check", sql`length(${t.irSchemaVersion}) > 0`), - check( - "circuit_version_status_check", - sql`${t.status} IN ('recognized', 'needs_review', 'electrically_valid', 'simulatable', 'archived')`, - ), - ], -); - -export const componentInstance = holotrace.table( - "component_instance", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - componentId: uuid("component_id").references(() => componentDefinition.id), - packageId: uuid("package_id"), - sourceDetectionId: uuid("source_detection_id").references(() => recognitionDetection.id), - referenceDesignator: text("reference_designator").notNull(), - displayName: text("display_name"), - properties: jsonb("properties").notNull().default({}), - recognitionConfidence: doublePrecision("recognition_confidence"), - resolutionState: text("resolution_state").notNull().default("resolved"), - }, - (t) => [ - foreignKey({ - columns: [t.packageId, t.componentId], - foreignColumns: [componentPackage.id, componentPackage.componentId], - name: "component_instance_package_component_fk", - }), - unique("component_instance_circuit_version_id_reference_designator_uq").on( - t.circuitVersionId, - t.referenceDesignator, - ), - unique("component_instance_id_circuit_version_id_uq").on(t.id, t.circuitVersionId), - check( - "component_instance_recognition_confidence_check", - sql`${t.recognitionConfidence} BETWEEN 0.0 AND 1.0`, - ), - check( - "component_instance_resolution_state_check", - sql`${t.resolutionState} IN ('resolved', 'inferred', 'ambiguous', 'unknown')`, - ), - check( - "component_instance_package_requires_component_check", - sql`${t.packageId} IS NULL OR ${t.componentId} IS NOT NULL`, - ), - ], -); - -export const componentInstancePin = holotrace.table( - "component_instance_pin", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - componentInstanceId: uuid("component_instance_id").notNull(), - componentPinId: uuid("component_pin_id").references(() => componentPin.id), - packagePinId: uuid("package_pin_id").references(() => packagePin.id), - pinKey: text("pin_key").notNull(), - displayName: text("display_name"), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - foreignKey({ - columns: [t.componentInstanceId, t.circuitVersionId], - foreignColumns: [componentInstance.id, componentInstance.circuitVersionId], - name: "component_instance_pin_instance_circuit_fk", - }).onDelete("cascade"), - unique("component_instance_pin_instance_id_pin_key_uq").on(t.componentInstanceId, t.pinKey), - unique("component_instance_pin_id_circuit_version_id_uq").on(t.id, t.circuitVersionId), - ], -); - -export const net = holotrace.table( - "net", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - netKey: text("net_key").notNull(), - name: text("name"), - kind: text("kind").notNull().default("signal"), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - unique("net_circuit_version_id_net_key_uq").on(t.circuitVersionId, t.netKey), - unique("net_id_circuit_version_id_uq").on(t.id, t.circuitVersionId), - check("net_kind_check", sql`${t.kind} IN ('signal', 'power', 'ground', 'unresolved')`), - ], -); - -export const netMember = holotrace.table( - "net_member", - { - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - netId: uuid("net_id").notNull(), - instancePinId: uuid("instance_pin_id").notNull(), - }, - (t) => [ - foreignKey({ - columns: [t.netId, t.circuitVersionId], - foreignColumns: [net.id, net.circuitVersionId], - name: "net_member_net_circuit_fk", - }).onDelete("cascade"), - foreignKey({ - columns: [t.instancePinId, t.circuitVersionId], - foreignColumns: [componentInstancePin.id, componentInstancePin.circuitVersionId], - name: "net_member_instance_pin_circuit_fk", - }).onDelete("cascade"), - primaryKey({ columns: [t.netId, t.instancePinId] }), - unique("net_member_circuit_version_id_instance_pin_id_uq").on(t.circuitVersionId, t.instancePinId), - ], -); - -// --------------------------------------------------------------------------- -// Validation issues -// --------------------------------------------------------------------------- - -export const validationIssue = holotrace.table( - "validation_issue", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - severity: text("severity").notNull(), - issueCode: text("issue_code").notNull(), - message: text("message").notNull(), - // Intentionally polymorphic (targetKind + targetId) — the app must - // verify the target belongs to the same circuit version. - targetKind: text("target_kind"), - targetId: uuid("target_id"), - details: jsonb("details").notNull().default({}), - resolvedAt: timestamp("resolved_at", { withTimezone: true }), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - index("validation_issue_open_idx") - .on(t.circuitVersionId, t.severity) - .where(sql`${t.resolvedAt} IS NULL`), - check("validation_issue_severity_check", sql`${t.severity} IN ('info', 'warning', 'error')`), - ], -); - -// --------------------------------------------------------------------------- -// Layouts -// --------------------------------------------------------------------------- - -export const circuitLayout = holotrace.table( - "circuit_layout", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - layoutKind: text("layout_kind").notNull(), - revision: integer("revision").notNull(), - generator: text("generator"), - generatorVersion: text("generator_version"), - viewport: jsonb("viewport").notNull().default({}), - metadata: jsonb("metadata").notNull().default({}), - createdBy: uuid("created_by").references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [ - unique("circuit_layout_circuit_version_id_layout_kind_revision_uq").on( - t.circuitVersionId, - t.layoutKind, - t.revision, - ), - unique("circuit_layout_id_circuit_version_id_uq").on(t.id, t.circuitVersionId), - check( - "circuit_layout_kind_check", - sql`${t.layoutKind} IN ('schematic_2d', 'physical_2d', 'physical_3d')`, - ), - check("circuit_layout_revision_check", sql`${t.revision} > 0`), - ], -); - -export const componentPlacement = holotrace.table( - "component_placement", - { - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - layoutId: uuid("layout_id").notNull(), - componentInstanceId: uuid("component_instance_id").notNull(), - // Position (2D layouts use x/y; z stays at its default). - positionX: doublePrecision("position_x").notNull().default(0), - positionY: doublePrecision("position_y").notNull().default(0), - positionZ: doublePrecision("position_z").notNull().default(0), - // Rotation as a quaternion (x, y, z, w) so a single placement can drive - // a 3D renderer with no Euler-order ambiguity; 2D layouts use rotation - // around the relevant axis only. - rotationX: doublePrecision("rotation_x").notNull().default(0), - rotationY: doublePrecision("rotation_y").notNull().default(0), - rotationZ: doublePrecision("rotation_z").notNull().default(0), - rotationW: doublePrecision("rotation_w").notNull().default(1), - scaleX: doublePrecision("scale_x").notNull().default(1), - scaleY: doublePrecision("scale_y").notNull().default(1), - scaleZ: doublePrecision("scale_z").notNull().default(1), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - foreignKey({ - columns: [t.layoutId, t.circuitVersionId], - foreignColumns: [circuitLayout.id, circuitLayout.circuitVersionId], - name: "component_placement_layout_circuit_fk", - }).onDelete("cascade"), - foreignKey({ - columns: [t.componentInstanceId, t.circuitVersionId], - foreignColumns: [componentInstance.id, componentInstance.circuitVersionId], - name: "component_placement_instance_circuit_fk", - }).onDelete("cascade"), - primaryKey({ columns: [t.layoutId, t.componentInstanceId] }), - ], -); - -export const wireRoute = holotrace.table( - "wire_route", - { - circuitVersionId: uuid("circuit_version_id") - .notNull() - .references(() => circuitVersion.id, { onDelete: "cascade" }), - layoutId: uuid("layout_id").notNull(), - netId: uuid("net_id").notNull(), - route: jsonb("route").notNull(), - style: jsonb("style").notNull().default({}), - }, - (t) => [ - foreignKey({ - columns: [t.layoutId, t.circuitVersionId], - foreignColumns: [circuitLayout.id, circuitLayout.circuitVersionId], - name: "wire_route_layout_circuit_fk", - }).onDelete("cascade"), - foreignKey({ - columns: [t.netId, t.circuitVersionId], - foreignColumns: [net.id, net.circuitVersionId], - name: "wire_route_net_circuit_fk", - }).onDelete("cascade"), - primaryKey({ columns: [t.layoutId, t.netId] }), - ], -); - -// --------------------------------------------------------------------------- -// Simulation sessions and signals -// --------------------------------------------------------------------------- - -export const simulationSession = holotrace.table( - "simulation_session", - { - id: uuid("id").primaryKey().defaultRandom(), - circuitVersionId: uuid("circuit_version_id").notNull().references(() => circuitVersion.id), - engineId: uuid("engine_id").notNull().references(() => simulationEngine.id), - status: text("status").notNull(), - configuration: jsonb("configuration").notNull().default({}), - modelManifest: jsonb("model_manifest").notNull().default({}), - summary: jsonb("summary"), - error: jsonb("error"), - createdBy: uuid("created_by").notNull().references(() => appUser.id), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - startedAt: timestamp("started_at", { withTimezone: true }), - completedAt: timestamp("completed_at", { withTimezone: true }), - }, - (t) => [ - index("simulation_session_circuit_idx").on(t.circuitVersionId, t.createdAt.desc()), - check( - "simulation_session_status_check", - sql`${t.status} IN ('created', 'running', 'paused', 'completed', 'failed', 'cancelled')`, - ), - ], -); - -export const simulationSignal = holotrace.table( - "simulation_signal", - { - id: uuid("id").primaryKey().defaultRandom(), - sessionId: uuid("session_id") - .notNull() - .references(() => simulationSession.id, { onDelete: "cascade" }), - signalKey: text("signal_key").notNull(), - name: text("name").notNull(), - quantity: text("quantity").notNull(), - unit: text("unit").notNull(), - sourceKind: text("source_kind"), - sourceId: uuid("source_id"), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - unique("simulation_signal_session_id_signal_key_uq").on(t.sessionId, t.signalKey), - // Needed as the referenced side of the composite FK from - // simulation_sample. - unique("simulation_signal_id_session_id_uq").on(t.id, t.sessionId), - ], -); - -// --------------------------------------------------------------------------- -// Sampled simulation values -// --------------------------------------------------------------------------- -// This is an ordinary PostgreSQL table. Only insert selected/downsampled -// output here, not every solver tick. Native partitioning can be introduced -// later if measured usage warrants it. - -export const simulationSample = holotrace.table( - "simulation_sample", - { - sampledAt: timestamp("sampled_at", { withTimezone: true }).notNull(), - sessionId: uuid("session_id").notNull(), - signalId: uuid("signal_id").notNull(), - value: doublePrecision("value").notNull(), - quality: smallint("quality"), - metadata: jsonb("metadata").notNull().default({}), - }, - (t) => [ - foreignKey({ - columns: [t.signalId, t.sessionId], - foreignColumns: [simulationSignal.id, simulationSignal.sessionId], - name: "simulation_sample_signal_session_fk", - }).onDelete("cascade"), - primaryKey({ columns: [t.sampledAt, t.sessionId, t.signalId] }), - index("simulation_sample_signal_time_idx").on(t.sessionId, t.signalId, t.sampledAt.desc()), - ], -); - -// --------------------------------------------------------------------------- -// Saved simulation artifacts -// --------------------------------------------------------------------------- - -export const simulationArtifact = holotrace.table( - "simulation_artifact", - { - sessionId: uuid("session_id") - .notNull() - .references(() => simulationSession.id, { onDelete: "cascade" }), - artifactId: uuid("artifact_id") - .notNull() - .references(() => artifact.id, { onDelete: "cascade" }), - purpose: text("purpose").notNull(), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (t) => [primaryKey({ columns: [t.sessionId, t.artifactId] })], -); +})); diff --git a/bun.lock b/bun.lock index 56524eb..0e1e6b8 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,5 @@ { - "lockfileVersion": 2, + "lockfileVersion": 1, "configVersion": 1, "workspaces": { "": { @@ -8,6 +8,7 @@ "@fontsource-variable/inter": "^5.3.0", "@fontsource/jetbrains-mono": "^5.3.0", "@tauri-apps/api": "^2.11.1", + "better-auth": "^1.7.5", "drizzle-kit": "^0.31.10", "drizzle-orm": "^0.45.2", "lucide-svelte": "^1.0.1", @@ -34,6 +35,24 @@ "packages": { "@alloc/quick-lru": ["@alloc/quick-lru@5.3.0", "", {}, "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA=="], + "@better-auth/core": ["@better-auth/core@1.7.5", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.41.1", "@standard-schema/spec": "^1.1.0", "zod": "^4.5.4" }, "peerDependencies": { "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2", "@opentelemetry/api": "^1.9.0", "better-call": "1.4.0", "jose": "^6.1.0", "kysely": "^0.28.5 || ^0.29.0", "nanostores": "^1.0.1" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-kVlSu4H8OKQfjg4b/Zj5MOaospt83N0JbX38wsDzE58Yw95jzovFkU3pxzB1eUFYc4mkuhUMZD8iT1gpUjNMcQ=="], + + "@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0" }, "optionalPeers": ["drizzle-orm"] }, "sha512-9SM7v1735SoaedRDcDbHc5ULgXEd2vUlEJkvRHpMF2Q9qf59TRh1b5A9hryyecyi56bm/0CNUDU3nY0uVWj5/Q=="], + + "@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "kysely": "^0.28.17 || ^0.29.0" }, "optionalPeers": ["kysely"] }, "sha512-1wE5gvnjW+c1i4GrLtL9HLn3s0Xrq4YneCDan1NO1dpz0mEguLFNlzfnUGykTFrDwvFh2X5rkIbA8ALCj6WzXQ=="], + + "@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2" } }, "sha512-YDmnfR9zOXbn5SNYYwfHBPuc19hg1d1C1vUXb+Hm8Q91pTsstFNX5OTlZbo7f28q06FpogAEfGGCN/2QV39cig=="], + + "@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "mongodb": "^6.0.0 || ^7.0.0" }, "optionalPeers": ["mongodb"] }, "sha512-Yq0LfF0VlA9Kfjcjp/v43MSsChv7vKd1ct0Mt15px4zlqaCPIGfPbjw9YNM6jTo0fGpqLR0n15PllSWmLLRp9g=="], + + "@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@prisma/client", "prisma"] }, "sha512-QfW6HS9vK0FMcbI/GsQLdplICxOz0EPzYWGONZT4ovL3cSItd4YH/09USbPPVl+VUQCdznAQIk+n+NKvHdmSag=="], + + "@better-auth/telemetry": ["@better-auth/telemetry@1.7.5", "", { "peerDependencies": { "@better-auth/core": "^1.7.5", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2" } }, "sha512-e/REPqMy9Em+gC6G0xWBikiMLRuy532Er7jqdoNkPBa65FbywgWcm1cZbgdW5CnHsrM3OLZsmKn14yeGoDISeg=="], + + "@better-auth/utils": ["@better-auth/utils@0.4.2", "", { "dependencies": { "@noble/hashes": "^2.0.1" } }, "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A=="], + + "@better-fetch/fetch": ["@better-fetch/fetch@1.3.2", "", {}, "sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow=="], + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], @@ -106,12 +125,18 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@noble/ciphers": ["@noble/ciphers@2.4.0", "", {}, "sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw=="], + + "@noble/hashes": ["@noble/hashes@2.4.0", "", {}, "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="], + "@oxc-project/types": ["@oxc-project/types@0.150.0", "", {}, "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw=="], "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], @@ -164,29 +189,29 @@ "@tauri-apps/api": ["@tauri-apps/api@2.11.1", "", {}, "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA=="], - "@tauri-apps/cli": ["@tauri-apps/cli@2.11.4", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.11.4", "@tauri-apps/cli-darwin-x64": "2.11.4", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", "@tauri-apps/cli-linux-arm64-musl": "2.11.4", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", "@tauri-apps/cli-linux-x64-gnu": "2.11.4", "@tauri-apps/cli-linux-x64-musl": "2.11.4", "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", "@tauri-apps/cli-win32-x64-msvc": "2.11.4" }, "bin": { "tauri": "tauri.js" } }, "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ=="], + "@tauri-apps/cli": ["@tauri-apps/cli@2.11.5", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.11.5", "@tauri-apps/cli-darwin-x64": "2.11.5", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.5", "@tauri-apps/cli-linux-arm64-gnu": "2.11.5", "@tauri-apps/cli-linux-arm64-musl": "2.11.5", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.5", "@tauri-apps/cli-linux-x64-gnu": "2.11.5", "@tauri-apps/cli-linux-x64-musl": "2.11.5", "@tauri-apps/cli-win32-arm64-msvc": "2.11.5", "@tauri-apps/cli-win32-ia32-msvc": "2.11.5", "@tauri-apps/cli-win32-x64-msvc": "2.11.5" }, "bin": { "tauri": "tauri.js" } }, "sha512-YbeJ6tctNoo40purO4u3Eeo3RVqmsjJr0NoKQRu+4pvO4gMLzkjta7x0k96SxSLmx+rQ+8um1ThOlw+HLpgFug=="], - "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.11.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ=="], + "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.11.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tggOiVOohjIHdiElbjeBfB41s6cmfsq+ZQ0PX0fEtCdsDdZ9cCi54e5gNK7tdPbR6JbdDe7RA4kbQdyyBUUk/Q=="], - "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.11.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A=="], + "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.11.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-SrO+KCbqvG1IvVPdlzQX4GEGZRQDISrmDY9bGcW68DLVFBCC06H+Loz6oyUZETUxsSMR6B4oDfvbQVgD4hxsqQ=="], - "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.11.4", "", { "os": "linux", "cpu": "arm" }, "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ=="], + "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.11.5", "", { "os": "linux", "cpu": "arm" }, "sha512-qLrOaCa8hLD5QVPQRjAgOXvhlTFKXmTliVF773GgvADYcWZSdmncnF5zBFAkdu1uQK8KfQbDlBUwqQYZqBfBRQ=="], - "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.11.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA=="], + "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.11.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Tq32xpQjiQEdIrvwDq7lwHhXemn070CXWdbCvr9rdi9rsv9NFTbQ6izVSIfNE+59QaerxuwtUtZ5IxDNWaoYBw=="], - "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.11.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw=="], + "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.11.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-+OdWKj5Aq+C8HXypQ4t926V8cpVnc0ZcJIdhTXWjVAJHkaNuo8EuQR6KRZKHWIbJJgKdMPCDosvwzIFaBBqHKQ=="], - "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.11.4", "", { "os": "linux", "cpu": "none" }, "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ=="], + "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.11.5", "", { "os": "linux", "cpu": "none" }, "sha512-Q0V2hjpllyDW8dWQZSsITuQDfcY9BpBZuhXkMa2T5AFLZAn+FJPXQSyvnxWNVxRowdQ59Xn0QVtGm6HEHNUEvw=="], - "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.11.4", "", { "os": "linux", "cpu": "x64" }, "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ=="], + "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.11.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Xz1s87gFjZJZMQKAhLa77YeiCJM6yVog3f9OxDgVd/KxDIoB1dA5V2xOnMM+SRkOGk9juwIBqesVAjV0kUB0DA=="], - "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.11.4", "", { "os": "linux", "cpu": "x64" }, "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A=="], + "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.11.5", "", { "os": "linux", "cpu": "x64" }, "sha512-6A88wqAZXZHgMaBrGiy/Bpa4GgUnftXM7uquKOeOXCuK78/XdBxEECicK/1oHgrT179XBFOaA6lQEHysjRmGig=="], - "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.11.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ=="], + "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.11.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-sRGgF/ObRfLcS3PtUdyTbJtkGq3E+PNZTknvAURwMNUtHw9DU/BF6S5si43y9lS5yEO9bWJCA+GGYvnn6cphQw=="], - "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.11.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA=="], + "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.11.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-bHOv/yxqfKpI7ioIFQi5wOfZ7jkbPzJD/UhXY52I/hrmE3qNh71cohIPyqZB5GQn3LZeJWdCUOqmIg/w6XX+Wg=="], - "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw=="], + "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.5", "", { "os": "win32", "cpu": "x64" }, "sha512-vaaOmavqdCeS7oMib2banBZemgrC5v54tSkwoBV+bxrXQZhQZrOwE2EO2i4x+CHNtvQUM/6bSs3iymZMAsycWg=="], "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], @@ -212,6 +237,10 @@ "baseline-browser-mapping": ["baseline-browser-mapping@2.11.25", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw=="], + "better-auth": ["better-auth@1.7.5", "", { "dependencies": { "@better-auth/core": "1.7.5", "@better-auth/drizzle-adapter": "1.7.5", "@better-auth/kysely-adapter": "1.7.5", "@better-auth/memory-adapter": "1.7.5", "@better-auth/mongo-adapter": "1.7.5", "@better-auth/prisma-adapter": "1.7.5", "@better-auth/telemetry": "1.7.5", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2", "@noble/ciphers": "^2.2.0", "@noble/hashes": "^2.2.0", "better-call": "1.4.0", "defu": "^6.1.4", "jose": "^6.2.3", "kysely": "^0.28.17 || ^0.29.0", "nanostores": "^1.3.0", "zod": "^4.5.4" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "drizzle-kit": ">=0.31.4 || >=1.0.0-beta.1", "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-aKE0Zt2EPTpFvmq4/oATNyG/mAfc6JUqWkW9pzGlrVnzUb0lso7GJ9BPxD6JPhLqYV1a9zOAb0uAz1Q5fm+eHA=="], + + "better-call": ["better-call@1.4.0", "", { "dependencies": { "@better-auth/utils": "^0.5.0", "@better-fetch/fetch": "^1.3.1", "rou3": "^0.9.1", "set-cookie-parser": "^3.1.2" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA=="], + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -236,6 +265,8 @@ "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "devalue": ["devalue@5.9.4", "", {}, "sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg=="], @@ -294,8 +325,12 @@ "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + "jose": ["jose@6.2.12", "", {}, "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw=="], + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "kysely": ["kysely@0.29.6", "", {}, "sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg=="], + "lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="], @@ -342,6 +377,8 @@ "nanoid": ["nanoid@3.3.19", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug=="], + "nanostores": ["nanostores@1.5.3", "", {}, "sha512-rQLB6eV4f2AW/n3L0JmwCROpaisYy9EDEADvEFSd1C/qG8hB6O5TPlh9A791JRbJr4CnMQBzptDcvD9OR1+6WA=="], + "node-releases": ["node-releases@2.0.56", "", {}, "sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -414,6 +451,8 @@ "rolldown": ["rolldown@1.2.9", "", { "dependencies": { "@oxc-project/types": "=0.150.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.9", "@rolldown/binding-android-arm64": "1.2.9", "@rolldown/binding-darwin-arm64": "1.2.9", "@rolldown/binding-darwin-x64": "1.2.9", "@rolldown/binding-freebsd-x64": "1.2.9", "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", "@rolldown/binding-linux-arm64-gnu": "1.2.9", "@rolldown/binding-linux-arm64-musl": "1.2.9", "@rolldown/binding-linux-ppc64-gnu": "1.2.9", "@rolldown/binding-linux-s390x-gnu": "1.2.9", "@rolldown/binding-linux-x64-gnu": "1.2.9", "@rolldown/binding-linux-x64-musl": "1.2.9", "@rolldown/binding-openharmony-arm64": "1.2.9", "@rolldown/binding-win32-arm64-msvc": "1.2.9", "@rolldown/binding-win32-x64-msvc": "1.2.9" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg=="], + "rou3": ["rou3@0.9.2", "", {}, "sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], @@ -452,7 +491,7 @@ "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], - "tsx": ["tsx@4.23.13", "", { "dependencies": { "esbuild": "~0.28.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw=="], + "tsx": ["tsx@4.23.14", "", { "dependencies": { "esbuild": "~0.28.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-yFwMnbAsUFz/T3kR8P2ENc/DDUaYd9tKg4oVYo0lhkX0LlK4UuqYAO6mpQ2y6lmcyip1uPJ34C2kPACopDwG4w=="], "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], @@ -470,12 +509,16 @@ "zimmerframe": ["zimmerframe@1.1.5", "", {}, "sha512-msJxIvYDYcoNL+PJsu+7qmpDWsYmAxTY+2TNYXXF0hzBzBk0BMecOqDOG/EckUoKCuKwObfbugIl8QpqHDXeFA=="], + "zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="], + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], "@sveltejs/vite-plugin-svelte/magic-string": ["magic-string@1.4.1", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.6.0" } }, "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow=="], "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "better-call/@better-auth/utils": ["@better-auth/utils@0.5.0", "", { "dependencies": { "@noble/hashes": "^2.0.1" } }, "sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], diff --git a/package.json b/package.json index e8188bc..af4f3a5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@fontsource-variable/inter": "^5.3.0", "@fontsource/jetbrains-mono": "^5.3.0", "@tauri-apps/api": "^2.11.1", + "better-auth": "^1.7.5", "drizzle-kit": "^0.31.10", "drizzle-orm": "^0.45.2", "lucide-svelte": "^1.0.1", diff --git a/reference/postgresql.md b/reference/postgresql.md index b9bf616..3894f6d 100644 --- a/reference/postgresql.md +++ b/reference/postgresql.md @@ -18,6 +18,15 @@ Object storage Workers and services Clients should access data through an authenticated API. Database credentials must not be embedded in the web application or a distributed Tauri binary. +The current authentication API uses Better Auth with Drizzle and keeps its `user`, `account`, `session`, and +`verification` records in a separate PostgreSQL `auth` schema. The Python model API remains a separate service and +must not receive user passwords or database credentials. The simplified application `users` table currently remains +unchanged; it is not the credential source for Better Auth. Saved circuit JSON is currently stored in +`public.projects`, whose text `owner` column references `auth.user.id`. The auth service exposes owner-scoped CRUD at +`/api/circuits`; the client does not connect to PostgreSQL directly. This simplified record is an interim persistence +surface and does not replace the versioned circuit model proposed below. The record tracks `lastOpenedAt`; list +requests order by that value, and the authenticated detail request advances it when the circuit is opened. + ## Proposed data areas ### Component catalog diff --git a/reference/schema.sql.md b/reference/schema.sql.md index 0e38d44..4cd0491 100644 --- a/reference/schema.sql.md +++ b/reference/schema.sql.md @@ -23,7 +23,14 @@ UUIDs use PostgreSQL's `gen_random_uuid()`. Status-like values use `CHECK` const ## Accounts, workspaces, and projects -Authentication remains external. `auth_subject` holds the stable identifier issued by the chosen identity provider. The client must access these records through the Holotrace API rather than connecting directly to PostgreSQL. +Authentication is currently provided by a self-hosted Better Auth service. Better Auth owns its tables in a separate +PostgreSQL `auth` schema and its user ID is the stable authenticated subject. In the planned full application schema, +`auth_subject` links application-owned records to that identifier without copying credentials into application +tables. The client must access these records through the Holotrace API rather than connecting directly to PostgreSQL. + +The current simplified implementation predates this full schema. It stores saved circuit JSON in `public.projects` +and links `public.projects.owner` directly to `auth.user.id`; authenticated CRUD is exposed at `/api/circuits`. This +is an interim bridge for user-owned saves, not an implementation of the workspace and immutable-version tables below. ```sql CREATE TABLE holotrace.app_user ( diff --git a/src/lib/authClient.ts b/src/lib/authClient.ts new file mode 100644 index 0000000..0c98cd1 --- /dev/null +++ b/src/lib/authClient.ts @@ -0,0 +1,14 @@ +import { createAuthClient } from 'better-auth/svelte'; +import { usernameClient } from 'better-auth/client/plugins'; + +const DEFAULT_AUTH_BASE_URL = 'https://api.ifyousmellityouwilleventuallydie.tech'; + +export const authBaseURL = import.meta.env.PUBLIC_AUTH_BASE_URL || DEFAULT_AUTH_BASE_URL; + +export const authClient = createAuthClient({ + baseURL: authBaseURL, + fetchOptions: { + credentials: 'include' + }, + plugins: [usernameClient()] +}); diff --git a/src/lib/circuitApi.ts b/src/lib/circuitApi.ts new file mode 100644 index 0000000..8c0b357 --- /dev/null +++ b/src/lib/circuitApi.ts @@ -0,0 +1,72 @@ +import { authBaseURL } from './authClient'; +import type { CircuitState } from './types'; + +export interface SavedCircuit { + id: number; + name: string; + data: CircuitState; + createdAt: string; + modifiedAt: string; + lastOpenedAt: string; +} + +export type SavedCircuitSummary = Omit; + +interface CircuitResponse { + circuit: SavedCircuit; +} + +interface CircuitListResponse { + circuits: SavedCircuitSummary[]; +} + +async function request(path: string, init?: RequestInit): Promise { + const response = await fetch(`${authBaseURL}${path}`, { + ...init, + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + ...init?.headers + } + }); + + if (!response.ok) { + const body = (await response.json().catch(() => null)) as { error?: string } | null; + throw new Error(body?.error ?? `Circuit request failed with status ${response.status}`); + } + + return (await response.json()) as T; +} + +export async function listSavedCircuits(): Promise { + const response = await request('/api/circuits'); + return response.circuits; +} + +export async function createSavedCircuit(name: string, data: CircuitState): Promise { + const response = await request('/api/circuits', { + method: 'POST', + body: JSON.stringify({ name, data }) + }); + return response.circuit; +} + +export async function updateSavedCircuit( + id: number, + name: string, + data: CircuitState +): Promise { + const response = await request(`/api/circuits/${id}`, { + method: 'PUT', + body: JSON.stringify({ name, data }) + }); + return response.circuit; +} + +export async function getSavedCircuit(id: number): Promise { + const response = await request(`/api/circuits/${id}/open`, { + method: 'POST', + body: '{}' + }); + return response.circuit; +} diff --git a/src/lib/components/AppShell.svelte b/src/lib/components/AppShell.svelte index c346c49..af7e269 100644 --- a/src/lib/components/AppShell.svelte +++ b/src/lib/components/AppShell.svelte @@ -17,6 +17,12 @@ import { viewMode, editMode } from '$lib/stores/circuit'; import { activeSheet, closeSheet, openSheet, isCompact, sketchPanelOpen, partsPanelOpen } from '$lib/stores/ui'; + import LoginPage from '$lib/components/LoginPage.svelte' + import RegisterPage from '$lib/components/RegisterPage.svelte' + import SavedCircuitsPage from '$lib/components/SavedCircuitsPage.svelte' + + let page_location = $state("/"); + interface Props { onUploadClick?: () => void; } @@ -29,60 +35,12 @@ } -{#if $isCompact} - -
- - -
- {#if $viewMode === 'circuit'} - - - -
- - - -
- {:else if $viewMode === 'schematic'} - - {:else} - - {/if} -
- - -
- - - - - - - - - - -
- -
-
+{#if page_location === "/login"} + +{:else if page_location === "/register"} + +{:else if page_location === "/circuits"} + {:else}
diff --git a/src/lib/components/LoginPage.svelte b/src/lib/components/LoginPage.svelte new file mode 100644 index 0000000..a7f330b --- /dev/null +++ b/src/lib/components/LoginPage.svelte @@ -0,0 +1,131 @@ + + +
+
+ + +
+

Login

+

Sign in to continue to your circuits.

+ +
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ + {#if errorMessage} + + {/if} + + +
+ +

+ Don't have an account? + +

+
+
+
diff --git a/src/lib/components/MobileTopBar.svelte b/src/lib/components/MobileTopBar.svelte index dd54cb9..2d7657e 100644 --- a/src/lib/components/MobileTopBar.svelte +++ b/src/lib/components/MobileTopBar.svelte @@ -4,8 +4,41 @@ import { viewMode, undo, redo, canUndo, canRedo } from '$lib/stores/circuit'; import { openSheet } from '$lib/stores/ui'; import { simulationRunning, startSimulation, stopSimulation } from '$lib/stores/simulation'; + import { authClient } from '$lib/authClient'; + import { clearSavedCircuitSelection, saveCurrentCircuit, saveError, saveStatus } from '$lib/stores/savedCircuits'; const onCanvas = $derived($viewMode === 'circuit'); + const session = authClient.useSession(); + let { location = $bindable('') } = $props(); + + async function toggleAuthentication() { + if ($session.data) { + await authClient.signOut(); + authClient.hydrateSession(null); + clearSavedCircuitSelection(); + location = '/'; + return; + } + + location = '/login'; + } + + async function save() { + if (!$session.data) { + location = '/login'; + return; + } + + try { + await saveCurrentCircuit(); + } catch { + // The button's accessible label reports that the save should be retried. + } + } + + function gotoSavedCircuits() { + location = $session.data ? '/circuits' : '/login'; + }
+ + + + {#if onCanvas} + +
+

Create account

+

Start digitizing your circuit sketches.

+ +
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ + {#if errorMessage} + + {/if} + + +
+ +

+ Already have an account? + +

+
+
+
\ No newline at end of file diff --git a/src/lib/components/SavedCircuitsPage.svelte b/src/lib/components/SavedCircuitsPage.svelte new file mode 100644 index 0000000..b881907 --- /dev/null +++ b/src/lib/components/SavedCircuitsPage.svelte @@ -0,0 +1,150 @@ + + +
+
+
+ + +
+ +
+
+ +
+
+

Saved circuits

+

Most recently opened circuits appear first.

+
+
+ + {#if error} + + {/if} + + {#if loading} +
+ + Loading saved circuits… +
+ {:else if !signedIn} +
+

Log in to see circuits saved to your account.

+ +
+ {:else if circuits.length === 0} +
+ +

No saved circuits yet

+

Create one from a sketch or save the circuit in the editor.

+
+ {:else} +
+ {#each circuits as saved (saved.id)} +
+
+
+

{saved.name}

+

+ + Opened {formatDate(saved.lastOpenedAt)} +

+
+ +
+

+ Last saved {formatDate(saved.modifiedAt)} +

+
+ {/each} +
+ {/if} +
+
diff --git a/src/lib/components/TopNav.svelte b/src/lib/components/TopNav.svelte index 9d4852a..3b86763 100644 --- a/src/lib/components/TopNav.svelte +++ b/src/lib/components/TopNav.svelte @@ -1,15 +1,52 @@