run402 2.39.2 → 2.39.3

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/ci.mjs CHANGED
@@ -240,7 +240,9 @@ jobs:
240
240
  ${environmentLine} steps:
241
241
  - uses: actions/checkout@v4
242
242
  - name: Deploy to run402
243
- run: npx --yes run402@${RUN402_VERSION} deploy apply --manifest ${shellQuote(manifest)} --project ${shellQuote(projectId)}
243
+ # Redirect stdin from /dev/null: a CI runner's stdin is a FIFO/file that
244
+ # older run402 CLIs counted as a second manifest source alongside --manifest.
245
+ run: npx --yes run402@${RUN402_VERSION} deploy apply --manifest ${shellQuote(manifest)} --project ${shellQuote(projectId)} < /dev/null
244
246
  `;
245
247
  }
246
248
 
package/lib/deploy-v2.mjs CHANGED
@@ -559,11 +559,35 @@ function parseApplyArgs(args) {
559
559
  return opts;
560
560
  }
561
561
 
562
- function applySourceField(opts) {
563
- if (opts.manifest !== null) return "manifest";
564
- if (opts.spec !== null) return "spec";
565
- if (opts.dir !== null && !hasStdinSource()) return "dir";
566
- return "stdin";
562
+ // Resolve the single manifest source from parsed opts + whether stdin actually
563
+ // has data (a pipe/file on fd 0). Explicit --manifest/--spec/--dir take
564
+ // precedence over incidental stdin: a CI runner (e.g. GitHub Actions) hands the
565
+ // step a FIFO/file stdin, which must NOT be mistaken for a piped manifest when a
566
+ // source flag is given. Exported for unit testing. Returns { source } | { error }.
567
+ export function resolveApplySource(opts, stdinPresent) {
568
+ const explicit = [];
569
+ if (opts.manifest !== null) explicit.push("--manifest");
570
+ if (opts.spec !== null) explicit.push("--spec");
571
+ if (explicit.length > 1) {
572
+ return {
573
+ error: {
574
+ code: "BAD_USAGE",
575
+ message: "Only one deploy manifest source may be provided: --manifest or --spec.",
576
+ details: { sources: explicit },
577
+ },
578
+ };
579
+ }
580
+ if (opts.manifest !== null) return { source: "manifest" };
581
+ if (opts.spec !== null) return { source: "spec" };
582
+ if (opts.dir !== null) return { source: "dir" };
583
+ if (stdinPresent) return { source: "stdin" };
584
+ return {
585
+ error: {
586
+ code: "BAD_USAGE",
587
+ message: "No deploy manifest provided. Use --manifest <path>, --spec '<json>', --dir <build>, or pipe a manifest on stdin.",
588
+ details: {},
589
+ },
590
+ };
567
591
  }
568
592
 
569
593
  async function mergeAstroReleaseSlice(spec, dirArg) {
@@ -621,29 +645,16 @@ async function mergeAstroReleaseSlice(spec, dirArg) {
621
645
  spec.functions = { replace: { ...existingFns, ...sliceFns } };
622
646
  }
623
647
 
624
- function validateApplySources(opts) {
625
- const sources = [];
626
- if (opts.manifest !== null) sources.push("--manifest");
627
- if (opts.spec !== null) sources.push("--spec");
628
- if (hasStdinSource()) sources.push("stdin");
629
- if (sources.length > 1) {
630
- fail({
631
- code: "BAD_USAGE",
632
- message: "Only one deploy manifest source may be provided: --spec, --manifest, or stdin.",
633
- details: { sources },
634
- });
635
- }
636
- }
637
-
638
648
  async function applyCmd(args) {
639
649
  const opts = parseApplyArgs(args);
640
- validateApplySources(opts);
650
+ const { source, error: sourceError } = resolveApplySource(opts, hasStdinSource());
651
+ if (sourceError) fail(sourceError);
641
652
 
642
653
  let raw;
643
654
  let manifestPath = null;
644
- if (opts.spec !== null) {
655
+ if (source === "spec") {
645
656
  raw = opts.spec;
646
- } else if (opts.manifest !== null) {
657
+ } else if (source === "manifest") {
647
658
  try {
648
659
  manifestPath = isAbsolute(opts.manifest) ? opts.manifest : resolve(process.cwd(), opts.manifest);
649
660
  raw = readFileSync(manifestPath, "utf-8");
@@ -654,11 +665,12 @@ async function applyCmd(args) {
654
665
  details: { flag: "--manifest", path: opts.manifest },
655
666
  });
656
667
  }
657
- } else if (opts.dir !== null && !hasStdinSource()) {
658
- // --dir without any other source: start from an empty spec and let the
668
+ } else if (source === "dir") {
669
+ // --dir without --manifest/--spec: start from an empty spec and let the
659
670
  // Astro release-slice fill in site/functions/routes below.
660
671
  raw = "{}";
661
672
  } else {
673
+ // source === "stdin": a manifest piped on stdin.
662
674
  raw = await readStdin();
663
675
  }
664
676
 
@@ -669,11 +681,11 @@ async function applyCmd(args) {
669
681
  fail({
670
682
  code: "BAD_USAGE",
671
683
  message: `Manifest is not valid JSON: ${err.message}`,
672
- details: { source: applySourceField(opts), parse_error: err.message },
684
+ details: { source, parse_error: err.message },
673
685
  });
674
686
  }
675
687
  rejectLegacySecretManifest(spec, {
676
- source: applySourceField(opts),
688
+ source,
677
689
  ...(manifestPath ? { path: manifestPath } : {}),
678
690
  });
679
691
 
@@ -720,7 +732,7 @@ async function applyCmd(args) {
720
732
  message: `Manifest contains no deployable sections. Expected at least one of: ${meaningful.join(", ")}`,
721
733
  hint: "Did you mean to write a 'site.replace' or 'database.migrations' block? See https://run402.com/schemas/manifest.v1.json",
722
734
  details: {
723
- field: applySourceField(opts),
735
+ field: source,
724
736
  ...(manifestPath ? { path: manifestPath } : {}),
725
737
  meaningful_keys: meaningful,
726
738
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "2.39.2",
3
+ "version": "2.39.3",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {