@arki/dot 0.1.0 → 0.1.1
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/README.md +36 -31
- package/dist/define-app.d.ts +58 -16
- package/dist/define-app.d.ts.map +1 -1
- package/dist/define-app.js +23 -13
- package/dist/define-app.js.map +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/kernel/app-instance.d.ts +3 -3
- package/dist/kernel/app-instance.d.ts.map +1 -1
- package/dist/kernel/app-instance.js +265 -159
- package/dist/kernel/app-instance.js.map +1 -1
- package/dist/lifecycle.d.ts +11 -9
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +15 -9
- package/dist/lifecycle.js.map +1 -1
- package/dist/pip-contract.d.ts +254 -149
- package/dist/pip-contract.d.ts.map +1 -1
- package/dist/pip-contract.js +185 -41
- package/dist/pip-contract.js.map +1 -1
- package/dist/pip.d.ts +9 -12
- package/dist/pip.d.ts.map +1 -1
- package/dist/pip.js +8 -11
- package/dist/pip.js.map +1 -1
- package/dist/test-harness.d.ts +13 -10
- package/dist/test-harness.d.ts.map +1 -1
- package/dist/test-harness.js +12 -12
- package/dist/test-harness.js.map +1 -1
- package/package.json +1 -1
- package/templates/app-minimal/AGENTS.md.tmpl +2 -2
package/dist/pip-contract.js
CHANGED
|
@@ -1,44 +1,202 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public pip contract for the DOT kernel.
|
|
2
|
+
* Public pip contract for the DOT kernel (v2).
|
|
3
3
|
*
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* A pip declares what it **needs** as a shape of type witnesses and
|
|
5
|
+
* publishes what it **provides** from its `boot` hook. The kernel wires
|
|
6
|
+
* services by key, injects them into hook contexts under the pip's local
|
|
7
|
+
* aliases, and fails loudly (coded errors) on unsatisfied needs or key
|
|
8
|
+
* collisions.
|
|
7
9
|
*
|
|
8
10
|
* Design constraints:
|
|
9
11
|
*
|
|
10
|
-
* - `configure` is SYNC. Returning a Promise is an error — the kernel
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* - `configure` is SYNC. Returning a Promise is an error — the kernel
|
|
13
|
+
* throws {@link DotLifecycleError} with code `DOT_LIFECYCLE_E001`.
|
|
14
|
+
* - Declaration order IS boot order. The app builder's type-level guard
|
|
15
|
+
* makes out-of-order composition a compile error; the kernel re-validates
|
|
16
|
+
* at runtime for erased/dynamic composition.
|
|
17
|
+
* - `stop` and `dispose` run in reverse declaration order and continue
|
|
18
|
+
* through individual pip failures, reporting an aggregate error.
|
|
16
19
|
*/
|
|
17
20
|
/**
|
|
18
|
-
*
|
|
21
|
+
* Create an app-local (anonymous) service witness for a `needs` shape.
|
|
22
|
+
*
|
|
23
|
+
* `service.lazy<T>()` creates a lifting witness instead — the hook context
|
|
24
|
+
* delivers a `Lazy<T>` handle whether the provider is eager or lazy.
|
|
25
|
+
*/
|
|
26
|
+
export const service = Object.assign(() => ({}), { lazy: () => ({ lazy: true }) });
|
|
27
|
+
/** Internal (kernel) check: is this witness a lazy-lifting one? */
|
|
28
|
+
export function isLazyWitness(witness) {
|
|
29
|
+
return 'lazy' in witness && witness.lazy === true;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a token. Curried so `T` is explicit while `K` is inferred as a
|
|
33
|
+
* literal: `const Db = token<DbHandle>()('arki.db')`.
|
|
34
|
+
*/
|
|
35
|
+
export function token() {
|
|
36
|
+
return (key) => ({
|
|
37
|
+
key,
|
|
38
|
+
instance(name) {
|
|
39
|
+
// Safe by construction: the runtime string is exactly the template type.
|
|
40
|
+
return token()(`${key}#${name}`);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Publish a value under a token's wire key. Returns a record typed by the
|
|
46
|
+
* token's literal key, so `boot: () => provide(Db, handle)` infers
|
|
47
|
+
* `TProvides = { 'arki.db': DbHandle }`.
|
|
48
|
+
*/
|
|
49
|
+
export function provide(tok, value) {
|
|
50
|
+
// Safe by construction: the computed key is exactly `tok.key: K`.
|
|
51
|
+
return { [tok.key]: value };
|
|
52
|
+
}
|
|
53
|
+
/** Runtime brand for lazy service handles (kernel detects these for auto-dispose). */
|
|
54
|
+
export const LazyTag = Symbol('dot.lazy');
|
|
55
|
+
/**
|
|
56
|
+
* Create a lazy service handle. See {@link Lazy} for semantics.
|
|
57
|
+
*
|
|
58
|
+
* @param init - Opens the resource. Runs at most once concurrently; a
|
|
59
|
+
* rejected attempt is not cached, so a later `get()` retries.
|
|
60
|
+
* @param options.dispose - Cleanup for the initialized value. Skipped when
|
|
61
|
+
* the handle was never initialized.
|
|
62
|
+
*/
|
|
63
|
+
export function lazy(init, options = {}) {
|
|
64
|
+
let state = { status: 'idle' };
|
|
65
|
+
return {
|
|
66
|
+
[LazyTag]: true,
|
|
67
|
+
get() {
|
|
68
|
+
if (state.status === 'ready')
|
|
69
|
+
return Promise.resolve(state.value);
|
|
70
|
+
if (state.status === 'pending')
|
|
71
|
+
return state.promise;
|
|
72
|
+
if (state.status === 'disposed') {
|
|
73
|
+
return Promise.reject(new Error('Lazy service handle is disposed — the app has shut down.'));
|
|
74
|
+
}
|
|
75
|
+
const promise = Promise.resolve()
|
|
76
|
+
.then(init)
|
|
77
|
+
.then(value => {
|
|
78
|
+
state = { status: 'ready', value };
|
|
79
|
+
return value;
|
|
80
|
+
}, (error) => {
|
|
81
|
+
// Failed initialization is not cached — allow retry.
|
|
82
|
+
state = { status: 'idle' };
|
|
83
|
+
throw error;
|
|
84
|
+
});
|
|
85
|
+
state = { status: 'pending', promise };
|
|
86
|
+
return promise;
|
|
87
|
+
},
|
|
88
|
+
get initialized() {
|
|
89
|
+
return state.status === 'ready';
|
|
90
|
+
},
|
|
91
|
+
peek() {
|
|
92
|
+
return state.status === 'ready' ? state.value : undefined;
|
|
93
|
+
},
|
|
94
|
+
async dispose() {
|
|
95
|
+
if (state.status === 'pending') {
|
|
96
|
+
try {
|
|
97
|
+
await state.promise;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Failed init: nothing to clean up.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (state.status === 'ready') {
|
|
104
|
+
const { value } = state;
|
|
105
|
+
state = { status: 'disposed' };
|
|
106
|
+
await options.dispose?.(value);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
state = { status: 'disposed' };
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Type guard: is this published value a lazy service handle? */
|
|
114
|
+
export function isLazy(value) {
|
|
115
|
+
return typeof value === 'object' && value !== null && LazyTag in value;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Wrap an already-available value in a pre-initialized `Lazy<T>` handle.
|
|
119
|
+
* Used by the kernel to lift eager provides for `service.lazy` consumers;
|
|
120
|
+
* also handy for handing fakes to lazy-consuming pips in tests. The handle
|
|
121
|
+
* has no cleanup of its own — the underlying value's lifecycle belongs to
|
|
122
|
+
* whoever created it.
|
|
123
|
+
*/
|
|
124
|
+
export function lazyOf(value) {
|
|
125
|
+
let disposed = false;
|
|
126
|
+
return {
|
|
127
|
+
[LazyTag]: true,
|
|
128
|
+
get: () => disposed
|
|
129
|
+
? Promise.reject(new Error('Lazy service handle is disposed — the app has shut down.'))
|
|
130
|
+
: Promise.resolve(value),
|
|
131
|
+
get initialized() {
|
|
132
|
+
return !disposed;
|
|
133
|
+
},
|
|
134
|
+
peek: () => (disposed ? undefined : value),
|
|
135
|
+
async dispose() {
|
|
136
|
+
disposed = true;
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Author a DOT pip.
|
|
142
|
+
*
|
|
143
|
+
* - `TShape` is inferred from the `needs` object literal.
|
|
144
|
+
* - `TProvides` is inferred from `boot`'s return type — no generic argument.
|
|
145
|
+
* - `boot({ db, log, $app })` destructures typed services under the local
|
|
146
|
+
* aliases declared in `needs`, plus the `$`-prefixed kernel keys.
|
|
147
|
+
* - `start` / `stop` / `dispose` additionally receive the pip's own
|
|
148
|
+
* provides. Reverse-order teardown guarantees needs are still alive in
|
|
149
|
+
* `dispose`.
|
|
19
150
|
*
|
|
20
151
|
* @example
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* export const billing = pip({
|
|
154
|
+
* name: 'billing',
|
|
155
|
+
* needs: { db: service<Db>(), log: service<Logger>() },
|
|
156
|
+
* async boot({ db, log }) {
|
|
157
|
+
* return { billing: new BillingService(db, log) };
|
|
26
158
|
* },
|
|
27
|
-
* async dispose({
|
|
28
|
-
* await
|
|
159
|
+
* async dispose({ billing }) {
|
|
160
|
+
* await billing.flush();
|
|
29
161
|
* },
|
|
30
162
|
* });
|
|
163
|
+
* ```
|
|
31
164
|
*/
|
|
32
|
-
export function
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
165
|
+
export function pip(def) {
|
|
166
|
+
return {
|
|
167
|
+
name: def.name,
|
|
168
|
+
...(def.version === undefined ? {} : { version: def.version }),
|
|
169
|
+
needs: def.needs ?? {},
|
|
170
|
+
renames: {},
|
|
171
|
+
hooks: {
|
|
172
|
+
...(def.configure === undefined ? {} : { configure: def.configure }),
|
|
173
|
+
...(def.boot === undefined ? {} : { boot: def.boot }),
|
|
174
|
+
...(def.start === undefined ? {} : { start: def.start }),
|
|
175
|
+
...(def.stop === undefined ? {} : { stop: def.stop }),
|
|
176
|
+
...(def.dispose === undefined ? {} : { dispose: def.dispose }),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
38
179
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Mount-time rename. `rename(dbPip, { db: 'reportsDb' }, 'reports-db')`
|
|
182
|
+
* publishes the same service under a different wire key, retyped
|
|
183
|
+
* accordingly — the way to mount a second instance of an adapter without
|
|
184
|
+
* a key collision. Renames compose: renaming an already-renamed key
|
|
185
|
+
* rewrites the earlier entry.
|
|
186
|
+
*/
|
|
187
|
+
export function rename(p, map, newName) {
|
|
188
|
+
const renames = { ...p.renames };
|
|
189
|
+
for (const [wireKey, next] of Object.entries(map)) {
|
|
190
|
+
if (typeof next !== 'string')
|
|
191
|
+
continue;
|
|
192
|
+
// If `wireKey` is itself the *result* of an earlier rename, rewrite that
|
|
193
|
+
// entry (compose); otherwise it is a local publish key.
|
|
194
|
+
const localKey = Object.entries(renames).find(([, w]) => w === wireKey)?.[0] ?? wireKey;
|
|
195
|
+
renames[localKey] = next;
|
|
196
|
+
}
|
|
197
|
+
// Phantom-only cast: runtime fields are unchanged except `renames`/`name`;
|
|
198
|
+
// only the [ProvidesSym] carrier retypes.
|
|
199
|
+
return { ...p, name: newName ?? p.name, renames };
|
|
42
200
|
}
|
|
43
201
|
/**
|
|
44
202
|
* Stable error thrown by DOT pip adapters.
|
|
@@ -55,20 +213,6 @@ export function pipDependencies(pip) {
|
|
|
55
213
|
*
|
|
56
214
|
* @see packages/dot/docs/principles.md — principle 1.3 ("errors are part
|
|
57
215
|
* of the API") and principle 4 ("agent-discoverable everywhere").
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```ts
|
|
61
|
-
* import { DotPipError } from '@arki/dot/pip';
|
|
62
|
-
*
|
|
63
|
-
* const KV_PIP_ERROR_CODES = { urlNotConfigured: 'KV_PIP_E001' } as const;
|
|
64
|
-
*
|
|
65
|
-
* throw new DotPipError({
|
|
66
|
-
* code: KV_PIP_ERROR_CODES.urlNotConfigured,
|
|
67
|
-
* message: '[kv] KV URL is not configured.',
|
|
68
|
-
* remediation: 'Pass options.url to kv(...) or set KV_URL in the environment.',
|
|
69
|
-
* docsUrl: 'https://arki.dev/dot/errors/kv-pip-e001',
|
|
70
|
-
* });
|
|
71
|
-
* ```
|
|
72
216
|
*/
|
|
73
217
|
export class DotPipError extends Error {
|
|
74
218
|
/** Stable error code, e.g. `KV_PIP_E001`. */
|
package/dist/pip-contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pip-contract.js","sourceRoot":"","sources":["../src/pip-contract.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pip-contract.js","sourceRoot":"","sources":["../src/pip-contract.ts"],"names":[],"mappings":"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"}
|
package/dist/pip.d.ts
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Narrow public surface for pip authors.
|
|
3
3
|
*
|
|
4
|
-
* Exposes the
|
|
5
|
-
* author
|
|
6
|
-
* `testApp` / `bootTestApp`, plus lifecycle / manifest /
|
|
4
|
+
* Exposes the pip contract and the entry points a pip author needs to
|
|
5
|
+
* author + test pips — `pip`, `service`, `token`, `provide`, `rename`,
|
|
6
|
+
* `defineApp`, `testApp` / `bootTestApp`, plus lifecycle / manifest /
|
|
7
|
+
* diagnostics types.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `@arki/kv/dot`, `@arki/db/dot`) import from this subpath so their
|
|
11
|
-
* `*.d.ts` graphs do not pull in the legacy surface — keeping their
|
|
12
|
-
* compile times tight and decoupling adapters from the legacy retirement
|
|
13
|
-
* schedule (Task 12).
|
|
9
|
+
* Adapter packages (e.g. `@arki/env/dot`, `@arki/kv/dot`, `@arki/db/dot`)
|
|
10
|
+
* import from this subpath so their `*.d.ts` graphs stay tight.
|
|
14
11
|
*
|
|
15
12
|
* @example
|
|
16
13
|
* ```ts
|
|
17
|
-
* import {
|
|
14
|
+
* import { pip, service, type Pip } from '@arki/dot/pip';
|
|
18
15
|
* ```
|
|
19
16
|
*/
|
|
20
|
-
export {
|
|
21
|
-
export type {
|
|
17
|
+
export { isLazy, lazy, lazyOf, pip, provide, rename, service, token, DotPipError } from './pip-contract.js';
|
|
18
|
+
export type { AnyPip, CtxOf, DotConfigureContext, EmptyShape, KernelCtx, Lazy, LazyService, NeedsShape, Pip, PipNeeds, PipProvides, RenamedProvides, Service, ServiceRecord, Token, WireNeeds, } from './pip-contract.js';
|
|
22
19
|
export { defineApp } from './define-app.js';
|
|
23
20
|
export type { DotApp, DotAppBuilder, DotAppConfigured } from './define-app.js';
|
|
24
21
|
export { testApp, bootTestApp } from './test-harness.js';
|
package/dist/pip.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pip.d.ts","sourceRoot":"","sources":["../src/pip.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pip.d.ts","sourceRoot":"","sources":["../src/pip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5G,YAAY,EACV,MAAM,EACN,KAAK,EACL,mBAAmB,EACnB,UAAU,EACV,SAAS,EACT,IAAI,EACJ,WAAW,EACX,UAAU,EACV,GAAG,EACH,QAAQ,EACR,WAAW,EACX,eAAe,EACf,OAAO,EACP,aAAa,EACb,KAAK,EACL,SAAS,GACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE/F,YAAY,EACV,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/pip.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Narrow public surface for pip authors.
|
|
3
3
|
*
|
|
4
|
-
* Exposes the
|
|
5
|
-
* author
|
|
6
|
-
* `testApp` / `bootTestApp`, plus lifecycle / manifest /
|
|
4
|
+
* Exposes the pip contract and the entry points a pip author needs to
|
|
5
|
+
* author + test pips — `pip`, `service`, `token`, `provide`, `rename`,
|
|
6
|
+
* `defineApp`, `testApp` / `bootTestApp`, plus lifecycle / manifest /
|
|
7
|
+
* diagnostics types.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `@arki/kv/dot`, `@arki/db/dot`) import from this subpath so their
|
|
11
|
-
* `*.d.ts` graphs do not pull in the legacy surface — keeping their
|
|
12
|
-
* compile times tight and decoupling adapters from the legacy retirement
|
|
13
|
-
* schedule (Task 12).
|
|
9
|
+
* Adapter packages (e.g. `@arki/env/dot`, `@arki/kv/dot`, `@arki/db/dot`)
|
|
10
|
+
* import from this subpath so their `*.d.ts` graphs stay tight.
|
|
14
11
|
*
|
|
15
12
|
* @example
|
|
16
13
|
* ```ts
|
|
17
|
-
* import {
|
|
14
|
+
* import { pip, service, type Pip } from '@arki/dot/pip';
|
|
18
15
|
* ```
|
|
19
16
|
*/
|
|
20
|
-
export {
|
|
17
|
+
export { isLazy, lazy, lazyOf, pip, provide, rename, service, token, DotPipError } from './pip-contract.js';
|
|
21
18
|
export { defineApp } from './define-app.js';
|
|
22
19
|
export { testApp, bootTestApp } from './test-harness.js';
|
|
23
20
|
export { DotLifecycleError, DotLifecycleErrorCode, DOT_LIFECYCLE_HOOKS } from './lifecycle.js';
|
package/dist/pip.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pip.js","sourceRoot":"","sources":["../src/pip.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pip.js","sourceRoot":"","sources":["../src/pip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAoB5G,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AASzD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAiC/F,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/test-harness.d.ts
CHANGED
|
@@ -5,38 +5,41 @@
|
|
|
5
5
|
* lifecycle behaviour, registration, and service publishing without dragging
|
|
6
6
|
* in concrete framework dependencies.
|
|
7
7
|
*
|
|
8
|
+
* NOTE: `testApp` takes an erased pip array, so the compile-time wiring
|
|
9
|
+
* guard does not apply here — the kernel's runtime validation (unsatisfied
|
|
10
|
+
* needs, collisions) still does. Use `defineApp(...).use(...)` chains in
|
|
11
|
+
* tests that should exercise the type-level guard.
|
|
12
|
+
*
|
|
8
13
|
* @example
|
|
9
|
-
* import { testApp,
|
|
14
|
+
* import { testApp, pip } from '@arki/dot';
|
|
10
15
|
*
|
|
11
|
-
* const myPip =
|
|
16
|
+
* const myPip = pip({
|
|
12
17
|
* name: 'counter',
|
|
13
|
-
*
|
|
14
|
-
* return { services: { counter: { value: 0 } } };
|
|
15
|
-
* },
|
|
18
|
+
* boot: () => ({ counter: { value: 0 } }),
|
|
16
19
|
* });
|
|
17
20
|
*
|
|
18
21
|
* it('publishes a counter service', async () => {
|
|
19
|
-
* const app = await
|
|
22
|
+
* const app = await bootTestApp<{ counter: { value: number } }>([myPip]);
|
|
20
23
|
* expect(app.services.counter.value).toBe(0);
|
|
21
24
|
* await app.dispose();
|
|
22
25
|
* });
|
|
23
26
|
*/
|
|
24
27
|
import type { DotApp, DotAppBuilder } from './define-app.js';
|
|
25
|
-
import type {
|
|
28
|
+
import type { AnyPip, EmptyShape, ServiceRecord } from './pip-contract.js';
|
|
26
29
|
export type TestAppOptions = {
|
|
27
30
|
/** App name used in the manifest. Defaults to `'test-app'`. */
|
|
28
31
|
name?: string;
|
|
29
|
-
/** Runtime config bag
|
|
32
|
+
/** Runtime config bag exposed to hooks as `$config`. */
|
|
30
33
|
config?: Readonly<Record<string, unknown>>;
|
|
31
34
|
};
|
|
32
35
|
/**
|
|
33
36
|
* Build a DOT app builder pre-populated with the given pips, ready to
|
|
34
37
|
* `.configure()`, `.boot()` or `.start()` from a test.
|
|
35
38
|
*/
|
|
36
|
-
export declare function testApp<TServices extends
|
|
39
|
+
export declare function testApp<TServices extends ServiceRecord = EmptyShape>(pips?: readonly AnyPip[], options?: TestAppOptions): DotAppBuilder<TServices>;
|
|
37
40
|
/**
|
|
38
41
|
* Convenience: build, boot, return the running app. Caller is responsible for
|
|
39
42
|
* calling `app.dispose()` when finished.
|
|
40
43
|
*/
|
|
41
|
-
export declare function bootTestApp<TServices extends
|
|
44
|
+
export declare function bootTestApp<TServices extends ServiceRecord = EmptyShape>(pips?: readonly AnyPip[], options?: TestAppOptions): Promise<DotApp<TServices>>;
|
|
42
45
|
//# sourceMappingURL=test-harness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-harness.d.ts","sourceRoot":"","sources":["../src/test-harness.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"test-harness.d.ts","sourceRoot":"","sources":["../src/test-harness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG3E,MAAM,MAAM,cAAc,GAAG;IAC3B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5C,CAAC;AAWF;;;GAGG;AACH,wBAAgB,OAAO,CAAC,SAAS,SAAS,aAAa,GAAG,UAAU,EAClE,IAAI,GAAE,SAAS,MAAM,EAAO,EAC5B,OAAO,GAAE,cAAmB,GAC3B,aAAa,CAAC,SAAS,CAAC,CAM1B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,SAAS,SAAS,aAAa,GAAG,UAAU,EAC5E,IAAI,GAAE,SAAS,MAAM,EAAO,EAC5B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAE5B"}
|
package/dist/test-harness.js
CHANGED
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
* lifecycle behaviour, registration, and service publishing without dragging
|
|
6
6
|
* in concrete framework dependencies.
|
|
7
7
|
*
|
|
8
|
+
* NOTE: `testApp` takes an erased pip array, so the compile-time wiring
|
|
9
|
+
* guard does not apply here — the kernel's runtime validation (unsatisfied
|
|
10
|
+
* needs, collisions) still does. Use `defineApp(...).use(...)` chains in
|
|
11
|
+
* tests that should exercise the type-level guard.
|
|
12
|
+
*
|
|
8
13
|
* @example
|
|
9
|
-
* import { testApp,
|
|
14
|
+
* import { testApp, pip } from '@arki/dot';
|
|
10
15
|
*
|
|
11
|
-
* const myPip =
|
|
16
|
+
* const myPip = pip({
|
|
12
17
|
* name: 'counter',
|
|
13
|
-
*
|
|
14
|
-
* return { services: { counter: { value: 0 } } };
|
|
15
|
-
* },
|
|
18
|
+
* boot: () => ({ counter: { value: 0 } }),
|
|
16
19
|
* });
|
|
17
20
|
*
|
|
18
21
|
* it('publishes a counter service', async () => {
|
|
19
|
-
* const app = await
|
|
22
|
+
* const app = await bootTestApp<{ counter: { value: number } }>([myPip]);
|
|
20
23
|
* expect(app.services.counter.value).toBe(0);
|
|
21
24
|
* await app.dispose();
|
|
22
25
|
* });
|
|
@@ -26,13 +29,10 @@ import { defineApp } from './define-app.js';
|
|
|
26
29
|
* Build a DOT app builder pre-populated with the given pips, ready to
|
|
27
30
|
* `.configure()`, `.boot()` or `.start()` from a test.
|
|
28
31
|
*/
|
|
29
|
-
export function testApp(
|
|
30
|
-
// Accept any pip shape — tests routinely mix services types. Internally
|
|
31
|
-
// we erase to `AnyDotPip` for the kernel.
|
|
32
|
-
pips = [], options = {}) {
|
|
32
|
+
export function testApp(pips = [], options = {}) {
|
|
33
33
|
let builder = defineApp(options.name ?? 'test-app', { config: options.config });
|
|
34
|
-
for (const
|
|
35
|
-
builder = builder.use(
|
|
34
|
+
for (const p of pips) {
|
|
35
|
+
builder = builder.use(p);
|
|
36
36
|
}
|
|
37
37
|
return builder;
|
|
38
38
|
}
|
package/dist/test-harness.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-harness.js","sourceRoot":"","sources":["../src/test-harness.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"test-harness.js","sourceRoot":"","sources":["../src/test-harness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAkB5C;;;GAGG;AACH,MAAM,UAAU,OAAO,CACrB,OAA0B,EAAE,EAC5B,UAA0B,EAAE;IAE5B,IAAI,OAAO,GAAY,SAAS,CAAC,OAAO,CAAC,IAAI,IAAI,UAAU,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,OAAO,GAAI,OAAwB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,OAAmC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAA0B,EAAE,EAC5B,UAA0B,EAAE;IAE5B,OAAO,OAAO,CAAY,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAClD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arki/dot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "TypeScript-first application composition framework for the ARKI package family — lifecycle-aware pips, deterministic boot order, manifest/diagnostics envelopes, and an agent-native CLI. A DOT app is the sum of its pips.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,8 +36,8 @@ command exits zero.
|
|
|
36
36
|
app reads belong here.
|
|
37
37
|
- Don't reach into `@arki/dot` internals (anything under
|
|
38
38
|
`@arki/dot/kernel`, `@arki/dot/legacy`, or `dist/` subpaths). Use the
|
|
39
|
-
public `defineApp` / `
|
|
40
|
-
`
|
|
39
|
+
public `defineApp` / `pip` API from `@arki/dot` and the
|
|
40
|
+
`pip` / `service` / `rename` symbols from `@arki/dot/pip`.
|
|
41
41
|
|
|
42
42
|
## DOT artifact locations
|
|
43
43
|
|