@specific.dev/cli 0.1.37

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 (204) hide show
  1. package/dist/admin/404/index.html +1 -0
  2. package/dist/admin/404.html +1 -0
  3. package/dist/admin/__next.__PAGE__.txt +9 -0
  4. package/dist/admin/__next._full.txt +20 -0
  5. package/dist/admin/__next._head.txt +6 -0
  6. package/dist/admin/__next._index.txt +5 -0
  7. package/dist/admin/__next._tree.txt +4 -0
  8. package/dist/admin/_next/static/0zkv3YeV6IWOWVWE1S1A1/_buildManifest.js +11 -0
  9. package/dist/admin/_next/static/0zkv3YeV6IWOWVWE1S1A1/_clientMiddlewareManifest.json +1 -0
  10. package/dist/admin/_next/static/0zkv3YeV6IWOWVWE1S1A1/_ssgManifest.js +1 -0
  11. package/dist/admin/_next/static/1o2O2QPOKhuZyxcNaCjq8/_buildManifest.js +11 -0
  12. package/dist/admin/_next/static/1o2O2QPOKhuZyxcNaCjq8/_clientMiddlewareManifest.json +1 -0
  13. package/dist/admin/_next/static/1o2O2QPOKhuZyxcNaCjq8/_ssgManifest.js +1 -0
  14. package/dist/admin/_next/static/2ZtqtFX2EkuM82mTM7NWT/_buildManifest.js +11 -0
  15. package/dist/admin/_next/static/2ZtqtFX2EkuM82mTM7NWT/_clientMiddlewareManifest.json +1 -0
  16. package/dist/admin/_next/static/2ZtqtFX2EkuM82mTM7NWT/_ssgManifest.js +1 -0
  17. package/dist/admin/_next/static/2vLF5bo4ZtUfhs8bdQBoF/_buildManifest.js +11 -0
  18. package/dist/admin/_next/static/2vLF5bo4ZtUfhs8bdQBoF/_clientMiddlewareManifest.json +1 -0
  19. package/dist/admin/_next/static/2vLF5bo4ZtUfhs8bdQBoF/_ssgManifest.js +1 -0
  20. package/dist/admin/_next/static/8_8s51m7RbLVvbIechG-b/_buildManifest.js +11 -0
  21. package/dist/admin/_next/static/8_8s51m7RbLVvbIechG-b/_clientMiddlewareManifest.json +1 -0
  22. package/dist/admin/_next/static/8_8s51m7RbLVvbIechG-b/_ssgManifest.js +1 -0
  23. package/dist/admin/_next/static/C4Y44KtLnP684m57gN3Ga/_buildManifest.js +11 -0
  24. package/dist/admin/_next/static/C4Y44KtLnP684m57gN3Ga/_clientMiddlewareManifest.json +1 -0
  25. package/dist/admin/_next/static/C4Y44KtLnP684m57gN3Ga/_ssgManifest.js +1 -0
  26. package/dist/admin/_next/static/DBeh36kAJnZBeBMJSPBW8/_buildManifest.js +11 -0
  27. package/dist/admin/_next/static/DBeh36kAJnZBeBMJSPBW8/_clientMiddlewareManifest.json +1 -0
  28. package/dist/admin/_next/static/DBeh36kAJnZBeBMJSPBW8/_ssgManifest.js +1 -0
  29. package/dist/admin/_next/static/REKEUu6DP2t99jKSAqNOu/_buildManifest.js +11 -0
  30. package/dist/admin/_next/static/REKEUu6DP2t99jKSAqNOu/_clientMiddlewareManifest.json +1 -0
  31. package/dist/admin/_next/static/REKEUu6DP2t99jKSAqNOu/_ssgManifest.js +1 -0
  32. package/dist/admin/_next/static/TDGT3mkKtTe0w_CxujLxI/_buildManifest.js +11 -0
  33. package/dist/admin/_next/static/TDGT3mkKtTe0w_CxujLxI/_clientMiddlewareManifest.json +1 -0
  34. package/dist/admin/_next/static/TDGT3mkKtTe0w_CxujLxI/_ssgManifest.js +1 -0
  35. package/dist/admin/_next/static/ZHMJ-g7mAlAMt_2uCXeEk/_buildManifest.js +11 -0
  36. package/dist/admin/_next/static/ZHMJ-g7mAlAMt_2uCXeEk/_clientMiddlewareManifest.json +1 -0
  37. package/dist/admin/_next/static/ZHMJ-g7mAlAMt_2uCXeEk/_ssgManifest.js +1 -0
  38. package/dist/admin/_next/static/a6JDAB-CdvWPvS4sBgJji/_buildManifest.js +11 -0
  39. package/dist/admin/_next/static/a6JDAB-CdvWPvS4sBgJji/_clientMiddlewareManifest.json +1 -0
  40. package/dist/admin/_next/static/a6JDAB-CdvWPvS4sBgJji/_ssgManifest.js +1 -0
  41. package/dist/admin/_next/static/abFUeBpymhlx-IxygVnM9/_buildManifest.js +11 -0
  42. package/dist/admin/_next/static/abFUeBpymhlx-IxygVnM9/_clientMiddlewareManifest.json +1 -0
  43. package/dist/admin/_next/static/abFUeBpymhlx-IxygVnM9/_ssgManifest.js +1 -0
  44. package/dist/admin/_next/static/chunks/0afa5e999b6c353a.js +1 -0
  45. package/dist/admin/_next/static/chunks/1584f10ea1cebcb2.js +4 -0
  46. package/dist/admin/_next/static/chunks/195bbec70cfcd241.js +2 -0
  47. package/dist/admin/_next/static/chunks/2583656ea9ac4ad6.js +5 -0
  48. package/dist/admin/_next/static/chunks/465f799faf41e6df.js +1 -0
  49. package/dist/admin/_next/static/chunks/4ab079bdcb131778.js +5 -0
  50. package/dist/admin/_next/static/chunks/4b5ae5ebb2087f0d.js +2 -0
  51. package/dist/admin/_next/static/chunks/605800ff25160d05.js +1 -0
  52. package/dist/admin/_next/static/chunks/656b870f0567ed5f.js +1 -0
  53. package/dist/admin/_next/static/chunks/71098a6cd6181738.css +3 -0
  54. package/dist/admin/_next/static/chunks/806bdb8e4a6a9b95.js +4 -0
  55. package/dist/admin/_next/static/chunks/895a6f91f0b479fb.js +2 -0
  56. package/dist/admin/_next/static/chunks/9032f4a1aac1ca5d.css +3 -0
  57. package/dist/admin/_next/static/chunks/a28af2dc6f5fbaad.js +1 -0
  58. package/dist/admin/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  59. package/dist/admin/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  60. package/dist/admin/_next/static/chunks/b4205fc2f84bda68.css +3 -0
  61. package/dist/admin/_next/static/chunks/c1a750c25bc8d092.js +1 -0
  62. package/dist/admin/_next/static/chunks/c3d30f6f144dca51.js +2 -0
  63. package/dist/admin/_next/static/chunks/cbf55ce8731457ae.js +2 -0
  64. package/dist/admin/_next/static/chunks/d2be314c3ece3fbe.js +1 -0
  65. package/dist/admin/_next/static/chunks/de6af6d8adf8b50a.js +5 -0
  66. package/dist/admin/_next/static/chunks/f0c001244d275aab.js +5 -0
  67. package/dist/admin/_next/static/chunks/fde89fd76ad6a3d0.css +3 -0
  68. package/dist/admin/_next/static/chunks/ff1a16fafef87110.js +1 -0
  69. package/dist/admin/_next/static/chunks/turbopack-a3d691c83d4b1778.js +4 -0
  70. package/dist/admin/_next/static/chunks/turbopack-e5185af8e7c716ca.js +4 -0
  71. package/dist/admin/_next/static/dcjrfD44GuB6g8bZ6BcFm/_buildManifest.js +11 -0
  72. package/dist/admin/_next/static/dcjrfD44GuB6g8bZ6BcFm/_clientMiddlewareManifest.json +1 -0
  73. package/dist/admin/_next/static/dcjrfD44GuB6g8bZ6BcFm/_ssgManifest.js +1 -0
  74. package/dist/admin/_next/static/fTEa8Scx922n-dMuqN3Vc/_buildManifest.js +11 -0
  75. package/dist/admin/_next/static/fTEa8Scx922n-dMuqN3Vc/_clientMiddlewareManifest.json +1 -0
  76. package/dist/admin/_next/static/fTEa8Scx922n-dMuqN3Vc/_ssgManifest.js +1 -0
  77. package/dist/admin/_next/static/kZNwyhHft01wPtJ_AvqQT/_buildManifest.js +11 -0
  78. package/dist/admin/_next/static/kZNwyhHft01wPtJ_AvqQT/_clientMiddlewareManifest.json +1 -0
  79. package/dist/admin/_next/static/kZNwyhHft01wPtJ_AvqQT/_ssgManifest.js +1 -0
  80. package/dist/admin/_next/static/kyVInC6N3DY6NWnjkLQ4J/_buildManifest.js +11 -0
  81. package/dist/admin/_next/static/kyVInC6N3DY6NWnjkLQ4J/_clientMiddlewareManifest.json +1 -0
  82. package/dist/admin/_next/static/kyVInC6N3DY6NWnjkLQ4J/_ssgManifest.js +1 -0
  83. package/dist/admin/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  84. package/dist/admin/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  85. package/dist/admin/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  86. package/dist/admin/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  87. package/dist/admin/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  88. package/dist/admin/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  89. package/dist/admin/_next/static/media/favicon.0b3bf435.ico +0 -0
  90. package/dist/admin/_next/static/twedXBdhyxpjS68UQoNAc/_buildManifest.js +11 -0
  91. package/dist/admin/_next/static/twedXBdhyxpjS68UQoNAc/_clientMiddlewareManifest.json +1 -0
  92. package/dist/admin/_next/static/twedXBdhyxpjS68UQoNAc/_ssgManifest.js +1 -0
  93. package/dist/admin/_not-found/__next._full.txt +14 -0
  94. package/dist/admin/_not-found/__next._head.txt +6 -0
  95. package/dist/admin/_not-found/__next._index.txt +5 -0
  96. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +5 -0
  97. package/dist/admin/_not-found/__next._not-found.txt +4 -0
  98. package/dist/admin/_not-found/__next._tree.txt +2 -0
  99. package/dist/admin/_not-found/index.html +1 -0
  100. package/dist/admin/_not-found/index.txt +14 -0
  101. package/dist/admin/databases/__next._full.txt +20 -0
  102. package/dist/admin/databases/__next._head.txt +6 -0
  103. package/dist/admin/databases/__next._index.txt +5 -0
  104. package/dist/admin/databases/__next._tree.txt +4 -0
  105. package/dist/admin/databases/__next.databases.__PAGE__.txt +9 -0
  106. package/dist/admin/databases/__next.databases.txt +4 -0
  107. package/dist/admin/databases/index.html +1 -0
  108. package/dist/admin/databases/index.txt +20 -0
  109. package/dist/admin/favicon.ico +0 -0
  110. package/dist/admin/file.svg +1 -0
  111. package/dist/admin/globe.svg +1 -0
  112. package/dist/admin/index.html +1 -0
  113. package/dist/admin/index.txt +20 -0
  114. package/dist/admin/next.svg +1 -0
  115. package/dist/admin/vercel.svg +1 -0
  116. package/dist/admin/window.svg +1 -0
  117. package/dist/cli.d.ts +3 -0
  118. package/dist/cli.d.ts.map +1 -0
  119. package/dist/cli.js +190523 -0
  120. package/dist/cli.js.map +1 -0
  121. package/dist/commands/check.d.ts +2 -0
  122. package/dist/commands/check.d.ts.map +1 -0
  123. package/dist/commands/check.js +104 -0
  124. package/dist/commands/check.js.map +1 -0
  125. package/dist/commands/clean.d.ts +2 -0
  126. package/dist/commands/clean.d.ts.map +1 -0
  127. package/dist/commands/clean.js +70 -0
  128. package/dist/commands/clean.js.map +1 -0
  129. package/dist/commands/deploy.d.ts +2 -0
  130. package/dist/commands/deploy.d.ts.map +1 -0
  131. package/dist/commands/deploy.js +11 -0
  132. package/dist/commands/deploy.js.map +1 -0
  133. package/dist/commands/dev.d.ts +2 -0
  134. package/dist/commands/dev.d.ts.map +1 -0
  135. package/dist/commands/dev.js +398 -0
  136. package/dist/commands/dev.js.map +1 -0
  137. package/dist/commands/docs.d.ts +2 -0
  138. package/dist/commands/docs.d.ts.map +1 -0
  139. package/dist/commands/docs.js +32 -0
  140. package/dist/commands/docs.js.map +1 -0
  141. package/dist/commands/exec.d.ts +2 -0
  142. package/dist/commands/exec.d.ts.map +1 -0
  143. package/dist/commands/exec.js +178 -0
  144. package/dist/commands/exec.js.map +1 -0
  145. package/dist/commands/init.d.ts +2 -0
  146. package/dist/commands/init.d.ts.map +1 -0
  147. package/dist/commands/init.js +339 -0
  148. package/dist/commands/init.js.map +1 -0
  149. package/dist/commands/psql.d.ts +2 -0
  150. package/dist/commands/psql.d.ts.map +1 -0
  151. package/dist/commands/psql.js +53 -0
  152. package/dist/commands/psql.js.map +1 -0
  153. package/dist/commands/secrets.d.ts +3 -0
  154. package/dist/commands/secrets.d.ts.map +1 -0
  155. package/dist/commands/secrets.js +136 -0
  156. package/dist/commands/secrets.js.map +1 -0
  157. package/dist/docs/builds.md +71 -0
  158. package/dist/docs/index.md +30 -0
  159. package/dist/docs/integrations/drizzle.md +83 -0
  160. package/dist/docs/integrations/nextjs.md +45 -0
  161. package/dist/docs/integrations/prisma.md +110 -0
  162. package/dist/docs/postgres.md +41 -0
  163. package/dist/docs/redis.md +33 -0
  164. package/dist/docs/secrets-config.md +141 -0
  165. package/dist/docs/services.md +325 -0
  166. package/dist/docs/storage.md +62 -0
  167. package/dist/docs/sync.md +66 -0
  168. package/dist/lib/dev/database-manager.d.ts +17 -0
  169. package/dist/lib/dev/database-manager.d.ts.map +1 -0
  170. package/dist/lib/dev/database-manager.js +114 -0
  171. package/dist/lib/dev/database-manager.js.map +1 -0
  172. package/dist/lib/dev/env-resolver.d.ts +14 -0
  173. package/dist/lib/dev/env-resolver.d.ts.map +1 -0
  174. package/dist/lib/dev/env-resolver.js +109 -0
  175. package/dist/lib/dev/env-resolver.js.map +1 -0
  176. package/dist/lib/dev/http-proxy.d.ts +11 -0
  177. package/dist/lib/dev/http-proxy.d.ts.map +1 -0
  178. package/dist/lib/dev/http-proxy.js +165 -0
  179. package/dist/lib/dev/http-proxy.js.map +1 -0
  180. package/dist/lib/dev/index.d.ts +11 -0
  181. package/dist/lib/dev/index.d.ts.map +1 -0
  182. package/dist/lib/dev/index.js +7 -0
  183. package/dist/lib/dev/index.js.map +1 -0
  184. package/dist/lib/dev/instance-state.d.ts +45 -0
  185. package/dist/lib/dev/instance-state.d.ts.map +1 -0
  186. package/dist/lib/dev/instance-state.js +213 -0
  187. package/dist/lib/dev/instance-state.js.map +1 -0
  188. package/dist/lib/dev/port-allocator.d.ts +5 -0
  189. package/dist/lib/dev/port-allocator.d.ts.map +1 -0
  190. package/dist/lib/dev/port-allocator.js +21 -0
  191. package/dist/lib/dev/port-allocator.js.map +1 -0
  192. package/dist/lib/dev/service-runner.d.ts +16 -0
  193. package/dist/lib/dev/service-runner.d.ts.map +1 -0
  194. package/dist/lib/dev/service-runner.js +61 -0
  195. package/dist/lib/dev/service-runner.js.map +1 -0
  196. package/dist/lib/secrets/index.d.ts +2 -0
  197. package/dist/lib/secrets/index.d.ts.map +1 -0
  198. package/dist/lib/secrets/index.js +2 -0
  199. package/dist/lib/secrets/index.js.map +1 -0
  200. package/dist/lib/secrets/parser.d.ts +37 -0
  201. package/dist/lib/secrets/parser.d.ts.map +1 -0
  202. package/dist/lib/secrets/parser.js +116 -0
  203. package/dist/lib/secrets/parser.js.map +1 -0
  204. package/package.json +54 -0
