@harperfast/harper 5.3.0-beta.4 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/bin/backup.ts +6 -1
  2. package/components/Application.ts +486 -115
  3. package/components/DESIGN.md +109 -21
  4. package/components/deploymentProvenance.ts +28 -0
  5. package/components/operations.js +14 -7
  6. package/components/packageComponent.ts +5 -1
  7. package/config-root.schema.json +1 -1
  8. package/dataLayer/DESIGN.md +35 -7
  9. package/dataLayer/blobBackup.ts +71 -30
  10. package/dataLayer/harperBridge/ResourceBridge.ts +16 -2
  11. package/dataLayer/rocksdbBackup.ts +88 -34
  12. package/dataLayer/schemaDescribe.ts +45 -1
  13. package/dist/bin/backup.js +1 -1
  14. package/dist/bin/backup.js.map +1 -1
  15. package/dist/components/Application.d.ts +11 -21
  16. package/dist/components/Application.js +436 -105
  17. package/dist/components/Application.js.map +1 -1
  18. package/dist/components/deploymentProvenance.d.ts +4 -0
  19. package/dist/components/deploymentProvenance.js +32 -0
  20. package/dist/components/deploymentProvenance.js.map +1 -0
  21. package/dist/components/operations.js +14 -7
  22. package/dist/components/operations.js.map +1 -1
  23. package/dist/components/packageComponent.js +6 -1
  24. package/dist/components/packageComponent.js.map +1 -1
  25. package/dist/dataLayer/blobBackup.d.ts +30 -3
  26. package/dist/dataLayer/blobBackup.js +73 -36
  27. package/dist/dataLayer/blobBackup.js.map +1 -1
  28. package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +1 -0
  29. package/dist/dataLayer/harperBridge/ResourceBridge.js +15 -3
  30. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  31. package/dist/dataLayer/rocksdbBackup.d.ts +4 -1
  32. package/dist/dataLayer/rocksdbBackup.js +74 -36
  33. package/dist/dataLayer/rocksdbBackup.js.map +1 -1
  34. package/dist/dataLayer/schemaDescribe.js +45 -1
  35. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  36. package/dist/resources/DatabaseTransaction.d.ts +1 -0
  37. package/dist/resources/DatabaseTransaction.js +33 -8
  38. package/dist/resources/DatabaseTransaction.js.map +1 -1
  39. package/dist/resources/ResourceInterface.d.ts +7 -3
  40. package/dist/resources/ResourceInterface.js +2 -0
  41. package/dist/resources/ResourceInterface.js.map +1 -1
  42. package/dist/resources/Table.d.ts +151 -445
  43. package/dist/resources/Table.js +209 -8
  44. package/dist/resources/Table.js.map +1 -1
  45. package/dist/resources/analytics/write.d.ts +11 -0
  46. package/dist/resources/analytics/write.js +3 -0
  47. package/dist/resources/analytics/write.js.map +1 -1
  48. package/dist/resources/blob.d.ts +30 -0
  49. package/dist/resources/blob.js +189 -1
  50. package/dist/resources/blob.js.map +1 -1
  51. package/dist/resources/databases.d.ts +1 -0
  52. package/dist/resources/databases.js +80 -15
  53. package/dist/resources/databases.js.map +1 -1
  54. package/dist/resources/derivedIndexRuntime.d.ts +13 -0
  55. package/dist/resources/derivedIndexRuntime.js +57 -5
  56. package/dist/resources/derivedIndexRuntime.js.map +1 -1
  57. package/dist/resources/derivedIndexes.d.ts +1 -0
  58. package/dist/resources/derivedIndexes.js +116 -15
  59. package/dist/resources/derivedIndexes.js.map +1 -1
  60. package/dist/resources/fullTextSchema.d.ts +5 -3
  61. package/dist/resources/fullTextSchema.js +48 -5
  62. package/dist/resources/fullTextSchema.js.map +1 -1
  63. package/dist/resources/fullTextSchemaLifecycle.d.ts +2 -0
  64. package/dist/resources/fullTextSchemaLifecycle.js +33 -0
  65. package/dist/resources/fullTextSchemaLifecycle.js.map +1 -1
  66. package/dist/resources/graphql.js +30 -12
  67. package/dist/resources/graphql.js.map +1 -1
  68. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +21 -1
  69. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +114 -5
  70. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  71. package/dist/resources/indexes/fullTextDerivedIndex.d.ts +11 -2
  72. package/dist/resources/indexes/fullTextDerivedIndex.js +187 -24
  73. package/dist/resources/indexes/fullTextDerivedIndex.js.map +1 -1
  74. package/dist/resources/indexes/fullTextNativeBinding.d.ts +99 -1
  75. package/dist/resources/indexes/fullTextNativeBinding.js +35 -1
  76. package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -1
  77. package/dist/resources/indexes/fullTextQueryIndex.d.ts +58 -0
  78. package/dist/resources/indexes/fullTextQueryIndex.js +943 -0
  79. package/dist/resources/indexes/fullTextQueryIndex.js.map +1 -0
  80. package/dist/resources/indexes/fullTextQueryProtocol.d.ts +6 -0
  81. package/dist/resources/indexes/fullTextQueryProtocol.js +32 -0
  82. package/dist/resources/indexes/fullTextQueryProtocol.js.map +1 -0
  83. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +4 -1
  84. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +30 -7
  85. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -1
  86. package/dist/resources/search.d.ts +41 -0
  87. package/dist/resources/search.js +468 -26
  88. package/dist/resources/search.js.map +1 -1
  89. package/dist/resources/transactionBroadcast.js +101 -50
  90. package/dist/resources/transactionBroadcast.js.map +1 -1
  91. package/dist/resources/typeParity.d.ts +9 -0
  92. package/dist/resources/typeParity.js +3 -0
  93. package/dist/resources/typeParity.js.map +1 -0
  94. package/dist/server/REST.js.map +1 -1
  95. package/dist/server/itc/serverHandlers.js +48 -8
  96. package/dist/server/itc/serverHandlers.js.map +1 -1
  97. package/dist/server/serverHelpers/contentTypes.d.ts +7 -0
  98. package/dist/server/serverHelpers/contentTypes.js +36 -23
  99. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  100. package/dist/server/serverHelpers/uwsServer.js +28 -5
  101. package/dist/server/serverHelpers/uwsServer.js.map +1 -1
  102. package/dist/server/threads/itc.js +19 -0
  103. package/dist/server/threads/itc.js.map +1 -1
  104. package/dist/server/threads/manageThreads.d.ts +3 -0
  105. package/dist/server/threads/manageThreads.js +90 -23
  106. package/dist/server/threads/manageThreads.js.map +1 -1
  107. package/dist/utility/operation_authorization.js +25 -7
  108. package/dist/utility/operation_authorization.js.map +1 -1
  109. package/dist/utility/signalling.js +3 -0
  110. package/dist/utility/signalling.js.map +1 -1
  111. package/dist/validation/searchValidator.js +22 -2
  112. package/dist/validation/searchValidator.js.map +1 -1
  113. package/npm-shrinkwrap.json +22 -22
  114. package/package.json +2 -4
  115. package/resources/DESIGN.md +19 -2
  116. package/resources/DatabaseTransaction.ts +40 -10
  117. package/resources/FULL_TEXT.md +97 -0
  118. package/resources/ResourceInterface.ts +8 -2
  119. package/resources/Table.ts +767 -17
  120. package/resources/analytics/write.ts +3 -3
  121. package/resources/blob.ts +183 -1
  122. package/resources/databases.ts +126 -14
  123. package/resources/derivedIndexRuntime.ts +79 -6
  124. package/resources/derivedIndexes.ts +142 -18
  125. package/resources/fullTextSchema.ts +55 -9
  126. package/resources/fullTextSchemaLifecycle.ts +45 -0
  127. package/resources/graphql.ts +33 -12
  128. package/resources/indexes/DESIGN.md +167 -15
  129. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +125 -5
  130. package/resources/indexes/fullTextDerivedIndex.ts +216 -32
  131. package/resources/indexes/fullTextNativeBinding.ts +133 -3
  132. package/resources/indexes/fullTextQueryIndex.ts +1120 -0
  133. package/resources/indexes/fullTextQueryProtocol.ts +35 -0
  134. package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +28 -8
  135. package/resources/search.ts +513 -26
  136. package/resources/transactionBroadcast.ts +86 -47
  137. package/resources/typeParity.ts +20 -0
  138. package/schema.graphql +18 -5
  139. package/server/DESIGN.md +18 -0
  140. package/server/REST.ts +1 -1
  141. package/server/itc/serverHandlers.js +61 -8
  142. package/server/serverHelpers/contentTypes.ts +31 -26
  143. package/server/serverHelpers/uwsServer.ts +35 -7
  144. package/server/threads/itc.js +21 -0
  145. package/server/threads/manageThreads.js +95 -21
  146. package/studio/web/assets/{Chat-Bq60AO-g.js → Chat-CNEKMllJ.js} +13 -13
  147. package/studio/web/assets/FloatingChat-CEnWhHeR.js +23 -0
  148. package/studio/web/assets/SearchDialog-CwhJdEdY.js +1 -0
  149. package/studio/web/assets/{abnfDiagram-O67JEVCF-DpPZWMOf.js → abnfDiagram-O67JEVCF-raXE027J.js} +1 -1
  150. package/studio/web/assets/alertDialog-BbWD9Xxa.js +1 -0
  151. package/studio/web/assets/apiToken-DC5vsaaO.js +1 -0
  152. package/studio/web/assets/applications-DQZxDy0x.js +296 -0
  153. package/studio/web/assets/architecture-7GRP2DOG-DDmz3hpI.js +1 -0
  154. package/studio/web/assets/{architectureDiagram-NJMV4G6O-OmgLraID.js → architectureDiagram-NJMV4G6O-C8_Eet7w.js} +1 -1
  155. package/studio/web/assets/arrow-up-D2g_57vT.js +1 -0
  156. package/studio/web/assets/authStore-CJCaADw9.js +3 -0
  157. package/studio/web/assets/{blockDiagram-BEXU5L5S-Cv7CD3Ai.js → blockDiagram-BEXU5L5S-DR6S5-1D.js} +1 -1
  158. package/studio/web/assets/{button-MFP9n8Ck.js → button-DWwfgGWI.js} +2 -2
  159. package/studio/web/assets/{c4Diagram-YGBWAQC7-Ds1vKYnN.js → c4Diagram-YGBWAQC7-BAfZ1G01.js} +1 -1
  160. package/studio/web/assets/channel-D0AkPjJ8.js +1 -0
  161. package/studio/web/assets/{chevron-up-CFe8x5Bp.js → chevron-up-CFxbMGv2.js} +1 -1
  162. package/studio/web/assets/{chunk-3FUC2YCW-DpnBPH8B.js → chunk-3FUC2YCW-DuRp-j19.js} +1 -1
  163. package/studio/web/assets/{chunk-5DYCD2WN-LLLCQSzg.js → chunk-5DYCD2WN-BceBfIHT.js} +1 -1
  164. package/studio/web/assets/{chunk-742MDFTN-BL8J_pIO.js → chunk-742MDFTN-CIkt8ijt.js} +1 -1
  165. package/studio/web/assets/{chunk-7INBJB4K-C-hJHiiK.js → chunk-7INBJB4K-BpeAXyOi.js} +1 -1
  166. package/studio/web/assets/{chunk-7M6MHVWA-C6ZqkFbA.js → chunk-7M6MHVWA-h6WlaTzO.js} +1 -1
  167. package/studio/web/assets/{chunk-7PRAP22T-CUXM8BG6.js → chunk-7PRAP22T-KyqX6x3f.js} +1 -1
  168. package/studio/web/assets/{chunk-GTNCS2PH-DJ2BFvS1.js → chunk-GTNCS2PH-DGHLXyow.js} +1 -1
  169. package/studio/web/assets/{chunk-GWA4HPMP-C42bSqLL.js → chunk-GWA4HPMP-DsejB6gA.js} +1 -1
  170. package/studio/web/assets/{chunk-MBY4JIJT-C-5jz6Lo.js → chunk-MBY4JIJT-BwSGweQP.js} +1 -1
  171. package/studio/web/assets/{chunk-NETBCI7D-D-bzlN4r.js → chunk-NETBCI7D-C8UnOw_f.js} +1 -1
  172. package/studio/web/assets/{chunk-O7XYJQB3-ep14zA23.js → chunk-O7XYJQB3-CBS3nZYV.js} +1 -1
  173. package/studio/web/assets/{chunk-UA2S7LBM-BMRWRHED.js → chunk-UA2S7LBM-BHpEdH8D.js} +1 -1
  174. package/studio/web/assets/{chunk-WEXAMYUT-DdLYVdX1.js → chunk-WEXAMYUT-BAIhTwyh.js} +1 -1
  175. package/studio/web/assets/{chunk-Z7XXMR3K-BmKEDjcP.js → chunk-Z7XXMR3K-DSHbImdf.js} +1 -1
  176. package/studio/web/assets/{chunk-ZIGJFQKS-DLZgdNxA.js → chunk-ZIGJFQKS-Cs8fUn7y.js} +1 -1
  177. package/studio/web/assets/{classDiagram-v2-NBCMYWYE-DOI5vgKT.js → classDiagram-v2-NBCMYWYE-DmDPkt2u.js} +1 -1
  178. package/studio/web/assets/cn-6T8VranJ.js +1 -0
  179. package/studio/web/assets/{codicon-Brq4_Ui5.ttf → codicon-DF1abBS2.ttf} +0 -0
  180. package/studio/web/assets/{createLucideIcon-bziYxJli.js → createLucideIcon-fO5dL7D5.js} +1 -1
  181. package/studio/web/assets/{css.worker-l1psR_wG.js → css.worker-DoT-OOzx.js} +36 -36
  182. package/studio/web/assets/{cssMode-DJyc9mHj.js → cssMode-Dz2DxF4e.js} +1 -1
  183. package/studio/web/assets/{cynefin-OW5HDTMX-BSW-DB7S.js → cynefin-OW5HDTMX-DIvbXLSj.js} +1 -1
  184. package/studio/web/assets/{cynefinDiagram-VND7K2PF-CbAHEwxt.js → cynefinDiagram-VND7K2PF-BdtaXiCE.js} +1 -1
  185. package/studio/web/assets/{dagre-6A5THRUB-Csxewgs4.js → dagre-6A5THRUB-C7RUWHyz.js} +1 -1
  186. package/studio/web/assets/{diagram-22UHCM2B-a0rt8tY4.js → diagram-22UHCM2B-DJCvcaWP.js} +1 -1
  187. package/studio/web/assets/{diagram-3UASUU5V-lEj2SVNh.js → diagram-3UASUU5V-Du6VKWln.js} +1 -1
  188. package/studio/web/assets/{diagram-ATOU4E4O-HcrAeB-q.js → diagram-ATOU4E4O-dxRfeG4B.js} +1 -1
  189. package/studio/web/assets/{diagram-CDSNMT55-CYxiuyEx.js → diagram-CDSNMT55-l5Ga0u-W.js} +1 -1
  190. package/studio/web/assets/{diagram-MLGK6HIB-ChbCJTgJ.js → diagram-MLGK6HIB-CNQY47LA.js} +1 -1
  191. package/studio/web/assets/{diagram-MPIPVDR6-DaX9Y-N3.js → diagram-MPIPVDR6-7prveD1B.js} +1 -1
  192. package/studio/web/assets/{dist-Cz2Y6-6G.js → dist-BrRuMUzt.js} +1 -1
  193. package/studio/web/assets/{download-CtostjYn.js → download-Cn6tPG4L.js} +1 -1
  194. package/studio/web/assets/{ebnfDiagram-ZINNZB2B-CwAsENB1.js → ebnfDiagram-ZINNZB2B-5OnkTpfi.js} +1 -1
  195. package/studio/web/assets/{editor-DDIsQfj6.js → editor-B3mjd3tz.js} +1 -1
  196. package/studio/web/assets/editor.worker-Yd1NR0QT.js +33 -0
  197. package/studio/web/assets/{elk-276RUBZZ-Hexg9E4D.js → elk-276RUBZZ-DxDQPjQT.js} +1 -1
  198. package/studio/web/assets/{erDiagram-OPXOYQCR-CeC-wwO1.js → erDiagram-OPXOYQCR-CQlCX84D.js} +1 -1
  199. package/studio/web/assets/eventmodeling-NTZA5JFV-DONQf5aG.js +1 -0
  200. package/studio/web/assets/flowDiagram-KWPJA3E3-BoZ8_QR1.js +1 -0
  201. package/studio/web/assets/{ganttDiagram-FUAMR5RP-C2_Hhl1-.js → ganttDiagram-FUAMR5RP-bloX3Voy.js} +1 -1
  202. package/studio/web/assets/{getAnalytics-CjthMQqF.js → getAnalytics-C0FHjtdQ.js} +1 -1
  203. package/studio/web/assets/{gitGraph-4MIJSDKK-xIk5Vuew.js → gitGraph-4MIJSDKK-BrXWmJt2.js} +1 -1
  204. package/studio/web/assets/{gitGraphDiagram-X574FWY7-CMxJ34up.js → gitGraphDiagram-X574FWY7-C2KnnZeY.js} +1 -1
  205. package/studio/web/assets/{html-g1BJHxLy.js → html-BsRGM7tp.js} +1 -1
  206. package/studio/web/assets/{html.worker-DdwM4IrA.js → html.worker-B1dwY0Ay.js} +27 -27
  207. package/studio/web/assets/{htmlMode-Vh5IglCQ.js → htmlMode-tUKJaA3o.js} +1 -1
  208. package/studio/web/assets/index-72cEH474.css +1 -0
  209. package/studio/web/assets/index-BuqFjN5K.js +828 -0
  210. package/studio/web/assets/index.lazy-CcpfQFY_.js +2 -0
  211. package/studio/web/assets/{info-A6RAGUB7-o49TEbj-.js → info-A6RAGUB7-BhzBHe4U.js} +1 -1
  212. package/studio/web/assets/{infoDiagram-VRGFBTTK-Cjhh7yzZ.js → infoDiagram-VRGFBTTK-B0J1132p.js} +1 -1
  213. package/studio/web/assets/{ishikawaDiagram-OU5B5YK6-C63aXRmh.js → ishikawaDiagram-OU5B5YK6-BNk0tuQx.js} +1 -1
  214. package/studio/web/assets/{javascript-5VIolqf7.js → javascript-BZ_uRGHl.js} +1 -1
  215. package/studio/web/assets/{journeyDiagram-ZHPQQLJL-D_o0P5Mu.js → journeyDiagram-ZHPQQLJL-Be79RMQM.js} +1 -1
  216. package/studio/web/assets/json.worker-BQqXGI3X.js +65 -0
  217. package/studio/web/assets/{jsonMode-DG4zQraI.js → jsonMode-DgB-aFMj.js} +1 -1
  218. package/studio/web/assets/{kanban-definition-PNTS6WVX-CTI9SSxY.js → kanban-definition-PNTS6WVX-4uuoQP9W.js} +1 -1
  219. package/studio/web/assets/{languageServices-t5FBpX-i.js → languageServices-BleuBw17.js} +1 -1
  220. package/studio/web/assets/localStorageKeys-etzFY_xV.js +1 -0
  221. package/studio/web/assets/{lspLanguageFeatures-DgVnNPh-.js → lspLanguageFeatures-ByVYLSsQ.js} +1 -1
  222. package/studio/web/assets/{mermaid-parser.core-C2lcH_jP.js → mermaid-parser.core-V1UYMeXV.js} +3 -3
  223. package/studio/web/assets/{mermaid.core-BG5bjfIG.js → mermaid.core-1PX6R49U.js} +4 -4
  224. package/studio/web/assets/{mindmap-definition-NLK3R4M7-BK7ho6JD.js → mindmap-definition-NLK3R4M7-C70Ctm0J.js} +1 -1
  225. package/studio/web/assets/notifications-D1Nf-Edn.js +1 -0
  226. package/studio/web/assets/notifications-TuzN0IMi.js +1 -0
  227. package/studio/web/assets/{packet-AYTQ26CC-BHPy6KBV.js → packet-AYTQ26CC-DWbXHx5g.js} +1 -1
  228. package/studio/web/assets/{pegDiagram-GJSIUBJH-DzjwG3jO.js → pegDiagram-GJSIUBJH-d6z1cc7W.js} +1 -1
  229. package/studio/web/assets/{pie-WAS4IAKB-D0cP-DTU.js → pie-WAS4IAKB-DjoTm3yr.js} +1 -1
  230. package/studio/web/assets/{pieDiagram-5QR66LMP-C_hOP9Lv.js → pieDiagram-5QR66LMP-Dz3RHpDA.js} +1 -1
  231. package/studio/web/assets/profile-D7C7Lupz.js +1 -0
  232. package/studio/web/assets/{quadrantDiagram-O4NWA36T-CZW8PbV1.js → quadrantDiagram-O4NWA36T-CIF5Qkou.js} +1 -1
  233. package/studio/web/assets/{radar-RG4KPBEZ-C8fk0U81.js → radar-RG4KPBEZ-CVBgjCOj.js} +1 -1
  234. package/studio/web/assets/{railroad-74A4TZTK-B60FWm17.js → railroad-74A4TZTK-BdhXw10Q.js} +1 -1
  235. package/studio/web/assets/railroad-abnf-HS5TGJTU-BcoQPN39.js +1 -0
  236. package/studio/web/assets/railroad-ebnf-LZEXJU2U-B1Lke2JN.js +1 -0
  237. package/studio/web/assets/railroad-peg-WCYAUIDC-D-oJFkiV.js +1 -0
  238. package/studio/web/assets/{railroadDiagram-XR7U4H2S-DyyNmgbU.js → railroadDiagram-XR7U4H2S-y3Jv2U6N.js} +1 -1
  239. package/studio/web/assets/regions-nGQCm-v8.js +1 -0
  240. package/studio/web/assets/register-C3x9Ze6P.js +909 -0
  241. package/studio/web/assets/register-DjpsE8to.css +1 -0
  242. package/studio/web/assets/{requirementDiagram-PLB6GJNP-C4H-mLKu.js → requirementDiagram-PLB6GJNP-ChINZEmu.js} +1 -1
  243. package/studio/web/assets/restartGate-nHAFLDh-.js +1 -0
  244. package/studio/web/assets/{sankeyDiagram-IPEJSGJF-DHDyga4c.js → sankeyDiagram-IPEJSGJF-D9AyLce2.js} +1 -1
  245. package/studio/web/assets/{sequenceDiagram-PO4LG4MO-CdNcHXRI.js → sequenceDiagram-PO4LG4MO-hfk4aIEm.js} +1 -1
  246. package/studio/web/assets/{setComponentFile-z4-qJCbA.js → setComponentFile-DpjrRqeG.js} +1 -1
  247. package/studio/web/assets/{setup-CS50uJ4x.js → setup-CGiKLZ9e.js} +2 -2
  248. package/studio/web/assets/{stateDiagram-v2-GCMORJYK-CpKuXq15.js → stateDiagram-v2-GCMORJYK-Bs8RIb9K.js} +1 -1
  249. package/studio/web/assets/status-CGJwrNPH.js +61 -0
  250. package/studio/web/assets/{swimlanes-2SLR337P-NRHa2D8I.js → swimlanes-2SLR337P-B52xrf6t.js} +1 -1
  251. package/studio/web/assets/swimlanesDiagram-TC7HE7FX-DfN7BAP5.js +8 -0
  252. package/studio/web/assets/tabs-BCTQzoQK.js +1 -0
  253. package/studio/web/assets/{timeline-definition-EJHVYXUP-D39Y-xpq.js → timeline-definition-EJHVYXUP-DJSITpQX.js} +1 -1
  254. package/studio/web/assets/toggleHighContrast-C-Ne6P7T.js +51 -0
  255. package/studio/web/assets/toggleHighContrast-n7clI0si.css +1 -0
  256. package/studio/web/assets/{treeView-Q6P3EWNA-CRWR9OqD.js → treeView-Q6P3EWNA-C-epdxRo.js} +1 -1
  257. package/studio/web/assets/{treemap-WGGIJYW6-ZfXyJgLO.js → treemap-WGGIJYW6-DOVyp_zw.js} +1 -1
  258. package/studio/web/assets/{ts.worker-DDMUrpqh.js → ts.worker-Clm12uY6.js} +131 -131
  259. package/studio/web/assets/{tsMode-D83Gg3cq.js → tsMode-CSreYTys.js} +1 -1
  260. package/studio/web/assets/{typescript-Dfp-GrNq.js → typescript-MnxBk89W.js} +1 -1
  261. package/studio/web/assets/{useEntityRestURL-BKetlINf.js → useEntityRestURL-TNrh77-s.js} +1 -1
  262. package/studio/web/assets/{usecaseDiagram-POWQR4AR-jf-zIDZ_.js → usecaseDiagram-POWQR4AR-B6252cbq.js} +1 -1
  263. package/studio/web/assets/{vendor-core-BdkdbUek.js → vendor-core-6LhfJlRC.js} +1 -1
  264. package/studio/web/assets/vendor-datadog-ozKf-pts.js +6 -0
  265. package/studio/web/assets/{vendor-react-izWchTRL.js → vendor-react-BOliS0BL.js} +1 -1
  266. package/studio/web/assets/vendor-tanstack-Bntfka-M.js +2 -0
  267. package/studio/web/assets/vendor-ui-9EYYDgoN.js +41 -0
  268. package/studio/web/assets/{vennDiagram-UO4OBE2U-BKYAZUh_.js → vennDiagram-UO4OBE2U-DZTsDA4k.js} +1 -1
  269. package/studio/web/assets/{wardley-WFR3VGLG-BO7f36ci.js → wardley-WFR3VGLG-Cfqoe6z4.js} +1 -1
  270. package/studio/web/assets/{wardleyDiagram-VNRHLVJA-Djb0JDQc.js → wardleyDiagram-VNRHLVJA-qu_f7Tvl.js} +1 -1
  271. package/studio/web/assets/{workers-CCvmDLH3.js → workers-BfZlUNVI.js} +3 -3
  272. package/studio/web/assets/{xml-06pZp00U.js → xml-BHd6qGH7.js} +1 -1
  273. package/studio/web/assets/{xychartDiagram-PMCCYNJV-BQh9ubvb.js → xychartDiagram-PMCCYNJV-UrOKRsmR.js} +1 -1
  274. package/studio/web/assets/{yaml-iSnWMVlV.js → yaml-C53R8OQq.js} +1 -1
  275. package/studio/web/assets/{yaml.worker-DAK2o_H1.js → yaml.worker-D9JekGdp.js} +183 -183
  276. package/studio/web/index.html +15 -15
  277. package/utility/operation_authorization.ts +27 -7
  278. package/utility/signalling.ts +3 -0
  279. package/validation/searchValidator.ts +22 -13
  280. package/studio/web/assets/FloatingChat-D4560T0p.js +0 -23
  281. package/studio/web/assets/alertDialog-UrbiMgQt.js +0 -1
  282. package/studio/web/assets/apiToken-BEvbFPMc.js +0 -1
  283. package/studio/web/assets/applications-CSUVTH4E.js +0 -296
  284. package/studio/web/assets/architecture-7GRP2DOG-11l4Ny1l.js +0 -1
  285. package/studio/web/assets/authStore-5jSS5pTW.js +0 -3
  286. package/studio/web/assets/channel-BDtouPd6.js +0 -1
  287. package/studio/web/assets/dialog-DTepachC.js +0 -1
  288. package/studio/web/assets/editor.worker-CkkvdXvO.js +0 -33
  289. package/studio/web/assets/eventmodeling-NTZA5JFV-CFb03e0o.js +0 -1
  290. package/studio/web/assets/flowDiagram-KWPJA3E3-Cidi00_Y.js +0 -1
  291. package/studio/web/assets/index-CPoDzQTe.css +0 -1
  292. package/studio/web/assets/index-DGRAzvO4.js +0 -824
  293. package/studio/web/assets/index.lazy-vgSic7et.js +0 -2
  294. package/studio/web/assets/json.worker-CSi2hF-a.js +0 -65
  295. package/studio/web/assets/notifications-BeWcX04m.js +0 -1
  296. package/studio/web/assets/notifications-DUGWrWoO.js +0 -1
  297. package/studio/web/assets/profile-BvUEDBzW.js +0 -1
  298. package/studio/web/assets/railroad-abnf-HS5TGJTU-CLMVZvH0.js +0 -1
  299. package/studio/web/assets/railroad-ebnf-LZEXJU2U--tlwFoVB.js +0 -1
  300. package/studio/web/assets/railroad-peg-WCYAUIDC-Dpuslblm.js +0 -1
  301. package/studio/web/assets/regions-CB-_2m7M.js +0 -1
  302. package/studio/web/assets/register-1w1Zr3b2.js +0 -848
  303. package/studio/web/assets/register-jjEx9u7D.css +0 -1
  304. package/studio/web/assets/setLocalStorage-D_kflv4U.js +0 -1
  305. package/studio/web/assets/status-CI0wOdOE.js +0 -61
  306. package/studio/web/assets/swimlanesDiagram-TC7HE7FX-BBk4t4hO.js +0 -8
  307. package/studio/web/assets/tabs-CnQ_zenf.js +0 -1
  308. package/studio/web/assets/toggleHighContrast--ixms01u.css +0 -1
  309. package/studio/web/assets/toggleHighContrast-BsAE4jPe.js +0 -49
  310. package/studio/web/assets/useLocalStorage-BYoZF60G.js +0 -1
  311. package/studio/web/assets/vendor-datadog-fCQhBHGk.js +0 -6
  312. package/studio/web/assets/vendor-tanstack-CQ1aRjVa.js +0 -2
  313. package/studio/web/assets/vendor-ui-aE1tHcW7.js +0 -41
  314. package/studio/web/assets/x-vYntCxm4.js +0 -1
