@harperfast/harper 5.2.6 → 5.2.8
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/components/mcp/tools/application.ts +8 -4
- package/dist/components/mcp/tools/application.js +7 -4
- package/dist/components/mcp/tools/application.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.js +2 -3
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +16 -0
- package/dist/resources/RecordEncoder.js +93 -3
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.js +11 -1
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.js +55 -1
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/auditStore.d.ts +1 -0
- package/dist/resources/auditStore.js +1 -0
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/graphql.js +1 -1
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/tracked.js +5 -0
- package/dist/resources/tracked.js.map +1 -1
- package/dist/resources/transactionBroadcast.js +5 -5
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/npm-shrinkwrap.json +47 -47
- package/package.json +4 -4
- package/resources/DESIGN.md +5 -0
- package/resources/PrimaryRocksDatabase.ts +3 -3
- package/resources/RecordEncoder.ts +85 -3
- package/resources/RocksTransactionLogStore.ts +11 -1
- package/resources/Table.ts +62 -2
- package/resources/auditStore.ts +3 -1
- package/resources/graphql.ts +1 -1
- package/resources/tracked.ts +4 -0
- package/resources/transactionBroadcast.ts +5 -5
- package/studio/web/assets/{Chat-BNHY84-Z.js → Chat-DDlysEi_.js} +71 -95
- package/studio/web/assets/FloatingChat-DdJ3DZJX.js +23 -0
- package/studio/web/assets/abnfDiagram-VCTEODGH-C0_BAZyO.js +1 -0
- package/studio/web/assets/{alertDialog-BaBrZQ4M.js → alertDialog-DIHt7Z0r.js} +1 -1
- package/studio/web/assets/apiToken-CrPb_98N.js +1 -0
- package/studio/web/assets/applications-C6Y4nL_X.js +296 -0
- package/studio/web/assets/arc-CVRByUzA.js +1 -0
- package/studio/web/assets/architecture-7GRP2DOG-DNdx5tEU.js +1 -0
- package/studio/web/assets/architectureDiagram-5GKGNRK7-BWzrASgm.js +36 -0
- package/studio/web/assets/authStore-qKmCZcaf.js +3 -0
- package/studio/web/assets/blockDiagram-NRAW4CY4-BdJX9Khj.js +129 -0
- package/studio/web/assets/{button-DfBmT4rc.js → button-DhiX-njv.js} +1 -1
- package/studio/web/assets/c4Diagram-UCG6FXSJ-CI6MzGmQ.js +38 -0
- package/studio/web/assets/channel-DtCV8PTL.js +1 -0
- package/studio/web/assets/chevron-up-Df2c8uoU.js +1 -0
- package/studio/web/assets/chunk-75Z2AOVW-BT8tVmks.js +2 -0
- package/studio/web/assets/chunk-DU6HZSFF-9kAOOmI6.js +127 -0
- package/studio/web/assets/{chunk-2GRJ4B5K-DtwG__pv.js → chunk-F27PBJKO-BW7ao8AY.js} +1 -1
- package/studio/web/assets/{chunk-KEIR6QF5-BICK3FdT.js → chunk-FOHPRMQF-DHwB1DNv.js} +2 -2
- package/studio/web/assets/{chunk-5RXB4S5H-D3c7okHC.js → chunk-G27WJ6UU-COyLMcgK.js} +2 -2
- package/studio/web/assets/chunk-GMAD6QVW-BNyXpoQO.js +72 -0
- package/studio/web/assets/chunk-JQ64N6SF-Cyz1IeLf.js +1 -0
- package/studio/web/assets/{chunk-GF5L2VYU-DreJ7Snz.js → chunk-LCL6LL3I-HOzK_ppE.js} +3 -3
- package/studio/web/assets/chunk-OBVCFTLP-D4wWOqDQ.js +1 -0
- package/studio/web/assets/chunk-P2QGCYS3-DmIFY4d7.js +1 -0
- package/studio/web/assets/{chunk-KBJHAD2P-CLDPbAA-.js → chunk-POPQ4Y6H-BPrvMyKz.js} +1 -1
- package/studio/web/assets/{chunk-4I5QYGJK-D1FhvtQq.js → chunk-PWAF6VOD-2zB6IW9i.js} +1 -1
- package/studio/web/assets/chunk-R7TYR2AO-Irip67yr.js +10 -0
- package/studio/web/assets/chunk-RHFEMEQ7-2FgyI8YU.js +168 -0
- package/studio/web/assets/{chunk-6Q2QTUOP-QviMM6bR.js → chunk-SVP7TREG-FwtbH2QC.js} +1 -1
- package/studio/web/assets/chunk-TEH6E4GO-P87k5mNi.js +62 -0
- package/studio/web/assets/{chunk-XXDRQBXY-CaP_jixK.js → chunk-XXDRQBXY-BoGZu3HH.js} +1 -1
- package/studio/web/assets/classDiagram-DTDB5LWJ-DbO_dCNE.js +1 -0
- package/studio/web/assets/classDiagram-v2-JRS7N3AN-DbO_dCNE.js +1 -0
- package/studio/web/assets/{cose-bilkent-JH36ORCC-BVTNhTKD.js → cose-bilkent-JH36ORCC-Cuuf67Bh.js} +1 -1
- package/studio/web/assets/{createLucideIcon-BMkDbMrz.js → createLucideIcon-BKGPfjm2.js} +1 -1
- package/studio/web/assets/cssMode-D8ceA4av.js +1 -0
- package/studio/web/assets/cynefin-OW5HDTMX-BRkpLFQV.js +1 -0
- package/studio/web/assets/cynefinDiagram-5FMLGOSQ-CHT1DaX6.js +62 -0
- package/studio/web/assets/cytoscape.esm-C2x7inlt.js +321 -0
- package/studio/web/assets/dagre-3AP2YEHR-DpUXBh63.js +4 -0
- package/studio/web/assets/dagre-PrKaheQc.js +1 -0
- package/studio/web/assets/diagram-S7CK7UJ4-BuymVFZT.js +30 -0
- package/studio/web/assets/diagram-UQ7AKVKN-CyP148RM.js +41 -0
- package/studio/web/assets/diagram-VSXAHHWV-CoCAg3M9.js +3 -0
- package/studio/web/assets/diagram-VX7I27RA-BpOqCFca.js +24 -0
- package/studio/web/assets/diagram-Z3DM3KII-Bfpw7Vbj.js +24 -0
- package/studio/web/assets/dialog-CBf0Mr1d.js +1 -0
- package/studio/web/assets/{dist-CeoU7cfW.js → dist-kYfyPZP9.js} +1 -1
- package/studio/web/assets/{dist-cY0BPcz0.js → dist-lkA3O3eM.js} +1 -1
- package/studio/web/assets/download-BtTOBem-.js +1 -0
- package/studio/web/assets/ebnfDiagram-PWID7BFC-DS_6aWqL.js +1 -0
- package/studio/web/assets/editor-C-jlLd1G.js +1 -0
- package/studio/web/assets/erDiagram-SSCWMZ5O-DJNk6Fgw.js +99 -0
- package/studio/web/assets/eventmodeling-NTZA5JFV-5jbe4A5P.js +1 -0
- package/studio/web/assets/flowDiagram-A5DVABFB-Dp9Ezlow.js +1 -0
- package/studio/web/assets/{ganttDiagram-PKOTCBZU-Cit41Zp3.js → ganttDiagram-EL5Y4UJY-2pOExxMY.js} +2 -2
- package/studio/web/assets/{getAnalytics-rTxZLIM5.js → getAnalytics-D4LKGeVy.js} +1 -1
- package/studio/web/assets/gitGraph-4MIJSDKK-CH5ZxwzF.js +1 -0
- package/studio/web/assets/gitGraphDiagram-WWUBYQGX-DVIsIhbO.js +106 -0
- package/studio/web/assets/html-BnuKFPjv.js +1 -0
- package/studio/web/assets/htmlMode-DXM6YYUw.js +1 -0
- package/studio/web/assets/index-BtTvoLf8.js +824 -0
- package/studio/web/assets/index-Cxj2_wsl.css +1 -0
- package/studio/web/assets/index.lazy-PVbC6xQh.js +2 -0
- package/studio/web/assets/info-A6RAGUB7-CPQfTnaG.js +1 -0
- package/studio/web/assets/infoDiagram-RXCK75RN-DlwLYlwm.js +2 -0
- package/studio/web/assets/{ishikawaDiagram-WSZJBQD7-BJYRB-hU.js → ishikawaDiagram-5VMMS53U-BRXRp29U.js} +2 -2
- package/studio/web/assets/{javascript-CGzSV8Sd.js → javascript-CAuAkYxc.js} +1 -1
- package/studio/web/assets/{journeyDiagram-NVQOT4AX-B8K4wuMz.js → journeyDiagram-EYS64GPL-B0ou8k0n.js} +1 -1
- package/studio/web/assets/jsonMode-Dny8hrU7.js +1 -0
- package/studio/web/assets/{kanban-definition-27J2QSJJ-DKFV1ovM.js → kanban-definition-3QL26DDD-uYg7iYzp.js} +11 -11
- package/studio/web/assets/languageServices-D1uNqC6s.js +1 -0
- package/studio/web/assets/linear-Cnt8506Q.js +1 -0
- package/studio/web/assets/lspLanguageFeatures-Bh-bvkyK.js +4 -0
- package/studio/web/assets/mermaid-parser.core-Ck-fC8b7.js +7 -0
- package/studio/web/assets/mermaid.core-CP8aNNYm.js +44 -0
- package/studio/web/assets/{mindmap-definition-FAOFIHXS-CKL4PdAv.js → mindmap-definition-FBJOCRG2-CgTZ-rit.js} +25 -25
- package/studio/web/assets/notifications-DPTOF-SX.js +1 -0
- package/studio/web/assets/notifications-DsE0S3zT.js +1 -0
- package/studio/web/assets/packet-AYTQ26CC-DEyoPtPb.js +1 -0
- package/studio/web/assets/pegDiagram-XKGWAZYB-DrD-7sD9.js +1 -0
- package/studio/web/assets/pie-WAS4IAKB-wjj-EI1d.js +1 -0
- package/studio/web/assets/pieDiagram-E7YTZNPT-GntqDCzv.js +39 -0
- package/studio/web/assets/profile-BIeCZr-w.js +1 -0
- package/studio/web/assets/{quadrantDiagram-CIZ2JOQS-CSbsuWtH.js → quadrantDiagram-AXDQQJYC-0UeqXQGd.js} +1 -1
- package/studio/web/assets/radar-RG4KPBEZ-DFSA5h7k.js +1 -0
- package/studio/web/assets/railroad-74A4TZTK-CaOUG9wR.js +1 -0
- package/studio/web/assets/railroad-abnf-HS5TGJTU-Bc0Qi0WH.js +1 -0
- package/studio/web/assets/railroad-ebnf-LZEXJU2U-G8rVVZ2C.js +1 -0
- package/studio/web/assets/railroad-peg-WCYAUIDC-CrehKBhC.js +1 -0
- package/studio/web/assets/railroadDiagram-O6MQD6OU-yHUELZaV.js +1 -0
- package/studio/web/assets/regions-B5lGduv5.js +1 -0
- package/studio/web/assets/{editor.api-eUd8PqEu.js → register-Cvc1TpmQ.js} +139 -138
- package/studio/web/assets/{requirementDiagram-LRYGKXZP-ZIF0Wlho.js → requirementDiagram-EFPCY7ZU-DNEGFjuW.js} +2 -2
- package/studio/web/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/studio/web/assets/safeParse-DeaoCCWH.js +1 -0
- package/studio/web/assets/{sankeyDiagram-W5VNT64P-BcRESt9x.js → sankeyDiagram-P5KCCOFB-DpyAmSVR.js} +1 -1
- package/studio/web/assets/{sequenceDiagram-SI44F4Z6-OpgTeJNU.js → sequenceDiagram-WJ2MYXX4-TyaT7xNk.js} +1 -1
- package/studio/web/assets/setComponentFile-D8ZLDWhU.js +1 -0
- package/studio/web/assets/setLocalStorage-D_kflv4U.js +1 -0
- package/studio/web/assets/setSessionStorage-B0bf71m4.js +1 -0
- package/studio/web/assets/setup-D2az-Ue_.js +2 -0
- package/studio/web/assets/src-CMc7m_Ut.js +1 -0
- package/studio/web/assets/stateDiagram-HBIQ2CUA-CeEdTArZ.js +1 -0
- package/studio/web/assets/stateDiagram-v2-4QOOHH4V-D4tuw9Su.js +1 -0
- package/studio/web/assets/status-BJegPrWN.js +61 -0
- package/studio/web/assets/step-vX8bovaY.js +1 -0
- package/studio/web/assets/swimlanes-XN3QIQJK-B54FmF46.js +1 -0
- package/studio/web/assets/swimlanesDiagram-VK2B7HYN-XOhmNEvq.js +8 -0
- package/studio/web/assets/tabs-B_G5zscN.js +1 -0
- package/studio/web/assets/{time-D55sDum-.js → time-Cclkb7kQ.js} +1 -1
- package/studio/web/assets/{timeline-definition-Z64GVDOM-Dy5A_tK2.js → timeline-definition-24CTP7MA-D-a9ujbo.js} +5 -5
- package/studio/web/assets/toggleHighContrast-BdIEw2rK.js +49 -0
- package/studio/web/assets/treeView-Q6P3EWNA-CrW_6JnS.js +1 -0
- package/studio/web/assets/treemap-WGGIJYW6-BxyYLdP_.js +1 -0
- package/studio/web/assets/tsMode-CulNMwI9.js +11 -0
- package/studio/web/assets/typescript-BpRqjmvQ.js +1 -0
- package/studio/web/assets/useEntityRestURL-C7x-Yz9r.js +1 -0
- package/studio/web/assets/useLocalStorage-Dtj1QS8_.js +1 -0
- package/studio/web/assets/{vendor-core-CddkYGh5.js → vendor-core-RCcadM3e.js} +1 -1
- package/studio/web/assets/vendor-datadog-BRv-mOv1.js +6 -0
- package/studio/web/assets/{vendor-react-BhazFIp8.js → vendor-react-Dyj4O3HE.js} +1 -1
- package/studio/web/assets/vendor-tanstack-BiFWSB3W.js +1 -0
- package/studio/web/assets/{vendor-ui-BLIveqaL.js → vendor-ui-vhu-UHhF.js} +11 -11
- package/studio/web/assets/{vennDiagram-T6HMQDX7-DRvMIiSo.js → vennDiagram-4TSXK5OY-Cy7s7Mpy.js} +3 -3
- package/studio/web/assets/wardley-WFR3VGLG-BeBL35g2.js +1 -0
- package/studio/web/assets/{wardleyDiagram-T6FBY63Y-B04FSA0i.js → wardleyDiagram-VM6X3IG4-BylmIGSg.js} +3 -3
- package/studio/web/assets/workers-B2WpJDK9.js +3 -0
- package/studio/web/assets/x-B9o9hsep.js +1 -0
- package/studio/web/assets/xml-CZnimVSX.js +1 -0
- package/studio/web/assets/{xychartDiagram-ELKLHX3M-BE0X7RA7.js → xychartDiagram-S5SC5T6Z-CoKALMXr.js} +3 -3
- package/studio/web/assets/yaml-BwNuyZS-.js +1 -0
- package/studio/web/assets/{yaml.worker-Iyy2Pf1T.js → yaml.worker-BDL8_iuk.js} +153 -153
- package/studio/web/harper-studio_black.png +0 -0
- package/studio/web/index.html +18 -24
- package/studio/web/assets/FloatingChat-BbztUci0.js +0 -23
- package/studio/web/assets/abnfDiagram-N423BO3Z-BRuH0ywn.js +0 -1
- package/studio/web/assets/apiToken-D0x_S8Wq.js +0 -1
- package/studio/web/assets/applications-BU83fSEG.js +0 -296
- package/studio/web/assets/arc-3Xw6uabx.js +0 -1
- package/studio/web/assets/architecture-TIHT7OUA-CsHfPErM.js +0 -1
- package/studio/web/assets/architectureDiagram-T3A2C74G-DrwbS7Gp.js +0 -36
- package/studio/web/assets/array-BifhSqXX.js +0 -1
- package/studio/web/assets/authStore-B3IhXrn6.js +0 -3
- package/studio/web/assets/blockDiagram-VBNYF7ZC-DKN1mht5.js +0 -132
- package/studio/web/assets/c4Diagram-5PPSVZJV-CT9bmjm_.js +0 -10
- package/studio/web/assets/card-ByrPS_wa.js +0 -1
- package/studio/web/assets/channel-mnKBfsP-.js +0 -1
- package/studio/web/assets/chevron-right-CY-tr2sG.js +0 -1
- package/studio/web/assets/chunk-3NCLNEKW-BVj72ixc.js +0 -1
- package/studio/web/assets/chunk-5FCAYU7R-Dh5nylU8.js +0 -1
- package/studio/web/assets/chunk-5HE753X5-Bw-yg4kO.js +0 -1
- package/studio/web/assets/chunk-5JV3BV7I-Cy5pj3QY.js +0 -1
- package/studio/web/assets/chunk-5TONJI2A-DQOY3q1H.js +0 -2
- package/studio/web/assets/chunk-7BUUIJ7U-Bb538aSH.js +0 -1
- package/studio/web/assets/chunk-7Z6QIM7H-BJhESwQK.js +0 -10
- package/studio/web/assets/chunk-BIQX33UG-DZEsGuSn.js +0 -1
- package/studio/web/assets/chunk-CQNSW5MT-B8S09OIh.js +0 -1
- package/studio/web/assets/chunk-CYSBUYHQ-C1Rf4art.js +0 -1
- package/studio/web/assets/chunk-EMLP6XTP-RLD4nXpI.js +0 -1
- package/studio/web/assets/chunk-I66GZJ75-DHPYnKNr.js +0 -125
- package/studio/web/assets/chunk-J7OUQ5F2-DcY_kb6i.js +0 -2
- package/studio/web/assets/chunk-JG7HCLWE-BYfiSaVt.js +0 -2
- package/studio/web/assets/chunk-JQJVKLGR-DtEmbHZj.js +0 -156
- package/studio/web/assets/chunk-MOZMSUNE-XVucA-n6.js +0 -1
- package/studio/web/assets/chunk-NSK5VX7P-DDFNzCU_.js +0 -2
- package/studio/web/assets/chunk-OSBZ3O6U-CrKZOUOr.js +0 -1
- package/studio/web/assets/chunk-QBLGF6JB-CxAyS2mW.js +0 -1
- package/studio/web/assets/chunk-QR6OTTB3-Df7OCENk.js +0 -62
- package/studio/web/assets/chunk-R7FJI6CG-Cnn3gE-Y.js +0 -1
- package/studio/web/assets/chunk-RYQCIY6F-N0MDKk5G.js +0 -1
- package/studio/web/assets/chunk-U6XO7XAA-BFxjP5U3.js +0 -2
- package/studio/web/assets/chunk-UBXNYLIW-rn0yw1mp.js +0 -1
- package/studio/web/assets/chunk-W5SLKNZC-DKMlAWZk.js +0 -1
- package/studio/web/assets/chunk-WRU74C26-Dg10j8Pf.js +0 -70
- package/studio/web/assets/chunk-YOTPTUD7-D0vRKqYp.js +0 -1
- package/studio/web/assets/chunk-ZIRB5QZD-O39ZBUk3.js +0 -32
- package/studio/web/assets/classDiagram-JCYQIIEL-BrXNP4fl.js +0 -1
- package/studio/web/assets/classDiagram-v2-OCEON4UE-BrXNP4fl.js +0 -1
- package/studio/web/assets/cssMode-DipmMR_-.js +0 -1
- package/studio/web/assets/cynefin-VYW2F7L2-Ds2Fw2Y0.js +0 -1
- package/studio/web/assets/cynefinDiagram-MW4NZA55-DcTzrsC5.js +0 -62
- package/studio/web/assets/cytoscape.esm-B-NFISlW.js +0 -321
- package/studio/web/assets/dagre-Buvkdvvj.js +0 -1
- package/studio/web/assets/dagre-VZM6K2ZE-CMyJ9QPU.js +0 -4
- package/studio/web/assets/diagram-7IWD3JNH-jEGuzdp3.js +0 -30
- package/studio/web/assets/diagram-B4RE2ZJO-Ba7wC7iw.js +0 -3
- package/studio/web/assets/diagram-LBJQPF4R-Bm7Wj_dF.js +0 -24
- package/studio/web/assets/diagram-Q27KOJAE-C-gdktLC.js +0 -24
- package/studio/web/assets/diagram-UB23O5K3-COBVIEEk.js +0 -41
- package/studio/web/assets/ebnfDiagram-BXEA7PRR-G-t56mVV.js +0 -1
- package/studio/web/assets/editor-BDfNodZS.js +0 -1
- package/studio/web/assets/erDiagram-JOGREHBK-DpHzpqx1.js +0 -85
- package/studio/web/assets/eventmodeling-45OFAUF4-CLEiVx5s.js +0 -1
- package/studio/web/assets/flowDiagram-UKHOOZJN-CIxxUUxn.js +0 -1
- package/studio/web/assets/getRegistrationInfo--NLLrics.js +0 -1
- package/studio/web/assets/gitGraph-TEB2WS4Q-CZFBqwW-.js +0 -1
- package/studio/web/assets/gitGraphDiagram-DS77QQ5N-DuGnRv2R.js +0 -106
- package/studio/web/assets/html-DmSSmgE8.js +0 -1
- package/studio/web/assets/htmlMode-B2LqJw1z.js +0 -1
- package/studio/web/assets/index-BO3NaEw8.css +0 -1
- package/studio/web/assets/index-BQB9R8Ug.js +0 -810
- package/studio/web/assets/index-BnYZFLIB.css +0 -1
- package/studio/web/assets/index.lazy-CtErm5q7.js +0 -13
- package/studio/web/assets/info-DKCQHKI2--1InqQeT.js +0 -1
- package/studio/web/assets/infoDiagram-6WML65LV-DliK38kp.js +0 -2
- package/studio/web/assets/isArrayLikeObject-BHDnhloL.js +0 -1
- package/studio/web/assets/jsonMode-BVS6P5Xk.js +0 -1
- package/studio/web/assets/languageServices-Bl-BvoAb.js +0 -1
- package/studio/web/assets/line-Bom3IjHi.js +0 -1
- package/studio/web/assets/linear-DwB_ruUT.js +0 -1
- package/studio/web/assets/lspLanguageFeatures-C7XtZA_w.js +0 -4
- package/studio/web/assets/map-BaFkSB1l.js +0 -1
- package/studio/web/assets/math-Bi_r_ZWc.js +0 -1
- package/studio/web/assets/mermaid-parser.core-Dd4RYr9Q.js +0 -4
- package/studio/web/assets/mermaid.core-Bbo24DGo.js +0 -11
- package/studio/web/assets/notifications-B8rDagJM.js +0 -1
- package/studio/web/assets/notifications-CPwYKDDH.js +0 -1
- package/studio/web/assets/packet-7NZHBO7P-BGMXB0XL.js +0 -1
- package/studio/web/assets/path-fybaL0A-.js +0 -1
- package/studio/web/assets/pegDiagram-VL7TDLO6-CWEktcBB.js +0 -1
- package/studio/web/assets/pie-RZYD4A2V-DgYg3tCt.js +0 -1
- package/studio/web/assets/pieDiagram-7S7Q4E2Y-DEAmZOqY.js +0 -39
- package/studio/web/assets/pollUnlessForbidden-DIDXGBc5.js +0 -1
- package/studio/web/assets/profile-D0hB1xdm.js +0 -1
- package/studio/web/assets/purify.es-DrVcFY1Q.js +0 -3
- package/studio/web/assets/queryClient-BLhQvmWC.js +0 -1
- package/studio/web/assets/radar-I7S5WNFK-Ag-zp_Rq.js +0 -1
- package/studio/web/assets/railroad-3IZDKUUU-aibJDIDV.js +0 -1
- package/studio/web/assets/railroad-abnf-AHOZXSZD-BBMEuvIl.js +0 -1
- package/studio/web/assets/railroad-ebnf-EBAXGLYW-Be1nseej.js +0 -1
- package/studio/web/assets/railroad-peg-LSFZ7HO6-DIvD-Eyb.js +0 -1
- package/studio/web/assets/railroadDiagram-AXF67PYL-BJWrgR10.js +0 -1
- package/studio/web/assets/react-VeAY02s6.js +0 -1
- package/studio/web/assets/react-redux-Ds7wf7Ax.js +0 -5
- package/studio/web/assets/regions-y_jxsBpN.js +0 -1
- package/studio/web/assets/register-3F1Tje_F.js +0 -2
- package/studio/web/assets/register-S_PdXsoi.js +0 -2
- package/studio/web/assets/rolldown-runtime-B0Z9INg1.js +0 -1
- package/studio/web/assets/select-CKgJgpkn.js +0 -1
- package/studio/web/assets/setComponentFile-DSHbURTI.js +0 -1
- package/studio/web/assets/setLocalStorage-CD_L8p_D.js +0 -1
- package/studio/web/assets/setup-J5SrM1Kp.js +0 -2
- package/studio/web/assets/src-DUvBCJIr.js +0 -1
- package/studio/web/assets/stateDiagram-OKZ733FA-D9oPLTjO.js +0 -1
- package/studio/web/assets/stateDiagram-v2-UEYNNEHI-CSD1wbuZ.js +0 -1
- package/studio/web/assets/status-IoJkDzlx.js +0 -61
- package/studio/web/assets/string-f6JzSHaO.js +0 -1
- package/studio/web/assets/swagger-ui-react-BlgSS25O.js +0 -240
- package/studio/web/assets/swimlanes-SLNWSIFB-BpeoNE9k.js +0 -2
- package/studio/web/assets/swimlanesDiagram-ULZ7WXOC-DHxwzxpp.js +0 -8
- package/studio/web/assets/table-BvFflPWi.js +0 -1
- package/studio/web/assets/tabs-Dd_ElZ36.js +0 -1
- package/studio/web/assets/textarea-a3RnTY31.js +0 -9
- package/studio/web/assets/toggleHighContrast-CyNC3SCQ.js +0 -49
- package/studio/web/assets/tokenization-CWuvR2gh.js +0 -7
- package/studio/web/assets/treeView-QDETBFTQ-uHZ-3Fz8.js +0 -1
- package/studio/web/assets/treemap-6X3UGDF4-BnUKyy3l.js +0 -1
- package/studio/web/assets/tsMode-CslzhcVk.js +0 -11
- package/studio/web/assets/typescript-Dtnury3t.js +0 -1
- package/studio/web/assets/useAuth-DiJUZS1C.js +0 -1
- package/studio/web/assets/useEntityRestURL-qfahJnvr.js +0 -1
- package/studio/web/assets/useLocalStorage-DetQlhBe.js +0 -1
- package/studio/web/assets/vendor-datadog-XDrpA25D.js +0 -6
- package/studio/web/assets/vendor-tanstack-FsM5XZNE.js +0 -1
- package/studio/web/assets/wardley-OPB4EBWU-Da7TLC2F.js +0 -1
- package/studio/web/assets/workers-BtibQGyk.js +0 -3
- package/studio/web/assets/x-D39AGKMb.js +0 -1
- package/studio/web/assets/xml-D41zWqPl.js +0 -1
- package/studio/web/assets/yaml-BFQ3mF1U.js +0 -1
- /package/studio/web/assets/{editor-jjEx9u7D.css → register-jjEx9u7D.css} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harperfast/harper",
|
|
3
3
|
"description": "Harper is an open-source Node.js performance platform that unifies database, cache, application, and messaging layers into one in-memory process.",
|
|
4
|
-
"version": "5.2.
|
|
4
|
+
"version": "5.2.8",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://harper.fast",
|
|
7
7
|
"bugs": {
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"@fastify/cors": "^11.2.0",
|
|
180
180
|
"@fastify/static": "^9.1.3",
|
|
181
181
|
"@harperfast/extended-iterable": "1.0.3",
|
|
182
|
-
"@harperfast/rocksdb-js": "2.
|
|
182
|
+
"@harperfast/rocksdb-js": "2.8.0",
|
|
183
183
|
"@harperfast/skills": "^1.10.8",
|
|
184
184
|
"@turf/area": "6.5.0",
|
|
185
185
|
"@turf/boolean-contains": "6.5.0",
|
|
@@ -223,7 +223,7 @@
|
|
|
223
223
|
"minimist": "1.2.8",
|
|
224
224
|
"moment": "2.30.1",
|
|
225
225
|
"mqtt-packet": "~9.0.1",
|
|
226
|
-
"msgpackr": "2.0.
|
|
226
|
+
"msgpackr": "2.0.6",
|
|
227
227
|
"needle": "3.5.0",
|
|
228
228
|
"node-forge": "^1.3.1",
|
|
229
229
|
"node-stream-zip": "1.16.0",
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
"ses": "^1.15.0",
|
|
245
245
|
"stream-chain": "2.2.5",
|
|
246
246
|
"stream-json": "1.9.1",
|
|
247
|
-
"structon": "1.0
|
|
247
|
+
"structon": "1.1.0",
|
|
248
248
|
"systeminformation": "^5.31.4",
|
|
249
249
|
"tar-fs": "^3.1.2",
|
|
250
250
|
"tar-stream": "^3.1.8",
|
package/resources/DESIGN.md
CHANGED
|
@@ -166,6 +166,11 @@ Tests: `../unitTests/resources/defineResource.test.js`, `../unitTests/resources/
|
|
|
166
166
|
|
|
167
167
|
## Conventions
|
|
168
168
|
|
|
169
|
+
- A record's `toJSON` is a response projection, not durable state. `recordUpdater` (and the cache-fill
|
|
170
|
+
and audit paths feeding it) projects records to stored fields via `storedFieldsOnly`, so no durable
|
|
171
|
+
form carries a resolver-owned (`@computed`/`@relationship`) name; materialization skips such names
|
|
172
|
+
when promoting a decoded record (`assignStoredFields`), which is what keeps rows written by affected
|
|
173
|
+
releases readable. See harper#2359 and `integrationTests/resources/cachedComputedAttribute.test.ts`.
|
|
169
174
|
- **Never** remove `transactional()` from a static method on `Resource` — it owns transaction context lifetime.
|
|
170
175
|
- New `Resource` subclasses should override **instance** methods (`get`, `put`, ...) for behavior; static methods are the protocol entry points and stay generic.
|
|
171
176
|
- **Overriding a static entry point takes over its whole contract.** Assigning `static post`/`put`/`patch` on a subclass shadows the `transactional()`-wrapped static, so none of that wrapper runs — including the `when(data, ...)` that resolves `data` and the `allowCreate`/`allowUpdate` gate. That is by design (it is how `login.ts` implements a deliberately pre-authentication endpoint), and it means an override owns two obligations the wrapper would otherwise have met:
|
|
@@ -3,7 +3,7 @@ import { RocksDatabase, type RocksDatabaseOptions, constants, type Store } from
|
|
|
3
3
|
const FRESH_VERSION_FLAG = constants.FRESH_VERSION_FLAG;
|
|
4
4
|
import { WeakLRUCache } from 'weak-lru-cache';
|
|
5
5
|
import { when } from '../utility/when.ts';
|
|
6
|
-
import { entryMap, METADATA, type Entry } from './RecordEncoder.ts';
|
|
6
|
+
import { assignStoredFields, entryMap, METADATA, type Entry } from './RecordEncoder.ts';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* RocksDatabase subclass that owns all primary-store behaviour for Harper tables:
|
|
@@ -60,7 +60,7 @@ export class PrimaryRocksDatabase extends RocksDatabase {
|
|
|
60
60
|
if (entry.value.constructor === Object && this.#enc.structPrototype) {
|
|
61
61
|
const originalValue = entry.value;
|
|
62
62
|
entry.value = new this.#enc.structPrototype.constructor();
|
|
63
|
-
|
|
63
|
+
assignStoredFields(entry.value, originalValue, this.#enc);
|
|
64
64
|
}
|
|
65
65
|
if (typeof entry.value === 'object' && entry.value !== null) {
|
|
66
66
|
entryMap.set(entry.value, entry);
|
|
@@ -164,7 +164,7 @@ export class PrimaryRocksDatabase extends RocksDatabase {
|
|
|
164
164
|
if (entry.value?.constructor === Object && enc.structPrototype) {
|
|
165
165
|
const originalValue = entry.value;
|
|
166
166
|
entry.value = new enc.structPrototype.constructor();
|
|
167
|
-
|
|
167
|
+
assignStoredFields(entry.value, originalValue, enc);
|
|
168
168
|
}
|
|
169
169
|
return entry;
|
|
170
170
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Encoder } from 'msgpackr';
|
|
9
|
-
import { createStructon } from 'structon';
|
|
9
|
+
import { createStructon, SOURCE_SYMBOL } from 'structon';
|
|
10
10
|
import {
|
|
11
11
|
HAS_PREVIOUS_RESIDENCY_ID,
|
|
12
12
|
HAS_CURRENT_RESIDENCY_ID,
|
|
@@ -123,12 +123,86 @@ let timestampNextEncoding = 0,
|
|
|
123
123
|
additionalAuditRefsNextEncoding: Array<{ version: number; nodeId: number }> | undefined;
|
|
124
124
|
// tracking metadata with a singleton works better than trying to alter response of getEntry/get and coordinating that across caching layers
|
|
125
125
|
export let lastMetadata: Entry | null = null;
|
|
126
|
+
/**
|
|
127
|
+
* A resolver owns its attribute's name, so no durable form of a record may carry a value under it.
|
|
128
|
+
* A value gets there either through the response `toJSON` the table installs on the record prototype
|
|
129
|
+
* (msgpackr consults an instance's toJSON when it encodes one) or as an own key from a source or
|
|
130
|
+
* peer payload.
|
|
131
|
+
*/
|
|
132
|
+
export function storedFieldsOnly(encoder: any, record: any) {
|
|
133
|
+
if (record === null || typeof record !== 'object') return record;
|
|
134
|
+
// Optional: this also runs for a store whose encode hook was grafted onto a foreign encoder
|
|
135
|
+
// (copyDb's migration target), which carries no table schema.
|
|
136
|
+
const resolved = encoder?.resolvedAttributeNames;
|
|
137
|
+
if (resolved === undefined) return record;
|
|
138
|
+
const resolvedList = encoder.resolvedAttributeNamesList ?? Array.from(resolved);
|
|
139
|
+
// A typed-struct instance keeps its stored fields as accessors on a structon-generated child
|
|
140
|
+
// prototype carrying structon's own toJSON, so it never reaches the response projection — and
|
|
141
|
+
// copying its own keys would encode an empty record.
|
|
142
|
+
let project =
|
|
143
|
+
encoder.surfacedToJSON !== undefined &&
|
|
144
|
+
record.toJSON === encoder.surfacedToJSON &&
|
|
145
|
+
record[SOURCE_SYMBOL] === undefined;
|
|
146
|
+
if (!project && typeof record.toJSON === 'function' && record[SOURCE_SYMBOL] === undefined) {
|
|
147
|
+
// A class instance with its own serialization: the encoder will consult that toJSON, so the
|
|
148
|
+
// projection has to run on its OUTPUT, or the serialized form smuggles resolver-owned keys past
|
|
149
|
+
// a check that only saw the instance. A non-object (or self) result is left for the encoder,
|
|
150
|
+
// which invokes toJSON again — serializers are assumed pure.
|
|
151
|
+
const json = record.toJSON();
|
|
152
|
+
if (json !== record && json !== null && typeof json === 'object') record = json;
|
|
153
|
+
}
|
|
154
|
+
if (!project) {
|
|
155
|
+
for (let i = 0; i < resolvedList.length; i++) {
|
|
156
|
+
if (Object.hasOwn(record, resolvedList[i])) {
|
|
157
|
+
project = true;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!project) return record;
|
|
163
|
+
const stored = {};
|
|
164
|
+
for (const key of Object.keys(record)) {
|
|
165
|
+
if (resolved.has(key)) continue;
|
|
166
|
+
// '__proto__' as an own key must stay a data property: plain assignment would run the inherited
|
|
167
|
+
// setter, dropping the field from the durable write and swapping the temporary's prototype.
|
|
168
|
+
if (key === '__proto__')
|
|
169
|
+
Object.defineProperty(stored, key, { value: record[key], enumerable: true, writable: true, configurable: true });
|
|
170
|
+
else stored[key] = record[key];
|
|
171
|
+
}
|
|
172
|
+
return stored;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* A resolver-owned name is skipped rather than assigned during record-instance promotion: through a
|
|
177
|
+
* read-only resolver the assignment throws, and through a writable one (a many-to-one
|
|
178
|
+
* `@relationship`) it would derive a foreign key from the stale stored value.
|
|
179
|
+
*/
|
|
180
|
+
export function assignStoredFields(target: any, source: any, encoder: any) {
|
|
181
|
+
const resolved = encoder?.resolvedAttributeNames;
|
|
182
|
+
if (resolved === undefined) return Object.assign(target, source);
|
|
183
|
+
// Own keys, matching the Object.assign fallback above and storedFieldsOnly: a decoded plain
|
|
184
|
+
// object has no inherited enumerables of its own, so walking the chain could only ever pick up
|
|
185
|
+
// somebody else's (a polluted Object.prototype included).
|
|
186
|
+
for (const key of Object.keys(source)) {
|
|
187
|
+
if (resolved.has(key)) continue;
|
|
188
|
+
if (key === '__proto__')
|
|
189
|
+
Object.defineProperty(target, key, { value: source[key], enumerable: true, writable: true, configurable: true });
|
|
190
|
+
else target[key] = source[key];
|
|
191
|
+
}
|
|
192
|
+
return target;
|
|
193
|
+
}
|
|
194
|
+
|
|
126
195
|
export class RecordEncoder extends StructonEncoder {
|
|
127
196
|
rootStore: any;
|
|
128
197
|
declare saveStructures: any;
|
|
129
198
|
declare getStructures: any;
|
|
130
199
|
declare _writeStruct: any;
|
|
131
200
|
structureUpdate?: any;
|
|
201
|
+
// Set by TableResource.updatedAttributes. Undefined for a store with no resolved attributes, which
|
|
202
|
+
// is what keeps the projection off that store's writes entirely.
|
|
203
|
+
resolvedAttributeNames?: Set<string>;
|
|
204
|
+
resolvedAttributeNamesList?: string[];
|
|
205
|
+
surfacedToJSON?: () => any;
|
|
132
206
|
isRocksDB: boolean;
|
|
133
207
|
name: string;
|
|
134
208
|
useVersions: boolean;
|
|
@@ -539,7 +613,7 @@ export function handleLocalTimeForGets(store, rootStore) {
|
|
|
539
613
|
// if an object was deserialized as a plain object, give it the right prototype for computed properties to be accessible
|
|
540
614
|
const originalValue = entry.value;
|
|
541
615
|
entry.value = new store.encoder.structPrototype.constructor();
|
|
542
|
-
|
|
616
|
+
assignStoredFields(entry.value, originalValue, store.encoder);
|
|
543
617
|
}
|
|
544
618
|
entryMap.set(entry.value, entry); // allow the record to access the entry
|
|
545
619
|
}
|
|
@@ -591,7 +665,7 @@ export function handleLocalTimeForGets(store, rootStore) {
|
|
|
591
665
|
// if an object was deserialized as a plain object, give it the right prototype for computed properties to be accessible
|
|
592
666
|
const originalValue = entry.value;
|
|
593
667
|
entry.value = new store.encoder.structPrototype.constructor();
|
|
594
|
-
|
|
668
|
+
assignStoredFields(entry.value, originalValue, store.encoder);
|
|
595
669
|
}
|
|
596
670
|
}
|
|
597
671
|
return entry;
|
|
@@ -708,6 +782,10 @@ export function recordUpdater(store, tableId, auditStore) {
|
|
|
708
782
|
// harper#1309: reset so a record===undefined call (delete/no-op) cannot carry stale bytes
|
|
709
783
|
// into the audit encodedRecord or write-size analytics of this call.
|
|
710
784
|
lastValueEncoding = undefined;
|
|
785
|
+
// Every durable form of the record — the stored value, the audit entry's encodedRecord and so the
|
|
786
|
+
// transaction log and replication payload — comes from this record, so projecting it here covers
|
|
787
|
+
// them all; nested values keep their own toJSON serialization.
|
|
788
|
+
record = storedFieldsOnly(store.encoder, record);
|
|
711
789
|
const isRocksDB = store instanceof RocksDatabase;
|
|
712
790
|
// determine if and how we apply the local timestamp
|
|
713
791
|
if (isRocksDB) {
|
|
@@ -809,6 +887,10 @@ export function recordUpdater(store, tableId, auditStore) {
|
|
|
809
887
|
if (audit) {
|
|
810
888
|
const username = typeof options?.user === 'string' ? options.user : options?.user?.username;
|
|
811
889
|
if (auditRecord) {
|
|
890
|
+
// The audit encodedRecord is durable record state too (it is the transaction log and the
|
|
891
|
+
// replication payload), so it takes the same projection — except for message/publish
|
|
892
|
+
// entries, whose auditRecord IS the published payload and must reach subscribers verbatim.
|
|
893
|
+
if (type !== 'message' && type !== 'publish') auditRecord = storedFieldsOnly(store.encoder, auditRecord);
|
|
812
894
|
encodeBlobsWithFilePath(() => store.encoder.encode(auditRecord), id, store.rootStore);
|
|
813
895
|
if (blobsWereEncoded) {
|
|
814
896
|
extendedType |= HAS_BLOBS;
|
|
@@ -117,7 +117,14 @@ export class RocksTransactionLogStore extends EventEmitter {
|
|
|
117
117
|
}
|
|
118
118
|
entryBinary = createAuditEntry(auditRecord, position);
|
|
119
119
|
}
|
|
120
|
-
if (this.listenerCount('aftercommit'))
|
|
120
|
+
if (this.listenerCount('aftercommit')) {
|
|
121
|
+
if (!(auditRecord instanceof Uint8Array)) {
|
|
122
|
+
const txnTimestamp = options.transaction.getTimestamp?.();
|
|
123
|
+
if (txnTimestamp != null) auditRecord.localTime = txnTimestamp;
|
|
124
|
+
auditRecord.recordVersion = auditRecord.version;
|
|
125
|
+
}
|
|
126
|
+
(options.transaction.logEntries ??= []).push(auditRecord);
|
|
127
|
+
}
|
|
121
128
|
// One commit hook per transaction handles both deferred side effects — the `aftercommit` emit and the
|
|
122
129
|
// per-(log, table) structureVersion watermark advances — so they apply only after a durable commit (never
|
|
123
130
|
// on an aborted/discarded transaction). This store is the sole setter of transaction.onCommit.
|
|
@@ -414,7 +421,10 @@ export class RocksTransactionLogStore extends EventEmitter {
|
|
|
414
421
|
position += 8;
|
|
415
422
|
}
|
|
416
423
|
const auditRecord = readAuditEntry(data, position, undefined);
|
|
424
|
+
// version stays the log key (replication resume relies on version === log key);
|
|
425
|
+
// the record's own version survives as recordVersion
|
|
417
426
|
auditRecord.version = timestamp;
|
|
427
|
+
auditRecord.localTime = timestamp;
|
|
418
428
|
auditRecord.endTxn = endTxn;
|
|
419
429
|
auditRecord.previousResidencyId = previousResidencyId;
|
|
420
430
|
auditRecord.previousVersion = previousVersion;
|
package/resources/Table.ts
CHANGED
|
@@ -72,7 +72,15 @@ import { getWorkerIndex, getWorkerCount } from '../server/threads/manageThreads.
|
|
|
72
72
|
import { HAS_BLOBS, auditRetention, removeAuditEntry } from './auditStore.ts';
|
|
73
73
|
import { buildEmbedBefore, createDefaultEmbedder, type EmbedAttribute, type Embedder } from './models/embedHook.ts';
|
|
74
74
|
import { autoCast, autoCastBooleanStrict } from '../utility/common_utils.ts';
|
|
75
|
-
import {
|
|
75
|
+
import {
|
|
76
|
+
recordUpdater,
|
|
77
|
+
removeEntry,
|
|
78
|
+
PENDING_LOCAL_TIME,
|
|
79
|
+
RecordObject,
|
|
80
|
+
type Entry,
|
|
81
|
+
entryMap,
|
|
82
|
+
storedFieldsOnly,
|
|
83
|
+
} from './RecordEncoder.ts';
|
|
76
84
|
import { recordAction, recordActionBinary } from './analytics/write.ts';
|
|
77
85
|
import { rebuildUpdateBefore } from './crdt.ts';
|
|
78
86
|
import { appendHeader } from '../server/serverHelpers/Headers.ts';
|
|
@@ -453,6 +461,18 @@ export function makeTable(options) {
|
|
|
453
461
|
// it, so such a table takes the guarded serialization path rather than the raw fast path.
|
|
454
462
|
let hasSurfacedComputed = false;
|
|
455
463
|
let runningRecordExpiration: boolean;
|
|
464
|
+
const reportedResolverCollisions = new Set<string>();
|
|
465
|
+
// Reached from record materialization, so it can never be the reason a record fails to load: the
|
|
466
|
+
// name is marked before the log call, and a throwing log sink is swallowed.
|
|
467
|
+
function reportResolverCollision(name: string) {
|
|
468
|
+
if (reportedResolverCollisions.has(name)) return;
|
|
469
|
+
reportedResolverCollisions.add(name);
|
|
470
|
+
try {
|
|
471
|
+
logger.warn?.(
|
|
472
|
+
`Table "${tableName}" has a stored value under "${name}", which is a computed attribute; the stored value is being discarded and the computed value used instead`
|
|
473
|
+
);
|
|
474
|
+
} catch {}
|
|
475
|
+
}
|
|
456
476
|
const isRocksDB = primaryStore instanceof RocksDatabase;
|
|
457
477
|
type BigInt64ArrayAndMaxSafeId = BigInt64Array & { maxSafeId: number };
|
|
458
478
|
let idIncrementer: BigInt64ArrayAndMaxSafeId;
|
|
@@ -4113,7 +4133,8 @@ export function makeTable(options) {
|
|
|
4113
4133
|
// been written, so are fresh in memory.
|
|
4114
4134
|
const entry: Entry = primaryStore.getEntry(id);
|
|
4115
4135
|
if (entry) {
|
|
4116
|
-
|
|
4136
|
+
// staleness is a record-version comparison; auditRecord.version is the log key on RocksDB
|
|
4137
|
+
if (entry.version !== (auditRecord.recordVersion ?? auditRecord.version)) return; // out of order event, with old update, don't send anything
|
|
4117
4138
|
value = entry.value;
|
|
4118
4139
|
type = entry.metadataFlags & INVALIDATED ? 'invalidate' : value ? 'put' : 'delete';
|
|
4119
4140
|
} else {
|
|
@@ -4990,6 +5011,9 @@ export function makeTable(options) {
|
|
|
4990
5011
|
for (const attribute of this.attributes) {
|
|
4991
5012
|
if (attribute.isPrimaryKey) primaryKeyAttribute = attribute;
|
|
4992
5013
|
attribute.resolve = null; // reset this
|
|
5014
|
+
// Also the setter, or a reload that turns a @relationship into a @computed keeps the
|
|
5015
|
+
// relationship's setter and writes a foreign key from a computed assignment.
|
|
5016
|
+
attribute.set = null;
|
|
4993
5017
|
const relationship = attribute.relationship;
|
|
4994
5018
|
const computed = attribute.computed;
|
|
4995
5019
|
// Register the default embedder unless an author override is set. Sits outside
|
|
@@ -5151,14 +5175,19 @@ export function makeTable(options) {
|
|
|
5151
5175
|
enumerableAttributeNames = [];
|
|
5152
5176
|
enumerableRelationDefs.clear();
|
|
5153
5177
|
hasSurfacedComputed = false;
|
|
5178
|
+
const resolvedAttributeNames: string[] = [];
|
|
5154
5179
|
for (const attribute of attributes) {
|
|
5155
5180
|
const name = attribute.name;
|
|
5156
5181
|
if (attribute.resolve) {
|
|
5182
|
+
resolvedAttributeNames.push(name);
|
|
5157
5183
|
Object.defineProperty(primaryStore.encoder.structPrototype, name, {
|
|
5158
5184
|
get() {
|
|
5159
5185
|
return attribute.resolve(this, contextStorage.getStore()); // it is only possible to get the context from ALS, we don't have a direct reference to the current context
|
|
5160
5186
|
},
|
|
5161
5187
|
set(related) {
|
|
5188
|
+
// A read-only resolver must never be the reason a record fails to materialize — the
|
|
5189
|
+
// same reason the one-to-many branch above installs a no-op.
|
|
5190
|
+
if (!attribute.set) return reportResolverCollision(name);
|
|
5162
5191
|
return attribute.set(this, related);
|
|
5163
5192
|
},
|
|
5164
5193
|
configurable: true,
|
|
@@ -5184,6 +5213,12 @@ export function makeTable(options) {
|
|
|
5184
5213
|
if (enumerableAttributeNames.length > 0)
|
|
5185
5214
|
installEnumerableToJSON(primaryStore.encoder.structPrototype, this, hasSurfacedComputed);
|
|
5186
5215
|
else if (primaryStore.encoder.structPrototype.toJSON) delete primaryStore.encoder.structPrototype.toJSON;
|
|
5216
|
+
// Undefined rather than an empty set for a table with no resolved attributes: that is the
|
|
5217
|
+
// check which keeps the projection off an unaffected store's write path.
|
|
5218
|
+
primaryStore.encoder.resolvedAttributeNames =
|
|
5219
|
+
resolvedAttributeNames.length > 0 ? new Set(resolvedAttributeNames) : undefined;
|
|
5220
|
+
primaryStore.encoder.resolvedAttributeNamesList = resolvedAttributeNames;
|
|
5221
|
+
primaryStore.encoder.surfacedToJSON = primaryStore.encoder.structPrototype.toJSON;
|
|
5187
5222
|
}
|
|
5188
5223
|
// #section: computed-history
|
|
5189
5224
|
static setComputedAttribute(attribute_name, resolver) {
|
|
@@ -5997,6 +6032,31 @@ export function makeTable(options) {
|
|
|
5997
6032
|
// before stamping the primary key and created/updated times below (records are immutable —
|
|
5998
6033
|
// 5.2 record caching relies on it — so we must not write through the frozen object).
|
|
5999
6034
|
if (isFrozenRecordObject(updatedRecord)) updatedRecord = { ...updatedRecord };
|
|
6035
|
+
// A writable resolver (a relationship) keeps its meaning for source payloads: a source
|
|
6036
|
+
// returning the related object instead of the foreign key gets the key derived, the way
|
|
6037
|
+
// the promotion setter used to. Derivation runs against a probe first — a malformed
|
|
6038
|
+
// value (a scalar, an object without the related primary key) derives undefined, and
|
|
6039
|
+
// applying that would durably wipe the foreign key. The projection then drops the
|
|
6040
|
+
// resolver-owned key itself, so the cache-fill response cannot be the one read
|
|
6041
|
+
// reporting the source's value.
|
|
6042
|
+
const resolvedNames = primaryStore.encoder.resolvedAttributeNamesList;
|
|
6043
|
+
if (resolvedNames) {
|
|
6044
|
+
for (const name of resolvedNames) {
|
|
6045
|
+
if (Object.hasOwn(updatedRecord, name)) {
|
|
6046
|
+
const resolvedAttribute = findAttribute(attributes, name);
|
|
6047
|
+
if (resolvedAttribute?.set && updatedRecord[name] != null) {
|
|
6048
|
+
const probe = {};
|
|
6049
|
+
resolvedAttribute.set(probe, updatedRecord[name]);
|
|
6050
|
+
for (const key in probe) {
|
|
6051
|
+
const derived = probe[key];
|
|
6052
|
+
const usable = Array.isArray(derived) ? derived.every((one) => one != null) : derived != null;
|
|
6053
|
+
if (usable) updatedRecord[key] = derived;
|
|
6054
|
+
}
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
updatedRecord = storedFieldsOnly(primaryStore.encoder, updatedRecord);
|
|
6000
6060
|
if (primaryKey && updatedRecord[primaryKey] !== id) updatedRecord[primaryKey] = id;
|
|
6001
6061
|
}
|
|
6002
6062
|
resolved = true;
|
package/resources/auditStore.ts
CHANGED
|
@@ -34,7 +34,8 @@ initSync();
|
|
|
34
34
|
|
|
35
35
|
export type AuditRecord = {
|
|
36
36
|
version: number;
|
|
37
|
-
|
|
37
|
+
recordVersion?: number; // the record's own version; on RocksDB reads `version` becomes the log key, so record identity uses this
|
|
38
|
+
localTime: number; // log position: LMDB audit-store key; RocksDB transaction-log timestamp
|
|
38
39
|
type: string;
|
|
39
40
|
encodedRecord?: Buffer;
|
|
40
41
|
extendedType?: number;
|
|
@@ -620,6 +621,7 @@ export function readAuditEntry(buffer: Uint8Array, start = 0, end = undefined):
|
|
|
620
621
|
return buffer.subarray(recordIdStart, recordIdEnd);
|
|
621
622
|
},
|
|
622
623
|
version,
|
|
624
|
+
recordVersion: version,
|
|
623
625
|
previousVersion,
|
|
624
626
|
get user() {
|
|
625
627
|
try {
|
package/resources/graphql.ts
CHANGED
|
@@ -351,4 +351,4 @@ async function processGraphQLSchema(gqlContent, urlPath, filePath, resources) {
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
// useful for testing
|
|
354
|
-
export const loadGQLSchema = (content) => processGraphQLSchema(content, null,
|
|
354
|
+
export const loadGQLSchema = (content) => processGraphQLSchema(content, null, '<inline-schema>', new Resources());
|
package/resources/tracked.ts
CHANGED
|
@@ -45,6 +45,10 @@ export function assignTrackedAccessors(Target, typeDef, useFullPropertyProxy = f
|
|
|
45
45
|
return attribute.resolve(this, this.getContext?.());
|
|
46
46
|
},
|
|
47
47
|
set(related) {
|
|
48
|
+
// Unlike the struct-prototype accessor (which tolerates a stored collision so a record can
|
|
49
|
+
// still load), this is a user assignment to a resolved attribute, and a read-only resolver
|
|
50
|
+
// (a scalar @computed has no attribute.set) has nowhere to put it (harper#2359).
|
|
51
|
+
if (!attribute.set) throw new ClientError(`${name} is a computed attribute and can not be assigned`);
|
|
48
52
|
return attribute.set(this, related);
|
|
49
53
|
},
|
|
50
54
|
configurable: true,
|
|
@@ -180,6 +180,9 @@ function notifyFromTransactionData(subscriptions, auditLogIterable?, allowYield
|
|
|
180
180
|
const auditRecord = result.value;
|
|
181
181
|
const timestamp: number = auditRecord.localTime ?? auditRecord.version;
|
|
182
182
|
subscriptions.lastTxnTime = timestamp;
|
|
183
|
+
// the transaction extent: RocksDB entries committed together share the log key (record
|
|
184
|
+
// versions may differ); LMDB's localTime is a per-entry audit key, so version delimits there
|
|
185
|
+
const txnKey = auditStore.reusableIterable ? timestamp : auditRecord.version;
|
|
183
186
|
if (ACTIONS_OF_INTEREST.includes(auditRecord.type)) {
|
|
184
187
|
const tableSubscriptions = subscriptions[auditRecord.tableId];
|
|
185
188
|
if (tableSubscriptions) {
|
|
@@ -204,7 +207,7 @@ function notifyFromTransactionData(subscriptions, auditLogIterable?, allowYield
|
|
|
204
207
|
}
|
|
205
208
|
try {
|
|
206
209
|
let beginTxn;
|
|
207
|
-
if (subscription.supportsTransactions && subscription.txnInProgress !==
|
|
210
|
+
if (subscription.supportsTransactions && subscription.txnInProgress !== txnKey) {
|
|
208
211
|
// if the subscriber supports transactions, we mark this as the beginning of a new transaction
|
|
209
212
|
// tracking the subscription so that we can delimit the transaction on next transaction
|
|
210
213
|
// (with a beginTxn flag, which may be on an endTxn event)
|
|
@@ -214,10 +217,7 @@ function notifyFromTransactionData(subscriptions, auditLogIterable?, allowYield
|
|
|
214
217
|
if (!subscribersWithTxns) subscribersWithTxns = [subscription];
|
|
215
218
|
else subscribersWithTxns.push(subscription);
|
|
216
219
|
}
|
|
217
|
-
|
|
218
|
-
// are part of the same transaction, and when the version changes, we know it is a new
|
|
219
|
-
// transaction
|
|
220
|
-
subscription.txnInProgress = auditRecord.version;
|
|
220
|
+
subscription.txnInProgress = txnKey;
|
|
221
221
|
}
|
|
222
222
|
subscription.listener(recordId, auditRecord, timestamp, beginTxn);
|
|
223
223
|
} catch (error) {
|