@milaboratories/pl-model-common 1.31.1 → 1.32.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 (279) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +7 -13
  2. package/dist/author_marker.d.ts.map +1 -0
  3. package/dist/base32_encode.cjs +1 -2
  4. package/dist/base32_encode.cjs.map +1 -1
  5. package/dist/base32_encode.js +1 -1
  6. package/dist/base32_encode.js.map +1 -1
  7. package/dist/base64.cjs +1 -2
  8. package/dist/base64.cjs.map +1 -1
  9. package/dist/base64.d.ts.map +1 -0
  10. package/dist/base64.js +1 -1
  11. package/dist/block_state.d.ts.map +1 -0
  12. package/dist/bmodel/block_config.cjs +1 -2
  13. package/dist/bmodel/block_config.cjs.map +1 -1
  14. package/dist/bmodel/block_config.d.ts +0 -1
  15. package/dist/bmodel/block_config.d.ts.map +1 -0
  16. package/dist/bmodel/block_config.js +1 -1
  17. package/dist/bmodel/block_config.js.map +1 -1
  18. package/dist/bmodel/code.cjs +2 -3
  19. package/dist/bmodel/code.cjs.map +1 -1
  20. package/dist/bmodel/code.d.ts +0 -1
  21. package/dist/bmodel/code.d.ts.map +1 -0
  22. package/dist/bmodel/code.js +1 -2
  23. package/dist/bmodel/code.js.map +1 -1
  24. package/dist/bmodel/container.d.ts.map +1 -0
  25. package/dist/bmodel/index.cjs +3 -3
  26. package/dist/bmodel/index.js +3 -3
  27. package/dist/bmodel/normalization.cjs +2 -4
  28. package/dist/bmodel/normalization.cjs.map +1 -1
  29. package/dist/bmodel/normalization.d.ts.map +1 -0
  30. package/dist/bmodel/normalization.js +2 -3
  31. package/dist/bmodel/normalization.js.map +1 -1
  32. package/dist/bmodel/types.d.ts.map +1 -0
  33. package/dist/branding.d.ts.map +1 -0
  34. package/dist/common_types.d.ts.map +1 -0
  35. package/dist/driver_kit.d.ts +0 -1
  36. package/dist/driver_kit.d.ts.map +1 -0
  37. package/dist/drivers/ChunkedStreamReader.cjs +1 -2
  38. package/dist/drivers/ChunkedStreamReader.cjs.map +1 -1
  39. package/dist/drivers/ChunkedStreamReader.d.ts.map +1 -0
  40. package/dist/drivers/ChunkedStreamReader.js +1 -1
  41. package/dist/drivers/ChunkedStreamReader.js.map +1 -1
  42. package/dist/drivers/blob.cjs +2 -3
  43. package/dist/drivers/blob.cjs.map +1 -1
  44. package/dist/drivers/blob.d.ts.map +1 -0
  45. package/dist/drivers/blob.js +1 -2
  46. package/dist/drivers/blob.js.map +1 -1
  47. package/dist/drivers/index.cjs +18 -18
  48. package/dist/drivers/index.d.ts +5 -6
  49. package/dist/drivers/index.js +17 -17
  50. package/dist/drivers/interfaces.d.ts.map +1 -0
  51. package/dist/drivers/log.cjs +11 -4
  52. package/dist/drivers/log.cjs.map +1 -1
  53. package/dist/drivers/log.d.ts +14 -7
  54. package/dist/drivers/log.d.ts.map +1 -0
  55. package/dist/drivers/log.js +11 -4
  56. package/dist/drivers/log.js.map +1 -1
  57. package/dist/drivers/ls.cjs +2 -3
  58. package/dist/drivers/ls.cjs.map +1 -1
  59. package/dist/drivers/ls.d.ts +0 -2
  60. package/dist/drivers/ls.d.ts.map +1 -0
  61. package/dist/drivers/ls.js +1 -2
  62. package/dist/drivers/ls.js.map +1 -1
  63. package/dist/drivers/pframe/column_filter.d.ts.map +1 -0
  64. package/dist/drivers/pframe/data_info.cjs +2 -3
  65. package/dist/drivers/pframe/data_info.cjs.map +1 -1
  66. package/dist/drivers/pframe/data_info.d.ts.map +1 -0
  67. package/dist/drivers/pframe/data_info.js +1 -2
  68. package/dist/drivers/pframe/data_info.js.map +1 -1
  69. package/dist/drivers/pframe/data_types.cjs +4 -5
  70. package/dist/drivers/pframe/data_types.cjs.map +1 -1
  71. package/dist/drivers/pframe/data_types.d.ts.map +1 -0
  72. package/dist/drivers/pframe/data_types.js +3 -4
  73. package/dist/drivers/pframe/data_types.js.map +1 -1
  74. package/dist/drivers/pframe/driver.cjs +1 -2
  75. package/dist/drivers/pframe/driver.cjs.map +1 -1
  76. package/dist/drivers/pframe/driver.d.ts +0 -1
  77. package/dist/drivers/pframe/driver.d.ts.map +1 -0
  78. package/dist/drivers/pframe/driver.js +1 -1
  79. package/dist/drivers/pframe/filter_spec.d.ts.map +1 -0
  80. package/dist/drivers/pframe/find_columns.d.ts.map +1 -0
  81. package/dist/drivers/pframe/index.cjs +15 -15
  82. package/dist/drivers/pframe/index.d.ts +4 -6
  83. package/dist/drivers/pframe/index.js +12 -12
  84. package/dist/drivers/pframe/linker_columns.cjs +3 -4
  85. package/dist/drivers/pframe/linker_columns.cjs.map +1 -1
  86. package/dist/drivers/pframe/linker_columns.d.ts.map +1 -0
  87. package/dist/drivers/pframe/linker_columns.js +1 -2
  88. package/dist/drivers/pframe/linker_columns.js.map +1 -1
  89. package/dist/drivers/pframe/pframe.d.ts +0 -2
  90. package/dist/drivers/pframe/pframe.d.ts.map +1 -0
  91. package/dist/drivers/pframe/query/index.cjs +1 -1
  92. package/dist/drivers/pframe/query/index.d.ts +2 -2
  93. package/dist/drivers/pframe/query/index.js +1 -1
  94. package/dist/drivers/pframe/query/query_common.d.ts +39 -4
  95. package/dist/drivers/pframe/query/query_common.d.ts.map +1 -0
  96. package/dist/drivers/pframe/query/query_data.d.ts +18 -5
  97. package/dist/drivers/pframe/query/query_data.d.ts.map +1 -0
  98. package/dist/drivers/pframe/query/query_spec.d.ts +14 -6
  99. package/dist/drivers/pframe/query/query_spec.d.ts.map +1 -0
  100. package/dist/drivers/pframe/query/utils.cjs +30 -4
  101. package/dist/drivers/pframe/query/utils.cjs.map +1 -1
  102. package/dist/drivers/pframe/query/utils.d.ts.map +1 -0
  103. package/dist/drivers/pframe/query/utils.js +28 -2
  104. package/dist/drivers/pframe/query/utils.js.map +1 -1
  105. package/dist/drivers/pframe/spec/anchored.cjs +4 -5
  106. package/dist/drivers/pframe/spec/anchored.cjs.map +1 -1
  107. package/dist/drivers/pframe/spec/anchored.d.ts +3 -3
  108. package/dist/drivers/pframe/spec/anchored.d.ts.map +1 -0
  109. package/dist/drivers/pframe/spec/anchored.js +1 -2
  110. package/dist/drivers/pframe/spec/anchored.js.map +1 -1
  111. package/dist/drivers/pframe/spec/filtered_column.cjs +1 -2
  112. package/dist/drivers/pframe/spec/filtered_column.cjs.map +1 -1
  113. package/dist/drivers/pframe/spec/filtered_column.d.ts.map +1 -0
  114. package/dist/drivers/pframe/spec/filtered_column.js +1 -1
  115. package/dist/drivers/pframe/spec/ids.cjs +2 -3
  116. package/dist/drivers/pframe/spec/ids.cjs.map +1 -1
  117. package/dist/drivers/pframe/spec/ids.d.ts +0 -2
  118. package/dist/drivers/pframe/spec/ids.d.ts.map +1 -0
  119. package/dist/drivers/pframe/spec/ids.js +1 -2
  120. package/dist/drivers/pframe/spec/ids.js.map +1 -1
  121. package/dist/drivers/pframe/spec/index.cjs +6 -6
  122. package/dist/drivers/pframe/spec/index.d.ts +1 -1
  123. package/dist/drivers/pframe/spec/index.js +6 -6
  124. package/dist/drivers/pframe/spec/native_id.cjs +4 -5
  125. package/dist/drivers/pframe/spec/native_id.cjs.map +1 -1
  126. package/dist/drivers/pframe/spec/native_id.d.ts +0 -2
  127. package/dist/drivers/pframe/spec/native_id.d.ts.map +1 -0
  128. package/dist/drivers/pframe/spec/native_id.js +1 -2
  129. package/dist/drivers/pframe/spec/native_id.js.map +1 -1
  130. package/dist/drivers/pframe/spec/selectors.cjs +3 -4
  131. package/dist/drivers/pframe/spec/selectors.cjs.map +1 -1
  132. package/dist/drivers/pframe/spec/selectors.d.ts +0 -2
  133. package/dist/drivers/pframe/spec/selectors.d.ts.map +1 -0
  134. package/dist/drivers/pframe/spec/selectors.js +1 -2
  135. package/dist/drivers/pframe/spec/selectors.js.map +1 -1
  136. package/dist/drivers/pframe/spec/spec.cjs +12 -8
  137. package/dist/drivers/pframe/spec/spec.cjs.map +1 -1
  138. package/dist/drivers/pframe/spec/spec.d.ts +15 -3
  139. package/dist/drivers/pframe/spec/spec.d.ts.map +1 -0
  140. package/dist/drivers/pframe/spec/spec.js +9 -5
  141. package/dist/drivers/pframe/spec/spec.js.map +1 -1
  142. package/dist/drivers/pframe/spec_driver.d.ts +37 -4
  143. package/dist/drivers/pframe/spec_driver.d.ts.map +1 -0
  144. package/dist/drivers/pframe/table.d.ts.map +1 -0
  145. package/dist/drivers/pframe/table_calculate.cjs +6 -7
  146. package/dist/drivers/pframe/table_calculate.cjs.map +1 -1
  147. package/dist/drivers/pframe/table_calculate.d.ts +0 -2
  148. package/dist/drivers/pframe/table_calculate.d.ts.map +1 -0
  149. package/dist/drivers/pframe/table_calculate.js +1 -2
  150. package/dist/drivers/pframe/table_calculate.js.map +1 -1
  151. package/dist/drivers/pframe/table_common.cjs +1 -2
  152. package/dist/drivers/pframe/table_common.cjs.map +1 -1
  153. package/dist/drivers/pframe/table_common.d.ts +0 -2
  154. package/dist/drivers/pframe/table_common.d.ts.map +1 -0
  155. package/dist/drivers/pframe/table_common.js +1 -1
  156. package/dist/drivers/pframe/unique_values.d.ts +0 -2
  157. package/dist/drivers/pframe/unique_values.d.ts.map +1 -0
  158. package/dist/drivers/upload.d.ts.map +1 -0
  159. package/dist/drivers/urls.cjs +1 -2
  160. package/dist/drivers/urls.cjs.map +1 -1
  161. package/dist/drivers/urls.d.ts.map +1 -0
  162. package/dist/drivers/urls.js +1 -1
  163. package/dist/errors.cjs +1 -2
  164. package/dist/errors.cjs.map +1 -1
  165. package/dist/errors.d.ts.map +1 -0
  166. package/dist/errors.js +1 -1
  167. package/dist/errors.js.map +1 -1
  168. package/dist/flags/block_flags.cjs +1 -2
  169. package/dist/flags/block_flags.cjs.map +1 -1
  170. package/dist/flags/block_flags.d.ts +0 -2
  171. package/dist/flags/block_flags.d.ts.map +1 -0
  172. package/dist/flags/block_flags.js +1 -1
  173. package/dist/flags/flag_utils.cjs +1 -2
  174. package/dist/flags/flag_utils.cjs.map +1 -1
  175. package/dist/flags/flag_utils.d.ts.map +1 -0
  176. package/dist/flags/flag_utils.js +1 -1
  177. package/dist/flags/flag_utils.js.map +1 -1
  178. package/dist/flags/type_utils.d.ts.map +1 -0
  179. package/dist/httpAuth.cjs +1 -2
  180. package/dist/httpAuth.cjs.map +1 -1
  181. package/dist/httpAuth.d.ts.map +1 -0
  182. package/dist/httpAuth.js +1 -1
  183. package/dist/index.cjs +47 -47
  184. package/dist/index.d.ts +6 -11
  185. package/dist/index.js +2 -3
  186. package/dist/json.cjs +2 -3
  187. package/dist/json.cjs.map +1 -1
  188. package/dist/json.d.ts.map +1 -0
  189. package/dist/json.js +1 -2
  190. package/dist/json.js.map +1 -1
  191. package/dist/navigation.cjs +1 -2
  192. package/dist/navigation.cjs.map +1 -1
  193. package/dist/navigation.d.ts.map +1 -0
  194. package/dist/navigation.js +1 -1
  195. package/dist/plid.cjs +6 -7
  196. package/dist/plid.cjs.map +1 -1
  197. package/dist/plid.d.ts.map +1 -0
  198. package/dist/plid.js +4 -5
  199. package/dist/plid.js.map +1 -1
  200. package/dist/pool/entry.d.ts.map +1 -0
  201. package/dist/pool/query.cjs +2 -3
  202. package/dist/pool/query.cjs.map +1 -1
  203. package/dist/pool/query.d.ts +0 -1
  204. package/dist/pool/query.d.ts.map +1 -0
  205. package/dist/pool/query.js +1 -2
  206. package/dist/pool/query.js.map +1 -1
  207. package/dist/pool/spec.cjs +2 -3
  208. package/dist/pool/spec.cjs.map +1 -1
  209. package/dist/pool/spec.d.ts +0 -2
  210. package/dist/pool/spec.d.ts.map +1 -0
  211. package/dist/pool/spec.js +1 -2
  212. package/dist/pool/spec.js.map +1 -1
  213. package/dist/pool_entry.cjs +1 -2
  214. package/dist/pool_entry.cjs.map +1 -1
  215. package/dist/pool_entry.d.ts.map +1 -0
  216. package/dist/pool_entry.js +1 -1
  217. package/dist/pool_entry.js.map +1 -1
  218. package/dist/ref.cjs +2 -3
  219. package/dist/ref.cjs.map +1 -1
  220. package/dist/ref.d.ts.map +1 -0
  221. package/dist/ref.js +1 -2
  222. package/dist/ref.js.map +1 -1
  223. package/dist/resource_types.cjs +1 -2
  224. package/dist/resource_types.cjs.map +1 -1
  225. package/dist/resource_types.d.ts.map +1 -0
  226. package/dist/resource_types.js +1 -1
  227. package/dist/services/index.cjs +6 -6
  228. package/dist/services/index.js +6 -6
  229. package/dist/services/service_capabilities.cjs +2 -3
  230. package/dist/services/service_capabilities.cjs.map +1 -1
  231. package/dist/services/service_capabilities.d.ts.map +1 -0
  232. package/dist/services/service_capabilities.js +1 -2
  233. package/dist/services/service_capabilities.js.map +1 -1
  234. package/dist/services/service_declarations.cjs +2 -3
  235. package/dist/services/service_declarations.cjs.map +1 -1
  236. package/dist/services/service_declarations.d.ts +0 -2
  237. package/dist/services/service_declarations.d.ts.map +1 -0
  238. package/dist/services/service_declarations.js +1 -2
  239. package/dist/services/service_declarations.js.map +1 -1
  240. package/dist/services/service_injector_factory.cjs +1 -2
  241. package/dist/services/service_injector_factory.cjs.map +1 -1
  242. package/dist/services/service_injector_factory.d.ts.map +1 -0
  243. package/dist/services/service_injector_factory.js +1 -1
  244. package/dist/services/service_injectors.cjs +4 -5
  245. package/dist/services/service_injectors.cjs.map +1 -1
  246. package/dist/services/service_injectors.d.ts.map +1 -0
  247. package/dist/services/service_injectors.js +1 -2
  248. package/dist/services/service_injectors.js.map +1 -1
  249. package/dist/services/service_registry.cjs +2 -3
  250. package/dist/services/service_registry.cjs.map +1 -1
  251. package/dist/services/service_registry.d.ts.map +1 -0
  252. package/dist/services/service_registry.js +1 -2
  253. package/dist/services/service_registry.js.map +1 -1
  254. package/dist/services/service_types.cjs +2 -3
  255. package/dist/services/service_types.cjs.map +1 -1
  256. package/dist/services/service_types.d.ts +7 -7
  257. package/dist/services/service_types.d.ts.map +1 -0
  258. package/dist/services/service_types.js +1 -2
  259. package/dist/services/service_types.js.map +1 -1
  260. package/dist/utag.d.ts.map +1 -0
  261. package/dist/util.cjs +1 -2
  262. package/dist/util.cjs.map +1 -1
  263. package/dist/util.d.ts.map +1 -0
  264. package/dist/util.js +1 -1
  265. package/dist/value_or_error.cjs +1 -2
  266. package/dist/value_or_error.cjs.map +1 -1
  267. package/dist/value_or_error.d.ts.map +1 -0
  268. package/dist/value_or_error.js +1 -1
  269. package/package.json +9 -9
  270. package/src/drivers/log.ts +21 -7
  271. package/src/drivers/pframe/query/query_common.ts +39 -0
  272. package/src/drivers/pframe/query/query_data.ts +20 -0
  273. package/src/drivers/pframe/query/query_spec.ts +17 -0
  274. package/src/drivers/pframe/query/utils.test.ts +37 -0
  275. package/src/drivers/pframe/query/utils.ts +25 -0
  276. package/src/drivers/pframe/spec/anchored.ts +8 -3
  277. package/src/drivers/pframe/spec/spec.ts +19 -6
  278. package/src/drivers/pframe/spec_driver.ts +42 -1
  279. package/src/services/service_types.ts +1 -6
