@ghostry/fabricator 0.0.3 → 0.0.4

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.
@@ -1,14 +1,15 @@
1
1
  import { shuffle } from "../Distribution/index.js";
2
2
  import { FabricatorError } from "../Error/index.js";
3
3
  import { Constructor } from "../Fabricator/Constructor.js";
4
+ import { toInnermostFrame } from "../Instance/Stack/Visible.js";
4
5
  import { toStreamFromTrace } from "../Random/index.js";
5
6
  import { plan, resolve } from "./Plan.js";
6
- function enumerables(source, limits, stack) {
7
- const Fabricator = Constructor(source, stack);
7
+ function enumerables(source, limits, stack, ancestry) {
8
+ const Fabricator = Constructor(source, stack, ancestry);
8
9
  function effectiveSource() {
9
10
  var _ref;
10
- var _stack_current;
11
- return null != (_ref = null == (_stack_current = stack.current()) ? void 0 : _stack_current.source) ? _ref : source;
11
+ var _toInnermostFrame;
12
+ return null != (_ref = null == (_toInnermostFrame = toInnermostFrame(stack, ancestry)) ? void 0 : _toInnermostFrame.source) ? _ref : source;
12
13
  }
13
14
  function iterable(rebuild) {
14
15
  return {
@@ -90,9 +91,9 @@ function enumerables(source, limits, stack) {
90
91
  }
91
92
  function orderer(source, salt) {
92
93
  const forked = source.fork(salt);
93
- const root = forked.toRoot();
94
+ const trace = forked.toConstructionTrace();
94
95
  const stream = toStreamFromTrace(forked.algorithm, {
95
- ...root,
96
+ ...trace,
96
97
  path: [],
97
98
  kind: "order"
98
99
  });
@@ -1,10 +1,11 @@
1
1
  import { FabricatorError } from "../Error/index.js";
2
+ import { toInnermostFrame } from "../Instance/Stack/Visible.js";
2
3
  import { Primitive } from "../Primitive/index.js";
3
4
  import { isLayered, normalizeSalt } from "../Random/index.js";
4
5
  import { toSchema } from "../Schema/Core.js";
5
6
  import { Adaptation, Fixed, Kind, Layer, Meta } from "../Types.js";
6
7
  import { inline } from "../Utility/Core.js";
7
- function Constructor(source, stack) {
8
+ function Constructor(source, stack, ancestry) {
8
9
  function make(schema, path, context) {
9
10
  schema = toSchema(schema);
10
11
  const kind = schema[Kind];
@@ -280,7 +281,7 @@ function Constructor(source, stack) {
280
281
  function construct(schema, options = {}) {
281
282
  var _options_path;
282
283
  if ("string" == typeof options.kind && options.kind !== schema[Kind]) throw new FabricatorError.TraceKindMismatchError(schema[Kind], options.kind);
283
- const context = toConstructionContext(source, options, stack);
284
+ const context = toConstructionContext(source, options, stack, ancestry);
284
285
  const made = make(schema, null != (_options_path = options.path) ? _options_path : [], context);
285
286
  const adaptations = schema[Adaptation];
286
287
  return adaptations ? {
@@ -290,21 +291,21 @@ function Constructor(source, stack) {
290
291
  }
291
292
  return construct;
292
293
  }
293
- function toConstructionContext(source, options, stack) {
294
- const { source: rooted, root: construction } = resolveScope(source, options, stack);
294
+ function toConstructionContext(source, options, stack, ancestry) {
295
+ const { source: resolved, trace } = resolveScope(source, options, stack, ancestry);
295
296
  return {
296
297
  toTrace: (path, kind)=>({
297
- ...construction,
298
+ ...trace,
298
299
  path,
299
300
  kind
300
301
  }),
301
- algorithm: rooted.algorithm
302
+ algorithm: resolved.algorithm
302
303
  };
303
304
  }
304
- function resolveScope(source, options, stack) {
305
+ function resolveScope(source, options, stack, ancestry) {
305
306
  var _ref;
306
- const frame = stack.current();
307
- const base = null != (_ref = null == frame ? void 0 : frame.source) ? _ref : source;
307
+ var _toInnermostFrame;
308
+ const base = null != (_ref = null == (_toInnermostFrame = toInnermostFrame(stack, ancestry)) ? void 0 : _toInnermostFrame.source) ? _ref : source;
308
309
  const salt = inline(()=>{
309
310
  if (!options.salt) return;
310
311
  if (isLayered(options.salt)) return [
@@ -320,7 +321,7 @@ function resolveScope(source, options, stack) {
320
321
  };
321
322
  return {
322
323
  source: base,
323
- root: base.toRoot(pins)
324
+ trace: base.toConstructionTrace(pins)
324
325
  };
325
326
  }
326
327
  export { Constructor };
@@ -5,6 +5,7 @@ import { defaultAlgorithm, deriveClock, isLayered, normalizeSalt, toRandomSource
5
5
  import { registry } from "../Schema/Registry.js";
6
6
  import { Layer } from "../Types.js";
7
7
  import { inline, isThenable, noop } from "../Utility/Core.js";
8
+ import { toInnermostFrame } from "./Stack/Visible.js";
8
9
  const DEFAULT_COMBINATORIAL_LIMIT = 1024;
9
10
  function resolveCombinatorialLimit(limit) {
10
11
  if (void 0 === limit) return DEFAULT_COMBINATORIAL_LIMIT;
@@ -14,6 +15,9 @@ function resolveCombinatorialLimit(limit) {
14
15
  function resolveClock(config) {
15
16
  return "number" == typeof config.clock ? config.clock : deriveClock(config.algorithm, normalizeSalt(config.salt));
16
17
  }
18
+ function mint() {
19
+ return Symbol("fabricator.instance");
20
+ }
17
21
  function overlay(base, over) {
18
22
  var _ref, _over_algorithm, _ref1, _over_types, _over_limits;
19
23
  var _this;
@@ -41,26 +45,40 @@ function overlay(base, over) {
41
45
  }
42
46
  };
43
47
  }
44
- function instantiate(config, stack) {
48
+ function instantiate(config, stack, parent) {
49
+ const ancestry = void 0 === parent ? [
50
+ mint()
51
+ ] : [
52
+ ...parent.ancestry,
53
+ mint()
54
+ ];
45
55
  const source = toRandomSource({
46
56
  salt: config.salt,
47
57
  algorithm: config.algorithm,
48
58
  clock: resolveClock(config)
49
59
  });
50
- const Fabricator = Constructor(source, stack);
51
- const { combinatorial, coverage } = enumerables(source, config.limits, stack);
60
+ const Fabricator = Constructor(source, stack, ancestry);
61
+ const { combinatorial, coverage } = enumerables(source, config.limits, stack, ancestry);
62
+ function derive(over) {
63
+ const derived = overlay(config, over);
64
+ return {
65
+ ...instantiate(derived, stack, {
66
+ ancestry,
67
+ root: instance.root
68
+ }),
69
+ config: derived
70
+ };
71
+ }
52
72
  function fork(forkOverlay = {}) {
53
- return instantiate(overlay(config, forkOverlay), stack).instance;
73
+ return derive(forkOverlay).instance;
54
74
  }
55
75
  function wrap(wrapOverlay, block) {
56
- var _ref;
57
- var _stack_current;
58
- const base = null != (_ref = null == (_stack_current = stack.current()) ? void 0 : _stack_current.config) ? _ref : config;
59
- const scopedConfig = overlay(base, wrapOverlay);
60
- const scoped = instantiate(scopedConfig, stack);
76
+ const scoped = derive(wrapOverlay);
61
77
  const result = stack.enter({
62
- config: scopedConfig,
63
- source: scoped.source
78
+ config: scoped.config,
79
+ source: scoped.source,
80
+ instance: scoped.instance,
81
+ ancestry
64
82
  }, ()=>block(scoped.instance));
65
83
  if (!stack.asynchronous && isThenable(result)) {
66
84
  result.then(noop, noop);
@@ -68,25 +86,41 @@ function instantiate(config, stack) {
68
86
  }
69
87
  return result;
70
88
  }
89
+ function visibleFrame() {
90
+ return toInnermostFrame(stack, ancestry);
91
+ }
71
92
  const context = {
72
93
  get salt () {
73
94
  var _ref;
74
- var _stack_current;
75
- return normalizeSalt((null != (_ref = null == (_stack_current = stack.current()) ? void 0 : _stack_current.config) ? _ref : config).salt);
95
+ var _visibleFrame;
96
+ return normalizeSalt((null != (_ref = null == (_visibleFrame = visibleFrame()) ? void 0 : _visibleFrame.config) ? _ref : config).salt);
76
97
  },
77
98
  get algorithm () {
78
99
  var _ref1;
79
- var _stack_current1;
80
- return (null != (_ref1 = null == (_stack_current1 = stack.current()) ? void 0 : _stack_current1.config) ? _ref1 : config).algorithm;
100
+ var _visibleFrame1;
101
+ return (null != (_ref1 = null == (_visibleFrame1 = visibleFrame()) ? void 0 : _visibleFrame1.config) ? _ref1 : config).algorithm;
81
102
  },
82
103
  get clock () {
83
104
  var _ref2;
84
- var _stack_current2;
85
- return resolveClock(null != (_ref2 = null == (_stack_current2 = stack.current()) ? void 0 : _stack_current2.config) ? _ref2 : config);
105
+ var _visibleFrame2;
106
+ return resolveClock(null != (_ref2 = null == (_visibleFrame2 = visibleFrame()) ? void 0 : _visibleFrame2.config) ? _ref2 : config);
107
+ },
108
+ scope: ()=>{
109
+ var _ref;
110
+ var _visibleFrame;
111
+ return null != (_ref = null == (_visibleFrame = visibleFrame()) ? void 0 : _visibleFrame.instance) ? _ref : instance;
112
+ },
113
+ get depth () {
114
+ return stack.visible(ancestry).length;
86
115
  }
87
116
  };
88
117
  const instance = {
89
118
  T: config.types,
119
+ ancestry,
120
+ get root () {
121
+ var _ref3;
122
+ return null != (_ref3 = null == parent ? void 0 : parent.root) ? _ref3 : instance;
123
+ },
90
124
  Fabricator,
91
125
  combinatorial,
92
126
  coverage,
@@ -1,10 +1,18 @@
1
1
  import { AsyncLocalStorage } from "async_hooks";
2
+ import { toVisible } from "./Visible.js";
2
3
  function toStack() {
3
4
  const store = new AsyncLocalStorage();
5
+ const getFrames = ()=>{
6
+ var _store_getStore;
7
+ return null != (_store_getStore = store.getStore()) ? _store_getStore : [];
8
+ };
4
9
  return {
5
10
  asynchronous: true,
6
- current: ()=>store.getStore(),
7
- enter: (frame, block)=>store.run(frame, block)
11
+ visible: (ancestry)=>toVisible(getFrames(), ancestry),
12
+ enter: (frame, block)=>store.run([
13
+ ...getFrames(),
14
+ frame
15
+ ], block)
8
16
  };
9
17
  }
10
18
  export { toStack };
@@ -1,8 +1,9 @@
1
+ import { toVisible } from "./Visible.js";
1
2
  function toStack() {
2
3
  const frames = [];
3
4
  return {
4
5
  asynchronous: false,
5
- current: ()=>frames[frames.length - 1],
6
+ visible: (ancestry)=>toVisible(frames, ancestry),
6
7
  enter: (frame, block)=>{
7
8
  frames.push(frame);
8
9
  try {
@@ -0,0 +1,13 @@
1
+ function onDirectLine(a, b) {
2
+ const shared = Math.min(a.length, b.length);
3
+ for(let index = 0; index < shared; index++)if (a[index] !== b[index]) return false;
4
+ return true;
5
+ }
6
+ function toVisible(frames, ancestry) {
7
+ return frames.filter((frame)=>onDirectLine(frame.ancestry, ancestry));
8
+ }
9
+ function toInnermostFrame(stack, ancestry) {
10
+ const frames = stack.visible(ancestry);
11
+ return frames[frames.length - 1];
12
+ }
13
+ export { toInnermostFrame, toVisible };
@@ -10,7 +10,7 @@ function Fabricator(context, forkSource, make) {
10
10
  function fabricateAt(depth) {
11
11
  const atMax = depth >= meta.depth.max;
12
12
  const target = atMax ? meta.terminal : meta.body;
13
- const construction = privateSource.toRoot();
13
+ const construction = privateSource.toConstructionTrace();
14
14
  const context = {
15
15
  toTrace: (path, kind)=>({
16
16
  ...construction,
@@ -71,7 +71,7 @@ function toRandomSource(options) {
71
71
  let algorithm = null != (_options_algorithm = options.algorithm) ? _options_algorithm : defaultAlgorithm;
72
72
  const clock = options.clock;
73
73
  let constructionOrdinal = 0;
74
- function toRoot(pins = {}) {
74
+ function toConstructionTrace(pins = {}) {
75
75
  var _pins_salt, _pins_clock;
76
76
  return {
77
77
  salt: null != (_pins_salt = pins.salt) ? _pins_salt : salt,
@@ -87,7 +87,7 @@ function toRandomSource(options) {
87
87
  });
88
88
  }
89
89
  return {
90
- toRoot,
90
+ toConstructionTrace,
91
91
  algorithm,
92
92
  salt,
93
93
  fork
@@ -1,25 +1,25 @@
1
- import type { Stack } from "../Instance/Types";
1
+ import type { Ancestry, Stack } from "../Instance/Types";
2
2
  import type { RandomSource } from "../Random/Types";
3
3
  import type { Enumerable, Limits } from "./Types";
4
4
  /**
5
5
  * Typed `combinatorial`/`coverage` boundary, closing over one instance's
6
6
  * `source` and its already-validated `limits` — same shape as
7
- * `Constructor(source, stack)`. No separate `clock`: `source` already carries
7
+ * `Constructor(source, stack, ancestry)`. No separate `clock`: `source` carries
8
8
  * its resolved clock (`Random/Types.ts`'s `Options.clock`), so `Constructor`'s
9
- * `toConstructionContext` reads it off whichever root a construction resolves
10
- * against. `plan`/ `resolve` (`./Plan.ts`) do the untyped recursive work; this
11
- * is the one precisely-typed layer, mirroring `Constructor.ts`'s `make`/
12
- * `construct` split.
9
+ * `toConstructionContext` reads it off the resolved `ConstructionTrace`.
10
+ * `plan`/ `resolve` (`./Plan.ts`) do the untyped recursive work; this is the
11
+ * one precisely-typed layer, mirroring `Constructor.ts`'s `make`/`construct`
12
+ * split.
13
13
  *
14
14
  * Two derived salts — one per API — each composed from the _effective_ source's
15
- * salt (`effectiveSource()` below — the active `wrap` frame's, or this
16
- * instance's `source`; read fresh on every `combinatorial(...)`/`coverage(...)`
17
- * call, not once when `enumerables()` was built, so the same `combinatorial`
18
- * reference behaves differently inside an active `wrap`). Each build pins that
19
- * salt via `new Fabricator(schema, { salt })` (see `Constructor.ts`'s
20
- * `construct()`) — a pin, not a fork — so every rebuild of one schema draws
21
- * from the same universe, distinct from anything built under the instance's own
22
- * salt.
15
+ * salt (`effectiveSource()` below — the innermost visible `wrap` frame's, or
16
+ * this instance's `source`; read fresh on every
17
+ * `combinatorial(...)`/`coverage(...)` call, not once when `enumerables()` was
18
+ * built, so the same `combinatorial` reference behaves differently inside a
19
+ * `wrap` this instance can see). Each build pins that salt via `new
20
+ * Fabricator(schema, { salt })` (see `Constructor.ts`'s `construct()`) — a pin,
21
+ * not a fork so every rebuild of one schema draws from the same universe,
22
+ * distinct from anything built under the instance's own salt.
23
23
  *
24
24
  * `ordinal: null` is pinned alongside it, and is not incidental: a salt says
25
25
  * nothing about ordering, so without this pin each lazy rebuild would take the
@@ -29,7 +29,7 @@ import type { Enumerable, Limits } from "./Types";
29
29
  * every iteration rebuilds from the same explicit identity, and the `null` can
30
30
  * never coincide with a counted construction.
31
31
  */
32
- export declare function enumerables(source: RandomSource, limits: Limits, stack: Stack): {
32
+ export declare function enumerables(source: RandomSource, limits: Limits, stack: Stack, ancestry: Ancestry): {
33
33
  combinatorial: Enumerable;
34
34
  coverage: Enumerable;
35
35
  };
@@ -1,4 +1,4 @@
1
- import type { Stack } from "../Instance/Types";
1
+ import type { Ancestry, Stack } from "../Instance/Types";
2
2
  import type { ConstructorOptions, RandomSource } from "../Random/Types";
3
3
  import { type Buildable } from "../Types";
4
4
  import { type AsFabricator } from "./Types";
@@ -25,17 +25,20 @@ export type Constructor = {
25
25
  * fabricator this `construct()` produces draws from that instance's own
26
26
  * salt/streams and never another instance's.
27
27
  *
28
- * `stack` is the instance's own lineage-wide ambient stack
29
- * (`Instance/Core.ts`'s `toStack()`) — passed straight through to
28
+ * `stack` is the ambient carrier and `ancestry` is this instance's position in
29
+ * its lineage (`Instance/Core.ts`) — both passed straight through to
30
30
  * `resolveScope` on every `construct()` call, never read here directly, so a
31
- * build reached inside an active `wrap` resolves against that frame
32
- * automatically, with nothing threaded through by the caller.
31
+ * build reached inside a `wrap` this instance can see resolves against that
32
+ * frame automatically, with nothing threaded through by the caller. `ancestry`
33
+ * is what decides "can see": a frame entered on a sibling instance is not one
34
+ * this `construct()` will ever resolve against.
33
35
  *
34
36
  * No separate `clock` parameter: `source` already carries its own resolved
35
37
  * clock intrinsically (`Random/Types.ts`'s `Options.clock`, baked in when the
36
38
  * source was built), and `resolveScope`'s chosen source — the active `wrap`
37
39
  * frame's, or this one — is exactly the source whose clock a construction
38
40
  * should resolve "now" against. `toConstructionContext` reads it straight off
39
- * the resolved root rather than threading a second value alongside `source`.
41
+ * the resolved construction trace rather than threading a second value
42
+ * alongside `source`.
40
43
  */
41
- export declare function Constructor(source: RandomSource, stack: Stack): Constructor;
44
+ export declare function Constructor(source: RandomSource, stack: Stack, ancestry: Ancestry): Constructor;
@@ -14,19 +14,20 @@ import type { PlainObject } from "../Utility/Types";
14
14
  * `toTrace` records this node's {@link Trace} — a plain object literal, no
15
15
  * hashing. Hashing is paid only where a kind actually calls
16
16
  * `toStreamFromTrace(algorithm, trace)`. Bound once in `construct()` to this
17
- * one construction's already-resolved `RandomSource`/ `ConstructionTrace` pair
17
+ * one construction's already-resolved `RandomSource`/`ConstructionTrace` pair
18
18
  * (see `Constructor.ts`'s `resolveScope`) — every leaf calls `toTrace` with
19
19
  * only its own structural `path` and kind, never re-resolving the
20
- * construction's root itself. `T.recursive` is the one kind that rebinds
21
- * `toTrace`: each lazy expansion opens its own scope on the node's own private
22
- * forked `RandomSource` (see `recursive/Fabricator.ts`), so a data-dependent
23
- * expansion count can never perturb, or be perturbed by, anything else built
24
- * from the same `initialize()` instance — `RandomSource.fork`
25
- * (`Random/Types.ts`) is the isolation primitive.
20
+ * construction-owned slots itself. `T.recursive` is the one kind that rebinds
21
+ * `toTrace`: each lazy expansion resolves its construction trace on the node's
22
+ * own private forked `RandomSource` (see `recursive/Fabricator.ts`), so a
23
+ * data-dependent expansion count can never perturb, or be perturbed by,
24
+ * anything else built from the same `initialize()` instance —
25
+ * `RandomSource.fork` (`Random/Types.ts`) is the isolation primitive.
26
26
  *
27
27
  * `algorithm` rather than the `RandomSource` itself: stream derivation depends
28
- * on no per-source state, and a leaf has no business with `toRoot`/`fork`.
29
- * `clock` is not a field of its own — it is always `trace.clock`.
28
+ * on no per-source state, and a leaf has no business with
29
+ * `toConstructionTrace`/`fork`. `clock` is not a field of its own — it is
30
+ * always `trace.clock`.
30
31
  *
31
32
  * `self` is what makes `case "recursive.self"` resolve to "recurse one level
32
33
  * deeper, right now" — absent outside any active recursion, which is how `case
@@ -47,11 +48,11 @@ export type ConstructionContext = {
47
48
  * `toStreamFromTrace(algorithm, trace)`. The guard is the call site's own `if
48
49
  * (meta.produce)` branch (or the equivalent drawing path), not an unevaluated
49
50
  * closure. `algorithm` rather than the `RandomSource`: derivation depends on no
50
- * per-source state, and a leaf has no business with `toRoot`/`fork`. No
51
- * `clock`: it is `trace.clock`, always. A kind-specific extra — an array's
52
- * `element`, an object's `fields`, a choice's `weightings` — still follows as
53
- * its own trailing parameter: those vary per kind and were never part of the
54
- * shared prefix this replaces.
51
+ * per-source state, and a leaf has no business with
52
+ * `toConstructionTrace`/`fork`. No `clock`: it is `trace.clock`, always. A
53
+ * kind-specific extra — an array's `element`, an object's `fields`, a choice's
54
+ * `weightings` — still follows as its own trailing parameter: those vary per
55
+ * kind and were never part of the shared prefix this replaces.
55
56
  */
56
57
  export type FabricatorContext<$Schema> = {
57
58
  schema: $Schema;
@@ -1,6 +1,6 @@
1
1
  import type { RandomSource } from "../Random/Types";
2
2
  import type { PlainObject } from "../Utility/Types";
3
- import type { Config, Instance, Overlay, Stack } from "./Types";
3
+ import type { Ancestry, Config, Instance, Overlay, Stack } from "./Types";
4
4
  /**
5
5
  * `combinatorial`'s default limit — `2**10`, so it admits ten independent
6
6
  * binary axes before requiring the caller to raise it explicitly. Each
@@ -51,12 +51,23 @@ export declare function overlay<$Registry extends PlainObject>(base: Partial<Con
51
51
  * than each independently re-deriving one from the same config (and so silently
52
52
  * diverging/duplicating construction ordinals).
53
53
  *
54
- * `stack` is threaded straight through to `Constructor`/`enumerables` — this
55
- * function never reads or writes it itself, only passes it along so every built
56
- * `Fabricator`/`combinatorial`/`coverage` can consult whichever frame is active
57
- * _at the moment each is called_, not at this moment.
54
+ * `stack` and `ancestry` are threaded straight through to
55
+ * `Constructor`/`enumerables` — this function never reads the stack itself,
56
+ * only passes both along so every built `Fabricator`/`combinatorial`/`coverage`
57
+ * can consult whichever frame is visible to _this_ instance _at the moment each
58
+ * is called_, not at this moment.
59
+ *
60
+ * `parent` describes the instance this one is derived from, and its absence is
61
+ * the single marker of a root: `initialize` passes none, every `fork`/`wrap`
62
+ * passes the receiver's.
63
+ *
64
+ * A fresh token is minted either way, so no two instances share an identity,
65
+ * and the `ancestry` built here is _this_ instance's: the parent's plus one.
58
66
  */
59
- export declare function instantiate<$Registry extends PlainObject>(config: Config<$Registry>, stack: Stack): {
67
+ export declare function instantiate<$Registry extends PlainObject>(config: Config<$Registry>, stack: Stack, parent?: {
68
+ ancestry: Ancestry;
69
+ root: Instance<PlainObject>;
70
+ }): {
60
71
  instance: Instance<$Registry>;
61
72
  source: RandomSource;
62
73
  };
@@ -7,6 +7,13 @@ import type { Stack } from "../Types";
7
7
  * package importable on a runtime with no `node:async_hooks` while every
8
8
  * runtime that has one gets async-safe `wrap` with nothing to configure.
9
9
  *
10
+ * The store holds the whole open chain, not one `Frame`: `run` _replaces_ the
11
+ * store for the duration of `block`, so `enter` rebuilds the chain with the new
12
+ * frame appended. A fresh array per `enter` is also what isolates concurrent
13
+ * `wrap`s — each async context keeps the chain it entered with, and an inner
14
+ * `enter` cannot mutate an outer one's view. Chains are at nesting depth, so
15
+ * copying one costs nothing worth avoiding.
16
+ *
10
17
  * `AsyncLocalStorage.run` returns whatever `block` returns, so this satisfies
11
18
  * `enter`'s sync-preserving `<$Return>` signature exactly as the sync carrier
12
19
  * does — a synchronous `wrap` is unaffected by which carrier is in play.
@@ -1,13 +1,15 @@
1
1
  import type { Stack } from "../Types";
2
2
  /**
3
3
  * The synchronous carrier: a private `Frame[]`, pushed on `enter` and popped in
4
- * a `finally` — correct even around a `throw` from `block`.
4
+ * a `finally` — correct even around a `throw` from `block`. Already in
5
+ * outermost-first order, which is the order `visible` reports, so it hands the
6
+ * array straight to `toVisible` and does no filtering of its own.
5
7
  *
6
8
  * Selected by the `#stack` `default` condition (`package.json`), i.e. on any
7
9
  * runtime without `node:async_hooks` — in practice a browser bundle. Its frame
8
10
  * cannot survive an `await`: `enter` returns `block()` without awaiting, so an
9
- * async block's frame unwinds at the block's first suspension point, and a
10
- * shared LIFO could not represent two overlapping scopes even if it did await.
11
+ * async block's frame unwinds at the block's first suspension point, and one
12
+ * shared array could not represent two overlapping scopes even if it did await.
11
13
  * Both are why `asynchronous` is `false` and `wrap` refuses an async block here
12
14
  * rather than resolving it against the base instance with no signal.
13
15
  */
@@ -0,0 +1,22 @@
1
+ import type { Ancestry, Frame, Stack } from "../Types";
2
+ /**
3
+ * The frames in `frames` that `ancestry` may resolve against, outermost first —
4
+ * the single definition of {@link Stack.visible}'s rule, which both carriers
5
+ * delegate to so neither can drift from the other. A carrier's own job is
6
+ * reduced to holding the chain in whatever way its runtime allows.
7
+ *
8
+ * Order is preserved rather than reduced to the innermost match, because the
9
+ * count is `context.depth` and the innermost is just the last element.
10
+ * Skipping, rather than stopping at, the first invisible frame is the outward
11
+ * walk: with a parent's `wrap` open and a child's nested inside it, that
12
+ * child's sibling must pass over the inner frame and still resolve against the
13
+ * outer one.
14
+ */
15
+ export declare function toVisible(frames: ReadonlyArray<Frame>, ancestry: Ancestry): ReadonlyArray<Frame>;
16
+ /**
17
+ * The one frame a read resolves against: the innermost frame visible to
18
+ * `ancestry`, or `undefined` outside any. Every consumer — `resolveScope`,
19
+ * `effectiveSource`, the `context` getters — goes through here rather than
20
+ * indexing `visible()` itself, so "innermost visible" has one definition.
21
+ */
22
+ export declare function toInnermostFrame(stack: Stack, ancestry: Ancestry): Frame | undefined;
@@ -47,27 +47,77 @@ export type Overlay<$Registry extends PlainObject> = Partial<Omit<Config<$Regist
47
47
  readonly salt?: Salt | Layered;
48
48
  readonly clock?: Date | "derived" | undefined;
49
49
  };
50
+ declare const Brand: unique symbol;
51
+ /**
52
+ * One instance's identity — minted fresh by every `instantiate`
53
+ * (`Instance/Core.ts`) and never equal to any other. Branded, and the brand key
54
+ * is module-private, so a token cannot be forged from outside this package: the
55
+ * only way to hold one is to have been handed an `Instance`.
56
+ */
57
+ export type Token = symbol & {
58
+ readonly [Brand]: "Instance";
59
+ };
60
+ /**
61
+ * Where an instance sits in its lineage: every token from the root down to and
62
+ * including its own, so `ancestry[0]` is the lineage identity (`a.ancestry[0]
63
+ * === b.ancestry[0]` answers "same root?") and the last element is the instance
64
+ * itself. Non-empty by construction — a root `initialize()` mints one token
65
+ * before there is anything to inherit.
66
+ *
67
+ * Derived from the _receiver_: `fork` and `wrap` alike append to the ancestry
68
+ * of the instance they were called on, exactly as they both lay their overlay
69
+ * over that instance's `config`. One rule, so an instance's position and its
70
+ * configuration always agree about who its parent is.
71
+ *
72
+ * Two chains describe instances on the same ancestral line when either is a
73
+ * prefix of the other, which is what {@link Stack.visible} tests. That relation
74
+ * decides whose calls resolve against whose frames: a parent's calls resolve
75
+ * against a child's frame and a child's against a parent's, while two siblings
76
+ * resolve against neither's. Note this never crosses lineages, and not for want
77
+ * of identity — two roots hold two separate carriers, so a `wrap` on one pushes
78
+ * where the other's reads never look.
79
+ */
80
+ export type Ancestry = readonly [Token, ...ReadonlyArray<Token>];
50
81
  /**
51
82
  * One active `wrap` — its resolved config plus the single `RandomSource` every
52
83
  * build reached inside that `wrap` shares, whether reached implicitly (any
53
- * instance in the lineage consulting the active frame) or explicitly
84
+ * instance on the origin's ancestral line consulting the frame) or explicitly
54
85
  * (`scope.Fabricator`, the `Instance` passed to the block). Storing the scope's
55
86
  * own already-built `source` here, rather than each consumer re-deriving one
56
87
  * from `config`, keeps the two routes resolving against the _same_ source —
57
88
  * sharing one set of construction-ordinal counters — instead of each silently
58
89
  * starting its own.
90
+ *
91
+ * `instance` is that same scope, kept so `context.scope()` can hand back the
92
+ * configuration in effect as a usable `Instance` rather than only as its
93
+ * separate `salt`/`algorithm`/`clock` fields.
94
+ *
95
+ * `ancestry` is the **origin's** — the instance `wrap` was called on — not the
96
+ * scope's. The scope is a fresh child of the origin, so keying on it would make
97
+ * every `fork` taken off that origin a _sibling_ of the scope, and calls on
98
+ * those forks would stop resolving against the frame. Keying on the origin
99
+ * keeps everything on the origin's own line resolving against it, which is the
100
+ * whole point of entering one.
59
101
  */
60
102
  export type Frame = {
61
103
  readonly config: Config<PlainObject>;
62
104
  readonly source: RandomSource;
105
+ readonly instance: Instance<PlainObject>;
106
+ readonly ancestry: Ancestry;
63
107
  };
64
108
  /**
65
- * The per-lineage ambient stack. Created once at a root `initialize()` and
66
- * threaded — never re-created — through every `fork`/`wrap` descended from it
67
- * (see `instantiate`, `Instance/Core.ts`). Two unrelated `initialize()` calls
68
- * stay fully isolated; one lineage's `wrap` reaches every instance in that
69
- * lineage its `Fabricator`, `combinatorial`, and `coverage` alike
70
- * regardless of where in the lineage that instance was itself created.
109
+ * The ambient frame carrier. Created once at a root `initialize()` and threaded
110
+ * — never re-created — through every `fork`/`wrap` descended from it (see
111
+ * `instantiate`, `Instance/Core.ts`).
112
+ *
113
+ * A carrier holds a chain of open frames and nothing else; which of them any
114
+ * given reader may see is {@link Ancestry}'s business, resolved by
115
+ * {@link visible}. Two unrelated `initialize()` calls hold separate carriers
116
+ * and so stay fully isolated — and because a reader is now gated on ancestry
117
+ * rather than on carrier identity, handing the _same_ carrier to two
118
+ * `initialize()` calls does not join them either: their roots mint unrelated
119
+ * tokens, so neither one's reads ever resolve the other's frames. `initialize({
120
+ * stack })` is therefore purely a choice of carrier.
71
121
  */
72
122
  export type Stack = {
73
123
  /**
@@ -80,24 +130,71 @@ export type Stack = {
80
130
  * instance. See `Instance/Stack/Sync.ts` and `Instance/Stack/Async.ts`.
81
131
  */
82
132
  readonly asynchronous: boolean;
83
- current(): Frame | undefined;
84
133
  /**
85
- * Push `frame`, run `block`, pop in a `finally`, so a frame unwinds
86
- * correctly even if `block` throws.
134
+ * Every open frame `ancestry` may resolve against, outermost first: those
135
+ * whose own `ancestry` is a prefix of this one or has this one as a prefix.
136
+ * The innermost visible frame — what a build or a `context` read actually
137
+ * resolves against — is the last element, and the count is `context.depth`.
138
+ *
139
+ * Filtering, rather than simply reporting the innermost frame, is what makes
140
+ * the outward walk possible: with a parent's `wrap` open and a child's nested
141
+ * inside it, the child's _sibling_ must skip the inner frame and still find
142
+ * the outer one. Callers never filter themselves — `toVisible`
143
+ * (`Instance/Stack/Visible.ts`) is the single definition both carriers
144
+ * delegate to, so the rule cannot drift between them.
145
+ */
146
+ visible(ancestry: Ancestry): ReadonlyArray<Frame>;
147
+ /**
148
+ * Append `frame`, run `block`, remove it in a `finally`, so a frame unwinds
149
+ * correctly even if `block` throws. Appends rather than replaces: the chain
150
+ * has to stay intact for {@link visible} to walk outward past a frame this
151
+ * reader cannot see.
87
152
  */
88
153
  enter<$Return>(frame: Frame, block: () => $Return): $Return;
89
154
  };
90
155
  /**
91
- * The configuration in effect _right now_ — the innermost active `wrap` frame,
92
- * or this instance's own when there is none. Distinct from
93
- * `ConstructionContext` (`Fabricator/Types.ts`), which is one construction's
94
- * internal dispatch plumbing; this is the caller-facing "what configuration is
95
- * in effect."
156
+ * What is in effect _right now_ — the innermost `wrap` frame this instance's
157
+ * calls can resolve against, or the instance itself when there is none.
158
+ *
159
+ * The four value properties are getters, so they are a live view only while
160
+ * this stays an object: destructuring one, or spreading the object, calls that
161
+ * getter once and freezes the result.
162
+ *
163
+ * {@link Context.scope} is deliberately a **function** rather than another
164
+ * getter: it is the one member a caller _acts through_ rather than reads, so
165
+ * freezing it would yield correct-looking code deriving from the wrong base. As
166
+ * a function it survives destructuring — `const { scope } = instance.context`,
167
+ * then `scope()`, still resolves live. Distinct from `ConstructionContext`
168
+ * (`Fabricator/Types.ts`), which is one construction's internal dispatch
169
+ * plumbing; this is the caller-facing "what is in effect."
96
170
  */
97
171
  export type Context = {
98
172
  readonly salt: ReadonlyArray<string>;
99
173
  readonly algorithm: Algorithm;
100
174
  readonly clock: number;
175
+ /**
176
+ * The configuration in effect as an `Instance` — the visible frame's own
177
+ * scope, or this instance outside any. This is how to compose deliberately
178
+ * against whatever is active: `context.scope().wrap({ salt: layer("x") },
179
+ * ...)` lays over the frame in effect, where a plain `wrap` lays over the
180
+ * instance it was called on. Unlike rebuilding an overlay out of `salt` by
181
+ * hand, it carries `types`, `limits`, `algorithm` and `clock` across too.
182
+ *
183
+ * A function, not a getter, so capturing it captures the _lookup_ rather than
184
+ * one answer (see this type's own note above). What it returns is an ordinary
185
+ * `Instance`, fixed like any other — so holding the **result** across a frame
186
+ * change is a caller stating they wanted that one, while holding `scope`
187
+ * itself stays live.
188
+ */
189
+ scope(): Instance<PlainObject>;
190
+ /**
191
+ * How many frames are currently visible to this instance — 0 outside any.
192
+ * Genuine dynamic nesting depth, counted off the carrier rather than inferred
193
+ * from {@link Ancestry}: a frame a sibling cannot see is not counted for that
194
+ * sibling, and entering two `wrap`s on one instance reads as 2 even though
195
+ * neither deepened anyone's ancestry.
196
+ */
197
+ readonly depth: number;
101
198
  };
102
199
  /**
103
200
  * A single initialized library instance: the registry it was given, and a
@@ -109,6 +206,49 @@ export type Context = {
109
206
  export interface Instance<$Registry extends PlainObject> extends Pick<RandomSource, "salt"> {
110
207
  /** The registry of type definers this instance was initialized with. */
111
208
  readonly T: $Registry;
209
+ /**
210
+ * This instance's position in its lineage — see {@link Ancestry}. Exposed so a
211
+ * caller can reason about which frames a given instance's calls resolve
212
+ * against; the tokens themselves are opaque and comparable only by identity.
213
+ * For the ordinary "same lineage?" question, compare {@link root} instead.
214
+ */
215
+ readonly ancestry: Ancestry;
216
+ /**
217
+ * The instance at the head of this lineage — the one `initialize()` returned.
218
+ * A root's own `root` is itself, so this is never `undefined` and no caller
219
+ * handles absence.
220
+ *
221
+ * Its job is identity: `a.root === b.root` answers "same lineage?", which is
222
+ * what `fork`/`wrap` descent preserves and what two separate `initialize()`
223
+ * calls never share — even when handed the same `stack`.
224
+ *
225
+ * It is **not** a way to reach "the ambient instance": every instance in a
226
+ * lineage resolves against the frames on its own line, so there is nothing to
227
+ * reach for. Nor is it a configuration to build against in preference to this
228
+ * one — `root`'s config is the lineage's starting point, not whatever is
229
+ * currently in effect. For that, see {@link Context.scope}.
230
+ *
231
+ * Typed at `PlainObject`, which is a deliberate shortcut rather than a
232
+ * necessity — unlike {@link Context.scope}, whose registry depends on which
233
+ * instance entered the innermost visible frame and so cannot be known
234
+ * statically at all.
235
+ *
236
+ * A root's registry is fixed at `initialize` and nothing later disturbs it: a
237
+ * `fork({ types })` mints a _new_ instance with a different registry and
238
+ * leaves the root exactly as it was. What is lost is the descendant's ability
239
+ * to name it — after such a fork this instance's `$Registry` is the fork's,
240
+ * so the root's is no longer recoverable from it. Typing this
241
+ * `Instance<$Registry>` would therefore be wrong if someone overrode
242
+ * `types`.
243
+ *
244
+ * Recovering it would mean threading a second parameter (`Instance<$Registry,
245
+ * $Root>`) through `fork` and `wrap`, which is a poor trade for an accessor
246
+ * whose job is identity: if you mean to _build_, you want the registry of the
247
+ * instance you are holding, not the one the lineage started from. So `root.T`
248
+ * is untyped, while `root.Fabricator` is unaffected since it carries no
249
+ * registry parameter.
250
+ */
251
+ readonly root: Instance<PlainObject>;
112
252
  /**
113
253
  * Turn a Schema built from `T` into a live Fabricator, deriving fresh
114
254
  * randomness from this instance's own salt for whichever leaves actually need
@@ -147,10 +287,19 @@ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSour
147
287
  * — a build reached after an `await` inside `block` sees this instance's own
148
288
  * configuration again, not the wrap's.
149
289
  *
150
- * A nested `wrap` lays over whichever frame is currently active, not over the
151
- * instance it was called on so `overlay.salt: layer(...)` accumulates with
152
- * nesting depth while a bare `salt` still replaces outright, discarding every
153
- * enclosing layer.
290
+ * The overlay lays over _this instance's_ config, exactly as `fork`'s does,
291
+ * whether or not a frame is already open. So a nested `wrap` accumulates when
292
+ * it is called on the enclosing scope `wrap(a, (scope) => scope.wrap(b,
293
+ * ...))` — and restates from this instance when it is called on a receiver
294
+ * bound outside, as a destructured `wrap` is. To compose onto whatever is
295
+ * active regardless of receiver, go through `context.scope().wrap(...)`.
296
+ *
297
+ * While the block runs, calls made on this instance's ancestral line resolve
298
+ * against the scope — its forks, their forks, and its own ancestors up to the
299
+ * root. Calls on a _sibling_ do not: a frame entered on one `fork` is not one
300
+ * that another `fork` of the same parent can resolve against, which keeps two
301
+ * unrelated derivations from drawing each other's data. See
302
+ * {@link Ancestry}.
154
303
  */
155
304
  wrap<$Return, const $WrapRegistry extends PlainObject = $Registry>(overlay: Overlay<$WrapRegistry>, block: (scope: Instance<$WrapRegistry>) => $Return): $Return;
156
305
  /**
@@ -161,3 +310,4 @@ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSour
161
310
  */
162
311
  readonly context: Context;
163
312
  }
313
+ export {};
@@ -28,14 +28,13 @@ export type Fabricator<$Schema extends {
28
28
  * how deep this `fabricate()` goes — so no structural path distinguishes
29
29
  * sibling expansions at the same depth (an `array` of three `self` children
30
30
  * calls `fabricateAt` three times on one shared element Fabricator; the schema
31
- * does not tell them apart). Each expansion gets its own _root_: `forkSource`
32
- * mints an isolated `RandomSource` salted from this node's draw, and each
33
- * `fabricateAt` resolves an ordinary construction root on it
34
- * (`RandomSource.toRoot`), recorded on each expansion's `trace`. The private
35
- * source's construction counter orders expansions; nothing to increment here.
36
- * Isolation also keeps this node's data-dependent draws from perturbing (or
37
- * being perturbed by) an unrelated Fabricator from the same `initialize()`
38
- * instance.
31
+ * does not tell them apart). `forkSource` mints an isolated `RandomSource`
32
+ * salted from this node's draw, and each `fabricateAt` resolves a
33
+ * `ConstructionTrace` on it (`RandomSource.toConstructionTrace`), recorded on
34
+ * each expansion's `trace`. The private source's construction counter orders
35
+ * expansions; nothing to increment here. Isolation also keeps this node's
36
+ * data-dependent draws from perturbing (or being perturbed by) an unrelated
37
+ * Fabricator from the same `initialize()` instance.
39
38
  *
40
39
  * Each `self` gets its own independently-dispatched expansion — calling
41
40
  * `context.self` twice (two array slots) is two `fabricateAt` calls, each with
@@ -68,8 +68,8 @@ export type Trace = {
68
68
  };
69
69
  /**
70
70
  * Caller-supplied overrides for the construction-owned {@link Trace} slots
71
- * {@link RandomSource.toRoot} resolves. `path`/`kind` are the only slots absent:
72
- * they are per-node and applied in `construct()`, not here.
71
+ * {@link RandomSource.toConstructionTrace} resolves. `path`/`kind` are the only
72
+ * slots absent: they are per-node and applied in `construct()`, not here.
73
73
  *
74
74
  * `salt` is a pin like the rest — it substitutes into that trace slot and does
75
75
  * nothing else. It does not fork, so it neither resets nor sidesteps this
@@ -82,17 +82,17 @@ export type Trace = {
82
82
  * ordinal" — is taken verbatim and does not advance the counter. That is all a
83
83
  * replay needs, since every real {@link Trace} carries a defined ordinal.
84
84
  */
85
- export type RootPins = {
85
+ export type ConstructionPins = {
86
86
  salt?: ReadonlyArray<string> | undefined;
87
87
  clock?: number | undefined;
88
88
  ordinal?: number | null | undefined;
89
89
  };
90
90
  /**
91
- * A construction's root: every {@link Trace} slot a construction fixes, before a
92
- * leaf supplies its own `path`/`kind`. `RandomSource.toRoot` resolves this once
93
- * per construction; callers spread it into a full {@link Trace} per leaf and
94
- * hand that to `toStreamFromTrace`. One construction-ordinal bump is reused
95
- * across every leaf that construction dispatches.
91
+ * Every {@link Trace} slot fixed once per construction, before a leaf supplies
92
+ * its own `path`/`kind`. `RandomSource.toConstructionTrace` resolves this once;
93
+ * callers spread it into a full {@link Trace} per leaf and hand that to
94
+ * `toStreamFromTrace`. One construction-ordinal bump is reused across every
95
+ * leaf that construction dispatches.
96
96
  */
97
97
  export type ConstructionTrace = Omit<Trace, "path" | "kind">;
98
98
  /**
@@ -173,9 +173,9 @@ export type Options = {
173
173
  * constructions like any other. Two same-salt builds therefore diverge.
174
174
  *
175
175
  * `clock` / `ordinal` pin the construction-owned {@link Trace} slots
176
- * {@link RandomSource.toRoot} would otherwise resolve. Definedness, not `in`: a
177
- * given `ordinal` — a number, or `null` for "no ordinal" — is taken verbatim
178
- * with no counter bump, which is all a replay needs; without it, the
176
+ * {@link RandomSource.toConstructionTrace} would otherwise resolve. Definedness,
177
+ * not `in`: a given `ordinal` — a number, or `null` for "no ordinal" — is taken
178
+ * verbatim with no counter bump, which is all a replay needs; without it, the
179
179
  * construction takes the source counter's next value. A salted construction is
180
180
  * not, by default, asking for a different "now"; a replayed trace whose `clock`
181
181
  * is present explicitly is.
@@ -205,20 +205,22 @@ export type ConstructorOptions = {
205
205
  */
206
206
  export type RandomSource = {
207
207
  /**
208
- * Resolve one construction's root: this source's own `salt`/`clock` and the
209
- * next construction ordinal, each overridable by {@link RootPins}. Called once
210
- * per `new Fabricator(...)` (or per lazy expansion of a `T.recursive` schema,
211
- * each of which resolves its own root on a private forked source), never per
212
- * leaf: the returned {@link ConstructionTrace} is what every leaf beneath it
213
- * completes into a full {@link Trace} and hands to `toStreamFromTrace`. One
214
- * construction-ordinal bump serves the whole construction.
208
+ * Resolve this source's `salt`/`clock` and the next construction ordinal,
209
+ * each overridable by {@link ConstructionPins}. Called once per `new
210
+ * Fabricator(...)` (or per lazy expansion of a `T.recursive` schema, each of
211
+ * which resolves its own construction trace on a private forked source),
212
+ * never per leaf: the returned {@link ConstructionTrace} is what every leaf
213
+ * beneath it completes into a full {@link Trace} and hands to
214
+ * `toStreamFromTrace`. One construction-ordinal bump serves the whole
215
+ * construction.
215
216
  */
216
- toRoot(pins?: RootPins): ConstructionTrace;
217
+ toConstructionTrace(pins?: ConstructionPins): ConstructionTrace;
217
218
  /**
218
219
  * The algorithm this source (and every fork of it) hashes with. Stream
219
220
  * derivation is _not_ a member: it depends on no per-source state, so it is
220
- * the free function `toStreamFromTrace(algorithm, trace)`. `toRoot` is the
221
- * only stateful member (the construction counter).
221
+ * the free function `toStreamFromTrace(algorithm, trace)`.
222
+ * `toConstructionTrace` is the only stateful member (the construction
223
+ * counter).
222
224
  */
223
225
  readonly algorithm: Algorithm;
224
226
  /**
@@ -63,7 +63,7 @@ export declare function toStream(algorithm: Algorithm, seed: string): Stream;
63
63
  * `toStream(algorithm, encode(trace)).seed === stream.seed`. Not a
64
64
  * {@link RandomSource} member: derivation depends on no per-source state (a
65
65
  * fork shares only the algorithm), so it is a free function of `(algorithm,
66
- * trace)`. `toRoot` is the only stateful member.
66
+ * trace)`. `toConstructionTrace` is the only stateful member.
67
67
  *
68
68
  * {@link deriveClock} cannot route through this: a {@link Trace} carries
69
69
  * `clock`, and `deriveClock` is what produces it. That circularity is why
@@ -76,7 +76,7 @@ export declare function toStreamFromTrace(algorithm: Algorithm, trace: Trace): S
76
76
  * single `initialize()` instance owns for its lifetime. `options.clock` is
77
77
  * baked in here, once, as a plain number — the `"derived"` policy is already
78
78
  * resolved by the caller (`Instance/Core.ts`'s `resolveClock`) before a source
79
- * is ever built, so every root this source resolves carries the identical
80
- * instant, and `fork` threads it forward unchanged.
79
+ * is ever built, so every construction trace this source resolves carries the
80
+ * identical instant, and `fork` threads it forward unchanged.
81
81
  */
82
82
  export declare function toRandomSource(options: Options): RandomSource;
@@ -50,7 +50,10 @@ export declare function initialize<const $Registry extends PlainObject = typeof
50
50
  clock?: Date | "derived";
51
51
  /**
52
52
  * The ambient carrier backing `wrap` for this lineage — override only to
53
- * force a specific one.
53
+ * force a specific one. A choice of carrier and nothing more: lineage
54
+ * identity is the instance's own `ancestry[0]`, so handing the same carrier
55
+ * to two `initialize()` calls does not join them — neither one's reads ever
56
+ * resolve the other's frames.
54
57
  *
55
58
  * Left unset (the norm), the `#stack` package import picks it: every
56
59
  * runtime with `node:async_hooks` — Node, Bun, Deno — gets the
@@ -149,5 +152,11 @@ export type { Trace } from "./Random/Types";
149
152
  * parameter is a `Partial` of; `Overlay` is what `fork`/`wrap` accept;
150
153
  * `Context` is `instance.context`'s own type, so a caller writing a helper that
151
154
  * reads it can name the parameter.
155
+ *
156
+ * `Ancestry` comes with `Stack`, whose `visible` takes one, so anyone
157
+ * implementing a carrier can name the parameter. `Token` is deliberately _not_
158
+ * exported: a chain is opaque, its elements are comparable only by identity,
159
+ * and the ordinary "same lineage?" question is `a.root === b.root` rather than
160
+ * anything a caller needs to name.
152
161
  */
153
- export type { Config, Context, Overlay, Stack } from "./Instance/Types";
162
+ export type { Ancestry, Config, Context, Overlay, Stack, } from "./Instance/Types";
@@ -63,7 +63,7 @@ export type { Axis, Enumerable, Pin, Resolvable } from "./Enumeration/Types";
63
63
  * directly, beneath the level `initialize()` itself exposes.
64
64
  */
65
65
  export { defaultAlgorithm, encode, randomSalt, toRandomSource, toStream, toStreamFromTrace, } from "./Random";
66
- export type { Algorithm, ConstructionTrace, ConstructorOptions, RootPins, Salt, Trace, } from "./Random/Types";
66
+ export type { Algorithm, ConstructionPins, ConstructionTrace, ConstructorOptions, Salt, Trace, } from "./Random/Types";
67
67
  /**
68
68
  * The synchronous ambient carrier. `#stack` (`package.json`) selects it only
69
69
  * where there is no `node:async_hooks` — in practice a browser bundle — so on
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostry/fabricator",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "license": "MIT",
5
5
  "description": "Fabricate typed data from composable schemas.",
6
6
  "keywords": [