@opetope/runtime 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +19 -9
  3. package/README.ru.md +21 -9
  4. package/dist/feature-authoring-types.d.ts +6 -10
  5. package/dist/feature-authoring.js +1 -1
  6. package/dist/feature-authoring.js.map +1 -1
  7. package/dist/feature-body.d.ts +1 -1
  8. package/dist/feature-body.js.map +1 -1
  9. package/dist/feature-contribution.d.ts +5 -3
  10. package/dist/feature-contribution.js +1 -1
  11. package/dist/feature-contribution.js.map +1 -1
  12. package/dist/feature-definition-api.d.ts +1 -1
  13. package/dist/feature-generation.js +1 -1
  14. package/dist/feature-generation.js.map +1 -1
  15. package/dist/feature-lazy-generation.d.ts +1 -1
  16. package/dist/feature-lazy-generation.js +1 -1
  17. package/dist/feature-lazy-generation.js.map +1 -1
  18. package/dist/feature-own-values.d.ts +10 -0
  19. package/dist/feature-own-values.js +2 -0
  20. package/dist/feature-own-values.js.map +1 -0
  21. package/dist/feature-port-binding.d.ts +2 -1
  22. package/dist/feature-port-binding.js +1 -1
  23. package/dist/feature-port-binding.js.map +1 -1
  24. package/dist/feature-port.d.ts +13 -23
  25. package/dist/feature-port.js +1 -1
  26. package/dist/feature-port.js.map +1 -1
  27. package/dist/public-module-types.d.ts +1 -1
  28. package/dist/public-module.d.ts +1 -1
  29. package/docs/agent-guide.md +11 -4
  30. package/docs/agent-guide.ru.md +11 -4
  31. package/docs/cookbook.md +9 -7
  32. package/docs/cookbook.ru.md +9 -7
  33. package/docs/decisions.md +14 -0
  34. package/docs/how-it-works.md +20 -5
  35. package/docs/how-it-works.ru.md +19 -5
  36. package/docs/spec.md +31 -17
  37. package/docs/spec.ru.md +32 -18
  38. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"feature-contribution.js","sources":["../src/feature-contribution.ts"],"sourcesContent":["import { computed, declarationId } from '@opetope/core';\nimport type { DeclarationId, Readable } from '@opetope/core';\nimport type {\n ContributionPublication,\n ContributionPublicationInput,\n ContributionTarget,\n PipeHandler,\n PipeRead,\n PipeReadContext,\n} from '@opetope/core/internal';\nimport { isContributionTarget, publishContributions } from '@opetope/core/internal';\n\nimport type { ContributionModelDeclaration, ContributionModelProps } from './feature-contribution-model';\nimport { assertExactDataKeys, assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactInput } from './feature-record';\n\ndeclare const featureContributionBrand: unique symbol;\n\ninterface FeatureContribution {\n readonly [featureContributionBrand]: true;\n}\n\ntype FeatureContributionValueFactory<Context, Value> = (context: Context) => Value;\n\n/**\n * `when` withholds a contribution while it reads `false`, so the target never lists it and `Slot`, `fold`, `select`\n * and emptiness checks skip it (D79). It is either a `Readable<boolean>` or a predicate of the instance: the\n * predicate answers a boolean and its `read` records what the answer depends on, so the runtime lowers it to one\n * computed readable of that instance and publishes it the way it always did (D220).\n */\ninterface FeatureContributionOptions<Evaluation = never> {\n readonly priority?: number;\n readonly when?: ((context: Evaluation) => boolean) | Readable<boolean>;\n}\n\n/**\n * Structural and renderer-free: with a props adapter the component must accept exactly what the adapter returns,\n * without one it must accept the props of the target. Slot props, adapter and component stay one chain (D85).\n */\ntype ContributionComponentProps<Component> = Component extends (props: infer Props, ...rest: never[]) => unknown\n ? Props\n : Component extends abstract new (props: infer Props, ...rest: never[]) => unknown\n ? Props\n : never;\n\ntype ContributionTargetProps<Value> = Value extends { readonly props?: (slotProps: infer Props) => unknown }\n ? Props\n : never;\n\ntype ContributionPropsMismatch = {\n readonly Component: 'contribution component must accept the props the adapter or the target supplies';\n};\n\n/** An erased component type states no props, so there is nothing left to check on that spec. */\ntype AcceptsProps<Supplied, Accepted> = [Accepted] extends [never]\n ? unknown\n : [Supplied] extends [Accepted]\n ? unknown\n : ContributionPropsMismatch;\n\ntype ExactContributionProps<Spec, Value> = Spec extends { readonly Component: infer Component }\n ? Spec extends { readonly props: (input: never) => infer Adapted }\n ? AcceptsProps<Adapted, ContributionComponentProps<Component>>\n : AcceptsProps<ContributionTargetProps<Value>, ContributionComponentProps<Component>>\n : unknown;\n\n/**\n * The check is a return type, not a parameter type: a conditional over `Spec` inside the parameter would make the\n * inference circular and TypeScript would fall back to the constraint, leaving the props chain unchecked.\n */\ntype ContributionModelsMissing = {\n readonly models: 'contribution must list every model its component requires';\n};\n\ntype ContributionModelPropsMismatch = {\n readonly models: 'a contribution model reads props this target does not publish';\n};\n\n/**\n * D118: a UI model of a contribution is created per mount and reads the props of that mount, so the props its\n * factory declares must be the props the target publishes. Without this the annotation was free and a wrong shape\n * Only failed when a component read a field the mount never had.\n */\ntype ContributionModelPropsGap<Spec, Value> = Spec extends {\n readonly models: infer Plans extends readonly unknown[];\n}\n ? {\n readonly [Index in keyof Plans]: [ContributionTargetProps<Value>] extends [ContributionModelProps<Plans[Index]>]\n ? never\n : Plans[Index];\n }[number]\n : never;\n\ntype ContributionModelDeclarations<Spec> = Spec extends { readonly models: readonly (infer Plan)[] }\n ? ContributionModelDeclaration<Plan>\n : never;\n\ntype ContributionRequiredModels<Spec> = Spec extends {\n readonly Component: { readonly requires: readonly (infer Required)[] };\n}\n ? Required\n : never;\n\ntype CheckedContribution<Spec, Value> =\n ExactContributionProps<Spec, Value> extends ContributionPropsMismatch\n ? ContributionPropsMismatch\n : [Exclude<ContributionRequiredModels<Spec>, ContributionModelDeclarations<Spec>>] extends [never]\n ? [ContributionModelPropsGap<Spec, Value>] extends [never]\n ? FeatureContribution\n : ContributionModelPropsMismatch\n : ContributionModelsMissing;\n\n/**\n * A slot contribution is a record, so the static form and the generation-scoped factory never collide. Each form is\n * its own signature and the props check is a return type: a conditional over `Spec` in the parameter would make the\n * inference circular and TypeScript would fall back to the constraint.\n */\ninterface FeatureSlotBuilder<Context, Evaluation> {\n <\n Value extends object,\n const Spec extends NoInfer<Value>,\n const Options extends FeatureContributionOptions<Evaluation>,\n >(\n target: ContributionTarget<Value>,\n contribution: (context: Context) => Spec,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n ): CheckedContribution<Spec, Value>;\n <\n Value extends object,\n const Spec extends NoInfer<Value>,\n const Options extends FeatureContributionOptions<Evaluation>,\n >(\n target: ContributionTarget<Value>,\n // oxlint-disable-next-line typescript/unified-signatures -- a union parameter leaves `Spec` uninferred (D85)\n contribution: Spec,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n ): CheckedContribution<Spec, Value>;\n}\n\n/**\n * D223: the second argument of `pipe` is a descriptor with one key. A handler is itself a function, so a bare\n * function could be read as either the handler or a factory of it; a record names which one it is, and the handler\n * receives the instance it belongs to together with the reader of the fold that is running.\n */\ntype FeaturePipeDescriptor<Value, Meta, Evaluation> = {\n readonly fold: (value: Value, meta: Meta, context: Evaluation) => Value;\n};\n\ntype FeaturePipeBuilder<Evaluation> = <\n Value,\n Meta,\n const Options extends FeatureContributionOptions<Evaluation> = FeatureContributionOptions<Evaluation>,\n>(\n target: ContributionTarget<PipeHandler<Value, Meta>>,\n descriptor: FeaturePipeDescriptor<Value, Meta, Evaluation>,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n) => FeatureContribution;\n\ntype FeatureRegisterBuilder<Context, Evaluation> = <\n Value extends object,\n const Options extends FeatureContributionOptions<Evaluation>,\n>(\n target: ContributionTarget<Value>,\n entry: FeatureContributionValueFactory<Context, NoInfer<Value>> | NoInfer<Value>,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n) => FeatureContribution;\n\ninterface FeatureContributionDescriptor {\n readonly id: DeclarationId;\n readonly priority: number;\n readonly target: ContributionPublicationInput['target'];\n}\n\n/** The live values of one instance, read by every reactive calculation that instance declared (D220). */\ntype FeatureEvaluationValues = Readonly<{\n exports: unknown;\n imports: unknown;\n own: unknown;\n}>;\n\ntype FeatureContributionPredicate = (context: unknown) => boolean;\n\n/** What a declaration keeps: the form was decided when it was written, so publication only asks for the readable. */\ntype FeatureContributionVisibility = (evaluation: FeatureEvaluationValues | undefined) => Readable<boolean>;\n\ntype SnapshotContributionOptions = {\n readonly priority: number;\n readonly when: FeatureContributionVisibility | undefined;\n};\n\n/** The handler an author wrote for a pipe: it runs on `fold`, never at declaration, preload or opening (D223). */\ntype FeaturePipeFold = (value: unknown, meta: unknown, context: unknown) => unknown;\n\ntype PendingFeatureContribution = SnapshotContributionOptions & {\n readonly fold: FeaturePipeFold | undefined;\n readonly target: ContributionPublicationInput['target'];\n readonly value: FeatureContributionValueFactory<unknown, unknown>;\n};\n\nconst contributionValueFactories = new WeakMap<object, FeatureContributionValueFactory<unknown, unknown>>();\nconst contributionVisibilities = new WeakMap<object, FeatureContributionVisibility>();\nconst contributionFolds = new WeakMap<object, FeaturePipeFold>();\n\nconst contributionOptionKeys = new Set(['priority', 'when']);\n\nfunction snapshotContributionPriority(value: unknown): number {\n if (value === undefined) return 0;\n\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new TypeError('Feature contribution priority must be a finite number.');\n }\n\n return value;\n}\n\n/**\n * D220: a predicate becomes one computed readable of this instance, and the publication path below stays the one\n * D79 and D196 already describe. `read` is the tracking reader of that computation, so a dynamic branch replaces\n * dependencies through the reactive graph, and a predicate that answers anything but a boolean fails its own read\n * instead of publishing a truthy object as visibility.\n */\nfunction predicateVisibility(\n predicate: FeatureContributionPredicate,\n evaluation: FeatureEvaluationValues | undefined,\n): Readable<boolean> {\n if (evaluation === undefined) throw new TypeError('Feature contribution when predicate has no instance to read.');\n\n return computed({\n read: read => {\n const answer = predicate({ ...evaluation, read });\n\n if (typeof answer !== 'boolean') {\n throw new TypeError('Feature contribution when predicate must return a boolean.');\n }\n\n return answer;\n },\n });\n}\n\n/**\n * D220: `when` is a readable or a predicate of the instance. The form is decided by what the author wrote, never by\n * what a call returns: the runtime does not invoke a predicate to classify it, and it never calls it twice.\n */\nfunction snapshotContributionVisibility(value: unknown): FeatureContributionVisibility | undefined {\n if (value === undefined) return undefined;\n\n if (typeof value === 'function') {\n const predicate = value as FeatureContributionPredicate;\n\n return evaluation => predicateVisibility(predicate, evaluation);\n }\n\n if (\n typeof value !== 'object' ||\n value === null ||\n typeof (value as Readable<boolean>).getSnapshot !== 'function' ||\n typeof (value as Readable<boolean>).subscribe !== 'function'\n ) {\n throw new TypeError('Feature contribution when must be a readable or a predicate of the instance.');\n }\n\n const readable = value as Readable<boolean>;\n\n return () => readable;\n}\n\nfunction snapshotContributionOptions(value: unknown): SnapshotContributionOptions {\n if (value === undefined) return { priority: 0, when: undefined };\n\n assertPlainRecord(value, 'Feature contribution options');\n const entries = dataEntries(value, 'Feature contribution options');\n\n if (entries.some(([key]) => !contributionOptionKeys.has(key))) {\n throw new TypeError('Feature contribution options accept only priority and when.');\n }\n\n const options = Object.fromEntries(entries);\n\n return {\n priority: snapshotContributionPriority(options['priority']),\n when: snapshotContributionVisibility(options['when']),\n };\n}\n\ntype FeatureContributionBuilders<Context, Evaluation> = {\n readonly declarations: WeakMap<object, PendingFeatureContribution>;\n readonly declared: Set<object>;\n readonly pipe: FeaturePipeBuilder<Evaluation>;\n readonly register: FeatureRegisterBuilder<Context, Evaluation>;\n readonly slot: FeatureSlotBuilder<Context, Evaluation>;\n};\n\n/** D223: a pipe declares a descriptor with exactly one key, so a bare function is named at the call site. */\nfunction snapshotPipeFold(value: unknown): FeaturePipeFold {\n if (typeof value === 'function' || typeof value !== 'object' || value === null) {\n throw new TypeError('Feature pipe expects a descriptor: pipe(target, { fold: (value, meta, context) => next }).');\n }\n\n assertPlainRecord(value, 'Feature pipe descriptor');\n const entries = dataEntries(value, 'Feature pipe descriptor');\n assertExactDataKeys(value, entries, ['fold'], 'Feature pipe descriptor');\n const fold = (value as { readonly fold: unknown }).fold;\n\n if (typeof fold !== 'function') throw new TypeError('Feature pipe fold must be a function.');\n\n return fold as FeaturePipeFold;\n}\n\nfunction createFeatureContributionBuilders<Context, Evaluation>(): FeatureContributionBuilders<Context, Evaluation> {\n const declarations = new WeakMap<object, PendingFeatureContribution>();\n const declared = new Set<object>();\n const declare = (target: unknown, value: unknown, options: unknown, label: string): FeatureContribution => {\n if (!isContributionTarget(target)) throw new TypeError(`Feature ${label} target is not authentic.`);\n\n const fold = label === 'pipe' ? snapshotPipeFold(value) : undefined;\n const factory: FeatureContributionValueFactory<unknown, unknown> =\n typeof value === 'function' ? (value as FeatureContributionValueFactory<unknown, unknown>) : () => value;\n\n const declaration = Object.freeze({});\n declared.add(declaration);\n declarations.set(declaration, { ...snapshotContributionOptions(options), fold, target, value: factory });\n\n return declaration as FeatureContribution;\n };\n\n return Object.freeze({\n declarations,\n declared,\n pipe: (target: unknown, value: unknown, options?: unknown) => declare(target, value, options, 'pipe'),\n register: (target: unknown, value: unknown, options?: unknown) => declare(target, value, options, 'register'),\n slot: ((target: unknown, value: unknown, options?: unknown) =>\n declare(target, value, options, 'slot')) as unknown as FeatureSlotBuilder<Context, Evaluation>,\n });\n}\n\nfunction isFeatureContributionDeclaration(\n builders: FeatureContributionBuilders<never, never>,\n value: unknown,\n): boolean {\n return typeof value === 'object' && value !== null && builders.declarations.has(value);\n}\n\nfunction snapshotFeatureContributions<Context, Evaluation>(\n featureId: string,\n builders: FeatureContributionBuilders<Context, Evaluation>,\n entries: readonly (readonly [string, unknown])[],\n): readonly FeatureContributionDescriptor[] {\n const seen = new Set<object>();\n const descriptors = entries.map(([key, candidate]): FeatureContributionDescriptor => {\n const declaration =\n typeof candidate === 'object' && candidate !== null ? builders.declarations.get(candidate) : undefined;\n\n if (declaration === undefined) throw new TypeError(`Feature contribution ${key} is not authentic.`);\n\n if (seen.has(candidate as object)) {\n throw new TypeError('Every feature contribution must be returned under exactly one key.');\n }\n\n seen.add(candidate as object);\n const descriptor: FeatureContributionDescriptor = Object.freeze({\n id: declarationId(`${featureId}.${key}`),\n priority: declaration.priority,\n target: declaration.target,\n });\n contributionValueFactories.set(descriptor, declaration.value);\n\n if (declaration.when !== undefined) contributionVisibilities.set(descriptor, declaration.when);\n\n if (declaration.fold !== undefined) contributionFolds.set(descriptor, declaration.fold);\n\n return descriptor;\n });\n\n if (seen.size !== builders.declared.size) {\n throw new TypeError('Every feature contribution must be returned under exactly one key.');\n }\n\n return Object.freeze(descriptors);\n}\n\n/**\n * D223: the descriptor is bound to its instance once, and the handler it publishes allocates nothing per call. The\n * context it hands to the author is frozen and built here; only the reader of the fold that is running changes, so\n * a nested fold with another reader pushes its own and the outer one continues with the reader it started with.\n */\nfunction boundPipeHandler(\n fold: FeaturePipeFold,\n evaluation: FeatureEvaluationValues | undefined,\n): PipeHandler<unknown, unknown> {\n if (evaluation === undefined) throw new TypeError('Feature pipe fold has no instance to read.');\n\n const readers: PipeRead[] = [];\n const context = Object.freeze({\n ...evaluation,\n read: <Value>(source: Readable<Value>): Value => {\n const reader = readers[readers.length - 1];\n\n return reader === undefined ? source.getSnapshot() : reader(source);\n },\n });\n\n return (value: unknown, meta: unknown, pipeContext: PipeReadContext): unknown => {\n readers.push(pipeContext.read);\n\n try {\n return fold(value, meta, context);\n } finally {\n readers.pop();\n }\n };\n}\n\n/**\n * Every published value carries the authority of the generation that produced it, so a renderer can give a\n * contribution the models of its own feature and nothing else (D70).\n */\nfunction createFeatureContributionPublication<Context>(\n descriptors: readonly FeatureContributionDescriptor[],\n context: Context,\n capture: (publication: ContributionPublication) => void,\n authority?: unknown,\n evaluation?: FeatureEvaluationValues,\n): ContributionPublication {\n const inputs = descriptors.map((descriptor): ContributionPublicationInput => {\n const createValue = contributionValueFactories.get(descriptor);\n\n if (createValue === undefined) throw new TypeError(`Feature contribution ${descriptor.id} is not authentic.`);\n\n const fold = contributionFolds.get(descriptor);\n const value = fold === undefined ? createValue(context) : boundPipeHandler(fold, evaluation);\n const visibility = contributionVisibilities.get(descriptor);\n\n return {\n id: descriptor.id,\n // The authority belongs to this publication: the same static value may be published by another feature (D70).\n ...(authority === undefined ? {} : { owner: authority }),\n priority: descriptor.priority,\n target: descriptor.target,\n value,\n when: visibility?.(evaluation),\n };\n });\n\n return publishContributions(inputs, capture);\n}\n\nexport {\n createFeatureContributionBuilders,\n createFeatureContributionPublication,\n isFeatureContributionDeclaration,\n snapshotFeatureContributions,\n};\nexport type {\n FeatureContribution,\n FeatureContributionDescriptor,\n FeatureEvaluationValues,\n FeaturePipeBuilder,\n FeatureRegisterBuilder,\n FeatureSlotBuilder,\n};\n"],"names":["contributionValueFactories","contributionVisibilities","contributionFolds","contributionOptionKeys","snapshotContributionPriority","value","predicateVisibility","predicate","evaluation","computed","read","answer","snapshotContributionVisibility","readable","snapshotContributionOptions","assertPlainRecord","entries","dataEntries","key","options","snapshotPipeFold","assertExactDataKeys","fold","createFeatureContributionBuilders","declarations","declared","declare","target","label","isContributionTarget","factory","declaration","isFeatureContributionDeclaration","builders","snapshotFeatureContributions","featureId","seen","descriptors","candidate","descriptor","declarationId","boundPipeHandler","readers","context","source","reader","meta","pipeContext","createFeatureContributionPublication","capture","authority","inputs","createValue","visibility","publishContributions"],"mappings":"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"}
