@carlos-tzin/tzin 1.0.7 → 1.0.8

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
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.8 — 2026-10-01
4
+
5
+ - **`tzin.config.ts` was silently ignored.** `loadConfig()` bailed out with
6
+ `null` for `.ts` files, so the `tzin.config.ts` that every scaffolded project
7
+ ships never applied — changing `port` there did nothing while the dev server
8
+ kept listening on the default. Added `loadConfigAsync()`, which reads a
9
+ TypeScript config through a dynamic import, and wired the dev server (which
10
+ runs under `tsx`) to it. The sync `loadConfig()` keeps its signature and
11
+ still handles `.js` / `.mjs` / `.json`.
12
+ - Tests: `tzin.config.ts` is now covered end to end (the dev server is spawned
13
+ and asserted to serve on the configured port).
14
+ - `vitest.config.ts`: exclude `.kilo/` and `.kilocode/`. Agent tooling leaves
15
+ git worktrees inside the repo holding stale copies of the suite, which the
16
+ default glob picked up (9 test files became 17).
17
+
3
18
  ## 1.0.7 — 2026-09-27
4
19
 
5
20
  The `tzin` CLI was announced as a headline feature but was **not reachable** in
package/dist/config.d.ts CHANGED
@@ -21,4 +21,10 @@ export interface TzinConfig {
21
21
  entry?: string;
22
22
  }
23
23
  export declare function loadConfig(cwd?: string): TzinConfig | null;
24
+ /**
25
+ * Same as {@link loadConfig}, but also reads a TypeScript `tzin.config.ts`
26
+ * through a dynamic import. Needs a TS loader in the process (the dev server
27
+ * runs under `tsx`).
28
+ */
29
+ export declare function loadConfigAsync(cwd?: string): Promise<TzinConfig | null>;
24
30
  export declare function defineConfig(config: TzinConfig): TzinConfig;
package/dist/config.js CHANGED
@@ -1,34 +1,58 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { createRequire } from 'node:module';
4
+ import { pathToFileURL } from 'node:url';
4
5
  const CONFIG_FILES = [
5
6
  'tzin.config.ts',
6
7
  'tzin.config.js',
7
8
  'tzin.config.mjs',
8
9
  'tzin.config.json',
9
10
  ];
10
- export function loadConfig(cwd = process.cwd()) {
11
+ function findConfigFile(cwd) {
11
12
  for (const file of CONFIG_FILES) {
12
13
  const path = resolve(cwd, file);
13
- if (existsSync(path)) {
14
- try {
15
- // For .ts files, we need to use a loader
16
- if (file.endsWith('.ts')) {
17
- // Return null for now - will be handled by tsx loader
18
- return null;
19
- }
20
- // createRequire, not a bare require(): the package is ESM, where a
21
- // bare require() is undefined and would silently drop the config.
22
- const config = createRequire(import.meta.url)(path);
23
- return config.default || config;
24
- }
25
- catch {
26
- return null;
27
- }
28
- }
14
+ if (existsSync(path))
15
+ return { file, path };
29
16
  }
30
17
  return null;
31
18
  }
19
+ export function loadConfig(cwd = process.cwd()) {
20
+ const found = findConfigFile(cwd);
21
+ if (!found)
22
+ return null;
23
+ // A .ts config needs a TS loader; only loadConfigAsync can do that.
24
+ if (found.file.endsWith('.ts'))
25
+ return null;
26
+ try {
27
+ // createRequire, not a bare require(): the package is ESM, where a
28
+ // bare require() is undefined and would silently drop the config.
29
+ const config = createRequire(import.meta.url)(found.path);
30
+ return config.default || config;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Same as {@link loadConfig}, but also reads a TypeScript `tzin.config.ts`
38
+ * through a dynamic import. Needs a TS loader in the process (the dev server
39
+ * runs under `tsx`).
40
+ */
41
+ export async function loadConfigAsync(cwd = process.cwd()) {
42
+ const found = findConfigFile(cwd);
43
+ if (!found)
44
+ return null;
45
+ if (!found.file.endsWith('.ts'))
46
+ return loadConfig(cwd);
47
+ try {
48
+ const mod = await import(pathToFileURL(found.path).href);
49
+ return (mod.default ?? mod);
50
+ }
51
+ catch (err) {
52
+ console.error(`tzin: failed to load ${found.file}: ${err.message}`);
53
+ return null;
54
+ }
55
+ }
32
56
  export function defineConfig(config) {
33
57
  return config;
34
58
  }
@@ -2,7 +2,7 @@ import { pathToFileURL } from 'node:url';
2
2
  import { resolve } from 'node:path';
3
3
  import { existsSync } from 'node:fs';
4
4
  import { listen } from './node.js';
5
- import { loadConfig } from './config.js';
5
+ import { loadConfigAsync } from './config.js';
6
6
  function pad(s, n) {
7
7
  return s.length >= n ? s : s + ' '.repeat(n - s.length);
8
8
  }
@@ -31,7 +31,7 @@ else {
31
31
  port = nonFlags[1] ? Number(nonFlags[1]) || 3000 : 3000;
32
32
  }
33
33
  // Load config
34
- const config = loadConfig() ?? {};
34
+ const config = (await loadConfigAsync()) ?? {};
35
35
  // Auto-detect entry: CLI arg > config > src/app.ts
36
36
  const entryFile = entry || config.entry || 'src/app.ts';
37
37
  const entryPath = resolve(entryFile);
package/dist/index.d.ts CHANGED
@@ -20,5 +20,5 @@ export { wsChannels, type WsRoute, type WsSend, type WsChannelOptions } from './
20
20
  export { attachChannels } from './ws-node.js';
21
21
  export { LocalBus, clusterHubs, type MessageBus } from './bus.js';
22
22
  export { cors, type CorsOptions } from './cors.js';
23
- export { defineConfig, loadConfig, type TzinConfig } from './config.js';
23
+ export { defineConfig, loadConfig, loadConfigAsync, type TzinConfig } from './config.js';
24
24
  export { loadRoutes, type RouteLoaderOptions } from './route-loader.js';
package/dist/index.js CHANGED
@@ -20,5 +20,5 @@ export { wsChannels } from './ws.js';
20
20
  export { attachChannels } from './ws-node.js';
21
21
  export { LocalBus, clusterHubs } from './bus.js';
22
22
  export { cors } from './cors.js';
23
- export { defineConfig, loadConfig } from './config.js';
23
+ export { defineConfig, loadConfig, loadConfigAsync } from './config.js';
24
24
  export { loadRoutes } from './route-loader.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlos-tzin/tzin",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Contract-first TypeScript framework. Types that scale, realtime channels with presence, and an MCP server for every API.",
5
5
  "license": "MIT",
6
6
  "author": "The tzin authors",