@human-synthesis/norns-tron 0.1.0 → 0.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@human-synthesis/norns-tron",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "TRON serialization for the Norns ecosystem — token-efficient, faster-than-JSON wire format for APIs and LLM-facing output.",
5
5
  "license": "MIT",
6
6
  "author": "Daniel Teodoroiu (https://humansynthesis.ai)",
@@ -15,10 +15,6 @@
15
15
  "README.md",
16
16
  "PERFORMANCE.md"
17
17
  ],
18
- "scripts": {
19
- "test": "bun test",
20
- "embed-wasm": "bun scripts/embed-wasm.mjs"
21
- },
22
18
  "exports": {
23
19
  ".": "./src/index.js",
24
20
  "./server": "./src/server.js",
@@ -40,5 +36,12 @@
40
36
  },
41
37
  "publishConfig": {
42
38
  "access": "public"
39
+ },
40
+ "scripts": {
41
+ "test": "bun test",
42
+ "embed-wasm": "bun scripts/embed-wasm.mjs"
43
+ },
44
+ "devDependencies": {
45
+ "valibot": "^1.4.0"
43
46
  }
44
47
  }
package/src/spec.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- export const SPEC_EXT: '.tron';
1
+ export const SPEC_EXT: '.t';
2
+ /** Accepted spec extensions, in preference order — `.t` is the default. */
3
+ export const SPEC_EXTS: readonly ['.t', '.tron'];
2
4
  export const APP_SPEC: 'app';
3
5
 
6
+ /** On-disk filename for a module: its existing file, else `<name>.t`. */
7
+ export function specFilename(name: string, files?: Record<string, string>): string;
8
+
4
9
  /** sha256 hex of a value's canonical text — the unit of change detection. */
5
10
  export function specHash(value: unknown): string;
6
11
 
@@ -20,6 +25,7 @@ export function writeSpec(
20
25
  export function readSpecs(dir: string): {
21
26
  app: unknown;
22
27
  modules: Record<string, unknown>;
28
+ files: Record<string, string>;
23
29
  hashes: Record<string, string>;
24
30
  version: string;
25
31
  };
package/src/spec.js CHANGED
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * Spec-file helpers — server-side only (`@human-synthesis/norns-tron/spec`).
3
3
  *
4
- * A Norns app's canonical spec lives in `specs/` as one `.tron` file per
5
- * module plus `app.tron`, written in canonical form (see canonical.js).
4
+ * A Norns app's canonical spec lives in `specs/` as one `.t` file per
5
+ * module plus `app.t`, written in canonical form (see canonical.js). The
6
+ * long-form `.tron` extension is accepted too; `.t` is the default for new
7
+ * files, matching the other Norns extensions (`.n`, `.c`, `.p`).
6
8
  * These helpers read/write that directory and compute the content-addressed
7
9
  * version hashes used by `ifVersion` optimistic checks and incremental
8
10
  * generation.
@@ -15,9 +17,16 @@ import { basename, dirname, join } from 'node:path';
15
17
  import { formatCanonical } from './canonical.js';
16
18
  import * as AUTO from './core/tron-auto.js';
17
19
 
18
- export const SPEC_EXT = '.tron';
20
+ export const SPEC_EXT = '.t';
21
+ /** Accepted spec extensions, in preference order — `.t` is the default. */
22
+ export const SPEC_EXTS = ['.t', '.tron'];
19
23
  export const APP_SPEC = 'app';
20
24
 
25
+ /** On-disk filename for a module: its existing file, else `<name>.t`. */
26
+ export function specFilename(name, files) {
27
+ return files?.[name] ?? name + SPEC_EXT;
28
+ }
29
+
21
30
  /** sha256 hex of a value's canonical text — the unit of change detection. */
22
31
  export function specHash(value) {
23
32
  return createHash('sha256').update(formatCanonical(value), 'utf-8').digest('hex');
@@ -55,27 +64,36 @@ export function writeSpec(file, value) {
55
64
  *
56
65
  * @param {string} dir
57
66
  * @returns {{
58
- * app: *, // app.tron contents (null if absent)
67
+ * app: *, // app spec contents (null if absent)
59
68
  * modules: Record<string, *>, // module name -> spec value
69
+ * files: Record<string, string>, // module name -> on-disk filename
60
70
  * hashes: Record<string, string>, // per-file canonical hash (incl. 'app')
61
71
  * version: string // hash over all files — the app version
62
72
  * }}
63
73
  */
64
74
  export function readSpecs(dir) {
65
75
  const names = readdirSync(dir)
66
- .filter((f) => f.endsWith(SPEC_EXT))
76
+ .filter((f) => SPEC_EXTS.some((ext) => f.endsWith(ext)))
67
77
  .sort();
68
78
  const modules = {};
79
+ const files = {};
69
80
  const hashes = {};
70
81
  let app = null;
71
82
  for (const f of names) {
72
- const name = basename(f, SPEC_EXT);
83
+ const ext = SPEC_EXTS.find((e) => f.endsWith(e));
84
+ const name = basename(f, ext);
85
+ if (files[name] !== undefined) {
86
+ throw new Error(
87
+ `duplicate spec for "${name}": ${files[name]} and ${f} — keep one (\`.t\` is the default)`
88
+ );
89
+ }
90
+ files[name] = f;
73
91
  const value = readSpec(join(dir, f));
74
92
  hashes[name] = specHash(value);
75
93
  if (name === APP_SPEC) app = value;
76
94
  else modules[name] = value;
77
95
  }
78
- return { app, modules, hashes, version: combineHashes(hashes) };
96
+ return { app, modules, files, hashes, version: combineHashes(hashes) };
79
97
  }
80
98
 
81
99
  /**