vyft 0.3.0-alpha → 0.4.1-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 (184) 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 +339 -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 +69 -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 -8
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +23 -6
  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 -9
  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 -46
  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 -11
  117. package/dist/build.js +0 -39
  118. package/dist/cli.d.ts +0 -2
  119. package/dist/cli.js +0 -398
  120. package/dist/context.d.ts +0 -39
  121. package/dist/context.js +0 -101
  122. package/dist/docker.d.ts +0 -62
  123. package/dist/docker.js +0 -876
  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/logger.d.ts +0 -2
  131. package/dist/logger.js +0 -10
  132. package/dist/proxy.d.ts +0 -16
  133. package/dist/proxy.js +0 -0
  134. package/dist/resource.d.ts +0 -174
  135. package/dist/resource.js +0 -45
  136. package/dist/services/index.d.ts +0 -24
  137. package/dist/services/index.js +0 -20
  138. package/dist/services/minio.d.ts +0 -36
  139. package/dist/services/minio.js +0 -53
  140. package/dist/services/mongo.d.ts +0 -28
  141. package/dist/services/mongo.js +0 -45
  142. package/dist/services/mysql.d.ts +0 -28
  143. package/dist/services/mysql.js +0 -44
  144. package/dist/services/nats.d.ts +0 -26
  145. package/dist/services/nats.js +0 -38
  146. package/dist/services/postgres.d.ts +0 -28
  147. package/dist/services/postgres.js +0 -45
  148. package/dist/services/rabbitmq.d.ts +0 -28
  149. package/dist/services/rabbitmq.js +0 -44
  150. package/dist/services/redis.d.ts +0 -28
  151. package/dist/services/redis.js +0 -49
  152. package/dist/services/storage.d.ts +0 -39
  153. package/dist/services/storage.js +0 -94
  154. package/dist/swarm/factories.d.ts +0 -16
  155. package/dist/swarm/factories.js +0 -63
  156. package/dist/swarm/index.d.ts +0 -20
  157. package/dist/swarm/index.js +0 -5
  158. package/dist/swarm/proxy.d.ts +0 -24
  159. package/dist/swarm/proxy.js +0 -339
  160. package/dist/swarm/types.d.ts +0 -26
  161. package/dist/swarm/types.js +0 -0
  162. package/dist/symbols.d.ts +0 -13
  163. package/dist/symbols.js +0 -2
  164. package/templates/fullstack/apps/api/Dockerfile +0 -22
  165. package/templates/fullstack/apps/api/package.json +0 -26
  166. package/templates/fullstack/apps/api/src/auth.ts +0 -21
  167. package/templates/fullstack/apps/api/src/db.ts +0 -16
  168. package/templates/fullstack/apps/api/src/index.ts +0 -17
  169. package/templates/fullstack/apps/api/src/router.ts +0 -11
  170. package/templates/fullstack/apps/api/src/schema.ts +0 -11
  171. package/templates/fullstack/apps/api/tsconfig.json +0 -8
  172. package/templates/fullstack/apps/web/index.html +0 -12
  173. package/templates/fullstack/apps/web/package.json +0 -21
  174. package/templates/fullstack/apps/web/src/app.tsx +0 -8
  175. package/templates/fullstack/apps/web/src/main.tsx +0 -9
  176. package/templates/fullstack/apps/web/tsconfig.json +0 -7
  177. package/templates/fullstack/apps/web/vite.config.ts +0 -14
  178. package/templates/fullstack/compose.yaml +0 -14
  179. package/templates/fullstack/dockerignore +0 -7
  180. package/templates/fullstack/gitignore +0 -3
  181. package/templates/fullstack/package.json +0 -18
  182. package/templates/fullstack/pnpm-workspace.yaml +0 -2
  183. package/templates/fullstack/tsconfig.json +0 -11
  184. package/templates/fullstack/vyft.config.ts +0 -22
