@specific.dev/cli 0.1.91 → 0.1.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +2 -2
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +5 -5
- package/dist/admin/__next._full.txt +8 -8
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +3 -3
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_next/static/chunks/42de6b5004222d9f.js +1 -0
- package/dist/admin/_next/static/chunks/{091449dbc4d3eb97.js → df799a08b7ff15f9.js} +2 -2
- package/dist/admin/_not-found/__next._full.txt +3 -3
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +3 -3
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +3 -3
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +2 -2
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +5 -5
- package/dist/admin/databases/__next._full.txt +8 -8
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +3 -3
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +8 -8
- package/dist/admin/fullscreen/__next._full.txt +4 -4
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +3 -3
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +4 -4
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +3 -3
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +2 -2
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +4 -4
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +4 -4
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +8 -8
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +2 -2
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +5 -5
- package/dist/admin/mail/__next._full.txt +8 -8
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +3 -3
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +8 -8
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +5 -5
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +2 -2
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +8 -8
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +3 -3
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +8 -8
- package/dist/cli.js +489 -2062
- package/dist/docs/postgres/reshape/index.md +6 -9
- package/dist/docs/services.md +49 -5
- package/package.json +1 -2
- package/dist/admin/_next/static/chunks/153355cea359ee0f.js +0 -1
- package/dist/postinstall.js +0 -182912
- /package/dist/admin/_next/static/{NRTSfx4J_pKuSA3c36hNC → bHtcCLWKGqkBj4NJ2_XcY}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{NRTSfx4J_pKuSA3c36hNC → bHtcCLWKGqkBj4NJ2_XcY}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{NRTSfx4J_pKuSA3c36hNC → bHtcCLWKGqkBj4NJ2_XcY}/_ssgManifest.js +0 -0
|
@@ -70,14 +70,11 @@ service "api" {
|
|
|
70
70
|
|
|
71
71
|
Place migration files in your migrations directory. Files are processed in **lexical order** (e.g., `001_first.toml` before `002_second.toml`).
|
|
72
72
|
|
|
73
|
-
**IMPORTANT:** You MUST run `specific
|
|
73
|
+
**IMPORTANT:** You MUST run `specific check` every time you create or edit a migration file. This validates both your `specific.hcl` configuration and all migration files, catching errors before the watcher applies them. Without this step, invalid migrations will silently fail to apply.
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
# Validate all migration files
|
|
77
|
-
specific
|
|
78
|
-
|
|
79
|
-
# Validate migrations for a specific database
|
|
80
|
-
specific reshape check main
|
|
76
|
+
# Validate specific.hcl and all migration files
|
|
77
|
+
specific check
|
|
81
78
|
```
|
|
82
79
|
|
|
83
80
|
Example migration (`migrations/001_create_users.toml`):
|
|
@@ -130,12 +127,12 @@ specific reshape abort main
|
|
|
130
127
|
## Development Workflow
|
|
131
128
|
|
|
132
129
|
1. Write your migration file in the migrations directory
|
|
133
|
-
2. Run `specific
|
|
130
|
+
2. Run `specific check` to validate both `specific.hcl` and migration syntax
|
|
134
131
|
3. `specific dev` automatically applies it
|
|
135
|
-
4. Iterate on the migration - run `specific
|
|
132
|
+
4. Iterate on the migration - run `specific check` after **every** change
|
|
136
133
|
5. When ready, add a new migration file to "lock in" the previous one
|
|
137
134
|
|
|
138
|
-
**Remember:** Always run `specific
|
|
135
|
+
**Remember:** Always run `specific check` after any change to a migration file or `specific.hcl`. This validates everything in one step.
|
|
139
136
|
|
|
140
137
|
Completed migrations are made read-only to prevent accidental changes. If you need to modify a completed migration, you'll need to manually change the file permissions first.
|
|
141
138
|
|
package/dist/docs/services.md
CHANGED
|
@@ -22,7 +22,13 @@ service "web" {
|
|
|
22
22
|
|
|
23
23
|
env = {
|
|
24
24
|
PORT = port
|
|
25
|
-
API_URL = service.api.public_url
|
|
25
|
+
API_URL = "https://${service.api.public_url}"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
dev {
|
|
29
|
+
env = {
|
|
30
|
+
API_URL = "http://${service.api.public_url}"
|
|
31
|
+
}
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
34
|
|
|
@@ -143,10 +149,34 @@ service "worker" {
|
|
|
143
149
|
|
|
144
150
|
Available service reference attributes:
|
|
145
151
|
|
|
146
|
-
- `service.<name>.private_url` - Internal URL without scheme (
|
|
152
|
+
- `service.<name>.private_url` - Internal URL without scheme (e.g., `localhost:3001`). Does NOT include `http://` or `https://`.
|
|
147
153
|
- `service.<name>.host` - Host only (e.g., `localhost`)
|
|
148
|
-
- `service.<name>.port` - Port only (e.g., `
|
|
149
|
-
- `service.<name>.public_url` - Public URL without scheme (
|
|
154
|
+
- `service.<name>.port` - Port only (e.g., `3001`)
|
|
155
|
+
- `service.<name>.public_url` - Public URL without scheme (e.g., `my-app.specific.app` in production, `localhost:3001` in dev). Does NOT include `http://` or `https://`. Only available for endpoints with `public = true`.
|
|
156
|
+
|
|
157
|
+
**Important:** `public_url` and `private_url` do NOT include a scheme. In production, services are served over HTTPS. In local development, services use plain HTTP. When you need to construct a full URL, use string interpolation with the correct scheme for each environment. Use the `dev { env = {} }` block to override with `http://` locally:
|
|
158
|
+
|
|
159
|
+
```hcl
|
|
160
|
+
service "web" {
|
|
161
|
+
build = build.web
|
|
162
|
+
command = "npm start"
|
|
163
|
+
|
|
164
|
+
endpoint {
|
|
165
|
+
public = true
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
env = {
|
|
169
|
+
PORT = port
|
|
170
|
+
API_URL = "https://${service.api.public_url}"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
dev {
|
|
174
|
+
env = {
|
|
175
|
+
API_URL = "http://${service.api.public_url}"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
150
180
|
|
|
151
181
|
For services with multiple named endpoints, you must specify the endpoint:
|
|
152
182
|
|
|
@@ -186,7 +216,13 @@ service "api" {
|
|
|
186
216
|
|
|
187
217
|
env = {
|
|
188
218
|
PORT = port
|
|
189
|
-
CORS_ORIGIN = service.web.public_url
|
|
219
|
+
CORS_ORIGIN = "https://${service.web.public_url}"
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
dev {
|
|
223
|
+
env = {
|
|
224
|
+
CORS_ORIGIN = "http://${service.web.public_url}"
|
|
225
|
+
}
|
|
190
226
|
}
|
|
191
227
|
}
|
|
192
228
|
```
|
|
@@ -315,11 +351,19 @@ service "worker" {
|
|
|
315
351
|
CUSTOM_DB = "host=${postgres.main.host} port=${postgres.main.port}"
|
|
316
352
|
PUBLIC_API = "https://${service.api.public_url}/v1"
|
|
317
353
|
}
|
|
354
|
+
|
|
355
|
+
dev {
|
|
356
|
+
env = {
|
|
357
|
+
PUBLIC_API = "http://${service.api.public_url}/v1"
|
|
358
|
+
}
|
|
359
|
+
}
|
|
318
360
|
}
|
|
319
361
|
```
|
|
320
362
|
|
|
321
363
|
All resource references (services, postgres, redis, storage, port, endpoint) can be used inside interpolated strings. Secret and config references cannot be interpolated — they must be used as standalone values.
|
|
322
364
|
|
|
365
|
+
Since `public_url` and `private_url` do not include a scheme, you should use `https://` in the top-level `env` (for production) and override with `http://` in the `dev { env = {} }` block (for local development). The `dev` env block is merged with the top-level env, so you only need to override the variables that differ.
|
|
366
|
+
|
|
323
367
|
## Service dev configuration
|
|
324
368
|
|
|
325
369
|
Override how a service runs in development. If the referenced build has no `dev` block, it is skipped.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@specific.dev/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"description": "CLI for Specific infrastructure-as-code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"link:dev": "npm run build:dev && npm link",
|
|
18
18
|
"link:staging": "npm run build:staging && npm link",
|
|
19
19
|
"link:prod": "npm run build && npm link",
|
|
20
|
-
"postinstall": "node dist/postinstall.js || true",
|
|
21
20
|
"build:binary": "npx tsx scripts/build-binary.ts"
|
|
22
21
|
},
|
|
23
22
|
"keywords": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,12283,35014,e=>{"use strict";var t=e.i(90795),r=e.i(59369);function o(){let e=window.location.hostname;return"localhost"===e||"127.0.0.1"===e}function n(){let e=window.location.hostname,t=".spcf.localhost";if("localhost"===e||"127.0.0.1"===e||"spcf.localhost"===e)return"default";if(e.endsWith(t)){let r=e.slice(0,-t.length);if(r&&!r.includes("."))return r}return null}function s(e,t){return o()&&t?`http://localhost:${t}`:"default"===e?"https://__drizzle_gateway.spcf.localhost":`https://__drizzle_gateway.${e}.spcf.localhost`}function a(e,t){return o()&&t?`http://localhost:${t}`:"default"===e?"https://__temporal.spcf.localhost":`https://__temporal.${e}.spcf.localhost`}e.s(["getDrizzleGatewayUrl",()=>s,"getInstanceKey",()=>n,"getTemporalUiUrl",()=>a],35014);let l=(0,r.createContext)(void 0);function i({children:e}){let[o,i]=(0,r.useState)(null),[c,u]=(0,r.useState)(null),[m,d]=(0,r.useState)(!1),h=(0,r.useMemo)(()=>n(),[]);(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();i(t),d(!0),u(null)}catch(e){e instanceof TypeError&&"Failed to fetch"===e.message?u("specific dev is not running. Restart it to reconnect."):u(e instanceof Error?e.message:"Unknown error"),d(!1)}}e();let t=setInterval(e,2e3);return()=>clearInterval(t)},[]);let f=o?.resources.some(e=>"postgres"===e.type)??!1,p=(0,r.useMemo)(()=>h?s(h,o?.drizzleGatewayPort):null,[h,o?.drizzleGatewayPort]),y=o?.hasTemporal??!1,v=(0,r.useMemo)(()=>h?a(h,o?.temporalUiPort):null,[h,o?.temporalUiPort]),g=o?.hasMail??!1,w=o?.mailApiUrl??null,T=o?.projectId??null,b=(0,r.useMemo)(()=>({state:o,error:c,connected:m,instanceKey:h,hasDatabases:f,drizzleGatewayUrl:p,hasTemporal:y,temporalUiUrl:v,hasMail:g,mailApiUrl:w,projectId:T}),[o,c,m,h,f,p,y,v,g,w,T]);return(0,t.jsx)(l.Provider,{value:b,children:e})}function c(){let e=(0,r.useContext)(l);if(void 0===e)throw Error("useDevState must be used within a DevStateProvider");return e}e.s(["DevStateProvider",()=>i,"useDevState",()=>c],12283)},70932,e=>{"use strict";var t=e.i(59369),r=(e,t,r,o,n,s,a,l)=>{let i=document.documentElement,c=["light","dark"];function u(t){var r;(Array.isArray(e)?e:[e]).forEach(e=>{let r="class"===e,o=r&&s?n.map(e=>s[e]||e):n;r?(i.classList.remove(...o),i.classList.add(s&&s[t]?s[t]:t)):i.setAttribute(e,t)}),r=t,l&&c.includes(r)&&(i.style.colorScheme=r)}if(o)u(o);else try{let e=localStorage.getItem(t)||r,o=a&&"system"===e?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e;u(o)}catch(e){}},o=["light","dark"],n="(prefers-color-scheme: dark)",s="u"<typeof window,a=t.createContext(void 0),l={setTheme:e=>{},themes:[]},i=()=>{var e;return null!=(e=t.useContext(a))?e:l},c=e=>t.useContext(a)?t.createElement(t.Fragment,null,e.children):t.createElement(m,{...e}),u=["light","dark"],m=({forcedTheme:e,disableTransitionOnChange:r=!1,enableSystem:s=!0,enableColorScheme:l=!0,storageKey:i="theme",themes:c=u,defaultTheme:m=s?"system":"light",attribute:y="data-theme",value:v,children:g,nonce:w,scriptProps:T})=>{let[b,S]=t.useState(()=>h(i,m)),[E,C]=t.useState(()=>"system"===b?p():b),P=v?Object.values(v):c,k=t.useCallback(e=>{let t=e;if(!t)return;"system"===e&&s&&(t=p());let n=v?v[t]:t,a=r?f(w):null,i=document.documentElement,c=e=>{"class"===e?(i.classList.remove(...P),n&&i.classList.add(n)):e.startsWith("data-")&&(n?i.setAttribute(e,n):i.removeAttribute(e))};if(Array.isArray(y)?y.forEach(c):c(y),l){let e=o.includes(m)?m:null,r=o.includes(t)?t:e;i.style.colorScheme=r}null==a||a()},[w]),_=t.useCallback(e=>{let t="function"==typeof e?e(b):e;S(t);try{localStorage.setItem(i,t)}catch(e){}},[b]),z=t.useCallback(t=>{C(p(t)),"system"===b&&s&&!e&&k("system")},[b,e]);t.useEffect(()=>{let e=window.matchMedia(n);return e.addListener(z),z(e),()=>e.removeListener(z)},[z]),t.useEffect(()=>{let e=e=>{e.key===i&&(e.newValue?S(e.newValue):_(m))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)},[_]),t.useEffect(()=>{k(null!=e?e:b)},[e,b]);let A=t.useMemo(()=>({theme:b,setTheme:_,forcedTheme:e,resolvedTheme:"system"===b?E:b,themes:s?[...c,"system"]:c,systemTheme:s?E:void 0}),[b,_,e,E,s,c]);return t.createElement(a.Provider,{value:A},t.createElement(d,{forcedTheme:e,storageKey:i,attribute:y,enableSystem:s,enableColorScheme:l,defaultTheme:m,value:v,themes:c,nonce:w,scriptProps:T}),g)},d=t.memo(({forcedTheme:e,storageKey:o,attribute:n,enableSystem:s,enableColorScheme:a,defaultTheme:l,value:i,themes:c,nonce:u,scriptProps:m})=>{let d=JSON.stringify([n,o,l,e,c,i,s,a]).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(!s){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(n)),e.matches?"dark":"light");e.s(["ThemeProvider",()=>c,"useTheme",()=>i])},49311,e=>{"use strict";var t=e.i(90795),r=e.i(70932);function o({children:e,...o}){return(0,t.jsx)(r.ThemeProvider,{...o,children:e})}e.s(["ThemeProvider",()=>o])}]);
|