@@ -120,6 +120,8 @@ export interface DerivedIndexBackendHost {
120
120
  /** True while `epoch` is the most recently minted owner epoch for this backend. */
121
121
  isOwnerEpoch(epoch: bigint): boolean;
122
122
  getReadiness(): DerivedIndexReadiness;
123
+ /** Publish a durable backend-only revision that peer workers must observe. */
124
+ publicationChanged(): void;
123
125
  }
124
126
 
125
127
  /**
@@ -131,6 +133,8 @@ export interface DerivedIndexBackendHost {
131
133
  */
132
134
  export interface DerivedIndexBackend {
133
135
  readonly id: string;
136
+ /** Allocate and publish cross-worker query revisions for backends with external reader state. */
137
+ readonly publishesQueryRevisions?: boolean;
134
138
  /** Receives the epoch fence and readiness reader before any delivery. */
135
139
  attach(host: DerivedIndexBackendHost): void;
136
140
  getDurableCursor(): DerivedIndexCursor | undefined;
@@ -345,8 +349,7 @@ export class DerivedIndexRuntime {
345
349
  this.#runners.delete(registration.backend.id);
346
350
  const waiting = this.#coverageWaits.get(registration.backend.id);
347
351
  if (waiting) {
348
- for (const waiter of waiting.waiters)
349
- waiter.finish(new ServerError('The native HNSW index is unavailable', 503));
352
+ for (const waiter of waiting.waiters) waiter.finish(new ServerError('The derived index is unavailable', 503));
350
353
  }
351
354
  this.#stopListeningIfIdle();
352
355
  }
@@ -387,7 +390,7 @@ export class DerivedIndexRuntime {
387
390
 
388
391
  waitForCoverage(backendId: string, since: bigint, timeout: number, signal?: AbortSignal): Promise<void> {
389
392
  if (this.#stopped || !this.#runners.has(backendId))
390
- return Promise.reject(new ServerError('The native HNSW index is unavailable', 503));
393
+ return Promise.reject(new ServerError('The derived index is unavailable', 503));
391
394
  let group = this.#coverageWaits.get(backendId);
392
395
  const first = !group;
393
396
  if (!group) this.#coverageWaits.set(backendId, (group = { waiters: new Set() }));
@@ -432,7 +435,7 @@ export class DerivedIndexRuntime {
432
435
  const after = readReadiness(views);
433
436
  if (after.state !== 'ready')
434
437
  throw new ServerError(
435
- `The native HNSW index is ${after.state === 'unavailable' ? 'unavailable' : 'rebuilding'}`,
438
+ `The derived index is ${after.state === 'unavailable' ? 'unavailable' : 'rebuilding'}`,
436
439
  503
437
440
  );
438
441
  const now = derivedIndexTime(this.#logStore.rootStore);
@@ -440,7 +443,7 @@ export class DerivedIndexRuntime {
440
443
  for (const waiter of group.waiters) {
441
444
  if (before.state === 'ready' && before.ownerEpoch === after.ownerEpoch && time >= waiter.since) waiter.finish();
442
445
  else if (now >= waiter.deadline)
443
- waiter.finish(new DerivedIndexLagError('Timed out waiting for native HNSW index coverage; retry this query'));
446
+ waiter.finish(new DerivedIndexLagError('Timed out waiting for derived index coverage; retry this query'));
444
447
  else delay = Math.min(delay, Math.max(1, Number(waiter.deadline - now) / 1e6));
445
448
  }
446
449
  if (group.waiters.size) group.timer = setTimeout(() => this.#pollCoverage(backendId, group), delay);
@@ -482,7 +485,7 @@ export class DerivedIndexRuntime {
482
485
  if (this.#stopping) return this.#stopping;
483
486
  this.#stopped = true;
484
487
  for (const group of this.#coverageWaits.values()) {
485
- for (const waiter of group.waiters) waiter.finish(new ServerError('The native HNSW index is unavailable', 503));
488
+ for (const waiter of group.waiters) waiter.finish(new ServerError('The derived index is unavailable', 503));
486
489
  }
487
490
  for (const runner of this.#runners.values()) this.#track(runner, runner.stop());
488
491
  this.#runners.clear();
@@ -649,7 +652,9 @@ class DerivedIndexRunner {
649
652
  #ownerEpoch?: bigint;
650
653
  #readinessBuffer: SharedReadinessBuffer;
651
654
  #wakeBuffer: SharedReadinessBuffer;
655
+ #publicationBuffer?: SharedReadinessBuffer;
652
656
  #sharedViews: SharedViews;
657
+ #publicationRevision?: BigInt64Array;
653
658
  #resetting?: Promise<void>;
654
659
  status: DerivedIndexRunnerStatus = { state: 'idle' };
655
660
 
@@ -703,10 +708,15 @@ class DerivedIndexRunner {
703
708
  );
704
709
  this.#wakeBuffer = this.readinessId === this.id ? this.#readinessBuffer : wakeBuffer(logStore, this.id, notified);
705
710
  this.#sharedViews = sharedViewsOf(this.#readinessBuffer);
711
+ if (registration.backend.publishesQueryRevisions) {
712
+ this.#publicationBuffer = publicationBuffer(logStore, this.readinessId);
713
+ this.#publicationRevision = new BigInt64Array(this.#publicationBuffer, 0, 1);
714
+ }
706
715
  try {
707
716
  registration.backend.attach({
708
717
  isOwnerEpoch: (epoch) => Atomics.load(this.#sharedViews.epoch, 0) === epoch,
709
718
  getReadiness: () => this.getReadiness(),
719
+ publicationChanged: () => this.#publicationChanged(),
710
720
  });
711
721
  this.#unsubscribeBackend = registration.backend.onStateChange((change = 'changed') =>
712
722
  this.#backendStateChanged(change)
@@ -714,6 +724,7 @@ class DerivedIndexRunner {
714
724
  } catch (error) {
715
725
  this.#readinessBuffer.cancel?.();
716
726
  if (this.#wakeBuffer !== this.#readinessBuffer) this.#wakeBuffer.cancel?.();
727
+ this.#publicationBuffer?.cancel?.();
717
728
  throw error;
718
729
  }
719
730
  this.#unregisterTables = registerDerivedIndexTables(
@@ -775,6 +786,7 @@ class DerivedIndexRunner {
775
786
  this.#unsubscribeBackend?.();
776
787
  this.#readinessBuffer.cancel?.();
777
788
  if (this.#wakeBuffer !== this.#readinessBuffer) this.#wakeBuffer.cancel?.();
789
+ this.#publicationBuffer?.cancel?.();
778
790
  } catch (error) {
779
791
  logger.warn?.(`Derived index '${this.id}' cleanup hook threw`, error);
780
792
  }
@@ -1639,6 +1651,8 @@ class DerivedIndexRunner {
1639
1651
  }
1640
1652
  }
1641
1653
  this.#boundaryPending = false;
1654
+ // A waiter that observes the covering clock must also observe this durable publication revision.
1655
+ if (offeredIndex > 0) this.#publicationChanged();
1642
1656
  for (let i = offeredIndex; i >= 0; i--) {
1643
1657
  const coverage = this.#offeredCursors[i].coverage;
1644
1658
  if (coverage) {
@@ -1654,6 +1668,16 @@ class DerivedIndexRunner {
1654
1668
  return true;
1655
1669
  }
1656
1670
 
1671
+ #publicationChanged(): void {
1672
+ if (!this.#publicationRevision || !this.#publicationBuffer) return;
1673
+ Atomics.add(this.#publicationRevision, 0, 1n);
1674
+ try {
1675
+ this.#publicationBuffer.notify?.();
1676
+ } catch (error) {
1677
+ logger.warn?.(`Derived index '${this.id}' could not notify peers of its publication`, error);
1678
+ }
1679
+ }
1680
+
1657
1681
  #publishCoverage(capture: CoverageCapture) {
1658
1682
  if (!this.#owned || this.#rebuilding || Atomics.load(this.#shared().epoch, 0) !== this.#ownerEpoch) return;
1659
1683
  if (capture.time <= Atomics.load(this.#shared().coverage, 0)) return;
@@ -2192,6 +2216,18 @@ function wakeBuffer(
2192
2216
  }) as SharedReadinessBuffer;
2193
2217
  }
2194
2218
 
2219
+ function publicationBuffer(
2220
+ logStore: RocksTransactionLogStore,
2221
+ backendId: string,
2222
+ callback?: () => void
2223
+ ): SharedReadinessBuffer {
2224
+ return logStore.getUserSharedBuffer(
2225
+ `derived-index:${backendId}:publication`,
2226
+ new ArrayBuffer(8),
2227
+ callback ? { callback } : undefined
2228
+ ) as SharedReadinessBuffer;
2229
+ }
2230
+
2195
2231
  type SharedViews = {
2196
2232
  words: Int32Array;
2197
2233
  epoch: BigInt64Array;
@@ -2207,6 +2243,7 @@ function sharedViewsOf(buffer: ArrayBufferLike): SharedViews {
2207
2243
  }
2208
2244
 
2209
2245
  const readinessViews = new WeakMap<object, Map<string, SharedViews>>();
2246
+ const publicationViews = new WeakMap<object, Map<string, BigInt64Array>>();
2210
2247
 
2211
2248
  function readReadiness({ words, epoch }: SharedViews): DerivedIndexReadiness {
2212
2249
  const stateIndex = Atomics.load(words, READINESS_STATE);
@@ -2235,6 +2272,42 @@ export function readDerivedIndexReadiness(
2235
2272
  return readReadiness(getReadinessViews(logStore, backendId));
2236
2273
  }
2237
2274
 
2275
+ export function readDerivedIndexPublicationRevision(
2276
+ logStore: RocksTransactionLogStore,
2277
+ backendId: string
2278
+ ): { ownerEpoch: bigint; revision: bigint } {
2279
+ const readiness = getReadinessViews(logStore, backendId);
2280
+ let byBackend = publicationViews.get(logStore);
2281
+ if (!byBackend) publicationViews.set(logStore, (byBackend = new Map()));
2282
+ let revision = byBackend.get(backendId);
2283
+ if (!revision) {
2284
+ const buffer = publicationBuffer(logStore, backendId);
2285
+ byBackend.set(backendId, (revision = new BigInt64Array(buffer, 0, 1)));
2286
+ }
2287
+ return {
2288
+ ownerEpoch: Atomics.load(readiness.epoch, 0),
2289
+ revision: Atomics.load(revision, 0),
2290
+ };
2291
+ }
2292
+
2293
+ export type DerivedIndexPublicationSubscription = {
2294
+ revision(): bigint;
2295
+ close(): void;
2296
+ };
2297
+
2298
+ export function subscribeDerivedIndexPublications(
2299
+ logStore: RocksTransactionLogStore,
2300
+ backendId: string,
2301
+ callback: () => void
2302
+ ): DerivedIndexPublicationSubscription {
2303
+ const buffer = publicationBuffer(logStore, backendId, callback);
2304
+ const revision = new BigInt64Array(buffer, 0, 1);
2305
+ return {
2306
+ revision: () => Atomics.load(revision, 0),
2307
+ close: () => buffer.cancel?.(),
2308
+ };
2309
+ }
2310
+
2238
2311
  /** Publish setup-time state before a backend runner exists. */
2239
2312
  export function publishDerivedIndexReadiness(
2240
2313
  logStore: RocksTransactionLogStore,
@@ -1,5 +1,9 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { ClientError } from '../utility/errors/hdbError.ts';
3
+ import { settleBeforeDeadline } from '../utility/when.ts';
4
+ import { ITC_EVENT_TYPES } from '../utility/hdbTerms.ts';
2
5
  import { loggerWithTag } from '../utility/logging/logger.ts';
6
+ import { sendItcEventStrict } from '../server/threads/itc.js';
3
7
  import { RocksDatabase } from '@harperfast/rocksdb-js';
4
8
  import type { RocksTransactionLogStore } from './RocksTransactionLogStore.ts';
5
9
  import {
@@ -23,9 +27,17 @@ import {
23
27
  } from './indexes/hnswDerivedIndex.ts';
24
28
  import {
25
29
  createNativeFullTextDerivedIndexBackend,
30
+ nativeFullTextIndexPath,
26
31
  retireNativeFullTextDerivedIndexStorage,
27
32
  } from './indexes/nativeFullTextDerivedIndexLifecycle.ts';
28
33
  import type { NativeFullTextModule } from './indexes/fullTextNativeBinding.ts';
34
+ import {
35
+ FULL_TEXT_QUERY_PAUSE_OPERATION,
36
+ FULL_TEXT_QUERY_RESUME_OPERATION,
37
+ FullTextQueryIndex,
38
+ pauseNativeFullTextQueryReaders,
39
+ resumeNativeFullTextQueryReaders,
40
+ } from './indexes/fullTextQueryIndex.ts';
29
41
  import { fullTextStorageDefinition, type FullTextDefinition } from './fullTextSchema.ts';
30
42
 
31
43
  const logger = loggerWithTag('HNSW');
@@ -33,14 +45,17 @@ const fullTextLogger = loggerWithTag('fulltext-derived-index');
33
45
  const derivedIndexLogger = loggerWithTag('derived-index');
34
46
  const DEFAULT_MAX_LAG_MILLISECONDS = 30_000;
35
47
  const DEFAULT_FULL_TEXT_RETIREMENT_RETRY_MILLISECONDS = 70_000;
36
- const FULL_TEXT_LIMITS = Object.freeze({
37
- indexingThreads: 1,
48
+ const FULL_TEXT_READER_COORDINATION_TIMEOUT_MILLISECONDS = 35_000;
49
+ const FULL_TEXT_RESET_TIMEOUT_MILLISECONDS = 105_000;
50
+ const FULL_TEXT_WRITER_LIMITS = Object.freeze({
51
+ indexingThreads: 2,
38
52
  searchThreads: 1,
39
- writerMemoryBytes: 32 * 1024 * 1024,
53
+ writerMemoryBytes: 64 * 1024 * 1024,
40
54
  maxQueuedCommands: 16,
41
55
  maxQueuedBytes: 64 * 1024 * 1024,
42
56
  maxBatchBytes: 8 * 1024 * 1024,
43
57
  });
58
+ const FULL_TEXT_READER_LIMITS = Object.freeze({ ...FULL_TEXT_WRITER_LIMITS, searchThreads: 2 });
44
59
 
45
60
  type RegisteredTable = { current: { Table: any }; owners: Set<{ Table: any }> };
46
61
  type RegisteredBackend = {
@@ -71,6 +86,7 @@ type FullTextTestConfiguration = {
71
86
  binding: NativeFullTextModule;
72
87
  closeTimeoutMilliseconds: number;
73
88
  shutdownTimeoutMilliseconds: number;
89
+ readerCoordinationTimeoutMilliseconds?: number;
74
90
  runnerOptions: {
75
91
  rebuildBackoffMilliseconds: number;
76
92
  maxRebuildBackoffMilliseconds: number;
@@ -291,6 +307,7 @@ export function attachDerivedIndexes(
291
307
  const hnswRetryBackendIds: string[] = [];
292
308
  const registeredBackends = new Map<string, RegisteredBackend>();
293
309
  const fullTextSetups = new Map<string, Promise<void>>();
310
+ const fullTextQueryIndexes = new Map<string, FullTextQueryIndex>();
294
311
  let closing = false;
295
312
  let registrationReleased = false;
296
313
  let closeOperation: Promise<void> | undefined;
@@ -393,6 +410,23 @@ export function attachDerivedIndexes(
393
410
  );
394
411
  return;
395
412
  }
413
+ if (!fullTextQueryIndexes.has(definition.name)) {
414
+ const queryIndex = new FullTextQueryIndex({
415
+ Table,
416
+ definition,
417
+ auditStore,
418
+ readinessId,
419
+ indexId: id,
420
+ storePath: Table.primaryStore.rootStore.path,
421
+ storeName: `${Table.tableName}/${definition.name}`,
422
+ sourceGeneration: `${Table.tableId}:${generation}`,
423
+ limits: { ...FULL_TEXT_READER_LIMITS },
424
+ ...(fullTextTest ? { binding: fullTextTest.binding } : null),
425
+ });
426
+ fullTextQueryIndexes.set(definition.name, queryIndex);
427
+ Table.fullTextQueryIndexes[definition.name] = { customIndex: queryIndex };
428
+ Table.hasFullTextQueryIndexes = true;
429
+ }
396
430
 
397
431
  const { settlePredecessor, predecessorSettled } = beginBackendHandoff(registered, id);
398
432
  const quiescePredecessor = async () => {
@@ -431,6 +465,7 @@ export function attachDerivedIndexes(
431
465
  if (retryUnavailableReadiness) retryDerivedIndexUnavailable(auditStore, readinessId);
432
466
  const storage = fullTextStorageDefinition(definition);
433
467
  const storeName = `${Table.tableName}/${definition.name}`;
468
+ const nativePath = nativeFullTextIndexPath(Table.primaryStore.rootStore.path, storeName);
434
469
  const warningKey = `${Table.primaryStore.rootStore.path}:${storeName}`;
435
470
  if (!warnedAuditIndexes.has(warningKey)) {
436
471
  warnedAuditIndexes.add(warningKey);
@@ -443,12 +478,17 @@ export function attachDerivedIndexes(
443
478
  storePath: Table.primaryStore.rootStore.path,
444
479
  storeName,
445
480
  sourceGeneration: `${Table.tableId}:${generation}`,
446
- fields: storage.fields,
481
+ fields: definition.fields.map(({ name, weight }) => ({ name, weight })),
447
482
  analyzer: storage.analyzer,
448
483
  stopWords: storage.stopWords,
449
484
  positions: storage.positions,
450
485
  surfaceTerms: storage.surfaceTerms,
451
- limits: { ...FULL_TEXT_LIMITS },
486
+ synonyms: storage.synonyms,
487
+ limits: { ...FULL_TEXT_WRITER_LIMITS },
488
+ hasBlobSources: definition.fields.some(({ mediaType }) => mediaType === 'text/plain'),
489
+ beforeReset: (ownerEpoch) => coordinateFullTextQueryReaders(nativePath, readinessId, ownerEpoch, true),
490
+ afterReset: (ownerEpoch) => coordinateFullTextQueryReaders(nativePath, readinessId, ownerEpoch, false),
491
+ shutdownTimeoutMilliseconds: FULL_TEXT_RESET_TIMEOUT_MILLISECONDS,
452
492
  ...(fullTextTest
453
493
  ? {
454
494
  binding: fullTextTest.binding,
@@ -468,6 +508,11 @@ export function attachDerivedIndexes(
468
508
  ...fullTextTest?.runnerOptions,
469
509
  },
470
510
  });
511
+ fullTextQueryIndexes.get(definition.name)?.attachDerivedHost({
512
+ readiness: () => registered.runtime.getReadiness(id),
513
+ requestRebuild: () => registered.runtime.requestRebuild(id),
514
+ waitForCoverage: (since, timeout, signal) => registered.runtime.waitForCoverage(id, since, timeout, signal),
515
+ });
471
516
  })().catch((error) => {
472
517
  if (!isCurrent()) return;
473
518
  // Setup runs on every worker, but readiness is shared. A local setup failure must not
@@ -494,6 +539,11 @@ export function attachDerivedIndexes(
494
539
  const settlements = dropping
495
540
  ? [...(registered.tableBackends.get(Table.tableId) ?? [])].map((backend) => backend.settle())
496
541
  : releases.map((release) => release());
542
+ for (const queryIndex of fullTextQueryIndexes.values()) settlements.push(queryIndex.close());
543
+ for (const [name, queryIndex] of fullTextQueryIndexes) {
544
+ if (Table.fullTextQueryIndexes[name]?.customIndex === queryIndex) delete Table.fullTextQueryIndexes[name];
545
+ }
546
+ Table.hasFullTextQueryIndexes = Object.keys(Table.fullTextQueryIndexes).length > 0;
497
547
  const retained = new Set(
498
548
  ((Table.fullTextIndexes ?? []) as FullTextDefinition[]).map((definition) => definition.name)
499
549
  );
@@ -559,10 +609,14 @@ export function attachDerivedIndexes(
559
609
  matchesCurrent() {
560
610
  if (closing || fullTextRetirementRecoveryFailed || !matchesCurrentHnsw()) return false;
561
611
  const currentDefinitions = (Table.fullTextIndexes ?? []) as FullTextDefinition[];
562
- return (
563
- fullTextActivationSnapshot(Table, currentDefinitions) === fullTextSnapshot &&
564
- JSON.stringify(Table.fullTextIndexRetirements ?? []) === fullTextRetirementSnapshot
565
- );
612
+ if (
613
+ fullTextActivationSnapshot(Table, currentDefinitions) !== fullTextSnapshot ||
614
+ JSON.stringify(Table.fullTextIndexRetirements ?? []) !== fullTextRetirementSnapshot
615
+ )
616
+ return false;
617
+ for (const definition of currentDefinitions)
618
+ fullTextQueryIndexes.get(definition.name)?.updateDefinition(definition);
619
+ return true;
566
620
  },
567
621
  retryUnavailableFullText() {
568
622
  if (closing) return;
@@ -629,6 +683,40 @@ export function attachDerivedIndexes(
629
683
  }
630
684
  }
631
685
 
686
+ async function coordinateFullTextQueryReaders(
687
+ path: string,
688
+ readinessId: string,
689
+ ownerEpoch: bigint,
690
+ pause: boolean,
691
+ timeout = FULL_TEXT_READER_COORDINATION_TIMEOUT_MILLISECONDS,
692
+ allowUnregisteredReadiness = false
693
+ ): Promise<void> {
694
+ if (pause) {
695
+ const draining = pauseNativeFullTextQueryReaders(path, readinessId, ownerEpoch, allowUnregisteredReadiness);
696
+ await settleBeforeDeadline([draining], Date.now() + timeout, () =>
697
+ Object.assign(new Error('Full-text reader drain timed out'), {
698
+ code: 'E_FULL_TEXT_READER_COORDINATION_TIMEOUT',
699
+ retryable: true,
700
+ })
701
+ );
702
+ await draining;
703
+ } else resumeNativeFullTextQueryReaders(path, readinessId, ownerEpoch);
704
+ await sendItcEventStrict(
705
+ {
706
+ type: ITC_EVENT_TYPES.SCHEMA,
707
+ message: {
708
+ operation: pause ? FULL_TEXT_QUERY_PAUSE_OPERATION : FULL_TEXT_QUERY_RESUME_OPERATION,
709
+ path,
710
+ readinessId,
711
+ ownerEpoch: ownerEpoch.toString(),
712
+ allowUnregisteredReadiness,
713
+ },
714
+ },
715
+ timeout,
716
+ true
717
+ );
718
+ }
719
+
632
720
  /** Retire durable native indexes even when their in-memory attachment could not be restored. */
633
721
  export async function retireFullTextIndexes(
634
722
  Table: any,
@@ -638,20 +726,48 @@ export async function retireFullTextIndexes(
638
726
  const fullTextTest = fullTextTestConfiguration;
639
727
  const retryMilliseconds =
640
728
  fullTextTest?.shutdownTimeoutMilliseconds ?? DEFAULT_FULL_TEXT_RETIREMENT_RETRY_MILLISECONDS;
729
+ const coordinationTimeoutMilliseconds =
730
+ fullTextTest?.readerCoordinationTimeoutMilliseconds ?? FULL_TEXT_READER_COORDINATION_TIMEOUT_MILLISECONDS;
641
731
  const deadline = Date.now() + retryMilliseconds;
642
732
  let retired = true;
733
+ const rootStore = Table.primaryStore.rootStore;
643
734
  for (const definition of definitions) {
644
735
  if (!shouldContinue()) return false;
736
+ const indexId = fullTextDerivedIndexId(Table, definition.name);
737
+ const storeName = `${Table.tableName}/${definition.name}`;
738
+ const nativePath = nativeFullTextIndexPath(rootStore.path, storeName);
739
+ const lockKey = `derived-index:${indexId}:runner`;
740
+ const readinessId = `${indexId}:retirement:${randomUUID()}`;
645
741
  let retryDelayMilliseconds = 10;
646
742
  let retrying = false;
647
743
  for (;;) {
648
744
  try {
649
- await retireNativeFullTextDerivedIndexStorage({
650
- storePath: Table.primaryStore.rootStore.path,
651
- storeName: `${Table.tableName}/${definition.name}`,
652
- indexId: fullTextDerivedIndexId(Table, definition.name),
653
- ...(fullTextTest ? { binding: fullTextTest.binding } : {}),
654
- });
745
+ if (!rootStore.tryLock(lockKey))
746
+ throw Object.assign(new Error('Full-text runner still owns the index'), { code: 'E_LOCK_BUSY' });
747
+ try {
748
+ // Keep orphan-pause recovery and every writer fenced until peer readers have drained.
749
+ try {
750
+ await coordinateFullTextQueryReaders(
751
+ nativePath,
752
+ readinessId,
753
+ 0n,
754
+ true,
755
+ Math.max(1, Math.min(coordinationTimeoutMilliseconds, deadline - Date.now())),
756
+ true
757
+ );
758
+ if (!shouldContinue()) return false;
759
+ await retireNativeFullTextDerivedIndexStorage({
760
+ storePath: rootStore.path,
761
+ storeName,
762
+ indexId,
763
+ ...(fullTextTest ? { binding: fullTextTest.binding } : {}),
764
+ });
765
+ } finally {
766
+ await coordinateFullTextQueryReaders(nativePath, readinessId, 0n, false, coordinationTimeoutMilliseconds);
767
+ }
768
+ } finally {
769
+ rootStore.unlock(lockKey);
770
+ }
655
771
  break;
656
772
  } catch (error) {
657
773
  if (!shouldContinue()) return false;
@@ -659,8 +775,9 @@ export async function retireFullTextIndexes(
659
775
  error && typeof error === 'object' && 'code' in error && typeof error.code === 'string'
660
776
  ? error.code
661
777
  : undefined;
778
+ const retryable = error && typeof error === 'object' && 'retryable' in error && error.retryable === true;
662
779
  const remaining = deadline - Date.now();
663
- if (code === 'E_LOCK_BUSY' && remaining > 0) {
780
+ if ((code === 'E_LOCK_BUSY' || retryable) && remaining > 0) {
664
781
  if (!retrying) {
665
782
  retrying = true;
666
783
  fullTextLogger.warn?.(
@@ -802,8 +919,8 @@ export function assertFullTextActivationSupported(
802
919
 
803
920
  function fullTextProjection(definition: FullTextDefinition) {
804
921
  return (record: Record<string, unknown>) => {
805
- const projection: Record<string, string | string[]> = Object.create(null);
806
- for (const { name } of definition.fields) {
922
+ const projection: Record<string, string | string[] | Blob> = Object.create(null);
923
+ for (const { name, mediaType } of definition.fields) {
807
924
  const value = record[name];
808
925
  if (typeof value === 'string') {
809
926
  projection[name] = value;
@@ -819,6 +936,13 @@ function fullTextProjection(definition: FullTextDefinition) {
819
936
  projection[name] = copied;
820
937
  continue;
821
938
  }
939
+ if (mediaType === 'text/plain' && value instanceof Blob) {
940
+ const actualMediaType = value.type.split(';', 1)[0].trim().toLowerCase();
941
+ if (actualMediaType && actualMediaType !== mediaType)
942
+ throw new ClientError(`Full-text Blob source '${name}' must contain ${mediaType} data`, 400);
943
+ projection[name] = value;
944
+ continue;
945
+ }
822
946
  if (value != null) throw new ClientError(`Full-text source '${name}' contains a non-text value`, 400);
823
947
  }
824
948
  return projection;
@@ -10,11 +10,11 @@ const FULL_TEXT_ARGUMENTS = new Set([
10
10
  'synonyms',
11
11
  'highlighting',
12
12
  ]);
13
- const SOURCE_ARGUMENTS = new Set(['name', 'weight', 'highlight']);
13
+ const SOURCE_ARGUMENTS = new Set(['name', 'weight', 'highlight', 'mediaType']);
14
14
  const SYNONYM_ARGUMENTS = new Set(['source', 'replacements']);
15
15
  const HIGHLIGHTING_ARGUMENTS = new Set(['maxFragments', 'fragmentLength']);
16
16
 
17
- const DEFAULT_ANALYZER = 'english@1';
17
+ const DEFAULT_ANALYZER = 'english@2';
18
18
  const DEFAULT_MAX_FRAGMENTS = 3;
19
19
  const DEFAULT_FRAGMENT_LENGTH = 160;
20
20
 
@@ -22,6 +22,7 @@ export type FullTextSource = {
22
22
  name: string;
23
23
  weight: number;
24
24
  highlight?: boolean;
25
+ mediaType?: 'text/plain';
25
26
  };
26
27
 
27
28
  export type FullTextSynonymRule = {
@@ -37,7 +38,7 @@ export type FullTextHighlighting = {
37
38
  export type FullTextDefinition = {
38
39
  name: string;
39
40
  fields: FullTextSource[];
40
- analyzer: 'english@1';
41
+ analyzer: 'english@2';
41
42
  stopWords: boolean;
42
43
  positions: boolean;
43
44
  surfaceTerms: boolean;
@@ -47,9 +48,9 @@ export type FullTextDefinition = {
47
48
 
48
49
  export type FullTextStorageDefinition = Pick<
49
50
  FullTextDefinition,
50
- 'analyzer' | 'stopWords' | 'positions' | 'surfaceTerms'
51
+ 'analyzer' | 'stopWords' | 'positions' | 'surfaceTerms' | 'synonyms'
51
52
  > & {
52
- fields: Array<Pick<FullTextSource, 'name' | 'weight'>>;
53
+ fields: Array<Pick<FullTextSource, 'name' | 'mediaType'>>;
53
54
  };
54
55
 
55
56
  export type FullTextIndexGenerations = Record<string, string>;
@@ -68,11 +69,18 @@ export function persistedFullTextIndexNames(values: unknown): string[] {
68
69
 
69
70
  export function fullTextStorageDefinition(definition: FullTextDefinition): FullTextStorageDefinition {
70
71
  return {
71
- fields: definition.fields.map(({ name, weight }) => ({ name, weight })),
72
+ fields: definition.fields.map(({ name, mediaType }) => ({
73
+ name,
74
+ ...(mediaType ? { mediaType } : null),
75
+ })),
72
76
  analyzer: definition.analyzer,
73
77
  stopWords: definition.stopWords,
74
78
  positions: definition.positions,
75
79
  surfaceTerms: definition.surfaceTerms,
80
+ synonyms: (definition.synonyms ?? []).map(({ source, replacements }) => ({
81
+ source,
82
+ replacements: [...replacements],
83
+ })),
76
84
  };
77
85
  }
78
86
 
@@ -109,6 +117,29 @@ export type FullTextSchemaAttribute = {
109
117
  relationship?: unknown;
110
118
  };
111
119
 
120
+ export function compileFullTextFields(
121
+ values: unknown,
122
+ definitions: readonly Pick<FullTextDefinition, 'name'>[],
123
+ attributes: readonly FullTextSchemaAttribute[],
124
+ requireAll = false
125
+ ): string[] {
126
+ if (!Array.isArray(values)) throw schemaError('fullTextFields must be a list of index names');
127
+ const indexes = new Set(definitions.map(({ name }) => name));
128
+ const stored = new Set(attributes.map(({ name }) => name));
129
+ const names = new Set<string>();
130
+ for (const name of values) {
131
+ if (typeof name !== 'string' || name.length === 0)
132
+ throw schemaError('fullTextFields must contain non-empty index names');
133
+ if (names.has(name)) throw schemaError(`Full-text field "${name}" is declared more than once`);
134
+ if (!indexes.has(name)) throw schemaError(`Full-text field "${name}" requires a declared @fullText index`);
135
+ if (stored.has(name)) throw schemaError(`Full-text field "${name}" conflicts with a stored attribute`);
136
+ names.add(name);
137
+ }
138
+ if (requireAll && names.size !== indexes.size)
139
+ throw schemaError('fullTextFields must include every declared @fullText index');
140
+ return [...names].sort();
141
+ }
142
+
112
143
  export function compileFullTextDefinitions(
113
144
  values: readonly unknown[],
114
145
  attributes: readonly FullTextSchemaAttribute[]
@@ -163,10 +194,11 @@ export function compileFullTextDefinition(
163
194
  if (typeof definition.name !== 'string' || definition.name.length === 0)
164
195
  throw schemaError('@fullText requires a non-empty string "name"');
165
196
  const indexName = definition.name;
166
-
167
197
  if (!Array.isArray(definition.fields) || definition.fields.length === 0)
168
198
  throw schemaError(`@fullText index "${indexName}" requires a non-empty "fields" list`);
169
199
  const attributesByName = new Map(attributes.map((attribute) => [attribute.name, attribute]));
200
+ if (attributesByName.has(indexName))
201
+ throw schemaError(`Full-text field "${indexName}" conflicts with a stored attribute`);
170
202
  const sourceNames = new Set<string>();
171
203
  const fields = definition.fields.map((entry, index) => {
172
204
  const source = requireObject(entry, `@fullText fields[${index}] on index "${indexName}"`);
@@ -184,8 +216,12 @@ export function compileFullTextDefinition(
184
216
  );
185
217
  if (!isSupportedSource(attribute))
186
218
  throw schemaError(
187
- `@fullText source field "${source.name}" must be String or [String]; got "${displayType(attribute)}"`
219
+ `@fullText source field "${source.name}" must be String, [String], or a declared text/plain Blob; got "${displayType(attribute)}"`
188
220
  );
221
+ if (attribute.type === 'Blob' && source.mediaType !== 'text/plain')
222
+ throw schemaError(`@fullText Blob source field "${source.name}" requires mediaType: "text/plain"`);
223
+ if (attribute.type !== 'Blob' && source.mediaType !== undefined)
224
+ throw schemaError(`@fullText source field "${source.name}" only accepts mediaType for Blob attributes`);
189
225
  const weight = source.weight === undefined ? 1 : source.weight;
190
226
  if (typeof weight !== 'number' || !Number.isFinite(weight) || weight <= 0)
191
227
  throw schemaError(`@fullText source field "${source.name}" requires a finite weight greater than zero`);
@@ -196,6 +232,7 @@ export function compileFullTextDefinition(
196
232
  name: source.name,
197
233
  weight,
198
234
  ...(typeof source.highlight === 'boolean' ? { highlight: source.highlight } : {}),
235
+ ...(source.mediaType === 'text/plain' ? { mediaType: 'text/plain' as const } : {}),
199
236
  };
200
237
  });
201
238
 
@@ -207,6 +244,11 @@ export function compileFullTextDefinition(
207
244
  const surfaceTerms = booleanOption(definition, 'surfaceTerms', true, indexName);
208
245
  const synonyms = compileSynonyms(definition.synonyms, indexName);
209
246
  const highlighting = compileHighlighting(definition.highlighting, indexName);
247
+ const highlightedFields = fields.filter(({ highlight }) => highlight === true);
248
+ if (highlighting && highlightedFields.length === 0)
249
+ throw schemaError(`@fullText index "${indexName}" requires at least one source field with highlight: true`);
250
+ if (highlighting && !surfaceTerms)
251
+ throw schemaError(`@fullText index "${indexName}" highlighting requires surfaceTerms: true`);
210
252
 
211
253
  return {
212
254
  name: indexName,
@@ -274,7 +316,11 @@ function booleanOption(
274
316
  }
275
317
 
276
318
  function isSupportedSource(attribute: FullTextSchemaAttribute): boolean {
277
- return attribute.type === 'String' || (attribute.type === 'array' && attribute.elements?.type === 'String');
319
+ return (
320
+ attribute.type === 'String' ||
321
+ attribute.type === 'Blob' ||
322
+ (attribute.type === 'array' && attribute.elements?.type === 'String')
323
+ );
278
324
  }
279
325
 
280
326
  function displayType(attribute: FullTextSchemaAttribute): string {