1
+ {"version":3,"file":"feature-contribution.js","sources":["../src/feature-contribution.ts"],"sourcesContent":["import { computed, declarationId } from '@opetope/core';\nimport type { DeclarationId, Readable } from '@opetope/core';\nimport type {\n ContributionPublication,\n ContributionPublicationInput,\n ContributionTarget,\n PipeHandler,\n PipeRead,\n PipeReadContext,\n} from '@opetope/core/internal';\nimport { isContributionTarget, publishContributions } from '@opetope/core/internal';\n\nimport { contributionModel } from './feature-contribution-model';\nimport type {\n ContributionModelBuilder,\n ContributionModelDeclaration,\n ContributionModelProps,\n} from './feature-contribution-model';\nimport { assertExactDataKeys, assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactInput } from './feature-record';\n\ndeclare const featureContributionBrand: unique symbol;\n\ninterface FeatureContribution {\n readonly [featureContributionBrand]: true;\n}\n\ntype FeatureContributionValueFactory<Context, Value> = (context: Context) => Value;\n\n/**\n * `when` withholds a contribution while it reads `false`, so the target never lists it and `Slot`, `fold`, `select`\n * and emptiness checks skip it (D79). It is either a `Readable<boolean>` or a predicate of the instance: the\n * predicate answers a boolean and its `read` records what the answer depends on, so the runtime lowers it to one\n * computed readable of that instance and publishes it the way it always did (D220).\n */\ninterface FeatureContributionOptions<Evaluation = never> {\n readonly priority?: number;\n readonly when?: ((context: Evaluation) => boolean) | Readable<boolean>;\n}\n\n/**\n * Structural and renderer-free: with a props adapter the component must accept exactly what the adapter returns,\n * without one it must accept the props of the target. Slot props, adapter and component stay one chain (D85).\n */\ntype ContributionComponentProps<Component> = Component extends (props: infer Props, ...rest: never[]) => unknown\n ? Props\n : Component extends abstract new (props: infer Props, ...rest: never[]) => unknown\n ? Props\n : never;\n\ntype ContributionTargetProps<Value> = Value extends { readonly props?: (slotProps: infer Props) => unknown }\n ? Props\n : never;\n\ntype ContributionPropsMismatch = {\n readonly Component: 'contribution component must accept the props the adapter or the target supplies';\n};\n\n/** An erased component type states no props, so there is nothing left to check on that spec. */\ntype AcceptsProps<Supplied, Accepted> = [Accepted] extends [never]\n ? unknown\n : [Supplied] extends [Accepted]\n ? unknown\n : ContributionPropsMismatch;\n\ntype ExactContributionProps<Spec, Value> = Spec extends { readonly Component: infer Component }\n ? Spec extends { readonly props: (input: never) => infer Adapted }\n ? AcceptsProps<Adapted, ContributionComponentProps<Component>>\n : AcceptsProps<ContributionTargetProps<Value>, ContributionComponentProps<Component>>\n : unknown;\n\n/**\n * The check is a return type, not a parameter type: a conditional over `Spec` inside the parameter would make the\n * inference circular and TypeScript would fall back to the constraint, leaving the props chain unchecked.\n */\ntype ContributionModelsMissing = {\n readonly models: 'contribution must list every model its component requires';\n};\n\ntype ContributionModelPropsMismatch = {\n readonly models: 'a contribution model reads props this target does not publish';\n};\n\n/**\n * D118: a UI model of a contribution is created per mount and reads the props of that mount, so the props its\n * factory declares must be the props the target publishes. Without this the annotation was free and a wrong shape\n * Only failed when a component read a field the mount never had.\n */\ntype ContributionModelPropsGap<Spec, Value> = Spec extends {\n readonly models: infer Plans extends readonly unknown[];\n}\n ? {\n readonly [Index in keyof Plans]: [ContributionTargetProps<Value>] extends [ContributionModelProps<Plans[Index]>]\n ? never\n : Plans[Index];\n }[number]\n : never;\n\ntype ContributionModelDeclarations<Spec> = Spec extends { readonly models: readonly (infer Plan)[] }\n ? ContributionModelDeclaration<Plan>\n : never;\n\ntype ContributionRequiredModels<Spec> = Spec extends {\n readonly Component: { readonly requires: readonly (infer Required)[] };\n}\n ? Required\n : never;\n\ntype CheckedContribution<Spec, Value> =\n ExactContributionProps<Spec, Value> extends ContributionPropsMismatch\n ? ContributionPropsMismatch\n : [Exclude<ContributionRequiredModels<Spec>, ContributionModelDeclarations<Spec>>] extends [never]\n ? [ContributionModelPropsGap<Spec, Value>] extends [never]\n ? FeatureContribution\n : ContributionModelPropsMismatch\n : ContributionModelsMissing;\n\n/**\n * A slot contribution is a record, so the static form and the generation-scoped factory never collide. Each form is\n * its own signature and the props check is a return type: a conditional over `Spec` in the parameter would make the\n * inference circular and TypeScript would fall back to the constraint.\n */\ninterface FeatureSlotBuilder<Context, Evaluation> {\n <\n Value extends object,\n const Spec extends NoInfer<Value>,\n const Options extends FeatureContributionOptions<Evaluation>,\n >(\n target: ContributionTarget<Value>,\n contribution: (context: Context & { readonly model: ContributionModelBuilder }) => Spec,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n ): CheckedContribution<Spec, Value>;\n <\n Value extends object,\n const Spec extends NoInfer<Value>,\n const Options extends FeatureContributionOptions<Evaluation>,\n >(\n target: ContributionTarget<Value>,\n // oxlint-disable-next-line typescript/unified-signatures -- a union parameter leaves `Spec` uninferred (D85)\n contribution: Spec,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n ): CheckedContribution<Spec, Value>;\n}\n\n/**\n * D223: the second argument of `pipe` is a descriptor with one key. A handler is itself a function, so a bare\n * function could be read as either the handler or a factory of it; a record names which one it is, and the handler\n * receives the instance it belongs to together with the reader of the fold that is running.\n */\ntype FeaturePipeDescriptor<Value, Meta, Evaluation> = {\n readonly fold: (value: Value, meta: Meta, context: Evaluation) => Value;\n};\n\ntype FeaturePipeBuilder<Evaluation> = <\n Value,\n Meta,\n const Options extends FeatureContributionOptions<Evaluation> = FeatureContributionOptions<Evaluation>,\n>(\n target: ContributionTarget<PipeHandler<Value, Meta>>,\n descriptor: FeaturePipeDescriptor<Value, Meta, Evaluation>,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n) => FeatureContribution;\n\ntype FeatureRegisterBuilder<Context, Evaluation> = <\n Value extends object,\n const Options extends FeatureContributionOptions<Evaluation>,\n>(\n target: ContributionTarget<Value>,\n entry: FeatureContributionValueFactory<Context, NoInfer<Value>> | NoInfer<Value>,\n options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>,\n) => FeatureContribution;\n\ninterface FeatureContributionDescriptor {\n readonly id: DeclarationId;\n readonly priority: number;\n readonly target: ContributionPublicationInput['target'];\n}\n\n/** The live values of one instance, read by every reactive calculation that instance declared (D220). */\ntype FeatureEvaluationValues = Readonly<{\n imports: unknown;\n own: unknown;\n}>;\n\ntype FeatureContributionPredicate = (context: unknown) => boolean;\n\n/** What a declaration keeps: the form was decided when it was written, so publication only asks for the readable. */\ntype FeatureContributionVisibility = (evaluation: FeatureEvaluationValues | undefined) => Readable<boolean>;\n\ntype SnapshotContributionOptions = {\n readonly priority: number;\n readonly when: FeatureContributionVisibility | undefined;\n};\n\n/** The handler an author wrote for a pipe: it runs on `fold`, never at declaration, preload or opening (D223). */\ntype FeaturePipeFold = (value: unknown, meta: unknown, context: unknown) => unknown;\n\ntype PendingFeatureContribution = SnapshotContributionOptions & {\n readonly fold: FeaturePipeFold | undefined;\n readonly slot: boolean;\n readonly target: ContributionPublicationInput['target'];\n readonly value: FeatureContributionValueFactory<unknown, unknown>;\n};\n\nconst contributionValueFactories = new WeakMap<object, FeatureContributionValueFactory<unknown, unknown>>();\nconst contributionVisibilities = new WeakMap<object, FeatureContributionVisibility>();\nconst contributionFolds = new WeakMap<object, FeaturePipeFold>();\nconst contributionSlots = new WeakSet<object>();\n\nconst contributionOptionKeys = new Set(['priority', 'when']);\n\nfunction snapshotContributionPriority(value: unknown): number {\n if (value === undefined) return 0;\n\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new TypeError('Feature contribution priority must be a finite number.');\n }\n\n return value;\n}\n\n/**\n * D220: a predicate becomes one computed readable of this instance, and the publication path below stays the one\n * D79 and D196 already describe. `read` is the tracking reader of that computation, so a dynamic branch replaces\n * dependencies through the reactive graph, and a predicate that answers anything but a boolean fails its own read\n * instead of publishing a truthy object as visibility.\n */\nfunction predicateVisibility(\n predicate: FeatureContributionPredicate,\n evaluation: FeatureEvaluationValues | undefined,\n): Readable<boolean> {\n if (evaluation === undefined) throw new TypeError('Feature contribution when predicate has no instance to read.');\n\n return computed({\n read: read => {\n const answer = predicate({ ...evaluation, read });\n\n if (typeof answer !== 'boolean') {\n throw new TypeError('Feature contribution when predicate must return a boolean.');\n }\n\n return answer;\n },\n });\n}\n\n/**\n * D220: `when` is a readable or a predicate of the instance. The form is decided by what the author wrote, never by\n * what a call returns: the runtime does not invoke a predicate to classify it, and it never calls it twice.\n */\nfunction snapshotContributionVisibility(value: unknown): FeatureContributionVisibility | undefined {\n if (value === undefined) return undefined;\n\n if (typeof value === 'function') {\n const predicate = value as FeatureContributionPredicate;\n\n return evaluation => predicateVisibility(predicate, evaluation);\n }\n\n if (\n typeof value !== 'object' ||\n value === null ||\n typeof (value as Readable<boolean>).getSnapshot !== 'function' ||\n typeof (value as Readable<boolean>).subscribe !== 'function'\n ) {\n throw new TypeError('Feature contribution when must be a readable or a predicate of the instance.');\n }\n\n const readable = value as Readable<boolean>;\n\n return () => readable;\n}\n\nfunction snapshotContributionOptions(value: unknown): SnapshotContributionOptions {\n if (value === undefined) return { priority: 0, when: undefined };\n\n assertPlainRecord(value, 'Feature contribution options');\n const entries = dataEntries(value, 'Feature contribution options');\n\n if (entries.some(([key]) => !contributionOptionKeys.has(key))) {\n throw new TypeError('Feature contribution options accept only priority and when.');\n }\n\n const options = Object.fromEntries(entries);\n\n return {\n priority: snapshotContributionPriority(options['priority']),\n when: snapshotContributionVisibility(options['when']),\n };\n}\n\ntype FeatureContributionBuilders<Context, Evaluation> = {\n readonly declarations: WeakMap<object, PendingFeatureContribution>;\n readonly declared: Set<object>;\n readonly pipe: FeaturePipeBuilder<Evaluation>;\n readonly register: FeatureRegisterBuilder<Context, Evaluation>;\n readonly slot: FeatureSlotBuilder<Context, Evaluation>;\n};\n\n/** D223: a pipe declares a descriptor with exactly one key, so a bare function is named at the call site. */\nfunction snapshotPipeFold(value: unknown): FeaturePipeFold {\n if (typeof value === 'function' || typeof value !== 'object' || value === null) {\n throw new TypeError('Feature pipe expects a descriptor: pipe(target, { fold: (value, meta, context) => next }).');\n }\n\n assertPlainRecord(value, 'Feature pipe descriptor');\n const entries = dataEntries(value, 'Feature pipe descriptor');\n assertExactDataKeys(value, entries, ['fold'], 'Feature pipe descriptor');\n const fold = (value as { readonly fold: unknown }).fold;\n\n if (typeof fold !== 'function') throw new TypeError('Feature pipe fold must be a function.');\n\n return fold as FeaturePipeFold;\n}\n\nfunction createFeatureContributionBuilders<Context, Evaluation>(): FeatureContributionBuilders<Context, Evaluation> {\n const declarations = new WeakMap<object, PendingFeatureContribution>();\n const declared = new Set<object>();\n const declare = (target: unknown, value: unknown, options: unknown, label: string): FeatureContribution => {\n if (!isContributionTarget(target)) throw new TypeError(`Feature ${label} target is not authentic.`);\n\n const fold = label === 'pipe' ? snapshotPipeFold(value) : undefined;\n const factory: FeatureContributionValueFactory<unknown, unknown> =\n typeof value === 'function' ? (value as FeatureContributionValueFactory<unknown, unknown>) : () => value;\n\n const declaration = Object.freeze({});\n declared.add(declaration);\n declarations.set(declaration, {\n ...snapshotContributionOptions(options),\n fold,\n slot: label === 'slot' && typeof value === 'function',\n target,\n value: factory,\n });\n\n return declaration as FeatureContribution;\n };\n\n return Object.freeze({\n declarations,\n declared,\n pipe: (target: unknown, value: unknown, options?: unknown) => declare(target, value, options, 'pipe'),\n register: (target: unknown, value: unknown, options?: unknown) => declare(target, value, options, 'register'),\n slot: ((target: unknown, value: unknown, options?: unknown) =>\n declare(target, value, options, 'slot')) as unknown as FeatureSlotBuilder<Context, Evaluation>,\n });\n}\n\nfunction isFeatureContributionDeclaration(\n builders: FeatureContributionBuilders<never, never>,\n value: unknown,\n): boolean {\n return typeof value === 'object' && value !== null && builders.declarations.has(value);\n}\n\nfunction rememberContribution(\n descriptor: FeatureContributionDescriptor,\n declaration: PendingFeatureContribution,\n): void {\n contributionValueFactories.set(descriptor, declaration.value);\n if (declaration.slot) contributionSlots.add(descriptor);\n if (declaration.when !== undefined) contributionVisibilities.set(descriptor, declaration.when);\n if (declaration.fold !== undefined) contributionFolds.set(descriptor, declaration.fold);\n}\n\nfunction snapshotFeatureContributions<Context, Evaluation>(\n featureId: string,\n builders: FeatureContributionBuilders<Context, Evaluation>,\n entries: readonly (readonly [string, unknown])[],\n): readonly FeatureContributionDescriptor[] {\n const seen = new Set<object>();\n const descriptors = entries.map(([key, candidate]): FeatureContributionDescriptor => {\n const declaration =\n typeof candidate === 'object' && candidate !== null ? builders.declarations.get(candidate) : undefined;\n\n if (declaration === undefined) throw new TypeError(`Feature contribution ${key} is not authentic.`);\n\n if (seen.has(candidate as object)) {\n throw new TypeError('Every feature contribution must be returned under exactly one key.');\n }\n\n seen.add(candidate as object);\n const descriptor: FeatureContributionDescriptor = Object.freeze({\n id: declarationId(`${featureId}.${key}`),\n priority: declaration.priority,\n target: declaration.target,\n });\n rememberContribution(descriptor, declaration);\n\n return descriptor;\n });\n\n if (seen.size !== builders.declared.size) {\n throw new TypeError('Every feature contribution must be returned under exactly one key.');\n }\n\n return Object.freeze(descriptors);\n}\n\n/**\n * D223: the descriptor is bound to its instance once, and the handler it publishes allocates nothing per call. The\n * context it hands to the author is frozen and built here; only the reader of the fold that is running changes, so\n * a nested fold with another reader pushes its own and the outer one continues with the reader it started with.\n */\nfunction boundPipeHandler(\n fold: FeaturePipeFold,\n evaluation: FeatureEvaluationValues | undefined,\n): PipeHandler<unknown, unknown> {\n if (evaluation === undefined) throw new TypeError('Feature pipe fold has no instance to read.');\n\n const readers: PipeRead[] = [];\n const context = Object.freeze({\n ...evaluation,\n read: <Value>(source: Readable<Value>): Value => {\n const reader = readers[readers.length - 1];\n\n return reader === undefined ? source.getSnapshot() : reader(source);\n },\n });\n\n return (value: unknown, meta: unknown, pipeContext: PipeReadContext): unknown => {\n readers.push(pipeContext.read);\n\n try {\n return fold(value, meta, context);\n } finally {\n readers.pop();\n }\n };\n}\n\n/**\n * Every published value carries the authority of the generation that produced it, so a renderer can give a\n * contribution the models of its own feature and nothing else (D70).\n */\nfunction createFeatureContributionPublication<Context>(\n descriptors: readonly FeatureContributionDescriptor[],\n context: Context,\n capture: (publication: ContributionPublication) => void,\n authority?: unknown,\n evaluation?: FeatureEvaluationValues,\n): ContributionPublication {\n let slotContext: (Context & { readonly model: ContributionModelBuilder }) | undefined;\n const inputs = descriptors.map((descriptor): ContributionPublicationInput => {\n const createValue = contributionValueFactories.get(descriptor);\n\n if (createValue === undefined) throw new TypeError(`Feature contribution ${descriptor.id} is not authentic.`);\n\n const fold = contributionFolds.get(descriptor);\n const valueContext = contributionSlots.has(descriptor)\n ? (slotContext ??= Object.freeze({ ...context, model: contributionModel }))\n : context;\n const value = fold === undefined ? createValue(valueContext) : boundPipeHandler(fold, evaluation);\n const visibility = contributionVisibilities.get(descriptor);\n\n return {\n id: descriptor.id,\n // The authority belongs to this publication: the same static value may be published by another feature (D70).\n ...(authority === undefined ? {} : { owner: authority }),\n priority: descriptor.priority,\n target: descriptor.target,\n value,\n when: visibility?.(evaluation),\n };\n });\n\n return publishContributions(inputs, capture);\n}\n\nexport {\n createFeatureContributionBuilders,\n createFeatureContributionPublication,\n isFeatureContributionDeclaration,\n snapshotFeatureContributions,\n};\nexport type {\n FeatureContribution,\n FeatureContributionDescriptor,\n FeatureEvaluationValues,\n FeaturePipeBuilder,\n FeatureRegisterBuilder,\n FeatureSlotBuilder,\n};\n"],"names":["contributionValueFactories","contributionVisibilities","contributionFolds","contributionSlots","contributionOptionKeys","snapshotContributionPriority","value","predicateVisibility","predicate","evaluation","computed","read","answer","snapshotContributionVisibility","readable","snapshotContributionOptions","assertPlainRecord","entries","dataEntries","key","options","snapshotPipeFold","assertExactDataKeys","fold","createFeatureContributionBuilders","declarations","declared","declare","target","label","isContributionTarget","factory","declaration","isFeatureContributionDeclaration","builders","rememberContribution","descriptor","snapshotFeatureContributions","featureId","seen","descriptors","candidate","declarationId","boundPipeHandler","readers","context","source","reader","meta","pipeContext","createFeatureContributionPublication","capture","authority","slotContext","inputs","createValue","valueContext","contributionModel","visibility","publishContributions"],"mappings":"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"}
@@ -14,7 +14,7 @@ type FeatureInput<Id extends string, Imports extends FeatureImportRecord, Requir
14
14
  readonly id: Id;
15
15
  readonly imports?: Imports;
16
16
  readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);
