@b9g/shovel 0.2.15 → 0.2.17

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/CHANGELOG.md CHANGED
@@ -2,6 +2,51 @@
2
2
 
3
3
  All notable changes to Shovel will be documented in this file.
4
4
 
5
+ ## [0.2.17] - 2026-02-26
6
+
7
+ ### Bug Fixes
8
+
9
+ - **`@b9g/shovel`** - Config expressions (e.g. `"$MODE == production"`) now work in boolean build fields (`build.minify`, `build.treeShaking`, `build.sourcemap`). Schema validation was running before expression evaluation; now expressions are evaluated first (closes #69)
10
+
11
+ ## [0.2.16] - 2026-02-26
12
+
13
+ ### Bug Fixes
14
+
15
+ - **`@b9g/shovel`** - `build.minify` config in `shovel.json` now propagates to client asset builds. Previously client JS/CSS was always minified regardless of the setting (closes #67)
16
+
17
+ ## @b9g/router 0.2.5 - 2026-02-25
18
+
19
+ ### Bug Fixes
20
+
21
+ - **`@b9g/router`** - Trailing slash middleware now also redirects when a catch-all route or error-handling middleware returns a 404 Response (not just thrown `NotFound` errors). In 0.2.4 the middleware only caught thrown errors, so catch-all routes returning 404 responses would not trigger the redirect
22
+
23
+ ## @b9g/router 0.2.4 - 2026-02-25
24
+
25
+ ### Bug Fixes
26
+
27
+ - **`@b9g/router`** - Trailing slash middleware now only redirects as a last resort. Previously it eagerly redirected before route matching, so routes explicitly defined with (or without) a trailing slash would always be redirected. Now the middleware yields to route matching first and only redirects on 404
28
+ - **`@b9g/router`** - Added `"append"` as an alias for `"add"` in `trailingSlash()` mode
29
+
30
+ ## [0.2.15] - 2026-02-25
31
+
32
+ ### Bug Fixes
33
+
34
+ - **`create-shovel`** - Fixed linting in generated JS projects (missing browser globals)
35
+ - **`create-shovel`** - Fixed linting in generated Crank projects (now uses `eslint-plugin-crank`)
36
+ - **`create-shovel`** - Fixed Crank `Counter` to use `this.refresh()` callback pattern
37
+
38
+ ## [0.2.14] - 2026-02-24
39
+
40
+ ### Features
41
+
42
+ - **`create-shovel`** - All static-site and full-stack templates now use bundled client entry points through Shovel's asset pipeline instead of CDN links or inline scripts
43
+ - **`create-shovel`** - Added type declarations (`env.d.ts`) for htmx and Alpine in TypeScript projects
44
+ - **`create-shovel`** - Generated projects include ESLint configuration
45
+
46
+ ### Bug Fixes
47
+
48
+ - **`@b9g/platform`** - Added `Window.addEventListener` overload for ServiceWorker event types in `globals.d.ts`
49
+
5
50
  ## [0.2.13] - 2026-02-24
6
51
 
7
52
  ### Bug Fixes
package/bin/cli.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  DEFAULTS,
6
6
  findProjectRoot,
7
7
  loadConfig
8
- } from "../src/_chunks/chunk-7GONPLNW.js";
8
+ } from "../src/_chunks/chunk-ZOLZXZ6E.js";
9
9
 
10
10
  // bin/cli.ts
11
11
  import { resolve, relative } from "path";
@@ -75,7 +75,7 @@ program.command("develop <entrypoint>").description("Start development server wi
75
75
  DEFAULTS.WORKERS
76
76
  ).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").action(async (entrypoint, options) => {
77
77
  checkPlatformReexec(options);
78
- const { developCommand } = await import("../src/_chunks/develop-I74XUWOE.js");
78
+ const { developCommand } = await import("../src/_chunks/develop-BLCM4BBB.js");
79
79
  await developCommand(entrypoint, options, config);
80
80
  });
81
81
  program.command("create [name]").description("Create a new Shovel project").action(async (name) => {
@@ -91,7 +91,7 @@ program.command("build <entrypoint>").description("Build app for production").op
91
91
  "Run ServiceWorker lifecycle after build (install or activate, default: activate)"
92
92
  ).action(async (entrypoint, options) => {
93
93
  checkPlatformReexec(options);
94
- const { buildCommand } = await import("../src/_chunks/build-YOORTV6F.js");
94
+ const { buildCommand } = await import("../src/_chunks/build-FZTZ3R4X.js");
95
95
  await buildCommand(entrypoint, options, config);
96
96
  process.exit(0);
97
97
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b9g/shovel",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "ServiceWorker-first universal deployment platform. Write ServiceWorker apps once, deploy anywhere (Node/Bun/Cloudflare). Registry-based multi-app orchestration.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,7 +35,7 @@
35
35
  "@b9g/assets": "^0.2.1",
36
36
  "@b9g/crank": "^0.7.7",
37
37
  "@b9g/libuild": "^0.1.24",
38
- "@b9g/router": "^0.2.3",
38
+ "@b9g/router": "^0.2.5",
39
39
  "@eslint/js": "^9.0.0",
40
40
  "@logtape/file": "^2.0.0",
41
41
  "@types/bun": "^1.3.4",
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  ServerBundler,
3
3
  loadPlatformModule
4
- } from "./chunk-DRCLXHTF.js";
4
+ } from "./chunk-RAQUFQW6.js";
5
5
  import {
6
6
  findProjectRoot,
7
7
  findWorkspaceRoot
8
- } from "./chunk-7GONPLNW.js";
8
+ } from "./chunk-ZOLZXZ6E.js";
9
9
 
