@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.
Files changed (314) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +345 -0
  4. package/README.ru.md +344 -0
  5. package/dist/application-compiler-edges.d.ts +3 -0
  6. package/dist/application-compiler-edges.js +2 -0
  7. package/dist/application-compiler-edges.js.map +1 -0
  8. package/dist/application-compiler-graph.d.ts +8 -0
  9. package/dist/application-compiler-graph.js +2 -0
  10. package/dist/application-compiler-graph.js.map +1 -0
  11. package/dist/application-compiler.d.ts +116 -0
  12. package/dist/application-compiler.js +2 -0
  13. package/dist/application-compiler.js.map +1 -0
  14. package/dist/application-conditions.d.ts +18 -0
  15. package/dist/application-conditions.js +2 -0
  16. package/dist/application-conditions.js.map +1 -0
  17. package/dist/application-definition.d.ts +30 -0
  18. package/dist/application-definition.js +2 -0
  19. package/dist/application-definition.js.map +1 -0
  20. package/dist/application-error.d.ts +10 -0
  21. package/dist/application-error.js +2 -0
  22. package/dist/application-error.js.map +1 -0
  23. package/dist/application-execution.d.ts +43 -0
  24. package/dist/application-execution.js +2 -0
  25. package/dist/application-execution.js.map +1 -0
  26. package/dist/application-feature-bindings.d.ts +11 -0
  27. package/dist/application-feature-bindings.js +2 -0
  28. package/dist/application-feature-bindings.js.map +1 -0
  29. package/dist/application-feature-instance.d.ts +5 -0
  30. package/dist/application-feature-instance.js +2 -0
  31. package/dist/application-feature-instance.js.map +1 -0
  32. package/dist/application-group-order.d.ts +29 -0
  33. package/dist/application-group-order.js +2 -0
  34. package/dist/application-group-order.js.map +1 -0
  35. package/dist/application-instance-retirement.d.ts +36 -0
  36. package/dist/application-instance-retirement.js +2 -0
  37. package/dist/application-instance-retirement.js.map +1 -0
  38. package/dist/application-open-options.d.ts +29 -0
  39. package/dist/application-open-options.js +2 -0
  40. package/dist/application-open-options.js.map +1 -0
  41. package/dist/application-port-compiler.d.ts +28 -0
  42. package/dist/application-port-compiler.js +2 -0
  43. package/dist/application-port-compiler.js.map +1 -0
  44. package/dist/attachment-call-declaration.d.ts +43 -0
  45. package/dist/attachment-call-declaration.js +2 -0
  46. package/dist/attachment-call-declaration.js.map +1 -0
  47. package/dist/attachment-declaration.d.ts +68 -0
  48. package/dist/attachment-declaration.js +2 -0
  49. package/dist/attachment-declaration.js.map +1 -0
  50. package/dist/attachment-execution.d.ts +9 -0
  51. package/dist/attachment-execution.js +2 -0
  52. package/dist/attachment-execution.js.map +1 -0
  53. package/dist/attachment-retirement-scheduler.d.ts +14 -0
  54. package/dist/attachment-retirement-scheduler.js +2 -0
  55. package/dist/attachment-retirement-scheduler.js.map +1 -0
  56. package/dist/call-option-snapshot.d.ts +20 -0
  57. package/dist/call-option-snapshot.js +2 -0
  58. package/dist/call-option-snapshot.js.map +1 -0
  59. package/dist/compile-call-target-bindings.d.ts +14 -0
  60. package/dist/compile-call-target-bindings.js +2 -0
  61. package/dist/compile-call-target-bindings.js.map +1 -0
  62. package/dist/compile-module-template.d.ts +38 -0
  63. package/dist/compile-module-template.js +2 -0
  64. package/dist/compile-module-template.js.map +1 -0
  65. package/dist/condition-group-execution.d.ts +44 -0
  66. package/dist/condition-group-execution.js +2 -0
  67. package/dist/condition-group-execution.js.map +1 -0
  68. package/dist/condition-override.d.ts +28 -0
  69. package/dist/condition-override.js +2 -0
  70. package/dist/condition-override.js.map +1 -0
  71. package/dist/condition-source.d.ts +10 -0
  72. package/dist/condition-source.js +2 -0
  73. package/dist/condition-source.js.map +1 -0
  74. package/dist/condition-types.d.ts +14 -0
  75. package/dist/condition.d.ts +28 -0
  76. package/dist/condition.js +2 -0
  77. package/dist/condition.js.map +1 -0
  78. package/dist/control-registry.d.ts +56 -0
  79. package/dist/control-registry.js +2 -0
  80. package/dist/control-registry.js.map +1 -0
  81. package/dist/dynamic-scope-child.d.ts +23 -0
  82. package/dist/dynamic-scope-child.js +2 -0
  83. package/dist/dynamic-scope-child.js.map +1 -0
  84. package/dist/dynamic-scope-controller.d.ts +16 -0
  85. package/dist/dynamic-scope-controller.js +2 -0
  86. package/dist/dynamic-scope-controller.js.map +1 -0
  87. package/dist/feature-attachment-authoring-types.d.ts +51 -0
  88. package/dist/feature-attachment-lowering.d.ts +18 -0
  89. package/dist/feature-attachment-lowering.js +2 -0
  90. package/dist/feature-attachment-lowering.js.map +1 -0
  91. package/dist/feature-attachment.d.ts +45 -0
  92. package/dist/feature-attachment.js +2 -0
  93. package/dist/feature-attachment.js.map +1 -0
  94. package/dist/feature-authoring-types.d.ts +196 -0
  95. package/dist/feature-authoring.d.ts +15 -0
  96. package/dist/feature-authoring.js +2 -0
  97. package/dist/feature-authoring.js.map +1 -0
  98. package/dist/feature-body.d.ts +53 -0
  99. package/dist/feature-body.js +2 -0
  100. package/dist/feature-body.js.map +1 -0
  101. package/dist/feature-call-authority.d.ts +8 -0
  102. package/dist/feature-call-authority.js +2 -0
  103. package/dist/feature-call-authority.js.map +1 -0
  104. package/dist/feature-call-types.d.ts +39 -0
  105. package/dist/feature-call.d.ts +18 -0
  106. package/dist/feature-call.js +2 -0
  107. package/dist/feature-call.js.map +1 -0
  108. package/dist/feature-calls.d.ts +6 -0
  109. package/dist/feature-calls.js +2 -0
  110. package/dist/feature-calls.js.map +1 -0
  111. package/dist/feature-contract.d.ts +70 -0
  112. package/dist/feature-contract.js +2 -0
  113. package/dist/feature-contract.js.map +1 -0
  114. package/dist/feature-contribution-model.d.ts +38 -0
  115. package/dist/feature-contribution-model.js +2 -0
  116. package/dist/feature-contribution-model.js.map +1 -0
  117. package/dist/feature-contribution.d.ts +126 -0
  118. package/dist/feature-contribution.js +2 -0
  119. package/dist/feature-contribution.js.map +1 -0
  120. package/dist/feature-definition-api.d.ts +53 -0
  121. package/dist/feature-definition-support.d.ts +21 -0
  122. package/dist/feature-definition-support.js +2 -0
  123. package/dist/feature-definition-support.js.map +1 -0
  124. package/dist/feature-effect.d.ts +26 -0
  125. package/dist/feature-effect.js +2 -0
  126. package/dist/feature-effect.js.map +1 -0
  127. package/dist/feature-event.d.ts +32 -0
  128. package/dist/feature-event.js +2 -0
  129. package/dist/feature-event.js.map +1 -0
  130. package/dist/feature-generation.d.ts +34 -0
  131. package/dist/feature-generation.js +2 -0
  132. package/dist/feature-generation.js.map +1 -0
  133. package/dist/feature-lazy-generation.d.ts +6 -0
  134. package/dist/feature-lazy-generation.js +2 -0
  135. package/dist/feature-lazy-generation.js.map +1 -0
  136. package/dist/feature-lazy.d.ts +44 -0
  137. package/dist/feature-lazy.js +2 -0
  138. package/dist/feature-lazy.js.map +1 -0
  139. package/dist/feature-materialization-binding.d.ts +31 -0
  140. package/dist/feature-materialization-binding.js +2 -0
  141. package/dist/feature-materialization-binding.js.map +1 -0
  142. package/dist/feature-materialization-types.d.ts +45 -0
  143. package/dist/feature-model-dependencies.d.ts +23 -0
  144. package/dist/feature-model-dependencies.js +2 -0
  145. package/dist/feature-model-dependencies.js.map +1 -0
  146. package/dist/feature-model.d.ts +60 -0
  147. package/dist/feature-model.js +2 -0
  148. package/dist/feature-model.js.map +1 -0
  149. package/dist/feature-optional.d.ts +15 -0
  150. package/dist/feature-optional.js +2 -0
  151. package/dist/feature-optional.js.map +1 -0
  152. package/dist/feature-own-lowering.d.ts +22 -0
  153. package/dist/feature-own-lowering.js +2 -0
  154. package/dist/feature-own-lowering.js.map +1 -0
  155. package/dist/feature-port-binding.d.ts +6 -0
  156. package/dist/feature-port-binding.js +2 -0
  157. package/dist/feature-port-binding.js.map +1 -0
  158. package/dist/feature-port.d.ts +66 -0
  159. package/dist/feature-port.js +2 -0
  160. package/dist/feature-port.js.map +1 -0
  161. package/dist/feature-record.d.ts +6 -0
  162. package/dist/feature-record.js +2 -0
  163. package/dist/feature-record.js.map +1 -0
  164. package/dist/feature-resource.d.ts +29 -0
  165. package/dist/feature-resource.js +2 -0
  166. package/dist/feature-resource.js.map +1 -0
  167. package/dist/feature-scope-types.d.ts +35 -0
  168. package/dist/feature-scope.d.ts +29 -0
  169. package/dist/feature-scope.js +2 -0
  170. package/dist/feature-scope.js.map +1 -0
  171. package/dist/feature-stream.d.ts +37 -0
  172. package/dist/feature-stream.js +2 -0
  173. package/dist/feature-stream.js.map +1 -0
  174. package/dist/feature-timers.d.ts +14 -0
  175. package/dist/feature-timers.js +2 -0
  176. package/dist/feature-timers.js.map +1 -0
  177. package/dist/index.d.ts +19 -0
  178. package/dist/index.js +2 -0
  179. package/dist/index.js.map +1 -0
  180. package/dist/inspection-activity-protocol.d.ts +63 -0
  181. package/dist/inspection-activity.d.ts +54 -0
  182. package/dist/inspection-activity.js +2 -0
  183. package/dist/inspection-activity.js.map +1 -0
  184. package/dist/inspection-diff.d.ts +10 -0
  185. package/dist/inspection-diff.js +2 -0
  186. package/dist/inspection-diff.js.map +1 -0
  187. package/dist/inspection-module-activity.d.ts +4 -0
  188. package/dist/inspection-module-activity.js +2 -0
  189. package/dist/inspection-module-activity.js.map +1 -0
  190. package/dist/inspection-observer.d.ts +38 -0
  191. package/dist/inspection-observer.js +2 -0
  192. package/dist/inspection-observer.js.map +1 -0
  193. package/dist/inspection-plan.d.ts +33 -0
  194. package/dist/inspection-plan.js +2 -0
  195. package/dist/inspection-plan.js.map +1 -0
  196. package/dist/inspection-protocol.d.ts +333 -0
  197. package/dist/inspection-protocol.js +2 -0
  198. package/dist/inspection-protocol.js.map +1 -0
  199. package/dist/inspection-registry.d.ts +41 -0
  200. package/dist/inspection-registry.js +2 -0
  201. package/dist/inspection-registry.js.map +1 -0
  202. package/dist/inspection-session.d.ts +92 -0
  203. package/dist/inspection-session.js +2 -0
  204. package/dist/inspection-session.js.map +1 -0
  205. package/dist/inspection-snapshot.d.ts +4 -0
  206. package/dist/inspection-snapshot.js +2 -0
  207. package/dist/inspection-snapshot.js.map +1 -0
  208. package/dist/inspection-state.d.ts +91 -0
  209. package/dist/inspection-state.js +2 -0
  210. package/dist/inspection-state.js.map +1 -0
  211. package/dist/instance-demand.d.ts +31 -0
  212. package/dist/instance-demand.js +2 -0
  213. package/dist/instance-demand.js.map +1 -0
  214. package/dist/internal.d.ts +41 -0
  215. package/dist/internal.js +2 -0
  216. package/dist/internal.js.map +1 -0
  217. package/dist/keyed-scope-controller.d.ts +11 -0
  218. package/dist/keyed-scope-controller.js +2 -0
  219. package/dist/keyed-scope-controller.js.map +1 -0
  220. package/dist/model-kernel.d.ts +18 -0
  221. package/dist/model-kernel.js +2 -0
  222. package/dist/model-kernel.js.map +1 -0
  223. package/dist/module-call-context.d.ts +7 -0
  224. package/dist/module-call-context.js +2 -0
  225. package/dist/module-call-context.js.map +1 -0
  226. package/dist/module-call-runtime.d.ts +21 -0
  227. package/dist/module-call-runtime.js +2 -0
  228. package/dist/module-call-runtime.js.map +1 -0
  229. package/dist/module-generation.d.ts +57 -0
  230. package/dist/module-generation.js +2 -0
  231. package/dist/module-generation.js.map +1 -0
  232. package/dist/module-instance-types.d.ts +156 -0
  233. package/dist/module-instance.d.ts +19 -0
  234. package/dist/module-instance.js +2 -0
  235. package/dist/module-instance.js.map +1 -0
  236. package/dist/module-runtime-identity.d.ts +4 -0
  237. package/dist/module-runtime-identity.js +2 -0
  238. package/dist/module-runtime-identity.js.map +1 -0
  239. package/dist/module-scope-open.d.ts +4 -0
  240. package/dist/module-scope-open.js +2 -0
  241. package/dist/module-scope-open.js.map +1 -0
  242. package/dist/module-scope-retirement.d.ts +3 -0
  243. package/dist/module-scope-retirement.js +2 -0
  244. package/dist/module-scope-retirement.js.map +1 -0
  245. package/dist/module-template-ir.d.ts +59 -0
  246. package/dist/owner-generation-retirement.d.ts +6 -0
  247. package/dist/owner-generation-retirement.js +2 -0
  248. package/dist/owner-generation-retirement.js.map +1 -0
  249. package/dist/owner-generation-state.d.ts +123 -0
  250. package/dist/owner-generation-state.js +2 -0
  251. package/dist/owner-generation-state.js.map +1 -0
  252. package/dist/owner-generation.d.ts +16 -0
  253. package/dist/owner-generation.js +2 -0
  254. package/dist/owner-generation.js.map +1 -0
  255. package/dist/public-module-definition.d.ts +9 -0
  256. package/dist/public-module-definition.js +2 -0
  257. package/dist/public-module-definition.js.map +1 -0
  258. package/dist/public-module-instance.d.ts +6 -0
  259. package/dist/public-module-instance.js +2 -0
  260. package/dist/public-module-instance.js.map +1 -0
  261. package/dist/public-module-retirement-diagnostics.d.ts +5 -0
  262. package/dist/public-module-retirement-diagnostics.js +2 -0
  263. package/dist/public-module-retirement-diagnostics.js.map +1 -0
  264. package/dist/public-module-retirement.d.ts +3 -0
  265. package/dist/public-module-retirement.js +2 -0
  266. package/dist/public-module-retirement.js.map +1 -0
  267. package/dist/public-module-scope.d.ts +5 -0
  268. package/dist/public-module-scope.js +2 -0
  269. package/dist/public-module-scope.js.map +1 -0
  270. package/dist/public-module-state.d.ts +28 -0
  271. package/dist/public-module-state.js +2 -0
  272. package/dist/public-module-state.js.map +1 -0
  273. package/dist/public-module-types.d.ts +295 -0
  274. package/dist/public-module.d.ts +4 -0
  275. package/dist/resource-cache.d.ts +12 -0
  276. package/dist/resource-cache.js +2 -0
  277. package/dist/resource-cache.js.map +1 -0
  278. package/dist/resource-controller.d.ts +29 -0
  279. package/dist/resource-controller.js +2 -0
  280. package/dist/resource-controller.js.map +1 -0
  281. package/dist/resource-policy.d.ts +16 -0
  282. package/dist/resource-policy.js +2 -0
  283. package/dist/resource-policy.js.map +1 -0
  284. package/dist/resource-snapshot.d.ts +12 -0
  285. package/dist/resource-snapshot.js +2 -0
  286. package/dist/resource-snapshot.js.map +1 -0
  287. package/dist/resource-types.d.ts +3 -0
  288. package/dist/runtime-error-reporting.d.ts +4 -0
  289. package/dist/runtime-error-reporting.js +2 -0
  290. package/dist/runtime-error-reporting.js.map +1 -0
  291. package/dist/stream-backpressure.d.ts +18 -0
  292. package/dist/stream-backpressure.js +2 -0
  293. package/dist/stream-backpressure.js.map +1 -0
  294. package/dist/stream-cleanup.d.ts +17 -0
  295. package/dist/stream-cleanup.js +2 -0
  296. package/dist/stream-cleanup.js.map +1 -0
  297. package/dist/stream-controller-types.d.ts +51 -0
  298. package/dist/stream-controller.d.ts +5 -0
  299. package/dist/stream-controller.js +2 -0
  300. package/dist/stream-controller.js.map +1 -0
  301. package/docs/agent-guide.md +214 -0
  302. package/docs/agent-guide.ru.md +208 -0
  303. package/docs/cookbook.md +734 -0
  304. package/docs/cookbook.ru.md +729 -0
  305. package/docs/decisions.md +1437 -0
  306. package/docs/devtools.md +423 -0
  307. package/docs/devtools.ru.md +419 -0
  308. package/docs/how-it-works.md +521 -0
  309. package/docs/how-it-works.ru.md +495 -0
  310. package/docs/releases.md +78 -0
  311. package/docs/releases.ru.md +78 -0
  312. package/docs/spec.md +874 -0
  313. package/docs/spec.ru.md +884 -0
  314. package/package.json +72 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-model-dependencies.js","sources":["../src/feature-model-dependencies.ts"],"sourcesContent":["import type { Call } from '@opetope/core';\n\nimport type { FeatureImportRef } from './feature-attachment-authoring-types';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport { resolveModuleCallTarget } from './public-module';\nimport type { ModuleCallRef, ModuleInstanceRef } from './public-module';\n\ntype ModelDependencyMap = Readonly<Record<string, object>>;\ntype ModelDependencyRefs<Refs extends ModelDependencyMap, Id extends string> = {\n readonly [Key in keyof Refs]: Refs[Key] extends FeatureImportRef<infer _Value, Id, infer _Mode>\n ? Refs[Key]\n : Refs[Key] extends ModuleCallRef<infer _Input, infer _Output, Id>\n ? Refs[Key]\n : never;\n};\ntype ModelDependencyValues<Refs extends ModelDependencyMap> = {\n readonly [Key in keyof Refs]: Refs[Key] extends FeatureImportRef<infer Value, infer _Id, infer _Mode>\n ? Value\n : Refs[Key] extends ModuleCallRef<infer Input, infer Output, infer _Owner>\n ? Call<Input, Output>\n : never;\n};\ntype ModelDependency =\n | { readonly importKey: string; readonly key: string; readonly kind: 'import' }\n | { readonly key: string; readonly kind: 'call'; readonly ref: object };\n\nfunction snapshotModelDependencies(\n value: unknown,\n importKeyOf: (source: object) => string | undefined,\n isLocalCall: (source: object) => boolean,\n): readonly ModelDependency[] {\n assertPlainRecord(value, 'Feature model dependencies');\n const entries = dataEntries(value, 'Feature model dependencies');\n\n if (entries.length === 0) throw new TypeError('Feature model dependencies must name at least one dependency.');\n\n return Object.freeze(\n entries.map(([key, source]): ModelDependency => {\n if (typeof source === 'object' && source !== null) {\n const importKey = importKeyOf(source);\n\n if (importKey !== undefined) return Object.freeze({ importKey, key, kind: 'import' });\n\n if (isLocalCall(source)) return Object.freeze({ key, kind: 'call', ref: source });\n }\n\n throw new TypeError(`Feature model dependency ${key} must be an import or Call ref of this definition.`);\n }),\n );\n}\n\nfunction resolveModelDependencies(\n dependencies: readonly ModelDependency[] | undefined,\n imports: Readonly<Record<string, unknown>>,\n instance: ModuleInstanceRef,\n): unknown {\n if (dependencies === undefined) return undefined;\n\n return Object.freeze(\n Object.fromEntries(\n dependencies.map(dependency => [\n dependency.key,\n dependency.kind === 'import'\n ? imports[dependency.importKey]\n : resolveModuleCallTarget(instance, dependency.ref as ModuleCallRef<never, unknown>),\n ]),\n ),\n );\n}\n\nexport { resolveModelDependencies, snapshotModelDependencies };\nexport type { ModelDependency, ModelDependencyMap, ModelDependencyRefs, ModelDependencyValues };\n"],"names":["snapshotModelDependencies","value","importKeyOf","isLocalCall","assertPlainRecord","entries","dataEntries","key","source","importKey","resolveModelDependencies","dependencies","imports","instance","dependency","resolveModuleCallTarget"],"mappings":"+IA0BA,SAASA,EACPC,EACAC,EACAC,EAAwC,CAExCC,EAAkBH,EAAO,4BAA4B,EACrD,MAAMI,EAAUC,EAAYL,EAAO,4BAA4B,EAE/D,GAAII,EAAQ,SAAW,EAAG,MAAM,IAAI,UAAU,+DAA+D,EAE7G,OAAO,OAAO,OACZA,EAAQ,IAAI,CAAC,CAACE,EAAKC,CAAM,IAAsB,CAC7C,GAAI,OAAOA,GAAW,UAAYA,IAAW,KAAM,CACjD,MAAMC,EAAYP,EAAYM,CAAM,EAEpC,GAAIC,IAAc,OAAW,OAAO,OAAO,OAAO,CAAE,UAAAA,EAAW,IAAAF,EAAK,KAAM,SAAU,EAEpF,GAAIJ,EAAYK,CAAM,EAAG,OAAO,OAAO,OAAO,CAAE,IAAAD,EAAK,KAAM,OAAQ,IAAKC,EAAQ,CAClF,CAEA,MAAM,IAAI,UAAU,4BAA4BD,CAAG,oDAAoD,CACzG,CAAC,CAAC,CAEN,CAEA,SAASG,EACPC,EACAC,EACAC,EAA2B,CAE3B,GAAIF,IAAiB,OAErB,OAAO,OAAO,OACZ,OAAO,YACLA,EAAa,IAAIG,GAAc,CAC7BA,EAAW,IACXA,EAAW,OAAS,SAChBF,EAAQE,EAAW,SAAS,EAC5BC,EAAwBF,EAAUC,EAAW,GAAoC,EACtF,CAAC,CACH,CAEL"}
