@ericminassian/plat 0.0.0-stage → 0.1.0

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 (156) hide show
  1. package/dist/api-types.d.ts +7 -0
  2. package/dist/api-types.js +3 -0
  3. package/dist/api-types.js.map +1 -0
  4. package/dist/api.d.ts +123 -0
  5. package/dist/api.js +271 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/bin.d.ts +2 -0
  8. package/dist/bin.js +4 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/build.d.ts +45 -0
  11. package/dist/build.js +188 -0
  12. package/dist/build.js.map +1 -0
  13. package/dist/commands/account.d.ts +2 -0
  14. package/dist/commands/account.js +45 -0
  15. package/dist/commands/account.js.map +1 -0
  16. package/dist/commands/apps.d.ts +2 -0
  17. package/dist/commands/apps.js +75 -0
  18. package/dist/commands/apps.js.map +1 -0
  19. package/dist/commands/common.d.ts +19 -0
  20. package/dist/commands/common.js +43 -0
  21. package/dist/commands/common.js.map +1 -0
  22. package/dist/commands/lifecycle.d.ts +3 -0
  23. package/dist/commands/lifecycle.js +105 -0
  24. package/dist/commands/lifecycle.js.map +1 -0
  25. package/dist/commands/manage.d.ts +2 -0
  26. package/dist/commands/manage.js +103 -0
  27. package/dist/commands/manage.js.map +1 -0
  28. package/dist/commands/observe.d.ts +8 -0
  29. package/dist/commands/observe.js +195 -0
  30. package/dist/commands/observe.js.map +1 -0
  31. package/dist/credentials.d.ts +13 -0
  32. package/dist/credentials.js +42 -0
  33. package/dist/credentials.js.map +1 -0
  34. package/dist/deploy.d.ts +23 -0
  35. package/dist/deploy.js +100 -0
  36. package/dist/deploy.js.map +1 -0
  37. package/dist/dev/crons.d.ts +16 -0
  38. package/dist/dev/crons.js +47 -0
  39. package/dist/dev/crons.js.map +1 -0
  40. package/dist/dev/entries.d.ts +6 -0
  41. package/dist/dev/entries.js +21 -0
  42. package/dist/dev/entries.js.map +1 -0
  43. package/dist/dev/index.d.ts +33 -0
  44. package/dist/dev/index.js +262 -0
  45. package/dist/dev/index.js.map +1 -0
  46. package/dist/dev/local-stage.d.ts +46 -0
  47. package/dist/dev/local-stage.js +116 -0
  48. package/dist/dev/local-stage.js.map +1 -0
  49. package/dist/dev/pretty.d.ts +16 -0
  50. package/dist/dev/pretty.js +91 -0
  51. package/dist/dev/pretty.js.map +1 -0
  52. package/dist/dev/proc.d.ts +7 -0
  53. package/dist/dev/proc.js +16 -0
  54. package/dist/dev/proc.js.map +1 -0
  55. package/dist/dev/router.d.ts +67 -0
  56. package/dist/dev/router.js +184 -0
  57. package/dist/dev/router.js.map +1 -0
  58. package/dist/dev/server-entry.d.ts +1 -0
  59. package/dist/dev/server-entry.js +28 -0
  60. package/dist/dev/server-entry.js.map +1 -0
  61. package/dist/dev/test.d.ts +10 -0
  62. package/dist/dev/test.js +62 -0
  63. package/dist/dev/test.js.map +1 -0
  64. package/dist/dev/worker-host.d.ts +1 -0
  65. package/dist/dev/worker-host.js +67 -0
  66. package/dist/dev/worker-host.js.map +1 -0
  67. package/dist/dev/worker.d.ts +57 -0
  68. package/dist/dev/worker.js +216 -0
  69. package/dist/dev/worker.js.map +1 -0
  70. package/dist/github.d.ts +39 -0
  71. package/dist/github.js +108 -0
  72. package/dist/github.js.map +1 -0
  73. package/dist/index.d.ts +14 -0
  74. package/dist/index.js +15 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/init.d.ts +23 -0
  77. package/dist/init.js +102 -0
  78. package/dist/init.js.map +1 -0
  79. package/dist/main.d.ts +3 -0
  80. package/dist/main.js +24 -0
  81. package/dist/main.js.map +1 -0
  82. package/dist/project.d.ts +22 -0
  83. package/dist/project.js +81 -0
  84. package/dist/project.js.map +1 -0
  85. package/dist/util/net.d.ts +4 -0
  86. package/dist/util/net.js +33 -0
  87. package/dist/util/net.js.map +1 -0
  88. package/dist/util/output.d.ts +42 -0
  89. package/dist/util/output.js +105 -0
  90. package/dist/util/output.js.map +1 -0
  91. package/dist/util/prompt.d.ts +3 -0
  92. package/dist/util/prompt.js +22 -0
  93. package/dist/util/prompt.js.map +1 -0
  94. package/dist/util/time.d.ts +11 -0
  95. package/dist/util/time.js +29 -0
  96. package/dist/util/time.js.map +1 -0
  97. package/dist/util/zip.d.ts +10 -0
  98. package/dist/util/zip.js +45 -0
  99. package/dist/util/zip.js.map +1 -0
  100. package/package.json +50 -3
  101. package/src/api-types.ts +8 -0
  102. package/src/api.ts +341 -0
  103. package/src/bin.ts +4 -0
  104. package/src/build.ts +255 -0
  105. package/src/commands/account.ts +62 -0
  106. package/src/commands/apps.ts +102 -0
  107. package/src/commands/common.ts +51 -0
  108. package/src/commands/lifecycle.ts +139 -0
  109. package/src/commands/manage.ts +169 -0
  110. package/src/commands/observe.ts +276 -0
  111. package/src/credentials.ts +50 -0
  112. package/src/deploy.ts +138 -0
  113. package/src/dev/crons.ts +70 -0
  114. package/src/dev/entries.ts +23 -0
  115. package/src/dev/index.ts +281 -0
  116. package/src/dev/local-stage.ts +176 -0
  117. package/src/dev/pretty.ts +90 -0
  118. package/src/dev/proc.ts +15 -0
  119. package/src/dev/router.ts +246 -0
  120. package/src/dev/server-entry.ts +21 -0
  121. package/src/dev/test.ts +68 -0
  122. package/src/dev/worker-host.ts +62 -0
  123. package/src/dev/worker.ts +332 -0
  124. package/src/github.ts +121 -0
  125. package/src/index.ts +20 -0
  126. package/src/init.ts +123 -0
  127. package/src/main.ts +28 -0
  128. package/src/project.ts +89 -0
  129. package/src/util/net.ts +33 -0
  130. package/src/util/output.ts +117 -0
  131. package/src/util/prompt.ts +20 -0
  132. package/src/util/time.ts +32 -0
  133. package/src/util/zip.ts +46 -0
  134. package/template/.github/workflows/platform.yml +24 -0
  135. package/template/AGENTS.md +134 -0
  136. package/template/CLAUDE.md +1 -0
  137. package/template/README.md +13 -0
  138. package/template/_gitignore +8 -0
  139. package/template/package.json +31 -0
  140. package/template/platform.json +18 -0
  141. package/template/src/server.ts +100 -0
  142. package/template/src/types.ts +21 -0
  143. package/template/src/worker.ts +32 -0
  144. package/template/test/server.test.ts +120 -0
  145. package/template/test/todos.integration.test.ts +30 -0
  146. package/template/tsconfig.json +18 -0
  147. package/template/vitest.config.ts +9 -0
  148. package/template/vitest.integration.config.ts +10 -0
  149. package/template/web/index.html +12 -0
  150. package/template/web/src/App.tsx +102 -0
  151. package/template/web/src/api.ts +11 -0
  152. package/template/web/src/main.tsx +10 -0
  153. package/template/web/src/styles.css +102 -0
  154. package/template/web/tsconfig.json +18 -0
  155. package/template/web/vite.config.ts +19 -0
  156. package/README.md +0 -3
