@opetope/runtime 0.1.1 → 0.2.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +19 -9
  3. package/README.ru.md +21 -9
  4. package/dist/feature-authoring-types.d.ts +6 -10
  5. package/dist/feature-authoring.js +1 -1
  6. package/dist/feature-authoring.js.map +1 -1
  7. package/dist/feature-body.d.ts +1 -1
  8. package/dist/feature-body.js.map +1 -1
  9. package/dist/feature-contribution.d.ts +5 -3
  10. package/dist/feature-contribution.js +1 -1
  11. package/dist/feature-contribution.js.map +1 -1
  12. package/dist/feature-definition-api.d.ts +1 -1
  13. package/dist/feature-generation.js +1 -1
  14. package/dist/feature-generation.js.map +1 -1
  15. package/dist/feature-lazy-generation.d.ts +1 -1
  16. package/dist/feature-lazy-generation.js +1 -1
  17. package/dist/feature-lazy-generation.js.map +1 -1
  18. package/dist/feature-own-values.d.ts +10 -0
  19. package/dist/feature-own-values.js +2 -0
  20. package/dist/feature-own-values.js.map +1 -0
  21. package/dist/feature-port-binding.d.ts +2 -1
  22. package/dist/feature-port-binding.js +1 -1
  23. package/dist/feature-port-binding.js.map +1 -1
  24. package/dist/feature-port.d.ts +13 -23
  25. package/dist/feature-port.js +1 -1
  26. package/dist/feature-port.js.map +1 -1
  27. package/dist/public-module-types.d.ts +1 -1
  28. package/dist/public-module.d.ts +1 -1
  29. package/docs/agent-guide.md +11 -4
  30. package/docs/agent-guide.ru.md +11 -4
  31. package/docs/cookbook.md +9 -7
  32. package/docs/cookbook.ru.md +9 -7
  33. package/docs/decisions.md +14 -0
  34. package/docs/how-it-works.md +20 -5
  35. package/docs/how-it-works.ru.md +19 -5
  36. package/docs/spec.md +31 -17
  37. package/docs/spec.ru.md +32 -18
  38. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @opetope/runtime
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2d41c56: Give `provides` only its declaration builders and let nested callbacks select the current instance's live values:
8
+
9
+ - The outer `provides` receives exactly `{ port, register, slot, pipe }`, with no `own`.
10
+ - `port(Port, ({ own }) => own.model.call)` or `port(Port, ({ own }) => own.call)` selects an authentic Call during instance preparation, before readiness and contribution publication. Its callback receives only `{ own }`.
11
+ - `register` factories receive `{ own, imports }`.
12
+ - `slot` factories receive `{ own, imports, model }` for per-mount UI models.
13
+ - `when` predicates and `pipe.fold` handlers receive `{ own, imports, read }`.
14
+
15
+ This is a breaking authoring API change. Remove `own` from the outer `provides` context. Replace both `port(Port, ref)` and `port(Port, { from, select })` with a selector of the ready value, such as `port(Port, ({ own }) => own.order.submit)`. Port targets remain known at declaration; selecting the Call waits for the concrete instance.
16
+
17
+ Contribution contexts no longer expose `exports` or `instance`, and `register` no longer exposes `model`. Replace `context.exports.submit` with the source value, such as `context.own.order.submit`; remove exports needed only for internal composition. Replace instance-based binding with the ready value from `own`. Private model calls can be registered without adding them to the feature's public API. There are no compatibility aliases.
18
+
19
+ ### Patch Changes
20
+
21
+ - @opetope/core@0.2.0
22
+
3
23
  ## 0.1.1
4
24
 
5
25
  ### Patch Changes
package/README.md CHANGED
@@ -98,9 +98,10 @@ its own context created (D139). The refs of `model()` take no part in the loweri
98
98
  cannot be used in `within`. A contribution component reads the models of its feature through `useModel` inside the
99
99
  contribution mount, which binds them automatically. A single field goes outward through
100
100
  `exports: ({ own }) => ({ x: own.model.field })`. A model call can also provide a port:
101
- `port(SubmitPort, { from: own.order, select: order => order.submit })`. The selector runs once on the materialized
102
- model before publication; the selected authentic `Call` is fenced by the provider's lifetime even if it passes
103
- through a dependency call. The direct `port(SubmitPort, own.submit)` form remains for a declared call ref (D169).
101
+ `port(SubmitPort, ({ own }) => own.order.submit)`. The selector receives only `{ own }` and runs once during instance
102
+ preparation, before readiness and publication; the selected authentic `Call` is fenced by the provider's lifetime
103
+ even if it passes through a dependency call. Use `port(SubmitPort, ({ own }) => own.submit)` for a call declared
104
+ directly in `own`. Both forms select ready Calls; direct refs and `{ from, select }` descriptors are not accepted (D255).
104
105
 
105
106
  `target` is a selector `(source) => Readable<T | null | undefined>` in both feature and model APIs.
106
107
  TypeScript infers the payload of the returned `Readable`, whose shape is checked before opening; a scalar
@@ -112,8 +113,8 @@ Both APIs publish one atomic snapshot `idle | opening | ready | refreshing | err
112
113
  work; demand is set by a separate `retain()` lease. Retention by default merges the StrictMode
113
114
  release/reacquire into one microtask and aborts unfinished work after the last lease. An explicit
114
115
  `scoped({ capacity })` holds the materialization until retirement and bounds the sticky
115
- cache. The UI of a feature gets an instance-bound facade through `bindFeatureResource(instance, own.x)`,
116
- and the React `useResource` holds one lease per mounted consumer.
116
+ cache. A nested contribution factory reads the instance-bound resource as `own.x` and can pass it to the UI;
117
+ the React `useResource` holds one lease per mounted consumer.
117
118
 
118
119
  There are exactly two policy factories, and both have a production pilot: `scoped({ capacity })` for retention and
119
120
  `latest()` for stream and event backpressure. The former `drop`, `sample` and `queue` are removed together with their branches:
@@ -207,7 +208,7 @@ explicit `key` keeps the current generation. `keyed` holds an independent child
207
208
  unique `string | number` key. A repeated key rejects the whole new snapshot before any change to the children that are
208
209
  already active. Retire fences the children synchronously and waits for their physical drain.
209
210
 
210
- The `provides` section declares both ports and contributions: `port` binds a call ref to a `Port`, while `slot`, `pipe` and
211
+ The `provides` section declares both ports and contributions: `port` selects an owned Call for a `Port`, while `slot`, `pipe` and
211
212
  `register` declare a contribution by the kind of its target:
212
213
 
213
214
  ```ts
@@ -223,16 +224,25 @@ const titleFeature = defineFeature({
223
224
  });
224
225
  ```
225
226
 
226
- The outer factory is synchronous and runs at `defineFeature`, so the target/id/priority are available
227
- to the application compiler before an instance opens. The second argument of `pipe(...)` is a `{ fold }` descriptor:
227
+ The outer factory receives only `{ port, register, slot, pipe }`, runs synchronously at `defineFeature`, and records
228
+ targets, ids and priorities for the application compiler before an instance opens. A `port` selector runs later,
229
+ with the instance's `{ own }`, during preparation. The second argument of `pipe(...)` is a `{ fold }` descriptor:
228
230
  the runtime binds it to the concrete instance after the critical barrier and calls the handler only on a fold (D223).
229
- `slot` and `register` take either a value factory with a concrete `FeatureOpenContext`, which also runs only after
231
+ `slot` and `register` take either a value factory for the concrete instance, which also runs only after
230
232
  that barrier, or a ready contribution value. An exact plain record must
231
233
  return every receipt exactly once; the id of an entry is derived as `featureId.key`. The whole batch goes through
232
234
  preflight and is published atomically. The start of retirement removes the entries synchronously before the async cleanup, including
233
235
  a reentrant retirement from a target listener; a failed opening or an error in the value factory leaves no partially
234
236
  published contributions.
235
237
 
238
+ The `register` value factory receives `{ own, imports }`; `slot` receives `{ own, imports, model }`, where `model`
239
+ declares a UI model created for each mount. `when` predicates and `pipe.fold` handlers receive `{ own, imports, read }`.
240
+ Their `own` contains the live models, calls and resources of that instance (D255). For example,
241
+ `register(target, ({ own }) => ({ key: 'submit', value: own.order.submit }))` registers a private model call without
242
+ exporting it. These contexts have no `exports` or `instance` field; `register` also has no `model` builder.
243
+ The outer `provides` has no `own`; each nested callback receives its own context of ready values. Model calls keep
244
+ their existing lifetime and owned state is read-only outside its model.
245
+
236
246
  The feature API is declared by the `exports: ({ own }) => ({ … })` section: the contract is created from the feature
237
247
  definition under the id `<feature>.exports`, and a consumer imports the definition itself — `imports: { provider: providerFeature }`.
238
248
  Assigned missing/extra keys and incompatible `Call` signatures are rejected at compile time. Host-only values
package/README.ru.md CHANGED
@@ -98,9 +98,11 @@ lookup: requires.lookup }, create)` передаёт readonly-запись ра
98
98
  нельзя использовать в `within`. Компонент вклада читает модели своей фичи через `useModel` внутри монтирования
99
99
  вклада, которое связывает их автоматически. Отдельное поле уходит наружу через
100
100
  `exports: ({ own }) => ({ x: own.model.field })`. Вызов модели также может предоставлять порт:
101
- `port(SubmitPort, { from: own.order, select: order => order.submit })`. Селектор вызывается один раз на готовой
102
- модели до публикации; выбранный подлинный `Call` ограничен временем жизни провайдера, даже если он напрямую
103
- передан из зависимости. Для объявленного call ref остаётся форма `port(SubmitPort, own.submit)` (D169).
101
+ `port(SubmitPort, ({ own }) => own.order.submit)`. Селектор получает только `{ own }` и вызывается один раз при
102
+ подготовке экземпляра, до readiness и публикации; выбранный подлинный `Call` ограничен временем жизни провайдера,
103
+ даже когда он напрямую передан из зависимости. Для вызова, объявленного прямо в `own`, используется
104
+ `port(SubmitPort, ({ own }) => own.submit)`. Обе формы выбирают готовые Calls; прямые refs и дескрипторы
105
+ `{ from, select }` не принимаются (D255).
104
106
 
105
107
  `target` — селектор `(source) => Readable<T | null | undefined>` и у фичи, и у модели.
106
108
  TypeScript выводит payload возвращённого `Readable`, форма которого проверяется перед открытием;
@@ -112,8 +114,8 @@ TypeScript выводит payload возвращённого `Readable`, фор
112
114
  работу; спрос задаёт отдельный lease `retain()`. Удержание по умолчанию объединяет StrictMode
113
115
  release/reacquire в одну микрозадачу и abort-ит незавершённую работу после последнего lease. Явный
114
116
  `scoped({ capacity })` удерживает materialization до retirement и ограничивает sticky
115
- кэша. UI фичи получает привязанный к экземпляру фасад через `bindFeatureResource(instance, own.x)`,
116
- а React `useResource` держит один lease на смонтированного потребителя.
117
+ кэша. Вложенная фабрика вклада получает привязанный к экземпляру ресурс как `own.x` и может передать его в UI;
118
+ React `useResource` держит один lease на смонтированного потребителя.
117
119
 
118
120
  Фабрик политик ровно две, и обе с production-пилотом: `scoped({ capacity })` для удержания и `latest()` для
119
121
  backpressure стрима и события. Прежние `drop`, `sample` и `queue` удалены вместе с их ветками: назвать их из авторского
