Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
- [API code generation](api-codegen.md) — repository-wide rules for maintained inputs, generated tagged-input mappings, shared compilation, deterministic Rust and TypeScript output, repository commands, and independent verification.
- [API query code generation](api-codegen-query.md) — query-specific generation guidance for the agreed selective-query API shape; implementation and release remain performance-gated.
- [@taffyjs/node decisions](taffyjs-node-decisions.md) — vouched choices for the Node binding's role, API priorities, module format, distribution, and testing strategy.
- [@taffyjs/wasm package design](taffyjs-wasm-package.md) — vouched public contract, artifact layout, initialization model, ownership boundary, and verification requirements for the explicit Wasm package.
- [Tooling decisions](tooling-decisions.md) — vouched rulings for test workspace package naming, the repository-wide TypeScript default, JavaScript package builds, repository command orchestration, tool ownership, and demand-driven API code generation.
- [@taffyjs/wasm package design](taffyjs-wasm-package.md) — public contract, artifact layout, initialization model, ownership boundary, and verification requirements for the explicit Wasm package.
- [Tooling decisions](tooling-decisions.md) — rulings for npm scope and test workspace package naming, the repository-wide TypeScript default, JavaScript package builds, repository command orchestration, tool ownership, and demand-driven API code generation.
6 changes: 2 additions & 4 deletions .agents/docs/taffyjs-wasm-package.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# @taffyjs/wasm Package Design

[VOUCHED @hyfdev 2026-08-15]

## Outcome

`@taffyjs/wasm` is the explicit distribution for consumers that want TaffyJS to run as WebAssembly in both Node.js and browsers. A consumer chooses it by importing that package; it is not an automatic fallback for `@taffyjs/node`, and installing `@taffyjs/node` must not download its Wasm binary.
Expand All @@ -26,7 +24,7 @@ The package is ESM-only, matching `@taffyjs/node`. A dedicated public CommonJS b

The package contains the threadless `wasm32-wasip1` artifact as one raw base64 string in a generated private JavaScript module. The npm tarball does not contain an independent `.wasm` file. Base64 increases the uncompressed payload size, but avoiding a separate binary asset is more important for this package and ordinary package compression still applies during transfer.

The base64 payload occurs exactly once in the package, even though the package retains browser and default public entries. The private Node and browser ESM adapters both import that generated no-TLA ESM payload module normally. The generated target package such as `@taffyjs/binding-wasm32-wasip1` is not a public dependency or separately published TaffyJS package.
The base64 payload occurs exactly once in the package, even though the package retains browser and default public entries. The private Node and browser ESM adapters both import that generated no-TLA ESM payload module normally. The generated unscoped target package such as `taffyjs-binding-wasm32-wasip1` is a build-only staging artifact, not a public dependency or separately published TaffyJS package.

The package root uses conditional exports with one declaration surface, a browser entry, and a default Node.js entry. The intended shape is:

Expand Down Expand Up @@ -77,7 +75,7 @@ Both runtime chains use napi-rs's JavaScript WASI implementation without forward
- A Node.js ESM consumer must import `@taffyjs/wasm` and use the ordinary public Taffy API without initialization calls, top-level await in the selected package graph, or native platform packages.
- A bundled browser consumer must use the same import and API, include the inline payload without emitting a `.wasm` asset, and work without `SharedArrayBuffer`, cross-origin isolation, COOP, or COEP.
- The Node and browser builds must derive their JavaScript and TypeScript surface from the same authored source. Except for a documented and evidenced host-specific exception, every public Node binding behavior test must run unchanged against both `@taffyjs/node` and `@taffyjs/wasm`; one test configuration redirects the exact package import instead of copying test files.
- Package inspection must show exactly one base64 Wasm payload, no independent `.wasm` file, exactly one browser-side `WebAssembly.compile`, synchronous `instantiateNapiModuleSync` in the Node graph, no Node environment or filesystem-root WASI capabilities, no dependency on `@taffyjs/binding-wasm32-wasip1`, no public initialization subpath, and no accidentally published raw binding entry.
- Package inspection must show exactly one base64 Wasm payload, no independent `.wasm` file, exactly one browser-side `WebAssembly.compile`, synchronous `instantiateNapiModuleSync` in the Node graph, no Node environment or filesystem-root WASI capabilities, no dependency on `taffyjs-binding-wasm32-wasip1`, no public initialization subpath, and no accidentally published raw binding entry.
- Generated napi-rs artifacts and all derived package modules must be reproducible from the pinned toolchain and repository generator. The napi-rs deferred loader must not contain maintained TaffyJS edits, and the Node adapter transformation must reject unexpected upstream template changes.

