toolPackage manifestv5.0.6

tool.bun

Shared Bun build presets and CLI for ContractSpec packages

@lssm-tech/tool.bun
Source, release and verification context

Source snapshot bcc79fcc · Declared package version 5.0.6. This page combines the checked-in package guide and manifest; commands and runtime behavior were not executed in this review.

Package source ↗ Manifest ↗
servernode
EXPLORE THE PACKAGE

See where this package fits.

Follow a declared connection, inspect an import, then open the source guide when you need the detail.

THIS PACKAGEtool.buntools

Arrows point from a package to its direct dependency. Each count is derived from the captured manifests.

2 déclarationsSELECT TO INSPECT

@lssm-tech/tool.bun

Website: https://contractspec.io

Shared Bun build presets and CLI for ContractSpec packages. Provides the contractspec-bun-build binary used by nearly every package's build, dev, and prebuild scripts.

What It Provides

  • Couche: tool
  • Consumers: all monorepo packages (via contractspec-bun-build in their scripts)

Installation

npm install @lssm-tech/tool.bun

or

bun add @lssm-tech/tool.bun

Usage

bash
npx contractspec-bun-build --help
# or
bunx contractspec-bun-build --help

Typed Config

The ordered configuration filenames are owned by this package's contractspec.development.configInputs manifest binding. Runtime discovery uses this validated list. The pending affected-work planner integration can use the same authority to bind configuration dependencies to the invoking workspace. This metadata describes dependencies; it does not authorize execution or waive artifact qualification.

The root package export includes TypeScript declarations for config presets:

ts
import {
	defineConfig,
	moduleLibrary,
	type BuildConfig,
} from "@lssm-tech/tool.bun";

const config: BuildConfig = {
	...moduleLibrary,
	styleMode: "copy",
};

export default defineConfig(() => config);

Pack Staging Helpers

@lssm-tech/tool.bun/pack-staging holds the contributor helpers that package pack verifiers share: stageBuiltPackage, stageWorkspaceDependencies, workspacePackageRoots, literalize, catalogVersions and run. They run under Bun inside a repository workspace, rewrite workspace:/catalog: ranges to publishable ranges in staged copies and never publish anything. stageWorkspaceDependencies(root, run, manifestRoot) stages the transitive workspace: runtime closure of the manifest you name explicitly.

ts
import {
  run,
  stageBuiltPackage,
  stageWorkspaceDependencies,
} from "@lssm-tech/tool.bun/pack-staging";

const staged = await stageBuiltPackage(packageRoot, join(temporaryRoot, "pkg"));
const closure = await stageWorkspaceDependencies(artifacts, run, packageRoot);

Pack Verification Helpers

@lssm-tech/tool.bun/pack-verification holds the production-pack verifier that package pack:verify scripts share. It runs under Bun inside a repository workspace, works in a temporary directory you own and never publishes.

  • packReproducibly(packageRoot, root, run) stages the built package (dist without test or build-state files, README, production manifest) and packs it twice with npm pack --ignore-scripts. It fails unless both tarballs are byte-identical and the source manifest is unchanged.
  • inspectPackedArtifact(tarball, root, run, { requiredDependencies }) rejects source, test or build-state entries, private dependency protocols, source export targets, missing required direct dependencies and undeclared runtime imports in the emitted JavaScript.
  • verifyPackConsumer(packageRoot, root, tarball, manifest, run) builds and packs the workspace dependency closure, installs everything into a clean consumer, imports every declared subpath in Node and Bun and type-checks them with the nearest node_modules/.bin/tsgo up to the workspace root. The install resolves third-party dependencies from the npm registry.

The production manifest uses publishConfig.exports, writes workspace: ranges as ^<version> and catalog: ranges as the catalog's verbatim value, and drops dev dependencies, scripts and publishConfig. A closure dependency that declares a pack:production script produces its own tarball. packProductionPackage, stageProductionPackage, stageLocalDependencies, productionManifest, assertRuntimeImportClosure and runCommand are the building blocks.

ts
import {
  inspectPackedArtifact,
  packReproducibly,
  runCommand,
  verifyPackConsumer,
} from "@lssm-tech/tool.bun/pack-verification";

const { tarball, sha256 } = await packReproducibly(packageRoot, root, runCommand);
const manifest = await inspectPackedArtifact(tarball, root, runCommand, {
  requiredDependencies: ["@lssm-tech/lib.schema"],
});
await verifyPackConsumer(packageRoot, root, tarball, manifest, runCommand);

Private Build Entries

