@harperfast/harper-pro 5.0.0-alpha.9 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/core/.dockerignore +9 -0
  2. package/core/.git-blame-ignore-revs +2 -0
  3. package/core/.github/workflows/create-release.yaml +4 -4
  4. package/core/.github/workflows/integration-tests.yml +12 -10
  5. package/core/.github/workflows/notify-release-published.yaml +1 -1
  6. package/core/.github/workflows/publish-docker.yaml +2 -2
  7. package/core/.github/workflows/publish-npm.yaml +4 -4
  8. package/core/CONTRIBUTING.md +1 -1
  9. package/core/Dockerfile +62 -0
  10. package/core/build-tools/build-studio.sh +12 -0
  11. package/core/build-tools/build.sh +22 -0
  12. package/core/build-tools/download-prebuilds.js +13 -0
  13. package/core/components/Logger.ts +14 -0
  14. package/core/components/Scope.ts +35 -11
  15. package/core/components/componentLoader.ts +27 -10
  16. package/core/components/operations.js +10 -2
  17. package/core/config/configUtils.js +1 -1
  18. package/core/dataLayer/CreateTableObject.js +2 -2
  19. package/core/dataLayer/schema.js +7 -5
  20. package/core/dataLayer/schemaDescribe.js +1 -1
  21. package/core/index.d.ts +11 -6
  22. package/core/index.js +2 -0
  23. package/core/integrationTests/README.md +24 -0
  24. package/core/integrationTests/apiTests/tests/10_otherRoleTests.mjs +6 -6
  25. package/core/integrationTests/apiTests/tests/12_configuration.mjs +1 -1
  26. package/core/integrationTests/apiTests/tests/14_tokenAuth.mjs +2 -2
  27. package/core/integrationTests/apiTests/tests/16_terminologyUpdates.mjs +4 -4
  28. package/core/integrationTests/apiTests/tests/1_environmentSetup.mjs +1 -1
  29. package/core/integrationTests/apiTests/tests/2_dataLoad.mjs +4 -4
  30. package/core/integrationTests/apiTests/tests/3_sqlTests.mjs +3 -3
  31. package/core/integrationTests/apiTests/tests/4_noSqlTests.mjs +12 -12
  32. package/core/integrationTests/apiTests/tests/5_noSqlRoleTesting.mjs +8 -8
  33. package/core/integrationTests/apiTests/tests/7_jobsAndJobRoleTesting.mjs +10 -12
  34. package/core/integrationTests/apiTests/tests/8_deleteTests.mjs +8 -8
  35. package/core/integrationTests/apiTests/tests/9_transactions.mjs +2 -2
  36. package/core/integrationTests/apiTests/utils/search.mjs +1 -1
  37. package/core/integrationTests/apiTests/utils/table.mjs +1 -1
  38. package/core/integrationTests/server/operation-user-rbac.test.ts +1 -1
  39. package/core/integrationTests/server/operations-server.test.ts +1 -1
  40. package/core/integrationTests/server/storage-reclamation.test.ts +1 -1
  41. package/core/integrationTests/utils/README.md +1 -15
  42. package/core/integrationTests/utils/harperLifecycle.ts +33 -21
  43. package/core/package.json +23 -5
  44. package/core/resources/ResourceInterface.ts +1 -1
  45. package/core/resources/Table.ts +26 -11
  46. package/core/resources/analytics/read.ts +33 -26
  47. package/core/resources/analytics/write.ts +3 -7
  48. package/core/resources/databases.ts +29 -18
  49. package/core/resources/search.ts +10 -5
  50. package/core/security/auth.ts +1 -1
  51. package/core/security/jsLoader.ts +302 -83
  52. package/core/security/keys.js +11 -12
  53. package/core/security/user.ts +3 -3
  54. package/core/server/REST.ts +18 -2
  55. package/core/server/Server.ts +2 -1
  56. package/core/server/fastifyRoutes.ts +1 -0
  57. package/core/server/http.ts +13 -9
  58. package/core/server/loadRootComponents.js +1 -0
  59. package/core/server/operationsServer.ts +2 -1
  60. package/core/server/threads/manageThreads.js +49 -35
  61. package/core/static/defaultConfig.yaml +3 -0
  62. package/core/unitTests/apiTests/RESTProperties-test.mjs +2 -2
  63. package/core/unitTests/apiTests/basicREST-test.mjs +2 -2
  64. package/core/unitTests/components/Scope.test.js +54 -16
  65. package/core/unitTests/components/fixtures/testJSWithDeps/child-dir/circular.js +4 -0
  66. package/core/unitTests/components/fixtures/testJSWithDeps/child-dir/in-child-dir.js +4 -0
  67. package/core/unitTests/components/fixtures/testJSWithDeps/child-dir/typestrip.ts +2 -0
  68. package/core/unitTests/components/fixtures/testJSWithDeps/resources.js +43 -0
  69. package/core/unitTests/components/fixtures/testJSWithDeps/test-child-process.js +18 -0
  70. package/core/unitTests/components/globalIsolation.test.js +87 -1
  71. package/core/unitTests/config/configUtils.test.js +1 -260
  72. package/core/unitTests/resources/query.test.js +16 -1
  73. package/core/unitTests/resources/vectorIndex.test.js +1 -1
  74. package/core/unitTests/server/fastifyRoutes/operations.test.js +1 -1
  75. package/core/unitTests/testUtils.js +0 -17
  76. package/core/utility/hdbTerms.ts +3 -0
  77. package/core/utility/installation.ts +2 -5
  78. package/core/utility/lmdb/commonUtility.js +21 -10
  79. package/dist/core/{resources/ResourceInterfaceV2.js → components/Logger.js} +1 -1
  80. package/dist/core/components/Logger.js.map +1 -0
  81. package/dist/core/components/Scope.js +18 -10
  82. package/dist/core/components/Scope.js.map +1 -1
  83. package/dist/core/components/componentLoader.js +17 -10
  84. package/dist/core/components/componentLoader.js.map +1 -1
  85. package/dist/core/components/operations.js +2 -2
  86. package/dist/core/components/operations.js.map +1 -1
  87. package/dist/core/config/configUtils.js +1 -1
  88. package/dist/core/config/configUtils.js.map +1 -1
  89. package/dist/core/dataLayer/CreateTableObject.js +2 -2
  90. package/dist/core/dataLayer/CreateTableObject.js.map +1 -1
  91. package/dist/core/dataLayer/schema.js +6 -5
  92. package/dist/core/dataLayer/schema.js.map +1 -1
  93. package/dist/core/dataLayer/schemaDescribe.js +1 -1
  94. package/dist/core/dataLayer/schemaDescribe.js.map +1 -1
  95. package/dist/core/index.js +2 -0
  96. package/dist/core/index.js.map +1 -1
  97. package/dist/core/resources/Table.js +12 -4
  98. package/dist/core/resources/Table.js.map +1 -1
  99. package/dist/core/resources/analytics/read.js +32 -22
  100. package/dist/core/resources/analytics/read.js.map +1 -1
  101. package/dist/core/resources/analytics/write.js +3 -6
  102. package/dist/core/resources/analytics/write.js.map +1 -1
  103. package/dist/core/resources/databases.js +22 -19
  104. package/dist/core/resources/databases.js.map +1 -1
  105. package/dist/core/resources/search.js +11 -5
  106. package/dist/core/resources/search.js.map +1 -1
  107. package/dist/core/security/auth.js +1 -1
  108. package/dist/core/security/auth.js.map +1 -1
  109. package/dist/core/security/jsLoader.js +265 -73
  110. package/dist/core/security/jsLoader.js.map +1 -1
  111. package/dist/core/security/keys.js +11 -12
  112. package/dist/core/security/keys.js.map +1 -1
  113. package/dist/core/security/user.js +3 -3
  114. package/dist/core/security/user.js.map +1 -1
  115. package/dist/core/server/REST.js +16 -2
  116. package/dist/core/server/REST.js.map +1 -1
  117. package/dist/core/server/Server.js.map +1 -1
  118. package/dist/core/server/fastifyRoutes.js +2 -0
  119. package/dist/core/server/fastifyRoutes.js.map +1 -1
  120. package/dist/core/server/http.js +12 -6
  121. package/dist/core/server/http.js.map +1 -1
  122. package/dist/core/server/loadRootComponents.js +1 -0
  123. package/dist/core/server/loadRootComponents.js.map +1 -1
  124. package/dist/core/server/operationsServer.js +3 -1
  125. package/dist/core/server/operationsServer.js.map +1 -1
  126. package/dist/core/server/threads/manageThreads.js +50 -35
  127. package/dist/core/server/threads/manageThreads.js.map +1 -1
  128. package/dist/core/utility/hdbTerms.js +3 -0
  129. package/dist/core/utility/hdbTerms.js.map +1 -1
  130. package/dist/core/utility/installation.js.map +1 -1
  131. package/dist/core/utility/lmdb/commonUtility.js +20 -13
  132. package/dist/core/utility/lmdb/commonUtility.js.map +1 -1
  133. package/dist/licensing/usageLicensing.js.map +1 -1
  134. package/dist/replication/knownNodes.js +5 -37
  135. package/dist/replication/knownNodes.js.map +1 -1
  136. package/dist/replication/nodeIdMapping.js +2 -35
  137. package/dist/replication/nodeIdMapping.js.map +1 -1
  138. package/dist/replication/replicationConnection.js +15 -6
  139. package/dist/replication/replicationConnection.js.map +1 -1
  140. package/dist/replication/replicator.js +3 -2
  141. package/dist/replication/replicator.js.map +1 -1
  142. package/dist/replication/setNode.js +1 -1
  143. package/dist/replication/setNode.js.map +1 -1
  144. package/dist/security/certificate.js.map +1 -1
  145. package/licensing/usageLicensing.ts +3 -2
  146. package/npm-shrinkwrap.json +303 -282
  147. package/package.json +4 -3
  148. package/replication/knownNodes.ts +3 -2
  149. package/replication/nodeIdMapping.ts +1 -1
  150. package/replication/replicationConnection.ts +33 -8
  151. package/replication/replicator.ts +7 -2
  152. package/replication/setNode.ts +1 -1
  153. package/security/certificate.ts +2 -1
  154. package/studio/web/assets/{index-v3wIpSYx.js → index-CWN9Wp5V.js} +2 -2
  155. package/studio/web/assets/{index-v3wIpSYx.js.map → index-CWN9Wp5V.js.map} +1 -1
  156. package/studio/web/assets/{index-ChCctErQ.js → index-CzghSAn2.js} +2 -2
  157. package/studio/web/assets/{index-ChCctErQ.js.map → index-CzghSAn2.js.map} +1 -1
  158. package/studio/web/assets/{index-Qu8D43wo.js → index-DMDhGP7N.js} +5 -5
  159. package/studio/web/assets/{index-Qu8D43wo.js.map → index-DMDhGP7N.js.map} +1 -1
  160. package/studio/web/assets/{index.lazy-tVSPM7bX.js → index.lazy-C-yDTGUy.js} +2 -2
  161. package/studio/web/assets/{index.lazy-tVSPM7bX.js.map → index.lazy-C-yDTGUy.js.map} +1 -1
  162. package/studio/web/assets/{profiler-C9as4sv-.js → profiler-0fZAOscv.js} +2 -2
  163. package/studio/web/assets/{profiler-C9as4sv-.js.map → profiler-0fZAOscv.js.map} +1 -1
  164. package/studio/web/assets/{react-redux-RRIhZnM6.js → react-redux-BIxqK8O6.js} +2 -2
  165. package/studio/web/assets/{react-redux-RRIhZnM6.js.map → react-redux-BIxqK8O6.js.map} +1 -1
  166. package/studio/web/assets/{startRecording-DYa4zCXV.js → startRecording-Ca3Gf2MY.js} +2 -2
  167. package/studio/web/assets/{startRecording-DYa4zCXV.js.map → startRecording-Ca3Gf2MY.js.map} +1 -1
  168. package/studio/web/index.html +1 -1
  169. package/core/resources/ResourceInterfaceV2.ts +0 -53
  170. package/core/resources/ResourceV2.ts +0 -67
  171. package/core/resources/analytics/profile.ts +0 -109
  172. package/core/unitTests/apiTests/analytics-test.mjs +0 -38
  173. package/core/v1.d.ts +0 -47
  174. package/core/v1.js +0 -38
  175. package/core/v2.d.ts +0 -47
  176. package/core/v2.js +0 -38
  177. package/dist/core/resources/ResourceInterfaceV2.js.map +0 -1
  178. package/dist/core/resources/ResourceV2.js +0 -27
  179. package/dist/core/resources/ResourceV2.js.map +0 -1
  180. package/dist/core/resources/analytics/profile.js +0 -144
  181. package/dist/core/resources/analytics/profile.js.map +0 -1
