run402 4.128.0 → 4.128.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/dev.mjs CHANGED
@@ -19,7 +19,7 @@
19
19
  * @run402/functions's default API_BASE.
20
20
  */
21
21
 
22
- import { spawn } from "node:child_process";
22
+ import { spawn, spawnSync } from "node:child_process";
23
23
  import { existsSync, readFileSync } from "node:fs";
24
24
  import { resolve } from "node:path";
25
25
  import { fail, reportLocalOrSdkError } from "./sdk-errors.mjs";
@@ -47,7 +47,10 @@ The command:
47
47
  2. Verifies RUN402_PROJECT_ID and RUN402_SERVICE_KEY are set
48
48
  3. With --as, mints a 2-hour test session and passes it to the dev server
49
49
  (server-side only: the browser never holds the token or the service key)
50
- 4. Spawns 'astro dev' with the env inherited
50
+ 4. Stops an Astro dev server already running for this project (it keeps
51
+ the environment it started with), then spawns 'astro dev' with the env
52
+ inherited. Under an AI agent Astro runs it in the background: stop it
53
+ with 'npx astro dev stop'
51
54
 
52
55
  SDK calls (db, getUser, cache.invalidate, assets.put) hit the LIVE
53
56
  project at https://api.run402.com — no local DB / S3 / KMS setup needed.
@@ -100,7 +103,7 @@ export async function run(sub, args = []) {
100
103
  fail({
101
104
  code: "BAD_USAGE",
102
105
  message: "Missing RUN402_SERVICE_KEY.",
103
- hint: "Add it to .env.local. Get the service key from 'run402 projects list' or your Run402 dashboard.",
106
+ hint: "Add it to .env.local. Print the project's keys with 'run402 credentials project-keys export --project <project_id> --reveal'.",
104
107
  });
105
108
  }
106
109
 
@@ -122,7 +125,7 @@ export async function run(sub, args = []) {
122
125
  fail({
123
126
  code: "BAD_USAGE",
124
127
  message: "Missing RUN402_ANON_KEY.",
125
- hint: "run402 dev --as signs db() calls in as the test user, which needs the anon key. Add it to .env.local; get it from 'run402 projects list'.",
128
+ hint: "run402 dev --as signs db() calls in as the test user, which needs the anon key. Add it to .env.local; print the project's keys with 'run402 credentials project-keys export --project <project_id> --reveal'.",
126
129
  });
127
130
  }
128
131
  try {
@@ -144,6 +147,12 @@ export async function run(sub, args = []) {
144
147
  if (signedInAs) {
145
148
  console.log(` signed in as: ${signedInAs.user.email} (test user, until ${signedInAs.expires_at})`);
146
149
  }
150
+ // A dev server Astro already runs for this project keeps the environment it
151
+ // started with, so a new `run402 dev` would silently serve the old identity.
152
+ const running = restartRunningDevServer(process.cwd());
153
+ if (running) {
154
+ console.log(` restarted: the dev server already running (pid ${running.pid}) kept its old environment`);
155
+ }
147
156
  console.log("");
148
157
 
149
158
  // Spawn `npx astro dev`. We use `npx` so the local astro install resolves
@@ -206,6 +215,44 @@ export async function mintDevTestSession({ projectId, label, keys, sdk }) {
206
215
  };
207
216
  }
208
217
 
218
+ /**
219
+ * The Astro dev server already running for the project in `cwd`, read from
220
+ * the lock file Astro 7.4+ writes (`.astro/dev.json`), or null. Astro starts
221
+ * `astro dev` in the background when it detects an agent, so such a server
222
+ * outlives the `run402 dev` that started it.
223
+ */
224
+ export function runningAstroDevServer(cwd) {
225
+ const lockFile = resolve(cwd, ".astro", "dev.json");
226
+ if (!existsSync(lockFile)) return null;
227
+ try {
228
+ const lock = JSON.parse(readFileSync(lockFile, "utf-8"));
229
+ if (!Number.isInteger(lock.pid) || lock.pid <= 0) return null;
230
+ process.kill(lock.pid, 0); // throws when the process is gone
231
+ return { pid: lock.pid, url: typeof lock.url === "string" ? lock.url : null, background: lock.background === true };
232
+ } catch {
233
+ return null;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Stop the running dev server (if any) with `astro dev stop`, so the one
239
+ * `run402 dev` starts next carries this invocation's environment. Returns
240
+ * the server it stopped, or null when none was running.
241
+ */
242
+ export function restartRunningDevServer(cwd, { run = (cmd, args) => spawnSync(cmd, args, { cwd, stdio: "ignore" }) } = {}) {
243
+ const running = runningAstroDevServer(cwd);
244
+ if (!running) return null;
245
+ run("npx", ["astro", "dev", "stop"]);
246
+ if (runningAstroDevServer(cwd)) {
247
+ fail({
248
+ code: "DEV_SERVER_RESTART_FAILED",
249
+ message: `An Astro dev server is already running for this project (pid ${running.pid}) and could not be stopped; it would keep serving with its old environment.`,
250
+ hint: "Stop it with 'npx astro dev stop' (or end pid " + running.pid + "), then run 'run402 dev' again.",
251
+ });
252
+ }
253
+ return running;
254
+ }
255
+
209
256
  function pickFlagValue(args, flag) {
210
257
  const idx = args.indexOf(flag);
211
258
  if (idx === -1) return undefined;
@@ -40,7 +40,7 @@ The scaffolded project includes:
40
40
  - astro.config.mjs (one-line @run402/astro preset)
41
41
  - src/pages/index.astro (hello page)
42
42
  - src/pages/[slug].astro (DB-backed dynamic page template)
43
- - .env.example (RUN402_PROJECT_ID + RUN402_SERVICE_KEY placeholders)
43
+ - .env.example (RUN402_PROJECT_ID + RUN402_SERVICE_KEY + RUN402_ANON_KEY placeholders)
44
44
 
45
45
  After scaffolding:
46
46
  cd <dir>
@@ -118,8 +118,10 @@ export default run402();
118
118
  path: ".env.example",
119
119
  content: `# Run402 project credentials. Copy to .env.local for 'run402 dev'.
120
120
  # In production, these are injected automatically.
121
+ # Print the keys with: run402 credentials project-keys export --project <project_id> --reveal
121
122
  RUN402_PROJECT_ID=prj_...
122
123
  RUN402_SERVICE_KEY=...
124
+ RUN402_ANON_KEY=...
123
125
  `,
124
126
  },
125
127
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "4.128.0",
3
+ "version": "4.128.1",
4
4
  "description": "CLI for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "surface_version": "4.128.0",
2
+ "surface_version": "4.128.1",
3
3
  "verbs": [
4
4
  "repos create",
5
5
  "repos list",