Declaration builds resolve dev-only workspace dependencies from the selected TypeScript build project's source and compiler configuration. Test-only dependencies excluded by that project do not trigger unrelated declaration builds. Runtime dependencies and required peers retain their artifact checks, and optional peers retain their type-only reference checks. Computed module expressions or relative imports outside the resolved project retain all dev dependencies conservatively. Test workflows continue to use the package's complete declared dependencies.

Non-UI packages can opt into entryMode: 'module-closure' with explicit literal entry paths and exports: { rewrite: false }. The existing manifest is the authority for supported exports: source export targets remain compatibility roots, including subpaths that the root barrel does not export. Runtime-relative imports are followed and each reachable module is emitted once per target. A new private helper never becomes a package export merely because it exists. Edit the manifest deliberately when adding a public entry. An exact subpath blocked with null in both frozen source and published maps adds no closure or emitted target. A block present in only one map fails validation. This mode implies no-bundle emission and uses sequential worker batches capped at 64 files or 8 MiB of source. A single module larger than 8 MiB fails explicitly in this opt-in mode. For mixed packages, browser emission starts only at exact frozen exports that advertise a browser target and follows their private dependencies. Unrelated Node-only public roots still build for Bun and Node and remain part of declaration emission. Shared-package inference retains browser output for those advertised roots; explicitly disabling browser remains an error. Node-only imports reachable from any browser root are rejected, and full-graph source validation still applies to backend roots. Direct entry mode retains its existing target inference. Single-entry tsconfig-override builds honor noBundle just like the normal CLI path and explicit closure batches. Local helpers stay separate, so React contexts and shared module state retain their identity. Bundled builds keep their existing behavior. The override worker resolves configured local TypeScript aliases to relative emitted modules while keeping declared external packages external; missing emitted helpers or assets fail validation. Platform entry selection, native worklets, client directives and explicit style copying remain separate parts of the existing build pipeline.

js
export default defineConfig({
  ...moduleLibrary,
  entry: ['src/index.ts', 'src/service.ts'],
  entryMode: 'module-closure',
  exports: { rewrite: false },
});

The initial opt-in supports non-UI relative JavaScript/TypeScript graphs and declared external packages. Computed imports/requires, local aliases, wildcard exports, assets and unadvertised platform-suffixed source graphs fail explicitly. An exact frozen public native/ios/android implementation root may use its dist/native layout; an exact web/browser root may use its existing root/browser layout. Only those advertised files are admitted, never private platform siblings or platform discovery. Published target paths must match the existing entry selection, and disabled targets still fail. Platform declaration aliases remain unsupported. Frozen conditional source exports retain every branch as a closure and declaration root. Each published condition must point to its matching source branch, honoring source condition order and default fallback. Browser reachability starts at that condition's source rather than unrelated native or backend branches. Multi-source maps are checked across every combination of their source/published condition names, including custom conditions, up to twelve distinct names per export. Larger or conflicting layouts fail explicitly and can use direct mode. Keep other platform graphs in direct mode. This does not change UI/Metro conditional exports or the existing direct-mode watcher. Declarations continue to use the package's complete TypeScript configuration. Full builds retain transactional rollback, and standalone transpile failures must never be treated as usable outputs. Closure mode freezes manifest bytes even when prebuild runs; it validates both source and published export mappings instead. Advertised runtime conditions must have enabled build targets. Browser claims are checked against the complete compatibility closure, not only intentional entries: a legacy-only Node builtin import fails before output is replaced. Its dev watcher recomputes reachability on source edits, including newly imported private files, serializes producers and retains the previous good output after a failed rebuild. It builds the Bun target by default (--all-targets includes the advertised targets). Manifest/compiler/build-config edits require restarting dev and terminate the watcher explicitly instead of using stale configuration.

Packages can emit implementation-only files without adding them to generated package exports. Use exports.exclude for files that public entries import relatively but consumers must not import as package subpaths:

js
export default {
	entry: ['src/**/*.ts', 'src/**/*.tsx'],
	exports: {
		rewrite: true,
		exclude: ['src/**/internal/**'],
	},
};

The files still build into dist, but prebuild omits matching paths from exports and publishConfig.exports.

Node ESM Relative Specifiers

Declared dependencies, optional dependencies and peers are explicitly external for JavaScript builds, including their subpaths. This preserves package boundaries when workspace TypeScript paths point at dependency source files: bundling local code must not inline a dependency and leak its transitive imports into the caller. Custom external entries remain additive. Development-only packages are not automatically treated as runtime dependencies.

