@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
|
@@ -18,6 +18,7 @@ import { toBufferKey } from 'ordered-binary';
|
|
|
18
18
|
import { loggerWithTag } from '../../utility/logging/logger.ts';
|
|
19
19
|
|
|
20
20
|
const logger = loggerWithTag('fulltext-derived-index');
|
|
21
|
+
const UTF8_DECODER = new TextDecoder('utf-8', { fatal: true });
|
|
21
22
|
|
|
22
23
|
const DEFAULT_MAX_QUEUED_BATCHES = 16;
|
|
23
24
|
export const HARPER_FULLTEXT_DEFAULT_MAX_QUEUED_BYTES = 64 * 1024 * 1024;
|
|
@@ -27,7 +28,9 @@ const DEFAULT_OPEN_RETRY_MILLISECONDS = 10;
|
|
|
27
28
|
const DEFAULT_MAX_OPEN_RETRY_MILLISECONDS = 5_000;
|
|
28
29
|
const DEFAULT_CLOSE_TIMEOUT_MILLISECONDS = 35_000;
|
|
29
30
|
const DEFAULT_MAX_APPLY_SLICE_RECORDS = 256;
|
|
31
|
+
const DEFAULT_BLOB_READ_TIMEOUT_MILLISECONDS = 5_000;
|
|
30
32
|
const APPLY_SLICE_MILLISECONDS = 5;
|
|
33
|
+
const MAX_FULL_TEXT_VALUE_BYTES = 1 << 20;
|
|
31
34
|
const TERMINAL_OPEN_ERROR_CODES = new Set([
|
|
32
35
|
'E_IDENTITY_MISMATCH',
|
|
33
36
|
'E_INCOMPLETE_CREATE',
|
|
@@ -61,11 +64,11 @@ export type FullTextDerivedIndexInspection =
|
|
|
61
64
|
export interface FullTextDerivedIndexLifecycle {
|
|
62
65
|
inspect(): FullTextDerivedIndexInspection;
|
|
63
66
|
open(): Promise<FullTextDerivedIndexEngine>;
|
|
64
|
-
reset(): Promise<void>;
|
|
67
|
+
reset(ownerEpoch: bigint): Promise<void>;
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
export type FullTextMutationBatch = {
|
|
68
|
-
upserts: Array<{ id: string; fields: Record<string, string | string[]> }>;
|
|
71
|
+
upserts: Array<{ id: string; version?: string; fields: Record<string, string | string[]> }>;
|
|
69
72
|
deletes: string[];
|
|
70
73
|
};
|
|
71
74
|
|
|
@@ -81,6 +84,12 @@ export type FullTextDerivedIndexBackendOptions = {
|
|
|
81
84
|
maxOpenRetryMilliseconds?: number;
|
|
82
85
|
closeTimeoutMilliseconds?: number;
|
|
83
86
|
shutdownTimeoutMilliseconds?: number;
|
|
87
|
+
blobReadTimeoutMilliseconds?: number;
|
|
88
|
+
hasBlobSources?: boolean;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type FullTextPublication = {
|
|
92
|
+
cursor?: DerivedIndexCursor;
|
|
84
93
|
};
|
|
85
94
|
|
|
86
95
|
type ApplyCommand = {
|
|
@@ -97,6 +106,7 @@ type BarrierCommand = {
|
|
|
97
106
|
epoch: bigint;
|
|
98
107
|
horizon: number;
|
|
99
108
|
cursor?: DerivedIndexCursor;
|
|
109
|
+
coverageOnly?: true;
|
|
100
110
|
};
|
|
101
111
|
|
|
102
112
|
type Command = ApplyCommand | BarrierCommand;
|
|
@@ -123,6 +133,7 @@ class FullTextDerivedIndexConfigurationError extends FullTextDerivedIndexError {
|
|
|
123
133
|
|
|
124
134
|
export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
125
135
|
readonly id: string;
|
|
136
|
+
readonly publishesQueryRevisions = true;
|
|
126
137
|
#lifecycle: FullTextDerivedIndexLifecycle;
|
|
127
138
|
#maxQueuedBatches: number;
|
|
128
139
|
#maxQueuedBytes: number;
|
|
@@ -133,6 +144,9 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
133
144
|
#maxOpenRetryMilliseconds: number;
|
|
134
145
|
#closeTimeoutMilliseconds: number;
|
|
135
146
|
#shutdownTimeoutMilliseconds: number;
|
|
147
|
+
#blobReadTimeoutMilliseconds: number;
|
|
148
|
+
#maxBlobApplySliceMilliseconds: number;
|
|
149
|
+
#hasBlobSources: boolean;
|
|
136
150
|
#host?: DerivedIndexBackendHost;
|
|
137
151
|
#wake?: (change?: DerivedIndexBackendStateChange) => void;
|
|
138
152
|
#engine?: FullTextDerivedIndexEngine;
|
|
@@ -225,6 +239,15 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
225
239
|
);
|
|
226
240
|
if (this.#shutdownTimeoutMilliseconds < this.#closeTimeoutMilliseconds * 2)
|
|
227
241
|
throw new RangeError('shutdownTimeoutMilliseconds must be at least twice closeTimeoutMilliseconds');
|
|
242
|
+
this.#blobReadTimeoutMilliseconds = positiveInteger(
|
|
243
|
+
options.blobReadTimeoutMilliseconds ?? DEFAULT_BLOB_READ_TIMEOUT_MILLISECONDS,
|
|
244
|
+
'blobReadTimeoutMilliseconds'
|
|
245
|
+
);
|
|
246
|
+
this.#maxBlobApplySliceMilliseconds = Math.max(
|
|
247
|
+
APPLY_SLICE_MILLISECONDS,
|
|
248
|
+
Math.floor((this.#shutdownTimeoutMilliseconds - this.#closeTimeoutMilliseconds) / 2)
|
|
249
|
+
);
|
|
250
|
+
this.#hasBlobSources = options.hasBlobSources !== false;
|
|
228
251
|
this.#openRetryDelayMilliseconds = Math.max(1, this.#openRetryMilliseconds);
|
|
229
252
|
this.#writerRetryDelayMilliseconds = Math.min(
|
|
230
253
|
this.#maxOpenRetryMilliseconds,
|
|
@@ -241,13 +264,14 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
241
264
|
getDurableCursor(): DerivedIndexCursor | undefined {
|
|
242
265
|
this.#assertAttached();
|
|
243
266
|
if (!this.#cursorInspectedForAcquisition) {
|
|
244
|
-
|
|
267
|
+
const publication = this.#inspectPublication();
|
|
268
|
+
this.#durableCursor = publication.cursor;
|
|
245
269
|
this.#cursorInspectedForAcquisition = true;
|
|
246
270
|
}
|
|
247
271
|
return this.#durableCursor;
|
|
248
272
|
}
|
|
249
273
|
|
|
250
|
-
#
|
|
274
|
+
#inspectPublication(): FullTextPublication {
|
|
251
275
|
let inspection: FullTextDerivedIndexInspection;
|
|
252
276
|
try {
|
|
253
277
|
inspection = this.#lifecycle.inspect();
|
|
@@ -258,12 +282,13 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
258
282
|
if (inspection.state !== 'checkpointed') {
|
|
259
283
|
if (inspection.state === 'incompatible')
|
|
260
284
|
logWarning(`Full-text derived index '${this.id}' is incompatible (${inspection.code}); rebuilding`);
|
|
261
|
-
return;
|
|
285
|
+
return {};
|
|
262
286
|
}
|
|
263
287
|
try {
|
|
264
|
-
return
|
|
288
|
+
return decodeFullTextPublication(inspection.committedPayload);
|
|
265
289
|
} catch {
|
|
266
290
|
logWarning(`Full-text derived index '${this.id}' has an invalid committed cursor; rebuilding`);
|
|
291
|
+
return {};
|
|
267
292
|
}
|
|
268
293
|
}
|
|
269
294
|
|
|
@@ -323,6 +348,34 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
323
348
|
this.#queueBarrier(this.#activeEpoch);
|
|
324
349
|
}
|
|
325
350
|
|
|
351
|
+
publishCoverage(positions: DerivedIndexPositions, ownerEpoch: bigint): void {
|
|
352
|
+
this.#assertSharedEpoch(ownerEpoch);
|
|
353
|
+
if (!this.#durableCursor) throw new FullTextDerivedIndexError('Cannot publish coverage without a durable cursor');
|
|
354
|
+
if (sameDerivedIndexPositions(this.#durableCursor.coverage, positions)) return;
|
|
355
|
+
let pending: BarrierCommand | undefined;
|
|
356
|
+
for (let index = this.#commands.length - 1; index >= 0; index--) {
|
|
357
|
+
if (this.#commands[index].type === 'barrier') {
|
|
358
|
+
pending = this.#commands[index] as BarrierCommand;
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
const horizon = this.#lastAcceptedSequence;
|
|
363
|
+
const cursor = {
|
|
364
|
+
...cloneCursor(this.#lastAcceptedCursor ?? this.#durableCursor)!,
|
|
365
|
+
coverage: clonePositions(positions),
|
|
366
|
+
};
|
|
367
|
+
if (pending?.epoch === ownerEpoch && pending.horizon === horizon) pending.cursor = cursor;
|
|
368
|
+
else
|
|
369
|
+
this.#commands.push({
|
|
370
|
+
type: 'barrier',
|
|
371
|
+
epoch: ownerEpoch,
|
|
372
|
+
horizon,
|
|
373
|
+
cursor,
|
|
374
|
+
coverageOnly: true,
|
|
375
|
+
});
|
|
376
|
+
this.#scheduleDrain();
|
|
377
|
+
}
|
|
378
|
+
|
|
326
379
|
shutdown(ownerEpoch: bigint): Promise<void> {
|
|
327
380
|
if (this.#shutdown?.epoch === ownerEpoch) {
|
|
328
381
|
this.#cursorInspectedForAcquisition = false;
|
|
@@ -368,9 +421,15 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
368
421
|
this.#assertAttached();
|
|
369
422
|
if (this.#resetOperation) {
|
|
370
423
|
this.#assertSharedEpoch(ownerEpoch);
|
|
371
|
-
if (this.#resetEpoch
|
|
372
|
-
|
|
373
|
-
|
|
424
|
+
if (this.#resetEpoch === ownerEpoch) return this.#boundedReset(this.#resetOperation);
|
|
425
|
+
const priorReset = this.#resetOperation;
|
|
426
|
+
try {
|
|
427
|
+
await this.#boundedReset(priorReset);
|
|
428
|
+
} catch (error) {
|
|
429
|
+
if (this.#resetOperation === priorReset) throw error;
|
|
430
|
+
}
|
|
431
|
+
this.#assertSharedEpoch(ownerEpoch);
|
|
432
|
+
return this.reset(ownerEpoch);
|
|
374
433
|
}
|
|
375
434
|
if (
|
|
376
435
|
this.#engine ||
|
|
@@ -406,7 +465,7 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
406
465
|
|
|
407
466
|
async #performReset(ownerEpoch: bigint): Promise<void> {
|
|
408
467
|
try {
|
|
409
|
-
await this.#lifecycle.reset();
|
|
468
|
+
await this.#lifecycle.reset(ownerEpoch);
|
|
410
469
|
} catch (error) {
|
|
411
470
|
logNativeError('Full-text native reset failed', error);
|
|
412
471
|
throw new FullTextDerivedIndexError('Full-text native reset failed');
|
|
@@ -509,18 +568,18 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
509
568
|
if (epoch === undefined) throw new FullTextDerivedIndexError('Full-text owner epoch is unavailable');
|
|
510
569
|
const engine = await this.#open(epoch);
|
|
511
570
|
if (!engine) return false;
|
|
512
|
-
let actual:
|
|
571
|
+
let actual: FullTextPublication;
|
|
513
572
|
try {
|
|
514
573
|
this.#assertCommandEpoch(epoch);
|
|
515
|
-
actual =
|
|
574
|
+
actual = decodeFullTextPublication(engine.committedPayload);
|
|
516
575
|
} catch (error) {
|
|
517
576
|
await this.#closeUninstalledEngine(engine);
|
|
518
577
|
throw error;
|
|
519
578
|
}
|
|
520
|
-
if (!sameCursor(actual, this.#durableCursor)) {
|
|
579
|
+
if (!sameCursor(actual.cursor, this.#durableCursor)) {
|
|
521
580
|
this.#lossPendingEpoch = epoch;
|
|
522
581
|
await this.#closeUninstalledEngine(engine);
|
|
523
|
-
this.#durableCursor = actual;
|
|
582
|
+
this.#durableCursor = actual.cursor;
|
|
524
583
|
this.#cursorInspectedForAcquisition = true;
|
|
525
584
|
this.#resetWriterRetryBackoff();
|
|
526
585
|
this.#discardCommands();
|
|
@@ -551,13 +610,34 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
551
610
|
this.#lastAppliedSequence = command.sequence;
|
|
552
611
|
return true;
|
|
553
612
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
613
|
+
let slice: Awaited<ReturnType<typeof toFullTextMutationSlice>>;
|
|
614
|
+
try {
|
|
615
|
+
const startedAt = performance.now();
|
|
616
|
+
const deadline = startedAt + APPLY_SLICE_MILLISECONDS;
|
|
617
|
+
slice = this.#hasBlobSources
|
|
618
|
+
? await toFullTextMutationSlice(
|
|
619
|
+
command.batch.records,
|
|
620
|
+
command.position,
|
|
621
|
+
this.#maxApplySliceRecords,
|
|
622
|
+
deadline,
|
|
623
|
+
startedAt + this.#maxBlobApplySliceMilliseconds,
|
|
624
|
+
this.#blobReadTimeoutMilliseconds
|
|
625
|
+
)
|
|
626
|
+
: {
|
|
627
|
+
...toFullTextMutationSliceSync(
|
|
628
|
+
command.batch.records,
|
|
629
|
+
command.position,
|
|
630
|
+
this.#maxApplySliceRecords,
|
|
631
|
+
deadline
|
|
632
|
+
),
|
|
633
|
+
rejected: 0,
|
|
634
|
+
};
|
|
635
|
+
} catch (error) {
|
|
636
|
+
await this.#loseAcceptedWork(command.epoch, error, { retry: true });
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
const { batch: logical, end, rejected: projectionRejected } = slice;
|
|
640
|
+
this.#stagedUnindexableRecords += projectionRejected;
|
|
561
641
|
const mutationCount = logical.upserts.length + logical.deletes.length;
|
|
562
642
|
if (mutationCount > 0) {
|
|
563
643
|
this.#hasStagedMutations = true;
|
|
@@ -602,7 +682,7 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
602
682
|
}
|
|
603
683
|
|
|
604
684
|
async #publish(command: BarrierCommand): Promise<boolean> {
|
|
605
|
-
if (command.horizon <= this.#lastPublishedSequence) return true;
|
|
685
|
+
if (!command.coverageOnly && command.horizon <= this.#lastPublishedSequence) return true;
|
|
606
686
|
this.#assertCommandEpoch(command.epoch);
|
|
607
687
|
if (this.#lastAppliedSequence < command.horizon)
|
|
608
688
|
throw new FullTextDerivedIndexError('Full-text publication barrier passed unapplied work');
|
|
@@ -620,14 +700,15 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
620
700
|
return false;
|
|
621
701
|
}
|
|
622
702
|
this.#assertCommandEpoch(command.epoch);
|
|
623
|
-
|
|
703
|
+
if (command.coverageOnly) this.#host!.publicationChanged();
|
|
704
|
+
this.#lastPublishedSequence = Math.max(this.#lastPublishedSequence, command.horizon);
|
|
624
705
|
this.#hasStagedMutations = false;
|
|
625
706
|
const rejected = this.#stagedUnindexableRecords;
|
|
626
707
|
this.#unindexableRecords += rejected;
|
|
627
708
|
this.#stagedUnindexableRecords = 0;
|
|
628
709
|
if (rejected > 0)
|
|
629
710
|
logWarning(
|
|
630
|
-
`Full-text derived index '${this.id}' removed ${rejected} records
|
|
711
|
+
`Full-text derived index '${this.id}' removed ${rejected} records with invalid projections or native record limits`
|
|
631
712
|
);
|
|
632
713
|
this.#durableCursor = cloneCursor(cursor);
|
|
633
714
|
this.#cursorInspectedForAcquisition = true;
|
|
@@ -895,10 +976,53 @@ export class FullTextDerivedIndexBackend implements DerivedIndexBackend {
|
|
|
895
976
|
}
|
|
896
977
|
|
|
897
978
|
export function toFullTextMutationBatch(batch: DerivedIndexBatch): FullTextMutationBatch {
|
|
898
|
-
return
|
|
979
|
+
return toFullTextMutationSliceSync(batch.records, 0, batch.records.length, Number.POSITIVE_INFINITY).batch;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
async function toFullTextMutationSlice(
|
|
983
|
+
records: DerivedIndexBatch['records'],
|
|
984
|
+
start: number,
|
|
985
|
+
maxRecords: number,
|
|
986
|
+
deadline: number,
|
|
987
|
+
wallDeadline: number,
|
|
988
|
+
readTimeoutMilliseconds: number
|
|
989
|
+
): Promise<{ batch: FullTextMutationBatch; end: number; rejected: number }> {
|
|
990
|
+
const upserts: FullTextMutationBatch['upserts'] = [];
|
|
991
|
+
const deletes: string[] = [];
|
|
992
|
+
let rejected = 0;
|
|
993
|
+
const limit = Math.min(start + maxRecords, records.length);
|
|
994
|
+
let index = start;
|
|
995
|
+
let previousTableId: number | undefined;
|
|
996
|
+
let tablePrefix = '';
|
|
997
|
+
let yieldDeadline = deadline;
|
|
998
|
+
for (; index < limit; index++) {
|
|
999
|
+
const record = records[index];
|
|
1000
|
+
if (record.recordId == null || typeof record.recordId === 'symbol') continue;
|
|
1001
|
+
if (record.tableId !== previousTableId) {
|
|
1002
|
+
previousTableId = record.tableId;
|
|
1003
|
+
tablePrefix = `${record.tableId}.`;
|
|
1004
|
+
}
|
|
1005
|
+
const id = tablePrefix + toBufferKey(record.recordId).toString('base64url');
|
|
1006
|
+
const recordState = record.state.kind === 'record' ? record.state : undefined;
|
|
1007
|
+
const resolved = recordState
|
|
1008
|
+
? await resolvedFullTextFields(recordState.projection, readTimeoutMilliseconds)
|
|
1009
|
+
: undefined;
|
|
1010
|
+
yieldDeadline += resolved?.waitMilliseconds ?? 0;
|
|
1011
|
+
if (resolved?.error) throw resolved.error;
|
|
1012
|
+
if (resolved?.rejected) rejected++;
|
|
1013
|
+
if (resolved?.fields && !resolved.rejected)
|
|
1014
|
+
upserts.push({ id, version: String(recordState!.version), fields: resolved.fields });
|
|
1015
|
+
else deletes.push(id);
|
|
1016
|
+
const now = performance.now();
|
|
1017
|
+
if (now >= yieldDeadline || now >= wallDeadline) {
|
|
1018
|
+
index++;
|
|
1019
|
+
break;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
return { batch: { upserts, deletes }, end: index, rejected };
|
|
899
1023
|
}
|
|
900
1024
|
|
|
901
|
-
function
|
|
1025
|
+
function toFullTextMutationSliceSync(
|
|
902
1026
|
records: DerivedIndexBatch['records'],
|
|
903
1027
|
start: number,
|
|
904
1028
|
maxRecords: number,
|
|
@@ -918,8 +1042,9 @@ function toFullTextMutationSlice(
|
|
|
918
1042
|
tablePrefix = `${record.tableId}.`;
|
|
919
1043
|
}
|
|
920
1044
|
const id = tablePrefix + toBufferKey(record.recordId).toString('base64url');
|
|
921
|
-
const
|
|
922
|
-
|
|
1045
|
+
const recordState = record.state.kind === 'record' ? record.state : undefined;
|
|
1046
|
+
const fields = recordState ? fullTextFields(recordState.projection) : undefined;
|
|
1047
|
+
if (fields) upserts.push({ id, version: String(recordState!.version), fields });
|
|
923
1048
|
else deletes.push(id);
|
|
924
1049
|
if ((index - start + 1) % 16 === 0 && performance.now() >= deadline) {
|
|
925
1050
|
index++;
|
|
@@ -1001,7 +1126,14 @@ export function decodeFullTextCursorPayload(
|
|
|
1001
1126
|
payload: string | null | undefined,
|
|
1002
1127
|
maxBytes = HARPER_FULLTEXT_MAX_CURSOR_PAYLOAD_BYTES
|
|
1003
1128
|
): DerivedIndexCursor | undefined {
|
|
1004
|
-
|
|
1129
|
+
return decodeFullTextPublication(payload, maxBytes).cursor;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
export function decodeFullTextPublication(
|
|
1133
|
+
payload: string | null | undefined,
|
|
1134
|
+
maxBytes = HARPER_FULLTEXT_MAX_CURSOR_PAYLOAD_BYTES
|
|
1135
|
+
): FullTextPublication {
|
|
1136
|
+
if (payload == null) return {};
|
|
1005
1137
|
if (typeof payload !== 'string' || Buffer.byteLength(payload) > maxBytes)
|
|
1006
1138
|
throw new FullTextDerivedIndexError('Full-text cursor payload is invalid or too large');
|
|
1007
1139
|
let decoded: unknown;
|
|
@@ -1014,10 +1146,10 @@ export function decodeFullTextCursorPayload(
|
|
|
1014
1146
|
!plainObject(decoded) ||
|
|
1015
1147
|
decoded.format !== 1 ||
|
|
1016
1148
|
!Object.hasOwn(decoded, 'cursor') ||
|
|
1017
|
-
Object.keys(decoded).some((name) => name !== 'format' && name !== 'cursor')
|
|
1149
|
+
Object.keys(decoded).some((name) => name !== 'format' && name !== 'cursor' && name !== 'dataRevision')
|
|
1018
1150
|
)
|
|
1019
1151
|
throw new FullTextDerivedIndexError('Full-text cursor payload has an unsupported format');
|
|
1020
|
-
if (decoded.cursor === null) return;
|
|
1152
|
+
if (decoded.cursor === null) return {};
|
|
1021
1153
|
if (
|
|
1022
1154
|
!plainObject(decoded.cursor) ||
|
|
1023
1155
|
decoded.cursor.format !== 1 ||
|
|
@@ -1025,7 +1157,7 @@ export function decodeFullTextCursorPayload(
|
|
|
1025
1157
|
Object.keys(decoded.cursor).some((name) => name !== 'format' && name !== 'logs' && name !== 'coverage')
|
|
1026
1158
|
)
|
|
1027
1159
|
throw new FullTextDerivedIndexError('Full-text cursor payload contains an invalid cursor');
|
|
1028
|
-
return normalizedCursor(decoded.cursor as DerivedIndexCursor);
|
|
1160
|
+
return { cursor: normalizedCursor(decoded.cursor as DerivedIndexCursor) };
|
|
1029
1161
|
}
|
|
1030
1162
|
|
|
1031
1163
|
function fullTextFields(projection: unknown): Record<string, string | string[]> | undefined {
|
|
@@ -1040,6 +1172,58 @@ function fullTextFields(projection: unknown): Record<string, string | string[]>
|
|
|
1040
1172
|
return fields;
|
|
1041
1173
|
}
|
|
1042
1174
|
|
|
1175
|
+
async function resolvedFullTextFields(
|
|
1176
|
+
projection: unknown,
|
|
1177
|
+
readTimeoutMilliseconds: number
|
|
1178
|
+
): Promise<{
|
|
1179
|
+
fields?: Record<string, string | string[]>;
|
|
1180
|
+
rejected: boolean;
|
|
1181
|
+
error?: unknown;
|
|
1182
|
+
waitMilliseconds: number;
|
|
1183
|
+
}> {
|
|
1184
|
+
let waitMilliseconds = 0;
|
|
1185
|
+
let fields = fullTextFields(projection);
|
|
1186
|
+
if (!projection || typeof projection !== 'object' || Array.isArray(projection))
|
|
1187
|
+
return { fields, rejected: false, waitMilliseconds };
|
|
1188
|
+
const deadline = performance.now() + readTimeoutMilliseconds;
|
|
1189
|
+
for (const name in projection) {
|
|
1190
|
+
if (!Object.hasOwn(projection, name)) continue;
|
|
1191
|
+
const value = (projection as Record<string, unknown>)[name];
|
|
1192
|
+
if (!(value instanceof Blob)) continue;
|
|
1193
|
+
if (value.size > MAX_FULL_TEXT_VALUE_BYTES) return { rejected: true, waitMilliseconds };
|
|
1194
|
+
let bytes: ArrayBuffer;
|
|
1195
|
+
try {
|
|
1196
|
+
const remaining = deadline - performance.now();
|
|
1197
|
+
if (remaining <= 0) throw new FullTextBlobReadTimeout();
|
|
1198
|
+
const reading = withTimeout(value.arrayBuffer(), remaining, () => new FullTextBlobReadTimeout());
|
|
1199
|
+
const waitStartedAt = performance.now();
|
|
1200
|
+
try {
|
|
1201
|
+
bytes = await reading;
|
|
1202
|
+
} finally {
|
|
1203
|
+
waitMilliseconds += performance.now() - waitStartedAt;
|
|
1204
|
+
}
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
return { rejected: false, error, waitMilliseconds };
|
|
1207
|
+
}
|
|
1208
|
+
let text: string;
|
|
1209
|
+
try {
|
|
1210
|
+
text = UTF8_DECODER.decode(bytes);
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
if (error instanceof TypeError) return { rejected: true, waitMilliseconds };
|
|
1213
|
+
throw error;
|
|
1214
|
+
}
|
|
1215
|
+
if (Buffer.byteLength(text) > MAX_FULL_TEXT_VALUE_BYTES) return { rejected: true, waitMilliseconds };
|
|
1216
|
+
(fields ??= Object.create(null))[name] = text;
|
|
1217
|
+
}
|
|
1218
|
+
return { fields, rejected: false, waitMilliseconds };
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
class FullTextBlobReadTimeout extends Error {
|
|
1222
|
+
constructor() {
|
|
1223
|
+
super('Full-text Blob read timed out');
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1043
1227
|
function isTerminalOpenError(error: unknown): boolean {
|
|
1044
1228
|
const code = nativeErrorCode(error);
|
|
1045
1229
|
return code !== undefined && TERMINAL_OPEN_ERROR_CODES.has(code);
|
|
@@ -2,15 +2,17 @@ import type { FullTextDerivedIndexEngine } from './fullTextDerivedIndex.ts';
|
|
|
2
2
|
import { loggerWithTag } from '../../utility/logging/logger.ts';
|
|
3
3
|
|
|
4
4
|
const FULLTEXT_LIFECYCLE_API_VERSION = 1;
|
|
5
|
-
const FULLTEXT_MUTATION_BATCH_API_VERSION =
|
|
5
|
+
const FULLTEXT_MUTATION_BATCH_API_VERSION = 4;
|
|
6
|
+
const FULLTEXT_QUERY_API_VERSION = 2;
|
|
6
7
|
const logger = loggerWithTag('fulltext-derived-index');
|
|
7
8
|
|
|
8
9
|
export interface NativeFullTextIndexConfiguration {
|
|
9
10
|
fields: Array<{ name: string; weight?: number }>;
|
|
10
|
-
analyzer: 'english@
|
|
11
|
+
analyzer: 'english@2';
|
|
11
12
|
stopWords?: boolean;
|
|
12
13
|
positions?: boolean;
|
|
13
14
|
surfaceTerms?: boolean;
|
|
15
|
+
synonyms?: NativeFullTextSynonymRule[];
|
|
14
16
|
limits: {
|
|
15
17
|
indexingThreads: number;
|
|
16
18
|
searchThreads: number;
|
|
@@ -21,14 +23,97 @@ export interface NativeFullTextIndexConfiguration {
|
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
export type NativeFullTextSynonymRule = { source: string; replacements: string[] };
|
|
27
|
+
|
|
28
|
+
export type NativeFullTextSearchMode = 'any' | 'all' | 'phrase' | 'prefix' | 'fuzzy' | 'fuzzy-prefix';
|
|
29
|
+
|
|
30
|
+
export type NativeFullTextSearchExpression =
|
|
31
|
+
| { text: string; mode?: NativeFullTextSearchMode; operator?: 'any' | 'all'; fields?: string[] }
|
|
32
|
+
| { operator: 'and' | 'or'; clauses: NativeFullTextSearchExpression[] }
|
|
33
|
+
| { operator: 'not'; clause: NativeFullTextSearchExpression };
|
|
34
|
+
|
|
35
|
+
export type NativeFullTextSearchRequest = {
|
|
36
|
+
text?: string;
|
|
37
|
+
query?: NativeFullTextSearchExpression;
|
|
38
|
+
mode?: NativeFullTextSearchMode;
|
|
39
|
+
operator?: 'any' | 'all';
|
|
40
|
+
fields?: string[];
|
|
41
|
+
candidateIds?: string[];
|
|
42
|
+
offset?: number;
|
|
43
|
+
limit?: number;
|
|
44
|
+
exactTotal?: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type NativeFullTextSearchResult = {
|
|
48
|
+
total: number;
|
|
49
|
+
totalRelation: 'exact' | 'lower-bound';
|
|
50
|
+
hits: Array<{ id: string; score: number; version?: string }>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type NativeFullTextTraceResult = {
|
|
54
|
+
complete: boolean;
|
|
55
|
+
records: Array<{
|
|
56
|
+
id: string;
|
|
57
|
+
values: Array<{
|
|
58
|
+
field: string;
|
|
59
|
+
valueIndex: number;
|
|
60
|
+
spans: Array<{ start: number; end: number }>;
|
|
61
|
+
fragments?: Array<{ text: string; start: number; spans: Array<{ start: number; end: number }> }>;
|
|
62
|
+
}>;
|
|
63
|
+
}>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export interface NativeFullTextReader {
|
|
67
|
+
readonly committedPayload?: string;
|
|
68
|
+
reload(): Promise<void>;
|
|
69
|
+
search(
|
|
70
|
+
request: NativeFullTextSearchRequest,
|
|
71
|
+
options?: { remainingBudgetMilliseconds?: number }
|
|
72
|
+
): Promise<NativeFullTextSearchResult>;
|
|
73
|
+
traceMatches(
|
|
74
|
+
request: Omit<NativeFullTextSearchRequest, 'query' | 'offset' | 'limit' | 'exactTotal'> & { text: string },
|
|
75
|
+
records: Array<{ id: string; fields: Record<string, string | string[]> }>,
|
|
76
|
+
options?: {
|
|
77
|
+
remainingBudgetMilliseconds?: number;
|
|
78
|
+
snippets?: boolean;
|
|
79
|
+
fragmentLength?: number;
|
|
80
|
+
maxFragmentsPerValue?: number;
|
|
81
|
+
}
|
|
82
|
+
): Promise<NativeFullTextTraceResult>;
|
|
83
|
+
close(): Promise<{ cleanupError?: unknown }>;
|
|
84
|
+
}
|
|
85
|
+
|
|
24
86
|
export type NativeFullTextRuntimeInfo = {
|
|
25
87
|
packageVersion: string;
|
|
26
88
|
tantivyVersion: string;
|
|
27
89
|
nativeAbiVersion: number;
|
|
90
|
+
queryClassIsolationMinimumSearchThreads: number;
|
|
28
91
|
lifecycleApiVersion: number;
|
|
29
92
|
mutationBatchApiVersion: number;
|
|
93
|
+
queryApiVersion: number;
|
|
30
94
|
storageBackends: ReadonlyArray<'native'>;
|
|
31
|
-
limits: {
|
|
95
|
+
limits: {
|
|
96
|
+
maxCommitPayloadBytes: number;
|
|
97
|
+
maxSearchWindow: number;
|
|
98
|
+
maxAutocompleteResults: number;
|
|
99
|
+
maxSearchBudgetMilliseconds: number;
|
|
100
|
+
maxTraceRecords: number;
|
|
101
|
+
maxTraceSourceBytes: number;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export type NativeFullTextQueryRuntimeInfo = Pick<
|
|
106
|
+
NativeFullTextRuntimeInfo,
|
|
107
|
+
'queryClassIsolationMinimumSearchThreads'
|
|
108
|
+
> & {
|
|
109
|
+
limits: Pick<
|
|
110
|
+
NativeFullTextRuntimeInfo['limits'],
|
|
111
|
+
| 'maxSearchWindow'
|
|
112
|
+
| 'maxAutocompleteResults'
|
|
113
|
+
| 'maxSearchBudgetMilliseconds'
|
|
114
|
+
| 'maxTraceRecords'
|
|
115
|
+
| 'maxTraceSourceBytes'
|
|
116
|
+
>;
|
|
32
117
|
};
|
|
33
118
|
|
|
34
119
|
export interface NativeFullTextModule {
|
|
@@ -50,6 +135,13 @@ export interface NativeFullTextModule {
|
|
|
50
135
|
generation: string;
|
|
51
136
|
}
|
|
52
137
|
): Promise<FullTextDerivedIndexEngine>;
|
|
138
|
+
openNativeFullTextReader(
|
|
139
|
+
options: NativeFullTextIndexConfiguration & {
|
|
140
|
+
path: string;
|
|
141
|
+
indexId: string;
|
|
142
|
+
generation: string;
|
|
143
|
+
}
|
|
144
|
+
): Promise<NativeFullTextReader>;
|
|
53
145
|
inspectNativeFullTextIndex(
|
|
54
146
|
options: Omit<NativeFullTextIndexConfiguration, 'limits'> & {
|
|
55
147
|
path: string;
|
|
@@ -109,6 +201,8 @@ export async function validateFullTextNativeBinding(module: unknown): Promise<Na
|
|
|
109
201
|
typeof prototype.close !== 'function' ||
|
|
110
202
|
!('openNativeFullTextIndex' in module) ||
|
|
111
203
|
typeof module.openNativeFullTextIndex !== 'function' ||
|
|
204
|
+
!('openNativeFullTextReader' in module) ||
|
|
205
|
+
typeof module.openNativeFullTextReader !== 'function' ||
|
|
112
206
|
!('validateNativeFullTextIndexOptions' in module) ||
|
|
113
207
|
typeof module.validateNativeFullTextIndexOptions !== 'function' ||
|
|
114
208
|
!('inspectNativeFullTextIndex' in module) ||
|
|
@@ -121,6 +215,7 @@ export async function validateFullTextNativeBinding(module: unknown): Promise<Na
|
|
|
121
215
|
throw new TypeError('@harperfast/fulltext/native does not implement the required Harper binding contract');
|
|
122
216
|
const binding = module as NativeFullTextModule;
|
|
123
217
|
const info = await binding.runtimeInfo();
|
|
218
|
+
validateFullTextQueryRuntimeInfo(info);
|
|
124
219
|
if (
|
|
125
220
|
!info ||
|
|
126
221
|
typeof info.packageVersion !== 'string' ||
|
|
@@ -128,6 +223,7 @@ export async function validateFullTextNativeBinding(module: unknown): Promise<Na
|
|
|
128
223
|
!Number.isSafeInteger(info.nativeAbiVersion) ||
|
|
129
224
|
info.lifecycleApiVersion !== FULLTEXT_LIFECYCLE_API_VERSION ||
|
|
130
225
|
info.mutationBatchApiVersion !== FULLTEXT_MUTATION_BATCH_API_VERSION ||
|
|
226
|
+
info.queryApiVersion !== FULLTEXT_QUERY_API_VERSION ||
|
|
131
227
|
!Array.isArray(info.storageBackends) ||
|
|
132
228
|
!info.storageBackends.includes('native') ||
|
|
133
229
|
!info.limits ||
|
|
@@ -144,3 +240,37 @@ export function getValidatedFullTextRuntimeInfo(binding: NativeFullTextModule):
|
|
|
144
240
|
if (!info) throw new Error('Full-text native binding has not been validated');
|
|
145
241
|
return info;
|
|
146
242
|
}
|
|
243
|
+
|
|
244
|
+
export function nativeFullTextSearchThreads(
|
|
245
|
+
info: Pick<NativeFullTextRuntimeInfo, 'queryClassIsolationMinimumSearchThreads'>,
|
|
246
|
+
configured: number
|
|
247
|
+
): number {
|
|
248
|
+
const minimum = info.queryClassIsolationMinimumSearchThreads;
|
|
249
|
+
if (!Number.isSafeInteger(minimum) || minimum <= 0)
|
|
250
|
+
throw new TypeError('@harperfast/fulltext/native reported an invalid query-class isolation threshold');
|
|
251
|
+
return Math.max(configured, minimum);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function validateFullTextQueryRuntimeInfo(info: unknown): NativeFullTextQueryRuntimeInfo {
|
|
255
|
+
const runtime = info as NativeFullTextQueryRuntimeInfo;
|
|
256
|
+
if (
|
|
257
|
+
!runtime ||
|
|
258
|
+
typeof runtime !== 'object' ||
|
|
259
|
+
!Number.isSafeInteger(runtime.queryClassIsolationMinimumSearchThreads) ||
|
|
260
|
+
runtime.queryClassIsolationMinimumSearchThreads <= 0 ||
|
|
261
|
+
!runtime.limits ||
|
|
262
|
+
!Number.isSafeInteger(runtime.limits.maxSearchWindow) ||
|
|
263
|
+
runtime.limits.maxSearchWindow <= 0 ||
|
|
264
|
+
!Number.isSafeInteger(runtime.limits.maxAutocompleteResults) ||
|
|
265
|
+
runtime.limits.maxAutocompleteResults <= 0 ||
|
|
266
|
+
runtime.limits.maxAutocompleteResults > runtime.limits.maxSearchWindow ||
|
|
267
|
+
!Number.isSafeInteger(runtime.limits.maxSearchBudgetMilliseconds) ||
|
|
268
|
+
runtime.limits.maxSearchBudgetMilliseconds <= 0 ||
|
|
269
|
+
!Number.isSafeInteger(runtime.limits.maxTraceRecords) ||
|
|
270
|
+
runtime.limits.maxTraceRecords <= 0 ||
|
|
271
|
+
!Number.isSafeInteger(runtime.limits.maxTraceSourceBytes) ||
|
|
272
|
+
runtime.limits.maxTraceSourceBytes <= 0
|
|
273
|
+
)
|
|
274
|
+
throw new TypeError('@harperfast/fulltext/native reported incompatible runtime capabilities');
|
|
275
|
+
return runtime;
|
|
276
|
+
}
|