@@ -0,0 +1,9 @@
1
+ .git/
2
+ /dist/
3
+ /node_modules/
4
+
5
+ /.idea/
6
+ /.claude/
7
+ /.github/
8
+
9
+ /harperfast-harper-*.tgz
@@ -5,3 +5,5 @@
5
5
  f66b9d9a77db9dfae1d1fe7b764b0a850883df60
6
6
  e892d2934b7048b610e4c879fd9b1a523b0004f7
7
7
  4e2e8b7980a31086a35c71de8fc8c305393ff771
8
+ 7e6779182655c4989d999ac1943fca54036e86af
9
+ 5c2b7323cdbaa43e22daa40c779fa0e526a73a73
@@ -46,7 +46,7 @@ jobs:
46
46
  uses: slackapi/slack-github-action@v2
47
47
  with:
48
48
  method: chat.postMessage
49
- token: ${{ secrets.SLACK_BOT_KEY }}
49
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
50
50
  payload: |
51
51
  {
52
52
  "channel": "#development-ci",
@@ -91,7 +91,7 @@ jobs:
91
91
  with:
92
92
  name: ${{ steps.tag-version.outputs.tagVersion }}
93
93
  tag_name: ${{ steps.tag-version.outputs.tagVersion }}
94
- files: harperfast-harper-*.tgz
94
+ files: harper-*.tgz
95
95
  fail_on_unmatched_files: true
96
96
  generate_release_notes: true
97
97
  prerelease: ${{ steps.version-components.outputs.prerelease != '' }}
@@ -106,7 +106,7 @@ jobs:
106
106
  - uses: slackapi/slack-github-action@v2
107
107
  with:
108
108
  method: chat.postMessage
109
- token: ${{ secrets.SLACK_BOT_KEY }}
109
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
110
110
  payload: |
111
111
  {
112
112
  "channel": "#development-ci",
@@ -147,7 +147,7 @@ jobs:
147
147
  - uses: slackapi/slack-github-action@v2
148
148
  with:
149
149
  method: chat.postMessage
150
- token: ${{ secrets.SLACK_BOT_KEY }}
150
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
151
151
  payload: |
152
152
  {
153
153
  "channel": "#development-ci",
@@ -64,7 +64,7 @@ jobs:
64
64
  run: npm run build || true # we currently have type errors so just ignore that
65
65
 
66
66
  - name: Upload build artifacts
67
- uses: actions/upload-artifact@v4
67
+ uses: actions/upload-artifact@v7
68
68
  with:
69
69
  name: harper-build-artifacts-node-${{ matrix.node-version }}
70
70
  path: |
@@ -95,7 +95,7 @@ jobs:
95
95
  package-manager-cache: false
96
96
 
97
97
  - name: Download build artifacts
98
- uses: actions/download-artifact@v4
98
+ uses: actions/download-artifact@v8
99
99
  with:
100
100
  name: harper-build-artifacts-node-${{ matrix.node-version }}
101
101
 
@@ -112,9 +112,10 @@ jobs:
112
112
  THREADS_DEBUG: false
113
113
  NODE_HOSTNAME: 'localhost'
114
114
  run: |
115
- node ./dist/bin/harper.js install
115
+ mkdir -p /tmp/hdb/log
116
+ node ./dist/bin/harper.js install > /tmp/hdb/log/install-stdout.log 2> /tmp/hdb/log/install-stderr.log
116
117
  sleep 10
117
- node ./dist/bin/harper.js start
118
+ node ./dist/bin/harper.js start > /tmp/hdb/log/start-stdout.log 2> /tmp/hdb/log/start-stderr.log &
118
119
  sleep 10
119
120
 
120
121
  - name: Run API Tests
@@ -125,12 +126,13 @@ jobs:
125
126
  run: npm run test:integration:api-tests
126
127
 
127
128
  - name: Upload Harper logs
128
- if: steps.run-api-tests.outcome == 'failure'
129
- uses: actions/upload-artifact@v4
129
+ if: failure()
130
+ uses: actions/upload-artifact@v7
130
131
  with:
131
132
  name: harper-integration-api-test-logs-node-${{ matrix.node-version }}
132
- path: /tmp/hdb/log/hdb.log
133
- retention-days: 2
133
+ path: /tmp/hdb/log/
134
+ retention-days: 3
135
+ if-no-files-found: ignore
134
136
 
135
137
  run-integration-tests:
136
138
  name: Integration Tests ${{matrix.shard}}/4 (Node.js v${{ matrix.node-version }})
@@ -155,7 +157,7 @@ jobs:
155
157
  package-manager-cache: false
156
158
 
157
159
  - name: Download build artifacts
158
- uses: actions/download-artifact@v4
160
+ uses: actions/download-artifact@v8
159
161
  with:
160
162
  name: harper-build-artifacts-node-${{ matrix.node-version }}
161
163
 
@@ -167,7 +169,7 @@ jobs:
167
169
 
168
170
  - name: Upload Harper server logs
169
171
  if: failure()
170
- uses: actions/upload-artifact@v4
172
+ uses: actions/upload-artifact@v7
171
173
  with:
172
174
  name: harper-server-logs-node-${{ matrix.node-version }}-shard-${{ matrix.shard }}
173
175
  path: /tmp/harper-integration-test-logs/
@@ -16,7 +16,7 @@ jobs:
16
16
  uses: slackapi/slack-github-action@v2
17
17
  with:
18
18
  method: chat.postMessage
19
- token: ${{ secrets.SLACK_BOT_KEY }}
19
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
20
20
  payload: |
21
21
  {
22
22
  "channel": "#development-ci",
@@ -99,7 +99,7 @@ jobs:
99
99
  uses: slackapi/slack-github-action@v2
100
100
  with:
101
101
  method: chat.postMessage
102
- token: ${{ secrets.SLACK_BOT_KEY }}
102
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
103
103
  payload: |
104
104
  {
105
105
  "channel": "#development-ci",
@@ -140,7 +140,7 @@ jobs:
140
140
  - uses: slackapi/slack-github-action@v2
141
141
  with:
142
142
  method: chat.postMessage
143
- token: ${{ secrets.SLACK_BOT_KEY }}
143
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
144
144
  payload: |
145
145
  {
146
146
  "channel": "#development-ci",
@@ -38,7 +38,7 @@ jobs:
38
38
  fi
39
39
  - name: Publish package to NPM registry
40
40
  env:
41
- NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_KEY }}
41
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
42
42
  run: npm publish --access=public --tag=${{ steps.package-tag.outputs.packageTag }} harper-*.tgz
43
43
 
44
44
  publish-harperfast-npm-package:
@@ -78,7 +78,7 @@ jobs:
78
78
  fi
79
79
  - name: Publish package to NPM registry
80
80
  env:
81
- NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_KEY }}
81
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
82
82
  run: npm publish --access=public --tag=${{ steps.package-tag.outputs.packageTag }} harperfast-harper-*.tgz
83
83
 
84
84
  send-slack-message-on-success:
@@ -92,7 +92,7 @@ jobs:
92
92
  uses: slackapi/slack-github-action@v2
93
93
  with:
94
94
  method: chat.postMessage
95
- token: ${{ secrets.SLACK_BOT_KEY }}
95
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
96
96
  payload: |
97
97
  {
98
98
  "channel": "#development-ci",
@@ -139,7 +139,7 @@ jobs:
139
139
  - uses: slackapi/slack-github-action@v2
140
140
  with:
141
141
  method: chat.postMessage
142
- token: ${{ secrets.SLACK_BOT_KEY }}
142
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
143
143
  payload: |
144
144
  {
145
145
  "channel": "#development-ci",
@@ -83,7 +83,7 @@ These are the steps @Ethan-Arrowood has been following to synchronize the reposi
83
83
 
84
84
  ### Last Synchronized Commit
85
85
 
86
- `e69e4b9c0c1c94576d306965c511e9c99efbf00c`
86
+ `f969f21d780581fd0cb5566730028f2d13f1363e`
87
87
 
88
88
  ## Code of Conduct
89
89
 
@@ -0,0 +1,62 @@
1
+ ARG NODE_BUILD_VERSION=24
2
+ ARG NODE_VERSION=24
3
+
4
+ FROM docker.io/node:${NODE_BUILD_VERSION} AS build
5
+
6
+ WORKDIR /usr/src/harper
7
+
8
+ COPY . .
9
+
10
+ RUN env NO_USE_GIT=true npm run package
11
+
12
+ FROM docker.io/node:${NODE_VERSION} AS run
13
+
14
+ # Change node user to harper
15
+ RUN <<-EOF
16
+ mkdir -p /home/harperdb
17
+ usermod -d /home/harperdb -l harperdb node
18
+ groupmod -n harperdb node
19
+ rm -rf /home/node
20
+ chown -R harperdb:harperdb /home/harperdb
21
+ EOF
22
+
23
+ WORKDIR /home/harperdb
24
+
25
+ USER harperdb
26
+
27
+ # Install pnpm
28
+ RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.bashrc" SHELL="$(which bash)" bash -
29
+
30
+ COPY --from=build /usr/src/harper/harper-*.tgz .
31
+
32
+ # Configure NPM
33
+ ENV NPM_CONFIG_PREFIX=/home/harperdb/.npm-global
34
+ ENV PATH=/home/harperdb/.npm-global/bin:$PATH
35
+
36
+ VOLUME /home/harperdb/harper
37
+
38
+ # Install Harper globally
39
+ RUN <<-EOF
40
+ npm install --global harper-*.tgz
41
+ rm harper-*.tgz
42
+ mkdir -p /home/harperdb/harper
43
+ chown harperdb:harperdb /home/harperdb/harper
44
+ EOF
45
+
46
+ # Harper config parameters
47
+ ENV HDB_ADMIN_USERNAME=admin
48
+ ENV ROOTPATH=/home/harperdb/harper
49
+ ENV TC_AGREEMENT=yes
50
+ ENV NETWORK_OPERATIONSAPI_PORT=9925
51
+ ENV LOGGING_STDSTREAMS=true
52
+ ENV NODE_HOSTNAME=localhost
53
+ ENV DEFAULTS_MODE=prod
54
+
55
+ EXPOSE 9925
56
+ EXPOSE 9926
57
+ EXPOSE 9932
58
+ EXPOSE 9933
59
+
60
+ ENTRYPOINT ["harper"]
61
+
62
+ CMD ["run"]
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+
3
+ rm -Rf studio-src studio
4
+ mkdir studio-src
5
+ cd studio-src
6
+ git clone --branch prod --single-branch --depth 1 https://github.com/HarperFast/studio.git .
7
+ npm install -g pnpm
8
+ pnpm install
9
+ VITE_STUDIO_VERSION="v$(jq -r '.version' ../package.json)" pnpm run build:local
10
+ cd ..
11
+ mkdir studio
12
+ mv ./studio-src/web ./studio/web
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ echo -e "\n📦 Installing core deps"
6
+ npm install
7
+
8
+ echo -e "\n📦 Building project"
9
+ npm run build || true
10
+
11
+ echo -e "\n📦 Creating shrinkwrap"
12
+ npm shrinkwrap
13
+
14
+ ./build-tools/build-studio.sh
15
+
16
+ echo -e "\n📦 Building package"
17
+ npm pack
18
+
19
+ version=$(npm pkg get version | tr -d \")
20
+ packageFile="harper-${version}.tgz"
21
+ echo -e "\n📦 Built Harper Pro ${version} in ${packageFile}"
22
+ echo "📦 Run 'npm publish ${packageFile}' to release"
@@ -0,0 +1,13 @@
1
+ const util = require('util');
2
+ const exec = util.promisify(require('child_process').exec);
3
+
4
+ (async function () {
5
+ // need prebuildify-ci for the downloads to run
6
+ let output = await exec('npm install -g prebuildify-ci');
7
+ console.error(output.stderr);
8
+ console.log(output.stdout);
9
+ // download lmdb (and msgpackr-extract) binaries
10
+ output = await exec('download-lmdb-prebuilds');
11
+ console.error(output.stderr);
12
+ console.log(output.stdout);
13
+ })();
@@ -0,0 +1,14 @@
1
+ export interface Logger {
2
+ logLevel: string;
3
+
4
+ notify?: (...args: any[]) => void;
5
+ fatal?: (...args: any[]) => void;
6
+ error?: (...args: any[]) => void;
7
+ warn?: (...args: any[]) => void;
8
+ info?: (...args: any[]) => void;
9
+ debug?: (...args: any[]) => void;
10
+ trace?: (...args: any[]) => void;
11
+
12
+ withTag: (tag: string) => Logger;
13
+ loggerWithTag: (tag: string) => Logger;
14
+ }
@@ -1,6 +1,7 @@
1
1
  import { type Logger } from '../utility/logging/logger.ts';
2
2
  import { loggerWithTag } from '../utility/logging/harper_logger.js';
3
3
  import { EventEmitter, once } from 'node:events';
4
+ import { databaseEventsEmitter } from '../resources/databases.ts';
4
5
  import { server, type Server } from '../server/Server.ts';
5
6
  import { EntryHandler, type EntryHandlerEventMap, type onEntryEventHandler } from './EntryHandler.ts';
6
7
  import { OptionsWatcher, OptionsWatcherEventMap } from './OptionsWatcher.ts';
@@ -17,17 +18,26 @@ export class MissingDefaultFilesOptionError extends Error {
17
18
  }
18
19
  }
19
20
 
21
+ export type ScopeEventsMap = {
22
+ all: [...args: unknown[]];
23
+ close: [];
24
+ error: [error: unknown];
25
+ ready: [];
26
+ [record: string]: [...args: unknown[]];
27
+ };
28
+
20
29
  /**
21
30
  * This class is what is passed to the `handleApplication` function of an extension.
22
31
  *
23
- * It is imperative that the instance is "ready" before its passed to the `handleApplication` function
32
+ * It is imperative that the instance is "ready" before it's passed to the `handleApplication` function
24
33
  * so that the developer can immediately start using `scope.options`, etc.
25
34
  *
26
35
  */
27
- export class Scope extends EventEmitter {
36
+ export class Scope extends EventEmitter<ScopeEventsMap> {
28
37
  #configFilePath: string;
29
38
  #directory: string;
30
- #name: string;
39
+ #appName: string;
40
+ #pluginName: string;
31
41
  #entryHandler?: EntryHandler;
32
42
  #entryHandlers: EntryHandler[];
33
43
  #logger: Logger;
@@ -38,14 +48,24 @@ export class Scope extends EventEmitter {
38
48
  resources?: Resources;
39
49
  server?: Server;
40
50
  ready: Promise<any[]>;
41
- constructor(name: string, directory: string, configFilePath: string, applicationScope: ApplicationScope) {
51
+ databaseEvents: typeof databaseEventsEmitter;
52
+
53
+ constructor(
54
+ appName: string,
55
+ pluginName: string,
56
+ directory: string,
57
+ configFilePath: string,
58
+ applicationScope: ApplicationScope
59
+ ) {
42
60
  super();
43
61
 
44
- this.#name = name;
62
+ this.#appName = appName;
63
+ this.#pluginName = pluginName;
45
64
  this.#directory = directory;
46
65
  this.#configFilePath = configFilePath;
47
- this.#logger = loggerWithTag(this.#name);
66
+ this.#logger = logger || loggerWithTag(this.#appName);
48
67
 
68
+ this.databaseEvents = databaseEventsEmitter;
49
69
  this.applicationScope = applicationScope;
50
70
  this.resources = applicationScope?.resources ?? resources;
51
71
  this.server = applicationScope?.server ?? server;
@@ -56,7 +76,7 @@ export class Scope extends EventEmitter {
56
76
  this.ready = once(this, 'ready');
57
77
 
58
78
  // Create the options instance for the scope immediately
59
- this.options = new OptionsWatcher(name, configFilePath, this.#logger)
79
+ this.options = new OptionsWatcher(pluginName, configFilePath, this.#logger)
60
80
  .on('error', this.#handleError.bind(this))
61
81
  .on('change', this.#optionsWatcherChangeListener.bind(this)())
62
82
  .on('ready', this.#handleOptionsWatcherReady.bind(this));
@@ -66,8 +86,12 @@ export class Scope extends EventEmitter {
66
86
  return this.#logger;
67
87
  }
68
88
 
69
- get name(): string {
70
- return this.#name;
89
+ get appName(): string {
90
+ return this.#appName;
91
+ }
92
+
93
+ get pluginName(): string {
94
+ return this.#pluginName;
71
95
  }
72
96
 
73
97
  get directory(): string {
@@ -107,7 +131,7 @@ export class Scope extends EventEmitter {
107
131
  }
108
132
 
109
133
  #createEntryHandler(config: FilesOption | FileAndURLPathConfig): EntryHandler {
110
- const entryHandler = new EntryHandler(this.#name, this.#directory, config, this.#logger)
134
+ const entryHandler = new EntryHandler(this.#pluginName, this.#directory, config, this.#logger)
111
135
  .on('error', this.#handleError.bind(this))
112
136
  .on('add', this.#defaultEntryHandlerListener('add'))
113
137
  .on('change', this.#defaultEntryHandlerListener('change'))
@@ -279,7 +303,7 @@ export class Scope extends EventEmitter {
279
303
  }
280
304
 
281
305
  requestRestart() {
282
- this.#logger.debug?.(`Restart requested from ${this.name} scope for ${this.directory}`);
306
+ this.#logger.debug?.(`Restart requested from ${this.#pluginName} scope for ${this.#appName}`);
283
307
  requestRestart();
284
308
  }
285
309
 
@@ -60,12 +60,20 @@ export function loadComponentDirectories(loadedPluginModules?: Map<any, any>, lo
60
60
  if (!appEntry.isDirectory() && !appEntry.isSymbolicLink()) continue;
61
61
  const appName = appEntry.name;
62
62
  const appFolder = join(CF_ROUTES_DIR, appName);
63
- cfsLoaded.push(loadComponent(appFolder, resources, HDB_ROOT_DIR_NAME));
63
+ cfsLoaded.push(
64
+ loadComponent(appFolder, resources, HDB_ROOT_DIR_NAME, { isRoot: false, autoReload: false, appName })
65
+ );
64
66
  }
65
67
  }
66
68
  const hdbAppFolder = process.env.RUN_HDB_APP;
67
69
  if (hdbAppFolder) {
68
- cfsLoaded.push(loadComponent(hdbAppFolder, resources, hdbAppFolder, { autoReload: Boolean(process.env.DEV_MODE) }));
70
+ cfsLoaded.push(
71
+ loadComponent(hdbAppFolder, resources, hdbAppFolder, {
72
+ isRoot: false,
73
+ autoReload: Boolean(process.env.DEV_MODE),
74
+ appName: hdbAppFolder,
75
+ })
76
+ );
69
77
  }
70
78
  return Promise.all(cfsLoaded).then(() => {
71
79
  watchesSetup = true;
@@ -176,7 +184,7 @@ function sequentiallyHandleApplication(scope: Scope, plugin: PluginModule) {
176
184
  // Timeout priority is user config, plugin default, finally 30 seconds
177
185
  const timeout = scope.options.get(['timeout']) || plugin.defaultTimeout || 30_000; // default 30 second timeout
178
186
  if (typeof timeout !== 'number') {
179
- throw new Error(`Invalid timeout value for ${scope.name}. Expected a number, received: ${typeof timeout}`);
187
+ throw new Error(`Invalid timeout value for ${scope.pluginName}. Expected a number, received: ${typeof timeout}`);
180
188
  }
181
189
  let whenResolved, timer;
182
190
  const callback = () => {
@@ -184,13 +192,13 @@ function sequentiallyHandleApplication(scope: Scope, plugin: PluginModule) {
184
192
  whenResolved(sequentiallyHandleApplication(scope, plugin));
185
193
  };
186
194
  const store = Status.primaryStore;
187
- const lockAcquired = store.tryLock(scope.name, callback);
195
+ const lockAcquired = store.tryLock(scope.pluginName, callback);
188
196
 
189
197
  if (!lockAcquired) {
190
198
  return new Promise((resolve, reject) => {
191
199
  whenResolved = resolve;
192
200
  timer = setTimeout(() => {
193
- reject(new Error(`Timeout waiting for lock on ${scope.name}`));
201
+ reject(new Error(`Timeout waiting for lock on ${scope.pluginName}`));
194
202
  }, timeout + 5_000); // extra time for lock acquisition
195
203
  });
196
204
  }
@@ -206,13 +214,18 @@ function sequentiallyHandleApplication(scope: Scope, plugin: PluginModule) {
206
214
  new Promise(
207
215
  (_, reject) =>
208
216
  (loadTimeout = setTimeout(
209
- () => reject(new Error(`handleApplication timed out after ${timeout}ms for ${scope.name}`)),
217
+ () =>
218
+ reject(
219
+ new Error(
220
+ `handleApplication timed out after ${timeout}ms for ${scope.pluginName} on behalf of ${scope.appName}`
221
+ )
222
+ ),
210
223
  timeout
211
224
  ))
212
225
  ),
213
226
  ]);
214
227
  } finally {
215
- Status.primaryStore.unlock(scope.name);
228
+ Status.primaryStore.unlock(scope.pluginName);
216
229
  clearTimeout(loadTimeout);
217
230
  }
218
231
  });
@@ -222,8 +235,8 @@ export interface LoadComponentOptions {
222
235
  isRoot?: boolean;
223
236
  applicationScope?: ApplicationScope;
224
237
  autoReload?: boolean;
225
- applicationContainment?: ApplicationContainment;
226
238
  providedLoadedComponents?: Map<any, any>;
239
+ appName?: string;
227
240
  }
228
241
 
229
242
  /**
@@ -249,6 +262,7 @@ export async function loadComponent(
249
262
  applicationScope = new ApplicationScope(basename(componentDirectory), resources, server),
250
263
  isRoot,
251
264
  autoReload,
265
+ appName,
252
266
  } = options;
253
267
  applicationScope.verifyPath ??= componentDirectory;
254
268
  if (providedLoadedComponents) loadedComponents = providedLoadedComponents;
@@ -321,7 +335,10 @@ export async function loadComponent(
321
335
  subApplicationScope.verifyPath = componentPath;
322
336
  if (!process.env.HARPER_SAFE_MODE) {
323
337
  extensionModule = await loadComponent(componentPath, resources, origin, {
338
+ isRoot: false,
324
339
  applicationScope: subApplicationScope,
340
+ autoReload: false,
341
+ appName: appName || componentName,
325
342
  });
326
343
  componentFunctionality[componentName] = true;
327
344
  }
@@ -373,7 +390,7 @@ export async function loadComponent(
373
390
 
374
391
  // New Plugin API (`handleApplication`)
375
392
  if (resources.isWorker && extensionModule.handleApplication) {
376
- const scope = new Scope(componentName, componentDirectory, configPath, applicationScope);
393
+ const scope = new Scope(appName || 'harper', componentName, componentDirectory, configPath, applicationScope);
377
394
 
378
395
  await sequentiallyHandleApplication(scope, extensionModule);
379
396
 
@@ -477,7 +494,7 @@ export async function loadComponent(
477
494
  return loadComponentDirectories(); // return the promise
478
495
  });
479
496
  }
480
- if (config.extensionModule || config.pluginModule) {
497
+ if ((config.extensionModule || config.pluginModule) && (!isMainThread || config.runOnMainThread)) {
481
498
  const extensionModule = await scopedImport(
482
499
  join(componentDirectory, config.extensionModule || config.pluginModule),
483
500
  applicationScope
@@ -408,7 +408,15 @@ async function deployComponent(req) {
408
408
  const componentLoader = require('./componentLoader.ts');
409
409
  let lastError;
410
410
  componentLoader.setErrorReporter((error) => (lastError = error));
411
- await componentLoader.loadComponent(application.dirPath, pseudoResources);
411
+ await componentLoader.loadComponent(
412
+ application.dirPath,
413
+ pseudoResources,
414
+ undefined,
415
+ false,
416
+ undefined,
417
+ false,
418
+ req.project
419
+ );
412
420
 
413
421
  if (lastError) throw lastError;
414
422
  }
@@ -473,7 +481,7 @@ async function getComponents() {
473
481
  const list = await fs.readdir(dir, { withFileTypes: true });
474
482
  for (let item of list) {
475
483
  const itemName = item.name;
476
- if (itemName.startsWith('.') || itemName === 'node_modules') continue;
484
+ if (itemName === 'node_modules') continue;
477
485
  const itemPath = path.join(dir, itemName);
478
486
  if (item.isDirectory() || item.isSymbolicLink()) {
479
487
  let res = {
@@ -140,7 +140,7 @@ function createConfigFile(args, skipFsValidation = false) {
140
140
  if (configDoc.errors?.length > 0) {
141
141
  throw handleHDBError(
142
142
  new Error(),
143
- `Error parsing harperdb-config.yaml ${configDoc.errors}`,
143
+ `Error parsing ${configFilePath} ${configDoc.errors}`,
144
144
  HTTP_STATUS_CODES.BAD_REQUEST,
145
145
  undefined,
146
146
  undefined,
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  class CreateTableObject {
4
- constructor(schema, table, hash_attribute) {
4
+ constructor(schema, table, primary_key) {
5
5
  this.schema = schema;
6
6
  this.table = table;
7
- this.hash_attribute = hash_attribute;
7
+ this.primary_key = primary_key;
8
8
  }
9
9
  }
10
10
 
@@ -13,7 +13,7 @@ const harperBridge = require('./harperBridge/harperBridge.js');
13
13
  const { handleHDBError, hdbErrors, ClientError } = require('../utility/errors/hdbError.js');
14
14
  const { HDB_ERROR_MSGS, HTTP_STATUS_CODES } = hdbErrors;
15
15
  const { SchemaEventMsg } = require('../server/threads/itc.js');
16
- const { getDatabases } = require('../resources/databases.ts');
16
+ const { getDatabases, dropTableMeta } = require('../resources/databases.ts');
17
17
  const { transformReq } = require('../utility/common_utils.js');
18
18
  const { server } = require('../server/Server.ts');
19
19
  const { cleanupOrphans } = require('../resources/blob.ts');
@@ -96,7 +96,7 @@ async function createSchemaStructure(schemaCreateObject) {
96
96
 
97
97
  async function createTable(createTableObject) {
98
98
  transformReq(createTableObject);
99
- createTableObject.hash_attribute = createTableObject.primary_key ?? createTableObject.hash_attribute;
99
+ createTableObject.primary_key = createTableObject.primary_key ?? createTableObject.hash_attribute;
100
100
  return await createTableStructure(createTableObject);
101
101
  }
102
102
 
@@ -108,7 +108,7 @@ async function createTableStructure(createTableObject) {
108
108
  schema: DB_NAME_CONSTRAINTS,
109
109
  table: TABLE_NAME_CONSTRAINTS,
110
110
  residence: Joi.array().items(Joi.string().min(1)).optional(),
111
- hash_attribute: PRIMARY_KEY_CONSTRAINTS,
111
+ primary_key: PRIMARY_KEY_CONSTRAINTS,
112
112
  })
113
113
  );
114
114
  if (validation) throw new ClientError(validation.message);
@@ -132,7 +132,7 @@ async function createTableStructure(createTableObject) {
132
132
  name: createTableObject.table,
133
133
  schema: createTableObject.schema,
134
134
  id: uuidV4(),
135
- hash_attribute: createTableObject.hash_attribute,
135
+ primary_key: createTableObject.primary_key,
136
136
  };
137
137
 
138
138
  if (createTableObject.residence) {
@@ -219,6 +219,8 @@ async function dropTable(dropTableObject) {
219
219
 
220
220
  await harperBridge.dropTable(dropTableObject);
221
221
 
222
+ await dropTableMeta({ table: dropTableObject.table, database: dropTableObject.schema });
223
+
222
224
  let response = await server.replication.replicateOperation(dropTableObject);
223
225
  response.message = `successfully deleted table '${dropTableObject.schema}.${dropTableObject.table}'`;
224
226
  return response;
@@ -260,7 +262,7 @@ async function dropAttribute(dropAttributeObject) {
260
262
 
261
263
  if (
262
264
  dropAttributeObject.attribute ===
263
- global.hdb_schema[dropAttributeObject.schema][dropAttributeObject.table].hash_attribute
265
+ global.hdb_schema[dropAttributeObject.schema][dropAttributeObject.table].primary_key
264
266
  ) {
265
267
  throw handleHDBError(
266
268
  new Error(),
@@ -192,7 +192,7 @@ async function descTable(describeTableObject, attrPerms) {
192
192
  let tableResult = {
193
193
  schema,
194
194
  name: tableObj.tableName,
195
- hash_attribute: tableObj.attributes.find((attribute) => attribute.isPrimaryKey || attribute.isPrimaryKey)?.name,
195
+ primary_key: tableObj.attributes.find((attribute) => attribute.isPrimaryKey || attribute.isPrimaryKey)?.name,
196
196
  audit: tableObj.audit,
197
197
  schema_defined: tableObj.schemaDefined,
198
198
  attributes,