Bun resolves TypeScript aliases before external flags. A temporary resolved tsconfig removes aliases belonging to external packages while retaining local aliases, so package boundaries survive that resolution order. The source config is not edited, and temporary configuration is removed after success or failure.

Shared-target inference follows runtime imports through local barrels, including literal dynamic imports and NodeNext .js specifiers resolving to TypeScript. Unselected tests remain excluded; custom source layouts and import cycles are supported. This is local source inference, not qualification of external packages or dynamic nonliteral imports for browser execution. Executable shebangs are normalized only in scanner input; source files remain unchanged and continue to build as CLI entry points.

Presets and default configuration share build-entry pattern definitions, including .spec.tsx and .test-support.ts/.test-support.tsx exclusions. Test helpers are not production entries, generated public subpaths, or target-inference roots. Keep test helpers excluded from package declaration tsconfigs as well. Explicit entry overrides remain supported, and test-runner discovery is independent of these build/export patterns.

Every production transpile target normalizes emitted relative ESM specifiers after Bun writes the complete target. Static imports, re-exports, and literal dynamic imports, and declaration import types (import("./module").Type and typeof import("./module")) resolve in this deterministic order:

  1. an existing exact file;
  2. a sibling .js file;
  3. an index.js file in the referenced directory.

Exact . and .. directory references resolve only to their index, never a similarly named sibling file. Declaration-only sidecars retain the same public types while their emitted specifiers use NodeNext-compatible .js paths.

Query strings and URL fragments are preserved. The normalizer is idempotent and syntax-aware, so import-shaped comments and ordinary strings are not changed. If any relative specifier cannot be resolved, the target fails before any emitted file is rewritten; incomplete Node ESM graphs cannot be published accidentally.

The TypeScript 7 parser and declaration emitter prefer the native binding for the current runtime architecture. If the package manager ran under a compatible alternate architecture (for example, x64 Node under Rosetta with arm64 Bun), the tool deterministically falls back to the installed same-platform binding.

Style Exports

contractspec-bun-build scans public CSS style entries separately from TypeScript entries so style files do not affect JavaScript output roots.

Default style entries:

  • styles/**/*.css
  • src/*.css
  • !**/*.module.css

Packages can override or disable style entries from their build config:

js
export default {
	styleEntry: ['styles/**/*.css'],
	// or: styles: { entry: ['styles/**/*.css'] },
	// or: styleEntry: false,
};

By default, style entries are processed with bun build. Packages that need to preserve CSS directives for another processor, such as Tailwind @source, @custom-variant, @theme, or @tailwind, can copy style files unchanged:

js
export default {
	styleEntry: ['src/styles/**/*.css'],
	styleMode: 'copy',
	// or: styles: { entry: ['src/styles/**/*.css'], mode: 'copy' },
};

Style entries are exported under the style and default conditions, for example ./styles/globals.css.

Type Declaration Emit

contractspec-bun-build types emits package declarations with stable TypeScript 7 (tsc) by generating a temporary declaration-only tsconfig and writing .d.ts files to dist.

Platform Variants

contractspec-bun-build recognizes platform suffixes in public TypeScript entries and emits conditional exports plus matching build outputs:

