Compare commits

..

9 Commits

Author SHA1 Message Date
11ada650e1 v3.3.2
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-24 19:02:50 +00:00
f7443fabf1 fix(config): migrate project metadata and documentation to .smartconfig.json 2026-03-24 19:02:50 +00:00
5128802ecf v3.3.1
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-24 15:09:42 +00:00
37da233ddf fix(config): switch configuration loading and saving from npmextra.json to smartconfig.json 2026-03-24 15:09:42 +00:00
6a3de7dba8 v3.3.0
Some checks failed
Default (tags) / security (push) Successful in 36s
Default (tags) / test (push) Failing after 4m2s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-10 15:54:55 +00:00
07cdee6bff feat(server): use UtilityWebsiteServer for dev server, add domain option, update docs, and bump dependencies 2026-03-10 15:54:55 +00:00
b62e380750 fix(deps): bump smartshell ^3.3.5 (detached:true) and smartexit ^2.0.2
Some checks failed
Default (tags) / security (push) Successful in 36s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-04 00:50:14 +00:00
0eef560f1d fix(deps): pin smartexit to ^2.0.1 and smartshell to ^3.3.4 for PID tracking
Some checks failed
Default (tags) / security (push) Successful in 33s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-04 00:17:35 +00:00
f7f42ff36c fix(watcher): always tree-kill on stop regardless of childProcess.killed flag
Some checks failed
Default (tags) / security (push) Successful in 33s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
The direct bash child may already be dead from terminal SIGINT while
grandchildren (tsrun, devserver) are still running. Removing the .killed
guard ensures tree-kill always runs to clean up the entire process tree.
2026-03-04 00:09:21 +00:00
17 changed files with 3209 additions and 3423 deletions

View File