@@ -1,5 +1,6 @@
1
- import { Branded } from "../branding.js";
1
+ import { Branded as Branded$1 } from "../branding.js";
2
2
  import { Services } from "./service_declarations.js";
3
+ import { UnionToIntersection } from "@milaboratories/helpers";
3
4
 
4
5
  //#region src/services/service_types.d.ts
5
6
  type ServiceTypesLike<Model = unknown, Ui = unknown, Kind extends ServiceType = ServiceType> = {
@@ -12,14 +13,14 @@ type ServiceTypesLike<Model = unknown, Ui = unknown, Kind extends ServiceType =
12
13
  type InferServiceModel<S extends ServiceTypesLike> = S extends ServiceTypesLike<infer M, unknown, ServiceType> ? M : unknown;
13
14
  type InferServiceUi<S extends ServiceTypesLike> = S extends ServiceTypesLike<unknown, infer U, ServiceType> ? U : unknown;
14
15
  type InferServiceKind<S extends ServiceTypesLike> = S extends ServiceTypesLike<unknown, unknown, infer K> ? K : ServiceType;
15
- type ServiceName<S extends ServiceTypesLike = ServiceTypesLike> = Branded<string, S>;
16
+ type ServiceName<S extends ServiceTypesLike = ServiceTypesLike> = Branded$1<string, S>;
16
17
  type ServiceType = "node" | "wasm";
17
18
  declare const service: <Model, Ui>() => <K extends ServiceType, N extends string>(options: {
18
19
  readonly type: K;
19
20
  readonly name: N;
20
- }) => Branded<N, ServiceTypesLike<Model, Ui, K>>, isNodeService: (id: ServiceName) => boolean;
21
+ }) => Branded$1<N, ServiceTypesLike<Model, Ui, K>>, isNodeService: (id: ServiceName) => boolean;
21
22
  declare function serviceFnKey(serviceId: string, method?: string): string;