@@ -1,339 +0,0 @@
1
- import { PassThrough } from "node:stream";
2
- import { log } from "@clack/prompts";
3
- import { parseRoute } from "../docker.js";
4
- const PROXY_SERVICE_NAME = "vyft-proxy";
5
- export function buildCaddyRoute(resourceId, route, handler) {
6
- const { host, path } = parseRoute(route);
7
- const match = { host: [host] };
8
- if (path)
9
- match.path = [path];
10
- return {
11
- "@id": `vyft-${resourceId}`,
12
- match: [match],
13
- terminal: true,
14
- handle: [handler],
15
- };
16
- }
17
- export class CaddyProxy {
18
- docker;
19
- log;
20
- constructor(docker, log) {
21
- this.docker = docker;
22
- this.log = log;
23
- }
24
- async ensure() {
25
- this.log.debug("checking proxy existence");
26
- const exists = await this.serviceExists(PROXY_SERVICE_NAME);
27
- if (exists) {
28
- this.log.debug("proxy already exists, verifying config structure");
29
- try {
30
- const raw = await this.caddyApiRequest("GET", "/config/");
31
- const config = JSON.parse(raw);
32
- if (!config?.apps?.http?.servers?.main) {
33
- this.log.debug("proxy config missing servers.main, re-seeding");
34
- await this.seedCaddyConfig();
35
- }
36
- }
37
- catch {
38
- this.log.debug("proxy config check failed, re-seeding");
39
- await this.seedCaddyConfig();
40
- }
41
- return;
42
- }
43
- // Create shared proxy network
44
- await this.ensureNetwork("vyft-network", {
45
- "vyft.infrastructure": "true",
46
- });
47
- this.log.debug("creating proxy service");
48
- await this.docker.createService({
49
- Name: PROXY_SERVICE_NAME,
50
- Labels: { "vyft.infrastructure": "true" },
51
- TaskTemplate: {
52
- ContainerSpec: {
53
- Image: "caddy:latest",
54
- Command: ["caddy", "run", "--resume"],
55
- Mounts: [
56
- {
57
- Type: "volume",
58
- Source: "vyft-proxy-config",
59
- Target: "/config",
60
- },
61
- {
62
- Type: "volume",
63
- Source: "vyft-proxy-data",
64
- Target: "/data",
65
- },
66
- ],
67
- Labels: { "vyft.infrastructure": "true" },
68
- },
69
- Networks: [{ Target: "vyft-network" }],
70
- },
71
- EndpointSpec: {
72
- Ports: [
73
- {
74
- Protocol: "tcp",
75
- TargetPort: 80,
76
- PublishedPort: 80,
77
- PublishMode: "ingress",
78
- },
79
- {
80
- Protocol: "tcp",
81
- TargetPort: 443,
82
- PublishedPort: 443,
83
- PublishMode: "ingress",
84
- },
85
- ],
86
- },
87
- Mode: { Replicated: { Replicas: 1 } },
88
- });
89
- log.step("Created vyft-proxy");
90
- await this.seedCaddyConfig();
91
- }
92
- async addRoute(resourceId, route, target) {
93
- this.log.debug({ resourceId, route }, "adding route");
94
- const handler = {
95
- handler: "reverse_proxy",
96
- upstreams: [{ dial: `${target.host}:${target.port}` }],
97
- };
98
- const caddyRoute = buildCaddyRoute(resourceId, route, handler);
99
- // Delete existing route for idempotency
100
- try {
101
- await this.caddyApiRequest("DELETE", `/id/vyft-${resourceId}`);
102
- }
103
- catch (err) {
104
- this.log.debug({ err, resourceId }, "idempotent route delete failed");
105
- }
106
- const maxAttempts = 5;
107
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
108
- try {
109
- await this.caddyApiRequest("POST", "/config/apps/http/servers/main/routes", caddyRoute);
110
- this.log.debug({ resourceId, route }, "route added");
111
- return;
112
- }
113
- catch (err) {
114
- this.log.debug({ err, resourceId, attempt: attempt + 1, max: maxAttempts }, "route add attempt failed");
115
- if (attempt === maxAttempts - 1) {
116
- this.log.error({ resourceId, route }, "route add exhausted retries");
117
- throw new Error(`Failed to add route for ${resourceId}`);
118
- }
119
- await new Promise((r) => setTimeout(r, 2000));
120
- }
121
- }
122
- }
123
- async removeRoute(resourceId) {
124
- this.log.debug({ resourceId }, "removing route");
125
- try {
126
- await this.caddyApiRequest("DELETE", `/id/vyft-${resourceId}`);
127
- this.log.debug({ resourceId }, "route removed");
128
- }
129
- catch (err) {
130
- this.log.debug({ err, resourceId }, "route removal failed (may not exist)");
131
- }
132
- }
133
- async logs(options) {
134
- const container = await this.findProxyContainer();
135
- const tail = options.tail ?? 100;
136
- if (options.follow) {
137
- const stream = await container.logs({
138
- stdout: true,
139
- stderr: true,
140
- follow: true,
141
- tail,
142
- timestamps: true,
143
- });
144
- const stdoutStream = new PassThrough();
145
- const stderrStream = new PassThrough();
146
- stdoutStream.pipe(process.stdout);
147
- stderrStream.pipe(process.stderr);
148
- this.docker.modem.demuxStream(stream, stdoutStream, stderrStream);
149
- await new Promise((resolve) => {
150
- stream.on("end", resolve);
151
- });
152
- }
153
- else {
154
- const buf = await container.logs({
155
- stdout: true,
156
- stderr: true,
157
- follow: false,
158
- tail,
159
- timestamps: true,
160
- });
161
- let offset = 0;
162
- while (offset + 8 <= buf.length) {
163
- const type = buf[offset];
164
- const size = buf.readUInt32BE(offset + 4);
165
- offset += 8;
166
- const payload = buf.subarray(offset, offset + size);
167
- if (type === 2) {
168
- process.stderr.write(payload);
169
- }
170
- else {
171
- process.stdout.write(payload);
172
- }
173
- offset += size;
174
- }
175
- }
176
- }
177
- async findProxyContainer() {
178
- const containers = await this.docker.listContainers({
179
- filters: JSON.stringify({
180
- label: [`com.docker.swarm.service.name=${PROXY_SERVICE_NAME}`],
181
- }),
182
- });
183
- if (containers.length === 0) {
184
- throw new Error("vyft-proxy container not found");
185
- }
186
- return this.docker.getContainer(containers[0].Id);
187
- }
188
- async caddyApiRequest(method, path, body) {
189
- const start = performance.now();
190
- this.log.debug({ method, path }, "caddy request started");
191
- const container = await this.findProxyContainer();
192
- let cmd;
193
- if (method === "POST") {
194
- const bodyStr = body ? JSON.stringify(body) : "";
195
- cmd = [
196
- "wget",
197
- "-q",
198
- "-O",
199
- "-",
200
- "--timeout=10",
201
- "--header=Content-Type: application/json",
202
- `--post-data=${bodyStr}`,
203
- `http://127.0.0.1:2019${path}`,
204
- ];
205
- }
206
- else if (method === "DELETE") {
207
- cmd = [
208
- "curl",
209
- "-s",
210
- "--connect-timeout",
211
- "5",
212
- "--max-time",
213
- "10",
214
- "-X",
215
- "DELETE",
216
- `http://127.0.0.1:2019${path}`,
217
- ];
218
- }
219
- else {
220
- cmd = [
221
- "wget",
222
- "-q",
223
- "-O",
224
- "-",
225
- "--timeout=10",
226
- `http://127.0.0.1:2019${path}`,
227
- ];
228
- }
229
- this.log.trace({ cmd }, "caddy exec command");
230
- const exec = await container.exec({
231
- Cmd: cmd,
232
- AttachStdout: true,
233
- AttachStderr: true,
234
- });
235
- const stream = await exec.start({});
236
- return new Promise((resolve, reject) => {
237
- const stdout = [];
238
- const stderr = [];
239
- const stdoutStream = new PassThrough();
240
- const stderrStream = new PassThrough();
241
- stdoutStream.on("data", (chunk) => stdout.push(chunk));
242
- stderrStream.on("data", (chunk) => stderr.push(chunk));
243
- this.docker.modem.demuxStream(stream, stdoutStream, stderrStream);
244
- stream.on("end", () => {
245
- const output = Buffer.concat(stdout).toString();
246
- const errOutput = Buffer.concat(stderr).toString();
247
- const durationMs = Math.round(performance.now() - start);
248
- this.log.trace({ stdoutBytes: output.length, stderrBytes: errOutput.length }, "caddy exec output");
249
- if (errOutput) {
250
- this.log.debug({ method, path, durationMs, stderr: errOutput }, "caddy request failed");
251
- reject(new Error(`Caddy API ${method} ${path} failed: ${errOutput}`));
252
- }
253
- else {
254
- this.log.debug({ method, path, durationMs }, "caddy request completed");
255
- resolve(output);
256
- }
257
- });
258
- });
259
- }
260
- async seedCaddyConfig() {
261
- const maxWait = 30000;
262
- const interval = 2000;
263
- let waited = 0;
264
- this.log.debug("waiting for proxy container");
265
- while (waited < maxWait) {
266
- try {
267
- await this.findProxyContainer();
268
- break;
269
- }
270
- catch (err) {
271
- this.log.debug({ err, waited, maxWait }, "proxy container not ready");
272
- await new Promise((r) => setTimeout(r, interval));
273
- waited += interval;
274
- }
275
- }
276
- const baseConfig = {
277
- logging: {
278
- logs: {
279
- default: {
280
- level: "INFO",
281
- },
282
- },
283
- },
284
- apps: {
285
- http: {
286
- servers: {
287
- main: {
288
- listen: [":443", ":80"],
289
- routes: [],
290
- logs: {},
291
- },
292
- },
293
- },
294
- },
295
- };
296
- const maxAttempts = 5;
297
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
298
- try {
299
- this.log.debug({ attempt: attempt + 1, max: maxAttempts }, "seeding caddy config");
300
- await this.caddyApiRequest("POST", "/load", baseConfig);
301
- this.log.debug("caddy config seeded");
302
- return;
303
- }
304
- catch (err) {
305
- this.log.debug({ err, attempt: attempt + 1, max: maxAttempts }, "seed attempt failed");
306
- if (attempt >= Math.floor(maxAttempts * 0.8)) {
307
- this.log.warn({ attempt: attempt + 1, max: maxAttempts }, "seed retry nearing limit");
308
- }
309
- await new Promise((r) => setTimeout(r, 2000));
310
- }
311
- }
312
- this.log.error("caddy config seed exhausted retries");
313
- throw new Error("Failed to seed Caddy config after retries");
314
- }
315
- async serviceExists(id) {
316
- try {
317
- await this.docker.getService(id).inspect();
318
- return true;
319
- }
320
- catch {
321
- return false;
322
- }
323
- }
324
- async ensureNetwork(name, labels = {}) {
325
- const networks = await this.docker.listNetworks({
326
- filters: JSON.stringify({ name: [name] }),
327
- });
328
- const exactMatch = networks.some((n) => n.Name === name);
329
- if (!exactMatch) {
330
- this.log.debug({ network: name }, "creating network");
331
- await this.docker.createNetwork({
332
- Name: name,
333
- Driver: "overlay",
334
- Attachable: true,
335
- Labels: labels,
336
- });
337
- }
338
- }
339
- }
@@ -1,26 +0,0 @@
1
- import type { ResourceLimits, ServiceConfig, VolumeConfig } from "../resource.js";
2
- /** Per-driver volume options. */
3
- export interface DriverVolumeOptions {
4
- local: {};
5
- overlay2: {};
6
- btrfs: {};
7
- zfs: {
8
- compression?: string;
9
- };
10
- }
11
- /** Supported storage driver names. */
12
- export type StorageDriver = keyof DriverVolumeOptions;
13
- /** Top-level configuration for the swarm runtime. */
14
- export interface SwarmConfig<D extends StorageDriver = "local"> {
15
- /** Storage driver used for volumes. @defaultValue `"local"` */
16
- storageDriver?: D;
17
- }
18
- /** Volume configuration extended with driver-specific options. */
19
- export type SwarmVolumeConfig<D extends StorageDriver = "local"> = VolumeConfig & DriverVolumeOptions[D];
20
- /** Service configuration with swarm-specific extensions. */
21
- export interface SwarmServiceConfig extends ServiceConfig {
22
- /** Number of replica tasks to run. @defaultValue `1` */
23
- replicas?: number;
24
- /** CPU and memory limits for each replica. */
25
- resources?: ResourceLimits;
26
- }
File without changes
package/dist/symbols.d.ts DELETED
@@ -1,13 +0,0 @@
1
- /** Symbol key used to attach runtime metadata to every resource. */
2
- export declare const VYFT_RUNTIME: unique symbol;
3
- /** Metadata describing which runtime backend owns a resource. */
4
- export interface RuntimeMeta {
5
- /** Runtime name (e.g. `"swarm"`). */
6
- name: string;
7
- /** Runtime-specific configuration. */
8
- config: Record<string, unknown>;
9
- }
10
- /** Mixin applied to every resource, tagging it with its runtime backend. */
11
- export interface RuntimeRef {
12
- readonly [VYFT_RUNTIME]: RuntimeMeta;
13
- }
package/dist/symbols.js DELETED
@@ -1,2 +0,0 @@
1
- /** Symbol key used to attach runtime metadata to every resource. */
2
- export const VYFT_RUNTIME = Symbol.for("vyft.runtime");
@@ -1,22 +0,0 @@
1
- FROM node:22-slim AS base
2
- RUN corepack enable
3
-
4
- FROM base AS deps
5
- WORKDIR /app
6
- COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
7
- COPY apps/api/package.json ./apps/api/
8
- RUN pnpm install --frozen-lockfile
9
-
10
- FROM deps AS build
11
- COPY tsconfig.json ./
12
- COPY apps/api/ ./apps/api/
13
- RUN pnpm --filter {{name}}-api build
14
-
15
- FROM build AS deploy
16
- RUN pnpm --filter {{name}}-api --prod deploy /prod/api
17
-
18
- FROM base
19
- WORKDIR /app
20
- COPY --from=deploy /prod/api .
21
- EXPOSE 3000
22
- CMD ["node", "dist/index.js"]
@@ -1,26 +0,0 @@
1
- {
2
- "name": "{{name}}-api",
3
- "private": true,
4
- "type": "module",
5
- "files": ["dist"],
6
- "scripts": {
7
- "dev": "tsx watch --env-file=../../.env src/index.ts",
8
- "build": "tsc"
9
- },
10
- "dependencies": {
11
- "@hono/node-server": "^1.14.1",
12
- "@hono/trpc-server": "^0.3.4",
13
- "@trpc/server": "^11.1.2",
14
- "better-auth": "^1.2.8",
15
- "drizzle-orm": "^0.44.2",
16
- "hono": "^4.7.10",
17
- "postgres": "^3.4.7",
18
- "zod": "^3.25.17"
19
- },
20
- "devDependencies": {
21
- "@types/node": "^22.15.0",
22
- "drizzle-kit": "^0.31.1",
23
- "tsx": "^4.19.4",
24
- "typescript": "^5.8.3"
25
- }
26
- }
@@ -1,21 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { betterAuth } from 'better-auth';
3
- import { drizzleAdapter } from 'better-auth/adapters/drizzle';
4
- import { db } from './db.js';
5
-
6
- function env(key: string): string {
7
- const fileKey = `${key}_FILE`;
8
- const filePath = process.env[fileKey];
9
- if (filePath) return readFileSync(filePath, 'utf-8').trim();
10
- const value = process.env[key];
11
- if (value) return value;
12
- throw new Error(`Missing env var: ${key} or ${fileKey}`);
13
- }
14
-
15
- export const auth = betterAuth({
16
- database: drizzleAdapter(db, { provider: 'pg' }),
17
- secret: env('AUTH_SECRET'),
18
- basePath: '/api/auth',
19
- baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3000',
20
- emailAndPassword: { enabled: true },
21
- });
@@ -1,16 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { drizzle } from 'drizzle-orm/postgres-js';
3
- import postgres from 'postgres';
4
- import * as schema from './schema.js';
5
-
6
- function env(key: string): string {
7
- const fileKey = `${key}_FILE`;
8
- const filePath = process.env[fileKey];
9
- if (filePath) return readFileSync(filePath, 'utf-8').trim();
10
- const value = process.env[key];
11
- if (value) return value;
12
- throw new Error(`Missing env var: ${key} or ${fileKey}`);
13
- }
14
-
15
- const client = postgres(env('DATABASE_URL'));
16
- export const db = drizzle(client, { schema });
@@ -1,17 +0,0 @@
1
- import { serve } from '@hono/node-server';
2
- import { trpcServer } from '@hono/trpc-server';
3
- import { Hono } from 'hono';
4
- import { auth } from './auth.js';
5
- import { appRouter } from './router.js';
6
-
7
- const app = new Hono().basePath('/api');
8
-
9
- app.on(['GET', 'POST'], '/auth/**', (c) => auth.handler(c.req.raw));
10
-
11
- app.use('/trpc/*', trpcServer({ router: appRouter }));
12
-
13
- app.get('/health', (c) => c.json({ ok: true }));
14
-
15
- serve({ fetch: app.fetch, port: 3000 }, (info) => {
16
- console.log(`Server running on http://localhost:${info.port}`);
17
- });
@@ -1,11 +0,0 @@
1
- import { initTRPC } from '@trpc/server';
2
-
3
- const t = initTRPC.create();
4
-
5
- export const appRouter = t.router({
6
- hello: t.procedure.query(() => {
7
- return { message: 'Hello from tRPC!' };
8
- }),
9
- });
10
-
11
- export type AppRouter = typeof appRouter;
@@ -1,11 +0,0 @@
1
- import { pgTable, text, timestamp } from 'drizzle-orm/pg-core';
2
-
3
- export const users = pgTable('users', {
4
- id: text('id').primaryKey(),
5
- name: text('name').notNull(),
6
- email: text('email').notNull().unique(),
7
- emailVerified: timestamp('email_verified'),
8
- image: text('image'),
9
- createdAt: timestamp('created_at').defaultNow().notNull(),
10
- updatedAt: timestamp('updated_at').defaultNow().notNull(),
11
- });
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "dist"
6
- },
7
- "include": ["src"]
8
- }
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>{{name}}</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/src/main.tsx"></script>
11
- </body>
12
- </html>
@@ -1,21 +0,0 @@
1
- {
2
- "name": "{{name}}-web",
3
- "private": true,
4
- "type": "module",
5
- "scripts": {
6
- "dev": "vite",
7
- "build": "vite build",
8
- "preview": "vite preview"
9
- },
10
- "dependencies": {
11
- "react": "^19.1.0",
12
- "react-dom": "^19.1.0"
13
- },
14
- "devDependencies": {
15
- "@types/react": "^19.1.6",
16
- "@types/react-dom": "^19.1.6",
17
- "@vitejs/plugin-react": "^4.5.2",
18
- "typescript": "^5.8.3",
19
- "vite": "^6.3.5"
20
- }
21
- }
@@ -1,8 +0,0 @@
1
- export function App() {
2
- return (
3
- <main>
4
- <h1>{{name}}</h1>
5
- <p>Edit <code>web/src/app.tsx</code> to get started.</p>
6
- </main>
7
- );
8
- }
@@ -1,9 +0,0 @@
1
- import { StrictMode } from 'react';
2
- import { createRoot } from 'react-dom/client';
3
- import { App } from './app.js';
4
-
5
- createRoot(document.getElementById('root')!).render(
6
- <StrictMode>
7
- <App />
8
- </StrictMode>,
9
- );
@@ -1,7 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "lib": ["ESNext", "DOM", "DOM.Iterable"]
5
- },
6
- "include": ["src"]
7
- }
@@ -1,14 +0,0 @@
1
- import react from '@vitejs/plugin-react';
2
- import { defineConfig } from 'vite';
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- server: {
7
- proxy: {
8
- '/api': {
9
- target: 'http://localhost:3000',
10
- changeOrigin: true,
11
- },
12
- },
13
- },
14
- });
@@ -1,14 +0,0 @@
1
- services:
2
- db:
3
- image: postgres:17
4
- restart: unless-stopped
5
- ports:
6
- - "5432:5432"
7
- environment:
8
- POSTGRES_DB: {{name}}
9
- POSTGRES_PASSWORD: postgres
10
- volumes:
11
- - db-data:/var/lib/postgresql/data
12
-
13
- volumes:
14
- db-data:
@@ -1,7 +0,0 @@
1
- node_modules
2
- .git
3
- .env
4
- dist
5
- *.md
6
- .vscode
7
- .idea
@@ -1,3 +0,0 @@
1
- node_modules
2
- dist
3
- .env
@@ -1,18 +0,0 @@
1
- {
2
- "name": "{{name}}",
3
- "private": true,
4
- "type": "module",
5
- "packageManager": "pnpm@9.15.9",
6
- "devDependencies": {
7
- "vyft": "latest"
8
- },
9
- "scripts": {
10
- "predev": "pnpm compose:up",
11
- "dev": "pnpm --parallel -r dev",
12
- "build": "pnpm --parallel -r build",
13
- "deploy": "vyft deploy",
14
- "compose:up": "docker compose up -d",
15
- "compose:down": "docker compose down",
16
- "compose:stop": "docker compose stop"
17
- }
18
- }
@@ -1,2 +0,0 @@
1
- packages:
2
- - "apps/*"
@@ -1,11 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "skipLibCheck": true,
8
- "esModuleInterop": true,
9
- "jsx": "react-jsx"
10
- }
11
- }