@everystack/server 0.4.17 → 0.4.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everystack/server",
3
- "version": "0.4.17",
3
+ "version": "0.4.19",
4
4
  "description": "Server runtime primitives for Lambda — event adapters, routing, SSR, image processing",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": "Scalable Technology, Inc. <licensing@scalable.technology>",
@@ -163,8 +163,8 @@
163
163
  "sst": "4.13.1",
164
164
  "ts-jest": "29.4.9",
165
165
  "typescript": "5.9.3",
166
- "@everystack/cli": "0.4.47",
167
- "@everystack/auth": "0.4.1"
166
+ "@everystack/auth": "0.4.2",
167
+ "@everystack/cli": "0.4.49"
168
168
  },
169
169
  "scripts": {
170
170
  "test": "jest",
package/src/index.ts CHANGED
@@ -336,11 +336,13 @@ export function createLambdaHandler(
336
336
  'cache-control': 'no-store',
337
337
  'x-request-id': requestId,
338
338
  },
339
+ // The error itself is already logged above against this same id, which `logs:query
340
+ // --traceId` looks up directly. Returning it here too would only copy it into an
341
+ // untrusted channel. The id goes in the BODY as well as the header because most clients
342
+ // surface a body and drop headers, and a caller who cannot quote the id cannot be helped.
339
343
  body: JSON.stringify({
340
344
  error: 'Internal Server Error',
341
- ...(process.env.ENVIRONMENT === 'dev'
342
- ? { details: String(error) }
343
- : {}),
345
+ requestId,
344
346
  }),
345
347
  };
346
348
  }
package/src/plugin.ts CHANGED
@@ -315,11 +315,11 @@ export function createPluginLambdaHandler(
315
315
  'cache-control': 'no-store',
316
316
  'x-request-id': requestId,
317
317
  },
318
+ // See the note on the same catch in index.ts: the error is already logged against this
319
+ // id, and `logs:query --traceId` resolves it. The id rides the body as well as the header.
318
320
  body: JSON.stringify({
319
321
  error: 'Internal Server Error',
320
- ...(process.env.ENVIRONMENT === 'dev'
321
- ? { details: String(error) }
322
- : {}),
322
+ requestId,
323
323
  }),
324
324
  };
325
325
  }
@@ -481,6 +481,24 @@ export interface DbPluginOptions {
481
481
  connectionInfo?: () => Promise<Record<string, string>>;
482
482
  /** Enable console action (default: true) */
483
483
  allowConsole?: boolean;
484
+ /**
485
+ * Enable the `seed` action. Default FALSE.
486
+ *
487
+ * Previously gated on `ctx.environment !== 'dev'` — i.e. on the stage being NAMED `dev`.
488
+ * `ENVIRONMENT` comes from `$app.stage`, so that refused a genuine dev stage called
489
+ * `development` and allowed a shared pre-prod someone happened to call `dev`. Declare the
490
+ * intent instead of naming a stage into it.
491
+ */
492
+ allowSeed?: boolean;
493
+ /**
494
+ * Enable the `db:reset` action, which runs `DROP SCHEMA ... CASCADE` on every schema in
495
+ * `schemas` and replays migrations. Default FALSE. **There is no undo.**
496
+ *
497
+ * Same history as `allowSeed`, higher stakes: a stage name decided whether a destructive verb
498
+ * was reachable. IAM already controls who may invoke the action at all; this controls whether
499
+ * the deployment offers it in the first place.
500
+ */
501
+ allowReset?: boolean;
484
502
  /** Optional read-replica URL for db:query. When unset, db:query runs on the operator
485
503
  * connection. (No env fallback — pass it explicitly if you have a replica.) */
486
504
  readDatabaseUrl?: string;
@@ -581,17 +599,28 @@ export function dbPlugin(options: DbPluginOptions): Plugin {
581
599
  if (options.seed) {
582
600
  const seedFn = options.seed;
583
601
  actions.seed = async (_payload, ctx) => {
584
- if (ctx.environment !== 'dev') {
585
- return { error: 'Seed is only available in dev environment' };
602
+ if (!options.allowSeed) {
603
+ return {
604
+ error:
605
+ 'seed is not enabled on this deployment. Pass `allowSeed: true` to dbPlugin for the '
606
+ + 'stages where seeding is intended. (This was previously allowed whenever the stage '
607
+ + 'was NAMED "dev", which is a deployment label, not a decision.)',
608
+ };
586
609
  }
587
610
  return await seedFn(opsDb, ctx.schema);
588
611
  };
589
612
  }
590
613
 
591
614
  // --- db:reset ---
592
- actions['db:reset'] = async (_payload, ctx) => {
593
- if (ctx.environment !== 'dev') {
594
- return { error: 'db:reset is only available in dev environment' };
615
+ actions['db:reset'] = async (_payload, _ctx) => {
616
+ if (!options.allowReset) {
617
+ return {
618
+ error:
619
+ 'db:reset is not enabled on this deployment. It DROPS every schema in `schemas` and '
620
+ + 'replays migrations, and there is no undo. Pass `allowReset: true` to dbPlugin only '
621
+ + 'on stages where that is acceptable. (This was previously allowed whenever the stage '
622
+ + 'was NAMED "dev", which is a deployment label, not a decision.)',
623
+ };
595
624
  }
596
625
  // Refuse BEFORE the drop: reset replays migrations after wiping the schemas — with no
597
626
  // migrations there is nothing to rebuild from, and the drop would strand the database.