@opetope/runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +345 -0
- package/README.ru.md +344 -0
- package/dist/application-compiler-edges.d.ts +3 -0
- package/dist/application-compiler-edges.js +2 -0
- package/dist/application-compiler-edges.js.map +1 -0
- package/dist/application-compiler-graph.d.ts +8 -0
- package/dist/application-compiler-graph.js +2 -0
- package/dist/application-compiler-graph.js.map +1 -0
- package/dist/application-compiler.d.ts +116 -0
- package/dist/application-compiler.js +2 -0
- package/dist/application-compiler.js.map +1 -0
- package/dist/application-conditions.d.ts +18 -0
- package/dist/application-conditions.js +2 -0
- package/dist/application-conditions.js.map +1 -0
- package/dist/application-definition.d.ts +30 -0
- package/dist/application-definition.js +2 -0
- package/dist/application-definition.js.map +1 -0
- package/dist/application-error.d.ts +10 -0
- package/dist/application-error.js +2 -0
- package/dist/application-error.js.map +1 -0
- package/dist/application-execution.d.ts +43 -0
- package/dist/application-execution.js +2 -0
- package/dist/application-execution.js.map +1 -0
- package/dist/application-feature-bindings.d.ts +11 -0
- package/dist/application-feature-bindings.js +2 -0
- package/dist/application-feature-bindings.js.map +1 -0
- package/dist/application-feature-instance.d.ts +5 -0
- package/dist/application-feature-instance.js +2 -0
- package/dist/application-feature-instance.js.map +1 -0
- package/dist/application-group-order.d.ts +29 -0
- package/dist/application-group-order.js +2 -0
- package/dist/application-group-order.js.map +1 -0
- package/dist/application-instance-retirement.d.ts +36 -0
- package/dist/application-instance-retirement.js +2 -0
- package/dist/application-instance-retirement.js.map +1 -0
- package/dist/application-open-options.d.ts +29 -0
- package/dist/application-open-options.js +2 -0
- package/dist/application-open-options.js.map +1 -0
- package/dist/application-port-compiler.d.ts +28 -0
- package/dist/application-port-compiler.js +2 -0
- package/dist/application-port-compiler.js.map +1 -0
- package/dist/attachment-call-declaration.d.ts +43 -0
- package/dist/attachment-call-declaration.js +2 -0
- package/dist/attachment-call-declaration.js.map +1 -0
- package/dist/attachment-declaration.d.ts +68 -0
- package/dist/attachment-declaration.js +2 -0
- package/dist/attachment-declaration.js.map +1 -0
- package/dist/attachment-execution.d.ts +9 -0
- package/dist/attachment-execution.js +2 -0
- package/dist/attachment-execution.js.map +1 -0
- package/dist/attachment-retirement-scheduler.d.ts +14 -0
- package/dist/attachment-retirement-scheduler.js +2 -0
- package/dist/attachment-retirement-scheduler.js.map +1 -0
- package/dist/call-option-snapshot.d.ts +20 -0
- package/dist/call-option-snapshot.js +2 -0
- package/dist/call-option-snapshot.js.map +1 -0
- package/dist/compile-call-target-bindings.d.ts +14 -0
- package/dist/compile-call-target-bindings.js +2 -0
- package/dist/compile-call-target-bindings.js.map +1 -0
- package/dist/compile-module-template.d.ts +38 -0
- package/dist/compile-module-template.js +2 -0
- package/dist/compile-module-template.js.map +1 -0
- package/dist/condition-group-execution.d.ts +44 -0
- package/dist/condition-group-execution.js +2 -0
- package/dist/condition-group-execution.js.map +1 -0
- package/dist/condition-override.d.ts +28 -0
- package/dist/condition-override.js +2 -0
- package/dist/condition-override.js.map +1 -0
- package/dist/condition-source.d.ts +10 -0
- package/dist/condition-source.js +2 -0
- package/dist/condition-source.js.map +1 -0
- package/dist/condition-types.d.ts +14 -0
- package/dist/condition.d.ts +28 -0
- package/dist/condition.js +2 -0
- package/dist/condition.js.map +1 -0
- package/dist/control-registry.d.ts +56 -0
- package/dist/control-registry.js +2 -0
- package/dist/control-registry.js.map +1 -0
- package/dist/dynamic-scope-child.d.ts +23 -0
- package/dist/dynamic-scope-child.js +2 -0
- package/dist/dynamic-scope-child.js.map +1 -0
- package/dist/dynamic-scope-controller.d.ts +16 -0
- package/dist/dynamic-scope-controller.js +2 -0
- package/dist/dynamic-scope-controller.js.map +1 -0
- package/dist/feature-attachment-authoring-types.d.ts +51 -0
- package/dist/feature-attachment-lowering.d.ts +18 -0
- package/dist/feature-attachment-lowering.js +2 -0
- package/dist/feature-attachment-lowering.js.map +1 -0
- package/dist/feature-attachment.d.ts +45 -0
- package/dist/feature-attachment.js +2 -0
- package/dist/feature-attachment.js.map +1 -0
- package/dist/feature-authoring-types.d.ts +196 -0
- package/dist/feature-authoring.d.ts +15 -0
- package/dist/feature-authoring.js +2 -0
- package/dist/feature-authoring.js.map +1 -0
- package/dist/feature-body.d.ts +53 -0
- package/dist/feature-body.js +2 -0
- package/dist/feature-body.js.map +1 -0
- package/dist/feature-call-authority.d.ts +8 -0
- package/dist/feature-call-authority.js +2 -0
- package/dist/feature-call-authority.js.map +1 -0
- package/dist/feature-call-types.d.ts +39 -0
- package/dist/feature-call.d.ts +18 -0
- package/dist/feature-call.js +2 -0
- package/dist/feature-call.js.map +1 -0
- package/dist/feature-calls.d.ts +6 -0
- package/dist/feature-calls.js +2 -0
- package/dist/feature-calls.js.map +1 -0
- package/dist/feature-contract.d.ts +70 -0
- package/dist/feature-contract.js +2 -0
- package/dist/feature-contract.js.map +1 -0
- package/dist/feature-contribution-model.d.ts +38 -0
- package/dist/feature-contribution-model.js +2 -0
- package/dist/feature-contribution-model.js.map +1 -0
- package/dist/feature-contribution.d.ts +126 -0
- package/dist/feature-contribution.js +2 -0
- package/dist/feature-contribution.js.map +1 -0
- package/dist/feature-definition-api.d.ts +53 -0
- package/dist/feature-definition-support.d.ts +21 -0
- package/dist/feature-definition-support.js +2 -0
- package/dist/feature-definition-support.js.map +1 -0
- package/dist/feature-effect.d.ts +26 -0
- package/dist/feature-effect.js +2 -0
- package/dist/feature-effect.js.map +1 -0
- package/dist/feature-event.d.ts +32 -0
- package/dist/feature-event.js +2 -0
- package/dist/feature-event.js.map +1 -0
- package/dist/feature-generation.d.ts +34 -0
- package/dist/feature-generation.js +2 -0
- package/dist/feature-generation.js.map +1 -0
- package/dist/feature-lazy-generation.d.ts +6 -0
- package/dist/feature-lazy-generation.js +2 -0
- package/dist/feature-lazy-generation.js.map +1 -0
- package/dist/feature-lazy.d.ts +44 -0
- package/dist/feature-lazy.js +2 -0
- package/dist/feature-lazy.js.map +1 -0
- package/dist/feature-materialization-binding.d.ts +31 -0
- package/dist/feature-materialization-binding.js +2 -0
- package/dist/feature-materialization-binding.js.map +1 -0
- package/dist/feature-materialization-types.d.ts +45 -0
- package/dist/feature-model-dependencies.d.ts +23 -0
- package/dist/feature-model-dependencies.js +2 -0
- package/dist/feature-model-dependencies.js.map +1 -0
- package/dist/feature-model.d.ts +60 -0
- package/dist/feature-model.js +2 -0
- package/dist/feature-model.js.map +1 -0
- package/dist/feature-optional.d.ts +15 -0
- package/dist/feature-optional.js +2 -0
- package/dist/feature-optional.js.map +1 -0
- package/dist/feature-own-lowering.d.ts +22 -0
- package/dist/feature-own-lowering.js +2 -0
- package/dist/feature-own-lowering.js.map +1 -0
- package/dist/feature-port-binding.d.ts +6 -0
- package/dist/feature-port-binding.js +2 -0
- package/dist/feature-port-binding.js.map +1 -0
- package/dist/feature-port.d.ts +66 -0
- package/dist/feature-port.js +2 -0
- package/dist/feature-port.js.map +1 -0
- package/dist/feature-record.d.ts +6 -0
- package/dist/feature-record.js +2 -0
- package/dist/feature-record.js.map +1 -0
- package/dist/feature-resource.d.ts +29 -0
- package/dist/feature-resource.js +2 -0
- package/dist/feature-resource.js.map +1 -0
- package/dist/feature-scope-types.d.ts +35 -0
- package/dist/feature-scope.d.ts +29 -0
- package/dist/feature-scope.js +2 -0
- package/dist/feature-scope.js.map +1 -0
- package/dist/feature-stream.d.ts +37 -0
- package/dist/feature-stream.js +2 -0
- package/dist/feature-stream.js.map +1 -0
- package/dist/feature-timers.d.ts +14 -0
- package/dist/feature-timers.js +2 -0
- package/dist/feature-timers.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/inspection-activity-protocol.d.ts +63 -0
- package/dist/inspection-activity.d.ts +54 -0
- package/dist/inspection-activity.js +2 -0
- package/dist/inspection-activity.js.map +1 -0
- package/dist/inspection-diff.d.ts +10 -0
- package/dist/inspection-diff.js +2 -0
- package/dist/inspection-diff.js.map +1 -0
- package/dist/inspection-module-activity.d.ts +4 -0
- package/dist/inspection-module-activity.js +2 -0
- package/dist/inspection-module-activity.js.map +1 -0
- package/dist/inspection-observer.d.ts +38 -0
- package/dist/inspection-observer.js +2 -0
- package/dist/inspection-observer.js.map +1 -0
- package/dist/inspection-plan.d.ts +33 -0
- package/dist/inspection-plan.js +2 -0
- package/dist/inspection-plan.js.map +1 -0
- package/dist/inspection-protocol.d.ts +333 -0
- package/dist/inspection-protocol.js +2 -0
- package/dist/inspection-protocol.js.map +1 -0
- package/dist/inspection-registry.d.ts +41 -0
- package/dist/inspection-registry.js +2 -0
- package/dist/inspection-registry.js.map +1 -0
- package/dist/inspection-session.d.ts +92 -0
- package/dist/inspection-session.js +2 -0
- package/dist/inspection-session.js.map +1 -0
- package/dist/inspection-snapshot.d.ts +4 -0
- package/dist/inspection-snapshot.js +2 -0
- package/dist/inspection-snapshot.js.map +1 -0
- package/dist/inspection-state.d.ts +91 -0
- package/dist/inspection-state.js +2 -0
- package/dist/inspection-state.js.map +1 -0
- package/dist/instance-demand.d.ts +31 -0
- package/dist/instance-demand.js +2 -0
- package/dist/instance-demand.js.map +1 -0
- package/dist/internal.d.ts +41 -0
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -0
- package/dist/keyed-scope-controller.d.ts +11 -0
- package/dist/keyed-scope-controller.js +2 -0
- package/dist/keyed-scope-controller.js.map +1 -0
- package/dist/model-kernel.d.ts +18 -0
- package/dist/model-kernel.js +2 -0
- package/dist/model-kernel.js.map +1 -0
- package/dist/module-call-context.d.ts +7 -0
- package/dist/module-call-context.js +2 -0
- package/dist/module-call-context.js.map +1 -0
- package/dist/module-call-runtime.d.ts +21 -0
- package/dist/module-call-runtime.js +2 -0
- package/dist/module-call-runtime.js.map +1 -0
- package/dist/module-generation.d.ts +57 -0
- package/dist/module-generation.js +2 -0
- package/dist/module-generation.js.map +1 -0
- package/dist/module-instance-types.d.ts +156 -0
- package/dist/module-instance.d.ts +19 -0
- package/dist/module-instance.js +2 -0
- package/dist/module-instance.js.map +1 -0
- package/dist/module-runtime-identity.d.ts +4 -0
- package/dist/module-runtime-identity.js +2 -0
- package/dist/module-runtime-identity.js.map +1 -0
- package/dist/module-scope-open.d.ts +4 -0
- package/dist/module-scope-open.js +2 -0
- package/dist/module-scope-open.js.map +1 -0
- package/dist/module-scope-retirement.d.ts +3 -0
- package/dist/module-scope-retirement.js +2 -0
- package/dist/module-scope-retirement.js.map +1 -0
- package/dist/module-template-ir.d.ts +59 -0
- package/dist/owner-generation-retirement.d.ts +6 -0
- package/dist/owner-generation-retirement.js +2 -0
- package/dist/owner-generation-retirement.js.map +1 -0
- package/dist/owner-generation-state.d.ts +123 -0
- package/dist/owner-generation-state.js +2 -0
- package/dist/owner-generation-state.js.map +1 -0
- package/dist/owner-generation.d.ts +16 -0
- package/dist/owner-generation.js +2 -0
- package/dist/owner-generation.js.map +1 -0
- package/dist/public-module-definition.d.ts +9 -0
- package/dist/public-module-definition.js +2 -0
- package/dist/public-module-definition.js.map +1 -0
- package/dist/public-module-instance.d.ts +6 -0
- package/dist/public-module-instance.js +2 -0
- package/dist/public-module-instance.js.map +1 -0
- package/dist/public-module-retirement-diagnostics.d.ts +5 -0
- package/dist/public-module-retirement-diagnostics.js +2 -0
- package/dist/public-module-retirement-diagnostics.js.map +1 -0
- package/dist/public-module-retirement.d.ts +3 -0
- package/dist/public-module-retirement.js +2 -0
- package/dist/public-module-retirement.js.map +1 -0
- package/dist/public-module-scope.d.ts +5 -0
- package/dist/public-module-scope.js +2 -0
- package/dist/public-module-scope.js.map +1 -0
- package/dist/public-module-state.d.ts +28 -0
- package/dist/public-module-state.js +2 -0
- package/dist/public-module-state.js.map +1 -0
- package/dist/public-module-types.d.ts +295 -0
- package/dist/public-module.d.ts +4 -0
- package/dist/resource-cache.d.ts +12 -0
- package/dist/resource-cache.js +2 -0
- package/dist/resource-cache.js.map +1 -0
- package/dist/resource-controller.d.ts +29 -0
- package/dist/resource-controller.js +2 -0
- package/dist/resource-controller.js.map +1 -0
- package/dist/resource-policy.d.ts +16 -0
- package/dist/resource-policy.js +2 -0
- package/dist/resource-policy.js.map +1 -0
- package/dist/resource-snapshot.d.ts +12 -0
- package/dist/resource-snapshot.js +2 -0
- package/dist/resource-snapshot.js.map +1 -0
- package/dist/resource-types.d.ts +3 -0
- package/dist/runtime-error-reporting.d.ts +4 -0
- package/dist/runtime-error-reporting.js +2 -0
- package/dist/runtime-error-reporting.js.map +1 -0
- package/dist/stream-backpressure.d.ts +18 -0
- package/dist/stream-backpressure.js +2 -0
- package/dist/stream-backpressure.js.map +1 -0
- package/dist/stream-cleanup.d.ts +17 -0
- package/dist/stream-cleanup.js +2 -0
- package/dist/stream-cleanup.js.map +1 -0
- package/dist/stream-controller-types.d.ts +51 -0
- package/dist/stream-controller.d.ts +5 -0
- package/dist/stream-controller.js +2 -0
- package/dist/stream-controller.js.map +1 -0
- package/docs/agent-guide.md +214 -0
- package/docs/agent-guide.ru.md +208 -0
- package/docs/cookbook.md +734 -0
- package/docs/cookbook.ru.md +729 -0
- package/docs/decisions.md +1437 -0
- package/docs/devtools.md +423 -0
- package/docs/devtools.ru.md +419 -0
- package/docs/how-it-works.md +521 -0
- package/docs/how-it-works.ru.md +495 -0
- package/docs/releases.md +78 -0
- package/docs/releases.ru.md +78 -0
- package/docs/spec.md +874 -0
- package/docs/spec.ru.md +884 -0
- package/package.json +72 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `openApplication` accepts, in one place: the exact option record, the condition bindings the host supplies and
|
|
3
|
+
* the cleanup policy every instance of the application inherits (D182).
|
|
4
|
+
*/
|
|
5
|
+
import type { Readable } from '@opetope/core';
|
|
6
|
+
import type { CompiledApplicationFeatureIR } from './application-compiler.js';
|
|
7
|
+
import type { ApplicationConditionId } from './application-definition.js';
|
|
8
|
+
import type { AnyFeature } from './feature-authoring.js';
|
|
9
|
+
import type { HostContract } from './feature-contract.js';
|
|
10
|
+
import type { CleanupFailurePolicy } from './public-module.js';
|
|
11
|
+
type ApplicationHostContract = CompiledApplicationFeatureIR['imports'][number]['contract'];
|
|
12
|
+
interface ApplicationImportBinding {
|
|
13
|
+
readonly contract: ApplicationHostContract;
|
|
14
|
+
readonly value: unknown;
|
|
15
|
+
}
|
|
16
|
+
/** The host binds one import at the call site, so the value is type-checked where the contract is named (D68). */
|
|
17
|
+
declare function bind<Value>(contract: HostContract<Value>, value: NoInfer<Value>): ApplicationImportBinding;
|
|
18
|
+
interface OpenApplicationOptions<Features extends readonly AnyFeature[] = readonly AnyFeature[]> {
|
|
19
|
+
/**
|
|
20
|
+
* What a failed cleanup costs the host: `report` (the default) hands the failure to the reporter and calls the
|
|
21
|
+
* instance closed, `quarantine` keeps the frontier and hands back a retry (D182).
|
|
22
|
+
*/
|
|
23
|
+
readonly cleanupFailure?: CleanupFailurePolicy;
|
|
24
|
+
readonly conditions: Readonly<Record<ApplicationConditionId<Features>, Readable<boolean>>>;
|
|
25
|
+
readonly imports: readonly ApplicationImportBinding[];
|
|
26
|
+
}
|
|
27
|
+
declare function snapshotOpenOptions(value: unknown): Required<OpenApplicationOptions>;
|
|
28
|
+
export { bind, snapshotOpenOptions };
|
|
29
|
+
export type { ApplicationImportBinding, OpenApplicationOptions };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{hasOwn as i}from"@opetope/core/internal";import{assertPlainRecord as p,dataEntries as f}from"./feature-record.js";const s=new WeakSet;function l(o,n){const e=Object.freeze({contract:o,value:n});return s.add(e),e}function d(o,n){if(!Array.isArray(o))throw new TypeError(`${n} must be an array.`);return Array.from(o)}function m(o){p(o,"openApplication conditions");const n=[];for(const e of Reflect.ownKeys(o)){if(typeof e!="string")throw new TypeError("openApplication conditions must use condition ids as keys.");const r=Object.getOwnPropertyDescriptor(o,e);if((r==null?void 0:r.enumerable)!==!0||!("value"in r))throw new TypeError(`openApplication conditions ${e} must be an enumerable data field.`);n.push([e,r.value])}return Object.freeze(Object.fromEntries(n))}function w(o){const n=o.cleanupFailure??"report";if(n!=="quarantine"&&n!=="report")throw new TypeError('openApplication cleanupFailure must be "report" or "quarantine".');return n}function b(o){p(o,"openApplication options");const n=f(o,"openApplication options");for(const[t]of n)if(t!=="cleanupFailure"&&t!=="conditions"&&t!=="imports")throw new TypeError("openApplication options requires exact data fields.");const e=Object.freeze(Object.fromEntries(n));if(!i(e,"conditions")||!i(e,"imports"))throw new TypeError("openApplication options requires exact data fields.");const r=w(e),a=m(e.conditions),c=d(e.imports,"openApplication imports").map((t,u)=>{if(typeof t!="object"||t===null||!s.has(t))throw new TypeError(`openApplication imports[${String(u)}] must come from bind(contract, value).`);return t});return Object.freeze({cleanupFailure:r,conditions:a,imports:c})}export{l as bind,b as snapshotOpenOptions};
|
|
2
|
+
//# sourceMappingURL=application-open-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-open-options.js","sources":["../src/application-open-options.ts"],"sourcesContent":["/**\n * What `openApplication` accepts, in one place: the exact option record, the condition bindings the host supplies and\n * the cleanup policy every instance of the application inherits (D182).\n */\n\nimport type { Readable } from '@opetope/core';\nimport { hasOwn } from '@opetope/core/internal';\n\nimport type { CompiledApplicationFeatureIR } from './application-compiler';\nimport type { ApplicationConditionId } from './application-definition';\nimport type { AnyFeature } from './feature-authoring';\nimport type { HostContract } from './feature-contract';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { CleanupFailurePolicy } from './public-module';\n\ntype ApplicationHostContract = CompiledApplicationFeatureIR['imports'][number]['contract'];\n\ninterface ApplicationImportBinding {\n readonly contract: ApplicationHostContract;\n readonly value: unknown;\n}\n\nconst importBindings = new WeakSet<object>();\n\n/** The host binds one import at the call site, so the value is type-checked where the contract is named (D68). */\nfunction bind<Value>(contract: HostContract<Value>, value: NoInfer<Value>): ApplicationImportBinding;\nfunction bind(contract: unknown, value: unknown): ApplicationImportBinding {\n const binding = Object.freeze({ contract: contract as ApplicationHostContract, value });\n importBindings.add(binding);\n\n return binding;\n}\n\ninterface OpenApplicationOptions<Features extends readonly AnyFeature[] = readonly AnyFeature[]> {\n /**\n * What a failed cleanup costs the host: `report` (the default) hands the failure to the reporter and calls the\n * instance closed, `quarantine` keeps the frontier and hands back a retry (D182).\n */\n readonly cleanupFailure?: CleanupFailurePolicy;\n readonly conditions: Readonly<Record<ApplicationConditionId<Features>, Readable<boolean>>>;\n readonly imports: readonly ApplicationImportBinding[];\n}\n\nfunction snapshotArray(value: unknown, label: string): readonly unknown[] {\n if (!Array.isArray(value)) throw new TypeError(`${label} must be an array.`);\n\n return Array.from(value as readonly unknown[]);\n}\n\n/** Condition keys are declaration ids, so they carry dots; only own enumerable data fields are read. */\nfunction snapshotConditionRecord(value: unknown): Readonly<Record<string, Readable<boolean>>> {\n assertPlainRecord(value, 'openApplication conditions');\n const entries: (readonly [string, Readable<boolean>])[] = [];\n\n for (const key of Reflect.ownKeys(value)) {\n if (typeof key !== 'string') throw new TypeError('openApplication conditions must use condition ids as keys.');\n\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n\n if (descriptor?.enumerable !== true || !('value' in descriptor)) {\n throw new TypeError(`openApplication conditions ${key} must be an enumerable data field.`);\n }\n\n entries.push([key, descriptor.value as Readable<boolean>]);\n }\n\n return Object.freeze(Object.fromEntries(entries));\n}\n\n/** The one optional key of the open options, so exactness is checked by membership rather than by count (D182). */\nfunction snapshotCleanupFailure(options: Readonly<Record<string, unknown>>): CleanupFailurePolicy {\n const cleanupFailure = options['cleanupFailure'] ?? 'report';\n\n if (cleanupFailure !== 'quarantine' && cleanupFailure !== 'report') {\n throw new TypeError('openApplication cleanupFailure must be \"report\" or \"quarantine\".');\n }\n\n return cleanupFailure;\n}\n\nfunction snapshotOpenOptions(value: unknown): Required<OpenApplicationOptions> {\n assertPlainRecord(value, 'openApplication options');\n const entries = dataEntries(value, 'openApplication options');\n\n for (const [key] of entries) {\n if (key !== 'cleanupFailure' && key !== 'conditions' && key !== 'imports') {\n throw new TypeError('openApplication options requires exact data fields.');\n }\n }\n\n const options = Object.freeze(Object.fromEntries(entries));\n\n if (!hasOwn(options, 'conditions') || !hasOwn(options, 'imports')) {\n throw new TypeError('openApplication options requires exact data fields.');\n }\n\n const cleanupFailure = snapshotCleanupFailure(options);\n const conditions = snapshotConditionRecord(options['conditions']);\n const imports = snapshotArray(options['imports'], 'openApplication imports').map((entry, index) => {\n if (typeof entry !== 'object' || entry === null || !importBindings.has(entry)) {\n throw new TypeError(`openApplication imports[${String(index)}] must come from bind(contract, value).`);\n }\n\n return entry as ApplicationImportBinding;\n });\n\n return Object.freeze({ cleanupFailure, conditions, imports });\n}\n\nexport { bind, snapshotOpenOptions };\nexport type { ApplicationImportBinding, OpenApplicationOptions };\n"],"names":["importBindings","bind","contract","value","binding","snapshotArray","label","snapshotConditionRecord","assertPlainRecord","entries","key","descriptor","snapshotCleanupFailure","options","cleanupFailure","snapshotOpenOptions","dataEntries","hasOwn","conditions","imports","entry","index"],"mappings":"yHAsBA,MAAMA,EAAiB,IAAI,QAI3B,SAASC,EAAKC,EAAmBC,EAAc,CAC7C,MAAMC,EAAU,OAAO,OAAO,CAAE,SAAUF,EAAqC,MAAAC,EAAO,EACtF,OAAAH,EAAe,IAAII,CAAO,EAEnBA,CACT,CAYA,SAASC,EAAcF,EAAgBG,EAAa,CAClD,GAAI,CAAC,MAAM,QAAQH,CAAK,EAAG,MAAM,IAAI,UAAU,GAAGG,CAAK,oBAAoB,EAE3E,OAAO,MAAM,KAAKH,CAA2B,CAC/C,CAGA,SAASI,EAAwBJ,EAAc,CAC7CK,EAAkBL,EAAO,4BAA4B,EACrD,MAAMM,EAAoD,CAAA,EAE1D,UAAWC,KAAO,QAAQ,QAAQP,CAAK,EAAG,CACxC,GAAI,OAAOO,GAAQ,SAAU,MAAM,IAAI,UAAU,4DAA4D,EAE7G,MAAMC,EAAa,OAAO,yBAAyBR,EAAOO,CAAG,EAE7D,IAAIC,GAAA,YAAAA,EAAY,cAAe,IAAQ,EAAE,UAAWA,GAClD,MAAM,IAAI,UAAU,8BAA8BD,CAAG,oCAAoC,EAG3FD,EAAQ,KAAK,CAACC,EAAKC,EAAW,KAA0B,CAAC,CAC3D,CAEA,OAAO,OAAO,OAAO,OAAO,YAAYF,CAAO,CAAC,CAClD,CAGA,SAASG,EAAuBC,EAA0C,CACxE,MAAMC,EAAiBD,EAAQ,gBAAqB,SAEpD,GAAIC,IAAmB,cAAgBA,IAAmB,SACxD,MAAM,IAAI,UAAU,kEAAkE,EAGxF,OAAOA,CACT,CAEA,SAASC,EAAoBZ,EAAc,CACzCK,EAAkBL,EAAO,yBAAyB,EAClD,MAAMM,EAAUO,EAAYb,EAAO,yBAAyB,EAE5D,SAAW,CAACO,CAAG,IAAKD,EAClB,GAAIC,IAAQ,kBAAoBA,IAAQ,cAAgBA,IAAQ,UAC9D,MAAM,IAAI,UAAU,qDAAqD,EAI7E,MAAMG,EAAU,OAAO,OAAO,OAAO,YAAYJ,CAAO,CAAC,EAEzD,GAAI,CAACQ,EAAOJ,EAAS,YAAY,GAAK,CAACI,EAAOJ,EAAS,SAAS,EAC9D,MAAM,IAAI,UAAU,qDAAqD,EAG3E,MAAMC,EAAiBF,EAAuBC,CAAO,EAC/CK,EAAaX,EAAwBM,EAAQ,UAAa,EAC1DM,EAAUd,EAAcQ,EAAQ,QAAY,yBAAyB,EAAE,IAAI,CAACO,EAAOC,IAAS,CAChG,GAAI,OAAOD,GAAU,UAAYA,IAAU,MAAQ,CAACpB,EAAe,IAAIoB,CAAK,EAC1E,MAAM,IAAI,UAAU,2BAA2B,OAAOC,CAAK,CAAC,yCAAyC,EAGvG,OAAOD,CACT,CAAC,EAED,OAAO,OAAO,OAAO,CAAE,eAAAN,EAAgB,WAAAI,EAAY,QAAAC,CAAO,CAAE,CAC9D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DeclarationId } from '@opetope/core';
|
|
2
|
+
import type { AnyFeature } from './feature-authoring.js';
|
|
3
|
+
import type { AnyPort } from './feature-port.js';
|
|
4
|
+
interface ApplicationPortProviderIR {
|
|
5
|
+
readonly definition: AnyFeature;
|
|
6
|
+
readonly featureId: DeclarationId;
|
|
7
|
+
readonly featureIndex: number;
|
|
8
|
+
readonly port: AnyPort;
|
|
9
|
+
readonly portId: DeclarationId;
|
|
10
|
+
readonly providerKey: string;
|
|
11
|
+
}
|
|
12
|
+
interface CompiledApplicationRequirementIR {
|
|
13
|
+
readonly consumerFeatureId: DeclarationId;
|
|
14
|
+
readonly consumerFeatureIndex: number;
|
|
15
|
+
/** `optional(port)`: the application may have no provider, and a call without one settles `unavailable` (D105). */
|
|
16
|
+
readonly optional: boolean;
|
|
17
|
+
readonly port: AnyPort;
|
|
18
|
+
readonly portId: DeclarationId;
|
|
19
|
+
readonly provider: ApplicationPortProviderIR | undefined;
|
|
20
|
+
readonly requirementKey: string;
|
|
21
|
+
}
|
|
22
|
+
type FeatureLifetimeAssertion = (provider: AnyFeature, consumer: AnyFeature, requirementKey: string) => void;
|
|
23
|
+
declare function compileApplicationPorts(features: readonly AnyFeature[], assertLifetime: FeatureLifetimeAssertion): Readonly<{
|
|
24
|
+
providers: readonly ApplicationPortProviderIR[];
|
|
25
|
+
requirements: readonly CompiledApplicationRequirementIR[];
|
|
26
|
+
}>;
|
|
27
|
+
export { compileApplicationPorts };
|
|
28
|
+
export type { ApplicationPortProviderIR, CompiledApplicationRequirementIR };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{requireFeatureRecord as y}from"./feature-definition-support.js";import{getRequiredPort as I,isOptionalPortRequirement as P}from"./feature-port.js";function l(r,t){return r<t?-1:r>t?1:0}function q(r){const t=new Map,o=new Map,c=[];for(const[s,n]of r.entries()){const i=[...y(n).providers].sort((e,p)=>l(e.key,p.key));for(const e of i){const p=o.get(e.port.id);if(p!==void 0)throw new TypeError(`Port ${e.port.id} has duplicate providers ${p.featureId}.${p.providerKey} and ${n.id}.${e.key}.`);const d=Object.freeze({definition:n,featureId:n.id,featureIndex:s,port:e.port,portId:e.port.id,providerKey:e.key});t.set(e.port,d),o.set(e.port.id,d),c.push(d)}}return Object.freeze(c.sort((s,n)=>l(s.portId,n.portId)))}function v(r,t,o,c,s,n){const i=s.get(o);if(i!==void 0)return i;if(n.has(o.id))throw new TypeError(`Feature requirement ${r.id}.${t} uses a different Port identity for ${o.id}.`);if(!c)throw new TypeError(`Feature requirement ${r.id}.${t} has no provider for ${o.id}: add a feature that provides(port, call) to defineApplication features, or require it as optional(port).`)}function $(r,t,o){const c=new Map(t.map(i=>[i.port,i])),s=new Map(t.map(i=>[i.portId,i])),n=[];for(const[i,e]of r.entries()){const p=Object.entries(e.requires??{}).sort(([d],[u])=>l(d,u));for(const[d,u]of p){const f=I(u),a=P(u),m=v(e,d,f,a,c,s);m!==void 0&&!a&&o(m.definition,e,d),n.push(Object.freeze({consumerFeatureId:e.id,consumerFeatureIndex:i,optional:a,port:f,portId:f.id,provider:m,requirementKey:d}))}}return Object.freeze(n)}function b(r,t){const o=q(r);return Object.freeze({providers:o,requirements:$(r,o,t)})}export{b as compileApplicationPorts};
|
|
2
|
+
//# sourceMappingURL=application-port-compiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-port-compiler.js","sources":["../src/application-port-compiler.ts"],"sourcesContent":["import type { DeclarationId } from '@opetope/core';\n\nimport type { AnyFeature } from './feature-authoring';\nimport { requireFeatureRecord } from './feature-definition-support';\nimport { getRequiredPort, isOptionalPortRequirement } from './feature-port';\nimport type { AnyPort } from './feature-port';\n\ninterface ApplicationPortProviderIR {\n readonly definition: AnyFeature;\n readonly featureId: DeclarationId;\n readonly featureIndex: number;\n readonly port: AnyPort;\n readonly portId: DeclarationId;\n readonly providerKey: string;\n}\n\ninterface CompiledApplicationRequirementIR {\n readonly consumerFeatureId: DeclarationId;\n readonly consumerFeatureIndex: number;\n /** `optional(port)`: the application may have no provider, and a call without one settles `unavailable` (D105). */\n readonly optional: boolean;\n readonly port: AnyPort;\n readonly portId: DeclarationId;\n readonly provider: ApplicationPortProviderIR | undefined;\n readonly requirementKey: string;\n}\n\ntype FeatureLifetimeAssertion = (provider: AnyFeature, consumer: AnyFeature, requirementKey: string) => void;\n\nfunction compareIds(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n\nfunction compilePortProviders(features: readonly AnyFeature[]): readonly ApplicationPortProviderIR[] {\n const byPort = new Map<object, ApplicationPortProviderIR>();\n const byPortId = new Map<DeclarationId, ApplicationPortProviderIR>();\n const providers: ApplicationPortProviderIR[] = [];\n\n for (const [featureIndex, definition] of features.entries()) {\n const descriptors = [...requireFeatureRecord(definition).providers].sort((left, right) =>\n compareIds(left.key, right.key),\n );\n\n for (const descriptor of descriptors) {\n const duplicate = byPortId.get(descriptor.port.id);\n\n if (duplicate !== undefined) {\n throw new TypeError(\n `Port ${descriptor.port.id} has duplicate providers ${duplicate.featureId}.${duplicate.providerKey} and ${definition.id}.${descriptor.key}.`,\n );\n }\n\n const provider = Object.freeze({\n definition,\n featureId: definition.id,\n featureIndex,\n port: descriptor.port,\n portId: descriptor.port.id,\n providerKey: descriptor.key,\n });\n byPort.set(descriptor.port, provider);\n byPortId.set(descriptor.port.id, provider);\n providers.push(provider);\n }\n }\n\n return Object.freeze(providers.sort((left, right) => compareIds(left.portId, right.portId)));\n}\n\n/** An `optional(port)` with no provider is a hole in the plan, not an error: only `required(port)` fails (D105). */\nfunction resolveRequirementProvider(\n consumer: AnyFeature,\n requirementKey: string,\n port: AnyPort,\n isOptional: boolean,\n byPort: ReadonlyMap<object, ApplicationPortProviderIR>,\n byPortId: ReadonlyMap<DeclarationId, ApplicationPortProviderIR>,\n): ApplicationPortProviderIR | undefined {\n const provider = byPort.get(port);\n\n if (provider !== undefined) return provider;\n\n if (byPortId.has(port.id)) {\n throw new TypeError(\n `Feature requirement ${consumer.id}.${requirementKey} uses a different Port identity for ${port.id}.`,\n );\n }\n\n if (isOptional) return undefined;\n\n throw new TypeError(\n `Feature requirement ${consumer.id}.${requirementKey} has no provider for ${port.id}: add a feature that ` +\n `provides(port, call) to defineApplication features, or require it as optional(port).`,\n );\n}\n\nfunction compilePortRequirements(\n features: readonly AnyFeature[],\n providers: readonly ApplicationPortProviderIR[],\n assertLifetime: FeatureLifetimeAssertion,\n): readonly CompiledApplicationRequirementIR[] {\n const byPort = new Map(providers.map(provider => [provider.port, provider] as const));\n const byPortId = new Map(providers.map(provider => [provider.portId, provider] as const));\n const requirements: CompiledApplicationRequirementIR[] = [];\n\n for (const [consumerFeatureIndex, consumer] of features.entries()) {\n const declarations = Object.entries(consumer.requires ?? {}).sort(([left], [right]) => compareIds(left, right));\n\n for (const [requirementKey, requirement] of declarations) {\n const port = getRequiredPort(requirement);\n const isOptional = isOptionalPortRequirement(requirement);\n const provider = resolveRequirementProvider(consumer, requirementKey, port, isOptional, byPort, byPortId);\n\n // A weak port is free of the inclusion law: a call without a live provider settles (D105).\n if (provider !== undefined && !isOptional) assertLifetime(provider.definition, consumer, requirementKey);\n\n requirements.push(\n Object.freeze({\n consumerFeatureId: consumer.id,\n consumerFeatureIndex,\n optional: isOptional,\n port,\n portId: port.id,\n provider,\n requirementKey,\n }),\n );\n }\n }\n\n return Object.freeze(requirements);\n}\n\nfunction compileApplicationPorts(\n features: readonly AnyFeature[],\n assertLifetime: FeatureLifetimeAssertion,\n): Readonly<{\n providers: readonly ApplicationPortProviderIR[];\n requirements: readonly CompiledApplicationRequirementIR[];\n}> {\n const providers = compilePortProviders(features);\n\n return Object.freeze({ providers, requirements: compilePortRequirements(features, providers, assertLifetime) });\n}\n\nexport { compileApplicationPorts };\nexport type { ApplicationPortProviderIR, CompiledApplicationRequirementIR };\n"],"names":["compareIds","left","right","compilePortProviders","features","byPort","byPortId","providers","featureIndex","definition","descriptors","requireFeatureRecord","descriptor","duplicate","provider","resolveRequirementProvider","consumer","requirementKey","port","isOptional","compilePortRequirements","assertLifetime","requirements","consumerFeatureIndex","declarations","requirement","getRequiredPort","isOptionalPortRequirement","compileApplicationPorts"],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CallContext, ExactInput } from '@opetope/core/internal';
|
|
2
|
+
import type { LifetimeAttachmentRefIdentity } from './attachment-declaration.js';
|
|
3
|
+
import type { CallOnceOption, CallPolicy, CallSingleFlightOption } from './call-option-snapshot.js';
|
|
4
|
+
declare const attachmentCallRefBrand: unique symbol;
|
|
5
|
+
declare const attachmentCallSignatureBrand: unique symbol;
|
|
6
|
+
interface AttachmentCallOptions<Input, Output> {
|
|
7
|
+
readonly run: (input: Input, context: CallContext) => Output | PromiseLike<Output>;
|
|
8
|
+
readonly within: LifetimeAttachmentRefIdentity;
|
|
9
|
+
}
|
|
10
|
+
interface AttachmentCallRefIdentity {
|
|
11
|
+
readonly [attachmentCallRefBrand]: true;
|
|
12
|
+
}
|
|
13
|
+
interface AttachmentCallRef<Input, Output> extends AttachmentCallRefIdentity {
|
|
14
|
+
readonly [attachmentCallSignatureBrand]: (input: Input) => Output;
|
|
15
|
+
}
|
|
16
|
+
type CompiledAttachmentCallPolicy<Input> = Readonly<{
|
|
17
|
+
lane?: object;
|
|
18
|
+
once?: CallOnceOption<Input>;
|
|
19
|
+
policy: CallPolicy;
|
|
20
|
+
singleFlight?: CallSingleFlightOption<Input>;
|
|
21
|
+
}>;
|
|
22
|
+
interface CompiledAttachmentCallRecipe<Input, Output> {
|
|
23
|
+
readonly nestedFeatureCalls?: true;
|
|
24
|
+
readonly policy?: CompiledAttachmentCallPolicy<Input>;
|
|
25
|
+
readonly run: (input: Input, context: CallContext) => Output | PromiseLike<Output>;
|
|
26
|
+
readonly within: LifetimeAttachmentRefIdentity;
|
|
27
|
+
}
|
|
28
|
+
declare function snapshotAttachmentCallOptions<Input, Output>(options: AttachmentCallOptions<Input, Output>): CompiledAttachmentCallRecipe<Input, Output>;
|
|
29
|
+
/** Package-private C4e lowering recipe; not a frozen feature-authoring API. */
|
|
30
|
+
declare function createAttachmentCall<Input, Output, const Options extends AttachmentCallOptions<Input, Output>>(options: ExactInput<Options, AttachmentCallOptions<Input, Output>>): AttachmentCallRef<Input, Output>;
|
|
31
|
+
declare function isAttachmentCallRef(value: unknown): value is AttachmentCallRefIdentity;
|
|
32
|
+
declare function getAttachmentCallRecipe<Input, Output>(call: AttachmentCallRef<Input, Output>): CompiledAttachmentCallRecipe<Input, Output>;
|
|
33
|
+
declare function invalidateAttachmentCall(call: AttachmentCallRefIdentity): void;
|
|
34
|
+
/**
|
|
35
|
+
* Lowering finishes one freshly created call in one step: policy and nested-call permission are written together, so
|
|
36
|
+
* the ref is proved authentic once instead of once per field (D165).
|
|
37
|
+
*/
|
|
38
|
+
declare function configureAttachmentCall<Input, Output>(call: AttachmentCallRef<Input, Output>, options: {
|
|
39
|
+
readonly nestedFeatureCalls: true;
|
|
40
|
+
readonly policy: CompiledAttachmentCallPolicy<Input>;
|
|
41
|
+
}): void;
|
|
42
|
+
export { configureAttachmentCall, createAttachmentCall, getAttachmentCallRecipe, invalidateAttachmentCall, isAttachmentCallRef, snapshotAttachmentCallOptions, };
|
|
43
|
+
export type { AttachmentCallOptions, AttachmentCallRef, AttachmentCallRefIdentity, CompiledAttachmentCallPolicy, CompiledAttachmentCallRecipe, };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{hasOwn as c}from"@opetope/core/internal";import{isLifetimeAttachmentRef as a}from"./attachment-declaration.js";const r=new WeakMap,i=new Set(["run","within"]);function l(t){const e=Object.getPrototypeOf(t);if(e!==Object.prototype&&e!==null)throw new TypeError("Attachment call options must be a plain object record.");for(const n of Reflect.ownKeys(t))if(!i.has(n))throw new TypeError(`Unknown attachment call option ${String(n)}.`);if(!c(t,"run")||!c(t,"within"))throw new TypeError("Attachment call requires own run and within fields.")}function o(t){if(typeof t!="object"||t===null)throw new TypeError("Attachment call options must be a plain object record.");l(t);const e=t.run,n=t.within;if(typeof e!="function")throw new TypeError("Attachment call run must be a function.");if(!a(n))throw new TypeError("Attachment call within must be an authentic LifetimeAttachmentRef.");return Object.freeze({run:e,within:n})}function f(t){const e=o(t),n=Object.freeze({});return r.set(n,e),n}function h(t){return typeof t=="object"&&t!==null&&r.has(t)}function u(t){const e=r.get(t);if(e===void 0)throw new TypeError("AttachmentCallRef is not authentic.");return e}function s(t){r.delete(t)}function p(t,e){const n=r.get(t);if(n===void 0)throw new TypeError("AttachmentCallRef is not authentic.");r.set(t,Object.freeze({...n,nestedFeatureCalls:e.nestedFeatureCalls,policy:e.policy}))}export{p as configureAttachmentCall,f as createAttachmentCall,u as getAttachmentCallRecipe,s as invalidateAttachmentCall,h as isAttachmentCallRef,o as snapshotAttachmentCallOptions};
|
|
2
|
+
//# sourceMappingURL=attachment-call-declaration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-call-declaration.js","sources":["../src/attachment-call-declaration.ts"],"sourcesContent":["import type { CallContext, ExactInput } from '@opetope/core/internal';\nimport { hasOwn } from '@opetope/core/internal';\n\nimport { isLifetimeAttachmentRef } from './attachment-declaration';\nimport type { LifetimeAttachmentRefIdentity } from './attachment-declaration';\nimport type { CallOnceOption, CallPolicy, CallSingleFlightOption } from './call-option-snapshot';\n\ndeclare const attachmentCallRefBrand: unique symbol;\ndeclare const attachmentCallSignatureBrand: unique symbol;\n\ninterface AttachmentCallOptions<Input, Output> {\n readonly run: (input: Input, context: CallContext) => Output | PromiseLike<Output>;\n readonly within: LifetimeAttachmentRefIdentity;\n}\n\ninterface AttachmentCallRefIdentity {\n readonly [attachmentCallRefBrand]: true;\n}\n\ninterface AttachmentCallRef<Input, Output> extends AttachmentCallRefIdentity {\n readonly [attachmentCallSignatureBrand]: (input: Input) => Output;\n}\n\ntype CompiledAttachmentCallPolicy<Input> = Readonly<{\n lane?: object;\n once?: CallOnceOption<Input>;\n policy: CallPolicy;\n singleFlight?: CallSingleFlightOption<Input>;\n}>;\n\ninterface CompiledAttachmentCallRecipe<Input, Output> {\n readonly nestedFeatureCalls?: true;\n readonly policy?: CompiledAttachmentCallPolicy<Input>;\n readonly run: (input: Input, context: CallContext) => Output | PromiseLike<Output>;\n readonly within: LifetimeAttachmentRefIdentity;\n}\n\nconst callDefinitions = new WeakMap<AttachmentCallRefIdentity, CompiledAttachmentCallRecipe<unknown, unknown>>();\nconst attachmentCallOptionKeys = new Set<PropertyKey>(['run', 'within']);\n\nfunction assertAttachmentCallOptions(options: object): void {\n const prototype: unknown = Object.getPrototypeOf(options);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError('Attachment call options must be a plain object record.');\n }\n\n for (const propertyKey of Reflect.ownKeys(options)) {\n if (!attachmentCallOptionKeys.has(propertyKey)) {\n throw new TypeError(`Unknown attachment call option ${String(propertyKey)}.`);\n }\n }\n\n if (!hasOwn(options, 'run') || !hasOwn(options, 'within')) {\n throw new TypeError('Attachment call requires own run and within fields.');\n }\n}\n\nfunction snapshotAttachmentCallOptions<Input, Output>(\n options: AttachmentCallOptions<Input, Output>,\n): CompiledAttachmentCallRecipe<Input, Output> {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Attachment call options must be a plain object record.');\n }\n\n assertAttachmentCallOptions(options);\n const run = options.run;\n const within = options.within;\n\n if (typeof run !== 'function') throw new TypeError('Attachment call run must be a function.');\n\n if (!isLifetimeAttachmentRef(within)) {\n throw new TypeError('Attachment call within must be an authentic LifetimeAttachmentRef.');\n }\n\n return Object.freeze({ run, within });\n}\n\n/** Package-private C4e lowering recipe; not a frozen feature-authoring API. */\nfunction createAttachmentCall<Input, Output, const Options extends AttachmentCallOptions<Input, Output>>(\n options: ExactInput<Options, AttachmentCallOptions<Input, Output>>,\n): AttachmentCallRef<Input, Output> {\n const recipe = snapshotAttachmentCallOptions(options);\n const call = Object.freeze({}) as AttachmentCallRef<Input, Output>;\n callDefinitions.set(call, recipe as unknown as CompiledAttachmentCallRecipe<unknown, unknown>);\n\n return call;\n}\n\nfunction isAttachmentCallRef(value: unknown): value is AttachmentCallRefIdentity {\n return typeof value === 'object' && value !== null && callDefinitions.has(value as AttachmentCallRefIdentity);\n}\n\nfunction getAttachmentCallRecipe<Input, Output>(\n call: AttachmentCallRef<Input, Output>,\n): CompiledAttachmentCallRecipe<Input, Output> {\n const recipe = callDefinitions.get(call);\n\n if (recipe === undefined) throw new TypeError('AttachmentCallRef is not authentic.');\n\n return recipe as unknown as CompiledAttachmentCallRecipe<Input, Output>;\n}\n\nfunction invalidateAttachmentCall(call: AttachmentCallRefIdentity): void {\n callDefinitions.delete(call);\n}\n\n/**\n * Lowering finishes one freshly created call in one step: policy and nested-call permission are written together, so\n * the ref is proved authentic once instead of once per field (D165).\n */\nfunction configureAttachmentCall<Input, Output>(\n call: AttachmentCallRef<Input, Output>,\n options: { readonly nestedFeatureCalls: true; readonly policy: CompiledAttachmentCallPolicy<Input> },\n): void {\n const recipe = callDefinitions.get(call);\n\n if (recipe === undefined) throw new TypeError('AttachmentCallRef is not authentic.');\n\n callDefinitions.set(\n call,\n Object.freeze({\n ...recipe,\n nestedFeatureCalls: options.nestedFeatureCalls,\n policy: options.policy,\n }) as CompiledAttachmentCallRecipe<unknown, unknown>,\n );\n}\n\nexport {\n configureAttachmentCall,\n createAttachmentCall,\n getAttachmentCallRecipe,\n invalidateAttachmentCall,\n isAttachmentCallRef,\n snapshotAttachmentCallOptions,\n};\nexport type {\n AttachmentCallOptions,\n AttachmentCallRef,\n AttachmentCallRefIdentity,\n CompiledAttachmentCallPolicy,\n CompiledAttachmentCallRecipe,\n};\n"],"names":["callDefinitions","attachmentCallOptionKeys","assertAttachmentCallOptions","options","prototype","propertyKey","hasOwn","snapshotAttachmentCallOptions","run","within","isLifetimeAttachmentRef","createAttachmentCall","recipe","call","isAttachmentCallRef","value","getAttachmentCallRecipe","invalidateAttachmentCall","configureAttachmentCall"],"mappings":"sHAqCA,MAAMA,EAAkB,IAAI,QACtBC,EAA2B,IAAI,IAAiB,CAAC,MAAO,QAAQ,CAAC,EAEvE,SAASC,EAA4BC,EAAe,CAClD,MAAMC,EAAqB,OAAO,eAAeD,CAAO,EAExD,GAAIC,IAAc,OAAO,WAAaA,IAAc,KAClD,MAAM,IAAI,UAAU,wDAAwD,EAG9E,UAAWC,KAAe,QAAQ,QAAQF,CAAO,EAC/C,GAAI,CAACF,EAAyB,IAAII,CAAW,EAC3C,MAAM,IAAI,UAAU,kCAAkC,OAAOA,CAAW,CAAC,GAAG,EAIhF,GAAI,CAACC,EAAOH,EAAS,KAAK,GAAK,CAACG,EAAOH,EAAS,QAAQ,EACtD,MAAM,IAAI,UAAU,qDAAqD,CAE7E,CAEA,SAASI,EACPJ,EAA6C,CAE7C,GAAI,OAAOA,GAAY,UAAYA,IAAY,KAC7C,MAAM,IAAI,UAAU,wDAAwD,EAG9ED,EAA4BC,CAAO,EACnC,MAAMK,EAAML,EAAQ,IACdM,EAASN,EAAQ,OAEvB,GAAI,OAAOK,GAAQ,WAAY,MAAM,IAAI,UAAU,yCAAyC,EAE5F,GAAI,CAACE,EAAwBD,CAAM,EACjC,MAAM,IAAI,UAAU,oEAAoE,EAG1F,OAAO,OAAO,OAAO,CAAE,IAAAD,EAAK,OAAAC,CAAM,CAAE,CACtC,CAGA,SAASE,EACPR,EAAkE,CAElE,MAAMS,EAASL,EAA8BJ,CAAO,EAC9CU,EAAO,OAAO,OAAO,EAAE,EAC7B,OAAAb,EAAgB,IAAIa,EAAMD,CAAmE,EAEtFC,CACT,CAEA,SAASC,EAAoBC,EAAc,CACzC,OAAO,OAAOA,GAAU,UAAYA,IAAU,MAAQf,EAAgB,IAAIe,CAAkC,CAC9G,CAEA,SAASC,EACPH,EAAsC,CAEtC,MAAMD,EAASZ,EAAgB,IAAIa,CAAI,EAEvC,GAAID,IAAW,OAAW,MAAM,IAAI,UAAU,qCAAqC,EAEnF,OAAOA,CACT,CAEA,SAASK,EAAyBJ,EAA+B,CAC/Db,EAAgB,OAAOa,CAAI,CAC7B,CAMA,SAASK,EACPL,EACAV,EAAoG,CAEpG,MAAMS,EAASZ,EAAgB,IAAIa,CAAI,EAEvC,GAAID,IAAW,OAAW,MAAM,IAAI,UAAU,qCAAqC,EAEnFZ,EAAgB,IACda,EACA,OAAO,OAAO,CACZ,GAAGD,EACH,mBAAoBT,EAAQ,mBAC5B,OAAQA,EAAQ,MACjB,CAAA,CAAmD,CAExD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Call } from '@opetope/core';
|
|
2
|
+
import type { Awaitable, ExactInput, ExactVoidResult } from '@opetope/core/internal';
|
|
3
|
+
type AttachmentReadinessPolicy = 'critical' | 'deferred';
|
|
4
|
+
declare const attachmentRefValueBrand: unique symbol;
|
|
5
|
+
declare const scopeBlueprintValueBrand: unique symbol;
|
|
6
|
+
declare const lifetimeAttachmentRefBrand: unique symbol;
|
|
7
|
+
declare const scopeBlueprintBrand: unique symbol;
|
|
8
|
+
type LiteralStepKey<Key extends string> = Key extends '' ? never : string extends Key ? never : Key;
|
|
9
|
+
interface AttachmentExecutionContext {
|
|
10
|
+
readonly invoke: <Input, Output>(target: Call<Input, Output>, input: Input) => Promise<Output>;
|
|
11
|
+
readonly signal: AbortSignal;
|
|
12
|
+
readonly throwIfAborted: () => void;
|
|
13
|
+
}
|
|
14
|
+
interface AttachmentStepContext {
|
|
15
|
+
readonly context: AttachmentExecutionContext;
|
|
16
|
+
}
|
|
17
|
+
interface AttachmentOwnedStep<Key extends string, Result, CleanupResult> {
|
|
18
|
+
readonly cleanup: (input: AttachmentStepContext) => CleanupResult;
|
|
19
|
+
readonly key: Key & LiteralStepKey<Key>;
|
|
20
|
+
readonly run: (input: AttachmentStepContext) => Awaitable<Result>;
|
|
21
|
+
}
|
|
22
|
+
interface AttachmentOwner {
|
|
23
|
+
readonly step: <const Key extends string, Result, CleanupResult extends Awaitable<void>, const Definition extends AttachmentOwnedStep<Key, Result, CleanupResult>>(definition: ExactInput<Definition, AttachmentOwnedStep<Key, Result, CleanupResult>> & ExactVoidResult<CleanupResult>) => Promise<Result>;
|
|
24
|
+
}
|
|
25
|
+
interface AttachmentOpenContext<Value> {
|
|
26
|
+
readonly source: Value;
|
|
27
|
+
/** Owned step: the word `own` names the section, so the attachment context spells the member itself (D94). */
|
|
28
|
+
readonly step: AttachmentOwner['step'];
|
|
29
|
+
}
|
|
30
|
+
interface AttachmentCloseContext {
|
|
31
|
+
readonly context: AttachmentExecutionContext;
|
|
32
|
+
}
|
|
33
|
+
interface LifetimeAttachmentOptions<Value, OpenResult extends Awaitable<void> = Awaitable<void>, CloseResult extends Awaitable<void> = Awaitable<void>> {
|
|
34
|
+
readonly close: (input: AttachmentCloseContext) => CloseResult;
|
|
35
|
+
readonly open: (input: AttachmentOpenContext<Value>) => OpenResult;
|
|
36
|
+
readonly readiness?: AttachmentReadinessPolicy;
|
|
37
|
+
}
|
|
38
|
+
interface LifetimeAttachmentRefIdentity {
|
|
39
|
+
readonly [lifetimeAttachmentRefBrand]: true;
|
|
40
|
+
}
|
|
41
|
+
interface LifetimeAttachmentRef<Value> extends LifetimeAttachmentRefIdentity {
|
|
42
|
+
readonly [attachmentRefValueBrand]: (_value: Value) => Value;
|
|
43
|
+
}
|
|
44
|
+
interface ScopeBlueprintIdentity {
|
|
45
|
+
readonly [scopeBlueprintBrand]: true;
|
|
46
|
+
}
|
|
47
|
+
interface ScopeBlueprint<Value> extends ScopeBlueprintIdentity {
|
|
48
|
+
readonly attach: <OpenResult extends Awaitable<void>, CloseResult extends Awaitable<void>, const Options extends LifetimeAttachmentOptions<Value, OpenResult, CloseResult>>(options: ExactInput<Options, LifetimeAttachmentOptions<Value, OpenResult, CloseResult>> & ExactVoidResult<CloseResult> & ExactVoidResult<OpenResult>) => LifetimeAttachmentRef<Value>;
|
|
49
|
+
readonly [scopeBlueprintValueBrand]: (_value: Value) => Value;
|
|
50
|
+
}
|
|
51
|
+
interface CompiledLifetimeAttachmentRecipe<Value> {
|
|
52
|
+
readonly close: (input: AttachmentCloseContext) => Awaitable<void>;
|
|
53
|
+
readonly open: (input: AttachmentOpenContext<Value>) => Awaitable<void>;
|
|
54
|
+
readonly readiness: AttachmentReadinessPolicy;
|
|
55
|
+
}
|
|
56
|
+
type LifetimeAttachmentDefinition<Value> = {
|
|
57
|
+
readonly owner: ScopeBlueprintIdentity;
|
|
58
|
+
readonly recipe: CompiledLifetimeAttachmentRecipe<Value>;
|
|
59
|
+
};
|
|
60
|
+
declare function isLifetimeAttachmentRef(value: unknown): value is LifetimeAttachmentRefIdentity;
|
|
61
|
+
declare function createScopeBlueprint<Value>(): ScopeBlueprint<Value>;
|
|
62
|
+
declare function sealScopeBlueprint(scope: ScopeBlueprintIdentity): void;
|
|
63
|
+
declare function invalidateScopeBlueprint(scope: ScopeBlueprintIdentity): void;
|
|
64
|
+
declare function isScopeBlueprint(value: unknown): value is ScopeBlueprintIdentity;
|
|
65
|
+
declare function getScopeAttachmentRefs(scope: ScopeBlueprintIdentity): readonly LifetimeAttachmentRefIdentity[];
|
|
66
|
+
declare function getAttachmentDefinition<Value = unknown>(attachment: LifetimeAttachmentRefIdentity): LifetimeAttachmentDefinition<Value>;
|
|
67
|
+
export { createScopeBlueprint, getAttachmentDefinition, getScopeAttachmentRefs, invalidateScopeBlueprint, isLifetimeAttachmentRef, isScopeBlueprint, sealScopeBlueprint, };
|
|
68
|
+
export type { AttachmentCloseContext, AttachmentExecutionContext, AttachmentOpenContext, AttachmentOwnedStep, AttachmentOwner, AttachmentReadinessPolicy, AttachmentStepContext, Awaitable, CompiledLifetimeAttachmentRecipe, LifetimeAttachmentOptions, LifetimeAttachmentRef, LifetimeAttachmentRefIdentity, ScopeBlueprint, ScopeBlueprintIdentity, };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{hasOwn as a}from"@opetope/core/internal";const r=new WeakMap,c=new WeakMap,f=new Set(["close","open","readiness"]);function p(e){return typeof e=="object"&&e!==null&&c.has(e)}function l(e){const t=Object.getPrototypeOf(e);if(t!==Object.prototype&&t!==null)throw new TypeError("scope.attach options must be a plain object record.");for(const n of Reflect.ownKeys(e))if(!f.has(n))throw new TypeError(`Unknown scope.attach option ${String(n)}.`);if(!a(e,"close")||!a(e,"open"))throw new TypeError("scope.attach requires own open and close callbacks.")}function u(e){l(e);const t=e.close,n=e.open,o=e.readiness??"critical";if(typeof t!="function"||typeof n!="function")throw new TypeError("scope.attach requires open and close callbacks.");if(o!=="critical"&&o!=="deferred")throw new TypeError(`Unknown scope.attach readiness policy ${String(o)}.`);return Object.freeze({close:t,open:n,readiness:o})}function h(){const e={attachments:[],invalidated:!1,sealed:!1},t={},n=o=>{if(e.invalidated)throw new TypeError("ScopeBlueprint belongs to an aborted transaction.");if(e.sealed)throw new TypeError("ScopeBlueprint is sealed after successful compilation.");if(typeof o!="object"||o===null)throw new TypeError("scope.attach options must be a plain object record.");const s=u(o),i=Object.freeze({});return e.attachments.push(i),c.set(i,Object.freeze({owner:t,recipe:s})),i};return t.attach=n,Object.freeze(t),r.set(t,e),t}function d(e){const t=r.get(e);if(t===void 0)throw new TypeError("ScopeBlueprint is not authentic.");Object.freeze(t.attachments),t.sealed=!0}function w(e){const t=r.get(e);t!==void 0&&(t.invalidated=!0,t.sealed=!0,Object.freeze(t.attachments),r.delete(e),t.attachments.forEach(n=>c.delete(n)))}function y(e){return typeof e=="object"&&e!==null&&r.has(e)}function m(e){const t=r.get(e);if(t===void 0)throw new TypeError("ScopeBlueprint is not authentic.");return t.attachments}function b(e){const t=c.get(e);if(t===void 0)throw new TypeError("LifetimeAttachmentRef is not authentic.");return t}export{h as createScopeBlueprint,b as getAttachmentDefinition,m as getScopeAttachmentRefs,w as invalidateScopeBlueprint,p as isLifetimeAttachmentRef,y as isScopeBlueprint,d as sealScopeBlueprint};
|
|
2
|
+
//# sourceMappingURL=attachment-declaration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-declaration.js","sources":["../src/attachment-declaration.ts"],"sourcesContent":["import type { Call } from '@opetope/core';\nimport type { Awaitable, ExactInput, ExactVoidResult } from '@opetope/core/internal';\nimport { hasOwn } from '@opetope/core/internal';\n\ntype AttachmentReadinessPolicy = 'critical' | 'deferred';\n\ndeclare const attachmentRefValueBrand: unique symbol;\ndeclare const scopeBlueprintValueBrand: unique symbol;\ndeclare const lifetimeAttachmentRefBrand: unique symbol;\ndeclare const scopeBlueprintBrand: unique symbol;\n\ntype LiteralStepKey<Key extends string> = Key extends '' ? never : string extends Key ? never : Key;\n\ninterface AttachmentExecutionContext {\n readonly invoke: <Input, Output>(target: Call<Input, Output>, input: Input) => Promise<Output>;\n readonly signal: AbortSignal;\n readonly throwIfAborted: () => void;\n}\n\ninterface AttachmentStepContext {\n readonly context: AttachmentExecutionContext;\n}\n\ninterface AttachmentOwnedStep<Key extends string, Result, CleanupResult> {\n readonly cleanup: (input: AttachmentStepContext) => CleanupResult;\n readonly key: Key & LiteralStepKey<Key>;\n readonly run: (input: AttachmentStepContext) => Awaitable<Result>;\n}\n\ninterface AttachmentOwner {\n readonly step: <\n const Key extends string,\n Result,\n CleanupResult extends Awaitable<void>,\n const Definition extends AttachmentOwnedStep<Key, Result, CleanupResult>,\n >(\n definition: ExactInput<Definition, AttachmentOwnedStep<Key, Result, CleanupResult>> &\n ExactVoidResult<CleanupResult>,\n ) => Promise<Result>;\n}\n\ninterface AttachmentOpenContext<Value> {\n readonly source: Value;\n /** Owned step: the word `own` names the section, so the attachment context spells the member itself (D94). */\n readonly step: AttachmentOwner['step'];\n}\n\ninterface AttachmentCloseContext {\n readonly context: AttachmentExecutionContext;\n}\n\ninterface LifetimeAttachmentOptions<\n Value,\n OpenResult extends Awaitable<void> = Awaitable<void>,\n CloseResult extends Awaitable<void> = Awaitable<void>,\n> {\n readonly close: (input: AttachmentCloseContext) => CloseResult;\n readonly open: (input: AttachmentOpenContext<Value>) => OpenResult;\n readonly readiness?: AttachmentReadinessPolicy;\n}\n\ninterface LifetimeAttachmentRefIdentity {\n readonly [lifetimeAttachmentRefBrand]: true;\n}\n\ninterface LifetimeAttachmentRef<Value> extends LifetimeAttachmentRefIdentity {\n readonly [attachmentRefValueBrand]: (_value: Value) => Value;\n}\n\ninterface ScopeBlueprintIdentity {\n readonly [scopeBlueprintBrand]: true;\n}\n\ninterface ScopeBlueprint<Value> extends ScopeBlueprintIdentity {\n readonly attach: <\n OpenResult extends Awaitable<void>,\n CloseResult extends Awaitable<void>,\n const Options extends LifetimeAttachmentOptions<Value, OpenResult, CloseResult>,\n >(\n options: ExactInput<Options, LifetimeAttachmentOptions<Value, OpenResult, CloseResult>> &\n ExactVoidResult<CloseResult> &\n ExactVoidResult<OpenResult>,\n ) => LifetimeAttachmentRef<Value>;\n readonly [scopeBlueprintValueBrand]: (_value: Value) => Value;\n}\n\ninterface CompiledLifetimeAttachmentRecipe<Value> {\n readonly close: (input: AttachmentCloseContext) => Awaitable<void>;\n readonly open: (input: AttachmentOpenContext<Value>) => Awaitable<void>;\n readonly readiness: AttachmentReadinessPolicy;\n}\n\ntype ScopeBlueprintDefinition = {\n readonly attachments: LifetimeAttachmentRefIdentity[];\n invalidated: boolean;\n sealed: boolean;\n};\ntype MutableScopeBlueprint<Value> = {\n -readonly [Key in keyof ScopeBlueprint<Value>]: ScopeBlueprint<Value>[Key];\n};\n\ntype LifetimeAttachmentDefinition<Value> = {\n readonly owner: ScopeBlueprintIdentity;\n readonly recipe: CompiledLifetimeAttachmentRecipe<Value>;\n};\n\nconst scopeDefinitions = new WeakMap<ScopeBlueprintIdentity, ScopeBlueprintDefinition>();\nconst attachmentDefinitions = new WeakMap<LifetimeAttachmentRefIdentity, LifetimeAttachmentDefinition<unknown>>();\nconst attachmentOptionKeys = new Set<PropertyKey>(['close', 'open', 'readiness']);\n\nfunction isLifetimeAttachmentRef(value: unknown): value is LifetimeAttachmentRefIdentity {\n return (\n typeof value === 'object' && value !== null && attachmentDefinitions.has(value as LifetimeAttachmentRefIdentity)\n );\n}\n\nfunction assertKnownAttachmentOptions(options: object): void {\n const prototype: unknown = Object.getPrototypeOf(options);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError('scope.attach options must be a plain object record.');\n }\n\n for (const key of Reflect.ownKeys(options)) {\n if (!attachmentOptionKeys.has(key)) {\n throw new TypeError(`Unknown scope.attach option ${String(key)}.`);\n }\n }\n\n if (!hasOwn(options, 'close') || !hasOwn(options, 'open')) {\n throw new TypeError('scope.attach requires own open and close callbacks.');\n }\n}\n\nfunction readAttachmentRecipe<Value>(\n options: LifetimeAttachmentOptions<Value>,\n): CompiledLifetimeAttachmentRecipe<Value> {\n assertKnownAttachmentOptions(options);\n const close = options.close;\n const open = options.open;\n const readiness = options.readiness ?? 'critical';\n\n if (typeof close !== 'function' || typeof open !== 'function') {\n throw new TypeError('scope.attach requires open and close callbacks.');\n }\n\n if (readiness !== 'critical' && readiness !== 'deferred') {\n throw new TypeError(`Unknown scope.attach readiness policy ${String(readiness)}.`);\n }\n\n return Object.freeze({ close, open, readiness });\n}\n\nfunction createScopeBlueprint<Value>(): ScopeBlueprint<Value> {\n const definition: ScopeBlueprintDefinition = { attachments: [], invalidated: false, sealed: false };\n const scope = {} as MutableScopeBlueprint<Value>;\n const attach: ScopeBlueprint<Value>['attach'] = options => {\n if (definition.invalidated) throw new TypeError('ScopeBlueprint belongs to an aborted transaction.');\n\n if (definition.sealed) throw new TypeError('ScopeBlueprint is sealed after successful compilation.');\n\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('scope.attach options must be a plain object record.');\n }\n\n const recipe = readAttachmentRecipe(options);\n const attachment = Object.freeze({}) as LifetimeAttachmentRef<Value>;\n definition.attachments.push(attachment);\n attachmentDefinitions.set(\n attachment,\n Object.freeze({ owner: scope, recipe }) as LifetimeAttachmentDefinition<unknown>,\n );\n\n return attachment;\n };\n scope.attach = attach;\n Object.freeze(scope);\n scopeDefinitions.set(scope, definition);\n\n return scope;\n}\n\nfunction sealScopeBlueprint(scope: ScopeBlueprintIdentity): void {\n const definition = scopeDefinitions.get(scope);\n\n if (definition === undefined) throw new TypeError('ScopeBlueprint is not authentic.');\n\n Object.freeze(definition.attachments);\n definition.sealed = true;\n}\n\nfunction invalidateScopeBlueprint(scope: ScopeBlueprintIdentity): void {\n const definition = scopeDefinitions.get(scope);\n\n if (definition === undefined) return;\n\n definition.invalidated = true;\n definition.sealed = true;\n Object.freeze(definition.attachments);\n scopeDefinitions.delete(scope);\n definition.attachments.forEach(attachment => attachmentDefinitions.delete(attachment));\n}\n\nfunction isScopeBlueprint(value: unknown): value is ScopeBlueprintIdentity {\n return typeof value === 'object' && value !== null && scopeDefinitions.has(value as ScopeBlueprintIdentity);\n}\n\nfunction getScopeAttachmentRefs(scope: ScopeBlueprintIdentity): readonly LifetimeAttachmentRefIdentity[] {\n const definition = scopeDefinitions.get(scope);\n\n if (definition === undefined) throw new TypeError('ScopeBlueprint is not authentic.');\n\n return definition.attachments;\n}\n\nfunction getAttachmentDefinition<Value = unknown>(\n attachment: LifetimeAttachmentRefIdentity,\n): LifetimeAttachmentDefinition<Value> {\n const definition = attachmentDefinitions.get(attachment);\n\n if (definition === undefined) throw new TypeError('LifetimeAttachmentRef is not authentic.');\n\n return definition;\n}\n\nexport {\n createScopeBlueprint,\n getAttachmentDefinition,\n getScopeAttachmentRefs,\n invalidateScopeBlueprint,\n isLifetimeAttachmentRef,\n isScopeBlueprint,\n sealScopeBlueprint,\n};\nexport type {\n AttachmentCloseContext,\n AttachmentExecutionContext,\n AttachmentOpenContext,\n AttachmentOwnedStep,\n AttachmentOwner,\n AttachmentReadinessPolicy,\n AttachmentStepContext,\n Awaitable,\n CompiledLifetimeAttachmentRecipe,\n LifetimeAttachmentOptions,\n LifetimeAttachmentRef,\n LifetimeAttachmentRefIdentity,\n ScopeBlueprint,\n ScopeBlueprintIdentity,\n};\n"],"names":["scopeDefinitions","attachmentDefinitions","attachmentOptionKeys","isLifetimeAttachmentRef","value","assertKnownAttachmentOptions","options","prototype","key","hasOwn","readAttachmentRecipe","close","open","readiness","createScopeBlueprint","definition","scope","attach","recipe","attachment","sealScopeBlueprint","invalidateScopeBlueprint","isScopeBlueprint","getScopeAttachmentRefs","getAttachmentDefinition"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AttachmentOpenContext as CoreAttachmentOpenContext } from '@opetope/core/internal';
|
|
2
|
+
import type { AttachmentExecutionContext, CompiledLifetimeAttachmentRecipe } from './attachment-declaration.js';
|
|
3
|
+
type AttachmentCallbackInvoker = <Result>(callback: () => Result) => Result;
|
|
4
|
+
type AttachmentErrorReporter = (error: unknown) => PromiseLike<void> | void;
|
|
5
|
+
declare function invokeAttachmentOpen<Value>(recipe: CompiledLifetimeAttachmentRecipe<Value>, coreContext: CoreAttachmentOpenContext<Value>, invoke: AttachmentCallbackInvoker, reporter: AttachmentErrorReporter | undefined, beforeCleanup: () => Promise<void>): Promise<void>;
|
|
6
|
+
declare function invokeAttachmentClose<Value>(recipe: CompiledLifetimeAttachmentRecipe<Value>, signal: AbortSignal, value: Value, invoke: AttachmentCallbackInvoker, reporter: AttachmentErrorReporter | undefined): Promise<void>;
|
|
7
|
+
declare function getAttachmentErrorReporter(context: AttachmentExecutionContext): AttachmentErrorReporter | undefined;
|
|
8
|
+
export { getAttachmentErrorReporter, invokeAttachmentClose, invokeAttachmentOpen };
|
|
9
|
+
export type { AttachmentCallbackInvoker, AttachmentErrorReporter };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{throwIfSignalAborted as i,settleGuardedResult as w,invokeCallTargetWithGuard as m,hasOwn as p}from"@opetope/core/internal";const d=new Set(["cleanup","key","run"]),f=new WeakMap;function b(e){if(typeof e!="object"||e===null)throw new TypeError("Attachment owned step must be a plain object record.");const t=Object.getPrototypeOf(e);if(t!==Object.prototype&&t!==null)throw new TypeError("Attachment owned step must be a plain object record.")}function A(e){for(const t of Reflect.ownKeys(e))if(!d.has(t))throw new TypeError(`Unknown attachment owned-step option ${String(t)}.`);if(!p(e,"cleanup")||!p(e,"key")||!p(e,"run"))throw new TypeError("Attachment owned step requires own cleanup, key and run fields.")}function k(e,t){let r=!0;const c=new TypeError("Attachment execution context is no longer active."),o=()=>{if(!r)throw c;i(e)},n=Object.freeze({invoke(u,s){try{o();const a=m(u,s,Object.freeze({signal:e}),o);return Promise.resolve(a)}catch(a){return Promise.reject(a)}},signal:e,throwIfAborted:o});return t!==void 0&&f.set(n,t),Object.freeze({assertActive:o,context:n,retire(){r&&(r=!1)}})}function y(e,t,r,c,o){const n=k(e,o);let u;try{n.assertActive(),u=c(()=>t(r(n.context)))}catch(s){let a=s;try{n.assertActive()}catch(l){a=l}return n.retire(),Promise.reject(a)}try{return Promise.resolve(w(u,{assertCurrent:n.assertActive,finalize:n.retire,waitForPhysicalSettlement:!0}))}catch(s){return n.retire(),Promise.reject(s)}}async function h(e,t,r,c,o){if(await y(e,t,r,c,o)!==void 0)throw new TypeError("Attachment callbacks must resolve to undefined.")}function v(e){b(e),A(e);const t=e.cleanup,r=e.key,c=e.run;if(typeof r!="string"||r.length===0)throw new TypeError("Attachment owned-step key must be non-empty.");if(typeof t!="function"||typeof c!="function")throw new TypeError(`Attachment owned step ${r} requires run and cleanup callbacks.`);return{cleanup:t,id:`own:${r}`,run:c}}function j(e,t,r,c){const{signal:o}=e;return Object.freeze({step:u=>{try{i(o);const s=v(u);return e.step({cleanup:async a=>(await c(),h(a.signal,s.cleanup,l=>({context:l}),t,r)),id:s.id,run:()=>y(o,s.run,a=>({context:a}),t,r)})}catch(s){return Promise.reject(s)}}})}async function O(e,t,r,c,o){const n=j(t,r,c,o);let u;try{i(t.signal),u=r(()=>e.open(Object.freeze({source:t.value,step:n.step})))}catch(a){throw i(t.signal),a}if(await w(u,{assertCurrent:()=>i(t.signal),waitForPhysicalSettlement:!0})!==void 0)throw new TypeError("Attachment callbacks must resolve to undefined.")}function E(e,t,r,c,o){return h(t,e.close,n=>Object.freeze({context:n,source:r}),c,o)}function g(e){return f.get(e)}export{g as getAttachmentErrorReporter,E as invokeAttachmentClose,O as invokeAttachmentOpen};
|
|
2
|
+
//# sourceMappingURL=attachment-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-execution.js","sources":["../src/attachment-execution.ts"],"sourcesContent":["import type { Call } from '@opetope/core';\nimport { hasOwn, invokeCallTargetWithGuard, settleGuardedResult, throwIfSignalAborted } from '@opetope/core/internal';\nimport type { AttachmentOpenContext as CoreAttachmentOpenContext } from '@opetope/core/internal';\n\nimport type {\n AttachmentExecutionContext,\n AttachmentOpenContext,\n AttachmentOwner,\n AttachmentStepContext,\n Awaitable,\n CompiledLifetimeAttachmentRecipe,\n} from './attachment-declaration';\ntype VoidCallback<Input> = (input: Input) => Awaitable<void>;\ntype AttachmentCallbackInvoker = <Result>(callback: () => Result) => Result;\ntype AttachmentErrorReporter = (error: unknown) => PromiseLike<void> | void;\ntype RuntimeOwnedStep<Key extends string, Result, CleanupResult> = {\n readonly cleanup: (input: AttachmentStepContext) => CleanupResult;\n readonly key: Key;\n readonly run: (input: AttachmentStepContext) => Awaitable<Result>;\n};\nconst ownedStepKeys = new Set<PropertyKey>(['cleanup', 'key', 'run']);\nconst executionContextReporters = new WeakMap<object, AttachmentErrorReporter>();\n\nfunction assertPlainOwnedStep(definition: unknown): asserts definition is object {\n if (typeof definition !== 'object' || definition === null) {\n throw new TypeError('Attachment owned step must be a plain object record.');\n }\n\n const prototype: unknown = Object.getPrototypeOf(definition);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError('Attachment owned step must be a plain object record.');\n }\n}\n\nfunction assertExactOwnedStepFields(definition: object): void {\n for (const propertyKey of Reflect.ownKeys(definition)) {\n if (!ownedStepKeys.has(propertyKey)) {\n throw new TypeError(`Unknown attachment owned-step option ${String(propertyKey)}.`);\n }\n }\n\n if (!hasOwn(definition, 'cleanup') || !hasOwn(definition, 'key') || !hasOwn(definition, 'run')) {\n throw new TypeError('Attachment owned step requires own cleanup, key and run fields.');\n }\n}\n\nfunction createExecutionContext(\n signal: AbortSignal,\n reporter: AttachmentErrorReporter | undefined,\n): {\n readonly assertActive: () => void;\n readonly context: AttachmentExecutionContext;\n readonly retire: () => void;\n} {\n let active = true;\n const retiredReason = new TypeError('Attachment execution context is no longer active.');\n const assertActive = (): void => {\n if (!active) throw retiredReason;\n\n throwIfSignalAborted(signal);\n };\n const context = Object.freeze({\n invoke<Input, Output>(target: Call<Input, Output>, input: Input): Promise<Output> {\n try {\n assertActive();\n const invocation = invokeCallTargetWithGuard(target, input, Object.freeze({ signal }), assertActive);\n\n return Promise.resolve(invocation);\n } catch (error) {\n return Promise.reject(error);\n }\n },\n signal,\n throwIfAborted: assertActive,\n });\n\n if (reporter !== undefined) executionContextReporters.set(context, reporter);\n\n return Object.freeze({\n assertActive,\n context,\n retire(): void {\n if (!active) return;\n\n active = false;\n },\n });\n}\n\nfunction invokeCallback<Input, Output>(\n signal: AbortSignal,\n callback: (input: Input) => Awaitable<Output>,\n input: (context: AttachmentExecutionContext) => Input,\n invoke: AttachmentCallbackInvoker,\n reporter: AttachmentErrorReporter | undefined,\n): Promise<Output> {\n const execution = createExecutionContext(signal, reporter);\n let result: Awaitable<Output>;\n\n try {\n execution.assertActive();\n result = invoke(() => callback(input(execution.context)));\n } catch (error) {\n let rejection = error;\n\n try {\n execution.assertActive();\n } catch (currentError) {\n rejection = currentError;\n }\n\n execution.retire();\n\n return Promise.reject(rejection);\n }\n\n try {\n return Promise.resolve(\n settleGuardedResult(result, {\n assertCurrent: execution.assertActive,\n finalize: execution.retire,\n waitForPhysicalSettlement: true,\n }),\n );\n } catch (error) {\n execution.retire();\n\n return Promise.reject(error);\n }\n}\n\nasync function invokeVoidCallback<Input>(\n signal: AbortSignal,\n callback: VoidCallback<Input>,\n input: (context: AttachmentExecutionContext) => Input,\n invoke: AttachmentCallbackInvoker,\n reporter: AttachmentErrorReporter | undefined,\n): Promise<void> {\n const result = await invokeCallback(signal, callback, input, invoke, reporter);\n\n if (result !== undefined) throw new TypeError('Attachment callbacks must resolve to undefined.');\n}\n\nfunction readOwnedStep<const Key extends string, Result, CleanupResult>(\n definition: RuntimeOwnedStep<Key, Result, CleanupResult>,\n): {\n readonly cleanup: VoidCallback<AttachmentStepContext>;\n readonly id: string;\n readonly run: (input: AttachmentStepContext) => Awaitable<Result>;\n} {\n assertPlainOwnedStep(definition);\n assertExactOwnedStepFields(definition);\n\n const cleanup = definition.cleanup;\n const key = definition.key;\n const run = definition.run;\n\n if (typeof key !== 'string' || key.length === 0) throw new TypeError('Attachment owned-step key must be non-empty.');\n\n if (typeof cleanup !== 'function' || typeof run !== 'function') {\n throw new TypeError(`Attachment owned step ${key} requires run and cleanup callbacks.`);\n }\n\n return { cleanup: cleanup as VoidCallback<AttachmentStepContext>, id: `own:${key}`, run };\n}\n\nfunction createAttachmentOwner<Value>(\n coreContext: CoreAttachmentOpenContext<Value>,\n invoke: AttachmentCallbackInvoker,\n reporter: AttachmentErrorReporter | undefined,\n beforeCleanup: () => Promise<void>,\n): AttachmentOwner {\n const { signal } = coreContext;\n const step: AttachmentOwner['step'] = definition => {\n try {\n throwIfSignalAborted(signal);\n const step = readOwnedStep(definition);\n\n return coreContext.step({\n cleanup: async context => {\n await beforeCleanup();\n\n return invokeVoidCallback(\n context.signal,\n step.cleanup,\n executionContext => ({ context: executionContext }),\n invoke,\n reporter,\n );\n },\n id: step.id,\n run: () =>\n invokeCallback(signal, step.run, executionContext => ({ context: executionContext }), invoke, reporter),\n });\n } catch (error) {\n return Promise.reject(error);\n }\n };\n\n return Object.freeze({ step });\n}\n\nasync function invokeAttachmentOpen<Value>(\n recipe: CompiledLifetimeAttachmentRecipe<Value>,\n coreContext: CoreAttachmentOpenContext<Value>,\n invoke: AttachmentCallbackInvoker,\n reporter: AttachmentErrorReporter | undefined,\n beforeCleanup: () => Promise<void>,\n): Promise<void> {\n const owner = createAttachmentOwner(coreContext, invoke, reporter, beforeCleanup);\n let invocation: Awaitable<void>;\n\n try {\n throwIfSignalAborted(coreContext.signal);\n invocation = invoke(() =>\n recipe.open(\n Object.freeze({ source: coreContext.value, step: owner.step } satisfies AttachmentOpenContext<Value>),\n ),\n );\n } catch (error) {\n throwIfSignalAborted(coreContext.signal);\n throw error;\n }\n\n const result = await settleGuardedResult(invocation, {\n assertCurrent: () => throwIfSignalAborted(coreContext.signal),\n waitForPhysicalSettlement: true,\n });\n\n if (result !== undefined) throw new TypeError('Attachment callbacks must resolve to undefined.');\n}\n\nfunction invokeAttachmentClose<Value>(\n recipe: CompiledLifetimeAttachmentRecipe<Value>,\n signal: AbortSignal,\n value: Value,\n invoke: AttachmentCallbackInvoker,\n reporter: AttachmentErrorReporter | undefined,\n): Promise<void> {\n return invokeVoidCallback(\n signal,\n recipe.close,\n context => Object.freeze({ context, source: value }),\n invoke,\n reporter,\n );\n}\n\nfunction getAttachmentErrorReporter(context: AttachmentExecutionContext): AttachmentErrorReporter | undefined {\n return executionContextReporters.get(context);\n}\n\nexport { getAttachmentErrorReporter, invokeAttachmentClose, invokeAttachmentOpen };\nexport type { AttachmentCallbackInvoker, AttachmentErrorReporter };\n"],"names":["ownedStepKeys","executionContextReporters","assertPlainOwnedStep","definition","prototype","assertExactOwnedStepFields","propertyKey","hasOwn","createExecutionContext","signal","reporter","active","retiredReason","assertActive","throwIfSignalAborted","context","target","input","invocation","invokeCallTargetWithGuard","error","invokeCallback","callback","invoke","execution","result","rejection","currentError","settleGuardedResult","invokeVoidCallback","readOwnedStep","cleanup","key","run","createAttachmentOwner","coreContext","beforeCleanup","step","executionContext","invokeAttachmentOpen","recipe","owner","invokeAttachmentClose","value","getAttachmentErrorReporter"],"mappings":"kIAoBA,MAAMA,EAAgB,IAAI,IAAiB,CAAC,UAAW,MAAO,KAAK,CAAC,EAC9DC,EAA4B,IAAI,QAEtC,SAASC,EAAqBC,EAAmB,CAC/C,GAAI,OAAOA,GAAe,UAAYA,IAAe,KACnD,MAAM,IAAI,UAAU,sDAAsD,EAG5E,MAAMC,EAAqB,OAAO,eAAeD,CAAU,EAE3D,GAAIC,IAAc,OAAO,WAAaA,IAAc,KAClD,MAAM,IAAI,UAAU,sDAAsD,CAE9E,CAEA,SAASC,EAA2BF,EAAkB,CACpD,UAAWG,KAAe,QAAQ,QAAQH,CAAU,EAClD,GAAI,CAACH,EAAc,IAAIM,CAAW,EAChC,MAAM,IAAI,UAAU,wCAAwC,OAAOA,CAAW,CAAC,GAAG,EAItF,GAAI,CAACC,EAAOJ,EAAY,SAAS,GAAK,CAACI,EAAOJ,EAAY,KAAK,GAAK,CAACI,EAAOJ,EAAY,KAAK,EAC3F,MAAM,IAAI,UAAU,iEAAiE,CAEzF,CAEA,SAASK,EACPC,EACAC,EAA6C,CAM7C,IAAIC,EAAS,GACb,MAAMC,EAAgB,IAAI,UAAU,mDAAmD,EACjFC,EAAe,IAAW,CAC9B,GAAI,CAACF,EAAQ,MAAMC,EAEnBE,EAAqBL,CAAM,CAC7B,EACMM,EAAU,OAAO,OAAO,CAC5B,OAAsBC,EAA6BC,EAAY,CAC7D,GAAI,CACFJ,EAAY,EACZ,MAAMK,EAAaC,EAA0BH,EAAQC,EAAO,OAAO,OAAO,CAAE,OAAAR,EAAQ,EAAGI,CAAY,EAEnG,OAAO,QAAQ,QAAQK,CAAU,CACnC,OAASE,EAAO,CACd,OAAO,QAAQ,OAAOA,CAAK,CAC7B,CACF,EACA,OAAAX,EACA,eAAgBI,CACjB,CAAA,EAED,OAAIH,IAAa,QAAWT,EAA0B,IAAIc,EAASL,CAAQ,EAEpE,OAAO,OAAO,CACnB,aAAAG,EACA,QAAAE,EACA,QAAM,CACCJ,IAELA,EAAS,GACX,CACD,CAAA,CACH,CAEA,SAASU,EACPZ,EACAa,EACAL,EACAM,EACAb,EAA6C,CAE7C,MAAMc,EAAYhB,EAAuBC,EAAQC,CAAQ,EACzD,IAAIe,EAEJ,GAAI,CACFD,EAAU,aAAY,EACtBC,EAASF,EAAO,IAAMD,EAASL,EAAMO,EAAU,OAAO,CAAC,CAAC,CAC1D,OAASJ,EAAO,CACd,IAAIM,EAAYN,EAEhB,GAAI,CACFI,EAAU,aAAY,CACxB,OAASG,EAAc,CACrBD,EAAYC,CACd,CAEA,OAAAH,EAAU,OAAM,EAET,QAAQ,OAAOE,CAAS,CACjC,CAEA,GAAI,CACF,OAAO,QAAQ,QACbE,EAAoBH,EAAQ,CAC1B,cAAeD,EAAU,aACzB,SAAUA,EAAU,OACpB,0BAA2B,EAC5B,CAAA,CAAC,CAEN,OAASJ,EAAO,CACd,OAAAI,EAAU,OAAM,EAET,QAAQ,OAAOJ,CAAK,CAC7B,CACF,CAEA,eAAeS,EACbpB,EACAa,EACAL,EACAM,EACAb,EAA6C,CAI7C,GAFe,MAAMW,EAAeZ,EAAQa,EAAUL,EAAOM,EAAQb,CAAQ,IAE9D,OAAW,MAAM,IAAI,UAAU,iDAAiD,CACjG,CAEA,SAASoB,EACP3B,EAAwD,CAMxDD,EAAqBC,CAAU,EAC/BE,EAA2BF,CAAU,EAErC,MAAM4B,EAAU5B,EAAW,QACrB6B,EAAM7B,EAAW,IACjB8B,EAAM9B,EAAW,IAEvB,GAAI,OAAO6B,GAAQ,UAAYA,EAAI,SAAW,EAAG,MAAM,IAAI,UAAU,8CAA8C,EAEnH,GAAI,OAAOD,GAAY,YAAc,OAAOE,GAAQ,WAClD,MAAM,IAAI,UAAU,yBAAyBD,CAAG,sCAAsC,EAGxF,MAAO,CAAE,QAASD,EAAgD,GAAI,OAAOC,CAAG,GAAI,IAAAC,CAAG,CACzF,CAEA,SAASC,EACPC,EACAZ,EACAb,EACA0B,EAAkC,CAElC,KAAM,CAAE,OAAA3B,CAAM,EAAK0B,EA2BnB,OAAO,OAAO,OAAO,CAAE,KA1BehC,GAAa,CACjD,GAAI,CACFW,EAAqBL,CAAM,EAC3B,MAAM4B,EAAOP,EAAc3B,CAAU,EAErC,OAAOgC,EAAY,KAAK,CACtB,QAAS,MAAMpB,IACb,MAAMqB,EAAa,EAEZP,EACLd,EAAQ,OACRsB,EAAK,QACLC,IAAqB,CAAE,QAASA,CAAgB,GAChDf,EACAb,CAAQ,GAGZ,GAAI2B,EAAK,GACT,IAAK,IACHhB,EAAeZ,EAAQ4B,EAAK,IAAKC,IAAqB,CAAE,QAASA,CAAgB,GAAKf,EAAQb,CAAQ,CACzG,CAAA,CACH,OAASU,EAAO,CACd,OAAO,QAAQ,OAAOA,CAAK,CAC7B,CACF,EAE6B,CAC/B,CAEA,eAAemB,EACbC,EACAL,EACAZ,EACAb,EACA0B,EAAkC,CAElC,MAAMK,EAAQP,EAAsBC,EAAaZ,EAAQb,EAAU0B,CAAa,EAChF,IAAIlB,EAEJ,GAAI,CACFJ,EAAqBqB,EAAY,MAAM,EACvCjB,EAAaK,EAAO,IAClBiB,EAAO,KACL,OAAO,OAAO,CAAE,OAAQL,EAAY,MAAO,KAAMM,EAAM,IAAI,CAAyC,CAAC,CACtG,CAEL,OAASrB,EAAO,CACd,MAAAN,EAAqBqB,EAAY,MAAM,EACjCf,CACR,CAOA,GALe,MAAMQ,EAAoBV,EAAY,CACnD,cAAe,IAAMJ,EAAqBqB,EAAY,MAAM,EAC5D,0BAA2B,EAC5B,CAAA,IAEc,OAAW,MAAM,IAAI,UAAU,iDAAiD,CACjG,CAEA,SAASO,EACPF,EACA/B,EACAkC,EACApB,EACAb,EAA6C,CAE7C,OAAOmB,EACLpB,EACA+B,EAAO,MACPzB,GAAW,OAAO,OAAO,CAAE,QAAAA,EAAS,OAAQ4B,CAAK,CAAE,EACnDpB,EACAb,CAAQ,CAEZ,CAEA,SAASkC,EAA2B7B,EAAmC,CACrE,OAAOd,EAA0B,IAAIc,CAAO,CAC9C"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AttachmentRetirement, AttachmentRetryOutcome } from '@opetope/core/internal';
|
|
2
|
+
import type { AttachmentInstance, AttachmentRetirementScheduler } from './module-instance-types.js';
|
|
3
|
+
interface AttachmentRetirementSchedulerOptions {
|
|
4
|
+
/** Live attachments in ascending dense scope-slot order. */
|
|
5
|
+
readonly attachments: readonly AttachmentInstance[];
|
|
6
|
+
/** Called exactly once after every live attachment is physically closed. */
|
|
7
|
+
readonly onTerminal: () => void;
|
|
8
|
+
/** Retirement handles aligned one-to-one with `attachments`. */
|
|
9
|
+
readonly retirements: readonly AttachmentRetirement[];
|
|
10
|
+
/** Retries the failed physical close for one exact live attachment. */
|
|
11
|
+
readonly retryAttachment: (attachment: AttachmentInstance) => Promise<AttachmentRetryOutcome>;
|
|
12
|
+
}
|
|
13
|
+
declare function createAttachmentRetirementScheduler(options: AttachmentRetirementSchedulerOptions): AttachmentRetirementScheduler;
|
|
14
|
+
export { createAttachmentRetirementScheduler };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const O=0,F=1,z=2,R=3,p=Object.freeze({kind:"closed"});function d(e){return Object.freeze({error:e,kind:"rejected"})}function m(){let e=i=>{},t=i=>{};return{promise:new Promise((i,r)=>{e=r,t=i}),reject:e,resolve:t}}function a(e,t){if(e===void 0)throw new TypeError(t);return e}function h(e){e.activePass=void 0,e.attachments=void 0,e.drainPromise=void 0,e.failures=void 0,e.onTerminal=void 0,e.retirements=void 0,e.retryAttachment=void 0,e.retryPromise=void 0,e.statuses=void 0}function c(e,t){const n=e.activePass;n!==void 0&&(e.activePass=void 0,n.reject(t))}function y(e){const t=e.failures;return Object.freeze(t===void 0?[]:t.filter(n=>n!==void 0))}function P(e){const t=e.activePass;if(t!==void 0){e.workspacePromise=t.promise;try{a(e.onTerminal,"Attachment retirement workspace callback is unavailable.")(),h(e),t.resolve(p)}catch(n){h(e),t.reject(n)}}}function A(e){const t=e.activePass;if(t===void 0)return;const n=y(e);if(n.length===0){c(e,new TypeError("Attachment retirement pass ended without a failed attachment."));return}e.activePass=void 0,t.resolve(Object.freeze({failedAttachments:n,kind:"quarantined"}))}function o(e){if(e.dispatchDepth!==0||e.inFlight!==0||e.activePass===void 0)return;const t=a(e.attachments,"Attachment retirement live set is unavailable.");if(e.closedCount===t.length){P(e);return}A(e)}function g(e,t,n){const i=a(e.attachments,"Attachment retirement live set is unavailable."),r=a(e.statuses,"Attachment retirement statuses are unavailable."),s=i[t];if(s===void 0)throw new TypeError(`Attachment retirement live index ${String(t)} is outside the plan.`);r[t]=3;const f=e.failures??(e.failures=Array.from({length:i.length}));f[t]=Object.freeze({attachmentId:s.id,attachmentSlot:s.slot,outcome:n})}function l(e,t){const n=a(e.statuses,"Attachment retirement statuses are unavailable.");if(n[t]!==1)throw new TypeError(`Attachment retirement live index ${String(t)} settled outside a running operation.`);n[t]=2,e.closedCount+=1,e.inFlight-=1,e.failures!==void 0&&(e.failures[t]=void 0)}function u(e,t,n){if(a(e.statuses,"Attachment retirement statuses are unavailable.")[t]!==1)throw new TypeError(`Attachment retirement live index ${String(t)} failed outside a running operation.`);e.inFlight-=1,g(e,t,n)}function w(e){return e.kind==="recovered"||e.kind==="not-needed"&&e.state==="closed"}function b(e){const t=e.kind==="interrupted"?e.outcome:e.kind;return d(new TypeError(`Attachment retry did not reach closed state: ${t}.`))}function S(e,t,n){n.then(i=>{e.dispatchDepth+=1;try{i.kind==="quarantined"?u(e,t,i):l(e,t)}catch(r){c(e,r)}finally{e.dispatchDepth-=1,o(e)}},i=>{try{u(e,t,d(i))}catch(r){c(e,r)}finally{o(e)}})}function k(e,t,n){n.then(i=>{e.dispatchDepth+=1;try{w(i)?l(e,t):i.kind==="quarantined"?u(e,t,i):u(e,t,b(i))}catch(r){c(e,r)}finally{e.dispatchDepth-=1,o(e)}},i=>{try{u(e,t,d(i))}catch(r){c(e,r)}finally{o(e)}})}function v(e,t){const n=a(e.statuses,"Attachment retirement statuses are unavailable.");if(n[t]!==0)return;const r=a(e.retirements,"Attachment retirement handles are unavailable.")[t];if(r===void 0)throw new TypeError(`Attachment retirement live index ${String(t)} lost its handle.`);n[t]=1,e.inFlight+=1;try{S(e,t,r.drain())}catch(s){u(e,t,d(s))}}function T(e,t){const n=a(e.statuses,"Attachment retirement statuses are unavailable.");if(n[t]!==3)return;const r=a(e.attachments,"Attachment retirement live set is unavailable.")[t];if(r===void 0)throw new TypeError(`Attachment retirement live index ${String(t)} is outside the plan.`);const s=a(e.retryAttachment,"Attachment retirement retry callback is unavailable.");n[t]=1,e.inFlight+=1;try{k(e,t,s(r))}catch(f){u(e,t,d(f))}}function j(e,t){e.activePass=t,e.dispatchDepth+=1;try{a(e.attachments,"Attachment retirement live set is unavailable.").forEach((i,r)=>v(e,r))}catch(n){c(e,n)}finally{e.dispatchDepth-=1,o(e)}}function E(e){const t=m();e.activePass=t,e.dispatchDepth+=1;try{a(e.statuses,"Attachment retirement statuses are unavailable.").forEach((i,r)=>{i===3&&T(e,r)})}catch(n){c(e,n)}finally{e.dispatchDepth-=1,o(e)}return t.promise}function D(e){if(e.attachments.length!==e.retirements.length)throw new TypeError("Attachment retirement scheduler inputs must be aligned one-to-one.");const t={activePass:void 0,attachments:e.attachments,closedCount:0,dispatchDepth:0,drainPromise:void 0,failures:void 0,inFlight:0,onTerminal:e.onTerminal,retirements:e.retirements,retryAttachment:e.retryAttachment,retryPromise:void 0,statuses:new Uint8Array(e.attachments.length),workspacePromise:void 0},n=()=>{if(t.workspacePromise!==void 0)return t.workspacePromise;if(t.drainPromise!==void 0)return t.drainPromise;const r=m();return t.drainPromise=r.promise,j(t,r),r.promise};return Object.freeze({drain:n,retry:()=>{if(t.workspacePromise!==void 0)return t.workspacePromise;if(t.retryPromise!==void 0)return t.retryPromise;const r=m();return t.retryPromise=r.promise,n().then(s=>s.kind==="closed"?s:E(t)).then(s=>{t.retryPromise===r.promise&&t.workspacePromise===void 0&&(t.retryPromise=void 0),r.resolve(s)},s=>{t.retryPromise===r.promise&&t.workspacePromise===void 0&&(t.retryPromise=void 0),r.reject(s)}),r.promise}})}export{D as createAttachmentRetirementScheduler};
|
|
2
|
+
//# sourceMappingURL=attachment-retirement-scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-retirement-scheduler.js","sources":["../src/attachment-retirement-scheduler.ts"],"sourcesContent":["import type { AttachmentDrainOutcome, AttachmentRetirement, AttachmentRetryOutcome } from '@opetope/core/internal';\n\nimport type {\n AttachmentInstance,\n AttachmentRetirementScheduler,\n LocalAttachmentCloseFailure,\n LocalAttachmentCloseFailureOutcome,\n LocalScopeDrainOutcome,\n} from './module-instance-types';\n\ninterface AttachmentRetirementSchedulerOptions {\n /** Live attachments in ascending dense scope-slot order. */\n readonly attachments: readonly AttachmentInstance[];\n /** Called exactly once after every live attachment is physically closed. */\n readonly onTerminal: () => void;\n /** Retirement handles aligned one-to-one with `attachments`. */\n readonly retirements: readonly AttachmentRetirement[];\n /** Retries the failed physical close for one exact live attachment. */\n readonly retryAttachment: (attachment: AttachmentInstance) => Promise<AttachmentRetryOutcome>;\n}\n\ntype SchedulerPass = {\n readonly promise: Promise<LocalScopeDrainOutcome>;\n readonly reject: (error: unknown) => void;\n readonly resolve: (outcome: LocalScopeDrainOutcome) => void;\n};\n\ntype SchedulerState = {\n activePass: SchedulerPass | undefined;\n attachments: readonly AttachmentInstance[] | undefined;\n closedCount: number;\n dispatchDepth: number;\n drainPromise: Promise<LocalScopeDrainOutcome> | undefined;\n failures: (LocalAttachmentCloseFailure | undefined)[] | undefined;\n inFlight: number;\n onTerminal: (() => void) | undefined;\n retirements: readonly AttachmentRetirement[] | undefined;\n retryAttachment: ((attachment: AttachmentInstance) => Promise<AttachmentRetryOutcome>) | undefined;\n retryPromise: Promise<LocalScopeDrainOutcome> | undefined;\n statuses: Uint8Array | undefined;\n workspacePromise: Promise<LocalScopeDrainOutcome> | undefined;\n};\n\nconst pendingStatus = 0;\nconst runningStatus = 1;\nconst closedStatus = 2;\nconst failedStatus = 3;\nconst closedOutcome = Object.freeze({ kind: 'closed' as const });\n\nfunction rejectedOutcome(error: unknown): LocalAttachmentCloseFailureOutcome {\n return Object.freeze({ error, kind: 'rejected' as const });\n}\n\nfunction createPass(): SchedulerPass {\n let reject = (_error: unknown): void => undefined;\n let resolve = (_outcome: LocalScopeDrainOutcome): void => undefined;\n const promise = new Promise<LocalScopeDrainOutcome>((onResolve, onReject) => {\n reject = onReject;\n resolve = onResolve;\n });\n\n return { promise, reject, resolve };\n}\n\nfunction requireStateValue<Value>(value: Value | undefined, message: string): Value {\n if (value === undefined) throw new TypeError(message);\n\n return value;\n}\n\nfunction compactTerminalState(state: SchedulerState): void {\n state.activePass = undefined;\n state.attachments = undefined;\n state.drainPromise = undefined;\n state.failures = undefined;\n state.onTerminal = undefined;\n state.retirements = undefined;\n state.retryAttachment = undefined;\n state.retryPromise = undefined;\n state.statuses = undefined;\n}\n\nfunction failPass(state: SchedulerState, error: unknown): void {\n const pass = state.activePass;\n\n if (pass === undefined) return;\n\n state.activePass = undefined;\n pass.reject(error);\n}\n\nfunction failureFrontier(state: SchedulerState): readonly LocalAttachmentCloseFailure[] {\n const failures = state.failures;\n\n if (failures === undefined) return Object.freeze([]);\n\n return Object.freeze(failures.filter((failure): failure is LocalAttachmentCloseFailure => failure !== undefined));\n}\n\nfunction finishTerminal(state: SchedulerState): void {\n const pass = state.activePass;\n\n if (pass === undefined) return;\n\n state.workspacePromise = pass.promise;\n\n try {\n requireStateValue(state.onTerminal, 'Attachment retirement workspace callback is unavailable.')();\n compactTerminalState(state);\n pass.resolve(closedOutcome);\n } catch (error) {\n compactTerminalState(state);\n pass.reject(error);\n }\n}\n\nfunction finishQuarantined(state: SchedulerState): void {\n const pass = state.activePass;\n\n if (pass === undefined) return;\n\n const failedAttachments = failureFrontier(state);\n\n if (failedAttachments.length === 0) {\n failPass(state, new TypeError('Attachment retirement pass ended without a failed attachment.'));\n\n return;\n }\n\n state.activePass = undefined;\n pass.resolve(Object.freeze({ failedAttachments, kind: 'quarantined' as const }));\n}\n\nfunction finishPassIfIdle(state: SchedulerState): void {\n if (state.dispatchDepth !== 0 || state.inFlight !== 0 || state.activePass === undefined) return;\n\n const attachments = requireStateValue(state.attachments, 'Attachment retirement live set is unavailable.');\n\n if (state.closedCount === attachments.length) {\n finishTerminal(state);\n\n return;\n }\n\n finishQuarantined(state);\n}\n\nfunction recordFailure(state: SchedulerState, liveIndex: number, outcome: LocalAttachmentCloseFailureOutcome): void {\n const attachments = requireStateValue(state.attachments, 'Attachment retirement live set is unavailable.');\n const statuses = requireStateValue(state.statuses, 'Attachment retirement statuses are unavailable.');\n const attachment = attachments[liveIndex];\n\n if (attachment === undefined)\n throw new TypeError(`Attachment retirement live index ${String(liveIndex)} is outside the plan.`);\n\n statuses[liveIndex] = failedStatus;\n const failures = (state.failures ??= Array.from({ length: attachments.length }));\n // The scheduler records the failure in the shape every layer above it reads (D164).\n failures[liveIndex] = Object.freeze({ attachmentId: attachment.id, attachmentSlot: attachment.slot, outcome });\n}\n\nfunction settleSuccess(state: SchedulerState, liveIndex: number): void {\n const statuses = requireStateValue(state.statuses, 'Attachment retirement statuses are unavailable.');\n\n if (statuses[liveIndex] !== runningStatus) {\n throw new TypeError(`Attachment retirement live index ${String(liveIndex)} settled outside a running operation.`);\n }\n\n statuses[liveIndex] = closedStatus;\n state.closedCount += 1;\n state.inFlight -= 1;\n\n if (state.failures !== undefined) state.failures[liveIndex] = undefined;\n}\n\nfunction settleFailure(state: SchedulerState, liveIndex: number, outcome: LocalAttachmentCloseFailureOutcome): void {\n const statuses = requireStateValue(state.statuses, 'Attachment retirement statuses are unavailable.');\n\n if (statuses[liveIndex] !== runningStatus) {\n throw new TypeError(`Attachment retirement live index ${String(liveIndex)} failed outside a running operation.`);\n }\n\n state.inFlight -= 1;\n recordFailure(state, liveIndex, outcome);\n}\n\nfunction successfulRetry(outcome: AttachmentRetryOutcome): boolean {\n return outcome.kind === 'recovered' || (outcome.kind === 'not-needed' && outcome.state === 'closed');\n}\n\nfunction invalidRetryOutcome(outcome: AttachmentRetryOutcome): LocalAttachmentCloseFailureOutcome {\n const detail = outcome.kind === 'interrupted' ? outcome.outcome : outcome.kind;\n\n return rejectedOutcome(new TypeError(`Attachment retry did not reach closed state: ${detail}.`));\n}\n\nfunction observeDrain(state: SchedulerState, liveIndex: number, operation: Promise<AttachmentDrainOutcome>): void {\n void operation.then(\n outcome => {\n state.dispatchDepth += 1;\n\n try {\n if (outcome.kind === 'quarantined') settleFailure(state, liveIndex, outcome);\n else settleSuccess(state, liveIndex);\n } catch (error) {\n failPass(state, error);\n } finally {\n state.dispatchDepth -= 1;\n finishPassIfIdle(state);\n }\n },\n (error: unknown) => {\n try {\n settleFailure(state, liveIndex, rejectedOutcome(error));\n } catch (settlementError) {\n failPass(state, settlementError);\n } finally {\n finishPassIfIdle(state);\n }\n },\n );\n}\n\nfunction observeRetry(state: SchedulerState, liveIndex: number, operation: Promise<AttachmentRetryOutcome>): void {\n void operation.then(\n outcome => {\n state.dispatchDepth += 1;\n\n try {\n if (successfulRetry(outcome)) settleSuccess(state, liveIndex);\n else if (outcome.kind === 'quarantined') settleFailure(state, liveIndex, outcome);\n else settleFailure(state, liveIndex, invalidRetryOutcome(outcome));\n } catch (error) {\n failPass(state, error);\n } finally {\n state.dispatchDepth -= 1;\n finishPassIfIdle(state);\n }\n },\n (error: unknown) => {\n try {\n settleFailure(state, liveIndex, rejectedOutcome(error));\n } catch (settlementError) {\n failPass(state, settlementError);\n } finally {\n finishPassIfIdle(state);\n }\n },\n );\n}\n\nfunction startDrain(state: SchedulerState, liveIndex: number): void {\n const statuses = requireStateValue(state.statuses, 'Attachment retirement statuses are unavailable.');\n\n if (statuses[liveIndex] !== pendingStatus) return;\n\n const retirements = requireStateValue(state.retirements, 'Attachment retirement handles are unavailable.');\n const retirement = retirements[liveIndex];\n\n if (retirement === undefined)\n throw new TypeError(`Attachment retirement live index ${String(liveIndex)} lost its handle.`);\n\n statuses[liveIndex] = runningStatus;\n state.inFlight += 1;\n\n try {\n observeDrain(state, liveIndex, retirement.drain());\n } catch (error) {\n settleFailure(state, liveIndex, rejectedOutcome(error));\n }\n}\n\nfunction startRetry(state: SchedulerState, liveIndex: number): void {\n const statuses = requireStateValue(state.statuses, 'Attachment retirement statuses are unavailable.');\n\n if (statuses[liveIndex] !== failedStatus) return;\n\n const attachments = requireStateValue(state.attachments, 'Attachment retirement live set is unavailable.');\n const attachment = attachments[liveIndex];\n\n if (attachment === undefined)\n throw new TypeError(`Attachment retirement live index ${String(liveIndex)} is outside the plan.`);\n\n const retryAttachment = requireStateValue(\n state.retryAttachment,\n 'Attachment retirement retry callback is unavailable.',\n );\n statuses[liveIndex] = runningStatus;\n state.inFlight += 1;\n\n try {\n observeRetry(state, liveIndex, retryAttachment(attachment));\n } catch (error) {\n settleFailure(state, liveIndex, rejectedOutcome(error));\n }\n}\n\n/** Every attachment of one scope closes in the same wave: nothing orders one close before another (D163). */\nfunction startInitialPass(state: SchedulerState, pass: SchedulerPass): void {\n state.activePass = pass;\n state.dispatchDepth += 1;\n\n try {\n const attachments = requireStateValue(state.attachments, 'Attachment retirement live set is unavailable.');\n\n attachments.forEach((_attachment, liveIndex) => startDrain(state, liveIndex));\n } catch (error) {\n failPass(state, error);\n } finally {\n state.dispatchDepth -= 1;\n finishPassIfIdle(state);\n }\n}\n\nfunction startRetryPass(state: SchedulerState): Promise<LocalScopeDrainOutcome> {\n const pass = createPass();\n state.activePass = pass;\n state.dispatchDepth += 1;\n\n try {\n const statuses = requireStateValue(state.statuses, 'Attachment retirement statuses are unavailable.');\n\n statuses.forEach((status, liveIndex) => {\n if (status === failedStatus) startRetry(state, liveIndex);\n });\n } catch (error) {\n failPass(state, error);\n } finally {\n state.dispatchDepth -= 1;\n finishPassIfIdle(state);\n }\n\n return pass.promise;\n}\n\nfunction createAttachmentRetirementScheduler(\n options: AttachmentRetirementSchedulerOptions,\n): AttachmentRetirementScheduler {\n if (options.attachments.length !== options.retirements.length) {\n throw new TypeError('Attachment retirement scheduler inputs must be aligned one-to-one.');\n }\n\n const state: SchedulerState = {\n activePass: undefined,\n attachments: options.attachments,\n closedCount: 0,\n dispatchDepth: 0,\n drainPromise: undefined,\n failures: undefined,\n inFlight: 0,\n onTerminal: options.onTerminal,\n retirements: options.retirements,\n retryAttachment: options.retryAttachment,\n retryPromise: undefined,\n statuses: new Uint8Array(options.attachments.length),\n workspacePromise: undefined,\n };\n const drain = (): Promise<LocalScopeDrainOutcome> => {\n if (state.workspacePromise !== undefined) return state.workspacePromise;\n\n if (state.drainPromise !== undefined) return state.drainPromise;\n\n const pass = createPass();\n state.drainPromise = pass.promise;\n startInitialPass(state, pass);\n\n return pass.promise;\n };\n const retry = (): Promise<LocalScopeDrainOutcome> => {\n if (state.workspacePromise !== undefined) return state.workspacePromise;\n\n if (state.retryPromise !== undefined) return state.retryPromise;\n\n const pass = createPass();\n state.retryPromise = pass.promise;\n void drain()\n .then(outcome => (outcome.kind === 'closed' ? outcome : startRetryPass(state)))\n .then(\n outcome => {\n if (state.retryPromise === pass.promise && state.workspacePromise === undefined) {\n state.retryPromise = undefined;\n }\n\n pass.resolve(outcome);\n },\n (error: unknown) => {\n if (state.retryPromise === pass.promise && state.workspacePromise === undefined) {\n state.retryPromise = undefined;\n }\n\n pass.reject(error);\n },\n );\n\n return pass.promise;\n };\n\n return Object.freeze({ drain, retry });\n}\n\nexport { createAttachmentRetirementScheduler };\n"],"names":["pendingStatus","runningStatus","closedStatus","failedStatus","closedOutcome","rejectedOutcome","error","createPass","reject","_error","resolve","_outcome","onResolve","onReject","requireStateValue","value","message","compactTerminalState","state","failPass","pass","failureFrontier","failures","failure","finishTerminal","finishQuarantined","failedAttachments","finishPassIfIdle","attachments","recordFailure","liveIndex","outcome","statuses","attachment","settleSuccess","settleFailure","successfulRetry","invalidRetryOutcome","detail","observeDrain","operation","settlementError","observeRetry","startDrain","retirement","startRetry","retryAttachment","startInitialPass","_attachment","startRetryPass","status","createAttachmentRetirementScheduler","options","drain"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CallKey, CallLane, CallScheduling } from '@opetope/core/internal';
|
|
2
|
+
type CallPolicy = 'latest' | 'parallel' | 'queue';
|
|
3
|
+
/** A call key is one fact for the author, the compiled policy and the kernel alike. */
|
|
4
|
+
type CallOnceOption<Input> = ((input: Input) => CallKey) | true;
|
|
5
|
+
type CallSingleFlightOption<Input> = (input: Input) => CallKey;
|
|
6
|
+
/**
|
|
7
|
+
* The once/singleFlight/policy triple is one fact, so both authoring surfaces — `own.call` of a feature and
|
|
8
|
+
* `own.call` of a model — validate it here and hand the authored value straight to the kernel (D161).
|
|
9
|
+
*/
|
|
10
|
+
declare function snapshotCallOnce(value: unknown, label: string): CallOnceOption<unknown> | undefined;
|
|
11
|
+
declare function snapshotCallSingleFlight(value: unknown, label: string): CallSingleFlightOption<unknown> | undefined;
|
|
12
|
+
/** D185: `latest` is the third policy of a call, and like `queue` it runs on a lane. */
|
|
13
|
+
declare function snapshotCallPolicy(value: unknown, label: string): CallPolicy;
|
|
14
|
+
/**
|
|
15
|
+
* The kernel takes the same three words the author wrote. A call without a lane of its own still names its policy,
|
|
16
|
+
* so `latest` gets the private lane the kernel builds for it.
|
|
17
|
+
*/
|
|
18
|
+
declare function kernelCallScheduling(policy: CallPolicy, lane: CallLane | undefined): CallScheduling;
|
|
19
|
+
export { kernelCallScheduling, snapshotCallOnce, snapshotCallPolicy, snapshotCallSingleFlight };
|
|
20
|
+
export type { CallOnceOption, CallPolicy, CallSingleFlightOption };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function r(n,e){if(n===void 0||n===!0)return n;if(typeof n!="function")throw new TypeError(`${e} once must be true or a key function.`);return n}function u(n,e){if(n!==void 0){if(typeof n!="function")throw new TypeError(`${e} singleFlight must be a key function.`);return n}}function o(n,e){const t=n??"queue";if(t!=="latest"&&t!=="parallel"&&t!=="queue")throw new TypeError(`${e} policy must be 'queue', 'latest' or 'parallel'.`);return t}function i(n,e){return n==="parallel"?{policy:n}:e===void 0?{policy:n}:{lane:e,policy:n}}export{i as kernelCallScheduling,r as snapshotCallOnce,o as snapshotCallPolicy,u as snapshotCallSingleFlight};
|
|
2
|
+
//# sourceMappingURL=call-option-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-option-snapshot.js","sources":["../src/call-option-snapshot.ts"],"sourcesContent":["import type { CallKey, CallLane, CallScheduling } from '@opetope/core/internal';\n\ntype CallPolicy = 'latest' | 'parallel' | 'queue';\n\n/** A call key is one fact for the author, the compiled policy and the kernel alike. */\ntype CallOnceOption<Input> = ((input: Input) => CallKey) | true;\ntype CallSingleFlightOption<Input> = (input: Input) => CallKey;\n\n/**\n * The once/singleFlight/policy triple is one fact, so both authoring surfaces — `own.call` of a feature and\n * `own.call` of a model — validate it here and hand the authored value straight to the kernel (D161).\n */\nfunction snapshotCallOnce(value: unknown, label: string): CallOnceOption<unknown> | undefined {\n if (value === undefined || value === true) return value;\n\n if (typeof value !== 'function') throw new TypeError(`${label} once must be true or a key function.`);\n\n return value as CallSingleFlightOption<unknown>;\n}\n\nfunction snapshotCallSingleFlight(value: unknown, label: string): CallSingleFlightOption<unknown> | undefined {\n if (value === undefined) return undefined;\n\n if (typeof value !== 'function') throw new TypeError(`${label} singleFlight must be a key function.`);\n\n return value as CallSingleFlightOption<unknown>;\n}\n\n/** D185: `latest` is the third policy of a call, and like `queue` it runs on a lane. */\nfunction snapshotCallPolicy(value: unknown, label: string): CallPolicy {\n const policy = value ?? 'queue';\n\n if (policy !== 'latest' && policy !== 'parallel' && policy !== 'queue') {\n throw new TypeError(`${label} policy must be 'queue', 'latest' or 'parallel'.`);\n }\n\n return policy;\n}\n\n/**\n * The kernel takes the same three words the author wrote. A call without a lane of its own still names its policy,\n * so `latest` gets the private lane the kernel builds for it.\n */\nfunction kernelCallScheduling(policy: CallPolicy, lane: CallLane | undefined): CallScheduling {\n if (policy === 'parallel') return { policy };\n\n return lane === undefined ? { policy } : { lane, policy };\n}\n\nexport { kernelCallScheduling, snapshotCallOnce, snapshotCallPolicy, snapshotCallSingleFlight };\nexport type { CallOnceOption, CallPolicy, CallSingleFlightOption };\n"],"names":["snapshotCallOnce","value","label","snapshotCallSingleFlight","snapshotCallPolicy","policy","kernelCallScheduling","lane"],"mappings":"AAYA,SAASA,EAAiBC,EAAgBC,EAAa,CACrD,GAAID,IAAU,QAAaA,IAAU,GAAM,OAAOA,EAElD,GAAI,OAAOA,GAAU,WAAY,MAAM,IAAI,UAAU,GAAGC,CAAK,uCAAuC,EAEpG,OAAOD,CACT,CAEA,SAASE,EAAyBF,EAAgBC,EAAa,CAC7D,GAAID,IAAU,OAEd,IAAI,OAAOA,GAAU,WAAY,MAAM,IAAI,UAAU,GAAGC,CAAK,uCAAuC,EAEpG,OAAOD,EACT,CAGA,SAASG,EAAmBH,EAAgBC,EAAa,CACvD,MAAMG,EAASJ,GAAS,QAExB,GAAII,IAAW,UAAYA,IAAW,YAAcA,IAAW,QAC7D,MAAM,IAAI,UAAU,GAAGH,CAAK,kDAAkD,EAGhF,OAAOG,CACT,CAMA,SAASC,EAAqBD,EAAoBE,EAA0B,CAC1E,OAAIF,IAAW,WAAmB,CAAE,OAAAA,CAAM,EAEnCE,IAAS,OAAY,CAAE,OAAAF,CAAM,EAAK,CAAE,KAAAE,EAAM,OAAAF,CAAM,CACzD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DeclarationId } from '@opetope/core';
|
|
2
|
+
import type { AttachmentCallRefIdentity, CompiledAttachmentCallRecipe } from './attachment-call-declaration.js';
|
|
3
|
+
import type { LifetimeAttachmentRefIdentity } from './attachment-declaration.js';
|
|
4
|
+
import type { AttachmentNodeIR, AttachmentTemplateSlot, CallTargetBindingIR, CallTargetBindingSlot } from './module-template-ir.js';
|
|
5
|
+
type RuntimeCallEntry = {
|
|
6
|
+
readonly key: string;
|
|
7
|
+
readonly value: unknown;
|
|
8
|
+
};
|
|
9
|
+
declare function compileCallTargetBindings(moduleId: DeclarationId, entries: readonly RuntimeCallEntry[], attachments: readonly AttachmentNodeIR[], attachmentSlots: ReadonlyMap<LifetimeAttachmentRefIdentity, AttachmentTemplateSlot>): {
|
|
10
|
+
readonly bindings: readonly CallTargetBindingIR[];
|
|
11
|
+
readonly recipes: readonly CompiledAttachmentCallRecipe<unknown, unknown>[];
|
|
12
|
+
readonly slots: ReadonlyMap<AttachmentCallRefIdentity, CallTargetBindingSlot>;
|
|
13
|
+
};
|
|
14
|
+
export { compileCallTargetBindings };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{declarationId as p}from"@opetope/core";import{getAttachmentCallRecipe as u}from"./attachment-call-declaration.js";function w(i,d,l,m){const r=[],c=new Map,h=d.map((e,f)=>{const a=e.value,o=u(a),t=m.get(o.within);if(t===void 0)throw new TypeError(`Attachment call runtime key ${e.key} must bind within an attachment returned by this feature runtime.`);const n=l[t];if(n===void 0)throw new TypeError(`Attachment call runtime key ${e.key} lost its attachment declaration.`);if(n.readiness==="deferred")throw new TypeError(`Attachment call runtime key ${e.key} cannot bind within deferred attachment ${n.identity.id}.`);const s=f;return c.set(a,s),r.push(o),Object.freeze({id:p(`${i}.${e.key}`),key:e.key,kind:"call-target-binding",moduleId:i,slot:s,stage:"runtime",withinAttachmentSlot:t})});return{bindings:Object.freeze(h),recipes:Object.freeze(r),slots:c}}export{w as compileCallTargetBindings};
|
|
2
|
+
//# sourceMappingURL=compile-call-target-bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-call-target-bindings.js","sources":["../src/compile-call-target-bindings.ts"],"sourcesContent":["import { declarationId } from '@opetope/core';\nimport type { DeclarationId } from '@opetope/core';\n\nimport { getAttachmentCallRecipe } from './attachment-call-declaration';\nimport type {\n AttachmentCallRef,\n AttachmentCallRefIdentity,\n CompiledAttachmentCallRecipe,\n} from './attachment-call-declaration';\nimport type { LifetimeAttachmentRefIdentity } from './attachment-declaration';\nimport type {\n AttachmentNodeIR,\n AttachmentTemplateSlot,\n CallTargetBindingIR,\n CallTargetBindingSlot,\n} from './module-template-ir';\n\ntype RuntimeCallEntry = {\n readonly key: string;\n readonly value: unknown;\n};\n\nfunction compileCallTargetBindings(\n moduleId: DeclarationId,\n entries: readonly RuntimeCallEntry[],\n attachments: readonly AttachmentNodeIR[],\n attachmentSlots: ReadonlyMap<LifetimeAttachmentRefIdentity, AttachmentTemplateSlot>,\n): {\n readonly bindings: readonly CallTargetBindingIR[];\n readonly recipes: readonly CompiledAttachmentCallRecipe<unknown, unknown>[];\n readonly slots: ReadonlyMap<AttachmentCallRefIdentity, CallTargetBindingSlot>;\n} {\n const recipes: CompiledAttachmentCallRecipe<unknown, unknown>[] = [];\n const slots = new Map<AttachmentCallRefIdentity, CallTargetBindingSlot>();\n const bindings = entries.map((entry, index): CallTargetBindingIR => {\n const call = entry.value as AttachmentCallRef<unknown, unknown>;\n const recipe = getAttachmentCallRecipe(call);\n const withinAttachmentSlot = attachmentSlots.get(recipe.within);\n\n if (withinAttachmentSlot === undefined) {\n throw new TypeError(\n `Attachment call runtime key ${entry.key} must bind within an attachment returned by this feature runtime.`,\n );\n }\n\n const withinAttachment = attachments[withinAttachmentSlot];\n\n if (withinAttachment === undefined) {\n throw new TypeError(`Attachment call runtime key ${entry.key} lost its attachment declaration.`);\n }\n\n if (withinAttachment.readiness === 'deferred') {\n throw new TypeError(\n `Attachment call runtime key ${entry.key} cannot bind within deferred attachment ${withinAttachment.identity.id}.`,\n );\n }\n\n const slot = index as CallTargetBindingSlot;\n slots.set(call, slot);\n recipes.push(recipe);\n\n return Object.freeze({\n id: declarationId(`${moduleId}.${entry.key}`),\n key: entry.key,\n kind: 'call-target-binding' as const,\n moduleId,\n slot,\n stage: 'runtime' as const,\n withinAttachmentSlot,\n });\n });\n\n return {\n bindings: Object.freeze(bindings),\n recipes: Object.freeze(recipes),\n slots,\n };\n}\n\nexport { compileCallTargetBindings };\n"],"names":["compileCallTargetBindings","moduleId","entries","attachments","attachmentSlots","recipes","slots","bindings","entry","index","call","recipe","getAttachmentCallRecipe","withinAttachmentSlot","withinAttachment","slot","declarationId"],"mappings":"yHAsBA,SAASA,EACPC,EACAC,EACAC,EACAC,EAAmF,CAMnF,MAAMC,EAA4D,CAAA,EAC5DC,EAAQ,IAAI,IACZC,EAAWL,EAAQ,IAAI,CAACM,EAAOC,IAA8B,CACjE,MAAMC,EAAOF,EAAM,MACbG,EAASC,EAAwBF,CAAI,EACrCG,EAAuBT,EAAgB,IAAIO,EAAO,MAAM,EAE9D,GAAIE,IAAyB,OAC3B,MAAM,IAAI,UACR,+BAA+BL,EAAM,GAAG,mEAAmE,EAI/G,MAAMM,EAAmBX,EAAYU,CAAoB,EAEzD,GAAIC,IAAqB,OACvB,MAAM,IAAI,UAAU,+BAA+BN,EAAM,GAAG,mCAAmC,EAGjG,GAAIM,EAAiB,YAAc,WACjC,MAAM,IAAI,UACR,+BAA+BN,EAAM,GAAG,2CAA2CM,EAAiB,SAAS,EAAE,GAAG,EAItH,MAAMC,EAAON,EACb,OAAAH,EAAM,IAAII,EAAMK,CAAI,EACpBV,EAAQ,KAAKM,CAAM,EAEZ,OAAO,OAAO,CACnB,GAAIK,EAAc,GAAGf,CAAQ,IAAIO,EAAM,GAAG,EAAE,EAC5C,IAAKA,EAAM,IACX,KAAM,sBACN,SAAAP,EACA,KAAAc,EACA,MAAO,UACP,qBAAAF,CACD,CAAA,CACH,CAAC,EAED,MAAO,CACL,SAAU,OAAO,OAAON,CAAQ,EAChC,QAAS,OAAO,OAAOF,CAAO,EAC9B,MAAAC,EAEJ"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { DeclarationId } from '@opetope/core';
|
|
2
|
+
import type { ExactInput } from '@opetope/core/internal';
|
|
3
|
+
import type { AttachmentCallRef, AttachmentCallRefIdentity, CompiledAttachmentCallRecipe } from './attachment-call-declaration.js';
|
|
4
|
+
import type { CompiledLifetimeAttachmentRecipe, LifetimeAttachmentRef, LifetimeAttachmentRefIdentity, ScopeBlueprint, ScopeBlueprintIdentity } from './attachment-declaration.js';
|
|
5
|
+
import type { AttachmentTemplateSlot, CallTargetBindingSlot, CompiledModuleTemplateIR, ScopeTemplateSlot } from './module-template-ir.js';
|
|
6
|
+
declare const localAttachmentModuleDefinitionBrand: unique symbol;
|
|
7
|
+
type RuntimeBlueprint = AttachmentCallRefIdentity | LifetimeAttachmentRefIdentity | ScopeBlueprintIdentity;
|
|
8
|
+
type RuntimeBlueprintRecord = Readonly<Record<string, RuntimeBlueprint>>;
|
|
9
|
+
type ModuleDefinitionCandidate = {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly runtime: RuntimeBlueprintRecord;
|
|
12
|
+
};
|
|
13
|
+
interface LocalAttachmentModuleDefinition<Runtime extends RuntimeBlueprintRecord = RuntimeBlueprintRecord> {
|
|
14
|
+
readonly id: DeclarationId;
|
|
15
|
+
readonly [localAttachmentModuleDefinitionBrand]: true;
|
|
16
|
+
readonly runtime: Runtime;
|
|
17
|
+
}
|
|
18
|
+
type CompiledModuleTemplateRecord = {
|
|
19
|
+
readonly attachmentCallRecipes: readonly CompiledAttachmentCallRecipe<unknown, unknown>[];
|
|
20
|
+
readonly attachmentCallSlots: ReadonlyMap<AttachmentCallRefIdentity, CallTargetBindingSlot>;
|
|
21
|
+
readonly attachmentSlots: ReadonlyMap<LifetimeAttachmentRefIdentity, AttachmentTemplateSlot>;
|
|
22
|
+
readonly recipes: readonly CompiledLifetimeAttachmentRecipe<unknown>[];
|
|
23
|
+
readonly scopeSlots: ReadonlyMap<ScopeBlueprintIdentity, ScopeTemplateSlot>;
|
|
24
|
+
};
|
|
25
|
+
declare function createLocalAttachmentModuleDefinition<const Options extends ModuleDefinitionCandidate>(options: ExactInput<Options, ModuleDefinitionCandidate>): LocalAttachmentModuleDefinition<Options['runtime']>;
|
|
26
|
+
declare function compileModuleTemplate(definition: LocalAttachmentModuleDefinition): CompiledModuleTemplateIR;
|
|
27
|
+
declare function getCompiledTemplateRecord(template: CompiledModuleTemplateIR): CompiledModuleTemplateRecord;
|
|
28
|
+
/**
|
|
29
|
+
* Authenticity of one template is one fact: instantiation resolves the record once and reads slots from it instead of
|
|
30
|
+
* re-proving the same template on every lookup (D165).
|
|
31
|
+
*/
|
|
32
|
+
declare function compiledAttachmentRecipe(record: CompiledModuleTemplateRecord, slot: AttachmentTemplateSlot): CompiledLifetimeAttachmentRecipe<unknown>;
|
|
33
|
+
declare function compiledAttachmentCallRecipe(record: CompiledModuleTemplateRecord, slot: CallTargetBindingSlot): CompiledAttachmentCallRecipe<unknown, unknown>;
|
|
34
|
+
declare function getCompiledCallTargetBindingSlot<Input, Output>(template: CompiledModuleTemplateIR, call: AttachmentCallRef<Input, Output>): CallTargetBindingSlot;
|
|
35
|
+
declare function getCompiledScopeSlot<Value>(template: CompiledModuleTemplateIR, scope: ScopeBlueprint<Value>): ScopeTemplateSlot;
|
|
36
|
+
declare function getCompiledAttachmentSlot<Value>(template: CompiledModuleTemplateIR, attachment: LifetimeAttachmentRef<Value>): AttachmentTemplateSlot;
|
|
37
|
+
export { compiledAttachmentCallRecipe, compiledAttachmentRecipe, compileModuleTemplate, createLocalAttachmentModuleDefinition, getCompiledAttachmentSlot, getCompiledCallTargetBindingSlot, getCompiledScopeSlot, getCompiledTemplateRecord, };
|
|
38
|
+
export type { CompiledModuleTemplateRecord, LocalAttachmentModuleDefinition, RuntimeBlueprint, RuntimeBlueprintRecord };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{declarationId as A}from"@opetope/core";import{hasOwn as w}from"@opetope/core/internal";import{isAttachmentCallRef as T}from"./attachment-call-declaration.js";import{sealScopeBlueprint as k,isScopeBlueprint as b,isLifetimeAttachmentRef as y,getScopeAttachmentRefs as z,getAttachmentDefinition as C}from"./attachment-declaration.js";import{compileCallTargetBindings as R}from"./compile-call-target-bindings.js";import{runtimeIdentity as g}from"./module-runtime-identity.js";const S=new WeakMap,E=new WeakMap,O=new WeakMap,j=new WeakMap,v=new Set(["id","runtime"]),$=/^[A-Za-z][A-Za-z0-9]*$/;function B(t){const e=Object.getPrototypeOf(t);if(e!==Object.prototype&&e!==null)throw new TypeError("Local attachment options must be a plain object.");for(const n of Reflect.ownKeys(t))if(!v.has(n))throw new TypeError(`Unknown local attachment option ${String(n)}.`);if(!w(t,"id")||!w(t,"runtime"))throw new TypeError("Local attachment definition requires own id and runtime fields.")}function D(t){if(typeof t!="object"||t===null)throw new TypeError("Feature runtime must be an object record.");const e=Object.getPrototypeOf(t);if(e!==Object.prototype&&e!==null)throw new TypeError("Feature runtime must be a plain object record.")}function M(t,e){if(!$.test(e))throw new TypeError(`Feature runtime key ${e} must be one identifier segment.`);const n=Object.getOwnPropertyDescriptor(t,e);if(!(n!=null&&n.enumerable))throw new TypeError(`Feature runtime key ${e} must be an enumerable own property.`);const o=Reflect.get(t,e);if(!T(o)&&!b(o)&&!y(o))throw new TypeError(`own.${e} is not a value created by the own builder.`);return Object.freeze({key:e,value:o})}function F(t){D(t);const e=Reflect.ownKeys(t);for(const r of e)if(typeof r!="string")throw new TypeError("Feature runtime keys must be strings.");const n=e;n.sort((r,c)=>r<c?-1:r>c?1:0);const o=n.map(r=>M(t,r));return Object.freeze(o)}function L(t){if(typeof t!="object"||t===null)throw new TypeError("Local attachment options must be an object.");B(t);const e=t.id,n=t.runtime,o=A(e),r=F(n),c=Object.freeze(Object.fromEntries(r.map(s=>[s.key,s.value]))),a=Object.freeze({id:o,runtime:c});return S.set(a,{entries:r,moduleId:o}),a}function I(t){const e=S.get(t);if(e===void 0)throw new TypeError("Local attachment definition is not authentic.");return e}function P(t,e){for(const n of e){const o=j.get(n);if(o!==void 0&&o!==t)throw new TypeError("Runtime blueprint already belongs to another definition.")}}function W(t,e){e.forEach(n=>j.set(n,t))}function x(t){const e=new Set,n=[],o=[],r=[];for(const c of t){if(e.has(c.value))throw new TypeError("A value of the own builder must be returned under exactly one key.");e.add(c.value),b(c.value)?r.push(c):y(c.value)?o.push(c):n.push(c)}return{attachmentCallEntries:Object.freeze(n),attachmentEntries:Object.freeze(o),blueprints:Object.freeze([...e]),scopeEntries:Object.freeze(r)}}function K(t){const e=new Map;return t.forEach((n,o)=>e.set(n.value,o)),e}function Z(t,e){for(const n of t){const o=n.value;for(const r of z(o))if(!e.has(r))throw new TypeError(`Attachment created by scope ${n.key} must be returned under one runtime key.`)}}function q(t){const e=new Map;return t.forEach((n,o)=>e.set(n.value,o)),e}function U(t,e,n){const o=[],r=[];return e.forEach((c,a)=>{const s=c.value,l=C(s),m=n.get(l.owner);if(m===void 0)throw new TypeError(`Attachment runtime key ${c.key} has an owner scope outside this feature runtime.`);const i=a,u=g(t,"attachment",c.key);o.push({identity:u,ownerScopeSlot:m,readiness:l.recipe.readiness,slot:i}),r.push(l.recipe)}),{drafts:o,recipes:Object.freeze(r)}}function G(t,e){const n=Array.from({length:t},()=>({attachmentSlots:[],criticalAttachmentSlots:[],drafts:[]}));for(const o of e){const r=n[o.ownerScopeSlot];if(r===void 0)throw new TypeError(`Attachment slot ${o.slot} lost its owner scope.`);r.attachmentSlots.push(o.slot),r.drafts.push(o),o.readiness==="critical"&&r.criticalAttachmentSlots.push(o.slot)}return n}function H(t,e,n,o){const r=q(e),{drafts:c,recipes:a}=U(t,e,n),s=G(o,c),l=Array.from({length:c.length}),m=s.map(i=>(i.drafts.forEach((u,p)=>{l[u.slot]=Object.freeze({identity:u.identity,ownerScopeSlot:u.ownerScopeSlot,readiness:u.readiness,scopeAttachmentSlot:p,slot:u.slot})}),Object.freeze({attachmentSlots:Object.freeze(i.attachmentSlots),criticalAttachmentSlots:Object.freeze(i.criticalAttachmentSlots)})));if(l.some(i=>i===void 0))throw new TypeError("Compiled attachment graph did not produce every attachment node.");return{attachments:Object.freeze(l),buckets:Object.freeze(m),recipes:a,slots:r}}function J(t,e,n,o){return Object.freeze(e.map(r=>{const c=n.get(r.value);if(c===void 0)throw new TypeError(`Scope runtime key ${r.key} lost its dense slot.`);const a=o[c];if(a===void 0)throw new TypeError(`Scope runtime key ${r.key} lost its attachment bucket.`);const s=g(t,"scope",r.key);return Object.freeze({attachmentSlots:Object.freeze(a.attachmentSlots),criticalAttachmentSlots:Object.freeze(a.criticalAttachmentSlots),identity:s,slot:c})}))}function N(t){const e=E.get(t);if(e!==void 0)return e;const{entries:n,moduleId:o}=I(t),{attachmentCallEntries:r,attachmentEntries:c,blueprints:a,scopeEntries:s}=x(n);P(t,a);const l=new Set(c.map(d=>d.value));Z(s,l);const m=K(s),i=H(o,c,m,s.length),u=J(o,s,m,i.buckets),p=R(o,r,i.attachments,i.slots),h=Object.freeze({attachments:i.attachments,callTargetBindings:p.bindings,moduleId:o,scopes:u});return W(t,a),s.forEach(d=>k(d.value)),O.set(h,{attachmentCallRecipes:p.recipes,attachmentCallSlots:p.slots,attachmentSlots:i.slots,recipes:i.recipes,scopeSlots:m}),E.set(t,h),h}function f(t){const e=O.get(t);if(e===void 0)throw new TypeError("Compiled template is not authentic.");return e}function Q(t,e){const n=t.recipes[e];if(n===void 0)throw new TypeError(`Attachment template slot ${e} is outside this compilation.`);return n}function V(t,e){const n=t.attachmentCallRecipes[e];if(n===void 0)throw new TypeError(`Call-target binding slot ${e} is outside this compilation.`);return n}function X(t,e){const n=f(t).attachmentCallSlots.get(e);if(n===void 0)throw new TypeError("AttachmentCallRef does not belong to this compiled template.");return n}function Y(t,e){const n=f(t).scopeSlots.get(e);if(n===void 0)throw new TypeError("ScopeBlueprint does not belong to this compiled template.");return n}function _(t,e){const n=f(t).attachmentSlots.get(e);if(n===void 0)throw new TypeError("LifetimeAttachmentRef does not belong to this compiled template.");return n}export{N as compileModuleTemplate,V as compiledAttachmentCallRecipe,Q as compiledAttachmentRecipe,L as createLocalAttachmentModuleDefinition,_ as getCompiledAttachmentSlot,X as getCompiledCallTargetBindingSlot,Y as getCompiledScopeSlot,f as getCompiledTemplateRecord};
|
|
2
|
+
//# sourceMappingURL=compile-module-template.js.map
|