@specific.dev/cli 0.1.62 → 0.1.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +2 -2
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +5 -5
  5. package/dist/admin/__next._full.txt +8 -8
  6. package/dist/admin/__next._head.txt +1 -1
  7. package/dist/admin/__next._index.txt +3 -3
  8. package/dist/admin/__next._tree.txt +1 -1
  9. package/dist/admin/_next/static/chunks/{59b95f8f36877231.js → 369cccd775763aa2.js} +2 -2
  10. package/dist/admin/_next/static/chunks/497f00630c8a5681.js +1 -0
  11. package/dist/admin/_next/static/chunks/{422a5aac8222197b.js → c7954d71061f1f9b.js} +2 -2
  12. package/dist/admin/_next/static/chunks/e3baf0c708c5b9ae.js +1 -0
  13. package/dist/admin/_not-found/__next._full.txt +3 -3
  14. package/dist/admin/_not-found/__next._head.txt +1 -1
  15. package/dist/admin/_not-found/__next._index.txt +3 -3
  16. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  17. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  18. package/dist/admin/_not-found/__next._tree.txt +1 -1
  19. package/dist/admin/_not-found/index.html +1 -1
  20. package/dist/admin/_not-found/index.txt +3 -3
  21. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +2 -2
  22. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  23. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +5 -5
  24. package/dist/admin/databases/__next._full.txt +8 -8
  25. package/dist/admin/databases/__next._head.txt +1 -1
  26. package/dist/admin/databases/__next._index.txt +3 -3
  27. package/dist/admin/databases/__next._tree.txt +1 -1
  28. package/dist/admin/databases/index.html +1 -1
  29. package/dist/admin/databases/index.txt +8 -8
  30. package/dist/admin/fullscreen/__next._full.txt +4 -4
  31. package/dist/admin/fullscreen/__next._head.txt +1 -1
  32. package/dist/admin/fullscreen/__next._index.txt +3 -3
  33. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  34. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
  35. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next._full.txt +4 -4
  37. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next._index.txt +3 -3
  39. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  40. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +2 -2
  41. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  42. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  43. package/dist/admin/fullscreen/databases/index.html +1 -1
  44. package/dist/admin/fullscreen/databases/index.txt +4 -4
  45. package/dist/admin/fullscreen/index.html +1 -1
  46. package/dist/admin/fullscreen/index.txt +4 -4
  47. package/dist/admin/index.html +1 -1
  48. package/dist/admin/index.txt +8 -8
  49. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +8 -0
  50. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +9 -0
  51. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +4 -0
  52. package/dist/admin/workflows/__next._full.txt +27 -0
  53. package/dist/admin/workflows/__next._head.txt +6 -0
  54. package/dist/admin/workflows/__next._index.txt +7 -0
  55. package/dist/admin/workflows/__next._tree.txt +5 -0
  56. package/dist/admin/workflows/index.html +1 -0
  57. package/dist/admin/workflows/index.txt +27 -0
  58. package/dist/cli.js +1316 -335
  59. package/dist/docs/builds.md +59 -13
  60. package/dist/docs/index.md +4 -0
  61. package/dist/docs/integrations/prisma.md +4 -2
  62. package/dist/docs/integrations/temporal.md +4 -0
  63. package/dist/docs/postgres.md +2 -0
  64. package/dist/docs/services.md +42 -0
  65. package/dist/docs/temporal.md +98 -0
  66. package/dist/docs/volumes.md +63 -0
  67. package/dist/postinstall.js +1 -1
  68. package/package.json +4 -2
  69. package/dist/admin/_next/static/chunks/144304e5f91b7ae5.js +0 -1
  70. /package/dist/admin/_next/static/{bSt01e539un5ZT_sTTRm7 → Au-tOFiLJaoIPzWnpCaGr}/_buildManifest.js +0 -0
  71. /package/dist/admin/_next/static/{bSt01e539un5ZT_sTTRm7 → Au-tOFiLJaoIPzWnpCaGr}/_clientMiddlewareManifest.json +0 -0
  72. /package/dist/admin/_next/static/{bSt01e539un5ZT_sTTRm7 → Au-tOFiLJaoIPzWnpCaGr}/_ssgManifest.js +0 -0
