@mindees/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 ADDED
@@ -0,0 +1,31 @@
1
+ # License
2
+
3
+ MindeesNative is dual-licensed under either of:
4
+
5
+ - **Apache License, Version 2.0** ([LICENSE-APACHE](./LICENSE-APACHE) or
6
+ <https://www.apache.org/licenses/LICENSE-2.0>)
7
+ - **MIT license** ([LICENSE-MIT](./LICENSE-MIT) or
8
+ <https://opensource.org/licenses/MIT>)
9
+
10
+ at your option.
11
+
12
+ This `MIT OR Apache-2.0` dual-license is the same model used by the Rust
13
+ ecosystem and many modern open-source projects. It gives downstream users
14
+ maximum flexibility: the MIT option is short and permissive, while the Apache
15
+ option adds an explicit patent grant.
16
+
17
+ ## SPDX identifier
18
+
19
+ ```
20
+ SPDX-License-Identifier: MIT OR Apache-2.0
21
+ ```
22
+
23
+ ## Contribution
24
+
25
+ Unless you explicitly state otherwise, any contribution intentionally
26
+ submitted for inclusion in the work by you, as defined in the Apache-2.0
27
+ license, shall be dual-licensed as above, without any additional terms or
28
+ conditions.
29
+
30
+ Contributions are accepted under the **Developer Certificate of Origin (DCO)**.
31
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for details on signing off your commits.
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # @mindees/core
2
+
3
+ The reactive runtime foundation of MindeesNative โ€” a fast, fine-grained
4
+ **signals** library (the same reactivity model behind SolidJS and modern
5
+ frameworks), written in strict TypeScript.
6
+
7
+ > **Status: ๐Ÿงช Experimental (Phases 1โ€“2).** Implemented and thoroughly tested:
8
+ > the **reactivity** layer (`signal`, `computed`/`memo`, `effect`, `batch`,
9
+ > `untrack`, `createRoot`, `onCleanup`), the **component model** (element tree +
10
+ > selector-based, re-render-isolated context), the **priority scheduler**, and a
11
+ > **thread-pool** abstraction (Web Worker backend + inline fallback). APIs may
12
+ > still change before `1.0`.
13
+
14
+ ## Install
15
+
16
+ > โš ๏ธ **Not published to npm yet.** `@mindees/core` is pre-1.0 and not on the npm
17
+ > registry. The command below is what you'll use **once it's published** (Phase
18
+ > 12). For now, work with it from the monorepo via the
19
+ > [contributor quick-start](../../README.md#-quickstart-contributors):
20
+ > `corepack enable && pnpm install && pnpm verify`.
21
+
22
+ ```bash
23
+ # coming soon (not yet published):
24
+ pnpm add @mindees/core
25
+ ```
26
+
27
+ ## Quick start
28
+
29
+ ```ts
30
+ import { signal, computed, effect, batch } from '@mindees/core'
31
+
32
+ const count = signal(0)
33
+ const doubled = computed(() => count() * 2)
34
+
35
+ effect(() => {
36
+ console.log(`count=${count()} doubled=${doubled()}`)
37
+ }) // logs immediately, then on every change
38
+
39
+ count.set(1) // re-runs the effect
40
+ count.update((n) => n + 1)
41
+
42
+ batch(() => { // coalesce multiple writes into one effect run
43
+ count.set(10)
44
+ count.set(20)
45
+ })
46
+ ```
47
+
48
+ ## Why signals?
49
+
50
+ Signals give you **fine-grained reactivity**: only the computations that actually
51
+ depend on a changed value re-run โ€” no virtual-DOM diffing, no manual
52
+ `useMemo`/`useCallback`, no whole-component re-renders. The engine is:
53
+
54
+ - **Glitch-free** โ€” a diamond dependency recomputes its consumer exactly once;
55
+ no observer ever sees an inconsistent intermediate state.
56
+ - **Lazy & cached** โ€” `computed` values recompute only when read *and* a
57
+ dependency changed; an equal recomputation stops propagation.
58
+ - **Leak-free** โ€” disposing an owner unlinks every subscription (verified by an
59
+ adversarial disposal test suite).
60
+ - **Synchronous & deterministic** โ€” predictable effect ordering, batched writes.
61
+
62
+ ## API
63
+
64
+ | Export | Kind | Description |
65
+ | --- | --- | --- |
66
+ | `signal(value, opts?)` | fn | Writable reactive value: `()` read ยท `.set` ยท `.update` ยท `.peek`. |
67
+ | `computed(fn, opts?)` / `memo` | fn | Lazy, cached derived value. |
68
+ | `effect(fn)` | fn | Re-runs on dependency change; returns a disposer; supports `onCleanup`. |
69
+ | `batch(fn)` | fn | Coalesce writes; effects run once at the end. |
70
+ | `untrack(fn)` | fn | Read without subscribing. |
71
+ | `createRoot(fn)` | fn | Non-tracked owner scope with manual `dispose`. |
72
+ | `onCleanup(fn)` | fn | Register teardown for the current scope. |
73
+ | `getOwner` / `runWithOwner` | fn | Inspect / re-enter an ownership scope. |
74
+ | `Signal`, `Memo`, `Accessor`, `EqualsFn`, `Owner`, โ€ฆ | type | Fully-typed public surface. |
75
+ | `NotImplementedError` / `notImplemented` | err | Honest markers for unbuilt research tracks. |
76
+
77
+ Custom equality is supported everywhere (`{ equals: (a, b) => โ€ฆ }`, or
78
+ `equals: false` to always notify).
79
+
80
+ ## Component model, scheduler & threading (Phase 2)
81
+
82
+ ```ts
83
+ import {
84
+ createContext, createProvider, createElement,
85
+ createScheduler, createInlineThreadPool,
86
+ } from '@mindees/core'
87
+
88
+ // Selector-based context with re-render isolation: a consumer only re-runs
89
+ // when its SELECTED slice changes, not on every context update.
90
+ const Session = createContext({ user: { name: 'Ada' }, unread: 0 })
91
+ const session = createProvider(Session)
92
+ const name = session.select((s) => s.user.name) // memo; isolated from `unread`
93
+
94
+ // Two-lane priority scheduler (sync vs normal), microtask-batched,
95
+ // with cancellable + dedup-by-key tasks.
96
+ const scheduler = createScheduler()
97
+ scheduler.schedule(() => paint(), { priority: 'sync', key: 'frame' })
98
+
99
+ // Thread-pool abstraction. The inline fallback runs jobs synchronously;
100
+ // createWorkerPool({ createWorker }) runs them on real Web Workers (see API below).
101
+ const pool = createInlineThreadPool()
102
+ await pool.run((n) => fib(n), 40)
103
+ ```
104
+
105
+ | Export | Kind | Description |
106
+ | --- | --- | --- |
107
+ | `createElement` / `Fragment` / `isElement` | fn | Renderer-agnostic element tree. |
108
+ | `createContext` / `createProvider` | fn | Selector-based, **re-render-isolated** context. |
109
+ | `renderComponent` | fn | Run a component in a disposable owner scope. |
110
+ | `createScheduler` / `Scheduler` | fn | Two-lane priority scheduler (cancellable, dedupable). |
111
+ | `createWorkerPool` / `createInlineThreadPool` | fn | `ThreadPool` backends (web + fallback). |
112
+ | `createNativeThreadPool` | fn | ๐Ÿ”ฌ research track โ€” throws `NotImplementedError`. |
113
+
114
+ > Native multi-threading is a **research track** (honest `NotImplementedError`);
115
+ > the Web Worker and inline backends work today.
116
+
117
+ ## License
118
+
119
+ `MIT OR Apache-2.0`
@@ -0,0 +1,112 @@
1
+ //#region src/component/component.d.ts
2
+ /**
3
+ * MindeesNative component model โ€” a minimal, renderer-agnostic element tree plus
4
+ * **selector-based, re-render-isolated context**.
5
+ *
6
+ * The element tree (`createElement` / `Fragment`) is a plain data structure: a
7
+ * component is a function of `props` returning elements. It carries no rendering
8
+ * logic itself โ€” the Helix renderer (Phase 3) turns this tree into host nodes.
9
+ *
10
+ * The context system is the important primitive: a `createContext` value is read
11
+ * through a **selector**, and a consumer only re-runs when its *selected slice*
12
+ * actually changes โ€” not on every context update. This is the re-render
13
+ * isolation the Quantum Router (Phase 6) builds on. It is implemented on the
14
+ * Phase 1 signals, so selection participates in normal reactivity.
15
+ *
16
+ * @module
17
+ */
18
+ /** A component: a function from props to a renderable node. */
19
+ type Component<P = Record<string, unknown>> = (props: P) => MindeesNode;
20
+ /**
21
+ * Anything that can appear in the tree.
22
+ *
23
+ * Includes an **accessor** form `() => MindeesNode`: a function child (or
24
+ * function prop value) is a *reactive region* โ€” the renderer subscribes to it
25
+ * and patches exactly that region when its signals change (the fine-grained
26
+ * update model, ร  la SolidJS). Static trees never need it; reactive UIs do.
27
+ */
28
+ type MindeesNode = MindeesElement | string | number | boolean | null | undefined | (() => MindeesNode) | MindeesNode[];
29
+ /** The tag of an element: a host string (e.g. `"view"`) or a component function. */
30
+ type ElementType = string | Component<never>;
31
+ /** A virtual element: a tag, its props, and its children. */
32
+ interface MindeesElement {
33
+ readonly $$typeof: typeof ELEMENT_TYPE;
34
+ readonly type: ElementType;
35
+ readonly props: Readonly<Record<string, unknown>>;
36
+ readonly children: readonly MindeesNode[];
37
+ readonly key: string | number | null;
38
+ }
39
+ /** Brand so a renderer can reliably distinguish elements from plain objects. */
40
+ declare const ELEMENT_TYPE: unique symbol;
41
+ /** Marker tag for a fragment (children with no wrapper host node). */
42
+ declare const Fragment: unique symbol;
43
+ interface PropsWithKey {
44
+ key?: string | number | null;
45
+ children?: MindeesNode;
46
+ }
47
+ /**
48
+ * Create a virtual element. `type` is a host-component string or a component
49
+ * function; `Fragment` groups children without a wrapper.
50
+ *
51
+ * @example
52
+ * createElement('view', { id: 'root' }, createElement('text', null, 'hi'))
53
+ */
54
+ declare function createElement(type: ElementType | typeof Fragment, props?: (Record<string, unknown> & PropsWithKey) | null, ...children: MindeesNode[]): MindeesElement;
55
+ /** Type guard: is `value` a MindeesElement? */
56
+ declare function isElement(value: unknown): value is MindeesElement;
57
+ /** Equality used by context selectors. Defaults to `Object.is`. */
58
+ type SelectorEquals<S> = (a: S, b: S) => boolean;
59
+ /** A context handle created by {@link createContext}. */
60
+ interface Context<T> {
61
+ /** Provide a value to a subtree (conceptually); returns a scoped reader set. */
62
+ readonly id: symbol;
63
+ /** The default value used when no provider is present. */
64
+ readonly defaultValue: T;
65
+ }
66
+ /**
67
+ * A live provider instance: holds the current value and lets consumers subscribe
68
+ * to a derived slice with re-render isolation.
69
+ */
70
+ interface ContextProvider<T> {
71
+ /** Replace the provided value (notifies only consumers whose slice changed). */
72
+ set(value: T): void;
73
+ /** Read the current value without subscribing. */
74
+ peek(): T;
75
+ /**
76
+ * Subscribe to a selected slice. The returned accessor is a memo that only
77
+ * changes โ€” and thus only re-runs its observers โ€” when `selector(value)`
78
+ * changes under `equals` (default `Object.is`).
79
+ */
80
+ select<S>(selector: (value: T) => S, equals?: SelectorEquals<S>): () => S;
81
+ }
82
+ /** Create a context with a default value. */
83
+ declare function createContext<T>(defaultValue: T): Context<T>;
84
+ /**
85
+ * Create a provider instance for `context`. Built on a signal, so selected
86
+ * slices are memos: a consumer that selects `c => c.user.name` does not re-run
87
+ * when an unrelated field changes.
88
+ *
89
+ * @example
90
+ * const Theme = createContext({ mode: 'light', accent: 'blue' })
91
+ * const p = createProvider(Theme, { mode: 'light', accent: 'blue' })
92
+ * const mode = p.select((t) => t.mode) // only re-runs when `mode` changes
93
+ */
94
+ declare function createProvider<T>(context: Context<T>, initial?: T): ContextProvider<T>;
95
+ /**
96
+ * Invoke a component within a reactive ownership scope, so every effect, memo,
97
+ * and `onCleanup` it registers is torn down together when `dispose` is called.
98
+ * Returns the produced node and that disposer.
99
+ *
100
+ * Built on the Phase 1 {@link createRoot}, so disposal reuses the same
101
+ * leak-free teardown the reactivity tests cover. This is a renderer building
102
+ * block; it does not touch any host.
103
+ */
104
+ declare function renderComponent<P>(component: Component<P>, props: P): {
105
+ node: MindeesNode;
106
+ dispose: () => void;
107
+ };
108
+ /** Whether code is currently running inside a reactive ownership scope. */
109
+ declare function hasOwner(): boolean;
110
+ //#endregion
111
+ export { Component, Context, ContextProvider, ELEMENT_TYPE, ElementType, Fragment, MindeesElement, MindeesNode, SelectorEquals, createContext, createElement, createProvider, hasOwner, isElement, renderComponent };
112
+ //# sourceMappingURL=component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.d.ts","names":[],"sources":["../../src/component/component.ts"],"mappings":";;AAwBA;;;;;;;;;;;;;;AAA8E;AAU9E;AAAA,KAVY,SAAA,KAAc,MAAA,sBAA4B,KAAA,EAAO,CAAA,KAAM,WAAA;;;;;;;;;KAUvD,WAAA,GACR,cAAA,yDAMO,WAAA,IACP,WAAA;;KAGQ,WAAA,YAAuB,SAAS;AAA5C;AAAA,UAGiB,cAAA;EAAA,SACN,QAAA,SAAiB,YAAA;EAAA,SACjB,IAAA,EAAM,WAAA;EAAA,SACN,KAAA,EAAO,QAAA,CAAS,MAAA;EAAA,SAChB,QAAA,WAAmB,WAAA;EAAA,SACnB,GAAA;AAAA;;cAIE,YAAA;;cAGA,QAAA;AAAA,UAEH,YAAA;EACR,GAAA;EACA,QAAA,GAAW,WAAW;AAAA;;;;;;;;iBAUR,aAAA,CACd,IAAA,EAAM,WAAA,UAAqB,QAAA,EAC3B,KAAA,IAAS,MAAA,oBAA0B,YAAA,aAChC,QAAA,EAAU,WAAA,KACZ,cAAA;;iBAea,SAAA,CAAU,KAAA,YAAiB,KAAA,IAAS,cAAc;AAxCpD;AAAA,KAqDF,cAAA,OAAqB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC;;UAG1B,OAAA;EApDuD;EAAA,SAsD7D,EAAA;EAnDE;EAAA,SAqDF,YAAA,EAAc,CAAC;AAAA;;AArD2C;AAAA;;UA4DpD,eAAA;EAxDO;EA0DtB,GAAA,CAAI,KAAA,EAAO,CAAA;EA1DX;EA4DA,IAAA,IAAQ,CAAA;EA5Dc;AAAA;AAUxB;;;EAwDE,MAAA,IAAU,QAAA,GAAW,KAAA,EAAO,CAAA,KAAM,CAAA,EAAG,MAAA,GAAS,cAAA,CAAe,CAAA,UAAW,CAAA;AAAA;;iBAI1D,aAAA,IAAiB,YAAA,EAAc,CAAA,GAAI,OAAA,CAAQ,CAAA;;;;;;;;;;;iBAc3C,cAAA,IAAkB,OAAA,EAAS,OAAA,CAAQ,CAAA,GAAI,OAAA,GAAU,CAAA,GAAI,eAAA,CAAgB,CAAA;;;;AAtEpE;AAejB;;;;;iBAmFgB,eAAA,IACd,SAAA,EAAW,SAAA,CAAU,CAAA,GACrB,KAAA,EAAO,CAAA;EACJ,IAAA,EAAM,WAAA;EAAa,OAAA;AAAA;AAzExB;AAAA,iBA8FgB,QAAA"}
@@ -0,0 +1,107 @@
1
+ import { computed, createRoot, getOwner, signal } from "../reactive/reactive.js";
2
+ //#region src/component/component.ts
3
+ /**
4
+ * MindeesNative component model โ€” a minimal, renderer-agnostic element tree plus
5
+ * **selector-based, re-render-isolated context**.
6
+ *
7
+ * The element tree (`createElement` / `Fragment`) is a plain data structure: a
8
+ * component is a function of `props` returning elements. It carries no rendering
9
+ * logic itself โ€” the Helix renderer (Phase 3) turns this tree into host nodes.
10
+ *
11
+ * The context system is the important primitive: a `createContext` value is read
12
+ * through a **selector**, and a consumer only re-runs when its *selected slice*
13
+ * actually changes โ€” not on every context update. This is the re-render
14
+ * isolation the Quantum Router (Phase 6) builds on. It is implemented on the
15
+ * Phase 1 signals, so selection participates in normal reactivity.
16
+ *
17
+ * @module
18
+ */
19
+ /** Brand so a renderer can reliably distinguish elements from plain objects. */
20
+ const ELEMENT_TYPE = Symbol.for("mindees.element");
21
+ /** Marker tag for a fragment (children with no wrapper host node). */
22
+ const Fragment = Symbol.for("mindees.fragment");
23
+ /**
24
+ * Create a virtual element. `type` is a host-component string or a component
25
+ * function; `Fragment` groups children without a wrapper.
26
+ *
27
+ * @example
28
+ * createElement('view', { id: 'root' }, createElement('text', null, 'hi'))
29
+ */
30
+ function createElement(type, props, ...children) {
31
+ const { key = null, children: propsChildren, ...rest } = props ?? {};
32
+ const resolved = children.length > 0 ? children : propsChildren !== void 0 ? [propsChildren] : [];
33
+ return {
34
+ $$typeof: ELEMENT_TYPE,
35
+ type,
36
+ props: Object.freeze({ ...rest }),
37
+ children: Object.freeze(resolved),
38
+ key
39
+ };
40
+ }
41
+ /** Type guard: is `value` a MindeesElement? */
42
+ function isElement(value) {
43
+ return typeof value === "object" && value !== null && value.$$typeof === ELEMENT_TYPE;
44
+ }
45
+ /** Create a context with a default value. */
46
+ function createContext(defaultValue) {
47
+ return {
48
+ id: Symbol("mindees.context"),
49
+ defaultValue
50
+ };
51
+ }
52
+ /**
53
+ * Create a provider instance for `context`. Built on a signal, so selected
54
+ * slices are memos: a consumer that selects `c => c.user.name` does not re-run
55
+ * when an unrelated field changes.
56
+ *
57
+ * @example
58
+ * const Theme = createContext({ mode: 'light', accent: 'blue' })
59
+ * const p = createProvider(Theme, { mode: 'light', accent: 'blue' })
60
+ * const mode = p.select((t) => t.mode) // only re-runs when `mode` changes
61
+ */
62
+ function createProvider(context, initial) {
63
+ const source = signal(initial ?? context.defaultValue, { equals: false });
64
+ return {
65
+ set: (value) => {
66
+ source.set(value);
67
+ },
68
+ peek: () => source.peek(),
69
+ select(selector, equals = Object.is) {
70
+ return computed(() => selector(source()), { equals });
71
+ }
72
+ };
73
+ }
74
+ /**
75
+ * Invoke a component within a reactive ownership scope, so every effect, memo,
76
+ * and `onCleanup` it registers is torn down together when `dispose` is called.
77
+ * Returns the produced node and that disposer.
78
+ *
79
+ * Built on the Phase 1 {@link createRoot}, so disposal reuses the same
80
+ * leak-free teardown the reactivity tests cover. This is a renderer building
81
+ * block; it does not touch any host.
82
+ */
83
+ function renderComponent(component, props) {
84
+ let node;
85
+ let dispose;
86
+ try {
87
+ createRoot((d) => {
88
+ dispose = d;
89
+ node = component(props);
90
+ });
91
+ } catch (error) {
92
+ dispose?.();
93
+ throw error;
94
+ }
95
+ return {
96
+ node,
97
+ dispose
98
+ };
99
+ }
100
+ /** Whether code is currently running inside a reactive ownership scope. */
101
+ function hasOwner() {
102
+ return getOwner() !== null;
103
+ }
104
+ //#endregion
105
+ export { ELEMENT_TYPE, Fragment, createContext, createElement, createProvider, hasOwner, isElement, renderComponent };
106
+
107
+ //# sourceMappingURL=component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.js","names":[],"sources":["../../src/component/component.ts"],"sourcesContent":["/**\n * MindeesNative component model โ€” a minimal, renderer-agnostic element tree plus\n * **selector-based, re-render-isolated context**.\n *\n * The element tree (`createElement` / `Fragment`) is a plain data structure: a\n * component is a function of `props` returning elements. It carries no rendering\n * logic itself โ€” the Helix renderer (Phase 3) turns this tree into host nodes.\n *\n * The context system is the important primitive: a `createContext` value is read\n * through a **selector**, and a consumer only re-runs when its *selected slice*\n * actually changes โ€” not on every context update. This is the re-render\n * isolation the Quantum Router (Phase 6) builds on. It is implemented on the\n * Phase 1 signals, so selection participates in normal reactivity.\n *\n * @module\n */\n\nimport { computed, createRoot, getOwner, signal } from '../reactive'\n\n// ---------------------------------------------------------------------------\n// Element tree\n// ---------------------------------------------------------------------------\n\n/** A component: a function from props to a renderable node. */\nexport type Component<P = Record<string, unknown>> = (props: P) => MindeesNode\n\n/**\n * Anything that can appear in the tree.\n *\n * Includes an **accessor** form `() => MindeesNode`: a function child (or\n * function prop value) is a *reactive region* โ€” the renderer subscribes to it\n * and patches exactly that region when its signals change (the fine-grained\n * update model, ร  la SolidJS). Static trees never need it; reactive UIs do.\n */\nexport type MindeesNode =\n | MindeesElement\n | string\n | number\n | boolean\n | null\n | undefined\n | (() => MindeesNode)\n | MindeesNode[]\n\n/** The tag of an element: a host string (e.g. `\"view\"`) or a component function. */\nexport type ElementType = string | Component<never>\n\n/** A virtual element: a tag, its props, and its children. */\nexport interface MindeesElement {\n readonly $$typeof: typeof ELEMENT_TYPE\n readonly type: ElementType\n readonly props: Readonly<Record<string, unknown>>\n readonly children: readonly MindeesNode[]\n readonly key: string | number | null\n}\n\n/** Brand so a renderer can reliably distinguish elements from plain objects. */\nexport const ELEMENT_TYPE: unique symbol = Symbol.for('mindees.element')\n\n/** Marker tag for a fragment (children with no wrapper host node). */\nexport const Fragment: unique symbol = Symbol.for('mindees.fragment')\n\ninterface PropsWithKey {\n key?: string | number | null\n children?: MindeesNode\n}\n\n/**\n * Create a virtual element. `type` is a host-component string or a component\n * function; `Fragment` groups children without a wrapper.\n *\n * @example\n * createElement('view', { id: 'root' }, createElement('text', null, 'hi'))\n */\nexport function createElement(\n type: ElementType | typeof Fragment,\n props?: (Record<string, unknown> & PropsWithKey) | null,\n ...children: MindeesNode[]\n): MindeesElement {\n const { key = null, children: propsChildren, ...rest } = props ?? {}\n // Children passed as args win over a `children` prop; otherwise fall back to it.\n const resolved: MindeesNode[] =\n children.length > 0 ? children : propsChildren !== undefined ? [propsChildren] : []\n return {\n $$typeof: ELEMENT_TYPE,\n type: type as ElementType,\n props: Object.freeze({ ...rest }),\n children: Object.freeze(resolved),\n key,\n }\n}\n\n/** Type guard: is `value` a MindeesElement? */\nexport function isElement(value: unknown): value is MindeesElement {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { $$typeof?: unknown }).$$typeof === ELEMENT_TYPE\n )\n}\n\n// ---------------------------------------------------------------------------\n// Selector-based, re-render-isolated context\n// ---------------------------------------------------------------------------\n\n/** Equality used by context selectors. Defaults to `Object.is`. */\nexport type SelectorEquals<S> = (a: S, b: S) => boolean\n\n/** A context handle created by {@link createContext}. */\nexport interface Context<T> {\n /** Provide a value to a subtree (conceptually); returns a scoped reader set. */\n readonly id: symbol\n /** The default value used when no provider is present. */\n readonly defaultValue: T\n}\n\n/**\n * A live provider instance: holds the current value and lets consumers subscribe\n * to a derived slice with re-render isolation.\n */\nexport interface ContextProvider<T> {\n /** Replace the provided value (notifies only consumers whose slice changed). */\n set(value: T): void\n /** Read the current value without subscribing. */\n peek(): T\n /**\n * Subscribe to a selected slice. The returned accessor is a memo that only\n * changes โ€” and thus only re-runs its observers โ€” when `selector(value)`\n * changes under `equals` (default `Object.is`).\n */\n select<S>(selector: (value: T) => S, equals?: SelectorEquals<S>): () => S\n}\n\n/** Create a context with a default value. */\nexport function createContext<T>(defaultValue: T): Context<T> {\n return { id: Symbol('mindees.context'), defaultValue }\n}\n\n/**\n * Create a provider instance for `context`. Built on a signal, so selected\n * slices are memos: a consumer that selects `c => c.user.name` does not re-run\n * when an unrelated field changes.\n *\n * @example\n * const Theme = createContext({ mode: 'light', accent: 'blue' })\n * const p = createProvider(Theme, { mode: 'light', accent: 'blue' })\n * const mode = p.select((t) => t.mode) // only re-runs when `mode` changes\n */\nexport function createProvider<T>(context: Context<T>, initial?: T): ContextProvider<T> {\n // equals:false at the root โ€” every set() re-evaluates selectors, but each\n // selector memo applies its own equality to isolate re-renders.\n const source = signal<T>(initial ?? context.defaultValue, { equals: false })\n return {\n set: (value: T) => {\n source.set(value)\n },\n peek: () => source.peek(),\n select<S>(selector: (value: T) => S, equals: SelectorEquals<S> = Object.is): () => S {\n return computed(() => selector(source()), { equals })\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Rendering a component subtree under an owner (so it can be disposed)\n// ---------------------------------------------------------------------------\n\n/**\n * Invoke a component within a reactive ownership scope, so every effect, memo,\n * and `onCleanup` it registers is torn down together when `dispose` is called.\n * Returns the produced node and that disposer.\n *\n * Built on the Phase 1 {@link createRoot}, so disposal reuses the same\n * leak-free teardown the reactivity tests cover. This is a renderer building\n * block; it does not touch any host.\n */\nexport function renderComponent<P>(\n component: Component<P>,\n props: P,\n): { node: MindeesNode; dispose: () => void } {\n let node!: MindeesNode\n // Capture the disposer eagerly: createRoot hands it to the callback synchronously\n // *before* the component runs, so if the component throws mid-render we can still\n // tear down anything it registered before the throw (effects, subscriptions,\n // timers). Without this, createRoot re-throws without disposing and the caller\n // never receives a disposer โ€” the partial scope would leak forever.\n let dispose!: () => void\n try {\n createRoot((d) => {\n dispose = d\n node = component(props)\n })\n } catch (error) {\n dispose?.()\n throw error\n }\n return { node, dispose }\n}\n\n/** Whether code is currently running inside a reactive ownership scope. */\nexport function hasOwner(): boolean {\n return getOwner() !== null\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyDA,MAAa,eAA8B,OAAO,IAAI,iBAAiB;;AAGvE,MAAa,WAA0B,OAAO,IAAI,kBAAkB;;;;;;;;AAcpE,SAAgB,cACd,MACA,OACA,GAAG,UACa;CAChB,MAAM,EAAE,MAAM,MAAM,UAAU,eAAe,GAAG,SAAS,SAAS,CAAC;CAEnE,MAAM,WACJ,SAAS,SAAS,IAAI,WAAW,kBAAkB,KAAA,IAAY,CAAC,aAAa,IAAI,CAAC;CACpF,OAAO;EACL,UAAU;EACJ;EACN,OAAO,OAAO,OAAO,EAAE,GAAG,KAAK,CAAC;EAChC,UAAU,OAAO,OAAO,QAAQ;EAChC;CACF;AACF;;AAGA,SAAgB,UAAU,OAAyC;CACjE,OACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAiC,aAAa;AAEnD;;AAmCA,SAAgB,cAAiB,cAA6B;CAC5D,OAAO;EAAE,IAAI,OAAO,iBAAiB;EAAG;CAAa;AACvD;;;;;;;;;;;AAYA,SAAgB,eAAkB,SAAqB,SAAiC;CAGtF,MAAM,SAAS,OAAU,WAAW,QAAQ,cAAc,EAAE,QAAQ,MAAM,CAAC;CAC3E,OAAO;EACL,MAAM,UAAa;GACjB,OAAO,IAAI,KAAK;EAClB;EACA,YAAY,OAAO,KAAK;EACxB,OAAU,UAA2B,SAA4B,OAAO,IAAa;GACnF,OAAO,eAAe,SAAS,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC;EACtD;CACF;AACF;;;;;;;;;;AAeA,SAAgB,gBACd,WACA,OAC4C;CAC5C,IAAI;CAMJ,IAAI;CACJ,IAAI;EACF,YAAY,MAAM;GAChB,UAAU;GACV,OAAO,UAAU,KAAK;EACxB,CAAC;CACH,SAAS,OAAO;EACd,UAAU;EACV,MAAM;CACR;CACA,OAAO;EAAE;EAAM;CAAQ;AACzB;;AAGA,SAAgB,WAAoB;CAClC,OAAO,SAAS,MAAM;AACxB"}
@@ -0,0 +1,23 @@
1
+ //#region src/errors.d.ts
2
+ /**
3
+ * Thrown by APIs that are declared but not yet implemented (a "research track").
4
+ *
5
+ * Per the MindeesNative Working-Code Doctrine, a not-yet-built capability must
6
+ * fail loudly and honestly rather than silently returning a fake value. This
7
+ * error type makes that failure explicit, typed, and traceable to an RFC.
8
+ */
9
+ declare class NotImplementedError extends Error {
10
+ readonly name = "NotImplementedError";
11
+ /** Stable, machine-readable error code. */
12
+ readonly code: "ERR_MINDEES_NOT_IMPLEMENTED";
13
+ /** The capability that is not implemented yet. */
14
+ readonly feature: string;
15
+ /** Optional reference to the tracking RFC (e.g. `"RFC-0007"`). */
16
+ readonly rfc?: string;
17
+ constructor(feature: string, options?: {
18
+ readonly rfc?: string;
19
+ });
20
+ }
21
+ //#endregion
22
+ export { NotImplementedError };
23
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","names":[],"sources":["../src/errors.ts"],"mappings":";;AAOA;;;;;;cAAa,mBAAA,SAA4B,KAAK;EAAA,SAC1B,IAAA;EAST;EAAA,SANA,IAAA;EAQG;EAAA,SALH,OAAA;EAKoB;EAAA,SAFpB,GAAA;cAEG,OAAA,UAAiB,OAAA;IAAA,SAAqB,GAAA;EAAA;AAAA"}
package/dist/errors.js ADDED
@@ -0,0 +1,28 @@
1
+ //#region src/errors.ts
2
+ /**
3
+ * Thrown by APIs that are declared but not yet implemented (a "research track").
4
+ *
5
+ * Per the MindeesNative Working-Code Doctrine, a not-yet-built capability must
6
+ * fail loudly and honestly rather than silently returning a fake value. This
7
+ * error type makes that failure explicit, typed, and traceable to an RFC.
8
+ */
9
+ var NotImplementedError = class extends Error {
10
+ name = "NotImplementedError";
11
+ /** Stable, machine-readable error code. */
12
+ code = "ERR_MINDEES_NOT_IMPLEMENTED";
13
+ /** The capability that is not implemented yet. */
14
+ feature;
15
+ /** Optional reference to the tracking RFC (e.g. `"RFC-0007"`). */
16
+ rfc;
17
+ constructor(feature, options) {
18
+ const rfc = options?.rfc;
19
+ super(`${feature} is not implemented yet (research track).${rfc ? ` See ${rfc}.` : ""}`);
20
+ this.feature = feature;
21
+ if (rfc !== void 0) this.rfc = rfc;
22
+ Object.setPrototypeOf(this, new.target.prototype);
23
+ }
24
+ };
25
+ //#endregion
26
+ export { NotImplementedError };
27
+
28
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Thrown by APIs that are declared but not yet implemented (a \"research track\").\n *\n * Per the MindeesNative Working-Code Doctrine, a not-yet-built capability must\n * fail loudly and honestly rather than silently returning a fake value. This\n * error type makes that failure explicit, typed, and traceable to an RFC.\n */\nexport class NotImplementedError extends Error {\n override readonly name = 'NotImplementedError'\n\n /** Stable, machine-readable error code. */\n readonly code = 'ERR_MINDEES_NOT_IMPLEMENTED' as const\n\n /** The capability that is not implemented yet. */\n readonly feature: string\n\n /** Optional reference to the tracking RFC (e.g. `\"RFC-0007\"`). */\n readonly rfc?: string\n\n constructor(feature: string, options?: { readonly rfc?: string }) {\n const rfc = options?.rfc\n super(`${feature} is not implemented yet (research track).${rfc ? ` See ${rfc}.` : ''}`)\n this.feature = feature\n if (rfc !== undefined) {\n this.rfc = rfc\n }\n // Preserve the prototype chain so `instanceof` works reliably.\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n"],"mappings":";;;;;;;;AAOA,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAyB;;CAGzB,OAAgB;;CAGhB;;CAGA;CAEA,YAAY,SAAiB,SAAqC;EAChE,MAAM,MAAM,SAAS;EACrB,MAAM,GAAG,QAAQ,2CAA2C,MAAM,QAAQ,IAAI,KAAK,IAAI;EACvF,KAAK,UAAU;EACf,IAAI,QAAQ,KAAA,GACV,KAAK,MAAM;EAGb,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS;CAClD;AACF"}
@@ -0,0 +1,31 @@
1
+ import { Maturity, PackageInfo } from "./types.js";
2
+ import { Component, Context, ContextProvider, ELEMENT_TYPE, ElementType, Fragment, MindeesElement, MindeesNode, SelectorEquals, createContext, createElement, createProvider, hasOwner, isElement, renderComponent } from "./component/component.js";
3
+ import { NotImplementedError } from "./errors.js";
4
+ import { notImplemented } from "./not-implemented.js";
5
+ import { Accessor, ComputedOptions, EqualsFn, Memo, Owner, Signal, SignalOptions, batch, computed, createRoot, effect, getOwner, memo, onCleanup, runWithOwner, signal, untrack } from "./reactive/reactive.js";
6
+ import { Priority, ScheduleOptions, ScheduledTask, Scheduler, SchedulerOptions, Task, createScheduler } from "./scheduler/scheduler.js";
7
+ import { ThreadPool, WorkerLike, WorkerPoolOptions, createInlineThreadPool, createNativeThreadPool, createWorkerPool } from "./threading/thread-pool.js";
8
+
9
+ //#region src/index.d.ts
10
+ /** The npm package name. */
11
+ declare const name = "@mindees/core";
12
+ /** The package version. All `@mindees/*` packages share one locked version line. */
13
+ declare const VERSION = "0.1.0";
14
+ /**
15
+ * Current maturity of this package. See the repository `STATUS.md`.
16
+ *
17
+ * The reactivity layer (signals/computed/effect/batch), the component model with
18
+ * selector-isolated context, the priority scheduler, and the thread-pool
19
+ * abstraction (Web Worker + inline) are all implemented and tested. Native
20
+ * multi-threading remains a research track (throws `NotImplementedError`).
21
+ */
22
+ declare const maturity: Maturity;
23
+ /**
24
+ * Static identity + maturity metadata for this package. Frozen so the
25
+ * self-reported identity tooling introspects cannot be mutated at runtime,
26
+ * matching the `readonly` fields of {@link PackageInfo}.
27
+ */
28
+ declare const info: PackageInfo;
29
+ //#endregion
30
+ export { type Accessor, type Component, type ComputedOptions, type Context, type ContextProvider, ELEMENT_TYPE, type ElementType, type EqualsFn, Fragment, type Maturity, type Memo, type MindeesElement, type MindeesNode, NotImplementedError, type Owner, type PackageInfo, type Priority, type ScheduleOptions, type ScheduledTask, Scheduler, type SchedulerOptions, type SelectorEquals, type Signal, type SignalOptions, type Task, type ThreadPool, VERSION, type WorkerLike, type WorkerPoolOptions, batch, computed, createContext, createElement, createInlineThreadPool, createNativeThreadPool, createProvider, createRoot, createScheduler, createWorkerPool, effect, getOwner, hasOwner, info, isElement, maturity, memo, name, notImplemented, onCleanup, renderComponent, runWithOwner, signal, untrack };
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;AAgGA;AAAA,cApBa,IAAA;;cAGA,OAAA;AAiBuE;;;;;;;;AAAA,cAPvE,QAAA,EAAU,QAAyB;;;;;;cAOnC,IAAA,EAAM,WAAiE"}
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ import { batch, computed, createRoot, effect, getOwner, memo, onCleanup, runWithOwner, signal, untrack } from "./reactive/reactive.js";
2
+ import { ELEMENT_TYPE, Fragment, createContext, createElement, createProvider, hasOwner, isElement, renderComponent } from "./component/component.js";
3
+ import { NotImplementedError } from "./errors.js";
4
+ import { notImplemented } from "./not-implemented.js";
5
+ import { Scheduler, createScheduler } from "./scheduler/scheduler.js";
6
+ import { createInlineThreadPool, createNativeThreadPool, createWorkerPool } from "./threading/thread-pool.js";
7
+ //#region src/index.ts
8
+ /** The npm package name. */
9
+ const name = "@mindees/core";
10
+ /** The package version. All `@mindees/*` packages share one locked version line. */
11
+ const VERSION = "0.1.0";
12
+ /**
13
+ * Current maturity of this package. See the repository `STATUS.md`.
14
+ *
15
+ * The reactivity layer (signals/computed/effect/batch), the component model with
16
+ * selector-isolated context, the priority scheduler, and the thread-pool
17
+ * abstraction (Web Worker + inline) are all implemented and tested. Native
18
+ * multi-threading remains a research track (throws `NotImplementedError`).
19
+ */
20
+ const maturity = "experimental";
21
+ /**
22
+ * Static identity + maturity metadata for this package. Frozen so the
23
+ * self-reported identity tooling introspects cannot be mutated at runtime,
24
+ * matching the `readonly` fields of {@link PackageInfo}.
25
+ */
26
+ const info = Object.freeze({
27
+ name,
28
+ version: VERSION,
29
+ maturity
30
+ });
31
+ //#endregion
32
+ export { ELEMENT_TYPE, Fragment, NotImplementedError, Scheduler, VERSION, batch, computed, createContext, createElement, createInlineThreadPool, createNativeThreadPool, createProvider, createRoot, createScheduler, createWorkerPool, effect, getOwner, hasOwner, info, isElement, maturity, memo, name, notImplemented, onCleanup, renderComponent, runWithOwner, signal, untrack };
33
+
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Maturity, PackageInfo } from './types'\n\n/**\n * Component model: a renderer-agnostic element tree plus selector-based,\n * re-render-isolated context. (Phase 2)\n */\nexport {\n type Component,\n type Context,\n type ContextProvider,\n createContext,\n createElement,\n createProvider,\n ELEMENT_TYPE,\n type ElementType,\n Fragment,\n hasOwner,\n isElement,\n type MindeesElement,\n type MindeesNode,\n renderComponent,\n type SelectorEquals,\n} from './component'\nexport { NotImplementedError } from './errors'\nexport { notImplemented } from './not-implemented'\n/**\n * Fine-grained reactivity: signals, computed values, effects, batching, and\n * disposal scopes. This is the reactive core of MindeesNative.\n */\nexport {\n type Accessor,\n batch,\n type ComputedOptions,\n computed,\n createRoot,\n type EqualsFn,\n effect,\n getOwner,\n type Memo,\n memo,\n type Owner,\n onCleanup,\n runWithOwner,\n type Signal,\n type SignalOptions,\n signal,\n untrack,\n} from './reactive'\n/**\n * Priority scheduler: two-lane (sync/normal), microtask-batched, with\n * cancellable and dedupable tasks. (Phase 2)\n */\nexport {\n createScheduler,\n type Priority,\n type ScheduledTask,\n type ScheduleOptions,\n Scheduler,\n type SchedulerOptions,\n type Task,\n} from './scheduler'\n/**\n * Threading abstraction: a {@link ThreadPool} contract with a working Web Worker\n * backend and an inline fallback. Native multi-threading is a research track. (Phase 2)\n */\nexport {\n createInlineThreadPool,\n createNativeThreadPool,\n createWorkerPool,\n type ThreadPool,\n type WorkerLike,\n type WorkerPoolOptions,\n} from './threading'\nexport type { Maturity, PackageInfo } from './types'\n\n/** The npm package name. */\nexport const name = '@mindees/core'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.1.0'\n\n/**\n * Current maturity of this package. See the repository `STATUS.md`.\n *\n * The reactivity layer (signals/computed/effect/batch), the component model with\n * selector-isolated context, the priority scheduler, and the thread-pool\n * abstraction (Web Worker + inline) are all implemented and tested. Native\n * multi-threading remains a research track (throws `NotImplementedError`).\n */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n"],"mappings":";;;;;;;;AA4EA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;;;;;;;;AAUvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
@@ -0,0 +1,16 @@
1
+ //#region src/not-implemented.d.ts
2
+ /**
3
+ * Throw a {@link NotImplementedError} for a not-yet-built capability.
4
+ *
5
+ * The `never` return type documents at the type level that this function never
6
+ * returns normally, so call sites type-check without bogus fallbacks.
7
+ *
8
+ * @param feature - Human-readable name of the unimplemented capability.
9
+ * @param options - Optional metadata, e.g. the tracking RFC.
10
+ */
11
+ declare function notImplemented(feature: string, options?: {
12
+ readonly rfc?: string;
13
+ }): never;
14
+ //#endregion
15
+ export { notImplemented };
16
+ //# sourceMappingURL=not-implemented.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-implemented.d.ts","names":[],"sources":["../src/not-implemented.ts"],"mappings":";;AAWA;;;;;;;;iBAAgB,cAAA,CAAe,OAAA,UAAiB,OAAA;EAAA,SAAqB,GAAA;AAAA"}
@@ -0,0 +1,18 @@
1
+ import { NotImplementedError } from "./errors.js";
2
+ //#region src/not-implemented.ts
3
+ /**
4
+ * Throw a {@link NotImplementedError} for a not-yet-built capability.
5
+ *
6
+ * The `never` return type documents at the type level that this function never
7
+ * returns normally, so call sites type-check without bogus fallbacks.
8
+ *
9
+ * @param feature - Human-readable name of the unimplemented capability.
10
+ * @param options - Optional metadata, e.g. the tracking RFC.
11
+ */
12
+ function notImplemented(feature, options) {
13
+ throw new NotImplementedError(feature, options);
14
+ }
15
+ //#endregion
16
+ export { notImplemented };
17
+
18
+ //# sourceMappingURL=not-implemented.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-implemented.js","names":[],"sources":["../src/not-implemented.ts"],"sourcesContent":["import { NotImplementedError } from './errors'\n\n/**\n * Throw a {@link NotImplementedError} for a not-yet-built capability.\n *\n * The `never` return type documents at the type level that this function never\n * returns normally, so call sites type-check without bogus fallbacks.\n *\n * @param feature - Human-readable name of the unimplemented capability.\n * @param options - Optional metadata, e.g. the tracking RFC.\n */\nexport function notImplemented(feature: string, options?: { readonly rfc?: string }): never {\n throw new NotImplementedError(feature, options)\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,eAAe,SAAiB,SAA4C;CAC1F,MAAM,IAAI,oBAAoB,SAAS,OAAO;AAChD"}