@@ -0,0 +1,141 @@
1
+ # Secrets and Configuration
2
+
3
+ Secrets and config let you parameterize values that services need. Use them to avoid hardcoding values in your `specific.hcl`.
4
+
5
+ ## When to use which
6
+
7
+ - **Secrets** - For sensitive information that should never be committed to version control: API keys, database passwords, signing keys, etc.
8
+ - **Config** - For non-sensitive values that may vary between environments: log levels, feature flags, URLs, etc.
9
+
10
+ ## Secrets
11
+
12
+ Declare secrets that your application needs. Values are stored separately from configuration in `specific.secrets` (gitignored).
13
+
14
+ ```hcl
15
+ secret "stripe_api_key" {}
16
+
17
+ secret "jwt_secret" {
18
+ generated = true
19
+ }
20
+
21
+ service "api" {
22
+ build = build.api
23
+ command = "./api"
24
+
25
+ endpoint {
26
+ public = true
27
+ }
28
+
29
+ env = {
30
+ STRIPE_API_KEY = secret.stripe_api_key
31
+ JWT_SECRET = secret.jwt_secret
32
+ }
33
+ }
34
+ ```
35
+
36
+ ### Secret fields
37
+
38
+ - `generated` - When `true`, auto-generates a random 64-character string if not manually set. Useful for internal secrets like JWT signing keys.
39
+ - `length` - Custom length for generated secrets (default: 64). Only applies when `generated = true`.
40
+
41
+ ### Setting secret values
42
+
43
+ For local development with `specific dev` or `specific exec`, use the CLI:
44
+
45
+ ```bash
46
+ specific secrets set stripe_api_key
47
+ ```
48
+
49
+ This prompts for the value interactively and stores it in `specific.secrets`. Production secrets are configured separately during deployment.
50
+
51
+ ### Generated vs manual secrets
52
+
53
+ - **Manual secrets** (no `generated` flag) - Must be set via `specific secrets set`. Error on startup if missing.
54
+ - **Generated secrets** (`generated = true`) - Auto-created on first run if not set. You can still override manually.
55
+
56
+ ## Config
57
+
58
+ Parameterize non-sensitive configuration values across environments.
59
+
60
+ ```hcl
61
+ config "log_level" {
62
+ default = "info"
63
+ }
64
+
65
+ service "api" {
66
+ build = build.api
67
+ command = "./api"
68
+
69
+ endpoint {
70
+ public = true
71
+ }
72
+
73
+ env = {
74
+ LOG_LEVEL = config.log_level
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Config fields
80
+
81
+ - `default` - Default value used if not overridden by an environment.
82
+
83
+ ### Environment overrides
84
+
85
+ Override config values per environment:
86
+
87
+ ```hcl
88
+ config "log_level" {
89
+ default = "info"
90
+ }
91
+
92
+ environment "production" {
93
+ config = {
94
+ log_level = "warn"
95
+ }
96
+ }
97
+
98
+ environment "staging" {
99
+ config = {
100
+ log_level = "debug"
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## Example
106
+
107
+ ```hcl
108
+ # External API key - must be set manually, sensitive
109
+ secret "stripe_api_key" {}
110
+
111
+ # Internal signing key - auto-generate, sensitive
112
+ secret "jwt_secret" {
113
+ generated = true
114
+ }
115
+
116
+ # Log level - not sensitive, varies by environment
117
+ config "log_level" {
118
+ default = "info"
119
+ }
120
+
121
+ service "api" {
122
+ build = build.api
123
+ command = "./api"
124
+
125
+ endpoint {
126
+ public = true
127
+ }
128
+
129
+ env = {
130
+ STRIPE_API_KEY = secret.stripe_api_key
131
+ JWT_SECRET = secret.jwt_secret
132
+ LOG_LEVEL = config.log_level
133
+ }
134
+ }
135
+
136
+ environment "production" {
137
+ config = {
138
+ log_level = "warn"
139
+ }
140
+ }
141
+ ```
@@ -0,0 +1,325 @@
1
+ # Services
2
+
3
+ Services define how to run the code and connect it to other parts of the infrastructure, both in production and in local development. All configuration for the app is handled through environment variables, which the code should read from.
4
+
5
+ ## Dynamic services
6
+
7
+ Run a server process exposed via HTTP. TLS is handled automatically.
8
+
9
+ ```hcl
10
+ build "api" {
11
+ base = "go"
12
+ command = "go build -o api"
13
+ }
14
+
15
+ service "api" {
16
+ build = build.api
17
+ command = "./api"
18
+
19
+ endpoint {
20
+ public = true
21
+ }
22
+
23
+ env = {
24
+ PORT = port
25
+ }
26
+ }
27
+ ```
28
+
29
+ - `command` - Command to start the server
30
+ - `endpoint` - Defines a network endpoint (see Endpoints below)
31
+ - `port` - Reference to the auto-assigned port (pass this to your server)
32
+
33
+ ## Endpoints
34
+
35
+ Endpoints define how a service is accessible over the network.
36
+
37
+ ### Single endpoint (most common)
38
+
39
+ ```hcl
40
+ service "api" {
41
+ build = build.api
42
+ command = "./api"
43
+
44
+ endpoint {
45
+ public = true
46
+ }
47
+
48
+ env = {
49
+ PORT = port
50
+ }
51
+ }
52
+ ```
53
+
54
+ - `public = true` - Makes the endpoint publicly accessible via HTTPS
55
+ - Omitting `public` (or `public = false`) keeps the endpoint internal-only
56
+
57
+ ### Multiple named endpoints
58
+
59
+ A service can expose multiple endpoints on different ports:
60
+
61
+ ```hcl
62
+ service "api" {
63
+ build = build.api
64
+ command = "./api"
65
+
66
+ endpoint "main" {
67
+ public = true
68
+ }
69
+
70
+ endpoint "admin" {}
71
+
72
+ env = {
73
+ MAIN_PORT = endpoint.main.port
74
+ ADMIN_PORT = endpoint.admin.port
75
+ }
76
+ }
77
+ ```
78
+
79
+ When using multiple endpoints, you must use `endpoint.<name>.port` instead of `port` to reference each endpoint's port.
80
+
81
+ ### Implicit endpoints
82
+
83
+ If a service uses `port` in its env vars but has no explicit endpoint blocks, an implicit internal endpoint is created:
84
+
85
+ ```hcl
86
+ service "worker" {
87
+ build = build.worker
88
+ command = "./worker"
89
+
90
+ env = {
91
+ PORT = port # Creates an implicit internal endpoint
92
+ }
93
+ }
94
+ ```
95
+
96
+ ## Inter-service communication
97
+
98
+ Services can reference other services' endpoints to communicate with each other:
99
+
100
+ ```hcl
101
+ service "api" {
102
+ build = build.api
103
+ command = "./api"
104
+
105
+ endpoint {
106
+ public = true
107
+ }
108
+
109
+ env = {
110
+ PORT = port
111
+ }
112
+ }
113
+
114
+ service "worker" {
115
+ build = build.worker
116
+ command = "./worker"
117
+
118
+ env = {
119
+ API_URL = service.api.url # http://localhost:PORT in dev, http://api:80 in prod
120
+ }
121
+ }
122
+ ```
123
+
124
+ Available service reference attributes:
125
+
126
+ - `service.<name>.url` - Full URL (e.g., `http://localhost:3000`)
127
+ - `service.<name>.host` - Host only (e.g., `localhost`)
128
+ - `service.<name>.port` - Port only (e.g., `3000`)
129
+
130
+ For services with multiple named endpoints, you must specify the endpoint:
131
+
132
+ ```hcl
133
+ env = {
134
+ MAIN_URL = service.api.endpoint.main.url
135
+ ADMIN_URL = service.api.endpoint.admin.url
136
+ }
137
+ ```
138
+
139
+ ## Workers
140
+
141
+ Background processes that don't expose HTTP endpoints.
142
+
143
+ ```hcl
144
+ build "worker" {
145
+ base = "node"
146
+ command = "npm run build"
147
+ }
148
+
149
+ service "worker" {
150
+ build = build.worker
151
+ command = "npm run worker"
152
+ }
153
+ ```
154
+
155
+ ## Environment variables
156
+
157
+ ```hcl
158
+ service "api" {
159
+ build = build.api
160
+ command = "./api"
161
+
162
+ endpoint {
163
+ public = true
164
+ }
165
+
166
+ env = {
167
+ PORT = port
168
+ NODE_ENV = "production"
169
+ DATABASE_URL = postgres.main.url
170
+ }
171
+ }
172
+ ```
173
+
174
+ ## Service dev configuration
175
+
176
+ Override how a service runs in development. If the referenced build has no `dev` block, it is skipped.
177
+
178
+ ```hcl
179
+ build "nextjs" {
180
+ base = "node"
181
+ command = "npm run build"
182
+ # No dev block = skipped in development
183
+ }
184
+
185
+ service "web" {
186
+ build = build.nextjs
187
+ command = "npm start"
188
+
189
+ endpoint {
190
+ public = true
191
+ }
192
+
193
+ env = {
194
+ PORT = port
195
+ }
196
+
197
+ dev {
198
+ command = "npm run dev" # Handles building + serving with hot reload
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## Dev-only services
204
+
205
+ Services that only run during local development, not deployed to production. Useful for running local versions of external cloud services like Temporal, LocalStack, or mock servers.
206
+
207
+ A service is dev-only if it has a `dev.command` but no top-level `command`:
208
+
209
+ ```hcl
210
+ service "temporal" {
211
+ dev {
212
+ command = "temporal server start-dev"
213
+ }
214
+ }
215
+
216
+ service "worker" {
217
+ build = build.worker
218
+ command = "node worker.js"
219
+
220
+ env = {
221
+ TEMPORAL_URL = secret.temporal_url # Production URL from secret
222
+ }
223
+
224
+ dev {
225
+ command = "node --watch worker.js"
226
+ env = {
227
+ TEMPORAL_URL = service.temporal.url # Override with local URL in dev
228
+ }
229
+ }
230
+ }
231
+
232
+ secret "temporal_url" {}
233
+ ```
234
+
235
+ Dev-only services:
236
+ - Cannot have a `build` reference (they run arbitrary commands)
237
+ - Are automatically excluded from production deployment
238
+ - Can define endpoints that other services reference during development
239
+
240
+ ## Deploy hooks
241
+
242
+ Run commands before or after deploying a service.
243
+
244
+ **Database migrations should use `pre_deploy` hooks.** This ensures migrations complete before the new code starts, and if they fail, the deployment is automatically aborted.
245
+
246
+ ```hcl
247
+ build "api" {
248
+ base = "node"
249
+ command = "npm run build"
250
+ }
251
+
252
+ service "api" {
253
+ build = build.api
254
+ command = "node dist/index.js"
255
+
256
+ endpoint {
257
+ public = true
258
+ }
259
+
260
+ env = {
261
+ PORT = port
262
+ DATABASE_URL = postgres.main.url
263
+ }
264
+
265
+ pre_deploy {
266
+ command = "npm run db:migrate"
267
+ }
268
+
269
+ post_deploy {
270
+ command = "npm run cache:warm"
271
+ }
272
+ }
273
+
274
+ postgres "main" {}
275
+ ```
276
+
277
+ - `pre_deploy` - Runs before the service is deployed (e.g., database migrations)
278
+ - `post_deploy` - Runs after the service is deployed (e.g., cache warming)
279
+
280
+ Hooks run as Kubernetes Jobs using the same container and environment variables as the service. If a hook fails, the deployment is aborted.
281
+
282
+ ### Database migrations
283
+
284
+ Always add a `pre_deploy` hook for database migrations. The hook runs **before** new service instances start, ensuring:
285
+
286
+ - The database schema is updated before new code runs
287
+ - If migrations fail, the deployment is aborted (no broken state)
288
+ - Migrations have access to `DATABASE_URL` and other service env vars
289
+
290
+ In development, use `specific exec ...` to run migrations/push database changes whenever the schema is changed. Do so automatically unless the user instructs otherwise. For example: `specific exec api -- npm run db:push`.
291
+
292
+ ## Serving static files
293
+
294
+ To serve static files, run a web server as a dynamic service. For example, using `npx serve`:
295
+
296
+ ```hcl
297
+ build "spa" {
298
+ base = "node"
299
+ command = "npm run build"
300
+ }
301
+
302
+ service "frontend" {
303
+ build = build.spa
304
+ command = "npx serve dist -l $PORT"
305
+
306
+ endpoint {
307
+ public = true
308
+ }
309
+
310
+ env = {
311
+ PORT = port
312
+ }
313
+
314
+ dev {
315
+ command = "npm run dev" # Use your framework's dev server
316
+ }
317
+ }
318
+ ```
319
+
320
+ ---
321
+
322
+ Related topics:
323
+ - Run `specific docs builds` for build configuration
324
+ - Run `specific docs exec` for running one-off commands during development
325
+ - Run `specific docs postgres` for database configuration
@@ -0,0 +1,62 @@
1
+ # Storage (S3-compatible)
2
+
3
+ Managed S3-compatible object storage.
4
+
5
+ ```hcl
6
+ storage "uploads" {}
7
+
8
+ storage "assets" {}
9
+ ```
10
+
11
+ Reference storage attributes in env blocks:
12
+
13
+ ```hcl
14
+ service "api" {
15
+ build = build.api
16
+ command = "./api"
17
+
18
+ endpoint {
19
+ public = true
20
+ }
21
+
22
+ env = {
23
+ S3_ENDPOINT = storage.uploads.endpoint
24
+ S3_ACCESS_KEY = storage.uploads.access_key
25
+ S3_SECRET_KEY = storage.uploads.secret_key
26
+ S3_BUCKET = storage.uploads.bucket
27
+ }
28
+ }
29
+
30
+ storage "uploads" {}
31
+ ```
32
+
33
+ ## Available storage attributes
34
+
35
+ - `endpoint` - S3-compatible endpoint URL (e.g., `http://127.0.0.1:5000`)
36
+ - `access_key` - Access key for authentication
37
+ - `secret_key` - Secret key for authentication
38
+ - `bucket` - Bucket name
39
+
40
+ ## Example using AWS SDK (JavaScript)
41
+
42
+ ```javascript
43
+ import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
44
+
45
+ const s3 = new S3Client({
46
+ endpoint: process.env.S3_ENDPOINT,
47
+ region: "us-east-1", // Required but ignored locally
48
+ credentials: {
49
+ accessKeyId: process.env.S3_ACCESS_KEY,
50
+ secretAccessKey: process.env.S3_SECRET_KEY,
51
+ },
52
+ forcePathStyle: true, // Required for local S3-compatible servers
53
+ });
54
+
55
+ await s3.send(
56
+ new PutObjectCommand({
57
+ Bucket: process.env.S3_BUCKET,
58
+ Key: "myfile.txt",
59
+ Body: "Hello, world!",
60
+ })
61
+ );
62
+ ```
@@ -0,0 +1,66 @@
1
+ # Real-time Sync
2
+
3
+ For Postgres databases, you can enable real-time data synchronization. This enables building real-time and local-first applications.
4
+
5
+ Sync is powered by Electric, a sync engine that streams changes from Postgres to clients using a plain HTTP API. It uses a proxy-based architecture where your backend proxies requests after handling authentication and authorization.
6
+
7
+ ## Enabling sync
8
+
9
+ Reference `sync.url` and `sync.secret` in your service env:
10
+
11
+ ```hcl
12
+ postgres "main" {}
13
+
14
+ service "api" {
15
+ command = "node index.js"
16
+
17
+ endpoint {
18
+ public = true
19
+ }
20
+
21
+ env = {
22
+ DATABASE_URL = postgres.main.url
23
+ DATABASE_SYNC_URL = postgres.main.sync.url
24
+ DATABASE_SYNC_SECRET = postgres.main.sync.secret
25
+ }
26
+ }
27
+ ```
28
+
29
+ When these references are present, Specific automatically starts a sync engine connected to your Postgres database during `specific dev`.
30
+
31
+ ## Available sync attributes
32
+
33
+ - `sync.url` - Sync engine HTTP endpoint URL (e.g., `http://127.0.0.1:5133`)
34
+ - `sync.secret` - Secret for authenticating requests to the sync engine. This should be passed as the `secret` query parameter from the backend to the Electric API.
35
+
36
+ ## How sync works
37
+
38
+ The sync engine streams "shapes" of data from Postgres to clients:
39
+
40
+ 1. Your backend proxies shape requests to the sync engine (handles auth/authz)
41
+ 2. The sync engine streams the initial data and subsequent changes
42
+ 3. Clients receive real-time updates over HTTP
43
+
44
+ For implementation details, see the Electric documentation:
45
+
46
+ - Authentication and proxying: https://electric-sql.com/docs/guides/auth
47
+ - Shapes and client usage: https://electric-sql.com/docs/guides/shapes
48
+ - Handling writes: https://electric-sql.com/docs/guides/writes
49
+
50
+ ## Using the Electric TypeScript SDK
51
+
52
+ When using `ShapeStream` from the Electric TypeScript SDK, a full URL is required (not a relative URL). In browsers, derive the full URL from `window.location.origin` instead of using a relative one:
53
+
54
+ ```typescript
55
+ import { ShapeStream } from "@electric-sql/client";
56
+
57
+ const stream = new ShapeStream({
58
+ url: `${window.location.origin}/api/sync/items`,
59
+ });
60
+ ```
61
+
62
+ This ensures the client works correctly regardless of the deployment environment.
63
+
64
+ ---
65
+
66
+ Run `specific docs postgres` for database configuration.
@@ -0,0 +1,17 @@
1
+ import type { Database } from "@specific/config";
2
+ export interface DatabaseInstance {
3
+ name: string;
4
+ engine: "postgres" | "redis" | "object_store";
5
+ port: number;
6
+ url: string;
7
+ host: string;
8
+ user: string;
9
+ password: string;
10
+ dbName: string;
11
+ endpoint?: string;
12
+ accessKey?: string;
13
+ secretKey?: string;
14
+ stop(): Promise<void>;
15
+ }
16
+ export declare function startDatabase(db: Database, port: number, dataDir?: string): Promise<DatabaseInstance>;
17
+ //# sourceMappingURL=database-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-manager.d.ts","sourceRoot":"","sources":["../../../src/lib/dev/database-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IAEf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAQ3B"}