@casual-simulation/aux-records 3.4.6-alpha.14668890889 → 3.5.0-alpha.15119114602

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 (211) hide show
  1. package/AIController.js +835 -890
  2. package/AIController.js.map +1 -1
  3. package/AIHumeInterface.js +43 -54
  4. package/AIHumeInterface.js.map +1 -1
  5. package/AIOpenAIRealtimeInterface.js +60 -71
  6. package/AIOpenAIRealtimeInterface.js.map +1 -1
  7. package/AnthropicAIChatInterface.js +96 -142
  8. package/AnthropicAIChatInterface.js.map +1 -1
  9. package/AuthController.d.ts +3 -2
  10. package/AuthController.js +1907 -1933
  11. package/AuthController.js.map +1 -1
  12. package/AuthStore.d.ts +1 -10
  13. package/BlockadeLabsGenerateSkyboxInterface.js +57 -72
  14. package/BlockadeLabsGenerateSkyboxInterface.js.map +1 -1
  15. package/CachingConfigStore.js +30 -45
  16. package/CachingConfigStore.js.map +1 -1
  17. package/CachingPolicyStore.d.ts +8 -2
  18. package/CachingPolicyStore.js +108 -135
  19. package/CachingPolicyStore.js.map +1 -1
  20. package/ComIdConfig.d.ts +18 -18
  21. package/ComIdConfig.js.map +1 -1
  22. package/ConsoleAuthMessenger.js +7 -20
  23. package/ConsoleAuthMessenger.js.map +1 -1
  24. package/DataRecordsController.d.ts +2 -2
  25. package/DataRecordsController.js +369 -377
  26. package/DataRecordsController.js.map +1 -1
  27. package/DataRecordsStore.d.ts +1 -1
  28. package/DataRecordsStore.js +1 -1
  29. package/DataRecordsStore.js.map +1 -1
  30. package/EventRecordsController.js +226 -240
  31. package/EventRecordsController.js.map +1 -1
  32. package/FileRecordsController.d.ts +13 -2
  33. package/FileRecordsController.js +458 -450
  34. package/FileRecordsController.js.map +1 -1
  35. package/GoogleAIChatInterface.js +133 -179
  36. package/GoogleAIChatInterface.js.map +1 -1
  37. package/LivekitController.js +43 -54
  38. package/LivekitController.js.map +1 -1
  39. package/LoomController.js +64 -75
  40. package/LoomController.js.map +1 -1
  41. package/MemoryAuthMessenger.js +10 -23
  42. package/MemoryAuthMessenger.js.map +1 -1
  43. package/MemoryCache.js +18 -35
  44. package/MemoryCache.js.map +1 -1
  45. package/MemoryFileRecordsLookup.js +105 -125
  46. package/MemoryFileRecordsLookup.js.map +1 -1
  47. package/MemoryModerationJobProvider.js +17 -30
  48. package/MemoryModerationJobProvider.js.map +1 -1
  49. package/MemoryRateLimiter.js +12 -27
  50. package/MemoryRateLimiter.js.map +1 -1
  51. package/MemoryStore.d.ts +18 -6
  52. package/MemoryStore.js +1879 -1997
  53. package/MemoryStore.js.map +1 -1
  54. package/MetricsStore.d.ts +2 -2
  55. package/ModerationController.js +186 -200
  56. package/ModerationController.js.map +1 -1
  57. package/OpenAIChatInterface.js +105 -135
  58. package/OpenAIChatInterface.js.map +1 -1
  59. package/OpenAIImageInterface.js +57 -51
  60. package/OpenAIImageInterface.js.map +1 -1
  61. package/PolicyController.d.ts +150 -10
  62. package/PolicyController.js +1546 -1299
  63. package/PolicyController.js.map +1 -1
  64. package/PolicyStore.d.ts +110 -2
  65. package/PolicyStore.js +36 -1
  66. package/PolicyStore.js.map +1 -1
  67. package/PrivoClient.js +398 -435
  68. package/PrivoClient.js.map +1 -1
  69. package/RateLimitController.js +25 -36
  70. package/RateLimitController.js.map +1 -1
  71. package/RecordsClient.js +51 -74
  72. package/RecordsClient.js.map +1 -1
  73. package/RecordsController.d.ts +2 -42
  74. package/RecordsController.js +1026 -1182
  75. package/RecordsController.js.map +1 -1
  76. package/RecordsServer.d.ts +196 -27
  77. package/RecordsServer.js +1701 -1343
  78. package/RecordsServer.js.map +1 -1
  79. package/RecordsStore.d.ts +1 -10
  80. package/RecordsStore.js.map +1 -1
  81. package/ServerConfig.d.ts +339 -195
  82. package/ServerConfig.js +13 -0
  83. package/ServerConfig.js.map +1 -1
  84. package/SloydInterface.js +62 -75
  85. package/SloydInterface.js.map +1 -1
  86. package/StabilityAIImageInterface.js +150 -167
  87. package/StabilityAIImageInterface.js.map +1 -1
  88. package/SubscriptionConfigBuilder.d.ts +6 -1
  89. package/SubscriptionConfigBuilder.js +22 -0
  90. package/SubscriptionConfigBuilder.js.map +1 -1
  91. package/SubscriptionConfiguration.d.ts +266 -169
  92. package/SubscriptionConfiguration.js +101 -79
  93. package/SubscriptionConfiguration.js.map +1 -1
  94. package/SubscriptionController.d.ts +2 -1
  95. package/SubscriptionController.js +643 -650
  96. package/SubscriptionController.js.map +1 -1
  97. package/SystemNotificationMessenger.d.ts +21 -4
  98. package/SystemNotificationMessenger.js +36 -30
  99. package/SystemNotificationMessenger.js.map +1 -1
  100. package/TestUtils.d.ts +9 -1
  101. package/TestUtils.js +105 -129
  102. package/TestUtils.js.map +1 -1
  103. package/Utils.d.ts +2 -16
  104. package/Utils.js +21 -22
  105. package/Utils.js.map +1 -1
  106. package/crud/CrudHelpers.js +17 -26
  107. package/crud/CrudHelpers.js.map +1 -1
  108. package/crud/CrudRecordsController.d.ts +1 -1
  109. package/crud/CrudRecordsController.js +259 -267
  110. package/crud/CrudRecordsController.js.map +1 -1
  111. package/crud/CrudRecordsControllerTests.js +174 -185
  112. package/crud/CrudRecordsControllerTests.js.map +1 -1
  113. package/crud/CrudRecordsStore.d.ts +7 -3
  114. package/crud/MemoryCrudRecordsStore.d.ts +4 -4
  115. package/crud/MemoryCrudRecordsStore.js +98 -118
  116. package/crud/MemoryCrudRecordsStore.js.map +1 -1
  117. package/crud/sub/MemorySubCrudRecordsStore.d.ts +24 -0
  118. package/crud/sub/MemorySubCrudRecordsStore.js +146 -0
  119. package/crud/sub/MemorySubCrudRecordsStore.js.map +1 -0
  120. package/crud/sub/SubCrudRecordsController.d.ts +182 -0
  121. package/crud/sub/SubCrudRecordsController.js +360 -0
  122. package/crud/sub/SubCrudRecordsController.js.map +1 -0
  123. package/crud/sub/SubCrudRecordsControllerTests.d.ts +39 -0
  124. package/crud/sub/SubCrudRecordsControllerTests.js +821 -0
  125. package/crud/sub/SubCrudRecordsControllerTests.js.map +1 -0
  126. package/crud/sub/SubCrudRecordsStore.d.ts +95 -0
  127. package/{forms/index.js → crud/sub/SubCrudRecordsStore.js} +2 -2
  128. package/crud/sub/SubCrudRecordsStore.js.map +1 -0
  129. package/crud/sub/index.d.ts +3 -0
  130. package/crud/sub/index.js +20 -0
  131. package/{forms → crud/sub}/index.js.map +1 -1
  132. package/index.d.ts +1 -1
  133. package/index.js +1 -1
  134. package/index.js.map +1 -1
  135. package/notifications/MemoryNotificationRecordsStore.js +189 -198
  136. package/notifications/MemoryNotificationRecordsStore.js.map +1 -1
  137. package/notifications/NotificationRecordsController.js +438 -460
  138. package/notifications/NotificationRecordsController.js.map +1 -1
  139. package/notifications/NotificationRecordsStore.d.ts +2 -1
  140. package/notifications/WebPushInterface.d.ts +0 -1
  141. package/notifications/WebPushInterface.js +0 -1
  142. package/notifications/WebPushInterface.js.map +1 -1
  143. package/package.json +6 -6
  144. package/packages/MemoryPackageRecordsStore.d.ts +10 -0
  145. package/packages/MemoryPackageRecordsStore.js +38 -0
  146. package/packages/MemoryPackageRecordsStore.js.map +1 -0
  147. package/packages/PackageRecordsController.d.ts +26 -0
  148. package/packages/PackageRecordsController.js +49 -0
  149. package/packages/PackageRecordsController.js.map +1 -0
  150. package/packages/PackageRecordsStore.d.ts +32 -0
  151. package/packages/PackageRecordsStore.js +19 -0
  152. package/packages/PackageRecordsStore.js.map +1 -0
  153. package/packages/index.d.ts +4 -0
  154. package/packages/index.js +21 -0
  155. package/packages/index.js.map +1 -0
  156. package/packages/version/MemoryPackageVersionRecordsStore.d.ts +21 -0
  157. package/packages/version/MemoryPackageVersionRecordsStore.js +177 -0
  158. package/packages/version/MemoryPackageVersionRecordsStore.js.map +1 -0
  159. package/packages/version/PackageVersionRecordsController.d.ts +144 -0
  160. package/packages/version/PackageVersionRecordsController.js +656 -0
  161. package/packages/version/PackageVersionRecordsController.js.map +1 -0
  162. package/packages/version/PackageVersionRecordsStore.d.ts +342 -0
  163. package/packages/version/PackageVersionRecordsStore.js +126 -0
  164. package/packages/version/PackageVersionRecordsStore.js.map +1 -0
  165. package/packages/version/index.d.ts +4 -0
  166. package/packages/version/index.js +21 -0
  167. package/packages/version/index.js.map +1 -0
  168. package/tracing/TracingDecorators.js +31 -40
  169. package/tracing/TracingDecorators.js.map +1 -1
  170. package/webhooks/MemoryWebhookRecordsStore.js +56 -72
  171. package/webhooks/MemoryWebhookRecordsStore.js.map +1 -1
  172. package/webhooks/WebhookEnvironment.d.ts +3 -3
  173. package/webhooks/WebhookRecordsController.d.ts +2 -1
  174. package/webhooks/WebhookRecordsController.js +389 -382
  175. package/webhooks/WebhookRecordsController.js.map +1 -1
  176. package/webhooks/WebhookRecordsStore.d.ts +2 -1
  177. package/websockets/InstRecordsStore.d.ts +50 -0
  178. package/websockets/InstRecordsStore.js +17 -0
  179. package/websockets/InstRecordsStore.js.map +1 -1
  180. package/websockets/MemoryTempInstRecordsStore.d.ts +5 -0
  181. package/websockets/MemoryTempInstRecordsStore.js +168 -179
  182. package/websockets/MemoryTempInstRecordsStore.js.map +1 -1
  183. package/websockets/MemoryWebsocketConnectionStore.js +98 -135
  184. package/websockets/MemoryWebsocketConnectionStore.js.map +1 -1
  185. package/websockets/MemoryWebsocketMessenger.js +29 -48
  186. package/websockets/MemoryWebsocketMessenger.js.map +1 -1
  187. package/websockets/SplitInstRecordsStore.d.ts +4 -1
  188. package/websockets/SplitInstRecordsStore.js +167 -185
  189. package/websockets/SplitInstRecordsStore.js.map +1 -1
  190. package/websockets/TemporaryInstRecordsStore.d.ts +19 -1
  191. package/websockets/TemporaryInstRecordsStore.js +17 -0
  192. package/websockets/TemporaryInstRecordsStore.js.map +1 -1
  193. package/websockets/WebsocketController.d.ts +147 -3
  194. package/websockets/WebsocketController.js +1735 -1391
  195. package/websockets/WebsocketController.js.map +1 -1
  196. package/websockets/index.d.ts +0 -1
  197. package/websockets/index.js +0 -1
  198. package/websockets/index.js.map +1 -1
  199. package/AAGUID.d.ts +0 -11
  200. package/AAGUID.js +0 -116
  201. package/AAGUID.js.map +0 -1
  202. package/AuthUtils.d.ts +0 -162
  203. package/AuthUtils.js +0 -327
  204. package/AuthUtils.js.map +0 -1
  205. package/forms/FormError.d.ts +0 -43
  206. package/forms/FormError.js +0 -56
  207. package/forms/FormError.js.map +0 -1
  208. package/forms/index.d.ts +0 -2
  209. package/websockets/Utils.d.ts +0 -33
  210. package/websockets/Utils.js +0 -82
  211. package/websockets/Utils.js.map +0 -1
@@ -4,40 +4,23 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
- return new (P || (P = Promise))(function (resolve, reject) {
10
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
- step((generator = generator.apply(thisArg, _arguments || [])).next());
14
- });
15
- };
16
- var __rest = (this && this.__rest) || function (s, e) {
17
- var t = {};
18
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
19
- t[p] = s[p];
20
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
21
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
22
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
23
- t[p[i]] = s[p[i]];
24
- }
25
- return t;
26
- };
27
- import { action, ON_WEBHOOK_ACTION_NAME, } from '@casual-simulation/aux-common/bots';
28
- import { YjsPartitionImpl } from '@casual-simulation/aux-common/partitions';
7
+ import { action, createInitializationUpdate, ON_WEBHOOK_ACTION_NAME, } from '@casual-simulation/aux-common/bots';
8
+ import { constructInitializationUpdate, YjsPartitionImpl, } from '@casual-simulation/aux-common/partitions';
29
9
  import { device, deviceError, deviceResult, } from '@casual-simulation/aux-common/common/RemoteActions';
30
10
  import { fromByteArray, toByteArray } from 'base64-js';
31
11
  import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
32
- import { WebsocketEventTypes, } from '@casual-simulation/aux-common/websockets/WebsocketEvents';
12
+ import { WebsocketEventTypes } from '@casual-simulation/aux-common/websockets/WebsocketEvents';
33
13
  import { sumBy } from 'lodash';
34
- import { PRIVATE_MARKER, ACCOUNT_MARKER, DEFAULT_BRANCH_NAME, } from '@casual-simulation/aux-common';
14
+ import { PRIVATE_MARKER, ACCOUNT_MARKER, DEFAULT_BRANCH_NAME, tryParseJson, } from '@casual-simulation/aux-common';
35
15
  import { SplitInstRecordsStore } from './SplitInstRecordsStore';
36
- import { v4 as uuid } from 'uuid';
16
+ import { v4 as uuid, v7 as uuidv7 } from 'uuid';
37
17
  import { getSubscriptionFeatures } from '../SubscriptionConfiguration';
38
18
  import { traced } from '../tracing/TracingDecorators';
39
19
  import { trace } from '@opentelemetry/api';
40
20
  import { SEMATTRS_ENDUSER_ID } from '@opentelemetry/semantic-conventions';
21
+ import { formatVersionSpecifier, } from '../packages/version';
22
+ import { STORED_AUX_SCHEMA } from '../webhooks';
23
+ import { formatInstId } from '@casual-simulation/aux-common';
41
24
  const TRACE_NAME = 'WebsocketController';
42
25
  export const SAVE_PERMANENT_BRANCHES_LOCK = 'savePermanentBranches';
43
26
  /**
@@ -47,7 +30,7 @@ export class WebsocketController {
47
30
  get messenger() {
48
31
  return this._messenger;
49
32
  }
50
- constructor(connectionStore, messenger, instStore, temporaryInstStore, auth, policies, config, metrics, authStore) {
33
+ constructor(connectionStore, messenger, instStore, temporaryInstStore, auth, policies, config, metrics, authStore, packageVersions = null) {
51
34
  this.mergeUpdatesOnMaxSizeExceeded = false;
52
35
  this._connectionStore = connectionStore;
53
36
  this._messenger = messenger;
@@ -58,6 +41,7 @@ export class WebsocketController {
58
41
  this._policies = policies;
59
42
  this._config = config;
60
43
  this._metrics = metrics;
44
+ this._packageVersions = packageVersions;
61
45
  }
62
46
  /**
63
47
  * Attempts to log the given connection in.
@@ -65,987 +49,1171 @@ export class WebsocketController {
65
49
  * @param requestId The ID of the request.
66
50
  * @param message The login message.
67
51
  */
