@git.zone/tspublish
Prepare and publish independently installable TypeScript packages from one repository. Each component has its own dependency list and package metadata; components share the repository version. TsBuild owns compilation. A release coordinator can prepare all packages before packing, journaling and publishing any of them.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Install
pnpm install --save-dev @git.zone/tspublish @git.zone/tsbuild
Repository structure
Keep the repository manifest private when it holds dependencies for the entire toolbox. Each named module becomes a separate public package with a filtered dependency manifest.
package.json
tsconfig.json
license.md
ts_core/
index.ts
readme.md
tspublish.json
ts_adapter/
index.ts
readme.md
tspublish.json
The repository's package.json supplies the shared version and external dependency
versions. Internal package dependencies use the exact shared version, even when an
older published version appears in the root manifest. Unknown external dependencies
fail validation instead of being assigned the repository version.
Each package requires its own readme.md. The root license is copied into every
prepared package. license.md is preferred; existing repositories using license
remain supported.
Module configuration
{
"name": "@example/adapter",
"order": 2,
"description": "Optional provider adapter for the example toolbox.",
"dependencies": ["@example/core", "external-sdk"],
"registries": ["useBase"],
"bin": [],
"engines": { "node": ">=24" },
"sideEffects": false,
"include": ["third-party-notices.md"]
}
Supported fields:
| Field | Meaning |
|---|---|
name |
Published npm package name. Unnamed descriptors remain available to TsBuild for ordering only. |
order |
Ordering preference among modules whose dependencies are ready. Dependencies always precede consumers. |
dependencies |
Required package names, resolved from sibling modules or root production dependencies. |
optionalDependencies |
Optional dependency names, resolved by the same rules. |
peerDependencies |
Explicit peer version ranges. |
peerDependenciesMeta |
Optional-peer metadata. |
description |
Package description; defaults to the root description. |
engines |
Runtime requirements; defaults to the root engines. |
os, cpu, libc |
Nonempty npm platform-selector arrays. Entries may use ! to exclude a platform; duplicate entries are rejected. Each module declares its own selectors. |
publishConfig.executableFiles |
Exact package-relative files that pnpm must pack with executable permissions. No leading ./, traversal, globs, duplicates, symlinks or directories. Every path must already be included in this package. Other publishConfig keys are rejected. |
sideEffects |
Standard package side-effect declaration. |
folders |
Additional ts_* folders owned by this package. A folder may have only one owner. |
exports |
Explicit subpath/conditional exports into the package's compiled folders. Defaults to typed root exports. |
include |
Exact repository-relative asset files or directories, including applicable notices. No globs or component source/compiled folders; use folders to declare source ownership. |
externalRuntimeAssets |
Exact repository-relative files or directories executed by another runtime, such as Deno source. Copied without npm import validation; the package owner must qualify that runtime and its dependency graph. The same filesystem and folder-ownership restrictions as include apply. Asset declarations cannot overlap. |
bin |
Executable names using the module's exported runCli() entrypoint. Wrappers are generated locally. |
registries |
Destination intent for the standalone publisher; also returned to release coordinators for validation. |
Root author, license, repository, homepage, bugs, keywords and funding metadata are preserved. The private repository flag, root scripts, unrelated dependencies and development dependencies are not copied into prepared packages.
Legacy main and types fields are derived from the root export's node,
import, default, and types conditions when available. They never point at
an unrelated default entrypoint when root exports are customized.
Native packages can declare "os": ["linux"], "cpu": ["x64"],
"libc": ["glibc"] and
"publishConfig": { "executableFiles": ["dist_ts_native/native"] }.
Place the built payload in that module's compiled folder before preparation and
include its applicable notices. Preparation preserves the payload's bytes and
source permissions; pnpm applies executable permissions when packing it. A parent
module can list these platform packages in optionalDependencies, which uses the
same exact sibling versions and dependency ordering as required dependencies.
A wrapper that launches Deno can declare "include": ["deno.json", "deno.lock"]
and "externalRuntimeAssets": ["mod.ts", "deno_src"]. These files are copied
unchanged. Validate the Deno configuration, locked dependencies and execution
separately before release. This declaration does not add npm dependencies or allow
component ts*/dist_ts* folders to bypass npm import checks. Node source imports
into these external assets are not admitted by the declaration.
For a subpath, include the additional source folder and declare both runtime and type entrypoints:
{
"name": "@example/core",
"order": 1,
"dependencies": [],
"registries": ["useBase"],
"folders": ["ts_migration"],
"exports": {
".": {
"types": "./dist_ts_core/index.d.ts",
"import": "./dist_ts_core/index.js"
},
"./migration": {
"types": "./dist_ts_migration/index.d.ts",
"import": "./dist_ts_migration/index.js"
}
}
}
Imports and local development
Import sibling components through their published package names and declare them
in dependencies. Configure TypeScript paths to their source entrypoints within
the same repository; GitZone's TypeScript formatter discovers these mappings from
tspublish.json. This requires no workspace symlinks or local package dependencies.
Run the normal repository build before preparation:
pnpm build
Preparation requires the matching dist_ts* outputs and verifies every export
target. It inspects literal imports in Node sources, declarations and ordinary
include assets, and rejects
undeclared dependencies and relative imports outside the component. Computed
runtime imports remain the responsibility of the module author. Built-in Node
modules are allowed. Browser compatibility must still be tested by each component.
Source folders, compiled folders and explicit assets are copied separately for
each package. Symlinks, credential files and local dependency directories are
rejected, including inside externalRuntimeAssets. Preparation does not bundle
dependency implementations.
Plan and prepare
import { TsPublish } from '@git.zone/tspublish';
const publisher = new TsPublish();
const plan = await publisher.plan(process.cwd());
// plan.modules is in deterministic dependency order; order equals its array index.
const packages = await publisher.prepare(
process.cwd(),
'/absolute/existing-parent/new-package-directory',
);
// Each result contains folder, folders, name, version, order, manifest,
// include, licenseFile, registries and its prepared directory.
plan() reads manifests and license availability without writes, builds or network
calls. It rejects duplicate package names, dependency cycles, unknown external
dependency versions, local dependency links and invalid package paths.
prepare() plans again and materializes the already-built packages. The output
directory must not exist; its parent must already exist at a canonical path. Output
cannot be nested inside an input folder. Preparation removes its own incomplete
output on failure and never overwrites a prior result. The caller owns successful
prepared directories and their cleanup.
Neither method installs dependencies, fetches templates, contacts registries, publishes packages or terminates the process.
The CLI exposes the same operations:
pnpm exec tspublish plan
pnpm exec tspublish prepare /absolute/existing-parent/new-package-directory
A release coordinator should validate every module's destination intent, prepare all modules, pack every package, record the complete immutable artifact set, and then publish in the returned dependency order. Publication recovery must reuse those retained tarballs rather than rebuilding or preparing again.
Existing standalone publisher
The existing TsPublish.publish(repository) API and no-argument CLI remain
available. They build and publish modules sequentially and do not provide
transaction recovery. Use the owning repository's approved release workflow.
The standalone publisher supports explicit registry.npmjs.org:public entries,
useBase, and extendBase with optional -URL exclusions. Base settings come
from @git.zone/cli.release.targets.npm in .smartconfig.json; the previous
release.registries and release.accessLevel fields remain readable.
An empty registry list means build without publishing.
Standalone generated builds use the repository's declared TsBuild version rather
than looking up a mutable latest version. The GiteaAssets helper remains
available from its source module for existing integrations.
Development
pnpm build
pnpm test
pnpm exec tsbuild check 'test/**/*'
Packaging tests use disposable directories and do not publish anything.
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.md 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.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.