vyft 0.4.0-alpha → 0.4.2-alpha

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 (189) hide show
  1. package/LICENSE +191 -21
  2. package/README.md +3 -49
  3. package/dist/commands/context/add.d.ts +4 -0
  4. package/dist/commands/context/add.d.ts.map +1 -0
  5. package/dist/commands/context/add.js +98 -0
  6. package/dist/commands/context/add.js.map +1 -0
  7. package/dist/commands/context/index.d.ts +4 -0
  8. package/dist/commands/context/index.d.ts.map +1 -0
  9. package/dist/commands/context/index.js +12 -0
  10. package/dist/commands/context/index.js.map +1 -0
  11. package/dist/commands/context/list.d.ts +4 -0
  12. package/dist/commands/context/list.d.ts.map +1 -0
  13. package/dist/commands/context/list.js +25 -0
  14. package/dist/commands/context/list.js.map +1 -0
  15. package/dist/commands/context/remove.d.ts +4 -0
  16. package/dist/commands/context/remove.d.ts.map +1 -0
  17. package/dist/commands/context/remove.js +36 -0
  18. package/dist/commands/context/remove.js.map +1 -0
  19. package/dist/commands/context/use.d.ts +4 -0
  20. package/dist/commands/context/use.d.ts.map +1 -0
  21. package/dist/commands/context/use.js +32 -0
  22. package/dist/commands/context/use.js.map +1 -0
  23. package/dist/commands/deploy.d.ts +4 -0
  24. package/dist/commands/deploy.d.ts.map +1 -0
  25. package/dist/commands/deploy.js +55 -0
  26. package/dist/commands/deploy.js.map +1 -0
  27. package/dist/commands/destroy.d.ts +4 -0
  28. package/dist/commands/destroy.d.ts.map +1 -0
  29. package/dist/commands/destroy.js +70 -0
  30. package/dist/commands/destroy.js.map +1 -0
  31. package/dist/commands/diff.d.ts +4 -0
  32. package/dist/commands/diff.d.ts.map +1 -0
  33. package/dist/commands/diff.js +52 -0
  34. package/dist/commands/diff.js.map +1 -0
  35. package/dist/commands/init.d.ts +4 -0
  36. package/dist/commands/init.d.ts.map +1 -0
  37. package/dist/commands/init.js +92 -0
  38. package/dist/commands/init.js.map +1 -0
  39. package/dist/commands/local/detect.d.ts +7 -0
  40. package/dist/commands/local/detect.d.ts.map +1 -0
  41. package/dist/commands/local/detect.js +146 -0
  42. package/dist/commands/local/detect.js.map +1 -0
  43. package/dist/commands/local/dev.d.ts +4 -0
  44. package/dist/commands/local/dev.d.ts.map +1 -0
  45. package/dist/commands/local/dev.js +387 -0
  46. package/dist/commands/local/dev.js.map +1 -0
  47. package/dist/commands/local/down.d.ts +4 -0
  48. package/dist/commands/local/down.d.ts.map +1 -0
  49. package/dist/commands/local/down.js +61 -0
  50. package/dist/commands/local/down.js.map +1 -0
  51. package/dist/commands/local/index.d.ts +4 -0
  52. package/dist/commands/local/index.d.ts.map +1 -0
  53. package/dist/commands/local/index.js +12 -0
  54. package/dist/commands/local/index.js.map +1 -0
  55. package/dist/commands/local/reset.d.ts +4 -0
  56. package/dist/commands/local/reset.d.ts.map +1 -0
  57. package/dist/commands/local/reset.js +67 -0
  58. package/dist/commands/local/reset.js.map +1 -0
  59. package/dist/commands/local/up.d.ts +4 -0
  60. package/dist/commands/local/up.d.ts.map +1 -0
  61. package/dist/commands/local/up.js +58 -0
  62. package/dist/commands/local/up.js.map +1 -0
  63. package/dist/commands/refresh.d.ts +4 -0
  64. package/dist/commands/refresh.d.ts.map +1 -0
  65. package/dist/commands/refresh.js +39 -0
  66. package/dist/commands/refresh.js.map +1 -0
  67. package/dist/config.d.ts +8 -0
  68. package/dist/config.d.ts.map +1 -0
  69. package/dist/config.js +65 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/contexts.d.ts +21 -0
  72. package/dist/contexts.d.ts.map +1 -0
  73. package/dist/contexts.js +72 -0
  74. package/dist/contexts.js.map +1 -0
  75. package/dist/index.d.ts +2 -9
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +23 -7
  78. package/dist/index.js.map +1 -0
  79. package/dist/lib.d.ts +7 -0
  80. package/dist/lib.d.ts.map +1 -0
  81. package/dist/lib.js +6 -0
  82. package/dist/lib.js.map +1 -0
  83. package/dist/providers.d.ts +9 -0
  84. package/dist/providers.d.ts.map +1 -0
  85. package/dist/providers.js +41 -0
  86. package/dist/providers.js.map +1 -0
  87. package/dist/runtime.d.ts +18 -15
  88. package/dist/runtime.d.ts.map +1 -0
  89. package/dist/runtime.js +154 -0
  90. package/dist/runtime.js.map +1 -0
  91. package/dist/runtime.test.d.ts +2 -0
  92. package/dist/runtime.test.d.ts.map +1 -0
  93. package/dist/runtime.test.js +119 -0
  94. package/dist/runtime.test.js.map +1 -0
  95. package/dist/utils/fs.d.ts +4 -0
  96. package/dist/utils/fs.d.ts.map +1 -0
  97. package/dist/utils/fs.js +33 -0
  98. package/dist/utils/fs.js.map +1 -0
  99. package/dist/utils/pm.d.ts +3 -0
  100. package/dist/utils/pm.d.ts.map +1 -0
  101. package/dist/utils/pm.js +17 -0
  102. package/dist/utils/pm.js.map +1 -0
  103. package/dist/utils/prompts.d.ts +2 -0
  104. package/dist/utils/prompts.d.ts.map +1 -0
  105. package/dist/utils/prompts.js +6 -0
  106. package/dist/utils/prompts.js.map +1 -0
  107. package/dist/utils/templates.d.ts +3 -0
  108. package/dist/utils/templates.d.ts.map +1 -0
  109. package/dist/utils/templates.js +48 -0
  110. package/dist/utils/templates.js.map +1 -0
  111. package/package.json +31 -48
  112. package/templates/bun/index.ts +8 -0
  113. package/templates/bun/package.json +15 -0
  114. package/templates/bun/tsconfig.json +15 -0
  115. package/templates/bun/vyft.config.ts +3 -0
  116. package/dist/build.d.ts +0 -12
  117. package/dist/build.js +0 -44
  118. package/dist/cli.d.ts +0 -2
  119. package/dist/cli.js +0 -842
  120. package/dist/context.d.ts +0 -39
  121. package/dist/context.js +0 -101
  122. package/dist/docker.d.ts +0 -69
  123. package/dist/docker.js +0 -958
  124. package/dist/exec.d.ts +0 -2
  125. package/dist/exec.js +0 -28
  126. package/dist/init.d.ts +0 -1
  127. package/dist/init.js +0 -117
  128. package/dist/interpolate.d.ts +0 -13
  129. package/dist/interpolate.js +0 -19
  130. package/dist/local/dev.d.ts +0 -31
  131. package/dist/local/dev.js +0 -109
  132. package/dist/local/index.d.ts +0 -2
  133. package/dist/local/index.js +0 -2
  134. package/dist/local/runtime.d.ts +0 -61
  135. package/dist/local/runtime.js +0 -391
  136. package/dist/logger.d.ts +0 -2
  137. package/dist/logger.js +0 -10
  138. package/dist/proxy.d.ts +0 -16
  139. package/dist/proxy.js +0 -0
  140. package/dist/resource.d.ts +0 -181
  141. package/dist/resource.js +0 -45
  142. package/dist/services/index.d.ts +0 -26
  143. package/dist/services/index.js +0 -35
  144. package/dist/services/minio.d.ts +0 -36
  145. package/dist/services/minio.js +0 -53
  146. package/dist/services/mongo.d.ts +0 -28
  147. package/dist/services/mongo.js +0 -45
  148. package/dist/services/mysql.d.ts +0 -28
  149. package/dist/services/mysql.js +0 -44
  150. package/dist/services/nats.d.ts +0 -26
  151. package/dist/services/nats.js +0 -38
  152. package/dist/services/postgres.d.ts +0 -28
  153. package/dist/services/postgres.js +0 -45
  154. package/dist/services/rabbitmq.d.ts +0 -28
  155. package/dist/services/rabbitmq.js +0 -44
  156. package/dist/services/redis.d.ts +0 -28
  157. package/dist/services/redis.js +0 -49
  158. package/dist/services/storage.d.ts +0 -39
  159. package/dist/services/storage.js +0 -94
  160. package/dist/swarm/factories.d.ts +0 -16
  161. package/dist/swarm/factories.js +0 -63
  162. package/dist/swarm/index.d.ts +0 -20
  163. package/dist/swarm/index.js +0 -5
  164. package/dist/swarm/proxy.d.ts +0 -24
  165. package/dist/swarm/proxy.js +0 -339
  166. package/dist/swarm/types.d.ts +0 -26
  167. package/dist/swarm/types.js +0 -0
  168. package/dist/symbols.d.ts +0 -15
  169. package/dist/symbols.js +0 -4
  170. package/templates/fullstack/apps/api/Dockerfile +0 -22
  171. package/templates/fullstack/apps/api/package.json +0 -26
  172. package/templates/fullstack/apps/api/src/auth.ts +0 -21
  173. package/templates/fullstack/apps/api/src/db.ts +0 -16
  174. package/templates/fullstack/apps/api/src/index.ts +0 -17
  175. package/templates/fullstack/apps/api/src/router.ts +0 -11
  176. package/templates/fullstack/apps/api/src/schema.ts +0 -11
  177. package/templates/fullstack/apps/api/tsconfig.json +0 -8
  178. package/templates/fullstack/apps/web/index.html +0 -12
  179. package/templates/fullstack/apps/web/package.json +0 -21
  180. package/templates/fullstack/apps/web/src/app.tsx +0 -8
  181. package/templates/fullstack/apps/web/src/main.tsx +0 -9
  182. package/templates/fullstack/apps/web/tsconfig.json +0 -7
  183. package/templates/fullstack/apps/web/vite.config.ts +0 -14
  184. package/templates/fullstack/dockerignore +0 -7
  185. package/templates/fullstack/gitignore +0 -3
  186. package/templates/fullstack/package.json +0 -14
  187. package/templates/fullstack/pnpm-workspace.yaml +0 -2
  188. package/templates/fullstack/tsconfig.json +0 -11
  189. package/templates/fullstack/vyft.config.ts +0 -22
