@saastemly/voidcommerce 0.15.0 → 0.16.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/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  runVoid,
22
22
  version,
23
23
  voidAppsIn
24
- } from "./index-jycz3x3g.js";
24
+ } from "./index-w0c96dxv.js";
25
25
  import {
26
26
  LOCAL_KEY_FILE,
27
27
  PRIVATE_KEY_VAR,
@@ -1379,7 +1379,7 @@ import color from "picocolors";
1379
1379
  // package.json
1380
1380
  var package_default = {
1381
1381
  name: "@saastemly/voidcommerce",
1382
- version: "0.15.0",
1382
+ version: "0.16.1",
1383
1383
  description: "Void, with a shop in it. `vc init` walks you through Better Auth, betterCommerce and every plugin; everything else passes through to `void`.",
1384
1384
  type: "module",
1385
1385
  license: "MIT",
@@ -1712,8 +1712,10 @@ function renderDistWorkflow(manifest) {
1712
1712
 
1713
1713
  # Generated by \`vc init\` from voidcommerce.json.
1714
1714
  #
1715
- # A push to main regenerates the Void app from the manifest, publishes it to
1716
- # \`${DIST_BRANCH}\` as a standalone tree, and deploys it to Cloudflare.
1715
+ # A push to main is checked, then regenerates the Void app from the manifest,
1716
+ # publishes it to \`${DIST_BRANCH}\` as a standalone tree, and deploys it to
1717
+ # Cloudflare. The check runs FIRST and on its own: nothing is built, created
1718
+ # or replaced for a shop that is not ready.
1717
1719
  #
1718
1720
  # The credentials come from the repository, set once by \`vc link\`:
1719
1721
  #
@@ -1738,8 +1740,32 @@ permissions:
1738
1740
  contents: write
1739
1741
 
1740
1742
  jobs:
1743
+ # ── Is what was just pushed fit to deploy? ─────────────────────────────
1744
+ #
1745
+ # First, and on its own, because everything after it costs something: a
1746
+ # build, a database, a worker replaced. It answers the question the deploy
1747
+ # would ask, against exactly what was pushed, and needs NO CREDENTIALS to
1748
+ # do it — config lives in the repository, encrypted, so readiness is a
1749
+ # property of the commit rather than of whoever pushed it.
1750
+ #
1751
+ # This is the gate. It cannot be skipped with --no-verify, and it runs the
1752
+ # same way for every push and every person.
1753
+ preflight:
1754
+ runs-on: ubuntu-latest
1755
+ steps:
1756
+ - uses: actions/checkout@v6
1757
+ - uses: oven-sh/setup-bun@v2
1758
+ - run: bun install --frozen-lockfile
1759
+
1760
+ # Every required key actually SET rather than merely declared, nothing
1761
+ # committed in the clear, the hostnames the manifest says, and no
1762
+ # migration generated but left uncommitted.
1763
+ - name: vc preflight --repo
1764
+ run: bunx vc preflight --repo
1765
+
1741
1766
  # ── Regenerate, and publish the standalone tree ────────────────────────
1742
1767
  dist:
1768
+ needs: preflight
1743
1769
  runs-on: ubuntu-latest
1744
1770
  steps:
1745
1771
  - uses: actions/checkout@v6
@@ -1839,7 +1865,12 @@ regenerate with \`vc generate\`.
1839
1865
  git push
1840
1866
  \`\`\`
1841
1867
 
1842
- That is the deploy. GitHub Actions regenerates the app from
1868
+ That is the deploy. It is checked first: a \`preflight\` job runs before
1869
+ anything is built, and refuses a shop whose secrets are declared but unset,
1870
+ whose values were committed in the clear, or whose migrations are not all
1871
+ committed. It needs no credentials — readiness is a property of the commit,
1872
+ not of the machine that pushed it — so it fails the same way for everyone,
1873
+ and cannot be skipped. GitHub Actions regenerates the app from
1843
1874
  \`voidcommerce.json\`, publishes a standalone copy to \`${DIST_BRANCH}\`, creates the
1844
1875
  database and queue if they are not there, applies the migrations, and deploys
1845
1876
  the worker with this repository's secrets attached.
@@ -2449,25 +2480,7 @@ async function generateHooks(root, result) {
2449
2480
  # history and has to be treated as burned.
2450
2481
  bunx vc guard
2451
2482
  `, result, "regenerate");
2452
- await put(root, ".husky/pre-push", `#!/usr/bin/env sh
2453
- # Generated by \`vc init\`.
2454
- #
2455
- # Pushing main deploys this shop, so the same checks the deploy would make
2456
- # run here first — where you can read the error and fix it, rather than in a
2457
- # build log after the shop is already updating.
2458
- #
2459
- # Needs no credentials: it reads only what is committed.
2460
- # To push anyway, deliberately: git push --no-verify
2461
-
2462
- while read -r _local_ref _local_sha remote_ref _remote_sha; do
2463
- case "$remote_ref" in
2464
- refs/heads/main|refs/heads/master)
2465
- echo "vc: main is the deploy branch — checking what you are about to publish"
2466
- bunx vc preflight --repo || exit 1
2467
- ;;
2468
- esac
2469
- done
2470
- `, result, "regenerate");
2483
+ await retire(root, ".husky/pre-push", result);
2471
2484
  }
2472
2485
  async function generate(root, manifest) {
2473
2486
  const result = { written: [], kept: [], retired: [], packages: packagesOf(manifest) };
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ import {
52
52
  routeProblem,
53
53
  strictDependencies,
54
54
  upsertJsonc
55
- } from "./index-jycz3x3g.js";
55
+ } from "./index-w0c96dxv.js";
56
56
  import {
57
57
  allEnvKeys,
58
58
  envSummary,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saastemly/voidcommerce",
3
- "version": "0.15.0",
3
+ "version": "0.16.1",
4
4
  "description": "Void, with a shop in it. `vc init` walks you through Better Auth, betterCommerce and every plugin; everything else passes through to `void`.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -66,11 +66,14 @@ export async function preflightCommand(args: string[]): Promise<number> {
66
66
  printPreflight(project, result, source);
67
67
  if (source !== "repository") return result.ready ? 0 : 1;
68
68
 
69
- // A repository check is a check on what will be PUSHED, so it also asks
70
- // the question CI would ask and cannot answer any earlier: is there a
71
- // migration that was generated and never committed? Applied under a fresh
72
- // name on the next run, against tables that already exist, it fails the
73
- // deploy and it fails it after the shop is already down for the update.
69
+ // Is there a migration that was generated and never committed?
70
+ //
71
+ // This one has teeth only LOCALLY. A CI checkout is by definition clean,
72
+ // so `git status` there reports nothing and this passes vacuously the
73
+ // job that actually catches it in CI is the one that runs AFTER `vc dist`
74
+ // regenerates, because that is the moment a new migration can appear.
75
+ // Both are kept: they catch the same mistake at the two different moments
76
+ // it can be made.
74
77
  const pending = await uncommittedMigrations(project.root);
75
78
  if (pending.length > 0) {
76
79
  console.error(
@@ -42,8 +42,10 @@ export function renderDistWorkflow(manifest: Manifest): string {
42
42
 
43
43
  # Generated by \`vc init\` from voidcommerce.json.
44
44
  #
45
- # A push to main regenerates the Void app from the manifest, publishes it to
46
- # \`${DIST_BRANCH}\` as a standalone tree, and deploys it to Cloudflare.
45
+ # A push to main is checked, then regenerates the Void app from the manifest,
46
+ # publishes it to \`${DIST_BRANCH}\` as a standalone tree, and deploys it to
47
+ # Cloudflare. The check runs FIRST and on its own: nothing is built, created
48
+ # or replaced for a shop that is not ready.
47
49
  #
48
50
  # The credentials come from the repository, set once by \`vc link\`:
49
51
  #
@@ -68,8 +70,32 @@ permissions:
68
70
  contents: write
69
71
 
70
72
  jobs:
73
+ # ── Is what was just pushed fit to deploy? ─────────────────────────────
74
+ #
75
+ # First, and on its own, because everything after it costs something: a
76
+ # build, a database, a worker replaced. It answers the question the deploy
77
+ # would ask, against exactly what was pushed, and needs NO CREDENTIALS to
78
+ # do it — config lives in the repository, encrypted, so readiness is a
79
+ # property of the commit rather than of whoever pushed it.
80
+ #
81
+ # This is the gate. It cannot be skipped with --no-verify, and it runs the
82
+ # same way for every push and every person.
83
+ preflight:
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@v6
87
+ - uses: oven-sh/setup-bun@v2
88
+ - run: bun install --frozen-lockfile
89
+
90
+ # Every required key actually SET rather than merely declared, nothing
91
+ # committed in the clear, the hostnames the manifest says, and no
92
+ # migration generated but left uncommitted.
93
+ - name: vc preflight --repo
94
+ run: bunx vc preflight --repo
95
+
71
96
  # ── Regenerate, and publish the standalone tree ────────────────────────
72
97
  dist:
98
+ needs: preflight
73
99
  runs-on: ubuntu-latest
74
100
  steps:
75
101
  - uses: actions/checkout@v6
@@ -171,7 +197,12 @@ regenerate with \`vc generate\`.
171
197
  git push
172
198
  \`\`\`
173
199
 
174
- That is the deploy. GitHub Actions regenerates the app from
200
+ That is the deploy. It is checked first: a \`preflight\` job runs before
201
+ anything is built, and refuses a shop whose secrets are declared but unset,
202
+ whose values were committed in the clear, or whose migrations are not all
203
+ committed. It needs no credentials — readiness is a property of the commit,
204
+ not of the machine that pushed it — so it fails the same way for everyone,
205
+ and cannot be skipped. GitHub Actions regenerates the app from
175
206
  \`voidcommerce.json\`, publishes a standalone copy to \`${DIST_BRANCH}\`, creates the
176
207
  database and queue if they are not there, applies the migrations, and deploys
177
208
  the worker with this repository's secrets attached.
@@ -229,46 +229,10 @@ bunx vc guard
229
229
  result,
230
230
  "regenerate",
231
231
  );
232
- /**
233
- * Pushing main IS the deploy, so this is the last moment anything is
234
- * checked by someone who can read the error.
235
- *
236
- * Everything the deploy needs is in the repository — that is the whole
237
- * point of keeping config in the environment — so the check needs no
238
- * credentials and runs anywhere. It asks the questions CI cannot answer
239
- * until it is too late to matter: is every required key actually SET
240
- * rather than merely declared, is anything committed in the clear, do the
241
- * hostnames match the manifest, is a migration missing.
242
- *
243
- * Only for main. Pushing a branch is not a deploy, and gating it would
244
- * teach people to reach for --no-verify, which turns the gate off for the
245
- * push that does matter.
246
- */
247
- await put(
248
- root,
249
- ".husky/pre-push",
250
- `#!/usr/bin/env sh
251
- # Generated by \`vc init\`.
252
- #
253
- # Pushing main deploys this shop, so the same checks the deploy would make
254
- # run here first — where you can read the error and fix it, rather than in a
255
- # build log after the shop is already updating.
256
- #
257
- # Needs no credentials: it reads only what is committed.
258
- # To push anyway, deliberately: git push --no-verify
259
-
260
- while read -r _local_ref _local_sha remote_ref _remote_sha; do
261
- case "$remote_ref" in
262
- refs/heads/main|refs/heads/master)
263
- echo "vc: main is the deploy branch — checking what you are about to publish"
264
- bunx vc preflight --repo || exit 1
265
- ;;
266
- esac
267
- done
268
- `,
269
- result,
270
- "regenerate",
271
- );
232
+ // The pre-PUSH gate lives in CI now: the deploy runs off-machine, so the
233
+ // authoritative check belongs there, where nobody can --no-verify past it.
234
+ // See renderDistWorkflow.
235
+ await retire(root, ".husky/pre-push", result);
272
236
  }
273
237
 
274
238
  export async function generate(root: string, manifest: Manifest): Promise<GenerateResult> {