22
- type ServiceBrand<T> = T extends Branded<string, infer S extends ServiceTypesLike> ? S : never;
23
+ type ServiceBrand<T> = T extends Branded$1<string, infer S extends ServiceTypesLike> ? S : never;
23
24
  type ModelServiceFactoryMap<SMap extends Record<string, ServiceName>> = { [K in keyof SMap]: (() => InferServiceModel<ServiceBrand<SMap[K]>>) | null };
24
25
  type UiServiceFactoryMap<SMap extends Record<string, ServiceName>> = { [K in keyof SMap]: (() => InferServiceUi<ServiceBrand<SMap[K]>>) | null };
25
26
  /** Contract between any service provider and any service consumer. */
@@ -29,7 +30,7 @@ interface ServiceDispatch {
29
30
  callServiceMethod(serviceId: ServiceName, method: string, ...args: unknown[]): unknown;
30
31
  }
31
32
  type SMap = typeof Services;
32
- type ExtractServiceName<T> = T extends Branded<infer N extends string, any> ? N : never;
33
+ type ExtractServiceName<T> = T extends Branded$1<infer N extends string, any> ? N : never;
33
34
  /** Model-side service interfaces keyed by service name literal. */
34
35
  type ModelServices = { [K in keyof SMap as ExtractServiceName<SMap[K]>]: InferServiceModel<ServiceBrand<SMap[K]>> };
35
36
  /** UI-side service interfaces keyed by service name literal. */