10
10
  // src/commands/build.ts
11
11
  import { resolve, join, dirname, basename } from "path";
@@ -4,7 +4,7 @@ import {
4
4
  generateStorageTypes,
5
5
  getNodeModulesPath,
6
6
  loadRawConfig
7
- } from "./chunk-7GONPLNW.js";
7
+ } from "./chunk-ZOLZXZ6E.js";
8
8
 
9
9
  // src/utils/bundler.ts
10
10
  import * as ESBuild2 from "esbuild";
@@ -44,6 +44,7 @@ function normalizePath(basePath) {
44
44
  }
45
45
  function assetsPlugin(options = {}) {
46
46
  const outDir = options.outDir ?? "dist";
47
+ const minify = options.minify ?? true;
47
48
  const sharedManifest = options.sharedManifest;
48
49
  const manifest = {
49
50
  assets: {},
@@ -114,7 +115,7 @@ function assetsPlugin(options = {}) {
114
115
  target: ["es2022", "chrome90"],
115
116
  platform: "browser",
116
117
  write: false,
117
- minify: true,
118
+ minify,
118
119
  // outdir is required for esbuild to know where to put extracted CSS and chunks
119
120
  outdir: outDir,
120
121
  // Apply polyfills and user-provided build options
@@ -216,7 +217,7 @@ function assetsPlugin(options = {}) {
216
217
  entryPoints: [entryPath],
217
218
  bundle: true,
218
219
  write: false,
219
- minify: true,
220
+ minify,
220
221
  // outdir required for esbuild to generate output paths
221
222
  outdir: outDir,
222
223
  plugins,
@@ -871,6 +872,7 @@ var ServerBundler = class {
871
872
  assetsPlugin({
872
873
  outDir: outputDir,
873
874
  plugins: userPlugins,
875
+ minify,
874
876
  jsx: jsxOptions.jsx,
875
877
  jsxFactory: jsxOptions.jsxFactory,
876
878
  jsxFragment: jsxOptions.jsxFragment,
@@ -925,42 +925,33 @@ function generateConfigModule(rawConfig, options) {
925
925
  export const config = ${configCode};
926
926
  `;
927
927
  }
928
- function loadRawConfig(cwd) {
929
- let rawConfig = {};
930
- let configSource = "defaults";
928
+ function readConfigFile(cwd) {
931
929
  try {
932
930
  const shovelPath = `${cwd}/shovel.json`;
933
931
  const content = readFileSync2(shovelPath, "utf-8");
934
- rawConfig = JSON.parse(content);
935
- configSource = "shovel.json";
932
+ return { raw: JSON.parse(content), source: "shovel.json" };
936
933
  } catch (error) {
937
934
  if (error?.code !== "ENOENT") {
938
935
  throw error;
939
936
  }
940
- try {
941
- const pkgPath = `${cwd}/package.json`;
942
- const content = readFileSync2(pkgPath, "utf-8");
943
- const pkgJSON = JSON.parse(content);
944
- if (pkgJSON.shovel) {
945
- rawConfig = pkgJSON.shovel;
946
- configSource = "package.json";
947
- }
948
- } catch (error2) {
949
- if (error2?.code !== "ENOENT") {
950
- throw error2;
951
- }
952
- }
953
937
  }
954
938
  try {
955
- return ShovelConfigSchema.parse(rawConfig);
939
+ const pkgPath = `${cwd}/package.json`;
940
+ const content = readFileSync2(pkgPath, "utf-8");
941
+ const pkgJSON = JSON.parse(content);
942
+ if (pkgJSON.shovel) {
943
+ return { raw: pkgJSON.shovel, source: "package.json" };
944
+ }
956
945
  } catch (error) {
957
- if (error instanceof z.ZodError) {
958
- const issues = error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
959
- throw new Error(`Invalid config in ${configSource}:
960
- ${issues}`);
946
+ if (error?.code !== "ENOENT") {
947
+ throw error;
961
948
  }
962
- throw error;
963
949
  }
950
+ return { raw: {}, source: "defaults" };
951
+ }
952
+ function loadRawConfig(cwd) {
953
+ const { raw } = readConfigFile(cwd);
954
+ return raw;
964
955
  }
965
956
  var configExpr = z.union([z.string(), z.number()]);
966
957
  var CacheConfigSchema = z.object({
@@ -1039,49 +1030,41 @@ var ShovelConfigSchema = z.object({
1039
1030
  }).strict();
1040
1031
  function loadConfig(cwd) {
1041
1032
  const env = getEnv();
1042
- let rawConfig = {};
1033
+ const { raw, source } = readConfigFile(cwd);
1034
+ const evaluated = processConfigValue(raw, env);
1035
+ let validated;
1043
1036
  try {
1044
- const shovelPath = `${cwd}/shovel.json`;
1045
- const content = readFileSync2(shovelPath, "utf-8");
1046
- rawConfig = JSON.parse(content);
1037
+ validated = ShovelConfigSchema.parse(evaluated);
1047
1038
  } catch (error) {
1048
- if (error?.code !== "ENOENT") {
1049
- throw error;
1050
- }
1051
- try {
1052
- const pkgPath = `${cwd}/package.json`;
1053
- const content = readFileSync2(pkgPath, "utf-8");
1054
- const pkgJSON = JSON.parse(content);
1055
- rawConfig = pkgJSON.shovel || {};
1056
- } catch (error2) {
1057
- if (error2?.code !== "ENOENT") {
1058
- throw error2;
1059
- }
1039
+ if (error instanceof z.ZodError) {
1040
+ const issues = error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
1041
+ throw new Error(`Invalid config in ${source}:
1042
+ ${issues}`);
1060
1043
  }
1044
+ throw error;
1061
1045
  }
1062
- const processed = processConfigValue(rawConfig, env);
1063
1046
  const config = {
1064
- platform: processed.platform ?? env.PLATFORM ?? void 0,
1065
- port: processed.port !== void 0 ? typeof processed.port === "number" ? processed.port : parseInt(String(processed.port), 10) : env.PORT ? parseInt(env.PORT, 10) : 3e3,
1066
- host: processed.host ?? env.HOST ?? "localhost",
1067
- workers: processed.workers !== void 0 ? typeof processed.workers === "number" ? processed.workers : parseInt(String(processed.workers), 10) : env.WORKERS ? parseInt(env.WORKERS, 10) : 1,
1047
+ platform: validated.platform ?? env.PLATFORM ?? void 0,
1048
+ port: validated.port !== void 0 ? typeof validated.port === "number" ? validated.port : parseInt(String(validated.port), 10) : env.PORT ? parseInt(env.PORT, 10) : 3e3,
1049
+ host: validated.host ?? env.HOST ?? "localhost",
1050
+ workers: validated.workers !== void 0 ? typeof validated.workers === "number" ? validated.workers : parseInt(String(validated.workers), 10) : env.WORKERS ? parseInt(env.WORKERS, 10) : 1,
1068
1051
  logging: {
1069
- sinks: processed.logging?.sinks || {},
1070
- loggers: processed.logging?.loggers || []
1052
+ sinks: validated.logging?.sinks || {},
1053
+ loggers: validated.logging?.loggers || []
1071
1054
  },
1072
1055
  build: {
1073
- target: processed.build?.target ?? "es2022",
1074
- minify: processed.build?.minify ?? false,
1075
- sourcemap: processed.build?.sourcemap ?? false,
1076
- treeShaking: processed.build?.treeShaking ?? true,
1077
- define: processed.build?.define ?? {},
1078
- alias: processed.build?.alias ?? {},
1079
- external: processed.build?.external ?? [],
1080
- plugins: processed.build?.plugins ?? []
1056
+ target: validated.build?.target ?? "es2022",
1057
+ minify: validated.build?.minify ?? false,
1058
+ sourcemap: validated.build?.sourcemap ?? false,
1059
+ treeShaking: validated.build?.treeShaking ?? true,
1060
+ define: validated.build?.define ?? {},
1061
+ alias: validated.build?.alias ?? {},
1062
+ external: validated.build?.external ?? [],
1063
+ plugins: validated.build?.plugins ?? []
1081
1064
  },
1082
- caches: processed.caches || {},
1083
- directories: processed.directories || {},
1084
- databases: processed.databases || {}
1065
+ caches: validated.caches || {},
1066
+ directories: validated.directories || {},
1067
+ databases: validated.databases || {}
1085
1068
  };
1086
1069
  return config;
1087
1070
  }
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  ServerBundler,
3
3
  loadPlatformModule
4
- } from "./chunk-DRCLXHTF.js";
4
+ } from "./chunk-RAQUFQW6.js";
5
5
  import {
6
6
  DEFAULTS
7
- } from "./chunk-7GONPLNW.js";
7
+ } from "./chunk-ZOLZXZ6E.js";
8
8
 
9
9
  // src/commands/develop.ts
10
10
  import { getLogger } from "@logtape/logtape";