@undefineds.co/xpod 0.4.11 → 0.4.12

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 (372) hide show
  1. package/config/components-ignore.json +5 -1
  2. package/config/notifications.json +68 -0
  3. package/config/xpod.base.json +9 -11
  4. package/dist/ai/service/AiCredentialSecret.d.ts +30 -0
  5. package/dist/ai/service/AiCredentialSecret.js +120 -0
  6. package/dist/ai/service/CredentialReaderImpl.d.ts +18 -0
  7. package/dist/ai/service/CredentialReaderImpl.js +81 -5
  8. package/dist/ai/service/CredentialReaderImpl.jsonld +42 -2
  9. package/dist/ai/service/EmbeddingModelPolicy.d.ts +79 -0
  10. package/dist/ai/service/EmbeddingModelPolicy.js +134 -0
  11. package/dist/ai/service/EmbeddingProviderError.js +6 -0
  12. package/dist/ai/service/EmbeddingServiceImpl.d.ts +13 -1
  13. package/dist/ai/service/EmbeddingServiceImpl.js +18 -5
  14. package/dist/ai/service/EmbeddingServiceImpl.jsonld +35 -0
  15. package/dist/ai/service/index.d.ts +2 -0
  16. package/dist/ai/service/index.js +2 -0
  17. package/dist/api/ai-gateway/connect/index.d.ts +20 -2
  18. package/dist/api/ai-gateway/connect/index.js +162 -16
  19. package/dist/api/ai-gateway/credentials/AiCredentialSecretDecoder.d.ts +12 -0
  20. package/dist/api/ai-gateway/credentials/AiCredentialSecretDecoder.js +30 -0
  21. package/dist/api/ai-gateway/errors.d.ts +1 -1
  22. package/dist/api/ai-gateway/models/GatewayEmbeddingModelCatalog.d.ts +11 -0
  23. package/dist/api/ai-gateway/models/GatewayEmbeddingModelCatalog.js +31 -0
  24. package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +7 -3
  25. package/dist/api/ai-gateway/models/ProviderCustomModelsService.d.ts +18 -0
  26. package/dist/api/ai-gateway/models/ProviderCustomModelsService.js +23 -0
  27. package/dist/api/ai-gateway/models/ProviderModelDiscoveryAdapters.d.ts +3 -1
  28. package/dist/api/ai-gateway/models/ProviderModelDiscoveryAdapters.js +2 -45
  29. package/dist/api/ai-gateway/models/ProviderModelSelectionService.d.ts +10 -0
  30. package/dist/api/ai-gateway/models/ProviderModelSelectionService.js +57 -20
  31. package/dist/api/ai-gateway/models/ProviderModelType.d.ts +28 -0
  32. package/dist/api/ai-gateway/models/ProviderModelType.js +34 -0
  33. package/dist/api/ai-gateway/models/ProviderModelsAdapter.d.ts +10 -0
  34. package/dist/api/ai-gateway/models/ProviderModelsAdapter.js +3 -4
  35. package/dist/api/ai-gateway/models/index.d.ts +1 -0
  36. package/dist/api/ai-gateway/models/index.js +3 -1
  37. package/dist/api/ai-gateway/providers/CustomRuntimeAdapter.d.ts +7 -0
  38. package/dist/api/ai-gateway/providers/CustomRuntimeAdapter.js +9 -2
  39. package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -1
  40. package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +4 -10
  41. package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +107 -0
  42. package/dist/api/ai-gateway/providers/ProviderRegistry.js +244 -21
  43. package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.d.ts +5 -0
  44. package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +5 -1
  45. package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.d.ts +12 -4
  46. package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +11 -11
  47. package/dist/api/ai-gateway/routing/ModelRouter.d.ts +14 -0
  48. package/dist/api/ai-gateway/routing/ModelRouter.js +43 -4
  49. package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +9 -1
  50. package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +3 -27
  51. package/dist/api/chatkit/pod-store.d.ts +31 -0
  52. package/dist/api/chatkit/pod-store.js +132 -8
  53. package/dist/api/container/common.js +24 -4
  54. package/dist/api/container/routes.js +17 -2
  55. package/dist/api/container/types.d.ts +3 -1
  56. package/dist/api/handlers/AdminHandler.d.ts +13 -0
  57. package/dist/api/handlers/AdminHandler.js +47 -18
  58. package/dist/api/handlers/AiConfigHandler.d.ts +6 -0
  59. package/dist/api/handlers/AiConfigHandler.js +28 -0
  60. package/dist/api/handlers/AiGatewayManagementHandler.js +36 -0
  61. package/dist/api/runs/RdfRunContextRetriever.d.ts +14 -0
  62. package/dist/api/runs/RdfRunContextRetriever.js +41 -5
  63. package/dist/api/runtime.js +2 -1
  64. package/dist/cli/commands/secret.d.ts +1 -0
  65. package/dist/cli/commands/secret.js +25 -7
  66. package/dist/components/components.jsonld +3 -1
  67. package/dist/components/context.jsonld +53 -1
  68. package/dist/http/SubgraphSparqlHttpHandler.d.ts +59 -2
  69. package/dist/http/SubgraphSparqlHttpHandler.js +145 -13
  70. package/dist/http/SubgraphSparqlHttpHandler.jsonld +37 -0
  71. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +0 -12
  72. package/dist/identity/drizzle/EdgeNodeRepository.js +5 -13
  73. package/dist/index.d.ts +2 -1
  74. package/dist/index.js +7 -3
  75. package/dist/logging/log-file.d.ts +17 -0
  76. package/dist/logging/log-file.js +69 -0
  77. package/dist/main.js +2 -1
  78. package/dist/notifications/NotificationChannelSweeper.d.ts +50 -0
  79. package/dist/notifications/NotificationChannelSweeper.js +131 -0
  80. package/dist/notifications/NotificationChannelSweeper.jsonld +136 -0
  81. package/dist/notifications/ReclaimingWebSocket2023Storer.d.ts +25 -0
  82. package/dist/notifications/ReclaimingWebSocket2023Storer.js +56 -0
  83. package/dist/notifications/ReclaimingWebSocket2023Storer.jsonld +77 -0
  84. package/dist/notifications/index.d.ts +2 -0
  85. package/dist/notifications/index.js +2 -0
  86. package/dist/runtime/Proxy.d.ts +37 -0
  87. package/dist/runtime/Proxy.js +88 -16
  88. package/dist/runtime/bootstrap.js +2 -1
  89. package/dist/runtime/upgrade/BunNativeUpgradeRelay.d.ts +116 -0
  90. package/dist/runtime/upgrade/BunNativeUpgradeRelay.js +423 -0
  91. package/dist/runtime/upgrade/UpgradeHandshake.d.ts +63 -0
  92. package/dist/runtime/upgrade/UpgradeHandshake.js +199 -0
  93. package/dist/runtime/upgrade/WebSocketFrames.d.ts +67 -0
  94. package/dist/runtime/upgrade/WebSocketFrames.js +224 -0
  95. package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +8 -1
  96. package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.d.ts +11 -2
  97. package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.js +27 -10
  98. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +7 -0
  99. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -11
  100. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.js +1 -1
  101. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +10 -6
  102. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +15 -0
  103. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +29 -3
  104. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMainHeader.js +18 -3
  105. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +16 -1
  106. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +92 -20
  107. package/node_modules/@undefineds.co/ai-connections/dist/AiCopyButton.d.ts +35 -0
  108. package/node_modules/@undefineds.co/ai-connections/dist/AiCopyButton.js +45 -0
  109. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +71 -11
  110. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialRow.js +9 -7
  111. package/node_modules/@undefineds.co/ai-connections/dist/AiEndpointList.d.ts +23 -0
  112. package/node_modules/@undefineds.co/ai-connections/dist/AiEndpointList.js +24 -0
  113. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +13 -4
  114. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +35 -38
  115. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.d.ts +21 -0
  116. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.js +51 -0
  117. package/node_modules/@undefineds.co/ai-connections/dist/AiInfoTooltip.d.ts +15 -0
  118. package/node_modules/@undefineds.co/ai-connections/dist/AiInfoTooltip.js +16 -0
  119. package/node_modules/@undefineds.co/ai-connections/dist/AiModelCatalog.d.ts +175 -0
  120. package/node_modules/@undefineds.co/ai-connections/dist/AiModelCatalog.js +133 -0
  121. package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.js +2 -2
  122. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +13 -64
  123. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.d.ts +21 -0
  124. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.js +12 -0
  125. package/node_modules/@undefineds.co/ai-connections/dist/AiRowAction.d.ts +15 -0
  126. package/node_modules/@undefineds.co/ai-connections/dist/AiRowAction.js +12 -0
  127. package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.js +2 -1
  128. package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +7 -0
  129. package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +6 -0
  130. package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.d.ts +36 -5
  131. package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.js +52 -9
  132. package/node_modules/@undefineds.co/ai-connections/dist/client/normalize.js +30 -3
  133. package/node_modules/@undefineds.co/ai-connections/dist/client/types.d.ts +21 -1
  134. package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +1 -3
  135. package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +3 -7
  136. package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +9 -7
  137. package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.d.ts +46 -0
  138. package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +231 -0
  139. package/node_modules/@undefineds.co/ai-connections/dist/collections.d.ts +119 -0
  140. package/node_modules/@undefineds.co/ai-connections/dist/collections.js +173 -0
  141. package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +71 -5
  142. package/node_modules/@undefineds.co/ai-connections/dist/controller.js +285 -16
  143. package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.d.ts +5 -0
  144. package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.js +8 -3
  145. package/node_modules/@undefineds.co/ai-connections/dist/credential-storage.d.ts +59 -0
  146. package/node_modules/@undefineds.co/ai-connections/dist/credential-storage.js +131 -0
  147. package/node_modules/@undefineds.co/ai-connections/dist/endpoint-urls.d.ts +15 -0
  148. package/node_modules/@undefineds.co/ai-connections/dist/endpoint-urls.js +20 -0
  149. package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.d.ts +14 -0
  150. package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +20 -0
  151. package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +8 -0
  152. package/node_modules/@undefineds.co/ai-connections/dist/index.js +8 -0
  153. package/node_modules/@undefineds.co/ai-connections/dist/manifest.js +1 -1
  154. package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.d.ts +14 -0
  155. package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.js +17 -0
  156. package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.cjs +68 -1
  157. package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.d.ts +75 -1
  158. package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.js +119 -0
  159. package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.d.ts +5 -0
  160. package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +5 -0
  161. package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +2 -27
  162. package/node_modules/@undefineds.co/ai-connections/package.json +1 -0
  163. package/node_modules/@undefineds.co/extension-sdk/dist/manifest.d.ts +1 -1
  164. package/node_modules/@undefineds.co/extension-sdk/dist/manifest.js +2 -0
  165. package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +150 -0
  166. package/node_modules/@undefineds.co/extension-sdk/package.json +2 -1
  167. package/node_modules/@undefineds.co/models/README.md +1 -1
  168. package/node_modules/@undefineds.co/models/dist/ai-config/index.d.ts +3 -3
  169. package/node_modules/@undefineds.co/models/dist/ai-gateway.schema.d.ts +5 -0
  170. package/node_modules/@undefineds.co/models/dist/ai-gateway.schema.js +9 -0
  171. package/node_modules/@undefineds.co/models/dist/ai-runtime.repository.d.ts +1 -1
  172. package/node_modules/@undefineds.co/models/dist/approval.repository.d.ts +2 -2
  173. package/node_modules/@undefineds.co/models/dist/audit.presentation.d.ts +2 -2
  174. package/node_modules/@undefineds.co/models/dist/capture.repository.d.ts +1 -1
  175. package/node_modules/@undefineds.co/models/dist/chat-project.repository.d.ts +1 -1
  176. package/node_modules/@undefineds.co/models/dist/chat.repository.d.ts +2 -2
  177. package/node_modules/@undefineds.co/models/dist/control-request.repository.d.ts +2 -2
  178. package/node_modules/@undefineds.co/models/dist/conversation-share.repository.d.ts +1 -1
  179. package/node_modules/@undefineds.co/models/dist/credential.schema.d.ts +12 -0
  180. package/node_modules/@undefineds.co/models/dist/credential.schema.js +15 -1
  181. package/node_modules/@undefineds.co/models/dist/discovery/index.d.ts +2 -2
  182. package/node_modules/@undefineds.co/models/dist/discovery/providers.json +248 -7
  183. package/node_modules/@undefineds.co/models/dist/discovery/types.d.ts +31 -0
  184. package/node_modules/@undefineds.co/models/dist/extension/index.d.ts +1 -1
  185. package/node_modules/@undefineds.co/models/dist/favorite/index.d.ts +2 -2
  186. package/node_modules/@undefineds.co/models/dist/fixtures/contracts-chat-contact.d.ts +5 -5
  187. package/node_modules/@undefineds.co/models/dist/import/index.d.ts +1 -1
  188. package/node_modules/@undefineds.co/models/dist/index.d.ts +73 -73
  189. package/node_modules/@undefineds.co/models/dist/index.js +1 -1
  190. package/node_modules/@undefineds.co/models/dist/input-request.repository.d.ts +2 -2
  191. package/node_modules/@undefineds.co/models/dist/knowledge/index.d.ts +1 -1
  192. package/node_modules/@undefineds.co/models/dist/message.repository.d.ts +1 -1
  193. package/node_modules/@undefineds.co/models/dist/namespaces.js +5 -0
  194. package/node_modules/@undefineds.co/models/dist/pod-storage-descriptor.d.ts +4815 -26
  195. package/node_modules/@undefineds.co/models/dist/pod-storage-descriptor.js +482 -132
  196. package/node_modules/@undefineds.co/models/dist/schema.d.ts +4 -0
  197. package/node_modules/@undefineds.co/models/dist/session/index.d.ts +1 -1
  198. package/node_modules/@undefineds.co/models/dist/settings/index.d.ts +1 -1
  199. package/node_modules/@undefineds.co/models/dist/sidecar/persistence-mapping.d.ts +5 -5
  200. package/node_modules/@undefineds.co/models/dist/thread.repository.d.ts +2 -2
  201. package/node_modules/@undefineds.co/models/dist/types/message-block.d.ts +1 -1
  202. package/node_modules/@undefineds.co/models/dist/vocab/_namespaces.d.ts +1 -1
  203. package/node_modules/@undefineds.co/models/dist/vocab/index.d.ts +10 -10
  204. package/node_modules/@undefineds.co/models/dist/vocab/sidecar.vocab.d.ts +1 -0
  205. package/node_modules/@undefineds.co/models/dist/vocab/sidecar.vocab.js +1 -0
  206. package/node_modules/@undefineds.co/models/package.json +4 -2
  207. package/node_modules/@undefineds.co/pod-collections/README.md +71 -0
  208. package/node_modules/@undefineds.co/pod-collections/dist/diff.d.ts +85 -0
  209. package/node_modules/@undefineds.co/pod-collections/dist/diff.js +166 -0
  210. package/node_modules/@undefineds.co/pod-collections/dist/feed.d.ts +17 -0
  211. package/node_modules/@undefineds.co/pod-collections/dist/feed.js +27 -0
  212. package/node_modules/@undefineds.co/pod-collections/dist/index.cjs +1042 -0
  213. package/node_modules/@undefineds.co/pod-collections/dist/index.d.ts +37 -0
  214. package/node_modules/@undefineds.co/pod-collections/dist/index.js +89 -0
  215. package/node_modules/@undefineds.co/pod-collections/dist/layout.d.ts +75 -0
  216. package/node_modules/@undefineds.co/pod-collections/dist/layout.js +173 -0
  217. package/node_modules/@undefineds.co/pod-collections/dist/mapping.d.ts +78 -0
  218. package/node_modules/@undefineds.co/pod-collections/dist/mapping.js +287 -0
  219. package/node_modules/@undefineds.co/pod-collections/dist/mutations.d.ts +83 -0
  220. package/node_modules/@undefineds.co/pod-collections/dist/mutations.js +273 -0
  221. package/node_modules/@undefineds.co/pod-collections/dist/react.d.ts +21 -0
  222. package/node_modules/@undefineds.co/pod-collections/dist/react.js +22 -0
  223. package/node_modules/@undefineds.co/pod-collections/dist/read.d.ts +65 -0
  224. package/node_modules/@undefineds.co/pod-collections/dist/read.js +31 -0
  225. package/node_modules/@undefineds.co/pod-collections/dist/sync.d.ts +66 -0
  226. package/node_modules/@undefineds.co/pod-collections/dist/sync.js +260 -0
  227. package/node_modules/@undefineds.co/pod-collections/dist/types.d.ts +155 -0
  228. package/node_modules/@undefineds.co/pod-collections/dist/types.js +9 -0
  229. package/node_modules/@undefineds.co/pod-collections/package.json +42 -0
  230. package/package.json +15 -7
  231. package/static/app/assets/main.css +1 -1
  232. package/static/auth-callback/assets/AiConfigContext-DnQs1ZpW.js +1 -0
  233. package/static/auth-callback/assets/AiConfigPage-DOtvlxH0.js +1 -0
  234. package/static/auth-callback/assets/DocumentProcessingPanel-BS2voQgL.js +1 -0
  235. package/static/auth-callback/assets/IndexLifecyclePanel-Cvt0cJtN.js +1 -0
  236. package/static/auth-callback/assets/{IndexSubjectPanel-BbUqop4b.js → IndexSubjectPanel-Dhf01GqF.js} +1 -1
  237. package/static/auth-callback/assets/ModelAssignmentsPanel-BJutWaAF.js +1 -0
  238. package/static/auth-callback/assets/ModelsPage-BRS0sje3.js +11 -0
  239. package/static/auth-callback/assets/{NetworkPage-Vp2PrMxs.js → NetworkPage-B3qBfANA.js} +2 -2
  240. package/static/auth-callback/assets/{PaneListHeader-DY7baSFl.js → PaneListHeader-QQeJGTp4.js} +1 -1
  241. package/static/auth-callback/assets/SearchIndexingPanel-MyNUSEwT.js +1 -0
  242. package/static/auth-callback/assets/{StatusSubjectPanel-ArIS-TxT.js → StatusSubjectPanel-DQkEVsFs.js} +1 -1
  243. package/static/{settings/assets/StatusWorkspace-CoMFRXoV.js → auth-callback/assets/StatusWorkspace-Dkv63Uwk.js} +1 -1
  244. package/static/auth-callback/assets/{SystemSettingsPage-BDvT1NUz.js → SystemSettingsPage-TIsUfX5d.js} +1 -1
  245. package/static/{dashboard/assets/SystemSettingsSubjectPanel-WaE8mTQi.js → auth-callback/assets/SystemSettingsSubjectPanel-BJWEt2-7.js} +5 -5
  246. package/static/auth-callback/assets/XpodAiConnectionsPodStore-BJiXm-PF.js +3 -0
  247. package/static/auth-callback/assets/{activity-D1Dsfa_0.js → activity-5hNeNKnL.js} +1 -1
  248. package/static/auth-callback/assets/ai-connections-CryuHGKW.js +1 -0
  249. package/static/auth-callback/assets/{auth-callback-Cmf4hXVZ.js → auth-callback-CAFZ3R0B.js} +6 -6
  250. package/static/auth-callback/assets/auth-callback-rk080mvG.css +1 -0
  251. package/static/auth-callback/assets/{badge-CZsHq3Ih.js → badge-CAIPI0CB.js} +1 -1
  252. package/static/auth-callback/assets/collection-runtime-D9s7h9YA.js +1 -0
  253. package/static/auth-callback/assets/dialog-BjA109aX.js +1 -0
  254. package/static/auth-callback/assets/{download-DU9ntlHw.js → download-B3Up5W2G.js} +1 -1
  255. package/static/auth-callback/assets/{external-link-BfzaaZDx.js → external-link-BTXgSPzB.js} +1 -1
  256. package/static/auth-callback/assets/index-BppXlxcp.js +41 -0
  257. package/static/auth-callback/assets/index-CirW4CJf.js +1 -0
  258. package/static/auth-callback/assets/index-DlLYWOhw.js +4 -0
  259. package/static/auth-callback/assets/{index-browser-BNFqqC74.js → index-browser-DtU38ni3.js} +1 -1
  260. package/static/auth-callback/assets/{key-round-BwP3DBWo.js → key-round-CQCOrZ7x.js} +1 -1
  261. package/static/auth-callback/assets/layout-DB3pMyTl.js +1 -0
  262. package/static/auth-callback/assets/pod-collections-host-KnnGFZHL.js +8 -0
  263. package/static/auth-callback/assets/{rotate-ccw-VMwnmyab.js → rotate-ccw-C1zM2KtS.js} +1 -1
  264. package/static/auth-callback/assets/{skeleton-CoD55rBT.js → skeleton-Cqp7_M9-.js} +1 -1
  265. package/static/auth-callback/assets/{waypoints-DRo_1Ca7.js → waypoints-Bj6gAUSQ.js} +1 -1
  266. package/static/auth-callback/assets/{workspace-layout--mcXl3My.js → workspace-layout-DK8mDzrY.js} +1 -1
  267. package/static/auth-callback/auth-callback.html +2 -2
  268. package/static/dashboard/assets/AiConfigContext-BsE7MqX8.js +1 -0
  269. package/static/dashboard/assets/AiConfigPage-DvM-lRXa.js +1 -0
  270. package/static/dashboard/assets/DocumentProcessingPanel-BPfdlfuf.js +1 -0
  271. package/static/dashboard/assets/IndexLifecyclePanel--m0AGxvh.js +1 -0
  272. package/static/dashboard/assets/{IndexSubjectPanel-B2cXwl8X.js → IndexSubjectPanel-Bb7m1k3d.js} +1 -1
  273. package/static/dashboard/assets/ModelAssignmentsPanel-BLi_zbMa.js +1 -0
  274. package/static/dashboard/assets/ModelsPage-CxdpgnfR.js +11 -0
  275. package/static/dashboard/assets/{NetworkPage-DV2V0qWO.js → NetworkPage-BAIPw-D_.js} +2 -2
  276. package/static/dashboard/assets/{PaneListHeader-D0c1yCFH.js → PaneListHeader-BBCMei0r.js} +1 -1
  277. package/static/dashboard/assets/SearchIndexingPanel-Ck4Y-xjR.js +1 -0
  278. package/static/dashboard/assets/{StatusSubjectPanel-oPSECj7i.js → StatusSubjectPanel-D1KWfAXE.js} +1 -1
  279. package/static/dashboard/assets/{StatusWorkspace-PdovQPKa.js → StatusWorkspace-JbA5gzXx.js} +1 -1
  280. package/static/dashboard/assets/{SystemSettingsPage-CtNDklkx.js → SystemSettingsPage-BbwQWsSR.js} +1 -1
  281. package/static/{settings/assets/SystemSettingsSubjectPanel-DExjDo_v.js → dashboard/assets/SystemSettingsSubjectPanel-N117nMt5.js} +5 -5
  282. package/static/dashboard/assets/XpodAiConnectionsPodStore-CdDOb4SV.js +18 -0
  283. package/static/dashboard/assets/{activity-B9ylSoyr.js → activity-DX1I96o_.js} +1 -1
  284. package/static/dashboard/assets/ai-connections-DwCRqOQa.js +1 -0
  285. package/static/dashboard/assets/{badge-BNbFbpIb.js → badge-k2vhtDqH.js} +1 -1
  286. package/static/dashboard/assets/collection-runtime-BFQ8teQJ.js +1 -0
  287. package/static/dashboard/assets/{dashboard-CD-FFVRD.js → dashboard-DWZ-fmCT.js} +4 -4
  288. package/static/dashboard/assets/dashboard-rk080mvG.css +1 -0
  289. package/static/dashboard/assets/dialog-1CCw-iHT.js +1 -0
  290. package/static/dashboard/assets/{download-nOP38LtW.js → download-C6-SNY1q.js} +1 -1
  291. package/static/dashboard/assets/{external-link-Bh2ewN9E.js → external-link-BgPcZ_j2.js} +1 -1
  292. package/static/dashboard/assets/index-6LcIUIYO.js +1 -0
  293. package/static/dashboard/assets/index-D7A8U6Pt.js +41 -0
  294. package/static/dashboard/assets/index-UD6QOE7H.js +4 -0
  295. package/static/dashboard/assets/{key-round-bGmguBLv.js → key-round-BOd7Jo0Q.js} +1 -1
  296. package/static/dashboard/assets/layout-DB3pMyTl.js +1 -0
  297. package/static/dashboard/assets/pod-collections-host-KnnGFZHL.js +8 -0
  298. package/static/dashboard/assets/{rotate-ccw-D2x__ODW.js → rotate-ccw-CCgJqsvx.js} +1 -1
  299. package/static/dashboard/assets/{skeleton-VOqft8WS.js → skeleton-Bc7abAn5.js} +1 -1
  300. package/static/dashboard/assets/{waypoints-fgRqm4oH.js → waypoints-s-opmJxx.js} +1 -1
  301. package/static/dashboard/assets/{workspace-layout-DV4dgeHX.js → workspace-layout-DqIQeTBV.js} +1 -1
  302. package/static/dashboard/dashboard.html +2 -2
  303. package/static/settings/assets/AiConfigContext-BB9KZySa.js +1 -0
  304. package/static/settings/assets/AiConfigPage-DGSXUkLs.js +1 -0
  305. package/static/settings/assets/DocumentProcessingPanel-Da2Re6Rg.js +1 -0
  306. package/static/settings/assets/IndexLifecyclePanel-BSZuIzgr.js +1 -0
  307. package/static/settings/assets/{IndexSubjectPanel-BgbI9c-a.js → IndexSubjectPanel-CFd0ay-r.js} +1 -1
  308. package/static/settings/assets/ModelAssignmentsPanel-CSAryvWJ.js +1 -0
  309. package/static/settings/assets/ModelsPage-BQwCwLHU.js +11 -0
  310. package/static/settings/assets/{NetworkPage-C8OA9Mtp.js → NetworkPage-BKymvsQc.js} +2 -2
  311. package/static/settings/assets/{PaneListHeader-COvlPJWj.js → PaneListHeader-Bjh3hRdQ.js} +1 -1
  312. package/static/settings/assets/SearchIndexingPanel-MjKL5QLU.js +1 -0
  313. package/static/settings/assets/{StatusSubjectPanel-BuLml7qn.js → StatusSubjectPanel-Bvl6K4mx.js} +1 -1
  314. package/static/settings/assets/StatusWorkspace-B0NzrP--.js +1 -0
  315. package/static/settings/assets/{SystemSettingsPage-DlzmaWV-.js → SystemSettingsPage-D2z6Z4FE.js} +1 -1
  316. package/static/{auth-callback/assets/SystemSettingsSubjectPanel-CDqRuC4t.js → settings/assets/SystemSettingsSubjectPanel-4sxma4X4.js} +5 -5
  317. package/static/settings/assets/XpodAiConnectionsPodStore-BkNQ8fZx.js +3 -0
  318. package/static/settings/assets/{activity-TLerXgMs.js → activity-CgJJGpjx.js} +1 -1
  319. package/static/settings/assets/ai-connections-CryuHGKW.js +1 -0
  320. package/static/settings/assets/{badge-Bcs8iWrH.js → badge-C4NypVyT.js} +1 -1
  321. package/static/settings/assets/collection-runtime-CTLCDxAi.js +1 -0
  322. package/static/settings/assets/dialog-Csq0vWUi.js +1 -0
  323. package/static/settings/assets/{download-Ct3QmHPt.js → download-DaLJJ-Wp.js} +1 -1
  324. package/static/settings/assets/{external-link-C8KiHbss.js → external-link--w_iW5Au.js} +1 -1
  325. package/static/settings/assets/index-B0mQa59b.js +4 -0
  326. package/static/settings/assets/index-BukHiu4y.js +1 -0
  327. package/static/settings/assets/index-COmVnZi2.js +41 -0
  328. package/static/settings/assets/{index-browser-CazX1pc2.js → index-browser-BGpvHwD0.js} +1 -1
  329. package/static/settings/assets/{key-round-B19YD1GA.js → key-round-Bk4YRjBu.js} +1 -1
  330. package/static/settings/assets/layout-DB3pMyTl.js +1 -0
  331. package/static/settings/assets/pod-collections-host-KnnGFZHL.js +8 -0
  332. package/static/settings/assets/{rotate-ccw-AQm2kMgU.js → rotate-ccw-TCabbqsr.js} +1 -1
  333. package/static/settings/assets/{settings-C-VBtt9r.js → settings-CJWpdbNC.js} +5 -5
  334. package/static/settings/assets/settings-rk080mvG.css +1 -0
  335. package/static/settings/assets/{skeleton-DyZ1OBYf.js → skeleton-JDHYVe7t.js} +1 -1
  336. package/static/settings/assets/{waypoints-CC3wq-SU.js → waypoints-DDvEl-MU.js} +1 -1
  337. package/static/settings/assets/{workspace-layout-BxXNKgf9.js → workspace-layout-DV5QU30U.js} +1 -1
  338. package/static/settings/settings.html +2 -2
  339. package/static/auth-callback/assets/AiConfigContext-DqWRSm7n.js +0 -1
  340. package/static/auth-callback/assets/AiConfigPage-C5YYyvzl.js +0 -1
  341. package/static/auth-callback/assets/DocumentProcessingPanel-DZCiacBz.js +0 -1
  342. package/static/auth-callback/assets/IndexLifecyclePanel-CCLeOljB.js +0 -1
  343. package/static/auth-callback/assets/ModelAssignmentsPanel-jUUTDKuh.js +0 -1
  344. package/static/auth-callback/assets/ModelsPage-B08zdtff.js +0 -10
  345. package/static/auth-callback/assets/SearchIndexingPanel-D4YRg1-8.js +0 -1
  346. package/static/auth-callback/assets/StatusWorkspace-Cp5LQ9Yx.js +0 -1
  347. package/static/auth-callback/assets/ai-connections-CHNTKemd.js +0 -1
  348. package/static/auth-callback/assets/auth-callback-DWMMiFjh.css +0 -1
  349. package/static/auth-callback/assets/index-DSNnLUbU.js +0 -4
  350. package/static/auth-callback/assets/index-FHhHoKgp.js +0 -41
  351. package/static/dashboard/assets/AiConfigContext-BpPDKSzI.js +0 -1
  352. package/static/dashboard/assets/AiConfigPage-wsqEZDIX.js +0 -1
  353. package/static/dashboard/assets/DocumentProcessingPanel-CDSy3juc.js +0 -1
  354. package/static/dashboard/assets/IndexLifecyclePanel-CVd6vQCX.js +0 -1
  355. package/static/dashboard/assets/ModelAssignmentsPanel-BeBZhnQd.js +0 -1
  356. package/static/dashboard/assets/ModelsPage-B6McSCJw.js +0 -25
  357. package/static/dashboard/assets/SearchIndexingPanel-CGs0OZ12.js +0 -1
  358. package/static/dashboard/assets/ai-connections-CHNTKemd.js +0 -1
  359. package/static/dashboard/assets/dashboard-DWMMiFjh.css +0 -1
  360. package/static/dashboard/assets/index-PgS-Bt7X.js +0 -41
  361. package/static/dashboard/assets/index-QN2QgEwr.js +0 -4
  362. package/static/settings/assets/AiConfigContext-zKQYdfai.js +0 -1
  363. package/static/settings/assets/AiConfigPage-Bs1EE3Ei.js +0 -1
  364. package/static/settings/assets/DocumentProcessingPanel-CSFfdOXS.js +0 -1
  365. package/static/settings/assets/IndexLifecyclePanel-BR9Su49B.js +0 -1
  366. package/static/settings/assets/ModelAssignmentsPanel-C0BE7nbk.js +0 -1
  367. package/static/settings/assets/ModelsPage-CU-YQ8_7.js +0 -10
  368. package/static/settings/assets/SearchIndexingPanel-Bdd46mIV.js +0 -1
  369. package/static/settings/assets/ai-connections-CHNTKemd.js +0 -1
  370. package/static/settings/assets/index-1Q2cRjZd.js +0 -41
  371. package/static/settings/assets/index-DBO_Vq0P.js +0 -4
  372. package/static/settings/assets/settings-DWMMiFjh.css +0 -1
