@b9g/shovel 0.2.0-beta.10 → 0.2.0-beta.11

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 ADDED
@@ -0,0 +1,160 @@
1
+ # Changelog
2
+
3
+ All notable changes to Shovel will be documented in this file.
4
+
5
+ ## [0.2.0-beta.11] - 2026-01-10
6
+
7
+ ### Changes since beta.10
8
+ - **ESBuild configuration support (#18)** - Custom esbuild options in shovel.json
9
+ - **Config expression syntax** - `$PORT || 3000`, `$DATABASE_URL ?? null`
10
+ - **Null fallback fix** - Allow intentional null fallbacks in config expressions
11
+ - **DatabaseStorage API redesign** - New open/get pattern with IndexedDB-style migrations
12
+ - **Migrated from Drizzle to @b9g/zen** - Simpler, more portable database layer
13
+ - **Logging DX improvements** - Better defaults, consolidated categories
14
+ - **`impl` key unification** - Simplified resource configuration
15
+ - **CI/lint enforcement** - ESLint and Prettier standardized
16
+ - **Documentation** - Comprehensive docs for all APIs
17
+
18
+ ### Package Updates
19
+ - `@b9g/router` → 0.2.0-beta.1 (CORS middleware, trailingSlash moved)
20
+ - `@b9g/node-webworker` → 0.2.0-beta.1 (CloseEvent, onclose, env option)
21
+ - `@b9g/cache-redis` → 0.2.0-beta.1 (logger category fix)
22
+ - `@b9g/assets` → 0.2.0-beta.0
23
+ - `@b9g/async-context` → 0.2.0-beta.0
24
+ - `@b9g/cache` → 0.2.0-beta.0
25
+ - `@b9g/http-errors` → 0.2.0-beta.0
26
+ - `@b9g/match-pattern` → 0.2.0-beta.0
27
+
28
+ ---
29
+
30
+ ## [0.2.0-beta.10] - Previous Beta
31
+
32
+ This is a major release that establishes Shovel as a complete ServiceWorker-based meta-framework. The 0.2.0 beta introduces locked-down APIs for core packages, a unified configuration system, and comprehensive platform support.
33
+
34
+ ### Breaking Changes
35
+
36
+ - **`self.buckets` renamed to `self.directories`** - The file system API now uses `directories` to align with web standards terminology
37
+ - **`@b9g/router` middleware moved** - `trailingSlash` middleware moved from main export to `@b9g/router/middleware`
38
+ - **`self.loggers.get()` signature changed** - Now takes an array: `self.loggers.get(["app", "db"])` instead of dot notation
39
+ - **Config `module`/`export` unified to `impl`** - Resource configurations now use a single `impl` key for reified implementations
40
+
41
+ ### New Features
42
+
43
+ #### Consistent Worker Execution Model (#17)
44
+ ServiceWorker code now ALWAYS runs in a worker thread, never the main thread. This ensures:
45
+ - Same globals/environment in dev and prod (eliminates mode-only bugs)
46
+ - Worker isolation preserved
47
+ - Simplified mental model
48
+
49
+ #### ESBuild Configuration Support (#18)
50
+ Custom ESBuild options can now be specified in `shovel.json`:
51
+ ```json
52
+ {
53
+ "esbuild": {
54
+ "external": ["lightningcss"],
55
+ "define": { "DEBUG": "true" }
56
+ }
57
+ }
58
+ ```
59
+
60
+ #### Config Expression Syntax
61
+ Environment variables and expressions in `shovel.json`:
62
+ ```json
63
+ {
64
+ "port": "$PORT || 3000",
65
+ "databases": {
66
+ "main": {
67
+ "url": "$DATABASE_URL"
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ #### Comprehensive Logging System
74
+ - Built-in LogTape integration with console sink by default
75
+ - Configurable sinks (file, OpenTelemetry, Sentry, etc.)
76
+ - Category-based log levels
77
+ - `shovel` category logs at `info` level by default
78
+
79
+ #### Database Storage API
80
+ New `self.databases` API with IndexedDB-style migrations:
81
+ ```typescript
82
+ self.addEventListener("activate", (event) => {
83
+ event.waitUntil(
84
+ databases.open("main", 2, (e) => {
85
+ e.waitUntil(e.db.exec`CREATE TABLE users (...)`);
86
+ })
87
+ );
88
+ });
89
+
90
+ // In fetch handlers
91
+ const db = databases.get("main");
92
+ const users = await db.all`SELECT * FROM users`;
93
+ ```
94
+
95
+ #### CORS Middleware
96
+ New CORS middleware in `@b9g/router/middleware`:
97
+ ```typescript
98
+ import { cors } from "@b9g/router/middleware";
99
+ router.use(cors({ origin: "https://example.com" }));
100
+ ```
101
+
102
+ ### Package Updates
103
+
104
+ #### Locked at 0.2.0-beta.0 (API stable)
105
+ - `@b9g/async-context` - AsyncContext polyfill
106
+ - `@b9g/match-pattern` - URLPattern implementation
107
+ - `@b9g/assets` - Static asset pipeline with content hashing
108
+ - `@b9g/cache` - Cache API implementation (memory, postmessage)
109
+ - `@b9g/http-errors` - HTTP error classes
110
+
111
+ #### Updated to 0.2.0-beta.1
112
+ - `@b9g/router` - Added CORS middleware, moved trailingSlash to /middleware
113
+ - `@b9g/node-webworker` - Added CloseEvent, onclose handler, env option
114
+ - `@b9g/cache-redis` - Logger category updates
115
+
116
+ #### Still Evolving (0.1.x)
117
+ - `@b9g/platform` - Core runtime and platform abstraction
118
+ - `@b9g/platform-bun` - Bun platform adapter
119
+ - `@b9g/platform-node` - Node.js platform adapter
120
+ - `@b9g/platform-cloudflare` - Cloudflare Workers adapter
121
+ - `@b9g/filesystem` - File System Access API implementation
122
+ - `@b9g/filesystem-s3` - S3 filesystem adapter
123
+
124
+ ### CLI Changes
125
+
126
+ - `shovel develop` - Development server with hot reload (note: `dev` alias removed)
127
+ - `shovel build` - Production build
128
+ - `shovel activate` - Static site generation
129
+ - Removed `--verbose` flags (use logging config instead)
130
+
131
+ ### Infrastructure
132
+
133
+ - Migrated from Drizzle ORM to `@b9g/zen` for database operations
134
+ - Added GitHub Actions CI with parallel test execution
135
+ - ESLint and Prettier configuration standardized
136
+ - Comprehensive test suites with `bun:test`
137
+
138
+ ### Documentation
139
+
140
+ New documentation pages:
141
+ - Getting Started guide
142
+ - CLI reference
143
+ - Configuration (shovel.json) reference
144
+ - Deployment guide
145
+ - ServiceWorker lifecycle
146
+ - Routing and middleware
147
+ - Storage APIs (databases, caches, directories)
148
+ - Cookies and AsyncContext
149
+
150
+ ---
151
+
152
+ ## [0.1.x] - Previous Releases
153
+
154
+ Initial development releases establishing core architecture:
155
+ - ServiceWorker-based request handling
156
+ - Platform abstraction layer
157
+ - Router with generator-based middleware
158
+ - Cache API implementations
159
+ - File System Access API
160
+ - Hot reload in development
package/README.md CHANGED
@@ -1,49 +1,23 @@
1
- # Shovel
1
+ # Shovel.js 🪏
2
2
 
3
- **The ServiceWorker platform for server-side JavaScript.**
3
+ **The portable meta-framework built on web standards.**
4
4
 
5
- Same code. Any runtime. Node.js, Bun, Cloudflare Workers.
5
+ Shovel is a CLI platform for developing and deploying service workers as application servers.
6
6
 
7
7
  ```javascript
8
- // app.js
9
- self.addEventListener("fetch", (event) => {
10
- event.respondWith(new Response("Hello World"));
8
+ import {Router} from "@b9g/router";
9
+ const router = new Router();
10
+
11
+ router.route("/").get(() => new Response("Hello world"));
12
+
13
+ self.addEventListener("fetch", (ev) => {
14
+ ev.respondWith(router.handle(ev.request));
11
15
  });
12
16
  ```
13
17
 
14
18
  ```bash
15
- npx @b9g/shovel develop app.js
19
+ shovel develop app.js
16
20
  ```
17
-
18
- ## Why Shovel?
19
-
20
- Browsers have ServiceWorker. Cloudflare has Workers. Node.js and Bun have... Express?
21
-
22
- Shovel brings the ServiceWorker programming model to server-side JavaScript. Write your app once using web standards, deploy it anywhere.
23
-
24
- ## Web Standards
25
-
26
- Shovel implements web platform APIs that server-side JavaScript is missing:
27
-
28
- | API | Standard | What it does |
29
- |-----|----------|--------------|
30
- | `fetch` event | [Service Workers](https://w3c.github.io/ServiceWorker/) | Request handling |
31
- | `self.caches` | [Cache API](https://w3c.github.io/ServiceWorker/#cache-interface) | Response caching |
32
- | `self.directories` | [FileSystem API](https://fs.spec.whatwg.org/) | Storage (local, S3, R2) |
33
- | `self.cookieStore` | [Cookie Store API](https://wicg.github.io/cookie-store/) | Cookie management |
34
- | `URLPattern` | [URLPattern](https://urlpattern.spec.whatwg.org/) | Route matching (100% WPT) |
35
- | `AsyncContext.Variable` | [TC39 Stage 2](https://github.com/tc39/proposal-async-context) | Request-scoped state |
36
-
37
- Your code uses standards. Shovel makes them work everywhere.
38
-
39
- ## True Portability
40
-
41
- Shovel is a complete meta-framework. Same code, any runtime, any rendering strategy:
42
-
43
- - **Server runtimes**: Node.js, Bun, Cloudflare Workers for development and production
44
- - **Browser ServiceWorkers**: The same app can run as a PWA service worker
45
- - **Universal rendering**: Dynamic, static, or client-side - link and deploy assets automatically
46
-
47
21
  ## Quick Start
48
22
 
49
23
  ```javascript
@@ -54,12 +28,12 @@ const router = new Router();
54
28
 
55
29
  router.route("/").get(() => new Response("Hello World"));
56
30
 
57
- router.route("/users/:id").get((request, {params}) => {
58
- return Response.json({id: params.id});
31
+ router.route("/greet/:name").get((request, {params}) => {
32
+ return new Response(`Hello ${params.name}`);
59
33
  });
60
34
 
61
35
  self.addEventListener("fetch", (event) => {
62
- event.respondWith(router.handler(event.request));
36
+ event.respondWith(router.handle(event.request));
63
37
  });
64
38
  ```
65
39
 
@@ -76,6 +50,51 @@ npx @b9g/shovel build app.js --platform=bun
76
50
  npx @b9g/shovel build app.js --platform=cloudflare
77
51
  ```
78
52
 
53
+
54
+ ## Web Standards
55
+ Shovel is obsessively standards-first. All Shovel APIs use web standards, and Shovel implements/shims useful standards when they're missing.
56
+
57
+ | API | Standard | Purpose |
58
+ |-----|----------|--------------|
59
+ | `fetch()` | [Fetch](https://fetch.spec.whatwg.org) | Networking |
60
+ | `"install"`, `"activate"`, `"fetch"` events | [Service Workers](https://w3c.github.io/ServiceWorker/) | Server lifecycle |
61
+ | `AsyncContext.Variable` | [TC39 Stage 2](https://github.com/tc39/proposal-async-context) | Request-scoped state |
62
+ | `self.caches` | [Cache API](https://w3c.github.io/ServiceWorker/#cache-interface) | Response caching |
63
+ | `self.directories` | [FileSystem API](https://fs.spec.whatwg.org/) | Storage (local, S3, R2) |
64
+ | `self.cookieStore` | [CookieStore API](https://cookiestore.spec.whatwg.org) | Cookie management |
65
+ | `URLPattern` | [URLPattern](https://urlpattern.spec.whatwg.org/) | Route matching |
66
+
67
+ Your code uses standards. Shovel makes them work everywhere.
68
+
69
+ ## Meta-Framework
70
+
71
+ Shovel is a meta-framework: it provides and implements primitives rather than opinions. Instead of dictating how you build, it gives you portable building blocks that work everywhere.
72
+
73
+ ## True Portability
74
+
75
+ Same code, any runtime, any rendering strategy:
76
+
77
+ - **Server runtimes**: Node.js, Bun, Cloudflare Workers
78
+ - **Browser ServiceWorkers**: The same app can run as a PWA
79
+ - **Universal rendering**: Dynamic, static, or client-side
80
+
81
+ The core abstraction is the **ServiceWorker-style storage pattern**. Globals provide a consistent API for common web concerns:
82
+
83
+ ```javascript
84
+ const cache = await self.caches.open("sessions"); // Cache API
85
+ const dir = await self.directories.open("uploads"); // FileSystem API
86
+ const db = self.databases.get("main"); // Zen DB (opened on activate)
87
+ const logger = self.loggers.get(["app", "requests"]); // LogTape
88
+ ```
89
+
90
+ Each storage type is:
91
+ - **Lazy** - connections created on first `open()`, cached thereafter
92
+ - **Configured uniformly** - all are configured by `shovel.json`
93
+ - **Platform-aware** - sensible defaults per platform, override what you need
94
+
95
+ This pattern means your app logic stays clean. Swap Redis for memory cache, S3 for local filesystem, Postgres for SQLite - change the config, not the code.
96
+
97
+
79
98
  ## Platform APIs
80
99
 
81
100
  ```javascript
@@ -121,6 +140,247 @@ Assets are served via the platform's best option:
121
140
  - **Cloudflare**: Workers Assets (edge-cached, zero config)
122
141
  - **Node/Bun**: Static file middleware or directory storage
123
142
 
143
+ ## Configuration
144
+
145
+ Configure Shovel using `shovel.json` in your project root.
146
+
147
+ ### Philosophy
148
+
149
+ Shovel's configuration follows these principles:
150
+
151
+ 1. **Platform Defaults, User Overrides** - Each platform provides sensible defaults. You only configure what you want to change.
152
+
153
+ 2. **Uniform Interface** - Caches, directories, databases, and loggers all use the same `{ module, export, ...options }` pattern. No magic strings or builtin aliases.
154
+
155
+ 3. **Layered Resolution** - For any cache or directory name:
156
+ - If config specifies `module`/`export` → use that
157
+ - Otherwise → use platform default
158
+
159
+ 4. **Platform Re-exports** - Each platform exports `DefaultCache` representing what makes sense for that environment:
160
+ - Cloudflare: Native Cache API
161
+ - Bun/Node: MemoryCache
162
+
163
+ 5. **Transparency** - Config is what you see. Every backend is an explicit module path, making it easy to debug and trace.
164
+
165
+ ### Basic Config
166
+
167
+ ```json
168
+ {
169
+ "port": "PORT || 3000",
170
+ "host": "HOST || localhost",
171
+ "workers": "WORKERS ?? 1",
172
+ "caches": {
173
+ "sessions": {
174
+ "module": "@b9g/cache-redis",
175
+ "export": "RedisCache",
176
+ "url": "REDIS_URL"
177
+ }
178
+ },
179
+ "directories": {
180
+ "uploads": {
181
+ "module": "@b9g/filesystem-s3",
182
+ "export": "S3Directory",
183
+ "bucket": "S3_BUCKET"
184
+ }
185
+ },
186
+ "databases": {
187
+ "main": {
188
+ "module": "@b9g/zen/bun",
189
+ "url": "DATABASE_URL"
190
+ }
191
+ },
192
+ "logging": {
193
+ "loggers": [
194
+ {"category": ["app"], "level": "info", "sinks": ["console"]}
195
+ ]
196
+ }
197
+ }
198
+ ```
199
+
200
+ ### Caches
201
+
202
+ Configure cache backends using `module` and `export`:
203
+
204
+ ```json
205
+ {
206
+ "caches": {
207
+ "api-responses": {
208
+ "module": "@b9g/cache/memory",
209
+ "export": "MemoryCache"
210
+ },
211
+ "sessions": {
212
+ "module": "@b9g/cache-redis",
213
+ "export": "RedisCache",
214
+ "url": "REDIS_URL"
215
+ }
216
+ }
217
+ }
218
+ ```
219
+
220
+ - **Default**: Platform's `DefaultCache` when no config specified (MemoryCache on Bun/Node, native on Cloudflare)
221
+ - **Pattern matching**: Use wildcards like `"api-*"` to match multiple cache names
222
+ - **Empty config**: `"my-cache": {}` uses platform default explicitly
223
+
224
+ ### Directories
225
+
226
+ Configure directory backends. Platforms provide defaults for well-known directories (`server`, `public`, `tmp`):
227
+
228
+ ```json
229
+ {
230
+ "directories": {
231
+ "uploads": {
232
+ "module": "@b9g/filesystem-s3",
233
+ "export": "S3Directory",
234
+ "bucket": "MY_BUCKET",
235
+ "region": "us-east-1"
236
+ },
237
+ "data": {
238
+ "module": "@b9g/filesystem/node-fs",
239
+ "export": "NodeFSDirectory",
240
+ "path": "./data"
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
246
+ - **Well-known defaults**: `server` (dist/server), `public` (dist/public), `tmp` (OS temp)
247
+ - **Custom directories**: Must be explicitly configured
248
+
249
+ ### Logging
250
+
251
+ Shovel uses [LogTape](https://logtape.org/) for logging:
252
+
253
+ ```typescript
254
+ const logger = self.loggers.get(["shovel", "myapp"]);
255
+ logger.info`Request received: ${request.url}`;
256
+ ```
257
+
258
+ **Zero-config logging**: Use the `["shovel", ...]` category hierarchy to inherit Shovel's default logging (info level to console). No configuration needed.
259
+
260
+ For custom configuration, use `shovel.json`:
261
+
262
+ ```json
263
+ {
264
+ "logging": {
265
+ "sinks": {
266
+ "file": {
267
+ "module": "@logtape/logtape",
268
+ "export": "getFileSink",
269
+ "path": "./logs/app.log"
270
+ }
271
+ },
272
+ "loggers": [
273
+ {"category": ["myapp"], "level": "info", "sinks": ["console"]},
274
+ {"category": ["myapp", "db"], "level": "debug", "sinks": ["file"]}
275
+ ]
276
+ }
277
+ }
278
+ ```
279
+
280
+ - **Console sink is implicit** - always available as `"console"`
281
+ - **Category hierarchy** - `["myapp", "db"]` inherits from `["myapp"]`
282
+ - **parentSinks** - use `"override"` to replace parent sinks instead of inheriting
283
+
284
+ ### Databases
285
+
286
+ Configure database drivers using the same `module`/`export` pattern:
287
+
288
+ ```json
289
+ {
290
+ "databases": {
291
+ "main": {
292
+ "module": "@b9g/zen/bun",
293
+ "url": "DATABASE_URL"
294
+ }
295
+ }
296
+ }
297
+ ```
298
+
299
+ Open databases in `activate` (for migrations), then use `get()` in requests:
300
+
301
+ ```javascript
302
+ self.addEventListener("activate", (event) => {
303
+ event.waitUntil(self.databases.open("main", 1, (e) => {
304
+ e.waitUntil(runMigrations(e));
305
+ }));
306
+ });
307
+
308
+ self.addEventListener("fetch", (event) => {
309
+ const db = self.databases.get("main");
310
+ });
311
+ ```
312
+
313
+ ### Expression Syntax
314
+
315
+ Configuration values support a domain-specific expression language that generates JavaScript code evaluated at runtime.
316
+
317
+ #### Environment Variables
318
+
319
+ ```
320
+ $VAR → process.env.VAR
321
+ $VAR || fallback → process.env.VAR || "fallback"
322
+ $VAR ?? fallback → process.env.VAR ?? "fallback"
323
+ ```
324
+
325
+ #### Bracket Placeholders
326
+
327
+ | Placeholder | Description | Resolution |
328
+ |-------------|-------------|------------|
329
+ | `[outdir]` | Build output directory | Build time |
330
+ | `[tmpdir]` | OS temp directory | Runtime |
331
+ | `[git]` | Git commit SHA | Build time |
332
+
333
+ The bracket syntax mirrors esbuild/webpack output filename templating (`[name]`, `[hash]`).
334
+
335
+ #### Operators
336
+
337
+ | Operator | Example | Description |
338
+ |----------|---------|-------------|
339
+ | `\|\|` | `$VAR \|\| default` | Logical OR (falsy fallback) |
340
+ | `??` | `$VAR ?? default` | Nullish coalescing |
341
+ | `&&` | `$A && $B` | Logical AND |
342
+ | `? :` | `$ENV === prod ? a : b` | Ternary conditional |
343
+ | `===`, `!==` | `$ENV === production` | Strict equality |
344
+ | `!` | `!$DISABLED` | Logical NOT |
345
+
346
+ #### Path Expressions
347
+
348
+ Path expressions support path segments and relative resolution:
349
+
350
+ ```
351
+ $DATADIR/uploads → joins env var with path segment
352
+ [outdir]/server → joins build output with path segment
353
+ ./data → resolved to absolute path at build time
354
+ ```
355
+
356
+ #### Example
357
+
358
+ ```json
359
+ {
360
+ "port": "$PORT || 3000",
361
+ "host": "$HOST || 0.0.0.0",
362
+ "directories": {
363
+ "server": { "path": "[outdir]/server" },
364
+ "public": { "path": "[outdir]/public" },
365
+ "tmp": { "path": "[tmpdir]" },
366
+ "data": { "path": "./data" },
367
+ "cache": { "path": "($CACHE_DIR || [tmpdir])/myapp" }
368
+ },
369
+ "cache": {
370
+ "provider": "$NODE_ENV === production ? redis : memory"
371
+ }
372
+ }
373
+ ```
374
+
375
+ Dynamic values (containing `$VAR` or `[tmpdir]`) use getters to ensure evaluation at access time, not module load time.
376
+
377
+ ### Access in Code
378
+
379
+ ```javascript
380
+ import {config} from "shovel:config";
381
+ console.log(config.port); // Resolved value
382
+ ```
383
+
124
384
  ## Packages
125
385
 
126
386
  | Package | Description |
@@ -128,7 +388,7 @@ Assets are served via the platform's best option:
128
388
  | `@b9g/shovel` | CLI for development and deployment |
129
389
  | `@b9g/platform` | Core runtime and platform APIs |
130
390
  | `@b9g/platform-node` | Node.js adapter |
131
- | `@b9g/platform-bun` | Bun adapter |
391
+ | `@b9g/platform-bun` | Bun.js adapter |
132
392
  | `@b9g/platform-cloudflare` | Cloudflare Workers adapter |
133
393
  | `@b9g/router` | URLPattern-based routing with middleware |
134
394
  | `@b9g/cache` | Cache API implementation |
@@ -136,7 +396,6 @@ Assets are served via the platform's best option:
136
396
  | `@b9g/match-pattern` | URLPattern with extensions (100% WPT) |
137
397
  | `@b9g/async-context` | AsyncContext.Variable implementation |
138
398
  | `@b9g/http-errors` | Standard HTTP error classes |
139
- | `@b9g/auth` | OAuth2/PKCE and CORS middleware |
140
399
  | `@b9g/assets` | Static asset handling |
141
400
 
142
401
  ## License
package/bin/cli.js CHANGED
@@ -5,41 +5,61 @@ import {
5
5
  DEFAULTS,
6
6
  findProjectRoot,
7
7
  loadConfig
8
- } from "../chunk-CSH7M4MK.js";
8
+ } from "../src/_chunks/chunk-GRAFMTEH.js";
9
9
 
10
10
  // bin/cli.ts
11
+ import { resolve } from "path";
11
12
  import { configureLogging } from "@b9g/platform/runtime";
12
13
  import { Command } from "commander";
13
14
  import pkg from "../package.json" with { type: "json" };
14
15
  var projectRoot = findProjectRoot();
15
16
  var config = loadConfig(projectRoot);
16
- await configureLogging(config.logging);
17
+ async function reifySinks(sinks, baseDir) {
18
+ const reified = {};
19
+ for (const [name, sinkConfig] of Object.entries(sinks ?? {})) {
20
+ const { module: modulePath, export: exportName, ...rest } = sinkConfig;
21
+ if (modulePath) {
22
+ const resolvedPath = modulePath.startsWith("./") || modulePath.startsWith("../") ? resolve(baseDir, modulePath) : modulePath;
23
+ const mod = await import(resolvedPath);
24
+ const impl = exportName ? mod[exportName] : mod.default;
25
+ reified[name] = { ...rest, impl };
26
+ } else if (sinkConfig.impl) {
27
+ reified[name] = sinkConfig;
28
+ }
29
+ }
30
+ return reified;
31
+ }
32
+ var reifiedSinks = await reifySinks(config.logging?.sinks, projectRoot);
33
+ await configureLogging({
34
+ sinks: reifiedSinks,
35
+ loggers: config.logging?.loggers
36
+ });
17
37
  var program = new Command();
18
38
  program.name("shovel").description("Shovel CLI").version(pkg.version);
19
39
  program.command("develop <entrypoint>").description("Start development server with hot reload").option("-p, --port <port>", "Port to listen on", DEFAULTS.SERVER.PORT).option("-h, --host <host>", "Host to bind to", DEFAULTS.SERVER.HOST).option(
20
40
  "-w, --workers <count>",
21
41
  "Number of workers (default: CPU cores)",
22
42
  DEFAULTS.WORKERS
23
- ).option("-v, --verbose", "Verbose logging", false).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").action(async (entrypoint, options) => {
24
- const { developCommand } = await import("../develop-5ORIPB7M.js");
43
+ ).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").action(async (entrypoint, options) => {
44
+ const { developCommand } = await import("../src/_chunks/develop-A7EU2ZDY.js");
25
45
  await developCommand(entrypoint, options, config);
26
46
  });
27
- program.command("build <entrypoint>").description("Build app for production").option("-w, --workers <count>", "Worker count (defaults to 1)", void 0).option("-v, --verbose", "Verbose logging", false).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").action(async (entrypoint, options) => {
28
- const { buildCommand } = await import("../build-NDUV2F2Z.js");
47
+ program.command("build <entrypoint>").description("Build app for production").option("-w, --workers <count>", "Worker count (defaults to 1)", void 0).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").action(async (entrypoint, options) => {
48
+ const { buildCommand } = await import("../src/_chunks/build-V3IPZGKC.js");
29
49
  await buildCommand(entrypoint, options, config);
30
50
  });
31
51
  program.command("activate <entrypoint>").description(
32
52
  "Activate ServiceWorker (for static site generation in activate event)"
33
- ).option("-v, --verbose", "Verbose logging", false).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").option(
53
+ ).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").option(
34
54
  "-w, --workers <count>",
35
55
  "Number of workers",
36
56
  DEFAULTS.WORKERS.toString()
37
57
  ).action(async (entrypoint, options) => {
38
- const { activateCommand } = await import("../activate-5LWUTBLL.js");
58
+ const { activateCommand } = await import("../src/_chunks/activate-TP6RQP47.js");
39
59
  await activateCommand(entrypoint, options, config);
40
60
  });
41
61
  program.command("info").description("Display platform and runtime information").action(async () => {
42
- const { infoCommand } = await import("../info-PRYEMZS4.js");
62
+ const { infoCommand } = await import("../src/_chunks/info-TDUY3FZN.js");
43
63
  await infoCommand();
44
64
  });
45
65
  program.parse();