@databehave/core 0.0.0-stage → 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/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ Upcoming package version: **0.1.0**. This section describes planned release contents, not a published release.
6
+
7
+ ### Runtime requirements
8
+
9
+ - Require Node.js 24 or 26; support and test majors 24 and 26. Node.js 18, 20 and 22 are unsupported.
10
+
11
+ ### Added
12
+
13
+ - Typed versioned capabilities, explicit dependency validation and instance-local plugin registration.
14
+ - Synchronous setup/sealing and separate prepare, activate and open barriers.
15
+ - Idempotent startup/close, cancellation, ingress drain and reverse resource disposal with cleanup failure reporting.
16
+
17
+ See [migration](../../MIGRATION.md) and [release procedures](../../docs/releasing.md).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ochairo
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 CHANGED
@@ -1,3 +1,77 @@
1
- # Temporary Holding Version
1
+ # @databehave/core
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Explicit, typed plugin composition with no product dependencies or global registry.
4
+
5
+ Requires Node.js 24 or 26; supported majors are 24 and 26. See the
6
+ [plugin author guide](../../docs/plugins.md) and [runnable plugin example](../../examples/plugin.mjs).
7
+
8
+ ```ts
9
+ import { capability, createHost, type Plugin } from '@databehave/core'
10
+
11
+ const greeting = capability<{ text: string }>('example/greeting', 1)
12
+ const provider: Plugin = {
13
+ id: 'greeting',
14
+ apiVersion: 1,
15
+ provides: [greeting],
16
+ setup(ctx) { ctx.provide(greeting, { text: 'Hello' }) },
17
+ }
18
+ const consumer: Plugin = {
19
+ id: 'printer',
20
+ apiVersion: 1,
21
+ requires: [greeting],
22
+ setup() {},
23
+ activate(ctx) { console.log(ctx.use(greeting).text) },
24
+ }
25
+ const host = createHost({ plugins: [consumer, provider] })
26
+ await host.start()
27
+ await host.close()
28
+ ```
29
+
30
+ Capability identity is its nonempty, trimmed name and positive integer version. Separate
31
+ copies of a contract match by those values. Generic tokens connect the capability's
32
+ value type to `provide`, `use`, and `get`; JavaScript values are trusted to honor that
33
+ contract. Names should be package-qualified. Duplicate providers of the same name/version,
34
+ missing requirements, duplicate plugin IDs, invalid API versions and cycles fail before
35
+ setup. Different capability versions may coexist when explicitly provided and required.
36
+ Plugins may only provide declared capabilities and consume declared requirements.
37
+ `host.get(token)` is for the application's composition boundary; it does not extend the
38
+ service's lifetime past host shutdown. Omitted plugins contribute no capabilities.
39
+
40
+ `createHost` validates the complete graph, runs synchronous setup in dependency order,
41
+ then invokes seal callbacks. Setup must not perform I/O or acquire resources. Async setup
42
+ and seal callbacks are rejected; trusted plugin code is not sandboxed and cannot be
43
+ forcibly undone. Setup contexts expire when their setup returns. Seal callbacks run after
44
+ all setup contributions and should seal feature-owned registries. Register contributions
45
+ through those feature contracts only while registration remains open.
46
+
47
+ Registration snapshots plugin identities and callback references. Object literals and class implementations
48
+ are supported; callbacks retain their original receiver, including private fields. Reassigning a handler
49
+ after construction does not replace the registered handler. Receiver and closure state remain plugin-owned.
50
+
51
+ Startup runs separate `prepare`, `activate`, then `open` barriers. Each phase is sequential:
52
+ providers precede consumers, and available independent plugins follow configuration order.
53
+ Context `order` always gives the original configuration index, allowing feature-owned
54
+ middleware ordering independent of dependency ordering. All preparation finishes before
55
+ any activation, and all activation finishes before any external ingress opens.
56
+
57
+ Call `ctx.defer(dispose)` immediately when acquiring each resource. Only `open` may call
58
+ `ctx.ownIngress({ stopAccepting, drainAndClose })`; do not also register the same ingress
59
+ as an ordinary disposer. Close stops all registered ingress synchronously, aborts the
60
+ lifetime signal, waits for the current startup hook, drains ingress in reverse acquisition
61
+ order, and disposes other resources in reverse acquisition order. A hook completing after
62
+ cancellation may still register its acquisitions; late ingress stops immediately. Its
63
+ context expires on completion, so detached background acquisition is unsupported. Hooks
64
+ must cooperate with cancellation, and ingress implementations own bounded draining.
65
+
66
+ Concurrent `start()` calls share one promise, as do all `close()` calls. Close during
67
+ startup prevents subsequent hooks/phases and rejects startup after cleanup. Repeated
68
+ start after a completed start returns that original promise and never restarts the host.
69
+ Closing before start rejects a later start. Failure is terminal: create a new host to retry.
70
+ Cleanup continues after errors and rejects with `AggregateError`; startup cleanup errors
71
+ also retain the original startup error as the first error and `cause`. If cleanup succeeds,
72
+ startup rejects with the original failure and close succeeds. States are `ready`, `starting`,
73
+ `running`, `closing`, `closed`, and `failed`.
74
+
75
+ Run `pnpm typecheck`, `pnpm test`, and `pnpm build` in the project development container.
76
+ The root `api:check` command verifies the package API report in `etc/core.api.md`.
77
+ Use `api:update` when intentionally changing the public contract.
@@ -0,0 +1,5 @@
1
+ import type { Capability, CapabilityKey } from './contracts.js';
2
+ /** Create a token; matching depends on name/version, never object or symbol identity. */
3
+ export declare function capability<T>(name: string, version?: number): Capability<T>;
4
+ export declare function capabilityId(token: CapabilityKey): string;
5
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE/D,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAItE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAQzD"}
@@ -0,0 +1,16 @@
1
+ /** Create a token; matching depends on name/version, never object or symbol identity. */
2
+ export function capability(name, version = 1) {
3
+ const token = { name, version };
4
+ capabilityId(token);
5
+ return Object.freeze(token);
6
+ }
7
+ export function capabilityId(token) {
8
+ if (!token || typeof token.name !== 'string' || token.name.trim() !== token.name || !token.name) {
9
+ throw new Error('Capability name must be a nonempty trimmed string');
10
+ }
11
+ if (!Number.isSafeInteger(token.version) || token.version < 1) {
12
+ throw new Error(`Invalid capability version for ${token.name}`);
13
+ }
14
+ return JSON.stringify([token.name, token.version]);
15
+ }
16
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAEA,yFAAyF;AACzF,MAAM,UAAU,UAAU,CAAI,IAAY,EAAE,OAAO,GAAG,CAAC;IACrD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IAC/B,YAAY,CAAC,KAAK,CAAC,CAAA;IACnB,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAoB;IAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChG,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;AACpD,CAAC"}
@@ -0,0 +1,52 @@
1
+ /** Stable identity shared by separately installed copies of a capability contract. */
2
+ export interface CapabilityKey {
3
+ readonly name: string;
4
+ readonly version: number;
5
+ }
6
+ /** Typed capability identity. The optional phantom member carries no runtime state. */
7
+ export interface Capability<T> extends CapabilityKey {
8
+ readonly __valueType?: (value: T) => T;
9
+ }
10
+ /** Synchronous, effect-free registration, available only during the plugin's setup. */
11
+ export interface SetupContext {
12
+ /** Original configuration index, independent of dependency ordering. */
13
+ readonly order: number;
14
+ use<T>(token: Capability<T>): T;
15
+ provide<T>(token: Capability<T>, value: T): void;
16
+ onSeal(fn: () => void): void;
17
+ }
18
+ /** External ingress stops synchronously before lifetime cancellation and draining. */
19
+ export interface IngressHandle {
20
+ stopAccepting(): void;
21
+ drainAndClose(): Promise<void>;
22
+ }
23
+ /** Resource ownership for one running hook; register cleanup immediately on acquisition. */
24
+ export interface LifecycleContext {
25
+ /** Original configuration index, independent of dependency ordering. */
26
+ readonly order: number;
27
+ use<T>(token: Capability<T>): T;
28
+ readonly signal: AbortSignal;
29
+ defer(dispose: () => void | Promise<void>): void;
30
+ ownIngress(handle: IngressHandle): void;
31
+ }
32
+ /** An explicit capability provider/consumer using host contract version 1. */
33
+ export interface Plugin {
34
+ readonly id: string;
35
+ readonly apiVersion: 1;
36
+ readonly provides?: readonly CapabilityKey[];
37
+ readonly requires?: readonly CapabilityKey[];
38
+ setup(ctx: SetupContext): void;
39
+ prepare?(ctx: LifecycleContext): void | Promise<void>;
40
+ activate?(ctx: LifecycleContext): void | Promise<void>;
41
+ open?(ctx: LifecycleContext): void | Promise<void>;
42
+ }
43
+ /** A host is terminal after close or failure; create another host to restart. */
44
+ export type HostState = 'ready' | 'starting' | 'running' | 'closing' | 'closed' | 'failed';
45
+ /** Independently owned application lifetime and its sealed capabilities. */
46
+ export interface Host {
47
+ readonly state: HostState;
48
+ start(): Promise<void>;
49
+ close(): Promise<void>;
50
+ get<T>(token: Capability<T>): T;
51
+ }
52
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,uFAAuF;AACvF,MAAM,WAAW,UAAU,CAAC,CAAC,CAAE,SAAQ,aAAa;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;CACvC;AAED,uFAAuF;AACvF,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAC/B,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IAChD,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CAC7B;AAED,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC5B,aAAa,IAAI,IAAI,CAAA;IACrB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/B;AAED,4FAA4F;AAC5F,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,KAAK,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;CACxC;AAED,8EAA8E;AAC9E,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAA;IAC5C,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAA;IAC5C,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAA;IAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrD,QAAQ,CAAC,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,IAAI,CAAC,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnD;AAED,iFAAiF;AACjF,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE1F,4EAA4E;AAC5E,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;CAChC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":""}
package/dist/host.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { Host, Plugin } from './contracts.js';
2
+ /** Validate, register and seal plugins synchronously, without starting their effects. */
3
+ export declare function createHost(options: {
4
+ readonly plugins: readonly Plugin[];
5
+ }): Host;
6
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA8C,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAG9F,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAsHjF"}
package/dist/host.js ADDED
@@ -0,0 +1,147 @@
1
+ import { register } from './registration.js';
2
+ /** Validate, register and seal plugins synchronously, without starting their effects. */
3
+ export function createHost(options) {
4
+ const registration = register(options.plugins);
5
+ const lifetime = new AbortController();
6
+ const disposers = [];
7
+ const ingress = [];
8
+ const stopped = new Set();
9
+ const cleanupErrors = [];
10
+ let state = 'ready';
11
+ let startPromise;
12
+ let execution;
13
+ let closePromise;
14
+ let failed = false;
15
+ let startupError;
16
+ let closing = false;
17
+ function stopAccepting(handle) {
18
+ if (stopped.has(handle))
19
+ return;
20
+ stopped.add(handle);
21
+ try {
22
+ handle.stopAccepting();
23
+ }
24
+ catch (error) {
25
+ cleanupErrors.push(error);
26
+ }
27
+ }
28
+ function beginClose() {
29
+ closing = true;
30
+ state = 'closing';
31
+ for (const handle of ingress)
32
+ stopAccepting(handle);
33
+ lifetime.abort();
34
+ }
35
+ async function cleanup() {
36
+ // A completing hook still owns its context, and can register a newly acquired resource.
37
+ try {
38
+ await execution;
39
+ }
40
+ catch { /* Startup failure is retained separately. */ }
41
+ for (const handle of [...ingress].reverse()) {
42
+ try {
43
+ await handle.drainAndClose();
44
+ }
45
+ catch (error) {
46
+ cleanupErrors.push(error);
47
+ }
48
+ }
49
+ for (const dispose of disposers.reverse()) {
50
+ try {
51
+ await dispose();
52
+ }
53
+ catch (error) {
54
+ cleanupErrors.push(error);
55
+ }
56
+ }
57
+ state = failed || cleanupErrors.length ? 'failed' : 'closed';
58
+ if (cleanupErrors.length) {
59
+ throw new AggregateError(failed ? [startupError, ...cleanupErrors] : cleanupErrors, 'Host cleanup failed', failed ? { cause: startupError } : undefined);
60
+ }
61
+ }
62
+ function close() {
63
+ if (!closePromise) {
64
+ // Schedule cleanup after installing the shared promise, before invoking plugin callbacks.
65
+ closePromise = Promise.resolve().then(cleanup);
66
+ beginClose();
67
+ }
68
+ return closePromise;
69
+ }
70
+ async function run() {
71
+ for (const phase of ['prepare', 'activate', 'open']) {
72
+ for (const owner of registration.ordered) {
73
+ if (closing)
74
+ return;
75
+ const hook = owner.plugin[phase];
76
+ if (!hook)
77
+ continue;
78
+ let active = true;
79
+ function assertActive() {
80
+ if (!active)
81
+ throw new Error(`Lifecycle context expired for ${owner.plugin.id}:${phase}`);
82
+ }
83
+ const context = {
84
+ order: owner.order,
85
+ signal: lifetime.signal,
86
+ use(token) {
87
+ assertActive();
88
+ return registration.use(owner, token);
89
+ },
90
+ defer(dispose) {
91
+ assertActive();
92
+ if (typeof dispose !== 'function')
93
+ throw new Error('Disposer must be a function');
94
+ disposers.push(dispose);
95
+ },
96
+ ownIngress(handle) {
97
+ assertActive();
98
+ if (phase !== 'open')
99
+ throw new Error('Ingress may only be acquired during open');
100
+ if (!handle || typeof handle.stopAccepting !== 'function' || typeof handle.drainAndClose !== 'function') {
101
+ throw new Error('Invalid ingress handle');
102
+ }
103
+ if (ingress.includes(handle))
104
+ throw new Error('Ingress handle already owned');
105
+ ingress.push(handle);
106
+ if (closing)
107
+ stopAccepting(handle);
108
+ },
109
+ };
110
+ try {
111
+ await hook.call(owner.plugin, context);
112
+ }
113
+ finally {
114
+ active = false;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ function start() {
120
+ if (!startPromise) {
121
+ if (closing) {
122
+ startPromise = Promise.reject(new Error('Cannot start a closed host'));
123
+ }
124
+ else {
125
+ state = 'starting';
126
+ execution = Promise.resolve().then(run).catch((error) => {
127
+ failed = true;
128
+ startupError = error;
129
+ throw error;
130
+ });
131
+ startPromise = execution.then(async () => {
132
+ if (closing) {
133
+ await close();
134
+ throw new Error('Host closed during startup');
135
+ }
136
+ state = 'running';
137
+ }, async (error) => {
138
+ await close();
139
+ throw error;
140
+ });
141
+ }
142
+ }
143
+ return startPromise;
144
+ }
145
+ return { start, close, get: registration.get, get state() { return state; } };
146
+ }
147
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { Capability, CapabilityKey, Host, HostState, IngressHandle, LifecycleContext, Plugin, SetupContext, } from './contracts.js';
2
+ export { capability } from './capability.js';
3
+ export { createHost } from './host.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,aAAa,EACb,IAAI,EACJ,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,MAAM,EACN,YAAY,GACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { capability } from './capability.js';
2
+ export { createHost } from './host.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
@@ -0,0 +1,17 @@
1
+ import type { Capability, Plugin } from './contracts.js';
2
+ /** Validated snapshot of one plugin and its declared capability identities. */
3
+ export interface RegisteredPlugin {
4
+ readonly order: number;
5
+ readonly plugin: Plugin;
6
+ readonly provides: ReadonlySet<string>;
7
+ readonly requires: ReadonlySet<string>;
8
+ }
9
+ /** The sealed, instance-local service registry and deterministic dependency order. */
10
+ export interface Registration {
11
+ readonly ordered: readonly RegisteredPlugin[];
12
+ get<T>(token: Capability<T>): T;
13
+ use<T>(owner: RegisteredPlugin, token: Capability<T>): T;
14
+ }
15
+ export declare function assertSynchronous(result: unknown, label: string): void;
16
+ export declare function register(plugins: readonly Plugin[]): Registration;
17
+ //# sourceMappingURL=registration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../src/registration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvE,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CACvC;AAED,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAA;IAC7C,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAC/B,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;CACzD;AAaD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOtE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAsGjE"}
@@ -0,0 +1,141 @@
1
+ import { capabilityId } from './capability.js';
2
+ function keys(tokens, owner) {
3
+ if (tokens !== undefined && !Array.isArray(tokens))
4
+ throw new Error(`Invalid capabilities in ${owner}`);
5
+ const result = new Set();
6
+ for (const token of tokens ?? []) {
7
+ const key = capabilityId(token);
8
+ if (result.has(key))
9
+ throw new Error(`Duplicate capability declaration ${key} in ${owner}`);
10
+ result.add(key);
11
+ }
12
+ return result;
13
+ }
14
+ export function assertSynchronous(result, label) {
15
+ if (result !== null && (typeof result === 'object' || typeof result === 'function') &&
16
+ 'then' in result && typeof result.then === 'function') {
17
+ // A rejected async hook must not become an unhandled rejection after construction fails.
18
+ void Promise.resolve(result).catch(() => { });
19
+ throw new Error(`${label} must be synchronous`);
20
+ }
21
+ }
22
+ export function register(plugins) {
23
+ if (!Array.isArray(plugins))
24
+ throw new Error('plugins must be an array');
25
+ const ids = new Set();
26
+ const providers = new Map();
27
+ const entries = plugins.map((input, order) => {
28
+ if (!input || typeof input.id !== 'string' || !input.id || input.id.trim() !== input.id) {
29
+ throw new Error('Plugin id must be a nonempty trimmed string');
30
+ }
31
+ if (ids.has(input.id))
32
+ throw new Error(`Duplicate plugin id ${input.id}`);
33
+ ids.add(input.id);
34
+ if (input.apiVersion !== 1)
35
+ throw new Error(`Unsupported host API version in ${input.id}`);
36
+ if (typeof input.setup !== 'function')
37
+ throw new Error(`Missing setup in ${input.id}`);
38
+ for (const phase of ['prepare', 'activate', 'open']) {
39
+ if (input[phase] !== undefined && typeof input[phase] !== 'function') {
40
+ throw new Error(`Invalid ${phase} hook in ${input.id}`);
41
+ }
42
+ }
43
+ const entry = {
44
+ order,
45
+ // Capture public callbacks while retaining the extension's receiver (including private fields).
46
+ plugin: {
47
+ id: input.id,
48
+ apiVersion: input.apiVersion,
49
+ setup: input.setup.bind(input),
50
+ ...(input.prepare === undefined ? {} : { prepare: input.prepare.bind(input) }),
51
+ ...(input.activate === undefined ? {} : { activate: input.activate.bind(input) }),
52
+ ...(input.open === undefined ? {} : { open: input.open.bind(input) }),
53
+ },
54
+ provides: keys(input.provides, input.id),
55
+ requires: keys(input.requires, input.id),
56
+ };
57
+ for (const key of entry.provides) {
58
+ const previous = providers.get(key);
59
+ if (previous)
60
+ throw new Error(`Duplicate provider for ${key}: ${previous.plugin.id}, ${input.id}`);
61
+ providers.set(key, entry);
62
+ }
63
+ return entry;
64
+ });
65
+ for (const entry of entries) {
66
+ for (const key of entry.requires) {
67
+ if (!providers.has(key))
68
+ throw new Error(`Missing capability ${key} required by ${entry.plugin.id}`);
69
+ }
70
+ }
71
+ const ordered = [];
72
+ const remaining = new Set(entries);
73
+ const resolved = new Set();
74
+ while (remaining.size) {
75
+ const next = entries.find(entry => remaining.has(entry) && [...entry.requires].every(key => resolved.has(key)));
76
+ if (!next)
77
+ throw new Error(`Capability dependency cycle: ${[...remaining].map(e => e.plugin.id).join(', ')}`);
78
+ remaining.delete(next);
79
+ ordered.push(next);
80
+ for (const key of next.provides)
81
+ resolved.add(key);
82
+ }
83
+ const services = new Map();
84
+ const seals = [];
85
+ function get(token) {
86
+ const key = capabilityId(token);
87
+ if (!services.has(key))
88
+ throw new Error(`Capability unavailable: ${key}`);
89
+ // provide() pairs each typed token with its value; name/version is the public identity boundary.
90
+ return services.get(key);
91
+ }
92
+ function use(owner, token) {
93
+ const key = capabilityId(token);
94
+ if (!owner.requires.has(key))
95
+ throw new Error(`Undeclared requirement ${key} in ${owner.plugin.id}`);
96
+ return get(token);
97
+ }
98
+ for (const owner of ordered) {
99
+ let registering = true;
100
+ function assertRegistering() {
101
+ if (!registering)
102
+ throw new Error(`Registration sealed for ${owner.plugin.id}`);
103
+ }
104
+ try {
105
+ const result = owner.plugin.setup({
106
+ order: owner.order,
107
+ use(token) {
108
+ assertRegistering();
109
+ return use(owner, token);
110
+ },
111
+ provide(token, value) {
112
+ assertRegistering();
113
+ const key = capabilityId(token);
114
+ if (!owner.provides.has(key))
115
+ throw new Error(`Undeclared provider ${key} in ${owner.plugin.id}`);
116
+ if (services.has(key))
117
+ throw new Error(`Capability already provided: ${key}`);
118
+ services.set(key, value);
119
+ },
120
+ onSeal(fn) {
121
+ assertRegistering();
122
+ if (typeof fn !== 'function')
123
+ throw new Error('Seal callback must be a function');
124
+ seals.push(fn);
125
+ },
126
+ });
127
+ assertSynchronous(result, `Setup for ${owner.plugin.id}`);
128
+ for (const key of owner.provides) {
129
+ if (!services.has(key))
130
+ throw new Error(`Declared capability ${key} not provided by ${owner.plugin.id}`);
131
+ }
132
+ }
133
+ finally {
134
+ registering = false;
135
+ }
136
+ }
137
+ for (const seal of seals)
138
+ assertSynchronous(seal(), 'Seal callback');
139
+ return { ordered, get, use };
140
+ }
141
+ //# sourceMappingURL=registration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.js","sourceRoot":"","sources":["../src/registration.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "@databehave/core",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Instance-local typed plugin composition and application lifecycle.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ochairo/databehave.git",
10
+ "directory": "packages/core"
11
+ },
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "sideEffects": false,
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "CHANGELOG.md"
25
+ ],
26
+ "engines": {
27
+ "node": "^24.0.0 || ^26.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "6.0.3",
31
+ "@types/node": "25.9.1"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public",
35
+ "provenance": true
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.build.json",
39
+ "build:test": "tsc -p tsconfig.test.json",
40
+ "typecheck": "tsc --noEmit",
41
+ "pretest": "pnpm build:test",
42
+ "test": "node --test dist-test/test/*.test.js",
43
+ "clean": "rm -rf dist dist-test"
44
+ }
6
45
  }