@@ -0,0 +1,21 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ /** Path to tsx's CLI (it has no `./cli` export, so go through its package.json). */
6
+ export function tsxCli() {
7
+ const pkg = createRequire(import.meta.url).resolve('tsx/package.json');
8
+ const bin = JSON.parse(readFileSync(pkg, 'utf8')).bin;
9
+ const rel = typeof bin === 'string' ? bin : (bin.tsx ?? Object.values(bin)[0]);
10
+ return join(dirname(pkg), rel);
11
+ }
12
+ /** A CLI-owned entry file next to this module (`.ts` in the repo, `.js` when published). */
13
+ export function devEntry(name) {
14
+ const ts = fileURLToPath(new URL(`./${name}.ts`, import.meta.url));
15
+ return existsSync(ts) ? ts : fileURLToPath(new URL(`./${name}.js`, import.meta.url));
16
+ }
17
+ /** argv for running an entry under tsx, optionally restarting on edits. */
18
+ export function tsxArgs(name, watch) {
19
+ return watch ? [tsxCli(), 'watch', '--clear-screen=false', devEntry(name)] : [tsxCli(), devEntry(name)];
20
+ }
21
+ //# sourceMappingURL=entries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entries.js","sourceRoot":"","sources":["../../src/dev/entries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,oFAAoF;AACpF,MAAM,UAAU,MAAM;IACpB,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvE,MAAM,GAAG,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAA8C,CAAC,GAAG,CAAC;IACpG,MAAM,GAAG,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,QAAQ,CAAC,IAAoC;IAC3D,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,KAAK,IAAI,KAAK,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACnE,OAAO,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,KAAK,IAAI,KAAK,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,OAAO,CAAC,IAAoC,EAAE,KAAc;IAC1E,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ import { type ResolvedManifest } from '@ericminassian/platform-core';
3
+ import { type LocalStage } from './local-stage.ts';
4
+ export interface DevOptions {
5
+ cwd: string;
6
+ port: number;
7
+ /** Print SDK trace spans too. */
8
+ spans?: boolean;
9
+ }
10
+ export declare const DEV_CONTROL_PREFIX = "/__plat_dev/";
11
+ /**
12
+ * `plat dev`: the whole app locally against the AWS Emulator.
13
+ *
14
+ * emulator ← engine (same code as prod; `webMode: 'external'`)
15
+ * web server (SDK wrapper, tsx watch) ─┐
16
+ * frontend dev server (web.dev) ───────┼─ local router (core `decide()`)
17
+ * local sign-in page ──────────────────┘
18
+ * worker (real Node, tsx watch) ← dispatcher (emulator SQS + EventBridge tap + local crons)
19
+ */
20
+ export declare function runDev(opts: DevOptions): Promise<void>;
21
+ /**
22
+ * The app's server exactly as the Web Function runs it (SDK wrapper, bindings,
23
+ * `AWS_LAMBDA_HTTP_ENDPOINT`), under `tsx watch` so edits restart it.
24
+ */
25
+ export declare function spawnWebServer(stage: LocalStage, manifest: ResolvedManifest, root: string, opts?: {
26
+ watch?: boolean;
27
+ workerUrl?: string;
28
+ }): Promise<{
29
+ child: ChildProcess;
30
+ port: number;
31
+ }>;
32
+ /** `plat dev run-cron <name>`: ask a running `plat dev` to fire a cron now. */
33
+ export declare function runCronOnDev(name: string, port: number): Promise<void>;
@@ -0,0 +1,262 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { resolve } from 'node:path';
3
+ import { LOCAL_STAGE } from '@ericminassian/platform-core';
4
+ import { EMULATOR_INSTALL_HINT } from '@ericminassian/platform-engine';
5
+ import pc from 'picocolors';
6
+ import { SDK_SERVER, withLocalBin } from '../build.js';
7
+ import { loadProject, resolveFromApp } from '../project.js';
8
+ import { freePort, waitForPort } from '../util/net.js';
9
+ import { CliError, info, step, success, warn } from '../util/output.js';
10
+ import { scheduleCrons } from './crons.js';
11
+ import { tsxArgs } from './entries.js';
12
+ import { localEnv, startLocalStage } from './local-stage.js';
13
+ import { prefixer } from './pretty.js';
14
+ import { killTree } from './proc.js';
15
+ import { localRouteRecord, startLocalRouter } from './router.js';
16
+ import { startLocalWorker, startWorkerDispatch } from './worker.js';
17
+ export const DEV_CONTROL_PREFIX = '/__plat_dev/';
18
+ /**
19
+ * `plat dev`: the whole app locally against the AWS Emulator.
20
+ *
21
+ * emulator ← engine (same code as prod; `webMode: 'external'`)
22
+ * web server (SDK wrapper, tsx watch) ─┐
23
+ * frontend dev server (web.dev) ───────┼─ local router (core `decide()`)
24
+ * local sign-in page ──────────────────┘
25
+ * worker (real Node, tsx watch) ← dispatcher (emulator SQS + EventBridge tap + local crons)
26
+ */
27
+ export async function runDev(opts) {
28
+ const { root, manifest } = loadProject(opts.cwd);
29
+ const children = [];
30
+ const cleanups = [];
31
+ let stage;
32
+ let router;
33
+ let shuttingDown = false;
34
+ const shutdown = async (code = 0) => {
35
+ if (shuttingDown)
36
+ return;
37
+ shuttingDown = true;
38
+ info(pc.dim('\nstopping…'));
39
+ for (const fn of cleanups)
40
+ await fn();
41
+ for (const c of children)
42
+ killTree(c);
43
+ router?.close();
44
+ await stage?.stop();
45
+ process.exit(code);
46
+ };
47
+ process.once('SIGINT', () => void shutdown(0));
48
+ process.once('SIGTERM', () => void shutdown(0));
49
+ try {
50
+ step('starting the AWS Emulator');
51
+ stage = await startLocalStage({
52
+ root,
53
+ manifest,
54
+ stage: LOCAL_STAGE,
55
+ port: opts.port,
56
+ log: (e) => {
57
+ if (e.level !== 'info' || process.env.PLAT_DEV_VERBOSE)
58
+ info(pc.dim(` engine ${e.level}: ${e.msg}`));
59
+ },
60
+ });
61
+ }
62
+ catch (err) {
63
+ await stage?.stop();
64
+ if (err.message === EMULATOR_INSTALL_HINT) {
65
+ throw new CliError('the AWS Emulator is not installed', { hint: EMULATOR_INSTALL_HINT });
66
+ }
67
+ throw err;
68
+ }
69
+ success(`provisioned ${manifest.name} (${stage.result.resources.length} resources) in the emulator`);
70
+ const state = {
71
+ record: localRouteRecord({
72
+ app: manifest.name,
73
+ stage: LOCAL_STAGE,
74
+ deploymentId: stage.deploymentId,
75
+ hasServer: !!manifest.web?.server,
76
+ hasStatic: !!(manifest.web?.static || manifest.web?.dev),
77
+ serverRoutes: manifest.web?.serverRoutes ?? ['/api/'],
78
+ spa: manifest.web?.spa ?? true,
79
+ }),
80
+ ...(manifest.web?.static ? { staticDir: resolve(root, manifest.web.static) } : {}),
81
+ };
82
+ // ------------------------------------------------------------ worker
83
+ let dispatcher;
84
+ let workerPort;
85
+ if (manifest.worker) {
86
+ const worker = await startLocalWorker(stage, manifest, root);
87
+ workerPort = worker.port;
88
+ children.push(worker.child);
89
+ const out = prefixer(pc.yellow('worker│'), (s) => process.stdout.write(s), { spans: opts.spans });
90
+ worker.child.stdout.on('data', out);
91
+ worker.child.stderr.on('data', out);
92
+ dispatcher = await startWorkerDispatch(stage, manifest, worker, (kind, name, outcome, detail) => {
93
+ if (outcome === 'error')
94
+ warn(`${kind} ${name} failed${detail ? `: ${detail}` : ''}`);
95
+ });
96
+ cleanups.push(() => dispatcher?.stop());
97
+ }
98
+ const runCron = async (name) => {
99
+ if (!dispatcher)
100
+ throw new CliError('this app has no worker');
101
+ if (!manifest.crons[name]) {
102
+ throw new CliError(`no cron named ${name}`, {
103
+ hint: `crons: ${Object.keys(manifest.crons).join(', ') || '(none)'}`,
104
+ });
105
+ }
106
+ info(`${pc.magenta('cron │')} running ${name}`);
107
+ const r = await dispatcher.runCron(name);
108
+ if (!r.ok)
109
+ throw new CliError(`cron ${name} failed: ${r.error?.message}`);
110
+ };
111
+ const crons = dispatcher
112
+ ? scheduleCrons(Object.entries(manifest.crons).map(([name, c]) => ({ name, ...c })), (name) => runCron(name).catch((err) => warn(err.message)))
113
+ : undefined;
114
+ if (crons)
115
+ cleanups.push(() => crons.stop());
116
+ // ------------------------------------------------------------ web server
117
+ if (manifest.web?.server) {
118
+ const { child, port: serverPort } = await spawnWebServer(stage, manifest, root, {
119
+ ...(workerPort ? { workerUrl: `http://127.0.0.1:${workerPort}/` } : {}),
120
+ });
121
+ children.push(child);
122
+ const out = prefixer(pc.green('web │'), (s) => process.stdout.write(s), { spans: opts.spans });
123
+ child.stdout.on('data', out);
124
+ child.stderr.on('data', out);
125
+ child.once('exit', (code) => {
126
+ if (!shuttingDown)
127
+ warn(`web server exited (code ${code})`);
128
+ });
129
+ void waitForPort(serverPort, '127.0.0.1', 60_000)
130
+ .then(() => {
131
+ state.server = { host: '127.0.0.1', port: serverPort };
132
+ })
133
+ .catch((err) => warn(`web server did not start: ${err.message}`));
134
+ }
135
+ // ------------------------------------------------------------ frontend dev server
136
+ if (manifest.web?.dev) {
137
+ const { command, port } = manifest.web.dev;
138
+ const child = spawn(command, {
139
+ cwd: root,
140
+ shell: true,
141
+ detached: true,
142
+ env: withLocalBin(root, { ...process.env, PLATFORM_DEV_ROUTER: `http://localhost:${opts.port}` }),
143
+ stdio: ['ignore', 'pipe', 'pipe'],
144
+ });
145
+ children.push(child);
146
+ const out = prefixer(pc.blue('front │'), (s) => process.stdout.write(s));
147
+ child.stdout.on('data', out);
148
+ child.stderr.on('data', out);
149
+ state.webDevStarting = true;
150
+ // Dev servers often bind `localhost` (::1 on many systems); connect the same way.
151
+ void waitForPort(port, 'localhost', 60_000)
152
+ .then(() => {
153
+ state.webDev = { host: 'localhost', port };
154
+ })
155
+ .catch((err) => warn(`frontend dev server did not start: ${err.message}`))
156
+ .finally(() => {
157
+ state.webDevStarting = false;
158
+ });
159
+ }
160
+ // ------------------------------------------------------------ router
161
+ const intercept = [
162
+ async (req, res, url) => {
163
+ if (!url.pathname.startsWith(DEV_CONTROL_PREFIX))
164
+ return false;
165
+ const cron = /^\/__plat_dev\/cron\/([^/]+)$/.exec(url.pathname);
166
+ if (cron && req.method === 'POST') {
167
+ try {
168
+ await runCron(decodeURIComponent(cron[1]));
169
+ res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ ok: true }));
170
+ }
171
+ catch (err) {
172
+ res
173
+ .writeHead(400, { 'content-type': 'application/json' })
174
+ .end(JSON.stringify({ error: err.message }));
175
+ }
176
+ return true;
177
+ }
178
+ if (url.pathname === `${DEV_CONTROL_PREFIX}status`) {
179
+ res
180
+ .writeHead(200, { 'content-type': 'application/json' })
181
+ .end(JSON.stringify({ app: manifest.name, bindings: stage.bindings, emulator: stage.conn.endpoint }));
182
+ return true;
183
+ }
184
+ res.writeHead(404).end();
185
+ return true;
186
+ },
187
+ ];
188
+ // Local sign-in (`/__platform/auth/*`) is served by the SDK's server wrapper in local mode.
189
+ router = await startLocalRouter({ port: opts.port, host: '127.0.0.1', state: () => state, intercept });
190
+ printBanner(manifest, stage, opts.port, crons);
191
+ await new Promise(() => { }); // run until signalled
192
+ }
193
+ /**
194
+ * The app's server exactly as the Web Function runs it (SDK wrapper, bindings,
195
+ * `AWS_LAMBDA_HTTP_ENDPOINT`), under `tsx watch` so edits restart it.
196
+ */
197
+ export async function spawnWebServer(stage, manifest, root, opts = {}) {
198
+ if (!manifest.web?.server)
199
+ throw new Error('manifest has no web.server');
200
+ const port = await freePort();
201
+ const env = localEnv(stage, manifest, {
202
+ AWS_LAMBDA_HTTP_ENDPOINT: `127.0.0.1:${port}`,
203
+ PLATFORM_LOG_PRETTY: '1',
204
+ PLATFORM_ENTRY: resolve(root, manifest.web.server),
205
+ PLATFORM_SDK_SERVER: resolveFromApp(root, SDK_SERVER),
206
+ // `invokeJob` locally: the SDK posts here instead of invoking the emulator's sandboxed Lambda.
207
+ ...(opts.workerUrl ? { PLATFORM_LOCAL_WORKER_URL: opts.workerUrl } : {}),
208
+ });
209
+ const child = spawn(process.execPath, tsxArgs('server-entry', opts.watch !== false), {
210
+ cwd: root,
211
+ env,
212
+ detached: true,
213
+ stdio: ['ignore', 'pipe', 'pipe'],
214
+ });
215
+ return { child, port };
216
+ }
217
+ function printBanner(manifest, stage, port, crons) {
218
+ const b = stage.bindings;
219
+ const lines = [
220
+ '',
221
+ ` ${pc.bold(manifest.name)} ${pc.dim('running locally on the AWS Emulator')}`,
222
+ '',
223
+ ` ${pc.green('➜')} App: ${pc.underline(`http://${manifest.name}.localhost:${port}`)} ${pc.dim(`(or http://localhost:${port})`)}`,
224
+ ` ${pc.dim('➜')} Emulator: ${stage.conn.endpoint}`,
225
+ ];
226
+ if (b.table)
227
+ lines.push(` ${pc.dim('➜')} Database: ${b.table}`);
228
+ const queues = Object.keys(b.queues);
229
+ if (queues.length)
230
+ lines.push(` ${pc.dim('➜')} Queues: ${queues.join(', ')}`);
231
+ if (manifest.events.length)
232
+ lines.push(` ${pc.dim('➜')} Events: ${manifest.events.join(', ')}`);
233
+ if (b.storage)
234
+ lines.push(` ${pc.dim('➜')} Storage: ${b.storage.stores.join(', ')}`);
235
+ if (b.auth)
236
+ lines.push(` ${pc.dim('➜')} Auth: local sign-in at /__platform/auth/login (any email)`);
237
+ for (const name of Object.keys(manifest.crons)) {
238
+ const next = crons?.next(name);
239
+ lines.push(` ${pc.dim('➜')} Cron: ${name} ${pc.dim(`next ${next?.toISOString() ?? '?'} · now: plat dev run-cron ${name}`)}`);
240
+ }
241
+ lines.push('', pc.dim(' Ctrl+C to stop. Emulator state lives in memory and is discarded on exit.'), '');
242
+ info(lines.join('\n'));
243
+ }
244
+ /** `plat dev run-cron <name>`: ask a running `plat dev` to fire a cron now. */
245
+ export async function runCronOnDev(name, port) {
246
+ let res;
247
+ try {
248
+ res = await fetch(`http://127.0.0.1:${port}${DEV_CONTROL_PREFIX}cron/${encodeURIComponent(name)}`, {
249
+ method: 'POST',
250
+ });
251
+ }
252
+ catch {
253
+ throw new CliError(`no \`plat dev\` running on port ${port}`, {
254
+ hint: 'start it with `plat dev` (or pass --port)',
255
+ });
256
+ }
257
+ if (!res.ok) {
258
+ const body = (await res.json().catch(() => ({})));
259
+ throw new CliError(body.error ?? `HTTP ${res.status}`);
260
+ }
261
+ }
262
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { Agent } from 'node:https';
2
+ import { type Bindings, type PlatformRuntimeConfig, type ResolvedManifest } from '@ericminassian/platform-core';
3
+ import { type DeployStageResult, type EmulatorConnection, type Engine, type EngineLogEntry, type S3Location } from '@ericminassian/platform-engine';
4
+ /**
5
+ * A stage running inside a private AWS Emulator: shared platform resources
6
+ * (`ensureLocalPlatform`) plus this app's resources, created by the same
7
+ * engine that deploys to AWS. The web server runs outside the emulator
8
+ * (`webMode: 'external'`) because the emulator doesn't serve Web Function
9
+ * endpoints yet.
10
+ */
11
+ export interface LocalStage {
12
+ conn: EmulatorConnection;
13
+ engine: Engine;
14
+ platform: PlatformRuntimeConfig;
15
+ result: DeployStageResult;
16
+ bindings: Bindings;
17
+ deploymentId: string;
18
+ stage: string;
19
+ stop(): Promise<void>;
20
+ }
21
+ export interface StartLocalStageOptions {
22
+ root: string;
23
+ manifest: ResolvedManifest;
24
+ stage: 'local' | 'test';
25
+ /** Public port of the local router (used in URLs, auth redirects). */
26
+ port: number;
27
+ log?: (e: EngineLogEntry) => void;
28
+ onEmulatorLog?: (line: string) => void;
29
+ }
30
+ export declare function startLocalStage(opts: StartLocalStageOptions): Promise<LocalStage>;
31
+ export declare function uploadWorker(engine: Engine, platform: PlatformRuntimeConfig, root: string, manifest: ResolvedManifest, stage: string, deploymentId: string): Promise<S3Location>;
32
+ /** Environment for the local web server, worker tests and `plat test`. */
33
+ export declare function localEnv(stage: LocalStage, manifest: ResolvedManifest, extra?: Record<string, string>): NodeJS.ProcessEnv;
34
+ /** AWS SDK client config for talking to the emulator from the CLI process itself. */
35
+ export declare function emulatorClientConfig(conn: EmulatorConnection): {
36
+ region: string;
37
+ endpoint: string;
38
+ credentials: {
39
+ accessKeyId: string;
40
+ secretAccessKey: string;
41
+ };
42
+ requestHandler: {
43
+ httpsAgent: Agent;
44
+ };
45
+ };
46
+ export declare function readDotEnv(path: string): Record<string, string>;
@@ -0,0 +1,116 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { Agent } from 'node:https';
3
+ import { join } from 'node:path';
4
+ import { PutParameterCommand, SSMClient } from '@aws-sdk/client-ssm';
5
+ import { encodeBindings, names, newDeploymentId, } from '@ericminassian/platform-core';
6
+ import { createEngine, emulatorChildEnv, ensureLocalPlatform, startEmulator, } from '@ericminassian/platform-engine';
7
+ import { bundleWorker, zipBundle } from '../build.js';
8
+ import { CliError } from '../util/output.js';
9
+ export async function startLocalStage(opts) {
10
+ const conn = await startEmulator({ port: 0, idleTimeoutSeconds: 6 * 3600, onLog: opts.onEmulatorLog });
11
+ try {
12
+ const engine = createEngine({
13
+ region: conn.region,
14
+ emulator: { endpoint: conn.endpoint, caFile: conn.caFile, credentials: conn.credentials },
15
+ log: opts.log,
16
+ });
17
+ const platform = await ensureLocalPlatform(engine, { port: opts.port, jwksBaseUrl: conn.endpoint });
18
+ const deploymentId = newDeploymentId();
19
+ const worker = opts.manifest.worker
20
+ ? await uploadWorker(engine, platform, opts.root, opts.manifest, opts.stage, deploymentId)
21
+ : undefined;
22
+ const result = await engine.deployStage({
23
+ manifest: opts.manifest,
24
+ stage: opts.stage,
25
+ deploymentId,
26
+ platform,
27
+ artifacts: worker ? { worker } : {},
28
+ webMode: 'external',
29
+ logRetentionDays: 1,
30
+ });
31
+ await seedSecrets(conn, result.bindings, opts.root);
32
+ return {
33
+ conn,
34
+ engine,
35
+ platform,
36
+ result,
37
+ bindings: result.bindings,
38
+ deploymentId,
39
+ stage: opts.stage,
40
+ stop: () => conn.stop(),
41
+ };
42
+ }
43
+ catch (err) {
44
+ await conn.stop();
45
+ throw err;
46
+ }
47
+ }
48
+ export async function uploadWorker(engine, platform, root, manifest, stage, deploymentId) {
49
+ const dir = await bundleWorker(root, manifest, join(root, '.plat', stage, 'worker'), { minify: false });
50
+ const zip = zipBundle(dir);
51
+ return engine.putArtifact(platform, names.artifactKey(manifest.name, stage, deploymentId, 'worker.zip'), zip);
52
+ }
53
+ /** Environment for the local web server, worker tests and `plat test`. */
54
+ export function localEnv(stage, manifest, extra = {}) {
55
+ return {
56
+ ...emulatorChildEnv(stage.conn),
57
+ ...manifest.env,
58
+ PLATFORM_BINDINGS: encodeBindings(stage.bindings),
59
+ PLATFORM_LOCAL: '1',
60
+ ...extra,
61
+ };
62
+ }
63
+ /** AWS SDK client config for talking to the emulator from the CLI process itself. */
64
+ export function emulatorClientConfig(conn) {
65
+ return {
66
+ region: conn.region,
67
+ endpoint: conn.endpoint,
68
+ credentials: conn.credentials,
69
+ requestHandler: { httpsAgent: new Agent({ ca: readFileSync(conn.caFile), keepAlive: true }) },
70
+ };
71
+ }
72
+ /**
73
+ * `.env.local` (KEY=VALUE, not committed) → SecureString parameters, so
74
+ * `secrets.get()` works locally exactly as deployed. Only names declared in
75
+ * platform.json are loaded.
76
+ */
77
+ async function seedSecrets(conn, bindings, root) {
78
+ const values = readDotEnv(join(root, '.env.local'));
79
+ const declared = new Set(bindings.secrets.names);
80
+ const entries = Object.entries(values).filter(([k]) => declared.has(k));
81
+ if (entries.length === 0)
82
+ return;
83
+ const ssm = new SSMClient(emulatorClientConfig(conn));
84
+ try {
85
+ for (const [name, value] of entries) {
86
+ await ssm.send(new PutParameterCommand({
87
+ Name: `${bindings.secrets.path}${name}`,
88
+ Value: value,
89
+ Type: 'SecureString',
90
+ Overwrite: true,
91
+ }));
92
+ }
93
+ }
94
+ catch (err) {
95
+ throw new CliError(`could not load .env.local secrets into the emulator: ${err.message}`);
96
+ }
97
+ finally {
98
+ ssm.destroy();
99
+ }
100
+ }
101
+ export function readDotEnv(path) {
102
+ if (!existsSync(path))
103
+ return {};
104
+ const out = {};
105
+ for (const line of readFileSync(path, 'utf8').split(/\r?\n/)) {
106
+ const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/.exec(line);
107
+ if (!m)
108
+ continue;
109
+ let v = m[2];
110
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'")))
111
+ v = v.slice(1, -1);
112
+ out[m[1]] = v;
113
+ }
114
+ return out;
115
+ }
116
+ //# sourceMappingURL=local-stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-stage.js","sourceRoot":"","sources":["../../src/dev/local-stage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type TelemetryEvent } from '@ericminassian/platform-core';
2
+ /**
3
+ * Human formatting for telemetry lines (`{"_p":1,...}`) printed by the SDK in
4
+ * the local web server and worker. Non-telemetry lines pass through as-is.
5
+ * Returns null for lines that are noise locally (spans, Lambda START/END).
6
+ */
7
+ export declare function prettyLine(line: string, opts?: {
8
+ spans?: boolean;
9
+ }): string | null;
10
+ export declare function formatEvent(e: TelemetryEvent, opts?: {
11
+ spans?: boolean;
12
+ }): string | null;
13
+ /** Prefix every line of a child process stream. */
14
+ export declare function prefixer(label: string, write: (s: string) => void, opts?: {
15
+ spans?: boolean;
16
+ }): (chunk: Buffer | string) => void;
@@ -0,0 +1,91 @@
1
+ import { isTelemetryEvent } from '@ericminassian/platform-core';
2
+ import pc from 'picocolors';
3
+ /**
4
+ * Human formatting for telemetry lines (`{"_p":1,...}`) printed by the SDK in
5
+ * the local web server and worker. Non-telemetry lines pass through as-is.
6
+ * Returns null for lines that are noise locally (spans, Lambda START/END).
7
+ */
8
+ export function prettyLine(line, opts = {}) {
9
+ const trimmed = line.trim();
10
+ if (!trimmed)
11
+ return null;
12
+ if (/^(START|END) RequestId:/.test(trimmed))
13
+ return null;
14
+ if (trimmed.startsWith('REPORT RequestId:')) {
15
+ const dur = /Duration: ([\d.]+) ms/.exec(trimmed)?.[1];
16
+ return pc.dim(`lambda invocation ${dur ? `${Math.round(Number(dur))}ms` : 'done'}`);
17
+ }
18
+ // Lambda prefixes console output with "<ts>\t<requestId>\t<LEVEL>\t" in text log format.
19
+ const jsonStart = trimmed.indexOf('{');
20
+ if (jsonStart === -1)
21
+ return trimmed;
22
+ let parsed;
23
+ try {
24
+ parsed = JSON.parse(trimmed.slice(jsonStart));
25
+ }
26
+ catch {
27
+ return trimmed;
28
+ }
29
+ if (!isTelemetryEvent(parsed))
30
+ return trimmed;
31
+ return formatEvent(parsed, opts);
32
+ }
33
+ export function formatEvent(e, opts = {}) {
34
+ const trace = e.trace ? pc.dim(` ${e.trace.slice(0, 8)}`) : '';
35
+ switch (e.t) {
36
+ case 'req': {
37
+ const color = e.status >= 500 ? pc.red : e.status >= 400 ? pc.yellow : pc.green;
38
+ return `${pc.bold(e.method.padEnd(6))} ${e.path} ${color(String(e.status))} ${pc.dim(`${Math.round(e.dur)}ms`)}${e.cold ? pc.magenta(' cold') : ''}${trace}`;
39
+ }
40
+ case 'err': {
41
+ const head = `${pc.red('✗')} ${pc.red(`${e.name}: ${e.message}`)}${e.route ? pc.dim(` at ${e.route}`) : ''}${e.job ? pc.dim(` in ${e.job}`) : ''}${trace}`;
42
+ const stack = e.stack
43
+ ?.split('\n')
44
+ .slice(1, 4)
45
+ .map((l) => pc.dim(` ${l.trim()}`))
46
+ .join('\n');
47
+ return stack ? `${head}\n${stack}` : head;
48
+ }
49
+ case 'job': {
50
+ const status = e.status === 'ok' ? pc.green('ok') : pc.red('error');
51
+ return `${pc.cyan('job')} ${e.kind}:${e.name} ${status} ${pc.dim(`${Math.round(e.dur)}ms`)}${e.attempt && e.attempt > 1 ? pc.yellow(` attempt ${e.attempt}`) : ''}${trace}`;
52
+ }
53
+ case 'log': {
54
+ const { _p, t, ts, app, stage, rev, trace: tr, span, parent, level, msg, ...fields } = e;
55
+ const color = level === 'error'
56
+ ? pc.red
57
+ : level === 'warn'
58
+ ? pc.yellow
59
+ : level === 'debug'
60
+ ? pc.dim
61
+ : (s) => s;
62
+ const extra = Object.keys(fields).length ? pc.dim(` ${JSON.stringify(fields)}`) : '';
63
+ return `${color(level.toUpperCase().padEnd(5))} ${msg}${extra}${trace}`;
64
+ }
65
+ case 'metric':
66
+ return pc.blue(`metric ${e.name}=${e.value}${e.unit ? e.unit : ''}`);
67
+ case 'env':
68
+ return pc.dim(`${e.runtime} environment ${e.event}${e.initMs !== undefined ? ` (${Math.round(e.initMs)}ms init)` : ''}`);
69
+ case 'span':
70
+ return opts.spans
71
+ ? pc.dim(` span ${e.op}${e.name ? ` ${e.name}` : ''} ${Math.round(e.dur)}ms ${e.status}`)
72
+ : null;
73
+ }
74
+ }
75
+ /** Prefix every line of a child process stream. */
76
+ export function prefixer(label, write, opts = {}) {
77
+ let buf = '';
78
+ return (chunk) => {
79
+ buf += chunk.toString();
80
+ let idx = buf.indexOf('\n');
81
+ while (idx !== -1) {
82
+ const line = buf.slice(0, idx);
83
+ buf = buf.slice(idx + 1);
84
+ const pretty = prettyLine(line, opts);
85
+ if (pretty !== null)
86
+ write(`${label} ${pretty.split('\n').join(`\n${label} `)}\n`);
87
+ idx = buf.indexOf('\n');
88
+ }
89
+ };
90
+ }
91
+ //# sourceMappingURL=pretty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pretty.js","sourceRoot":"","sources":["../../src/dev/pretty.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+ /**
3
+ * Dev children are spawned `detached` so each leads its own process group:
4
+ * `shell: true` commands (`pnpm --dir web dev` → pnpm → vite) and `tsx watch`
5
+ * fork grandchildren that a plain `child.kill()` leaves running.
6
+ */
7
+ export declare function killTree(child: ChildProcess, signal?: NodeJS.Signals): void;