@b9g/shovel 0.2.17 → 0.2.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/CHANGELOG.md +44 -0
- package/bin/cli.js +3 -3
- package/bin/create.js +11 -0
- package/package.json +6 -5
- package/src/_chunks/{build-FZTZ3R4X.js → build-YQCWR6LD.js} +2 -2
- package/src/_chunks/{chunk-RAQUFQW6.js → chunk-JY5SZDJK.js} +95 -3
- package/src/_chunks/{chunk-ZOLZXZ6E.js → chunk-MUNERPYV.js} +6 -0
- package/src/_chunks/{develop-BLCM4BBB.js → develop-Y2BWTIZ6.js} +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Shovel will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.19] - 2026-03-17
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **Glob asset import clobbers individual import** — When the same file was imported both individually and via a glob pattern with different `assetBase` values, the glob import overwrote the individual import's manifest entry. Both URLs now coexist correctly. (fixes [#81](https://github.com/bikeshaving/shovel/issues/81))
|
|
10
|
+
|
|
11
|
+
## [0.2.18] - 2026-03-16
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- **Glob asset imports** — Import multiple static files with a single glob pattern:
|
|
16
|
+
`import urls from "./public/**/*" with { assetBase: "/", assetName: "[name].[ext]" }`
|
|
17
|
+
Files flow through the existing asset pipeline (hashing, manifesting, dist/public/).
|
|
18
|
+
Works across all platforms (Node, Bun, Cloudflare). ([#75](https://github.com/bikeshaving/shovel/issues/75), [PR #77](https://github.com/bikeshaving/shovel/pull/77))
|
|
19
|
+
|
|
20
|
+
### Dependencies
|
|
21
|
+
|
|
22
|
+
- Added `glob` package for glob pattern expansion in asset imports
|
|
23
|
+
|
|
24
|
+
## @b9g/platform-bun 0.1.17 - 2026-03-16
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
- **BroadcastChannel relay** — Worker code generation now includes BroadcastChannel message relay between supervisor and workers
|
|
29
|
+
|
|
30
|
+
## @b9g/broadcastchannel-redis 0.1.0 - 2026-03-16
|
|
31
|
+
|
|
32
|
+
### Features
|
|
33
|
+
|
|
34
|
+
- **Initial release** — Redis pub/sub backend for Shovel BroadcastChannel, enabling cross-process message broadcasting via Redis
|
|
35
|
+
|
|
36
|
+
## @b9g/platform-cloudflare 0.1.17 - 2026-03-03
|
|
37
|
+
|
|
38
|
+
### Bug Fixes
|
|
39
|
+
|
|
40
|
+
- **`@b9g/platform-cloudflare`** - Fix Miniflare dev server returning 404 for all routes by adding `routerConfig: {has_user_worker: true}` to assets config (#72)
|
|
41
|
+
|
|
42
|
+
## @b9g/platform-cloudflare 0.1.16, create-shovel 0.1.3 - 2026-03-02
|
|
43
|
+
|
|
44
|
+
### Features
|
|
45
|
+
|
|
46
|
+
- **`@b9g/platform-cloudflare`** - Miniflare dev server now configures static assets directory and `ASSETS` binding, matching Cloudflare Workers production behavior (#71)
|
|
47
|
+
- **`create-shovel`** - Cloudflare projects now generate a `wrangler.toml` with assets directory config (#71)
|
|
48
|
+
|
|
5
49
|
## [0.2.17] - 2026-02-26
|
|
6
50
|
|
|
7
51
|
### 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-
|
|
8
|
+
} from "../src/_chunks/chunk-MUNERPYV.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-
|
|
78
|
+
const { developCommand } = await import("../src/_chunks/develop-Y2BWTIZ6.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-
|
|
94
|
+
const { buildCommand } = await import("../src/_chunks/build-YQCWR6LD.js");
|
|
95
95
|
await buildCommand(entrypoint, options, config);
|
|
96
96
|
process.exit(0);
|
|
97
97
|
});
|
package/bin/create.js
CHANGED
|
@@ -406,6 +406,17 @@ dist/
|
|
|
406
406
|
.DS_Store
|
|
407
407
|
`;
|
|
408
408
|
await writeFile(join(projectPath, ".gitignore"), gitignore);
|
|
409
|
+
if (config.platform === "cloudflare") {
|
|
410
|
+
const wranglerToml = `name = "${config.name}"
|
|
411
|
+
main = "dist/server/worker.js"
|
|
412
|
+
compatibility_date = "2024-09-23"
|
|
413
|
+
compatibility_flags = ["nodejs_compat"]
|
|
414
|
+
|
|
415
|
+
[assets]
|
|
416
|
+
directory = "./dist/public"
|
|
417
|
+
`;
|
|
418
|
+
await writeFile(join(projectPath, "wrangler.toml"), wranglerToml);
|
|
419
|
+
}
|
|
409
420
|
}
|
|
410
421
|
function generateAppFile(config) {
|
|
411
422
|
switch (config.template) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b9g/shovel",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
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": {
|
|
@@ -19,15 +19,16 @@
|
|
|
19
19
|
"@b9g/filesystem": "^0.2.0",
|
|
20
20
|
"@b9g/http-errors": "^0.2.1",
|
|
21
21
|
"@b9g/node-webworker": "^0.2.1",
|
|
22
|
-
"@b9g/platform": "^0.1.
|
|
23
|
-
"@b9g/platform-bun": "^0.1.
|
|
24
|
-
"@b9g/platform-cloudflare": "^0.1.
|
|
22
|
+
"@b9g/platform": "^0.1.19",
|
|
23
|
+
"@b9g/platform-bun": "^0.1.17",
|
|
24
|
+
"@b9g/platform-cloudflare": "^0.1.17",
|
|
25
25
|
"@b9g/platform-node": "^0.1.17",
|
|
26
26
|
"@clack/prompts": "^0.7.0",
|
|
27
27
|
"@logtape/logtape": "^2.0.0",
|
|
28
28
|
"commander": "^13.1.0",
|
|
29
29
|
"esbuild": "^0.27.2",
|
|
30
30
|
"esbuild-plugins-node-modules-polyfill": "^1.8.1",
|
|
31
|
+
"glob": "^13.0.6",
|
|
31
32
|
"mime": "^4.0.4",
|
|
32
33
|
"zod": "^3.23.0"
|
|
33
34
|
},
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
"eslint": "^9.0.0",
|
|
45
46
|
"eslint-config-prettier": "^10.0.0",
|
|
46
47
|
"eslint-plugin-prettier": "^5.0.0",
|
|
47
|
-
"miniflare": "^4.
|
|
48
|
+
"miniflare": "^4.20260305.0",
|
|
48
49
|
"mitata": "^1.0.34",
|
|
49
50
|
"typescript": "^5.7.3"
|
|
50
51
|
},
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ServerBundler,
|
|
3
3
|
loadPlatformModule
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JY5SZDJK.js";
|
|
5
5
|
import {
|
|
6
6
|
findProjectRoot,
|
|
7
7
|
findWorkspaceRoot
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-MUNERPYV.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-
|
|
7
|
+
} from "./chunk-MUNERPYV.js";
|
|
8
8
|
|
|
9
9
|
// src/utils/bundler.ts
|
|
10
10
|
import * as ESBuild2 from "esbuild";
|
|
@@ -322,9 +322,9 @@ function assetsPlugin(options = {}) {
|
|
|
322
322
|
size: content.length,
|
|
323
323
|
type: mimeType
|
|
324
324
|
};
|
|
325
|
-
manifest.assets[
|
|
325
|
+
manifest.assets[publicURL] = manifestEntry;
|
|
326
326
|
if (sharedManifest) {
|
|
327
|
-
sharedManifest.assets[
|
|
327
|
+
sharedManifest.assets[publicURL] = manifestEntry;
|
|
328
328
|
sharedManifest.generated = manifest.generated;
|
|
329
329
|
}
|
|
330
330
|
return {
|
|
@@ -369,6 +369,95 @@ function assetsPlugin(options = {}) {
|
|
|
369
369
|
};
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
// src/plugins/glob-assets.ts
|
|
373
|
+
import { globSync } from "glob";
|
|
374
|
+
import { posix } from "path";
|
|
375
|
+
var GLOB_NAMESPACE = "shovel-glob-assets";
|
|
376
|
+
function getGlobRoot(pattern) {
|
|
377
|
+
const parts = pattern.split("/");
|
|
378
|
+
const rootParts = [];
|
|
379
|
+
for (const part of parts) {
|
|
380
|
+
if (part.includes("*"))
|
|
381
|
+
break;
|
|
382
|
+
rootParts.push(part);
|
|
383
|
+
}
|
|
384
|
+
return rootParts.join("/") || ".";
|
|
385
|
+
}
|
|
386
|
+
function globAssetsPlugin() {
|
|
387
|
+
return {
|
|
388
|
+
name: "shovel-glob-assets",
|
|
389
|
+
setup(build2) {
|
|
390
|
+
build2.onResolve({ filter: /\*/ }, (args) => {
|
|
391
|
+
if (!args.with?.assetBase)
|
|
392
|
+
return null;
|
|
393
|
+
return {
|
|
394
|
+
path: args.path,
|
|
395
|
+
namespace: GLOB_NAMESPACE,
|
|
396
|
+
pluginData: {
|
|
397
|
+
resolveDir: args.resolveDir,
|
|
398
|
+
importAttributes: args.with
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
});
|
|
402
|
+
build2.onLoad({ filter: /.*/, namespace: GLOB_NAMESPACE }, (args) => {
|
|
403
|
+
const { resolveDir, importAttributes } = args.pluginData;
|
|
404
|
+
const pattern = args.path;
|
|
405
|
+
const assetBase = importAttributes.assetBase;
|
|
406
|
+
const files = globSync(pattern, {
|
|
407
|
+
cwd: resolveDir,
|
|
408
|
+
nodir: true,
|
|
409
|
+
dot: false
|
|
410
|
+
});
|
|
411
|
+
if (files.length === 0) {
|
|
412
|
+
return {
|
|
413
|
+
warnings: [
|
|
414
|
+
{
|
|
415
|
+
text: `Glob pattern "${pattern}" matched no files`
|
|
416
|
+
}
|
|
417
|
+
],
|
|
418
|
+
contents: "export default {};",
|
|
419
|
+
loader: "js"
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const globRoot = getGlobRoot(pattern);
|
|
423
|
+
const imports = [];
|
|
424
|
+
const exports = [];
|
|
425
|
+
for (let i = 0; i < files.length; i++) {
|
|
426
|
+
const file = files[i];
|
|
427
|
+
const relativeToRoot = posix.relative(globRoot, file);
|
|
428
|
+
const fileDir = posix.dirname(relativeToRoot);
|
|
429
|
+
const fileAttrs = {
|
|
430
|
+
...importAttributes
|
|
431
|
+
};
|
|
432
|
+
let fileAssetBase = assetBase;
|
|
433
|
+
if (fileDir && fileDir !== ".") {
|
|
434
|
+
fileAssetBase = posix.join(assetBase, fileDir, "/");
|
|
435
|
+
}
|
|
436
|
+
if (!fileAssetBase.endsWith("/")) {
|
|
437
|
+
fileAssetBase += "/";
|
|
438
|
+
}
|
|
439
|
+
fileAttrs.assetBase = fileAssetBase;
|
|
440
|
+
const withClause = Object.entries(fileAttrs).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ");
|
|
441
|
+
const importPath = file.startsWith(".") ? file : `./${file}`;
|
|
442
|
+
imports.push(
|
|
443
|
+
`import _${i} from ${JSON.stringify(importPath)} with { ${withClause} };`
|
|
444
|
+
);
|
|
445
|
+
exports.push(`${JSON.stringify(relativeToRoot)}: _${i}`);
|
|
446
|
+
}
|
|
447
|
+
const contents = [
|
|
448
|
+
...imports,
|
|
449
|
+
`export default { ${exports.join(", ")} };`
|
|
450
|
+
].join("\n");
|
|
451
|
+
return {
|
|
452
|
+
contents,
|
|
453
|
+
loader: "js",
|
|
454
|
+
resolveDir
|
|
455
|
+
};
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
372
461
|
// src/plugins/import-meta.ts
|
|
373
462
|
import { readFile } from "fs/promises";
|
|
374
463
|
import { dirname as dirname2 } from "path";
|
|
@@ -791,6 +880,7 @@ var ServerBundler = class {
|
|
|
791
880
|
this.#userEntryPath = entryPath;
|
|
792
881
|
const outputDir = resolve(this.#projectRoot, this.#options.outDir);
|
|
793
882
|
await mkdir(join5(outputDir, "server"), { recursive: true });
|
|
883
|
+
await mkdir(join5(outputDir, "public"), { recursive: true });
|
|
794
884
|
const initialBuildPromise = new Promise((resolve2) => {
|
|
795
885
|
this.#initialBuildResolve = resolve2;
|
|
796
886
|
});
|
|
@@ -868,6 +958,8 @@ var ServerBundler = class {
|
|
|
868
958
|
}),
|
|
869
959
|
createEntryPlugin(this.#projectRoot, platformEntryPoints),
|
|
870
960
|
importMetaPlugin(),
|
|
961
|
+
// globAssetsPlugin expands glob patterns into individual imports for assetsPlugin
|
|
962
|
+
globAssetsPlugin(),
|
|
871
963
|
// assetsPlugin must come before assetsManifestPlugin so onEnd order is correct
|
|
872
964
|
assetsPlugin({
|
|
873
965
|
outDir: outputDir,
|
|
@@ -879,6 +879,9 @@ function generateConfigModule(rawConfig, options) {
|
|
|
879
879
|
const platformConfig = platformCaches[name] || {};
|
|
880
880
|
const userConfig = userCaches[name] || {};
|
|
881
881
|
const mergedConfig = { ...platformConfig, ...userConfig };
|
|
882
|
+
if (userConfig.module && !userConfig.export) {
|
|
883
|
+
delete mergedConfig.export;
|
|
884
|
+
}
|
|
882
885
|
caches[name] = reifyModule(mergedConfig, "cache", name);
|
|
883
886
|
}
|
|
884
887
|
config2.caches = caches;
|
|
@@ -895,6 +898,9 @@ function generateConfigModule(rawConfig, options) {
|
|
|
895
898
|
const platformConfig = platformDirectories[name] || {};
|
|
896
899
|
const userConfig = userDirectories[name] || {};
|
|
897
900
|
const mergedConfig = { ...platformConfig, ...userConfig };
|
|
901
|
+
if (userConfig.module && !userConfig.export) {
|
|
902
|
+
delete mergedConfig.export;
|
|
903
|
+
}
|
|
898
904
|
directories[name] = reifyModule(mergedConfig, "directory", name);
|
|
899
905
|
}
|
|
900
906
|
config2.directories = directories;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ServerBundler,
|
|
3
3
|
loadPlatformModule
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JY5SZDJK.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULTS
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MUNERPYV.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/develop.ts
|
|
10
10
|
import { getLogger } from "@logtape/logtape";
|