## Evidence
Expand Down
10 changes: 10 additions & 0 deletions .agents/docs/tooling-decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ This ledger records only tooling judgments that Yunfei explicitly expressed for

## Decided

### The @taffyjs scope is reserved for published packages

**Ruling:** A package name may use the `@taffyjs` npm scope only when that package is intended to be published separately under the organization. Repository-only workspaces and generated or staged build-only packages must use unscoped names.

**Limits:** Separately published implementation artifacts qualify even when consumers should not import them directly. The native platform packages used as `@taffyjs/node` optional dependencies therefore remain scoped because they must be published with the public package, while the generated Wasm target package is unscoped because it is only a staging input. A temporary `private` field or missing publication automation during repository bootstrap does not by itself override the intended distribution boundary.

**Why:** Yunfei reserved the organization scope for packages that will actually be published; no additional rationale was given.

**Source:** Yunfei (`@hyfdev`), 2026-08-16; asked to generalize the test-package correction so every package that is not truly published avoids the `@taffyjs` scope.

### Direct names for top-level test packages

[VOUCHED @hyfdev 2026-08-16]
Expand Down
2 changes: 1 addition & 1 deletion packages/taffyjs-wasm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
},
"napi": {
"binaryName": "taffyjs",
"packageName": "@taffyjs/binding",
"packageName": "taffyjs-binding",
"targets": [
"wasm32-wasip1"
],
Expand Down
5 changes: 2 additions & 3 deletions tests/taffyjs-wasm/tests/package-contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ assert.equal(deferredLoader.includes("initial: 1024"), true);

const manifest = await import("@taffyjs/wasm/package.json", { with: { type: "json" } });
assert.deepEqual(Object.keys(manifest.default.exports).sort(), [".", "./package.json"]);
assert.equal(manifest.default.napi.packageName, "taffyjs-binding");
assert.equal(
Object.keys(manifest.default.dependencies).some((name) =>
name.startsWith("@taffyjs/binding-wasm"),
),
Object.keys(manifest.default.dependencies).some((name) => name.includes("binding-wasm")),
false,
);

Expand Down
5 changes: 3 additions & 2 deletions tools/taffy-wasm/generate-inline-wasm-runtime-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ const __wasmDebugFilePath = __nodePath.join(__dirname, 'taffyjs.wasm32-wasip1.de
if (__nodeFs.existsSync(__wasmDebugFilePath)) {
__wasmFilePath = __wasmDebugFilePath
} else if (!__nodeFs.existsSync(__wasmFilePath)) {
const __wasiPackageEntry = require.resolve('@taffyjs/binding-wasm32-wasip1')
const __wasiPackageEntry = require.resolve('taffyjs-binding-wasm32-wasip1')
const __packagedWasmFilePath = __nodePath.join(
__nodePath.dirname(__wasiPackageEntry),
'taffyjs.wasm32-wasip1.wasm',
)
if (!__nodeFs.existsSync(__packagedWasmFilePath)) {
throw new Error(
'@taffyjs/binding-wasm32-wasip1 is installed but is missing taffyjs.wasm32-wasip1.wasm.',
'taffyjs-binding-wasm32-wasip1 is installed but is missing taffyjs.wasm32-wasip1.wasm.',
)
}
__wasmFilePath = __packagedWasmFilePath
Expand All @@ -124,6 +124,7 @@ for (const forbidden of [
"preopens",
"__wasmFilePath",
"@taffyjs/binding-wasm",
"taffyjs-binding-wasm",
"require('./taffyjs.wasm-base64",
]) {
if (nodeLoaderSource.includes(forbidden)) {
Expand Down