@@ -206,7 +208,7 @@ own: ({ imports, scope }) => ({
206
208
  уникальный `string | number` key. Повтор ключа отклоняет весь новый snapshot до любых изменений уже
207
209
  активных детей. Retire синхронно фенсит детей и ждёт их физический дренаж.
208
210
 
209
- Секция `provides` объявляет и порты, и вклады: `port` связывает call-ref с `Port`, `slot`, `pipe` и
211
+ Секция `provides` объявляет и порты, и вклады: `port` выбирает владеемый Call для `Port`, `slot`, `pipe` и
210
212
  `register` объявляют вклад по виду цели:
211
213
 
212
214
  ```ts
@@ -222,16 +224,26 @@ const titleFeature = defineFeature({
222
224
  });
223
225
  ```
224
226
 
225
- Внешняя factory синхронна и выполняется при `defineFeature`, поэтому target/id/priority доступны
226
- компилятор приложения до открытия экземпляра. Второй аргумент `pipe(...)` — дескриптор `{ fold }`: рантайм
227
+ Внешняя factory получает только `{ port, register, slot, pipe }`, синхронно выполняется при `defineFeature` и
228
+ записывает target/id/priority для компилятора приложения до открытия экземпляра. Селектор `port` выполняется
229
+ позже, с `{ own }` конкретного экземпляра, при его подготовке. Второй аргумент `pipe(...)` — дескриптор `{ fold }`: рантайм
227
230
  связывает его с конкретным экземпляром после critical barrier и вызывает обработчик только на свёртке (D223).
228
- `slot` и `register` принимают либо value factory с concrete `FeatureOpenContext`, которая тоже выполняется только
231
+ `slot` и `register` принимают либо value factory конкретного экземпляра, которая тоже выполняется только
229
232
  после этого барьера, либо готовое значение вклада. Exact plain record обязан
230
233
  вернуть каждый receipt ровно один раз; id записи выводится как `featureId.key`. Весь batch проходит
231
234
  preflight и публикуется атомарно. Начало retirement синхронно удаляет записи до async cleanup, включая
232
235
  reentrant retirement из target listener; failed opening или ошибка value factory не оставляют частично
233
236
  опубликованных вкладов.
234
237
 
238
+ Value factory `register` получает `{ own, imports }`, а `slot` — `{ own, imports, model }`, где `model` объявляет
239
+ UI-модель, создаваемую на каждое монтирование. Предикаты `when` и обработчики `pipe.fold` получают `{ own, imports, read }`.
240
+ Их `own` содержит готовые модели, вызовы и ресурсы конкретного экземпляра (D255). Например,
241
+ `register(target, ({ own }) => ({ key: 'submit', value: own.order.submit }))` регистрирует вызов внутренней модели
242
+ без его экспорта. В этих контекстах нет полей `exports` и `instance`; у `register` также нет построителя `model`.
243
+ У внешней `provides` нет `own`; каждый вложенный колбэк получает собственный контекст готовых значений.
244
+ Вызовы модели сохраняют своё время жизни, а owned state за пределами модели доступен
245
+ только для чтения.
246
+
235
247
  Feature API объявляется секцией `exports: ({ own }) => ({ … })`: contract создаётся из определения
236
248
  фичи под id `<feature>.exports`, а consumer импортирует само определение — `imports: { provider: providerFeature }`.
237
249
  Assigned missing/extra keys и несовместимые `Call` signatures отклоняются compile-time. Host-only значения
@@ -6,7 +6,6 @@ import type { FeatureAttachBuilder, FeatureCallsBuilder, FeatureImportRef, Featu
6
6
  import type { FeatureCallBuilder, FeatureCallLaneBuilder, FeatureExposureMode, FeatureImportedAttachmentRef } from './feature-call-types.js';
7
7
  import type { FeatureContract, FeatureContractIdentity, FeatureImportRecord, FeatureImportValues } from './feature-contract.js';
8
8
  import type { FeatureContributionDescriptor } from './feature-contribution.js';
9
- import type { ContributionModelBuilder } from './feature-contribution-model.js';
10
9
  import type { FeatureResourceRef, FeatureStreamRef } from './feature-materialization-types.js';
11
10
  import type { FeatureDataDescriptor, FeatureModelBuilder, FeatureModelRef } from './feature-model.js';
12
11
  import type { FeatureRequiredCalls, PortProviderDescriptor, PortRequirementRecord, RequiredPortValues } from './feature-port.js';
@@ -15,7 +14,7 @@ import type { FeatureResourceBuilder } from './feature-resource.js';
15
14
  import type { FeatureScopeBuilder } from './feature-scope-types.js';
16
15
  import type { FeatureStreamBuilder } from './feature-stream.js';
17
16
  import type { FeatureTimers } from './feature-timers.js';
18
- import type { ModuleAttachmentRefIdentity, ModuleCallRef, ModuleInstanceRef, ModuleRuntimeRefIdentity, ModuleScopeRef } from './public-module.js';
17
+ import type { ModuleAttachmentRefIdentity, ModuleCallRef, ModuleRuntimeRefIdentity, ModuleScopeRef } from './public-module.js';
19
18
  declare const featureBrand: unique symbol;
20
19
  type FeatureLifecycleRef<Source, Id extends string, Imports extends FeatureImportRecord, Mode extends FeatureExposureMode> = FeatureImportedAttachmentRef<Source, Id, FeatureImportValues<Imports>, Mode>;
21
20
  type FeatureEffectRunContext<Source, Value> = {
@@ -144,18 +143,15 @@ type FeatureRead = <Value>(source: Readable<Value>) => Value;
144
143
  * is the materialized form `exports` already uses — a model field is a `Readable`, not the ref the declaration
145
144
  * context carries — because a calculation reads values and never constructs a node (D220).
146
145
  */
147
- type FeatureEvaluationContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord> = {
148
- readonly exports: Exports;
146
+ type FeatureEvaluationContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>> = {
149
147
  readonly imports: FeatureImportValues<Imports>;
150
148
  readonly own: FeatureOwnValues<Id, Runtime>;
151
149
  readonly read: FeatureRead;
152
150
  };
153
- type FeatureOpenContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord> = {
154
- readonly exports: Exports;
151
+ /** Contribution factories select live values; the outer `provides` carries only declaration builders (D255). */
152
+ type FeatureOpenContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>> = {
155
153
  readonly imports: FeatureImportValues<Imports>;
156
- readonly instance: ModuleInstanceRef<Id>;
157
- readonly model: ContributionModelBuilder;
158
- readonly own: Runtime;
154
+ readonly own: FeatureOwnValues<Id, Runtime>;
159
155
  };
160
156
  type FeatureRecord = {
161
157
  readonly contributions: readonly FeatureContributionDescriptor[];
@@ -193,4 +189,4 @@ type FeatureExportDeclarationSnapshot = {
193
189
  readonly own: unknown;
194
190
  }) => unknown;
195
191
  };
196
- export type { AnyFeature, AttachmentLowering, AttachmentProjection, AttachmentRecipe, Feature, FeatureAttachBuilder, FeatureCallBuilder, FeatureCallOperation, FeatureConditionsOf, FeatureEffectBuilder, FeatureEvaluationContext, FeatureEventBuilder, FeatureExportDeclarationSnapshot, FeatureExportRecord, FeatureExportsFactory, FeatureExportsOf, FeatureExposureMode, FeatureIdOf, FeatureImportRecord, FeatureImportRef, FeatureImportsOf, FeatureImportValues, FeatureLifecycleRef, FeatureOpenContext, FeatureOwnBuilder, FeatureOwnRecord, FeatureRecord, FeatureRequirementsOf, };
192
+ export type { AnyFeature, AttachmentLowering, AttachmentProjection, AttachmentRecipe, Feature, FeatureAttachBuilder, FeatureCallBuilder, FeatureCallOperation, FeatureConditionsOf, FeatureEffectBuilder, FeatureEvaluationContext, FeatureEventBuilder, FeatureExportDeclarationSnapshot, FeatureExportRecord, FeatureExportsFactory, FeatureExportsOf, FeatureExposureMode, FeatureIdOf, FeatureImportRecord, FeatureImportRef, FeatureImportsOf, FeatureImportValues, FeatureLifecycleRef, FeatureOpenContext, FeatureOwnBuilder, FeatureOwnRecord, FeatureOwnValues, FeatureRecord, FeatureRequirementsOf, };
@@ -1,2 +1,2 @@
1
- import{declarationId as I}from"@opetope/core";import{snapshotFeatureConditions as q}from"./condition.js";import{preloadFeatureBody as M,featureBody as k,requireFeatureBody as L}from"./feature-body.js";import{defineFeatureContract as z}from"./feature-contract.js";import{isFeatureContributionDeclaration as x,snapshotFeatureContributions as V,createFeatureContributionBuilders as G}from"./feature-contribution.js";import{snapshotFeatureOptions as H,requireString as W,snapshotFeatureExportDeclaration as K,optionalFunction as F,snapshotFeatureImports as g,snapshotFeatureRequirements as E,registerFeatureRecord as P,requireFeatureRecord as A}from"./feature-definition-support.js";import{isFeature as ve}from"./feature-definition-support.js";import{snapshotDeclaredProvided as J,registerLazyFeature as N,assertBodyMatchesHeader as Q}from"./feature-lazy.js";import{lowerFeatureOwn as D}from"./feature-own-lowering.js";import{createPortBuilder as U,snapshotPortProviders as X}from"./feature-port.js";import{dataEntries as y,assertPlainRecord as Y}from"./feature-record.js";import{defineModule as Z}from"./public-module-definition.js";const C=Z;function _(r){if((typeof r!="object"||r===null)&&typeof r!="function")return!1;let e=r;for(;e!==null;){const o=Object.getOwnPropertyDescriptor(e,"then");if(o!==void 0)return"value"in o&&typeof o.value=="function";e=Object.getPrototypeOf(e)}return!1}function S(r,e,o,c){const i=G();if(e===void 0)return Object.freeze({contributions:Object.freeze([]),providers:Object.freeze([])});const n=e({own:o,pipe:i.pipe,port:U(),register:i.register,slot:i.slot});if(_(n))throw Promise.resolve(n).catch(()=>{}),new TypeError("defineFeature provides must return synchronously.");Y(n,"defineFeature provides result");const d=y(n,"defineFeature provides result"),s=d.filter(([,u])=>x(i,u)),a=d.filter(([,u])=>!x(i,u));return Object.freeze({contributions:V(r,i,s),providers:X(c,a)})}const h=new WeakMap;function ee(r,e){const o=F(e.own,"defineFeature own")??(()=>({})),c=K(e.exports),i=F(e.provides,"defineFeature provides");let n;const d=C({id:r.id,runtime:l=>(n=D(l,{build:o,id:r.id,importKeys:r.importKeys,imports:r.imports,requirementKeys:r.requirementKeys}),n.loweredRuntime)});if(n===void 0)throw new TypeError("defineFeature own did not produce a public record.");const{dataDescriptors:s,importScopeKey:a,publicRuntime:u,requirementScopeKey:p}=n,m=u,t=new Set(Object.values(m).filter(l=>typeof l=="object")),{contributions:f,providers:w}=S(r.id,i,u,t);return{own:m,record:{contributions:f,dataDescriptors:s,exports:c.from,importKeys:r.importKeys,importScopeKey:a,module:d,providers:w,requirementKeys:r.requirementKeys,requirementScopeKey:p}}}function re(r,e){for(const t of["exports","own"])if(r[t]!==void 0)throw new TypeError(`defineFeature ${e} declares body and ${t}: the implementation belongs to the body.`);if(typeof r.provides=="function")throw new TypeError(`defineFeature ${e} declares body and a provides factory: the header declares targets only.`);const o=r.body;if(typeof o!="function")throw new TypeError("defineFeature body must be a loader function.");const c=g(r.imports),i=E(r.requires),n=Object.freeze(y(c,"defineFeature imports").map(([t])=>t)),d=Object.freeze(y(i,"defineFeature requires").map(([t])=>t)),s=J(e,r.provides),a=z(`${e}.exports`);let u=Object.freeze({});const p=Object.freeze({exports:a,id:I(e),imports:c,get own(){return u},requires:i,when:q(r.when)}),m={id:e,importKeys:n,imports:c,requirementKeys:d};return P(p,{contributions:s.contributions,dataDescriptors:Object.freeze([]),exports:()=>({}),importKeys:n,importScopeKey:void 0,module:Object.freeze({}),providers:s.providers.map(t=>Object.freeze({...t,target:void 0})),requirementKeys:d,requirementScopeKey:void 0}),N(p,{load:()=>Promise.resolve(o()).then(t=>L(e,t)),materialize:t=>{const f=ee(m,t);return Q(e,s,f.record),u=Object.freeze(f.own),f.record}}),h.set(a,p),p}function te(r){const e=H(r),o=W(e.id,"defineFeature id");if(e.body!==void 0)return re(e,o);const c=K(e.exports),i=F(e.own,"defineFeature own")??(()=>({})),n=c.from,d=F(e.provides,"defineFeature provides"),s=g(e.imports),a=E(e.requires),u=y(a,"defineFeature requires"),p=Object.freeze(y(s,"defineFeature imports").map(([b])=>b)),m=Object.freeze(u.map(([b])=>b));let t;const f=C({id:o,runtime:b=>(t=D(b,{build:i,id:o,importKeys:p,imports:s,requirementKeys:m}),t.loweredRuntime)});if(t===void 0)throw new TypeError("defineFeature own did not produce a public record.");const{dataDescriptors:w,importScopeKey:l,publicRuntime:v,requirementScopeKey:B}=t,R=new Set(Object.values(v)),{contributions:T,providers:$}=S(o,d,v,R),j=z(`${o}.exports`),O=Object.freeze({exports:j,id:f.id,imports:s,own:v,requires:a,when:q(e.when)});return P(O,{contributions:T,dataDescriptors:w,exports:n,importKeys:p,importScopeKey:l,module:f,providers:$,requirementKeys:m,requirementScopeKey:B}),h.set(j,O),O}function oe(r){return h.get(r)}const ne=Object.assign(te,{body:k,preload:M});function ie(r){return A(r).contributions}export{ne as defineFeature,oe as getFeatureByExportContract,ie as getFeatureContributionDescriptors,ve as isFeature};
1
+ import{declarationId as $}from"@opetope/core";import{snapshotFeatureConditions as O}from"./condition.js";import{preloadFeatureBody as I,featureBody as M,requireFeatureBody as k}from"./feature-body.js";import{defineFeatureContract as q}from"./feature-contract.js";import{isFeatureContributionDeclaration as z,snapshotFeatureContributions as L,createFeatureContributionBuilders as G}from"./feature-contribution.js";import{snapshotFeatureOptions as H,requireString as W,snapshotFeatureExportDeclaration as x,optionalFunction as b,snapshotFeatureImports as j,snapshotFeatureRequirements as K,registerFeatureRecord as g,requireFeatureRecord as A}from"./feature-definition-support.js";import{isFeature as we}from"./feature-definition-support.js";import{snapshotDeclaredProvided as J,registerLazyFeature as N,assertBodyMatchesHeader as Q}from"./feature-lazy.js";import{lowerFeatureOwn as E}from"./feature-own-lowering.js";import{createPortBuilder as U,snapshotPortProviders as V}from"./feature-port.js";import{dataEntries as y,assertPlainRecord as X}from"./feature-record.js";import{defineModule as Y}from"./public-module-definition.js";const P=Y;function Z(r){if((typeof r!="object"||r===null)&&typeof r!="function")return!1;let e=r;for(;e!==null;){const t=Object.getOwnPropertyDescriptor(e,"then");if(t!==void 0)return"value"in t&&typeof t.value=="function";e=Object.getPrototypeOf(e)}return!1}function D(r,e){const t=G();if(e===void 0)return Object.freeze({contributions:Object.freeze([]),providers:Object.freeze([])});const i=e({pipe:t.pipe,port:U(),register:t.register,slot:t.slot});if(Z(i))throw Promise.resolve(i).catch(()=>{}),new TypeError("defineFeature provides must return synchronously.");X(i,"defineFeature provides result");const u=y(i,"defineFeature provides result"),s=u.filter(([,n])=>z(t,n)),c=u.filter(([,n])=>!z(t,n));return Object.freeze({contributions:L(r,t,s),providers:V(c)})}const v=new WeakMap;function _(r,e){const t=b(e.own,"defineFeature own")??(()=>({})),i=x(e.exports),u=b(e.provides,"defineFeature provides");let s;const c=P({id:r.id,runtime:F=>(s=E(F,{build:t,id:r.id,importKeys:r.importKeys,imports:r.imports,requirementKeys:r.requirementKeys}),s.loweredRuntime)});if(s===void 0)throw new TypeError("defineFeature own did not produce a public record.");const{dataDescriptors:n,importScopeKey:p,publicRuntime:f,requirementScopeKey:d}=s,m=f,{contributions:o,providers:a}=D(r.id,u);return{own:m,record:{contributions:o,dataDescriptors:n,exports:i.from,importKeys:r.importKeys,importScopeKey:p,module:c,providers:a,requirementKeys:r.requirementKeys,requirementScopeKey:d}}}function ee(r,e){for(const o of["exports","own"])if(r[o]!==void 0)throw new TypeError(`defineFeature ${e} declares body and ${o}: the implementation belongs to the body.`);if(typeof r.provides=="function")throw new TypeError(`defineFeature ${e} declares body and a provides factory: the header declares targets only.`);const t=r.body;if(typeof t!="function")throw new TypeError("defineFeature body must be a loader function.");const i=j(r.imports),u=K(r.requires),s=Object.freeze(y(i,"defineFeature imports").map(([o])=>o)),c=Object.freeze(y(u,"defineFeature requires").map(([o])=>o)),n=J(e,r.provides),p=q(`${e}.exports`);let f=Object.freeze({});const d=Object.freeze({exports:p,id:$(e),imports:i,get own(){return f},requires:u,when:O(r.when)}),m={id:e,importKeys:s,imports:i,requirementKeys:c};return g(d,{contributions:n.contributions,dataDescriptors:Object.freeze([]),exports:()=>({}),importKeys:s,importScopeKey:void 0,module:Object.freeze({}),providers:n.providers.map(o=>Object.freeze({...o,target:void 0})),requirementKeys:c,requirementScopeKey:void 0}),N(d,{load:()=>Promise.resolve(t()).then(o=>k(e,o)),materialize:o=>{const a=_(m,o);return Q(e,n,a.record),f=Object.freeze(a.own),a.record}}),v.set(p,d),d}function re(r){const e=H(r),t=W(e.id,"defineFeature id");if(e.body!==void 0)return ee(e,t);const i=x(e.exports),u=b(e.own,"defineFeature own")??(()=>({})),s=i.from,c=b(e.provides,"defineFeature provides"),n=j(e.imports),p=K(e.requires),f=y(p,"defineFeature requires"),d=Object.freeze(y(n,"defineFeature imports").map(([l])=>l)),m=Object.freeze(f.map(([l])=>l));let o;const a=P({id:t,runtime:l=>(o=E(l,{build:u,id:t,importKeys:d,imports:n,requirementKeys:m}),o.loweredRuntime)});if(o===void 0)throw new TypeError("defineFeature own did not produce a public record.");const{dataDescriptors:F,importScopeKey:C,publicRuntime:B,requirementScopeKey:R}=o,{contributions:S,providers:T}=D(t,c),h=q(`${t}.exports`),w=Object.freeze({exports:h,id:a.id,imports:n,own:B,requires:p,when:O(e.when)});return g(w,{contributions:S,dataDescriptors:F,exports:s,importKeys:d,importScopeKey:C,module:a,providers:T,requirementKeys:m,requirementScopeKey:R}),v.set(h,w),w}function te(r){return v.get(r)}const oe=Object.assign(re,{body:M,preload:I});function ne(r){return A(r).contributions}export{oe as defineFeature,te as getFeatureByExportContract,ne as getFeatureContributionDescriptors,we as isFeature};
2
2
  //# sourceMappingURL=feature-authoring.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-authoring.js","sources":["../src/feature-authoring.ts"],"sourcesContent":["import { declarationId } from '@opetope/core';\n\nimport { snapshotFeatureConditions } from './condition';\nimport type { Condition } from './condition';\nimport type {\n AnyFeature,\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureImportRecord,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n FeatureRecord,\n} from './feature-authoring-types';\nimport { featureBody, preloadFeatureBody, requireFeatureBody } from './feature-body';\nimport type { LoadedFeatureBody } from './feature-body';\nimport { defineFeatureContract } from './feature-contract';\nimport {\n createFeatureContributionBuilders,\n isFeatureContributionDeclaration,\n snapshotFeatureContributions,\n} from './feature-contribution';\nimport type { FeatureContributionDescriptor } from './feature-contribution';\nimport type { DefineFeature, FeatureInput } from './feature-definition-api';\nimport {\n isFeature,\n optionalFunction,\n registerFeatureRecord,\n requireFeatureRecord,\n requireString,\n snapshotFeatureExportDeclaration,\n snapshotFeatureImports,\n snapshotFeatureOptions,\n snapshotFeatureRequirements,\n} from './feature-definition-support';\nimport { assertBodyMatchesHeader, registerLazyFeature, snapshotDeclaredProvided } from './feature-lazy';\nimport { lowerFeatureOwn } from './feature-own-lowering';\nimport type { FeatureOwnLoweringResult } from './feature-own-lowering';\nimport { createPortBuilder, snapshotPortProviders } from './feature-port';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport { defineModule } from './public-module';\nimport type { ModuleDefinition, ModuleRuntimeBuilder, ModuleRuntimeRecord } from './public-module';\n\ntype DefineGeneratedModule = <Id extends string, Runtime extends ModuleRuntimeRecord<Id>>(options: {\n readonly id: Id;\n readonly runtime: (builder: ModuleRuntimeBuilder<Id>) => Runtime;\n}) => ModuleDefinition<Id, Runtime>;\n\n// The public defineModule guard rejects union author records. Feature lowering has already applied\n// the same guard before it appends collision-free private refs to one concrete `own` record.\nconst defineGeneratedModule = defineModule as DefineGeneratedModule;\n\nfunction hasDataThen(value: unknown): boolean {\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n\n let source: object | null = value;\n\n while (source !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(source, 'then');\n\n if (descriptor !== undefined) return 'value' in descriptor && typeof descriptor.value === 'function';\n\n source = Object.getPrototypeOf(source) as object | null;\n }\n\n return false;\n}\n\n/** `provides` returns ports and contributions in one record; each entry is split by the builder that made it. */\nfunction buildFeatureProvided<\n Id extends string,\n Context,\n Evaluation,\n Runtime extends FeatureOwnRecord<Id>,\n Provided extends FeatureProvidedRecord<Id>,\n>(\n featureId: string,\n build: FeatureProvidesFactory<Id, Context, Evaluation, Runtime, Provided> | undefined,\n own: Runtime,\n runtimeValues: ReadonlySet<object>,\n): Readonly<{\n contributions: readonly FeatureContributionDescriptor[];\n providers: FeatureRecord['providers'];\n}> {\n const builders = createFeatureContributionBuilders<Context, Evaluation>();\n\n if (build === undefined) return Object.freeze({ contributions: Object.freeze([]), providers: Object.freeze([]) });\n\n const value = build({\n own,\n pipe: builders.pipe,\n port: createPortBuilder<Id>(),\n register: builders.register,\n slot: builders.slot,\n });\n\n if (hasDataThen(value)) {\n void Promise.resolve(value).catch(() => undefined);\n\n throw new TypeError('defineFeature provides must return synchronously.');\n }\n\n assertPlainRecord(value, 'defineFeature provides result');\n const entries = dataEntries(value, 'defineFeature provides result');\n const contributionEntries = entries.filter(([, entry]) => isFeatureContributionDeclaration(builders as never, entry));\n const providerEntries = entries.filter(([, entry]) => !isFeatureContributionDeclaration(builders as never, entry));\n\n return Object.freeze({\n contributions: snapshotFeatureContributions(featureId, builders, contributionEntries),\n providers: snapshotPortProviders(runtimeValues, providerEntries),\n });\n}\n\nconst featuresByExportContract = new WeakMap<object, AnyFeature>();\n\ntype FeatureHeader = {\n readonly exportsContract: object;\n readonly id: string;\n readonly importKeys: readonly string[];\n readonly imports: FeatureImportRecord;\n readonly requirementKeys: readonly string[];\n readonly requirements: PortRequirementRecord;\n};\n\n/**\n * The heavy half of a feature: lowering `own`, running `provides` and selecting `exports`. An eager feature runs it\n * at declaration; a lazy one runs the very same code once its body has loaded (D186).\n */\nfunction materializeFeatureImplementation(\n header: FeatureHeader,\n body: LoadedFeatureBody,\n): { readonly own: Readonly<Record<string, unknown>>; readonly record: FeatureRecord } {\n const build =\n optionalFunction<(builder: never) => Readonly<Record<string, unknown>>>(body.own, 'defineFeature own') ??\n (() => ({}));\n const exportDeclaration = snapshotFeatureExportDeclaration(body.exports);\n const buildProvides = optionalFunction<FeatureProvidesFactory<string, never, never, never, never>>(\n body.provides,\n 'defineFeature provides',\n );\n let lowering: FeatureOwnLoweringResult<string, never> | undefined;\n const module = defineGeneratedModule({\n id: header.id,\n runtime: low => {\n lowering = lowerFeatureOwn(low as never, {\n build: build as never,\n id: header.id,\n importKeys: header.importKeys,\n imports: header.imports,\n requirementKeys: header.requirementKeys,\n }) as FeatureOwnLoweringResult<string, never>;\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n const own = publicRuntime as unknown as Readonly<Record<string, unknown>>;\n const runtimeValues = new Set<object>(\n Object.values(own).filter((value): value is object => typeof value === 'object'),\n );\n const { contributions, providers } = buildFeatureProvided(\n header.id,\n buildProvides as never,\n publicRuntime,\n runtimeValues,\n );\n\n return {\n own,\n record: {\n contributions,\n dataDescriptors,\n exports: exportDeclaration.from,\n importKeys: header.importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys: header.requirementKeys,\n requirementScopeKey,\n },\n };\n}\n\n/**\n * D186: a header opens nothing by itself. It registers the identity, the edges and the declared border, and keeps\n * the loader; the body is materialized once, on the first open, and every later open reuses the same code.\n */\nfunction defineLazyFeature(source: Readonly<Record<string, unknown>>, id: string): AnyFeature {\n for (const key of ['exports', 'own'] as const) {\n if (source[key] !== undefined) {\n throw new TypeError(`defineFeature ${id} declares body and ${key}: the implementation belongs to the body.`);\n }\n }\n\n if (typeof source['provides'] === 'function') {\n throw new TypeError(`defineFeature ${id} declares body and a provides factory: the header declares targets only.`);\n }\n\n const load = source['body'];\n\n if (typeof load !== 'function') throw new TypeError('defineFeature body must be a loader function.');\n\n const imports = snapshotFeatureImports(source['imports'] as FeatureImportRecord | undefined);\n const requirements = snapshotFeatureRequirements(source['requires'] as PortRequirementRecord | undefined);\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(dataEntries(requirements, 'defineFeature requires').map(([key]) => key));\n const declared = snapshotDeclaredProvided(id, source['provides']);\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n // The refs of `own` are minted by the body, so the header reads them through the record it materializes later.\n let materializedOwn: Readonly<Record<string, unknown>> = Object.freeze({});\n const feature = Object.freeze({\n exports: exportsContract,\n id: declarationId(id),\n imports,\n get own(): Readonly<Record<string, unknown>> {\n return materializedOwn;\n },\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as AnyFeature;\n const header: FeatureHeader = { exportsContract, id, importKeys, imports, requirementKeys, requirements };\n\n registerFeatureRecord(feature, {\n contributions: declared.contributions,\n dataDescriptors: Object.freeze([]),\n exports: () => ({}),\n importKeys,\n importScopeKey: undefined,\n module: Object.freeze({}),\n providers: declared.providers.map(entry => Object.freeze({ ...entry, target: undefined })) as never,\n requirementKeys,\n requirementScopeKey: undefined,\n });\n registerLazyFeature(feature, {\n load: () => Promise.resolve((load as () => PromiseLike<unknown>)()).then(value => requireFeatureBody(id, value)),\n materialize: (body: LoadedFeatureBody) => {\n const materialized = materializeFeatureImplementation(header, body);\n assertBodyMatchesHeader(id, declared, materialized.record);\n materializedOwn = Object.freeze(materialized.own);\n\n return materialized.record;\n },\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\nfunction defineFeatureImplementation<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n const Requires extends PortRequirementRecord = {},\n const Provided extends FeatureProvidedRecord<Id> = FeatureProvidedRecord<Id>,\n When extends readonly Condition[] = readonly Condition[],\n const Keys extends PropertyKey = keyof FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n>(\n options: ExactKeys<Keys, FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>> &\n FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n): Feature<Id, Imports, Runtime, Exports, Requires, When> {\n const source = snapshotFeatureOptions(options);\n const id = requireString<Id>(source['id'], 'defineFeature id');\n\n if (source['body'] !== undefined) {\n return defineLazyFeature(source, id) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n }\n\n const exportDeclaration = snapshotFeatureExportDeclaration(source['exports']);\n const build =\n optionalFunction<(builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime>(\n source['own'],\n 'defineFeature own',\n ) ?? ((() => ({})) as unknown as (builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime);\n const selectExports = exportDeclaration.from;\n const buildProvides = optionalFunction<\n FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Runtime, Exports>,\n FeatureEvaluationContext<Id, Imports, Runtime, Exports>,\n Runtime,\n Provided\n >\n >(source['provides'], 'defineFeature provides');\n\n const imports = snapshotFeatureImports(source['imports'] as Imports);\n const requirements = snapshotFeatureRequirements(source['requires'] as Requires | undefined);\n const requirementEntries = dataEntries(requirements, 'defineFeature requires');\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(requirementEntries.map(([key]) => key));\n let lowering: FeatureOwnLoweringResult<Id, Runtime> | undefined;\n const module = defineGeneratedModule({\n id,\n runtime: low => {\n lowering = lowerFeatureOwn(low, {\n build,\n id,\n importKeys,\n imports,\n requirementKeys,\n });\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n\n const runtimeValues = new Set(Object.values(publicRuntime));\n const { contributions, providers } = buildFeatureProvided<\n Id,\n FeatureOpenContext<Id, Imports, Runtime, Exports>,\n FeatureEvaluationContext<Id, Imports, Runtime, Exports>,\n Runtime,\n Provided\n >(id, buildProvides, publicRuntime, runtimeValues);\n\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n const feature = Object.freeze({\n exports: exportsContract,\n id: module.id,\n imports,\n own: publicRuntime,\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n registerFeatureRecord(feature, {\n contributions,\n dataDescriptors,\n exports: selectExports,\n importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys,\n requirementScopeKey,\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\n/** `imports` stores the contract, so the application world resolves a feature edge back to the feature (D68). */\nfunction getFeatureByExportContract(contract: object): AnyFeature | undefined {\n return featuresByExportContract.get(contract);\n}\n\n// D186: one word, two forms — the eager triple and the lazy header, so the overload set is the public type.\n// D207: `defineFeature.body` writes the implementation of a header; a member costs no new word of the vocabulary.\nconst defineFeature = Object.assign(defineFeatureImplementation as unknown as DefineFeature, {\n body: featureBody,\n preload: preloadFeatureBody,\n});\n\nfunction getFeatureModule<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n>(feature: Feature<Id, Imports, Runtime, Exports>): ModuleDefinition<Id> {\n return requireFeatureRecord(feature).module as ModuleDefinition<Id>;\n}\n\nfunction getFeatureContributionDescriptors(feature: AnyFeature): FeatureRecord['contributions'] {\n return requireFeatureRecord(feature).contributions;\n}\n\nexport { defineFeature, getFeatureByExportContract, getFeatureContributionDescriptors, getFeatureModule, isFeature };\nexport type {\n AnyFeature,\n Feature,\n FeatureConditionsOf,\n FeatureExportRecord,\n FeatureExportsOf,\n FeatureIdOf,\n FeatureImportRecord,\n FeatureImportsOf,\n FeatureImportValues,\n FeatureOwnRecord,\n FeatureRequirementsOf,\n} from './feature-authoring-types';\n"],"names":["defineGeneratedModule","defineModule","hasDataThen","value","source","descriptor","buildFeatureProvided","featureId","build","own","runtimeValues","builders","createFeatureContributionBuilders","createPortBuilder","assertPlainRecord","entries","dataEntries","contributionEntries","entry","isFeatureContributionDeclaration","providerEntries","snapshotFeatureContributions","snapshotPortProviders","featuresByExportContract","materializeFeatureImplementation","header","body","optionalFunction","exportDeclaration","snapshotFeatureExportDeclaration","buildProvides","lowering","module","low","lowerFeatureOwn","dataDescriptors","importScopeKey","publicRuntime","requirementScopeKey","contributions","providers","defineLazyFeature","id","key","load","imports","snapshotFeatureImports","requirements","snapshotFeatureRequirements","importKeys","requirementKeys","declared","snapshotDeclaredProvided","exportsContract","defineFeatureContract","materializedOwn","feature","declarationId","snapshotFeatureConditions","registerFeatureRecord","registerLazyFeature","requireFeatureBody","materialized","assertBodyMatchesHeader","defineFeatureImplementation","options","snapshotFeatureOptions","requireString","selectExports","requirementEntries","getFeatureByExportContract","contract","defineFeature","featureBody","preloadFeatureBody","getFeatureContributionDescriptors","requireFeatureRecord"],"mappings":"0mCAqDA,MAAMA,EAAwBC,EAE9B,SAASC,EAAYC,EAAc,CACjC,IAAK,OAAOA,GAAU,UAAYA,IAAU,OAAS,OAAOA,GAAU,WAAY,MAAO,GAEzF,IAAIC,EAAwBD,EAE5B,KAAOC,IAAW,MAAM,CACtB,MAAMC,EAAa,OAAO,yBAAyBD,EAAQ,MAAM,EAEjE,GAAIC,IAAe,OAAW,MAAO,UAAWA,GAAc,OAAOA,EAAW,OAAU,WAE1FD,EAAS,OAAO,eAAeA,CAAM,CACvC,CAEA,MAAO,EACT,CAGA,SAASE,EAOPC,EACAC,EACAC,EACAC,EAAkC,CAKlC,MAAMC,EAAWC,EAAiC,EAElD,GAAIJ,IAAU,OAAW,OAAO,OAAO,OAAO,CAAE,cAAe,OAAO,OAAO,EAAE,EAAG,UAAW,OAAO,OAAO,CAAA,CAAE,CAAC,CAAE,EAEhH,MAAML,EAAQK,EAAM,CAClB,IAAAC,EACA,KAAME,EAAS,KACf,KAAME,EAAiB,EACvB,SAAUF,EAAS,SACnB,KAAMA,EAAS,IAChB,CAAA,EAED,GAAIT,EAAYC,CAAK,EACnB,MAAK,QAAQ,QAAQA,CAAK,EAAE,MAAM,IAAA,EAAe,EAE3C,IAAI,UAAU,mDAAmD,EAGzEW,EAAkBX,EAAO,+BAA+B,EACxD,MAAMY,EAAUC,EAAYb,EAAO,+BAA+B,EAC5Dc,EAAsBF,EAAQ,OAAO,CAAC,CAAA,CAAGG,CAAK,IAAMC,EAAiCR,EAAmBO,CAAK,CAAC,EAC9GE,EAAkBL,EAAQ,OAAO,CAAC,CAAA,CAAGG,CAAK,IAAM,CAACC,EAAiCR,EAAmBO,CAAK,CAAC,EAEjH,OAAO,OAAO,OAAO,CACnB,cAAeG,EAA6Bd,EAAWI,EAAUM,CAAmB,EACpF,UAAWK,EAAsBZ,EAAeU,CAAe,CAChE,CAAA,CACH,CAEA,MAAMG,EAA2B,IAAI,QAerC,SAASC,GACPC,EACAC,EAAuB,CAEvB,MAAMlB,EACJmB,EAAwED,EAAK,IAAK,mBAAmB,IACpG,KAAO,CAAA,IACJE,EAAoBC,EAAiCH,EAAK,OAAO,EACjEI,EAAgBH,EACpBD,EAAK,SACL,wBAAwB,EAE1B,IAAIK,EACJ,MAAMC,EAAShC,EAAsB,CACnC,GAAIyB,EAAO,GACX,QAASQ,IACPF,EAAWG,EAAgBD,EAAc,CACvC,MAAOzB,EACP,GAAIiB,EAAO,GACX,WAAYA,EAAO,WACnB,QAASA,EAAO,QAChB,gBAAiBA,EAAO,eACzB,CAAA,EAEMM,EAAS,eAEnB,CAAA,EAED,GAAIA,IAAa,OAAW,MAAM,IAAI,UAAU,oDAAoD,EAEpG,KAAM,CAAE,gBAAAI,EAAiB,eAAAC,EAAgB,cAAAC,EAAe,oBAAAC,CAAmB,EAAKP,EAC1EtB,EAAM4B,EACN3B,EAAgB,IAAI,IACxB,OAAO,OAAOD,CAAG,EAAE,OAAQN,GAA2B,OAAOA,GAAU,QAAQ,CAAC,EAE5E,CAAE,cAAAoC,EAAe,UAAAC,CAAS,EAAKlC,EACnCmB,EAAO,GACPK,EACAO,EACA3B,CAAa,EAGf,MAAO,CACL,IAAAD,EACA,OAAQ,CACN,cAAA8B,EACA,gBAAAJ,EACA,QAASP,EAAkB,KAC3B,WAAYH,EAAO,WACnB,eAAAW,EACA,OAAAJ,EACA,UAAAQ,EACA,gBAAiBf,EAAO,gBACxB,oBAAAa,CACD,EAEL,CAMA,SAASG,GAAkBrC,EAA2CsC,EAAU,CAC9E,UAAWC,IAAO,CAAC,UAAW,KAAK,EACjC,GAAIvC,EAAOuC,CAAG,IAAM,OAClB,MAAM,IAAI,UAAU,iBAAiBD,CAAE,sBAAsBC,CAAG,2CAA2C,EAI/G,GAAI,OAAOvC,EAAO,UAAgB,WAChC,MAAM,IAAI,UAAU,iBAAiBsC,CAAE,0EAA0E,EAGnH,MAAME,EAAOxC,EAAO,KAEpB,GAAI,OAAOwC,GAAS,WAAY,MAAM,IAAI,UAAU,+CAA+C,EAEnG,MAAMC,EAAUC,EAAuB1C,EAAO,OAA6C,EACrF2C,EAAeC,EAA4B5C,EAAO,QAAgD,EAClG6C,EAAa,OAAO,OAAOjC,EAAY6B,EAAS,uBAAuB,EAAE,IAAI,CAAC,CAACF,CAAG,IAAMA,CAAG,CAAC,EAC5FO,EAAkB,OAAO,OAAOlC,EAAY+B,EAAc,wBAAwB,EAAE,IAAI,CAAC,CAACJ,CAAG,IAAMA,CAAG,CAAC,EACvGQ,EAAWC,EAAyBV,EAAItC,EAAO,QAAW,EAC1DiD,EAAkBC,EAA0B,GAAGZ,CAAE,UAAU,EAEjE,IAAIa,EAAqD,OAAO,OAAO,EAAE,EACzE,MAAMC,EAAU,OAAO,OAAO,CAC5B,QAASH,EACT,GAAII,EAAcf,CAAE,EACpB,QAAAG,EACA,IAAI,KAAG,CACL,OAAOU,CACT,EACA,SAAUR,EACV,KAAMW,EAA0BtD,EAAO,IAAO,CAC/C,CAAA,EACKqB,EAAwB,CAAmB,GAAAiB,EAAI,WAAAO,EAAY,QAAAJ,EAAS,gBAAAK,GAE1E,OAAAS,EAAsBH,EAAS,CAC7B,cAAeL,EAAS,cACxB,gBAAiB,OAAO,OAAO,EAAE,EACjC,QAAS,KAAO,CAAA,GAChB,WAAAF,EACA,eAAgB,OAChB,OAAQ,OAAO,OAAO,EAAE,EACxB,UAAWE,EAAS,UAAU,IAAIjC,GAAS,OAAO,OAAO,CAAE,GAAGA,EAAO,OAAQ,MAAS,CAAE,CAAC,EACzF,gBAAAgC,EACA,oBAAqB,MACtB,CAAA,EACDU,EAAoBJ,EAAS,CAC3B,KAAM,IAAM,QAAQ,QAASZ,EAAmC,CAAE,EAAE,KAAKzC,GAAS0D,EAAmBnB,EAAIvC,CAAK,CAAC,EAC/G,YAAcuB,GAA2B,CACvC,MAAMoC,EAAetC,GAAiCC,EAAQC,CAAI,EAClE,OAAAqC,EAAwBrB,EAAIS,EAAUW,EAAa,MAAM,EACzDP,EAAkB,OAAO,OAAOO,EAAa,GAAG,EAEzCA,EAAa,MACtB,CACD,CAAA,EACDvC,EAAyB,IAAI8B,EAAiBG,CAAO,EAE9CA,CACT,CAEA,SAASQ,GAUPC,EACuE,CAEvE,MAAM7D,EAAS8D,EAAuBD,CAAO,EACvCvB,EAAKyB,EAAkB/D,EAAO,GAAO,kBAAkB,EAE7D,GAAIA,EAAO,OAAY,OACrB,OAAOqC,GAAkBrC,EAAQsC,CAAE,EAGrC,MAAMd,EAAoBC,EAAiCzB,EAAO,OAAU,EACtEI,EACJmB,EACEvB,EAAO,IACP,mBAAmB,IACd,KAAO,CAAA,IACVgE,EAAgBxC,EAAkB,KAClCE,EAAgBH,EAQpBvB,EAAO,SAAa,wBAAwB,EAExCyC,EAAUC,EAAuB1C,EAAO,OAAqB,EAC7D2C,EAAeC,EAA4B5C,EAAO,QAAmC,EACrFiE,EAAqBrD,EAAY+B,EAAc,wBAAwB,EACvEE,EAAa,OAAO,OAAOjC,EAAY6B,EAAS,uBAAuB,EAAE,IAAI,CAAC,CAACF,CAAG,IAAMA,CAAG,CAAC,EAC5FO,EAAkB,OAAO,OAAOmB,EAAmB,IAAI,CAAC,CAAC1B,CAAG,IAAMA,CAAG,CAAC,EAC5E,IAAIZ,EACJ,MAAMC,EAAShC,EAAsB,CACnC,GAAA0C,EACA,QAAST,IACPF,EAAWG,EAAgBD,EAAK,CAC9B,MAAAzB,EACA,GAAAkC,EACA,WAAAO,EACA,QAAAJ,EACA,gBAAAK,CACD,CAAA,EAEMnB,EAAS,eAEnB,CAAA,EAED,GAAIA,IAAa,OAAW,MAAM,IAAI,UAAU,oDAAoD,EAEpG,KAAM,CAAE,gBAAAI,EAAiB,eAAAC,EAAgB,cAAAC,EAAe,oBAAAC,CAAmB,EAAKP,EAE1ErB,EAAgB,IAAI,IAAI,OAAO,OAAO2B,CAAa,CAAC,EACpD,CAAE,cAAAE,EAAe,UAAAC,GAAclC,EAMnCoC,EAAIZ,EAAeO,EAAe3B,CAAa,EAE3C2C,EAAkBC,EAA0B,GAAGZ,CAAE,UAAU,EAC3Dc,EAAU,OAAO,OAAO,CAC5B,QAASH,EACT,GAAIrB,EAAO,GACX,QAAAa,EACA,IAAKR,EACL,SAAUU,EACV,KAAMW,EAA0BtD,EAAO,IAAO,CAC/C,CAAA,EACD,OAAAuD,EAAsBH,EAAS,CAC7B,cAAAjB,EACA,gBAAAJ,EACA,QAASiC,EACT,WAAAnB,EACA,eAAAb,EACA,OAAAJ,EACA,UAAAQ,EACA,gBAAAU,EACA,oBAAAZ,CACD,CAAA,EACDf,EAAyB,IAAI8B,EAAiBG,CAAO,EAE9CA,CACT,CAGA,SAASc,GAA2BC,EAAgB,CAClD,OAAOhD,EAAyB,IAAIgD,CAAQ,CAC9C,CAIA,MAAMC,GAAgB,OAAO,OAAOR,GAAyD,CAC3F,KAAMS,EACN,QAASC,CACV,CAAA,EAWD,SAASC,GAAkCnB,EAAmB,CAC5D,OAAOoB,EAAqBpB,CAAO,EAAE,aACvC"}
1
+ {"version":3,"file":"feature-authoring.js","sources":["../src/feature-authoring.ts"],"sourcesContent":["import { declarationId } from '@opetope/core';\n\nimport { snapshotFeatureConditions } from './condition';\nimport type { Condition } from './condition';\nimport type {\n AnyFeature,\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureImportRecord,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n FeatureRecord,\n} from './feature-authoring-types';\nimport { featureBody, preloadFeatureBody, requireFeatureBody } from './feature-body';\nimport type { LoadedFeatureBody } from './feature-body';\nimport { defineFeatureContract } from './feature-contract';\nimport {\n createFeatureContributionBuilders,\n isFeatureContributionDeclaration,\n snapshotFeatureContributions,\n} from './feature-contribution';\nimport type { FeatureContributionDescriptor } from './feature-contribution';\nimport type { DefineFeature, FeatureInput } from './feature-definition-api';\nimport {\n isFeature,\n optionalFunction,\n registerFeatureRecord,\n requireFeatureRecord,\n requireString,\n snapshotFeatureExportDeclaration,\n snapshotFeatureImports,\n snapshotFeatureOptions,\n snapshotFeatureRequirements,\n} from './feature-definition-support';\nimport { assertBodyMatchesHeader, registerLazyFeature, snapshotDeclaredProvided } from './feature-lazy';\nimport { lowerFeatureOwn } from './feature-own-lowering';\nimport type { FeatureOwnLoweringResult } from './feature-own-lowering';\nimport { createPortBuilder, snapshotPortProviders } from './feature-port';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport { defineModule } from './public-module';\nimport type { ModuleDefinition, ModuleRuntimeBuilder, ModuleRuntimeRecord } from './public-module';\n\ntype DefineGeneratedModule = <Id extends string, Runtime extends ModuleRuntimeRecord<Id>>(options: {\n readonly id: Id;\n readonly runtime: (builder: ModuleRuntimeBuilder<Id>) => Runtime;\n}) => ModuleDefinition<Id, Runtime>;\n\n// The public defineModule guard rejects union author records. Feature lowering has already applied\n// the same guard before it appends collision-free private refs to one concrete `own` record.\nconst defineGeneratedModule = defineModule as DefineGeneratedModule;\n\nfunction hasDataThen(value: unknown): boolean {\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n\n let source: object | null = value;\n\n while (source !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(source, 'then');\n\n if (descriptor !== undefined) return 'value' in descriptor && typeof descriptor.value === 'function';\n\n source = Object.getPrototypeOf(source) as object | null;\n }\n\n return false;\n}\n\n/** `provides` returns ports and contributions in one record; each entry is split by the builder that made it. */\nfunction buildFeatureProvided<\n Id extends string,\n Context,\n Evaluation,\n Runtime extends FeatureOwnRecord<Id>,\n Provided extends FeatureProvidedRecord<Id>,\n>(\n featureId: string,\n build: FeatureProvidesFactory<Id, Context, Evaluation, Runtime, Provided> | undefined,\n): Readonly<{\n contributions: readonly FeatureContributionDescriptor[];\n providers: FeatureRecord['providers'];\n}> {\n const builders = createFeatureContributionBuilders<Context, Evaluation>();\n\n if (build === undefined) return Object.freeze({ contributions: Object.freeze([]), providers: Object.freeze([]) });\n\n const value = build({\n pipe: builders.pipe,\n port: createPortBuilder(),\n register: builders.register,\n slot: builders.slot,\n });\n\n if (hasDataThen(value)) {\n void Promise.resolve(value).catch(() => undefined);\n\n throw new TypeError('defineFeature provides must return synchronously.');\n }\n\n assertPlainRecord(value, 'defineFeature provides result');\n const entries = dataEntries(value, 'defineFeature provides result');\n const contributionEntries = entries.filter(([, entry]) => isFeatureContributionDeclaration(builders as never, entry));\n const providerEntries = entries.filter(([, entry]) => !isFeatureContributionDeclaration(builders as never, entry));\n\n return Object.freeze({\n contributions: snapshotFeatureContributions(featureId, builders, contributionEntries),\n providers: snapshotPortProviders(providerEntries),\n });\n}\n\nconst featuresByExportContract = new WeakMap<object, AnyFeature>();\n\ntype FeatureHeader = {\n readonly exportsContract: object;\n readonly id: string;\n readonly importKeys: readonly string[];\n readonly imports: FeatureImportRecord;\n readonly requirementKeys: readonly string[];\n readonly requirements: PortRequirementRecord;\n};\n\n/**\n * The heavy half of a feature: lowering `own`, running `provides` and selecting `exports`. An eager feature runs it\n * at declaration; a lazy one runs the very same code once its body has loaded (D186).\n */\nfunction materializeFeatureImplementation(\n header: FeatureHeader,\n body: LoadedFeatureBody,\n): { readonly own: Readonly<Record<string, unknown>>; readonly record: FeatureRecord } {\n const build =\n optionalFunction<(builder: never) => Readonly<Record<string, unknown>>>(body.own, 'defineFeature own') ??\n (() => ({}));\n const exportDeclaration = snapshotFeatureExportDeclaration(body.exports);\n const buildProvides = optionalFunction<FeatureProvidesFactory<string, never, never, never, never>>(\n body.provides,\n 'defineFeature provides',\n );\n let lowering: FeatureOwnLoweringResult<string, never> | undefined;\n const module = defineGeneratedModule({\n id: header.id,\n runtime: low => {\n lowering = lowerFeatureOwn(low as never, {\n build: build as never,\n id: header.id,\n importKeys: header.importKeys,\n imports: header.imports,\n requirementKeys: header.requirementKeys,\n }) as FeatureOwnLoweringResult<string, never>;\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n const own = publicRuntime as unknown as Readonly<Record<string, unknown>>;\n const { contributions, providers } = buildFeatureProvided(header.id, buildProvides as never);\n\n return {\n own,\n record: {\n contributions,\n dataDescriptors,\n exports: exportDeclaration.from,\n importKeys: header.importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys: header.requirementKeys,\n requirementScopeKey,\n },\n };\n}\n\n/**\n * D186: a header opens nothing by itself. It registers the identity, the edges and the declared border, and keeps\n * the loader; the body is materialized once, on the first open, and every later open reuses the same code.\n */\nfunction defineLazyFeature(source: Readonly<Record<string, unknown>>, id: string): AnyFeature {\n for (const key of ['exports', 'own'] as const) {\n if (source[key] !== undefined) {\n throw new TypeError(`defineFeature ${id} declares body and ${key}: the implementation belongs to the body.`);\n }\n }\n\n if (typeof source['provides'] === 'function') {\n throw new TypeError(`defineFeature ${id} declares body and a provides factory: the header declares targets only.`);\n }\n\n const load = source['body'];\n\n if (typeof load !== 'function') throw new TypeError('defineFeature body must be a loader function.');\n\n const imports = snapshotFeatureImports(source['imports'] as FeatureImportRecord | undefined);\n const requirements = snapshotFeatureRequirements(source['requires'] as PortRequirementRecord | undefined);\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(dataEntries(requirements, 'defineFeature requires').map(([key]) => key));\n const declared = snapshotDeclaredProvided(id, source['provides']);\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n // The refs of `own` are minted by the body, so the header reads them through the record it materializes later.\n let materializedOwn: Readonly<Record<string, unknown>> = Object.freeze({});\n const feature = Object.freeze({\n exports: exportsContract,\n id: declarationId(id),\n imports,\n get own(): Readonly<Record<string, unknown>> {\n return materializedOwn;\n },\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as AnyFeature;\n const header: FeatureHeader = { exportsContract, id, importKeys, imports, requirementKeys, requirements };\n\n registerFeatureRecord(feature, {\n contributions: declared.contributions,\n dataDescriptors: Object.freeze([]),\n exports: () => ({}),\n importKeys,\n importScopeKey: undefined,\n module: Object.freeze({}),\n providers: declared.providers.map(entry => Object.freeze({ ...entry, target: undefined })) as never,\n requirementKeys,\n requirementScopeKey: undefined,\n });\n registerLazyFeature(feature, {\n load: () => Promise.resolve((load as () => PromiseLike<unknown>)()).then(value => requireFeatureBody(id, value)),\n materialize: (body: LoadedFeatureBody) => {\n const materialized = materializeFeatureImplementation(header, body);\n assertBodyMatchesHeader(id, declared, materialized.record);\n materializedOwn = Object.freeze(materialized.own);\n\n return materialized.record;\n },\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\nfunction defineFeatureImplementation<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n const Requires extends PortRequirementRecord = {},\n const Provided extends FeatureProvidedRecord<Id> = FeatureProvidedRecord<Id>,\n When extends readonly Condition[] = readonly Condition[],\n const Keys extends PropertyKey = keyof FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n>(\n options: ExactKeys<Keys, FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>> &\n FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n): Feature<Id, Imports, Runtime, Exports, Requires, When> {\n const source = snapshotFeatureOptions(options);\n const id = requireString<Id>(source['id'], 'defineFeature id');\n\n if (source['body'] !== undefined) {\n return defineLazyFeature(source, id) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n }\n\n const exportDeclaration = snapshotFeatureExportDeclaration(source['exports']);\n const build =\n optionalFunction<(builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime>(\n source['own'],\n 'defineFeature own',\n ) ?? ((() => ({})) as unknown as (builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime);\n const selectExports = exportDeclaration.from;\n const buildProvides = optionalFunction<\n FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Runtime>,\n FeatureEvaluationContext<Id, Imports, Runtime>,\n Runtime,\n Provided\n >\n >(source['provides'], 'defineFeature provides');\n\n const imports = snapshotFeatureImports(source['imports'] as Imports);\n const requirements = snapshotFeatureRequirements(source['requires'] as Requires | undefined);\n const requirementEntries = dataEntries(requirements, 'defineFeature requires');\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(requirementEntries.map(([key]) => key));\n let lowering: FeatureOwnLoweringResult<Id, Runtime> | undefined;\n const module = defineGeneratedModule({\n id,\n runtime: low => {\n lowering = lowerFeatureOwn(low, {\n build,\n id,\n importKeys,\n imports,\n requirementKeys,\n });\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n\n const { contributions, providers } = buildFeatureProvided<\n Id,\n FeatureOpenContext<Id, Imports, Runtime>,\n FeatureEvaluationContext<Id, Imports, Runtime>,\n Runtime,\n Provided\n >(id, buildProvides);\n\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n const feature = Object.freeze({\n exports: exportsContract,\n id: module.id,\n imports,\n own: publicRuntime,\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n registerFeatureRecord(feature, {\n contributions,\n dataDescriptors,\n exports: selectExports,\n importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys,\n requirementScopeKey,\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\n/** `imports` stores the contract, so the application world resolves a feature edge back to the feature (D68). */\nfunction getFeatureByExportContract(contract: object): AnyFeature | undefined {\n return featuresByExportContract.get(contract);\n}\n\n// D186: one word, two forms — the eager triple and the lazy header, so the overload set is the public type.\n// D207: `defineFeature.body` writes the implementation of a header; a member costs no new word of the vocabulary.\nconst defineFeature = Object.assign(defineFeatureImplementation as unknown as DefineFeature, {\n body: featureBody,\n preload: preloadFeatureBody,\n});\n\nfunction getFeatureModule<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n>(feature: Feature<Id, Imports, Runtime, Exports>): ModuleDefinition<Id> {\n return requireFeatureRecord(feature).module as ModuleDefinition<Id>;\n}\n\nfunction getFeatureContributionDescriptors(feature: AnyFeature): FeatureRecord['contributions'] {\n return requireFeatureRecord(feature).contributions;\n}\n\nexport { defineFeature, getFeatureByExportContract, getFeatureContributionDescriptors, getFeatureModule, isFeature };\nexport type {\n AnyFeature,\n Feature,\n FeatureConditionsOf,\n FeatureExportRecord,\n FeatureExportsOf,\n FeatureIdOf,\n FeatureImportRecord,\n FeatureImportsOf,\n FeatureImportValues,\n FeatureOwnRecord,\n FeatureRequirementsOf,\n} from './feature-authoring-types';\n"],"names":["defineGeneratedModule","defineModule","hasDataThen","value","source","descriptor","buildFeatureProvided","featureId","build","builders","createFeatureContributionBuilders","createPortBuilder","assertPlainRecord","entries","dataEntries","contributionEntries","entry","isFeatureContributionDeclaration","providerEntries","snapshotFeatureContributions","snapshotPortProviders","featuresByExportContract","materializeFeatureImplementation","header","body","optionalFunction","exportDeclaration","snapshotFeatureExportDeclaration","buildProvides","lowering","module","low","lowerFeatureOwn","dataDescriptors","importScopeKey","publicRuntime","requirementScopeKey","own","contributions","providers","defineLazyFeature","id","key","load","imports","snapshotFeatureImports","requirements","snapshotFeatureRequirements","importKeys","requirementKeys","declared","snapshotDeclaredProvided","exportsContract","defineFeatureContract","materializedOwn","feature","declarationId","snapshotFeatureConditions","registerFeatureRecord","registerLazyFeature","requireFeatureBody","materialized","assertBodyMatchesHeader","defineFeatureImplementation","options","snapshotFeatureOptions","requireString","selectExports","requirementEntries","getFeatureByExportContract","contract","defineFeature","featureBody","preloadFeatureBody","getFeatureContributionDescriptors","requireFeatureRecord"],"mappings":"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"}
@@ -22,7 +22,7 @@ interface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord>
22
22
  type FeatureBodyInput<Id extends string, Imports extends FeatureImportRecord, Requires extends PortRequirementRecord, Own extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord, Provided extends FeatureProvidedRecord<Id>> = {
23
23
  readonly exports?: FeatureExportsFactory<Id, Own, Exports>;
24
24
  readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);
25
- readonly provides?: FeatureProvidesFactory<Id, FeatureOpenContext<Id, Imports, Own, Exports>, FeatureEvaluationContext<Id, Imports, Own, Exports>, Own, Provided>;
25
+ readonly provides?: FeatureProvidesFactory<Id, FeatureOpenContext<Id, Imports, Own>, FeatureEvaluationContext<Id, Imports, Own>, Own, Provided>;
26
26
  };
27
27
  type FeatureImportRecordOf<Header> = Header extends Feature<infer _Id, infer Imports, infer _Own, infer _Exports, infer _Requires, infer _When> ? Imports : never;
28
28
  type FeatureExportRecordOf<Header> = Header extends Feature<infer _Id, infer _Imports, infer _Own, infer Exports, infer _Requires, infer _When> ? Exports : never;
@@ -1 +1 @@
1
- {"version":3,"file":"feature-body.js","sources":["../src/feature-body.ts"],"sourcesContent":["import type { Condition } from './condition';\nimport type {\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureExportsFactory,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n} from './feature-authoring-types';\nimport type { FeatureImportRecord } from './feature-contract';\nimport { isFeature } from './feature-definition-support';\nimport { getLazyFeature, loadFeatureBody } from './feature-lazy';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport type { ExactNonUnionRuntime } from './public-module';\n\n/**\n * D186: the header of a feature and its body are two files. The header is the identity every consumer imports; the\n * body is the implementation the loader brings in later. `FeatureBody<Exports>` is the narrow view the header names\n * in the return type of its loader — it carries the export contract and nothing else, so the header never depends on\n * the body module and the two types cannot form a cycle.\n */\ninterface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord> {\n readonly exports?: (context: never) => Exports;\n readonly own?: unknown;\n readonly provides?: unknown;\n}\n\n/**\n * The body as its own file writes it: `own`, `exports` and `provides` of the declared header, with the builders typed\n * from the header's id, imports and requirements. The record is plain data — the header already owns the identity,\n * so a body needs no second authentic declaration.\n */\ntype FeatureBodyInput<\n Id extends string,\n Imports extends FeatureImportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id>,\n Exports extends FeatureExportRecord,\n Provided extends FeatureProvidedRecord<Id>,\n> = {\n readonly exports?: FeatureExportsFactory<Id, Own, Exports>;\n readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);\n readonly provides?: FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Own, Exports>,\n FeatureEvaluationContext<Id, Imports, Own, Exports>,\n Own,\n Provided\n >;\n};\n\ntype FeatureImportRecordOf<Header> =\n Header extends Feature<infer _Id, infer Imports, infer _Own, infer _Exports, infer _Requires, infer _When>\n ? Imports\n : never;\ntype FeatureExportRecordOf<Header> =\n Header extends Feature<infer _Id, infer _Imports, infer _Own, infer Exports, infer _Requires, infer _When>\n ? Exports\n : never;\ntype FeatureRequirementRecordOf<Header> =\n Header extends Feature<infer _Id, infer _Imports, infer _Own, infer _Exports, infer Requires, infer _When>\n ? Requires\n : never;\ntype FeatureHeaderIdOf<Header> =\n Header extends Feature<infer Id, infer _Imports, infer _Own, infer _Exports, infer _Requires, infer _When>\n ? Id\n : never;\n\n/** What the body file annotates itself with: everything the header already fixed, and the own record it invents. */\ntype FeatureBodyOf<\n Header,\n Own extends FeatureOwnRecord<FeatureHeaderIdOf<Header>> = FeatureOwnRecord<FeatureHeaderIdOf<Header>>,\n Provided extends FeatureProvidedRecord<FeatureHeaderIdOf<Header>> = FeatureProvidedRecord<FeatureHeaderIdOf<Header>>,\n> = FeatureBodyInput<\n FeatureHeaderIdOf<Header>,\n FeatureImportRecordOf<Header>,\n FeatureRequirementRecordOf<Header>,\n Own,\n FeatureExportRecordOf<Header>,\n Provided\n>;\n\ntype LoadedFeatureBody = {\n readonly exports?: unknown;\n readonly own?: unknown;\n readonly provides?: unknown;\n};\n\nconst bodyKeys = new Set(['exports', 'own', 'provides']);\n\nfunction assertPlainBodyRecord(featureId: string, value: unknown): asserts value is object {\n if (typeof value !== 'object' || value === null) {\n throw new TypeError(`Feature ${featureId} body must be a record of own, exports and provides.`);\n }\n\n const prototype: unknown = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`Feature ${featureId} body must be a plain object record.`);\n }\n}\n\n/** The loader is foreign code, so what it returns is checked before anything of the feature is materialized. */\nfunction requireFeatureBody(featureId: string, value: unknown): LoadedFeatureBody {\n assertPlainBodyRecord(featureId, value);\n\n for (const key of Reflect.ownKeys(value)) {\n if (typeof key !== 'string' || !bodyKeys.has(key)) {\n throw new TypeError(`Feature ${featureId} body contains unknown field ${String(key)}.`);\n }\n }\n\n return value;\n}\n\n/**\n * D207: the body is written through `defineFeature.body`, a member of the word that already names a feature. A\n * function is what lets TypeScript infer `own` for `exports` and `provides`, exactly as the eager form does, and a\n * member spends no new word on the author's vocabulary. It mints no identity — the header already is the feature.\n */\nfunction featureBody<\n Id extends string,\n Imports extends FeatureImportRecord,\n Exports extends FeatureExportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id> = {},\n Provided extends FeatureProvidedRecord<Id> = {},\n>(\n header: Feature<Id, Imports, FeatureOwnRecord<Id>, Exports, Requires, readonly Condition[]>,\n body: FeatureBodyInput<Id, Imports, Requires, Own, Exports, Provided>,\n): FeatureBody<Exports> {\n if (!isFeature(header)) throw new TypeError('featureBody takes the feature its header declared.');\n\n return requireFeatureBody(header.id, body) as FeatureBody<Exports>;\n}\n\n/**\n * D186 asked for a way to fetch the code without opening anything: a host that knows a feature is about to be\n * needed — a hovered entry point, an idle callback — warms its chunk here. It opens no instance, holds no lease and\n * publishes no state; a failure is the caller's to observe, and the next open tries the loader again.\n */\nfunction preloadFeatureBody(header: unknown): Promise<void> {\n if (!isFeature(header)) throw new TypeError('defineFeature.preload takes a feature declaration.');\n\n if (getLazyFeature(header) === undefined) return Promise.resolve();\n\n return loadFeatureBody(header).then(() => undefined);\n}\n\nexport { featureBody, preloadFeatureBody, requireFeatureBody };\nexport type { FeatureBody, FeatureBodyOf, LoadedFeatureBody };\n"],"names":["bodyKeys","assertPlainBodyRecord","featureId","value","prototype","requireFeatureBody","key","featureBody","header","body","isFeature","preloadFeatureBody","getLazyFeature","loadFeatureBody"],"mappings":"oIAyFA,MAAMA,EAAW,IAAI,IAAI,CAAC,UAAW,MAAO,UAAU,CAAC,EAEvD,SAASC,EAAsBC,EAAmBC,EAAc,CAC9D,GAAI,OAAOA,GAAU,UAAYA,IAAU,KACzC,MAAM,IAAI,UAAU,WAAWD,CAAS,sDAAsD,EAGhG,MAAME,EAAqB,OAAO,eAAeD,CAAK,EAEtD,GAAIC,IAAc,OAAO,WAAaA,IAAc,KAClD,MAAM,IAAI,UAAU,WAAWF,CAAS,sCAAsC,CAElF,CAGA,SAASG,EAAmBH,EAAmBC,EAAc,CAC3DF,EAAsBC,EAAWC,CAAK,EAEtC,UAAWG,KAAO,QAAQ,QAAQH,CAAK,EACrC,GAAI,OAAOG,GAAQ,UAAY,CAACN,EAAS,IAAIM,CAAG,EAC9C,MAAM,IAAI,UAAU,WAAWJ,CAAS,gCAAgC,OAAOI,CAAG,CAAC,GAAG,EAI1F,OAAOH,CACT,CAOA,SAASI,EAQPC,EACAC,EAAqE,CAErE,GAAI,CAACC,EAAUF,CAAM,EAAG,MAAM,IAAI,UAAU,oDAAoD,EAEhG,OAAOH,EAAmBG,EAAO,GAAIC,CAAI,CAC3C,CAOA,SAASE,EAAmBH,EAAe,CACzC,GAAI,CAACE,EAAUF,CAAM,EAAG,MAAM,IAAI,UAAU,oDAAoD,EAEhG,OAAII,EAAeJ,CAAM,IAAM,OAAkB,QAAQ,QAAO,EAEzDK,EAAgBL,CAAM,EAAE,KAAK,IAAA,EAAe,CACrD"}
1
+ {"version":3,"file":"feature-body.js","sources":["../src/feature-body.ts"],"sourcesContent":["import type { Condition } from './condition';\nimport type {\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureExportsFactory,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n} from './feature-authoring-types';\nimport type { FeatureImportRecord } from './feature-contract';\nimport { isFeature } from './feature-definition-support';\nimport { getLazyFeature, loadFeatureBody } from './feature-lazy';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport type { ExactNonUnionRuntime } from './public-module';\n\n/**\n * D186: the header of a feature and its body are two files. The header is the identity every consumer imports; the\n * body is the implementation the loader brings in later. `FeatureBody<Exports>` is the narrow view the header names\n * in the return type of its loader — it carries the export contract and nothing else, so the header never depends on\n * the body module and the two types cannot form a cycle.\n */\ninterface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord> {\n readonly exports?: (context: never) => Exports;\n readonly own?: unknown;\n readonly provides?: unknown;\n}\n\n/**\n * The body as its own file writes it: `own`, `exports` and `provides` of the declared header, with the builders typed\n * from the header's id, imports and requirements. The record is plain data — the header already owns the identity,\n * so a body needs no second authentic declaration.\n */\ntype FeatureBodyInput<\n Id extends string,\n Imports extends FeatureImportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id>,\n Exports extends FeatureExportRecord,\n Provided extends FeatureProvidedRecord<Id>,\n> = {\n readonly exports?: FeatureExportsFactory<Id, Own, Exports>;\n readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);\n readonly provides?: FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Own>,\n FeatureEvaluationContext<Id, Imports, Own>,\n Own,\n Provided\n >;\n};\n\ntype FeatureImportRecordOf<Header> =\n Header extends Feature<infer _Id, infer Imports, infer _Own, infer _Exports, infer _Requires, infer _When>\n ? Imports\n : never;\ntype FeatureExportRecordOf<Header> =\n Header extends Feature<infer _Id, infer _Imports, infer _Own, infer Exports, infer _Requires, infer _When>\n ? Exports\n : never;\ntype FeatureRequirementRecordOf<Header> =\n Header extends Feature<infer _Id, infer _Imports, infer _Own, infer _Exports, infer Requires, infer _When>\n ? Requires\n : never;\ntype FeatureHeaderIdOf<Header> =\n Header extends Feature<infer Id, infer _Imports, infer _Own, infer _Exports, infer _Requires, infer _When>\n ? Id\n : never;\n\n/** What the body file annotates itself with: everything the header already fixed, and the own record it invents. */\ntype FeatureBodyOf<\n Header,\n Own extends FeatureOwnRecord<FeatureHeaderIdOf<Header>> = FeatureOwnRecord<FeatureHeaderIdOf<Header>>,\n Provided extends FeatureProvidedRecord<FeatureHeaderIdOf<Header>> = FeatureProvidedRecord<FeatureHeaderIdOf<Header>>,\n> = FeatureBodyInput<\n FeatureHeaderIdOf<Header>,\n FeatureImportRecordOf<Header>,\n FeatureRequirementRecordOf<Header>,\n Own,\n FeatureExportRecordOf<Header>,\n Provided\n>;\n\ntype LoadedFeatureBody = {\n readonly exports?: unknown;\n readonly own?: unknown;\n readonly provides?: unknown;\n};\n\nconst bodyKeys = new Set(['exports', 'own', 'provides']);\n\nfunction assertPlainBodyRecord(featureId: string, value: unknown): asserts value is object {\n if (typeof value !== 'object' || value === null) {\n throw new TypeError(`Feature ${featureId} body must be a record of own, exports and provides.`);\n }\n\n const prototype: unknown = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`Feature ${featureId} body must be a plain object record.`);\n }\n}\n\n/** The loader is foreign code, so what it returns is checked before anything of the feature is materialized. */\nfunction requireFeatureBody(featureId: string, value: unknown): LoadedFeatureBody {\n assertPlainBodyRecord(featureId, value);\n\n for (const key of Reflect.ownKeys(value)) {\n if (typeof key !== 'string' || !bodyKeys.has(key)) {\n throw new TypeError(`Feature ${featureId} body contains unknown field ${String(key)}.`);\n }\n }\n\n return value;\n}\n\n/**\n * D207: the body is written through `defineFeature.body`, a member of the word that already names a feature. A\n * function is what lets TypeScript infer `own` for `exports` and `provides`, exactly as the eager form does, and a\n * member spends no new word on the author's vocabulary. It mints no identity — the header already is the feature.\n */\nfunction featureBody<\n Id extends string,\n Imports extends FeatureImportRecord,\n Exports extends FeatureExportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id> = {},\n Provided extends FeatureProvidedRecord<Id> = {},\n>(\n header: Feature<Id, Imports, FeatureOwnRecord<Id>, Exports, Requires, readonly Condition[]>,\n body: FeatureBodyInput<Id, Imports, Requires, Own, Exports, Provided>,\n): FeatureBody<Exports> {\n if (!isFeature(header)) throw new TypeError('featureBody takes the feature its header declared.');\n\n return requireFeatureBody(header.id, body) as FeatureBody<Exports>;\n}\n\n/**\n * D186 asked for a way to fetch the code without opening anything: a host that knows a feature is about to be\n * needed — a hovered entry point, an idle callback — warms its chunk here. It opens no instance, holds no lease and\n * publishes no state; a failure is the caller's to observe, and the next open tries the loader again.\n */\nfunction preloadFeatureBody(header: unknown): Promise<void> {\n if (!isFeature(header)) throw new TypeError('defineFeature.preload takes a feature declaration.');\n\n if (getLazyFeature(header) === undefined) return Promise.resolve();\n\n return loadFeatureBody(header).then(() => undefined);\n}\n\nexport { featureBody, preloadFeatureBody, requireFeatureBody };\nexport type { FeatureBody, FeatureBodyOf, LoadedFeatureBody };\n"],"names":["bodyKeys","assertPlainBodyRecord","featureId","value","prototype","requireFeatureBody","key","featureBody","header","body","isFeature","preloadFeatureBody","getLazyFeature","loadFeatureBody"],"mappings":"oIAyFA,MAAMA,EAAW,IAAI,IAAI,CAAC,UAAW,MAAO,UAAU,CAAC,EAEvD,SAASC,EAAsBC,EAAmBC,EAAc,CAC9D,GAAI,OAAOA,GAAU,UAAYA,IAAU,KACzC,MAAM,IAAI,UAAU,WAAWD,CAAS,sDAAsD,EAGhG,MAAME,EAAqB,OAAO,eAAeD,CAAK,EAEtD,GAAIC,IAAc,OAAO,WAAaA,IAAc,KAClD,MAAM,IAAI,UAAU,WAAWF,CAAS,sCAAsC,CAElF,CAGA,SAASG,EAAmBH,EAAmBC,EAAc,CAC3DF,EAAsBC,EAAWC,CAAK,EAEtC,UAAWG,KAAO,QAAQ,QAAQH,CAAK,EACrC,GAAI,OAAOG,GAAQ,UAAY,CAACN,EAAS,IAAIM,CAAG,EAC9C,MAAM,IAAI,UAAU,WAAWJ,CAAS,gCAAgC,OAAOI,CAAG,CAAC,GAAG,EAI1F,OAAOH,CACT,CAOA,SAASI,EAQPC,EACAC,EAAqE,CAErE,GAAI,CAACC,EAAUF,CAAM,EAAG,MAAM,IAAI,UAAU,oDAAoD,EAEhG,OAAOH,EAAmBG,EAAO,GAAIC,CAAI,CAC3C,CAOA,SAASE,EAAmBH,EAAe,CACzC,GAAI,CAACE,EAAUF,CAAM,EAAG,MAAM,IAAI,UAAU,oDAAoD,EAEhG,OAAII,EAAeJ,CAAM,IAAM,OAAkB,QAAQ,QAAO,EAEzDK,EAAgBL,CAAM,EAAE,KAAK,IAAA,EAAe,CACrD"}
@@ -1,6 +1,6 @@
1
1
  import type { DeclarationId, Readable } from '@opetope/core';
2
2
  import type { ContributionPublication, ContributionPublicationInput, ContributionTarget, PipeHandler } from '@opetope/core/internal';
3
- import type { ContributionModelDeclaration, ContributionModelProps } from './feature-contribution-model.js';
3
+ import type { ContributionModelBuilder, ContributionModelDeclaration, ContributionModelProps } from './feature-contribution-model.js';
4
4
  import type { ExactInput } from './feature-record.js';
5
5
  declare const featureContributionBrand: unique symbol;
6
6
  interface FeatureContribution {
@@ -70,7 +70,9 @@ type CheckedContribution<Spec, Value> = ExactContributionProps<Spec, Value> exte
70
70
  * inference circular and TypeScript would fall back to the constraint.
71
71
  */
72
72
  interface FeatureSlotBuilder<Context, Evaluation> {
73
- <Value extends object, const Spec extends NoInfer<Value>, const Options extends FeatureContributionOptions<Evaluation>>(target: ContributionTarget<Value>, contribution: (context: Context) => Spec, options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>): CheckedContribution<Spec, Value>;
73
+ <Value extends object, const Spec extends NoInfer<Value>, const Options extends FeatureContributionOptions<Evaluation>>(target: ContributionTarget<Value>, contribution: (context: Context & {
74
+ readonly model: ContributionModelBuilder;
75
+ }) => Spec, options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>): CheckedContribution<Spec, Value>;
74
76
  <Value extends object, const Spec extends NoInfer<Value>, const Options extends FeatureContributionOptions<Evaluation>>(target: ContributionTarget<Value>, contribution: Spec, options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>): CheckedContribution<Spec, Value>;
75
77
  }
76
78
  /**
@@ -90,7 +92,6 @@ interface FeatureContributionDescriptor {
90
92
  }
91
93
  /** The live values of one instance, read by every reactive calculation that instance declared (D220). */
92
94
  type FeatureEvaluationValues = Readonly<{
93
- exports: unknown;
94
95
  imports: unknown;
95
96
  own: unknown;
96
97
  }>;
@@ -104,6 +105,7 @@ type SnapshotContributionOptions = {
104
105
  type FeaturePipeFold = (value: unknown, meta: unknown, context: unknown) => unknown;
105
106
  type PendingFeatureContribution = SnapshotContributionOptions & {
106
107
  readonly fold: FeaturePipeFold | undefined;
108
+ readonly slot: boolean;
107
109
  readonly target: ContributionPublicationInput['target'];
108
110
  readonly value: FeatureContributionValueFactory<unknown, unknown>;
109
111
  };
@@ -1,2 +1,2 @@
1
- import{declarationId as h,computed as l}from"@opetope/core";import{isContributionTarget as F,publishContributions as m}from"@opetope/core/internal";import{assertPlainRecord as a,dataEntries as d,assertExactDataKeys as E}from"./feature-record.js";const b=new WeakMap,y=new WeakMap,w=new WeakMap,g=new Set(["priority","when"]);function T(e){if(e===void 0)return 0;if(typeof e!="number"||!Number.isFinite(e))throw new TypeError("Feature contribution priority must be a finite number.");return e}function j(e,t){if(t===void 0)throw new TypeError("Feature contribution when predicate has no instance to read.");return l({read:r=>{const n=e({...t,read:r});if(typeof n!="boolean")throw new TypeError("Feature contribution when predicate must return a boolean.");return n}})}function C(e){if(e===void 0)return;if(typeof e=="function"){const r=e;return n=>j(r,n)}if(typeof e!="object"||e===null||typeof e.getSnapshot!="function"||typeof e.subscribe!="function")throw new TypeError("Feature contribution when must be a readable or a predicate of the instance.");const t=e;return()=>t}function x(e){if(e===void 0)return{priority:0,when:void 0};a(e,"Feature contribution options");const t=d(e,"Feature contribution options");if(t.some(([n])=>!g.has(n)))throw new TypeError("Feature contribution options accept only priority and when.");const r=Object.fromEntries(t);return{priority:T(r.priority),when:C(r.when)}}function O(e){if(typeof e=="function"||typeof e!="object"||e===null)throw new TypeError("Feature pipe expects a descriptor: pipe(target, { fold: (value, meta, context) => next }).");a(e,"Feature pipe descriptor");const t=d(e,"Feature pipe descriptor");E(e,t,["fold"],"Feature pipe descriptor");const r=e.fold;if(typeof r!="function")throw new TypeError("Feature pipe fold must be a function.");return r}function z(){const e=new WeakMap,t=new Set,r=(n,o,s,i)=>{if(!F(n))throw new TypeError(`Feature ${i} target is not authentic.`);const u=i==="pipe"?O(o):void 0,c=typeof o=="function"?o:()=>o,p=Object.freeze({});return t.add(p),e.set(p,{...x(s),fold:u,target:n,value:c}),p};return Object.freeze({declarations:e,declared:t,pipe:(n,o,s)=>r(n,o,s,"pipe"),register:(n,o,s)=>r(n,o,s,"register"),slot:((n,o,s)=>r(n,o,s,"slot"))})}function k(e,t){return typeof t=="object"&&t!==null&&e.declarations.has(t)}function P(e,t,r){const n=new Set,o=r.map(([s,i])=>{const u=typeof i=="object"&&i!==null?t.declarations.get(i):void 0;if(u===void 0)throw new TypeError(`Feature contribution ${s} is not authentic.`);if(n.has(i))throw new TypeError("Every feature contribution must be returned under exactly one key.");n.add(i);const c=Object.freeze({id:h(`${e}.${s}`),priority:u.priority,target:u.target});return b.set(c,u.value),u.when!==void 0&&y.set(c,u.when),u.fold!==void 0&&w.set(c,u.fold),c});if(n.size!==t.declared.size)throw new TypeError("Every feature contribution must be returned under exactly one key.");return Object.freeze(o)}function S(e,t){if(t===void 0)throw new TypeError("Feature pipe fold has no instance to read.");const r=[],n=Object.freeze({...t,read:o=>{const s=r[r.length-1];return s===void 0?o.getSnapshot():s(o)}});return(o,s,i)=>{r.push(i.read);try{return e(o,s,n)}finally{r.pop()}}}function V(e,t,r,n,o){const s=e.map(i=>{const u=b.get(i);if(u===void 0)throw new TypeError(`Feature contribution ${i.id} is not authentic.`);const c=w.get(i),p=c===void 0?u(t):S(c,o),f=y.get(i);return{id:i.id,...n===void 0?{}:{owner:n},priority:i.priority,target:i.target,value:p,when:f==null?void 0:f(o)}});return m(s,r)}export{z as createFeatureContributionBuilders,V as createFeatureContributionPublication,k as isFeatureContributionDeclaration,P as snapshotFeatureContributions};
1
+ import{declarationId as F,computed as E}from"@opetope/core";import{isContributionTarget as g,publishContributions as T}from"@opetope/core/internal";import{contributionModel as j}from"./feature-contribution-model.js";import{assertPlainRecord as a,dataEntries as d,assertExactDataKeys as C}from"./feature-record.js";const b=new WeakMap,y=new WeakMap,w=new WeakMap,h=new WeakSet,O=new Set(["priority","when"]);function x(e){if(e===void 0)return 0;if(typeof e!="number"||!Number.isFinite(e))throw new TypeError("Feature contribution priority must be a finite number.");return e}function z(e,t){if(t===void 0)throw new TypeError("Feature contribution when predicate has no instance to read.");return E({read:r=>{const n=e({...t,read:r});if(typeof n!="boolean")throw new TypeError("Feature contribution when predicate must return a boolean.");return n}})}function S(e){if(e===void 0)return;if(typeof e=="function"){const r=e;return n=>z(r,n)}if(typeof e!="object"||e===null||typeof e.getSnapshot!="function"||typeof e.subscribe!="function")throw new TypeError("Feature contribution when must be a readable or a predicate of the instance.");const t=e;return()=>t}function k(e){if(e===void 0)return{priority:0,when:void 0};a(e,"Feature contribution options");const t=d(e,"Feature contribution options");if(t.some(([n])=>!O.has(n)))throw new TypeError("Feature contribution options accept only priority and when.");const r=Object.fromEntries(t);return{priority:x(r.priority),when:S(r.when)}}function M(e){if(typeof e=="function"||typeof e!="object"||e===null)throw new TypeError("Feature pipe expects a descriptor: pipe(target, { fold: (value, meta, context) => next }).");a(e,"Feature pipe descriptor");const t=d(e,"Feature pipe descriptor");C(e,t,["fold"],"Feature pipe descriptor");const r=e.fold;if(typeof r!="function")throw new TypeError("Feature pipe fold must be a function.");return r}function P(){const e=new WeakMap,t=new Set,r=(n,o,i,s)=>{if(!g(n))throw new TypeError(`Feature ${s} target is not authentic.`);const u=s==="pipe"?M(o):void 0,c=typeof o=="function"?o:()=>o,f=Object.freeze({});return t.add(f),e.set(f,{...k(i),fold:u,slot:s==="slot"&&typeof o=="function",target:n,value:c}),f};return Object.freeze({declarations:e,declared:t,pipe:(n,o,i)=>r(n,o,i,"pipe"),register:(n,o,i)=>r(n,o,i,"register"),slot:((n,o,i)=>r(n,o,i,"slot"))})}function V(e,t){return typeof t=="object"&&t!==null&&e.declarations.has(t)}function W(e,t){b.set(e,t.value),t.slot&&h.add(e),t.when!==void 0&&y.set(e,t.when),t.fold!==void 0&&w.set(e,t.fold)}function $(e,t,r){const n=new Set,o=r.map(([i,s])=>{const u=typeof s=="object"&&s!==null?t.declarations.get(s):void 0;if(u===void 0)throw new TypeError(`Feature contribution ${i} is not authentic.`);if(n.has(s))throw new TypeError("Every feature contribution must be returned under exactly one key.");n.add(s);const c=Object.freeze({id:F(`${e}.${i}`),priority:u.priority,target:u.target});return W(c,u),c});if(n.size!==t.declared.size)throw new TypeError("Every feature contribution must be returned under exactly one key.");return Object.freeze(o)}function D(e,t){if(t===void 0)throw new TypeError("Feature pipe fold has no instance to read.");const r=[],n=Object.freeze({...t,read:o=>{const i=r[r.length-1];return i===void 0?o.getSnapshot():i(o)}});return(o,i,s)=>{r.push(s.read);try{return e(o,i,n)}finally{r.pop()}}}function K(e,t,r,n,o){let i;const s=e.map(u=>{const c=b.get(u);if(c===void 0)throw new TypeError(`Feature contribution ${u.id} is not authentic.`);const f=w.get(u),l=h.has(u)?i??(i=Object.freeze({...t,model:j})):t,m=f===void 0?c(l):D(f,o),p=y.get(u);return{id:u.id,...n===void 0?{}:{owner:n},priority:u.priority,target:u.target,value:m,when:p==null?void 0:p(o)}});return T(s,r)}export{P as createFeatureContributionBuilders,K as createFeatureContributionPublication,V as isFeatureContributionDeclaration,$ as snapshotFeatureContributions};
2
2
  //# sourceMappingURL=feature-contribution.js.map