@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.
- package/bin/backup.ts +6 -1
- package/components/Application.ts +486 -115
- package/components/DESIGN.md +109 -21
- package/components/deploymentProvenance.ts +28 -0
- package/components/operations.js +14 -7
- package/components/packageComponent.ts +5 -1
- package/config-root.schema.json +1 -1
- package/dataLayer/DESIGN.md +35 -7
- package/dataLayer/blobBackup.ts +71 -30
- package/dataLayer/harperBridge/ResourceBridge.ts +16 -2
- package/dataLayer/rocksdbBackup.ts +88 -34
- package/dataLayer/schemaDescribe.ts +45 -1
- package/dist/bin/backup.js +1 -1
- package/dist/bin/backup.js.map +1 -1
- package/dist/components/Application.d.ts +11 -21
- package/dist/components/Application.js +436 -105
- package/dist/components/Application.js.map +1 -1
- package/dist/components/deploymentProvenance.d.ts +4 -0
- package/dist/components/deploymentProvenance.js +32 -0
- package/dist/components/deploymentProvenance.js.map +1 -0
- package/dist/components/operations.js +14 -7
- package/dist/components/operations.js.map +1 -1
- package/dist/components/packageComponent.js +6 -1
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/dataLayer/blobBackup.d.ts +30 -3
- package/dist/dataLayer/blobBackup.js +73 -36
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +1 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.js +15 -3
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +4 -1
- package/dist/dataLayer/rocksdbBackup.js +74 -36
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +45 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +1 -0
- package/dist/resources/DatabaseTransaction.js +33 -8
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +7 -3
- package/dist/resources/ResourceInterface.js +2 -0
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/Table.d.ts +151 -445
- package/dist/resources/Table.js +209 -8
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.d.ts +11 -0
- package/dist/resources/analytics/write.js +3 -0
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/blob.d.ts +30 -0
- package/dist/resources/blob.js +189 -1
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/databases.d.ts +1 -0
- package/dist/resources/databases.js +80 -15
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/derivedIndexRuntime.d.ts +13 -0
- package/dist/resources/derivedIndexRuntime.js +57 -5
- package/dist/resources/derivedIndexRuntime.js.map +1 -1
- package/dist/resources/derivedIndexes.d.ts +1 -0
- package/dist/resources/derivedIndexes.js +116 -15
- package/dist/resources/derivedIndexes.js.map +1 -1
- package/dist/resources/fullTextSchema.d.ts +5 -3
- package/dist/resources/fullTextSchema.js +48 -5
- package/dist/resources/fullTextSchema.js.map +1 -1
- package/dist/resources/fullTextSchemaLifecycle.d.ts +2 -0
- package/dist/resources/fullTextSchemaLifecycle.js +33 -0
- package/dist/resources/fullTextSchemaLifecycle.js.map +1 -1
- package/dist/resources/graphql.js +30 -12
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +21 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +114 -5
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/fullTextDerivedIndex.d.ts +11 -2
- package/dist/resources/indexes/fullTextDerivedIndex.js +187 -24
- package/dist/resources/indexes/fullTextDerivedIndex.js.map +1 -1
- package/dist/resources/indexes/fullTextNativeBinding.d.ts +99 -1
- package/dist/resources/indexes/fullTextNativeBinding.js +35 -1
- package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -1
- package/dist/resources/indexes/fullTextQueryIndex.d.ts +58 -0
- package/dist/resources/indexes/fullTextQueryIndex.js +943 -0
- package/dist/resources/indexes/fullTextQueryIndex.js.map +1 -0
- package/dist/resources/indexes/fullTextQueryProtocol.d.ts +6 -0
- package/dist/resources/indexes/fullTextQueryProtocol.js +32 -0
- package/dist/resources/indexes/fullTextQueryProtocol.js.map +1 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +4 -1
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +30 -7
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -1
- package/dist/resources/search.d.ts +41 -0
- package/dist/resources/search.js +468 -26
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transactionBroadcast.js +101 -50
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/resources/typeParity.d.ts +9 -0
- package/dist/resources/typeParity.js +3 -0
- package/dist/resources/typeParity.js.map +1 -0
- package/dist/server/REST.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +48 -8
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +7 -0
- package/dist/server/serverHelpers/contentTypes.js +36 -23
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/uwsServer.js +28 -5
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/threads/itc.js +19 -0
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +3 -0
- package/dist/server/threads/manageThreads.js +90 -23
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/utility/operation_authorization.js +25 -7
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/signalling.js +3 -0
- package/dist/utility/signalling.js.map +1 -1
- package/dist/validation/searchValidator.js +22 -2
- package/dist/validation/searchValidator.js.map +1 -1
- package/npm-shrinkwrap.json +22 -22
- package/package.json +2 -4
- package/resources/DESIGN.md +19 -2
- package/resources/DatabaseTransaction.ts +40 -10
- package/resources/FULL_TEXT.md +97 -0
- package/resources/ResourceInterface.ts +8 -2
- package/resources/Table.ts +767 -17
- package/resources/analytics/write.ts +3 -3
- package/resources/blob.ts +183 -1
- package/resources/databases.ts +126 -14
- package/resources/derivedIndexRuntime.ts +79 -6
- package/resources/derivedIndexes.ts +142 -18
- package/resources/fullTextSchema.ts +55 -9
- package/resources/fullTextSchemaLifecycle.ts +45 -0
- package/resources/graphql.ts +33 -12
- package/resources/indexes/DESIGN.md +167 -15
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +125 -5
- package/resources/indexes/fullTextDerivedIndex.ts +216 -32
- package/resources/indexes/fullTextNativeBinding.ts +133 -3
- package/resources/indexes/fullTextQueryIndex.ts +1120 -0
- package/resources/indexes/fullTextQueryProtocol.ts +35 -0
- package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +28 -8
- package/resources/search.ts +513 -26
- package/resources/transactionBroadcast.ts +86 -47
- package/resources/typeParity.ts +20 -0
- package/schema.graphql +18 -5
- package/server/DESIGN.md +18 -0
- package/server/REST.ts +1 -1
- package/server/itc/serverHandlers.js +61 -8
- package/server/serverHelpers/contentTypes.ts +31 -26
- package/server/serverHelpers/uwsServer.ts +35 -7
- package/server/threads/itc.js +21 -0
- package/server/threads/manageThreads.js +95 -21
- package/studio/web/assets/{Chat-Bq60AO-g.js → Chat-CNEKMllJ.js} +13 -13
- package/studio/web/assets/FloatingChat-CEnWhHeR.js +23 -0
- package/studio/web/assets/SearchDialog-CwhJdEdY.js +1 -0
- package/studio/web/assets/{abnfDiagram-O67JEVCF-DpPZWMOf.js → abnfDiagram-O67JEVCF-raXE027J.js} +1 -1
- package/studio/web/assets/alertDialog-BbWD9Xxa.js +1 -0
- package/studio/web/assets/apiToken-DC5vsaaO.js +1 -0
- package/studio/web/assets/applications-DQZxDy0x.js +296 -0
- package/studio/web/assets/architecture-7GRP2DOG-DDmz3hpI.js +1 -0
- package/studio/web/assets/{architectureDiagram-NJMV4G6O-OmgLraID.js → architectureDiagram-NJMV4G6O-C8_Eet7w.js} +1 -1
- package/studio/web/assets/arrow-up-D2g_57vT.js +1 -0
- package/studio/web/assets/authStore-CJCaADw9.js +3 -0
- package/studio/web/assets/{blockDiagram-BEXU5L5S-Cv7CD3Ai.js → blockDiagram-BEXU5L5S-DR6S5-1D.js} +1 -1
- package/studio/web/assets/{button-MFP9n8Ck.js → button-DWwfgGWI.js} +2 -2
- package/studio/web/assets/{c4Diagram-YGBWAQC7-Ds1vKYnN.js → c4Diagram-YGBWAQC7-BAfZ1G01.js} +1 -1
- package/studio/web/assets/channel-D0AkPjJ8.js +1 -0
- package/studio/web/assets/{chevron-up-CFe8x5Bp.js → chevron-up-CFxbMGv2.js} +1 -1
- package/studio/web/assets/{chunk-3FUC2YCW-DpnBPH8B.js → chunk-3FUC2YCW-DuRp-j19.js} +1 -1
- package/studio/web/assets/{chunk-5DYCD2WN-LLLCQSzg.js → chunk-5DYCD2WN-BceBfIHT.js} +1 -1
- package/studio/web/assets/{chunk-742MDFTN-BL8J_pIO.js → chunk-742MDFTN-CIkt8ijt.js} +1 -1
- package/studio/web/assets/{chunk-7INBJB4K-C-hJHiiK.js → chunk-7INBJB4K-BpeAXyOi.js} +1 -1
- package/studio/web/assets/{chunk-7M6MHVWA-C6ZqkFbA.js → chunk-7M6MHVWA-h6WlaTzO.js} +1 -1
- package/studio/web/assets/{chunk-7PRAP22T-CUXM8BG6.js → chunk-7PRAP22T-KyqX6x3f.js} +1 -1
- package/studio/web/assets/{chunk-GTNCS2PH-DJ2BFvS1.js → chunk-GTNCS2PH-DGHLXyow.js} +1 -1
- package/studio/web/assets/{chunk-GWA4HPMP-C42bSqLL.js → chunk-GWA4HPMP-DsejB6gA.js} +1 -1
- package/studio/web/assets/{chunk-MBY4JIJT-C-5jz6Lo.js → chunk-MBY4JIJT-BwSGweQP.js} +1 -1
- package/studio/web/assets/{chunk-NETBCI7D-D-bzlN4r.js → chunk-NETBCI7D-C8UnOw_f.js} +1 -1
- package/studio/web/assets/{chunk-O7XYJQB3-ep14zA23.js → chunk-O7XYJQB3-CBS3nZYV.js} +1 -1
- package/studio/web/assets/{chunk-UA2S7LBM-BMRWRHED.js → chunk-UA2S7LBM-BHpEdH8D.js} +1 -1
- package/studio/web/assets/{chunk-WEXAMYUT-DdLYVdX1.js → chunk-WEXAMYUT-BAIhTwyh.js} +1 -1
- package/studio/web/assets/{chunk-Z7XXMR3K-BmKEDjcP.js → chunk-Z7XXMR3K-DSHbImdf.js} +1 -1
- package/studio/web/assets/{chunk-ZIGJFQKS-DLZgdNxA.js → chunk-ZIGJFQKS-Cs8fUn7y.js} +1 -1
- package/studio/web/assets/{classDiagram-v2-NBCMYWYE-DOI5vgKT.js → classDiagram-v2-NBCMYWYE-DmDPkt2u.js} +1 -1
- package/studio/web/assets/cn-6T8VranJ.js +1 -0
- package/studio/web/assets/{codicon-Brq4_Ui5.ttf → codicon-DF1abBS2.ttf} +0 -0
- package/studio/web/assets/{createLucideIcon-bziYxJli.js → createLucideIcon-fO5dL7D5.js} +1 -1
- package/studio/web/assets/{css.worker-l1psR_wG.js → css.worker-DoT-OOzx.js} +36 -36
- package/studio/web/assets/{cssMode-DJyc9mHj.js → cssMode-Dz2DxF4e.js} +1 -1
- package/studio/web/assets/{cynefin-OW5HDTMX-BSW-DB7S.js → cynefin-OW5HDTMX-DIvbXLSj.js} +1 -1
- package/studio/web/assets/{cynefinDiagram-VND7K2PF-CbAHEwxt.js → cynefinDiagram-VND7K2PF-BdtaXiCE.js} +1 -1
- package/studio/web/assets/{dagre-6A5THRUB-Csxewgs4.js → dagre-6A5THRUB-C7RUWHyz.js} +1 -1
- package/studio/web/assets/{diagram-22UHCM2B-a0rt8tY4.js → diagram-22UHCM2B-DJCvcaWP.js} +1 -1
- package/studio/web/assets/{diagram-3UASUU5V-lEj2SVNh.js → diagram-3UASUU5V-Du6VKWln.js} +1 -1
- package/studio/web/assets/{diagram-ATOU4E4O-HcrAeB-q.js → diagram-ATOU4E4O-dxRfeG4B.js} +1 -1
- package/studio/web/assets/{diagram-CDSNMT55-CYxiuyEx.js → diagram-CDSNMT55-l5Ga0u-W.js} +1 -1
- package/studio/web/assets/{diagram-MLGK6HIB-ChbCJTgJ.js → diagram-MLGK6HIB-CNQY47LA.js} +1 -1
- package/studio/web/assets/{diagram-MPIPVDR6-DaX9Y-N3.js → diagram-MPIPVDR6-7prveD1B.js} +1 -1
- package/studio/web/assets/{dist-Cz2Y6-6G.js → dist-BrRuMUzt.js} +1 -1
- package/studio/web/assets/{download-CtostjYn.js → download-Cn6tPG4L.js} +1 -1
- package/studio/web/assets/{ebnfDiagram-ZINNZB2B-CwAsENB1.js → ebnfDiagram-ZINNZB2B-5OnkTpfi.js} +1 -1
- package/studio/web/assets/{editor-DDIsQfj6.js → editor-B3mjd3tz.js} +1 -1
- package/studio/web/assets/editor.worker-Yd1NR0QT.js +33 -0
- package/studio/web/assets/{elk-276RUBZZ-Hexg9E4D.js → elk-276RUBZZ-DxDQPjQT.js} +1 -1
- package/studio/web/assets/{erDiagram-OPXOYQCR-CeC-wwO1.js → erDiagram-OPXOYQCR-CQlCX84D.js} +1 -1
- package/studio/web/assets/eventmodeling-NTZA5JFV-DONQf5aG.js +1 -0
- package/studio/web/assets/flowDiagram-KWPJA3E3-BoZ8_QR1.js +1 -0
- package/studio/web/assets/{ganttDiagram-FUAMR5RP-C2_Hhl1-.js → ganttDiagram-FUAMR5RP-bloX3Voy.js} +1 -1
- package/studio/web/assets/{getAnalytics-CjthMQqF.js → getAnalytics-C0FHjtdQ.js} +1 -1
- package/studio/web/assets/{gitGraph-4MIJSDKK-xIk5Vuew.js → gitGraph-4MIJSDKK-BrXWmJt2.js} +1 -1
- package/studio/web/assets/{gitGraphDiagram-X574FWY7-CMxJ34up.js → gitGraphDiagram-X574FWY7-C2KnnZeY.js} +1 -1
- package/studio/web/assets/{html-g1BJHxLy.js → html-BsRGM7tp.js} +1 -1
- package/studio/web/assets/{html.worker-DdwM4IrA.js → html.worker-B1dwY0Ay.js} +27 -27
- package/studio/web/assets/{htmlMode-Vh5IglCQ.js → htmlMode-tUKJaA3o.js} +1 -1
- package/studio/web/assets/index-72cEH474.css +1 -0
- package/studio/web/assets/index-BuqFjN5K.js +828 -0
- package/studio/web/assets/index.lazy-CcpfQFY_.js +2 -0
- package/studio/web/assets/{info-A6RAGUB7-o49TEbj-.js → info-A6RAGUB7-BhzBHe4U.js} +1 -1
- package/studio/web/assets/{infoDiagram-VRGFBTTK-Cjhh7yzZ.js → infoDiagram-VRGFBTTK-B0J1132p.js} +1 -1
- package/studio/web/assets/{ishikawaDiagram-OU5B5YK6-C63aXRmh.js → ishikawaDiagram-OU5B5YK6-BNk0tuQx.js} +1 -1
- package/studio/web/assets/{javascript-5VIolqf7.js → javascript-BZ_uRGHl.js} +1 -1
- package/studio/web/assets/{journeyDiagram-ZHPQQLJL-D_o0P5Mu.js → journeyDiagram-ZHPQQLJL-Be79RMQM.js} +1 -1
- package/studio/web/assets/json.worker-BQqXGI3X.js +65 -0
- package/studio/web/assets/{jsonMode-DG4zQraI.js → jsonMode-DgB-aFMj.js} +1 -1
- package/studio/web/assets/{kanban-definition-PNTS6WVX-CTI9SSxY.js → kanban-definition-PNTS6WVX-4uuoQP9W.js} +1 -1
- package/studio/web/assets/{languageServices-t5FBpX-i.js → languageServices-BleuBw17.js} +1 -1
- package/studio/web/assets/localStorageKeys-etzFY_xV.js +1 -0
- package/studio/web/assets/{lspLanguageFeatures-DgVnNPh-.js → lspLanguageFeatures-ByVYLSsQ.js} +1 -1
- package/studio/web/assets/{mermaid-parser.core-C2lcH_jP.js → mermaid-parser.core-V1UYMeXV.js} +3 -3
- package/studio/web/assets/{mermaid.core-BG5bjfIG.js → mermaid.core-1PX6R49U.js} +4 -4
- package/studio/web/assets/{mindmap-definition-NLK3R4M7-BK7ho6JD.js → mindmap-definition-NLK3R4M7-C70Ctm0J.js} +1 -1
- package/studio/web/assets/notifications-D1Nf-Edn.js +1 -0
- package/studio/web/assets/notifications-TuzN0IMi.js +1 -0
- package/studio/web/assets/{packet-AYTQ26CC-BHPy6KBV.js → packet-AYTQ26CC-DWbXHx5g.js} +1 -1
- package/studio/web/assets/{pegDiagram-GJSIUBJH-DzjwG3jO.js → pegDiagram-GJSIUBJH-d6z1cc7W.js} +1 -1
- package/studio/web/assets/{pie-WAS4IAKB-D0cP-DTU.js → pie-WAS4IAKB-DjoTm3yr.js} +1 -1
- package/studio/web/assets/{pieDiagram-5QR66LMP-C_hOP9Lv.js → pieDiagram-5QR66LMP-Dz3RHpDA.js} +1 -1
- package/studio/web/assets/profile-D7C7Lupz.js +1 -0
- package/studio/web/assets/{quadrantDiagram-O4NWA36T-CZW8PbV1.js → quadrantDiagram-O4NWA36T-CIF5Qkou.js} +1 -1
- package/studio/web/assets/{radar-RG4KPBEZ-C8fk0U81.js → radar-RG4KPBEZ-CVBgjCOj.js} +1 -1
- package/studio/web/assets/{railroad-74A4TZTK-B60FWm17.js → railroad-74A4TZTK-BdhXw10Q.js} +1 -1
- package/studio/web/assets/railroad-abnf-HS5TGJTU-BcoQPN39.js +1 -0
- package/studio/web/assets/railroad-ebnf-LZEXJU2U-B1Lke2JN.js +1 -0
- package/studio/web/assets/railroad-peg-WCYAUIDC-D-oJFkiV.js +1 -0
- package/studio/web/assets/{railroadDiagram-XR7U4H2S-DyyNmgbU.js → railroadDiagram-XR7U4H2S-y3Jv2U6N.js} +1 -1
- package/studio/web/assets/regions-nGQCm-v8.js +1 -0
- package/studio/web/assets/register-C3x9Ze6P.js +909 -0
- package/studio/web/assets/register-DjpsE8to.css +1 -0
- package/studio/web/assets/{requirementDiagram-PLB6GJNP-C4H-mLKu.js → requirementDiagram-PLB6GJNP-ChINZEmu.js} +1 -1
- package/studio/web/assets/restartGate-nHAFLDh-.js +1 -0
- package/studio/web/assets/{sankeyDiagram-IPEJSGJF-DHDyga4c.js → sankeyDiagram-IPEJSGJF-D9AyLce2.js} +1 -1
- package/studio/web/assets/{sequenceDiagram-PO4LG4MO-CdNcHXRI.js → sequenceDiagram-PO4LG4MO-hfk4aIEm.js} +1 -1
- package/studio/web/assets/{setComponentFile-z4-qJCbA.js → setComponentFile-DpjrRqeG.js} +1 -1
- package/studio/web/assets/{setup-CS50uJ4x.js → setup-CGiKLZ9e.js} +2 -2
- package/studio/web/assets/{stateDiagram-v2-GCMORJYK-CpKuXq15.js → stateDiagram-v2-GCMORJYK-Bs8RIb9K.js} +1 -1
- package/studio/web/assets/status-CGJwrNPH.js +61 -0
- package/studio/web/assets/{swimlanes-2SLR337P-NRHa2D8I.js → swimlanes-2SLR337P-B52xrf6t.js} +1 -1
- package/studio/web/assets/swimlanesDiagram-TC7HE7FX-DfN7BAP5.js +8 -0
- package/studio/web/assets/tabs-BCTQzoQK.js +1 -0
- package/studio/web/assets/{timeline-definition-EJHVYXUP-D39Y-xpq.js → timeline-definition-EJHVYXUP-DJSITpQX.js} +1 -1
- package/studio/web/assets/toggleHighContrast-C-Ne6P7T.js +51 -0
- package/studio/web/assets/toggleHighContrast-n7clI0si.css +1 -0
- package/studio/web/assets/{treeView-Q6P3EWNA-CRWR9OqD.js → treeView-Q6P3EWNA-C-epdxRo.js} +1 -1
- package/studio/web/assets/{treemap-WGGIJYW6-ZfXyJgLO.js → treemap-WGGIJYW6-DOVyp_zw.js} +1 -1
- package/studio/web/assets/{ts.worker-DDMUrpqh.js → ts.worker-Clm12uY6.js} +131 -131
- package/studio/web/assets/{tsMode-D83Gg3cq.js → tsMode-CSreYTys.js} +1 -1
- package/studio/web/assets/{typescript-Dfp-GrNq.js → typescript-MnxBk89W.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-BKetlINf.js → useEntityRestURL-TNrh77-s.js} +1 -1
- package/studio/web/assets/{usecaseDiagram-POWQR4AR-jf-zIDZ_.js → usecaseDiagram-POWQR4AR-B6252cbq.js} +1 -1
- package/studio/web/assets/{vendor-core-BdkdbUek.js → vendor-core-6LhfJlRC.js} +1 -1
- package/studio/web/assets/vendor-datadog-ozKf-pts.js +6 -0
- package/studio/web/assets/{vendor-react-izWchTRL.js → vendor-react-BOliS0BL.js} +1 -1
- package/studio/web/assets/vendor-tanstack-Bntfka-M.js +2 -0
- package/studio/web/assets/vendor-ui-9EYYDgoN.js +41 -0
- package/studio/web/assets/{vennDiagram-UO4OBE2U-BKYAZUh_.js → vennDiagram-UO4OBE2U-DZTsDA4k.js} +1 -1
- package/studio/web/assets/{wardley-WFR3VGLG-BO7f36ci.js → wardley-WFR3VGLG-Cfqoe6z4.js} +1 -1
- package/studio/web/assets/{wardleyDiagram-VNRHLVJA-Djb0JDQc.js → wardleyDiagram-VNRHLVJA-qu_f7Tvl.js} +1 -1
- package/studio/web/assets/{workers-CCvmDLH3.js → workers-BfZlUNVI.js} +3 -3
- package/studio/web/assets/{xml-06pZp00U.js → xml-BHd6qGH7.js} +1 -1
- package/studio/web/assets/{xychartDiagram-PMCCYNJV-BQh9ubvb.js → xychartDiagram-PMCCYNJV-UrOKRsmR.js} +1 -1
- package/studio/web/assets/{yaml-iSnWMVlV.js → yaml-C53R8OQq.js} +1 -1
- package/studio/web/assets/{yaml.worker-DAK2o_H1.js → yaml.worker-D9JekGdp.js} +183 -183
- package/studio/web/index.html +15 -15
- package/utility/operation_authorization.ts +27 -7
- package/utility/signalling.ts +3 -0
- package/validation/searchValidator.ts +22 -13
- package/studio/web/assets/FloatingChat-D4560T0p.js +0 -23
- package/studio/web/assets/alertDialog-UrbiMgQt.js +0 -1
- package/studio/web/assets/apiToken-BEvbFPMc.js +0 -1
- package/studio/web/assets/applications-CSUVTH4E.js +0 -296
- package/studio/web/assets/architecture-7GRP2DOG-11l4Ny1l.js +0 -1
- package/studio/web/assets/authStore-5jSS5pTW.js +0 -3
- package/studio/web/assets/channel-BDtouPd6.js +0 -1
- package/studio/web/assets/dialog-DTepachC.js +0 -1
- package/studio/web/assets/editor.worker-CkkvdXvO.js +0 -33
- package/studio/web/assets/eventmodeling-NTZA5JFV-CFb03e0o.js +0 -1
- package/studio/web/assets/flowDiagram-KWPJA3E3-Cidi00_Y.js +0 -1
- package/studio/web/assets/index-CPoDzQTe.css +0 -1
- package/studio/web/assets/index-DGRAzvO4.js +0 -824
- package/studio/web/assets/index.lazy-vgSic7et.js +0 -2
- package/studio/web/assets/json.worker-CSi2hF-a.js +0 -65
- package/studio/web/assets/notifications-BeWcX04m.js +0 -1
- package/studio/web/assets/notifications-DUGWrWoO.js +0 -1
- package/studio/web/assets/profile-BvUEDBzW.js +0 -1
- package/studio/web/assets/railroad-abnf-HS5TGJTU-CLMVZvH0.js +0 -1
- package/studio/web/assets/railroad-ebnf-LZEXJU2U--tlwFoVB.js +0 -1
- package/studio/web/assets/railroad-peg-WCYAUIDC-Dpuslblm.js +0 -1
- package/studio/web/assets/regions-CB-_2m7M.js +0 -1
- package/studio/web/assets/register-1w1Zr3b2.js +0 -848
- package/studio/web/assets/register-jjEx9u7D.css +0 -1
- package/studio/web/assets/setLocalStorage-D_kflv4U.js +0 -1
- package/studio/web/assets/status-CI0wOdOE.js +0 -61
- package/studio/web/assets/swimlanesDiagram-TC7HE7FX-BBk4t4hO.js +0 -8
- package/studio/web/assets/tabs-CnQ_zenf.js +0 -1
- package/studio/web/assets/toggleHighContrast--ixms01u.css +0 -1
- package/studio/web/assets/toggleHighContrast-BsAE4jPe.js +0 -49
- package/studio/web/assets/useLocalStorage-BYoZF60G.js +0 -1
- package/studio/web/assets/vendor-datadog-fCQhBHGk.js +0 -6
- package/studio/web/assets/vendor-tanstack-CQ1aRjVa.js +0 -2
- package/studio/web/assets/vendor-ui-aE1tHcW7.js +0 -41
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
37
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
563
|
-
fullTextActivationSnapshot(Table, currentDefinitions)
|
|
564
|
-
JSON.stringify(Table.fullTextIndexRetirements ?? [])
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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@
|
|
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@
|
|
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' | '
|
|
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,
|
|
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
|
|
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
|
|
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 {
|