@@ -0,0 +1,287 @@
1
+ import { PodCollectionError } from './types.js';
2
+ import { rowKeyOf, rowKeyVariable } from './layout.js';
3
+ /**
4
+ * RDF ↔ 行映射(`docs/pod-collections.md` §2.4)。
5
+ *
6
+ * 映射的唯一来源是 **descriptor 的字段声明**:`fields[*].predicate` 决定哪个表列
7
+ * 承载该字段(列名由 drizzle 表的 mapping 给出,不由字段名猜)。两个 0.2.57 实测的
8
+ * 证据:`createdAt` 经 `dcterms:created` 落到 `createdAt` 列(谓词不在 `ns#` 下),
9
+ * 而行标识字段 `id` 的谓词是 `ns#id`、**不**落到表里那个同名的 `id` 列上(那是 `@id`
10
+ * 虚列)—— 所以按名绑定会在第二个例子上直接错。字段类型只由 `fields[*].type` 决定,
11
+ * **不从 term 类型反推**(§2.4 边界 1:以 `http(s)://` 开头的 `string` 会被写成
12
+ * named node)。
13
+ *
14
+ * 字面量 datatype 按 drizzle-solid 的 SPARQL helper 规则
15
+ * (`node_modules/@undefineds.co/drizzle-solid/dist/esm/core/sparql/helpers.js`
16
+ * 的 `buildLiteralTerm`):整数 `xsd:integer`、非整数 `xsd:decimal`、`xsd:boolean`、
17
+ * `xsd:dateTime`。注意同一文件的 `formatValue()`(写路径)对整数发的是**无 datatype**
18
+ * 的字面量,两者并不一致;本层按 §2.4 表格取 `buildLiteralTerm` 的规则,写路径仍完全
19
+ * 交给 drizzle-solid 自己格式化。
20
+ */
21
+ const XSD = 'http://www.w3.org/2001/XMLSchema#';
22
+ /** 表列 → 谓词(跳过 `@id` 虚列)。 */
23
+ export function tableColumnPredicates(table) {
24
+ const mapping = table.getMapping();
25
+ const predicates = new Map();
26
+ for (const [column, entry] of Object.entries(mapping.columns)) {
27
+ if (entry.predicate === '@id')
28
+ continue;
29
+ predicates.set(column, entry.predicate);
30
+ }
31
+ return predicates;
32
+ }
33
+ /** descriptor 字段 → 承载它的表列(按谓词,不按字段名)。 */
34
+ export function fieldBindings(descriptor, table) {
35
+ const byPredicate = new Map();
36
+ for (const [column, predicate] of tableColumnPredicates(table)) {
37
+ byPredicate.set(predicate, column);
38
+ }
39
+ const bindings = new Map();
40
+ for (const [field, fieldDescriptor] of Object.entries(descriptor.fields)) {
41
+ bindings.set(field, { field, descriptor: fieldDescriptor, column: byPredicate.get(fieldDescriptor.predicate) });
42
+ }
43
+ return bindings;
44
+ }
45
+ /**
46
+ * 行标识字段:`resourceIdPattern` 的 `{…}` 键 slot 名(`#{id}` → `id`)。
47
+ * 它由 drizzle-solid 的虚列 `id` / `@id` 承载,不落在任何谓词列上。
48
+ */
49
+ export function identityFieldOf(descriptor) {
50
+ return rowKeyVariable(descriptor.storage.resourceIdPattern);
51
+ }
52
+ /**
53
+ * descriptor 声明了、但表里找不到对应谓词的字段(§2.7 的漂移面)。
54
+ * 行标识字段不算:它由行本身承载(`mapSubjectRows` 用行键填它)。
55
+ */
56
+ export function descriptorFieldsWithoutColumn(descriptor, table) {
57
+ const identity = identityFieldOf(descriptor);
58
+ return [...fieldBindings(descriptor, table).values()]
59
+ .filter((binding) => binding.column === undefined && binding.field !== identity)
60
+ .map((binding) => binding.field)
61
+ .sort();
62
+ }
63
+ /** 表里有、但 descriptor 没声明的列(§2.7 的漂移面)。 */
64
+ export function tableColumnsWithoutDescriptorField(descriptor, table) {
65
+ const declaredPredicates = new Set(Object.values(descriptor.fields).map((field) => field.predicate));
66
+ return [...tableColumnPredicates(table)]
67
+ .filter(([, predicate]) => !declaredPredicates.has(predicate))
68
+ .map(([column]) => column)
69
+ .sort();
70
+ }
71
+ /**
72
+ * 类过滤的显式化(§2.4 边界 2):行准入以 descriptor 的 `class` 为准,而 drizzle 的
73
+ * 读把它编译成 `?subject rdf:type <class>`(表 options 的 `type`)。两者必须同源,
74
+ * 否则读回来的行与 descriptor 不是一套 schema —— 抛错而不是静默接受。
75
+ */
76
+ export function assertDescriptorTableAlignment(descriptor, table) {
77
+ const tableClass = table.getType();
78
+ if (descriptor.class !== tableClass) {
79
+ throw new PodCollectionError('mapping_class_mismatch', `descriptor ${descriptor.uri} declares class ${descriptor.class} but table ${table.config.name} reads ${tableClass}`);
80
+ }
81
+ }
82
+ /**
83
+ * 只写字段(`secret: true`):**写入可以带、读取永远读不回**。
84
+ *
85
+ * §2.1 把投影定义为「descriptor 的非 secret 字段」,所以这些字段既不在
86
+ * `mapSubjectRows()` 的行里,也不可能出现在服务端投影里。这个集合是那条规则的
87
+ * 唯一来源:读写两侧(`mapSubjectRows()` 与 §4.2 的确认协议)都从它取,避免
88
+ * 「哪边算 secret」出现第二份判断。
89
+ *
90
+ * 特别注意它与「descriptor 声明了但表里没有列」的字段(§2.7 的漂移面)不是一回事:
91
+ * 后者是**可读**字段,只是当前不可投影,语义上仍要求出现在服务端行里。
92
+ */
93
+ export function writeOnlyFields(descriptor) {
94
+ return new Set(Object.entries(descriptor.fields)
95
+ .filter(([, field]) => field.secret === true)
96
+ .map(([name]) => name));
97
+ }
98
+ /**
99
+ * 投影后的字段顺序:按谓词排序(§3.2 的投影哈希要求确定性,与字段声明顺序无关)。
100
+ */
101
+ export function projectionFieldOrder(descriptor) {
102
+ // The projection is the *readable* row: `secret: true` fields never come back
103
+ // from a read (see `writeOnlyFields`), so counting them would make the row the
104
+ // store completed differ from the row we wrote and turn our own echo into a
105
+ // spurious update.
106
+ const writeOnly = writeOnlyFields(descriptor);
107
+ return Object.entries(descriptor.fields)
108
+ .filter(([field]) => !writeOnly.has(field))
109
+ .sort(([, left], [, right]) => (left.predicate < right.predicate ? -1 : left.predicate > right.predicate ? 1 : 0))
110
+ .map(([field]) => field);
111
+ }
112
+ function isRdfTerm(value) {
113
+ return typeof value === 'object' && value !== null
114
+ && typeof value.termType === 'string'
115
+ && typeof value.value === 'string';
116
+ }
117
+ function termDatatypeOf(value) {
118
+ const datatype = value.datatype;
119
+ if (!datatype)
120
+ return undefined;
121
+ return typeof datatype === 'string' ? datatype : datatype.value;
122
+ }
123
+ function coerceScalar(field, input) {
124
+ if (input === null || input === undefined || input === '')
125
+ return undefined;
126
+ const term = isRdfTerm(input) ? input : undefined;
127
+ const raw = term ? term.value : input;
128
+ const datatype = term ? termDatatypeOf(term) : undefined;
129
+ switch (field.type) {
130
+ case 'uri':
131
+ return term && term.termType !== 'NamedNode' ? String(raw) : String(raw);
132
+ case 'string':
133
+ case 'text':
134
+ return typeof raw === 'boolean' || typeof raw === 'number' ? String(raw) : String(raw);
135
+ case 'number': {
136
+ if (typeof raw === 'number')
137
+ return raw;
138
+ const parsed = Number(raw);
139
+ return Number.isFinite(parsed) ? parsed : undefined;
140
+ }
141
+ case 'boolean':
142
+ if (typeof raw === 'boolean')
143
+ return raw;
144
+ if (raw === 'true')
145
+ return true;
146
+ if (raw === 'false')
147
+ return false;
148
+ return Boolean(raw);
149
+ case 'timestamp': {
150
+ const date = raw instanceof Date ? raw : new Date(String(raw));
151
+ return Number.isNaN(date.getTime()) ? undefined : date;
152
+ }
153
+ case 'json': {
154
+ // JSON 的序列化细节属于 drizzle-solid(§2.4):非 term 输入(ORM 已解码的值)
155
+ // 原样透传;term 输入(本层 valueToTerm 的产物)解析回值,解析不了就当字符串。
156
+ if (!term)
157
+ return input;
158
+ if (datatype && !/#json(Array)?$/u.test(datatype) && raw === '')
159
+ return undefined;
160
+ try {
161
+ return JSON.parse(String(raw));
162
+ }
163
+ catch {
164
+ return raw;
165
+ }
166
+ }
167
+ default:
168
+ return raw;
169
+ }
170
+ }
171
+ /** 值 → 行字段值;同时接受 drizzle-solid 已解码的值与 RDF term(§2.4)。 */
172
+ export function coerceFieldValue(field, input) {
173
+ if (field.array) {
174
+ if (input === undefined || input === null)
175
+ return undefined;
176
+ const list = Array.isArray(input) ? input : [input];
177
+ const values = list
178
+ .map((item) => coerceScalar(field, item))
179
+ .filter((item) => item !== undefined);
180
+ return values.length > 0 ? values : undefined;
181
+ }
182
+ return coerceScalar(field, input);
183
+ }
184
+ /** 值 → RDF term(§2.4;datatype 规则见文件头)。 */
185
+ export function valueToTerm(field, value) {
186
+ if (value === undefined || value === null)
187
+ return undefined;
188
+ if (field.type === 'uri')
189
+ return { termType: 'NamedNode', value: String(value) };
190
+ if (field.type === 'number') {
191
+ const numeric = typeof value === 'number' ? value : Number(value);
192
+ if (!Number.isFinite(numeric))
193
+ return undefined;
194
+ return {
195
+ termType: 'Literal',
196
+ value: String(numeric),
197
+ datatype: Number.isInteger(numeric) ? `${XSD}integer` : `${XSD}decimal`,
198
+ };
199
+ }
200
+ if (field.type === 'boolean') {
201
+ return { termType: 'Literal', value: value ? 'true' : 'false', datatype: `${XSD}boolean` };
202
+ }
203
+ if (field.type === 'timestamp') {
204
+ const date = value instanceof Date ? value : new Date(String(value));
205
+ if (Number.isNaN(date.getTime()))
206
+ return undefined;
207
+ return { termType: 'Literal', value: date.toISOString(), datatype: `${XSD}dateTime` };
208
+ }
209
+ if (field.type === 'json') {
210
+ return { termType: 'Literal', value: typeof value === 'string' ? value : JSON.stringify(value) };
211
+ }
212
+ const text = String(value);
213
+ // §2.4 边界 1:`string` 字段的值以 http(s):// 开头时会被写成 named node。
214
+ if (/^https?:\/\//u.test(text))
215
+ return { termType: 'NamedNode', value: text };
216
+ return { termType: 'Literal', value: text };
217
+ }
218
+ /** array 字段:每个元素一个 term(每元素一条三元组,§2.4)。 */
219
+ export function valuesToTerms(field, value) {
220
+ const list = Array.isArray(value) ? value : [value];
221
+ return list
222
+ .map((item) => valueToTerm(field, item))
223
+ .filter((term) => term !== undefined);
224
+ }
225
+ /**
226
+ * 主语行 → 集合行(`RowOf<D>`):只投影 descriptor 的非 `secret` 字段,
227
+ * `secret: true` 的字段默认不出现在行里(§2.1)。文档归属由读原语(`read.ts`)
228
+ * 决定,这里只做投影与键提取。
229
+ */
230
+ export function mapSubjectRows(descriptor, table, subjects) {
231
+ const bindings = fieldBindings(descriptor, table);
232
+ const identityField = identityFieldOf(descriptor);
233
+ const writeOnly = writeOnlyFields(descriptor);
234
+ const rows = [];
235
+ for (const subject of subjects) {
236
+ const key = rowKeyOf(descriptor, subject);
237
+ if (key === undefined)
238
+ continue;
239
+ const row = { id: key };
240
+ if (identityField !== 'id')
241
+ row[identityField] = key;
242
+ const subjectIri = subject['@id'] ?? subject.uri ?? subject.subject;
243
+ if (typeof subjectIri === 'string')
244
+ row['@id'] = subjectIri;
245
+ for (const binding of bindings.values()) {
246
+ if (writeOnly.has(binding.field))
247
+ continue;
248
+ if (binding.column === undefined)
249
+ continue;
250
+ const value = coerceFieldValue(binding.descriptor, subject[binding.column]);
251
+ if (value !== undefined)
252
+ row[binding.field] = value;
253
+ }
254
+ rows.push(row);
255
+ }
256
+ return rows;
257
+ }
258
+ /**
259
+ * 集合行 → drizzle 写负载(列名 → 值),供 `insert().values()` / `updateById()`。
260
+ * `array + uri` 字段由调用方走 `writeField()` 的 PATCH 旁路,不进 ORM(§4.1)。
261
+ * 返回的负载总是包含行标识列 `id`(表列 `id` 是 base-relative resource id)。
262
+ */
263
+ export function descriptorRowToColumnValues(descriptor, table, row, options) {
264
+ const bindings = fieldBindings(descriptor, table);
265
+ const values = { id: options.resourceId };
266
+ for (const [field, value] of Object.entries(row)) {
267
+ if (field === 'id' || field === '@id')
268
+ continue;
269
+ const binding = bindings.get(field);
270
+ if (!binding || binding.column === undefined)
271
+ continue;
272
+ if (options.includeField && !options.includeField(field))
273
+ continue;
274
+ values[binding.column] = value;
275
+ }
276
+ return values;
277
+ }
278
+ /** 该字段是否走 §4.1 的 PATCH 旁路:`array: true` + `type: 'uri'`。 */
279
+ export function isUriArrayField(field) {
280
+ return field.array === true && field.type === 'uri';
281
+ }
282
+ /** descriptor 里所有走 PATCH 旁路的字段。 */
283
+ export function uriArrayFields(descriptor) {
284
+ return Object.entries(descriptor.fields)
285
+ .filter(([, field]) => isUriArrayField(field))
286
+ .map(([name]) => name);
287
+ }
@@ -0,0 +1,83 @@
1
+ import type { AnyPodTable, SolidDatabase } from '@undefineds.co/drizzle-solid';
2
+ import type { PodModelDescriptor } from '@undefineds.co/models';
3
+ import type { InsertMutationFn, UpdateMutationFn, DeleteMutationFn } from '@tanstack/db';
4
+ import type { PodRowConflict, RowOf } from './types.js';
5
+ /**
6
+ * 未确认的本地写。`sync` 每轮读回文档后调用 `reconcilePendingWrites()`:
7
+ * 读回意图 → 确认;读回第三方值 → 冲突(server wins + 标记);仍未见意图 → 继续等。
8
+ */
9
+ export interface PodPendingWrite<R extends object> {
10
+ key: string;
11
+ /** 写入意图;删除时为 `undefined`。 */
12
+ intent: R | undefined;
13
+ /** 本地认为的行(删除时为删除前的行),仅用于冲突呈现。 */
14
+ localRow: R | undefined;
15
+ /** 写前的服务端投影哈希;`undefined` = 该行此前不在文档里。 */
16
+ beforeHash: string | undefined;
17
+ settled: boolean;
18
+ error: Error | undefined;
19
+ settledPromise: Promise<void>;
20
+ resolveSettled: () => void;
21
+ }
22
+ export interface RegisterPendingWriteInput<R extends object> {
23
+ key: string;
24
+ intent: R | undefined;
25
+ localRow: R | undefined;
26
+ beforeHash: string | undefined;
27
+ }
28
+ export interface PodPendingWrites<R extends object> {
29
+ /** 有未确认写的 key(同一个 Set 直接暴露给 `PodCollection.pendingKeys`)。 */
30
+ readonly keys: ReadonlySet<string>;
31
+ readonly entries: ReadonlyMap<string, PodPendingWrite<R>>;
32
+ readonly conflicts: readonly PodRowConflict<R>[];
33
+ register(input: RegisterPendingWriteInput<R>): PodPendingWrite<R>;
34
+ clear(key: string): void;
35
+ /** 该 key 的写是否已确认(意图已出现在服务端投影里)。 */
36
+ isConfirmed(key: string): boolean;
37
+ /** @internal 记录一次冲突(server wins + 标记 + 事务失败)。 */
38
+ recordConflict(conflict: PodRowConflict<R>): void;
39
+ /** @internal 结束一个未确认写:`error` 为空表示确认。 */
40
+ settle(entry: PodPendingWrite<R>, error?: Error): void;
41
+ }
42
+ export declare function createPendingWrites<R extends object>(onConflict?: (conflict: PodRowConflict<R>) => void): PodPendingWrites<R>;
43
+ /** 冲突标记:记录 + 回调 + 让写事务失败(§4.5)。 */
44
+ export declare function markConflict<R extends object>(pending: PodPendingWrites<R>, entry: PodPendingWrite<R>, server: R): void;
45
+ /**
46
+ * 每轮读回文档后调和未确认写(§4.2、§4.4、§4.5)。
47
+ * - 服务端投影覆盖了意图的**可读**字段:确认(handler 可以 resolve,乐观层被同值服务端行替换)。
48
+ * - 服务端投影 ∉ {意图, 写前值}:外部冲突,server wins + 标记 + 事务失败。
49
+ * - 服务端还没有该行:继续等下一轮(写可能还在索引后面)。
50
+ *
51
+ * `writeOnly` 是 `mapping.writeOnlyFields(descriptor)`:`secret: true` 的字段读不回来,
52
+ * 因此**不参与**「覆盖」判定,也不会因为它们而判冲突 —— 规则与理由见
53
+ * `diff.projectionCovers()`。可读字段的比对一字未松:意图里任何一个非 secret 字段
54
+ * 在服务端行里对不上,仍然走冲突分支。
55
+ */
56
+ export declare function reconcilePendingWrites<R extends object>(pending: PodPendingWrites<R>, next: ReadonlyMap<string, R>, hashOf: (row: R) => string, writeOnly?: ReadonlySet<string>): void;
57
+ export interface PodMutationContext<D extends PodModelDescriptor> {
58
+ descriptor: D;
59
+ table: AnyPodTable;
60
+ database: SolidDatabase;
61
+ podUrl: string;
62
+ document: string;
63
+ pending: PodPendingWrites<RowOf<D>>;
64
+ /** §4.2 的确认协议;由 sync 提供(立刻重读 + 至多 N 次合并窗口重试)。 */
65
+ confirm: (key: string) => Promise<void>;
66
+ /** PATCH 用的认证 fetch;缺省时从 database 的 session 取(见 `sessionFetchOf`)。 */
67
+ authenticatedFetch?: typeof fetch;
68
+ }
69
+ /**
70
+ * `array: true` + `type: 'uri'` 字段的唯一写入口(§4.1):一次 SPARQL PATCH,
71
+ * 先删旧值再插新值。`array + uri` 之外字段不允许走这里。
72
+ */
73
+ export declare function writeField<D extends PodModelDescriptor>(context: PodMutationContext<D>, fieldName: string, options: {
74
+ subjectIri: string;
75
+ previous: unknown;
76
+ next: unknown;
77
+ }): Promise<void>;
78
+ export interface PodMutationHandlers<D extends PodModelDescriptor> {
79
+ onInsert: InsertMutationFn<RowOf<D>, string>;
80
+ onUpdate: UpdateMutationFn<RowOf<D>, string>;
81
+ onDelete: DeleteMutationFn<RowOf<D>, string>;
82
+ }
83
+ export declare function createMutationHandlers<D extends PodModelDescriptor>(context: PodMutationContext<D>): PodMutationHandlers<D>;
@@ -0,0 +1,273 @@
1
+ import { PodCollectionError } from './types.js';
2
+ import { descriptorRowToColumnValues, fieldBindings, isUriArrayField, projectionFieldOrder, } from './mapping.js';
3
+ import { documentOfIri, resourceIdForRow, subjectIriForRow } from './layout.js';
4
+ import { sessionFetchOf } from './read.js';
5
+ import { projectionCovers, projectionHash } from './diff.js';
6
+ function createDeferred() {
7
+ let resolve;
8
+ const promise = new Promise((settle) => {
9
+ resolve = () => settle();
10
+ });
11
+ return { promise, resolve };
12
+ }
13
+ export function createPendingWrites(onConflict) {
14
+ const keys = new Set();
15
+ const entries = new Map();
16
+ const conflicts = [];
17
+ const clear = (key) => {
18
+ keys.delete(key);
19
+ entries.delete(key);
20
+ };
21
+ const settle = (entry, error) => {
22
+ if (entry.settled)
23
+ return;
24
+ entry.error = error;
25
+ entry.settled = true;
26
+ entry.resolveSettled();
27
+ };
28
+ const register = (input) => {
29
+ // 同一 key 上只允许一个未确认写(库的乐观层也只展示最后一个);后者取代前者。
30
+ clear(input.key);
31
+ const deferred = createDeferred();
32
+ const entry = {
33
+ ...input,
34
+ settled: false,
35
+ error: undefined,
36
+ settledPromise: deferred.promise,
37
+ resolveSettled: deferred.resolve,
38
+ };
39
+ entries.set(input.key, entry);
40
+ keys.add(input.key);
41
+ return entry;
42
+ };
43
+ return {
44
+ keys,
45
+ entries,
46
+ conflicts,
47
+ register,
48
+ clear,
49
+ settle,
50
+ isConfirmed: (key) => entries.get(key)?.settled === true && entries.get(key)?.error === undefined,
51
+ recordConflict: (conflict) => {
52
+ conflicts.push(conflict);
53
+ onConflict?.(conflict);
54
+ },
55
+ };
56
+ }
57
+ /** 冲突标记:记录 + 回调 + 让写事务失败(§4.5)。 */
58
+ export function markConflict(pending, entry, server) {
59
+ pending.recordConflict({
60
+ key: entry.key,
61
+ server,
62
+ local: (entry.localRow ?? entry.intent ?? server),
63
+ at: Date.now(),
64
+ });
65
+ pending.settle(entry, new PodCollectionError('write_conflict', `row ${entry.key} was changed by someone else; server wins`));
66
+ }
67
+ /**
68
+ * 每轮读回文档后调和未确认写(§4.2、§4.4、§4.5)。
69
+ * - 服务端投影覆盖了意图的**可读**字段:确认(handler 可以 resolve,乐观层被同值服务端行替换)。
70
+ * - 服务端投影 ∉ {意图, 写前值}:外部冲突,server wins + 标记 + 事务失败。
71
+ * - 服务端还没有该行:继续等下一轮(写可能还在索引后面)。
72
+ *
73
+ * `writeOnly` 是 `mapping.writeOnlyFields(descriptor)`:`secret: true` 的字段读不回来,
74
+ * 因此**不参与**「覆盖」判定,也不会因为它们而判冲突 —— 规则与理由见
75
+ * `diff.projectionCovers()`。可读字段的比对一字未松:意图里任何一个非 secret 字段
76
+ * 在服务端行里对不上,仍然走冲突分支。
77
+ */
78
+ export function reconcilePendingWrites(pending, next, hashOf, writeOnly = EMPTY_WRITE_ONLY) {
79
+ for (const entry of pending.entries.values()) {
80
+ if (entry.settled)
81
+ continue;
82
+ const server = next.get(entry.key);
83
+ if (entry.intent === undefined) {
84
+ // 删除意图:行不在了就是确认。
85
+ if (server === undefined) {
86
+ pending.settle(entry);
87
+ continue;
88
+ }
89
+ if (entry.beforeHash !== undefined && hashOf(server) !== entry.beforeHash) {
90
+ markConflict(pending, entry, server);
91
+ }
92
+ continue;
93
+ }
94
+ if (projectionCovers(server, entry.intent, writeOnly)) {
95
+ // 意图的可读字段都在服务端行里(插入意图可能只带一部分字段;带 secret 的意图
96
+ // 只按可读部分确认,secret 的证据是写调用已经成功)。
97
+ pending.settle(entry);
98
+ continue;
99
+ }
100
+ if (server !== undefined && hashOf(server) !== entry.beforeHash) {
101
+ markConflict(pending, entry, server);
102
+ continue;
103
+ }
104
+ if (server === undefined && entry.beforeHash !== undefined) {
105
+ // 我们想改的行已经不在文档里:外部删除,服务端状态已是「不存在」。
106
+ pending.settle(entry, new PodCollectionError('write_conflict', `row ${entry.key} disappeared before the write was confirmed; server wins`));
107
+ }
108
+ }
109
+ }
110
+ /** 默认「没有只写字段」,与 `projectionCovers()` 的默认值同义。 */
111
+ const EMPTY_WRITE_ONLY = new Set();
112
+ function absoluteUri(value, base) {
113
+ if (typeof value !== 'string' || value.length === 0)
114
+ return undefined;
115
+ if (/^[a-z][a-z0-9+.-]*:/iu.test(value))
116
+ return value;
117
+ return new URL(value, base).toString();
118
+ }
119
+ /**
120
+ * `array: true` + `type: 'uri'` 字段的唯一写入口(§4.1):一次 SPARQL PATCH,
121
+ * 先删旧值再插新值。`array + uri` 之外字段不允许走这里。
122
+ */
123
+ export async function writeField(context, fieldName, options) {
124
+ const field = context.descriptor.fields[fieldName];
125
+ if (!field || !isUriArrayField(field)) {
126
+ throw new PodCollectionError('write_field_not_uri_array', `field ${fieldName} is not array+uri; it must go through the ORM`);
127
+ }
128
+ const documentUrl = documentOfIri(context.document);
129
+ const previous = (Array.isArray(options.previous) ? options.previous : [options.previous])
130
+ .map((value) => absoluteUri(value, documentUrl))
131
+ .filter((value) => value !== undefined);
132
+ const next = (Array.isArray(options.next) ? options.next : [options.next])
133
+ .map((value) => absoluteUri(value, documentUrl))
134
+ .filter((value) => value !== undefined);
135
+ const triples = (iris) => iris
136
+ .map((iri) => `<${options.subjectIri}> <${field.predicate}> <${iri}> .`)
137
+ .join('\n');
138
+ const operations = [
139
+ previous.length > 0 ? `DELETE DATA { ${triples(previous)} }` : undefined,
140
+ next.length > 0 ? `INSERT DATA { ${triples(next)} }` : undefined,
141
+ ].filter((operation) => operation !== undefined);
142
+ if (operations.length === 0)
143
+ return;
144
+ const fetchFn = context.authenticatedFetch ?? sessionFetchOf(context.database);
145
+ if (!fetchFn) {
146
+ throw new PodCollectionError('write_field_no_fetch', 'array+uri fields need an authenticated fetch (SolidAuthSession.fetch); none available');
147
+ }
148
+ const response = await fetchFn(documentUrl, {
149
+ method: 'PATCH',
150
+ headers: { 'content-type': 'application/sparql-update' },
151
+ body: operations.join(';\n'),
152
+ });
153
+ if (!response.ok) {
154
+ throw new PodCollectionError('write_field_rejected', `SPARQL PATCH for ${fieldName} failed with HTTP ${response.status}`);
155
+ }
156
+ }
157
+ export function createMutationHandlers(context) {
158
+ const { descriptor, table, pending } = context;
159
+ const fieldOrder = projectionFieldOrder(descriptor);
160
+ const hashOf = (row) => projectionHash(row, fieldOrder);
161
+ const uriArrayFieldNames = new Set(Object.entries(descriptor.fields)
162
+ .filter(([, field]) => isUriArrayField(field))
163
+ .map(([name]) => name));
164
+ const columnBindings = fieldBindings(descriptor, table);
165
+ const columnOf = (field) => columnBindings.get(field)?.column;
166
+ const runWrite = async (key, write) => {
167
+ try {
168
+ await write();
169
+ }
170
+ catch (error) {
171
+ pending.clear(key);
172
+ throw error instanceof Error
173
+ ? error
174
+ : new PodCollectionError('write_failed', String(error), { cause: error });
175
+ }
176
+ try {
177
+ await context.confirm(key);
178
+ }
179
+ finally {
180
+ pending.clear(key);
181
+ }
182
+ };
183
+ return {
184
+ onInsert: async ({ transaction }) => {
185
+ for (const mutation of transaction.mutations) {
186
+ const row = mutation.modified;
187
+ const key = String(mutation.key);
188
+ const resourceId = resourceIdForRow(descriptor, context.document, context.podUrl, key);
189
+ const subjectIri = subjectIriForRow(descriptor, context.document, key);
190
+ pending.register({
191
+ key,
192
+ intent: row,
193
+ localRow: row,
194
+ beforeHash: undefined,
195
+ });
196
+ await runWrite(key, async () => {
197
+ const values = descriptorRowToColumnValues(descriptor, table, row, {
198
+ resourceId,
199
+ includeField: (field) => !uriArrayFieldNames.has(field),
200
+ });
201
+ await context.database.insert(table).values(values).execute();
202
+ await writeUriArrayFields(context, row, subjectIri, undefined, row);
203
+ });
204
+ }
205
+ },
206
+ onUpdate: async ({ transaction }) => {
207
+ for (const mutation of transaction.mutations) {
208
+ const key = String(mutation.key);
209
+ const original = mutation.original;
210
+ const modified = mutation.modified;
211
+ const changes = mutation.changes;
212
+ const resourceId = resourceIdForRow(descriptor, context.document, context.podUrl, key);
213
+ const subjectIri = subjectIriForRow(descriptor, context.document, key);
214
+ const beforeHash = original && Object.keys(original).length > 0 ? hashOf(original) : undefined;
215
+ pending.register({
216
+ key,
217
+ intent: modified,
218
+ localRow: modified,
219
+ beforeHash,
220
+ });
221
+ await runWrite(key, async () => {
222
+ const columnChanges = {};
223
+ for (const [field, value] of Object.entries(changes)) {
224
+ if (uriArrayFieldNames.has(field))
225
+ continue;
226
+ const column = columnOf(field);
227
+ if (column === undefined)
228
+ continue;
229
+ columnChanges[column] = value;
230
+ }
231
+ if (Object.keys(columnChanges).length > 0) {
232
+ const updated = await context.database.updateById(table, resourceId, columnChanges);
233
+ if (!updated) {
234
+ throw new PodCollectionError('write_rejected', `drizzle-solid did not update ${resourceId}`);
235
+ }
236
+ }
237
+ await writeUriArrayFields(context, changes, subjectIri, original, modified);
238
+ });
239
+ }
240
+ },
241
+ onDelete: async ({ transaction }) => {
242
+ for (const mutation of transaction.mutations) {
243
+ const key = String(mutation.key);
244
+ const original = mutation.original;
245
+ const resourceId = resourceIdForRow(descriptor, context.document, context.podUrl, key);
246
+ pending.register({
247
+ key,
248
+ intent: undefined,
249
+ localRow: original,
250
+ beforeHash: original && Object.keys(original).length > 0 ? hashOf(original) : undefined,
251
+ });
252
+ await runWrite(key, async () => {
253
+ // 返回 false = 该行本来就不在:意图(行不存在)已经满足,交给确认协议判定。
254
+ await context.database.deleteById(table, resourceId);
255
+ });
256
+ }
257
+ },
258
+ };
259
+ }
260
+ /** 遍历本次写涉及的 `array + uri` 字段,逐个走 §4.1 的 PATCH 旁路。 */
261
+ async function writeUriArrayFields(context, changed, subjectIri, previousRow, nextRow) {
262
+ for (const [field, fieldDescriptor] of Object.entries(context.descriptor.fields)) {
263
+ if (!isUriArrayField(fieldDescriptor))
264
+ continue;
265
+ if (!(field in changed))
266
+ continue;
267
+ await writeField(context, field, {
268
+ subjectIri,
269
+ previous: previousRow?.[field],
270
+ next: nextRow?.[field],
271
+ });
272
+ }
273
+ }
@@ -0,0 +1,21 @@
1
+ import { useLiveQuery } from '@tanstack/react-db';
2
+ import type { PodCollection } from './types.js';
3
+ /**
4
+ * `./react` 入口(§6.2):只有这里 import `@tanstack/react-db`,主入口保持无 React。
5
+ *
6
+ * P1 只保证这一层的签名与编译(§8.2 的测试清单里没有 React 用例);真实渲染、
7
+ * live query 与乐观层的交互验收在 P3 的 pilot 页面上做(§8.6)。
8
+ */
9
+ export { useLiveQuery };
10
+ export type { PodCollection } from './types.js';
11
+ /**
12
+ * 便捷 hook:把一个集合当单表读出来。
13
+ * `rows` 已含乐观行(库的 `state` 语义),`status` 直接来自 live query。
14
+ */
15
+ export declare function usePodCollection<R extends {
16
+ id: string;
17
+ }>(collection: PodCollection<R>): {
18
+ rows: R[];
19
+ status: ReturnType<typeof useLiveQuery>['status'];
20
+ isLoading: boolean;
21
+ };