npm Packages

Creating a distributable npm package from your DSM model — the TypeScript analogue of Python wheels, over the @digitalsubstrate/dsviper Node binding instead of CPython.

Quick Start

Step 1: Generate

python3 tools/dsm_util.py create_node_package model.dsm

This creates a ready-to-build package in model/:

  • TypeScript sources in model/src/ (including the embedded definitions blob, resources.ts)

  • model/package.json and model/tsconfig.json

Unlike create_python_package, there is no --wheel flag — package.json and tsconfig.json are always emitted.

Step 2: Review package.json

The generated manifest names the package after the DSM namespace, depends on the Node binding, and builds with tsc:

{
    "name": "model",
    "version": "1.0.0",
    "type": "module",
    "exports": {
        ".": {
            "types": "./dist/index.d.ts",
            "import": "./dist/index.js"
        }
    },
    "files": ["dist", "src"],
    "scripts": {
        "build": "tsc -p tsconfig.json"
    },
    "dependencies": {
        "@digitalsubstrate/dsviper": ">=1.2.1 <1.3.0"
    },
    "devDependencies": {
        "typescript": "^5.0.0"
    },
    "license": "UNLICENSED"
}

Adjust name, version, and license for your release; keep the @digitalsubstrate/dsviper range aligned with the 1.2 runtime contract.

Step 3: Build

cd model
npm install
npm run build

npm run build runs tsc -p tsconfig.json, compiling src/ to dist/ (.js plus .d.ts declarations).

Step 4: Distribute

Pack the package into a tarball:

npm pack

This creates model-1.0.0.tgz (the files entry ships dist and src). Publish it to a private npm registry, or install the tarball directly in a consuming application.

Step 5: Use

import { Tuto_UserKey, Tuto_Login } from "model";

const key = Tuto_UserKey.create();

The entry point re-exports the data classes at the package root; the other surfaces are available as namespaces (attachments, databaseAttachments, path, types, definitions, functionPoolRemotes, attachmentFunctionPoolRemotes).

Package Structure

After generation, before building:

model/
├── package.json
├── tsconfig.json
└── src/
    ├── index.ts                            # Entry point — re-exports data + namespaced modules
    ├── data.ts                             # Concept, struct, enum, key classes
    ├── value_type.ts                       # Dynamic type definitions
    ├── definitions.ts                      # DSM type definitions
    ├── path.ts                             # Field path constants
    ├── attachments.ts                      # Typed attachment proxies (over the Node binding)
    ├── database_attachments.ts             # Typed database-attachment proxies
    ├── function_pool_remotes.ts            # Typed remote-call clients (over ServiceRemote)
    ├── attachment_function_pool_remotes.ts # Typed remote stateful-call clients
    └── resources.ts                        # Embedded definitions (base64 blob)

npm run build adds a dist/ directory holding the compiled .js and .d.ts files.

A Node back-end consumes services as a remote client only, so the generated surface ships the remote function-pool clients but not the local pools — see Templated Features for the full template list.

Distribution

Private npm registry

npm publish --registry https://your-registry.example.com

Consuming application

The package declares @digitalsubstrate/dsviper as a peer runtime dependency; the consuming application installs it from npm alongside the generated package:

npm install @digitalsubstrate/dsviper ./model-1.0.0.tgz

Version Management

Bump the version field in package.json for each release; follow semver against your DSM model surface.

Embedded definitions

create_node_package writes the DSM definitions into src/resources.ts as a base64 string:

export const B64_DEFINITIONS = "…";

The bytes are the default StreamTokenBinary encoding — exactly what the Node binding’s Definitions.decode(blob) assumes when no codec is given, so definitions.ts decodes the blob as-is. The blob is not compressed (the Python package’s resources.py zlib-compresses; the Node one does not).