@@ -0,0 +1,60 @@
1
+ import type { DeclarationId, ModelContext, ModelOf } from '@opetope/core';
2
+ import type { ModelIdentity } from '@opetope/core/internal';
3
+ import type { ModelDependency, ModelDependencyMap, ModelDependencyRefs, ModelDependencyValues } from './feature-model-dependencies.js';
4
+ import type { FeatureActivityOwner } from './inspection-activity.js';
5
+ import type { ModuleInstanceRef, ModuleRuntimeRefIdentity } from './public-module.js';
6
+ import type { RuntimeErrorReporter } from './runtime-error-reporting.js';
7
+ declare const featureDataRefBrand: unique symbol;
8
+ declare const featureModelBrand: unique symbol;
9
+ type AnyModel = ModelIdentity;
10
+ /**
11
+ * Feature-owned data is a runtime ref of the owning module, but not one of the three kernel ref kinds: a model can
12
+ * never stand in for an attachment, a call or a scope.
13
+ */
14
+ interface FeatureDataRefIdentity<Id extends string = string> extends ModuleRuntimeRefIdentity<Id> {
15
+ readonly [featureDataRefBrand]: true;
16
+ }
17
+ /** A model owned by the feature: the declaration it satisfies is carried covariantly for `bindFeatureModel`. */
18
+ interface FeatureModelRef<Declaration extends AnyModel, Id extends string = string> extends FeatureDataRefIdentity<Id> {
19
+ readonly [featureModelBrand]: () => Declaration;
20
+ }
21
+ type FeatureModelFactory<Declaration extends AnyModel, Source> = (context: ModelContext, source: Source) => ModelOf<Declaration>;
22
+ /**
23
+ * The dependency map determines the factory inputs; the factory cannot widen or replace the selected refs.
24
+ */
25
+ interface FeatureModelBuilder<Id extends string> {
26
+ <Declaration extends AnyModel>(declaration: Declaration, create: (context: ModelContext) => ModelOf<Declaration>): FeatureModelRef<Declaration, Id>;
27
+ <Declaration extends AnyModel, const Refs extends ModelDependencyMap>(declaration: Declaration, dependencies: ModelDependencyRefs<Refs, Id> & Refs, create: FeatureModelFactory<Declaration, NoInfer<ModelDependencyValues<Refs>>>): FeatureModelRef<Declaration, Id>;
28
+ }
29
+ type FeatureDataDescriptor = {
30
+ readonly create: (context: ModelContext, source: unknown) => unknown;
31
+ readonly declaration: AnyModel;
32
+ readonly dependencies: readonly ModelDependency[] | undefined;
33
+ readonly ref: object;
34
+ };
35
+ interface FeatureDataScope {
36
+ readonly drain: () => Promise<void>;
37
+ readonly fence: () => void;
38
+ readonly ownsCall: (target: object) => boolean;
39
+ readonly read: (ref: object) => unknown;
40
+ }
41
+ declare function isFeatureDataRef(value: unknown): boolean;
42
+ /** Registers a model's state and kernel before its factory can run or fail. */
43
+ declare function createFeatureModelOwner(reporter: RuntimeErrorReporter | undefined, activity?: FeatureActivityOwner): {
44
+ readonly create: (featureId: DeclarationId, modelId: string) => ModelContext;
45
+ readonly drain: () => Promise<void>;
46
+ readonly fence: () => void;
47
+ readonly ownsCall: (target: object) => boolean;
48
+ };
49
+ declare function materializeFeatureData(featureId: DeclarationId, descriptors: readonly FeatureDataDescriptor[], imports: Readonly<Record<string, unknown>>, instance: ModuleInstanceRef, reporter: RuntimeErrorReporter, register: (scope: FeatureDataScope) => void, activity?: FeatureActivityOwner): FeatureDataScope;
50
+ declare function registerFeatureDataScope(instance: ModuleInstanceRef, scope: FeatureDataScope): void;
51
+ /** Every model the generation owns, paired with its declaration: the authority a contribution renders with (D70). */
52
+ declare function readInstanceModels(instance: ModuleInstanceRef, descriptors: readonly FeatureDataDescriptor[]): readonly (readonly [AnyModel, unknown])[];
53
+ declare function requireFeatureDataScope(instance: object): FeatureDataScope;
54
+ declare function bindFeatureModel<Declaration extends AnyModel, const Id extends string>(instance: ModuleInstanceRef<Id>, model: FeatureModelRef<Declaration, Id>): ModelOf<Declaration>;
55
+ declare function createFeatureDataAuthoring<Id extends string>(importKeyOf: (source: object) => string | undefined, isLocalCall: (source: object) => boolean): {
56
+ readonly descriptors: readonly FeatureDataDescriptor[];
57
+ readonly model: FeatureModelBuilder<Id>;
58
+ };
59
+ export { bindFeatureModel, createFeatureDataAuthoring, createFeatureModelOwner, isFeatureDataRef, materializeFeatureData, readInstanceModels, registerFeatureDataScope, requireFeatureDataScope, };
60
+ export type { FeatureDataDescriptor, FeatureModelBuilder, FeatureModelRef };
@@ -0,0 +1,2 @@
1
+ import{FeatureError as F}from"@opetope/core";import{createState as M,isCallTarget as g}from"@opetope/core/internal";import{snapshotModelDependencies as S,resolveModelDependencies as j}from"./feature-model-dependencies.js";import{assertPlainRecord as T}from"./feature-record.js";import{createModelKernel as D}from"./model-kernel.js";import{reportRuntimeFailure as d}from"./runtime-error-reporting.js";const m=new WeakSet,w=new WeakMap;function E(){const e=Object.freeze({});return m.add(e),e}function k(e){return typeof e=="object"&&e!==null&&m.has(e)}function C(e){if(typeof e!="object"||e===null)throw new TypeError("Feature model requires a model declaration.");return e}function O(e){if(typeof e!="function")throw new TypeError("Feature model requires a factory function.");return e}function z(e){return typeof e=="object"&&e!==null&&typeof e.getSnapshot=="function"&&typeof e.subscribe=="function"}function R(e,r){for(const[n,o]of Object.entries(r))if(!(z(o)||g(o)||typeof o=="function"))throw new TypeError(`Model ${String(e)}.${n} requires a Readable, a Call or a readable factory.`)}function q(e,r,n,o,c,a,i){return D(r,n.signal,a,t=>o.create(t),(t,s)=>{if(!o.owns(t))throw new TypeError("Model update accepts only state created by this model context.");if(c()){d(new F("retired",e),a);return}t.set(s)},i)}function x(e){const r=new WeakSet;let n=[],o=!1;return Object.freeze({close:()=>{o=!0;const c=n;n=[];for(const a of c)try{a.close()}catch(i){d(i,e)}},create:c=>{if(o)throw new TypeError("Model state is unavailable after retire.");const a=M(c);return r.add(a),n.push(a),a},owns:c=>typeof c=="object"&&c!==null&&r.has(c)})}function h(e,r){const n=new AbortController,o=[],c=[];let a=!1,i;return{create(t,s){if(a)throw new TypeError("Model is unavailable after retire.");const f=x(e);o.push(f);const l=q(t,s,n,f,()=>a,e,r);return c.push(l),l.context},drain:()=>i??(i=(async()=>{for(const t of c.splice(0).reverse())try{await t.drain()}catch(s){d(s,e)}})()),fence(){if(!a){a=!0;for(const t of c)try{t.fence()}catch(s){d(s,e)}n.abort();for(const t of o.splice(0))t.close()}},ownsCall:t=>c.some(s=>s.ownsCall(t))}}function $(e,r,n,o,c,a,i){const t=h(c,i),s=new Map,f=Object.freeze({drain:t.drain,fence:t.fence,ownsCall:t.ownsCall,read:l=>{if(!s.has(l))throw new TypeError("This is not data the instance owns.");return s.get(l)}});a(f);for(const[l,u]of r.entries()){const y=t.create(e,`${e}.model.${String(l+1)}`),b=j(u.dependencies,n,o),p=u.create(y,b);T(p,`Feature model ${String(u.declaration.id)}`),R(u.declaration.id,p),s.set(u.ref,Object.freeze({...p}))}return f}function W(e,r){w.set(e,r)}function A(e,r){const n=w.get(e);return Object.freeze(n===void 0?[]:r.map(o=>[o.declaration,n.read(o.ref)]))}function K(e){const r=w.get(e);if(r===void 0)throw new TypeError("This instance of the feature owns no models.");return r}function P(e,r){const n=[];return{descriptors:n,model:((c,a,i)=>{const t=E(),s=i!==void 0,f=s?S(a,e,r):void 0,l=C(c);return n.push({create:O(s?i:a),declaration:l,dependencies:f,ref:t}),t})}}export{P as createFeatureDataAuthoring,h as createFeatureModelOwner,k as isFeatureDataRef,$ as materializeFeatureData,A as readInstanceModels,W as registerFeatureDataScope,K as requireFeatureDataScope};
2
+ //# sourceMappingURL=feature-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-model.js","sources":["../src/feature-model.ts"],"sourcesContent":["import { FeatureError } from '@opetope/core';\nimport type { DeclarationId, ModelContext, ModelOf, OwnedState, Readable, State } from '@opetope/core';\nimport { createState, isCallTarget } from '@opetope/core/internal';\nimport type { ModelIdentity } from '@opetope/core/internal';\n\nimport { resolveModelDependencies, snapshotModelDependencies } from './feature-model-dependencies';\nimport type {\n ModelDependency,\n ModelDependencyMap,\n ModelDependencyRefs,\n ModelDependencyValues,\n} from './feature-model-dependencies';\nimport { assertPlainRecord } from './feature-record';\nimport type { FeatureActivityOwner } from './inspection-activity';\nimport { createModelKernel } from './model-kernel';\nimport type { ModelKernel } from './model-kernel';\nimport type { ModuleInstanceRef, ModuleRuntimeRefIdentity } from './public-module';\nimport { reportRuntimeFailure } from './runtime-error-reporting';\nimport type { RuntimeErrorReporter } from './runtime-error-reporting';\n\ndeclare const featureDataRefBrand: unique symbol;\ndeclare const featureModelBrand: unique symbol;\n\ntype AnyModel = ModelIdentity;\n\n/**\n * Feature-owned data is a runtime ref of the owning module, but not one of the three kernel ref kinds: a model can\n * never stand in for an attachment, a call or a scope.\n */\ninterface FeatureDataRefIdentity<Id extends string = string> extends ModuleRuntimeRefIdentity<Id> {\n readonly [featureDataRefBrand]: true;\n}\n\n/** A model owned by the feature: the declaration it satisfies is carried covariantly for `bindFeatureModel`. */\ninterface FeatureModelRef<Declaration extends AnyModel, Id extends string = string> extends FeatureDataRefIdentity<Id> {\n readonly [featureModelBrand]: () => Declaration;\n}\n\ntype FeatureModelFactory<Declaration extends AnyModel, Source> = (\n context: ModelContext,\n source: Source,\n) => ModelOf<Declaration>;\n\n/**\n * The dependency map determines the factory inputs; the factory cannot widen or replace the selected refs.\n */\ninterface FeatureModelBuilder<Id extends string> {\n <Declaration extends AnyModel>(\n declaration: Declaration,\n create: (context: ModelContext) => ModelOf<Declaration>,\n ): FeatureModelRef<Declaration, Id>;\n <Declaration extends AnyModel, const Refs extends ModelDependencyMap>(\n declaration: Declaration,\n dependencies: ModelDependencyRefs<Refs, Id> & Refs,\n create: FeatureModelFactory<Declaration, NoInfer<ModelDependencyValues<Refs>>>,\n ): FeatureModelRef<Declaration, Id>;\n}\n\ntype FeatureDataDescriptor = {\n readonly create: (context: ModelContext, source: unknown) => unknown;\n readonly declaration: AnyModel;\n readonly dependencies: readonly ModelDependency[] | undefined;\n readonly ref: object;\n};\n\ninterface FeatureStateCells {\n readonly close: () => void;\n readonly create: <Value>(initial: Value) => State<Value>;\n readonly owns: (value: unknown) => boolean;\n}\n\ninterface FeatureDataScope {\n readonly drain: () => Promise<void>;\n readonly fence: () => void;\n readonly ownsCall: (target: object) => boolean;\n readonly read: (ref: object) => unknown;\n}\n\nconst dataRefs = new WeakSet<object>();\nconst instanceScopes = new WeakMap<object, FeatureDataScope>();\n\nfunction createDataRef(): object {\n const ref = Object.freeze({});\n dataRefs.add(ref);\n\n return ref;\n}\n\nfunction isFeatureDataRef(value: unknown): boolean {\n return typeof value === 'object' && value !== null && dataRefs.has(value);\n}\n\nfunction requireModelDeclaration(value: unknown): AnyModel {\n if (typeof value !== 'object' || value === null) throw new TypeError('Feature model requires a model declaration.');\n\n return value as AnyModel;\n}\n\nfunction requireFactory(value: unknown): (context: ModelContext, source: unknown) => unknown {\n if (typeof value !== 'function') throw new TypeError('Feature model requires a factory function.');\n\n return value as (context: ModelContext, source: unknown) => unknown;\n}\n\n/**\n * The context a model receives. State cells stay private to the context, so `update` accepts only what this model\n * created and a write after the generation is fenced is reported instead of thrown at an unrelated caller. The other\n * members are kernel nodes the model owns: they open with the generation and drain with it (D73).\n */\nfunction isReadableField(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Readable<unknown>).getSnapshot === 'function' &&\n typeof (value as Readable<unknown>).subscribe === 'function'\n );\n}\n\n/**\n * A model is a record of the three shapes `ModelField` allows: a `Readable`, a `Call`, or a factory that returns a\n * readable for a key. Checking it where the record is built names the field, instead of letting a stray value travel\n * To a contribution mount and fail there as an inauthentic command.\n */\nfunction assertModelFields(id: DeclarationId, model: object): void {\n for (const [key, value] of Object.entries(model)) {\n if (isReadableField(value) || isCallTarget(value) || typeof value === 'function') continue;\n\n throw new TypeError(`Model ${String(id)}.${key} requires a Readable, a Call or a readable factory.`);\n }\n}\n\nfunction createFeatureModelKernel(\n featureId: DeclarationId,\n modelId: string,\n controller: AbortController,\n cells: FeatureStateCells,\n isFenced: () => boolean,\n reporter: RuntimeErrorReporter | undefined,\n activity: FeatureActivityOwner | undefined,\n): ModelKernel {\n return createModelKernel(\n modelId,\n controller.signal,\n reporter,\n <Value>(initial: Value): OwnedState<Value> => cells.create(initial) as unknown as OwnedState<Value>,\n <Value>(state: OwnedState<Value>, value: Value): void => {\n if (!cells.owns(state)) throw new TypeError('Model update accepts only state created by this model context.');\n\n if (isFenced()) {\n reportRuntimeFailure(new FeatureError('retired', featureId), reporter);\n\n return;\n }\n\n (state as unknown as State<Value>).set(value);\n },\n activity,\n );\n}\n\nfunction createFeatureStateCells(reporter?: RuntimeErrorReporter): FeatureStateCells {\n const owned = new WeakSet<object>();\n let open: State<unknown>[] = [];\n let closed = false;\n\n return Object.freeze({\n close: (): void => {\n closed = true;\n const closing = open;\n open = [];\n\n for (const cell of closing) {\n try {\n cell.close();\n } catch (error) {\n reportRuntimeFailure(error, reporter);\n }\n }\n },\n create: <Value>(initial: Value): State<Value> => {\n if (closed) throw new TypeError('Model state is unavailable after retire.');\n\n const cell = createState(initial);\n owned.add(cell);\n open.push(cell as State<unknown>);\n\n return cell;\n },\n owns: (value: unknown): boolean => typeof value === 'object' && value !== null && owned.has(value),\n });\n}\n\n/** Registers a model's state and kernel before its factory can run or fail. */\nfunction createFeatureModelOwner(\n reporter: RuntimeErrorReporter | undefined,\n activity?: FeatureActivityOwner,\n): {\n readonly create: (featureId: DeclarationId, modelId: string) => ModelContext;\n readonly drain: () => Promise<void>;\n readonly fence: () => void;\n readonly ownsCall: (target: object) => boolean;\n} {\n const controller = new AbortController();\n const cells: FeatureStateCells[] = [];\n const kernels: ModelKernel[] = [];\n let fenced = false;\n let drain: Promise<void> | undefined;\n\n return {\n create(featureId, modelId) {\n if (fenced) throw new TypeError('Model is unavailable after retire.');\n\n const owned = createFeatureStateCells(reporter);\n cells.push(owned);\n const kernel = createFeatureModelKernel(featureId, modelId, controller, owned, () => fenced, reporter, activity);\n kernels.push(kernel);\n\n return kernel.context;\n },\n drain: () =>\n (drain ??= (async () => {\n for (const kernel of kernels.splice(0).reverse()) {\n try {\n await kernel.drain();\n } catch (error) {\n reportRuntimeFailure(error, reporter);\n }\n }\n })()),\n fence() {\n if (fenced) return;\n\n fenced = true;\n\n for (const kernel of kernels) {\n try {\n kernel.fence();\n } catch (error) {\n reportRuntimeFailure(error, reporter);\n }\n }\n\n controller.abort();\n\n for (const owned of cells.splice(0)) owned.close();\n },\n ownsCall: (target: object): boolean => kernels.some(kernel => kernel.ownsCall(target)),\n };\n}\n\nfunction materializeFeatureData(\n featureId: DeclarationId,\n descriptors: readonly FeatureDataDescriptor[],\n imports: Readonly<Record<string, unknown>>,\n instance: ModuleInstanceRef,\n reporter: RuntimeErrorReporter,\n register: (scope: FeatureDataScope) => void,\n activity?: FeatureActivityOwner,\n): FeatureDataScope {\n const owner = createFeatureModelOwner(reporter, activity);\n const values = new Map<object, unknown>();\n const scope: FeatureDataScope = Object.freeze({\n drain: owner.drain,\n fence: owner.fence,\n ownsCall: owner.ownsCall,\n read: (ref: object): unknown => {\n if (!values.has(ref)) throw new TypeError('This is not data the instance owns.');\n\n return values.get(ref);\n },\n });\n register(scope);\n\n for (const [index, descriptor] of descriptors.entries()) {\n const context = owner.create(featureId, `${featureId}.model.${String(index + 1)}`);\n const source = resolveModelDependencies(descriptor.dependencies, imports, instance);\n const model = descriptor.create(context, source);\n assertPlainRecord(model, `Feature model ${String(descriptor.declaration.id)}`);\n assertModelFields(descriptor.declaration.id, model);\n values.set(descriptor.ref, Object.freeze({ ...model }));\n }\n\n return scope;\n}\n\nfunction registerFeatureDataScope(instance: ModuleInstanceRef, scope: FeatureDataScope): void {\n instanceScopes.set(instance, scope);\n}\n\n/** Every model the generation owns, paired with its declaration: the authority a contribution renders with (D70). */\nfunction readInstanceModels(\n instance: ModuleInstanceRef,\n descriptors: readonly FeatureDataDescriptor[],\n): readonly (readonly [AnyModel, unknown])[] {\n const scope = instanceScopes.get(instance);\n\n if (scope === undefined) return Object.freeze([]);\n\n return Object.freeze(descriptors.map(descriptor => [descriptor.declaration, scope.read(descriptor.ref)] as const));\n}\n\nfunction requireFeatureDataScope(instance: object): FeatureDataScope {\n const scope = instanceScopes.get(instance);\n\n if (scope === undefined) throw new TypeError('This instance of the feature owns no models.');\n\n return scope;\n}\n\nfunction bindFeatureModel<Declaration extends AnyModel, const Id extends string>(\n instance: ModuleInstanceRef<Id>,\n model: FeatureModelRef<Declaration, Id>,\n): ModelOf<Declaration>;\nfunction bindFeatureModel(instance: object, model: object): unknown {\n return requireFeatureDataScope(instance).read(model);\n}\n\nfunction createFeatureDataAuthoring<Id extends string>(\n importKeyOf: (source: object) => string | undefined,\n isLocalCall: (source: object) => boolean,\n): {\n readonly descriptors: readonly FeatureDataDescriptor[];\n readonly model: FeatureModelBuilder<Id>;\n} {\n const descriptors: FeatureDataDescriptor[] = [];\n const model = ((declaration: unknown, second: unknown, third?: unknown) => {\n const ref = createDataRef();\n const hasSource = third !== undefined;\n const dependencies = hasSource ? snapshotModelDependencies(second, importKeyOf, isLocalCall) : undefined;\n\n const modelDeclaration = requireModelDeclaration(declaration);\n descriptors.push({\n create: requireFactory(hasSource ? third : second),\n declaration: modelDeclaration,\n dependencies,\n ref,\n });\n\n return ref;\n }) as unknown as FeatureModelBuilder<Id>;\n\n return { descriptors, model };\n}\n\nexport {\n bindFeatureModel,\n createFeatureDataAuthoring,\n createFeatureModelOwner,\n isFeatureDataRef,\n materializeFeatureData,\n readInstanceModels,\n registerFeatureDataScope,\n requireFeatureDataScope,\n};\nexport type { FeatureDataDescriptor, FeatureModelBuilder, FeatureModelRef };\n"],"names":["dataRefs","instanceScopes","createDataRef","ref","isFeatureDataRef","value","requireModelDeclaration","requireFactory","isReadableField","assertModelFields","id","model","key","isCallTarget","createFeatureModelKernel","featureId","modelId","controller","cells","isFenced","reporter","activity","createModelKernel","initial","state","reportRuntimeFailure","FeatureError","createFeatureStateCells","owned","open","closed","closing","cell","error","createState","createFeatureModelOwner","kernels","fenced","drain","kernel","target","materializeFeatureData","descriptors","imports","instance","register","owner","values","scope","index","descriptor","context","source","resolveModelDependencies","assertPlainRecord","registerFeatureDataScope","readInstanceModels","requireFeatureDataScope","createFeatureDataAuthoring","importKeyOf","isLocalCall","declaration","second","third","hasSource","dependencies","snapshotModelDependencies","modelDeclaration"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { Port } from '@opetope/core';
2
+ import type { DirectImportDeclaration, FeatureImportDeclaration, OptionalHostContract } from './feature-contract.js';
3
+ import type { OptionalPort } from './feature-port.js';
4
+ /**
5
+ * One word for both edges: `optional(x)` in `imports` and `optional(port)` in `requires`. A weak edge lets the
6
+ * consumer outlive the provider: it never pulls the provider into the world, never orders activation, and the
7
+ * containment law of `when` does not apply to it (D105). The port overload names the branded `Port`, because a port
8
+ * identity is structurally just `{ id }` and every host contract would match it.
9
+ */
10
+ interface OptionalDeclaration {
11
+ <Declaration extends FeatureImportDeclaration>(source: DirectImportDeclaration<Declaration>): OptionalHostContract<Declaration>;
12
+ <PortType extends Port<never, unknown>>(port: PortType): OptionalPort<PortType>;
13
+ }
14
+ declare const optional: OptionalDeclaration;
15
+ export { optional };
@@ -0,0 +1,2 @@
1
+ import{isPort as t}from"@opetope/core/internal";import{optionalImport as r}from"./feature-contract.js";import{optionalPort as i,isOptionalPortRequirement as n}from"./feature-port.js";const p=(o=>{if(t(o))return i(o);if(n(o))throw new TypeError("optional requires one direct authentic Port.");return r(o)});export{p as optional};
2
+ //# sourceMappingURL=feature-optional.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-optional.js","sources":["../src/feature-optional.ts"],"sourcesContent":["import type { Port } from '@opetope/core';\nimport { isPort } from '@opetope/core/internal';\n\nimport type { DirectImportDeclaration, FeatureImportDeclaration, OptionalHostContract } from './feature-contract';\nimport { optionalImport } from './feature-contract';\nimport type { OptionalPort } from './feature-port';\nimport { isOptionalPortRequirement, optionalPort } from './feature-port';\n\n/**\n * One word for both edges: `optional(x)` in `imports` and `optional(port)` in `requires`. A weak edge lets the\n * consumer outlive the provider: it never pulls the provider into the world, never orders activation, and the\n * containment law of `when` does not apply to it (D105). The port overload names the branded `Port`, because a port\n * identity is structurally just `{ id }` and every host contract would match it.\n */\ninterface OptionalDeclaration {\n <Declaration extends FeatureImportDeclaration>(\n source: DirectImportDeclaration<Declaration>,\n ): OptionalHostContract<Declaration>;\n <PortType extends Port<never, unknown>>(port: PortType): OptionalPort<PortType>;\n}\n\nconst optional = ((source: unknown) => {\n if (isPort(source)) return optionalPort(source);\n\n if (isOptionalPortRequirement(source)) throw new TypeError('optional requires one direct authentic Port.');\n\n return optionalImport(source as FeatureImportDeclaration);\n}) as OptionalDeclaration;\n\nexport { optional };\n"],"names":["optional","source","isPort","optionalPort","isOptionalPortRequirement","optionalImport"],"mappings":"uLAqBA,MAAMA,GAAaC,GAAmB,CACpC,GAAIC,EAAOD,CAAM,EAAG,OAAOE,EAAaF,CAAM,EAE9C,GAAIG,EAA0BH,CAAM,EAAG,MAAM,IAAI,UAAU,8CAA8C,EAEzG,OAAOI,EAAeJ,CAAkC,CAC1D"}
@@ -0,0 +1,22 @@
1
+ import type { FeatureOwnBuilder, FeatureOwnRecord } from './feature-authoring-types.js';
2
+ import type { FeatureImportRecord } from './feature-contract.js';
3
+ import type { FeatureDataDescriptor } from './feature-model.js';
4
+ import type { PortRequirementRecord } from './feature-port.js';
5
+ import type { ModuleRuntimeBuilder, ModuleRuntimeRecord } from './public-module.js';
6
+ type FeatureRuntimeLoweringOptions<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>, Requires extends PortRequirementRecord> = {
7
+ readonly build: (builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime;
8
+ readonly id: Id;
9
+ readonly importKeys: readonly string[];
10
+ readonly imports: Imports;
11
+ readonly requirementKeys: readonly string[];
12
+ };
13
+ type FeatureOwnLoweringResult<Id extends string, Runtime extends FeatureOwnRecord<Id>> = {
14
+ readonly dataDescriptors: readonly FeatureDataDescriptor[];
15
+ readonly importScopeKey: string | undefined;
16
+ readonly loweredRuntime: ModuleRuntimeRecord<Id>;
17
+ readonly publicRuntime: Runtime;
18
+ readonly requirementScopeKey: string | undefined;
19
+ };
20
+ declare function lowerFeatureOwn<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>, Requires extends PortRequirementRecord>(low: ModuleRuntimeBuilder<Id>, options: FeatureRuntimeLoweringOptions<Id, Imports, Runtime, Requires>): FeatureOwnLoweringResult<Id, Runtime>;
21
+ export { lowerFeatureOwn };
22
+ export type { FeatureOwnLoweringResult };
@@ -0,0 +1,2 @@
1
+ import{CallError as b}from"@opetope/core";import{configureAttachmentCall as w,isAttachmentCallRef as g,getAttachmentCallRecipe as O}from"./attachment-call-declaration.js";import{createAttachmentRecipe as A}from"./feature-attachment.js";import{requirementAttachmentSource as z,selectFeatureAttachmentArguments as C,selectAttachmentLowering as S}from"./feature-attachment-lowering.js";import{createFeatureCallAuthoring as F}from"./feature-call.js";import{projectCallContext as q}from"./feature-call-authority.js";import{createCallsOperationEntries as y}from"./feature-calls.js";import{indexRuntimeIdentities as v,allocateHiddenKey as h}from"./feature-definition-support.js";import{createFeatureEffectBuilder as E}from"./feature-effect.js";import{createFeatureEventBuilder as K}from"./feature-event.js";import{createFeatureDataAuthoring as B,isFeatureDataRef as M}from"./feature-model.js";import{assertPlainRecord as x,dataEntries as W}from"./feature-record.js";import{createFeatureResourceBuilder as k}from"./feature-resource.js";import{createFeatureScopeBuilder as D}from"./feature-scope.js";import{createFeatureStreamBuilder as I}from"./feature-stream.js";function T(a,n,t){const r={},i=new WeakMap,o=n.length===0?void 0:a.scope(),l=t.length===0?void 0:a.scope();if(o!==void 0)for(const f of n){const c=Object.freeze({});r[f]=c,i.set(c,f)}return Object.freeze({importRefKeys:i,importRefs:Object.freeze(r),importScope:o,requirementScope:l})}function $(a,n){const t=[],r=new WeakMap,i=(o,l,f)=>{const{options:c,source:s}=C(o,l,n.importRefKeys),{projection:u,scope:m}=S(n.importScope,n.requirementScope,a,s),e=A(m,u.select,c);return r.set(e,u),f===void 0?t.push({attachment:e}):t.push({attachment:e,hiddenKey:f}),e};return Object.freeze({attach:i,createAttachment:i,projections:r,recipes:t})}function H(a,n,t){const r=F(n,c=>t.projections.has(c)),i=c=>{const s=r.snapshotCall(c),u=t.projections.get(s.within);if(u===void 0)throw new TypeError("own.call needs within from the same feature: pass what own.attach returned here.");const m=s.within,e=(d,R)=>s.run(d,q(R,u)),p=a.call({run:e,within:m});return w(p,{nestedFeatureCalls:!0,policy:s.policy}),p},o=new WeakMap,l=c=>{if(t.projections.has(c))return c;const s=o.get(c);if(s!==void 0)return s;const u=t.createAttachment(c,void 0,"callsSource");return o.set(c,u),u};return Object.freeze({call:i,calls:(c,s)=>{const u=l(c),m=t.projections.get(u);if(m===void 0)throw new TypeError("own.calls needs a source from the same feature: an import or what own.attach returned.");const e=y(u,s,m.exposure);return Object.freeze(Object.fromEntries(e.map(([p,d])=>[p,i(d)])))},lane:r.lane})}function j(a,n,t,r){if(r===void 0)return;const i=h(n,t);return a[i]=r,i}function L(a,n,t){t.hiddenKey!==void 0&&(a[h(n,t.hiddenKey)]=t.attachment)}function P(a,n,t,r,i){const o={},l=v(a),f=new Set(a.map(([e])=>e)),c=j(o,f,"featureImports",n.importScope),s=j(o,f,"featureRequirements",n.requirementScope);for(const e of t)L(o,f,e);const u=new Set;for(const e of r)l.get(e.ref)===void 0&&!u.has(e.ref)&&(o[h(f,e.preferred)]=e.ref,u.add(e.ref));const m=Object.fromEntries(a.filter(([,e])=>!M(e)));return Object.freeze({dataDescriptors:i,importScopeKey:c,loweredRuntime:Object.freeze({...m,...o}),requirementScopeKey:s})}function U(a,n,t){if(a.length===0)return Object.freeze({privateRefs:Object.freeze([]),refs:Object.freeze({})});const r=n.createAttachment(z,void 0,"featureRequirements"),i=a.map(o=>{const l=(f,c)=>{const s=c.source[o];if(s===void 0)throw new b("unavailable",`Feature requirement ${o} has no provider.`);return c.invoke(s,f)};return[o,t.call({run:l,within:r})]});return Object.freeze({privateRefs:Object.freeze(i.map(([o,l])=>{var f;return{preferred:`require${((f=o[0])==null?void 0:f.toUpperCase())??""}${o.slice(1)}`,ref:l}})),refs:Object.freeze(Object.fromEntries(i))})}function G(a,n){const t=T(a,n.importKeys,n.requirementKeys),r=$(n.imports,t),i=H(a,n.id,r),o=B(e=>t.importRefKeys.get(e),e=>g(e)&&r.projections.has(O(e).within)),l=U(n.requirementKeys,r,i),f=Object.freeze({attach:r.attach,call:i.call,calls:i.calls,effect:E(r.attach),event:K(r.attach),imports:t.importRefs,lane:i.lane,model:o.model,requires:l.refs,resource:k(r.attach),scope:D(n.id,r.attach),stream:I(r.attach)}),c=n.build(f);x(c,"defineFeature own result");const s=W(c,"defineFeature own result"),u=Object.freeze(Object.fromEntries(s)),m=P(s,t,r.recipes,[...l.privateRefs,...o.descriptors.flatMap(e=>(e.dependencies??[]).flatMap(p=>p.kind==="call"?[{preferred:"modelDependency",ref:p.ref}]:[]))],o.descriptors);return Object.freeze({...m,publicRuntime:u})}export{G as lowerFeatureOwn};
2
+ //# sourceMappingURL=feature-own-lowering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-own-lowering.js","sources":["../src/feature-own-lowering.ts"],"sourcesContent":["import { CallError } from '@opetope/core';\n\nimport { configureAttachmentCall, getAttachmentCallRecipe, isAttachmentCallRef } from './attachment-call-declaration';\nimport type { AttachmentCallRef } from './attachment-call-declaration';\nimport { createAttachmentRecipe } from './feature-attachment';\nimport type {\n FeatureAttachBuilder,\n FeatureCallsBuilder,\n FeatureImportRef,\n FeatureImportRefs,\n} from './feature-attachment-authoring-types';\nimport {\n requirementAttachmentSource,\n selectAttachmentLowering,\n selectFeatureAttachmentArguments,\n} from './feature-attachment-lowering';\nimport type {\n AttachmentProjection,\n AttachmentRecipe,\n FeatureCallBuilder,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n} from './feature-authoring-types';\nimport { createFeatureCallAuthoring } from './feature-call';\nimport { projectCallContext } from './feature-call-authority';\nimport type { FeatureCallLaneBuilder } from './feature-call-types';\nimport { createCallsOperationEntries } from './feature-calls';\nimport type { FeatureImportRecord, FeatureImportValues } from './feature-contract';\nimport { allocateHiddenKey, indexRuntimeIdentities } from './feature-definition-support';\nimport { createFeatureEffectBuilder } from './feature-effect';\nimport { createFeatureEventBuilder } from './feature-event';\nimport { createFeatureDataAuthoring, isFeatureDataRef } from './feature-model';\nimport type { FeatureDataDescriptor } from './feature-model';\nimport type { FeatureRequiredCalls, PortRequirementRecord } from './feature-port';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport { createFeatureResourceBuilder } from './feature-resource';\nimport { createFeatureScopeBuilder } from './feature-scope';\nimport { createFeatureStreamBuilder } from './feature-stream';\nimport type {\n ModuleAttachmentRef,\n ModuleCallContext,\n ModuleRuntimeBuilder,\n ModuleRuntimeRecord,\n ModuleRuntimeRef,\n ModuleScopeRef,\n} from './public-module';\n\ntype CreateAttachment<Id extends string> = (\n first: unknown,\n second?: unknown,\n hiddenKey?: string,\n) => ModuleAttachmentRef<unknown, Id>;\n\ntype PrivateRuntimeRef<Id extends string> = {\n readonly preferred: string;\n readonly ref: ModuleRuntimeRef<Id>;\n};\n\ntype RuntimeScopeAuthoring<Id extends string, Imports extends FeatureImportRecord> = {\n readonly importRefKeys: Readonly<WeakMap<object, string>>;\n readonly importRefs: FeatureImportRefs<Id, Imports>;\n readonly importScope: ModuleScopeRef<FeatureImportValues<Imports>, Id> | undefined;\n readonly requirementScope: ModuleScopeRef<Readonly<Record<string, object>>, Id> | undefined;\n};\n\ntype RuntimeAttachmentAuthoring<Id extends string, Imports extends FeatureImportRecord> = {\n readonly attach: FeatureAttachBuilder<Id, Imports>;\n readonly createAttachment: CreateAttachment<Id>;\n readonly projections: Readonly<WeakMap<object, AttachmentProjection>>;\n readonly recipes: readonly AttachmentRecipe<Id>[];\n};\n\ntype RuntimeCallAuthoring<Id extends string> = {\n readonly call: FeatureCallBuilder<Id>;\n readonly calls: FeatureCallsBuilder<Id>;\n readonly lane: FeatureCallLaneBuilder<Id>;\n};\n\ntype FeatureRuntimeLoweringOptions<\n Id extends string,\n Imports extends FeatureImportRecord,\n Runtime extends FeatureOwnRecord<Id>,\n Requires extends PortRequirementRecord,\n> = {\n readonly build: (builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime;\n readonly id: Id;\n readonly importKeys: readonly string[];\n readonly imports: Imports;\n readonly requirementKeys: readonly string[];\n};\n\ntype FeatureOwnLoweringResult<Id extends string, Runtime extends FeatureOwnRecord<Id>> = {\n readonly dataDescriptors: readonly FeatureDataDescriptor[];\n readonly importScopeKey: string | undefined;\n readonly loweredRuntime: ModuleRuntimeRecord<Id>;\n readonly publicRuntime: Runtime;\n readonly requirementScopeKey: string | undefined;\n};\n\nfunction createRuntimeScopeAuthoring<Id extends string, Imports extends FeatureImportRecord>(\n low: ModuleRuntimeBuilder<Id>,\n importKeys: readonly string[],\n requirementKeys: readonly string[],\n): RuntimeScopeAuthoring<Id, Imports> {\n const importRefs: Record<string, FeatureImportRef<unknown, Id, 'adapter-method' | 'feature-call-target'>> = {};\n const importRefKeys = new WeakMap<object, string>();\n const importScope = importKeys.length === 0 ? undefined : low.scope<FeatureImportValues<Imports>>();\n const requirementScope = requirementKeys.length === 0 ? undefined : low.scope<Readonly<Record<string, object>>>();\n\n if (importScope !== undefined) {\n for (const importKey of importKeys) {\n const ref = Object.freeze({}) as FeatureImportRef<unknown, Id, 'adapter-method' | 'feature-call-target'>;\n importRefs[importKey] = ref;\n importRefKeys.set(ref, importKey);\n }\n }\n\n return Object.freeze({\n importRefKeys,\n importRefs: Object.freeze(importRefs) as unknown as FeatureImportRefs<Id, Imports>,\n importScope,\n requirementScope,\n });\n}\n\nfunction createRuntimeAttachmentAuthoring<Id extends string, Imports extends FeatureImportRecord>(\n imports: Imports,\n scopes: RuntimeScopeAuthoring<Id, Imports>,\n): RuntimeAttachmentAuthoring<Id, Imports> {\n const recipes: AttachmentRecipe<Id>[] = [];\n const projections = new WeakMap<object, AttachmentProjection>();\n const createAttachment: CreateAttachment<Id> = (first, second, hiddenKey) => {\n const { options, source } = selectFeatureAttachmentArguments(first, second, scopes.importRefKeys);\n const { projection, scope } = selectAttachmentLowering(\n scopes.importScope,\n scopes.requirementScope,\n imports,\n source,\n );\n const attachment = createAttachmentRecipe(scope, projection.select, options);\n projections.set(attachment, projection);\n\n if (hiddenKey === undefined) recipes.push({ attachment });\n else recipes.push({ attachment, hiddenKey });\n\n return attachment;\n };\n\n return Object.freeze({\n attach: createAttachment as unknown as FeatureAttachBuilder<Id, Imports>,\n createAttachment,\n projections,\n recipes,\n });\n}\n\nfunction createRuntimeCallAuthoring<Id extends string, Imports extends FeatureImportRecord>(\n low: ModuleRuntimeBuilder<Id>,\n id: Id,\n attachments: RuntimeAttachmentAuthoring<Id, Imports>,\n): RuntimeCallAuthoring<Id> {\n const callAuthoring = createFeatureCallAuthoring(id, value => attachments.projections.has(value));\n const createCall = (value: unknown): ModuleRuntimeRef<Id> => {\n const operation = callAuthoring.snapshotCall(value);\n const projection = attachments.projections.get(operation.within);\n\n if (projection === undefined) {\n throw new TypeError('own.call needs within from the same feature: pass what own.attach returned here.');\n }\n\n const erasedWithin = operation.within as unknown as ModuleAttachmentRef<unknown, Id>;\n const run = (input: unknown, context: ModuleCallContext<unknown>): unknown =>\n operation.run(input, projectCallContext(context, projection));\n const created = low.call({ run, within: erasedWithin });\n configureAttachmentCall(created as unknown as AttachmentCallRef<unknown, unknown>, {\n nestedFeatureCalls: true,\n policy: operation.policy,\n });\n\n return created;\n };\n const implicitAttachments = new WeakMap<object, object>();\n /** `calls(imports.x, keys)` needs no `attach`: a source without open/close gets one implicit attachment. */\n const resolveCallsTarget = (within: object): object => {\n if (attachments.projections.has(within)) return within;\n\n const existing = implicitAttachments.get(within);\n\n if (existing !== undefined) return existing;\n\n const created = attachments.createAttachment(within, undefined, 'callsSource');\n implicitAttachments.set(within, created);\n\n return created;\n };\n const createAdapterCalls = (source: object, keys: unknown): Readonly<Record<string, ModuleRuntimeRef<Id>>> => {\n const within = resolveCallsTarget(source);\n const projection = attachments.projections.get(within);\n\n if (projection === undefined) {\n throw new TypeError('own.calls needs a source from the same feature: an import or what own.attach returned.');\n }\n\n const entries = createCallsOperationEntries(within, keys, projection.exposure);\n\n return Object.freeze(Object.fromEntries(entries.map(([key, operation]) => [key, createCall(operation)])));\n };\n\n return Object.freeze({\n call: createCall as FeatureCallBuilder<Id>,\n calls: createAdapterCalls as FeatureCallsBuilder<Id>,\n lane: callAuthoring.lane as FeatureCallLaneBuilder<Id>,\n });\n}\n\nfunction registerHiddenScope<Id extends string>(\n hidden: Record<string, ModuleRuntimeRef<Id>>,\n runtimeKeys: Set<string>,\n preferred: string,\n scope: ModuleRuntimeRef<Id> | undefined,\n): string | undefined {\n if (scope === undefined) return undefined;\n\n const key = allocateHiddenKey(runtimeKeys, preferred);\n hidden[key] = scope;\n\n return key;\n}\n\n/** A hidden attachment (`calls(imports.x)`, the requirements scope) still needs a runtime key of its own. */\nfunction lowerAttachmentRecipe<Id extends string>(\n hidden: Record<string, ModuleRuntimeRef<Id>>,\n runtimeKeys: Set<string>,\n recipe: AttachmentRecipe<Id>,\n): void {\n if (recipe.hiddenKey === undefined) return;\n\n hidden[allocateHiddenKey(runtimeKeys, recipe.hiddenKey)] = recipe.attachment;\n}\n\nfunction finalizeRuntimeLowering<\n Id extends string,\n Imports extends FeatureImportRecord,\n Runtime extends FeatureOwnRecord<Id>,\n>(\n runtimeEntries: readonly (readonly [string, unknown])[],\n scopes: RuntimeScopeAuthoring<Id, Imports>,\n recipes: readonly AttachmentRecipe<Id>[],\n privateRefs: readonly PrivateRuntimeRef<Id>[],\n dataDescriptors: readonly FeatureDataDescriptor[],\n): Omit<FeatureOwnLoweringResult<Id, Runtime>, 'publicRuntime'> {\n const hidden: Record<string, ModuleRuntimeRef<Id>> = {};\n const runtimeIdentities = indexRuntimeIdentities(runtimeEntries);\n const runtimeKeys = new Set(runtimeEntries.map(([key]) => key));\n const importScopeKey = registerHiddenScope(hidden, runtimeKeys, 'featureImports', scopes.importScope);\n const requirementScopeKey = registerHiddenScope(hidden, runtimeKeys, 'featureRequirements', scopes.requirementScope);\n\n for (const recipe of recipes) lowerAttachmentRecipe(hidden, runtimeKeys, recipe);\n\n const registered = new Set<object>();\n\n for (const privateRef of privateRefs) {\n if (runtimeIdentities.get(privateRef.ref) === undefined && !registered.has(privateRef.ref)) {\n hidden[allocateHiddenKey(runtimeKeys, privateRef.preferred)] = privateRef.ref;\n registered.add(privateRef.ref);\n }\n }\n\n const moduleRuntime = Object.fromEntries(\n runtimeEntries.filter(([, value]) => !isFeatureDataRef(value)),\n ) as ModuleRuntimeRecord<Id>;\n\n return Object.freeze({\n dataDescriptors,\n importScopeKey,\n loweredRuntime: Object.freeze({ ...moduleRuntime, ...hidden }),\n requirementScopeKey,\n });\n}\n\n/** Every requirement is lowered to one call of the hidden requirements attachment, so `requires.x` is a real ref. */\nfunction createRequirementCalls<Id extends string, Imports extends FeatureImportRecord>(\n requirementKeys: readonly string[],\n attachments: RuntimeAttachmentAuthoring<Id, Imports>,\n calls: RuntimeCallAuthoring<Id>,\n): Readonly<{ privateRefs: readonly PrivateRuntimeRef<Id>[]; refs: Readonly<Record<string, ModuleRuntimeRef<Id>>> }> {\n if (requirementKeys.length === 0) return Object.freeze({ privateRefs: Object.freeze([]), refs: Object.freeze({}) });\n\n const within = attachments.createAttachment(requirementAttachmentSource, undefined, 'featureRequirements');\n const entries = requirementKeys.map(key => {\n const run = (\n input: unknown,\n context: {\n readonly invoke: (target: unknown, input: unknown) => unknown;\n readonly source: Readonly<Record<string, unknown>>;\n },\n ): unknown => {\n const target = context.source[key];\n\n // A weak port without a provider settles instead of failing the consumer (D105).\n if (target === undefined) throw new CallError('unavailable', `Feature requirement ${key} has no provider.`);\n\n return context.invoke(target, input);\n };\n\n return [key, calls.call({ run, within } as never)] as const;\n });\n\n return Object.freeze({\n privateRefs: Object.freeze(\n entries.map(([key, ref]) => ({ preferred: `require${key[0]?.toUpperCase() ?? ''}${key.slice(1)}`, ref })),\n ),\n refs: Object.freeze(Object.fromEntries(entries)),\n });\n}\n\nfunction lowerFeatureOwn<\n Id extends string,\n Imports extends FeatureImportRecord,\n Runtime extends FeatureOwnRecord<Id>,\n Requires extends PortRequirementRecord,\n>(\n low: ModuleRuntimeBuilder<Id>,\n options: FeatureRuntimeLoweringOptions<Id, Imports, Runtime, Requires>,\n): FeatureOwnLoweringResult<Id, Runtime> {\n const scopes = createRuntimeScopeAuthoring<Id, Imports>(low, options.importKeys, options.requirementKeys);\n const attachments = createRuntimeAttachmentAuthoring(options.imports, scopes);\n const calls = createRuntimeCallAuthoring(low, options.id, attachments);\n const data = createFeatureDataAuthoring<Id>(\n source => scopes.importRefKeys.get(source),\n source =>\n isAttachmentCallRef(source) &&\n attachments.projections.has(getAttachmentCallRecipe(source as AttachmentCallRef<unknown, unknown>).within),\n );\n const requires = createRequirementCalls<Id, Imports>(options.requirementKeys, attachments, calls);\n const builder: FeatureOwnBuilder<Id, Imports, Requires> = Object.freeze({\n attach: attachments.attach,\n call: calls.call,\n calls: calls.calls,\n effect: createFeatureEffectBuilder(attachments.attach),\n event: createFeatureEventBuilder(attachments.attach),\n imports: scopes.importRefs,\n lane: calls.lane,\n model: data.model,\n requires: requires.refs as FeatureRequiredCalls<Id, Requires>,\n resource: createFeatureResourceBuilder(attachments.attach),\n scope: createFeatureScopeBuilder(options.id, attachments.attach),\n stream: createFeatureStreamBuilder(attachments.attach),\n });\n const built = options.build(builder);\n assertPlainRecord(built, 'defineFeature own result');\n const runtimeEntries = dataEntries(built, 'defineFeature own result');\n const publicRuntime = Object.freeze(Object.fromEntries(runtimeEntries)) as Runtime;\n const finalized = finalizeRuntimeLowering<Id, Imports, Runtime>(\n runtimeEntries,\n scopes,\n attachments.recipes,\n [\n ...requires.privateRefs,\n ...data.descriptors.flatMap(descriptor =>\n (descriptor.dependencies ?? []).flatMap(dependency =>\n dependency.kind === 'call'\n ? [{ preferred: 'modelDependency', ref: dependency.ref as ModuleRuntimeRef<Id> }]\n : [],\n ),\n ),\n ],\n data.descriptors,\n );\n\n return Object.freeze({\n ...finalized,\n publicRuntime,\n });\n}\n\nexport { lowerFeatureOwn };\nexport type { FeatureOwnLoweringResult };\n"],"names":["createRuntimeScopeAuthoring","low","importKeys","requirementKeys","importRefs","importRefKeys","importScope","requirementScope","importKey","ref","createRuntimeAttachmentAuthoring","imports","scopes","recipes","projections","createAttachment","first","second","hiddenKey","options","source","selectFeatureAttachmentArguments","projection","scope","selectAttachmentLowering","attachment","createAttachmentRecipe","createRuntimeCallAuthoring","id","attachments","callAuthoring","createFeatureCallAuthoring","value","createCall","operation","erasedWithin","run","input","context","projectCallContext","created","configureAttachmentCall","implicitAttachments","resolveCallsTarget","within","existing","keys","entries","createCallsOperationEntries","key","registerHiddenScope","hidden","runtimeKeys","preferred","allocateHiddenKey","lowerAttachmentRecipe","recipe","finalizeRuntimeLowering","runtimeEntries","privateRefs","dataDescriptors","runtimeIdentities","indexRuntimeIdentities","importScopeKey","requirementScopeKey","registered","privateRef","moduleRuntime","isFeatureDataRef","createRequirementCalls","calls","requirementAttachmentSource","target","CallError","_a","lowerFeatureOwn","data","createFeatureDataAuthoring","isAttachmentCallRef","getAttachmentCallRecipe","requires","builder","createFeatureEffectBuilder","createFeatureEventBuilder","createFeatureResourceBuilder","createFeatureScopeBuilder","createFeatureStreamBuilder","built","assertPlainRecord","dataEntries","publicRuntime","finalized","descriptor","dependency"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { PortRefOf } from '@opetope/core/internal';
2
+ import type { AnyPort, PortProviderDescriptor } from './feature-port.js';
3
+ import type { ModuleInstanceRef } from './public-module.js';
4
+ declare function bindFeatureReadyPorts(ready: object, descriptors: readonly PortProviderDescriptor[], instance: ModuleInstanceRef): void;
5
+ declare function resolveFeatureReadyPort<PortType extends AnyPort>(ready: object, port: PortType): PortRefOf<PortType>;
6
+ export { bindFeatureReadyPorts, resolveFeatureReadyPort };
@@ -0,0 +1,2 @@
1
+ import{isCallTarget as m,createAttachmentReadinessController as C,defineCallTarget as b,combineAbortSignals as h,inheritCallContextLifetime as w,inheritCallExecutionMetadata as y,settleGuardedResult as v,invokeCallTarget as T,throwIfSignalAborted as P,bindCallTargetToAttachment as M,releaseCallExecutionMetadata as k,retireCallContext as R}from"@opetope/core/internal";import{requireFeatureDataScope as f}from"./feature-model.js";import{bindProvidedPort as A}from"./feature-port.js";import{resolveModuleCallTarget as F,registerModuleRetirementParticipant as E}from"./public-module-instance.js";const p=new WeakMap;function $(n,a,r){const e=C({id:a}),t=new AbortController;E(r,{fence:()=>{e.publishInactive(),t.abort()}}),e.publishReady(e.beginOpen());const o=b({id:n.id,run(i,d){const u=h([d.signal,t.signal]),s=u.signal,l={signal:s},c=()=>{u.dispose(),k(l),R(l)};try{return w(d,l),y(d,l),v(T(n,i,l),{assertCurrent:()=>P(s),finalize:c,signal:s})}catch(g){throw c(),g}}});return M(o,e.ref)}function x(n,a,r){const e=new Map;for(const t of a){const o=t.target;let i=o.kind==="call"?F(r,o.ref):o.select(f(r).read(o.ref));if(!m(i))throw new TypeError(`Feature port ${t.key} model projection must return an authentic Call.`);o.kind==="model"&&!f(r).ownsCall(i)&&(i=$(i,`${t.port.id}.${t.key}.provider`,r)),e.set(t.port,A(t,i))}p.set(n,e)}function S(n,a){var e;const r=(e=p.get(n))==null?void 0:e.get(a);if(r===void 0)throw new TypeError(`Feature ready value does not provide Port ${a.id}.`);return r}export{x as bindFeatureReadyPorts,S as resolveFeatureReadyPort};
2
+ //# sourceMappingURL=feature-port-binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-port-binding.js","sources":["../src/feature-port-binding.ts"],"sourcesContent":["import type { Call, PortRef } from '@opetope/core';\nimport type { PortRefOf } from '@opetope/core/internal';\nimport {\n bindCallTargetToAttachment,\n combineAbortSignals,\n createAttachmentReadinessController,\n defineCallTarget,\n inheritCallContextLifetime,\n inheritCallExecutionMetadata,\n invokeCallTarget,\n isCallTarget,\n releaseCallExecutionMetadata,\n retireCallContext,\n settleGuardedResult,\n throwIfSignalAborted,\n} from '@opetope/core/internal';\n\nimport { requireFeatureDataScope } from './feature-model';\nimport { bindProvidedPort } from './feature-port';\nimport type { AnyPort, PortProviderDescriptor } from './feature-port';\nimport { registerModuleRetirementParticipant, resolveModuleCallTarget } from './public-module';\nimport type { ModuleCallRef, ModuleInstanceRef } from './public-module';\n\nconst readyPorts = new WeakMap<object, ReadonlyMap<object, PortRef<never, unknown>>>();\n\n/** Add the provider lease without replacing the selected Call's existing lifetime origin. */\nfunction bindModelProviderTarget(\n target: Call<unknown, unknown>,\n id: string,\n instance: ModuleInstanceRef,\n): Call<unknown, unknown> {\n const authority = createAttachmentReadinessController({ id });\n const provider = new AbortController();\n registerModuleRetirementParticipant(instance, {\n fence: () => {\n authority.publishInactive();\n provider.abort();\n },\n });\n authority.publishReady(authority.beginOpen());\n const forwarding = defineCallTarget({\n id: target.id,\n run(input: unknown, context) {\n const lifetime = combineAbortSignals([context.signal, provider.signal]);\n const signal = lifetime.signal;\n const forwarded = { signal };\n const finalize = (): void => {\n lifetime.dispose();\n releaseCallExecutionMetadata(forwarded);\n retireCallContext(forwarded);\n };\n\n try {\n inheritCallContextLifetime(context, forwarded);\n inheritCallExecutionMetadata(context, forwarded);\n\n // The selected target retains physical ownership; this adapter only forwards cancellation and settlement.\n return settleGuardedResult(invokeCallTarget(target, input, forwarded), {\n assertCurrent: () => throwIfSignalAborted(signal),\n finalize,\n signal,\n });\n } catch (error) {\n finalize();\n throw error;\n }\n },\n });\n\n return bindCallTargetToAttachment(forwarding, authority.ref);\n}\n\nfunction bindFeatureReadyPorts(\n ready: object,\n descriptors: readonly PortProviderDescriptor[],\n instance: ModuleInstanceRef,\n): void {\n const ports = new Map<object, PortRef<never, unknown>>();\n\n for (const descriptor of descriptors) {\n const binding = descriptor.target;\n let target =\n binding.kind === 'call'\n ? resolveModuleCallTarget(instance, binding.ref as ModuleCallRef<never, unknown>)\n : binding.select(requireFeatureDataScope(instance).read(binding.ref));\n\n if (!isCallTarget(target))\n throw new TypeError(`Feature port ${descriptor.key} model projection must return an authentic Call.`);\n\n if (binding.kind === 'model' && !requireFeatureDataScope(instance).ownsCall(target)) {\n target = bindModelProviderTarget(target, `${descriptor.port.id}.${descriptor.key}.provider`, instance);\n }\n\n ports.set(descriptor.port, bindProvidedPort(descriptor, target as Call<never, unknown>));\n }\n\n readyPorts.set(ready, ports);\n}\n\nfunction resolveFeatureReadyPort<PortType extends AnyPort>(ready: object, port: PortType): PortRefOf<PortType> {\n const ref = readyPorts.get(ready)?.get(port);\n\n if (ref === undefined) throw new TypeError(`Feature ready value does not provide Port ${port.id}.`);\n\n return ref as PortRefOf<PortType>;\n}\n\nexport { bindFeatureReadyPorts, resolveFeatureReadyPort };\n"],"names":["readyPorts","bindModelProviderTarget","target","id","instance","authority","createAttachmentReadinessController","provider","registerModuleRetirementParticipant","forwarding","defineCallTarget","input","context","lifetime","combineAbortSignals","signal","forwarded","finalize","releaseCallExecutionMetadata","retireCallContext","inheritCallContextLifetime","inheritCallExecutionMetadata","settleGuardedResult","invokeCallTarget","throwIfSignalAborted","error","bindCallTargetToAttachment","bindFeatureReadyPorts","ready","descriptors","ports","descriptor","binding","resolveModuleCallTarget","requireFeatureDataScope","isCallTarget","bindProvidedPort","resolveFeatureReadyPort","port","ref","_a"],"mappings":"mlBAuBA,MAAMA,EAAa,IAAI,QAGvB,SAASC,EACPC,EACAC,EACAC,EAA2B,CAE3B,MAAMC,EAAYC,EAAoC,CAAE,GAAAH,EAAI,EACtDI,EAAW,IAAI,gBACrBC,EAAoCJ,EAAU,CAC5C,MAAO,IAAK,CACVC,EAAU,gBAAe,EACzBE,EAAS,MAAK,CAChB,CACD,CAAA,EACDF,EAAU,aAAaA,EAAU,WAAW,EAC5C,MAAMI,EAAaC,EAAiB,CAClC,GAAIR,EAAO,GACX,IAAIS,EAAgBC,EAAO,CACzB,MAAMC,EAAWC,EAAoB,CAACF,EAAQ,OAAQL,EAAS,MAAM,CAAC,EAChEQ,EAASF,EAAS,OAClBG,EAAY,CAAE,OAAAD,CAAM,EACpBE,EAAW,IAAW,CAC1BJ,EAAS,QAAO,EAChBK,EAA6BF,CAAS,EACtCG,EAAkBH,CAAS,CAC7B,EAEA,GAAI,CACF,OAAAI,EAA2BR,EAASI,CAAS,EAC7CK,EAA6BT,EAASI,CAAS,EAGxCM,EAAoBC,EAAiBrB,EAAQS,EAAOK,CAAS,EAAG,CACrE,cAAe,IAAMQ,EAAqBT,CAAM,EAChD,SAAAE,EACA,OAAAF,CACD,CAAA,CACH,OAASU,EAAO,CACd,MAAAR,EAAQ,EACFQ,CACR,CACF,CACD,CAAA,EAED,OAAOC,EAA2BjB,EAAYJ,EAAU,GAAG,CAC7D,CAEA,SAASsB,EACPC,EACAC,EACAzB,EAA2B,CAE3B,MAAM0B,EAAQ,IAAI,IAElB,UAAWC,KAAcF,EAAa,CACpC,MAAMG,EAAUD,EAAW,OAC3B,IAAI7B,EACF8B,EAAQ,OAAS,OACbC,EAAwB7B,EAAU4B,EAAQ,GAAoC,EAC9EA,EAAQ,OAAOE,EAAwB9B,CAAQ,EAAE,KAAK4B,EAAQ,GAAG,CAAC,EAExE,GAAI,CAACG,EAAajC,CAAM,EACtB,MAAM,IAAI,UAAU,gBAAgB6B,EAAW,GAAG,kDAAkD,EAElGC,EAAQ,OAAS,SAAW,CAACE,EAAwB9B,CAAQ,EAAE,SAASF,CAAM,IAChFA,EAASD,EAAwBC,EAAQ,GAAG6B,EAAW,KAAK,EAAE,IAAIA,EAAW,GAAG,YAAa3B,CAAQ,GAGvG0B,EAAM,IAAIC,EAAW,KAAMK,EAAiBL,EAAY7B,CAA8B,CAAC,CACzF,CAEAF,EAAW,IAAI4B,EAAOE,CAAK,CAC7B,CAEA,SAASO,EAAkDT,EAAeU,EAAc,OACtF,MAAMC,GAAMC,EAAAxC,EAAW,IAAI4B,CAAK,IAApB,YAAAY,EAAuB,IAAIF,GAEvC,GAAIC,IAAQ,OAAW,MAAM,IAAI,UAAU,6CAA6CD,EAAK,EAAE,GAAG,EAElG,OAAOC,CACT"}
@@ -0,0 +1,66 @@
1
+ import type { Call, ModelOf, PortRef } from '@opetope/core';
2
+ import type { ModelIdentity, PortIdentity, PortInput, PortOutput } from '@opetope/core/internal';
3
+ import type { FeatureContribution, FeaturePipeBuilder, FeatureRegisterBuilder, FeatureSlotBuilder } from './feature-contribution.js';
4
+ import type { FeatureModelRef } from './feature-model.js';
5
+ import type { ModuleCallRef, ModuleCallRefIdentity } from './public-module.js';
6
+ declare const optionalPortBrand: unique symbol;
7
+ declare const portProviderBrand: unique symbol;
8
+ type AnyPort = PortIdentity;
9
+ /**
10
+ * `optional(port)` is the weak edge of a port: the application may have no provider, and a call without one
11
+ * settles with `CallError` code `unavailable` instead of failing the consumer (D105).
12
+ */
13
+ interface OptionalPort<PortType extends AnyPort> {
14
+ readonly [optionalPortBrand]: readonly [PortType];
15
+ }
16
+ type PortRequirementRecord = Readonly<Record<string, AnyPort | OptionalPort<AnyPort>>>;
17
+ type RequiredPortValues<Requires extends PortRequirementRecord> = {
18
+ readonly [Key in keyof Requires]: Requires[Key] extends OptionalPort<infer PortType> ? PortRef<PortInput<PortType>, PortOutput<PortType>> | undefined : Requires[Key] extends AnyPort ? PortRef<PortInput<Requires[Key]>, PortOutput<Requires[Key]>> : never;
19
+ };
20
+ /** Every requirement is a `Call` of this feature: the application chooses the provider, the author calls the ref. */
21
+ type FeatureRequiredCalls<Id extends string, Requires extends PortRequirementRecord> = {
22
+ readonly [Key in keyof Requires]: Requires[Key] extends OptionalPort<infer PortType> ? ModuleCallRef<PortInput<PortType>, PortOutput<PortType>, Id> : Requires[Key] extends AnyPort ? ModuleCallRef<PortInput<Requires[Key]>, PortOutput<Requires[Key]>, Id> : never;
23
+ };
24
+ interface PortProviderBinding<PortType extends AnyPort, Id extends string> {
25
+ readonly [portProviderBrand]: readonly [PortType, Id];
26
+ }
27
+ interface FeaturePortBuilder<Id extends string> {
28
+ <PortType extends AnyPort>(port: PortType, target: ModuleCallRef<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>, Id>): PortProviderBinding<PortType, Id>;
29
+ <PortType extends AnyPort, Declaration extends ModelIdentity>(port: PortType, projection: {
30
+ readonly from: FeatureModelRef<Declaration, Id>;
31
+ readonly select: (model: ModelOf<NoInfer<Declaration>>) => Call<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>>;
32
+ }): PortProviderBinding<PortType, Id>;
33
+ }
34
+ type PortProviderTarget = {
35
+ readonly kind: 'call';
36
+ readonly ref: ModuleCallRefIdentity;
37
+ } | {
38
+ readonly kind: 'model';
39
+ readonly ref: object;
40
+ readonly select: (model: unknown) => unknown;
41
+ };
42
+ type PortProviderDescriptor = {
43
+ readonly key: string;
44
+ readonly port: AnyPort;
45
+ readonly target: PortProviderTarget;
46
+ };
47
+ /** One section for every extension point: `port` for ports, `slot`, `pipe` and `register` for contributions. */
48
+ type FeatureProvidesFactory<Id extends string, Context, Evaluation, Runtime extends Readonly<Record<string, object>>, Provided extends FeatureProvidedRecord<Id>> = (context: {
49
+ readonly own: Runtime;
50
+ readonly pipe: FeaturePipeBuilder<Evaluation>;
51
+ readonly port: FeaturePortBuilder<Id>;
52
+ readonly register: FeatureRegisterBuilder<Context, Evaluation>;
53
+ readonly slot: FeatureSlotBuilder<Context, Evaluation>;
54
+ }) => Provided;
55
+ type FeatureProvidedRecord<Id extends string> = Readonly<Record<string, FeatureContribution | PortProviderBinding<AnyPort, Id>>>;
56
+ /** An explicit wrapper marks the weak requirement; an authentic bare Port is the strong requirement. */
57
+ declare function optionalPort<PortType extends AnyPort>(port: PortType): OptionalPort<PortType>;
58
+ /** Tolerant on purpose: the caller may hold any requirement declaration or none at all. */
59
+ declare function isOptionalPortRequirement(requirement: unknown): boolean;
60
+ declare function getRequiredPort(requirement: unknown): AnyPort;
61
+ declare function createPortBuilder<Id extends string>(): FeaturePortBuilder<Id>;
62
+ declare function snapshotPortProviders(runtimeValues: ReadonlySet<object>, entries: readonly (readonly [string, unknown])[]): readonly PortProviderDescriptor[];
63
+ declare function bindProvidedPort(descriptor: PortProviderDescriptor, target: Call<never, unknown>): PortRef<never, unknown>;
64
+ declare function assertRequiredPortValue(port: AnyPort, value: unknown, key: string, isOptional: boolean): asserts value is PortRef<never, unknown> | undefined;
65
+ export { assertRequiredPortValue, bindProvidedPort, createPortBuilder, getRequiredPort, isOptionalPortRequirement, optionalPort, snapshotPortProviders, };
66
+ export type { AnyPort, FeatureProvidedRecord, FeatureProvidesFactory, FeatureRequiredCalls, OptionalPort, PortProviderDescriptor, PortRequirementRecord, RequiredPortValues, };
@@ -0,0 +1,2 @@
1
+ import{isPort as a,isPortRefFor as p,bindPortRef as d}from"@opetope/core/internal";import{isAttachmentCallRef as u}from"./attachment-call-declaration.js";import{isFeatureDataRef as l}from"./feature-model.js";import{assertPlainRecord as w,assertExactDataKeys as P,dataEntries as m}from"./feature-record.js";const f=new WeakMap,s=new WeakSet,c=new WeakMap;function h(r){if(!a(r))throw new TypeError("optional expects an authentic Port.");const e=Object.freeze({});return f.set(e,r),s.add(e),e}function b(r){return typeof r=="object"&&r!==null&&s.has(r)}function j(r){if(a(r))return r;if(typeof r!="object"||r===null)throw new TypeError("Feature requirement is not an authentic required Port.");const e=f.get(r);if(e===void 0)throw new TypeError("Feature requirement is not an authentic required Port.");return e}function y(){return(r,e)=>{if(!a(r))throw new TypeError("provides.port takes a port created by definePort.");let o;if(u(e))o=Object.freeze({kind:"call",ref:e});else{if(w(e,"Feature port model projection"),P(e,m(e,"Feature port model projection"),["from","select"],"Feature port model projection"),!l(e.from)||typeof e.select!="function")throw new TypeError("provides.port takes an owned Call ref or a model projection with from and select.");o=Object.freeze({kind:"model",ref:e.from,select:e.select})}const t=Object.freeze({});return c.set(t,Object.freeze({port:r,target:o})),t}}function E(r,e){const o=e.map(([t,i])=>{if(typeof i!="object"||i===null)throw new TypeError(`Feature provider ${t} is not an authentic Port provider.`);const n=c.get(i);if(n===void 0)throw new TypeError(`Feature provider ${t} is not an authentic Port provider.`);if(!r.has(n.target.ref))throw new TypeError(`Feature provider ${t} must select a call or model ref from its public own.`);return Object.freeze({key:t,port:n.port,target:n.target})});return Object.freeze(o)}function F(r,e){return d(r.port,e)}function R(r,e,o,t){if(!(t&&e===void 0)&&!p(r,e))throw new TypeError(`openFeature requirement ${o} must be a PortRef for ${r.id}.`)}export{R as assertRequiredPortValue,F as bindProvidedPort,y as createPortBuilder,j as getRequiredPort,b as isOptionalPortRequirement,h as optionalPort,E as snapshotPortProviders};
2
+ //# sourceMappingURL=feature-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-port.js","sources":["../src/feature-port.ts"],"sourcesContent":["import type { Call, ModelOf, Port, PortRef } from '@opetope/core';\nimport type { ModelIdentity, PortIdentity, PortInput, PortOutput } from '@opetope/core/internal';\nimport { bindPortRef, isPort, isPortRefFor } from '@opetope/core/internal';\n\nimport { isAttachmentCallRef } from './attachment-call-declaration';\nimport type {\n FeatureContribution,\n FeaturePipeBuilder,\n FeatureRegisterBuilder,\n FeatureSlotBuilder,\n} from './feature-contribution';\nimport { isFeatureDataRef } from './feature-model';\nimport type { FeatureModelRef } from './feature-model';\nimport { assertExactDataKeys, assertPlainRecord, dataEntries } from './feature-record';\nimport type { ModuleCallRef, ModuleCallRefIdentity } from './public-module';\n\ndeclare const optionalPortBrand: unique symbol;\ndeclare const portProviderBrand: unique symbol;\n\ntype AnyPort = PortIdentity;\n\n/**\n * `optional(port)` is the weak edge of a port: the application may have no provider, and a call without one\n * settles with `CallError` code `unavailable` instead of failing the consumer (D105).\n */\ninterface OptionalPort<PortType extends AnyPort> {\n readonly [optionalPortBrand]: readonly [PortType];\n}\n\ntype PortRequirementRecord = Readonly<Record<string, AnyPort | OptionalPort<AnyPort>>>;\ntype RequiredPortValues<Requires extends PortRequirementRecord> = {\n readonly [Key in keyof Requires]: Requires[Key] extends OptionalPort<infer PortType>\n ? PortRef<PortInput<PortType>, PortOutput<PortType>> | undefined\n : Requires[Key] extends AnyPort\n ? PortRef<PortInput<Requires[Key]>, PortOutput<Requires[Key]>>\n : never;\n};\n/** Every requirement is a `Call` of this feature: the application chooses the provider, the author calls the ref. */\ntype FeatureRequiredCalls<Id extends string, Requires extends PortRequirementRecord> = {\n readonly [Key in keyof Requires]: Requires[Key] extends OptionalPort<infer PortType>\n ? ModuleCallRef<PortInput<PortType>, PortOutput<PortType>, Id>\n : Requires[Key] extends AnyPort\n ? ModuleCallRef<PortInput<Requires[Key]>, PortOutput<Requires[Key]>, Id>\n : never;\n};\n\ninterface PortProviderBinding<PortType extends AnyPort, Id extends string> {\n readonly [portProviderBrand]: readonly [PortType, Id];\n}\n\ninterface FeaturePortBuilder<Id extends string> {\n <PortType extends AnyPort>(\n port: PortType,\n target: ModuleCallRef<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>, Id>,\n ): PortProviderBinding<PortType, Id>;\n <PortType extends AnyPort, Declaration extends ModelIdentity>(\n port: PortType,\n projection: {\n readonly from: FeatureModelRef<Declaration, Id>;\n readonly select: (\n model: ModelOf<NoInfer<Declaration>>,\n ) => Call<PortInput<NoInfer<PortType>>, PortOutput<NoInfer<PortType>>>;\n },\n ): PortProviderBinding<PortType, Id>;\n}\n\ntype PortProviderTarget =\n | { readonly kind: 'call'; readonly ref: ModuleCallRefIdentity }\n | { readonly kind: 'model'; readonly ref: object; readonly select: (model: unknown) => unknown };\n\ntype PortProviderDescriptor = {\n readonly key: string;\n readonly port: AnyPort;\n readonly target: PortProviderTarget;\n};\n/** One section for every extension point: `port` for ports, `slot`, `pipe` and `register` for contributions. */\ntype FeatureProvidesFactory<\n Id extends string,\n Context,\n Evaluation,\n Runtime extends Readonly<Record<string, object>>,\n Provided extends FeatureProvidedRecord<Id>,\n> = (context: {\n readonly own: Runtime;\n readonly pipe: FeaturePipeBuilder<Evaluation>;\n readonly port: FeaturePortBuilder<Id>;\n readonly register: FeatureRegisterBuilder<Context, Evaluation>;\n readonly slot: FeatureSlotBuilder<Context, Evaluation>;\n}) => Provided;\n\ntype FeatureProvidedRecord<Id extends string> = Readonly<\n Record<string, FeatureContribution | PortProviderBinding<AnyPort, Id>>\n>;\n\nconst requiredPorts = new WeakMap<object, AnyPort>();\nconst optionalPorts = new WeakSet<object>();\nconst portProviders = new WeakMap<object, Readonly<{ port: AnyPort; target: PortProviderTarget }>>();\n\n/** An explicit wrapper marks the weak requirement; an authentic bare Port is the strong requirement. */\nfunction optionalPort<PortType extends AnyPort>(port: PortType): OptionalPort<PortType> {\n if (!isPort(port)) throw new TypeError('optional expects an authentic Port.');\n\n const requirement = Object.freeze({}) as OptionalPort<PortType>;\n requiredPorts.set(requirement, port);\n optionalPorts.add(requirement);\n\n return requirement;\n}\n\n/** Tolerant on purpose: the caller may hold any requirement declaration or none at all. */\nfunction isOptionalPortRequirement(requirement: unknown): boolean {\n return typeof requirement === 'object' && requirement !== null && optionalPorts.has(requirement);\n}\n\nfunction getRequiredPort(requirement: unknown): AnyPort {\n if (isPort(requirement)) return requirement;\n\n if (typeof requirement !== 'object' || requirement === null) {\n throw new TypeError('Feature requirement is not an authentic required Port.');\n }\n\n const port = requiredPorts.get(requirement);\n\n if (port === undefined) throw new TypeError('Feature requirement is not an authentic required Port.');\n\n return port;\n}\n\nfunction createPortBuilder<Id extends string>(): FeaturePortBuilder<Id> {\n return <PortType extends AnyPort>(port: PortType, value: unknown) => {\n if (!isPort(port)) throw new TypeError('provides.port takes a port created by definePort.');\n\n let target: PortProviderTarget;\n\n if (isAttachmentCallRef(value)) {\n target = Object.freeze({ kind: 'call', ref: value as unknown as ModuleCallRefIdentity });\n } else {\n assertPlainRecord(value, 'Feature port model projection');\n assertExactDataKeys(\n value,\n dataEntries(value, 'Feature port model projection'),\n ['from', 'select'],\n 'Feature port model projection',\n );\n\n if (!isFeatureDataRef(value['from']) || typeof value['select'] !== 'function') {\n throw new TypeError('provides.port takes an owned Call ref or a model projection with from and select.');\n }\n\n target = Object.freeze({\n kind: 'model',\n ref: value['from'] as object,\n select: value['select'] as (model: unknown) => unknown,\n });\n }\n\n const binding = Object.freeze({}) as PortProviderBinding<PortType, Id>;\n portProviders.set(binding, Object.freeze({ port, target }));\n\n return binding;\n };\n}\n\nfunction snapshotPortProviders(\n runtimeValues: ReadonlySet<object>,\n entries: readonly (readonly [string, unknown])[],\n): readonly PortProviderDescriptor[] {\n const descriptors = entries.map(([key, binding]) => {\n if (typeof binding !== 'object' || binding === null) {\n throw new TypeError(`Feature provider ${key} is not an authentic Port provider.`);\n }\n\n const definition = portProviders.get(binding);\n\n if (definition === undefined) throw new TypeError(`Feature provider ${key} is not an authentic Port provider.`);\n\n if (!runtimeValues.has(definition.target.ref)) {\n throw new TypeError(`Feature provider ${key} must select a call or model ref from its public own.`);\n }\n\n return Object.freeze({ key, port: definition.port, target: definition.target });\n });\n\n return Object.freeze(descriptors);\n}\n\nfunction bindProvidedPort(descriptor: PortProviderDescriptor, target: Call<never, unknown>): PortRef<never, unknown> {\n return bindPortRef(descriptor.port as Port<never, unknown>, target);\n}\n\nfunction assertRequiredPortValue(\n port: AnyPort,\n value: unknown,\n key: string,\n isOptional: boolean,\n): asserts value is PortRef<never, unknown> | undefined {\n if (isOptional && value === undefined) return;\n\n if (!isPortRefFor(port as Port<never, unknown>, value)) {\n throw new TypeError(`openFeature requirement ${key} must be a PortRef for ${port.id}.`);\n }\n}\n\nexport {\n assertRequiredPortValue,\n bindProvidedPort,\n createPortBuilder,\n getRequiredPort,\n isOptionalPortRequirement,\n optionalPort,\n snapshotPortProviders,\n};\nexport type {\n AnyPort,\n FeatureProvidedRecord,\n FeatureProvidesFactory,\n FeatureRequiredCalls,\n OptionalPort,\n PortProviderDescriptor,\n PortRequirementRecord,\n RequiredPortValues,\n};\n"],"names":["requiredPorts","optionalPorts","portProviders","optionalPort","port","isPort","requirement","isOptionalPortRequirement","getRequiredPort","createPortBuilder","value","target","isAttachmentCallRef","assertPlainRecord","assertExactDataKeys","dataEntries","isFeatureDataRef","binding","snapshotPortProviders","runtimeValues","entries","descriptors","key","definition","bindProvidedPort","descriptor","bindPortRef","assertRequiredPortValue","isOptional","isPortRefFor"],"mappings":"kTA8FA,MAAMA,EAAgB,IAAI,QACpBC,EAAgB,IAAI,QACpBC,EAAgB,IAAI,QAG1B,SAASC,EAAuCC,EAAc,CAC5D,GAAI,CAACC,EAAOD,CAAI,EAAG,MAAM,IAAI,UAAU,qCAAqC,EAE5E,MAAME,EAAc,OAAO,OAAO,EAAE,EACpC,OAAAN,EAAc,IAAIM,EAAaF,CAAI,EACnCH,EAAc,IAAIK,CAAW,EAEtBA,CACT,CAGA,SAASC,EAA0BD,EAAoB,CACrD,OAAO,OAAOA,GAAgB,UAAYA,IAAgB,MAAQL,EAAc,IAAIK,CAAW,CACjG,CAEA,SAASE,EAAgBF,EAAoB,CAC3C,GAAID,EAAOC,CAAW,EAAG,OAAOA,EAEhC,GAAI,OAAOA,GAAgB,UAAYA,IAAgB,KACrD,MAAM,IAAI,UAAU,wDAAwD,EAG9E,MAAMF,EAAOJ,EAAc,IAAIM,CAAW,EAE1C,GAAIF,IAAS,OAAW,MAAM,IAAI,UAAU,wDAAwD,EAEpG,OAAOA,CACT,CAEA,SAASK,GAAiB,CACxB,MAAO,CAA2BL,EAAgBM,IAAkB,CAClE,GAAI,CAACL,EAAOD,CAAI,EAAG,MAAM,IAAI,UAAU,mDAAmD,EAE1F,IAAIO,EAEJ,GAAIC,EAAoBF,CAAK,EAC3BC,EAAS,OAAO,OAAO,CAAE,KAAM,OAAQ,IAAKD,EAA2C,MAClF,CASL,GARAG,EAAkBH,EAAO,+BAA+B,EACxDI,EACEJ,EACAK,EAAYL,EAAO,+BAA+B,EAClD,CAAC,OAAQ,QAAQ,EACjB,+BAA+B,EAG7B,CAACM,EAAiBN,EAAM,IAAO,GAAK,OAAOA,EAAM,QAAc,WACjE,MAAM,IAAI,UAAU,mFAAmF,EAGzGC,EAAS,OAAO,OAAO,CACrB,KAAM,QACN,IAAKD,EAAM,KACX,OAAQA,EAAM,MACf,CAAA,CACH,CAEA,MAAMO,EAAU,OAAO,OAAO,EAAE,EAChC,OAAAf,EAAc,IAAIe,EAAS,OAAO,OAAO,CAAE,KAAAb,EAAM,OAAAO,CAAM,CAAE,CAAC,EAEnDM,CACT,CACF,CAEA,SAASC,EACPC,EACAC,EAAgD,CAEhD,MAAMC,EAAcD,EAAQ,IAAI,CAAC,CAACE,EAAKL,CAAO,IAAK,CACjD,GAAI,OAAOA,GAAY,UAAYA,IAAY,KAC7C,MAAM,IAAI,UAAU,oBAAoBK,CAAG,qCAAqC,EAGlF,MAAMC,EAAarB,EAAc,IAAIe,CAAO,EAE5C,GAAIM,IAAe,OAAW,MAAM,IAAI,UAAU,oBAAoBD,CAAG,qCAAqC,EAE9G,GAAI,CAACH,EAAc,IAAII,EAAW,OAAO,GAAG,EAC1C,MAAM,IAAI,UAAU,oBAAoBD,CAAG,uDAAuD,EAGpG,OAAO,OAAO,OAAO,CAAE,IAAAA,EAAK,KAAMC,EAAW,KAAM,OAAQA,EAAW,OAAQ,CAChF,CAAC,EAED,OAAO,OAAO,OAAOF,CAAW,CAClC,CAEA,SAASG,EAAiBC,EAAoCd,EAA4B,CACxF,OAAOe,EAAYD,EAAW,KAA8Bd,CAAM,CACpE,CAEA,SAASgB,EACPvB,EACAM,EACAY,EACAM,EAAmB,CAEnB,GAAI,EAAAA,GAAclB,IAAU,SAExB,CAACmB,EAAazB,EAA8BM,CAAK,EACnD,MAAM,IAAI,UAAU,2BAA2BY,CAAG,0BAA0BlB,EAAK,EAAE,GAAG,CAE1F"}
@@ -0,0 +1,6 @@
1
+ import type { ExactInput, ExactKeys } from '@opetope/core/internal';
2
+ declare function assertPlainRecord(value: unknown, label: string): asserts value is Readonly<Record<string, unknown>>;
3
+ declare function dataEntries(value: Readonly<Record<string, unknown>>, label: string): readonly (readonly [string, unknown])[];
4
+ declare function assertExactDataKeys(value: Readonly<Record<string, unknown>>, entries: readonly (readonly [string, unknown])[], expectedKeys: readonly string[], label: string): void;
5
+ export { assertExactDataKeys, assertPlainRecord, dataEntries };
6
+ export type { ExactInput, ExactKeys };
@@ -0,0 +1,2 @@
1
+ import{hasOwn as i}from"@opetope/core/internal";const s=/^[A-Za-z][A-Za-z0-9]*$/;function a(t,o){if(typeof t!="object"||t===null)throw new TypeError(`${o} must be a plain object record.`);const r=Object.getPrototypeOf(t);if(r!==Object.prototype&&r!==null)throw new TypeError(`${o} must be a plain object record.`)}function f(t,o){const r=[];for(const e of Reflect.ownKeys(t)){if(typeof e!="string"||!s.test(e))throw new TypeError(`${o} key ${String(e)} must be one identifier segment.`);const n=Object.getOwnPropertyDescriptor(t,e);if((n==null?void 0:n.enumerable)!==!0||!("value"in n))throw new TypeError(`${o}.${e} must be an enumerable data field.`);r.push([e,n.value])}return r}function c(t,o,r,e){if(o.length!==r.length)throw new TypeError(`${e} requires exact data fields.`);for(const n of r)if(!i(t,n))throw new TypeError(`${e} requires exact data fields.`)}export{c as assertExactDataKeys,a as assertPlainRecord,f as dataEntries};
2
+ //# sourceMappingURL=feature-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-record.js","sources":["../src/feature-record.ts"],"sourcesContent":["import type { ExactInput, ExactKeys } from '@opetope/core/internal';\nimport { hasOwn } from '@opetope/core/internal';\n\nconst identifierKeyPattern = /^[A-Za-z][A-Za-z0-9]*$/;\n\nfunction assertPlainRecord(value: unknown, label: string): asserts value is Readonly<Record<string, unknown>> {\n if (typeof value !== 'object' || value === null) throw new TypeError(`${label} must be a plain object record.`);\n\n const prototype: unknown = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`${label} must be a plain object record.`);\n }\n}\n\nfunction dataEntries(value: Readonly<Record<string, unknown>>, label: string): readonly (readonly [string, unknown])[] {\n const entries: (readonly [string, unknown])[] = [];\n\n for (const propertyKey of Reflect.ownKeys(value)) {\n if (typeof propertyKey !== 'string' || !identifierKeyPattern.test(propertyKey)) {\n throw new TypeError(`${label} key ${String(propertyKey)} must be one identifier segment.`);\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(value, propertyKey);\n\n if (descriptor?.enumerable !== true || !('value' in descriptor)) {\n throw new TypeError(`${label}.${propertyKey} must be an enumerable data field.`);\n }\n\n entries.push([propertyKey, descriptor.value]);\n }\n\n return entries;\n}\n\nfunction assertExactDataKeys(\n value: Readonly<Record<string, unknown>>,\n entries: readonly (readonly [string, unknown])[],\n expectedKeys: readonly string[],\n label: string,\n): void {\n if (entries.length !== expectedKeys.length) throw new TypeError(`${label} requires exact data fields.`);\n\n for (const key of expectedKeys) {\n if (!hasOwn(value, key)) throw new TypeError(`${label} requires exact data fields.`);\n }\n}\n\nexport { assertExactDataKeys, assertPlainRecord, dataEntries };\nexport type { ExactInput, ExactKeys };\n"],"names":["identifierKeyPattern","assertPlainRecord","value","label","prototype","dataEntries","entries","propertyKey","descriptor","assertExactDataKeys","expectedKeys","key","hasOwn"],"mappings":"gDAGA,MAAMA,EAAuB,yBAE7B,SAASC,EAAkBC,EAAgBC,EAAa,CACtD,GAAI,OAAOD,GAAU,UAAYA,IAAU,KAAM,MAAM,IAAI,UAAU,GAAGC,CAAK,iCAAiC,EAE9G,MAAMC,EAAqB,OAAO,eAAeF,CAAK,EAEtD,GAAIE,IAAc,OAAO,WAAaA,IAAc,KAClD,MAAM,IAAI,UAAU,GAAGD,CAAK,iCAAiC,CAEjE,CAEA,SAASE,EAAYH,EAA0CC,EAAa,CAC1E,MAAMG,EAA0C,CAAA,EAEhD,UAAWC,KAAe,QAAQ,QAAQL,CAAK,EAAG,CAChD,GAAI,OAAOK,GAAgB,UAAY,CAACP,EAAqB,KAAKO,CAAW,EAC3E,MAAM,IAAI,UAAU,GAAGJ,CAAK,QAAQ,OAAOI,CAAW,CAAC,kCAAkC,EAG3F,MAAMC,EAAa,OAAO,yBAAyBN,EAAOK,CAAW,EAErE,IAAIC,GAAA,YAAAA,EAAY,cAAe,IAAQ,EAAE,UAAWA,GAClD,MAAM,IAAI,UAAU,GAAGL,CAAK,IAAII,CAAW,oCAAoC,EAGjFD,EAAQ,KAAK,CAACC,EAAaC,EAAW,KAAK,CAAC,CAC9C,CAEA,OAAOF,CACT,CAEA,SAASG,EACPP,EACAI,EACAI,EACAP,EAAa,CAEb,GAAIG,EAAQ,SAAWI,EAAa,OAAQ,MAAM,IAAI,UAAU,GAAGP,CAAK,8BAA8B,EAEtG,UAAWQ,KAAOD,EAChB,GAAI,CAACE,EAAOV,EAAOS,CAAG,EAAG,MAAM,IAAI,UAAU,GAAGR,CAAK,8BAA8B,CAEvF"}
@@ -0,0 +1,29 @@
1
+ import type { Readable } from '@opetope/core';
2
+ import type { FeatureAttachBuilder, FeatureImportRecord, FeatureImportRef } from './feature-authoring-types.js';
3
+ import type { FeatureExposureMode } from './feature-call-types.js';
4
+ import type { FeatureMaterializationTarget, FeatureResourceOptions as FeatureResourceOptionsInput, FeatureResourceRef } from './feature-materialization-types.js';
5
+ import type { ExactKeys } from './feature-record.js';
6
+ import type { ResourceRequestKey, ResourceRetention, ResourceRetry } from './resource-types.js';
7
+ type FeatureResourceOptions = {
8
+ readonly from: object;
9
+ readonly key: (target: unknown) => ResourceRequestKey;
10
+ readonly load: (target: unknown, context: {
11
+ readonly signal: AbortSignal;
12
+ readonly source: unknown;
13
+ }) => unknown;
14
+ readonly retention: ResourceRetention;
15
+ readonly retry: ResourceRetry | undefined;
16
+ readonly target: (source: unknown) => Readable<unknown | null>;
17
+ };
18
+ /**
19
+ * `from` and `target` are positional so TypeScript resolves `Source` and then `Target` before it contextually types
20
+ * the option callbacks. Key order inside the options object is therefore irrelevant.
21
+ */
22
+ type FeatureResourceBuilder<Id extends string> = <Source, Target, Data, Key extends ResourceRequestKey, Mode extends FeatureExposureMode, const Keys extends PropertyKey = keyof FeatureResourceOptionsInput<Source, Target, Data, Key>>(from: FeatureImportRef<Source, Id, Mode>, target: FeatureMaterializationTarget<NoInfer<Source>, Target>, options: ExactKeys<Keys, FeatureResourceOptionsInput<NoInfer<Source>, NoInfer<Target>, Data, Key>> & FeatureResourceOptionsInput<NoInfer<Source>, NoInfer<Target>, Data, Key>) => FeatureResourceRef<Data, Key, Id>;
23
+ declare function selectTargetReadable(select: (source: unknown) => unknown, source: unknown, label: string): Readable<unknown | null>;
24
+ declare function requireTargetSelector(value: unknown, label: string): (source: unknown) => unknown;
25
+ declare function requireRequestKey(value: unknown): ResourceRequestKey;
26
+ declare function snapshotFeatureResourceOptions(source: unknown, select: unknown, value: unknown): FeatureResourceOptions;
27
+ declare function createFeatureResourceBuilder<Id extends string, Imports extends FeatureImportRecord>(attach: FeatureAttachBuilder<Id, Imports>): FeatureResourceBuilder<Id>;
28
+ export { createFeatureResourceBuilder, requireRequestKey, requireTargetSelector, selectTargetReadable, snapshotFeatureResourceOptions, };
29
+ export type { FeatureResourceBuilder };
@@ -0,0 +1,2 @@
1
+ import{getFeatureAttachmentReporter as R}from"./feature-attachment.js";import{openingMaterializationGenerationAllocator as k,attachOpeningMaterialization as F,registerFeatureMaterialization as E}from"./feature-materialization-binding.js";import{assertPlainRecord as T,dataEntries as q}from"./feature-record.js";import{createResourceController as $}from"./resource-controller.js";import{snapshotResourceRetry as j,snapshotResourceRetention as S}from"./resource-policy.js";const z=new Set(["key","load","retention","retry"]);function O(e){for(const r of e)if(!z.has(r))throw new TypeError(`Unknown feature resource option ${r}.`);for(const r of["key","load"])if(!e.has(r))throw new TypeError(`Feature resource requires own ${r}.`)}function p(e,r){if(typeof e!="function")throw new TypeError(`Feature resource ${r} must be a function.`);return e}function K(e,r){if(typeof e!="object"||e===null)throw new TypeError(`${r} must return a Readable.`);const t=Reflect.get(e,"getSnapshot"),i=Reflect.get(e,"subscribe");if(typeof t!="function"||typeof i!="function")throw new TypeError(`${r} must return a Readable.`);return e}function m(e,r,t){if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(`${t} source must be an object.`);return K(e(r),t)}function d(e,r){if(typeof e!="function")throw new TypeError(`${r} must be a selector function.`);return e}function w(e){if(typeof e!="string"&&typeof e!="number")throw new TypeError("Feature resource key must return a string or number.");if(typeof e=="number"&&!Number.isFinite(e))throw new TypeError("Feature resource key must return a finite number.");return e}function b(e,r,t){T(t,"Feature resource options");const i=q(t,"Feature resource options"),o=new Set(i.map(([n])=>n));if(O(o),typeof e!="object"||e===null)throw new TypeError("Feature resource from must be an import from this definition.");const s=p(t.load,"load"),a=p(t.key,"key"),c=d(r,"Feature resource target");return Object.freeze({from:e,key:a,load:s,retention:S(t.retention),retry:j(t.retry),target:c})}function M(e){return((r,t,i)=>{const o=b(r,t,i),s={},a=()=>{if(s.token===void 0)throw new TypeError("Feature resource is not registered.");return s.token},c=e(o.from,{open:n=>{const g=m(o.target,n.source,"Feature resource target"),y=R(n),u=$({allocateGeneration:k(a()),key:f=>w(o.key(f)),load:(f,l)=>o.load(f,l),retention:o.retention,source:n.source,target:g,...y===void 0?{}:{reporter:y},...o.retry===void 0?{}:{retry:o.retry}});n.signal.addEventListener("abort",u.fence,{once:!0}),n.signal.aborted&&u.fence();const h=F(a(),u);return async()=>{n.signal.removeEventListener("abort",u.fence);try{await u.close()}finally{h()}}}});return s.token=E(c,"resource"),c})}export{M as createFeatureResourceBuilder,w as requireRequestKey,d as requireTargetSelector,m as selectTargetReadable,b as snapshotFeatureResourceOptions};
2
+ //# sourceMappingURL=feature-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-resource.js","sources":["../src/feature-resource.ts"],"sourcesContent":["import type { Readable } from '@opetope/core';\n\nimport type { LifetimeAttachmentRefIdentity } from './attachment-declaration';\nimport { getFeatureAttachmentReporter } from './feature-attachment';\nimport type { FeatureAttachBuilder, FeatureImportRecord, FeatureImportRef } from './feature-authoring-types';\nimport type { FeatureExposureMode } from './feature-call-types';\nimport {\n attachOpeningMaterialization,\n openingMaterializationGenerationAllocator,\n registerFeatureMaterialization,\n} from './feature-materialization-binding';\nimport type {\n FeatureMaterializationTarget,\n FeatureResourceOptions as FeatureResourceOptionsInput,\n FeatureResourceRef,\n} from './feature-materialization-types';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport { createResourceController } from './resource-controller';\nimport { snapshotResourceRetention, snapshotResourceRetry } from './resource-policy';\nimport type { ResourceRequestKey, ResourceRetention, ResourceRetry } from './resource-types';\n\ntype FeatureResourceOptions = {\n readonly from: object;\n readonly key: (target: unknown) => ResourceRequestKey;\n readonly load: (target: unknown, context: { readonly signal: AbortSignal; readonly source: unknown }) => unknown;\n readonly retention: ResourceRetention;\n readonly retry: ResourceRetry | undefined;\n readonly target: (source: unknown) => Readable<unknown | null>;\n};\n\n/**\n * `from` and `target` are positional so TypeScript resolves `Source` and then `Target` before it contextually types\n * the option callbacks. Key order inside the options object is therefore irrelevant.\n */\ntype FeatureResourceBuilder<Id extends string> = <\n Source,\n Target,\n Data,\n Key extends ResourceRequestKey,\n // D187: every exposure mode may feed a resource or a stream; only `calls` cares which one it is.\n Mode extends FeatureExposureMode,\n const Keys extends PropertyKey = keyof FeatureResourceOptionsInput<Source, Target, Data, Key>,\n>(\n from: FeatureImportRef<Source, Id, Mode>,\n target: FeatureMaterializationTarget<NoInfer<Source>, Target>,\n options: ExactKeys<Keys, FeatureResourceOptionsInput<NoInfer<Source>, NoInfer<Target>, Data, Key>> &\n FeatureResourceOptionsInput<NoInfer<Source>, NoInfer<Target>, Data, Key>,\n) => FeatureResourceRef<Data, Key, Id>;\n\nconst resourceOptionKeys = new Set(['key', 'load', 'retention', 'retry']);\n\nfunction assertFeatureResourceKeys(keys: ReadonlySet<string>): void {\n for (const key of keys) {\n if (!resourceOptionKeys.has(key)) throw new TypeError(`Unknown feature resource option ${key}.`);\n }\n\n for (const key of ['key', 'load'] as const) {\n if (!keys.has(key)) throw new TypeError(`Feature resource requires own ${key}.`);\n }\n}\n\nfunction requireResourceFunction(value: unknown, key: string): (...arguments_: never[]) => unknown {\n if (typeof value !== 'function') throw new TypeError(`Feature resource ${key} must be a function.`);\n\n return value as (...arguments_: never[]) => unknown;\n}\n\nfunction requireReadable(value: unknown, label: string): Readable<unknown | null> {\n if (typeof value !== 'object' || value === null) throw new TypeError(`${label} must return a Readable.`);\n\n const getSnapshot: unknown = Reflect.get(value, 'getSnapshot');\n const subscribe: unknown = Reflect.get(value, 'subscribe');\n\n if (typeof getSnapshot !== 'function' || typeof subscribe !== 'function') {\n throw new TypeError(`${label} must return a Readable.`);\n }\n\n return value as Readable<unknown | null>;\n}\n\nfunction selectTargetReadable(\n select: (source: unknown) => unknown,\n source: unknown,\n label: string,\n): Readable<unknown | null> {\n if ((typeof source !== 'object' && typeof source !== 'function') || source === null) {\n throw new TypeError(`${label} source must be an object.`);\n }\n\n return requireReadable(select(source), label);\n}\n\nfunction requireTargetSelector(value: unknown, label: string): (source: unknown) => unknown {\n if (typeof value !== 'function') throw new TypeError(`${label} must be a selector function.`);\n\n return value as (source: unknown) => unknown;\n}\n\nfunction requireRequestKey(value: unknown): ResourceRequestKey {\n if (typeof value !== 'string' && typeof value !== 'number') {\n throw new TypeError('Feature resource key must return a string or number.');\n }\n\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw new TypeError('Feature resource key must return a finite number.');\n }\n\n return value;\n}\n\nfunction snapshotFeatureResourceOptions(source: unknown, select: unknown, value: unknown): FeatureResourceOptions {\n assertPlainRecord(value, 'Feature resource options');\n const entries = dataEntries(value, 'Feature resource options');\n const keys = new Set(entries.map(([key]) => key));\n assertFeatureResourceKeys(keys);\n\n if (typeof source !== 'object' || source === null) {\n throw new TypeError('Feature resource from must be an import from this definition.');\n }\n\n const load = requireResourceFunction(value['load'], 'load');\n const key = requireResourceFunction(value['key'], 'key');\n const target = requireTargetSelector(select, 'Feature resource target');\n\n return Object.freeze({\n from: source,\n key: key as FeatureResourceOptions['key'],\n load: load as FeatureResourceOptions['load'],\n retention: snapshotResourceRetention(value['retention']),\n retry: snapshotResourceRetry(value['retry']),\n target: target as FeatureResourceOptions['target'],\n });\n}\n\nfunction createFeatureResourceBuilder<Id extends string, Imports extends FeatureImportRecord>(\n attach: FeatureAttachBuilder<Id, Imports>,\n): FeatureResourceBuilder<Id> {\n return ((source: unknown, select: unknown, value: unknown) => {\n const options = snapshotFeatureResourceOptions(source, select, value);\n const registration: { token?: ReturnType<typeof registerFeatureMaterialization> } = {};\n const requireToken = (): ReturnType<typeof registerFeatureMaterialization> => {\n if (registration.token === undefined) throw new TypeError('Feature resource is not registered.');\n\n return registration.token;\n };\n const attachment = attach(options.from as FeatureImportRef<unknown, Id, 'adapter-method'>, {\n open: context => {\n const target = selectTargetReadable(options.target, context.source, 'Feature resource target');\n const reporter = getFeatureAttachmentReporter(context);\n const controller = createResourceController({\n allocateGeneration: openingMaterializationGenerationAllocator(requireToken()),\n key: selected => requireRequestKey(options.key(selected)),\n load: (selected, loadContext) => options.load(selected, loadContext),\n retention: options.retention,\n source: context.source,\n target,\n ...(reporter === undefined ? {} : { reporter }),\n ...(options.retry === undefined ? {} : { retry: options.retry }),\n });\n context.signal.addEventListener('abort', controller.fence, { once: true });\n\n if (context.signal.aborted) controller.fence();\n\n const detach = attachOpeningMaterialization(requireToken(), controller);\n\n return async () => {\n context.signal.removeEventListener('abort', controller.fence);\n try {\n await controller.close();\n } finally {\n detach();\n }\n };\n },\n });\n registration.token = registerFeatureMaterialization(\n attachment as unknown as LifetimeAttachmentRefIdentity,\n 'resource',\n );\n\n return attachment;\n }) as unknown as FeatureResourceBuilder<Id>;\n}\n\nexport {\n createFeatureResourceBuilder,\n requireRequestKey,\n requireTargetSelector,\n selectTargetReadable,\n snapshotFeatureResourceOptions,\n};\nexport type { FeatureResourceBuilder };\n"],"names":["resourceOptionKeys","assertFeatureResourceKeys","keys","key","requireResourceFunction","value","requireReadable","label","getSnapshot","subscribe","selectTargetReadable","select","source","requireTargetSelector","requireRequestKey","snapshotFeatureResourceOptions","assertPlainRecord","entries","dataEntries","load","target","snapshotResourceRetention","snapshotResourceRetry","createFeatureResourceBuilder","attach","options","registration","requireToken","attachment","context","reporter","getFeatureAttachmentReporter","controller","createResourceController","openingMaterializationGenerationAllocator","selected","loadContext","detach","attachOpeningMaterialization","registerFeatureMaterialization"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { Readable } from '@opetope/core';
2
+ import type { Awaitable } from '@opetope/core/internal';
3
+ import type { FeatureDisposer } from './feature-attachment.js';
4
+ import type { FeatureImportRecord, FeatureImportRef, FeatureLifecycleRef } from './feature-authoring-types.js';
5
+ import type { FeatureExposureMode } from './feature-call-types.js';
6
+ import type { ExactKeys } from './feature-record.js';
7
+ import type { FeatureTimers } from './feature-timers.js';
8
+ type FeatureReadableValue<Source> = Source extends Readable<infer Value> ? Value : never;
9
+ type FeatureScopeKey = number | string;
10
+ type FeatureScopeOpenContext = {
11
+ readonly signal: AbortSignal;
12
+ readonly timers: FeatureTimers;
13
+ };
14
+ interface FeatureWhileScopeOptions<Source extends Readable<unknown>, Id extends string, Mode extends FeatureExposureMode> {
15
+ readonly from: FeatureImportRef<Source, Id, Mode>;
16
+ readonly open: (value: FeatureReadableValue<Source>, context: FeatureScopeOpenContext) => Awaitable<FeatureDisposer | void>;
17
+ readonly when?: (value: FeatureReadableValue<Source>) => boolean;
18
+ }
19
+ interface FeatureSwitchScopeOptions<Source extends Readable<unknown>, Id extends string, Mode extends FeatureExposureMode> {
20
+ readonly from: FeatureImportRef<Source, Id, Mode>;
21
+ readonly key?: (value: NonNullable<FeatureReadableValue<Source>>) => FeatureScopeKey;
22
+ readonly open: (value: NonNullable<FeatureReadableValue<Source>>, context: FeatureScopeOpenContext) => Awaitable<FeatureDisposer | void>;
23
+ }
24
+ type FeatureKeyedScopeItem<Source> = Source extends Readable<readonly (infer Item)[]> ? Item : never;
25
+ interface FeatureKeyedScopeOptions<Source extends Readable<readonly unknown[]>, Id extends string, Mode extends FeatureExposureMode> {
26
+ readonly from: FeatureImportRef<Source, Id, Mode>;
27
+ readonly key: (value: FeatureKeyedScopeItem<Source>) => FeatureScopeKey;
28
+ readonly open: (value: FeatureKeyedScopeItem<Source>, context: FeatureScopeOpenContext) => Awaitable<FeatureDisposer | void>;
29
+ }
30
+ interface FeatureScopeBuilder<Id extends string, Imports extends FeatureImportRecord> {
31
+ readonly keyed: <Source extends Readable<readonly unknown[]>, Mode extends FeatureExposureMode, const Keys extends PropertyKey = keyof FeatureKeyedScopeOptions<Source, Id, Mode>>(options: ExactKeys<Keys, FeatureKeyedScopeOptions<Source, Id, Mode>> & FeatureKeyedScopeOptions<Source, Id, Mode>) => FeatureLifecycleRef<Source, Id, Imports, Mode>;
32
+ readonly switch: <Source extends Readable<unknown>, Mode extends FeatureExposureMode, const Keys extends PropertyKey = keyof FeatureSwitchScopeOptions<Source, Id, Mode>>(options: ExactKeys<Keys, FeatureSwitchScopeOptions<Source, Id, Mode>> & FeatureSwitchScopeOptions<Source, Id, Mode>) => FeatureLifecycleRef<Source, Id, Imports, Mode>;
33
+ readonly while: <Source extends Readable<unknown>, Mode extends FeatureExposureMode, const Keys extends PropertyKey = keyof FeatureWhileScopeOptions<Source, Id, Mode>>(options: ExactKeys<Keys, FeatureWhileScopeOptions<Source, Id, Mode>> & FeatureWhileScopeOptions<Source, Id, Mode>) => FeatureLifecycleRef<Source, Id, Imports, Mode>;
34
+ }
35
+ export type { FeatureScopeBuilder, FeatureScopeKey };
@@ -0,0 +1,29 @@
1
+ import type { FeatureAttachBuilder, FeatureImportRecord } from './feature-authoring-types.js';
2
+ import type { FeatureScopeBuilder } from './feature-scope-types.js';
3
+ import type { ErrorReporter } from './public-module.js';
4
+ interface ReactiveScopeController {
5
+ readonly dispose: () => Promise<void>;
6
+ readonly fence: () => void;
7
+ readonly invalidateProjection?: () => void;
8
+ readonly project: (snapshot: unknown) => unknown;
9
+ readonly update: (snapshot: unknown) => Promise<void>;
10
+ }
11
+ interface ReactiveScopeState {
12
+ readonly close: () => Promise<void>;
13
+ readonly fence: () => void;
14
+ readonly open: () => Promise<void>;
15
+ }
16
+ declare function createReactiveScopeState(source: unknown, ownerSignal: AbortSignal, controller: ReactiveScopeController, reporter: ErrorReporter | undefined): ReactiveScopeState;
17
+ type ReactiveScopeNode = {
18
+ readonly createController: (reporter: ErrorReporter | undefined) => ReactiveScopeController;
19
+ readonly from: object;
20
+ };
21
+ type ReactiveScopeKind = 'keyed' | 'switch' | 'while';
22
+ /**
23
+ * One node description for both owners: `own` binds it to an attachment, a model opens it directly against its own
24
+ * signal (D73). The dynamic child module and the controller semantics stay single-sourced.
25
+ */
26
+ declare function createReactiveScopeNode(kind: ReactiveScopeKind, id: string, value: unknown): ReactiveScopeNode;
27
+ declare function createFeatureScopeBuilder<Id extends string, Imports extends FeatureImportRecord>(featureId: Id, attach: FeatureAttachBuilder<Id, Imports>): FeatureScopeBuilder<Id, Imports>;
28
+ export { createFeatureScopeBuilder, createReactiveScopeNode, createReactiveScopeState };
29
+ export type { ReactiveScopeKind };
@@ -0,0 +1,2 @@
1
+ import{isReadable as R}from"@opetope/core/internal";import{createDynamicScopeChild as h}from"./dynamic-scope-child.js";import{closedSelection as S,dynamicScopeSelection as b,createDynamicScopeController as k}from"./dynamic-scope-controller.js";import{createFeatureStatefulAttachment as $,getFeatureAttachmentReporter as C}from"./feature-attachment.js";import{assertPlainRecord as T,dataEntries as z}from"./feature-record.js";import{createKeyedScopeController as K}from"./keyed-scope-controller.js";import{reportRuntimeFailure as g}from"./runtime-error-reporting.js";function w(e,t){return{dispose:e.dispose,fence:e.fence,...e.invalidateProjection===void 0?{}:{invalidateProjection:e.invalidateProjection},project:t,update:n=>e.update(n)}}const L=new Set(["from","open","when"]),q=new Set(["from","key","open"]),A=new Set(["from","key","open"]);function m(e,t){if(typeof e!="function")throw new TypeError(`${t} must be a function.`);return e}function F(e,t){if(e!==void 0)return m(e,t)}function l(e,t,n,a){T(e,t);const i=z(e,t),r=new Set(i.map(([o])=>o));for(const o of r)if(!n.has(o))throw new TypeError(`Unknown ${t} option ${o}.`);for(const o of a)if(!r.has(o))throw new TypeError(`${t} requires own ${o}.`);const c=Object.freeze(Object.fromEntries(i));if(typeof c.from!="object"||c.from===null)throw new TypeError(`${t} from must be an import from this definition.`);return c}function B(e){const t=l(e,"Feature while scope",L,["from","open"]);return Object.freeze({from:t.from,open:m(t.open,"Feature while scope open"),when:F(t.when,"Feature while scope when")})}function D(e){const t=l(e,"Feature switch scope",q,["from","open"]);return Object.freeze({from:t.from,key:F(t.key,"Feature switch scope key"),open:m(t.open,"Feature switch scope open")})}function N(e){const t=l(e,"Feature keyed scope",A,["from","key","open"]);return Object.freeze({from:t.from,key:m(t.key,"Feature keyed scope key"),open:m(t.open,"Feature keyed scope open")})}function U(e){if(!R(e))throw new TypeError("Feature dynamic scope from must resolve to a Readable.")}function j(e,t){if(typeof e!="string"&&typeof e!="number")throw new TypeError(`${t} must return a string or number.`);return e}function O(e,t,n,a){U(e);let i=!0,r=0,c;const o=s=>g(s,a),f=()=>{var d;const s=++r;(d=n.invalidateProjection)==null||d.call(n);try{const y=e.getSnapshot();if(!i||s!==r)return Promise.resolve();const P=n.project(y);return!i||s!==r?Promise.resolve():n.update(P)}catch(y){return Promise.reject(y)}},p=()=>{i&&f().catch(o)},u=()=>{i&&(i=!1,r+=1,t.removeEventListener("abort",u),n.fence())},E=()=>{c!==void 0&&(c(),c=void 0)};return Object.freeze({async close(){u();let s;try{E()}catch(d){s=d}try{await n.dispose()}catch(d){s===void 0?s=d:o(d)}if(s!==void 0)return Promise.reject(s)},fence:u,async open(){try{const s=e.subscribe(p);if(typeof s!="function")throw new TypeError("Readable subscribe must return an unsubscribe function.");if(c=s,t.addEventListener("abort",u,{once:!0}),t.aborted&&u(),!i)return;await f()}catch(s){throw u(),s}}})}function v(e,t,n){if(e==="while"){const r=B(n),c=h(t,r.open);return{createController:o=>{const f=k(c,o);return w(f,p=>{var u;return((u=r.when)==null?void 0:u.call(r,p))??!!p?b(p,"active"):S})},from:r.from}}if(e==="switch"){const r=D(n),c=h(t,r.open);return{createController:o=>{const f=k(c,o);return w(f,p=>{if(p==null)return S;const u=r.key===void 0?p:j(r.key(p),"Feature switch scope key");return b(p,u)})},from:r.from}}const a=N(n),i=h(t,a.open);return{createController:r=>{const c=K(i,o=>j(a.key(o),"Feature keyed scope key"),r);return w(c,o=>o)},from:a.from}}function W(e,t){let n=0;const a=t,i=(r,c)=>{n+=1;const o=v(r,`${e}.scope.${String(n)}`,c);return a(o.from,$({close:f=>f.close(),create:f=>{const p=C(f);return O(f.source,f.signal,o.createController(p),p)},open:f=>f.open()}))};return Object.freeze({keyed:r=>i("keyed",r),switch:r=>i("switch",r),while:r=>i("while",r)})}export{W as createFeatureScopeBuilder,v as createReactiveScopeNode,O as createReactiveScopeState};
2
+ //# sourceMappingURL=feature-scope.js.map