@intra-mart/juggling-core
v0.1.2
Published
Domain-logic TypeScript library for IM-Juggling: intra-mart module catalog retrieval, repository access, project/module-structure operations, and WAR/static build output. ESM-only, Node >= 22.19.0.
Readme
@intra-mart/juggling-core
TypeScript library implementing the IM-Juggling domain logic — intra-mart module catalog retrieval, repository access, project/module-structure operations, and WAR/static build output — as a set of composable, strongly-typed APIs for Node.
Full usage manual (Japanese): README.ja.md walks through every use case end to end — catalog retrieval, project creation, module selection, user modules, configuration deployment, WAR / static output, patches, and version upgrades — with runnable, type-checked examples.
Overview
@intra-mart/juggling-core ports the module/repository/build logic of IM-Juggling into a
pure TypeScript library. It covers the full flow from fetching module catalogs to producing
deployable WAR and static outputs, and mirrors the observable behavior of the current
IM-Juggling tooling. Known compatibility quirks are documented and exposed programmatically
through the compat subpath.
- ESM-only, targeting Node.js >= 22.19 (also runs on Bun).
- Layered, side-effect-free core: the model / i18n / expr / rules layers are pure, synchronous, and deterministic; all I/O lives behind injectable runtime ports.
- Distributed as compiled
.js+.d.tswith one entry per public subpath.
Requirements
- Node.js >= 22.19 (or Bun)
- ESM (
"type": "module", orimport()from CommonJS)
Installation
bun add @intra-mart/juggling-core
# or: npm install @intra-mart/juggling-coreRuntime dependencies (sax, undici, yauzl, yazl) are installed automatically.
Public subpaths
The package exposes one entry point per area. Import only what you need.
| Subpath | Contents | Layer |
|---|---|---|
| @intra-mart/juggling-core (root) | Aggregate facade: createJuggling() wires the repository service together with projects.* (create / createFromRecommended / open) and build.* (exportWar / exportStatic / templates). | facade |
| @intra-mart/juggling-core/model | Domain model (ModuleKey / Version / metadata / catalog types / dependencies / hashes / enums) — pure and synchronous. | L0 |
| @intra-mart/juggling-core/i18n | Locale-candidate resolution, .properties handling, message resolution, LocalizedText. | L0 |
| @intra-mart/juggling-core/expr | OGNL-subset evaluator (parser + evaluator + host bindings). | L0 |
| @intra-mart/juggling-core/rules | Declarative rule catalog (validation, filtering, selection propagation, edition detection) plus an extension registry. | L1 |
| @intra-mart/juggling-core/repository | Repository reads (FILESET / HTTP), cross-cutting retrieval, catalog, merge, and createJuggling. | L2 |
| @intra-mart/juggling-core/project | ModuleStructure, selection operations, the project-layer model, and conf/schema deployment. | L2 |
| @intra-mart/juggling-core/lifecycle | Use-case procedures: create / open / save, patch, upgrade (plan → apply), additional resources. | L2 |
| @intra-mart/juggling-core/build | imm expansion engine, web.xml synthesis, WAR / static output, template definitions. | L2 |
| @intra-mart/juggling-core/compat | Machine-readable compatibility ledger and format-compatibility conversion helpers. | L2 |
| @intra-mart/juggling-core/runtime, .../runtime/node | Runtime port types and the Node implementation. | L3 |
| @intra-mart/juggling-core/testing | In-memory / fixture ports and comparison helpers for use in your own tests. | L3 |
Quick start
// Start with all defaults: management repository = ~/.juggling/repository,
// module repositories = product defaults, locale = host environment. The root import is
// the aggregate facade (repository service + projects.* + build.*).
import { createJuggling } from "@intra-mart/juggling-core";
const juggling = await createJuggling();
// --- Catalog (categories, recommended configuration) ---
const base = await juggling.catalog.getBaseCategories(); // base modules
const apps = await juggling.catalog.getApplicationCategories(); // applications
const recommended = await juggling.catalog.getRecommendedData();
for (const category of base) {
console.log(category.id, category.name?.get()); // name is a LocalizedText
for (const m of category.availableModules()) {
console.log(" ", m.id, m.version.toString());
}
}
// --- Metadata and module retrieval ---
import { ModuleKey, parseVersion } from "@intra-mart/juggling-core/model";
const key = ModuleKey.of("jp.co.intra_mart.vendor.velocity", parseVersion("1.7.0"));
const meta = await juggling.repositoryService.getMetadata(key);
const mod = await juggling.repositoryService.getModule(key); // SHA-1 verified
const patch = await juggling.catalog.findPatch(key); // latest patch, or null- Override the locale or repositories with
createJuggling({ locale: "en", repositories: [...] }). - Retrieved
name/descriptionvalues areLocalizedText: use.get()for the resolved value and.rawfor the original.
Projects and builds
const project = await juggling.projects.create({ // → JugglingProject
dir: "/ws/myapp", name: "myapp", base, applications,
});
// Open an existing project instead: const project = await juggling.projects.open("/ws/myapp");
project.applyCheckState(module, true); // selection (synchronous)
const status = await project.validate(); // AggregateStatus (a value, not a throw)
await project.save({ description: "Initial configuration" });
await juggling.build.exportWar(project, { // WAR output
template: "resin40", destDir: "/out", fileName: "imart",
inputs: { licenseType: "product", environment: "product", includeSamples: false },
});
await project.compact(); // drop history, keep latest onlyLower-level standalone functions are also available for progressive disclosure:
createProject(req, ctx) / openProject(dir, ctx) (lifecycle), buildWarFromProject(args) /
exportWar(opts, deps) (build), applyCheckState(structure, m, checked) (project).
Usage guide
The Japanese manual documents the complete workflow, one section per use case. Every code sample there is executed against a live repository and type-checked:
- Create a project — retrieve catalogs, narrow applications to a base
(
filterApplicationCandidates), validate the selection, andprojects.create(...). - Open a project — restore a
JugglingProjectfrom a savedjuggling.im. - Select modules — edit the module structure with check-state propagation and resolve missing modules.
- Add user modules — register your own
.immfiles (addUserModules) and handle theAddUserModulesResultoutcomes. - Deploy configurations — expand
conf/*.xmlandschema/*.xsdinto the project. - Build a WAR —
build.plan(...)thenbuild.exportWar(...). - Build static output —
build.exportStatic(...)for a PUBLIC-resource zip. - Find and apply patches —
findPatches()/applyPatches(). - Upgrade —
planUpgrade(...)thenapplyUpgrade(...). - Configure repositories — inspect and change module repositories.
Errors follow a deliberate split: I/O and integrity failures throw typed exceptions
(BuildError / JugglingError / ArgumentError), while business-rule outcomes are returned
as values (AggregateStatus, AddUserModulesResult, DeployBatchResult, and so on).
Development
This project uses Bun for dependency management and scripts.
bun install # install dependencies
bun run typecheck # tsc --noEmit (strict + exactOptionalPropertyTypes)
bun run lint # eslint + dependency-cruiser (layer boundaries)
bun run build # Vite library build → dist/ (ESM + .d.ts)
bun run check # typecheck + lint + buildLayer rules are enforced in CI: the L0 (model / i18n / expr) and L1 (rules) layers must stay pure, synchronous, and deterministic; cross-layer imports are checked by dependency-cruiser.
Distribution
- The build is ESM-only and produced by Vite.
exportsmaps each public subpath to its compileddist/<subpath>/index.jsplus a.d.tstype declaration. - Node.js >= 22.19 fully supports ESM, so a CommonJS dual build is intentionally not provided.
- Bundled assets (message catalogs, build templates,
juggling.xsd, and related resources) are included indist/.
License
Distributed under the GNU Lesser General Public License v3.0 (LGPL-3.0-only).
The LGPL-3.0 incorporates the terms of the GPL-3.0; both texts are included as
LICENSE (LGPL-3.0) and LICENSE.GPL-3.0 (GPL-3.0). See
also NOTICE.
Copyright (C) 2026 INTRAMART CORPORATION.