@@ -1,7 +1,7 @@
{ {
"json.schemas": [ "json.schemas": [
{ {
"fileMatch": ["/npmextra.json"], "fileMatch": ["/.smartconfig.json"],
"schema": { "schema": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -1,5 +1,27 @@
# Changelog # Changelog
## 2026-03-24 - 3.3.2 - fix(config)
migrate project metadata and documentation to .smartconfig.json
- replace npmextra.json with .smartconfig.json in package files and documentation
- update dependency versions to align with the smartconfig-based setup
- allow watcher executions to be undefined until a process starts
## 2026-03-24 - 3.3.1 - fix(config)
switch configuration loading and saving from npmextra.json to smartconfig.json
- replace the @push.rocks/npmextra dependency with @push.rocks/smartconfig
- update config handling, CLI messaging, and init flow to use smartconfig.json consistently
## 2026-03-10 - 3.3.0 - feat(server)
use UtilityWebsiteServer for dev server, add domain option, update docs, and bump dependencies
- Replace TypedServer with UtilityWebsiteServer in TsWatch (start/stop/reload adapted)
- Add server.domain config option and update interfaces
- Update readme to document UtilityWebsiteServer features (PWA, brotli+gzip, service worker, live reload via WebSocket) and add bundle config hints (outputMode, bundler, production)
- Bump dependencies and devDependencies (notable: @api.global/typedserver ^8.4.2, @git.zone/tsbundle ^2.9.1, @push.rocks/* updates)
- Remove unused taskbuffer export from tswatch.plugins.ts
## 2026-03-03 - 3.2.1 - fix(watcher) ## 2026-03-03 - 3.2.1 - fix(watcher)
ensure child processes are killed and awaited during shutdown; improve cleanup handlers; bump smartshell dependency to ^3.3.2 ensure child processes are killed and awaited during shutdown; improve cleanup handlers; bump smartshell dependency to ^3.3.2

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018 Lossless GmbH (hello@lossless.com) Copyright (c) 2018 Task Venture Capital GmbH (hello@task.vc)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tswatch", "name": "@git.zone/tswatch",
"version": "3.2.2", "version": "3.3.2",
"private": false, "private": false,
"description": "A development tool for automatically watching and re-compiling TypeScript projects upon detecting file changes, enhancing developer workflows.", "description": "A development tool for automatically watching and re-compiling TypeScript projects upon detecting file changes, enhancing developer workflows.",
"exports": { "exports": {
@@ -18,27 +18,26 @@
"buildDocs": "tsdoc" "buildDocs": "tsdoc"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^4.1.2", "@git.zone/tsbuild": "^4.4.0",
"@git.zone/tstest": "^3.1.8", "@git.zone/tstest": "^3.5.1",
"@types/node": "^25.2.1" "@types/node": "^25.5.0"
}, },
"dependencies": { "dependencies": {
"@api.global/typedserver": "^8.3.0", "@api.global/typedserver": "^8.4.6",
"@git.zone/tsbundle": "^2.9.0", "@git.zone/tsbundle": "^2.10.0",
"@git.zone/tsrun": "^2.0.1", "@git.zone/tsrun": "^2.0.1",
"@push.rocks/early": "^4.0.4", "@push.rocks/early": "^4.0.4",
"@push.rocks/lik": "^6.2.2", "@push.rocks/lik": "^6.4.0",
"@push.rocks/npmextra": "^5.3.3",
"@push.rocks/smartcli": "^4.0.20", "@push.rocks/smartcli": "^4.0.20",
"@push.rocks/smartconfig": "^6.0.1",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartexit": "2.0.0", "@push.rocks/smartexit": "^2.0.3",
"@push.rocks/smartfs": "^1.3.1", "@push.rocks/smartfs": "^1.5.0",
"@push.rocks/smartinteract": "^2.0.16", "@push.rocks/smartinteract": "^2.0.16",
"@push.rocks/smartlog": "^3.1.10", "@push.rocks/smartlog": "^3.2.1",
"@push.rocks/smartlog-destination-local": "^9.0.2", "@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartshell": "^3.3.3", "@push.rocks/smartshell": "^3.3.8",
"@push.rocks/smartwatch": "^6.3.0", "@push.rocks/smartwatch": "^6.4.0"
"@push.rocks/taskbuffer": "^4.2.0"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",
@@ -49,7 +48,7 @@
"dist_ts_web/**/*", "dist_ts_web/**/*",
"assets/**/*", "assets/**/*",
"cli.js", "cli.js",
"npmextra.json", ".smartconfig.json",
"readme.md" "readme.md"
], ],
"browserslist": [ "browserslist": [

6356
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,13 +2,13 @@
## Core Architecture (v3.x - Config-Driven) ## Core Architecture (v3.x - Config-Driven)
tswatch is now a config-driven TypeScript file watcher. Configuration is read from `npmextra.json` under the key `@git.zone/tswatch`. tswatch is a config-driven TypeScript file watcher. Configuration is read from `.smartconfig.json` under the key `@git.zone/tswatch`.
### Key Classes ### Key Classes
- **TsWatch**: Main orchestrator class, accepts `ITswatchConfig` - **TsWatch**: Main orchestrator class, accepts `ITswatchConfig`
- **Watcher**: Handles individual file watching with debouncing and restart modes - **Watcher**: Handles individual file watching with debouncing and restart modes
- **ConfigHandler**: Loads and manages configuration from npmextra.json - **ConfigHandler**: Loads and manages configuration from .smartconfig.json
- **TswatchInit**: Interactive wizard for creating configuration - **TswatchInit**: Interactive wizard for creating configuration
### Configuration Structure ### Configuration Structure
@@ -63,10 +63,10 @@ tswatch is now a config-driven TypeScript file watcher. Configuration is read fr
- Uses `@push.rocks/smartwatch` (v6.x) for file watching - class is `Smartwatch` - Uses `@push.rocks/smartwatch` (v6.x) for file watching - class is `Smartwatch`
- Uses `@push.rocks/smartfs` (v1.x) for filesystem operations - Uses `@push.rocks/smartfs` (v1.x) for filesystem operations
- Uses `@push.rocks/npmextra` for reading npmextra.json config - Uses `@push.rocks/smartconfig` for reading .smartconfig.json config
- Uses `@push.rocks/smartinteract` for the init wizard - Uses `@push.rocks/smartinteract` for the init wizard
- Uses `@git.zone/tsbundle` for bundling with esbuild - Uses `@git.zone/tsbundle` for bundling with esbuild
- Uses `@api.global/typedserver` for development server - Uses `@api.global/typedserver` `UtilityWebsiteServer` for development server (wraps TypedServer with service worker, PWA manifest, and live reload)
### Watcher Features ### Watcher Features
@@ -77,12 +77,16 @@ tswatch is now a config-driven TypeScript file watcher. Configuration is read fr
### Server Features ### Server Features
- Uses `UtilityWebsiteServer` from `@api.global/typedserver` (not raw `TypedServer`)
- Port configurable (default: 3002) - Port configurable (default: 3002)
- CORS enabled - CORS enabled
- Gzip compression - Compression (brotli + gzip)
- Live reload injection (configurable) - Live reload via WebSocket (service worker + devtools injection)
- SPA fallback support - SPA fallback support
- No-cache headers (prevents browser caching during development) - No-cache headers (prevents browser caching during development)
- PWA manifest auto-generated
- Service worker version info handler
- Domain configurable (default: 'localhost')
## Project Structure ## Project Structure

106
readme.md
View File

@@ -1,6 +1,6 @@
# @git.zone/tswatch # @git.zone/tswatch
A powerful, config-driven TypeScript file watcher that automatically recompiles and executes your project when files change. Built for modern TypeScript development with zero-config presets and deep customization options. A powerful, config-driven TypeScript file watcher that automatically recompiles and executes your project when files change. Built for modern TypeScript development with zero-config presets, smart bundling, a built-in dev server with live reload, and deep customization options.
## Issue Reporting and Security ## Issue Reporting and Security
@@ -8,14 +8,15 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
## ✨ Features ## ✨ Features
- 🔄 **Config-driven architecture** - Define watchers, bundles, and dev server in `npmextra.json` - 🔄 **Config-driven architecture** Define watchers, bundles, and dev server in `.smartconfig.json`
-**Zero-config presets** - Get started instantly with `npm`, `element`, `service`, `website`, and `test` presets -**Zero-config presets** Get started instantly with `npm`, `element`, `service`, `website`, and `test` presets
- 🧙 **Interactive wizard** - Run `tswatch init` to generate configuration interactively - 🧙 **Interactive wizard** Run `tswatch init` to generate configuration interactively
- 🌐 **Built-in dev server** - Live reload, CORS, compression, SPA fallback out of the box - 🌐 **Built-in dev server** Live reload, CORS, compression, SPA fallback out of the box
- 📦 **Smart bundling** - TypeScript, HTML, and assets with esbuild integration - 📦 **Smart bundling** TypeScript, HTML, and assets with esbuild/rolldown/rspack integration
- 🔁 **Debounced execution** - Configurable debounce prevents command spam - 🔁 **Debounced execution** Configurable debounce prevents command spam during rapid file saves
- 🛑 **Process management** - Automatic restart or queue mode for long-running commands - 🛑 **Process management** Automatic restart or queue mode for long-running commands
- 🎯 **Glob patterns** - Watch any files with flexible pattern matching - 🎯 **Glob patterns** Watch any files with flexible pattern matching
- 🧹 **Graceful shutdown** — Signal-aware process lifecycle with tree-kill for clean teardowns
## 📦 Installation ## 📦 Installation
@@ -36,7 +37,7 @@ pnpm install --save-dev @git.zone/tswatch
tswatch init tswatch init
``` ```
The wizard will guide you through creating a `npmextra.json` configuration with your chosen preset or custom watchers. The wizard guides you through creating a `.smartconfig.json` configuration with your chosen preset or custom watchers.
### Using Presets ### Using Presets
@@ -46,11 +47,11 @@ If you already have a configuration, just run:
tswatch tswatch
``` ```
This reads your config from `npmextra.json` under the `@git.zone/tswatch` key and starts watching. This reads your config from `.smartconfig.json` under the `@git.zone/tswatch` key and starts watching.
## ⚙️ Configuration ## ⚙️ Configuration
tswatch uses `npmextra.json` for configuration. Add your config under the `@git.zone/tswatch` key: tswatch uses `.smartconfig.json` for configuration. Add your config under the `@git.zone/tswatch` key:
```json ```json
{ {
@@ -68,7 +69,7 @@ tswatch uses `npmextra.json` for configuration. Add your config under the `@git.
| `test` | Watch `ts/` and `test/`, run `npm run test2` on changes | | `test` | Watch `ts/` and `test/`, run `npm run test2` on changes |
| `service` | Watch `ts/`, restart `npm run startTs` (ideal for backend services) | | `service` | Watch `ts/`, restart `npm run startTs` (ideal for backend services) |
| `element` | Dev server on port 3002 + bundling for web components | | `element` | Dev server on port 3002 + bundling for web components |
| `website` | Full-stack: backend + frontend bundling + asset processing | | `website` | Full-stack: backend restart + frontend bundling + asset processing |
### Full Configuration Schema ### Full Configuration Schema
@@ -81,7 +82,8 @@ tswatch uses `npmextra.json` for configuration. Add your config under the `@git.
"enabled": true, "enabled": true,
"port": 3002, "port": 3002,
"serveDir": "./dist_watch/", "serveDir": "./dist_watch/",
"liveReload": true "liveReload": true,
"domain": "localhost"
}, },
"bundles": [ "bundles": [
@@ -90,7 +92,9 @@ tswatch uses `npmextra.json` for configuration. Add your config under the `@git.
"from": "./ts_web/index.ts", "from": "./ts_web/index.ts",
"to": "./dist_watch/bundle.js", "to": "./dist_watch/bundle.js",
"watchPatterns": ["./ts_web/**/*"], "watchPatterns": ["./ts_web/**/*"],
"triggerReload": true "triggerReload": true,
"bundler": "esbuild",
"production": false
}, },
{ {
"name": "html", "name": "html",
@@ -134,13 +138,15 @@ tswatch uses `npmextra.json` for configuration. Add your config under the `@git.
| `server` | `IServerConfig` | Development server configuration | | `server` | `IServerConfig` | Development server configuration |
| `bundles` | `IBundleConfig[]` | Bundle configurations | | `bundles` | `IBundleConfig[]` | Bundle configurations |
> **Tip:** When a preset is specified alongside explicit `watchers`, `bundles`, or `server`, your explicit values take precedence over the preset defaults.
#### `IWatcherConfig` #### `IWatcherConfig`
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `name` | `string` | *required* | Name for logging purposes | | `name` | `string` | *required* | Name for logging purposes |
| `watch` | `string \| string[]` | *required* | Glob pattern(s) to watch | | `watch` | `string \| string[]` | *required* | Glob pattern(s) to watch |
| `command` | `string` | - | Shell command to execute on changes | | `command` | `string` | | Shell command to execute on changes |
| `restart` | `boolean` | `true` | Kill previous process before restarting | | `restart` | `boolean` | `true` | Kill previous process before restarting |
| `debounce` | `number` | `300` | Debounce delay in milliseconds | | `debounce` | `number` | `300` | Debounce delay in milliseconds |
| `runOnStart` | `boolean` | `true` | Run the command immediately on start | | `runOnStart` | `boolean` | `true` | Run the command immediately on start |
@@ -153,22 +159,28 @@ tswatch uses `npmextra.json` for configuration. Add your config under the `@git.
| `port` | `number` | `3002` | Server port | | `port` | `number` | `3002` | Server port |
| `serveDir` | `string` | `./dist_watch/` | Directory to serve | | `serveDir` | `string` | `./dist_watch/` | Directory to serve |
| `liveReload` | `boolean` | `true` | Inject live reload script | | `liveReload` | `boolean` | `true` | Inject live reload script |
| `domain` | `string` | `localhost` | Domain name for the dev server |
#### `IBundleConfig` #### `IBundleConfig`
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `name` | `string` | - | Name for logging purposes | | `name` | `string` | | Name for logging purposes |
| `from` | `string` | *required* | Entry point file | | `from` | `string` | *required* | Entry point file |
| `to` | `string` | *required* | Output file | | `to` | `string` | *required* | Output file |
| `watchPatterns` | `string[]` | - | Additional patterns to watch | | `watchPatterns` | `string[]` | | Additional patterns to watch |
| `triggerReload` | `boolean` | `true` | Trigger server reload after bundling | | `triggerReload` | `boolean` | `true` | Trigger server reload after bundling |
| `outputMode` | `'bundle' \| 'base64ts'` | `'bundle'` | Output mode for the bundle |
| `bundler` | `'esbuild' \| 'rolldown' \| 'rspack'` | `'esbuild'` | Bundler engine to use |
| `production` | `boolean` | `false` | Enable minification for production builds |
| `includeFiles` | `(string \| { from, to })[]` | — | Additional files to include alongside the bundle |
| `maxLineLength` | `number` | — | Max chars per line for `base64ts` output mode |
## 🛠️ CLI Commands ## 🛠️ CLI Commands
### `tswatch` ### `tswatch`
Runs with configuration from `npmextra.json`. If no config exists, launches the interactive wizard. Runs with configuration from `.smartconfig.json`. If no config exists, launches the interactive wizard automatically.
```bash ```bash
tswatch tswatch
@@ -184,12 +196,11 @@ tswatch init
## 💻 Programmatic API ## 💻 Programmatic API
### Basic Usage with Config ### Basic Usage with Inline Config
```typescript ```typescript
import { TsWatch } from '@git.zone/tswatch'; import { TsWatch } from '@git.zone/tswatch';
// Create TsWatch with inline configuration
const watcher = new TsWatch({ const watcher = new TsWatch({
watchers: [ watchers: [
{ {
@@ -214,7 +225,7 @@ await watcher.stop();
```typescript ```typescript
import { TsWatch } from '@git.zone/tswatch'; import { TsWatch } from '@git.zone/tswatch';
// Load configuration from npmextra.json // Load configuration from .smartconfig.json
const watcher = TsWatch.fromConfig(); const watcher = TsWatch.fromConfig();
if (watcher) { if (watcher) {
@@ -237,7 +248,7 @@ if (configHandler.hasConfig()) {
// Get available presets // Get available presets
const presets = configHandler.getPresetNames(); const presets = configHandler.getPresetNames();
console.log(presets); // ['npm', 'test', 'service', 'element', 'website'] // => ['npm', 'test', 'service', 'element', 'website']
// Get a specific preset // Get a specific preset
const npmPreset = configHandler.getPreset('npm'); const npmPreset = configHandler.getPreset('npm');
@@ -280,7 +291,7 @@ const watcher = new Watcher({
await watcher.start(); await watcher.start();
``` ```
## 📁 Project Structures ## 📁 Project Structure Examples
### NPM Package / Node.js Library ### NPM Package / Node.js Library
@@ -289,10 +300,9 @@ project/
├── ts/ # TypeScript source files ├── ts/ # TypeScript source files
├── test/ # Test files ├── test/ # Test files
├── package.json # With "test" script ├── package.json # With "test" script
└── npmextra.json # tswatch config └── .smartconfig.json # tswatch config
``` ```
Config:
```json ```json
{ {
"@git.zone/tswatch": { "@git.zone/tswatch": {
@@ -307,10 +317,9 @@ Config:
project/ project/
├── ts/ # TypeScript source files ├── ts/ # TypeScript source files
├── package.json # With "startTs" script ├── package.json # With "startTs" script
└── npmextra.json └── .smartconfig.json
``` ```
Config:
```json ```json
{ {
"@git.zone/tswatch": { "@git.zone/tswatch": {
@@ -329,10 +338,9 @@ project/
│ ├── index.ts # Web entry point │ ├── index.ts # Web entry point
│ └── index.html │ └── index.html
├── dist_watch/ # Output (auto-created) ├── dist_watch/ # Output (auto-created)
└── npmextra.json └── .smartconfig.json
``` ```
Config:
```json ```json
{ {
"@git.zone/tswatch": { "@git.zone/tswatch": {
@@ -354,10 +362,9 @@ project/
│ └── index.html │ └── index.html
├── assets/ # Static assets ├── assets/ # Static assets
├── dist_serve/ # Output ├── dist_serve/ # Output
└── npmextra.json └── .smartconfig.json
``` ```
Config:
```json ```json
{ {
"@git.zone/tswatch": { "@git.zone/tswatch": {
@@ -368,30 +375,37 @@ Config:
## 🌐 Development Server ## 🌐 Development Server
The built-in development server (enabled in `element` and `website` presets) features: The built-in development server (powered by `@api.global/typedserver`'s `UtilityWebsiteServer`) is enabled in `element` and `website` presets:
- **Live Reload** - Automatically refreshes browser on changes - 🔄 **Live Reload** — WebSocket-based instant browser refresh on changes (via service worker + devtools injection)
- **No Caching** - Prevents browser caching during development (sends `Cache-Control: no-store, no-cache` headers) - 🚫 **No Caching** Prevents browser caching during development (`Cache-Control: no-store, no-cache` headers)
- **CORS** - Cross-origin requests enabled - 🌍 **CORS** Cross-origin requests enabled
- **Compression** - Gzip compression for faster loading - 🗜️ **Compression** — Brotli + gzip compression for faster loading
- **SPA Fallback** - Single-page application routing support - 📱 **SPA Fallback** Single-page application routing support
- **Security Headers** - Cross-origin isolation headers - 🔒 **Security Headers** Cross-origin isolation (`COOP`, `COEP`)
- 📦 **PWA Manifest** — Auto-generated Progressive Web App manifest
-**Service Worker** — Built-in service worker version info for cache busting
Default configuration: Default configuration:
- **Port**: 3002
- **Serve Directory**: `./dist_watch/` | Setting | Default |
- **Live Reload**: Enabled |---------|---------|
| Port | `3002` |
| Serve Directory | `./dist_watch/` |
| Live Reload | Enabled |
| Domain | `localhost` |
## 🔧 Configuration Tips ## 🔧 Configuration Tips
1. **Use presets for common workflows** - They're battle-tested and cover most use cases 1. **Use presets for common workflows** They're battle-tested and cover most use cases
2. **Customize with explicit config** - Override preset defaults by adding explicit `watchers`, `bundles`, or `server` config 2. **Customize with explicit config** Override preset defaults by adding explicit `watchers`, `bundles`, or `server` config
3. **Debounce wisely** - Default 300ms works well; increase for slower builds 3. **Debounce wisely** Default 300ms works well; increase for slower builds
4. **Use `restart: false`** for one-shot commands (like builds) and `restart: true` for long-running processes (like servers) 4. **Use `restart: false`** for one-shot commands (like builds) and `restart: true` for long-running processes (like servers)
5. **Multiple bundlers** — Choose between `esbuild` (fastest), `rolldown` (smallest output), or `rspack` (webpack-compatible) per bundle
## License and Legal Information ## License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file. This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](./license) file.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file. **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tswatch', name: '@git.zone/tswatch',
version: '3.2.1', version: '3.3.2',
description: 'A development tool for automatically watching and re-compiling TypeScript projects upon detecting file changes, enhancing developer workflows.' description: 'A development tool for automatically watching and re-compiling TypeScript projects upon detecting file changes, enhancing developer workflows.'
} }

View File

@@ -28,6 +28,8 @@ export interface IServerConfig {
serveDir?: string; serveDir?: string;
/** Whether to inject live reload script (default: true) */ /** Whether to inject live reload script (default: true) */
liveReload?: boolean; liveReload?: boolean;
/** Domain name for the dev server (default: 'localhost') */
domain?: string;
} }
/** /**

View File

@@ -119,28 +119,28 @@ const presets: Record<string, interfaces.ITswatchConfig> = {
* Handles loading and managing tswatch configuration * Handles loading and managing tswatch configuration
*/ */
export class ConfigHandler { export class ConfigHandler {
private npmextra: plugins.npmextra.Npmextra; private smartconfig: plugins.smartconfig.Smartconfig;
private cwd: string; private cwd: string;
constructor(cwdArg?: string) { constructor(cwdArg?: string) {
this.cwd = cwdArg || paths.cwd; this.cwd = cwdArg || paths.cwd;
this.npmextra = new plugins.npmextra.Npmextra(this.cwd); this.smartconfig = new plugins.smartconfig.Smartconfig(this.cwd);
} }
/** /**
* Check if a tswatch configuration exists * Check if a tswatch configuration exists
*/ */
public hasConfig(): boolean { public hasConfig(): boolean {
const config = this.npmextra.dataFor<interfaces.ITswatchConfig>(CONFIG_KEY, null); const config = this.smartconfig.dataFor<interfaces.ITswatchConfig>(CONFIG_KEY, null);
return config !== null; return config !== null;
} }
/** /**
* Load configuration from npmextra.json * Load configuration from smartconfig.json
* If a preset is specified, merge preset defaults with user overrides * If a preset is specified, merge preset defaults with user overrides
*/ */
public loadConfig(): interfaces.ITswatchConfig | null { public loadConfig(): interfaces.ITswatchConfig | null {
const config = this.npmextra.dataFor<interfaces.ITswatchConfig>(CONFIG_KEY, null); const config = this.smartconfig.dataFor<interfaces.ITswatchConfig>(CONFIG_KEY, null);
if (!config) { if (!config) {
return null; return null;
@@ -177,7 +177,7 @@ export class ConfigHandler {
} }
/** /**
* Get the config key for npmextra.json * Get the config key for smartconfig.json
*/ */
public getConfigKey(): string { public getConfigKey(): string {
return CONFIG_KEY; return CONFIG_KEY;

View File

@@ -9,13 +9,13 @@ import { logger } from './tswatch.logging.js';
/** /**
* TsWatch - Config-driven file watcher * TsWatch - Config-driven file watcher
* *
* Reads configuration from npmextra.json under the key '@git.zone/tswatch' * Reads configuration from smartconfig.json under the key '@git.zone/tswatch'
* and sets up watchers, bundles, and dev server accordingly. * and sets up watchers, bundles, and dev server accordingly.
*/ */
export class TsWatch { export class TsWatch {
public config: interfaces.ITswatchConfig; public config: interfaces.ITswatchConfig;
public watcherMap = new plugins.lik.ObjectMap<Watcher>(); public watcherMap = new plugins.lik.ObjectMap<Watcher>();
public typedserver: plugins.typedserver.TypedServer | null = null; public utilityWebsiteServer: plugins.typedserver.utilityservers.UtilityWebsiteServer | null = null;
private tsbundle = new plugins.tsbundle.TsBundle(); private tsbundle = new plugins.tsbundle.TsBundle();
private customBundleHandler = new plugins.tsbundle.CustomBundleHandler(); private customBundleHandler = new plugins.tsbundle.CustomBundleHandler();
@@ -27,7 +27,7 @@ export class TsWatch {
} }
/** /**
* Create TsWatch from npmextra.json configuration * Create TsWatch from smartconfig.json configuration
*/ */
public static fromConfig(cwdArg?: string): TsWatch | null { public static fromConfig(cwdArg?: string): TsWatch | null {
const configHandler = new ConfigHandler(cwdArg); const configHandler = new ConfigHandler(cwdArg);
@@ -75,8 +75,8 @@ export class TsWatch {
}); });
// Start server after watchers are ready // Start server after watchers are ready
if (this.typedserver) { if (this.utilityWebsiteServer) {
await this.typedserver.start(); await this.utilityWebsiteServer.start(this.config.server?.port || 3002);
logger.log('ok', `Dev server started on port ${this.config.server?.port || 3002}`); logger.log('ok', `Dev server started on port ${this.config.server?.port || 3002}`);
} }
} }
@@ -91,14 +91,14 @@ export class TsWatch {
logger.log('info', `Setting up dev server on port ${port}, serving ${serveDir}`); logger.log('info', `Setting up dev server on port ${port}, serving ${serveDir}`);
this.typedserver = new plugins.typedserver.TypedServer({ this.utilityWebsiteServer = new plugins.typedserver.utilityservers.UtilityWebsiteServer({
cors: true, domain: serverConfig.domain || 'localhost',
injectReload: serverConfig.liveReload !== false,
serveDir: plugins.path.join(paths.cwd, serveDir), serveDir: plugins.path.join(paths.cwd, serveDir),
port: port, port: port,
compression: true, cors: true,
spaFallback: true, spaFallback: true,
noCache: true, noCache: true,
injectReload: serverConfig.liveReload !== false,
securityHeaders: { securityHeaders: {
crossOriginOpenerPolicy: 'same-origin', crossOriginOpenerPolicy: 'same-origin',
crossOriginEmbedderPolicy: 'require-corp', crossOriginEmbedderPolicy: 'require-corp',
@@ -159,8 +159,8 @@ export class TsWatch {
logger.log('ok', `[${name}] bundle complete`); logger.log('ok', `[${name}] bundle complete`);
// Trigger reload if configured and server is running // Trigger reload if configured and server is running
if (bundleConfig.triggerReload !== false && this.typedserver) { if (bundleConfig.triggerReload !== false && this.utilityWebsiteServer?.typedserver) {
await this.typedserver.reload(); await this.utilityWebsiteServer.typedserver.reload();
} }
}; };
@@ -211,8 +211,8 @@ export class TsWatch {
* stops the execution of any active Watchers * stops the execution of any active Watchers
*/ */
public async stop() { public async stop() {
if (this.typedserver) { if (this.utilityWebsiteServer) {
await this.typedserver.stop(); await this.utilityWebsiteServer.stop();
} }
await this.watcherMap.forEach(async (watcher) => { await this.watcherMap.forEach(async (watcher) => {
await watcher.stop(); await watcher.stop();

View File

@@ -32,7 +32,7 @@ export class Watcher {
executor: 'bash', executor: 'bash',
}); });
private currentExecution: plugins.smartshell.IExecResultStreaming; private currentExecution: plugins.smartshell.IExecResultStreaming | undefined;
private smartwatchInstance = new plugins.smartwatch.Smartwatch([]); private smartwatchInstance = new plugins.smartwatch.Smartwatch([]);
private options: IWatcherConstructorOptions; private options: IWatcherConstructorOptions;
private debounceTimer: NodeJS.Timeout | null = null; private debounceTimer: NodeJS.Timeout | null = null;
@@ -202,7 +202,9 @@ export class Watcher {
clearTimeout(this.debounceTimer); clearTimeout(this.debounceTimer);
} }
await this.smartwatchInstance.stop(); await this.smartwatchInstance.stop();
if (this.currentExecution && !this.currentExecution.childProcess.killed) { if (this.currentExecution) {
// Always tree-kill — even if the direct child is dead (.killed === true),
// grandchildren (e.g. tsrun, devserver) may still be running.
await this.currentExecution.kill(); await this.currentExecution.kill();
} }
} }

View File

@@ -18,7 +18,7 @@ tswatchCli.standardCommand().subscribe(async (argvArg) => {
// Config exists - run with it // Config exists - run with it
const tsWatch = TsWatch.fromConfig(); const tsWatch = TsWatch.fromConfig();
if (tsWatch) { if (tsWatch) {
logger.log('info', 'Starting tswatch with configuration from npmextra.json'); logger.log('info', 'Starting tswatch with configuration from smartconfig.json');
await tsWatch.start(); await tsWatch.start();
} else { } else {
logger.log('error', 'Failed to load configuration'); logger.log('error', 'Failed to load configuration');
@@ -26,7 +26,7 @@ tswatchCli.standardCommand().subscribe(async (argvArg) => {
} }
} else { } else {
// No config - launch wizard // No config - launch wizard
logger.log('info', 'No tswatch configuration found in npmextra.json'); logger.log('info', 'No tswatch configuration found in smartconfig.json');
const config = await runInit(); const config = await runInit();
if (config) { if (config) {
// Run with the newly created config // Run with the newly created config

View File

@@ -56,10 +56,10 @@ export class TswatchInit {
config = { ...preset, preset: template as interfaces.ITswatchConfig['preset'] }; config = { ...preset, preset: template as interfaces.ITswatchConfig['preset'] };
} }
// Save to npmextra.json // Save to smartconfig.json
await this.saveConfig(config); await this.saveConfig(config);
console.log('\nConfiguration saved to npmextra.json'); console.log('\nConfiguration saved to smartconfig.json');
console.log('Run "tswatch" to start watching.\n'); console.log('Run "tswatch" to start watching.\n');
return config; return config;
@@ -166,16 +166,16 @@ export class TswatchInit {
} }
/** /**
* Save configuration to npmextra.json * Save configuration to smartconfig.json
*/ */
private async saveConfig(config: interfaces.ITswatchConfig): Promise<void> { private async saveConfig(config: interfaces.ITswatchConfig): Promise<void> {
const npmextraPath = plugins.path.join(paths.cwd, 'npmextra.json'); const smartconfigPath = plugins.path.join(paths.cwd, 'smartconfig.json');
// Read existing npmextra.json if it exists // Read existing smartconfig.json if it exists
let existingConfig: Record<string, any> = {}; let existingConfig: Record<string, any> = {};
try { try {
const smartfsInstance = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode()); const smartfsInstance = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
const content = await smartfsInstance.file(npmextraPath).encoding('utf8').read() as string; const content = await smartfsInstance.file(smartconfigPath).encoding('utf8').read() as string;
existingConfig = JSON.parse(content); existingConfig = JSON.parse(content);
} catch { } catch {
// File doesn't exist or is invalid, start fresh // File doesn't exist or is invalid, start fresh
@@ -186,7 +186,7 @@ export class TswatchInit {
// Write back // Write back
const smartfsInstance = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode()); const smartfsInstance = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
await smartfsInstance.file(npmextraPath).encoding('utf8').write(JSON.stringify(existingConfig, null, 2)); await smartfsInstance.file(smartconfigPath).encoding('utf8').write(JSON.stringify(existingConfig, null, 2));
} }
} }

View File

@@ -13,7 +13,7 @@ export { typedserver };
// @push.rocks scope // @push.rocks scope
import * as lik from '@push.rocks/lik'; import * as lik from '@push.rocks/lik';
import * as npmextra from '@push.rocks/npmextra'; import * as smartconfig from '@push.rocks/smartconfig';
import * as smartcli from '@push.rocks/smartcli'; import * as smartcli from '@push.rocks/smartcli';
import * as smartdelay from '@push.rocks/smartdelay'; import * as smartdelay from '@push.rocks/smartdelay';
import * as smartexit from '@push.rocks/smartexit'; import * as smartexit from '@push.rocks/smartexit';
@@ -23,11 +23,10 @@ import * as smartlog from '@push.rocks/smartlog';
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local'; import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
import * as smartshell from '@push.rocks/smartshell'; import * as smartshell from '@push.rocks/smartshell';
import * as smartwatch from '@push.rocks/smartwatch'; import * as smartwatch from '@push.rocks/smartwatch';
import * as taskbuffer from '@push.rocks/taskbuffer';
export { export {
lik, lik,
npmextra, smartconfig,
smartcli, smartcli,
smartdelay, smartdelay,
smartexit, smartexit,
@@ -37,5 +36,4 @@ export {
smartlogDestinationLocal, smartlogDestinationLocal,
smartshell, smartshell,
smartwatch, smartwatch,
taskbuffer,
}; };

View File

@@ -7,7 +7,6 @@
"moduleResolution": "NodeNext", "moduleResolution": "NodeNext",
"esModuleInterop": true, "esModuleInterop": true,
"verbatimModuleSyntax": true, "verbatimModuleSyntax": true,
"baseUrl": ".",
"paths": {} "paths": {}
}, },
"exclude": [ "exclude": [