Source suffix Export condition Build output
.web browser dist/browser/* plus the Bun default when no base entry exists
.native react-native dist/native/*
.ios ios dist/native/*
.android android dist/native/*

Exact subpaths such as ./foo.web, ./foo.native, ./foo.ios, and ./foo.android are exported alongside canonical subpaths such as ./foo.

Public Entry Points

  • contractspec-bun-build -> ./bin/contractspec-bun-build.mjs
  • . — ./index.js

Local Commands

  • bun run test — bun test
  • bun run publish:pkg — bun publish --tolerate-republish --ignore-scripts --verbose
  • bun run publish:pkg:canary — bun publish:pkg --tag canary

Recent Updates

  • Normalize emitted relative Node ESM specifiers and fail closed on incomplete graphs
  • Add copy mode for public CSS style files that must preserve framework directives
  • Add direct CSS style subpath exports for public style files
  • Replace eslint+prettier by biomejs to optimize speed
  • Add multi platform support to bun build
  • Use-client within lib surface-runtime

Notes

  • Changes here affect every package's build pipeline -- test broadly before merging
  • Do not remove or rename CLI sub-commands (transpile, types, dev, prebuild) without updating all consumers
  • Keep runtime dependencies deliberate: glob powers source discovery and stable typescript powers declaration emit and artifact parsing
  • The published package contains only the binary, runtime library, typed root export, README, and changelog; conformance tests stay in the repository

Artifact normalization snapshots

Relative-import normalization uses the same source snapshot as its AST offsets. A concurrent normalizer that already produced the identical output is an idempotent no-op. If a file differs from both the parsed source and expected normalized output at publication checks, normalization reparses the graph up to three attempts. Continuous conflicts fail with an explicit changed-artifact error and preserve the observed newer file. A successful normalization is not a lock against arbitrary external emitters; build orchestration must still isolate output directories during emission.

Artifact parser deadlines

Each emitted-artifact parse has a two-minute I/O deadline. Snapshot disposal and API shutdown each have a two-second grace period before process termination and workspace cleanup. Timeout is an error, never successful artifact validation, and the serialized parser queue remains usable after rejection. Large graphs and NodeNext/native specifier checks remain in the conformance suite.

Compiler stdout is drained concurrently. If its pipe remains open ten seconds after the compiler exits, the build fails explicitly and cancels the reader. This deadline does not limit compilation time and never treats missing output as a successful build.

Parser RPC failures include the current snapshot/project/file-batch phase. A parser process exit rejects pending RPCs immediately with its exit status and bounded stderr tail, rather than waiting silently until the I/O deadline.

Multi-file artifact validation partitions native parser projects by source bytes (8 MiB) and file count (16). A single larger file remains intact. Projects close between groups, preserving ordered AST results and full validation while avoiding one native project retaining a large monorepo's repeated bundled source graphs.

Declaration compilation uses noEmitOnError so type/root-boundary failures cannot write partial declarations, including escaped output in sibling source trees. Consumers must still honor the nonzero build result; previous valid artifacts do not qualify a new source revision.

Concrete published declaration paths are required once a dependency declares a build:types producer. Missing artifacts fail before consumer compilation instead of silently falling back to sibling sources. Source-only dependencies remain supported. Standalone .d.ts/.d.mts/.d.cts inputs retain their suffix and are copied after successful type checking; generated sibling declarations take priority.

Dependency freshness checks read the same discovered source timestamps with at most eight concurrent metadata reads. They preserve the maximum timestamp and first source-order error, and settle every started read before returning.

Standalone declaration copying uses TypeScript's resolved input list. This covers custom layouts such as root-level ui/ and respects explicit project exclusions instead of assuming every package uses src/.

Unused optional workspace peers do not impose declaration-build prerequisites. The builder conservatively checks selected source files and resolved compiler options for peer references, including type-only imports. Required dependencies and referenced optional peers still require their advertised declaration artifacts.

Types-only builds materialize configured style entries before relative-import validation, using the same copy/build mode as JavaScript bundles. A cold checkout therefore includes styles referenced by emitted declarations without weakening artifact-integrity checks.

Artifact parsing explicitly opens the temporary tsconfig project and selects that project for every batch. It never relies on emitted files finding an ancestor or inferred project. Each project contains the requested JavaScript/declaration roots only, with dependency resolution, ambient type discovery, and default libraries disabled. All requested roots must still yield ASTs, and relative-import closure validation still rejects unresolved artifacts before writes. This isolates parsing from consumer tsconfig exclusions and keeps byte/file batch limits effective.

Full package output rebuilds

Standard consumers run contractspec-bun-build build from their build script. Bun still runs package prebuild lifecycle hooks; custom pipelines retain their explicit stages. This source-distributed tool has no build script. Run conformance with bun run test separately. Turbo hashes builder runtime sources directly.

contractspec-bun-build build saves the previous dist, emits JavaScript and declarations into a fresh output tree, and validates both stages before discarding the previous tree. A failed stage restores the previous output. This removes obsolete nested declarations after output layouts change without guessing whether individual declaration-only modules are stale. Standalone transpile retains its Turbo declaration-preservation behavior. Hand-authored declarations belong in the configured source inputs so successful type generation copies them into output.

An exclusive .contractspec-build.lock records the owner PID, hostname, and unique token. Concurrent full producers wait up to five minutes and then fail explicitly; every successful caller runs its own build. Only a same-host owner whose PID probe returns ESRCH is automatically recovered. Live/reused PIDs, permission failures, and foreign-host ownership never authorize reclamation.

A dead owner's interrupted output is rolled back before rebuilding. A commit marker distinguishes completed builds from interrupted backup cleanup. Recovery claims serialize competing reclaimers, and lock directories retire by atomic rename before deletion. Retired .released-* and .recovered-* directories may remain after process termination; they are ignored by Git and preserve any remaining backup for inspection.

Ownerless legacy locks, invalid journals, failed rollback, and interrupted recovery claims require manual recovery: first inspect live producers, preserve both current output and the lock directory outside the package, restore the previous lock/dist when present, and only remove the lock after establishing that no producer is using it. Never delete a live lock or infer death from age.

The standalone transpile and types commands take the same lock, so a bundle-only or declaration-only writer never interleaves with a full rebuild or with each other in one package. They update dist in place without a backup journal, so a crashed partial writer leaves nothing to restore. Watch-mode dev and Turbo cache restoration are not serialized by this lock. Use one workspace build owner when consumers must read dependency output while it remains stable.

Bun override builds

Bun 1.4.2 can emit directory mismatch when its CLI reads a --tsconfig-override file (upstream report). The shared builder runs builds requiring an override through Bun.build() in an isolated child process. A resolver marks declared external package imports and their subpaths external before workspace aliases can inline them; local aliases remain available. This also preserves boundaries on Bun versions whose JavaScript API does not honor the custom tsconfig option.

The source tsconfig remains unchanged, temporary configs are cleaned after success or failure, and build diagnostics remain visible. Builds without an override continue to use the Bun CLI. This is a compatible internal fix with no consumer configuration changes.

Declaration resolution honors a dependency's explicit published export map. Packages with intentional roots receive exact aliases, so inferred declaration references cannot choose an implicit wildcard pointing at unpublished private files. Existing declared wildcard maps and legacy packages without a published map retain their previous fallback resolution.

On Windows, the native TypeScript artifact parser detects named-pipe readiness without opening the pipe, preserving the connection for the actual API client. Workspace dependency identities use portable repository-relative paths on every host. Neither correction changes package exports or builder commands.

Declared capabilities.

This manifest does not declare a capability catalogue. Use the guide, import map and source to assess the package.

Imports and export paths.

3 entries

These are package-manifest entry points. Named symbols listed above come from the capability catalogue; this is not an exhaustive TypeScript symbol reference.

3 imports

Dependencies and related packages.

Runtime dependencies 2
glob
catalog:build
typescript
catalog:

Package scripts.

Commands declared by this package. Review its setup requirements before running them; no command here was executed by this review.

publish:pkgbun publish --tolerate-republish --ignore-scripts --verbose
publish:pkg:canarybun publish:pkg --tag canary
testbun test
typecheckbun test test/types.test.ts
Votre vue

Make room for your context.

Shape the presentation around this moment. You can change it whenever you need.

Votre contexte

The different parts of you

Choose a starting point

Un mélange utile de contexte, de visuels et de guidage discret.

Tune each dimension
Each dimension can change independently. Product permissions and available actions stay unchanged.

Support the way you begin and return

Tune your support

Confort de lecture

Choisir votre langue

La langue de l’interface change uniquement le texte. Les marchés, les prix et les parcours conservent leurs propres paramètres.

Couverture des traductions

Une partie du contenu est affichée en anglais.

Navigation151
Graphe616
Catégories378
Portfolio833
Exemples2 035
Aperçu de la source1 542

D’autres traductions seront ajoutées à mesure que le contenu sera relu.

Cette préférence est enregistrée dans ce navigateur.

Rechercher sur le site

Des points de départ utiles

Aucun résultat. Essayez une expression plus courte, un nom d’opération ou un autre périmètre de recherche.

UN PEU DE PLACE POUR EXPLORER

Trouvez quelque chose à explorer.

Ouvrez un aperçu détaillé sur cette page, essayez une autre perspective ou suivez le détail vers sa propre page.

Fonctionnement des aperçus et des commandes
01

Regarder avant de partir

Survolez un lien ou sélectionnez-le avec Tab pour voir un aperçu. Cliquer sur le lien d’origine ou appuyer sur Entrée ouvre toujours sa destination.

02

Rester dans le contexte

Entrez dans l’aperçu pour explorer ses sections. Depuis un lien sélectionné, utilisez Alt + ↓ pour y entrer au clavier. Échap le ferme.

03

Ouvrir les possibilités

Les lignes dépliables, les choix de perspective et les commandes mises en évidence révèlent davantage. Votre vue adapte le confort de lecture et le contexte exploré.

Un bouton séparé pour voir de plus près

Affichez de petits boutons d’aperçu à côté des liens quand l’espace le permet. Touchez l’œil pour examiner ou le lien pour y aller directement. Ce choix reste dans cet onglet.

Aucun historique de navigation n’est collecté. La réduction des animations suit votre appareil et Votre vue.