@@ -1,391 +0,0 @@
1
- import { randomBytes } from "node:crypto";
2
- import { PassThrough } from "node:stream";
3
- import Docker from "dockerode";
4
- import { logger as defaultLogger } from "../logger.js";
5
- import { isInterpolation, isReference } from "../resource.js";
6
- /**
7
- * Docker runtime for local development.
8
- *
9
- * Runs managed infrastructure (databases, caches, etc.) as plain Docker
10
- * containers with ports published to localhost. Secrets are generated
11
- * in-memory and injected as environment variables.
12
- */
13
- export class LocalRuntime {
14
- docker;
15
- project;
16
- log;
17
- secretValues = new Map();
18
- containers = [];
19
- networkName;
20
- constructor(project, opts) {
21
- this.docker = new Docker({ socketPath: "/var/run/docker.sock" });
22
- this.project = project;
23
- this.networkName = `${project}-dev`;
24
- this.log = (opts?.parentLogger ?? defaultLogger).child({
25
- component: "local-runtime",
26
- project,
27
- });
28
- }
29
- /** Create bridge network for inter-container DNS. */
30
- async ensureInfrastructure() {
31
- const networks = await this.docker.listNetworks({
32
- filters: JSON.stringify({ name: [this.networkName] }),
33
- });
34
- const exists = networks.some((n) => n.Name === this.networkName);
35
- if (!exists) {
36
- this.log.debug({ network: this.networkName }, "creating bridge network");
37
- await this.docker.createNetwork({
38
- Name: this.networkName,
39
- Driver: "bridge",
40
- Labels: {
41
- "vyft.dev": "true",
42
- "vyft.project": this.project,
43
- },
44
- });
45
- }
46
- }
47
- /** Generate a random secret value and store it in memory. */
48
- createSecret(secret) {
49
- const length = secret.config.length || 32;
50
- const value = randomBytes(length).toString("base64url");
51
- this.secretValues.set(secret.id, value);
52
- this.log.debug({ secretName: secret.id }, "secret generated");
53
- }
54
- /** Get the generated value for a secret. */
55
- getSecretValue(id) {
56
- return this.secretValues.get(id);
57
- }
58
- /** Create a Docker volume for persistent data. */
59
- async createVolume(volume) {
60
- const name = volume.id;
61
- try {
62
- await this.docker.getVolume(name).inspect();
63
- this.log.debug({ volumeName: name }, "volume already exists");
64
- return;
65
- }
66
- catch {
67
- // Volume doesn't exist, create it
68
- }
69
- await this.docker.createVolume({
70
- Name: name,
71
- Labels: {
72
- "vyft.dev": "true",
73
- "vyft.project": this.project,
74
- },
75
- });
76
- this.log.debug({ volumeName: name }, "volume created");
77
- }
78
- /**
79
- * Resolve env vars for a managed service container.
80
- *
81
- * Secrets become plain `KEY=<value>` env vars.
82
- * Interpolations are fully resolved with generated secret values.
83
- */
84
- resolveEnv(env) {
85
- const result = [];
86
- for (const [key, value] of Object.entries(env)) {
87
- if (typeof value === "string") {
88
- result.push(`${key}=${value}`);
89
- }
90
- else if (isReference(value)) {
91
- const secretValue = this.secretValues.get(value.id);
92
- if (!secretValue) {
93
- throw new Error(`Secret ${value.id} not yet generated`);
94
- }
95
- result.push(`${key}=${secretValue}`);
96
- }
97
- else if (isInterpolation(value)) {
98
- const parts = [];
99
- for (let i = 0; i < value.strings.length; i++) {
100
- parts.push(value.strings[i]);
101
- if (i < value.values.length) {
102
- const v = value.values[i];
103
- if (isReference(v)) {
104
- const secretValue = this.secretValues.get(v.id);
105
- if (!secretValue) {
106
- throw new Error(`Secret ${v.id} not yet generated`);
107
- }
108
- parts.push(secretValue);
109
- }
110
- else {
111
- parts.push(v);
112
- }
113
- }
114
- }
115
- result.push(`${key}=${parts.join("")}`);
116
- }
117
- }
118
- return result;
119
- }
120
- /**
121
- * Build an entrypoint wrapper that writes secret values to /run/secrets/
122
- * before exec'ing the original entrypoint.
123
- *
124
- * This is needed because some factory images (e.g. redis) read passwords
125
- * from `/run/secrets/*-password` via shell glob.
126
- */
127
- buildSecretInit(secrets, originalEntrypoint, originalCmd) {
128
- if (secrets.length === 0) {
129
- return { entrypoint: originalEntrypoint, cmd: originalCmd };
130
- }
131
- const writeCommands = secrets
132
- .map((s) => `printf '%s' "$${s.envVar}" > /run/secrets/${s.name}`)
133
- .join(" && ");
134
- // Build the original command to exec
135
- const original = [...originalEntrypoint, ...originalCmd];
136
- const execCmd = original.length > 0 ? `exec ${original.map(shellEscape).join(" ")}` : "";
137
- const script = `mkdir -p /run/secrets && ${writeCommands}${execCmd ? ` && ${execCmd}` : ""}`;
138
- return {
139
- entrypoint: ["sh", "-c", script],
140
- cmd: [],
141
- };
142
- }
143
- /** Pull, create, and start a container for a managed service. */
144
- async createService(service) {
145
- const config = service.config;
146
- const image = typeof config.image === "string" ? config.image : `${service.id}:latest`;
147
- const port = config.port || 3000;
148
- // Stop and remove existing container if present
149
- await this.removeContainer(service.id);
150
- // Pull image
151
- this.log.debug({ image }, "pulling image");
152
- const pullStream = await this.docker.pull(image);
153
- await new Promise((resolve, reject) => {
154
- this.docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve());
155
- });
156
- // Resolve env
157
- const envList = config.env ? this.resolveEnv(config.env) : [];
158
- // Collect secrets that need /run/secrets/ files
159
- const secretMappings = [];
160
- if (config.env) {
161
- let idx = 0;
162
- for (const [, value] of Object.entries(config.env)) {
163
- if (isReference(value)) {
164
- const envVar = `__VYFT_S${idx}`;
165
- secretMappings.push({
166
- name: value.id.replace(/^.*-/, ""), // short name e.g. "db-password" -> "password"
167
- envVar,
168
- });
169
- // The full id as a file too, for glob patterns like *-password
170
- secretMappings.push({
171
- name: value.id,
172
- envVar,
173
- });
174
- const secretVal = this.secretValues.get(value.id);
175
- if (secretVal) {
176
- envList.push(`${envVar}=${secretVal}`);
177
- }
178
- idx++;
179
- }
180
- }
181
- }
182
- // Inspect image for default entrypoint/cmd
183
- const imageInfo = await this.docker.getImage(image).inspect();
184
- const rawEntrypoint = imageInfo.Config?.Entrypoint ?? [];
185
- const defaultEntrypoint = Array.isArray(rawEntrypoint)
186
- ? rawEntrypoint
187
- : [rawEntrypoint];
188
- const rawCmd = imageInfo.Config?.Cmd ?? [];
189
- const defaultCmd = Array.isArray(rawCmd) ? rawCmd : [rawCmd];
190
- // Use config.command if specified, otherwise image defaults
191
- const userCmd = config.command ?? defaultCmd;
192
- const { entrypoint, cmd } = this.buildSecretInit(secretMappings, defaultEntrypoint, userCmd);
193
- // Build volume mounts
194
- const mounts = config.volumes?.map(({ volume, mount }) => ({
195
- Type: "volume",
196
- Source: volume.id,
197
- Target: mount,
198
- }));
199
- // Health check
200
- const healthCheck = config.healthCheck
201
- ? {
202
- Test: ["CMD", ...config.healthCheck.command],
203
- Interval: config.healthCheck.interval
204
- ? parseDurationNs(config.healthCheck.interval)
205
- : undefined,
206
- Timeout: config.healthCheck.timeout
207
- ? parseDurationNs(config.healthCheck.timeout)
208
- : undefined,
209
- Retries: config.healthCheck.retries,
210
- StartPeriod: config.healthCheck.startPeriod
211
- ? parseDurationNs(config.healthCheck.startPeriod)
212
- : undefined,
213
- }
214
- : undefined;
215
- const containerName = `${service.id}-dev`;
216
- this.log.debug({ containerName, image, port }, "creating container");
217
- const container = await this.docker.createContainer({
218
- name: containerName,
219
- Image: image,
220
- Entrypoint: entrypoint.length > 0 ? entrypoint : undefined,
221
- Cmd: cmd.length > 0 ? cmd : undefined,
222
- Env: envList,
223
- ExposedPorts: { [`${port}/tcp`]: {} },
224
- Healthcheck: healthCheck,
225
- Labels: {
226
- "vyft.dev": "true",
227
- "vyft.project": this.project,
228
- "vyft.service": service.id,
229
- },
230
- HostConfig: {
231
- PortBindings: {
232
- [`${port}/tcp`]: [{ HostIp: "127.0.0.1", HostPort: `${port}` }],
233
- },
234
- NetworkMode: this.networkName,
235
- Mounts: mounts,
236
- },
237
- });
238
- await container.start();
239
- this.containers.push({
240
- id: service.id,
241
- name: containerName,
242
- containerId: container.id,
243
- });
244
- this.log.debug({ containerName, port }, "container started");
245
- return port;
246
- }
247
- /** Wait for a container to pass its health check. */
248
- async waitForHealthy(id, timeoutMs = 120000) {
249
- const info = this.containers.find((c) => c.id === id);
250
- if (!info)
251
- return;
252
- const start = performance.now();
253
- const interval = 1000;
254
- this.log.debug({ resourceId: id }, "waiting for healthy");
255
- while (performance.now() - start < timeoutMs) {
256
- const container = this.docker.getContainer(info.containerId);
257
- const data = await container.inspect();
258
- const health = data.State?.Health?.Status;
259
- if (health === "healthy") {
260
- this.log.debug({ resourceId: id }, "container is healthy");
261
- return;
262
- }
263
- if (health === undefined) {
264
- // No health check configured, just check if running
265
- if (data.State?.Running) {
266
- this.log.debug({ resourceId: id }, "container running (no health check)");
267
- return;
268
- }
269
- }
270
- await new Promise((r) => setTimeout(r, interval));
271
- }
272
- throw new Error(`Container ${id} did not become healthy within ${timeoutMs}ms`);
273
- }
274
- /** Stream logs from a container. */
275
- async *containerLogs(id) {
276
- const info = this.containers.find((c) => c.id === id);
277
- if (!info)
278
- return;
279
- const container = this.docker.getContainer(info.containerId);
280
- const stream = await container.logs({
281
- stdout: true,
282
- stderr: true,
283
- follow: true,
284
- tail: 0,
285
- });
286
- const buffer = [];
287
- let notify = null;
288
- let done = false;
289
- const push = (entry) => {
290
- buffer.push(entry);
291
- if (notify) {
292
- const n = notify;
293
- notify = null;
294
- n();
295
- }
296
- };
297
- const stdoutPT = new PassThrough();
298
- const stderrPT = new PassThrough();
299
- stdoutPT.on("data", (chunk) => {
300
- for (const line of chunk.toString().split("\n")) {
301
- if (line)
302
- push({ stream: "stdout", text: line });
303
- }
304
- });
305
- stderrPT.on("data", (chunk) => {
306
- for (const line of chunk.toString().split("\n")) {
307
- if (line)
308
- push({ stream: "stderr", text: line });
309
- }
310
- });
311
- this.docker.modem.demuxStream(stream, stdoutPT, stderrPT);
312
- stream.on("end", () => {
313
- done = true;
314
- if (notify) {
315
- const n = notify;
316
- notify = null;
317
- n();
318
- }
319
- });
320
- while (!done || buffer.length > 0) {
321
- if (buffer.length === 0) {
322
- await new Promise((r) => {
323
- notify = r;
324
- });
325
- }
326
- while (buffer.length > 0) {
327
- yield buffer.shift();
328
- }
329
- }
330
- }
331
- /** Stop and remove all managed containers (keep volumes). */
332
- async stop() {
333
- for (const info of this.containers) {
334
- try {
335
- const container = this.docker.getContainer(info.containerId);
336
- await container.stop({ t: 5 });
337
- await container.remove();
338
- this.log.debug({ containerName: info.name }, "container stopped");
339
- }
340
- catch {
341
- this.log.debug({ containerName: info.name }, "container already stopped");
342
- }
343
- }
344
- this.containers = [];
345
- }
346
- /** List running dev containers for this project. */
347
- async listContainers() {
348
- const containers = await this.docker.listContainers({
349
- filters: JSON.stringify({
350
- label: ["vyft.dev=true", `vyft.project=${this.project}`],
351
- }),
352
- });
353
- return containers.map((c) => ({
354
- id: c.Labels["vyft.service"] || "",
355
- name: c.Names[0]?.replace(/^\//, "") || "",
356
- containerId: c.Id,
357
- }));
358
- }
359
- async removeContainer(serviceId) {
360
- const containerName = `${serviceId}-dev`;
361
- try {
362
- const container = this.docker.getContainer(containerName);
363
- await container.stop({ t: 2 });
364
- await container.remove();
365
- this.log.debug({ containerName }, "removed existing container");
366
- }
367
- catch {
368
- // Container didn't exist
369
- }
370
- }
371
- }
372
- function parseDurationNs(duration) {
373
- const match = duration.match(/^(\d+)(ms|s|m|h)$/);
374
- if (!match?.[1] || !match[2]) {
375
- throw new Error(`Invalid duration format: ${duration}`);
376
- }
377
- const value = parseInt(match[1], 10);
378
- const unit = match[2];
379
- const multipliers = {
380
- ms: 1_000_000,
381
- s: 1_000_000_000,
382
- m: 60_000_000_000,
383
- h: 3_600_000_000_000,
384
- };
385
- return value * multipliers[unit];
386
- }
387
- function shellEscape(s) {
388
- if (/^[a-zA-Z0-9_./:=-]+$/.test(s))
389
- return s;
390
- return `'${s.replace(/'/g, "'\\''")}'`;
391
- }
package/dist/logger.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import pino from "pino";
2
- export declare const logger: pino.Logger<never, boolean>;
package/dist/logger.js DELETED
@@ -1,10 +0,0 @@
1
- import pino from "pino";
2
- function resolveLevel() {
3
- const val = process.env.LOG_LEVEL;
4
- if (!val)
5
- return "silent";
6
- return val;
7
- }
8
- export const logger = pino({
9
- level: resolveLevel(),
10
- });
package/dist/proxy.d.ts DELETED
@@ -1,16 +0,0 @@
1
- export interface ReverseProxy {
2
- /** Ensure the proxy service is running and configured. */
3
- ensure(): Promise<void>;
4
- /** Register or update a route for a resource. */
5
- addRoute(resourceId: string, route: string, target: {
6
- host: string;
7
- port: number;
8
- }): Promise<void>;
9
- /** Remove a route for a resource. No-op if it doesn't exist. */
10
- removeRoute(resourceId: string): Promise<void>;
11
- /** Stream proxy access logs. */
12
- logs(options: {
13
- follow?: boolean;
14
- tail?: number;
15
- }): Promise<void>;
16
- }
package/dist/proxy.js DELETED
File without changes
@@ -1,181 +0,0 @@
1
- import type { RuntimeRef } from "./symbols.js";
2
- /** Discriminant for the four resource kinds. */
3
- export type ResourceType = "volume" | "secret" | "service" | "site";
4
- /** Configuration for a persistent volume. */
5
- export interface VolumeConfig {
6
- /** Human-readable size hint (e.g. `"10GB"`). Informational only. */
7
- size?: string;
8
- }
9
- /** Configuration for an auto-generated secret. */
10
- export interface SecretConfig {
11
- /** Length of the generated random value in bytes. */
12
- length?: number;
13
- }
14
- /** Container health-check configuration. */
15
- export interface HealthCheckConfig {
16
- /** Command to run inside the container (e.g. `["pg_isready", "-U", "postgres"]`). */
17
- command: string[];
18
- /** Time between checks (e.g. `"5s"`, `"1m"`). */
19
- interval?: string;
20
- /** Maximum time a single check may take. */
21
- timeout?: string;
22
- /** Consecutive failures required to mark unhealthy. */
23
- retries?: number;
24
- /** Grace period before the first check runs. */
25
- startPeriod?: string;
26
- }
27
- /** CPU and memory limits for a service. */
28
- export interface ResourceLimits {
29
- /** Memory ceiling (e.g. `"512MB"`, `"2GB"`). */
30
- memory?: string;
31
- /** CPU core limit (e.g. `0.5`, `2`). */
32
- cpus?: number;
33
- }
34
- /** A persistent storage volume. */
35
- export interface Volume extends RuntimeRef {
36
- type: "volume";
37
- id: string;
38
- config: VolumeConfig;
39
- }
40
- /** An auto-generated secret value, injected at deploy time. */
41
- export interface Secret extends RuntimeRef {
42
- type: "secret";
43
- id: string;
44
- config: SecretConfig;
45
- }
46
- /**
47
- * A long-running service (container).
48
- *
49
- * Use `host` and `port` to reference this service from other services
50
- * in the same project, or `url` for the full address.
51
- */
52
- export interface Service extends RuntimeRef {
53
- type: "service";
54
- id: string;
55
- config: ServiceConfig;
56
- /** Internal hostname reachable by other services. */
57
- host: string;
58
- /** Port the service listens on. */
59
- port: number;
60
- /** Full URL — `https://<route>` if routed, otherwise `http://<host>:<port>`. */
61
- url: string;
62
- }
63
- /** A static site served via Caddy. */
64
- export interface Site extends RuntimeRef {
65
- type: "site";
66
- id: string;
67
- config: SiteConfig;
68
- /** Public URL derived from the route (e.g. `https://example.com`). */
69
- url: string;
70
- }
71
- /** Union of all deployable resource types. */
72
- export type Resource = Volume | Secret | Service | Site;
73
- /**
74
- * A deferred reference to a value that isn't known until deploy time.
75
- *
76
- * Currently only {@link Secret} produces deferred values. Expand this
77
- * union as more resources gain deferred outputs.
78
- */
79
- export type Reference = Secret;
80
- /**
81
- * A tagged-template interpolation that mixes literal strings with
82
- * {@link Reference} values. Created via {@link interpolate}.
83
- *
84
- * @example
85
- * ```ts
86
- * const connStr = interpolate`postgres://user:${dbPassword}@${db.host}:5432/app`;
87
- * ```
88
- */
89
- export interface Interpolation {
90
- type: "interpolation";
91
- strings: TemplateStringsArray;
92
- values: Array<Reference | string>;
93
- }
94
- /**
95
- * A value that can appear in a service's `env` map.
96
- *
97
- * - Plain `string` — set verbatim.
98
- * - {@link Reference} — resolved at deploy time (e.g. a secret).
99
- * - {@link Interpolation} — a template mixing strings and references.
100
- */
101
- export type EnvValue = string | Reference | Interpolation;
102
- /** Type-guard: returns `true` if `value` is a {@link Reference}. */
103
- export declare function isReference(value: unknown): value is Reference;
104
- /** Type-guard: returns `true` if `value` is a {@link Secret}. */
105
- export declare function isSecret(value: unknown): value is Secret;
106
- /** Type-guard: returns `true` if `value` is an {@link Interpolation}. */
107
- export declare function isInterpolation(value: unknown): value is Interpolation;
108
- /** Configuration for a long-running service. */
109
- export interface ServiceConfig {
110
- /**
111
- * Container image to run.
112
- *
113
- * - `string` — a registry image (e.g. `"node:22"`).
114
- * - `{ context, dockerfile }` — build from a local Dockerfile.
115
- */
116
- image: string | {
117
- context?: string;
118
- dockerfile?: string;
119
- };
120
- /** Public route to expose (e.g. `"api.example.com"` or `"example.com/api"`). */
121
- route?: string;
122
- /** Port the container listens on. Defaults to `3000`. */
123
- port?: number;
124
- /** Environment variables injected into the container. */
125
- env?: Record<string, EnvValue>;
126
- /** Override the container's default command. */
127
- command?: string[];
128
- /** Volumes to mount into the container. */
129
- volumes?: Array<{
130
- volume: Volume;
131
- mount: string;
132
- }>;
133
- /** Services that must be healthy before this one starts. */
134
- dependsOn?: Service[];
135
- /** Container health check. */
136
- healthCheck?: HealthCheckConfig;
137
- /**
138
- * Restart behaviour on failure.
139
- * @defaultValue `"any"`
140
- */
141
- restartPolicy?: "none" | "on-failure" | "any";
142
- /** Local development configuration. Used by `vyft dev`. */
143
- dev?: {
144
- /** Shell command to run (e.g. `"bun run dev"`). */
145
- command: string;
146
- /** Working directory relative to project root. */
147
- cwd?: string;
148
- };
149
- }
150
- /** Configuration for a static site. */
151
- export interface SiteConfig {
152
- /** Domain (and optional path) to serve the site on. */
153
- route: string;
154
- /**
155
- * Enable single-page application mode. When `true`, all requests that
156
- * don't match a static file are rewritten to `/index.html`.
157
- * @defaultValue `true`
158
- */
159
- spa?: boolean;
160
- /** Build settings for the static site. */
161
- build: {
162
- /** Working directory containing the source (relative to project root). */
163
- cwd: string;
164
- /** Directory containing the built output (relative to `cwd`). Defaults to `"dist"`. */
165
- output?: string;
166
- /** Build command to run (e.g. `"npm run build"`). */
167
- command?: string;
168
- /** Environment variables passed to the build command. */
169
- env?: Record<string, string>;
170
- };
171
- }
172
- /**
173
- * Validates a resource ID.
174
- * @throws If the ID is empty, too long, or contains invalid characters.
175
- */
176
- export declare function validateId(id: string): void;
177
- /**
178
- * Validates a route string.
179
- * @throws If the route is empty or not a valid domain with optional path.
180
- */
181
- export declare function validateRoute(route: string): void;
package/dist/resource.js DELETED
@@ -1,45 +0,0 @@
1
- /** Type-guard: returns `true` if `value` is a {@link Reference}. */
2
- export function isReference(value) {
3
- return isSecret(value);
4
- }
5
- /** Type-guard: returns `true` if `value` is a {@link Secret}. */
6
- export function isSecret(value) {
7
- return (typeof value === "object" &&
8
- value !== null &&
9
- value.type === "secret");
10
- }
11
- /** Type-guard: returns `true` if `value` is an {@link Interpolation}. */
12
- export function isInterpolation(value) {
13
- return (typeof value === "object" &&
14
- value !== null &&
15
- value.type === "interpolation");
16
- }
17
- const ID_PATTERN = /^[a-z][a-z0-9-]*[a-z0-9]$|^[a-z]$/;
18
- const ROUTE_PATTERN = /^(\*\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*(\/.+)?$/;
19
- /**
20
- * Validates a resource ID.
21
- * @throws If the ID is empty, too long, or contains invalid characters.
22
- */
23
- export function validateId(id) {
24
- if (!id || id.length < 1) {
25
- throw new Error("Resource ID cannot be empty");
26
- }
27
- if (id.length > 63) {
28
- throw new Error("Resource ID cannot exceed 63 characters");
29
- }
30
- if (!ID_PATTERN.test(id)) {
31
- throw new Error(`Invalid resource ID "${id}": must start with a letter, contain only lowercase letters, numbers, and hyphens, and end with a letter or number`);
32
- }
33
- }
34
- /**
35
- * Validates a route string.
36
- * @throws If the route is empty or not a valid domain with optional path.
37
- */
38
- export function validateRoute(route) {
39
- if (!route) {
40
- throw new Error("Route cannot be empty");
41
- }
42
- if (!ROUTE_PATTERN.test(route)) {
43
- throw new Error(`Invalid route "${route}": must be a valid domain with optional path`);
44
- }
45
- }
@@ -1,26 +0,0 @@
1
- import type { Secret, SecretConfig, Service, ServiceConfig, Volume, VolumeConfig } from "../resource.js";
2
- export interface Primitives {
3
- volume(id: string, config?: VolumeConfig): Volume;
4
- service(id: string, config: ServiceConfig): Service;
5
- secret(id: string, config?: SecretConfig): Secret;
6
- }
7
- /** Returns `true` if a resource was created by a built-in factory. */
8
- export declare function isManaged(resource: unknown): boolean;
9
- export declare function createServices(p: Primitives): {
10
- postgres: (id: string, config?: import("./postgres.js").PostgresConfig) => import("./postgres.js").Postgres;
11
- redis: (id: string, config?: import("./redis.js").RedisConfig) => import("./redis.js").Redis;
12
- rabbitmq: (id: string, config?: import("./rabbitmq.js").RabbitmqConfig) => import("./rabbitmq.js").Rabbitmq;
13
- nats: (id: string, config?: import("./nats.js").NatsConfig) => import("./nats.js").Nats;
14
- mysql: (id: string, config?: import("./mysql.js").MysqlConfig) => import("./mysql.js").Mysql;
15
- mongo: (id: string, config?: import("./mongo.js").MongoConfig) => import("./mongo.js").Mongo;
16
- minio: (id: string, config?: import("./minio.js").MinioConfig) => import("./minio.js").Minio;
17
- storage: (id: string, config?: import("./storage.js").StorageConfig) => import("./storage.js").Storage;
18
- };
19
- export type { Bucket, Minio, MinioConfig } from "./minio.js";
20
- export type { Mongo, MongoConfig } from "./mongo.js";
21
- export type { Mysql, MysqlConfig } from "./mysql.js";
22
- export type { Nats, NatsConfig } from "./nats.js";
23
- export type { Postgres, PostgresConfig } from "./postgres.js";
24
- export type { Rabbitmq, RabbitmqConfig } from "./rabbitmq.js";
25
- export type { Redis, RedisConfig } from "./redis.js";
26
- export type { BackupConfig, Storage, StorageConfig } from "./storage.js";