17
- readonly provides?: FeatureProvidesFactory<Id, FeatureOpenContext<Id, Imports, Own, Exports>, FeatureEvaluationContext<Id, Imports, Own, Exports>, Own, Provided>;
17
+ readonly provides?: FeatureProvidesFactory<Id, FeatureOpenContext<Id, Imports, Own>, FeatureEvaluationContext<Id, Imports, Own>, Own, Provided>;
18
18
  readonly requires?: Requires;
19
19
  /** The feature lives while every condition holds; an empty or absent list is a permanent feature (D93). */
20
20
  readonly when?: When;
@@ -1,2 +1,2 @@
1
- import{FeatureError as m}from"@opetope/core";import{hasOwn as x,withdrawContributions as T,isCallTarget as M}from"@opetope/core/internal";import{isLifetimeAttachmentRef as k}from"./attachment-declaration.js";import{registerFeatureInstanceImports as D,registerFeatureInstanceCallTargets as G}from"./feature-call-authority.js";import{createFeatureContributionPublication as K}from"./feature-contribution.js";import{contributionModel as $}from"./feature-contribution-model.js";import{requireFeatureRecord as V,registerFeatureExportFacade as A}from"./feature-definition-support.js";import{getLazyFeature as L}from"./feature-lazy.js";import{openLazyFeatureInstance as Q}from"./feature-lazy-generation.js";import{isFeatureMaterializationRef as U,bindFeatureResource as W}from"./feature-materialization-binding.js";import{materializeFeatureData as B,readInstanceModels as H,registerFeatureDataScope as J,isFeatureDataRef as N,requireFeatureDataScope as X}from"./feature-model.js";import{assertRequiredPortValue as Y,isOptionalPortRequirement as Z,getRequiredPort as _}from"./feature-port.js";import{bindFeatureReadyPorts as v}from"./feature-port-binding.js";import{assertPlainRecord as l,dataEntries as F}from"./feature-record.js";import{registerModuleActivity as ee}from"./inspection-module-activity.js";import{carryFeatureGenerationFence as re,openFeature as ne,notReadyGeneration as te,quarantinedGeneration as oe}from"./module-generation.js";import{registerModuleRetirementParticipant as g,resolveModuleCallTarget as ie}from"./public-module-instance.js";const ue=new Set(["cleanupFailure","imports","reporter","requirements"]);function ae(e,r){return{authority:void 0,context:void 0,contributions:r,evaluation:void 0,featureId:e,inactive:!1,inactiveReason:void 0,publication:void 0,retirement:void 0,retirementCause:void 0}}function R(e){return e.inactiveReason??(e.inactiveReason=new m("retired",e.featureId))}function p(e){e.context=void 0,e.evaluation=void 0}function E(e){if(e.inactive=!0,p(e),e.authority=void 0,e.publication===void 0)return;const r=e.publication;T(r),e.publication=void 0}function ce(e,r,n,t){e.context=r,e.evaluation=t,g(n,{fence:()=>E(e)})}function b(e){return e instanceof m&&e.code==="quarantined"&&e.retryCleanup!==void 0}function w(e,r){let n;return oe(e.declarationId,e.failures,r,()=>(n!==void 0||(n=(async()=>{try{await e.retryCleanup()}catch(t){throw b(t)?w(t,r):t}})()),n))}function j(e,r,n){if(e.retirementCause??(e.retirementCause=n),e.retirement!==void 0)return e.retirement;let t=()=>{},o=()=>{};const u=new Promise((i,a)=>{t=a,o=i});e.retirement=u;try{r.close().then(o,i=>{e.retirement===u&&(e.retirement=void 0),t(e.retirementCause!==void 0&&b(i)?w(i,e.retirementCause):i)})}catch(i){e.retirement=void 0,t(e.retirementCause!==void 0&&b(i)?w(i,e.retirementCause):i)}return u}function pe(e){const r=e.context;if(r===void 0)throw new TypeError("Feature contribution context is unavailable.");return{context:r}}function fe(e,r){e.publication=r,e.inactive&&E(e)}async function se(e,r,n){try{if(e.inactive)throw R(e);const{context:t}=pe(e);if(K(e.contributions,t,o=>{fe(e,o)},e.authority,e.evaluation),p(e),e.inactive)throw R(e);return n}catch(t){p(e);const o=t instanceof m&&t.code==="retired"?t:te(e.featureId,Object.freeze({cause:t,phase:"open",stage:"prepare"}));throw await j(e,r,o),o}}function de(e,r){const n=r.ready.then(t=>se(e,r,t),t=>{throw p(e),t});return{close:()=>j(e,r),instance:r.instance,ready:n}}function z(e,r,n){l(e,n);const t=F(e,n);if(t.length!==r.length||r.some(o=>!x(e,o)))throw new TypeError(`${n} must contain every exact field once.`);return Object.freeze(Object.fromEntries(t))}function me(e){if(e!==void 0&&e!=="report"&&e!=="quarantine")throw new TypeError('openFeature cleanupFailure must be "report" or "quarantine".')}function le(e,r,n){var t;for(const o of r.requirementKeys){const u=(t=e.requires)==null?void 0:t[o];Y(_(u),n[o],o,Z(u))}}function Fe(e,r,n){l(n,"openFeature options");const t=F(n,"openFeature options");for(const[i]of t)if(!ue.has(i))throw new TypeError(`Unknown openFeature option ${i}.`);for(const i of["imports","reporter"])if(!x(n,i))throw new TypeError(`openFeature requires ${i}.`);if(typeof n.reporter!="function")throw new TypeError("openFeature reporter must be a function.");me(n.cleanupFailure);const o=z(n.imports,r.importKeys,"openFeature imports"),u=z(n.requirements??{},r.requirementKeys,"openFeature requirements");return le(e,r,u),Object.freeze({...Object.fromEntries(t),imports:o,requirements:u})}function be(e,r,n){if(N(n))return X(e).read(n);if(U(n))return W(e,n);if(k(n))throw new TypeError(`own.${r} is a lifecycle binding, so exports has no value to take from it.`);return ie(e,n)}function we(e,r){const n=new Map,t={};for(const[o,u]of Object.entries(r))Object.defineProperty(t,o,{enumerable:!0,get:()=>(n.has(o)||n.set(o,be(e,o,u)),n.get(o))});return Object.freeze(t)}function he(e,r){if(M(r))return r;const n=r;if(typeof(n==null?void 0:n.getSnapshot)=="function"&&typeof n.subscribe=="function")return r;throw new TypeError(`Feature export ${e} must be a Call, a Readable or a Resource.`)}function ye(e,r,n){const t=n({own:r}),o=t===r?Object.fromEntries(Object.keys(r).map(i=>[i,r[i]])):t;l(o,"defineFeature exports result");const u=Object.freeze(Object.fromEntries(F(o,"defineFeature exports result").map(([i,a])=>[i,he(i,a)])));return A(e,u),u}function Ce(e,r,n){const t=n.imports;D(e.imports,t);const o=n.requirements;G(o);const u={};return r.importScopeKey!==void 0&&(u[r.importScopeKey]=t),r.requirementScopeKey!==void 0&&(u[r.requirementScopeKey]=o),Object.freeze({imports:t,lowScopes:Object.freeze(u)})}function I(e,r,n,t){var y;(y=t==null?void 0:t.changed)==null||y.call(t);const{imports:o,lowScopes:u}=Ce(e,r,n),i=n.reporter,a=r.contributions.length===0?void 0:ae(e.id,r.contributions),f=ne(r.module,{...n.cleanupFailure===void 0?{}:{cleanupFailure:n.cleanupFailure},prepare:c=>{t!==void 0&&ee(c,t),r.dataDescriptors.length>0&&B(e.id,r.dataDescriptors,o,c,i,d=>{J(c,d),g(c,{fence:()=>{d.fence();const O=d.drain();return{drain:()=>O,retry:()=>O}}})},t);const C=we(c,e.own),s=ye(e.exports,C,r.exports),S=Object.freeze({exports:s,imports:o,instance:c,model:$,own:e.own});a!==void 0&&(ce(a,S,c,{exports:s,imports:o,own:C}),a.authority=Object.freeze({models:H(c,r.dataDescriptors)}));const q=Object.freeze({exports:s});return v(q,r.providers,c),q},reporter:i,scopes:u});if(a===void 0)return f;const h=de(a,f);return re(f,h),h}function P(e,r,n){const t=V(e),o=Fe(e,t,r);return L(e)===void 0?I(e,t,o,n):Q(e,u=>I(e,u,o,n))}function qe(e,r){return P(e,r)}const Oe=qe;export{Oe as openFeature,P as openFeatureWithActivity};
1
+ import{FeatureError as l}from"@opetope/core";import{hasOwn as E,withdrawContributions as K,isCallTarget as k}from"@opetope/core/internal";import{registerFeatureInstanceImports as D,registerFeatureInstanceCallTargets as $}from"./feature-call-authority.js";import{createFeatureContributionPublication as M}from"./feature-contribution.js";import{requireFeatureRecord as V,registerFeatureExportFacade as A}from"./feature-definition-support.js";import{getLazyFeature as L}from"./feature-lazy.js";import{openLazyFeatureInstance as Q}from"./feature-lazy-generation.js";import{materializeFeatureData as U,readInstanceModels as W,registerFeatureDataScope as B}from"./feature-model.js";import{materializeFeatureOwn as H}from"./feature-own-values.js";import{assertRequiredPortValue as J,isOptionalPortRequirement as N,getRequiredPort as X}from"./feature-port.js";import{bindFeatureReadyPorts as Y}from"./feature-port-binding.js";import{assertPlainRecord as F,dataEntries as b}from"./feature-record.js";import{registerModuleActivity as Z}from"./inspection-module-activity.js";import{carryFeatureGenerationFence as _,openFeature as v,notReadyGeneration as ee,quarantinedGeneration as ne}from"./module-generation.js";import{registerModuleRetirementParticipant as R}from"./public-module-instance.js";const re=new Set(["cleanupFailure","imports","reporter","requirements"]);function te(e,n){return{authority:void 0,context:void 0,contributions:n,evaluation:void 0,featureId:e,inactive:!1,inactiveReason:void 0,publication:void 0,retirement:void 0,retirementCause:void 0}}function j(e){return e.inactiveReason??(e.inactiveReason=new l("retired",e.featureId))}function f(e){e.context=void 0,e.evaluation=void 0}function z(e){if(e.inactive=!0,f(e),e.authority=void 0,e.publication===void 0)return;const n=e.publication;K(n),e.publication=void 0}function oe(e,n,t,r){e.context=n,e.evaluation=r,R(t,{fence:()=>z(e)})}function w(e){return e instanceof l&&e.code==="quarantined"&&e.retryCleanup!==void 0}function h(e,n){let t;return ne(e.declarationId,e.failures,n,()=>(t!==void 0||(t=(async()=>{try{await e.retryCleanup()}catch(r){throw w(r)?h(r,n):r}})()),t))}function I(e,n,t){if(e.retirementCause??(e.retirementCause=t),e.retirement!==void 0)return e.retirement;let r=()=>{},o=()=>{};const u=new Promise((i,a)=>{r=a,o=i});e.retirement=u;try{n.close().then(o,i=>{e.retirement===u&&(e.retirement=void 0),r(e.retirementCause!==void 0&&w(i)?h(i,e.retirementCause):i)})}catch(i){e.retirement=void 0,r(e.retirementCause!==void 0&&w(i)?h(i,e.retirementCause):i)}return u}function ie(e){const n=e.context;if(n===void 0)throw new TypeError("Feature contribution context is unavailable.");return{context:n}}function ue(e,n){e.publication=n,e.inactive&&z(e)}async function ce(e,n,t){try{if(e.inactive)throw j(e);const{context:r}=ie(e);if(M(e.contributions,r,o=>{ue(e,o)},e.authority,e.evaluation),f(e),e.inactive)throw j(e);return t}catch(r){f(e);const o=r instanceof l&&r.code==="retired"?r:ee(e.featureId,Object.freeze({cause:r,phase:"open",stage:"prepare"}));throw await I(e,n,o),o}}function ae(e,n){const t=n.ready.then(r=>ce(e,n,r),r=>{throw f(e),r});return{close:()=>I(e,n),instance:n.instance,ready:t}}function S(e,n,t){F(e,t);const r=b(e,t);if(r.length!==n.length||n.some(o=>!E(e,o)))throw new TypeError(`${t} must contain every exact field once.`);return Object.freeze(Object.fromEntries(r))}function pe(e){if(e!==void 0&&e!=="report"&&e!=="quarantine")throw new TypeError('openFeature cleanupFailure must be "report" or "quarantine".')}function fe(e,n,t){var r;for(const o of n.requirementKeys){const u=(r=e.requires)==null?void 0:r[o];J(X(u),t[o],o,N(u))}}function de(e,n,t){F(t,"openFeature options");const r=b(t,"openFeature options");for(const[i]of r)if(!re.has(i))throw new TypeError(`Unknown openFeature option ${i}.`);for(const i of["imports","reporter"])if(!E(t,i))throw new TypeError(`openFeature requires ${i}.`);if(typeof t.reporter!="function")throw new TypeError("openFeature reporter must be a function.");pe(t.cleanupFailure);const o=S(t.imports,n.importKeys,"openFeature imports"),u=S(t.requirements??{},n.requirementKeys,"openFeature requirements");return fe(e,n,u),Object.freeze({...Object.fromEntries(r),imports:o,requirements:u})}function se(e,n){if(k(n))return n;const t=n;if(typeof(t==null?void 0:t.getSnapshot)=="function"&&typeof t.subscribe=="function")return n;throw new TypeError(`Feature export ${e} must be a Call, a Readable or a Resource.`)}function me(e,n,t){const r=t({own:n}),o=r===n?Object.fromEntries(Object.keys(n).map(i=>[i,n[i]])):r;F(o,"defineFeature exports result");const u=Object.freeze(Object.fromEntries(b(o,"defineFeature exports result").map(([i,a])=>[i,se(i,a)])));return A(e,u),u}function le(e,n,t){const r=t.imports;D(e.imports,r);const o=t.requirements;$(o);const u={};return n.importScopeKey!==void 0&&(u[n.importScopeKey]=r),n.requirementScopeKey!==void 0&&(u[n.requirementScopeKey]=o),Object.freeze({imports:r,lowScopes:Object.freeze(u)})}function P(e,n,t,r,o){var q;(q=r==null?void 0:r.changed)==null||q.call(r);const{imports:u,lowScopes:i}=le(e,n,t),a=t.reporter,p=n.contributions.length===0?void 0:te(e.id,n.contributions),d=v(n.module,{...t.cleanupFailure===void 0?{}:{cleanupFailure:t.cleanupFailure},prepare:c=>{r!==void 0&&Z(c,r),n.dataDescriptors.length>0&&U(e.id,n.dataDescriptors,u,c,a,m=>{B(c,m),R(c,{fence:()=>{m.fence();const g=m.drain();return{drain:()=>g,retry:()=>g}}})},r);const O=n.providers.length===0?void 0:{available:new Set,local:new Set},s=H(c,e.own,O),G=me(e.exports,s,n.exports);o==null||o();const x=Object.freeze({imports:u,own:s});p!==void 0&&(oe(p,x,c,x),p.authority=Object.freeze({models:W(c,n.dataDescriptors)}));const C=Object.freeze({exports:G});return Y(C,n.providers,c,s,O,o),C},reporter:a,scopes:i});if(p===void 0)return d;const y=ae(p,d);return _(d,y),y}function T(e,n,t){const r=V(e),o=de(e,r,n);return L(e)===void 0?P(e,r,o,t):Q(e,(u,i)=>P(e,u,o,t,i))}function Fe(e,n){return T(e,n)}const be=Fe;export{be as openFeature,T as openFeatureWithActivity};
2
2
  //# sourceMappingURL=feature-generation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-generation.js","sources":["../src/feature-generation.ts"],"sourcesContent":["import { FeatureError } from '@opetope/core';\nimport type { DeclarationId, Readable } from '@opetope/core';\nimport { hasOwn, isCallTarget, withdrawContributions } from '@opetope/core/internal';\nimport type { ContributionPublication } from '@opetope/core/internal';\n\nimport { isLifetimeAttachmentRef } from './attachment-declaration';\nimport type {\n AnyFeature,\n Feature,\n FeatureExportRecord,\n FeatureExportsOf,\n FeatureImportRecord,\n FeatureImportValues,\n FeatureOwnRecord,\n} from './feature-authoring';\nimport { registerFeatureInstanceCallTargets, registerFeatureInstanceImports } from './feature-call-authority';\nimport type { FeatureContractIdentity } from './feature-contract';\nimport { createFeatureContributionPublication } from './feature-contribution';\nimport type { FeatureContributionDescriptor, FeatureEvaluationValues } from './feature-contribution';\nimport { contributionModel } from './feature-contribution-model';\nimport { registerFeatureExportFacade, requireFeatureRecord } from './feature-definition-support';\nimport { getLazyFeature } from './feature-lazy';\nimport { openLazyFeatureInstance } from './feature-lazy-generation';\nimport { bindFeatureResource, isFeatureMaterializationRef } from './feature-materialization-binding';\nimport {\n isFeatureDataRef,\n materializeFeatureData,\n readInstanceModels,\n registerFeatureDataScope,\n requireFeatureDataScope,\n} from './feature-model';\nimport { assertRequiredPortValue, getRequiredPort, isOptionalPortRequirement } from './feature-port';\nimport type { PortRequirementRecord, RequiredPortValues } from './feature-port';\nimport { bindFeatureReadyPorts } from './feature-port-binding';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport type { FeatureActivityOwner } from './inspection-activity';\nimport { registerModuleActivity } from './inspection-module-activity';\nimport {\n carryFeatureGenerationFence,\n notReadyGeneration,\n openFeature as openLoweredModuleInstance,\n quarantinedGeneration,\n} from './module-generation';\nimport type { FeatureInstance } from './module-generation';\nimport { registerModuleRetirementParticipant, resolveModuleCallTarget } from './public-module';\nimport type { CleanupFailurePolicy, ErrorReporter, ModuleCallRef, ModuleInstanceRef } from './public-module';\n\ninterface FeatureReady<Exports> {\n readonly exports: Exports;\n}\n\ntype FeatureInstanceOf<Id extends string, Exports> = FeatureInstance<Id, FeatureReady<Exports>>;\n\ntype FeatureReadyOf<Definition> = FeatureReady<FeatureExportsOf<Definition>>;\n\ntype FeatureContributionInstanceState = {\n authority: unknown;\n context: unknown | undefined;\n readonly contributions: readonly FeatureContributionDescriptor[];\n evaluation: FeatureEvaluationValues | undefined;\n readonly featureId: DeclarationId;\n inactive: boolean;\n inactiveReason: FeatureError | undefined;\n publication: ContributionPublication | undefined;\n retirement: Promise<void> | undefined;\n retirementCause: FeatureError | undefined;\n};\n\ntype FeatureOpenBaseOptions<Imports> = {\n readonly cleanupFailure?: CleanupFailurePolicy;\n readonly imports: Imports;\n readonly reporter: ErrorReporter;\n};\n\ntype FeatureRequirementOpenOptions<Requirements, Keys extends PropertyKey> = keyof Requirements extends never\n ? { readonly requirements?: ExactKeys<Keys, Requirements> & Requirements }\n : { readonly requirements: ExactKeys<Keys, Requirements> & Requirements };\n\ntype ExactExpectedObjectMember<Actual, Expected> = Expected extends unknown\n ? Actual extends Expected\n ? keyof Actual extends keyof Expected\n ? true\n : never\n : never\n : never;\ntype ExactObjectUnionMember<Actual, Expected> = Actual extends unknown\n ? Actual extends readonly unknown[]\n ? true\n : Actual extends object\n ? true extends ExactExpectedObjectMember<Actual, Expected>\n ? true\n : false\n : true\n : never;\ntype NoExtraObjectKeys<Actual, Expected> = false extends ExactObjectUnionMember<Actual, Expected> ? never : unknown;\ntype ExactImportValueFields<Actual, Expected> = {\n readonly [Key in keyof Expected]: Key extends keyof Actual ? NoExtraObjectKeys<Actual[Key], Expected[Key]> : never;\n};\n\nconst featureOpenOptionKeys = new Set(['cleanupFailure', 'imports', 'reporter', 'requirements']);\n\nfunction createFeatureContributionInstanceState(\n featureId: DeclarationId,\n contributions: readonly FeatureContributionDescriptor[],\n): FeatureContributionInstanceState {\n return {\n authority: undefined,\n context: undefined,\n contributions,\n evaluation: undefined,\n featureId,\n inactive: false,\n inactiveReason: undefined,\n publication: undefined,\n retirement: undefined,\n retirementCause: undefined,\n };\n}\n\nfunction featureContributionInactiveReason(state: FeatureContributionInstanceState): FeatureError {\n return (state.inactiveReason ??= new FeatureError('retired', state.featureId));\n}\n\nfunction releaseFeatureContributionPreparation(state: FeatureContributionInstanceState): void {\n state.context = undefined;\n state.evaluation = undefined;\n}\n\nfunction fenceFeatureContributions(state: FeatureContributionInstanceState): void {\n state.inactive = true;\n releaseFeatureContributionPreparation(state);\n // The authority a mount was granted dies with the fence: keeping it alive would outlive the models it names.\n state.authority = undefined;\n\n if (state.publication === undefined) return;\n\n const publication = state.publication;\n withdrawContributions(publication);\n state.publication = undefined;\n}\n\nfunction prepareFeatureContributions(\n state: FeatureContributionInstanceState,\n context: unknown,\n instance: ModuleInstanceRef,\n evaluation: FeatureEvaluationValues,\n): void {\n state.context = context;\n state.evaluation = evaluation;\n registerModuleRetirementParticipant(instance, { fence: () => fenceFeatureContributions(state) });\n}\n\nfunction isQuarantinedGeneration(\n error: unknown,\n): error is FeatureError & { readonly retryCleanup: () => Promise<void> } {\n return error instanceof FeatureError && error.code === 'quarantined' && error.retryCleanup !== undefined;\n}\n\nfunction preserveFeatureContributionQuarantine(\n error: FeatureError & { readonly retryCleanup: () => Promise<void> },\n cause: FeatureError,\n): FeatureError {\n let recovery: Promise<void> | undefined;\n\n return quarantinedGeneration(error.declarationId, error.failures, cause, () => {\n if (recovery !== undefined) return recovery;\n\n recovery = (async () => {\n try {\n await error.retryCleanup();\n } catch (nextError) {\n if (isQuarantinedGeneration(nextError)) {\n throw preserveFeatureContributionQuarantine(nextError, cause);\n }\n\n throw nextError;\n }\n })();\n\n return recovery;\n });\n}\n\nfunction retireFeatureContributionGeneration(\n state: FeatureContributionInstanceState,\n generation: FeatureInstance<string, unknown>,\n cause?: FeatureError,\n): Promise<void> {\n state.retirementCause ??= cause;\n\n if (state.retirement !== undefined) return state.retirement;\n\n let rejectRetirement: (cause: unknown) => void = () => undefined;\n let resolveRetirement: () => void = () => undefined;\n const pending = new Promise<void>((resolve, reject) => {\n rejectRetirement = reject;\n resolveRetirement = resolve;\n });\n state.retirement = pending;\n\n try {\n void generation.close().then(resolveRetirement, (retirementCause: unknown) => {\n if (state.retirement === pending) state.retirement = undefined;\n\n rejectRetirement(\n state.retirementCause !== undefined && isQuarantinedGeneration(retirementCause)\n ? preserveFeatureContributionQuarantine(retirementCause, state.retirementCause)\n : retirementCause,\n );\n });\n } catch (retirementCause) {\n state.retirement = undefined;\n rejectRetirement(\n state.retirementCause !== undefined && isQuarantinedGeneration(retirementCause)\n ? preserveFeatureContributionQuarantine(retirementCause, state.retirementCause)\n : retirementCause,\n );\n }\n\n return pending;\n}\n\nfunction requireFeatureContributionPreparation(state: FeatureContributionInstanceState): {\n readonly context: unknown;\n} {\n const context = state.context;\n\n if (context === undefined) throw new TypeError('Feature contribution context is unavailable.');\n\n return { context };\n}\n\nfunction captureFeatureContributionPublication(\n state: FeatureContributionInstanceState,\n publication: ContributionPublication,\n): void {\n state.publication = publication;\n\n if (state.inactive) fenceFeatureContributions(state);\n}\n\nasync function publishFeatureContributions<Prepared>(\n state: FeatureContributionInstanceState,\n generation: FeatureInstance<string, unknown>,\n value: Prepared,\n): Promise<Prepared> {\n try {\n if (state.inactive) throw featureContributionInactiveReason(state);\n\n const { context } = requireFeatureContributionPreparation(state);\n createFeatureContributionPublication(\n state.contributions,\n context,\n publication => {\n captureFeatureContributionPublication(state, publication);\n },\n state.authority,\n state.evaluation,\n );\n releaseFeatureContributionPreparation(state);\n\n if (state.inactive) throw featureContributionInactiveReason(state);\n\n return value;\n } catch (cause) {\n releaseFeatureContributionPreparation(state);\n const failure =\n cause instanceof FeatureError && cause.code === 'retired'\n ? cause\n : notReadyGeneration(\n state.featureId,\n Object.freeze({ cause, phase: 'open' as const, stage: 'prepare' as const }),\n );\n await retireFeatureContributionGeneration(state, generation, failure);\n\n throw failure;\n }\n}\n\nfunction wrapFeatureContributionInstance<Prepared>(\n state: FeatureContributionInstanceState,\n generation: FeatureInstance<string, Prepared>,\n): FeatureInstance<string, Prepared> {\n const ready = generation.ready.then(\n value => publishFeatureContributions(state, generation, value),\n (cause: unknown) => {\n releaseFeatureContributionPreparation(state);\n\n throw cause;\n },\n );\n\n return {\n close: () => retireFeatureContributionGeneration(state, generation),\n instance: generation.instance,\n ready,\n };\n}\n\nfunction snapshotExactValues(\n value: unknown,\n expectedKeys: readonly string[],\n label: string,\n): Readonly<Record<string, unknown>> {\n assertPlainRecord(value, label);\n const entries = dataEntries(value, label);\n\n if (entries.length !== expectedKeys.length || expectedKeys.some(key => !hasOwn(value, key))) {\n throw new TypeError(`${label} must contain every exact field once.`);\n }\n\n return Object.freeze(Object.fromEntries(entries));\n}\n\nfunction checkFeatureCleanupPolicy(value: unknown): void {\n if (value !== undefined && value !== 'report' && value !== 'quarantine') {\n throw new TypeError('openFeature cleanupFailure must be \"report\" or \"quarantine\".');\n }\n}\n\n/** Validates every declared requirement binding; an `optional` port may be left unbound (D105). */\nfunction checkFeatureRequirements(\n feature: AnyFeature,\n record: ReturnType<typeof requireFeatureRecord>,\n requirements: Readonly<Record<string, unknown>>,\n): void {\n for (const key of record.requirementKeys) {\n const requirement = feature.requires?.[key];\n assertRequiredPortValue(\n getRequiredPort(requirement),\n requirements[key],\n key,\n isOptionalPortRequirement(requirement),\n );\n }\n}\n\nfunction snapshotFeatureOpenOptions(\n feature: Feature,\n record: ReturnType<typeof requireFeatureRecord>,\n value: unknown,\n): Readonly<Record<string, unknown>> {\n assertPlainRecord(value, 'openFeature options');\n const entries = dataEntries(value, 'openFeature options');\n\n for (const [key] of entries) {\n if (!featureOpenOptionKeys.has(key)) throw new TypeError(`Unknown openFeature option ${key}.`);\n }\n\n for (const key of ['imports', 'reporter'] as const) {\n if (!hasOwn(value, key)) throw new TypeError(`openFeature requires ${key}.`);\n }\n\n if (typeof value['reporter'] !== 'function') {\n throw new TypeError('openFeature reporter must be a function.');\n }\n\n checkFeatureCleanupPolicy(value['cleanupFailure']);\n const imports = snapshotExactValues(value['imports'], record.importKeys, 'openFeature imports');\n const requirements = snapshotExactValues(\n value['requirements'] ?? {},\n record.requirementKeys,\n 'openFeature requirements',\n );\n\n checkFeatureRequirements(feature, record, requirements);\n\n return Object.freeze({ ...Object.fromEntries(entries), imports, requirements });\n}\n\n/**\n * One `own` ref as the live value the instance holds: `exports` runs at open, so a call ref is already a `Call`, a\n * model or a state ref is already materialized data and a resource or a stream ref is already a `Resource` (D88).\n */\nfunction readFeatureOwnValue(instance: ModuleInstanceRef, key: string, ref: object): unknown {\n if (isFeatureDataRef(ref)) return requireFeatureDataScope(instance).read(ref);\n\n if (isFeatureMaterializationRef(ref)) return bindFeatureResource(instance, ref as never);\n\n if (isLifetimeAttachmentRef(ref)) {\n throw new TypeError(`own.${key} is a lifecycle binding, so exports has no value to take from it.`);\n }\n\n return resolveModuleCallTarget(instance, ref as ModuleCallRef<unknown, unknown>);\n}\n\n/** Lazy so a feature that owns attachments still runs `exports`: only the selected keys are materialized. */\nfunction materializeFeatureOwn(\n instance: ModuleInstanceRef,\n refs: Readonly<Record<string, object>>,\n): Readonly<Record<string, unknown>> {\n const values = new Map<string, unknown>();\n const own: Record<string, unknown> = {};\n\n for (const [key, ref] of Object.entries(refs)) {\n Object.defineProperty(own, key, {\n enumerable: true,\n get: (): unknown => {\n if (!values.has(key)) values.set(key, readFeatureOwnValue(instance, key, ref));\n\n return values.get(key);\n },\n });\n }\n\n return Object.freeze(own);\n}\n\n/** The export record carries live values, so a ref, a model record or a plain object never reaches an importer. */\nfunction requireFeatureExportValue(key: string, value: unknown): unknown {\n if (isCallTarget(value)) return value;\n\n const readable = value as Partial<Readable<unknown>>;\n\n if (typeof readable?.getSnapshot === 'function' && typeof readable.subscribe === 'function') return value;\n\n throw new TypeError(`Feature export ${key} must be a Call, a Readable or a Resource.`);\n}\n\nfunction buildFeatureExports(\n contract: FeatureContractIdentity,\n values: Readonly<Record<string, unknown>>,\n select: (context: { readonly own: Readonly<Record<string, unknown>> }) => unknown,\n): Readonly<Record<string, unknown>> {\n const returned = select({ own: values });\n // `({ own }) => own` means «export every value this instance owns» (D127). The record the runtime handed to the\n // author reads its members lazily, so returning it materializes every one of them here, before the shared check\n // that a result carries data fields. A member with no value form still fails on its Own key, where D88 belongs.\n const selected =\n returned === values ? Object.fromEntries(Object.keys(values).map(key => [key, values[key]])) : returned;\n\n assertPlainRecord(selected, 'defineFeature exports result');\n const facade = Object.freeze(\n Object.fromEntries(\n dataEntries(selected, 'defineFeature exports result').map(([key, value]) => [\n key,\n requireFeatureExportValue(key, value),\n ]),\n ),\n );\n\n registerFeatureExportFacade(contract, facade);\n\n return facade;\n}\n\nfunction prepareFeatureInstanceInputs(\n feature: AnyFeature,\n record: ReturnType<typeof requireFeatureRecord>,\n snapshot: Readonly<Record<string, unknown>>,\n): Readonly<{ imports: Readonly<Record<string, unknown>>; lowScopes: Readonly<Record<string, unknown>> }> {\n const imports = snapshot['imports'] as Readonly<Record<string, unknown>>;\n registerFeatureInstanceImports(feature.imports, imports);\n const requirementCalls = snapshot['requirements'] as Readonly<Record<string, unknown>>;\n registerFeatureInstanceCallTargets(requirementCalls);\n const lowScopes: Record<string, unknown> = {};\n\n if (record.importScopeKey !== undefined) lowScopes[record.importScopeKey] = imports;\n\n if (record.requirementScopeKey !== undefined) lowScopes[record.requirementScopeKey] = requirementCalls;\n\n return Object.freeze({ imports, lowScopes: Object.freeze(lowScopes) });\n}\n\nfunction openMaterializedFeature(\n feature: Feature,\n record: ReturnType<typeof requireFeatureRecord>,\n snapshot: Readonly<Record<string, unknown>>,\n activity?: FeatureActivityOwner,\n): FeatureInstanceOf<string, unknown> {\n activity?.changed?.();\n const { imports, lowScopes } = prepareFeatureInstanceInputs(feature, record, snapshot);\n const reporter = snapshot['reporter'] as ErrorReporter;\n const contributionState =\n record.contributions.length === 0\n ? undefined\n : createFeatureContributionInstanceState(feature.id, record.contributions);\n\n const openGeneration = openLoweredModuleInstance as unknown as (\n definition: object,\n generationOptions: unknown,\n ) => FeatureInstance<string, FeatureReady<unknown>>;\n const generation = openGeneration(record.module, {\n ...(snapshot['cleanupFailure'] === undefined\n ? {}\n : { cleanupFailure: snapshot['cleanupFailure'] as CleanupFailurePolicy }),\n prepare: (instance: ModuleInstanceRef) => {\n if (activity !== undefined) registerModuleActivity(instance, activity);\n\n if (record.dataDescriptors.length > 0) {\n materializeFeatureData(\n feature.id,\n record.dataDescriptors,\n imports,\n instance,\n reporter,\n data => {\n registerFeatureDataScope(instance, data);\n registerModuleRetirementParticipant(instance, {\n fence: () => {\n data.fence();\n const drain = data.drain();\n\n return { drain: () => drain, retry: () => drain };\n },\n });\n },\n activity,\n );\n }\n\n // D220: one materialized `own` for this instance serves both `exports` and every reactive calculation the\n // instance declared, so a predicate reads the same live values an importer sees.\n const ownValues = materializeFeatureOwn(instance, feature.own);\n const bound = buildFeatureExports(feature.exports, ownValues, record.exports);\n const context = Object.freeze({\n exports: bound,\n imports,\n instance,\n model: contributionModel,\n own: feature.own,\n });\n\n if (contributionState !== undefined) {\n prepareFeatureContributions(contributionState, context, instance, {\n exports: bound,\n imports,\n own: ownValues,\n });\n contributionState.authority = Object.freeze({\n models: readInstanceModels(instance, record.dataDescriptors),\n });\n }\n\n const ready = Object.freeze({ exports: bound });\n bindFeatureReadyPorts(ready, record.providers, instance);\n\n return ready;\n },\n reporter,\n scopes: lowScopes,\n });\n\n if (contributionState === undefined) return generation;\n\n const wrapped = wrapFeatureContributionInstance(contributionState, generation);\n carryFeatureGenerationFence(generation, wrapped);\n\n return wrapped;\n}\n\nfunction openFeatureWithActivity(\n feature: Feature,\n options: unknown,\n activity?: FeatureActivityOwner,\n): FeatureInstanceOf<string, unknown> {\n const record = requireFeatureRecord(feature);\n // D211: exact bindings and base options belong to the call, never to the eventual body-load completion.\n const snapshot = snapshotFeatureOpenOptions(feature, record, options);\n\n return getLazyFeature(feature) === undefined\n ? openMaterializedFeature(feature, record, snapshot, activity)\n : openLazyFeatureInstance(feature, body => openMaterializedFeature(feature, body, snapshot, activity));\n}\n\nfunction openFeatureInstance<\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 ImportValues extends FeatureImportValues<Imports>,\n const OptionKeys extends PropertyKey,\n const ImportKeys extends PropertyKey,\n const RequirementKeys extends PropertyKey,\n>(\n feature: Feature<Id, Imports, Runtime, Exports, Requires>,\n options: ExactKeys<\n OptionKeys,\n FeatureOpenBaseOptions<FeatureImportValues<Imports>> &\n FeatureRequirementOpenOptions<RequiredPortValues<Requires>, keyof RequiredPortValues<Requires>>\n > &\n FeatureOpenBaseOptions<ImportValues> &\n FeatureRequirementOpenOptions<RequiredPortValues<Requires>, RequirementKeys> & {\n readonly imports: ExactImportValueFields<ImportValues, FeatureImportValues<Imports>> &\n ExactKeys<ImportKeys, FeatureImportValues<Imports>>;\n },\n): FeatureInstanceOf<Id, Exports>;\nfunction openFeatureInstance(feature: Feature, options: unknown): FeatureInstanceOf<string, unknown> {\n return openFeatureWithActivity(feature, options);\n}\n\nconst openFeature = openFeatureInstance;\n\nexport { openFeature, openFeatureWithActivity };\nexport type { FeatureReady, FeatureReadyOf };\n"],"names":["featureOpenOptionKeys","createFeatureContributionInstanceState","featureId","contributions","featureContributionInactiveReason","state","FeatureError","releaseFeatureContributionPreparation","fenceFeatureContributions","publication","withdrawContributions","prepareFeatureContributions","context","instance","evaluation","registerModuleRetirementParticipant","isQuarantinedGeneration","error","preserveFeatureContributionQuarantine","cause","recovery","quarantinedGeneration","nextError","retireFeatureContributionGeneration","generation","rejectRetirement","resolveRetirement","pending","resolve","reject","retirementCause","requireFeatureContributionPreparation","captureFeatureContributionPublication","publishFeatureContributions","value","createFeatureContributionPublication","failure","notReadyGeneration","wrapFeatureContributionInstance","ready","snapshotExactValues","expectedKeys","label","assertPlainRecord","entries","dataEntries","key","hasOwn","checkFeatureCleanupPolicy","checkFeatureRequirements","feature","record","requirements","requirement","_a","assertRequiredPortValue","getRequiredPort","isOptionalPortRequirement","snapshotFeatureOpenOptions","imports","readFeatureOwnValue","ref","isFeatureDataRef","requireFeatureDataScope","isFeatureMaterializationRef","bindFeatureResource","isLifetimeAttachmentRef","resolveModuleCallTarget","materializeFeatureOwn","refs","values","own","requireFeatureExportValue","isCallTarget","readable","buildFeatureExports","contract","select","returned","selected","facade","registerFeatureExportFacade","prepareFeatureInstanceInputs","snapshot","registerFeatureInstanceImports","requirementCalls","registerFeatureInstanceCallTargets","lowScopes","openMaterializedFeature","activity","reporter","contributionState","openLoweredModuleInstance","registerModuleActivity","materializeFeatureData","data","registerFeatureDataScope","drain","ownValues","bound","contributionModel","readInstanceModels","bindFeatureReadyPorts","wrapped","carryFeatureGenerationFence","openFeatureWithActivity","options","requireFeatureRecord","getLazyFeature","openLazyFeatureInstance","body","openFeatureInstance","openFeature"],"mappings":"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"}