68
- login(connectionId, requestId, message) {
69
- return __awaiter(this, void 0, void 0, function* () {
70
- try {
71
- let userId = null;
72
- let sessionId = null;
73
- let clientConnectionId;
74
- if (!message.connectionToken) {
75
- if (!message.connectionId) {
76
- yield this._messenger.sendMessage([connectionId], {
77
- type: 'login_result',
78
- success: false,
79
- errorCode: 'unacceptable_connection_id',
80
- errorMessage: 'A connection ID must be specified when logging in without a connection token.',
81
- });
82
- return;
83
- }
84
- yield this._connectionStore.saveConnection({
85
- serverConnectionId: connectionId,
86
- clientConnectionId: message.connectionId,
87
- userId: null,
88
- sessionId: null,
89
- token: null,
90
- });
91
- clientConnectionId = message.connectionId;
92
- }
93
- else {
94
- const validationResult = yield this._auth.validateConnectionToken(message.connectionToken);
95
- if (validationResult.success === false) {
96
- yield this._messenger.sendMessage([connectionId], {
97
- type: 'login_result',
98
- success: false,
99
- errorCode: validationResult.errorCode,
100
- errorMessage: validationResult.errorMessage,
101
- });
102
- return;
103
- }
104
- yield this._connectionStore.saveConnection({
105
- serverConnectionId: connectionId,
106
- userId: validationResult.userId,
107
- sessionId: validationResult.sessionId,
108
- clientConnectionId: validationResult.connectionId,
109
- token: message.connectionToken,
52
+ async login(connectionId, requestId, message) {
53
+ try {
54
+ let userId = null;
55
+ let sessionId = null;
56
+ let clientConnectionId;
57
+ if (!message.connectionToken) {
58
+ if (!message.connectionId) {
59
+ await this._messenger.sendMessage([connectionId], {
60
+ type: 'login_result',
61
+ success: false,
62
+ errorCode: 'unacceptable_connection_id',
63
+ errorMessage: 'A connection ID must be specified when logging in without a connection token.',
110
64
  });
111
- yield this._connectionStore.saveAuthorizedInst(connectionId, validationResult.recordName, validationResult.inst, 'token');
112
- userId = validationResult.userId;
113
- sessionId = validationResult.sessionId;
114
- clientConnectionId = validationResult.connectionId;
115
- const span = trace.getActiveSpan();
116
- if (span) {
117
- span.setAttributes({
118
- [SEMATTRS_ENDUSER_ID]: userId,
119
- ['request.userId']: userId,
120
- ['request.sessionId']: sessionId,
121
- ['request.subscriptionId']: validationResult.subscriptionId,
122
- ['request.subscriptionTier']: validationResult.subscriptionTier,
123
- });
124
- }
65
+ return;
125
66
  }
126
- yield this._messenger.sendMessage([connectionId], {
127
- type: 'login_result',
128
- success: true,
129
- info: {
130
- userId,
131
- sessionId,
132
- connectionId: clientConnectionId,
133
- },
67
+ await this._connectionStore.saveConnection({
68
+ serverConnectionId: connectionId,
69
+ clientConnectionId: message.connectionId,
70
+ userId: null,
71
+ sessionId: null,
72
+ token: null,
134
73
  });
74
+ clientConnectionId = message.connectionId;
135
75
  }
136
- catch (err) {
137
- console.error('[WebsocketController] [login] Error while logging in.', err);
138
- yield this.sendError(connectionId, requestId, {
139
- success: false,
140
- errorCode: 'server_error',
141
- errorMessage: 'A server error occurred while logging in.',
76
+ else {
77
+ const validationResult = await this._auth.validateConnectionToken(message.connectionToken);
78
+ if (validationResult.success === false) {
79
+ await this._messenger.sendMessage([connectionId], {
80
+ type: 'login_result',
81
+ success: false,
82
+ errorCode: validationResult.errorCode,
83
+ errorMessage: validationResult.errorMessage,
84
+ });
85
+ return;
86
+ }
87
+ await this._connectionStore.saveConnection({
88
+ serverConnectionId: connectionId,
89
+ userId: validationResult.userId,
90
+ sessionId: validationResult.sessionId,
91
+ clientConnectionId: validationResult.connectionId,
92
+ token: message.connectionToken,
142
93
  });
94
+ await this._connectionStore.saveAuthorizedInst(connectionId, validationResult.recordName, validationResult.inst, 'token');
95
+ userId = validationResult.userId;
96
+ sessionId = validationResult.sessionId;
97
+ clientConnectionId = validationResult.connectionId;
98
+ const span = trace.getActiveSpan();
99
+ if (span) {
100
+ span.setAttributes({
101
+ [SEMATTRS_ENDUSER_ID]: userId,
102
+ ['request.userId']: userId,
103
+ ['request.sessionId']: sessionId,
104
+ ['request.subscriptionId']: validationResult.subscriptionId,
105
+ ['request.subscriptionTier']: validationResult.subscriptionTier,
106
+ });
107
+ }
143
108
  }
144
- });
109
+ await this._messenger.sendMessage([connectionId], {
110
+ type: 'login_result',
111
+ success: true,
112
+ info: {
113
+ userId,
114
+ sessionId,
115
+ connectionId: clientConnectionId,
116
+ },
117
+ });
118
+ }
119
+ catch (err) {
120
+ console.error('[WebsocketController] [login] Error while logging in.', err);
121
+ await this.sendError(connectionId, requestId, {
122
+ success: false,
123
+ errorCode: 'server_error',
124
+ errorMessage: 'A server error occurred while logging in.',
125
+ });
126
+ }
145
127
  }
146
- disconnect(connectionId) {
128
+ async disconnect(connectionId) {
147
129
  var _a;
148
- return __awaiter(this, void 0, void 0, function* () {
149
- const loadedConnections = yield this._connectionStore.getConnections(connectionId);
150
- yield this._connectionStore.clearConnection(connectionId);
151
- for (let connection of loadedConnections) {
152
- if (connection.mode === 'branch') {
153
- if (connection.temporary) {
154
- const count = yield this._connectionStore.countConnectionsByBranch(connection.mode, connection.recordName, connection.inst, connection.branch);
155
- if (count <= 0) {
156
- const branch = (_a = (yield this._instStore.getBranchByName(connection.recordName, connection.inst, connection.branch))) !== null && _a !== void 0 ? _a : (yield this._temporaryStore.getBranchByName(connection.recordName, connection.inst, connection.branch));
157
- if (branch.temporary) {
158
- console.log('[WebsocketController] Deleting temporary branch', connection.recordName, connection.inst, connection.branch);
159
- yield this._temporaryStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
160
- yield this._instStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
161
- }
130
+ const loadedConnections = await this._connectionStore.getConnections(connectionId);
131
+ await this._connectionStore.clearConnection(connectionId);
132
+ for (let connection of loadedConnections) {
133
+ if (connection.mode === 'branch') {
134
+ if (connection.temporary) {
135
+ const count = await this._connectionStore.countConnectionsByBranch(connection.mode, connection.recordName, connection.inst, connection.branch);
136
+ if (count <= 0) {
137
+ const branch = (_a = (await this._instStore.getBranchByName(connection.recordName, connection.inst, connection.branch))) !== null && _a !== void 0 ? _a : (await this._temporaryStore.getBranchByName(connection.recordName, connection.inst, connection.branch));
138
+ if (branch.temporary) {
139
+ console.log('[WebsocketController] Deleting temporary branch', connection.recordName, connection.inst, connection.branch);
140
+ await this._temporaryStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
141
+ await this._instStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
162
142
  }
163
143
  }
164
- const watchingDevices = yield this._connectionStore.getConnectionsByBranch('watch_branch', connection.recordName, connection.inst, connection.branch);
165
- yield this._messenger.sendMessage(watchingDevices.map((d) => d.serverConnectionId), {
166
- type: 'repo/disconnected_from_branch',
167
- broadcast: false,
168
- recordName: connection.recordName,
169
- inst: connection.inst,
170
- branch: connection.branch,
171
- connection: connectionInfo(connection),
172
- });
173
144
  }
145
+ const watchingDevices = await this._connectionStore.getConnectionsByBranch('watch_branch', connection.recordName, connection.inst, connection.branch);
146
+ await this._messenger.sendMessage(watchingDevices.map((d) => d.serverConnectionId), {
147
+ type: 'repo/disconnected_from_branch',
148
+ broadcast: false,
149
+ recordName: connection.recordName,
150
+ inst: connection.inst,
151
+ branch: connection.branch,
152
+ connection: connectionInfo(connection),
153
+ });
174
154
  }
175
- });
155
+ }
176
156
  }
177
- watchBranch(connectionId, event) {
157
+ async watchBranch(connectionId, event) {
178
158
  var _a, _b, _c, _d;
179
- return __awaiter(this, void 0, void 0, function* () {
180
- if (!event) {
181
- console.warn('[CasualRepoServer] Trying to watch branch with a null event!');
182
- return;
183
- }
184
- console.log(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, ${connectionId}] Watch`);
185
- const connection = yield this._connectionStore.getConnection(connectionId);
186
- if (!connection) {
187
- console.error(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Unable to watch branch. Connection not found!`);
188
- yield this.sendError(connectionId, -1, {
159
+ if (!event) {
160
+ console.warn('[CasualRepoServer] Trying to watch branch with a null event!');
161
+ return;
162
+ }
163
+ console.log(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, ${connectionId}] Watch`);
164
+ const connection = await this._connectionStore.getConnection(connectionId);
165
+ if (!connection) {
166
+ console.error(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Unable to watch branch. Connection not found!`);
167
+ await this.sendError(connectionId, -1, {
168
+ success: false,
169
+ errorCode: 'invalid_connection_state',
170
+ errorMessage: `A server error occurred. (namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId})`,
171
+ recordName: event.recordName,
172
+ inst: event.inst,
173
+ branch: event.branch,
174
+ });
175
+ await this.messenger.disconnect(connectionId);
176
+ return;
177
+ }
178
+ if (connection.token && event.recordName) {
179
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'token');
180
+ if (!authorized) {
181
+ await this.messenger.sendMessage([connectionId], {
182
+ type: 'repo/watch_branch_result',
189
183
  success: false,
190
- errorCode: 'invalid_connection_state',
191
- errorMessage: `A server error occurred. (namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId})`,
184
+ errorCode: 'not_authorized',
185
+ errorMessage: 'You are not authorized to access this inst.',
192
186
  recordName: event.recordName,
193
187
  inst: event.inst,
194
188
  branch: event.branch,
189
+ reason: {
190
+ type: 'invalid_token',
191
+ },
195
192
  });
196
- yield this.messenger.disconnect(connectionId);
197
- return;
198
- }
199
- if (connection.token && event.recordName) {
200
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'token');
201
- if (!authorized) {
202
- yield this.messenger.sendMessage([connectionId], {
203
- type: 'repo/watch_branch_result',
204
- success: false,
205
- errorCode: 'not_authorized',
206
- errorMessage: 'You are not authorized to access this inst.',
207
- recordName: event.recordName,
208
- inst: event.inst,
209
- branch: event.branch,
210
- reason: {
211
- type: 'invalid_token',
212
- },
213
- });
214
- return;
215
- }
216
- }
217
- const config = yield this._config.getSubscriptionConfiguration();
218
- if (!event.recordName) {
219
- if (((_b = (_a = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _a === void 0 ? void 0 : _a.publicInsts) === null || _b === void 0 ? void 0 : _b.allowed) === false) {
220
- yield this.messenger.sendMessage([connectionId], {
221
- type: 'repo/watch_branch_result',
222
- success: false,
223
- errorCode: 'not_authorized',
224
- errorMessage: 'Temporary insts are not allowed.',
225
- recordName: event.recordName,
226
- inst: event.inst,
227
- branch: event.branch,
228
- });
229
- return;
230
- }
231
- }
232
- const instResult = yield this._getOrCreateInst(event.recordName, event.inst, connection.userId, config);
233
- if (instResult.success === false) {
234
- yield this.messenger.sendMessage([connectionId], Object.assign(Object.assign({}, instResult), { type: 'repo/watch_branch_result', recordName: event.recordName, inst: event.inst, branch: event.branch }));
235
193
  return;
236
194
  }
237
- const inst = instResult.inst;
238
- const features = instResult.features;
239
- let maxConnections = null;
240
- if (features &&
241
- typeof features.insts.maxActiveConnectionsPerInst === 'number') {
242
- maxConnections = features.insts.maxActiveConnectionsPerInst;
243
- }
244
- else if (!event.recordName &&
245
- typeof ((_d = (_c = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _c === void 0 ? void 0 : _c.publicInsts) === null || _d === void 0 ? void 0 : _d.maxActiveConnectionsPerInst) === 'number') {
246
- maxConnections =
247
- config.defaultFeatures.publicInsts.maxActiveConnectionsPerInst;
248
- }
249
- if (maxConnections) {
250
- const count = yield this._connectionStore.countConnectionsByBranch('branch', event.recordName, event.inst, event.branch);
251
- if (count >= maxConnections) {
252
- yield this.messenger.sendMessage([connectionId], {
253
- type: 'repo/watch_branch_result',
254
- success: false,
255
- errorCode: features
256
- ? 'subscription_limit_reached'
257
- : 'not_authorized',
258
- errorMessage: 'The maximum number of active connections to this inst has been reached.',
259
- recordName: event.recordName,
260
- inst: event.inst,
261
- branch: event.branch,
262
- });
263
- return;
264
- }
265
- }
266
- yield this._connectionStore.saveBranchConnection(Object.assign(Object.assign({}, connection), { serverConnectionId: connectionId, mode: 'branch', recordName: event.recordName, inst: event.inst, branch: event.branch, temporary: event.temporary || false }));
267
- const branch = yield this._getOrCreateBranch(event.recordName, event.inst, event.branch, event.temporary, inst);
268
- let updates;
269
- if (branch.temporary) {
270
- // Temporary branches use a temporary inst data store.
271
- // This is because temporary branches are never persisted to disk.
272
- updates = yield this._temporaryStore.getUpdates(event.recordName, event.inst, event.branch);
273
- }
274
- else {
275
- updates = yield this._instStore.getCurrentUpdates(event.recordName, event.inst, event.branch);
276
- }
277
- if (!updates) {
278
- // branch info exists, but no updates for them exist yet.
279
- updates = {
280
- updates: [],
281
- timestamps: [],
282
- instSizeInBytes: 0,
283
- };
284
- }
285
- const watchingDevices = yield this._connectionStore.getConnectionsByBranch('watch_branch', event.recordName, event.inst, event.branch);
286
- console.log(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, ${connectionId}] Connected.`);
287
- const promises = [
288
- this._messenger.sendMessage(watchingDevices.map((d) => d.serverConnectionId), {
289
- type: 'repo/connected_to_branch',
290
- broadcast: false,
291
- branch: event,
292
- connection: connectionInfo(connection),
293
- }),
294
- this._messenger.sendMessage([connection.serverConnectionId], {
295
- type: 'repo/add_updates',
195
+ }
196
+ const config = await this._config.getSubscriptionConfiguration();
197
+ if (!event.recordName) {
198
+ if (((_b = (_a = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _a === void 0 ? void 0 : _a.publicInsts) === null || _b === void 0 ? void 0 : _b.allowed) === false) {
199
+ await this.messenger.sendMessage([connectionId], {
200
+ type: 'repo/watch_branch_result',
201
+ success: false,
202
+ errorCode: 'not_authorized',
203
+ errorMessage: 'Temporary insts are not allowed.',
296
204
  recordName: event.recordName,
297
205
  inst: event.inst,
298
206
  branch: event.branch,
299
- updates: updates.updates,
300
- initial: true,
301
- }),
302
- this._messenger.sendMessage([connection.serverConnectionId], {
207
+ });
208
+ return;
209
+ }
210
+ }
211
+ const instResult = await this._getOrCreateInst(event.recordName, event.inst, connection.userId, config);
212
+ if (instResult.success === false) {
213
+ await this.messenger.sendMessage([connectionId], {
214
+ ...instResult,
215
+ type: 'repo/watch_branch_result',
216
+ recordName: event.recordName,
217
+ inst: event.inst,
218
+ branch: event.branch,
219
+ });
220
+ return;
221
+ }
222
+ const inst = instResult.inst;
223
+ const features = instResult.features;
224
+ let maxConnections = null;
225
+ if (features &&
226
+ typeof features.insts.maxActiveConnectionsPerInst === 'number') {
227
+ maxConnections = features.insts.maxActiveConnectionsPerInst;
228
+ }
229
+ else if (!event.recordName &&
230
+ typeof ((_d = (_c = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _c === void 0 ? void 0 : _c.publicInsts) === null || _d === void 0 ? void 0 : _d.maxActiveConnectionsPerInst) === 'number') {
231
+ maxConnections =
232
+ config.defaultFeatures.publicInsts.maxActiveConnectionsPerInst;
233
+ }
234
+ if (maxConnections) {
235
+ const count = await this._connectionStore.countConnectionsByBranch('branch', event.recordName, event.inst, event.branch);
236
+ if (count >= maxConnections) {
237
+ await this.messenger.sendMessage([connectionId], {
303
238
  type: 'repo/watch_branch_result',
239
+ success: false,
240
+ errorCode: features
241
+ ? 'subscription_limit_reached'
242
+ : 'not_authorized',
243
+ errorMessage: 'The maximum number of active connections to this inst has been reached.',
304
244
  recordName: event.recordName,
305
245
  inst: event.inst,
306
246
  branch: event.branch,
307
- success: true,
308
- }),
309
- ];
310
- yield Promise.all(promises);
247
+ });
248
+ return;
249
+ }
250
+ }
251
+ await this._connectionStore.saveBranchConnection({
252
+ ...connection,
253
+ serverConnectionId: connectionId,
254
+ mode: 'branch',
255
+ recordName: event.recordName,
256
+ inst: event.inst,
257
+ branch: event.branch,
258
+ temporary: event.temporary || false,
311
259
  });
260
+ const branch = await this._getOrCreateBranch(event.recordName, event.inst, event.branch, event.temporary, inst);
261
+ let updates;
262
+ if (branch.temporary) {
263
+ // Temporary branches use a temporary inst data store.
264
+ // This is because temporary branches are never persisted to disk.
265
+ updates = await this._temporaryStore.getUpdates(event.recordName, event.inst, event.branch);
266
+ }
267
+ else {
268
+ updates = await this._instStore.getCurrentUpdates(event.recordName, event.inst, event.branch);
269
+ }
270
+ if (!updates) {
271
+ // branch info exists, but no updates for them exist yet.
272
+ updates = {
273
+ updates: [],
274
+ timestamps: [],
275
+ instSizeInBytes: 0,
276
+ };
277
+ }
278
+ const watchingDevices = await this._connectionStore.getConnectionsByBranch('watch_branch', event.recordName, event.inst, event.branch);
279
+ console.log(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, ${connectionId}] Connected.`);
280
+ const promises = [
281
+ this._messenger.sendMessage(watchingDevices.map((d) => d.serverConnectionId), {
282
+ type: 'repo/connected_to_branch',
283
+ broadcast: false,
284
+ branch: event,
285
+ connection: connectionInfo(connection),
286
+ }),
287
+ this._messenger.sendMessage([connection.serverConnectionId], {
288
+ type: 'repo/add_updates',
289
+ recordName: event.recordName,
290
+ inst: event.inst,
291
+ branch: event.branch,
292
+ updates: updates.updates,
293
+ initial: true,
294
+ }),
295
+ this._messenger.sendMessage([connection.serverConnectionId], {
296
+ type: 'repo/watch_branch_result',
297
+ recordName: event.recordName,
298
+ inst: event.inst,
299
+ branch: event.branch,
300
+ success: true,
301
+ }),
302
+ ];
303
+ await Promise.all(promises);
312
304
  }
313
- unwatchBranch(connectionId, recordName, inst, branch) {
305
+ async unwatchBranch(connectionId, recordName, inst, branch) {
314
306
  var _a;
315
- return __awaiter(this, void 0, void 0, function* () {
316
- if (!branch) {
317
- console.warn('[CasualRepoServer] Trying to unwatch branch with a null event!');
318
- return;
319
- }
320
- console.log(`[CausalRepoServer] [namespace: ${recordName}/${inst}/${branch}, ${connectionId}] Unwatch`);
321
- const connection = yield this._connectionStore.getBranchConnection(connectionId, 'branch', recordName, inst, branch);
322
- if (connection) {
323
- yield this._connectionStore.deleteBranchConnection(connectionId, 'branch', recordName, inst, branch);
324
- if (connection.temporary) {
325
- const count = yield this._connectionStore.countConnectionsByBranch('branch', recordName, inst, branch);
326
- if (count <= 0) {
327
- const branch = (_a = (yield this._instStore.getBranchByName(connection.recordName, connection.inst, connection.branch))) !== null && _a !== void 0 ? _a : (yield this._temporaryStore.getBranchByName(connection.recordName, connection.inst, connection.branch));
328
- if (branch === null || branch === void 0 ? void 0 : branch.temporary) {
329
- yield this._temporaryStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
330
- // Delete the branch from the permentent store even if it is temporary
331
- // because it is possible that the branch was created before temporary branches were only stored in the temporary store.
332
- yield this._instStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
333
- }
307
+ if (!branch) {
308
+ console.warn('[CasualRepoServer] Trying to unwatch branch with a null event!');
309
+ return;
310
+ }
311
+ console.log(`[WebsocketController] [namespace: ${recordName}/${inst}/${branch}, ${connectionId}] Unwatch`);
312
+ const connection = await this._connectionStore.getBranchConnection(connectionId, 'branch', recordName, inst, branch);
313
+ if (connection) {
314
+ await this._connectionStore.deleteBranchConnection(connectionId, 'branch', recordName, inst, branch);
315
+ if (connection.temporary) {
316
+ const count = await this._connectionStore.countConnectionsByBranch('branch', recordName, inst, branch);
317
+ if (count <= 0) {
318
+ const branch = (_a = (await this._instStore.getBranchByName(connection.recordName, connection.inst, connection.branch))) !== null && _a !== void 0 ? _a : (await this._temporaryStore.getBranchByName(connection.recordName, connection.inst, connection.branch));
319
+ if (branch === null || branch === void 0 ? void 0 : branch.temporary) {
320
+ await this._temporaryStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
321
+ // Delete the branch from the permentent store even if it is temporary
322
+ // because it is possible that the branch was created before temporary branches were only stored in the temporary store.
323
+ await this._instStore.deleteBranch(connection.recordName, connection.inst, connection.branch);
334
324
  }
335
325
  }
336
- const watchingDevices = yield this._connectionStore.getConnectionsByBranch('watch_branch', recordName, inst, branch);
337
- yield this._messenger.sendMessage(watchingDevices.map((d) => d.serverConnectionId), {
338
- type: 'repo/disconnected_from_branch',
339
- broadcast: false,
340
- recordName,
341
- inst,
342
- branch: branch,
343
- connection: connectionInfo(connection),
344
- });
345
326
  }
346
- });
327
+ const watchingDevices = await this._connectionStore.getConnectionsByBranch('watch_branch', recordName, inst, branch);
328
+ await this._messenger.sendMessage(watchingDevices.map((d) => d.serverConnectionId), {
329
+ type: 'repo/disconnected_from_branch',
330
+ broadcast: false,
331
+ recordName,
332
+ inst,
333
+ branch: branch,
334
+ connection: connectionInfo(connection),
335
+ });
336
+ }
347
337
  }
348
- addUpdates(connectionId, event) {
338
+ async addUpdates(connectionId, event) {
349
339
  var _a, _b, _c, _d, _e;
350
- return __awaiter(this, void 0, void 0, function* () {
351
- if (!event) {
352
- console.warn('[CasualRepoServer] Trying to add atoms with a null event!');
353
- return;
354
- }
355
- console.log(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Add Updates`);
356
- const connection = yield this._connectionStore.getConnection(connectionId);
357
- if (!connection) {
358
- console.error(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Unable to add updates. Connection not found!`);
359
- yield this.sendError(connectionId, -1, {
340
+ if (!event) {
341
+ console.warn('[CasualRepoServer] Trying to add atoms with a null event!');
342
+ return;
343
+ }
344
+ console.log(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Add Updates`);
345
+ const connection = await this._connectionStore.getConnection(connectionId);
346
+ if (!connection) {
347
+ console.error(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Unable to add updates. Connection not found!`);
348
+ await this.sendError(connectionId, -1, {
349
+ success: false,
350
+ errorCode: 'invalid_connection_state',
351
+ errorMessage: `A server error occurred. (namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId})`,
352
+ recordName: event.recordName,
353
+ inst: event.inst,
354
+ branch: event.branch,
355
+ });
356
+ await this.messenger.disconnect(connectionId);
357
+ return;
358
+ }
359
+ if (connection.token && event.recordName) {
360
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'token');
361
+ if (!authorized) {
362
+ await this.sendError(connectionId, -1, {
360
363
  success: false,
361
- errorCode: 'invalid_connection_state',
362
- errorMessage: `A server error occurred. (namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId})`,
364
+ errorCode: 'not_authorized',
365
+ errorMessage: 'You are not authorized to access this inst.',
363
366
  recordName: event.recordName,
364
367
  inst: event.inst,
365
368
  branch: event.branch,
369
+ reason: {
370
+ type: 'invalid_token',
371
+ },
366
372
  });
367
- yield this.messenger.disconnect(connectionId);
368
373
  return;
369
374
  }
370
- if (connection.token && event.recordName) {
371
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'token');
372
- if (!authorized) {
373
- yield this.sendError(connectionId, -1, {
375
+ }
376
+ if (event.updates) {
377
+ let branch = (_a = (await this._instStore.getBranchByName(event.recordName, event.inst, event.branch))) !== null && _a !== void 0 ? _a : (await this._temporaryStore.getBranchByName(event.recordName, event.inst, event.branch));
378
+ const updateSize = sumBy(event.updates, (u) => Buffer.byteLength(u, 'utf8'));
379
+ const config = await this._config.getSubscriptionConfiguration();
380
+ let features = null;
381
+ if (!event.recordName) {
382
+ if (((_c = (_b = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _b === void 0 ? void 0 : _b.publicInsts) === null || _c === void 0 ? void 0 : _c.allowed) === false) {
383
+ await this.sendError(connectionId, -1, {
374
384
  success: false,
375
385
  errorCode: 'not_authorized',
376
- errorMessage: 'You are not authorized to access this inst.',
386
+ errorMessage: 'Temporary insts are not allowed.',
377
387
  recordName: event.recordName,
378
388
  inst: event.inst,
379
389
  branch: event.branch,
380
- reason: {
381
- type: 'invalid_token',
382
- },
383
390
  });
384
391
  return;
385
392
  }
386
393
  }
387
- if (event.updates) {
388
- let branch = (_a = (yield this._instStore.getBranchByName(event.recordName, event.inst, event.branch))) !== null && _a !== void 0 ? _a : (yield this._temporaryStore.getBranchByName(event.recordName, event.inst, event.branch));
389
- const updateSize = sumBy(event.updates, (u) => Buffer.byteLength(u, 'utf8'));
390
- const config = yield this._config.getSubscriptionConfiguration();
391
- let features = null;
392
- if (!event.recordName) {
393
- if (((_c = (_b = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _b === void 0 ? void 0 : _b.publicInsts) === null || _c === void 0 ? void 0 : _c.allowed) === false) {
394
- yield this.sendError(connectionId, -1, {
395
- success: false,
396
- errorCode: 'not_authorized',
397
- errorMessage: 'Temporary insts are not allowed.',
398
- recordName: event.recordName,
399
- inst: event.inst,
400
- branch: event.branch,
401
- });
402
- return;
403
- }
404
- }
405
- if (!branch) {
406
- console.log(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Branch not found!`);
407
- const instResult = yield this._getOrCreateInst(event.recordName, event.inst, connection.userId, config);
408
- if (instResult.success === false) {
409
- yield this.sendError(connectionId, -1, Object.assign(Object.assign({}, instResult), { recordName: event.recordName, inst: event.inst, branch: event.branch }));
410
- return;
411
- }
412
- else if (event.recordName) {
413
- const authorizeResult = yield this._policies.authorizeUserAndInstances(instResult.context, {
414
- resourceKind: 'inst',
415
- resourceId: event.inst,
416
- action: 'updateData',
417
- userId: connection.userId,
418
- markers: instResult.inst.markers,
419
- instances: [],
420
- });
421
- if (authorizeResult.success === false) {
422
- yield this.sendError(connectionId, -1, Object.assign(Object.assign({}, authorizeResult), { recordName: event.recordName, inst: event.inst, branch: event.branch }));
423
- return;
424
- }
425
- }
426
- features = instResult.features;
427
- const branchResult = yield this._instStore.saveBranch({
428
- branch: event.branch,
429
- inst: event.inst,
394
+ if (!branch) {
395
+ console.log(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Branch not found!`);
396
+ const instResult = await this._getOrCreateInst(event.recordName, event.inst, connection.userId, config);
397
+ if (instResult.success === false) {
398
+ await this.sendError(connectionId, -1, {
399
+ ...instResult,
430
400
  recordName: event.recordName,
431
- temporary: false,
401
+ inst: event.inst,
402
+ branch: event.branch,
432
403
  });
433
- if (branchResult.success === false) {
434
- yield this.sendError(connectionId, -1, Object.assign(Object.assign({}, branchResult), { recordName: event.recordName, inst: event.inst, branch: event.branch }));
435
- return;
436
- }
437
- branch = yield this._instStore.getBranchByName(event.recordName, event.inst, event.branch);
404
+ return;
438
405
  }
439
406
  else if (event.recordName) {
440
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'updateData');
441
- if (!authorized) {
442
- if (!branch.linkedInst) {
443
- console.error('[WebsocketController] The inst was not found even though the branch was found and exists in a record!');
444
- yield this.sendError(connectionId, -1, {
445
- success: false,
446
- errorCode: 'inst_not_found',
447
- errorMessage: 'The inst was not found.',
448
- recordName: event.recordName,
449
- inst: event.inst,
450
- branch: event.branch,
451
- });
452
- return;
453
- }
454
- const contextResult = yield this._policies.constructAuthorizationContext({
455
- recordKeyOrRecordName: event.recordName,
456
- userId: connection.userId,
457
- });
458
- if (contextResult.success === false) {
459
- yield this.sendError(connectionId, -1, Object.assign(Object.assign({}, contextResult), { recordName: event.recordName, inst: event.inst, branch: event.branch }));
460
- return;
461
- }
462
- const authorizeResult = yield this._policies.authorizeUserAndInstancesForResources(contextResult.context, {
463
- userId: connection.userId,
464
- instances: [],
465
- resources: [
466
- {
467
- resourceKind: 'inst',
468
- resourceId: event.inst,
469
- action: 'read',
470
- markers: branch.linkedInst.markers,
471
- },
472
- {
473
- resourceKind: 'inst',
474
- resourceId: event.inst,
475
- action: 'updateData',
476
- markers: branch.linkedInst.markers,
477
- },
478
- ],
479
- });
480
- // const authorizeReadResult =
481
- // await this._policies.authorizeRequestUsingContext(
482
- // contextResult.context,
483
- // {
484
- // action: 'inst.read',
485
- // inst: event.inst,
486
- // recordKeyOrRecordName: event.recordName,
487
- // resourceMarkers: branch.linkedInst.markers,
488
- // userId: connection.userId,
489
- // }
490
- // );
491
- if (authorizeResult.success === false) {
492
- yield this.sendError(connectionId, -1, Object.assign(Object.assign({}, authorizeResult), { recordName: event.recordName, inst: event.inst, branch: event.branch }));
493
- return;
494
- }
495
- // const authorizeUpdateResult =
496
- // await this._policies.authorizeUserAndInstances(
497
- // contextResult.context,
498
- // {
499
- // resourceKind: 'inst',
500
- // resourceId: event.inst,
501
- // action: 'updateData',
502
- // markers: branch.linkedInst.markers,
503
- // userId: connection.userId,
504
- // instances: [],
505
- // }
506
- // );
507
- // if (authorizeUpdateResult.success === false) {
508
- // await this.sendError(connectionId, -1, {
509
- // ...authorizeUpdateResult,
510
- // recordName: event.recordName,
511
- // inst: event.inst,
512
- // branch: event.branch,
513
- // });
514
- // return;
515
- // }
516
- yield this._connectionStore.saveAuthorizedInst(connectionId, event.recordName, event.inst, 'updateData');
517
- }
518
- }
519
- if (!features && branch.linkedInst) {
520
- features = getSubscriptionFeatures(config, branch.linkedInst.subscriptionStatus, branch.linkedInst.subscriptionId, branch.linkedInst.subscriptionType);
521
- }
522
- let maxInstSize = null;
523
- if (features &&
524
- typeof features.insts.maxBytesPerInst === 'number') {
525
- maxInstSize = features.insts.maxBytesPerInst;
526
- }
527
- else if (!event.recordName &&
528
- typeof ((_e = (_d = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _d === void 0 ? void 0 : _d.publicInsts) === null || _e === void 0 ? void 0 : _e.maxBytesPerInst) ===
529
- 'number') {
530
- maxInstSize =
531
- config.defaultFeatures.publicInsts.maxBytesPerInst;
532
- }
533
- if (maxInstSize) {
534
- const currentSize = branch.temporary
535
- ? yield this._temporaryStore.getInstSize(event.recordName, event.inst)
536
- : yield this._instStore.getInstSize(event.recordName, event.inst);
537
- const neededSizeInBytes = currentSize + updateSize;
538
- if (neededSizeInBytes > maxInstSize) {
539
- yield this._messenger.sendMessage([connectionId], {
540
- type: 'repo/updates_received',
407
+ const authorizeResult = await this._policies.authorizeUserAndInstances(instResult.context, {
408
+ resourceKind: 'inst',
409
+ resourceId: event.inst,
410
+ action: 'updateData',
411
+ userId: connection.userId,
412
+ markers: instResult.inst.markers,
413
+ instances: [],
414
+ });
415
+ if (authorizeResult.success === false) {
416
+ await this.sendError(connectionId, -1, {
417
+ ...authorizeResult,
541
418
  recordName: event.recordName,
542
419
  inst: event.inst,
543
420
  branch: event.branch,
544
- updateId: event.updateId,
545
- errorCode: 'max_size_reached',
546
- maxBranchSizeInBytes: maxInstSize,
547
- neededBranchSizeInBytes: neededSizeInBytes,
548
421
  });
549
422
  return;
550
423
  }
551
424
  }
552
- if (branch.temporary) {
553
- // Temporary branches use a temporary inst data store.
554
- // This is because temporary branches are never persisted to disk.
555
- yield this._temporaryStore.addUpdates(event.recordName, event.inst, event.branch, event.updates, updateSize);
556
- }
557
- else {
558
- const result = yield this._instStore.addUpdates(event.recordName, event.inst, event.branch, event.updates, updateSize);
559
- if (result.success === false) {
560
- console.log(`[CausalRepoServer] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Failed to add updates`, result);
561
- if (result.errorCode === 'max_size_reached') {
562
- if (result.success === false) {
563
- if ('updateId' in event) {
564
- let { success, branch } = result, rest = __rest(result, ["success", "branch"]);
565
- yield this._messenger.sendMessage([connectionId], Object.assign({ type: 'repo/updates_received', recordName: event.recordName, inst: event.inst, branch: event.branch, updateId: event.updateId }, rest));
566
- }
567
- return;
568
- }
569
- }
570
- }
571
- else {
572
- if (event.recordName &&
573
- this._instStore instanceof SplitInstRecordsStore) {
574
- this._instStore.temp.markBranchAsDirty({
575
- recordName: event.recordName,
576
- inst: event.inst,
577
- branch: event.branch,
578
- });
579
- }
580
- }
581
- }
582
- }
583
- const hasUpdates = event.updates && event.updates.length > 0;
584
- if (hasUpdates) {
585
- const connectedDevices = yield this._connectionStore.getConnectionsByBranch('branch', event.recordName, event.inst, event.branch);
586
- let ret = {
587
- type: 'repo/add_updates',
588
- recordName: event.recordName,
589
- inst: event.inst,
425
+ features = instResult.features;
426
+ const branchResult = await this._instStore.saveBranch({
590
427
  branch: event.branch,
591
- updates: event.updates,
592
- };
593
- yield this._messenger.sendMessage(connectedDevices.map((c) => c.serverConnectionId), ret, connectionId);
594
- }
595
- if ('updateId' in event) {
596
- yield this._messenger.sendMessage([connectionId], {
597
- type: 'repo/updates_received',
598
- recordName: event.recordName,
599
428
  inst: event.inst,
600
- branch: event.branch,
601
- updateId: event.updateId,
429
+ recordName: event.recordName,
430
+ temporary: false,
602
431
  });
603
- }
604
- });
605
- }
606
- sendAction(connectionId, event) {
607
- return __awaiter(this, void 0, void 0, function* () {
608
- if (!event) {
609
- console.warn('[CasualRepoServer] Trying to send event with a null event!');
610
- return;
611
- }
612
- // const namespace = branchNamespace(event.recordName, event.inst, event.branch);
613
- const connectedDevices = yield this._connectionStore.getConnectionsByBranch('branch', event.recordName, event.inst, event.branch);
614
- if (event.action.type === 'remote') {
615
- const action = event.action.event;
616
- }
617
- let finalAction;
618
- if (event.action.sessionId ||
619
- event.action.connectionId ||
620
- event.action.userId ||
621
- (typeof event.action.broadcast !== 'undefined' &&
622
- event.action.broadcast !== null)) {
623
- finalAction = event.action;
624
- }
625
- else {
626
- // TODO: Replace with system that selects target devices with better uniformity
627
- // than Math.random().
628
- const randomDeviceIndex = Math.min(connectedDevices.length - 1, Math.max(Math.floor(Math.random() * connectedDevices.length), 0));
629
- const randomDevice = connectedDevices[randomDeviceIndex];
630
- if (randomDevice) {
631
- finalAction = Object.assign(Object.assign({}, event.action), { connectionId: randomDevice.clientConnectionId });
632
- }
633
- }
634
- if (!finalAction) {
635
- return;
636
- }
637
- const currentConnection = yield this._connectionStore.getConnection(connectionId);
638
- if (currentConnection.token && event.recordName) {
639
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'token');
640
- if (!authorized) {
641
- yield this.sendError(connectionId, -1, {
642
- success: false,
643
- errorCode: 'not_authorized',
644
- errorMessage: 'You are not authorized to access this inst.',
432
+ if (branchResult.success === false) {
433
+ await this.sendError(connectionId, -1, {
434
+ ...branchResult,
645
435
  recordName: event.recordName,
646
436
  inst: event.inst,
647
437
  branch: event.branch,
648
- reason: {
649
- type: 'invalid_token',
650
- },
651
438
  });
652
439
  return;
653
440
  }
441
+ branch = await this._instStore.getBranchByName(event.recordName, event.inst, event.branch);
654
442
  }
655
- if (event.recordName) {
656
- const config = yield this._config.getSubscriptionConfiguration();
657
- const instResult = yield this._getInst(event.recordName, event.inst, currentConnection.userId, config);
658
- if (instResult.success === false) {
659
- yield this.sendError(connectionId, -1, instResult);
660
- return;
661
- }
662
- else if (!instResult.inst) {
663
- yield this.sendError(connectionId, -1, {
664
- success: false,
665
- errorCode: 'inst_not_found',
666
- errorMessage: 'The inst was not found.',
667
- });
668
- return;
669
- }
670
- const authorizeResult = yield this._policies.authorizeUserAndInstances(instResult.context, {
671
- resourceKind: 'inst',
672
- resourceId: event.inst,
673
- action: 'sendAction',
674
- markers: instResult.inst.markers,
675
- userId: currentConnection.userId,
676
- instances: [],
677
- });
678
- if (authorizeResult.success === false) {
679
- yield this.sendError(connectionId, -1, authorizeResult);
680
- return;
681
- }
682
- }
683
- const targetedDevices = connectedDevices.filter((d) => isEventForDevice(finalAction, d));
684
- const dEvent = finalAction.type === 'remote'
685
- ? device(connectionInfo(currentConnection), finalAction.event, finalAction.taskId)
686
- : finalAction.type === 'remote_result'
687
- ? deviceResult(connectionInfo(currentConnection), finalAction.result, finalAction.taskId)
688
- : deviceError(connectionInfo(currentConnection), finalAction.error, finalAction.taskId);
689
- yield this._messenger.sendMessage(targetedDevices.map((c) => c.serverConnectionId), {
690
- type: 'repo/receive_action',
691
- recordName: event.recordName,
692
- inst: event.inst,
693
- branch: event.branch,
694
- action: dEvent,
695
- });
696
- });
697
- }
698
- watchBranchDevices(connectionId, recordName, inst, branch) {
699
- return __awaiter(this, void 0, void 0, function* () {
700
- console.log(`[CausalRepoServer] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Watch devices for branch`);
701
- const connection = yield this._connectionStore.getConnection(connectionId);
702
- if (!connection) {
703
- console.error(`[CausalRepoServer] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Unable to watch_branch_devices. Connection not found!`);
704
- yield this.sendError(connectionId, -1, {
705
- success: false,
706
- errorCode: 'invalid_connection_state',
707
- errorMessage: `A server error occurred. (namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId})`,
708
- recordName: recordName,
709
- inst: inst,
710
- branch: branch,
711
- });
712
- yield this.messenger.disconnect(connectionId);
713
- return;
714
- }
715
- if (connection.token && recordName) {
716
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, recordName, inst, 'token');
443
+ else if (event.recordName) {
444
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'updateData');
717
445
  if (!authorized) {
718
- yield this.sendError(connectionId, -1, {
719
- success: false,
720
- errorCode: 'not_authorized',
721
- errorMessage: 'You are not authorized to access this inst.',
722
- recordName,
723
- inst,
724
- branch,
725
- reason: {
726
- type: 'invalid_token',
727
- },
446
+ if (!branch.linkedInst) {
447
+ console.error('[WebsocketController] The inst was not found even though the branch was found and exists in a record!');
448
+ await this.sendError(connectionId, -1, {
449
+ success: false,
450
+ errorCode: 'inst_not_found',
451
+ errorMessage: 'The inst was not found.',
452
+ recordName: event.recordName,
453
+ inst: event.inst,
454
+ branch: event.branch,
455
+ });
456
+ return;
457
+ }
458
+ const contextResult = await this._policies.constructAuthorizationContext({
459
+ recordKeyOrRecordName: event.recordName,
460
+ userId: connection.userId,
728
461
  });
729
- return;
462
+ if (contextResult.success === false) {
463
+ await this.sendError(connectionId, -1, {
464
+ ...contextResult,
465
+ recordName: event.recordName,
466
+ inst: event.inst,
467
+ branch: event.branch,
468
+ });
469
+ return;
470
+ }
471
+ const authorizeResult = await this._policies.authorizeUserAndInstancesForResources(contextResult.context, {
472
+ userId: connection.userId,
473
+ instances: [],
474
+ resources: [
475
+ {
476
+ resourceKind: 'inst',
477
+ resourceId: event.inst,
478
+ action: 'read',
479
+ markers: branch.linkedInst.markers,
480
+ },
481
+ {
482
+ resourceKind: 'inst',
483
+ resourceId: event.inst,
484
+ action: 'updateData',
485
+ markers: branch.linkedInst.markers,
486
+ },
487
+ ],
488
+ });
489
+ // const authorizeReadResult =
490
+ // await this._policies.authorizeRequestUsingContext(
491
+ // contextResult.context,
492
+ // {
493
+ // action: 'inst.read',
494
+ // inst: event.inst,
495
+ // recordKeyOrRecordName: event.recordName,
496
+ // resourceMarkers: branch.linkedInst.markers,
497
+ // userId: connection.userId,
498
+ // }
499
+ // );
500
+ if (authorizeResult.success === false) {
501
+ await this.sendError(connectionId, -1, {
502
+ ...authorizeResult,
503
+ recordName: event.recordName,
504
+ inst: event.inst,
505
+ branch: event.branch,
506
+ });
507
+ return;
508
+ }
509
+ // const authorizeUpdateResult =
510
+ // await this._policies.authorizeUserAndInstances(
511
+ // contextResult.context,
512
+ // {
513
+ // resourceKind: 'inst',
514
+ // resourceId: event.inst,
515
+ // action: 'updateData',
516
+ // markers: branch.linkedInst.markers,
517
+ // userId: connection.userId,
518
+ // instances: [],
519
+ // }
520
+ // );
521
+ // if (authorizeUpdateResult.success === false) {
522
+ // await this.sendError(connectionId, -1, {
523
+ // ...authorizeUpdateResult,
524
+ // recordName: event.recordName,
525
+ // inst: event.inst,
526
+ // branch: event.branch,
527
+ // });
528
+ // return;
529
+ // }
530
+ await this._connectionStore.saveAuthorizedInst(connectionId, event.recordName, event.inst, 'updateData');
730
531
  }
731
532
  }
732
- if (recordName) {
733
- const config = yield this._config.getSubscriptionConfiguration();
734
- const instResult = yield this._getInst(recordName, inst, connection.userId, config);
735
- if (instResult.success === false) {
736
- yield this.sendError(connectionId, -1, instResult);
737
- return;
738
- }
533
+ if (!features && branch.linkedInst) {
534
+ features = getSubscriptionFeatures(config, branch.linkedInst.subscriptionStatus, branch.linkedInst.subscriptionId, branch.linkedInst.subscriptionType);
739
535
  }
740
- yield this._connectionStore.saveBranchConnection(Object.assign(Object.assign({}, connection), { mode: 'watch_branch', serverConnectionId: connectionId, recordName,
741
- inst,
742
- branch, temporary: true }));
743
- const currentDevices = yield this._connectionStore.getConnectionsByBranch('branch', recordName, inst, branch);
744
- const promises = currentDevices.map((device) => this._messenger.sendMessage([connectionId], {
745
- type: 'repo/connected_to_branch',
746
- broadcast: false,
747
- connection: connectionInfo(device),
748
- branch: {
749
- type: 'repo/watch_branch',
750
- recordName: recordName,
751
- inst: inst,
752
- branch: branch,
753
- temporary: device.temporary,
754
- },
755
- }));
756
- yield Promise.all(promises);
757
- });
758
- }
759
- unwatchBranchDevices(connectionId, recordName, inst, branch) {
760
- return __awaiter(this, void 0, void 0, function* () {
761
- yield this._connectionStore.deleteBranchConnection(connectionId, 'watch_branch', recordName, inst, branch);
762
- });
763
- }
764
- deviceCount(connectionId, recordName, inst, branch) {
765
- return __awaiter(this, void 0, void 0, function* () {
766
- const count = typeof branch !== 'undefined' && branch !== null
767
- ? yield this._connectionStore.countConnectionsByBranch('branch', recordName, inst, branch)
768
- : yield this._connectionStore.countConnections();
769
- const currentConnection = yield this._connectionStore.getConnection(connectionId);
770
- if (recordName && (currentConnection === null || currentConnection === void 0 ? void 0 : currentConnection.token)) {
771
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, recordName, inst, 'token');
772
- if (!authorized) {
773
- yield this.sendError(connectionId, -1, {
774
- success: false,
775
- errorCode: 'not_authorized',
776
- errorMessage: 'You are not authorized to access this inst.',
777
- recordName,
778
- inst,
779
- branch,
780
- reason: {
781
- type: 'invalid_token',
782
- },
536
+ let maxInstSize = null;
537
+ if (features &&
538
+ typeof features.insts.maxBytesPerInst === 'number') {
539
+ maxInstSize = features.insts.maxBytesPerInst;
540
+ }
541
+ else if (!event.recordName &&
542
+ typeof ((_e = (_d = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _d === void 0 ? void 0 : _d.publicInsts) === null || _e === void 0 ? void 0 : _e.maxBytesPerInst) ===
543
+ 'number') {
544
+ maxInstSize =
545
+ config.defaultFeatures.publicInsts.maxBytesPerInst;
546
+ }
547
+ if (maxInstSize) {
548
+ const currentSize = branch.temporary
549
+ ? await this._temporaryStore.getInstSize(event.recordName, event.inst)
550
+ : await this._instStore.getInstSize(event.recordName, event.inst);
551
+ const neededSizeInBytes = currentSize + updateSize;
552
+ if (neededSizeInBytes > maxInstSize) {
553
+ await this._messenger.sendMessage([connectionId], {
554
+ type: 'repo/updates_received',
555
+ recordName: event.recordName,
556
+ inst: event.inst,
557
+ branch: event.branch,
558
+ updateId: event.updateId,
559
+ errorCode: 'max_size_reached',
560
+ maxBranchSizeInBytes: maxInstSize,
561
+ neededBranchSizeInBytes: neededSizeInBytes,
783
562
  });
784
563
  return;
785
564
  }
786
565
  }
787
- if (recordName) {
788
- const config = yield this._config.getSubscriptionConfiguration();
789
- const instResult = yield this._getInst(recordName, inst, currentConnection === null || currentConnection === void 0 ? void 0 : currentConnection.userId, config);
790
- if (instResult.success === false) {
791
- yield this.sendError(connectionId, -1, instResult);
792
- return;
566
+ if (branch.temporary) {
567
+ // Temporary branches use a temporary inst data store.
568
+ // This is because temporary branches are never persisted to disk.
569
+ await this._temporaryStore.addUpdates(event.recordName, event.inst, event.branch, event.updates, updateSize);
570
+ }
571
+ else {
572
+ const result = await this._instStore.addUpdates(event.recordName, event.inst, event.branch, event.updates, updateSize);
573
+ if (result.success === false) {
574
+ console.log(`[WebsocketController] [namespace: ${event.recordName}/${event.inst}/${event.branch}, connectionId: ${connectionId}] Failed to add updates`, result);
575
+ if (result.errorCode === 'max_size_reached') {
576
+ if (result.success === false) {
577
+ if ('updateId' in event) {
578
+ let { success, branch, ...rest } = result;
579
+ await this._messenger.sendMessage([connectionId], {
580
+ type: 'repo/updates_received',
581
+ recordName: event.recordName,
582
+ inst: event.inst,
583
+ branch: event.branch,
584
+ updateId: event.updateId,
585
+ ...rest,
586
+ });
587
+ }
588
+ return;
589
+ }
590
+ }
793
591
  }
794
- else if (!instResult.inst) {
795
- yield this.sendError(connectionId, -1, {
796
- success: false,
797
- errorCode: 'inst_not_found',
798
- errorMessage: 'The inst was not found.',
799
- });
800
- return;
592
+ else {
593
+ if (event.recordName &&
594
+ this._instStore instanceof SplitInstRecordsStore) {
595
+ this._instStore.temp.markBranchAsDirty({
596
+ recordName: event.recordName,
597
+ inst: event.inst,
598
+ branch: event.branch,
599
+ });
600
+ }
801
601
  }
802
602
  }
803
- yield this._messenger.sendMessage([connectionId], {
804
- type: 'repo/connection_count',
805
- recordName,
806
- inst,
807
- branch,
808
- count: count,
603
+ }
604
+ const hasUpdates = event.updates && event.updates.length > 0;
605
+ if (hasUpdates) {
606
+ const connectedDevices = await this._connectionStore.getConnectionsByBranch('branch', event.recordName, event.inst, event.branch);
607
+ let ret = {
608
+ type: 'repo/add_updates',
609
+ recordName: event.recordName,
610
+ inst: event.inst,
611
+ branch: event.branch,
612
+ updates: event.updates,
613
+ };
614
+ await this._messenger.sendMessage(connectedDevices.map((c) => c.serverConnectionId), ret, connectionId);
615
+ }
616
+ if ('updateId' in event) {
617
+ await this._messenger.sendMessage([connectionId], {
618
+ type: 'repo/updates_received',
619
+ recordName: event.recordName,
620
+ inst: event.inst,
621
+ branch: event.branch,
622
+ updateId: event.updateId,
809
623
  });
810
- });
624
+ }
811
625
  }
812
- /**
813
- * Gets the data from the given branch in the given inst.
814
- * @param userId The ID of the user that is currently logged in.
815
- * @param recordName The name of the record that the inst is in. Null if accessing a public inst.
816
- * @param inst The name of the inst.
817
- * @param branch The name of the branch in the inst.
818
- * @param auxVersion The AUX version to return.
819
- */
820
- getBranchData(userId, recordName, inst, branch, auxVersion = 1) {
821
- var _a;
822
- return __awaiter(this, void 0, void 0, function* () {
823
- console.log(`[CausalRepoServer] [namespace: ${recordName}/${inst}/${branch}] Get Data`);
824
- if (recordName) {
825
- const config = yield this._config.getSubscriptionConfiguration();
826
- const instResult = yield this._getInst(recordName, inst, userId, config);
827
- if (instResult.success === false) {
828
- return instResult;
829
- }
830
- else if (!instResult.inst) {
626
+ async addUserUpdates(request) {
627
+ var _a, _b, _c, _d, _e;
628
+ console.log(`[CausalRepoServer] [namespace: ${request.recordName}/${request.inst}/${request.branch}, userId: ${request.userId}] Add Updates`);
629
+ if (request.updates) {
630
+ let branch = (_a = (await this._instStore.getBranchByName(request.recordName, request.inst, request.branch))) !== null && _a !== void 0 ? _a : (await this._temporaryStore.getBranchByName(request.recordName, request.inst, request.branch));
631
+ const updateSize = sumBy(request.updates, (u) => Buffer.byteLength(u, 'utf8'));
632
+ const config = await this._config.getSubscriptionConfiguration();
633
+ let features = null;
634
+ if (!request.recordName) {
635
+ if (((_c = (_b = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _b === void 0 ? void 0 : _b.publicInsts) === null || _c === void 0 ? void 0 : _c.allowed) === false) {
831
636
  return {
832
637
  success: false,
833
- errorCode: 'inst_not_found',
834
- errorMessage: 'The inst was not found.',
638
+ errorCode: 'not_authorized',
639
+ errorMessage: 'Temporary insts are not allowed.',
835
640
  };
836
641
  }
837
642
  }
838
- const updates = (_a = (yield this._instStore.getCurrentUpdates(recordName, inst, branch))) !== null && _a !== void 0 ? _a : {
839
- updates: [],
840
- timestamps: [],
841
- instSizeInBytes: 0,
842
- };
843
- if (auxVersion === 1) {
844
- const partition = new YjsPartitionImpl({ type: 'yjs' });
845
- for (let updateBase64 of updates.updates) {
846
- const update = toByteArray(updateBase64);
847
- applyUpdate(partition.doc, update);
643
+ if (!branch) {
644
+ console.log(`[CausalRepoServer] [namespace: ${request.recordName}/${request.inst}/${request.branch}, userId: ${request.userId}] Branch not found!`);
645
+ const instResult = await this._getOrCreateInst(request.recordName, request.inst, request.userId, config);
646
+ if (instResult.success === false) {
647
+ return instResult;
848
648
  }
849
- return {
850
- success: true,
851
- data: {
852
- version: 1,
853
- state: partition.state,
854
- },
855
- };
856
- }
857
- else {
858
- let stored = [];
859
- for (let i = 0; i < updates.updates.length; i++) {
860
- stored.push({
861
- id: i,
862
- update: updates.updates[i],
863
- timestamp: updates.timestamps[i],
649
+ else if (request.recordName) {
650
+ const authorizeResult = await this._policies.authorizeUserAndInstances(instResult.context, {
651
+ resourceKind: 'inst',
652
+ resourceId: request.inst,
653
+ action: 'updateData',
654
+ userId: request.userId,
655
+ markers: instResult.inst.markers,
656
+ instances: [],
864
657
  });
658
+ if (authorizeResult.success === false) {
659
+ return authorizeResult;
660
+ }
865
661
  }
866
- return {
867
- success: true,
868
- data: {
869
- version: 2,
870
- updates: stored,
871
- },
872
- };
873
- }
874
- });
875
- }
876
- listInsts(recordName, userId, startingInst) {
877
- return __awaiter(this, void 0, void 0, function* () {
878
- try {
879
- if (!recordName) {
880
- return {
881
- success: true,
882
- insts: [],
883
- totalCount: 0,
884
- };
662
+ features = instResult.features;
663
+ const branchResult = await this._instStore.saveBranch({
664
+ branch: request.branch,
665
+ inst: request.inst,
666
+ recordName: request.recordName,
667
+ temporary: false,
668
+ });
669
+ if (branchResult.success === false) {
670
+ return branchResult;
885
671
  }
886
- const contextResult = yield this._policies.constructAuthorizationContext({
887
- recordKeyOrRecordName: recordName,
888
- userId,
672
+ branch = await this._instStore.getBranchByName(request.recordName, request.inst, request.branch);
673
+ }
674
+ else if (request.recordName) {
675
+ const contextResult = await this._policies.constructAuthorizationContext({
676
+ recordKeyOrRecordName: request.recordName,
677
+ userId: request.userId,
889
678
  });
890
679
  if (contextResult.success === false) {
891
680
  return contextResult;
892
681
  }
893
- const context = contextResult.context;
894
- const authorizeResult = yield this._policies.authorizeUserAndInstances(context, {
895
- resourceKind: 'inst',
896
- action: 'list',
897
- userId,
898
- markers: [PRIVATE_MARKER],
682
+ const authorizeResult = await this._policies.authorizeUserAndInstancesForResources(contextResult.context, {
683
+ userId: request.userId,
899
684
  instances: [],
685
+ resources: [
686
+ {
687
+ resourceKind: 'inst',
688
+ resourceId: request.inst,
689
+ action: 'read',
690
+ markers: branch.linkedInst.markers,
691
+ },
692
+ {
693
+ resourceKind: 'inst',
694
+ resourceId: request.inst,
695
+ action: 'updateData',
696
+ markers: branch.linkedInst.markers,
697
+ },
698
+ ],
900
699
  });
901
700
  if (authorizeResult.success === false) {
902
701
  return authorizeResult;
903
702
  }
904
- const metricsResult = yield this._metrics.getSubscriptionInstMetricsByRecordName(recordName);
905
- const config = yield this._config.getSubscriptionConfiguration();
906
- const features = getSubscriptionFeatures(config, metricsResult.subscriptionStatus, metricsResult.subscriptionId, metricsResult.subscriptionType);
907
- if (!features.insts.allowed) {
703
+ }
704
+ if (!features && branch.linkedInst) {
705
+ features = getSubscriptionFeatures(config, branch.linkedInst.subscriptionStatus, branch.linkedInst.subscriptionId, branch.linkedInst.subscriptionType);
706
+ }
707
+ let maxInstSize = null;
708
+ if (features &&
709
+ typeof features.insts.maxBytesPerInst === 'number') {
710
+ maxInstSize = features.insts.maxBytesPerInst;
711
+ }
712
+ else if (!request.recordName &&
713
+ typeof ((_e = (_d = config === null || config === void 0 ? void 0 : config.defaultFeatures) === null || _d === void 0 ? void 0 : _d.publicInsts) === null || _e === void 0 ? void 0 : _e.maxBytesPerInst) ===
714
+ 'number') {
715
+ maxInstSize =
716
+ config.defaultFeatures.publicInsts.maxBytesPerInst;
717
+ }
718
+ if (maxInstSize) {
719
+ const currentSize = branch.temporary
720
+ ? await this._temporaryStore.getInstSize(request.recordName, request.inst)
721
+ : await this._instStore.getInstSize(request.recordName, request.inst);
722
+ const neededSizeInBytes = currentSize + updateSize;
723
+ if (neededSizeInBytes > maxInstSize) {
908
724
  return {
909
725
  success: false,
910
- errorCode: 'not_authorized',
911
- errorMessage: 'Insts are not allowed for this subscription.',
726
+ errorCode: 'subscription_limit_reached',
727
+ errorMessage: 'The inst has reached its maximum size.',
912
728
  };
913
729
  }
914
- const instsResult = yield this._instStore.listInstsByRecord(recordName, startingInst);
915
- if (!instsResult.success) {
916
- return instsResult;
730
+ }
731
+ if (branch.temporary) {
732
+ // Temporary branches use a temporary inst data store.
733
+ // This is because temporary branches are never persisted to disk.
734
+ await this._temporaryStore.addUpdates(request.recordName, request.inst, request.branch, request.updates, updateSize);
735
+ }
736
+ else {
737
+ const result = await this._instStore.addUpdates(request.recordName, request.inst, request.branch, request.updates, updateSize);
738
+ if (result.success === false) {
739
+ console.log(`[CausalRepoServer] [namespace: ${request.recordName}/${request.inst}/${request.branch}, userId: ${request.userId}] Failed to add updates`, result);
740
+ if (result.errorCode === 'max_size_reached') {
741
+ if (result.success === false) {
742
+ return {
743
+ success: false,
744
+ errorCode: 'subscription_limit_reached',
745
+ errorMessage: 'The inst has reached its maximum size.',
746
+ };
747
+ }
748
+ }
917
749
  }
918
- return {
919
- success: true,
920
- insts: instsResult.insts,
921
- totalCount: instsResult.totalCount,
750
+ else {
751
+ if (request.recordName &&
752
+ this._instStore instanceof SplitInstRecordsStore) {
753
+ this._instStore.temp.markBranchAsDirty({
754
+ recordName: request.recordName,
755
+ inst: request.inst,
756
+ branch: request.branch,
757
+ });
758
+ }
759
+ }
760
+ }
761
+ }
762
+ const hasUpdates = request.updates && request.updates.length > 0;
763
+ if (hasUpdates) {
764
+ const connectedDevices = await this._connectionStore.getConnectionsByBranch('branch', request.recordName, request.inst, request.branch);
765
+ let ret = {
766
+ type: 'repo/add_updates',
767
+ recordName: request.recordName,
768
+ inst: request.inst,
769
+ branch: request.branch,
770
+ updates: request.updates,
771
+ };
772
+ await this._messenger.sendMessage(connectedDevices.map((c) => c.serverConnectionId), ret);
773
+ }
774
+ return {
775
+ success: true,
776
+ };
777
+ }
778
+ async sendAction(connectionId, event) {
779
+ if (!event) {
780
+ console.warn('[CasualRepoServer] Trying to send event with a null event!');
781
+ return;
782
+ }
783
+ // const namespace = branchNamespace(event.recordName, event.inst, event.branch);
784
+ const connectedDevices = await this._connectionStore.getConnectionsByBranch('branch', event.recordName, event.inst, event.branch);
785
+ if (event.action.type === 'remote') {
786
+ const action = event.action.event;
787
+ }
788
+ let finalAction;
789
+ if (event.action.sessionId ||
790
+ event.action.connectionId ||
791
+ event.action.userId ||
792
+ (typeof event.action.broadcast !== 'undefined' &&
793
+ event.action.broadcast !== null)) {
794
+ finalAction = event.action;
795
+ }
796
+ else {
797
+ // TODO: Replace with system that selects target devices with better uniformity
798
+ // than Math.random().
799
+ const randomDeviceIndex = Math.min(connectedDevices.length - 1, Math.max(Math.floor(Math.random() * connectedDevices.length), 0));
800
+ const randomDevice = connectedDevices[randomDeviceIndex];
801
+ if (randomDevice) {
802
+ finalAction = {
803
+ ...event.action,
804
+ connectionId: randomDevice.clientConnectionId,
922
805
  };
923
806
  }
924
- catch (err) {
925
- console.error(`[WebsocketController] A server error occurred while listing insts:`, err);
926
- return {
807
+ }
808
+ if (!finalAction) {
809
+ return;
810
+ }
811
+ const currentConnection = await this._connectionStore.getConnection(connectionId);
812
+ if (currentConnection.token && event.recordName) {
813
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, event.recordName, event.inst, 'token');
814
+ if (!authorized) {
815
+ await this.sendError(connectionId, -1, {
927
816
  success: false,
928
- errorCode: 'server_error',
929
- errorMessage: 'A server error occurred.',
930
- };
817
+ errorCode: 'not_authorized',
818
+ errorMessage: 'You are not authorized to access this inst.',
819
+ recordName: event.recordName,
820
+ inst: event.inst,
821
+ branch: event.branch,
822
+ reason: {
823
+ type: 'invalid_token',
824
+ },
825
+ });
826
+ return;
931
827
  }
932
- });
933
- }
934
- getUpdates(connectionId, recordName, inst, branch) {
935
- var _a;
936
- return __awaiter(this, void 0, void 0, function* () {
937
- if (!branch) {
938
- console.warn('[CasualRepoServer] Trying to get branch with a null branch!');
828
+ }
829
+ if (event.recordName) {
830
+ const config = await this._config.getSubscriptionConfiguration();
831
+ const instResult = await this._getInst(event.recordName, event.inst, currentConnection.userId, config);
832
+ if (instResult.success === false) {
833
+ await this.sendError(connectionId, -1, instResult);
939
834
  return;
940
835
  }
941
- const connection = yield this._connectionStore.getConnection(connectionId);
942
- if (!connection) {
943
- console.error(`[CausalRepoServer] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Unable to get_updates. Connection not found!`);
944
- yield this.sendError(connectionId, -1, {
836
+ else if (!instResult.inst) {
837
+ await this.sendError(connectionId, -1, {
945
838
  success: false,
946
- errorCode: 'invalid_connection_state',
947
- errorMessage: `A server error occurred. (namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId})`,
948
- recordName: recordName,
949
- inst: inst,
950
- branch: branch,
839
+ errorCode: 'inst_not_found',
840
+ errorMessage: 'The inst was not found.',
951
841
  });
952
- yield this.messenger.disconnect(connectionId);
953
842
  return;
954
843
  }
955
- if (connection.token && recordName) {
956
- const authorized = yield this._connectionStore.isAuthorizedInst(connectionId, recordName, inst, 'token');
957
- if (!authorized) {
958
- yield this.sendError(connectionId, -1, {
959
- success: false,
960
- errorCode: 'not_authorized',
961
- errorMessage: 'You are not authorized to access this inst.',
962
- recordName,
963
- inst,
964
- branch,
965
- reason: {
966
- type: 'invalid_token',
967
- },
968
- });
969
- return;
970
- }
844
+ const authorizeResult = await this._policies.authorizeUserAndInstances(instResult.context, {
845
+ resourceKind: 'inst',
846
+ resourceId: event.inst,
847
+ action: 'sendAction',
848
+ markers: instResult.inst.markers,
849
+ userId: currentConnection.userId,
850
+ instances: [],
851
+ });
852
+ if (authorizeResult.success === false) {
853
+ await this.sendError(connectionId, -1, authorizeResult);
854
+ return;
855
+ }
856
+ }
857
+ const targetedDevices = connectedDevices.filter((d) => isEventForDevice(finalAction, d));
858
+ const dEvent = finalAction.type === 'remote'
859
+ ? device(connectionInfo(currentConnection), finalAction.event, finalAction.taskId)
860
+ : finalAction.type === 'remote_result'
861
+ ? deviceResult(connectionInfo(currentConnection), finalAction.result, finalAction.taskId)
862
+ : deviceError(connectionInfo(currentConnection), finalAction.error, finalAction.taskId);
863
+ await this._messenger.sendMessage(targetedDevices.map((c) => c.serverConnectionId), {
864
+ type: 'repo/receive_action',
865
+ recordName: event.recordName,
866
+ inst: event.inst,
867
+ branch: event.branch,
868
+ action: dEvent,
869
+ });
870
+ }
871
+ async watchBranchDevices(connectionId, recordName, inst, branch) {
872
+ console.log(`[WebsocketController] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Watch devices for branch`);
873
+ const connection = await this._connectionStore.getConnection(connectionId);
874
+ if (!connection) {
875
+ console.error(`[WebsocketController] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Unable to watch_branch_devices. Connection not found!`);
876
+ await this.sendError(connectionId, -1, {
877
+ success: false,
878
+ errorCode: 'invalid_connection_state',
879
+ errorMessage: `A server error occurred. (namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId})`,
880
+ recordName: recordName,
881
+ inst: inst,
882
+ branch: branch,
883
+ });
884
+ await this.messenger.disconnect(connectionId);
885
+ return;
886
+ }
887
+ if (connection.token && recordName) {
888
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, recordName, inst, 'token');
889
+ if (!authorized) {
890
+ await this.sendError(connectionId, -1, {
891
+ success: false,
892
+ errorCode: 'not_authorized',
893
+ errorMessage: 'You are not authorized to access this inst.',
894
+ recordName,
895
+ inst,
896
+ branch,
897
+ reason: {
898
+ type: 'invalid_token',
899
+ },
900
+ });
901
+ return;
971
902
  }
972
- // const namespace = branchNamespace(recordName, inst, branch);
973
- console.log(`[CausalRepoServer] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Get Updates`);
974
- const config = yield this._config.getSubscriptionConfiguration();
975
- const instResult = yield this._getInst(recordName, inst, connection.userId, config);
903
+ }
904
+ if (recordName) {
905
+ const config = await this._config.getSubscriptionConfiguration();
906
+ const instResult = await this._getInst(recordName, inst, connection.userId, config);
976
907
  if (instResult.success === false) {
977
- yield this.sendError(connectionId, -1, Object.assign(Object.assign({}, instResult), { recordName,
908
+ await this.sendError(connectionId, -1, instResult);
909
+ return;
910
+ }
911
+ }
912
+ await this._connectionStore.saveBranchConnection({
913
+ ...connection,
914
+ mode: 'watch_branch',
915
+ serverConnectionId: connectionId,
916
+ recordName,
917
+ inst,
918
+ branch,
919
+ temporary: true,
920
+ });
921
+ const currentDevices = await this._connectionStore.getConnectionsByBranch('branch', recordName, inst, branch);
922
+ const promises = currentDevices.map((device) => this._messenger.sendMessage([connectionId], {
923
+ type: 'repo/connected_to_branch',
924
+ broadcast: false,
925
+ connection: connectionInfo(device),
926
+ branch: {
927
+ type: 'repo/watch_branch',
928
+ recordName: recordName,
929
+ inst: inst,
930
+ branch: branch,
931
+ temporary: device.temporary,
932
+ },
933
+ }));
934
+ await Promise.all(promises);
935
+ }
936
+ async unwatchBranchDevices(connectionId, recordName, inst, branch) {
937
+ await this._connectionStore.deleteBranchConnection(connectionId, 'watch_branch', recordName, inst, branch);
938
+ }
939
+ async deviceCount(connectionId, recordName, inst, branch) {
940
+ const count = typeof branch !== 'undefined' && branch !== null
941
+ ? await this._connectionStore.countConnectionsByBranch('branch', recordName, inst, branch)
942
+ : await this._connectionStore.countConnections();
943
+ const currentConnection = await this._connectionStore.getConnection(connectionId);
944
+ if (recordName && (currentConnection === null || currentConnection === void 0 ? void 0 : currentConnection.token)) {
945
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, recordName, inst, 'token');
946
+ if (!authorized) {
947
+ await this.sendError(connectionId, -1, {
948
+ success: false,
949
+ errorCode: 'not_authorized',
950
+ errorMessage: 'You are not authorized to access this inst.',
951
+ recordName,
978
952
  inst,
979
- branch }));
953
+ branch,
954
+ reason: {
955
+ type: 'invalid_token',
956
+ },
957
+ });
980
958
  return;
981
959
  }
982
- else if (recordName && !instResult.inst) {
983
- yield this.sendError(connectionId, -1, {
960
+ }
961
+ if (recordName) {
962
+ const config = await this._config.getSubscriptionConfiguration();
963
+ const instResult = await this._getInst(recordName, inst, currentConnection === null || currentConnection === void 0 ? void 0 : currentConnection.userId, config);
964
+ if (instResult.success === false) {
965
+ await this.sendError(connectionId, -1, instResult);
966
+ return;
967
+ }
968
+ else if (!instResult.inst) {
969
+ await this.sendError(connectionId, -1, {
984
970
  success: false,
985
971
  errorCode: 'inst_not_found',
986
972
  errorMessage: 'The inst was not found.',
973
+ });
974
+ return;
975
+ }
976
+ }
977
+ await this._messenger.sendMessage([connectionId], {
978
+ type: 'repo/connection_count',
979
+ recordName,
980
+ inst,
981
+ branch,
982
+ count: count,
983
+ });
984
+ }
985
+ /**
986
+ * Gets the data from the given branch in the given inst.
987
+ * @param userId The ID of the user that is currently logged in.
988
+ * @param recordName The name of the record that the inst is in. Null if accessing a public inst.
989
+ * @param inst The name of the inst.
990
+ * @param branch The name of the branch in the inst.
991
+ * @param auxVersion The AUX version to return.
992
+ */
993
+ async getBranchData(userId, recordName, inst, branch, auxVersion = 1) {
994
+ var _a;
995
+ console.log(`[WebsocketController] [namespace: ${recordName}/${inst}/${branch}] Get Data`);
996
+ if (recordName) {
997
+ const config = await this._config.getSubscriptionConfiguration();
998
+ const instResult = await this._getInst(recordName, inst, userId, config);
999
+ if (instResult.success === false) {
1000
+ return instResult;
1001
+ }
1002
+ else if (!instResult.inst) {
1003
+ return {
1004
+ success: false,
1005
+ errorCode: 'inst_not_found',
1006
+ errorMessage: 'The inst was not found.',
1007
+ };
1008
+ }
1009
+ }
1010
+ const updates = (_a = (await this._instStore.getCurrentUpdates(recordName, inst, branch))) !== null && _a !== void 0 ? _a : {
1011
+ updates: [],
1012
+ timestamps: [],
1013
+ instSizeInBytes: 0,
1014
+ };
1015
+ if (auxVersion === 1) {
1016
+ const partition = new YjsPartitionImpl({ type: 'yjs' });
1017
+ for (let updateBase64 of updates.updates) {
1018
+ const update = toByteArray(updateBase64);
1019
+ applyUpdate(partition.doc, update);
1020
+ }
1021
+ return {
1022
+ success: true,
1023
+ data: {
1024
+ version: 1,
1025
+ state: partition.state,
1026
+ },
1027
+ };
1028
+ }
1029
+ else {
1030
+ let stored = [];
1031
+ for (let i = 0; i < updates.updates.length; i++) {
1032
+ stored.push({
1033
+ id: i,
1034
+ update: updates.updates[i],
1035
+ timestamp: updates.timestamps[i],
1036
+ });
1037
+ }
1038
+ return {
1039
+ success: true,
1040
+ data: {
1041
+ version: 2,
1042
+ updates: stored,
1043
+ },
1044
+ };
1045
+ }
1046
+ }
1047
+ async listInsts(recordName, userId, startingInst) {
1048
+ try {
1049
+ if (!recordName) {
1050
+ return {
1051
+ success: true,
1052
+ insts: [],
1053
+ totalCount: 0,
1054
+ };
1055
+ }
1056
+ const contextResult = await this._policies.constructAuthorizationContext({
1057
+ recordKeyOrRecordName: recordName,
1058
+ userId,
1059
+ });
1060
+ if (contextResult.success === false) {
1061
+ return contextResult;
1062
+ }
1063
+ const context = contextResult.context;
1064
+ const authorizeResult = await this._policies.authorizeUserAndInstances(context, {
1065
+ resourceKind: 'inst',
1066
+ action: 'list',
1067
+ userId,
1068
+ markers: [PRIVATE_MARKER],
1069
+ instances: [],
1070
+ });
1071
+ if (authorizeResult.success === false) {
1072
+ return authorizeResult;
1073
+ }
1074
+ const metricsResult = await this._metrics.getSubscriptionInstMetricsByRecordName(recordName);
1075
+ const config = await this._config.getSubscriptionConfiguration();
1076
+ const features = getSubscriptionFeatures(config, metricsResult.subscriptionStatus, metricsResult.subscriptionId, metricsResult.subscriptionType);
1077
+ if (!features.insts.allowed) {
1078
+ return {
1079
+ success: false,
1080
+ errorCode: 'not_authorized',
1081
+ errorMessage: 'Insts are not allowed for this subscription.',
1082
+ };
1083
+ }
1084
+ const instsResult = await this._instStore.listInstsByRecord(recordName, startingInst);
1085
+ if (!instsResult.success) {
1086
+ return instsResult;
1087
+ }
1088
+ return {
1089
+ success: true,
1090
+ insts: instsResult.insts,
1091
+ totalCount: instsResult.totalCount,
1092
+ };
1093
+ }
1094
+ catch (err) {
1095
+ console.error(`[WebsocketController] A server error occurred while listing insts:`, err);
1096
+ return {
1097
+ success: false,
1098
+ errorCode: 'server_error',
1099
+ errorMessage: 'A server error occurred.',
1100
+ };
1101
+ }
1102
+ }
1103
+ async getUpdates(connectionId, recordName, inst, branch) {
1104
+ var _a;
1105
+ if (!branch) {
1106
+ console.warn('[CasualRepoServer] Trying to get branch with a null branch!');
1107
+ return;
1108
+ }
1109
+ const connection = await this._connectionStore.getConnection(connectionId);
1110
+ if (!connection) {
1111
+ console.error(`[WebsocketController] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Unable to get_updates. Connection not found!`);
1112
+ await this.sendError(connectionId, -1, {
1113
+ success: false,
1114
+ errorCode: 'invalid_connection_state',
1115
+ errorMessage: `A server error occurred. (namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId})`,
1116
+ recordName: recordName,
1117
+ inst: inst,
1118
+ branch: branch,
1119
+ });
1120
+ await this.messenger.disconnect(connectionId);
1121
+ return;
1122
+ }
1123
+ if (connection.token && recordName) {
1124
+ const authorized = await this._connectionStore.isAuthorizedInst(connectionId, recordName, inst, 'token');
1125
+ if (!authorized) {
1126
+ await this.sendError(connectionId, -1, {
1127
+ success: false,
1128
+ errorCode: 'not_authorized',
1129
+ errorMessage: 'You are not authorized to access this inst.',
987
1130
  recordName,
988
1131
  inst,
989
1132
  branch,
1133
+ reason: {
1134
+ type: 'invalid_token',
1135
+ },
990
1136
  });
991
1137
  return;
992
1138
  }
993
- const updates = (_a = (yield this._instStore.getAllUpdates(recordName, inst, branch))) !== null && _a !== void 0 ? _a : {
994
- updates: [],
995
- timestamps: [],
996
- };
997
- yield this._messenger.sendMessage([connection.serverConnectionId], {
998
- type: 'repo/add_updates',
1139
+ }
1140
+ // const namespace = branchNamespace(recordName, inst, branch);
1141
+ console.log(`[WebsocketController] [namespace: ${recordName}/${inst}/${branch}, connectionId: ${connectionId}] Get Updates`);
1142
+ const config = await this._config.getSubscriptionConfiguration();
1143
+ const instResult = await this._getInst(recordName, inst, connection.userId, config);
1144
+ if (instResult.success === false) {
1145
+ await this.sendError(connectionId, -1, {
1146
+ ...instResult,
999
1147
  recordName,
1000
1148
  inst,
1001
- branch: branch,
1002
- updates: updates.updates,
1003
- timestamps: updates.timestamps,
1149
+ branch,
1150
+ });
1151
+ return;
1152
+ }
1153
+ else if (recordName && !instResult.inst) {
1154
+ await this.sendError(connectionId, -1, {
1155
+ success: false,
1156
+ errorCode: 'inst_not_found',
1157
+ errorMessage: 'The inst was not found.',
1158
+ recordName,
1159
+ inst,
1160
+ branch,
1004
1161
  });
1162
+ return;
1163
+ }
1164
+ const updates = (_a = (await this._instStore.getAllUpdates(recordName, inst, branch))) !== null && _a !== void 0 ? _a : {
1165
+ updates: [],
1166
+ timestamps: [],
1167
+ };
1168
+ await this._messenger.sendMessage([connection.serverConnectionId], {
1169
+ type: 'repo/add_updates',
1170
+ recordName,
1171
+ inst,
1172
+ branch: branch,
1173
+ updates: updates.updates,
1174
+ timestamps: updates.timestamps,
1005
1175
  });
1006
1176
  }
1007
- eraseInst(recordKeyOrName, inst, userId) {
1008
- return __awaiter(this, void 0, void 0, function* () {
1009
- try {
1010
- const context = yield this._policies.constructAuthorizationContext({
1011
- recordKeyOrRecordName: recordKeyOrName,
1012
- userId,
1013
- });
1014
- if (context.success === false) {
1015
- return context;
1016
- }
1017
- const recordName = context.context.recordName;
1018
- const storedInst = yield this._instStore.getInstByName(recordName, inst);
1019
- if (!storedInst) {
1020
- return {
1021
- success: true,
1022
- };
1023
- }
1024
- const authResult = yield this._policies.authorizeUserAndInstances(context.context, {
1025
- resourceKind: 'inst',
1026
- resourceId: inst,
1027
- action: 'delete',
1028
- markers: storedInst.markers,
1029
- userId,
1030
- instances: [],
1031
- });
1032
- if (authResult.success === false) {
1033
- return authResult;
1034
- }
1035
- yield this._instStore.deleteInst(recordName, inst);
1177
+ async eraseInst(recordKeyOrName, inst, userId) {
1178
+ try {
1179
+ const context = await this._policies.constructAuthorizationContext({
1180
+ recordKeyOrRecordName: recordKeyOrName,
1181
+ userId,
1182
+ });
1183
+ if (context.success === false) {
1184
+ return context;
1185
+ }
1186
+ const recordName = context.context.recordName;
1187
+ const storedInst = await this._instStore.getInstByName(recordName, inst);
1188
+ if (!storedInst) {
1036
1189
  return {
1037
1190
  success: true,
1038
1191
  };
1039
1192
  }
1040
- catch (err) {
1041
- console.error('[WebsocketController] [eraseInst] Error while erasing inst.', err);
1042
- return {
1043
- success: false,
1044
- errorCode: 'server_error',
1045
- errorMessage: 'A server error occurred.',
1046
- };
1193
+ const authResult = await this._policies.authorizeUserAndInstances(context.context, {
1194
+ resourceKind: 'inst',
1195
+ resourceId: inst,
1196
+ action: 'delete',
1197
+ markers: storedInst.markers,
1198
+ userId,
1199
+ instances: [],
1200
+ });
1201
+ if (authResult.success === false) {
1202
+ return authResult;
1047
1203
  }
1048
- });
1204
+ await this._instStore.deleteInst(recordName, inst);
1205
+ return {
1206
+ success: true,
1207
+ };
1208
+ }
1209
+ catch (err) {
1210
+ console.error('[WebsocketController] [eraseInst] Error while erasing inst.', err);
1211
+ return {
1212
+ success: false,
1213
+ errorCode: 'server_error',
1214
+ errorMessage: 'A server error occurred.',
1215
+ };
1216
+ }
1049
1217
  }
1050
1218
  /**
1051
1219
  * Processes a webhook and returns the status code that should be returned.
@@ -1055,182 +1223,369 @@ export class WebsocketController {
1055
1223
  * @param headers The headers that were included in the request.
1056
1224
  * @param data The data included in the request.
1057
1225
  */
1058
- webhook(recordName, inst, branch, method, url, headers, data) {
1059
- return __awaiter(this, void 0, void 0, function* () {
1060
- // TODO: Change webhooks to be records.
1061
- if (recordName) {
1062
- return;
1063
- }
1064
- // const namespace = branchNamespace(recordName, inst, branch);
1065
- const b = yield this._instStore.getBranchByName(recordName, inst, branch);
1066
- if (!b) {
1067
- return 404;
1068
- }
1069
- const connectedDevices = yield this._connectionStore.getConnectionsByBranch('branch', recordName, inst, branch);
1070
- if (connectedDevices.some((d) => !d)) {
1071
- return 500;
1072
- }
1073
- if (connectedDevices.length <= 0) {
1074
- return 404;
1075
- }
1076
- // TODO: Replace with system that selects target devices with better uniformity
1077
- // than Math.random().
1078
- const randomDeviceIndex = Math.min(connectedDevices.length - 1, Math.max(Math.floor(Math.random() * connectedDevices.length), 0));
1079
- const randomDevice = connectedDevices[randomDeviceIndex];
1080
- if (!randomDevice) {
1081
- return 500;
1082
- }
1083
- const a = action(ON_WEBHOOK_ACTION_NAME, null, null, {
1084
- method,
1085
- url,
1086
- headers,
1087
- data,
1088
- });
1089
- yield this._messenger.sendMessage([randomDevice.serverConnectionId], {
1090
- type: 'repo/receive_action',
1091
- recordName,
1092
- inst,
1093
- branch,
1094
- action: a,
1095
- });
1096
- return 200;
1226
+ async webhook(recordName, inst, branch, method, url, headers, data) {
1227
+ // TODO: Change webhooks to be records.
1228
+ if (recordName) {
1229
+ return;
1230
+ }
1231
+ // const namespace = branchNamespace(recordName, inst, branch);
1232
+ const b = await this._instStore.getBranchByName(recordName, inst, branch);
1233
+ if (!b) {
1234
+ return 404;
1235
+ }
1236
+ const connectedDevices = await this._connectionStore.getConnectionsByBranch('branch', recordName, inst, branch);
1237
+ if (connectedDevices.some((d) => !d)) {
1238
+ return 500;
1239
+ }
1240
+ if (connectedDevices.length <= 0) {
1241
+ return 404;
1242
+ }
1243
+ // TODO: Replace with system that selects target devices with better uniformity
1244
+ // than Math.random().
1245
+ const randomDeviceIndex = Math.min(connectedDevices.length - 1, Math.max(Math.floor(Math.random() * connectedDevices.length), 0));
1246
+ const randomDevice = connectedDevices[randomDeviceIndex];
1247
+ if (!randomDevice) {
1248
+ return 500;
1249
+ }
1250
+ const a = action(ON_WEBHOOK_ACTION_NAME, null, null, {
1251
+ method,
1252
+ url,
1253
+ headers,
1254
+ data,
1255
+ });
1256
+ await this._messenger.sendMessage([randomDevice.serverConnectionId], {
1257
+ type: 'repo/receive_action',
1258
+ recordName,
1259
+ inst,
1260
+ branch,
1261
+ action: a,
1097
1262
  });
1263
+ return 200;
1098
1264
  }
1099
1265
  /**
1100
1266
  * Requests that the user be given permission to access the given resource.
1101
1267
  * @param connectionId The ID of the connection that is making the request.
1102
1268
  * @param event The request missing permission event.
1103
1269
  */
1104
- requestMissingPermission(connectionId, event) {
1105
- return __awaiter(this, void 0, void 0, function* () {
1106
- const connection = yield this._connectionStore.getConnection(connectionId);
1107
- if (!connection) {
1108
- console.error(`[CausalRepoServer] [connectionId: ${connectionId}] Unable to request permission. Connection not found!`);
1109
- yield this.sendError(connectionId, -1, {
1110
- success: false,
1111
- errorCode: 'invalid_connection_state',
1112
- errorMessage: `A server error occurred. (connectionId: ${connectionId})`,
1113
- });
1114
- yield this.messenger.disconnect(connectionId);
1115
- return;
1116
- }
1117
- if (event.reason.type !== 'missing_permission') {
1118
- yield this._messenger.sendMessage([connectionId], {
1119
- type: 'permission/request/missing/response',
1120
- success: false,
1121
- recordName: event.reason.recordName,
1122
- resourceKind: event.reason.resourceKind,
1123
- resourceId: event.reason.resourceId,
1124
- subjectType: event.reason.subjectType,
1125
- subjectId: event.reason.subjectId,
1126
- errorCode: 'unacceptable_request',
1127
- errorMessage: 'It is only possible to request missing permissions.',
1128
- });
1129
- return;
1130
- }
1131
- else if (event.reason.resourceKind !== 'inst') {
1132
- yield this._messenger.sendMessage([connectionId], {
1133
- type: 'permission/request/missing/response',
1134
- success: false,
1135
- recordName: event.reason.recordName,
1136
- resourceKind: event.reason.resourceKind,
1137
- resourceId: event.reason.resourceId,
1138
- subjectType: event.reason.subjectType,
1139
- subjectId: event.reason.subjectId,
1140
- errorCode: 'unacceptable_request',
1141
- errorMessage: 'Permissions can only be requested to access insts.',
1142
- });
1143
- return;
1144
- }
1145
- else if (event.reason.subjectType !== 'user' ||
1146
- event.reason.subjectId !== connection.userId) {
1147
- yield this._messenger.sendMessage([connectionId], {
1148
- type: 'permission/request/missing/response',
1149
- success: false,
1150
- recordName: event.reason.recordName,
1151
- resourceKind: event.reason.resourceKind,
1152
- resourceId: event.reason.resourceId,
1153
- subjectType: event.reason.subjectType,
1154
- subjectId: event.reason.subjectId,
1155
- errorCode: 'unacceptable_request',
1156
- errorMessage: 'Permissions can only be requested for the current user.',
1157
- });
1158
- return;
1159
- }
1160
- const connections = yield this._connectionStore.getConnectionsByBranch('branch', event.reason.recordName, event.reason.resourceId, DEFAULT_BRANCH_NAME);
1161
- if (connections.length > 0) {
1162
- const userInfoResult = yield this._auth.getPublicUserInfo(connection.userId);
1163
- let userInfo = null;
1164
- if (userInfoResult.success === false) {
1165
- console.error('[WebsocketController] [requestMissingPermission] Error while getting user info.', userInfoResult);
1166
- }
1167
- else {
1168
- userInfo = userInfoResult.user;
1169
- }
1170
- const inst = `${event.reason.resourceKind}/${event.reason.resourceId}`;
1171
- const branch = `${event.reason.subjectType}/${event.reason.subjectId}`;
1172
- yield this._connectionStore.saveBranchConnection(Object.assign(Object.assign({}, connection), { serverConnectionId: connectionId, mode: 'missing_permission', recordName: event.reason.recordName, inst: inst, branch: branch, temporary: true }));
1173
- yield this._messenger.sendMessage(connections.map((c) => c.serverConnectionId), {
1174
- type: 'permission/request/missing',
1175
- reason: event.reason,
1176
- connection: connectionInfo(connection),
1177
- user: userInfo,
1178
- });
1270
+ async requestMissingPermission(connectionId, event) {
1271
+ const connection = await this._connectionStore.getConnection(connectionId);
1272
+ if (!connection) {
1273
+ console.error(`[WebsocketController] [connectionId: ${connectionId}] Unable to request permission. Connection not found!`);
1274
+ await this.sendError(connectionId, -1, {
1275
+ success: false,
1276
+ errorCode: 'invalid_connection_state',
1277
+ errorMessage: `A server error occurred. (connectionId: ${connectionId})`,
1278
+ });
1279
+ await this.messenger.disconnect(connectionId);
1280
+ return;
1281
+ }
1282
+ if (event.reason.type !== 'missing_permission') {
1283
+ await this._messenger.sendMessage([connectionId], {
1284
+ type: 'permission/request/missing/response',
1285
+ success: false,
1286
+ recordName: event.reason.recordName,
1287
+ resourceKind: event.reason.resourceKind,
1288
+ resourceId: event.reason.resourceId,
1289
+ subjectType: event.reason.subjectType,
1290
+ subjectId: event.reason.subjectId,
1291
+ errorCode: 'unacceptable_request',
1292
+ errorMessage: 'It is only possible to request missing permissions.',
1293
+ });
1294
+ return;
1295
+ }
1296
+ else if (event.reason.resourceKind !== 'inst') {
1297
+ await this._messenger.sendMessage([connectionId], {
1298
+ type: 'permission/request/missing/response',
1299
+ success: false,
1300
+ recordName: event.reason.recordName,
1301
+ resourceKind: event.reason.resourceKind,
1302
+ resourceId: event.reason.resourceId,
1303
+ subjectType: event.reason.subjectType,
1304
+ subjectId: event.reason.subjectId,
1305
+ errorCode: 'unacceptable_request',
1306
+ errorMessage: 'Permissions can only be requested to access insts.',
1307
+ });
1308
+ return;
1309
+ }
1310
+ else if (event.reason.subjectType !== 'user' ||
1311
+ event.reason.subjectId !== connection.userId) {
1312
+ await this._messenger.sendMessage([connectionId], {
1313
+ type: 'permission/request/missing/response',
1314
+ success: false,
1315
+ recordName: event.reason.recordName,
1316
+ resourceKind: event.reason.resourceKind,
1317
+ resourceId: event.reason.resourceId,
1318
+ subjectType: event.reason.subjectType,
1319
+ subjectId: event.reason.subjectId,
1320
+ errorCode: 'unacceptable_request',
1321
+ errorMessage: 'Permissions can only be requested for the current user.',
1322
+ });
1323
+ return;
1324
+ }
1325
+ const connections = await this._connectionStore.getConnectionsByBranch('branch', event.reason.recordName, event.reason.resourceId, DEFAULT_BRANCH_NAME);
1326
+ if (connections.length > 0) {
1327
+ const userInfoResult = await this._auth.getPublicUserInfo(connection.userId);
1328
+ let userInfo = null;
1329
+ if (userInfoResult.success === false) {
1330
+ console.error('[WebsocketController] [requestMissingPermission] Error while getting user info.', userInfoResult);
1179
1331
  }
1180
1332
  else {
1181
- yield this._messenger.sendMessage([connectionId], {
1182
- type: 'permission/request/missing/response',
1183
- success: false,
1184
- recordName: event.reason.recordName,
1185
- resourceKind: event.reason.resourceKind,
1186
- resourceId: event.reason.resourceId,
1187
- subjectType: event.reason.subjectType,
1188
- subjectId: event.reason.subjectId,
1189
- errorCode: 'unacceptable_request',
1190
- errorMessage: 'There are no currently no users available that can grant access to the inst.',
1191
- });
1192
- return;
1193
- }
1333
+ userInfo = userInfoResult.user;
1334
+ }
1335
+ const inst = `${event.reason.resourceKind}/${event.reason.resourceId}`;
1336
+ const branch = `${event.reason.subjectType}/${event.reason.subjectId}`;
1337
+ await this._connectionStore.saveBranchConnection({
1338
+ ...connection,
1339
+ serverConnectionId: connectionId,
1340
+ mode: 'missing_permission',
1341
+ recordName: event.reason.recordName,
1342
+ inst: inst,
1343
+ branch: branch,
1344
+ temporary: true,
1345
+ });
1346
+ await this._messenger.sendMessage(connections.map((c) => c.serverConnectionId), {
1347
+ type: 'permission/request/missing',
1348
+ reason: event.reason,
1349
+ connection: connectionInfo(connection),
1350
+ user: userInfo,
1351
+ });
1352
+ }
1353
+ else {
1354
+ await this._messenger.sendMessage([connectionId], {
1355
+ type: 'permission/request/missing/response',
1356
+ success: false,
1357
+ recordName: event.reason.recordName,
1358
+ resourceKind: event.reason.resourceKind,
1359
+ resourceId: event.reason.resourceId,
1360
+ subjectType: event.reason.subjectType,
1361
+ subjectId: event.reason.subjectId,
1362
+ errorCode: 'unacceptable_request',
1363
+ errorMessage: 'There are no currently no users available that can grant access to the inst.',
1364
+ });
1365
+ return;
1366
+ }
1367
+ }
1368
+ /**
1369
+ * Responds to a missing permission request.
1370
+ * @param connectionId The ID of the connection that is responding to the request.
1371
+ * @param event The response to the missing permission request.
1372
+ */
1373
+ async respondToPermissionRequest(connectionId, event) {
1374
+ const connection = await this._connectionStore.getConnection(connectionId);
1375
+ if (!connection) {
1376
+ console.error(`[WebsocketController] [connectionId: ${connectionId}] Unable to respond to permission request. Connection not found!`);
1377
+ await this.sendError(connectionId, -1, {
1378
+ success: false,
1379
+ errorCode: 'invalid_connection_state',
1380
+ errorMessage: `A server error occurred. (connectionId: ${connectionId})`,
1381
+ });
1382
+ await this.messenger.disconnect(connectionId);
1383
+ return;
1384
+ }
1385
+ const inst = `${event.resourceKind}/${event.resourceId}`;
1386
+ const branch = `${event.subjectType}/${event.subjectId}`;
1387
+ const otherConnections = await this._connectionStore.getConnectionsByBranch('missing_permission', event.recordName, inst, branch);
1388
+ if (otherConnections.length > 0) {
1389
+ for (let c of otherConnections) {
1390
+ await this._connectionStore.deleteBranchConnection(c.serverConnectionId, 'missing_permission', event.recordName, inst, branch);
1391
+ }
1392
+ await this._messenger.sendMessage(otherConnections.map((c) => c.serverConnectionId), {
1393
+ type: 'permission/request/missing/response',
1394
+ ...event,
1395
+ connection: connectionInfo(connection),
1396
+ });
1397
+ }
1398
+ }
1399
+ /**
1400
+ * Attempts to install a package into an inst.
1401
+ * @param request The request to load the package.
1402
+ */
1403
+ async installPackage(request) {
1404
+ var _a, _b;
1405
+ if (!this._packageVersions) {
1406
+ return {
1407
+ success: false,
1408
+ errorCode: 'not_supported',
1409
+ errorMessage: 'Package loading is not supported.',
1410
+ };
1411
+ }
1412
+ const userId = request.userId;
1413
+ const key = (_a = request.package.key) !== null && _a !== void 0 ? _a : {};
1414
+ console.log(`[CausalRepoServer] [namespace: ${request.recordName}/${request.inst}, ${userId}, package: ${request.package.recordName}/${request.package.address}@${formatVersionSpecifier(key)}] Install Package`);
1415
+ const p = await this._packageVersions.getItem({
1416
+ recordName: request.package.recordName,
1417
+ address: request.package.address,
1418
+ key,
1419
+ userId: userId,
1420
+ instances: request.instances,
1421
+ });
1422
+ if (p.success === false) {
1423
+ console.error(`[CausalRepoServer] [userId: ${userId}] Unable to load package.`, p);
1424
+ return p;
1425
+ }
1426
+ if (p.auxFile.success === false) {
1427
+ console.error(`[CausalRepoServer] [userId: ${userId}] Unable to load package file.`, p.auxFile);
1428
+ return p.auxFile;
1429
+ }
1430
+ const loadedPackageStore = this._instStore;
1431
+ const loadedPackage = await loadedPackageStore.isPackageLoaded(request.recordName, request.inst, p.item.packageId);
1432
+ if (loadedPackage) {
1433
+ // Already loaded
1434
+ console.log(`[CausalRepoServer] [userId: ${userId}] Package already loaded.`);
1435
+ return {
1436
+ success: true,
1437
+ packageLoadId: loadedPackage.id,
1438
+ package: p.item,
1439
+ };
1440
+ }
1441
+ // check that the user and target inst has the ability to run the package
1442
+ const context = await this._policies.constructAuthorizationContext({
1443
+ recordKeyOrRecordName: request.package.recordName,
1444
+ userId,
1445
+ });
1446
+ if (context.success === false) {
1447
+ return context;
1448
+ }
1449
+ const authorization = await this._policies.authorizeUserAndInstances(context.context, {
1450
+ userId,
1451
+ instances: [formatInstId(request.recordName, request.inst)],
1452
+ resourceKind: 'package.version',
1453
+ resourceId: p.item.address,
1454
+ action: 'run',
1455
+ markers: p.item.markers,
1456
+ });
1457
+ if (authorization.success === false) {
1458
+ return authorization;
1459
+ }
1460
+ const fileResponse = await fetch(p.auxFile.requestUrl, {
1461
+ method: p.auxFile.requestMethod,
1462
+ headers: new Headers(p.auxFile.requestHeaders),
1194
1463
  });
1464
+ if (fileResponse.status >= 300) {
1465
+ console.error(`[CausalRepoServer] [userId: ${userId}] Unable to load package file.`);
1466
+ // Failed
1467
+ return {
1468
+ success: false,
1469
+ errorCode: 'invalid_file_data',
1470
+ errorMessage: 'The package file could not be loaded.',
1471
+ };
1472
+ }
1473
+ const json = await fileResponse.text();
1474
+ const packageData = tryParseJson(json);
1475
+ if (packageData.success === false) {
1476
+ console.error(`[CausalRepoServer] [userId: ${userId}] Unable to parse package file.`, packageData);
1477
+ return {
1478
+ success: false,
1479
+ errorCode: 'invalid_file_data',
1480
+ errorMessage: 'The package file could not be parsed. It must be valid JSON.',
1481
+ };
1482
+ }
1483
+ const parsed = STORED_AUX_SCHEMA.safeParse(packageData.value);
1484
+ if (parsed.success === false) {
1485
+ console.error(`[CausalRepoServer] [userId: ${userId}] Unable to parse package file.`, packageData);
1486
+ return {
1487
+ success: false,
1488
+ errorCode: 'invalid_file_data',
1489
+ errorMessage: 'The package file could not be parsed.',
1490
+ issues: parsed.error.issues,
1491
+ };
1492
+ }
1493
+ const updates = parsed.data.version === 2
1494
+ ? parsed.data.updates.map((u) => u.update)
1495
+ : [
1496
+ constructInitializationUpdate(createInitializationUpdate(Object.values(parsed.data.state))).update,
1497
+ ];
1498
+ const timestamps = parsed.data.version === 2
1499
+ ? parsed.data.updates.map((u) => u.timestamp)
1500
+ : [0];
1501
+ const branch = (_b = request.branch) !== null && _b !== void 0 ? _b : DEFAULT_BRANCH_NAME;
1502
+ const result = await this.addUserUpdates({
1503
+ userId: request.userId,
1504
+ userRole: request.userRole,
1505
+ recordName: request.recordName,
1506
+ inst: request.inst,
1507
+ branch,
1508
+ updates: updates,
1509
+ timestamps: timestamps,
1510
+ });
1511
+ if (result.success === false) {
1512
+ return result;
1513
+ }
1514
+ const loadedPackageId = uuidv7();
1515
+ await loadedPackageStore.saveLoadedPackage({
1516
+ id: loadedPackageId,
1517
+ recordName: request.recordName,
1518
+ inst: request.inst,
1519
+ branch,
1520
+ packageId: p.item.packageId,
1521
+ packageVersionId: p.item.id,
1522
+ userId: userId,
1523
+ });
1524
+ return {
1525
+ success: true,
1526
+ packageLoadId: loadedPackageId,
1527
+ package: p.item,
1528
+ };
1195
1529
  }
1196
- /**
1197
- * Responds to a missing permission request.
1198
- * @param connectionId The ID of the connection that is responding to the request.
1199
- * @param event The response to the missing permission request.
1200
- */
1201
- respondToPermissionRequest(connectionId, event) {
1202
- return __awaiter(this, void 0, void 0, function* () {
1203
- const connection = yield this._connectionStore.getConnection(connectionId);
1204
- if (!connection) {
1205
- console.error(`[CausalRepoServer] [connectionId: ${connectionId}] Unable to respond to permission request. Connection not found!`);
1206
- yield this.sendError(connectionId, -1, {
1530
+ async listInstalledPackages(request) {
1531
+ if (!this._packageVersions) {
1532
+ return {
1533
+ success: false,
1534
+ errorCode: 'not_supported',
1535
+ errorMessage: 'Packages are not supported.',
1536
+ };
1537
+ }
1538
+ if (request.recordName) {
1539
+ const context = await this._policies.constructAuthorizationContext({
1540
+ recordKeyOrRecordName: request.recordName,
1541
+ userId: request.userId,
1542
+ });
1543
+ if (context.success === false) {
1544
+ return context;
1545
+ }
1546
+ const recordName = context.context.recordName;
1547
+ const instName = request.inst;
1548
+ const savedInst = await this._instStore.getInstByName(recordName, instName);
1549
+ if (!savedInst) {
1550
+ return {
1207
1551
  success: false,
1208
- errorCode: 'invalid_connection_state',
1209
- errorMessage: `A server error occurred. (connectionId: ${connectionId})`,
1210
- });
1211
- yield this.messenger.disconnect(connectionId);
1212
- return;
1552
+ errorCode: 'inst_not_found',
1553
+ errorMessage: 'The inst was not found.',
1554
+ };
1213
1555
  }
1214
- const inst = `${event.resourceKind}/${event.resourceId}`;
1215
- const branch = `${event.subjectType}/${event.subjectId}`;
1216
- const otherConnections = yield this._connectionStore.getConnectionsByBranch('missing_permission', event.recordName, inst, branch);
1217
- if (otherConnections.length > 0) {
1218
- for (let c of otherConnections) {
1219
- yield this._connectionStore.deleteBranchConnection(c.serverConnectionId, 'missing_permission', event.recordName, inst, branch);
1220
- }
1221
- yield this._messenger.sendMessage(otherConnections.map((c) => c.serverConnectionId), Object.assign(Object.assign({ type: 'permission/request/missing/response' }, event), { connection: connectionInfo(connection) }));
1556
+ const authResult = await this._policies.authorizeUserAndInstances(context.context, {
1557
+ resourceKind: 'inst',
1558
+ resourceId: instName,
1559
+ action: 'read',
1560
+ markers: savedInst.markers,
1561
+ userId: request.userId,
1562
+ instances: request.instances,
1563
+ });
1564
+ if (authResult.success === false) {
1565
+ return authResult;
1222
1566
  }
1223
- });
1567
+ }
1568
+ const packages = await this._instStore.listLoadedPackages(request.recordName, request.inst);
1569
+ return {
1570
+ success: true,
1571
+ packages: packages.map((p) => ({
1572
+ id: p.id,
1573
+ recordName: p.recordName,
1574
+ inst: p.inst,
1575
+ branch: p.branch,
1576
+ packageId: p.packageId,
1577
+ packageVersionId: p.packageVersionId,
1578
+ userId: p.userId,
1579
+ })),
1580
+ };
1224
1581
  }
1225
- syncTime(connectionId, event, requestTime) {
1226
- return __awaiter(this, void 0, void 0, function* () {
1227
- yield this._messenger.sendMessage([connectionId], {
1228
- type: 'sync/time/response',
1229
- id: event.id,
1230
- clientRequestTime: event.clientRequestTime,
1231
- serverReceiveTime: requestTime,
1232
- serverTransmitTime: Date.now(),
1233
- });
1582
+ async syncTime(connectionId, event, requestTime) {
1583
+ await this._messenger.sendMessage([connectionId], {
1584
+ type: 'sync/time/response',
1585
+ id: event.id,
1586
+ clientRequestTime: event.clientRequestTime,
1587
+ serverReceiveTime: requestTime,
1588
+ serverTransmitTime: Date.now(),
1234
1589
  });
1235
1590
  }
1236
1591
  /**
@@ -1240,127 +1595,119 @@ export class WebsocketController {
1240
1595
  * @param totalHits The total number of hits by the connection.
1241
1596
  * @param timeMs The current time in unix time in miliseconds.
1242
1597
  */
1243
- rateLimitExceeded(connectionId, retryAfter, totalHits, timeMs) {
1598
+ async rateLimitExceeded(connectionId, retryAfter, totalHits, timeMs) {
1244
1599
  var _a;
1245
- return __awaiter(this, void 0, void 0, function* () {
1246
- const lastHit = (_a = (yield this._connectionStore.getConnectionRateLimitExceededTime(connectionId))) !== null && _a !== void 0 ? _a : -Infinity;
1247
- const difference = timeMs - lastHit;
1248
- yield this._connectionStore.setConnectionRateLimitExceededTime(connectionId, timeMs);
1249
- if (difference >= 1000) {
1250
- yield this._messenger.sendMessage([connectionId], {
1251
- type: 'rate_limit_exceeded',
1252
- retryAfter,
1253
- totalHits,
1254
- });
1255
- }
1256
- });
1600
+ const lastHit = (_a = (await this._connectionStore.getConnectionRateLimitExceededTime(connectionId))) !== null && _a !== void 0 ? _a : -Infinity;
1601
+ const difference = timeMs - lastHit;
1602
+ await this._connectionStore.setConnectionRateLimitExceededTime(connectionId, timeMs);
1603
+ if (difference >= 1000) {
1604
+ await this._messenger.sendMessage([connectionId], {
1605
+ type: 'rate_limit_exceeded',
1606
+ retryAfter,
1607
+ totalHits,
1608
+ });
1609
+ }
1257
1610
  }
1258
1611
  /**
1259
1612
  * Processes the given upload request.
1260
1613
  * @param connectionId The ID of the connection that is requesting the upload.
1261
1614
  * @param requestId The ID of the request.
1262
1615
  */
1263
- uploadRequest(connectionId, requestId) {
1264
- return __awaiter(this, void 0, void 0, function* () {
1265
- try {
1266
- const result = yield this._messenger.presignMessageUpload();
1267
- if (result.success === false) {
1268
- console.log(`[WebsocketController] [uploadRequest] Upload requests are not supported!`);
1269
- yield this.sendError(connectionId, requestId, {
1270
- success: false,
1271
- errorCode: 'not_supported',
1272
- errorMessage: 'Upload requests are not supported.',
1273
- });
1274
- return;
1275
- }
1276
- yield this.sendEvent(connectionId, [
1277
- WebsocketEventTypes.UploadResponse,
1278
- requestId,
1279
- result.uploadUrl,
1280
- result.uploadMethod,
1281
- result.uploadHeaders,
1282
- ]);
1283
- }
1284
- catch (err) {
1285
- console.error('[WebsocketController] [uploadRequest] Error while processing upload request.', err);
1286
- yield this.sendError(connectionId, requestId, {
1616
+ async uploadRequest(connectionId, requestId) {
1617
+ try {
1618
+ const result = await this._messenger.presignMessageUpload();
1619
+ if (result.success === false) {
1620
+ console.log(`[WebsocketController] [uploadRequest] Upload requests are not supported!`);
1621
+ await this.sendError(connectionId, requestId, {
1287
1622
  success: false,
1288
- errorCode: 'server_error',
1289
- errorMessage: 'Error while processing upload request.',
1623
+ errorCode: 'not_supported',
1624
+ errorMessage: 'Upload requests are not supported.',
1290
1625
  });
1626
+ return;
1291
1627
  }
1292
- });
1628
+ await this.sendEvent(connectionId, [
1629
+ WebsocketEventTypes.UploadResponse,
1630
+ requestId,
1631
+ result.uploadUrl,
1632
+ result.uploadMethod,
1633
+ result.uploadHeaders,
1634
+ ]);
1635
+ }
1636
+ catch (err) {
1637
+ console.error('[WebsocketController] [uploadRequest] Error while processing upload request.', err);
1638
+ await this.sendError(connectionId, requestId, {
1639
+ success: false,
1640
+ errorCode: 'server_error',
1641
+ errorMessage: 'Error while processing upload request.',
1642
+ });
1643
+ }
1293
1644
  }
1294
- downloadRequest(connectionId, requestId, url, method, headers) {
1295
- return __awaiter(this, void 0, void 0, function* () {
1296
- try {
1297
- const message = yield this._messenger.downloadMessage(url, method, headers);
1298
- if (message === undefined) {
1299
- console.log(`[WebsocketController] [downloadRequest] Download requests are not supported!`);
1300
- return {
1301
- success: false,
1302
- errorCode: 'not_supported',
1303
- errorMessage: 'Download requests are not supported.',
1304
- };
1305
- }
1306
- else if (message === null) {
1307
- return {
1308
- success: false,
1309
- errorCode: 'message_not_found',
1310
- errorMessage: 'Message not found.',
1311
- };
1312
- }
1313
- else {
1314
- return {
1315
- success: true,
1316
- requestId,
1317
- message,
1318
- };
1319
- }
1645
+ async downloadRequest(connectionId, requestId, url, method, headers) {
1646
+ try {
1647
+ const message = await this._messenger.downloadMessage(url, method, headers);
1648
+ if (message === undefined) {
1649
+ console.log(`[WebsocketController] [downloadRequest] Download requests are not supported!`);
1650
+ return {
1651
+ success: false,
1652
+ errorCode: 'not_supported',
1653
+ errorMessage: 'Download requests are not supported.',
1654
+ };
1320
1655
  }
1321
- catch (err) {
1322
- console.error('[WebsocketController] [downloadRequest] Error while processing download request.', err);
1656
+ else if (message === null) {
1323
1657
  return {
1324
1658
  success: false,
1325
- errorCode: 'server_error',
1326
- errorMessage: 'Error while processing download request.',
1659
+ errorCode: 'message_not_found',
1660
+ errorMessage: 'Message not found.',
1327
1661
  };
1328
1662
  }
1329
- });
1663
+ else {
1664
+ return {
1665
+ success: true,
1666
+ requestId,
1667
+ message,
1668
+ };
1669
+ }
1670
+ }
1671
+ catch (err) {
1672
+ console.error('[WebsocketController] [downloadRequest] Error while processing download request.', err);
1673
+ return {
1674
+ success: false,
1675
+ errorCode: 'server_error',
1676
+ errorMessage: 'Error while processing download request.',
1677
+ };
1678
+ }
1330
1679
  }
1331
1680
  /**
1332
1681
  * Saves all of the permanent branches that are currently in memory.
1333
1682
  * @param timeout The timeout for the operation. Defaults to 30 seconds.
1334
1683
  */
1335
- savePermanentBranches(timeout = 30000) {
1336
- return __awaiter(this, void 0, void 0, function* () {
1337
- const store = this._instStore;
1338
- if (store instanceof SplitInstRecordsStore) {
1339
- const unlock = yield store.temp.acquireLock(SAVE_PERMANENT_BRANCHES_LOCK, timeout);
1340
- if (!unlock) {
1341
- console.log(`[WebsocketController] [savePermanentBranches] Unable to acquire lock.`);
1342
- return;
1343
- }
1344
- console.log('[WebsocketController] [savePermanentBranches] Lock acquired.');
1345
- try {
1346
- const generation = yield store.temp.getDirtyBranchGeneration();
1347
- store.temp.setDirtyBranchGeneration(uuid());
1348
- const branches = yield store.temp.listDirtyBranches(generation);
1349
- for (let branch of branches) {
1350
- if (!branch.recordName) {
1351
- continue;
1352
- }
1353
- yield this._saveBranchUpdates(store, branch);
1684
+ async savePermanentBranches(timeout = 30000) {
1685
+ const store = this._instStore;
1686
+ if (store instanceof SplitInstRecordsStore) {
1687
+ const unlock = await store.temp.acquireLock(SAVE_PERMANENT_BRANCHES_LOCK, timeout);
1688
+ if (!unlock) {
1689
+ console.log(`[WebsocketController] [savePermanentBranches] Unable to acquire lock.`);
1690
+ return;
1691
+ }
1692
+ console.log('[WebsocketController] [savePermanentBranches] Lock acquired.');
1693
+ try {
1694
+ const generation = await store.temp.getDirtyBranchGeneration();
1695
+ store.temp.setDirtyBranchGeneration(uuid());
1696
+ const branches = await store.temp.listDirtyBranches(generation);
1697
+ for (let branch of branches) {
1698
+ if (!branch.recordName) {
1699
+ continue;
1354
1700
  }
1355
- yield store.temp.clearDirtyBranches(generation);
1356
- console.log(`[WebsocketController] [savePermanentBranches] Saved.`);
1357
- }
1358
- finally {
1359
- unlock();
1360
- console.log('[WebsocketController] [savePermanentBranches] Released lock.');
1701
+ await this._saveBranchUpdates(store, branch);
1361
1702
  }
1703
+ await store.temp.clearDirtyBranches(generation);
1704
+ console.log(`[WebsocketController] [savePermanentBranches] Saved.`);
1362
1705
  }
1363
- });
1706
+ finally {
1707
+ unlock();
1708
+ console.log('[WebsocketController] [savePermanentBranches] Released lock.');
1709
+ }
1710
+ }
1364
1711
  }
1365
1712
  /**
1366
1713
  * Gets or creates the inst with the given name in the given record.
@@ -1373,147 +1720,135 @@ export class WebsocketController {
1373
1720
  * @param userId The ID of the user that is trying to access the inst.
1374
1721
  * @param context The authorization context.
1375
1722
  */
1376
- _getOrCreateInst(recordName, instName, userId, config, context = null) {
1377
- return __awaiter(this, void 0, void 0, function* () {
1378
- let inst = null;
1379
- let features = null;
1380
- if (recordName) {
1381
- const getInstResult = yield this._getInst(recordName, instName, userId, config, context);
1382
- if (getInstResult.success === false) {
1383
- return getInstResult;
1384
- }
1385
- const savedInst = getInstResult.inst;
1723
+ async _getOrCreateInst(recordName, instName, userId, config, context = null) {
1724
+ let inst = null;
1725
+ let features = null;
1726
+ if (recordName) {
1727
+ const getInstResult = await this._getInst(recordName, instName, userId, config, context);
1728
+ if (getInstResult.success === false) {
1729
+ return getInstResult;
1730
+ }
1731
+ const savedInst = getInstResult.inst;
1732
+ if (!context) {
1733
+ context = getInstResult.context;
1734
+ }
1735
+ if (!features) {
1736
+ features = getInstResult.features;
1737
+ }
1738
+ if (!savedInst) {
1386
1739
  if (!context) {
1387
- context = getInstResult.context;
1388
- }
1389
- if (!features) {
1390
- features = getInstResult.features;
1391
- }
1392
- if (!savedInst) {
1393
- if (!context) {
1394
- const contextResult = yield this._policies.constructAuthorizationContext({
1395
- recordKeyOrRecordName: recordName,
1396
- userId,
1397
- });
1398
- if (contextResult.success === false) {
1399
- return contextResult;
1400
- }
1401
- context = contextResult.context;
1402
- }
1403
- const authorizationResult = yield this._policies.authorizeUserAndInstancesForResources(context, {
1404
- userId: userId,
1405
- instances: [],
1406
- resources: [
1407
- {
1408
- resourceKind: 'inst',
1409
- resourceId: instName,
1410
- action: 'create',
1411
- markers: [PRIVATE_MARKER],
1412
- },
1413
- {
1414
- resourceKind: 'marker',
1415
- resourceId: PRIVATE_MARKER,
1416
- action: 'assign',
1417
- markers: [ACCOUNT_MARKER],
1418
- },
1419
- {
1420
- resourceKind: 'inst',
1421
- resourceId: instName,
1422
- action: 'read',
1423
- markers: [PRIVATE_MARKER],
1424
- },
1425
- ],
1740
+ const contextResult = await this._policies.constructAuthorizationContext({
1741
+ recordKeyOrRecordName: recordName,
1742
+ userId,
1426
1743
  });
1427
- if (authorizationResult.success === false) {
1428
- console.log('[WebsocketController] Unable to authorize inst creation.', authorizationResult);
1429
- return authorizationResult;
1430
- }
1431
- // const authorizeCreateResult =
1432
- // await this._policies.authorizeUserAndInstances(context, {
1433
- // resourceKind: 'inst',
1434
- // resourceId: instName,
1435
- // action: 'create',
1436
- // markers: [PRIVATE_MARKER],
1437
- // userId,
1438
- // instances: [],
1439
- // });
1440
- // if (authorizeCreateResult.success === false) {
1441
- // console.log(
1442
- // '[WebsocketController] Unable to authorize inst creation.',
1443
- // authorizeCreateResult
1444
- // );
1445
- // return authorizeCreateResult;
1446
- // }
1447
- // const authorizeReadResult =
1448
- // await this._policies.authorizeUserAndInstances(context, {
1449
- // resourceKind: 'inst',
1450
- // resourceId: instName,
1451
- // action: 'read',
1452
- // markers: [PRIVATE_MARKER],
1453
- // userId,
1454
- // instances: [],
1455
- // });
1456
- // if (authorizeReadResult.success === false) {
1457
- // console.log(
1458
- // '[WebsocketController] Unable to authorize inst creation.',
1459
- // authorizeReadResult
1460
- // );
1461
- // return authorizeReadResult;
1462
- // }
1463
- const instMetrics = yield this._metrics.getSubscriptionInstMetricsByRecordName(recordName);
1464
- features = getSubscriptionFeatures(config, instMetrics.subscriptionStatus, instMetrics.subscriptionId, instMetrics.subscriptionType);
1465
- if (!features.insts.allowed) {
1466
- return {
1467
- success: false,
1468
- errorCode: 'not_authorized',
1469
- errorMessage: 'Insts are not allowed for this subscription.',
1470
- };
1471
- }
1472
- else if (typeof features.insts.maxInsts === 'number' &&
1473
- instMetrics.totalInsts >= features.insts.maxInsts) {
1474
- return {
1475
- success: false,
1476
- errorCode: 'subscription_limit_reached',
1477
- errorMessage: 'The maximum number of insts has been reached.',
1478
- };
1744
+ if (contextResult.success === false) {
1745
+ return contextResult;
1479
1746
  }
1480
- // Create the inst
1481
- inst = {
1482
- recordName: recordName,
1483
- inst: instName,
1484
- markers: [PRIVATE_MARKER],
1485
- subscriptionId: instMetrics.subscriptionId,
1486
- subscriptionStatus: instMetrics.subscriptionStatus,
1487
- subscriptionType: instMetrics.subscriptionType,
1747
+ context = contextResult.context;
1748
+ }
1749
+ const authorizationResult = await this._policies.authorizeUserAndInstancesForResources(context, {
1750
+ userId: userId,
1751
+ instances: [],
1752
+ resources: [
1753
+ {
1754
+ resourceKind: 'inst',
1755
+ resourceId: instName,
1756
+ action: 'create',
1757
+ markers: [PRIVATE_MARKER],
1758
+ },
1759
+ {
1760
+ resourceKind: 'marker',
1761
+ resourceId: PRIVATE_MARKER,
1762
+ action: 'assign',
1763
+ markers: [ACCOUNT_MARKER],
1764
+ },
1765
+ {
1766
+ resourceKind: 'inst',
1767
+ resourceId: instName,
1768
+ action: 'read',
1769
+ markers: [PRIVATE_MARKER],
1770
+ },
1771
+ ],
1772
+ });
1773
+ if (authorizationResult.success === false) {
1774
+ console.log('[WebsocketController] Unable to authorize inst creation.', authorizationResult);
1775
+ return authorizationResult;
1776
+ }
1777
+ // const authorizeCreateResult =
1778
+ // await this._policies.authorizeUserAndInstances(context, {
1779
+ // resourceKind: 'inst',
1780
+ // resourceId: instName,
1781
+ // action: 'create',
1782
+ // markers: [PRIVATE_MARKER],
1783
+ // userId,
1784
+ // instances: [],
1785
+ // });
1786
+ // if (authorizeCreateResult.success === false) {
1787
+ // console.log(
1788
+ // '[WebsocketController] Unable to authorize inst creation.',
1789
+ // authorizeCreateResult
1790
+ // );
1791
+ // return authorizeCreateResult;
1792
+ // }
1793
+ // const authorizeReadResult =
1794
+ // await this._policies.authorizeUserAndInstances(context, {
1795
+ // resourceKind: 'inst',
1796
+ // resourceId: instName,
1797
+ // action: 'read',
1798
+ // markers: [PRIVATE_MARKER],
1799
+ // userId,
1800
+ // instances: [],
1801
+ // });
1802
+ // if (authorizeReadResult.success === false) {
1803
+ // console.log(
1804
+ // '[WebsocketController] Unable to authorize inst creation.',
1805
+ // authorizeReadResult
1806
+ // );
1807
+ // return authorizeReadResult;
1808
+ // }
1809
+ const instMetrics = await this._metrics.getSubscriptionInstMetricsByRecordName(recordName);
1810
+ features = getSubscriptionFeatures(config, instMetrics.subscriptionStatus, instMetrics.subscriptionId, instMetrics.subscriptionType);
1811
+ if (!features.insts.allowed) {
1812
+ return {
1813
+ success: false,
1814
+ errorCode: 'not_authorized',
1815
+ errorMessage: 'Insts are not allowed for this subscription.',
1488
1816
  };
1489
- const result = yield this._instStore.saveInst(inst);
1490
- if (result.success === false) {
1491
- console.log('[WebsocketController] Unable to save inst.', result);
1492
- return result;
1493
- }
1494
1817
  }
1495
- else {
1496
- inst = savedInst;
1818
+ else if (typeof features.insts.maxInsts === 'number' &&
1819
+ instMetrics.totalInsts >= features.insts.maxInsts) {
1820
+ return {
1821
+ success: false,
1822
+ errorCode: 'subscription_limit_reached',
1823
+ errorMessage: 'The maximum number of insts has been reached.',
1824
+ };
1825
+ }
1826
+ // Create the inst
1827
+ inst = {
1828
+ recordName: recordName,
1829
+ inst: instName,
1830
+ markers: [PRIVATE_MARKER],
1831
+ subscriptionId: instMetrics.subscriptionId,
1832
+ subscriptionStatus: instMetrics.subscriptionStatus,
1833
+ subscriptionType: instMetrics.subscriptionType,
1834
+ };
1835
+ const result = await this._instStore.saveInst(inst);
1836
+ if (result.success === false) {
1837
+ console.log('[WebsocketController] Unable to save inst.', result);
1838
+ return result;
1497
1839
  }
1498
1840
  }
1499
1841
  else {
1500
- // null record name means public temporary inst
1501
- const userInfo = yield this._authStore.findUser(userId);
1502
- if (userInfo) {
1503
- const userPrivacyFeatures = userInfo.privacyFeatures;
1504
- if (userPrivacyFeatures) {
1505
- if (!userPrivacyFeatures.allowPublicInsts) {
1506
- return {
1507
- success: false,
1508
- errorCode: 'not_authorized',
1509
- errorMessage: 'Public insts are not allowed.',
1510
- };
1511
- }
1512
- }
1513
- }
1514
- else {
1515
- const privoConfig = yield this._config.getPrivoConfiguration();
1516
- if (privoConfig) {
1842
+ inst = savedInst;
1843
+ }
1844
+ }
1845
+ else {
1846
+ // null record name means public temporary inst
1847
+ const userInfo = await this._authStore.findUser(userId);
1848
+ if (userInfo) {
1849
+ const userPrivacyFeatures = userInfo.privacyFeatures;
1850
+ if (userPrivacyFeatures) {
1851
+ if (!userPrivacyFeatures.allowPublicInsts) {
1517
1852
  return {
1518
1853
  success: false,
1519
1854
  errorCode: 'not_authorized',
@@ -1522,13 +1857,23 @@ export class WebsocketController {
1522
1857
  }
1523
1858
  }
1524
1859
  }
1525
- return {
1526
- success: true,
1527
- inst,
1528
- context,
1529
- features,
1530
- };
1531
- });
1860
+ else {
1861
+ const privoConfig = await this._config.getPrivoConfiguration();
1862
+ if (privoConfig) {
1863
+ return {
1864
+ success: false,
1865
+ errorCode: 'not_authorized',
1866
+ errorMessage: 'Public insts are not allowed.',
1867
+ };
1868
+ }
1869
+ }
1870
+ }
1871
+ return {
1872
+ success: true,
1873
+ inst,
1874
+ context,
1875
+ features,
1876
+ };
1532
1877
  }
1533
1878
  /**
1534
1879
  * Gets the inst with the given name in the given record.
@@ -1540,154 +1885,144 @@ export class WebsocketController {
1540
1885
  * @param instName The name of the inst.
1541
1886
  * @param userId The ID of the user that is trying to access the inst.
1542
1887
  */
1543
- _getInst(recordName, instName, userId, config, context = null) {
1544
- return __awaiter(this, void 0, void 0, function* () {
1545
- let inst = null;
1546
- let features = null;
1547
- if (recordName) {
1548
- const savedInst = yield this._instStore.getInstByName(recordName, instName);
1549
- if (savedInst) {
1550
- features = getSubscriptionFeatures(config, savedInst.subscriptionStatus, savedInst.subscriptionId, savedInst.subscriptionType);
1551
- if (!features.insts.allowed) {
1552
- return {
1553
- success: false,
1554
- errorCode: 'not_authorized',
1555
- errorMessage: 'Insts are not allowed for this subscription.',
1556
- };
1557
- }
1558
- if (!context) {
1559
- const contextResult = yield this._policies.constructAuthorizationContext({
1560
- recordKeyOrRecordName: recordName,
1561
- userId,
1562
- });
1563
- if (contextResult.success === false) {
1564
- return contextResult;
1565
- }
1566
- context = contextResult.context;
1567
- }
1568
- const authorizeResult = yield this._policies.authorizeUserAndInstances(context, {
1569
- resourceKind: 'inst',
1570
- resourceId: instName,
1571
- action: 'read',
1572
- markers: savedInst.markers,
1888
+ async _getInst(recordName, instName, userId, config, context = null) {
1889
+ let inst = null;
1890
+ let features = null;
1891
+ if (recordName) {
1892
+ const savedInst = await this._instStore.getInstByName(recordName, instName);
1893
+ if (savedInst) {
1894
+ features = getSubscriptionFeatures(config, savedInst.subscriptionStatus, savedInst.subscriptionId, savedInst.subscriptionType);
1895
+ if (!features.insts.allowed) {
1896
+ return {
1897
+ success: false,
1898
+ errorCode: 'not_authorized',
1899
+ errorMessage: 'Insts are not allowed for this subscription.',
1900
+ };
1901
+ }
1902
+ if (!context) {
1903
+ const contextResult = await this._policies.constructAuthorizationContext({
1904
+ recordKeyOrRecordName: recordName,
1573
1905
  userId,
1574
- instances: [],
1575
1906
  });
1576
- if (authorizeResult.success === false) {
1577
- console.log('[WebsocketController] Unable to authorize inst read.', authorizeResult);
1578
- return authorizeResult;
1907
+ if (contextResult.success === false) {
1908
+ return contextResult;
1579
1909
  }
1910
+ context = contextResult.context;
1911
+ }
1912
+ const authorizeResult = await this._policies.authorizeUserAndInstances(context, {
1913
+ resourceKind: 'inst',
1914
+ resourceId: instName,
1915
+ action: 'read',
1916
+ markers: savedInst.markers,
1917
+ userId,
1918
+ instances: [],
1919
+ });
1920
+ if (authorizeResult.success === false) {
1921
+ console.log('[WebsocketController] Unable to authorize inst read.', authorizeResult);
1922
+ return authorizeResult;
1580
1923
  }
1581
- return {
1582
- success: true,
1583
- inst: savedInst,
1584
- context,
1585
- features,
1586
- };
1587
1924
  }
1588
1925
  return {
1589
1926
  success: true,
1590
- inst,
1927
+ inst: savedInst,
1591
1928
  context,
1592
1929
  features,
1593
1930
  };
1594
- });
1931
+ }
1932
+ return {
1933
+ success: true,
1934
+ inst,
1935
+ context,
1936
+ features,
1937
+ };
1595
1938
  }
1596
- _getOrCreateBranch(recordName, inst, branch, temporary, linkedInst) {
1597
- return __awaiter(this, void 0, void 0, function* () {
1598
- if (temporary) {
1599
- let b = yield this._temporaryStore.getBranchByName(recordName, inst, branch);
1600
- if (!b) {
1601
- // Save the branch to the temp store
1602
- yield this._temporaryStore.saveBranchInfo({
1603
- recordName: recordName,
1604
- inst: inst,
1605
- branch: branch,
1606
- temporary: true,
1607
- linkedInst: linkedInst,
1608
- });
1609
- b = yield this._temporaryStore.getBranchByName(recordName, inst, branch);
1610
- }
1611
- return b;
1939
+ async _getOrCreateBranch(recordName, inst, branch, temporary, linkedInst) {
1940
+ if (temporary) {
1941
+ let b = await this._temporaryStore.getBranchByName(recordName, inst, branch);
1942
+ if (!b) {
1943
+ // Save the branch to the temp store
1944
+ await this._temporaryStore.saveBranchInfo({
1945
+ recordName: recordName,
1946
+ inst: inst,
1947
+ branch: branch,
1948
+ temporary: true,
1949
+ linkedInst: linkedInst,
1950
+ });
1951
+ b = await this._temporaryStore.getBranchByName(recordName, inst, branch);
1612
1952
  }
1613
- else {
1614
- let b = yield this._instStore.getBranchByName(recordName, inst, branch);
1615
- if (!b) {
1616
- // Save the branch to the inst store
1617
- yield this._instStore.saveBranch({
1618
- branch: branch,
1619
- inst: inst,
1620
- recordName: recordName,
1621
- temporary: temporary || false,
1622
- });
1623
- b = yield this._instStore.getBranchByName(recordName, inst, branch);
1624
- }
1625
- return b;
1953
+ return b;
1954
+ }
1955
+ else {
1956
+ let b = await this._instStore.getBranchByName(recordName, inst, branch);
1957
+ if (!b) {
1958
+ // Save the branch to the inst store
1959
+ await this._instStore.saveBranch({
1960
+ branch: branch,
1961
+ inst: inst,
1962
+ recordName: recordName,
1963
+ temporary: temporary || false,
1964
+ });
1965
+ b = await this._instStore.getBranchByName(recordName, inst, branch);
1626
1966
  }
1627
- });
1967
+ return b;
1968
+ }
1628
1969
  }
1629
- _saveBranchUpdates(store, branch) {
1630
- return __awaiter(this, void 0, void 0, function* () {
1631
- console.log(`[WebsocketController] Saving branch updates for ${branch.recordName}/${branch.inst}/${branch.branch}`);
1632
- let [updateCount, size] = yield Promise.all([
1633
- store.temp.countBranchUpdates(branch.recordName, branch.inst, branch.branch),
1634
- store.temp.getBranchSize(branch.recordName, branch.inst, branch.branch),
1635
- ]);
1636
- if (updateCount <= 0) {
1637
- console.log(`[WebsocketController] Branch has no updates to save.`);
1638
- return;
1639
- }
1640
- const branchInfo = yield store.getBranchByName(branch.recordName, branch.inst, branch.branch);
1641
- if (!branchInfo) {
1642
- console.log(`[WebsocketController] Branch info not found.`);
1643
- return;
1644
- }
1645
- if (branchInfo.temporary) {
1646
- console.log(`[WebsocketController] Branch is temporary.`);
1970
+ async _saveBranchUpdates(store, branch) {
1971
+ console.log(`[WebsocketController] Saving branch updates for ${branch.recordName}/${branch.inst}/${branch.branch}`);
1972
+ let [updateCount, size] = await Promise.all([
1973
+ store.temp.countBranchUpdates(branch.recordName, branch.inst, branch.branch),
1974
+ store.temp.getBranchSize(branch.recordName, branch.inst, branch.branch),
1975
+ ]);
1976
+ if (updateCount <= 0) {
1977
+ console.log(`[WebsocketController] Branch has no updates to save.`);
1978
+ return;
1979
+ }
1980
+ const branchInfo = await store.getBranchByName(branch.recordName, branch.inst, branch.branch);
1981
+ if (!branchInfo) {
1982
+ console.log(`[WebsocketController] Branch info not found.`);
1983
+ return;
1984
+ }
1985
+ if (branchInfo.temporary) {
1986
+ console.log(`[WebsocketController] Branch is temporary.`);
1987
+ return;
1988
+ }
1989
+ const updates = await store.temp.getUpdates(branch.recordName, branch.inst, branch.branch);
1990
+ if (updates) {
1991
+ const doc = new Doc({
1992
+ gc: true,
1993
+ });
1994
+ for (let update of updates.updates) {
1995
+ const bytes = toByteArray(update);
1996
+ applyUpdate(doc, bytes);
1997
+ }
1998
+ const mergedBytes = encodeStateAsUpdate(doc);
1999
+ const mergedBase64 = fromByteArray(mergedBytes);
2000
+ const permanentReplaceResult = await store.perm.replaceCurrentUpdates(branch.recordName, branch.inst, branch.branch, mergedBase64, mergedBase64.length);
2001
+ if (permanentReplaceResult.success === false) {
2002
+ console.error(`[WebsocketController] Failed to replace permanent updates.`, permanentReplaceResult);
1647
2003
  return;
1648
2004
  }
1649
- const updates = yield store.temp.getUpdates(branch.recordName, branch.inst, branch.branch);
1650
- if (updates) {
1651
- const doc = new Doc({
1652
- gc: true,
1653
- });
1654
- for (let update of updates.updates) {
1655
- const bytes = toByteArray(update);
1656
- applyUpdate(doc, bytes);
1657
- }
1658
- const mergedBytes = encodeStateAsUpdate(doc);
1659
- const mergedBase64 = fromByteArray(mergedBytes);
1660
- const permanentReplaceResult = yield store.perm.replaceCurrentUpdates(branch.recordName, branch.inst, branch.branch, mergedBase64, mergedBase64.length);
1661
- if (permanentReplaceResult.success === false) {
1662
- console.error(`[WebsocketController] Failed to replace permanent updates.`, permanentReplaceResult);
1663
- return;
1664
- }
1665
- yield store.temp.addUpdates(branch.recordName, branch.inst, branch.branch, [mergedBase64], mergedBase64.length);
1666
- yield store.temp.trimUpdates(branch.recordName, branch.inst, branch.branch, updateCount);
1667
- yield Promise.all([
1668
- store.temp.addBranchSize(branch.recordName, branch.inst, branch.branch, -size),
1669
- store.temp.addInstSize(branch.recordName, branch.inst, -size),
1670
- ]);
1671
- }
1672
- else {
1673
- console.log(`[WebsocketController] No updates found.`);
1674
- }
1675
- console.log(`[WebsocketController] Updates complete.`);
1676
- });
1677
- }
1678
- sendError(connectionId, requestId, info) {
1679
- return __awaiter(this, void 0, void 0, function* () {
1680
- yield this.sendEvent(connectionId, [
1681
- WebsocketEventTypes.Error,
1682
- requestId,
1683
- info,
2005
+ await store.temp.addUpdates(branch.recordName, branch.inst, branch.branch, [mergedBase64], mergedBase64.length);
2006
+ await store.temp.trimUpdates(branch.recordName, branch.inst, branch.branch, updateCount);
2007
+ await Promise.all([
2008
+ store.temp.addBranchSize(branch.recordName, branch.inst, branch.branch, -size),
2009
+ store.temp.addInstSize(branch.recordName, branch.inst, -size),
1684
2010
  ]);
1685
- });
2011
+ }
2012
+ else {
2013
+ console.log(`[WebsocketController] No updates found.`);
2014
+ }
2015
+ console.log(`[WebsocketController] Updates complete.`);
1686
2016
  }
1687
- sendEvent(connectionId, event) {
1688
- return __awaiter(this, void 0, void 0, function* () {
1689
- yield this._messenger.sendEvent(connectionId, event);
1690
- });
2017
+ async sendError(connectionId, requestId, info) {
2018
+ await this.sendEvent(connectionId, [
2019
+ WebsocketEventTypes.Error,
2020
+ requestId,
2021
+ info,
2022
+ ]);
2023
+ }
2024
+ async sendEvent(connectionId, event) {
2025
+ await this._messenger.sendEvent(connectionId, event);
1691
2026
  }
1692
2027
  }
1693
2028
  __decorate([
@@ -1705,6 +2040,9 @@ __decorate([
1705
2040
  __decorate([
1706
2041
  traced(TRACE_NAME)
1707
2042
  ], WebsocketController.prototype, "addUpdates", null);
2043
+ __decorate([
2044
+ traced(TRACE_NAME)
2045
+ ], WebsocketController.prototype, "addUserUpdates", null);
1708
2046
  __decorate([
1709
2047
  traced(TRACE_NAME)
1710
2048
  ], WebsocketController.prototype, "sendAction", null);
@@ -1738,6 +2076,12 @@ __decorate([
1738
2076
  __decorate([
1739
2077
  traced(TRACE_NAME)
1740
2078
  ], WebsocketController.prototype, "respondToPermissionRequest", null);
2079
+ __decorate([
2080
+ traced(TRACE_NAME)
2081
+ ], WebsocketController.prototype, "installPackage", null);
2082
+ __decorate([
2083
+ traced(TRACE_NAME)
2084
+ ], WebsocketController.prototype, "listInstalledPackages", null);
1741
2085
  __decorate([
1742
2086
  traced(TRACE_NAME)
1743
2087
  ], WebsocketController.prototype, "syncTime", null);