@hudhod/core 0.1.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 +21 -0
- package/README.md +165 -0
- package/dist/index.d.ts +1017 -0
- package/dist/index.js +2084 -0
- package/dist/paths-B3gr2EuI.js +282 -0
- package/dist/spawner-CqGITKbd.d.ts +150 -0
- package/dist/webcontainer/index.d.ts +67 -0
- package/dist/webcontainer/index.js +200 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hudhod
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# @hudhod/core
|
|
2
|
+
|
|
3
|
+
The headless runtime behind [hudhod](../../README.md), an in-browser IDE built on
|
|
4
|
+
WebContainers.
|
|
5
|
+
|
|
6
|
+
This package implements the API described by
|
|
7
|
+
[`@hudhod/sdk`](../sdk/README.md): file system, search, diff, process, command,
|
|
8
|
+
and extension-host services. It contains **no UI and no framework code** — no
|
|
9
|
+
React, no state library — so it can be driven by any front end and unit tested in
|
|
10
|
+
plain Node.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add @hudhod/core @hudhod/sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use `@hudhod/webcontainer` when a browser host needs WebContainer adapters.
|
|
19
|
+
|
|
20
|
+
## Entry points
|
|
21
|
+
|
|
22
|
+
| Import | Environment | Contents |
|
|
23
|
+
| ---------------------- | ----------- | -------------------------------------------- |
|
|
24
|
+
| `@hudhod/core` | Any | Services, runtime factory, extension host |
|
|
25
|
+
| `@hudhod/webcontainer` | Browser | WebContainer filesystem and process adapters |
|
|
26
|
+
|
|
27
|
+
The split is deliberate. `@webcontainer/api` requires `SharedArrayBuffer` and
|
|
28
|
+
cross-origin isolation, so it cannot load in Node. Keeping those adapters in a
|
|
29
|
+
separate package means the main entry stays importable from tests, scripts, and
|
|
30
|
+
server code — which is what makes the runtime testable without a browser.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// Safe anywhere.
|
|
34
|
+
import { DisposableStore, Emitter } from "@hudhod/core";
|
|
35
|
+
|
|
36
|
+
// Browser only.
|
|
37
|
+
import { createWebContainerServices } from "@hudhod/webcontainer";
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Base primitives
|
|
41
|
+
|
|
42
|
+
### `Disposable` and `DisposableStore`
|
|
43
|
+
|
|
44
|
+
Every subscription returns a `Disposable`. `DisposableStore` collects them and
|
|
45
|
+
releases them together, newest-first:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { DisposableStore, toDisposable } from "@hudhod/core";
|
|
49
|
+
|
|
50
|
+
const store = new DisposableStore();
|
|
51
|
+
store.add(emitter.event(handler));
|
|
52
|
+
store.add(toDisposable(() => socket.close()));
|
|
53
|
+
store.dispose();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Two behaviours are worth knowing:
|
|
57
|
+
|
|
58
|
+
- Adding to an already-disposed store **disposes the argument immediately**, so
|
|
59
|
+
a late registration cannot leak.
|
|
60
|
+
- If one disposable throws, the rest still run; the failures are collected and
|
|
61
|
+
rethrown together as an `AggregateError`.
|
|
62
|
+
|
|
63
|
+
### `Emitter`
|
|
64
|
+
|
|
65
|
+
The `Event<T>` producer:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { Emitter } from "@hudhod/core";
|
|
69
|
+
|
|
70
|
+
const emitter = new Emitter<string>();
|
|
71
|
+
const sub = emitter.event((name) => console.log(name));
|
|
72
|
+
emitter.fire("world");
|
|
73
|
+
sub.dispose();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`fire()` iterates a snapshot of the listener set, so subscribing or
|
|
77
|
+
unsubscribing during dispatch cannot disturb the in-flight delivery. A throwing
|
|
78
|
+
listener is reported to `onListenerError` rather than propagating to whoever
|
|
79
|
+
called `fire()` — a producer usually cannot do anything useful about a
|
|
80
|
+
consumer's bug.
|
|
81
|
+
|
|
82
|
+
### `CancellationTokenSource`
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { CancellationTokenSource } from "@hudhod/core";
|
|
86
|
+
|
|
87
|
+
const source = new CancellationTokenSource();
|
|
88
|
+
const results = await search(query, source.token);
|
|
89
|
+
source.cancel();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Listeners registered _after_ cancellation are invoked immediately, so a late
|
|
93
|
+
subscriber cannot miss the signal. `tokenFromAbortSignal()` adapts a standard
|
|
94
|
+
`AbortSignal` if you already have one.
|
|
95
|
+
|
|
96
|
+
### Paths
|
|
97
|
+
|
|
98
|
+
hudhod paths are always absolute and POSIX-style, rooted at the workspace root.
|
|
99
|
+
These helpers are deliberately independent of Node's `path` so behaviour is
|
|
100
|
+
identical in the browser and free of platform separator quirks.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { basename, dirname, isSubPath, joinPath, normalizePath } from "@hudhod/core";
|
|
104
|
+
|
|
105
|
+
normalizePath("/src//lib/../index.ts"); // "/src/index.ts"
|
|
106
|
+
joinPath("/src", "lib", "index.ts"); // "/src/lib/index.ts"
|
|
107
|
+
isSubPath("/src", "/src-old"); // false — whole segments only
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`normalizePath()` throws `InvalidPath` for relative paths, null bytes, and any
|
|
111
|
+
path traversing above the root. Every service normalises its inputs, so path
|
|
112
|
+
traversal is rejected at the boundary rather than reaching the file system.
|
|
113
|
+
|
|
114
|
+
### Errors
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { fileNotFound } from "@hudhod/core";
|
|
118
|
+
|
|
119
|
+
throw fileNotFound("/missing.ts"); // code: "FileNotFound", path: "/missing.ts"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Consumers should branch on `error.code` via `isHudhodError()` from
|
|
123
|
+
`@hudhod/sdk`. Message text is not part of the contract.
|
|
124
|
+
|
|
125
|
+
## Extensions
|
|
126
|
+
|
|
127
|
+
`InProcessExtensionHost` loads the curated, first-party extension modules used
|
|
128
|
+
by hudhod. It validates each manifest with Zod before registration, supports
|
|
129
|
+
`onStartup`, `onCommand:*`, `onFileOpen:*`, and `onView:*` activation events,
|
|
130
|
+
and automatically disposes resources pushed onto `context.subscriptions` when
|
|
131
|
+
an extension deactivates.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { createHudhodRuntime } from "@hudhod/core";
|
|
135
|
+
|
|
136
|
+
const runtime = createHudhodRuntime({
|
|
137
|
+
fileSystemProvider,
|
|
138
|
+
processSpawner,
|
|
139
|
+
windowUiProvider,
|
|
140
|
+
});
|
|
141
|
+
runtime.extensions.register(extension);
|
|
142
|
+
await runtime.extensions.activateByEvent("onStartup");
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Concurrent activation triggers are deduplicated, so an extension's `activate()`
|
|
146
|
+
hook runs once even if a view and command arrive together.
|
|
147
|
+
|
|
148
|
+
For a React/Dockview host, use `createHudhodReactHost()` and `HudhodWorkbench`
|
|
149
|
+
from `@hudhod/react`. See [COMPOSABLE-IDE-DEVELOPMENT.md](../../COMPOSABLE-IDE-DEVELOPMENT.md).
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pnpm test # run the suite
|
|
155
|
+
pnpm test:watch # watch mode
|
|
156
|
+
pnpm test:coverage # coverage, enforced at 80%
|
|
157
|
+
pnpm typecheck
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Tests run in Node against the in-memory file system provider — no browser and no
|
|
161
|
+
WebContainer required.
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT
|