@githolon/testing 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +45 -0
- package/README.md +159 -0
- package/build.mjs +23 -0
- package/index.d.ts +142 -0
- package/package.json +43 -0
- package/src/index.mjs +449 -0
- package/vendor/engine/engine.mjs +1370 -0
- package/vendor/engine/git-fs.mjs +93 -0
- package/vendor/engine/tree.mjs +73 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Nomos Pre-Release License (v1)
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 Captain App Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This is a pre-release of Nomos. This license gives you what you need to BUILD
|
|
6
|
+
with it; we keep the rest for now.
|
|
7
|
+
|
|
8
|
+
## You may
|
|
9
|
+
|
|
10
|
+
- install and use these packages to author Nomos domains, compile them, and
|
|
11
|
+
deploy them to Nomos Cloud or any Nomos instance Captain App operates or
|
|
12
|
+
authorizes;
|
|
13
|
+
- build, run, and ship applications on top of them — including commercial ones;
|
|
14
|
+
- keep everything that's yours: code you write, and everything these tools
|
|
15
|
+
generate FOR you (scaffolds from `create-githolon` / `githolon generate`, generated
|
|
16
|
+
clients, compiled domain packages) carries NO restriction from us — it is
|
|
17
|
+
yours outright.
|
|
18
|
+
|
|
19
|
+
## You may not
|
|
20
|
+
|
|
21
|
+
- redistribute these packages or their source, in whole or in part, outside
|
|
22
|
+
your team;
|
|
23
|
+
- modify them or build derivative tools, SDKs, or runtimes from their source;
|
|
24
|
+
- offer the Nomos runtime, or anything materially similar, as a hosted service;
|
|
25
|
+
- reverse-engineer the holon wasm runtime.
|
|
26
|
+
|
|
27
|
+
## Data retention
|
|
28
|
+
|
|
29
|
+
This is a pre-release we are actively evaluating. Workspaces you retire stop
|
|
30
|
+
counting toward your quota but are NOT deleted: **we retain all workspace data
|
|
31
|
+
(ledgers, law, intents) and may examine it to evaluate how the product is
|
|
32
|
+
used.** Don't put anything in a pre-release workspace you wouldn't want the
|
|
33
|
+
builders to read. If you need something truly expunged, ask:
|
|
34
|
+
jack@captainapp.co.uk.
|
|
35
|
+
|
|
36
|
+
## The rest
|
|
37
|
+
|
|
38
|
+
Provided **as is**, with no warranty of any kind; to the maximum extent
|
|
39
|
+
permitted by law, Captain App Ltd accepts no liability arising from your use.
|
|
40
|
+
This license terminates automatically if you breach it.
|
|
41
|
+
|
|
42
|
+
Want the kernel source, broader rights, or to do something this doesn't cover?
|
|
43
|
+
**Ask: jack@captainapp.co.uk.** The plan is to open Nomos up gradually, with
|
|
44
|
+
the people actually using it — telling us what you're building is how that
|
|
45
|
+
happens faster.
|
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# @githolon/testing — law TDD for Nomos domains
|
|
2
|
+
|
|
3
|
+
Test your law the way the cloud judges it. `testHolon()` boots **the real engine
|
|
4
|
+
plane** in-process — the vendored `cloud/holon-host` engine over the one
|
|
5
|
+
wasm32-wasip1 artifact, the exact machinery every cloud DO, heavy container and
|
|
6
|
+
web client runs — installs your compiled law at genesis, and hands you a holon
|
|
7
|
+
you drive from vitest. Nothing is simulated: every `dispatch` runs the real
|
|
8
|
+
author gate (payload zod → plan re-run → invariant oracle → kernel fold →
|
|
9
|
+
sealed onto the chain), and `verify()` is the same wasm `verify_chain` the
|
|
10
|
+
cloud runs on an upload birth.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i -D @githolon/testing vitest
|
|
14
|
+
npx nomos-compile # your law → build/<name>.deploy.json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { describe, expect, it } from "vitest";
|
|
19
|
+
import { testHolon } from "@githolon/testing";
|
|
20
|
+
|
|
21
|
+
it("the law refuses an over-capacity booking", async () => {
|
|
22
|
+
const h = await testHolon({ deploy: "./build/seats.deploy.json", deterministic: true });
|
|
23
|
+
const b = await h.dispatch("seats", "openBooking", { label: "launch", capacity: 2 });
|
|
24
|
+
await h.dispatch("seats", "takeSeat", { bookingId: b.id, attendee: "ada", takenAt: T });
|
|
25
|
+
await h.dispatch("seats", "takeSeat", { bookingId: b.id, attendee: "bob", takenAt: T });
|
|
26
|
+
|
|
27
|
+
// THE HEADLINE — invariants are real law; the refusal carries the law's own reject code:
|
|
28
|
+
await expect(
|
|
29
|
+
h.dispatch("seats", "takeSeat", { bookingId: b.id, attendee: "eve", takenAt: T }),
|
|
30
|
+
).rejects.toThrow(/seats-exceed-capacity/);
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## The surface
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const h = await testHolon({
|
|
38
|
+
deploy: "./build/<name>.deploy.json", // the nomos-compile output (path, URL or object)
|
|
39
|
+
// or: law: usdaText, manifests: { readManifest, identityManifests }
|
|
40
|
+
deterministic: true, // pinned clock + seeded rng + fixed replica (below)
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await h.dispatch(domain, directiveId, payload, { at?, rngDraws? });
|
|
44
|
+
// → { head, id, created, intent } (id = the first minted aggregate id)
|
|
45
|
+
// → throws Refusal — message carries the gate's verdict VERBATIM, so
|
|
46
|
+
// expect(...).rejects.toThrow(/your-reject-code/) asserts the law
|
|
47
|
+
|
|
48
|
+
h.byId(id); // [{ id, data }] — projected rows (partial folds are normal)
|
|
49
|
+
h.query(queryId, params); // a declared query — indexed probe, never a scan
|
|
50
|
+
h.count(countId, group); // maintained O(1) tally → number
|
|
51
|
+
h.sum(sumId, group); // maintained O(1) sum → number
|
|
52
|
+
h.extremum(id, "min"|"max", group);
|
|
53
|
+
|
|
54
|
+
h.intents(); // the chain, parsed — genesis installs first, then every dispatch
|
|
55
|
+
h.verify(); // the wasm verify_chain verdict (the cloud's upload-birth gate)
|
|
56
|
+
await h.fork(); // a cheap what-if branch — a fresh engine cold-mounting the
|
|
57
|
+
// exact tree bytes; fork dispatches never touch the parent
|
|
58
|
+
h.lawHash; // sha256(package bytes) — the content-addressed law id
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`Refusal` is typed: `{ name: "Refusal", domain, directiveId, refusal }` with the
|
|
62
|
+
verdict verbatim in `message` — payload-schema refusals, missing instances and
|
|
63
|
+
declared invariants all arrive through the same lane, exactly as on the edge.
|
|
64
|
+
|
|
65
|
+
## Deterministic clock & rng
|
|
66
|
+
|
|
67
|
+
A plan is a pure function of `(payload, ports)`; the HOST stamps the captured
|
|
68
|
+
clock and rng onto each intent's envelope. The harness pins both at that host
|
|
69
|
+
boundary (scoped to the synchronous author call — the engine is untouched):
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// the shorthand: clock 2026-01-01 advancing +1s/intent, seed 42, replica 7
|
|
73
|
+
const h = await testHolon({ deploy, deterministic: true });
|
|
74
|
+
|
|
75
|
+
// or granular:
|
|
76
|
+
const h = await testHolon({
|
|
77
|
+
deploy,
|
|
78
|
+
clock: { start: "2026-01-01T00:00:00.000Z", stepMs: 1000 }, // or an ISO/ms start, or () => now
|
|
79
|
+
seed: 7, // minted ids reproduce run-to-run
|
|
80
|
+
replica: 99, // the 63-bit replica id on every captured clock
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await h.dispatch(d, id, p, { at: "2026-03-01T09:00:00.000Z" }); // pin ONE intent's clock
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Same seed + clock + replica ⇒ **byte-identical history**: the same minted ids,
|
|
87
|
+
the same chain head, run after run. (Remember: domain timestamps still ride IN
|
|
88
|
+
your payloads as ISO strings — the captured clock is the envelope's, not your
|
|
89
|
+
law's.)
|
|
90
|
+
|
|
91
|
+
## Recipes
|
|
92
|
+
|
|
93
|
+
**Test an invariant** (real since the invariant gate landed — declared
|
|
94
|
+
invariants execute at author, admission AND verify):
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
await expect(h.dispatch("seats", "takeSeat", overCapacityPayload))
|
|
98
|
+
.rejects.toThrow(/seats-exceed-capacity/);
|
|
99
|
+
expect(h.intents().length).toBe(before); // a refusal commits NOTHING
|
|
100
|
+
expect(h.verify().valid).toBe(true); // the chain stays green
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Test a merge driver** — the merge IS the law:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
await h.dispatch("guestbook", "tagEntry", { entryId, tags: ["kind"] });
|
|
107
|
+
await h.dispatch("guestbook", "tagEntry", { entryId, tags: ["warm", "kind"] });
|
|
108
|
+
expect(h.byId(entryId)[0].data.tags).toEqual(["kind", "warm"]); // AddWins unions
|
|
109
|
+
|
|
110
|
+
await h.dispatch("guestbook", "reactToEntry", { entryId, reactor: "bob", reaction: "👏", reactedAt });
|
|
111
|
+
await h.dispatch("guestbook", "reactToEntry", { entryId, reactor: "bob", reaction: "💚", reactedAt: later });
|
|
112
|
+
expect(h.byId(entryId)[0].data.reactions).toEqual({ bob: "💚" }); // MapOf(Lww): per-key last write
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Test a derived field** — engine-projected, never in the ledger:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const { id } = await h.dispatch("guestbook", "signGuestbook", { mood: "grumpy", ... });
|
|
119
|
+
expect(h.byId(id)[0].data.moodEmoji).toBe("😠"); // projected
|
|
120
|
+
expect(JSON.stringify(h.intents().at(-1))).not.toContain("moodEmoji"); // never sealed
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**What-if on a fork** — consequence-free branches:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
const f = await h.fork();
|
|
127
|
+
await expect(f.dispatch(...breachingWrite)).rejects.toThrow(/your-code/);
|
|
128
|
+
await f.dispatch(...somethingElse); // lands on the fork
|
|
129
|
+
expect(h.byId(thatId)).toHaveLength(0); // the parent never saw it
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Worked examples: this package's own suite (`test/harness.test.mjs`, the seats
|
|
133
|
+
fixture) and the guestbook example's law tests
|
|
134
|
+
(`examples/guestbook/test/law.test.mts`).
|
|
135
|
+
|
|
136
|
+
## How the runtime arrives (the wasm story, honestly)
|
|
137
|
+
|
|
138
|
+
The engine JS is **vendored into this package at build** (synced verbatim from
|
|
139
|
+
`cloud/holon-host/src` — the cli/deploy.sh pattern, so it can't fork). The wasm
|
|
140
|
+
artifact + the baked bootstrap/nomos packages and manifests are **not** in the
|
|
141
|
+
npm package (the wasm alone is tens of MB); they resolve, first hit wins:
|
|
142
|
+
|
|
143
|
+
1. **`runtimeDir`** option / `GITHOLON_RUNTIME_DIR` — a directory you control
|
|
144
|
+
holding `{holon.wasm, manifests.json, packages.json}` (the cache shape).
|
|
145
|
+
Pin this in CI for fully hermetic runs.
|
|
146
|
+
2. **The monorepo** — inside the nomos2 repo, `cloud/holon-host`'s vendored
|
|
147
|
+
wasm + domain artifacts are used directly. Never any network.
|
|
148
|
+
3. **The shared cache** — `~/.holon/runtime` (`HOLON_CONFIG_DIR` overrides),
|
|
149
|
+
the SAME cache the `githolon` cli populates: any prior `githolon ledger`
|
|
150
|
+
run, or any prior `testHolon()` run, already warmed it.
|
|
151
|
+
4. **The cloud** — one fetch of `/v1/runtime/{holon.wasm,manifests,packages}`
|
|
152
|
+
from `https://nomos.captainapp.co.uk` (`cloud` option / `NOMOS_CLOUD`
|
|
153
|
+
override), written into the cache. Every run after is offline.
|
|
154
|
+
|
|
155
|
+
So: the FIRST run on a fresh machine outside the monorepo needs the network
|
|
156
|
+
once. `offline: true` (or `GITHOLON_TESTING_OFFLINE=1`) forbids lane 4 — you
|
|
157
|
+
get a clear error naming your options instead of a surprise fetch. The wasm in
|
|
158
|
+
the cache is the cloud's own deployed artifact: byte-identical machinery,
|
|
159
|
+
which is the point.
|
package/build.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Vendor THE ENGINE PLANE (cloud/holon-host/src/{engine,git-fs,tree}.mjs — the
|
|
2
|
+
// exact machinery the edge DO and the heavy container run) into this package so
|
|
3
|
+
// `testHolon()` boots holons in-process with the same code path the cloud uses.
|
|
4
|
+
// Sync-at-build keeps it un-forked (the cli/build.mjs / deploy.sh pattern); the
|
|
5
|
+
// published package ships the vendored copies and skips the sync when the
|
|
6
|
+
// monorepo source is absent.
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
|
|
11
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const ENGINE_SRC = join(HERE, "..", "cloud", "holon-host", "src");
|
|
13
|
+
const VENDOR = join(HERE, "vendor", "engine");
|
|
14
|
+
|
|
15
|
+
if (existsSync(ENGINE_SRC)) {
|
|
16
|
+
mkdirSync(VENDOR, { recursive: true });
|
|
17
|
+
for (const f of ["engine.mjs", "git-fs.mjs", "tree.mjs"]) {
|
|
18
|
+
const body = readFileSync(join(ENGINE_SRC, f), "utf8");
|
|
19
|
+
writeFileSync(join(VENDOR, f), `// AUTO-SYNCED from cloud/holon-host/src/${f} by testing/build.mjs — DO NOT EDIT HERE.\n${body}`, "utf8");
|
|
20
|
+
}
|
|
21
|
+
} else if (!existsSync(join(VENDOR, "engine.mjs"))) {
|
|
22
|
+
throw new Error("engine plane not found: neither ../cloud/holon-host/src nor vendor/engine exists");
|
|
23
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// @githolon/testing — the typed surface (see README.md for the vitest recipes).
|
|
2
|
+
|
|
3
|
+
/** A projected read-model row. Every field is partial — partial folds are normal. */
|
|
4
|
+
export interface Row<T = Record<string, unknown>> {
|
|
5
|
+
type?: string;
|
|
6
|
+
id: string;
|
|
7
|
+
data: Partial<T>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** What a successful dispatch resolves with. */
|
|
11
|
+
export interface DispatchResult {
|
|
12
|
+
/** The new chain head (a git commit oid). */
|
|
13
|
+
head: string;
|
|
14
|
+
/** The FIRST aggregate id this intent minted, or null (callers never supply ids). */
|
|
15
|
+
id: string | null;
|
|
16
|
+
/** Every aggregate id this intent minted (batch-creating plans mint many). */
|
|
17
|
+
created: string[];
|
|
18
|
+
/** The sealed chain entry, parsed. */
|
|
19
|
+
intent: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface DispatchOptions {
|
|
23
|
+
/** Pin THIS intent's captured clock (ISO string or epoch ms). */
|
|
24
|
+
at?: string | number;
|
|
25
|
+
/**
|
|
26
|
+
* The captured-entropy budget the plan may consume (19 draws per minted id;
|
|
27
|
+
* default 64 covers 3 mints). Raise it for batch-creating directives —
|
|
28
|
+
* commit-only-consumed: only the consumed prefix is sealed.
|
|
29
|
+
*/
|
|
30
|
+
rngDraws?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A dispatch the gate REFUSED — payload validation, a missing instance, or a
|
|
35
|
+
* declared invariant. The law's own reject code rides `message` verbatim, so
|
|
36
|
+
* `expect(...).rejects.toThrow(/seats-exceed-capacity/)` asserts the law.
|
|
37
|
+
*/
|
|
38
|
+
export declare class Refusal extends Error {
|
|
39
|
+
name: "Refusal";
|
|
40
|
+
domain: string;
|
|
41
|
+
directiveId: string;
|
|
42
|
+
/** The gate's verdict, verbatim. */
|
|
43
|
+
refusal: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The wasm verify_chain verdict — the same gate the cloud runs on an upload birth. */
|
|
47
|
+
export interface Verdict {
|
|
48
|
+
valid: boolean;
|
|
49
|
+
head?: string;
|
|
50
|
+
intents?: number;
|
|
51
|
+
plansRerun?: number;
|
|
52
|
+
controllerHash?: string;
|
|
53
|
+
installedDomains?: string[];
|
|
54
|
+
/** On an invalid chain: the refusing check + index + error. */
|
|
55
|
+
check?: string;
|
|
56
|
+
atIndex?: number;
|
|
57
|
+
error?: string;
|
|
58
|
+
[k: string]: unknown;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface DeployBody {
|
|
62
|
+
packageUsda: string;
|
|
63
|
+
readManifest?: Record<string, unknown>;
|
|
64
|
+
identityManifests?: Record<string, string>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ClockOption =
|
|
68
|
+
| string
|
|
69
|
+
| number
|
|
70
|
+
| { start?: string | number; stepMs?: number }
|
|
71
|
+
| (() => string | number);
|
|
72
|
+
|
|
73
|
+
export interface TestHolonOptions {
|
|
74
|
+
/** Path / URL / parsed object of the nomos-compile `<name>.deploy.json`. */
|
|
75
|
+
deploy?: string | URL | DeployBody;
|
|
76
|
+
/** Alternative to `deploy`: the raw package USDA text… */
|
|
77
|
+
law?: string;
|
|
78
|
+
/** …plus its manifests (omit and declared queries/derived fields won't route). */
|
|
79
|
+
manifests?: { readManifest?: Record<string, unknown>; identityManifests?: Record<string, string> };
|
|
80
|
+
/** true ⇒ pinned clock (2026-01-01, +1s per intent), seed 42, replica 7 — full reproducibility. */
|
|
81
|
+
deterministic?: boolean;
|
|
82
|
+
/** Pin the captured clock: a start (ISO/ms, advancing +1s per intent), {start, stepMs}, or a function. */
|
|
83
|
+
clock?: ClockOption;
|
|
84
|
+
/** Seed the captured rng — minted ids reproduce run-to-run. */
|
|
85
|
+
seed?: number;
|
|
86
|
+
/** Pin the 63-bit replica id (defaults: 7 under `deterministic`, seed-derived under `seed`, else random). */
|
|
87
|
+
replica?: number | bigint;
|
|
88
|
+
/** The principal stamped on the genesis installs (default "law-test"). */
|
|
89
|
+
installedBy?: string;
|
|
90
|
+
/** Runtime acquisition (see README): a dir holding {holon.wasm, manifests.json, packages.json}. */
|
|
91
|
+
runtimeDir?: string;
|
|
92
|
+
/** The cloud to fetch runtime artifacts from on first use (default https://nomos.captainapp.co.uk). */
|
|
93
|
+
cloud?: string;
|
|
94
|
+
/** Forbid the network fallback — fail with the offline story instead of fetching. */
|
|
95
|
+
offline?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface TestHolon {
|
|
99
|
+
/** sha256(package bytes) of the installed law — the content-addressed law id. */
|
|
100
|
+
readonly lawHash: string;
|
|
101
|
+
/** This holon's 63-bit replica id (rides every intent's captured clock). */
|
|
102
|
+
readonly replica: bigint;
|
|
103
|
+
/** The in-engine workspace name reads/authors bind to. */
|
|
104
|
+
readonly workspace: string;
|
|
105
|
+
/** The raw engine handle (the vendored engine plane) — the escape hatch. */
|
|
106
|
+
readonly engine: unknown;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Author ONE intent through the real gate (payload zod → plan re-run →
|
|
110
|
+
* invariant oracle → kernel fold → sealed onto the chain). Resolves with the
|
|
111
|
+
* result or REJECTS with a typed {@link Refusal}.
|
|
112
|
+
*/
|
|
113
|
+
dispatch(domain: string, directiveId: string, payload: unknown, opts?: DispatchOptions): Promise<DispatchResult>;
|
|
114
|
+
|
|
115
|
+
/** All projected rows for one aggregate id. */
|
|
116
|
+
byId<T = Record<string, unknown>>(aggregateId: string): Row<T>[];
|
|
117
|
+
/** A declared query — an indexed probe, never a scan. */
|
|
118
|
+
query<T = Record<string, unknown>>(queryId: string, params?: Record<string, unknown>): Row<T>[];
|
|
119
|
+
/** A maintained count tally (O(1)). */
|
|
120
|
+
count(countId: string, group?: string): number;
|
|
121
|
+
/** A maintained sum tally (O(1)). */
|
|
122
|
+
sum(sumId: string, group?: string): number;
|
|
123
|
+
/** A maintained min/max read; absent group ⇒ null. */
|
|
124
|
+
extremum(extremumId: string, kind: "min" | "max", group?: string): number | null;
|
|
125
|
+
|
|
126
|
+
/** The chain so far, parsed — genesis installs first, then every dispatch. */
|
|
127
|
+
intents(): Record<string, unknown>[];
|
|
128
|
+
/** The wasm verify_chain verdict over this holon's chain (the cloud's gate). */
|
|
129
|
+
verify(): Verdict;
|
|
130
|
+
/**
|
|
131
|
+
* A cheap what-if branch: a fresh engine cold-mounting this holon's exact
|
|
132
|
+
* tree bytes. Dispatches on the fork never touch the parent.
|
|
133
|
+
*/
|
|
134
|
+
fork(opts?: { replica?: number | bigint }): Promise<TestHolon>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Boot a law-under-test holon: the REAL engine plane (the vendored
|
|
139
|
+
* cloud/holon-host engine over the one wasm artifact), your compiled law
|
|
140
|
+
* installed at genesis, fully offline after the one-time runtime acquisition.
|
|
141
|
+
*/
|
|
142
|
+
export declare function testHolon(opts?: TestHolonOptions): Promise<TestHolon>;
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@githolon/testing",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "@githolon/testing — law TDD for Nomos domains: boot the REAL engine plane in-process (the exact machinery every cloud DO, heavy container and web client runs), dispatch directives, assert rows, assert TYPED REFUSALS, fork for what-ifs — fully offline inside vitest.",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Captain-App/nomos2.git",
|
|
10
|
+
"directory": "testing"
|
|
11
|
+
},
|
|
12
|
+
"main": "./src/index.mjs",
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./index.d.ts",
|
|
17
|
+
"default": "./src/index.mjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"src",
|
|
22
|
+
"vendor",
|
|
23
|
+
"index.d.ts",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE.md",
|
|
26
|
+
"build.mjs"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "node build.mjs",
|
|
33
|
+
"prepare": "npm run build",
|
|
34
|
+
"test": "vitest run"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@bjorn3/browser_wasi_shim": "0.4.2",
|
|
38
|
+
"isomorphic-git": "^1.38.4"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"vitest": "^2.1.8"
|
|
42
|
+
}
|
|
43
|
+
}
|