@@ -11,11 +11,14 @@ build "api" {
11
11
 
12
12
  ## Required fields
13
13
 
14
- - `base` - Base environment. Supported: `"node"`, `"python"`, `"go"`, `"rust"`, `"java"`.
14
+ One of the following is required (mutually exclusive):
15
+
16
+ - `base` - Base environment. Supported: `"node"`, `"python"`, `"go"`, `"rust"`, `"java"`. If another base or customization is needed, use a custom Dockerfile instead.
17
+ - `dockerfile` - Path to a custom Dockerfile, relative to `specific.hcl`. See [Custom Dockerfile](#custom-dockerfile) below.
15
18
 
16
19
  ## Optional fields
17
20
 
18
- - `command` - Build command to run after dependencies are installed (e.g., `npm run build`, `go build -o api`).
21
+ - `command` - Build command to run after dependencies are installed (e.g., `npm run build`, `go build -o api`). Only valid with `base`, not with `dockerfile`.
19
22
  - `root` - Working directory for build commands, relative to `specific.hcl`. Defaults to `"."`. Sets the `WORKDIR` in the generated Dockerfile. Services that reference this build inherit its root. Dependency detection (e.g., `package.json`) also looks in this directory.
20
23
  - `context` - Docker build context scope, relative to `specific.hcl`. Defaults to `"."`. Controls what files are available to `COPY` in the Dockerfile and what's included in the deployment tarball. Use this when you need to include files outside of `root` (e.g., shared libraries in a monorepo).
21
24
  - `env` - Environment variables available during the build. Supports string literals and `service.<name>.public_url` references. These are passed as Docker build args.
@@ -24,17 +27,17 @@ build "api" {
24
27
 
25
28
  Specific automatically installs dependencies before running your build command. Dependencies are cached in a separate Docker layer for faster builds when only source code changes.
26
29
 
27
- | Base | Detected Files | Install Command |
28
- |------|----------------|-----------------|
29
- | `node` | `package-lock.json` | `npm ci` |
30
- | `node` | `yarn.lock` | `yarn install --frozen-lockfile` |
31
- | `node` | `pnpm-lock.yaml` | `pnpm install --frozen-lockfile` |
32
- | `node` | `package.json` only | `npm install` |
33
- | `python` | `requirements.txt` | `pip install -r requirements.txt` |
34
- | `python` | `Pipfile.lock` | `pipenv install --deploy --system` |
35
- | `python` | `poetry.lock` | `poetry install` |
36
- | `python` | `pyproject.toml` | `pip install .` |
37
- | `go` | `go.mod` | `go mod download` |
30
+ | Base | Detected Files | Install Command |
31
+ | -------- | ------------------- | ---------------------------------- |
32
+ | `node` | `package-lock.json` | `npm ci` |
33
+ | `node` | `yarn.lock` | `yarn install --frozen-lockfile` |
34
+ | `node` | `pnpm-lock.yaml` | `pnpm install --frozen-lockfile` |
35
+ | `node` | `package.json` only | `npm install` |
36
+ | `python` | `requirements.txt` | `pip install -r requirements.txt` |
37
+ | `python` | `Pipfile.lock` | `pipenv install --deploy --system` |
38
+ | `python` | `poetry.lock` | `poetry install` |
39
+ | `python` | `pyproject.toml` | `pip install .` |
40
+ | `go` | `go.mod` | `go mod download` |
38
41
 
39
42
  For simple projects that only need dependencies installed, you can omit the `command` field:
40
43
 
@@ -115,6 +118,49 @@ build "api" {
115
118
  }
116
119
  ```
117
120
 
121
+ ## Custom Dockerfile
122
+
123
+ For full control over the Docker build, provide your own Dockerfile instead of using `base`:
124
+
125
+ ```hcl
126
+ build "api" {
127
+ dockerfile = "Dockerfile"
128
+ }
129
+ ```
130
+
131
+ When using a custom Dockerfile:
132
+
133
+ - `command` is not allowed — define build steps in the Dockerfile itself.
134
+ - `context` still controls the Docker build context.
135
+ - `env` vars are passed as Docker build args. Use `ARG` instructions in your Dockerfile to consume them.
136
+ - The service `command` still overrides the container `CMD` at runtime.
137
+
138
+ ### Custom Dockerfile with build args
139
+
140
+ ```hcl
141
+ build "web" {
142
+ dockerfile = "docker/Dockerfile.prod"
143
+ context = "."
144
+
145
+ env = {
146
+ NEXT_PUBLIC_API_URL = service.api.public_url
147
+ NODE_ENV = "production"
148
+ }
149
+ }
150
+ ```
151
+
152
+ In the Dockerfile:
153
+
154
+ ```dockerfile
155
+ FROM node:20-slim
156
+ ARG NEXT_PUBLIC_API_URL
157
+ ARG NODE_ENV
158
+ WORKDIR /app
159
+ COPY . .
160
+ RUN npm ci && npm run build
161
+ CMD ["npm", "start"]
162
+ ```
163
+
118
164
  ## Dev configuration
119
165
 
120
166
  Override the build command for local development. If no `dev` block is defined, the build is skipped in development.
@@ -23,6 +23,10 @@ A full development environment can be started with `specific dev`. To deploy any
23
23
  - [Sync](/sync): define real-time, partial synchronisation out of PostgreSQL into frontends or other services. Should be used to implement real-time and collaborative apps.
24
24
  - [Storage](/storage): define S3-compatible object/blob storage for services to store files in.
25
25
  - [Redis](/redis): define non-durable Redis-compatible databases for caching and more.
26
+ - [Volumes](/volumes): define persistent storage volumes for services to store files in.
27
+ <!-- beta:temporal -->
28
+ - [Temporal](/temporal): managed durable workflow engine for background tasks, AI agents, cron jobs and more.
29
+ <!-- /beta:temporal -->
26
30
 
27
31
  ## Common integrations
28
32
 
@@ -23,6 +23,7 @@ service "api" {
23
23
  env = {
24
24
  PORT = port
25
25
  DATABASE_URL = postgres.main.url
26
+ DIRECT_URL = postgres.main.direct_url
26
27
  }
27
28
 
28
29
  pre_deploy {
@@ -45,8 +46,9 @@ Configure the datasource in `prisma/schema.prisma`:
45
46
 
46
47
  ```prisma
47
48
  datasource db {
48
- provider = "postgresql"
49
- url = env("DATABASE_URL")
49
+ provider = "postgresql"
50
+ url = env("DATABASE_URL")
51
+ directUrl = env("DIRECT_URL")
50
52
  }
51
53
 
52
54
  generator client {
@@ -1,5 +1,9 @@
1
1
  # Temporal
2
2
 
3
+ <!-- beta:temporal -->
4
+ > **Beta**: Specific now has built-in Temporal support. See [Temporal](/temporal) for the recommended approach using the `temporal` block. The manual setup below still works but is no longer needed.
5
+ <!-- /beta:temporal -->
6
+
3
7
  Temporal is a durable workflow engine. This guide covers running Temporal locally during development and connecting to Temporal Cloud in production.
4
8
 
5
9
  Temporal has extensive SDK support across many languages including TypeScript, Python, Go, Java, .NET, and PHP. See the [Temporal documentation](https://docs.temporal.io/) for language-specific guides on implementing workers, workflows, and activities. This document only covers integration with Specific.
@@ -33,6 +33,8 @@ postgres "main" {}
33
33
  - `user` - Database user
34
34
  - `password` - Database password
35
35
  - `name` - Database name
36
+ - `direct_url` - Non-pooled connection string, bypassing the connection pooler. Use when you need a direct database connection (e.g., Prisma's `directUrl`).
37
+ - `direct_host` - Non-pooled database host, bypassing the connection pooler.
36
38
 
37
39
  ## Querying the database
38
40
 
@@ -240,6 +240,48 @@ service "worker" {
240
240
  }
241
241
  ```
242
242
 
243
+ ## Pre-existing images
244
+
245
+ Services can use a pre-existing container image instead of a build. This is useful for running third-party services or any pre-built container:
246
+
247
+ ```hcl
248
+ service "redis" {
249
+ image = "redis:7"
250
+ command = "redis-server --port $PORT"
251
+
252
+ endpoint {}
253
+
254
+ env = {
255
+ PORT = port
256
+ }
257
+ }
258
+ ```
259
+
260
+ - `image` - Container image reference (e.g., `redis:7`, `ghcr.io/org/image:tag`)
261
+ - `image` and `build` are mutually exclusive — use one or the other
262
+ - Services with `image` skip the build step entirely
263
+ - Deploy hooks (`pre_deploy`, `post_deploy`) work with image-based services
264
+ - Use `dev.command` for local development:
265
+
266
+ ```hcl
267
+ service "redis" {
268
+ image = "redis:7"
269
+ command = "redis-server --port $PORT"
270
+
271
+ endpoint {}
272
+
273
+ env = {
274
+ PORT = port
275
+ }
276
+
277
+ dev {
278
+ command = "redis-server --port $PORT"
279
+ }
280
+ }
281
+ ```
282
+
283
+ You can mix build-based and image-based services in the same project.
284
+
243
285
  ## Environment variables
244
286
 
245
287
  ```hcl
@@ -0,0 +1,98 @@
1
+ <!-- beta:temporal -->
2
+ # Temporal
3
+
4
+ Define managed Temporal workflow engines for durable workflows, background tasks, AI agents, cron jobs, batch jobs and more.
5
+
6
+ Temporal has extensive SDK support across many languages including TypeScript, Python, Go, Java, .NET, and PHP. See the [Temporal documentation](https://docs.temporal.io/) for language-specific guides on implementing workers, workflows, and activities. This document only covers integration with Specific.
7
+
8
+ ## Configuration
9
+
10
+ Define a `temporal` block in `specific.hcl` and reference it from services:
11
+
12
+ ```hcl
13
+ temporal "tasks" {}
14
+
15
+ build "app" {
16
+ base = "node"
17
+ }
18
+
19
+ service "worker" {
20
+ build = build.app
21
+ command = "node worker.js"
22
+
23
+ env = {
24
+ TEMPORAL_ADDRESS = temporal.tasks.url
25
+ TEMPORAL_NAMESPACE = temporal.tasks.namespace
26
+ TEMPORAL_API_KEY = temporal.tasks.api_key
27
+ }
28
+
29
+ dev {
30
+ command = "node --watch worker.js"
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Reference attributes
36
+
37
+ Each `temporal` block exposes the following reference attributes:
38
+
39
+ | Attribute | Description | Dev value |
40
+ |-----------|-------------|-----------|
41
+ | `temporal.<name>.url` | gRPC address of the Temporal server | `localhost:<port>` |
42
+ | `temporal.<name>.namespace` | Temporal namespace | `default` |
43
+ | `temporal.<name>.api_key` | API key for authentication | `""` (empty, no auth in dev) |
44
+
45
+ These attributes can be used in service `env` blocks, both as standalone values and inside interpolated strings.
46
+
47
+ ## Development
48
+
49
+ Running `specific dev` automatically:
50
+
51
+ 1. Downloads the Temporal CLI (first run only)
52
+ 2. Starts a Temporal dev server with persistent storage
53
+ 3. Makes the Temporal Web UI available in the admin sidebar under "Workflows"
54
+
55
+ Workflow data persists across dev server restarts using a SQLite database stored in `.specific/keys/<key>/data/`.
56
+
57
+ The `api_key` attribute returns an empty string in dev since the Temporal dev server does not require authentication. This is safe because Temporal SDKs conditionally apply authentication based on whether a non-empty key is provided.
58
+
59
+ ## Production
60
+
61
+ Production Temporal support is not yet available through `temporal` blocks. For production, use configs and secrets to pass Temporal Cloud credentials directly:
62
+
63
+ ```hcl
64
+ temporal "tasks" {}
65
+
66
+ config "temporal_address" {}
67
+ secret "temporal_api_key" {
68
+ dev {
69
+ required = false
70
+ }
71
+ }
72
+
73
+ service "worker" {
74
+ build = build.app
75
+ command = "node worker.js"
76
+
77
+ env = {
78
+ # Use built-in temporal block for dev
79
+ TEMPORAL_NAMESPACE = temporal.tasks.namespace
80
+
81
+ # Override address and API key for production via config/secret
82
+ TEMPORAL_ADDRESS = config.temporal_address
83
+ TEMPORAL_API_KEY = secret.temporal_api_key
84
+ }
85
+
86
+ dev {
87
+ command = "node --watch worker.js"
88
+ env = {
89
+ # In dev, use the local Temporal server
90
+ TEMPORAL_ADDRESS = temporal.tasks.url
91
+ TEMPORAL_API_KEY = temporal.tasks.api_key
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ Set the production values with `specific secrets set` and environment config before deploying.
98
+ <!-- /beta:temporal -->
@@ -0,0 +1,63 @@
1
+ # Volumes
2
+
3
+ Persistent storage volumes for services. Volumes provide a directory that persists across deployments, useful for file uploads, caches, and other data that needs to survive restarts.
4
+
5
+ Volumes are defined as sub-blocks within a service. Each volume has a name and exposes a `path` attribute that resolves to the directory path.
6
+
7
+ ```hcl
8
+ service "api" {
9
+ build = build.api
10
+ command = "node server.js"
11
+
12
+ volume "uploads" {}
13
+
14
+ env = {
15
+ UPLOADS_DIR = volume.uploads.path
16
+ }
17
+ }
18
+ ```
19
+
20
+ ## Available volume attributes
21
+
22
+ - `path` - Absolute path to the volume directory
23
+
24
+ ## How it works
25
+
26
+ - **In production (Kubernetes):** Each volume creates a PersistentVolumeClaim. The `path` attribute resolves to `/volumes/{name}` inside the container.
27
+ - **In development (`specific dev`):** Each volume maps to a local directory at `.specific/keys/.../data/volumes/{service}/{name}/`. The `path` attribute resolves to this local directory.
28
+
29
+ Volume data persists across deployments and dev server restarts.
30
+
31
+ ## Multiple volumes
32
+
33
+ A service can define multiple volumes:
34
+
35
+ ```hcl
36
+ service "api" {
37
+ build = build.api
38
+ command = "node server.js"
39
+
40
+ volume "uploads" {}
41
+ volume "cache" {}
42
+
43
+ env = {
44
+ UPLOADS_DIR = volume.uploads.path
45
+ CACHE_DIR = volume.cache.path
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Example usage (Node.js)
51
+
52
+ ```javascript
53
+ import fs from "fs";
54
+ import path from "path";
55
+
56
+ const uploadsDir = process.env.UPLOADS_DIR;
57
+
58
+ // Write a file
59
+ fs.writeFileSync(path.join(uploadsDir, "myfile.txt"), "Hello, world!");
60
+
61
+ // Read it back (persists across restarts)
62
+ const content = fs.readFileSync(path.join(uploadsDir, "myfile.txt"), "utf8");
63
+ ```
@@ -111,7 +111,7 @@ function trackEvent(event, properties) {
111
111
  event,
112
112
  properties: {
113
113
  ...properties,
114
- cli_version: "0.1.62",
114
+ cli_version: "0.1.64",
115
115
  platform: process.platform,
116
116
  node_version: process.version,
117
117
  project_id: getProjectId(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.62",
3
+ "version": "0.1.64",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -35,10 +35,11 @@
35
35
  "node": ">=18"
36
36
  },
37
37
  "dependencies": {
38
+ "@babel/code-frame": "^7.29.0",
38
39
  "chokidar": "^5.0.0",
40
+ "commander": "^14.0.2",
39
41
  "dns2": "^2.1.0",
40
42
  "hcl2-json-parser": "^1.0.1",
41
- "commander": "^14.0.2",
42
43
  "http-proxy": "^1.18.1",
43
44
  "ink": "^6.5.1",
44
45
  "ink-spinner": "^5.0.0",
@@ -53,6 +54,7 @@
53
54
  "devDependencies": {
54
55
  "@specific/config": "file:../config",
55
56
  "@specific/tunnel-client": "file:../tunnel/client",
57
+ "@types/babel__code-frame": "^7.27.0",
56
58
  "@types/http-proxy": "^1.17.17",
57
59
  "@types/node": "^25.0.1",
58
60
  "@types/node-forge": "^1.3.11",
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,12283,e=>{"use strict";var t=e.i(90795),r=e.i(59369);let n=(0,r.createContext)(void 0);function s({children:e}){let[s,a]=(0,r.useState)(null),[o,l]=(0,r.useState)(null),[i,c]=(0,r.useState)(!1),u=(0,r.useMemo)(()=>(function(){let e=window.location.hostname,t=".local.spcf.app";if("local.spcf.app"===e)return"default";if(e.endsWith(t)){let r=e.slice(0,-t.length);if(r&&!r.includes("."))return r}return null})(),[]),m=(0,r.useMemo)(()=>u?"default"===u?"https://__drizzle_gateway.local.spcf.app":`https://__drizzle_gateway.${u}.local.spcf.app`:null,[u]);(0,r.useEffect)(()=>{async function e(){try{let e=await fetch("/api/state");if(!e.ok)throw Error("Failed to fetch state");let t=await e.json();a(t),c(!0),l(null)}catch(e){l(e instanceof Error?e.message:"Unknown error"),c(!1)}}e();let t=setInterval(e,2e3);return()=>clearInterval(t)},[]);let d=s?.resources.some(e=>"postgres"===e.type)??!1,h=s?.projectId??null,f=(0,r.useMemo)(()=>({state:s,error:o,connected:i,instanceKey:u,hasDatabases:d,drizzleGatewayUrl:m,projectId:h}),[s,o,i,u,d,m,h]);return(0,t.jsx)(n.Provider,{value:f,children:e})}function a(){let e=(0,r.useContext)(n);if(void 0===e)throw Error("useDevState must be used within a DevStateProvider");return e}e.s(["DevStateProvider",()=>s,"useDevState",()=>a],12283)},70932,e=>{"use strict";var t=e.i(59369),r=(e,t,r,n,s,a,o,l)=>{let i=document.documentElement,c=["light","dark"];function u(t){var r;(Array.isArray(e)?e:[e]).forEach(e=>{let r="class"===e,n=r&&a?s.map(e=>a[e]||e):s;r?(i.classList.remove(...n),i.classList.add(a&&a[t]?a[t]:t)):i.setAttribute(e,t)}),r=t,l&&c.includes(r)&&(i.style.colorScheme=r)}if(n)u(n);else try{let e=localStorage.getItem(t)||r,n=o&&"system"===e?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e;u(n)}catch(e){}},n=["light","dark"],s="(prefers-color-scheme: dark)",a="u"<typeof window,o=t.createContext(void 0),l={setTheme:e=>{},themes:[]},i=()=>{var e;return null!=(e=t.useContext(o))?e:l},c=e=>t.useContext(o)?t.createElement(t.Fragment,null,e.children):t.createElement(m,{...e}),u=["light","dark"],m=({forcedTheme:e,disableTransitionOnChange:r=!1,enableSystem:a=!0,enableColorScheme:l=!0,storageKey:i="theme",themes:c=u,defaultTheme:m=a?"system":"light",attribute:v="data-theme",value:y,children:g,nonce:w,scriptProps:b})=>{let[S,T]=t.useState(()=>h(i,m)),[E,C]=t.useState(()=>"system"===S?p():S),k=y?Object.values(y):c,P=t.useCallback(e=>{let t=e;if(!t)return;"system"===e&&a&&(t=p());let s=y?y[t]:t,o=r?f(w):null,i=document.documentElement,c=e=>{"class"===e?(i.classList.remove(...k),s&&i.classList.add(s)):e.startsWith("data-")&&(s?i.setAttribute(e,s):i.removeAttribute(e))};if(Array.isArray(v)?v.forEach(c):c(v),l){let e=n.includes(m)?m:null,r=n.includes(t)?t:e;i.style.colorScheme=r}null==o||o()},[w]),A=t.useCallback(e=>{let t="function"==typeof e?e(S):e;T(t);try{localStorage.setItem(i,t)}catch(e){}},[S]),L=t.useCallback(t=>{C(p(t)),"system"===S&&a&&!e&&P("system")},[S,e]);t.useEffect(()=>{let e=window.matchMedia(s);return e.addListener(L),L(e),()=>e.removeListener(L)},[L]),t.useEffect(()=>{let e=e=>{e.key===i&&(e.newValue?T(e.newValue):A(m))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)},[A]),t.useEffect(()=>{P(null!=e?e:S)},[e,S]);let x=t.useMemo(()=>({theme:S,setTheme:A,forcedTheme:e,resolvedTheme:"system"===S?E:S,themes:a?[...c,"system"]:c,systemTheme:a?E:void 0}),[S,A,e,E,a,c]);return t.createElement(o.Provider,{value:x},t.createElement(d,{forcedTheme:e,storageKey:i,attribute:v,enableSystem:a,enableColorScheme:l,defaultTheme:m,value:y,themes:c,nonce:w,scriptProps:b}),g)},d=t.memo(({forcedTheme:e,storageKey:n,attribute:s,enableSystem:a,enableColorScheme:o,defaultTheme:l,value:i,themes:c,nonce:u,scriptProps:m})=>{let d=JSON.stringify([s,n,l,e,c,i,a,o]).slice(1,-1);return t.createElement("script",{...m,suppressHydrationWarning:!0,nonce:"u"<typeof window?u:"",dangerouslySetInnerHTML:{__html:`(${r.toString()})(${d})`}})}),h=(e,t)=>{let r;if(!a){try{r=localStorage.getItem(e)||void 0}catch(e){}return r||t}},f=e=>{let t=document.createElement("style");return e&&t.setAttribute("nonce",e),t.appendChild(document.createTextNode("*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}")),document.head.appendChild(t),()=>{window.getComputedStyle(document.body),setTimeout(()=>{document.head.removeChild(t)},1)}},p=e=>(e||(e=window.matchMedia(s)),e.matches?"dark":"light");e.s(["ThemeProvider",()=>c,"useTheme",()=>i])},49311,e=>{"use strict";var t=e.i(90795),r=e.i(70932);function n({children:e,...n}){return(0,t.jsx)(r.ThemeProvider,{...n,children:e})}e.s(["ThemeProvider",()=>n])}]);