@@ -38,8 +39,7 @@ type UiServices = { [K in keyof SMap as ExtractServiceName<SMap[K]>]: InferServi
38
39
  type ServiceNameLiterals = { [K in keyof SMap]: ExtractServiceName<SMap[K]> };
39
40
  /** Auto-derived requires* feature flags from Services keys. */
40
41
  type ServiceRequireFlags = { [K in keyof SMap as `requires${K & string}`]?: boolean };
41
- type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
42
- type RequireServices<T extends ServiceName> = UnionToIntersection<T extends Branded<infer N extends string, infer S extends ServiceTypesLike> ? Record<N, InferServiceModel<S>> : never>;
42
+ type RequireServices<T extends ServiceName> = UnionToIntersection<T extends Branded$1<infer N extends string, infer S extends ServiceTypesLike> ? Record<N, InferServiceModel<S>> : never>;
43
43
  //#endregion
44
44
  export { InferServiceKind, InferServiceModel, InferServiceUi, ModelServiceFactoryMap, ModelServices, RequireServices, ServiceBrand, ServiceDispatch, ServiceName, ServiceNameLiterals, ServiceRequireFlags, ServiceType, ServiceTypesLike, UiServiceFactoryMap, UiServices, isNodeService, service, serviceFnKey };
45
45
  //# sourceMappingURL=service_types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service_types.d.ts","names":[],"sources":["../../src/services/service_types.ts"],"mappings":";;;;;KAKY,gBAAA,6CAGG,WAAA,GAAc,WAAA;EAAA,SAElB,OAAA;IAAY,KAAA,EAAO,KAAA;IAAO,EAAA,EAAI,EAAA;IAAI,IAAA,EAAM,IAAA;EAAA;AAAA;AAAA,KAGvC,iBAAA,WAA4B,gBAAA,IACtC,CAAA,SAAU,gBAAA,mBAAmC,WAAA,IAAe,CAAA;AAAA,KAElD,cAAA,WAAyB,gBAAA,IACnC,CAAA,SAAU,gBAAA,mBAAmC,WAAA,IAAe,CAAA;AAAA,KAElD,gBAAA,WAA2B,gBAAA,IACrC,CAAA,SAAU,gBAAA,8BAA8C,CAAA,GAAI,WAAA;AAAA,KAElD,WAAA,WAAsB,gBAAA,GAAmB,gBAAA,IAAoB,SAAA,SAAgB,CAAA;AAAA,KAE7E,WAAA;AAAA,cAIG,OAAA,8BAIS,WAAA,oBAA6B,OAAA;IAAA,SACpC,IAAA,EAAM,CAAA;IAAA,SACN,IAAA,EAAM,CAAA;EAAA,MACb,SAAA,CAAQ,CAAA,EAAG,gBAAA,CAAiB,KAAA,EAAO,EAAA,EAAI,CAAA,IAAA,aAAA,GAPZ,EAAA,EAqBf,WAAA;AAAA,iBAMN,YAAA,CAAa,SAAA,UAAmB,MAAA;AAAA,KAIpC,YAAA,MACV,CAAA,SAAU,SAAA,yBAAgC,gBAAA,IAAoB,CAAA;AAAA,KAEpD,sBAAA,cAAoC,MAAA,SAAe,WAAA,mBACjD,IAAA,UAAc,iBAAA,CAAkB,YAAA,CAAa,IAAA,CAAK,CAAA;AAAA,KAGpD,mBAAA,cAAiC,MAAA,SAAe,WAAA,mBAC9C,IAAA,UAAc,cAAA,CAAe,YAAA,CAAa,IAAA,CAAK,CAAA;;UAI5C,eAAA;EACf,eAAA,IAAmB,WAAA;EACnB,iBAAA,CAAkB,SAAA,EAAW,WAAA;EAC7B,iBAAA,CAAkB,SAAA,EAAW,WAAA,EAAa,MAAA,aAAmB,IAAA;AAAA;AAAA,KAM1D,IAAA,UAAc,QAAA;AAAA,KAEd,kBAAA,MAAwB,CAAA,SAAU,SAAA,gCAAuC,CAAA;;KAGlE,aAAA,iBACE,IAAA,IAAQ,kBAAA,CAAmB,IAAA,CAAK,CAAA,KAAM,iBAAA,CAAkB,YAAA,CAAa,IAAA,CAAK,CAAA;;KAI5E,UAAA,iBACE,IAAA,IAAQ,kBAAA,CAAmB,IAAA,CAAK,CAAA,KAAM,cAAA,CAAe,YAAA,CAAa,IAAA,CAAK,CAAA;;KAIzE,mBAAA,iBACE,IAAA,GAAO,kBAAA,CAAmB,IAAA,CAAK,CAAA;AAhF7C;AAAA,KAoFY,mBAAA,iBACE,IAAA,eAAmB,CAAA;AAAA,KAGrB,eAAA,WAA0B,WAAA,IAAe,mBAAA,CACnD,CAAA,SAAU,SAAA,yCAAgD,gBAAA,IACtD,MAAA,CAAO,CAAA,EAAG,iBAAA,CAAkB,CAAA"}
@@ -1,5 +1,4 @@
1
1
  import { ServiceAlreadyRegisteredError, ServiceInvalidIdError } from "../errors.js";
2
-
3
2
  //#region src/services/service_types.ts
4
3
  const SERVICE_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*$/;
5
4
  const { service, isNodeService } = (() => {
@@ -22,7 +21,7 @@ const { service, isNodeService } = (() => {
22
21
  function serviceFnKey(serviceId, method = "") {
23
22
  return `service:${serviceId}:${method}`;
24
23
  }
25
-
26
24
  //#endregion
27
25
  export { isNodeService, service, serviceFnKey };
26
+
28
27
  //# sourceMappingURL=service_types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"service_types.js","names":[],"sources":["../../src/services/service_types.ts"],"sourcesContent":["import type { Branded } from \"../branding\";\nimport { ServiceAlreadyRegisteredError, ServiceInvalidIdError } from \"../errors\";\nimport type { Services } from \"./service_declarations\";\n\nexport type ServiceTypesLike<\n Model = unknown,\n Ui = unknown,\n Kind extends ServiceType = ServiceType,\n> = {\n readonly __types?: { model: Model; ui: Ui; kind: Kind };\n};\n\nexport type InferServiceModel<S extends ServiceTypesLike> =\n S extends ServiceTypesLike<infer M, unknown, ServiceType> ? M : unknown;\n\nexport type InferServiceUi<S extends ServiceTypesLike> =\n S extends ServiceTypesLike<unknown, infer U, ServiceType> ? U : unknown;\n\nexport type InferServiceKind<S extends ServiceTypesLike> =\n S extends ServiceTypesLike<unknown, unknown, infer K> ? K : ServiceType;\n\nexport type ServiceName<S extends ServiceTypesLike = ServiceTypesLike> = Branded<string, S>;\n\nexport type ServiceType = \"node\" | \"wasm\";\n\nconst SERVICE_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*$/;\n\nexport const { service, isNodeService } = (() => {\n const typeMap = new Map<string, ServiceType>();\n return {\n service<Model, Ui>() {\n return <K extends ServiceType, N extends string>(options: {\n readonly type: K;\n readonly name: N;\n }): Branded<N, ServiceTypesLike<Model, Ui, K>> => {\n const { name, type } = options;\n if (!SERVICE_ID_PATTERN.test(name)) {\n throw new ServiceInvalidIdError(\n `Invalid service ID \"${name}\": must match ${SERVICE_ID_PATTERN}`,\n );\n }\n if (typeMap.has(name)) {\n throw new ServiceAlreadyRegisteredError(`Service \"${name}\" already registered`);\n }\n typeMap.set(name, type);\n return name as Branded<N, ServiceTypesLike<Model, Ui, K>>;\n };\n },\n isNodeService(id: ServiceName): boolean {\n return typeMap.get(id) === \"node\";\n },\n };\n})();\n\nexport function serviceFnKey(serviceId: string, method = \"\"): string {\n return `service:${serviceId}:${method}`;\n}\n\nexport type ServiceBrand<T> =\n T extends Branded<string, infer S extends ServiceTypesLike> ? S : never;\n\nexport type ModelServiceFactoryMap<SMap extends Record<string, ServiceName>> = {\n [K in keyof SMap]: (() => InferServiceModel<ServiceBrand<SMap[K]>>) | null;\n};\n\nexport type UiServiceFactoryMap<SMap extends Record<string, ServiceName>> = {\n [K in keyof SMap]: (() => InferServiceUi<ServiceBrand<SMap[K]>>) | null;\n};\n\n/** Contract between any service provider and any service consumer. */\nexport interface ServiceDispatch {\n getServiceNames(): ServiceName[];\n getServiceMethods(serviceId: ServiceName): string[];\n callServiceMethod(serviceId: ServiceName, method: string, ...args: unknown[]): unknown;\n}\n\n// Auto-derived types from the Services const in service_declarations.ts.\n// Adding a service to Services automatically updates all of these.\n\ntype SMap = typeof Services;\n\ntype ExtractServiceName<T> = T extends Branded<infer N extends string, any> ? N : never;\n\n/** Model-side service interfaces keyed by service name literal. */\nexport type ModelServices = {\n [K in keyof SMap as ExtractServiceName<SMap[K]>]: InferServiceModel<ServiceBrand<SMap[K]>>;\n};\n\n/** UI-side service interfaces keyed by service name literal. */\nexport type UiServices = {\n [K in keyof SMap as ExtractServiceName<SMap[K]>]: InferServiceUi<ServiceBrand<SMap[K]>>;\n};\n\n/** Map from Services keys to their unbranded string name literals. */\nexport type ServiceNameLiterals = {\n [K in keyof SMap]: ExtractServiceName<SMap[K]>;\n};\n\n/** Auto-derived requires* feature flags from Services keys. */\nexport type ServiceRequireFlags = {\n [K in keyof SMap as `requires${K & string}`]?: boolean;\n};\n\ntype UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\nexport type RequireServices<T extends ServiceName> = UnionToIntersection<\n T extends Branded<infer N extends string, infer S extends ServiceTypesLike>\n ? Record<N, InferServiceModel<S>>\n : never\n>;\n"],"mappings":";;;AAyBA,MAAM,qBAAqB;AAE3B,MAAa,EAAE,SAAS,yBAAyB;CAC/C,MAAM,0BAAU,IAAI,KAA0B;AAC9C,QAAO;EACL,UAAqB;AACnB,WAAiD,YAGC;IAChD,MAAM,EAAE,MAAM,SAAS;AACvB,QAAI,CAAC,mBAAmB,KAAK,KAAK,CAChC,OAAM,IAAI,sBACR,uBAAuB,KAAK,gBAAgB,qBAC7C;AAEH,QAAI,QAAQ,IAAI,KAAK,CACnB,OAAM,IAAI,8BAA8B,YAAY,KAAK,sBAAsB;AAEjF,YAAQ,IAAI,MAAM,KAAK;AACvB,WAAO;;;EAGX,cAAc,IAA0B;AACtC,UAAO,QAAQ,IAAI,GAAG,KAAK;;EAE9B;IACC;AAEJ,SAAgB,aAAa,WAAmB,SAAS,IAAY;AACnE,QAAO,WAAW,UAAU,GAAG"}
1
+ {"version":3,"file":"service_types.js","names":[],"sources":["../../src/services/service_types.ts"],"sourcesContent":["import { UnionToIntersection } from \"@milaboratories/helpers\";\nimport type { Branded } from \"../branding\";\nimport { ServiceAlreadyRegisteredError, ServiceInvalidIdError } from \"../errors\";\nimport type { Services } from \"./service_declarations\";\n\nexport type ServiceTypesLike<\n Model = unknown,\n Ui = unknown,\n Kind extends ServiceType = ServiceType,\n> = {\n readonly __types?: { model: Model; ui: Ui; kind: Kind };\n};\n\nexport type InferServiceModel<S extends ServiceTypesLike> =\n S extends ServiceTypesLike<infer M, unknown, ServiceType> ? M : unknown;\n\nexport type InferServiceUi<S extends ServiceTypesLike> =\n S extends ServiceTypesLike<unknown, infer U, ServiceType> ? U : unknown;\n\nexport type InferServiceKind<S extends ServiceTypesLike> =\n S extends ServiceTypesLike<unknown, unknown, infer K> ? K : ServiceType;\n\nexport type ServiceName<S extends ServiceTypesLike = ServiceTypesLike> = Branded<string, S>;\n\nexport type ServiceType = \"node\" | \"wasm\";\n\nconst SERVICE_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9]*$/;\n\nexport const { service, isNodeService } = (() => {\n const typeMap = new Map<string, ServiceType>();\n return {\n service<Model, Ui>() {\n return <K extends ServiceType, N extends string>(options: {\n readonly type: K;\n readonly name: N;\n }): Branded<N, ServiceTypesLike<Model, Ui, K>> => {\n const { name, type } = options;\n if (!SERVICE_ID_PATTERN.test(name)) {\n throw new ServiceInvalidIdError(\n `Invalid service ID \"${name}\": must match ${SERVICE_ID_PATTERN}`,\n );\n }\n if (typeMap.has(name)) {\n throw new ServiceAlreadyRegisteredError(`Service \"${name}\" already registered`);\n }\n typeMap.set(name, type);\n return name as Branded<N, ServiceTypesLike<Model, Ui, K>>;\n };\n },\n isNodeService(id: ServiceName): boolean {\n return typeMap.get(id) === \"node\";\n },\n };\n})();\n\nexport function serviceFnKey(serviceId: string, method = \"\"): string {\n return `service:${serviceId}:${method}`;\n}\n\nexport type ServiceBrand<T> =\n T extends Branded<string, infer S extends ServiceTypesLike> ? S : never;\n\nexport type ModelServiceFactoryMap<SMap extends Record<string, ServiceName>> = {\n [K in keyof SMap]: (() => InferServiceModel<ServiceBrand<SMap[K]>>) | null;\n};\n\nexport type UiServiceFactoryMap<SMap extends Record<string, ServiceName>> = {\n [K in keyof SMap]: (() => InferServiceUi<ServiceBrand<SMap[K]>>) | null;\n};\n\n/** Contract between any service provider and any service consumer. */\nexport interface ServiceDispatch {\n getServiceNames(): ServiceName[];\n getServiceMethods(serviceId: ServiceName): string[];\n callServiceMethod(serviceId: ServiceName, method: string, ...args: unknown[]): unknown;\n}\n\n// Auto-derived types from the Services const in service_declarations.ts.\n// Adding a service to Services automatically updates all of these.\n\ntype SMap = typeof Services;\n\ntype ExtractServiceName<T> = T extends Branded<infer N extends string, any> ? N : never;\n\n/** Model-side service interfaces keyed by service name literal. */\nexport type ModelServices = {\n [K in keyof SMap as ExtractServiceName<SMap[K]>]: InferServiceModel<ServiceBrand<SMap[K]>>;\n};\n\n/** UI-side service interfaces keyed by service name literal. */\nexport type UiServices = {\n [K in keyof SMap as ExtractServiceName<SMap[K]>]: InferServiceUi<ServiceBrand<SMap[K]>>;\n};\n\n/** Map from Services keys to their unbranded string name literals. */\nexport type ServiceNameLiterals = {\n [K in keyof SMap]: ExtractServiceName<SMap[K]>;\n};\n\n/** Auto-derived requires* feature flags from Services keys. */\nexport type ServiceRequireFlags = {\n [K in keyof SMap as `requires${K & string}`]?: boolean;\n};\n\nexport type RequireServices<T extends ServiceName> = UnionToIntersection<\n T extends Branded<infer N extends string, infer S extends ServiceTypesLike>\n ? Record<N, InferServiceModel<S>>\n : never\n>;\n"],"mappings":";;AA0BA,MAAM,qBAAqB;AAE3B,MAAa,EAAE,SAAS,yBAAyB;CAC/C,MAAM,0BAAU,IAAI,KAA0B;AAC9C,QAAO;EACL,UAAqB;AACnB,WAAiD,YAGC;IAChD,MAAM,EAAE,MAAM,SAAS;AACvB,QAAI,CAAC,mBAAmB,KAAK,KAAK,CAChC,OAAM,IAAI,sBACR,uBAAuB,KAAK,gBAAgB,qBAC7C;AAEH,QAAI,QAAQ,IAAI,KAAK,CACnB,OAAM,IAAI,8BAA8B,YAAY,KAAK,sBAAsB;AAEjF,YAAQ,IAAI,MAAM,KAAK;AACvB,WAAO;;;EAGX,cAAc,IAA0B;AACtC,UAAO,QAAQ,IAAI,GAAG,KAAK;;EAE9B;IACC;AAEJ,SAAgB,aAAa,WAAmB,SAAS,IAAY;AACnE,QAAO,WAAW,UAAU,GAAG"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utag.d.ts","names":[],"sources":["../src/utag.ts"],"mappings":";;;;UAGiB,aAAA;EAAA;EAAA,SAEN,KAAA,EAAO,CAAA;EAFY;;;;;;;EAAA,SAWnB,IAAA;AAAA;AAAA,UAGM,sBAAA,YAAkC,aAAA,CAAc,CAAA;EAAA,SACtD,MAAA,GAAS,YAAA;AAAA"}
package/dist/util.cjs CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  //#region src/util.ts
3
2
  function assertNever(x) {
4
3
  throw new Error("Unexpected object: " + x);
@@ -10,8 +9,8 @@ function assertNever(x) {
10
9
  function uniqueBy(array, makeId) {
11
10
  return [...new Map(array.map((e) => [makeId(e), e])).values()];
12
11
  }
13
-
14
12
  //#endregion
15
13
  exports.assertNever = assertNever;
16
14
  exports.uniqueBy = uniqueBy;
15
+
17
16
  //# sourceMappingURL=util.cjs.map
package/dist/util.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.cjs","names":[],"sources":["../src/util.ts"],"sourcesContent":["export function assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x); // This is ok, because this is a possible runtime error\n}\n\n/**\n * Return unique entries of the array by the provided id\n * For each id, the last entry is kept\n */\nexport function uniqueBy<T>(array: T[], makeId: (entry: T) => string): T[] {\n return [...new Map(array.map((e) => [makeId(e), e])).values()];\n}\n"],"mappings":";;AAAA,SAAgB,YAAY,GAAiB;AAC3C,OAAM,IAAI,MAAM,wBAAwB,EAAE;;;;;;AAO5C,SAAgB,SAAY,OAAY,QAAmC;AACzE,QAAO,CAAC,GAAG,IAAI,IAAI,MAAM,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC"}
1
+ {"version":3,"file":"util.cjs","names":[],"sources":["../src/util.ts"],"sourcesContent":["export function assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x); // This is ok, because this is a possible runtime error\n}\n\n/**\n * Return unique entries of the array by the provided id\n * For each id, the last entry is kept\n */\nexport function uniqueBy<T>(array: T[], makeId: (entry: T) => string): T[] {\n return [...new Map(array.map((e) => [makeId(e), e])).values()];\n}\n"],"mappings":";AAAA,SAAgB,YAAY,GAAiB;AAC3C,OAAM,IAAI,MAAM,wBAAwB,EAAE;;;;;;AAO5C,SAAgB,SAAY,OAAY,QAAmC;AACzE,QAAO,CAAC,GAAG,IAAI,IAAI,MAAM,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","names":[],"sources":["../src/util.ts"],"mappings":";iBAAgB,WAAA,CAAY,CAAA;AAA5B;;;;AAAA,iBAQgB,QAAA,GAAA,CAAY,KAAA,EAAO,CAAA,IAAK,MAAA,GAAS,KAAA,EAAO,CAAA,cAAe,CAAA"}
package/dist/util.js CHANGED
@@ -9,7 +9,7 @@ function assertNever(x) {
9
9
  function uniqueBy(array, makeId) {
10
10
  return [...new Map(array.map((e) => [makeId(e), e])).values()];
11
11
  }
12
-
13
12
  //#endregion
14
13
  export { assertNever, uniqueBy };
14
+
15
15
  //# sourceMappingURL=util.js.map
@@ -1,4 +1,3 @@
1
-
2
1
  //#region src/value_or_error.ts
3
2
  function mapValueInVOE(voe, cb) {
4
3
  return voe.ok ? {
@@ -6,7 +5,7 @@ function mapValueInVOE(voe, cb) {
6
5
  value: cb(voe.value)
7
6
  } : voe;
8
7
  }
9
-
10
8
  //#endregion
11
9
  exports.mapValueInVOE = mapValueInVOE;
10
+
12
11
  //# sourceMappingURL=value_or_error.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"value_or_error.cjs","names":[],"sources":["../src/value_or_error.ts"],"sourcesContent":["export type ValueOrError<V, E> =\n | {\n ok: true;\n value: V;\n }\n | {\n ok: false;\n error: E;\n };\n\nexport function mapValueInVOE<V1, V2, E>(\n voe: ValueOrError<V1, E>,\n cb: (value: V1) => V2,\n): ValueOrError<V2, E> {\n return voe.ok ? { ok: true, value: cb(voe.value) } : voe;\n}\n"],"mappings":";;AAUA,SAAgB,cACd,KACA,IACqB;AACrB,QAAO,IAAI,KAAK;EAAE,IAAI;EAAM,OAAO,GAAG,IAAI,MAAM;EAAE,GAAG"}
1
+ {"version":3,"file":"value_or_error.cjs","names":[],"sources":["../src/value_or_error.ts"],"sourcesContent":["export type ValueOrError<V, E> =\n | {\n ok: true;\n value: V;\n }\n | {\n ok: false;\n error: E;\n };\n\nexport function mapValueInVOE<V1, V2, E>(\n voe: ValueOrError<V1, E>,\n cb: (value: V1) => V2,\n): ValueOrError<V2, E> {\n return voe.ok ? { ok: true, value: cb(voe.value) } : voe;\n}\n"],"mappings":";AAUA,SAAgB,cACd,KACA,IACqB;AACrB,QAAO,IAAI,KAAK;EAAE,IAAI;EAAM,OAAO,GAAG,IAAI,MAAM;EAAE,GAAG"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value_or_error.d.ts","names":[],"sources":["../src/value_or_error.ts"],"mappings":";KAAY,YAAA;EAEN,EAAA;EACA,KAAA,EAAO,CAAA;AAAA;EAGP,EAAA;EACA,KAAA,EAAO,CAAA;AAAA;AAAA,iBAGG,aAAA,WAAA,CACd,GAAA,EAAK,YAAA,CAAa,EAAA,EAAI,CAAA,GACtB,EAAA,GAAK,KAAA,EAAO,EAAA,KAAO,EAAA,GAClB,YAAA,CAAa,EAAA,EAAI,CAAA"}
@@ -5,7 +5,7 @@ function mapValueInVOE(voe, cb) {
5
5
  value: cb(voe.value)
6
6
  } : voe;
7
7
  }
8
-
9
8
  //#endregion
10
9
  export { mapValueInVOE };
10
+
11
11
  //# sourceMappingURL=value_or_error.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-model-common",
3
- "version": "1.31.1",
3
+ "version": "1.32.0",
4
4
  "description": "Platforma SDK Model",
5
5
  "files": [
6
6
  "./dist/**/*",
@@ -18,17 +18,17 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "canonicalize": "~2.1.0",
21
- "zod": "~3.23.8",
22
- "@milaboratories/pl-error-like": "1.12.9",
23
- "@milaboratories/helpers": "1.14.1"
21
+ "zod": "~3.25.76",
22
+ "@milaboratories/helpers": "1.14.1",
23
+ "@milaboratories/pl-error-like": "1.12.9"
24
24
  },
25
25
  "devDependencies": {
26
- "@vitest/coverage-istanbul": "^4.0.18",
26
+ "@vitest/coverage-istanbul": "^4.1.3",
27
27
  "typescript": "~5.9.3",
28
- "vitest": "^4.0.18",
29
- "@milaboratories/build-configs": "1.5.2",
30
- "@milaboratories/ts-configs": "1.2.2",
31
- "@milaboratories/ts-builder": "1.3.0"
28
+ "vitest": "^4.1.3",
29
+ "@milaboratories/build-configs": "2.0.0",
30
+ "@milaboratories/ts-builder": "1.3.2",
31
+ "@milaboratories/ts-configs": "1.2.3"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "ts-builder build --target node",
@@ -1,18 +1,32 @@
1
- /** Handle of logs. This handle should be passed
2
- * to the driver for retrieving logs. */
3
- export type AnyLogHandle = LiveLogHandle | ReadyLogHandle;
1
+ import type { Branded } from "../branding";
2
+
3
+ /** Prefix constants — single source of truth for handle format. */
4
+ const LIVE_LOG_PREFIX = "log+live://log/";
5
+ const READY_LOG_PREFIX = "log+ready://log/";
4
6
 
5
7
  /** Handle of the live logs of a program.
6
8
  * The resource that represents a log can be deleted,
7
9
  * in this case the handle should be refreshed. */
8
- export type LiveLogHandle = `log+live://log/${string}`;
10
+ export type LiveLogHandle = Branded<`${typeof LIVE_LOG_PREFIX}${string}`, "LiveLogHandle">;
9
11
 
10
12
  /** Handle of the ready logs of a program. */
11
- export type ReadyLogHandle = `log+ready://log/${string}`;
13
+ export type ReadyLogHandle = Branded<`${typeof READY_LOG_PREFIX}${string}`, "ReadyLogHandle">;
14
+
15
+ /** Handle of logs. This handle should be passed
16
+ * to the driver for retrieving logs. */
17
+ export type AnyLogHandle = LiveLogHandle | ReadyLogHandle;
18
+
19
+ /** Type guard to check if a value is any kind of log handle. */
20
+ export function isAnyLogHandle(value: unknown): value is AnyLogHandle {
21
+ return (
22
+ typeof value === "string" &&
23
+ (value.startsWith(LIVE_LOG_PREFIX) || value.startsWith(READY_LOG_PREFIX))
24
+ );
25
+ }
12
26
 
13
- /** Type guard to check if log is live, and corresponding porcess is not finished. */
27
+ /** Type guard to check if log is live, and corresponding process is not finished. */
14
28
  export function isLiveLog(handle: AnyLogHandle | undefined): handle is LiveLogHandle {
15
- return handle !== undefined && handle.startsWith("log+live://log/");
29
+ return handle !== undefined && handle.startsWith(LIVE_LOG_PREFIX);
16
30
  }
17
31
 
18
32
  /** Driver to retrieve logs given log handle */
@@ -881,3 +881,42 @@ export interface QueryJoinEntry<Q> {
881
881
  /** The query to be joined */
882
882
  entry: Q;
883
883
  }
884
+
885
+ /**
886
+ * Linker-join query operation.
887
+ *
888
+ * Inner-joins a linker column (`linker`) with one or more secondary subqueries,
889
+ * then projects out the linker's one-side axes from the joined result. Used to
890
+ * traverse a linker relationship: rows on the secondary side are "lifted" onto
891
+ * the linker's many-side axes, with one-side axes collapsed away.
892
+ *
893
+ * Mirrors {@link QueryOuterJoin}'s `{ primary, secondary }` shape (with
894
+ * `secondary` as an array), but the linker side is a specialized sub-struct —
895
+ * a plain column reference rather than a full join entry.
896
+ *
897
+ * **Join behavior**:
898
+ * - The linker column is inner-joined with all `secondary` entries
899
+ * - After the join, the linker's one-side axes are projected out
900
+ * - Result axes = joined axes minus the linker's one-side axes
901
+ *
902
+ * **Note**: `secondary` must contain at least one entry (empty has no
903
+ * well-defined meaning for linker-join).
904
+ *
905
+ * @template L - Linker sub-struct type (layer-specific)
906
+ * @template JE - Join entry type for the secondary side
907
+ *
908
+ * @example
909
+ * // Traverse linker l1 and read rest data lifted onto l1's many-side
910
+ * {
911
+ * type: 'linkerJoin',
912
+ * linker: { column: 'l1' },
913
+ * secondary: [{ entry: restQuery, ... }]
914
+ * }
915
+ */
916
+ export interface QueryLinkerJoin<L, JE extends QueryJoinEntry<unknown>> {
917
+ type: "linkerJoin";
918
+ /** Linker side — column reference plus layer-specific integration data. */
919
+ linker: L;
920
+ /** Rest side — one or more subqueries joined with the linker (at least one). */
921
+ secondary: JE[];
922
+ }
@@ -21,6 +21,7 @@ import type {
21
21
  QueryFilter,
22
22
  QueryInlineColumn,
23
23
  QueryJoinEntry,
24
+ QueryLinkerJoin,
24
25
  QueryOuterJoin,
25
26
  QuerySliceAxes,
26
27
  QuerySort,
@@ -69,6 +70,24 @@ export type DataQuerySparseToDenseColumn = QuerySparseToDenseColumn<PObjectId, C
69
70
  export type DataQuerySymmetricJoin = QuerySymmetricJoin<DataQueryJoinEntry>;
70
71
  /** @see QueryOuterJoin */
71
72
  export type DataQueryOuterJoin = QueryOuterJoin<DataQueryJoinEntry>;
73
+ /**
74
+ * Linker side of a data-layer linker-join.
75
+ *
76
+ * Carries the linker column id along with integration-derived artifacts needed
77
+ * for execution:
78
+ * - `axesMapping` — how the linker's axes map into the joined result
79
+ * - `oneSideAxesIndices` — which axis indices in the joined result to project out
80
+ */
81
+ export type DataQueryLinkerJoinLinker = {
82
+ /** Linker column reference. */
83
+ column: PObjectId;
84
+ /** Linker's axes mapped into the joined result. */
85
+ axesMapping: number[];
86
+ /** Axis indices (in the joined result) to project out — the linker's one-side axes. */
87
+ oneSideAxesIndices: number[];
88
+ };
89
+ /** @see QueryLinkerJoin */
90
+ export type DataQueryLinkerJoin = QueryLinkerJoin<DataQueryLinkerJoinLinker, DataQueryJoinEntry>;
72
91
  /** @see QuerySliceAxes */
73
92
  export type DataQuerySliceAxes = QuerySliceAxes<DataQuery, QueryAxisSelector<number>>;
74
93
  /** @see QuerySort */
@@ -93,6 +112,7 @@ export type DataQuery =
93
112
  | DataQuerySparseToDenseColumn
94
113
  | DataQuerySymmetricJoin
95
114
  | DataQueryOuterJoin
115
+ | DataQueryLinkerJoin
96
116
  | DataQuerySliceAxes
97
117
  | DataQuerySort
98
118
  | DataQueryFilter;
@@ -21,6 +21,7 @@ import type {
21
21
  QueryFilter,
22
22
  QueryInlineColumn,
23
23
  QueryJoinEntry,
24
+ QueryLinkerJoin,
24
25
  QueryOuterJoin,
25
26
  QuerySliceAxes,
26
27
  QuerySort,
@@ -81,6 +82,21 @@ export type SpecQuerySparseToDenseColumn<C = PObjectId> = QuerySparseToDenseColu
81
82
  export type SpecQuerySymmetricJoin<C = PObjectId> = QuerySymmetricJoin<SpecQueryJoinEntry<C>>;
82
83
  /** @see QueryOuterJoin */
83
84
  export type SpecQueryOuterJoin<C = PObjectId> = QueryOuterJoin<SpecQueryJoinEntry<C>>;
85
+ /**
86
+ * Linker side of a spec-layer linker-join.
87
+ *
88
+ * At the spec layer the linker is just a column reference — integration artifacts
89
+ * (axes mapping, one-side indices) are derived during spec→data conversion.
90
+ */
91
+ export type SpecQueryLinkerJoinLinker<C = PObjectId> = {
92
+ /** Linker column reference. */
93
+ column: C;
94
+ };
95
+ /** @see QueryLinkerJoin */
96
+ export type SpecQueryLinkerJoin<C = PObjectId> = QueryLinkerJoin<
97
+ SpecQueryLinkerJoinLinker<C>,
98
+ SpecQueryJoinEntry<C>
99
+ >;
84
100
  /** @see QuerySliceAxes */
85
101
  export type SpecQuerySliceAxes<C = PObjectId> = QuerySliceAxes<
86
102
  SpecQuery<C>,
@@ -112,6 +128,7 @@ export type SpecQuery<C = PObjectId> =
112
128
  | SpecQuerySparseToDenseColumn<C>
113
129
  | SpecQuerySymmetricJoin<C>
114
130
  | SpecQueryOuterJoin<C>
131
+ | SpecQueryLinkerJoin<C>
115
132
  | SpecQuerySliceAxes<C>
116
133
  | SpecQuerySort<C>
117
134
  | SpecQueryFilter<C>;
@@ -74,6 +74,20 @@ describe("traverseQuerySpec", () => {
74
74
  });
75
75
  });
76
76
 
77
+ it("transforms columns inside linkerJoin", () => {
78
+ const q: Q = {
79
+ type: "linkerJoin",
80
+ linker: { column: "l" },
81
+ secondary: [entry(col("a")), entry(col("b"))],
82
+ };
83
+ const result = traverseQuerySpec(q, { column: (c) => c.toUpperCase() });
84
+ expect(result).toEqual({
85
+ type: "linkerJoin",
86
+ linker: { column: "L" },
87
+ secondary: [entry({ type: "column", column: "A" }), entry({ type: "column", column: "B" })],
88
+ });
89
+ });
90
+
77
91
  it("transforms columns inside filter", () => {
78
92
  const q: Q = {
79
93
  type: "filter",
@@ -195,6 +209,15 @@ describe("collectSpecQueryColumns", () => {
195
209
  } as unknown as Q;
196
210
  expect(collectSpecQueryColumns(q)).toEqual([]);
197
211
  });
212
+
213
+ it("collects linker and secondary columns from linkerJoin", () => {
214
+ const q: Q = {
215
+ type: "linkerJoin",
216
+ linker: { column: "l" },
217
+ secondary: [entry(col("a")), entry(col("b"))],
218
+ };
219
+ expect(collectSpecQueryColumns(q)).toEqual(["l", "a", "b"]);
220
+ });
198
221
  });
199
222
 
200
223
  describe("sortSpecQuery", () => {
@@ -221,6 +244,20 @@ describe("sortSpecQuery", () => {
221
244
  });
222
245
  });
223
246
 
247
+ it("sorts linkerJoin secondary entries (linker column unchanged)", () => {
248
+ const q: SpecQuery = {
249
+ type: "linkerJoin",
250
+ linker: { column: pid("l") },
251
+ secondary: [pentry(pcol("c")), pentry(pcol("a")), pentry(pcol("b"))],
252
+ };
253
+ const result = sortSpecQuery(q);
254
+ expect(result).toEqual({
255
+ type: "linkerJoin",
256
+ linker: { column: "l" },
257
+ secondary: [pentry(pcol("a")), pentry(pcol("b")), pentry(pcol("c"))],
258
+ });
259
+ });
260
+
224
261
  it("sorts sparseToDenseColumn axesIndices", () => {
225
262
  const q: SpecQuery = {
226
263
  type: "sparseToDenseColumn",
@@ -78,6 +78,13 @@ export function traverseQuerySpec<C1, C2>(
78
78
  secondary: query.secondary.map(traverseEntry),
79
79
  };
80
80
  break;
81
+ case "linkerJoin":
82
+ result = {
83
+ ...query,
84
+ linker: { ...query.linker, column: visitor.column(query.linker.column) },
85
+ secondary: query.secondary.map(traverseEntry),
86
+ };
87
+ break;
81
88
  case "filter":
82
89
  case "sort":
83
90
  case "sliceAxes":
@@ -126,6 +133,10 @@ export function sortSpecQuery(query: SpecQuery): SpecQuery {
126
133
  const sorted = [...node.secondary].sort(cmpQueryJoinEntrySpec);
127
134
  return { ...node, secondary: sorted };
128
135
  }
136
+ case "linkerJoin": {
137
+ const sorted = [...node.secondary].sort(cmpQueryJoinEntrySpec);
138
+ return { ...node, secondary: sorted };
139
+ }
129
140
  case "sliceAxes":
130
141
  return {
131
142
  ...node,
@@ -198,6 +209,20 @@ function cmpQuerySpec(lhs: SpecQuery, rhs: SpecQuery): number {
198
209
  }
199
210
  return 0;
200
211
  }
212
+ case "linkerJoin": {
213
+ const rhsLinker = rhs as typeof lhs;
214
+ if (lhs.linker.column !== rhsLinker.linker.column) {
215
+ return lhs.linker.column < rhsLinker.linker.column ? -1 : 1;
216
+ }
217
+ if (lhs.secondary.length !== rhsLinker.secondary.length) {
218
+ return lhs.secondary.length - rhsLinker.secondary.length;
219
+ }
220
+ for (let i = 0; i < lhs.secondary.length; i++) {
221
+ const cmp = cmpQueryJoinEntrySpec(lhs.secondary[i], rhsLinker.secondary[i]);
222
+ if (cmp !== 0) return cmp;
223
+ }
224
+ return 0;
225
+ }
201
226
  case "sliceAxes":
202
227
  return cmpQuerySpec(lhs.input, (rhs as typeof lhs).input);
203
228
  case "sort":
@@ -50,7 +50,12 @@ export class AnchoredIdDeriver {
50
50
  * Creates a new anchor context from a set of anchor column specifications
51
51
  * @param anchors Record of anchor column specifications indexed by anchor ID
52
52
  */
53
- constructor(public readonly anchors: Record<string, PColumnSpec>) {
53
+ constructor(
54
+ public readonly anchors: Record<
55
+ string,
56
+ Pick<PColumnSpec, "axesSpec" | "domain" | "contextDomain">
57
+ >,
58
+ ) {
54
59
  const anchorEntries = Object.entries(anchors);
55
60
  anchorEntries.sort((a, b) => a[0].localeCompare(b[0]));
56
61
  for (const [anchorId, spec] of anchorEntries) {
@@ -241,7 +246,7 @@ export type ResolveAnchorsOptions = {
241
246
  * @returns A non-anchored column matcher with all references resolved to actual values
242
247
  */
243
248
  export function resolveAnchors(
244
- anchors: Record<string, PColumnSpec>,
249
+ anchors: Record<string, Pick<PColumnSpec, "axesSpec" | "domain" | "contextDomain">>,
245
250
  matcher: AnchoredPColumnSelector,
246
251
  options?: ResolveAnchorsOptions,
247
252
  ): PColumnSelector {
@@ -321,7 +326,7 @@ export function resolveAnchors(
321
326
  * Resolves an anchored axis reference to a concrete AxisId
322
327
  */
323
328
  function resolveAxisReference(
324
- anchors: Record<string, PColumnSpec>,
329
+ anchors: Record<string, Pick<PColumnSpec, "axesSpec">>,
325
330
  axisRef: AAxisSelector,
326
331
  ): LegacyAxisSelector {
327
332
  if (!isAnchorAxisRef(axisRef)) return axisRef;
@@ -145,6 +145,7 @@ export const Annotation = {
145
145
  IsScore: "pl7.app/isScore",
146
146
  IsSubset: "pl7.app/isSubset",
147
147
  Label: "pl7.app/label",
148
+ LinkLabel: "pl7.app/linkLabel",
148
149
  Max: "pl7.app/max",
149
150
  Min: "pl7.app/min",
150
151
  MultipliesBy: "pl7.app/multipliesBy",
@@ -204,10 +205,24 @@ export type Annotation = Metadata &
204
205
  [Annotation.Table.FontFamily]: string;
205
206
  [Annotation.Table.OrderPriority]: StringifiedJson<number>;
206
207
  [Annotation.Table.Visibility]: "hidden" | "optional" | (string & {});
207
- [Annotation.Trace]: StringifiedJson<Record<string, unknown>>;
208
+ [Annotation.Trace]: StringifiedJson<Trace>;
208
209
  [Annotation.VDJ.IsAssemblingFeature]: StringifiedJson<boolean>;
209
210
  }>;
210
211
 
212
+ /// One step in a column's derivation lineage. Only `type` and `label` are part
213
+ /// of the typed public surface; writers may add fields (e.g. `id`, `importance`)
214
+ /// passed through opaquely as `unknown`, accessed via explicit narrowing.
215
+ const TraceEntrySchema = z
216
+ .object({
217
+ type: z.string(),
218
+ label: z.string(),
219
+ })
220
+ .catchall(z.unknown());
221
+
222
+ export type TraceEntry = z.infer<typeof TraceEntrySchema>;
223
+
224
+ export type Trace = TraceEntry[];
225
+
211
226
  // export const AxisSpec = z.object({
212
227
  // type: z.nativeEnum(ValueType),
213
228
  // name: z.string(),
@@ -256,7 +271,7 @@ export const AnnotationJson: AnnotationJson = {
256
271
  [Annotation.Sequence.Annotation.Mapping]: z.record(z.string(), z.string()),
257
272
  [Annotation.Sequence.IsAnnotation]: z.boolean(),
258
273
  [Annotation.Table.OrderPriority]: z.number(),
259
- [Annotation.Trace]: z.record(z.string(), z.unknown()),
274
+ [Annotation.Trace]: z.array(TraceEntrySchema),
260
275
  [Annotation.VDJ.IsAssemblingFeature]: z.boolean(),
261
276
  };
262
277
 
@@ -527,11 +542,9 @@ export function getNormalizedAxesList(axes: AxisSpec[]): AxisSpecNormalized[] {
527
542
 
528
543
  /** Create list of regular axisSpec from normalized (parents are indexes, inside of current axes list) */
529
544
  export function getDenormalizedAxesList(axesSpec: AxisSpecNormalized[]): AxisSpec[] {
530
- const idsList = axesSpec.map((axisSpec) => canonicalizeJson(getAxisId(axisSpec)));
545
+ const idsList = axesSpec.map(canonicalizeAxisId);
531
546
  return axesSpec.map((axisSpec) => {
532
- const parentsIds = axisSpec.parentAxesSpec.map((axisSpec) =>
533
- canonicalizeJson(getAxisId(axisSpec)),
534
- );
547
+ const parentsIds = axisSpec.parentAxesSpec.map(canonicalizeAxisId);
535
548
  const parentIdxs = parentsIds.map((id) => idsList.indexOf(id));
536
549
  const { parentAxesSpec: _, ...copiedRest } = axisSpec;
537
550
  if (parentIdxs.length) {
@@ -1,5 +1,6 @@
1
1
  import type { Branded } from "@milaboratories/helpers";
2
2
  import type { PoolEntry } from "../../pool_entry";
3
+ import type { PObjectId } from "../../pool";
3
4
  import type {
4
5
  AxisSpec,
5
6
  AxesSpec,
@@ -111,8 +112,48 @@ export interface DiscoverColumnsLinkerStep {
111
112
  qualifications: AxisQualification[];
112
113
  }
113
114
 
115
+ /**
116
+ * Filter step: intersects the current subquery with a filter column on shared
117
+ * axes. Filter columns carry `pl7.app/isSubset: "true"` with axes ⊆ dataset
118
+ * axes, so the inner-join narrows the key space to rows where the filter is
119
+ * present.
120
+ */
121
+ export interface DiscoverColumnsFilterStep {
122
+ type: "filter";
123
+ /** The filter column applied in this step */
124
+ filter: PColumnIdAndSpec;
125
+ }
126
+
114
127
  /** A step traversed during path-based column discovery. Discriminated by `type`. */
115
- export type DiscoverColumnsStepInfo = DiscoverColumnsLinkerStep;
128
+ export type DiscoverColumnsStepInfo = DiscoverColumnsLinkerStep | DiscoverColumnsFilterStep;
129
+
130
+ /**
131
+ * Input to {@link PFrameWasmV4.buildQuery}: a terminal column plus an ordered
132
+ * path of wrapping steps (linker hops, filter joins). Produces a
133
+ * {@link SpecQueryJoinEntry} ready to be plugged into an
134
+ * `innerJoin`/`fullJoin`/`outerJoin` entry list.
135
+ *
136
+ * Path ordering: `path[0]` is outermost (first applied), `path[N-1]` is
137
+ * closest to `column`. Omit or pass `[]` for a direct column with no
138
+ * wrapping.
139
+ *
140
+ * Columns are referenced by id — specs are resolved later at
141
+ * {@link PFrameWasmV4.evaluateQuery} against the registered specs of the
142
+ * PFrame, so the caller cannot disagree with the frame about spec content.
143
+ *
144
+ * Qualifications annotate the resulting outermost entry; they do not
145
+ * propagate into the inner query.
146
+ */
147
+ export type BuildQueryInput = {
148
+ /** Shape version marker — bumped only on breaking structural changes. */
149
+ readonly version: "v1";
150
+ /** Terminal column id — the column actually returning data. */
151
+ readonly column: PObjectId;
152
+ /** Ordered path from source integration to `column`. Outermost first. */
153
+ readonly path?: DiscoverColumnsStepInfo[];
154
+ /** Axis qualifications attached to the resulting join entry. */
155
+ readonly qualifications?: AxisQualification[];
156
+ };
116
157
 
117
158
  /** Qualifications info for a discover columns response mapping variant */
118
159
  export interface DiscoverColumnsResponseQualifications {
@@ -1,3 +1,4 @@
1
+ import { UnionToIntersection } from "@milaboratories/helpers";
1
2
  import type { Branded } from "../branding";
2
3
  import { ServiceAlreadyRegisteredError, ServiceInvalidIdError } from "../errors";
3
4
  import type { Services } from "./service_declarations";
@@ -101,12 +102,6 @@ export type ServiceRequireFlags = {
101
102
  [K in keyof SMap as `requires${K & string}`]?: boolean;
102
103
  };
103
104
 
104
- type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (
105
- k: infer I,
106
- ) => void
107
- ? I
108
- : never;
109
-
110
105
  export type RequireServices<T extends ServiceName> = UnionToIntersection<
111
106
  T extends Branded<infer N extends string, infer S extends ServiceTypesLike>
112
107
  ? Record<N, InferServiceModel<S>>