1
+ {"version":3,"file":"feature-generation.js","sources":["../src/feature-generation.ts"],"sourcesContent":["import { FeatureError } from '@opetope/core';\nimport type { DeclarationId, Readable } from '@opetope/core';\nimport { hasOwn, isCallTarget, withdrawContributions } from '@opetope/core/internal';\nimport type { ContributionPublication } from '@opetope/core/internal';\n\nimport type {\n AnyFeature,\n Feature,\n FeatureExportRecord,\n FeatureExportsOf,\n FeatureImportRecord,\n FeatureImportValues,\n FeatureOwnRecord,\n} from './feature-authoring';\nimport { registerFeatureInstanceCallTargets, registerFeatureInstanceImports } from './feature-call-authority';\nimport type { FeatureContractIdentity } from './feature-contract';\nimport { createFeatureContributionPublication } from './feature-contribution';\nimport type { FeatureContributionDescriptor, FeatureEvaluationValues } from './feature-contribution';\nimport { registerFeatureExportFacade, requireFeatureRecord } from './feature-definition-support';\nimport { getLazyFeature } from './feature-lazy';\nimport { openLazyFeatureInstance } from './feature-lazy-generation';\nimport { materializeFeatureData, readInstanceModels, registerFeatureDataScope } from './feature-model';\nimport { materializeFeatureOwn } from './feature-own-values';\nimport { assertRequiredPortValue, getRequiredPort, isOptionalPortRequirement } from './feature-port';\nimport type { PortRequirementRecord, RequiredPortValues } from './feature-port';\nimport { bindFeatureReadyPorts } from './feature-port-binding';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport type { FeatureActivityOwner } from './inspection-activity';\nimport { registerModuleActivity } from './inspection-module-activity';\nimport {\n carryFeatureGenerationFence,\n notReadyGeneration,\n openFeature as openLoweredModuleInstance,\n quarantinedGeneration,\n} from './module-generation';\nimport type { FeatureInstance } from './module-generation';\nimport { registerModuleRetirementParticipant } from './public-module';\nimport type { CleanupFailurePolicy, ErrorReporter, ModuleInstanceRef } from './public-module';\n\ninterface FeatureReady<Exports> {\n readonly exports: Exports;\n}\n\ntype FeatureInstanceOf<Id extends string, Exports> = FeatureInstance<Id, FeatureReady<Exports>>;\n\ntype FeatureReadyOf<Definition> = FeatureReady<FeatureExportsOf<Definition>>;\n\ntype FeatureContributionInstanceState = {\n authority: unknown;\n context: unknown | undefined;\n readonly contributions: readonly FeatureContributionDescriptor[];\n evaluation: FeatureEvaluationValues | undefined;\n readonly featureId: DeclarationId;\n inactive: boolean;\n inactiveReason: FeatureError | undefined;\n publication: ContributionPublication | undefined;\n retirement: Promise<void> | undefined;\n retirementCause: FeatureError | undefined;\n};\n\ntype FeatureOpenBaseOptions<Imports> = {\n readonly cleanupFailure?: CleanupFailurePolicy;\n readonly imports: Imports;\n readonly reporter: ErrorReporter;\n};\n\ntype FeatureRequirementOpenOptions<Requirements, Keys extends PropertyKey> = keyof Requirements extends never\n ? { readonly requirements?: ExactKeys<Keys, Requirements> & Requirements }\n : { readonly requirements: ExactKeys<Keys, Requirements> & Requirements };\n\ntype ExactExpectedObjectMember<Actual, Expected> = Expected extends unknown\n ? Actual extends Expected\n ? keyof Actual extends keyof Expected\n ? true\n : never\n : never\n : never;\ntype ExactObjectUnionMember<Actual, Expected> = Actual extends unknown\n ? Actual extends readonly unknown[]\n ? true\n : Actual extends object\n ? true extends ExactExpectedObjectMember<Actual, Expected>\n ? true\n : false\n : true\n : never;\ntype NoExtraObjectKeys<Actual, Expected> = false extends ExactObjectUnionMember<Actual, Expected> ? never : unknown;\ntype ExactImportValueFields<Actual, Expected> = {\n readonly [Key in keyof Expected]: Key extends keyof Actual ? NoExtraObjectKeys<Actual[Key], Expected[Key]> : never;\n};\n\nconst featureOpenOptionKeys = new Set(['cleanupFailure', 'imports', 'reporter', 'requirements']);\n\nfunction createFeatureContributionInstanceState(\n featureId: DeclarationId,\n contributions: readonly FeatureContributionDescriptor[],\n): FeatureContributionInstanceState {\n return {\n authority: undefined,\n context: undefined,\n contributions,\n evaluation: undefined,\n featureId,\n inactive: false,\n inactiveReason: undefined,\n publication: undefined,\n retirement: undefined,\n retirementCause: undefined,\n };\n}\n\nfunction featureContributionInactiveReason(state: FeatureContributionInstanceState): FeatureError {\n return (state.inactiveReason ??= new FeatureError('retired', state.featureId));\n}\n\nfunction releaseFeatureContributionPreparation(state: FeatureContributionInstanceState): void {\n state.context = undefined;\n state.evaluation = undefined;\n}\n\nfunction fenceFeatureContributions(state: FeatureContributionInstanceState): void {\n state.inactive = true;\n releaseFeatureContributionPreparation(state);\n // The authority a mount was granted dies with the fence: keeping it alive would outlive the models it names.\n state.authority = undefined;\n\n if (state.publication === undefined) return;\n\n const publication = state.publication;\n withdrawContributions(publication);\n state.publication = undefined;\n}\n\nfunction prepareFeatureContributions(\n state: FeatureContributionInstanceState,\n context: unknown,\n instance: ModuleInstanceRef,\n evaluation: FeatureEvaluationValues,\n): void {\n state.context = context;\n state.evaluation = evaluation;\n registerModuleRetirementParticipant(instance, { fence: () => fenceFeatureContributions(state) });\n}\n\nfunction isQuarantinedGeneration(\n error: unknown,\n): error is FeatureError & { readonly retryCleanup: () => Promise<void> } {\n return error instanceof FeatureError && error.code === 'quarantined' && error.retryCleanup !== undefined;\n}\n\nfunction preserveFeatureContributionQuarantine(\n error: FeatureError & { readonly retryCleanup: () => Promise<void> },\n cause: FeatureError,\n): FeatureError {\n let recovery: Promise<void> | undefined;\n\n return quarantinedGeneration(error.declarationId, error.failures, cause, () => {\n if (recovery !== undefined) return recovery;\n\n recovery = (async () => {\n try {\n await error.retryCleanup();\n } catch (nextError) {\n if (isQuarantinedGeneration(nextError)) {\n throw preserveFeatureContributionQuarantine(nextError, cause);\n }\n\n throw nextError;\n }\n })();\n\n return recovery;\n });\n}\n\nfunction retireFeatureContributionGeneration(\n state: FeatureContributionInstanceState,\n generation: FeatureInstance<string, unknown>,\n cause?: FeatureError,\n): Promise<void> {\n state.retirementCause ??= cause;\n\n if (state.retirement !== undefined) return state.retirement;\n\n let rejectRetirement: (cause: unknown) => void = () => undefined;\n let resolveRetirement: () => void = () => undefined;\n const pending = new Promise<void>((resolve, reject) => {\n rejectRetirement = reject;\n resolveRetirement = resolve;\n });\n state.retirement = pending;\n\n try {\n void generation.close().then(resolveRetirement, (retirementCause: unknown) => {\n if (state.retirement === pending) state.retirement = undefined;\n\n rejectRetirement(\n state.retirementCause !== undefined && isQuarantinedGeneration(retirementCause)\n ? preserveFeatureContributionQuarantine(retirementCause, state.retirementCause)\n : retirementCause,\n );\n });\n } catch (retirementCause) {\n state.retirement = undefined;\n rejectRetirement(\n state.retirementCause !== undefined && isQuarantinedGeneration(retirementCause)\n ? preserveFeatureContributionQuarantine(retirementCause, state.retirementCause)\n : retirementCause,\n );\n }\n\n return pending;\n}\n\nfunction requireFeatureContributionPreparation(state: FeatureContributionInstanceState): {\n readonly context: unknown;\n} {\n const context = state.context;\n\n if (context === undefined) throw new TypeError('Feature contribution context is unavailable.');\n\n return { context };\n}\n\nfunction captureFeatureContributionPublication(\n state: FeatureContributionInstanceState,\n publication: ContributionPublication,\n): void {\n state.publication = publication;\n\n if (state.inactive) fenceFeatureContributions(state);\n}\n\nasync function publishFeatureContributions<Prepared>(\n state: FeatureContributionInstanceState,\n generation: FeatureInstance<string, unknown>,\n value: Prepared,\n): Promise<Prepared> {\n try {\n if (state.inactive) throw featureContributionInactiveReason(state);\n\n const { context } = requireFeatureContributionPreparation(state);\n createFeatureContributionPublication(\n state.contributions,\n context,\n publication => {\n captureFeatureContributionPublication(state, publication);\n },\n state.authority,\n state.evaluation,\n );\n releaseFeatureContributionPreparation(state);\n\n if (state.inactive) throw featureContributionInactiveReason(state);\n\n return value;\n } catch (cause) {\n releaseFeatureContributionPreparation(state);\n const failure =\n cause instanceof FeatureError && cause.code === 'retired'\n ? cause\n : notReadyGeneration(\n state.featureId,\n Object.freeze({ cause, phase: 'open' as const, stage: 'prepare' as const }),\n );\n await retireFeatureContributionGeneration(state, generation, failure);\n\n throw failure;\n }\n}\n\nfunction wrapFeatureContributionInstance<Prepared>(\n state: FeatureContributionInstanceState,\n generation: FeatureInstance<string, Prepared>,\n): FeatureInstance<string, Prepared> {\n const ready = generation.ready.then(\n value => publishFeatureContributions(state, generation, value),\n (cause: unknown) => {\n releaseFeatureContributionPreparation(state);\n\n throw cause;\n },\n );\n\n return {\n close: () => retireFeatureContributionGeneration(state, generation),\n instance: generation.instance,\n ready,\n };\n}\n\nfunction snapshotExactValues(\n value: unknown,\n expectedKeys: readonly string[],\n label: string,\n): Readonly<Record<string, unknown>> {\n assertPlainRecord(value, label);\n const entries = dataEntries(value, label);\n\n if (entries.length !== expectedKeys.length || expectedKeys.some(key => !hasOwn(value, key))) {\n throw new TypeError(`${label} must contain every exact field once.`);\n }\n\n return Object.freeze(Object.fromEntries(entries));\n}\n\nfunction checkFeatureCleanupPolicy(value: unknown): void {\n if (value !== undefined && value !== 'report' && value !== 'quarantine') {\n throw new TypeError('openFeature cleanupFailure must be \"report\" or \"quarantine\".');\n }\n}\n\n/** Validates every declared requirement binding; an `optional` port may be left unbound (D105). */\nfunction checkFeatureRequirements(\n feature: AnyFeature,\n record: ReturnType<typeof requireFeatureRecord>,\n requirements: Readonly<Record<string, unknown>>,\n): void {\n for (const key of record.requirementKeys) {\n const requirement = feature.requires?.[key];\n assertRequiredPortValue(\n getRequiredPort(requirement),\n requirements[key],\n key,\n isOptionalPortRequirement(requirement),\n );\n }\n}\n\nfunction snapshotFeatureOpenOptions(\n feature: Feature,\n record: ReturnType<typeof requireFeatureRecord>,\n value: unknown,\n): Readonly<Record<string, unknown>> {\n assertPlainRecord(value, 'openFeature options');\n const entries = dataEntries(value, 'openFeature options');\n\n for (const [key] of entries) {\n if (!featureOpenOptionKeys.has(key)) throw new TypeError(`Unknown openFeature option ${key}.`);\n }\n\n for (const key of ['imports', 'reporter'] as const) {\n if (!hasOwn(value, key)) throw new TypeError(`openFeature requires ${key}.`);\n }\n\n if (typeof value['reporter'] !== 'function') {\n throw new TypeError('openFeature reporter must be a function.');\n }\n\n checkFeatureCleanupPolicy(value['cleanupFailure']);\n const imports = snapshotExactValues(value['imports'], record.importKeys, 'openFeature imports');\n const requirements = snapshotExactValues(\n value['requirements'] ?? {},\n record.requirementKeys,\n 'openFeature requirements',\n );\n\n checkFeatureRequirements(feature, record, requirements);\n\n return Object.freeze({ ...Object.fromEntries(entries), imports, requirements });\n}\n\n/** The export record carries live values, so a ref, a model record or a plain object never reaches an importer. */\nfunction requireFeatureExportValue(key: string, value: unknown): unknown {\n if (isCallTarget(value)) return value;\n\n const readable = value as Partial<Readable<unknown>>;\n\n if (typeof readable?.getSnapshot === 'function' && typeof readable.subscribe === 'function') return value;\n\n throw new TypeError(`Feature export ${key} must be a Call, a Readable or a Resource.`);\n}\n\nfunction buildFeatureExports(\n contract: FeatureContractIdentity,\n values: Readonly<Record<string, unknown>>,\n select: (context: { readonly own: Readonly<Record<string, unknown>> }) => unknown,\n): Readonly<Record<string, unknown>> {\n const returned = select({ own: values });\n // `({ own }) => own` means «export every value this instance owns» (D127). The record the runtime handed to the\n // author reads its members lazily, so returning it materializes every one of them here, before the shared check\n // that a result carries data fields. A member with no value form still fails on its Own key, where D88 belongs.\n const selected =\n returned === values ? Object.fromEntries(Object.keys(values).map(key => [key, values[key]])) : returned;\n\n assertPlainRecord(selected, 'defineFeature exports result');\n const facade = Object.freeze(\n Object.fromEntries(\n dataEntries(selected, 'defineFeature exports result').map(([key, value]) => [\n key,\n requireFeatureExportValue(key, value),\n ]),\n ),\n );\n\n registerFeatureExportFacade(contract, facade);\n\n return facade;\n}\n\nfunction prepareFeatureInstanceInputs(\n feature: AnyFeature,\n record: ReturnType<typeof requireFeatureRecord>,\n snapshot: Readonly<Record<string, unknown>>,\n): Readonly<{ imports: Readonly<Record<string, unknown>>; lowScopes: Readonly<Record<string, unknown>> }> {\n const imports = snapshot['imports'] as Readonly<Record<string, unknown>>;\n registerFeatureInstanceImports(feature.imports, imports);\n const requirementCalls = snapshot['requirements'] as Readonly<Record<string, unknown>>;\n registerFeatureInstanceCallTargets(requirementCalls);\n const lowScopes: Record<string, unknown> = {};\n\n if (record.importScopeKey !== undefined) lowScopes[record.importScopeKey] = imports;\n\n if (record.requirementScopeKey !== undefined) lowScopes[record.requirementScopeKey] = requirementCalls;\n\n return Object.freeze({ imports, lowScopes: Object.freeze(lowScopes) });\n}\n\nfunction openMaterializedFeature(\n feature: Feature,\n record: ReturnType<typeof requireFeatureRecord>,\n snapshot: Readonly<Record<string, unknown>>,\n activity?: FeatureActivityOwner,\n assertCurrent?: () => void,\n): FeatureInstanceOf<string, unknown> {\n activity?.changed?.();\n const { imports, lowScopes } = prepareFeatureInstanceInputs(feature, record, snapshot);\n const reporter = snapshot['reporter'] as ErrorReporter;\n const contributionState =\n record.contributions.length === 0\n ? undefined\n : createFeatureContributionInstanceState(feature.id, record.contributions);\n\n const openGeneration = openLoweredModuleInstance as unknown as (\n definition: object,\n generationOptions: unknown,\n ) => FeatureInstance<string, FeatureReady<unknown>>;\n const generation = openGeneration(record.module, {\n ...(snapshot['cleanupFailure'] === undefined\n ? {}\n : { cleanupFailure: snapshot['cleanupFailure'] as CleanupFailurePolicy }),\n prepare: (instance: ModuleInstanceRef) => {\n if (activity !== undefined) registerModuleActivity(instance, activity);\n\n if (record.dataDescriptors.length > 0) {\n materializeFeatureData(\n feature.id,\n record.dataDescriptors,\n imports,\n instance,\n reporter,\n data => {\n registerFeatureDataScope(instance, data);\n registerModuleRetirementParticipant(instance, {\n fence: () => {\n data.fence();\n const drain = data.drain();\n\n return { drain: () => drain, retry: () => drain };\n },\n });\n },\n activity,\n );\n }\n\n // D255: exports, contribution factories and reactive calculations share this instance's live values.\n const portTargets =\n record.providers.length === 0 ? undefined : { available: new Set<object>(), local: new Set<object>() };\n const ownValues = materializeFeatureOwn(instance, feature.own, portTargets);\n const bound = buildFeatureExports(feature.exports, ownValues, record.exports);\n assertCurrent?.();\n const context = Object.freeze({\n imports,\n own: ownValues,\n });\n\n if (contributionState !== undefined) {\n prepareFeatureContributions(contributionState, context, instance, context);\n contributionState.authority = Object.freeze({\n models: readInstanceModels(instance, record.dataDescriptors),\n });\n }\n\n const ready = Object.freeze({ exports: bound });\n bindFeatureReadyPorts(ready, record.providers, instance, ownValues, portTargets, assertCurrent);\n\n return ready;\n },\n reporter,\n scopes: lowScopes,\n });\n\n if (contributionState === undefined) return generation;\n\n const wrapped = wrapFeatureContributionInstance(contributionState, generation);\n carryFeatureGenerationFence(generation, wrapped);\n\n return wrapped;\n}\n\nfunction openFeatureWithActivity(\n feature: Feature,\n options: unknown,\n activity?: FeatureActivityOwner,\n): FeatureInstanceOf<string, unknown> {\n const record = requireFeatureRecord(feature);\n // D211: exact bindings and base options belong to the call, never to the eventual body-load completion.\n const snapshot = snapshotFeatureOpenOptions(feature, record, options);\n\n return getLazyFeature(feature) === undefined\n ? openMaterializedFeature(feature, record, snapshot, activity)\n : openLazyFeatureInstance(feature, (body, assertCurrent) =>\n openMaterializedFeature(feature, body, snapshot, activity, assertCurrent),\n );\n}\n\nfunction openFeatureInstance<\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 ImportValues extends FeatureImportValues<Imports>,\n const OptionKeys extends PropertyKey,\n const ImportKeys extends PropertyKey,\n const RequirementKeys extends PropertyKey,\n>(\n feature: Feature<Id, Imports, Runtime, Exports, Requires>,\n options: ExactKeys<\n OptionKeys,\n FeatureOpenBaseOptions<FeatureImportValues<Imports>> &\n FeatureRequirementOpenOptions<RequiredPortValues<Requires>, keyof RequiredPortValues<Requires>>\n > &\n FeatureOpenBaseOptions<ImportValues> &\n FeatureRequirementOpenOptions<RequiredPortValues<Requires>, RequirementKeys> & {\n readonly imports: ExactImportValueFields<ImportValues, FeatureImportValues<Imports>> &\n ExactKeys<ImportKeys, FeatureImportValues<Imports>>;\n },\n): FeatureInstanceOf<Id, Exports>;\nfunction openFeatureInstance(feature: Feature, options: unknown): FeatureInstanceOf<string, unknown> {\n return openFeatureWithActivity(feature, options);\n}\n\nconst openFeature = openFeatureInstance;\n\nexport { openFeature, openFeatureWithActivity };\nexport type { FeatureReady, FeatureReadyOf };\n"],"names":["featureOpenOptionKeys","createFeatureContributionInstanceState","featureId","contributions","featureContributionInactiveReason","state","FeatureError","releaseFeatureContributionPreparation","fenceFeatureContributions","publication","withdrawContributions","prepareFeatureContributions","context","instance","evaluation","registerModuleRetirementParticipant","isQuarantinedGeneration","error","preserveFeatureContributionQuarantine","cause","recovery","quarantinedGeneration","nextError","retireFeatureContributionGeneration","generation","rejectRetirement","resolveRetirement","pending","resolve","reject","retirementCause","requireFeatureContributionPreparation","captureFeatureContributionPublication","publishFeatureContributions","value","createFeatureContributionPublication","failure","notReadyGeneration","wrapFeatureContributionInstance","ready","snapshotExactValues","expectedKeys","label","assertPlainRecord","entries","dataEntries","key","hasOwn","checkFeatureCleanupPolicy","checkFeatureRequirements","feature","record","requirements","requirement","_a","assertRequiredPortValue","getRequiredPort","isOptionalPortRequirement","snapshotFeatureOpenOptions","imports","requireFeatureExportValue","isCallTarget","readable","buildFeatureExports","contract","values","select","returned","selected","facade","registerFeatureExportFacade","prepareFeatureInstanceInputs","snapshot","registerFeatureInstanceImports","requirementCalls","registerFeatureInstanceCallTargets","lowScopes","openMaterializedFeature","activity","assertCurrent","reporter","contributionState","openLoweredModuleInstance","registerModuleActivity","materializeFeatureData","data","registerFeatureDataScope","drain","portTargets","ownValues","materializeFeatureOwn","bound","readInstanceModels","bindFeatureReadyPorts","wrapped","carryFeatureGenerationFence","openFeatureWithActivity","options","requireFeatureRecord","getLazyFeature","openLazyFeatureInstance","body","openFeatureInstance","openFeature"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { Feature } from './feature-authoring.js';
2
2
  import type { FeatureRecord } from './feature-authoring-types.js';
3
3
  import type { FeatureInstance } from './module-generation.js';
4
- type Opening<Prepared> = (record: FeatureRecord) => FeatureInstance<string, Prepared>;
4
+ type Opening<Prepared> = (record: FeatureRecord, assertCurrent: () => void) => FeatureInstance<string, Prepared>;
5
5
  declare function openLazyFeatureInstance<Prepared>(feature: Feature, opening: Opening<Prepared>): FeatureInstance<string, Prepared>;
6
6
  export { openLazyFeatureInstance };
@@ -1,2 +1,2 @@
1
- import{FeatureError as d}from"@opetope/core";import{observeFeatureBody as a}from"./feature-lazy.js";import{registerFeatureGenerationFence as f,fenceFeatureGeneration as o}from"./module-generation.js";class c{ready;get instance(){if(this.opened===void 0)throw new d("not-ready",this.id);return this.opened.instance}id;opened;opening;readiness;releaseBody;retired=!1;retirement;starting=!1;constructor(e,i){this.id=e.id,this.opening=i,this.ready=new Promise((t,n)=>{this.readiness={reject:n,resolve:t}}),f(this,this.fence),this.releaseBody=a(e,t=>this.start(t),this.fail)}close=()=>{if(this.retirement!==void 0)return this.retirement.promise;let e,i;const t=new Promise((s,h)=>{i=s,e=h}),n={promise:t,reject:e,resolve:i};this.retirement=n;try{this.fence(),this.starting||this.drain(n)}catch(s){this.failRetirement(n,s)}return t};drain(e){const i=this.opened;if(i===void 0){e.resolve();return}try{i.close().then(e.resolve,t=>this.failRetirement(e,t))}catch(t){this.failRetirement(e,t)}}fail=e=>{this.stopWaitingForBody();const i=this.readiness;this.readiness=void 0,this.opening=void 0,i==null||i.reject(e)};failRetirement(e,i){this.retirement===e&&(this.retirement=void 0),e.reject(i)}fence=()=>{this.retired||(this.retired=!0,this.stopWaitingForBody(),this.opening=void 0,this.readiness!==void 0&&this.fail(new d("retired",this.id)),this.opened!==void 0&&o(this.opened))};start(e){this.stopWaitingForBody();const i=this.opening;if(this.opening=void 0,i!==void 0){this.starting=!0;try{this.opened=i(e),this.opened.ready.then(t=>{const n=this.readiness;this.readiness=void 0,n==null||n.resolve(t)},this.fail),this.retired&&o(this.opened)}catch(t){this.fail(t)}finally{this.starting=!1,this.retirement!==void 0&&this.drain(this.retirement)}}}stopWaitingForBody(){const e=this.releaseBody;this.releaseBody=void 0,e==null||e()}}function u(r,e){return new c(r,e)}export{u as openLazyFeatureInstance};
1
+ import{FeatureError as r}from"@opetope/core";import{observeFeatureBody as a}from"./feature-lazy.js";import{registerFeatureGenerationFence as f,fenceFeatureGeneration as o}from"./module-generation.js";class u{ready;get instance(){if(this.opened===void 0)throw new r("not-ready",this.id);return this.opened.instance}id;opened;opening;readiness;releaseBody;retired=!1;retirement;starting=!1;constructor(e,i){this.id=e.id,this.opening=i,this.ready=new Promise((t,n)=>{this.readiness={reject:n,resolve:t}}),f(this,this.fence),this.releaseBody=a(e,t=>this.start(t),this.fail)}close=()=>{if(this.retirement!==void 0)return this.retirement.promise;let e,i;const t=new Promise((s,h)=>{i=s,e=h}),n={promise:t,reject:e,resolve:i};this.retirement=n;try{this.fence(),this.starting||this.drain(n)}catch(s){this.failRetirement(n,s)}return t};drain(e){const i=this.opened;if(i===void 0){e.resolve();return}try{i.close().then(e.resolve,t=>this.failRetirement(e,t))}catch(t){this.failRetirement(e,t)}}fail=e=>{this.stopWaitingForBody();const i=this.readiness;this.readiness=void 0,this.opening=void 0,i==null||i.reject(e)};assertCurrent=()=>{if(this.retired)throw new r("retired",this.id)};failRetirement(e,i){this.retirement===e&&(this.retirement=void 0),e.reject(i)}fence=()=>{this.retired||(this.retired=!0,this.stopWaitingForBody(),this.opening=void 0,this.readiness!==void 0&&this.fail(new r("retired",this.id)),this.opened!==void 0&&o(this.opened))};start(e){this.stopWaitingForBody();const i=this.opening;if(this.opening=void 0,i!==void 0){this.starting=!0;try{this.opened=i(e,this.assertCurrent),this.opened.ready.then(t=>{const n=this.readiness;this.readiness=void 0,n==null||n.resolve(t)},this.fail),this.retired&&o(this.opened)}catch(t){this.fail(t)}finally{this.starting=!1,this.retirement!==void 0&&this.drain(this.retirement)}}}stopWaitingForBody(){const e=this.releaseBody;this.releaseBody=void 0,e==null||e()}}function c(d,e){return new u(d,e)}export{c as openLazyFeatureInstance};
2
2
  //# sourceMappingURL=feature-lazy-generation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-lazy-generation.js","sources":["../src/feature-lazy-generation.ts"],"sourcesContent":["import { FeatureError } from '@opetope/core';\nimport type { DeclarationId } from '@opetope/core';\n\nimport type { Feature } from './feature-authoring';\nimport type { FeatureRecord } from './feature-authoring-types';\nimport { observeFeatureBody } from './feature-lazy';\nimport { fenceFeatureGeneration, registerFeatureGenerationFence } from './module-generation';\nimport type { FeatureInstance } from './module-generation';\n\ntype Opening<Prepared> = (record: FeatureRecord) => FeatureInstance<string, Prepared>;\ntype Completion<Value> = {\n readonly reject: (cause: unknown) => void;\n readonly resolve: (value: Value) => void;\n};\ntype Retirement = Completion<void> & { readonly promise: Promise<void> };\n\n/**\n * D211: the shared code load is independent of this opening attempt. A retired attempt drops its inputs and\n * rejects readiness immediately; only a materialization already started owns work that close must drain.\n */\nclass LazyFeatureGeneration<Prepared> implements FeatureInstance<string, Prepared> {\n readonly ready: Promise<Prepared>;\n get instance(): FeatureInstance<string, Prepared>['instance'] {\n if (this.opened === undefined) throw new FeatureError('not-ready', this.id);\n\n return this.opened.instance;\n }\n private readonly id: DeclarationId;\n private opened: FeatureInstance<string, Prepared> | undefined;\n private opening: Opening<Prepared> | undefined;\n private readiness: Completion<Prepared> | undefined;\n private releaseBody: (() => void) | undefined;\n private retired = false;\n private retirement: Retirement | undefined;\n\n private starting = false;\n\n constructor(feature: Feature, opening: Opening<Prepared>) {\n this.id = feature.id;\n this.opening = opening;\n this.ready = new Promise((resolve, reject) => {\n this.readiness = { reject, resolve };\n });\n registerFeatureGenerationFence(this, this.fence);\n this.releaseBody = observeFeatureBody(feature, record => this.start(record), this.fail);\n }\n\n readonly close = (): Promise<void> => {\n if (this.retirement !== undefined) return this.retirement.promise;\n\n let reject!: (cause: unknown) => void;\n let resolve!: () => void;\n const promise = new Promise<void>((accept, refuse) => {\n resolve = accept;\n reject = refuse;\n });\n const retirement = { promise, reject, resolve };\n this.retirement = retirement;\n\n try {\n // Reserve the shared completion before fencing: observers may call close again from their notification.\n this.fence();\n\n if (!this.starting) this.drain(retirement);\n } catch (cause) {\n this.failRetirement(retirement, cause);\n }\n\n return promise;\n };\n\n private drain(retirement: Retirement): void {\n const opened = this.opened;\n\n if (opened === undefined) {\n retirement.resolve();\n\n return;\n }\n\n try {\n void opened.close().then(retirement.resolve, (cause: unknown) => this.failRetirement(retirement, cause));\n } catch (cause) {\n this.failRetirement(retirement, cause);\n }\n }\n\n private readonly fail = (cause: unknown): void => {\n this.stopWaitingForBody();\n const readiness = this.readiness;\n this.readiness = undefined;\n this.opening = undefined;\n readiness?.reject(cause);\n };\n\n private failRetirement(retirement: Retirement, cause: unknown): void {\n // Like the eager contribution wrapper, a failed cleanup can be retried through its error capability.\n if (this.retirement === retirement) this.retirement = undefined;\n\n retirement.reject(cause);\n }\n\n private readonly fence = (): void => {\n if (this.retired) return;\n\n this.retired = true;\n this.stopWaitingForBody();\n this.opening = undefined;\n\n if (this.readiness !== undefined) this.fail(new FeatureError('retired', this.id));\n\n if (this.opened !== undefined) fenceFeatureGeneration(this.opened);\n };\n\n private start(record: FeatureRecord): void {\n this.stopWaitingForBody();\n const opening = this.opening;\n this.opening = undefined;\n\n if (opening === undefined) return;\n\n this.starting = true;\n\n try {\n this.opened = opening(record);\n void this.opened.ready.then(value => {\n const readiness = this.readiness;\n this.readiness = undefined;\n readiness?.resolve(value);\n }, this.fail);\n\n // A factory or source callback may close the facade before the materialized instance has been returned.\n if (this.retired) fenceFeatureGeneration(this.opened);\n } catch (cause) {\n this.fail(cause);\n } finally {\n this.starting = false;\n\n if (this.retirement !== undefined) this.drain(this.retirement);\n }\n }\n\n private stopWaitingForBody(): void {\n const release = this.releaseBody;\n this.releaseBody = undefined;\n release?.();\n }\n}\n\nfunction openLazyFeatureInstance<Prepared>(\n feature: Feature,\n opening: Opening<Prepared>,\n): FeatureInstance<string, Prepared> {\n return new LazyFeatureGeneration(feature, opening);\n}\n\nexport { openLazyFeatureInstance };\n"],"names":["LazyFeatureGeneration","FeatureError","feature","opening","resolve","reject","registerFeatureGenerationFence","observeFeatureBody","record","promise","accept","refuse","retirement","cause","opened","readiness","fenceFeatureGeneration","value","release","openLazyFeatureInstance"],"mappings":"wMAoBA,MAAMA,CAAqB,CAChB,MACT,IAAI,UAAQ,CACV,GAAI,KAAK,SAAW,OAAW,MAAM,IAAIC,EAAa,YAAa,KAAK,EAAE,EAE1E,OAAO,KAAK,OAAO,QACrB,CACiB,GACT,OACA,QACA,UACA,YACA,QAAU,GACV,WAEA,SAAW,GAEnB,YAAYC,EAAkBC,EAA0B,CACtD,KAAK,GAAKD,EAAQ,GAClB,KAAK,QAAUC,EACf,KAAK,MAAQ,IAAI,QAAQ,CAACC,EAASC,IAAU,CAC3C,KAAK,UAAY,CAAE,OAAAA,EAAQ,QAAAD,CAAO,CACpC,CAAC,EACDE,EAA+B,KAAM,KAAK,KAAK,EAC/C,KAAK,YAAcC,EAAmBL,EAASM,GAAU,KAAK,MAAMA,CAAM,EAAG,KAAK,IAAI,CACxF,CAES,MAAQ,IAAoB,CACnC,GAAI,KAAK,aAAe,OAAW,OAAO,KAAK,WAAW,QAE1D,IAAIH,EACAD,EACJ,MAAMK,EAAU,IAAI,QAAc,CAACC,EAAQC,IAAU,CACnDP,EAAUM,EACVL,EAASM,CACX,CAAC,EACKC,EAAa,CAAE,QAAAH,EAAS,OAAAJ,EAAQ,QAAAD,CAAO,EAC7C,KAAK,WAAaQ,EAElB,GAAI,CAEF,KAAK,MAAK,EAEL,KAAK,UAAU,KAAK,MAAMA,CAAU,CAC3C,OAASC,EAAO,CACd,KAAK,eAAeD,EAAYC,CAAK,CACvC,CAEA,OAAOJ,CACT,EAEQ,MAAMG,EAAsB,CAClC,MAAME,EAAS,KAAK,OAEpB,GAAIA,IAAW,OAAW,CACxBF,EAAW,QAAO,EAElB,MACF,CAEA,GAAI,CACGE,EAAO,QAAQ,KAAKF,EAAW,QAAUC,GAAmB,KAAK,eAAeD,EAAYC,CAAK,CAAC,CACzG,OAASA,EAAO,CACd,KAAK,eAAeD,EAAYC,CAAK,CACvC,CACF,CAEiB,KAAQA,GAAwB,CAC/C,KAAK,mBAAkB,EACvB,MAAME,EAAY,KAAK,UACvB,KAAK,UAAY,OACjB,KAAK,QAAU,OACfA,GAAA,MAAAA,EAAW,OAAOF,EACpB,EAEQ,eAAeD,EAAwBC,EAAc,CAEvD,KAAK,aAAeD,IAAY,KAAK,WAAa,QAEtDA,EAAW,OAAOC,CAAK,CACzB,CAEiB,MAAQ,IAAW,CAC9B,KAAK,UAET,KAAK,QAAU,GACf,KAAK,mBAAkB,EACvB,KAAK,QAAU,OAEX,KAAK,YAAc,QAAW,KAAK,KAAK,IAAIZ,EAAa,UAAW,KAAK,EAAE,CAAC,EAE5E,KAAK,SAAW,QAAWe,EAAuB,KAAK,MAAM,EACnE,EAEQ,MAAMR,EAAqB,CACjC,KAAK,mBAAkB,EACvB,MAAML,EAAU,KAAK,QAGrB,GAFA,KAAK,QAAU,OAEXA,IAAY,OAEhB,MAAK,SAAW,GAEhB,GAAI,CACF,KAAK,OAASA,EAAQK,CAAM,EACvB,KAAK,OAAO,MAAM,KAAKS,GAAQ,CAClC,MAAMF,EAAY,KAAK,UACvB,KAAK,UAAY,OACjBA,GAAA,MAAAA,EAAW,QAAQE,EACrB,EAAG,KAAK,IAAI,EAGR,KAAK,SAASD,EAAuB,KAAK,MAAM,CACtD,OAASH,EAAO,CACd,KAAK,KAAKA,CAAK,CACjB,SACE,KAAK,SAAW,GAEZ,KAAK,aAAe,QAAW,KAAK,MAAM,KAAK,UAAU,CAC/D,EACF,CAEQ,oBAAkB,CACxB,MAAMK,EAAU,KAAK,YACrB,KAAK,YAAc,OACnBA,GAAA,MAAAA,GACF,CACD,CAED,SAASC,EACPjB,EACAC,EAA0B,CAE1B,OAAO,IAAIH,EAAsBE,EAASC,CAAO,CACnD"}
1
+ {"version":3,"file":"feature-lazy-generation.js","sources":["../src/feature-lazy-generation.ts"],"sourcesContent":["import { FeatureError } from '@opetope/core';\nimport type { DeclarationId } from '@opetope/core';\n\nimport type { Feature } from './feature-authoring';\nimport type { FeatureRecord } from './feature-authoring-types';\nimport { observeFeatureBody } from './feature-lazy';\nimport { fenceFeatureGeneration, registerFeatureGenerationFence } from './module-generation';\nimport type { FeatureInstance } from './module-generation';\n\ntype Opening<Prepared> = (record: FeatureRecord, assertCurrent: () => void) => FeatureInstance<string, Prepared>;\ntype Completion<Value> = {\n readonly reject: (cause: unknown) => void;\n readonly resolve: (value: Value) => void;\n};\ntype Retirement = Completion<void> & { readonly promise: Promise<void> };\n\n/**\n * D211: the shared code load is independent of this opening attempt. A retired attempt drops its inputs and\n * rejects readiness immediately; only a materialization already started owns work that close must drain.\n */\nclass LazyFeatureGeneration<Prepared> implements FeatureInstance<string, Prepared> {\n readonly ready: Promise<Prepared>;\n get instance(): FeatureInstance<string, Prepared>['instance'] {\n if (this.opened === undefined) throw new FeatureError('not-ready', this.id);\n\n return this.opened.instance;\n }\n private readonly id: DeclarationId;\n private opened: FeatureInstance<string, Prepared> | undefined;\n private opening: Opening<Prepared> | undefined;\n private readiness: Completion<Prepared> | undefined;\n private releaseBody: (() => void) | undefined;\n private retired = false;\n private retirement: Retirement | undefined;\n\n private starting = false;\n\n constructor(feature: Feature, opening: Opening<Prepared>) {\n this.id = feature.id;\n this.opening = opening;\n this.ready = new Promise((resolve, reject) => {\n this.readiness = { reject, resolve };\n });\n registerFeatureGenerationFence(this, this.fence);\n this.releaseBody = observeFeatureBody(feature, record => this.start(record), this.fail);\n }\n\n readonly close = (): Promise<void> => {\n if (this.retirement !== undefined) return this.retirement.promise;\n\n let reject!: (cause: unknown) => void;\n let resolve!: () => void;\n const promise = new Promise<void>((accept, refuse) => {\n resolve = accept;\n reject = refuse;\n });\n const retirement = { promise, reject, resolve };\n this.retirement = retirement;\n\n try {\n // Reserve the shared completion before fencing: observers may call close again from their notification.\n this.fence();\n\n if (!this.starting) this.drain(retirement);\n } catch (cause) {\n this.failRetirement(retirement, cause);\n }\n\n return promise;\n };\n\n private drain(retirement: Retirement): void {\n const opened = this.opened;\n\n if (opened === undefined) {\n retirement.resolve();\n\n return;\n }\n\n try {\n void opened.close().then(retirement.resolve, (cause: unknown) => this.failRetirement(retirement, cause));\n } catch (cause) {\n this.failRetirement(retirement, cause);\n }\n }\n\n private readonly fail = (cause: unknown): void => {\n this.stopWaitingForBody();\n const readiness = this.readiness;\n this.readiness = undefined;\n this.opening = undefined;\n readiness?.reject(cause);\n };\n\n private readonly assertCurrent = (): void => {\n if (this.retired) throw new FeatureError('retired', this.id);\n };\n\n private failRetirement(retirement: Retirement, cause: unknown): void {\n // Like the eager contribution wrapper, a failed cleanup can be retried through its error capability.\n if (this.retirement === retirement) this.retirement = undefined;\n\n retirement.reject(cause);\n }\n\n private readonly fence = (): void => {\n if (this.retired) return;\n\n this.retired = true;\n this.stopWaitingForBody();\n this.opening = undefined;\n\n if (this.readiness !== undefined) this.fail(new FeatureError('retired', this.id));\n\n if (this.opened !== undefined) fenceFeatureGeneration(this.opened);\n };\n\n private start(record: FeatureRecord): void {\n this.stopWaitingForBody();\n const opening = this.opening;\n this.opening = undefined;\n\n if (opening === undefined) return;\n\n this.starting = true;\n\n try {\n this.opened = opening(record, this.assertCurrent);\n void this.opened.ready.then(value => {\n const readiness = this.readiness;\n this.readiness = undefined;\n readiness?.resolve(value);\n }, this.fail);\n\n // A factory or source callback may close the facade before the materialized instance has been returned.\n if (this.retired) fenceFeatureGeneration(this.opened);\n } catch (cause) {\n this.fail(cause);\n } finally {\n this.starting = false;\n\n if (this.retirement !== undefined) this.drain(this.retirement);\n }\n }\n\n private stopWaitingForBody(): void {\n const release = this.releaseBody;\n this.releaseBody = undefined;\n release?.();\n }\n}\n\nfunction openLazyFeatureInstance<Prepared>(\n feature: Feature,\n opening: Opening<Prepared>,\n): FeatureInstance<string, Prepared> {\n return new LazyFeatureGeneration(feature, opening);\n}\n\nexport { openLazyFeatureInstance };\n"],"names":["LazyFeatureGeneration","FeatureError","feature","opening","resolve","reject","registerFeatureGenerationFence","observeFeatureBody","record","promise","accept","refuse","retirement","cause","opened","readiness","fenceFeatureGeneration","value","release","openLazyFeatureInstance"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ModuleInstanceRef } from './public-module.js';
2
+ /** Targets exposed by the selected own values, and the subset already bound to this module's lifetime. */
3
+ type FeatureOwnCallTargets = {
4
+ readonly available: Set<object>;
5
+ readonly local: Set<object>;
6
+ };
7
+ /** Lazy so a feature that owns attachments still runs `exports`: only the selected keys are materialized. */
8
+ declare function materializeFeatureOwn(instance: ModuleInstanceRef, refs: Readonly<Record<string, object>>, targets?: FeatureOwnCallTargets): Readonly<Record<string, unknown>>;
9
+ export { materializeFeatureOwn };
10
+ export type { FeatureOwnCallTargets };
@@ -0,0 +1,2 @@
1
+ import{isCallTarget as l}from"@opetope/core/internal";import{isLifetimeAttachmentRef as d}from"./attachment-declaration.js";import{isFeatureMaterializationRef as c,bindFeatureResource as m}from"./feature-materialization-binding.js";import{isFeatureDataRef as u,requireFeatureDataScope as s}from"./feature-model.js";import{resolveModuleCallTarget as p}from"./public-module-instance.js";function b(t,r,e){if(l(r))e.available.add(r),e.local.add(r);else if(u(t))for(const i of Object.values(r))l(i)&&e.available.add(i)}function w(t,r,e){if(u(e))return s(t).read(e);if(c(e))return m(t,e);if(d(e))throw new TypeError(`own.${r} is a lifecycle binding and has no materialized value.`);return p(t,e)}function O(t,r,e){const i=new Map,o={};for(const[a,n]of Object.entries(r))Object.defineProperty(o,a,{enumerable:!0,get:()=>{if(!i.has(a)){const f=w(t,a,n);i.set(a,f),e!==void 0&&b(n,f,e)}return i.get(a)}});return Object.freeze(o)}export{O as materializeFeatureOwn};
2
+ //# sourceMappingURL=feature-own-values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-own-values.js","sources":["../src/feature-own-values.ts"],"sourcesContent":["import { isCallTarget } from '@opetope/core/internal';\n\nimport { isLifetimeAttachmentRef } from './attachment-declaration';\nimport { bindFeatureResource, isFeatureMaterializationRef } from './feature-materialization-binding';\nimport { isFeatureDataRef, requireFeatureDataScope } from './feature-model';\nimport { resolveModuleCallTarget } from './public-module';\nimport type { ModuleCallRef, ModuleInstanceRef } from './public-module';\n\n/** Targets exposed by the selected own values, and the subset already bound to this module's lifetime. */\ntype FeatureOwnCallTargets = {\n readonly available: Set<object>;\n readonly local: Set<object>;\n};\n\nfunction recordOwnCalls(ref: object, value: unknown, targets: FeatureOwnCallTargets): void {\n if (isCallTarget(value)) {\n targets.available.add(value);\n targets.local.add(value);\n } else if (isFeatureDataRef(ref)) {\n for (const field of Object.values(value as Readonly<Record<string, unknown>>)) {\n if (isCallTarget(field)) targets.available.add(field);\n }\n }\n}\n\n/**\n * One `own` ref as the live value the instance holds: `exports` runs at open, so a call ref is already a `Call`, a\n * model or a state ref is already materialized data and a resource or a stream ref is already a `Resource` (D88).\n */\nfunction readFeatureOwnValue(instance: ModuleInstanceRef, key: string, ref: object): unknown {\n if (isFeatureDataRef(ref)) return requireFeatureDataScope(instance).read(ref);\n\n if (isFeatureMaterializationRef(ref)) return bindFeatureResource(instance, ref as never);\n\n if (isLifetimeAttachmentRef(ref)) {\n throw new TypeError(`own.${key} is a lifecycle binding and has no materialized value.`);\n }\n\n return resolveModuleCallTarget(instance, ref as ModuleCallRef<unknown, unknown>);\n}\n\n/** Lazy so a feature that owns attachments still runs `exports`: only the selected keys are materialized. */\nfunction materializeFeatureOwn(\n instance: ModuleInstanceRef,\n refs: Readonly<Record<string, object>>,\n targets?: FeatureOwnCallTargets,\n): Readonly<Record<string, unknown>> {\n const values = new Map<string, unknown>();\n const own: Record<string, unknown> = {};\n\n for (const [key, ref] of Object.entries(refs)) {\n Object.defineProperty(own, key, {\n enumerable: true,\n get: (): unknown => {\n if (!values.has(key)) {\n const value = readFeatureOwnValue(instance, key, ref);\n values.set(key, value);\n if (targets !== undefined) recordOwnCalls(ref, value, targets);\n }\n\n return values.get(key);\n },\n });\n }\n\n return Object.freeze(own);\n}\n\nexport { materializeFeatureOwn };\nexport type { FeatureOwnCallTargets };\n"],"names":["recordOwnCalls","ref","value","targets","isCallTarget","isFeatureDataRef","field","readFeatureOwnValue","instance","key","requireFeatureDataScope","isFeatureMaterializationRef","bindFeatureResource","isLifetimeAttachmentRef","resolveModuleCallTarget","materializeFeatureOwn","refs","values","own"],"mappings":"iYAcA,SAASA,EAAeC,EAAaC,EAAgBC,EAA8B,CACjF,GAAIC,EAAaF,CAAK,EACpBC,EAAQ,UAAU,IAAID,CAAK,EAC3BC,EAAQ,MAAM,IAAID,CAAK,UACdG,EAAiBJ,CAAG,EAC7B,UAAWK,KAAS,OAAO,OAAOJ,CAA0C,EACtEE,EAAaE,CAAK,GAAGH,EAAQ,UAAU,IAAIG,CAAK,CAG1D,CAMA,SAASC,EAAoBC,EAA6BC,EAAaR,EAAW,CAChF,GAAII,EAAiBJ,CAAG,EAAG,OAAOS,EAAwBF,CAAQ,EAAE,KAAKP,CAAG,EAE5E,GAAIU,EAA4BV,CAAG,EAAG,OAAOW,EAAoBJ,EAAUP,CAAY,EAEvF,GAAIY,EAAwBZ,CAAG,EAC7B,MAAM,IAAI,UAAU,OAAOQ,CAAG,wDAAwD,EAGxF,OAAOK,EAAwBN,EAAUP,CAAsC,CACjF,CAGA,SAASc,EACPP,EACAQ,EACAb,EAA+B,CAE/B,MAAMc,EAAS,IAAI,IACbC,EAA+B,CAAA,EAErC,SAAW,CAACT,EAAKR,CAAG,IAAK,OAAO,QAAQe,CAAI,EAC1C,OAAO,eAAeE,EAAKT,EAAK,CAC9B,WAAY,GACZ,IAAK,IAAc,CACjB,GAAI,CAACQ,EAAO,IAAIR,CAAG,EAAG,CACpB,MAAMP,EAAQK,EAAoBC,EAAUC,EAAKR,CAAG,EACpDgB,EAAO,IAAIR,EAAKP,CAAK,EACjBC,IAAY,QAAWH,EAAeC,EAAKC,EAAOC,CAAO,CAC/D,CAEA,OAAOc,EAAO,IAAIR,CAAG,CACvB,CACD,CAAA,EAGH,OAAO,OAAO,OAAOS,CAAG,CAC1B"}
@@ -1,6 +1,7 @@
1
1
  import type { PortRefOf } from '@opetope/core/internal';
2
+ import type { FeatureOwnCallTargets } from './feature-own-values.js';
2
3
  import type { AnyPort, PortProviderDescriptor } from './feature-port.js';
3
4
  import type { ModuleInstanceRef } from './public-module.js';
4
- declare function bindFeatureReadyPorts(ready: object, descriptors: readonly PortProviderDescriptor[], instance: ModuleInstanceRef): void;
5
+ declare function bindFeatureReadyPorts(ready: object, descriptors: readonly PortProviderDescriptor[], instance: ModuleInstanceRef, own: Readonly<Record<string, unknown>>, targets: FeatureOwnCallTargets | undefined, assertCurrent?: () => void): void;
5
6
  declare function resolveFeatureReadyPort<PortType extends AnyPort>(ready: object, port: PortType): PortRefOf<PortType>;
6
7
  export { bindFeatureReadyPorts, resolveFeatureReadyPort };
@@ -1,2 +1,2 @@
1
- import{isCallTarget as m,createAttachmentReadinessController as C,defineCallTarget as b,combineAbortSignals as h,inheritCallContextLifetime as w,inheritCallExecutionMetadata as y,settleGuardedResult as v,invokeCallTarget as T,throwIfSignalAborted as P,bindCallTargetToAttachment as M,releaseCallExecutionMetadata as k,retireCallContext as R}from"@opetope/core/internal";import{requireFeatureDataScope as f}from"./feature-model.js";import{bindProvidedPort as A}from"./feature-port.js";import{resolveModuleCallTarget as F,registerModuleRetirementParticipant as E}from"./public-module-instance.js";const p=new WeakMap;function $(n,a,r){const e=C({id:a}),t=new AbortController;E(r,{fence:()=>{e.publishInactive(),t.abort()}}),e.publishReady(e.beginOpen());const o=b({id:n.id,run(i,d){const u=h([d.signal,t.signal]),s=u.signal,l={signal:s},c=()=>{u.dispose(),k(l),R(l)};try{return w(d,l),y(d,l),v(T(n,i,l),{assertCurrent:()=>P(s),finalize:c,signal:s})}catch(g){throw c(),g}}});return M(o,e.ref)}function x(n,a,r){const e=new Map;for(const t of a){const o=t.target;let i=o.kind==="call"?F(r,o.ref):o.select(f(r).read(o.ref));if(!m(i))throw new TypeError(`Feature port ${t.key} model projection must return an authentic Call.`);o.kind==="model"&&!f(r).ownsCall(i)&&(i=$(i,`${t.port.id}.${t.key}.provider`,r)),e.set(t.port,A(t,i))}p.set(n,e)}function S(n,a){var e;const r=(e=p.get(n))==null?void 0:e.get(a);if(r===void 0)throw new TypeError(`Feature ready value does not provide Port ${a.id}.`);return r}export{x as bindFeatureReadyPorts,S as resolveFeatureReadyPort};
1
+ import{isCallTarget as m,createAttachmentReadinessController as g,defineCallTarget as h,combineAbortSignals as w,inheritCallContextLifetime as b,inheritCallExecutionMetadata as y,settleGuardedResult as v,invokeCallTarget as P,throwIfSignalAborted as T,bindCallTargetToAttachment as C,releaseCallExecutionMetadata as F,retireCallContext as M}from"@opetope/core/internal";import{requireFeatureDataScope as R}from"./feature-model.js";import{bindProvidedPort as k}from"./feature-port.js";import{registerModuleRetirementParticipant as A}from"./public-module-instance.js";const u=new WeakMap;function E(r,n,e){const t=g({id:n}),a=new AbortController;A(e,{fence:()=>{t.publishInactive(),a.abort()}}),t.publishReady(t.beginOpen());const f=h({id:r.id,run(c,l){const i=w([l.signal,a.signal]),o=i.signal,d={signal:o},s=()=>{i.dispose(),F(d),M(d)};try{return b(l,d),y(l,d),v(P(r,c,d),{assertCurrent:()=>T(o),finalize:s,signal:o})}catch(p){throw s(),p}}});return C(f,t.ref)}function $(r,n,e){e==null||e();const t=r.target(n);if(e==null||e(),!m(t))throw new TypeError(`Feature port ${r.key} selector must return an authentic Call.`);return t}function x(r,n,e,t,a,f){if(a===void 0)return;const c=new Map,l=Object.freeze({own:t});for(const i of n){let o=$(i,l,f);if(!a.available.has(o))throw new TypeError(`Feature port ${i.key} must select a Call from its own.`);!a.local.has(o)&&!R(e).ownsCall(o)&&(o=E(o,`${i.port.id}.${i.key}.provider`,e)),c.set(i.port,k(i,o))}u.set(r,c)}function S(r,n){var t;const e=(t=u.get(r))==null?void 0:t.get(n);if(e===void 0)throw new TypeError(`Feature ready value does not provide Port ${n.id}.`);return e}export{x as bindFeatureReadyPorts,S as resolveFeatureReadyPort};
2
2
  //# sourceMappingURL=feature-port-binding.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-port-binding.js","sources":["../src/feature-port-binding.ts"],"sourcesContent":["import type { Call, PortRef } from '@opetope/core';\nimport type { PortRefOf } from '@opetope/core/internal';\nimport {\n bindCallTargetToAttachment,\n combineAbortSignals,\n createAttachmentReadinessController,\n defineCallTarget,\n inheritCallContextLifetime,\n inheritCallExecutionMetadata,\n invokeCallTarget,\n isCallTarget,\n releaseCallExecutionMetadata,\n retireCallContext,\n settleGuardedResult,\n throwIfSignalAborted,\n} from '@opetope/core/internal';\n\nimport { requireFeatureDataScope } from './feature-model';\nimport { bindProvidedPort } from './feature-port';\nimport type { AnyPort, PortProviderDescriptor } from './feature-port';\nimport { registerModuleRetirementParticipant, resolveModuleCallTarget } from './public-module';\nimport type { ModuleCallRef, ModuleInstanceRef } from './public-module';\n\nconst readyPorts = new WeakMap<object, ReadonlyMap<object, PortRef<never, unknown>>>();\n\n/** Add the provider lease without replacing the selected Call's existing lifetime origin. */\nfunction bindModelProviderTarget(\n target: Call<unknown, unknown>,\n id: string,\n instance: ModuleInstanceRef,\n): Call<unknown, unknown> {\n const authority = createAttachmentReadinessController({ id });\n const provider = new AbortController();\n registerModuleRetirementParticipant(instance, {\n fence: () => {\n authority.publishInactive();\n provider.abort();\n },\n });\n authority.publishReady(authority.beginOpen());\n const forwarding = defineCallTarget({\n id: target.id,\n run(input: unknown, context) {\n const lifetime = combineAbortSignals([context.signal, provider.signal]);\n const signal = lifetime.signal;\n const forwarded = { signal };\n const finalize = (): void => {\n lifetime.dispose();\n releaseCallExecutionMetadata(forwarded);\n retireCallContext(forwarded);\n };\n\n try {\n inheritCallContextLifetime(context, forwarded);\n inheritCallExecutionMetadata(context, forwarded);\n\n // The selected target retains physical ownership; this adapter only forwards cancellation and settlement.\n return settleGuardedResult(invokeCallTarget(target, input, forwarded), {\n assertCurrent: () => throwIfSignalAborted(signal),\n finalize,\n signal,\n });\n } catch (error) {\n finalize();\n throw error;\n }\n },\n });\n\n return bindCallTargetToAttachment(forwarding, authority.ref);\n}\n\nfunction bindFeatureReadyPorts(\n ready: object,\n descriptors: readonly PortProviderDescriptor[],\n instance: ModuleInstanceRef,\n): void {\n const ports = new Map<object, PortRef<never, unknown>>();\n\n for (const descriptor of descriptors) {\n const binding = descriptor.target;\n let target =\n binding.kind === 'call'\n ? resolveModuleCallTarget(instance, binding.ref as ModuleCallRef<never, unknown>)\n : binding.select(requireFeatureDataScope(instance).read(binding.ref));\n\n if (!isCallTarget(target))\n throw new TypeError(`Feature port ${descriptor.key} model projection must return an authentic Call.`);\n\n if (binding.kind === 'model' && !requireFeatureDataScope(instance).ownsCall(target)) {\n target = bindModelProviderTarget(target, `${descriptor.port.id}.${descriptor.key}.provider`, instance);\n }\n\n ports.set(descriptor.port, bindProvidedPort(descriptor, target as Call<never, unknown>));\n }\n\n readyPorts.set(ready, ports);\n}\n\nfunction resolveFeatureReadyPort<PortType extends AnyPort>(ready: object, port: PortType): PortRefOf<PortType> {\n const ref = readyPorts.get(ready)?.get(port);\n\n if (ref === undefined) throw new TypeError(`Feature ready value does not provide Port ${port.id}.`);\n\n return ref as PortRefOf<PortType>;\n}\n\nexport { bindFeatureReadyPorts, resolveFeatureReadyPort };\n"],"names":["readyPorts","bindModelProviderTarget","target","id","instance","authority","createAttachmentReadinessController","provider","registerModuleRetirementParticipant","forwarding","defineCallTarget","input","context","lifetime","combineAbortSignals","signal","forwarded","finalize","releaseCallExecutionMetadata","retireCallContext","inheritCallContextLifetime","inheritCallExecutionMetadata","settleGuardedResult","invokeCallTarget","throwIfSignalAborted","error","bindCallTargetToAttachment","bindFeatureReadyPorts","ready","descriptors","ports","descriptor","binding","resolveModuleCallTarget","requireFeatureDataScope","isCallTarget","bindProvidedPort","resolveFeatureReadyPort","port","ref","_a"],"mappings":"mlBAuBA,MAAMA,EAAa,IAAI,QAGvB,SAASC,EACPC,EACAC,EACAC,EAA2B,CAE3B,MAAMC,EAAYC,EAAoC,CAAE,GAAAH,EAAI,EACtDI,EAAW,IAAI,gBACrBC,EAAoCJ,EAAU,CAC5C,MAAO,IAAK,CACVC,EAAU,gBAAe,EACzBE,EAAS,MAAK,CAChB,CACD,CAAA,EACDF,EAAU,aAAaA,EAAU,WAAW,EAC5C,MAAMI,EAAaC,EAAiB,CAClC,GAAIR,EAAO,GACX,IAAIS,EAAgBC,EAAO,CACzB,MAAMC,EAAWC,EAAoB,CAACF,EAAQ,OAAQL,EAAS,MAAM,CAAC,EAChEQ,EAASF,EAAS,OAClBG,EAAY,CAAE,OAAAD,CAAM,EACpBE,EAAW,IAAW,CAC1BJ,EAAS,QAAO,EAChBK,EAA6BF,CAAS,EACtCG,EAAkBH,CAAS,CAC7B,EAEA,GAAI,CACF,OAAAI,EAA2BR,EAASI,CAAS,EAC7CK,EAA6BT,EAASI,CAAS,EAGxCM,EAAoBC,EAAiBrB,EAAQS,EAAOK,CAAS,EAAG,CACrE,cAAe,IAAMQ,EAAqBT,CAAM,EAChD,SAAAE,EACA,OAAAF,CACD,CAAA,CACH,OAASU,EAAO,CACd,MAAAR,EAAQ,EACFQ,CACR,CACF,CACD,CAAA,EAED,OAAOC,EAA2BjB,EAAYJ,EAAU,GAAG,CAC7D,CAEA,SAASsB,EACPC,EACAC,EACAzB,EAA2B,CAE3B,MAAM0B,EAAQ,IAAI,IAElB,UAAWC,KAAcF,EAAa,CACpC,MAAMG,EAAUD,EAAW,OAC3B,IAAI7B,EACF8B,EAAQ,OAAS,OACbC,EAAwB7B,EAAU4B,EAAQ,GAAoC,EAC9EA,EAAQ,OAAOE,EAAwB9B,CAAQ,EAAE,KAAK4B,EAAQ,GAAG,CAAC,EAExE,GAAI,CAACG,EAAajC,CAAM,EACtB,MAAM,IAAI,UAAU,gBAAgB6B,EAAW,GAAG,kDAAkD,EAElGC,EAAQ,OAAS,SAAW,CAACE,EAAwB9B,CAAQ,EAAE,SAASF,CAAM,IAChFA,EAASD,EAAwBC,EAAQ,GAAG6B,EAAW,KAAK,EAAE,IAAIA,EAAW,GAAG,YAAa3B,CAAQ,GAGvG0B,EAAM,IAAIC,EAAW,KAAMK,EAAiBL,EAAY7B,CAA8B,CAAC,CACzF,CAEAF,EAAW,IAAI4B,EAAOE,CAAK,CAC7B,CAEA,SAASO,EAAkDT,EAAeU,EAAc,OACtF,MAAMC,GAAMC,EAAAxC,EAAW,IAAI4B,CAAK,IAApB,YAAAY,EAAuB,IAAIF,GAEvC,GAAIC,IAAQ,OAAW,MAAM,IAAI,UAAU,6CAA6CD,EAAK,EAAE,GAAG,EAElG,OAAOC,CACT"}
1
+ {"version":3,"file":"feature-port-binding.js","sources":["../src/feature-port-binding.ts"],"sourcesContent":["import type { Call, PortRef } from '@opetope/core';\nimport type { PortRefOf } from '@opetope/core/internal';\nimport {\n bindCallTargetToAttachment,\n combineAbortSignals,\n createAttachmentReadinessController,\n defineCallTarget,\n inheritCallContextLifetime,\n inheritCallExecutionMetadata,\n invokeCallTarget,\n isCallTarget,\n releaseCallExecutionMetadata,\n retireCallContext,\n settleGuardedResult,\n throwIfSignalAborted,\n} from '@opetope/core/internal';\n\nimport { requireFeatureDataScope } from './feature-model';\nimport type { FeatureOwnCallTargets } from './feature-own-values';\nimport { bindProvidedPort } from './feature-port';\nimport type { AnyPort, PortProviderDescriptor } from './feature-port';\nimport { registerModuleRetirementParticipant } from './public-module';\nimport type { ModuleInstanceRef } from './public-module';\n\nconst readyPorts = new WeakMap<object, ReadonlyMap<object, PortRef<never, unknown>>>();\n\n/** Add the provider lease without replacing the selected Call's existing lifetime origin. */\nfunction bindModelProviderTarget(\n target: Call<unknown, unknown>,\n id: string,\n instance: ModuleInstanceRef,\n): Call<unknown, unknown> {\n const authority = createAttachmentReadinessController({ id });\n const provider = new AbortController();\n registerModuleRetirementParticipant(instance, {\n fence: () => {\n authority.publishInactive();\n provider.abort();\n },\n });\n authority.publishReady(authority.beginOpen());\n const forwarding = defineCallTarget({\n id: target.id,\n run(input: unknown, context) {\n const lifetime = combineAbortSignals([context.signal, provider.signal]);\n const signal = lifetime.signal;\n const forwarded = { signal };\n const finalize = (): void => {\n lifetime.dispose();\n releaseCallExecutionMetadata(forwarded);\n retireCallContext(forwarded);\n };\n\n try {\n inheritCallContextLifetime(context, forwarded);\n inheritCallExecutionMetadata(context, forwarded);\n\n // The selected target retains physical ownership; this adapter only forwards cancellation and settlement.\n return settleGuardedResult(invokeCallTarget(target, input, forwarded), {\n assertCurrent: () => throwIfSignalAborted(signal),\n finalize,\n signal,\n });\n } catch (error) {\n finalize();\n throw error;\n }\n },\n });\n\n return bindCallTargetToAttachment(forwarding, authority.ref);\n}\n\nfunction selectProviderCall(\n descriptor: PortProviderDescriptor,\n context: { readonly own: Readonly<Record<string, unknown>> },\n assertCurrent: (() => void) | undefined,\n): Call<unknown, unknown> {\n assertCurrent?.();\n const target = descriptor.target(context);\n assertCurrent?.();\n\n if (!isCallTarget(target))\n throw new TypeError(`Feature port ${descriptor.key} selector must return an authentic Call.`);\n\n return target;\n}\n\nfunction bindFeatureReadyPorts(\n ready: object,\n descriptors: readonly PortProviderDescriptor[],\n instance: ModuleInstanceRef,\n own: Readonly<Record<string, unknown>>,\n targets: FeatureOwnCallTargets | undefined,\n assertCurrent?: () => void,\n): void {\n if (targets === undefined) return;\n\n const ports = new Map<object, PortRef<never, unknown>>();\n const context = Object.freeze({ own });\n\n for (const descriptor of descriptors) {\n let target = selectProviderCall(descriptor, context, assertCurrent);\n\n if (!targets.available.has(target))\n throw new TypeError(`Feature port ${descriptor.key} must select a Call from its own.`);\n\n if (!targets.local.has(target) && !requireFeatureDataScope(instance).ownsCall(target)) {\n target = bindModelProviderTarget(target, `${descriptor.port.id}.${descriptor.key}.provider`, instance);\n }\n\n ports.set(descriptor.port, bindProvidedPort(descriptor, target));\n }\n\n readyPorts.set(ready, ports);\n}\n\nfunction resolveFeatureReadyPort<PortType extends AnyPort>(ready: object, port: PortType): PortRefOf<PortType> {\n const ref = readyPorts.get(ready)?.get(port);\n\n if (ref === undefined) throw new TypeError(`Feature ready value does not provide Port ${port.id}.`);\n\n return ref as PortRefOf<PortType>;\n}\n\nexport { bindFeatureReadyPorts, resolveFeatureReadyPort };\n"],"names":["readyPorts","bindModelProviderTarget","target","id","instance","authority","createAttachmentReadinessController","provider","registerModuleRetirementParticipant","forwarding","defineCallTarget","input","context","lifetime","combineAbortSignals","signal","forwarded","finalize","releaseCallExecutionMetadata","retireCallContext","inheritCallContextLifetime","inheritCallExecutionMetadata","settleGuardedResult","invokeCallTarget","throwIfSignalAborted","error","bindCallTargetToAttachment","selectProviderCall","descriptor","assertCurrent","isCallTarget","bindFeatureReadyPorts","ready","descriptors","own","targets","ports","requireFeatureDataScope","bindProvidedPort","resolveFeatureReadyPort","port","ref","_a"],"mappings":"sjBAwBA,MAAMA,EAAa,IAAI,QAGvB,SAASC,EACPC,EACAC,EACAC,EAA2B,CAE3B,MAAMC,EAAYC,EAAoC,CAAE,GAAAH,EAAI,EACtDI,EAAW,IAAI,gBACrBC,EAAoCJ,EAAU,CAC5C,MAAO,IAAK,CACVC,EAAU,gBAAe,EACzBE,EAAS,MAAK,CAChB,CACD,CAAA,EACDF,EAAU,aAAaA,EAAU,WAAW,EAC5C,MAAMI,EAAaC,EAAiB,CAClC,GAAIR,EAAO,GACX,IAAIS,EAAgBC,EAAO,CACzB,MAAMC,EAAWC,EAAoB,CAACF,EAAQ,OAAQL,EAAS,MAAM,CAAC,EAChEQ,EAASF,EAAS,OAClBG,EAAY,CAAE,OAAAD,CAAM,EACpBE,EAAW,IAAW,CAC1BJ,EAAS,QAAO,EAChBK,EAA6BF,CAAS,EACtCG,EAAkBH,CAAS,CAC7B,EAEA,GAAI,CACF,OAAAI,EAA2BR,EAASI,CAAS,EAC7CK,EAA6BT,EAASI,CAAS,EAGxCM,EAAoBC,EAAiBrB,EAAQS,EAAOK,CAAS,EAAG,CACrE,cAAe,IAAMQ,EAAqBT,CAAM,EAChD,SAAAE,EACA,OAAAF,CACD,CAAA,CACH,OAASU,EAAO,CACd,MAAAR,EAAQ,EACFQ,CACR,CACF,CACD,CAAA,EAED,OAAOC,EAA2BjB,EAAYJ,EAAU,GAAG,CAC7D,CAEA,SAASsB,EACPC,EACAhB,EACAiB,EAAuC,CAEvCA,GAAA,MAAAA,IACA,MAAM3B,EAAS0B,EAAW,OAAOhB,CAAO,EAGxC,GAFAiB,GAAA,MAAAA,IAEI,CAACC,EAAa5B,CAAM,EACtB,MAAM,IAAI,UAAU,gBAAgB0B,EAAW,GAAG,0CAA0C,EAE9F,OAAO1B,CACT,CAEA,SAAS6B,EACPC,EACAC,EACA7B,EACA8B,EACAC,EACAN,EAA0B,CAE1B,GAAIM,IAAY,OAAW,OAE3B,MAAMC,EAAQ,IAAI,IACZxB,EAAU,OAAO,OAAO,CAAE,IAAAsB,CAAG,CAAE,EAErC,UAAWN,KAAcK,EAAa,CACpC,IAAI/B,EAASyB,EAAmBC,EAAYhB,EAASiB,CAAa,EAElE,GAAI,CAACM,EAAQ,UAAU,IAAIjC,CAAM,EAC/B,MAAM,IAAI,UAAU,gBAAgB0B,EAAW,GAAG,mCAAmC,EAEnF,CAACO,EAAQ,MAAM,IAAIjC,CAAM,GAAK,CAACmC,EAAwBjC,CAAQ,EAAE,SAASF,CAAM,IAClFA,EAASD,EAAwBC,EAAQ,GAAG0B,EAAW,KAAK,EAAE,IAAIA,EAAW,GAAG,YAAaxB,CAAQ,GAGvGgC,EAAM,IAAIR,EAAW,KAAMU,EAAiBV,EAAY1B,CAAM,CAAC,CACjE,CAEAF,EAAW,IAAIgC,EAAOI,CAAK,CAC7B,CAEA,SAASG,EAAkDP,EAAeQ,EAAc,OACtF,MAAMC,GAAMC,EAAA1C,EAAW,IAAIgC,CAAK,IAApB,YAAAU,EAAuB,IAAIF,GAEvC,GAAIC,IAAQ,OAAW,MAAM,IAAI,UAAU,6CAA6CD,EAAK,EAAE,GAAG,EAElG,OAAOC,CACT"}
@@ -1,8 +1,8 @@
1
- import type { Call, ModelOf, PortRef } from '@opetope/core';
2
- import type { ModelIdentity, PortIdentity, PortInput, PortOutput } from '@opetope/core/internal';
1
+ import type { Call, PortRef } from '@opetope/core';
2
+ import type { PortIdentity, PortInput, PortOutput } from '@opetope/core/internal';
3
+ import type { FeatureOwnValues } from './feature-authoring-types.js';
3
4
  import type { FeatureContribution, FeaturePipeBuilder, FeatureRegisterBuilder, FeatureSlotBuilder } from './feature-contribution.js';
4
- import type { FeatureModelRef } from './feature-model.js';
5
- import type { ModuleCallRef, ModuleCallRefIdentity } from './public-module.js';
5
+ import type { ModuleCallRef } from './public-module.js';
6
6
  declare const optionalPortBrand: unique symbol;
7
7
  declare const portProviderBrand: unique symbol;
8
8
  type AnyPort = PortIdentity;
@@ -24,21 +24,12 @@ type FeatureRequiredCalls<Id extends string, Requires extends PortRequirementRec
24
24
  interface PortProviderBinding<PortType extends AnyPort, Id extends string> {
25
25
  readonly [portProviderBrand]: readonly [PortType, Id];
26
26
  }
27
- interface FeaturePortBuilder<Id extends string> {
28
- <PortType extends AnyPort>(port: PortType, target: ModuleCallRef<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>, Id>): PortProviderBinding<PortType, Id>;
29
- <PortType extends AnyPort, Declaration extends ModelIdentity>(port: PortType, projection: {
30
- readonly from: FeatureModelRef<Declaration, Id>;
31
- readonly select: (model: ModelOf<NoInfer<Declaration>>) => Call<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>>;
32
- }): PortProviderBinding<PortType, Id>;
33
- }
34
- type PortProviderTarget = {
35
- readonly kind: 'call';
36
- readonly ref: ModuleCallRefIdentity;
37
- } | {
38
- readonly kind: 'model';
39
- readonly ref: object;
40
- readonly select: (model: unknown) => unknown;
41
- };
27
+ type FeaturePortBuilder<Id extends string, Own> = <PortType extends AnyPort>(port: PortType, select: (context: {
28
+ readonly own: Own;
29
+ }) => Call<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>>) => PortProviderBinding<PortType, Id>;
30
+ type PortProviderTarget = (context: {
31
+ readonly own: Readonly<Record<string, unknown>>;
32
+ }) => unknown;
42
33
  type PortProviderDescriptor = {
43
34
  readonly key: string;
44
35
  readonly port: AnyPort;
@@ -46,9 +37,8 @@ type PortProviderDescriptor = {
46
37
  };
47
38
  /** One section for every extension point: `port` for ports, `slot`, `pipe` and `register` for contributions. */
48
39
  type FeatureProvidesFactory<Id extends string, Context, Evaluation, Runtime extends Readonly<Record<string, object>>, Provided extends FeatureProvidedRecord<Id>> = (context: {
49
- readonly own: Runtime;
50
40
  readonly pipe: FeaturePipeBuilder<Evaluation>;
51
- readonly port: FeaturePortBuilder<Id>;
41
+ readonly port: FeaturePortBuilder<Id, FeatureOwnValues<Id, Runtime>>;
52
42
  readonly register: FeatureRegisterBuilder<Context, Evaluation>;
53
43
  readonly slot: FeatureSlotBuilder<Context, Evaluation>;
54
44
  }) => Provided;
@@ -58,8 +48,8 @@ declare function optionalPort<PortType extends AnyPort>(port: PortType): Optiona
58
48
  /** Tolerant on purpose: the caller may hold any requirement declaration or none at all. */
59
49
  declare function isOptionalPortRequirement(requirement: unknown): boolean;
60
50
  declare function getRequiredPort(requirement: unknown): AnyPort;
61
- declare function createPortBuilder<Id extends string>(): FeaturePortBuilder<Id>;
62
- declare function snapshotPortProviders(runtimeValues: ReadonlySet<object>, entries: readonly (readonly [string, unknown])[]): readonly PortProviderDescriptor[];
51
+ declare function createPortBuilder<Id extends string, Own>(): FeaturePortBuilder<Id, Own>;
52
+ declare function snapshotPortProviders(entries: readonly (readonly [string, unknown])[]): readonly PortProviderDescriptor[];
63
53
  declare function bindProvidedPort(descriptor: PortProviderDescriptor, target: Call<never, unknown>): PortRef<never, unknown>;
64
54
  declare function assertRequiredPortValue(port: AnyPort, value: unknown, key: string, isOptional: boolean): asserts value is PortRef<never, unknown> | undefined;
65
55
  export { assertRequiredPortValue, bindProvidedPort, createPortBuilder, getRequiredPort, isOptionalPortRequirement, optionalPort, snapshotPortProviders, };
@@ -1,2 +1,2 @@
1
- import{isPort as a,isPortRefFor as p,bindPortRef as d}from"@opetope/core/internal";import{isAttachmentCallRef as u}from"./attachment-call-declaration.js";import{isFeatureDataRef as l}from"./feature-model.js";import{assertPlainRecord as w,assertExactDataKeys as P,dataEntries as m}from"./feature-record.js";const f=new WeakMap,s=new WeakSet,c=new WeakMap;function h(r){if(!a(r))throw new TypeError("optional expects an authentic Port.");const e=Object.freeze({});return f.set(e,r),s.add(e),e}function b(r){return typeof r=="object"&&r!==null&&s.has(r)}function j(r){if(a(r))return r;if(typeof r!="object"||r===null)throw new TypeError("Feature requirement is not an authentic required Port.");const e=f.get(r);if(e===void 0)throw new TypeError("Feature requirement is not an authentic required Port.");return e}function y(){return(r,e)=>{if(!a(r))throw new TypeError("provides.port takes a port created by definePort.");let o;if(u(e))o=Object.freeze({kind:"call",ref:e});else{if(w(e,"Feature port model projection"),P(e,m(e,"Feature port model projection"),["from","select"],"Feature port model projection"),!l(e.from)||typeof e.select!="function")throw new TypeError("provides.port takes an owned Call ref or a model projection with from and select.");o=Object.freeze({kind:"model",ref:e.from,select:e.select})}const t=Object.freeze({});return c.set(t,Object.freeze({port:r,target:o})),t}}function E(r,e){const o=e.map(([t,i])=>{if(typeof i!="object"||i===null)throw new TypeError(`Feature provider ${t} is not an authentic Port provider.`);const n=c.get(i);if(n===void 0)throw new TypeError(`Feature provider ${t} is not an authentic Port provider.`);if(!r.has(n.target.ref))throw new TypeError(`Feature provider ${t} must select a call or model ref from its public own.`);return Object.freeze({key:t,port:n.port,target:n.target})});return Object.freeze(o)}function F(r,e){return d(r.port,e)}function R(r,e,o,t){if(!(t&&e===void 0)&&!p(r,e))throw new TypeError(`openFeature requirement ${o} must be a PortRef for ${r.id}.`)}export{R as assertRequiredPortValue,F as bindProvidedPort,y as createPortBuilder,j as getRequiredPort,b as isOptionalPortRequirement,h as optionalPort,E as snapshotPortProviders};
1
+ import{isPort as i,isPortRefFor as p,bindPortRef as s}from"@opetope/core/internal";const a=new WeakMap,u=new WeakSet,f=new WeakMap;function c(e){if(!i(e))throw new TypeError("optional expects an authentic Port.");const r=Object.freeze({});return a.set(r,e),u.add(r),r}function d(e){return typeof e=="object"&&e!==null&&u.has(e)}function P(e){if(i(e))return e;if(typeof e!="object"||e===null)throw new TypeError("Feature requirement is not an authentic required Port.");const r=a.get(e);if(r===void 0)throw new TypeError("Feature requirement is not an authentic required Port.");return r}function w(){return(e,r)=>{if(!i(e))throw new TypeError("provides.port takes a port created by definePort.");if(typeof r!="function")throw new TypeError("provides.port takes a selector of an owned Call.");const o=r,t=Object.freeze({});return f.set(t,Object.freeze({port:e,target:o})),t}}function h(e){const r=e.map(([o,t])=>{if(typeof t!="object"||t===null)throw new TypeError(`Feature provider ${o} is not an authentic Port provider.`);const n=f.get(t);if(n===void 0)throw new TypeError(`Feature provider ${o} is not an authentic Port provider.`);return Object.freeze({key:o,port:n.port,target:n.target})});return Object.freeze(r)}function l(e,r){return s(e.port,r)}function b(e,r,o,t){if(!(t&&r===void 0)&&!p(e,r))throw new TypeError(`openFeature requirement ${o} must be a PortRef for ${e.id}.`)}export{b as assertRequiredPortValue,l as bindProvidedPort,w as createPortBuilder,P as getRequiredPort,d as isOptionalPortRequirement,c as optionalPort,h as snapshotPortProviders};
2
2
  //# sourceMappingURL=feature-port.js.map