@opetope/runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +345 -0
- package/README.ru.md +344 -0
- package/dist/application-compiler-edges.d.ts +3 -0
- package/dist/application-compiler-edges.js +2 -0
- package/dist/application-compiler-edges.js.map +1 -0
- package/dist/application-compiler-graph.d.ts +8 -0
- package/dist/application-compiler-graph.js +2 -0
- package/dist/application-compiler-graph.js.map +1 -0
- package/dist/application-compiler.d.ts +116 -0
- package/dist/application-compiler.js +2 -0
- package/dist/application-compiler.js.map +1 -0
- package/dist/application-conditions.d.ts +18 -0
- package/dist/application-conditions.js +2 -0
- package/dist/application-conditions.js.map +1 -0
- package/dist/application-definition.d.ts +30 -0
- package/dist/application-definition.js +2 -0
- package/dist/application-definition.js.map +1 -0
- package/dist/application-error.d.ts +10 -0
- package/dist/application-error.js +2 -0
- package/dist/application-error.js.map +1 -0
- package/dist/application-execution.d.ts +43 -0
- package/dist/application-execution.js +2 -0
- package/dist/application-execution.js.map +1 -0
- package/dist/application-feature-bindings.d.ts +11 -0
- package/dist/application-feature-bindings.js +2 -0
- package/dist/application-feature-bindings.js.map +1 -0
- package/dist/application-feature-instance.d.ts +5 -0
- package/dist/application-feature-instance.js +2 -0
- package/dist/application-feature-instance.js.map +1 -0
- package/dist/application-group-order.d.ts +29 -0
- package/dist/application-group-order.js +2 -0
- package/dist/application-group-order.js.map +1 -0
- package/dist/application-instance-retirement.d.ts +36 -0
- package/dist/application-instance-retirement.js +2 -0
- package/dist/application-instance-retirement.js.map +1 -0
- package/dist/application-open-options.d.ts +29 -0
- package/dist/application-open-options.js +2 -0
- package/dist/application-open-options.js.map +1 -0
- package/dist/application-port-compiler.d.ts +28 -0
- package/dist/application-port-compiler.js +2 -0
- package/dist/application-port-compiler.js.map +1 -0
- package/dist/attachment-call-declaration.d.ts +43 -0
- package/dist/attachment-call-declaration.js +2 -0
- package/dist/attachment-call-declaration.js.map +1 -0
- package/dist/attachment-declaration.d.ts +68 -0
- package/dist/attachment-declaration.js +2 -0
- package/dist/attachment-declaration.js.map +1 -0
- package/dist/attachment-execution.d.ts +9 -0
- package/dist/attachment-execution.js +2 -0
- package/dist/attachment-execution.js.map +1 -0
- package/dist/attachment-retirement-scheduler.d.ts +14 -0
- package/dist/attachment-retirement-scheduler.js +2 -0
- package/dist/attachment-retirement-scheduler.js.map +1 -0
- package/dist/call-option-snapshot.d.ts +20 -0
- package/dist/call-option-snapshot.js +2 -0
- package/dist/call-option-snapshot.js.map +1 -0
- package/dist/compile-call-target-bindings.d.ts +14 -0
- package/dist/compile-call-target-bindings.js +2 -0
- package/dist/compile-call-target-bindings.js.map +1 -0
- package/dist/compile-module-template.d.ts +38 -0
- package/dist/compile-module-template.js +2 -0
- package/dist/compile-module-template.js.map +1 -0
- package/dist/condition-group-execution.d.ts +44 -0
- package/dist/condition-group-execution.js +2 -0
- package/dist/condition-group-execution.js.map +1 -0
- package/dist/condition-override.d.ts +28 -0
- package/dist/condition-override.js +2 -0
- package/dist/condition-override.js.map +1 -0
- package/dist/condition-source.d.ts +10 -0
- package/dist/condition-source.js +2 -0
- package/dist/condition-source.js.map +1 -0
- package/dist/condition-types.d.ts +14 -0
- package/dist/condition.d.ts +28 -0
- package/dist/condition.js +2 -0
- package/dist/condition.js.map +1 -0
- package/dist/control-registry.d.ts +56 -0
- package/dist/control-registry.js +2 -0
- package/dist/control-registry.js.map +1 -0
- package/dist/dynamic-scope-child.d.ts +23 -0
- package/dist/dynamic-scope-child.js +2 -0
- package/dist/dynamic-scope-child.js.map +1 -0
- package/dist/dynamic-scope-controller.d.ts +16 -0
- package/dist/dynamic-scope-controller.js +2 -0
- package/dist/dynamic-scope-controller.js.map +1 -0
- package/dist/feature-attachment-authoring-types.d.ts +51 -0
- package/dist/feature-attachment-lowering.d.ts +18 -0
- package/dist/feature-attachment-lowering.js +2 -0
- package/dist/feature-attachment-lowering.js.map +1 -0
- package/dist/feature-attachment.d.ts +45 -0
- package/dist/feature-attachment.js +2 -0
- package/dist/feature-attachment.js.map +1 -0
- package/dist/feature-authoring-types.d.ts +196 -0
- package/dist/feature-authoring.d.ts +15 -0
- package/dist/feature-authoring.js +2 -0
- package/dist/feature-authoring.js.map +1 -0
- package/dist/feature-body.d.ts +53 -0
- package/dist/feature-body.js +2 -0
- package/dist/feature-body.js.map +1 -0
- package/dist/feature-call-authority.d.ts +8 -0
- package/dist/feature-call-authority.js +2 -0
- package/dist/feature-call-authority.js.map +1 -0
- package/dist/feature-call-types.d.ts +39 -0
- package/dist/feature-call.d.ts +18 -0
- package/dist/feature-call.js +2 -0
- package/dist/feature-call.js.map +1 -0
- package/dist/feature-calls.d.ts +6 -0
- package/dist/feature-calls.js +2 -0
- package/dist/feature-calls.js.map +1 -0
- package/dist/feature-contract.d.ts +70 -0
- package/dist/feature-contract.js +2 -0
- package/dist/feature-contract.js.map +1 -0
- package/dist/feature-contribution-model.d.ts +38 -0
- package/dist/feature-contribution-model.js +2 -0
- package/dist/feature-contribution-model.js.map +1 -0
- package/dist/feature-contribution.d.ts +126 -0
- package/dist/feature-contribution.js +2 -0
- package/dist/feature-contribution.js.map +1 -0
- package/dist/feature-definition-api.d.ts +53 -0
- package/dist/feature-definition-support.d.ts +21 -0
- package/dist/feature-definition-support.js +2 -0
- package/dist/feature-definition-support.js.map +1 -0
- package/dist/feature-effect.d.ts +26 -0
- package/dist/feature-effect.js +2 -0
- package/dist/feature-effect.js.map +1 -0
- package/dist/feature-event.d.ts +32 -0
- package/dist/feature-event.js +2 -0
- package/dist/feature-event.js.map +1 -0
- package/dist/feature-generation.d.ts +34 -0
- package/dist/feature-generation.js +2 -0
- package/dist/feature-generation.js.map +1 -0
- package/dist/feature-lazy-generation.d.ts +6 -0
- package/dist/feature-lazy-generation.js +2 -0
- package/dist/feature-lazy-generation.js.map +1 -0
- package/dist/feature-lazy.d.ts +44 -0
- package/dist/feature-lazy.js +2 -0
- package/dist/feature-lazy.js.map +1 -0
- package/dist/feature-materialization-binding.d.ts +31 -0
- package/dist/feature-materialization-binding.js +2 -0
- package/dist/feature-materialization-binding.js.map +1 -0
- package/dist/feature-materialization-types.d.ts +45 -0
- package/dist/feature-model-dependencies.d.ts +23 -0
- package/dist/feature-model-dependencies.js +2 -0
- package/dist/feature-model-dependencies.js.map +1 -0
- package/dist/feature-model.d.ts +60 -0
- package/dist/feature-model.js +2 -0
- package/dist/feature-model.js.map +1 -0
- package/dist/feature-optional.d.ts +15 -0
- package/dist/feature-optional.js +2 -0
- package/dist/feature-optional.js.map +1 -0
- package/dist/feature-own-lowering.d.ts +22 -0
- package/dist/feature-own-lowering.js +2 -0
- package/dist/feature-own-lowering.js.map +1 -0
- package/dist/feature-port-binding.d.ts +6 -0
- package/dist/feature-port-binding.js +2 -0
- package/dist/feature-port-binding.js.map +1 -0
- package/dist/feature-port.d.ts +66 -0
- package/dist/feature-port.js +2 -0
- package/dist/feature-port.js.map +1 -0
- package/dist/feature-record.d.ts +6 -0
- package/dist/feature-record.js +2 -0
- package/dist/feature-record.js.map +1 -0
- package/dist/feature-resource.d.ts +29 -0
- package/dist/feature-resource.js +2 -0
- package/dist/feature-resource.js.map +1 -0
- package/dist/feature-scope-types.d.ts +35 -0
- package/dist/feature-scope.d.ts +29 -0
- package/dist/feature-scope.js +2 -0
- package/dist/feature-scope.js.map +1 -0
- package/dist/feature-stream.d.ts +37 -0
- package/dist/feature-stream.js +2 -0
- package/dist/feature-stream.js.map +1 -0
- package/dist/feature-timers.d.ts +14 -0
- package/dist/feature-timers.js +2 -0
- package/dist/feature-timers.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/inspection-activity-protocol.d.ts +63 -0
- package/dist/inspection-activity.d.ts +54 -0
- package/dist/inspection-activity.js +2 -0
- package/dist/inspection-activity.js.map +1 -0
- package/dist/inspection-diff.d.ts +10 -0
- package/dist/inspection-diff.js +2 -0
- package/dist/inspection-diff.js.map +1 -0
- package/dist/inspection-module-activity.d.ts +4 -0
- package/dist/inspection-module-activity.js +2 -0
- package/dist/inspection-module-activity.js.map +1 -0
- package/dist/inspection-observer.d.ts +38 -0
- package/dist/inspection-observer.js +2 -0
- package/dist/inspection-observer.js.map +1 -0
- package/dist/inspection-plan.d.ts +33 -0
- package/dist/inspection-plan.js +2 -0
- package/dist/inspection-plan.js.map +1 -0
- package/dist/inspection-protocol.d.ts +333 -0
- package/dist/inspection-protocol.js +2 -0
- package/dist/inspection-protocol.js.map +1 -0
- package/dist/inspection-registry.d.ts +41 -0
- package/dist/inspection-registry.js +2 -0
- package/dist/inspection-registry.js.map +1 -0
- package/dist/inspection-session.d.ts +92 -0
- package/dist/inspection-session.js +2 -0
- package/dist/inspection-session.js.map +1 -0
- package/dist/inspection-snapshot.d.ts +4 -0
- package/dist/inspection-snapshot.js +2 -0
- package/dist/inspection-snapshot.js.map +1 -0
- package/dist/inspection-state.d.ts +91 -0
- package/dist/inspection-state.js +2 -0
- package/dist/inspection-state.js.map +1 -0
- package/dist/instance-demand.d.ts +31 -0
- package/dist/instance-demand.js +2 -0
- package/dist/instance-demand.js.map +1 -0
- package/dist/internal.d.ts +41 -0
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -0
- package/dist/keyed-scope-controller.d.ts +11 -0
- package/dist/keyed-scope-controller.js +2 -0
- package/dist/keyed-scope-controller.js.map +1 -0
- package/dist/model-kernel.d.ts +18 -0
- package/dist/model-kernel.js +2 -0
- package/dist/model-kernel.js.map +1 -0
- package/dist/module-call-context.d.ts +7 -0
- package/dist/module-call-context.js +2 -0
- package/dist/module-call-context.js.map +1 -0
- package/dist/module-call-runtime.d.ts +21 -0
- package/dist/module-call-runtime.js +2 -0
- package/dist/module-call-runtime.js.map +1 -0
- package/dist/module-generation.d.ts +57 -0
- package/dist/module-generation.js +2 -0
- package/dist/module-generation.js.map +1 -0
- package/dist/module-instance-types.d.ts +156 -0
- package/dist/module-instance.d.ts +19 -0
- package/dist/module-instance.js +2 -0
- package/dist/module-instance.js.map +1 -0
- package/dist/module-runtime-identity.d.ts +4 -0
- package/dist/module-runtime-identity.js +2 -0
- package/dist/module-runtime-identity.js.map +1 -0
- package/dist/module-scope-open.d.ts +4 -0
- package/dist/module-scope-open.js +2 -0
- package/dist/module-scope-open.js.map +1 -0
- package/dist/module-scope-retirement.d.ts +3 -0
- package/dist/module-scope-retirement.js +2 -0
- package/dist/module-scope-retirement.js.map +1 -0
- package/dist/module-template-ir.d.ts +59 -0
- package/dist/owner-generation-retirement.d.ts +6 -0
- package/dist/owner-generation-retirement.js +2 -0
- package/dist/owner-generation-retirement.js.map +1 -0
- package/dist/owner-generation-state.d.ts +123 -0
- package/dist/owner-generation-state.js +2 -0
- package/dist/owner-generation-state.js.map +1 -0
- package/dist/owner-generation.d.ts +16 -0
- package/dist/owner-generation.js +2 -0
- package/dist/owner-generation.js.map +1 -0
- package/dist/public-module-definition.d.ts +9 -0
- package/dist/public-module-definition.js +2 -0
- package/dist/public-module-definition.js.map +1 -0
- package/dist/public-module-instance.d.ts +6 -0
- package/dist/public-module-instance.js +2 -0
- package/dist/public-module-instance.js.map +1 -0
- package/dist/public-module-retirement-diagnostics.d.ts +5 -0
- package/dist/public-module-retirement-diagnostics.js +2 -0
- package/dist/public-module-retirement-diagnostics.js.map +1 -0
- package/dist/public-module-retirement.d.ts +3 -0
- package/dist/public-module-retirement.js +2 -0
- package/dist/public-module-retirement.js.map +1 -0
- package/dist/public-module-scope.d.ts +5 -0
- package/dist/public-module-scope.js +2 -0
- package/dist/public-module-scope.js.map +1 -0
- package/dist/public-module-state.d.ts +28 -0
- package/dist/public-module-state.js +2 -0
- package/dist/public-module-state.js.map +1 -0
- package/dist/public-module-types.d.ts +295 -0
- package/dist/public-module.d.ts +4 -0
- package/dist/resource-cache.d.ts +12 -0
- package/dist/resource-cache.js +2 -0
- package/dist/resource-cache.js.map +1 -0
- package/dist/resource-controller.d.ts +29 -0
- package/dist/resource-controller.js +2 -0
- package/dist/resource-controller.js.map +1 -0
- package/dist/resource-policy.d.ts +16 -0
- package/dist/resource-policy.js +2 -0
- package/dist/resource-policy.js.map +1 -0
- package/dist/resource-snapshot.d.ts +12 -0
- package/dist/resource-snapshot.js +2 -0
- package/dist/resource-snapshot.js.map +1 -0
- package/dist/resource-types.d.ts +3 -0
- package/dist/runtime-error-reporting.d.ts +4 -0
- package/dist/runtime-error-reporting.js +2 -0
- package/dist/runtime-error-reporting.js.map +1 -0
- package/dist/stream-backpressure.d.ts +18 -0
- package/dist/stream-backpressure.js +2 -0
- package/dist/stream-backpressure.js.map +1 -0
- package/dist/stream-cleanup.d.ts +17 -0
- package/dist/stream-cleanup.js +2 -0
- package/dist/stream-cleanup.js.map +1 -0
- package/dist/stream-controller-types.d.ts +51 -0
- package/dist/stream-controller.d.ts +5 -0
- package/dist/stream-controller.js +2 -0
- package/dist/stream-controller.js.map +1 -0
- package/docs/agent-guide.md +214 -0
- package/docs/agent-guide.ru.md +208 -0
- package/docs/cookbook.md +734 -0
- package/docs/cookbook.ru.md +729 -0
- package/docs/decisions.md +1437 -0
- package/docs/devtools.md +423 -0
- package/docs/devtools.ru.md +419 -0
- package/docs/how-it-works.md +521 -0
- package/docs/how-it-works.ru.md +495 -0
- package/docs/releases.md +78 -0
- package/docs/releases.ru.md +78 -0
- package/docs/spec.md +874 -0
- package/docs/spec.ru.md +884 -0
- package/package.json +72 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Call, Lookup, Readable } from '@opetope/core';
|
|
2
|
+
import type { AdapterMethodKey, AdapterMethodSignature, Awaitable, ExactVoidResult, IsAny, UniqueExposeKeys } from '@opetope/core/internal';
|
|
3
|
+
import type { FeatureAttachmentOptions, FeatureDisposer, FeatureOpenOnlyAttachmentOptions } from './feature-attachment.js';
|
|
4
|
+
import type { FeatureExposureMode, FeatureImportedAttachmentRef } from './feature-call-types.js';
|
|
5
|
+
import type { FeatureContractIdentity, FeatureImportRecord, FeatureImportValues, OptionalHostContract } from './feature-contract.js';
|
|
6
|
+
import type { ExactInput } from './feature-record.js';
|
|
7
|
+
import type { ModuleCallRef } from './public-module.js';
|
|
8
|
+
declare const featureImportRefBrand: unique symbol;
|
|
9
|
+
declare const featureImportRefOwnerBrand: unique symbol;
|
|
10
|
+
interface FeatureImportRef<Value, Id extends string, Mode extends FeatureExposureMode> {
|
|
11
|
+
readonly [featureImportRefBrand]: (value: Value) => Value;
|
|
12
|
+
readonly [featureImportRefOwnerBrand]: (id: Id, mode: Mode) => readonly [Id, Mode];
|
|
13
|
+
}
|
|
14
|
+
type FeatureImportDeclarationMode<Declaration> = Declaration extends FeatureContractIdentity | {
|
|
15
|
+
readonly exports: FeatureContractIdentity;
|
|
16
|
+
} ? 'feature-call-target' : 'adapter-method';
|
|
17
|
+
/** D187: a weak feature edge selects calls of its provider, so it carries its own exposure mode. */
|
|
18
|
+
type FeatureImportMode<Declaration> = Declaration extends OptionalHostContract<infer Optional> ? FeatureImportDeclarationMode<Optional> extends 'feature-call-target' ? 'optional-feature-call-target' : 'adapter-method' : FeatureImportDeclarationMode<Declaration>;
|
|
19
|
+
type FeatureImportRefs<Id extends string, Imports extends FeatureImportRecord> = {
|
|
20
|
+
readonly [Key in keyof Imports]: FeatureImportRef<FeatureImportValues<Imports>[Key], Id, FeatureImportMode<Imports[Key]>>;
|
|
21
|
+
};
|
|
22
|
+
interface FeatureAttachBuilder<Id extends string, Imports extends FeatureImportRecord> {
|
|
23
|
+
<Value, Mode extends FeatureExposureMode>(source: FeatureImportRef<Value, Id, Mode>): FeatureImportedAttachmentRef<Value, Id, FeatureImportValues<Imports>, Mode>;
|
|
24
|
+
<Value, Mode extends FeatureExposureMode, OpenResult extends Awaitable<void> = Awaitable<void>, CloseResult extends Awaitable<void> = Awaitable<void>, const Options extends FeatureAttachmentOptions<Value, OpenResult, CloseResult> = FeatureAttachmentOptions<Value, OpenResult, CloseResult>>(source: FeatureImportRef<Value, Id, Mode>, options: ExactInput<Options, FeatureAttachmentOptions<Value, OpenResult, CloseResult>> & ExactVoidResult<CloseResult> & ExactVoidResult<OpenResult>): FeatureImportedAttachmentRef<Value, Id, FeatureImportValues<Imports>, Mode>;
|
|
25
|
+
<Value, Mode extends FeatureExposureMode, OpenResult extends Awaitable<FeatureDisposer | void> = Awaitable<FeatureDisposer | void>, const Options extends FeatureOpenOnlyAttachmentOptions<Value, OpenResult> = FeatureOpenOnlyAttachmentOptions<Value, OpenResult>>(source: FeatureImportRef<Value, Id, Mode>, options: ExactInput<Options, FeatureOpenOnlyAttachmentOptions<Value, OpenResult>>): FeatureImportedAttachmentRef<Value, Id, FeatureImportValues<Imports>, Mode>;
|
|
26
|
+
}
|
|
27
|
+
type FeatureCallTargetKey<Value> = {
|
|
28
|
+
readonly [Key in keyof Value]-?: Key extends string ? Value[Key] extends Call<infer Input, infer Output> ? IsAny<Input> extends true ? never : IsAny<Output> extends true ? never : Key : never : never;
|
|
29
|
+
}[keyof Value];
|
|
30
|
+
type ExposedAdapterCalls<Value, Keys extends readonly PropertyKey[], Id extends string> = {
|
|
31
|
+
readonly [Key in Keys[number]]: AdapterMethodSignature<Value[Key & keyof Value]> extends {
|
|
32
|
+
readonly input: infer Input;
|
|
33
|
+
readonly output: infer Output;
|
|
34
|
+
} ? ModuleCallRef<Input, Output, Id> : never;
|
|
35
|
+
};
|
|
36
|
+
type ExposedFeatureCalls<Value, Keys extends readonly PropertyKey[], Id extends string> = {
|
|
37
|
+
readonly [Key in Keys[number]]: Value[Key & keyof Value] extends Call<infer Input, infer Output> ? ModuleCallRef<Input, Output, Id> : never;
|
|
38
|
+
};
|
|
39
|
+
interface FeatureCallsBuilder<Id extends string> {
|
|
40
|
+
/**
|
|
41
|
+
* D187: `calls` over a weak edge. The keys are the exported `Call`s of the provider, and every selected call
|
|
42
|
+
* answers `CallError` with code `unavailable` while nothing provides it.
|
|
43
|
+
*/
|
|
44
|
+
<Exports, const Keys extends readonly [FeatureCallTargetKey<Exports>, ...FeatureCallTargetKey<Exports>[]]>(source: FeatureImportRef<Readable<Lookup<Exports>>, Id, 'optional-feature-call-target'>, keys: Keys & UniqueExposeKeys<Keys>): ExposedFeatureCalls<Exports, Keys, Id>;
|
|
45
|
+
<Value, const Keys extends readonly [FeatureCallTargetKey<Value>, ...FeatureCallTargetKey<Value>[]]>(source: FeatureImportRef<Value, Id, 'feature-call-target'>, keys: Keys & UniqueExposeKeys<Keys>): ExposedFeatureCalls<Value, Keys, Id>;
|
|
46
|
+
/** A source without open or close needs no `attach`: the import ref itself names the calls. */
|
|
47
|
+
<Value, const Keys extends readonly [AdapterMethodKey<Value>, ...AdapterMethodKey<Value>[]]>(source: FeatureImportRef<Value, Id, 'adapter-method'>, keys: Keys & UniqueExposeKeys<Keys>): ExposedAdapterCalls<Value, Keys, Id>;
|
|
48
|
+
<Value, ImportValues extends object, const Keys extends readonly [AdapterMethodKey<Value>, ...AdapterMethodKey<Value>[]]>(within: FeatureImportedAttachmentRef<Value, Id, ImportValues, 'adapter-method'>, keys: Keys & UniqueExposeKeys<Keys>): ExposedAdapterCalls<Value, Keys, Id>;
|
|
49
|
+
<Value, ImportValues extends object, const Keys extends readonly [FeatureCallTargetKey<Value>, ...FeatureCallTargetKey<Value>[]]>(within: FeatureImportedAttachmentRef<Value, Id, ImportValues, 'feature-call-target'>, keys: Keys & UniqueExposeKeys<Keys>): ExposedFeatureCalls<Value, Keys, Id>;
|
|
50
|
+
}
|
|
51
|
+
export type { FeatureAttachBuilder, FeatureCallsBuilder, FeatureImportRef, FeatureImportRefs };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { snapshotAttachmentOptions } from './feature-attachment.js';
|
|
2
|
+
import type { AttachmentLowering } from './feature-authoring-types.js';
|
|
3
|
+
import type { FeatureImportRecord, FeatureImportValues } from './feature-contract.js';
|
|
4
|
+
import type { ModuleScopeRef } from './public-module.js';
|
|
5
|
+
/** Marker the `own` lowering passes to attach the hidden requirements scope. */
|
|
6
|
+
declare const requirementAttachmentSource: Readonly<{}>;
|
|
7
|
+
type FeatureAttachmentSource = Readonly<{
|
|
8
|
+
key: string;
|
|
9
|
+
kind: 'import';
|
|
10
|
+
}> | Readonly<{
|
|
11
|
+
kind: 'requirement';
|
|
12
|
+
}>;
|
|
13
|
+
declare function selectFeatureAttachmentArguments(first: unknown, second: unknown, importKeys: Readonly<WeakMap<object, string>>): Readonly<{
|
|
14
|
+
options: ReturnType<typeof snapshotAttachmentOptions<unknown>>;
|
|
15
|
+
source: FeatureAttachmentSource;
|
|
16
|
+
}>;
|
|
17
|
+
declare function selectAttachmentLowering<Id extends string, Imports extends FeatureImportRecord>(importScope: ModuleScopeRef<FeatureImportValues<Imports>, Id> | undefined, requirementScope: ModuleScopeRef<Readonly<Record<string, object>>, Id> | undefined, imports: Imports, source: FeatureAttachmentSource): AttachmentLowering<Id>;
|
|
18
|
+
export { requirementAttachmentSource, selectAttachmentLowering, selectFeatureAttachmentArguments };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{snapshotAttachmentOptions as f}from"./feature-attachment.js";import{isFeatureContract as p,isHostContractOptional as l}from"./feature-contract.js";const s=Object.freeze({kind:"open-only",open:()=>{}}),u=Object.freeze({});function m(e,t){if(!(typeof e!="object"||e===null))return t.get(e)}function d(e,t){if(typeof e!="object"||e===null)throw new TypeError("Feature attach source is not an import from this definition.");const r=t.get(e);if(r===void 0)throw new TypeError("Feature attach source is not an import from this definition.");return r}function h(e,t,r){if(t===void 0){if(e===u)return{options:s,source:{kind:"requirement"}};const n=m(e,r);if(n!==void 0)return{options:s,source:{key:n,kind:"import"}}}if(t===void 0)throw new TypeError("Feature attach requires an import or a host contract as its source.");return{options:f(t),source:{key:d(e,r),kind:"import"}}}function y(e,t,r,n){if(n.kind==="requirement"){if(t===void 0)throw new TypeError("Feature requirements scope is missing.");return{projection:{callTargets:!0,exposure:"feature-call-target",importValues:!1,select:i=>i},scope:t}}if(e===void 0)throw new TypeError("Feature imports scope is missing.");const a=r[n.key],o=p(a),c=o&&l(a);return{projection:{callTargets:o,exposure:c?"optional-feature-call-target":o?"feature-call-target":"adapter-method",importValues:!0,select:i=>i[n.key]},scope:e}}export{u as requirementAttachmentSource,y as selectAttachmentLowering,h as selectFeatureAttachmentArguments};
|
|
2
|
+
//# sourceMappingURL=feature-attachment-lowering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-attachment-lowering.js","sources":["../src/feature-attachment-lowering.ts"],"sourcesContent":["import { snapshotAttachmentOptions } from './feature-attachment';\nimport type { AttachmentLowering } from './feature-authoring-types';\nimport { isFeatureContract, isHostContractOptional } from './feature-contract';\nimport type { FeatureImportRecord, FeatureImportValues } from './feature-contract';\nimport type { ModuleScopeRef } from './public-module';\n\nconst defaultImportedAttachmentOptions = Object.freeze({ kind: 'open-only' as const, open: () => undefined });\n/** Marker the `own` lowering passes to attach the hidden requirements scope. */\nconst requirementAttachmentSource = Object.freeze({});\n\ntype FeatureAttachmentSource = Readonly<{ key: string; kind: 'import' }> | Readonly<{ kind: 'requirement' }>;\n\nfunction findRefKey(value: unknown, keys: Readonly<WeakMap<object, string>>): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n\n return keys.get(value);\n}\n\nfunction requireImportKey(source: unknown, keys: Readonly<WeakMap<object, string>>): string {\n if (typeof source !== 'object' || source === null) {\n throw new TypeError('Feature attach source is not an import from this definition.');\n }\n\n const key = keys.get(source);\n\n if (key === undefined) throw new TypeError('Feature attach source is not an import from this definition.');\n\n return key;\n}\n\nfunction selectFeatureAttachmentArguments(\n first: unknown,\n second: unknown,\n importKeys: Readonly<WeakMap<object, string>>,\n): Readonly<{ options: ReturnType<typeof snapshotAttachmentOptions<unknown>>; source: FeatureAttachmentSource }> {\n if (second === undefined) {\n if (first === requirementAttachmentSource) {\n return { options: defaultImportedAttachmentOptions, source: { kind: 'requirement' } };\n }\n\n const implicitImportKey = findRefKey(first, importKeys);\n\n if (implicitImportKey !== undefined) {\n return { options: defaultImportedAttachmentOptions, source: { key: implicitImportKey, kind: 'import' } };\n }\n }\n\n if (second === undefined) {\n throw new TypeError('Feature attach requires an import or a host contract as its source.');\n }\n\n return {\n options: snapshotAttachmentOptions<unknown>(second),\n source: { key: requireImportKey(first, importKeys), kind: 'import' },\n };\n}\n\nfunction selectAttachmentLowering<Id extends string, Imports extends FeatureImportRecord>(\n importScope: ModuleScopeRef<FeatureImportValues<Imports>, Id> | undefined,\n requirementScope: ModuleScopeRef<Readonly<Record<string, object>>, Id> | undefined,\n imports: Imports,\n source: FeatureAttachmentSource,\n): AttachmentLowering<Id> {\n if (source.kind === 'requirement') {\n if (requirementScope === undefined) throw new TypeError('Feature requirements scope is missing.');\n\n return {\n projection: { callTargets: true, exposure: 'feature-call-target', importValues: false, select: value => value },\n scope: requirementScope as unknown as ModuleScopeRef<unknown, Id>,\n };\n }\n\n if (importScope === undefined) throw new TypeError('Feature imports scope is missing.');\n\n const declaration = imports[source.key];\n // D187: a weak feature edge keeps the call authority of its provider, but its value arrives as a projection.\n const featureCalls = isFeatureContract(declaration);\n const weakFeatureCalls = featureCalls && isHostContractOptional(declaration);\n\n return {\n projection: {\n callTargets: featureCalls,\n exposure: weakFeatureCalls\n ? 'optional-feature-call-target'\n : featureCalls\n ? 'feature-call-target'\n : 'adapter-method',\n importValues: true,\n select: value => (value as Readonly<Record<string, unknown>>)[source.key],\n },\n scope: importScope as unknown as ModuleScopeRef<unknown, Id>,\n };\n}\n\nexport { requirementAttachmentSource, selectAttachmentLowering, selectFeatureAttachmentArguments };\n"],"names":["defaultImportedAttachmentOptions","requirementAttachmentSource","findRefKey","value","keys","requireImportKey","source","key","selectFeatureAttachmentArguments","first","second","importKeys","implicitImportKey","snapshotAttachmentOptions","selectAttachmentLowering","importScope","requirementScope","imports","declaration","featureCalls","isFeatureContract","weakFeatureCalls","isHostContractOptional"],"mappings":"0JAMA,MAAMA,EAAmC,OAAO,OAAO,CAAE,KAAM,YAAsB,KAAM,IAAA,GAAiB,EAEtGC,EAA8B,OAAO,OAAO,CAAA,CAAE,EAIpD,SAASC,EAAWC,EAAgBC,EAAuC,CACzE,GAAI,SAAOD,GAAU,UAAYA,IAAU,MAE3C,OAAOC,EAAK,IAAID,CAAK,CACvB,CAEA,SAASE,EAAiBC,EAAiBF,EAAuC,CAChF,GAAI,OAAOE,GAAW,UAAYA,IAAW,KAC3C,MAAM,IAAI,UAAU,8DAA8D,EAGpF,MAAMC,EAAMH,EAAK,IAAIE,CAAM,EAE3B,GAAIC,IAAQ,OAAW,MAAM,IAAI,UAAU,8DAA8D,EAEzG,OAAOA,CACT,CAEA,SAASC,EACPC,EACAC,EACAC,EAA6C,CAE7C,GAAID,IAAW,OAAW,CACxB,GAAID,IAAUR,EACZ,MAAO,CAAE,QAASD,EAAkC,OAAQ,CAAE,KAAM,cAAe,EAGrF,MAAMY,EAAoBV,EAAWO,EAAOE,CAAU,EAEtD,GAAIC,IAAsB,OACxB,MAAO,CAAE,QAASZ,EAAkC,OAAQ,CAAE,IAAKY,EAAmB,KAAM,SAAU,CAE1G,CAEA,GAAIF,IAAW,OACb,MAAM,IAAI,UAAU,qEAAqE,EAG3F,MAAO,CACL,QAASG,EAAmCH,CAAM,EAClD,OAAQ,CAAE,IAAKL,EAAiBI,EAAOE,CAAU,EAAG,KAAM,QAAQ,EAEtE,CAEA,SAASG,EACPC,EACAC,EACAC,EACAX,EAA+B,CAE/B,GAAIA,EAAO,OAAS,cAAe,CACjC,GAAIU,IAAqB,OAAW,MAAM,IAAI,UAAU,wCAAwC,EAEhG,MAAO,CACL,WAAY,CAAE,YAAa,GAAM,SAAU,sBAAuB,aAAc,GAAO,OAAQb,GAASA,CAAK,EAC7G,MAAOa,EAEX,CAEA,GAAID,IAAgB,OAAW,MAAM,IAAI,UAAU,mCAAmC,EAEtF,MAAMG,EAAcD,EAAQX,EAAO,GAAG,EAEhCa,EAAeC,EAAkBF,CAAW,EAC5CG,EAAmBF,GAAgBG,EAAuBJ,CAAW,EAE3E,MAAO,CACL,WAAY,CACV,YAAaC,EACb,SAAUE,EACN,+BACAF,EACE,sBACA,iBACN,aAAc,GACd,OAAQhB,GAAUA,EAA4CG,EAAO,GAAG,CACzE,EACD,MAAOS,EAEX"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Awaitable } from '@opetope/core/internal';
|
|
2
|
+
import type { FeatureTimers } from './feature-timers.js';
|
|
3
|
+
import type { ModuleAttachmentRef, ModuleScopeRef } from './public-module.js';
|
|
4
|
+
import type { RuntimeErrorReporter } from './runtime-error-reporting.js';
|
|
5
|
+
type FeatureAttachmentOpenContext<Value> = {
|
|
6
|
+
readonly signal: AbortSignal;
|
|
7
|
+
readonly source: Value;
|
|
8
|
+
readonly timers: FeatureTimers;
|
|
9
|
+
};
|
|
10
|
+
type FeatureAttachmentCloseContext<Value> = Omit<FeatureAttachmentOpenContext<Value>, 'timers'>;
|
|
11
|
+
type FeatureDisposer = () => Awaitable<void>;
|
|
12
|
+
declare const featureStatefulAttachmentBrand: unique symbol;
|
|
13
|
+
interface FeatureStatefulAttachmentHandle<Value> {
|
|
14
|
+
readonly [featureStatefulAttachmentBrand]: (value: Value) => Value;
|
|
15
|
+
}
|
|
16
|
+
interface FeatureAttachmentOptions<Value, OpenResult extends Awaitable<void> = Awaitable<void>, CloseResult extends Awaitable<void> = Awaitable<void>> {
|
|
17
|
+
readonly close: (context: FeatureAttachmentCloseContext<Value>) => CloseResult;
|
|
18
|
+
readonly open: (context: FeatureAttachmentOpenContext<Value>) => OpenResult;
|
|
19
|
+
}
|
|
20
|
+
interface FeatureOpenOnlyAttachmentOptions<Value, OpenResult extends Awaitable<FeatureDisposer | void>> {
|
|
21
|
+
readonly open: (context: FeatureAttachmentOpenContext<Value>) => OpenResult;
|
|
22
|
+
}
|
|
23
|
+
type FeatureAttachmentRecipeOptions<Value> = {
|
|
24
|
+
readonly close: (context: FeatureAttachmentCloseContext<Value>) => Awaitable<void>;
|
|
25
|
+
readonly kind: 'close';
|
|
26
|
+
readonly open: (context: FeatureAttachmentOpenContext<Value>) => Awaitable<void>;
|
|
27
|
+
} | {
|
|
28
|
+
readonly close: (state: unknown, context: FeatureAttachmentCloseContext<Value>) => Awaitable<void>;
|
|
29
|
+
readonly create: (context: FeatureAttachmentOpenContext<Value>) => unknown;
|
|
30
|
+
readonly kind: 'stateful';
|
|
31
|
+
readonly open: (state: unknown, context: FeatureAttachmentOpenContext<Value>) => Awaitable<void>;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: 'open-only';
|
|
34
|
+
readonly open: (context: FeatureAttachmentOpenContext<Value>) => Awaitable<FeatureDisposer | void>;
|
|
35
|
+
};
|
|
36
|
+
declare function createFeatureStatefulAttachment<Value, State>(options: {
|
|
37
|
+
readonly close: (state: State, context: FeatureAttachmentCloseContext<Value>) => Awaitable<void>;
|
|
38
|
+
readonly create: (context: FeatureAttachmentOpenContext<Value>) => State;
|
|
39
|
+
readonly open: (state: State, context: FeatureAttachmentOpenContext<Value>) => Awaitable<void>;
|
|
40
|
+
}): FeatureStatefulAttachmentHandle<Value>;
|
|
41
|
+
declare function getFeatureAttachmentReporter(context: object): RuntimeErrorReporter | undefined;
|
|
42
|
+
declare function snapshotAttachmentOptions<Value>(value: unknown): FeatureAttachmentRecipeOptions<Value>;
|
|
43
|
+
declare function createAttachmentRecipe<Id extends string, ScopeValue, Value>(scope: ModuleScopeRef<ScopeValue, Id>, select: (value: ScopeValue) => Value, options: FeatureAttachmentRecipeOptions<Value>): ModuleAttachmentRef<ScopeValue, Id>;
|
|
44
|
+
export { createAttachmentRecipe, createFeatureStatefulAttachment, getFeatureAttachmentReporter, snapshotAttachmentOptions, };
|
|
45
|
+
export type { FeatureAttachmentOptions, FeatureDisposer, FeatureOpenOnlyAttachmentOptions, FeatureStatefulAttachmentHandle, };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{getAttachmentErrorReporter as p}from"./attachment-execution.js";import{assertPlainRecord as R,dataEntries as w}from"./feature-record.js";import{createTimerRegistry as h}from"./feature-timers.js";const g=new WeakMap,y=new WeakMap;function A(e){const s=Object.freeze({});return y.set(s,{close:(t,o)=>e.close(t,o),create:t=>e.create(t),kind:"stateful",open:(t,o)=>e.open(t,o)}),s}function m(e,s,t,o){const i=Object.freeze({signal:s,source:t,timers:e});return o!==void 0&&g.set(i,o),i}function O(e){return g.get(e)}function k(e,s){return e.size!==s.length?!1:s.every(t=>e.has(t))}function F(e){if(!(typeof e!="object"||e===null))return y.get(e)}function b(e){const s=F(e);if(s!==void 0)return s;R(e,"Feature attachment options");const t=w(e,"Feature attachment options"),o=new Set(t.map(([c])=>c)),i=Reflect.get(e,"close"),n=Reflect.get(e,"open");if(k(o,["open"])&&typeof n=="function")return Object.freeze({kind:"open-only",open:n});if(k(o,["close","open"])&&typeof i=="function"&&typeof n=="function")return Object.freeze({close:i,kind:"close",open:n});throw new TypeError("own.attach takes open, or open and close, and nothing else.")}function j(e,s,t){return t.kind==="stateful"?e.attach({close:()=>{},open:({source:o,step:i})=>{let n=!1,c,u;const a=s(o);return i({cleanup:({context:l})=>{const r=u;return u=void 0,r==null||r.close(),n?t.close(c,{signal:l.signal,source:a}):void 0},key:"open",run:({context:l})=>{const r=p(l);u=h(l.signal,r);const f=m(u.timers,l.signal,a,r);return c=t.create(f),n=!0,t.open(c,f)}})}}):t.kind==="close"?e.attach({close:()=>{},open:({source:o,step:i})=>{let n;const c=s(o);return i({cleanup:({context:u})=>{const a=n;return n=void 0,a==null||a.close(),t.close({signal:u.signal,source:c})},key:"open",run:({context:u})=>{const a=p(u);return n=h(u.signal,a),t.open(m(n.timers,u.signal,c,a))}})}}):e.attach({close:()=>{},open:({source:o,step:i})=>{let n,c,u;const a=s(o),l=()=>{const r=n;if(r===void 0)return;const f=r();if(f===void 0){n=void 0;return}return Promise.resolve(f).then(()=>{n===r&&(n=void 0)})};return i({cleanup:()=>{const r=u;u=void 0,r==null||r.close();const f=c;return c=void 0,f===void 0?l():f.then(l,()=>{})},key:"open",run:({context:r})=>{const f=p(r);return u=h(r.signal,f),c=Promise.resolve(t.open(m(u.timers,r.signal,a,f))).then(d=>{if(d!==void 0&&typeof d!="function")throw new TypeError("own.attach open must return nothing or a disposer.");d!==void 0&&(n=d)}),c}})}})}export{j as createAttachmentRecipe,A as createFeatureStatefulAttachment,O as getFeatureAttachmentReporter,b as snapshotAttachmentOptions};
|
|
2
|
+
//# sourceMappingURL=feature-attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-attachment.js","sources":["../src/feature-attachment.ts"],"sourcesContent":["import type { Awaitable } from '@opetope/core/internal';\n\nimport { getAttachmentErrorReporter } from './attachment-execution';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport { createTimerRegistry } from './feature-timers';\nimport type { FeatureTimers } from './feature-timers';\nimport type { ModuleAttachmentRef, ModuleScopeRef } from './public-module';\nimport type { RuntimeErrorReporter } from './runtime-error-reporting';\n\ntype FeatureAttachmentOpenContext<Value> = {\n readonly signal: AbortSignal;\n readonly source: Value;\n readonly timers: FeatureTimers;\n};\n\ntype FeatureAttachmentCloseContext<Value> = Omit<FeatureAttachmentOpenContext<Value>, 'timers'>;\n\ntype FeatureDisposer = () => Awaitable<void>;\n\ndeclare const featureStatefulAttachmentBrand: unique symbol;\n\ninterface FeatureStatefulAttachmentHandle<Value> {\n readonly [featureStatefulAttachmentBrand]: (value: Value) => Value;\n}\n\ninterface FeatureAttachmentOptions<\n Value,\n OpenResult extends Awaitable<void> = Awaitable<void>,\n CloseResult extends Awaitable<void> = Awaitable<void>,\n> {\n readonly close: (context: FeatureAttachmentCloseContext<Value>) => CloseResult;\n readonly open: (context: FeatureAttachmentOpenContext<Value>) => OpenResult;\n}\n\ninterface FeatureOpenOnlyAttachmentOptions<Value, OpenResult extends Awaitable<FeatureDisposer | void>> {\n readonly open: (context: FeatureAttachmentOpenContext<Value>) => OpenResult;\n}\n\ntype FeatureAttachmentRecipeOptions<Value> =\n | {\n readonly close: (context: FeatureAttachmentCloseContext<Value>) => Awaitable<void>;\n readonly kind: 'close';\n readonly open: (context: FeatureAttachmentOpenContext<Value>) => Awaitable<void>;\n }\n | {\n readonly close: (state: unknown, context: FeatureAttachmentCloseContext<Value>) => Awaitable<void>;\n readonly create: (context: FeatureAttachmentOpenContext<Value>) => unknown;\n readonly kind: 'stateful';\n readonly open: (state: unknown, context: FeatureAttachmentOpenContext<Value>) => Awaitable<void>;\n }\n | {\n readonly kind: 'open-only';\n readonly open: (context: FeatureAttachmentOpenContext<Value>) => Awaitable<FeatureDisposer | void>;\n };\n\nconst featureAttachmentReporters = new WeakMap<object, RuntimeErrorReporter>();\nconst featureStatefulAttachmentOptions = new WeakMap<object, FeatureAttachmentRecipeOptions<unknown>>();\n\nfunction createFeatureStatefulAttachment<Value, State>(options: {\n readonly close: (state: State, context: FeatureAttachmentCloseContext<Value>) => Awaitable<void>;\n readonly create: (context: FeatureAttachmentOpenContext<Value>) => State;\n readonly open: (state: State, context: FeatureAttachmentOpenContext<Value>) => Awaitable<void>;\n}): FeatureStatefulAttachmentHandle<Value> {\n const handle = Object.freeze({}) as FeatureStatefulAttachmentHandle<Value>;\n\n featureStatefulAttachmentOptions.set(handle, {\n close: (state, context) => options.close(state as State, context as FeatureAttachmentCloseContext<Value>),\n create: context => options.create(context as FeatureAttachmentOpenContext<Value>),\n kind: 'stateful',\n open: (state, context) => options.open(state as State, context as FeatureAttachmentOpenContext<Value>),\n });\n\n return handle;\n}\n\nfunction createFeatureOpenContext<Value>(\n timers: FeatureTimers,\n signal: AbortSignal,\n source: Value,\n reporter: RuntimeErrorReporter | undefined,\n): FeatureAttachmentOpenContext<Value> {\n const context = Object.freeze({ signal, source, timers });\n\n if (reporter !== undefined) featureAttachmentReporters.set(context, reporter);\n\n return context;\n}\n\nfunction getFeatureAttachmentReporter(context: object): RuntimeErrorReporter | undefined {\n return featureAttachmentReporters.get(context);\n}\n\nfunction hasExactKeys(keys: ReadonlySet<string>, expected: readonly string[]): boolean {\n if (keys.size !== expected.length) return false;\n\n return expected.every(key => keys.has(key));\n}\n\nfunction getFeatureStatefulAttachmentOptions<Value>(value: unknown): FeatureAttachmentRecipeOptions<Value> | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n\n return featureStatefulAttachmentOptions.get(value);\n}\n\nfunction snapshotAttachmentOptions<Value>(value: unknown): FeatureAttachmentRecipeOptions<Value> {\n const stateful = getFeatureStatefulAttachmentOptions<Value>(value);\n\n if (stateful !== undefined) return stateful;\n\n assertPlainRecord(value, 'Feature attachment options');\n const entries = dataEntries(value, 'Feature attachment options');\n const keys = new Set(entries.map(([key]) => key));\n const close = Reflect.get(value, 'close');\n const open = Reflect.get(value, 'open');\n\n if (hasExactKeys(keys, ['open']) && typeof open === 'function') {\n return Object.freeze({ kind: 'open-only', open }) as FeatureAttachmentRecipeOptions<Value>;\n }\n\n if (hasExactKeys(keys, ['close', 'open']) && typeof close === 'function' && typeof open === 'function') {\n return Object.freeze({ close, kind: 'close', open }) as FeatureAttachmentRecipeOptions<Value>;\n }\n\n throw new TypeError('own.attach takes open, or open and close, and nothing else.');\n}\n\nfunction createAttachmentRecipe<Id extends string, ScopeValue, Value>(\n scope: ModuleScopeRef<ScopeValue, Id>,\n select: (value: ScopeValue) => Value,\n options: FeatureAttachmentRecipeOptions<Value>,\n): ModuleAttachmentRef<ScopeValue, Id> {\n if (options.kind === 'stateful') {\n return scope.attach({\n close: () => undefined,\n open: ({ source, step }) => {\n let created = false;\n let state: unknown;\n let timerRegistry: ReturnType<typeof createTimerRegistry> | undefined;\n const value = select(source);\n\n return step({\n cleanup: ({ context }) => {\n const registry = timerRegistry;\n timerRegistry = undefined;\n registry?.close();\n\n return created ? options.close(state, { signal: context.signal, source: value }) : undefined;\n },\n key: 'open',\n run: ({ context }) => {\n const reporter = getAttachmentErrorReporter(context);\n timerRegistry = createTimerRegistry(context.signal, reporter);\n const featureContext = createFeatureOpenContext(timerRegistry.timers, context.signal, value, reporter);\n state = options.create(featureContext);\n created = true;\n\n return options.open(state, featureContext);\n },\n });\n },\n });\n }\n\n if (options.kind === 'close') {\n return scope.attach({\n close: () => undefined,\n open: ({ source, step }) => {\n let timerRegistry: ReturnType<typeof createTimerRegistry> | undefined;\n const value = select(source);\n\n return step({\n cleanup: ({ context }) => {\n const registry = timerRegistry;\n timerRegistry = undefined;\n registry?.close();\n\n return options.close({ signal: context.signal, source: value });\n },\n key: 'open',\n run: ({ context }) => {\n const reporter = getAttachmentErrorReporter(context);\n timerRegistry = createTimerRegistry(context.signal, reporter);\n\n return options.open(createFeatureOpenContext(timerRegistry.timers, context.signal, value, reporter));\n },\n });\n },\n });\n }\n\n return scope.attach({\n close: () => undefined,\n open: ({ source, step }) => {\n let disposer: FeatureDisposer | undefined;\n let opening: Promise<void> | undefined;\n let timerRegistry: ReturnType<typeof createTimerRegistry> | undefined;\n const value = select(source);\n\n const dispose = (): Awaitable<void> => {\n const current = disposer;\n\n if (current === undefined) return;\n\n const result = current();\n\n if (result === undefined) {\n disposer = undefined;\n\n return;\n }\n\n return Promise.resolve(result).then(() => {\n if (disposer === current) disposer = undefined;\n });\n };\n\n return step({\n cleanup: () => {\n const registry = timerRegistry;\n timerRegistry = undefined;\n registry?.close();\n\n const pending = opening;\n opening = undefined;\n\n return pending === undefined ? dispose() : pending.then(dispose, () => undefined);\n },\n key: 'open',\n run: ({ context }) => {\n const reporter = getAttachmentErrorReporter(context);\n timerRegistry = createTimerRegistry(context.signal, reporter);\n opening = Promise.resolve(\n options.open(createFeatureOpenContext(timerRegistry.timers, context.signal, value, reporter)),\n ).then(opened => {\n if (opened !== undefined && typeof opened !== 'function') {\n throw new TypeError('own.attach open must return nothing or a disposer.');\n }\n\n if (opened !== undefined) disposer = opened;\n });\n\n return opening;\n },\n });\n },\n });\n}\n\nexport {\n createAttachmentRecipe,\n createFeatureStatefulAttachment,\n getFeatureAttachmentReporter,\n snapshotAttachmentOptions,\n};\nexport type {\n FeatureAttachmentOptions,\n FeatureDisposer,\n FeatureOpenOnlyAttachmentOptions,\n FeatureStatefulAttachmentHandle,\n};\n"],"names":["featureAttachmentReporters","featureStatefulAttachmentOptions","createFeatureStatefulAttachment","options","handle","state","context","createFeatureOpenContext","timers","signal","source","reporter","getFeatureAttachmentReporter","hasExactKeys","keys","expected","key","getFeatureStatefulAttachmentOptions","value","snapshotAttachmentOptions","stateful","assertPlainRecord","entries","dataEntries","close","open","createAttachmentRecipe","scope","select","step","created","timerRegistry","registry","getAttachmentErrorReporter","createTimerRegistry","featureContext","disposer","opening","dispose","current","result","pending","opened"],"mappings":"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"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Call, DeclarationId, LatestBackpressure, ModelOf, OwnedState, Readable, Resource } from '@opetope/core';
|
|
2
|
+
import type { Awaitable } from '@opetope/core/internal';
|
|
3
|
+
import type { Condition } from './condition-types.js';
|
|
4
|
+
import type { FeatureDisposer } from './feature-attachment.js';
|
|
5
|
+
import type { FeatureAttachBuilder, FeatureCallsBuilder, FeatureImportRef, FeatureImportRefs } from './feature-attachment-authoring-types.js';
|
|
6
|
+
import type { FeatureCallBuilder, FeatureCallLaneBuilder, FeatureExposureMode, FeatureImportedAttachmentRef } from './feature-call-types.js';
|
|
7
|
+
import type { FeatureContract, FeatureContractIdentity, FeatureImportRecord, FeatureImportValues } from './feature-contract.js';
|
|
8
|
+
import type { FeatureContributionDescriptor } from './feature-contribution.js';
|
|
9
|
+
import type { ContributionModelBuilder } from './feature-contribution-model.js';
|
|
10
|
+
import type { FeatureResourceRef, FeatureStreamRef } from './feature-materialization-types.js';
|
|
11
|
+
import type { FeatureDataDescriptor, FeatureModelBuilder, FeatureModelRef } from './feature-model.js';
|
|
12
|
+
import type { FeatureRequiredCalls, PortProviderDescriptor, PortRequirementRecord, RequiredPortValues } from './feature-port.js';
|
|
13
|
+
import type { ExactInput, ExactKeys } from './feature-record.js';
|
|
14
|
+
import type { FeatureResourceBuilder } from './feature-resource.js';
|
|
15
|
+
import type { FeatureScopeBuilder } from './feature-scope-types.js';
|
|
16
|
+
import type { FeatureStreamBuilder } from './feature-stream.js';
|
|
17
|
+
import type { FeatureTimers } from './feature-timers.js';
|
|
18
|
+
import type { ModuleAttachmentRefIdentity, ModuleCallRef, ModuleInstanceRef, ModuleRuntimeRefIdentity, ModuleScopeRef } from './public-module.js';
|
|
19
|
+
declare const featureBrand: unique symbol;
|
|
20
|
+
type FeatureLifecycleRef<Source, Id extends string, Imports extends FeatureImportRecord, Mode extends FeatureExposureMode> = FeatureImportedAttachmentRef<Source, Id, FeatureImportValues<Imports>, Mode>;
|
|
21
|
+
type FeatureEffectRunContext<Source, Value> = {
|
|
22
|
+
readonly current: Value;
|
|
23
|
+
readonly previous: Value | undefined;
|
|
24
|
+
readonly signal: AbortSignal;
|
|
25
|
+
readonly source: Source;
|
|
26
|
+
readonly timers: FeatureTimers;
|
|
27
|
+
};
|
|
28
|
+
type FeatureEffectDisposeContext<Source> = {
|
|
29
|
+
readonly source: Source;
|
|
30
|
+
};
|
|
31
|
+
type FeatureReadableValue<Source> = Source extends Readable<infer Value> ? Value : never;
|
|
32
|
+
interface FeatureEffectOptions<Source extends Readable<unknown>, Id extends string, Mode extends FeatureExposureMode> {
|
|
33
|
+
readonly from: FeatureImportRef<Source, Id, Mode>;
|
|
34
|
+
readonly onDispose?: (context: FeatureEffectDisposeContext<Source>) => Awaitable<void>;
|
|
35
|
+
readonly run: (context: FeatureEffectRunContext<Source, FeatureReadableValue<Source>>) => Awaitable<FeatureDisposer | void>;
|
|
36
|
+
readonly when?: (current: FeatureReadableValue<Source>, previous: FeatureReadableValue<Source> | undefined) => boolean;
|
|
37
|
+
}
|
|
38
|
+
type FeatureEffectBuilder<Id extends string, Imports extends FeatureImportRecord> = <Source extends Readable<unknown>, Mode extends FeatureExposureMode, const Keys extends PropertyKey = keyof FeatureEffectOptions<Source, Id, Mode>>(options: ExactKeys<Keys, FeatureEffectOptions<Source, Id, Mode>> & FeatureEffectOptions<Source, Id, Mode>) => FeatureLifecycleRef<Source, Id, Imports, Mode>;
|
|
39
|
+
type FeatureEventOpenContext<Source, Payload> = {
|
|
40
|
+
readonly emit: (payload: Payload) => void;
|
|
41
|
+
readonly signal: AbortSignal;
|
|
42
|
+
readonly source: Source;
|
|
43
|
+
readonly timers: FeatureTimers;
|
|
44
|
+
};
|
|
45
|
+
type FeatureEventRunContext<Source, Payload> = {
|
|
46
|
+
readonly payload: Payload;
|
|
47
|
+
readonly signal: AbortSignal;
|
|
48
|
+
readonly source: Source;
|
|
49
|
+
};
|
|
50
|
+
interface FeatureEventOptions<Source, Payload> {
|
|
51
|
+
/**
|
|
52
|
+
* The same word a stream uses, and the only policy either of them publishes. Without it the payload that reached
|
|
53
|
+
* the waiting slot first keeps it and a newer `emit` is dropped with a failure record; with `latest()` the newest
|
|
54
|
+
* payload replaces the waiting one and nothing is reported (D247).
|
|
55
|
+
*/
|
|
56
|
+
readonly backpressure?: LatestBackpressure;
|
|
57
|
+
readonly run: (context: FeatureEventRunContext<Source, Payload>) => Awaitable<void>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* `from` and `subscribe` are positional so TypeScript resolves `Source` and then `Payload` before it contextually
|
|
61
|
+
* types `run`. Key order inside the options object is therefore irrelevant.
|
|
62
|
+
*/
|
|
63
|
+
type FeatureEventBuilder<Id extends string, Imports extends FeatureImportRecord> = <Source, Payload, Mode extends FeatureExposureMode, const Options extends FeatureEventOptions<NoInfer<Source>, NoInfer<Payload>>>(from: FeatureImportRef<Source, Id, Mode>, subscribe: (context: FeatureEventOpenContext<NoInfer<Source>, Payload>) => Awaitable<FeatureDisposer | void>, options: ExactInput<Options, FeatureEventOptions<NoInfer<Source>, NoInfer<Payload>>>) => FeatureLifecycleRef<Source, Id, Imports, Mode>;
|
|
64
|
+
interface FeatureOwnBuilder<Id extends string, Imports extends FeatureImportRecord, Requires extends PortRequirementRecord = {}> {
|
|
65
|
+
readonly attach: FeatureAttachBuilder<Id, Imports>;
|
|
66
|
+
readonly call: FeatureCallBuilder<Id>;
|
|
67
|
+
readonly calls: FeatureCallsBuilder<Id>;
|
|
68
|
+
readonly effect: FeatureEffectBuilder<Id, Imports>;
|
|
69
|
+
readonly event: FeatureEventBuilder<Id, Imports>;
|
|
70
|
+
readonly imports: FeatureImportRefs<Id, Imports>;
|
|
71
|
+
readonly lane: FeatureCallLaneBuilder<Id>;
|
|
72
|
+
readonly model: FeatureModelBuilder<Id>;
|
|
73
|
+
readonly requires: FeatureRequiredCalls<Id, Requires>;
|
|
74
|
+
readonly resource: FeatureResourceBuilder<Id>;
|
|
75
|
+
readonly scope: FeatureScopeBuilder<Id, Imports>;
|
|
76
|
+
readonly stream: FeatureStreamBuilder<Id>;
|
|
77
|
+
}
|
|
78
|
+
/** What `own` may return: any runtime ref of this feature, including the model refs from `model()`. */
|
|
79
|
+
type FeatureOwnRecord<Id extends string = string> = Readonly<Record<string, ModuleRuntimeRefIdentity<Id>>>;
|
|
80
|
+
declare const featureOwnValueUnavailableBrand: unique symbol;
|
|
81
|
+
/** An `own` member with no value form: an attachment, a scope, an effect or an event cannot enter `exports` (D88). */
|
|
82
|
+
interface FeatureOwnValueUnavailable {
|
|
83
|
+
readonly [featureOwnValueUnavailableBrand]: 'Feature exports carry calls, readables and resources.';
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A model field the way the rest of the world sees it: the writer stays with the owner, so an `OwnedState` narrows
|
|
87
|
+
* to `Readable` for everyone but the model that created it. Without this, `ctx.update` on a foreign feature's field
|
|
88
|
+
* Compiled and failed at the caller (D88).
|
|
89
|
+
*/
|
|
90
|
+
type ExportedModelField<Field> = Field extends OwnedState<infer Value> ? Readable<Value> : Field;
|
|
91
|
+
type ExportedModel<Shape> = {
|
|
92
|
+
readonly [Key in keyof Shape]: ExportedModelField<Shape[Key]>;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* What one `own` ref becomes when the instance opens: a call ref is a `Call`, a model ref is the model record with
|
|
96
|
+
* every owned state narrowed to `Readable`, a resource or a stream ref is a `Resource` (D88). Anything else an author
|
|
97
|
+
* can own — a plain attachment, a scope, an effect or an event — has no value form at all.
|
|
98
|
+
*/
|
|
99
|
+
type FeatureOwnValue<Id extends string, Ref> = Ref extends ModuleCallRef<infer Input, infer Output, Id> ? Call<Input, Output> : Ref extends FeatureModelRef<infer Declaration, Id> ? ExportedModel<ModelOf<Declaration>> : Ref extends FeatureResourceRef<infer Data, infer Key, Id> ? Resource<Data, Key> : Ref extends FeatureStreamRef<infer Data, infer Key, Id> ? Resource<Data, Key> : FeatureOwnValueUnavailable;
|
|
100
|
+
type FeatureOwnValues<Id extends string, Runtime> = {
|
|
101
|
+
readonly [Key in keyof Runtime]: FeatureOwnValue<Id, Runtime[Key]>;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* What a feature may hand to its importers: a `Call`, a `Readable` or a `Resource`, which is a `Readable` of its
|
|
105
|
+
* snapshot. A whole model is a record of those, not one of them, so the record type is the model ban (D88).
|
|
106
|
+
*/
|
|
107
|
+
type FeatureExportValue = Call<never, unknown> | Readable<unknown>;
|
|
108
|
+
type FeatureExportRecord = Readonly<Record<string, FeatureExportValue>>;
|
|
109
|
+
interface AnyFeature {
|
|
110
|
+
readonly exports: FeatureContractIdentity;
|
|
111
|
+
readonly id: DeclarationId;
|
|
112
|
+
/** Authored declarations; `snapshotFeatureImports` stores each one as the contract it resolves to. */
|
|
113
|
+
readonly imports: FeatureImportRecord;
|
|
114
|
+
readonly own: Readonly<Record<string, object>>;
|
|
115
|
+
readonly requires?: PortRequirementRecord;
|
|
116
|
+
/** The feature lives while every condition holds; an empty list is a permanent feature (D93). */
|
|
117
|
+
readonly when: readonly Condition[];
|
|
118
|
+
}
|
|
119
|
+
interface Feature<Id extends string = string, Imports extends FeatureImportRecord = FeatureImportRecord, Runtime extends FeatureOwnRecord<Id> = FeatureOwnRecord<Id>, Exports extends FeatureExportRecord = FeatureExportRecord, Requires extends PortRequirementRecord = {}, When extends readonly Condition[] = readonly Condition[]> extends AnyFeature {
|
|
120
|
+
readonly exports: FeatureContract<Exports>;
|
|
121
|
+
readonly [featureBrand]: (exports: Exports) => Exports;
|
|
122
|
+
readonly id: DeclarationId & Id;
|
|
123
|
+
readonly imports: Imports;
|
|
124
|
+
readonly own: Runtime;
|
|
125
|
+
readonly requires: Requires;
|
|
126
|
+
readonly when: When;
|
|
127
|
+
}
|
|
128
|
+
type FeatureImportsOf<Definition> = Definition extends Feature<infer _Id, infer Imports, infer _Runtime, infer _Exports> ? FeatureImportValues<Imports> : never;
|
|
129
|
+
type FeatureIdOf<Definition> = Definition extends Feature<infer Id, infer _Imports, infer _Runtime, infer _Exports> ? Id : never;
|
|
130
|
+
type FeatureExportsOf<Definition> = Definition extends Feature<infer _Id, infer _Imports, infer _Runtime, infer Exports> ? Exports : never;
|
|
131
|
+
type FeatureConditionsOf<Definition> = Definition extends Feature<infer _Id, infer _Imports, infer _Runtime, infer _Exports, infer _Requires, infer When> ? When : never;
|
|
132
|
+
type FeatureRequirementsOf<Definition> = Definition extends Feature<infer _Id, infer _Imports, infer _Runtime, infer _Exports, infer Requires> ? RequiredPortValues<Requires> : never;
|
|
133
|
+
/**
|
|
134
|
+
* `exports` runs when the instance opens and selects live values from a materialized `own`; the contract that
|
|
135
|
+
* importers name is the feature definition itself (D88).
|
|
136
|
+
*/
|
|
137
|
+
type FeatureExportsFactory<Id extends string, Runtime extends FeatureOwnRecord<Id>, Exports> = (context: {
|
|
138
|
+
readonly own: FeatureOwnValues<Id, NoInfer<Runtime>>;
|
|
139
|
+
}) => Exports;
|
|
140
|
+
/** Reads a source and records it as a dependency of the calculation that is running (D220). */
|
|
141
|
+
type FeatureRead = <Value>(source: Readable<Value>) => Value;
|
|
142
|
+
/**
|
|
143
|
+
* What a reactive calculation of one instance sees: the live values of that instance and a tracking `read`. `own`
|
|
144
|
+
* is the materialized form `exports` already uses — a model field is a `Readable`, not the ref the declaration
|
|
145
|
+
* context carries — because a calculation reads values and never constructs a node (D220).
|
|
146
|
+
*/
|
|
147
|
+
type FeatureEvaluationContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord> = {
|
|
148
|
+
readonly exports: Exports;
|
|
149
|
+
readonly imports: FeatureImportValues<Imports>;
|
|
150
|
+
readonly own: FeatureOwnValues<Id, Runtime>;
|
|
151
|
+
readonly read: FeatureRead;
|
|
152
|
+
};
|
|
153
|
+
type FeatureOpenContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord> = {
|
|
154
|
+
readonly exports: Exports;
|
|
155
|
+
readonly imports: FeatureImportValues<Imports>;
|
|
156
|
+
readonly instance: ModuleInstanceRef<Id>;
|
|
157
|
+
readonly model: ContributionModelBuilder;
|
|
158
|
+
readonly own: Runtime;
|
|
159
|
+
};
|
|
160
|
+
type FeatureRecord = {
|
|
161
|
+
readonly contributions: readonly FeatureContributionDescriptor[];
|
|
162
|
+
readonly dataDescriptors: readonly FeatureDataDescriptor[];
|
|
163
|
+
readonly exports: (context: {
|
|
164
|
+
readonly own: Readonly<Record<string, unknown>>;
|
|
165
|
+
}) => unknown;
|
|
166
|
+
readonly importKeys: readonly string[];
|
|
167
|
+
readonly importScopeKey: string | undefined;
|
|
168
|
+
readonly module: object;
|
|
169
|
+
readonly providers: readonly PortProviderDescriptor[];
|
|
170
|
+
readonly requirementKeys: readonly string[];
|
|
171
|
+
readonly requirementScopeKey: string | undefined;
|
|
172
|
+
};
|
|
173
|
+
type AttachmentRecipe<Id extends string> = {
|
|
174
|
+
readonly attachment: ModuleAttachmentRefIdentity<Id>;
|
|
175
|
+
readonly hiddenKey?: string;
|
|
176
|
+
};
|
|
177
|
+
type AttachmentProjection = {
|
|
178
|
+
readonly callTargets: boolean;
|
|
179
|
+
readonly exposure: FeatureExposureMode;
|
|
180
|
+
readonly importValues: boolean;
|
|
181
|
+
readonly select: (value: unknown) => unknown;
|
|
182
|
+
};
|
|
183
|
+
type AttachmentLowering<Id extends string> = {
|
|
184
|
+
readonly projection: AttachmentProjection;
|
|
185
|
+
readonly scope: ModuleScopeRef<unknown, Id>;
|
|
186
|
+
};
|
|
187
|
+
type FeatureCallOperation = {
|
|
188
|
+
readonly run: (input: unknown, context: unknown) => unknown;
|
|
189
|
+
readonly within: object;
|
|
190
|
+
};
|
|
191
|
+
type FeatureExportDeclarationSnapshot = {
|
|
192
|
+
readonly from: (context: {
|
|
193
|
+
readonly own: unknown;
|
|
194
|
+
}) => unknown;
|
|
195
|
+
};
|
|
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, };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AnyFeature, Feature, FeatureExportRecord, FeatureImportRecord, FeatureOwnRecord, FeatureRecord } from './feature-authoring-types.js';
|
|
2
|
+
import { featureBody, preloadFeatureBody } from './feature-body.js';
|
|
3
|
+
import type { DefineFeature } from './feature-definition-api.js';
|
|
4
|
+
import { isFeature } from './feature-definition-support.js';
|
|
5
|
+
import type { ModuleDefinition } from './public-module.js';
|
|
6
|
+
/** `imports` stores the contract, so the application world resolves a feature edge back to the feature (D68). */
|
|
7
|
+
declare function getFeatureByExportContract(contract: object): AnyFeature | undefined;
|
|
8
|
+
declare const defineFeature: DefineFeature & {
|
|
9
|
+
body: typeof featureBody;
|
|
10
|
+
preload: typeof preloadFeatureBody;
|
|
11
|
+
};
|
|
12
|
+
declare function getFeatureModule<const Id extends string, const Imports extends FeatureImportRecord, const Runtime extends FeatureOwnRecord<Id>, const Exports extends FeatureExportRecord>(feature: Feature<Id, Imports, Runtime, Exports>): ModuleDefinition<Id>;
|
|
13
|
+
declare function getFeatureContributionDescriptors(feature: AnyFeature): FeatureRecord['contributions'];
|
|
14
|
+
export { defineFeature, getFeatureByExportContract, getFeatureContributionDescriptors, getFeatureModule, isFeature };
|
|
15
|
+
export type { AnyFeature, Feature, FeatureConditionsOf, FeatureExportRecord, FeatureExportsOf, FeatureIdOf, FeatureImportRecord, FeatureImportsOf, FeatureImportValues, FeatureOwnRecord, FeatureRequirementsOf, } from './feature-authoring-types.js';
|
|
@@ -0,0 +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};
|
|
2
|
+
//# sourceMappingURL=feature-authoring.js.map
|
|
@@ -0,0 +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":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Condition } from './condition.js';
|
|
2
|
+
import type { Feature, FeatureEvaluationContext, FeatureExportRecord, FeatureExportsFactory, FeatureOpenContext, FeatureOwnBuilder, FeatureOwnRecord } from './feature-authoring-types.js';
|
|
3
|
+
import type { FeatureImportRecord } from './feature-contract.js';
|
|
4
|
+
import type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port.js';
|
|
5
|
+
import type { ExactNonUnionRuntime } from './public-module.js';
|
|
6
|
+
/**
|
|
7
|
+
* D186: the header of a feature and its body are two files. The header is the identity every consumer imports; the
|
|
8
|
+
* body is the implementation the loader brings in later. `FeatureBody<Exports>` is the narrow view the header names
|
|
9
|
+
* in the return type of its loader — it carries the export contract and nothing else, so the header never depends on
|
|
10
|
+
* the body module and the two types cannot form a cycle.
|
|
11
|
+
*/
|
|
12
|
+
interface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord> {
|
|
13
|
+
readonly exports?: (context: never) => Exports;
|
|
14
|
+
readonly own?: unknown;
|
|
15
|
+
readonly provides?: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The body as its own file writes it: `own`, `exports` and `provides` of the declared header, with the builders typed
|
|
19
|
+
* from the header's id, imports and requirements. The record is plain data — the header already owns the identity,
|
|
20
|
+
* so a body needs no second authentic declaration.
|
|
21
|
+
*/
|
|
22
|
+
type FeatureBodyInput<Id extends string, Imports extends FeatureImportRecord, Requires extends PortRequirementRecord, Own extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord, Provided extends FeatureProvidedRecord<Id>> = {
|
|
23
|
+
readonly exports?: FeatureExportsFactory<Id, Own, Exports>;
|
|
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>;
|
|
26
|
+
};
|
|
27
|
+
type FeatureImportRecordOf<Header> = Header extends Feature<infer _Id, infer Imports, infer _Own, infer _Exports, infer _Requires, infer _When> ? Imports : never;
|
|
28
|
+
type FeatureExportRecordOf<Header> = Header extends Feature<infer _Id, infer _Imports, infer _Own, infer Exports, infer _Requires, infer _When> ? Exports : never;
|
|
29
|
+
type FeatureRequirementRecordOf<Header> = Header extends Feature<infer _Id, infer _Imports, infer _Own, infer _Exports, infer Requires, infer _When> ? Requires : never;
|
|
30
|
+
type FeatureHeaderIdOf<Header> = Header extends Feature<infer Id, infer _Imports, infer _Own, infer _Exports, infer _Requires, infer _When> ? Id : never;
|
|
31
|
+
/** What the body file annotates itself with: everything the header already fixed, and the own record it invents. */
|
|
32
|
+
type FeatureBodyOf<Header, Own extends FeatureOwnRecord<FeatureHeaderIdOf<Header>> = FeatureOwnRecord<FeatureHeaderIdOf<Header>>, Provided extends FeatureProvidedRecord<FeatureHeaderIdOf<Header>> = FeatureProvidedRecord<FeatureHeaderIdOf<Header>>> = FeatureBodyInput<FeatureHeaderIdOf<Header>, FeatureImportRecordOf<Header>, FeatureRequirementRecordOf<Header>, Own, FeatureExportRecordOf<Header>, Provided>;
|
|
33
|
+
type LoadedFeatureBody = {
|
|
34
|
+
readonly exports?: unknown;
|
|
35
|
+
readonly own?: unknown;
|
|
36
|
+
readonly provides?: unknown;
|
|
37
|
+
};
|
|
38
|
+
/** The loader is foreign code, so what it returns is checked before anything of the feature is materialized. */
|
|
39
|
+
declare function requireFeatureBody(featureId: string, value: unknown): LoadedFeatureBody;
|
|
40
|
+
/**
|
|
41
|
+
* D207: the body is written through `defineFeature.body`, a member of the word that already names a feature. A
|
|
42
|
+
* function is what lets TypeScript infer `own` for `exports` and `provides`, exactly as the eager form does, and a
|
|
43
|
+
* member spends no new word on the author's vocabulary. It mints no identity — the header already is the feature.
|
|
44
|
+
*/
|
|
45
|
+
declare function featureBody<Id extends string, Imports extends FeatureImportRecord, Exports extends FeatureExportRecord, Requires extends PortRequirementRecord, Own extends FeatureOwnRecord<Id> = {}, Provided extends FeatureProvidedRecord<Id> = {}>(header: Feature<Id, Imports, FeatureOwnRecord<Id>, Exports, Requires, readonly Condition[]>, body: FeatureBodyInput<Id, Imports, Requires, Own, Exports, Provided>): FeatureBody<Exports>;
|
|
46
|
+
/**
|
|
47
|
+
* D186 asked for a way to fetch the code without opening anything: a host that knows a feature is about to be
|
|
48
|
+
* needed — a hovered entry point, an idle callback — warms its chunk here. It opens no instance, holds no lease and
|
|
49
|
+
* publishes no state; a failure is the caller's to observe, and the next open tries the loader again.
|
|
50
|
+
*/
|
|
51
|
+
declare function preloadFeatureBody(header: unknown): Promise<void>;
|
|
52
|
+
export { featureBody, preloadFeatureBody, requireFeatureBody };
|
|
53
|
+
export type { FeatureBody, FeatureBodyOf, LoadedFeatureBody };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{isFeature as t}from"./feature-definition-support.js";import{getLazyFeature as i,loadFeatureBody as d}from"./feature-lazy.js";const f=new Set(["exports","own","provides"]);function y(e,r){if(typeof r!="object"||r===null)throw new TypeError(`Feature ${e} body must be a record of own, exports and provides.`);const o=Object.getPrototypeOf(r);if(o!==Object.prototype&&o!==null)throw new TypeError(`Feature ${e} body must be a plain object record.`)}function n(e,r){y(e,r);for(const o of Reflect.ownKeys(r))if(typeof o!="string"||!f.has(o))throw new TypeError(`Feature ${e} body contains unknown field ${String(o)}.`);return r}function a(e,r){if(!t(e))throw new TypeError("featureBody takes the feature its header declared.");return n(e.id,r)}function u(e){if(!t(e))throw new TypeError("defineFeature.preload takes a feature declaration.");return i(e)===void 0?Promise.resolve():d(e).then(()=>{})}export{a as featureBody,u as preloadFeatureBody,n as requireFeatureBody};
|
|
2
|
+
//# sourceMappingURL=feature-body.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AttachmentProjection } from './feature-authoring-types.js';
|
|
2
|
+
import type { FeatureImportRecord } from './feature-contract.js';
|
|
3
|
+
import type { ModuleCallContext } from './public-module.js';
|
|
4
|
+
declare function registerFeatureInstanceImports(declarations: FeatureImportRecord, values: Readonly<Record<string, unknown>>): void;
|
|
5
|
+
/** Requirement values are `Call`s of the record itself, so the record is the authority for `context.invoke`. */
|
|
6
|
+
declare function registerFeatureInstanceCallTargets(values: Readonly<Record<string, unknown>>): void;
|
|
7
|
+
declare function projectCallContext(context: ModuleCallContext<unknown>, projection: AttachmentProjection): Readonly<Record<string, unknown>>;
|
|
8
|
+
export { projectCallContext, registerFeatureInstanceCallTargets, registerFeatureInstanceImports };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{hasOwn as w,isCallTarget as h,invokeCallTargetWithGuard as m}from"@opetope/core/internal";import{isAttachmentCallRef as b}from"./attachment-call-declaration.js";import{isFeatureContract as g,isHostContractOptional as y}from"./feature-contract.js";import{isFeatureExportFacade as k}from"./feature-definition-support.js";import{resolveLocalCallTarget as T}from"./module-call-context.js";const c=new WeakMap;function l(e,t){const r=Object.getOwnPropertyDescriptor(e,t);return r!==void 0&&w(r,"value")?r.value:void 0}function u(e,t){if(!((typeof t!="object"||t===null)&&typeof t!="function"))for(const r of Reflect.ownKeys(t)){const o=l(t,r);h(o)&&e.add(o)}}function C(e,t){const r=t;if(typeof(r==null?void 0:r.getSnapshot)!="function"||typeof r.subscribe!="function")throw new TypeError(`openFeature import ${e} must be a Readable projection of its optional provider.`);return r}function j(e,t){const r=new Set,o=[];for(const[n,a]of Object.entries(e)){if(!g(a))continue;const i=l(t,n);if(y(a)){o.push(C(n,i));continue}if(!k(a,i))throw new TypeError(`openFeature import ${n} must be an authentic facade for its feature contract.`);u(r,i)}c.set(t,Object.freeze({targets:r,weak:Object.freeze(o)}))}function v(e){const t=new Set;u(t,e),c.set(e,Object.freeze({targets:t,weak:Object.freeze([])}))}const d=new WeakMap;function I(e){const t=d.get(e);if(t!==void 0)return t;const r=new Set;u(r,e);const o=r;return d.set(e,o),o}function O(e,t){return e.targets.has(t)?!0:e.weak.some(r=>{const o=r.getSnapshot();if(o.kind!=="found")return!1;const n=o.value;return typeof n=="object"&&n!==null&&I(n).has(t)})}function A(e,t){const r=t.select(e.source),o=t.importValues?e.source:void 0,n=t.callTargets?e.source:void 0,a=n===void 0?void 0:c.get(n),i=(f,p)=>{try{e.throwIfAborted();let s;if(b(f))s=T(e,f);else{if(a===void 0||!O(a,f))throw new TypeError("This call is not declared by the imports of this instance.");s=f}return Promise.resolve(m(s,p,e,e.throwIfAborted))}catch(s){return Promise.reject(s)}};return o!==void 0?{imports:o,invoke:i,signal:e.signal,source:r,throwIfAborted:e.throwIfAborted}:{invoke:i,signal:e.signal,source:r,throwIfAborted:e.throwIfAborted}}export{A as projectCallContext,v as registerFeatureInstanceCallTargets,j as registerFeatureInstanceImports};
|
|
2
|
+
//# sourceMappingURL=feature-call-authority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-call-authority.js","sources":["../src/feature-call-authority.ts"],"sourcesContent":["import type { Call, Lookup, Readable } from '@opetope/core';\nimport { hasOwn, invokeCallTargetWithGuard, isCallTarget } from '@opetope/core/internal';\n\nimport { isAttachmentCallRef } from './attachment-call-declaration';\nimport type { AttachmentCallRef } from './attachment-call-declaration';\nimport type { AttachmentProjection } from './feature-authoring-types';\nimport type { FeatureImportRecord } from './feature-contract';\nimport { isFeatureContract, isHostContractOptional } from './feature-contract';\nimport { isFeatureExportFacade } from './feature-definition-support';\nimport { resolveLocalCallTarget } from './module-call-context';\nimport type { ModuleCallContext } from './public-module';\n\n/**\n * What `context.invoke` may reach: the call targets of every hard import plus, live, the ones a weak import projects\n * right now. A weak provider reopens with new targets, so its authority is read at call time, not at open (D105).\n */\ntype ImportAuthority = {\n readonly targets: ReadonlySet<object>;\n readonly weak: readonly Readable<Lookup<unknown>>[];\n};\n\nconst importedCallTargets = new WeakMap<object, ImportAuthority>();\n\nfunction ownDataValue(source: object, key: PropertyKey): unknown {\n const descriptor = Object.getOwnPropertyDescriptor(source, key);\n\n return descriptor !== undefined && hasOwn(descriptor, 'value') ? descriptor.value : undefined;\n}\n\nfunction collectCallTargets(targets: Set<object>, source: unknown): void {\n if ((typeof source !== 'object' || source === null) && typeof source !== 'function') return;\n\n for (const fieldKey of Reflect.ownKeys(source)) {\n const field = ownDataValue(source, fieldKey);\n\n if (isCallTarget(field)) targets.add(field);\n }\n}\n\nfunction requireWeakProjection(key: string, value: unknown): Readable<Lookup<unknown>> {\n const projection = value as Partial<Readable<Lookup<unknown>>>;\n\n if (typeof projection?.getSnapshot !== 'function' || typeof projection.subscribe !== 'function') {\n throw new TypeError(`openFeature import ${key} must be a Readable projection of its optional provider.`);\n }\n\n return projection as Readable<Lookup<unknown>>;\n}\n\nfunction registerFeatureInstanceImports(\n declarations: FeatureImportRecord,\n values: Readonly<Record<string, unknown>>,\n): void {\n const targets = new Set<object>();\n const weak: Readable<Lookup<unknown>>[] = [];\n\n for (const [key, contract] of Object.entries(declarations)) {\n if (!isFeatureContract(contract)) continue;\n\n const facade = ownDataValue(values, key);\n\n // A weak edge arrives as a projection, so its authority is whatever the provider publishes right now (D105).\n if (isHostContractOptional(contract)) {\n weak.push(requireWeakProjection(key, facade));\n\n continue;\n }\n\n if (!isFeatureExportFacade(contract, facade)) {\n throw new TypeError(`openFeature import ${key} must be an authentic facade for its feature contract.`);\n }\n\n collectCallTargets(targets, facade);\n }\n\n importedCallTargets.set(values, Object.freeze({ targets, weak: Object.freeze(weak) }));\n}\n\n/** Requirement values are `Call`s of the record itself, so the record is the authority for `context.invoke`. */\nfunction registerFeatureInstanceCallTargets(values: Readonly<Record<string, unknown>>): void {\n const targets = new Set<object>();\n collectCallTargets(targets, values);\n importedCallTargets.set(values, Object.freeze({ targets, weak: Object.freeze([]) }));\n}\n\n/**\n * The call targets of one provider export record. Keyed by the record, so a weak edge walks its provider once per\n * Instance instead of once per invocation, and the entry disappears with the instance that owned it.\n */\nconst weakProviderTargets = new WeakMap<object, ReadonlySet<object>>();\n\nfunction providerCallTargets(exports: object): ReadonlySet<object> {\n const cached = weakProviderTargets.get(exports);\n\n if (cached !== undefined) return cached;\n\n const targets = new Set<object>();\n collectCallTargets(targets, exports);\n const frozen: ReadonlySet<object> = targets;\n weakProviderTargets.set(exports, frozen);\n\n return frozen;\n}\n\nfunction authorityAllows(authority: ImportAuthority, target: object): boolean {\n if (authority.targets.has(target)) return true;\n\n return authority.weak.some(projection => {\n const lookup = projection.getSnapshot();\n\n if (lookup.kind !== 'found') return false;\n\n const exports = lookup.value;\n\n return typeof exports === 'object' && exports !== null && providerCallTargets(exports).has(target);\n });\n}\n\nfunction projectCallContext(\n context: ModuleCallContext<unknown>,\n projection: AttachmentProjection,\n): Readonly<Record<string, unknown>> {\n const source = projection.select(context.source);\n const imports = projection.importValues ? (context.source as object) : undefined;\n const authority = projection.callTargets ? (context.source as object) : undefined;\n const allowed = authority === undefined ? undefined : importedCallTargets.get(authority);\n const invoke = <Input, Output>(\n target: AttachmentCallRef<Input, Output> | Call<Input, Output>,\n input: Input,\n ): Promise<Output> => {\n try {\n context.throwIfAborted();\n let resolved: Call<Input, Output>;\n\n if (!isAttachmentCallRef(target)) {\n if (allowed === undefined || !authorityAllows(allowed, target)) {\n throw new TypeError('This call is not declared by the imports of this instance.');\n }\n\n resolved = target;\n } else {\n resolved = resolveLocalCallTarget(context, target);\n }\n\n return Promise.resolve(invokeCallTargetWithGuard(resolved, input, context, context.throwIfAborted));\n } catch (error) {\n return Promise.reject(error);\n }\n };\n\n if (imports !== undefined)\n return { imports, invoke, signal: context.signal, source, throwIfAborted: context.throwIfAborted };\n\n return { invoke, signal: context.signal, source, throwIfAborted: context.throwIfAborted };\n}\n\nexport { projectCallContext, registerFeatureInstanceCallTargets, registerFeatureInstanceImports };\n"],"names":["importedCallTargets","ownDataValue","source","key","descriptor","hasOwn","collectCallTargets","targets","fieldKey","field","isCallTarget","requireWeakProjection","value","projection","registerFeatureInstanceImports","declarations","values","weak","contract","isFeatureContract","facade","isHostContractOptional","isFeatureExportFacade","registerFeatureInstanceCallTargets","weakProviderTargets","providerCallTargets","exports","cached","frozen","authorityAllows","authority","target","lookup","projectCallContext","context","imports","allowed","invoke","input","resolved","isAttachmentCallRef","resolveLocalCallTarget","invokeCallTargetWithGuard","error"],"mappings":"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"}
|