@casual-simulation/aux-records 3.4.6-alpha.14668890889 → 3.5.0-alpha.15117651144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AIController.js +835 -890
- package/AIController.js.map +1 -1
- package/AIHumeInterface.js +43 -54
- package/AIHumeInterface.js.map +1 -1
- package/AIOpenAIRealtimeInterface.js +60 -71
- package/AIOpenAIRealtimeInterface.js.map +1 -1
- package/AnthropicAIChatInterface.js +96 -142
- package/AnthropicAIChatInterface.js.map +1 -1
- package/AuthController.d.ts +3 -2
- package/AuthController.js +1907 -1933
- package/AuthController.js.map +1 -1
- package/AuthStore.d.ts +1 -10
- package/BlockadeLabsGenerateSkyboxInterface.js +57 -72
- package/BlockadeLabsGenerateSkyboxInterface.js.map +1 -1
- package/CachingConfigStore.js +30 -45
- package/CachingConfigStore.js.map +1 -1
- package/CachingPolicyStore.d.ts +8 -2
- package/CachingPolicyStore.js +108 -135
- package/CachingPolicyStore.js.map +1 -1
- package/ComIdConfig.d.ts +18 -18
- package/ComIdConfig.js.map +1 -1
- package/ConsoleAuthMessenger.js +7 -20
- package/ConsoleAuthMessenger.js.map +1 -1
- package/DataRecordsController.d.ts +2 -2
- package/DataRecordsController.js +369 -377
- package/DataRecordsController.js.map +1 -1
- package/DataRecordsStore.d.ts +1 -1
- package/DataRecordsStore.js +1 -1
- package/DataRecordsStore.js.map +1 -1
- package/EventRecordsController.js +226 -240
- package/EventRecordsController.js.map +1 -1
- package/FileRecordsController.d.ts +13 -2
- package/FileRecordsController.js +458 -450
- package/FileRecordsController.js.map +1 -1
- package/GoogleAIChatInterface.js +133 -179
- package/GoogleAIChatInterface.js.map +1 -1
- package/LivekitController.js +43 -54
- package/LivekitController.js.map +1 -1
- package/LoomController.js +64 -75
- package/LoomController.js.map +1 -1
- package/MemoryAuthMessenger.js +10 -23
- package/MemoryAuthMessenger.js.map +1 -1
- package/MemoryCache.js +18 -35
- package/MemoryCache.js.map +1 -1
- package/MemoryFileRecordsLookup.js +105 -125
- package/MemoryFileRecordsLookup.js.map +1 -1
- package/MemoryModerationJobProvider.js +17 -30
- package/MemoryModerationJobProvider.js.map +1 -1
- package/MemoryRateLimiter.js +12 -27
- package/MemoryRateLimiter.js.map +1 -1
- package/MemoryStore.d.ts +18 -6
- package/MemoryStore.js +1879 -1997
- package/MemoryStore.js.map +1 -1
- package/MetricsStore.d.ts +2 -2
- package/ModerationController.js +186 -200
- package/ModerationController.js.map +1 -1
- package/OpenAIChatInterface.js +105 -135
- package/OpenAIChatInterface.js.map +1 -1
- package/OpenAIImageInterface.js +57 -51
- package/OpenAIImageInterface.js.map +1 -1
- package/PolicyController.d.ts +150 -10
- package/PolicyController.js +1546 -1299
- package/PolicyController.js.map +1 -1
- package/PolicyStore.d.ts +110 -2
- package/PolicyStore.js +36 -1
- package/PolicyStore.js.map +1 -1
- package/PrivoClient.js +398 -435
- package/PrivoClient.js.map +1 -1
- package/RateLimitController.js +25 -36
- package/RateLimitController.js.map +1 -1
- package/RecordsClient.js +51 -74
- package/RecordsClient.js.map +1 -1
- package/RecordsController.d.ts +2 -42
- package/RecordsController.js +1026 -1182
- package/RecordsController.js.map +1 -1
- package/RecordsServer.d.ts +196 -27
- package/RecordsServer.js +1701 -1343
- package/RecordsServer.js.map +1 -1
- package/RecordsStore.d.ts +1 -10
- package/RecordsStore.js.map +1 -1
- package/ServerConfig.d.ts +339 -195
- package/ServerConfig.js +13 -0
- package/ServerConfig.js.map +1 -1
- package/SloydInterface.js +62 -75
- package/SloydInterface.js.map +1 -1
- package/StabilityAIImageInterface.js +150 -167
- package/StabilityAIImageInterface.js.map +1 -1
- package/SubscriptionConfigBuilder.d.ts +6 -1
- package/SubscriptionConfigBuilder.js +22 -0
- package/SubscriptionConfigBuilder.js.map +1 -1
- package/SubscriptionConfiguration.d.ts +266 -169
- package/SubscriptionConfiguration.js +101 -79
- package/SubscriptionConfiguration.js.map +1 -1
- package/SubscriptionController.d.ts +2 -1
- package/SubscriptionController.js +643 -650
- package/SubscriptionController.js.map +1 -1
- package/SystemNotificationMessenger.d.ts +21 -4
- package/SystemNotificationMessenger.js +36 -30
- package/SystemNotificationMessenger.js.map +1 -1
- package/TestUtils.d.ts +9 -1
- package/TestUtils.js +105 -129
- package/TestUtils.js.map +1 -1
- package/Utils.d.ts +2 -16
- package/Utils.js +21 -22
- package/Utils.js.map +1 -1
- package/crud/CrudHelpers.js +17 -26
- package/crud/CrudHelpers.js.map +1 -1
- package/crud/CrudRecordsController.d.ts +1 -1
- package/crud/CrudRecordsController.js +259 -267
- package/crud/CrudRecordsController.js.map +1 -1
- package/crud/CrudRecordsControllerTests.js +174 -185
- package/crud/CrudRecordsControllerTests.js.map +1 -1
- package/crud/CrudRecordsStore.d.ts +7 -3
- package/crud/MemoryCrudRecordsStore.d.ts +4 -4
- package/crud/MemoryCrudRecordsStore.js +98 -118
- package/crud/MemoryCrudRecordsStore.js.map +1 -1
- package/crud/sub/MemorySubCrudRecordsStore.d.ts +24 -0
- package/crud/sub/MemorySubCrudRecordsStore.js +146 -0
- package/crud/sub/MemorySubCrudRecordsStore.js.map +1 -0
- package/crud/sub/SubCrudRecordsController.d.ts +182 -0
- package/crud/sub/SubCrudRecordsController.js +360 -0
- package/crud/sub/SubCrudRecordsController.js.map +1 -0
- package/crud/sub/SubCrudRecordsControllerTests.d.ts +39 -0
- package/crud/sub/SubCrudRecordsControllerTests.js +821 -0
- package/crud/sub/SubCrudRecordsControllerTests.js.map +1 -0
- package/crud/sub/SubCrudRecordsStore.d.ts +95 -0
- package/{forms/index.js → crud/sub/SubCrudRecordsStore.js} +2 -2
- package/crud/sub/SubCrudRecordsStore.js.map +1 -0
- package/crud/sub/index.d.ts +3 -0
- package/crud/sub/index.js +20 -0
- package/{forms → crud/sub}/index.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/notifications/MemoryNotificationRecordsStore.js +189 -198
- package/notifications/MemoryNotificationRecordsStore.js.map +1 -1
- package/notifications/NotificationRecordsController.js +438 -460
- package/notifications/NotificationRecordsController.js.map +1 -1
- package/notifications/NotificationRecordsStore.d.ts +2 -1
- package/notifications/WebPushInterface.d.ts +0 -1
- package/notifications/WebPushInterface.js +0 -1
- package/notifications/WebPushInterface.js.map +1 -1
- package/package.json +6 -6
- package/packages/MemoryPackageRecordsStore.d.ts +10 -0
- package/packages/MemoryPackageRecordsStore.js +38 -0
- package/packages/MemoryPackageRecordsStore.js.map +1 -0
- package/packages/PackageRecordsController.d.ts +26 -0
- package/packages/PackageRecordsController.js +49 -0
- package/packages/PackageRecordsController.js.map +1 -0
- package/packages/PackageRecordsStore.d.ts +32 -0
- package/packages/PackageRecordsStore.js +19 -0
- package/packages/PackageRecordsStore.js.map +1 -0
- package/packages/index.d.ts +4 -0
- package/packages/index.js +21 -0
- package/packages/index.js.map +1 -0
- package/packages/version/MemoryPackageVersionRecordsStore.d.ts +21 -0
- package/packages/version/MemoryPackageVersionRecordsStore.js +177 -0
- package/packages/version/MemoryPackageVersionRecordsStore.js.map +1 -0
- package/packages/version/PackageVersionRecordsController.d.ts +144 -0
- package/packages/version/PackageVersionRecordsController.js +656 -0
- package/packages/version/PackageVersionRecordsController.js.map +1 -0
- package/packages/version/PackageVersionRecordsStore.d.ts +342 -0
- package/packages/version/PackageVersionRecordsStore.js +126 -0
- package/packages/version/PackageVersionRecordsStore.js.map +1 -0
- package/packages/version/index.d.ts +4 -0
- package/packages/version/index.js +21 -0
- package/packages/version/index.js.map +1 -0
- package/tracing/TracingDecorators.js +31 -40
- package/tracing/TracingDecorators.js.map +1 -1
- package/webhooks/MemoryWebhookRecordsStore.js +56 -72
- package/webhooks/MemoryWebhookRecordsStore.js.map +1 -1
- package/webhooks/WebhookEnvironment.d.ts +3 -3
- package/webhooks/WebhookRecordsController.d.ts +2 -1
- package/webhooks/WebhookRecordsController.js +389 -382
- package/webhooks/WebhookRecordsController.js.map +1 -1
- package/webhooks/WebhookRecordsStore.d.ts +2 -1
- package/websockets/InstRecordsStore.d.ts +50 -0
- package/websockets/InstRecordsStore.js +17 -0
- package/websockets/InstRecordsStore.js.map +1 -1
- package/websockets/MemoryTempInstRecordsStore.d.ts +5 -0
- package/websockets/MemoryTempInstRecordsStore.js +168 -179
- package/websockets/MemoryTempInstRecordsStore.js.map +1 -1
- package/websockets/MemoryWebsocketConnectionStore.js +98 -135
- package/websockets/MemoryWebsocketConnectionStore.js.map +1 -1
- package/websockets/MemoryWebsocketMessenger.js +29 -48
- package/websockets/MemoryWebsocketMessenger.js.map +1 -1
- package/websockets/SplitInstRecordsStore.d.ts +4 -1
- package/websockets/SplitInstRecordsStore.js +167 -185
- package/websockets/SplitInstRecordsStore.js.map +1 -1
- package/websockets/TemporaryInstRecordsStore.d.ts +19 -1
- package/websockets/TemporaryInstRecordsStore.js +17 -0
- package/websockets/TemporaryInstRecordsStore.js.map +1 -1
- package/websockets/WebsocketController.d.ts +147 -3
- package/websockets/WebsocketController.js +1735 -1391
- package/websockets/WebsocketController.js.map +1 -1
- package/websockets/index.d.ts +0 -1
- package/websockets/index.js +0 -1
- package/websockets/index.js.map +1 -1
- package/AAGUID.d.ts +0 -11
- package/AAGUID.js +0 -116
- package/AAGUID.js.map +0 -1
- package/AuthUtils.d.ts +0 -162
- package/AuthUtils.js +0 -327
- package/AuthUtils.js.map +0 -1
- package/forms/FormError.d.ts +0 -43
- package/forms/FormError.js +0 -56
- package/forms/FormError.js.map +0 -1
- package/forms/index.d.ts +0 -2
- package/websockets/Utils.d.ts +0 -33
- package/websockets/Utils.js +0 -82
- package/websockets/Utils.js.map +0 -1
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
/* CasualOS is a set of web-based tools designed to facilitate the creation of real-time, multi-user, context-aware interactive experiences.
|
|
2
|
+
*
|
|
3
|
+
* Copyright (c) 2019-2025 Casual Simulation, Inc.
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as
|
|
7
|
+
* published by the Free Software Foundation, either version 3 of the
|
|
8
|
+
* License, or (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU Affero General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
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;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
import { PRIVATE_MARKER, isPackageReviewerRole, } from '@casual-simulation/aux-common';
|
|
25
|
+
import { getMarkerResourcesForCreation, getMarkerResourcesForUpdate, } from '../../PolicyController';
|
|
26
|
+
import { getPackageFeatures } from '../../SubscriptionConfiguration';
|
|
27
|
+
import { getHash } from '@casual-simulation/crypto';
|
|
28
|
+
import { traced } from '../../tracing/TracingDecorators';
|
|
29
|
+
import { SpanStatusCode, trace } from '@opentelemetry/api';
|
|
30
|
+
import { v7 as uuid } from 'uuid';
|
|
31
|
+
import { isEqual } from 'lodash';
|
|
32
|
+
const TRACE_NAME = 'PackageVersionRecordsController';
|
|
33
|
+
/**
|
|
34
|
+
* Defines a controller that can be used to interact with NotificationRecords.
|
|
35
|
+
*/
|
|
36
|
+
export class PackageVersionRecordsController {
|
|
37
|
+
get store() {
|
|
38
|
+
return this._store;
|
|
39
|
+
}
|
|
40
|
+
get config() {
|
|
41
|
+
return this._config;
|
|
42
|
+
}
|
|
43
|
+
get policies() {
|
|
44
|
+
return this._policies;
|
|
45
|
+
}
|
|
46
|
+
get files() {
|
|
47
|
+
return this._files;
|
|
48
|
+
}
|
|
49
|
+
constructor(config) {
|
|
50
|
+
this._name = 'PackageVersionRecordsController';
|
|
51
|
+
this._store = config.store;
|
|
52
|
+
this._recordStore = config.recordItemStore;
|
|
53
|
+
this._policies = config.policies;
|
|
54
|
+
this._packages = config.packages;
|
|
55
|
+
this._config = config.config;
|
|
56
|
+
this._files = config.files;
|
|
57
|
+
this._systemNotifications = config.systemNotifications;
|
|
58
|
+
this._resourceKind = 'package.version';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Creates or updates an item in the given record.
|
|
62
|
+
* @param request The request.
|
|
63
|
+
*/
|
|
64
|
+
async recordItem(request) {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
try {
|
|
67
|
+
const contextResult = await this._policies.constructAuthorizationContext({
|
|
68
|
+
recordKeyOrRecordName: request.recordKeyOrRecordName,
|
|
69
|
+
userId: request.userId,
|
|
70
|
+
});
|
|
71
|
+
if (contextResult.success === false) {
|
|
72
|
+
return contextResult;
|
|
73
|
+
}
|
|
74
|
+
const recordName = contextResult.context.recordName;
|
|
75
|
+
const existingItem = await this._store.getItemByKey(recordName, request.item.address, request.item.key);
|
|
76
|
+
let parentMarkers;
|
|
77
|
+
if (!existingItem.parentMarkers) {
|
|
78
|
+
console.log(`[${this._name}] Parent package not found.`);
|
|
79
|
+
parentMarkers = [PRIVATE_MARKER];
|
|
80
|
+
const result = await this._packages.recordItem({
|
|
81
|
+
userId: request.userId,
|
|
82
|
+
recordKeyOrRecordName: recordName,
|
|
83
|
+
instances: request.instances,
|
|
84
|
+
item: {
|
|
85
|
+
address: request.item.address,
|
|
86
|
+
markers: parentMarkers,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
if (result.success === false) {
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(`[${this._name}] Created parent package ${request.item.address}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
parentMarkers = existingItem.parentMarkers;
|
|
98
|
+
}
|
|
99
|
+
let resourceMarkers;
|
|
100
|
+
let action = existingItem.item
|
|
101
|
+
? 'update'
|
|
102
|
+
: 'create';
|
|
103
|
+
let authorization;
|
|
104
|
+
if (action === 'update') {
|
|
105
|
+
const existingMarkers = existingItem.item.markers;
|
|
106
|
+
resourceMarkers = (_a = request.item.markers) !== null && _a !== void 0 ? _a : existingMarkers;
|
|
107
|
+
// resourceMarkers = existingItem.item.markers;
|
|
108
|
+
action = 'update';
|
|
109
|
+
authorization =
|
|
110
|
+
await this._policies.authorizeUserAndInstancesForResources(contextResult.context, {
|
|
111
|
+
userId: request.userId,
|
|
112
|
+
instances: request.instances,
|
|
113
|
+
resources: [
|
|
114
|
+
{
|
|
115
|
+
resourceKind: this._resourceKind,
|
|
116
|
+
resourceId: existingItem.item.address,
|
|
117
|
+
action: action,
|
|
118
|
+
markers: resourceMarkers,
|
|
119
|
+
},
|
|
120
|
+
...getMarkerResourcesForUpdate(existingMarkers, resourceMarkers),
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
if (authorization.success === false) {
|
|
124
|
+
return authorization;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// TODO: Allow these markers to be inherited from the parent package.
|
|
129
|
+
// When the markers are inherited, then the user shouldn't need permission to assign them.
|
|
130
|
+
let usingGivenMarkers = true;
|
|
131
|
+
resourceMarkers = request.item.markers;
|
|
132
|
+
if (!resourceMarkers) {
|
|
133
|
+
resourceMarkers = parentMarkers;
|
|
134
|
+
usingGivenMarkers = false;
|
|
135
|
+
}
|
|
136
|
+
let resources = [
|
|
137
|
+
{
|
|
138
|
+
resourceKind: this._resourceKind,
|
|
139
|
+
resourceId: request.item.address,
|
|
140
|
+
action: action,
|
|
141
|
+
markers: resourceMarkers,
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
if (!usingGivenMarkers) {
|
|
145
|
+
resources.push(...getMarkerResourcesForCreation(resourceMarkers));
|
|
146
|
+
}
|
|
147
|
+
// TODO: Make sure that whenever the user is selecting markers that they also have permissions to
|
|
148
|
+
// assign the markers they are selecting.
|
|
149
|
+
authorization =
|
|
150
|
+
await this._policies.authorizeUserAndInstancesForResources(contextResult.context, {
|
|
151
|
+
userId: request.userId,
|
|
152
|
+
instances: request.instances,
|
|
153
|
+
resources,
|
|
154
|
+
});
|
|
155
|
+
if (authorization.success === false) {
|
|
156
|
+
return authorization;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!resourceMarkers || resourceMarkers.length <= 0) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
errorCode: 'invalid_request',
|
|
163
|
+
errorMessage: 'The item must have markers.',
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const subscriptionResult = await this._checkSubscriptionMetrics(action, contextResult.context, authorization, request.item);
|
|
167
|
+
if (subscriptionResult.success === false) {
|
|
168
|
+
return subscriptionResult;
|
|
169
|
+
}
|
|
170
|
+
if (action === 'update') {
|
|
171
|
+
const sizeInBytes = request.item.auxFileRequest.fileByteLength;
|
|
172
|
+
const fileName = existingItem.item.auxFileName;
|
|
173
|
+
const sha256 = getHash({
|
|
174
|
+
auxFileName: fileName,
|
|
175
|
+
auxSha256: request.item.auxFileRequest.fileSha256Hex,
|
|
176
|
+
createdAtMs: existingItem.item.createdAtMs,
|
|
177
|
+
entitlements: request.item.entitlements,
|
|
178
|
+
description: request.item.description,
|
|
179
|
+
sizeInBytes: sizeInBytes,
|
|
180
|
+
});
|
|
181
|
+
if (sha256 !== existingItem.item.sha256) {
|
|
182
|
+
return {
|
|
183
|
+
success: false,
|
|
184
|
+
errorCode: 'not_supported',
|
|
185
|
+
errorMessage: 'Updating package versions is not supported.',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// TODO: File records should always be private if the system is creating them
|
|
190
|
+
// so that the file can only be accessed via the package version API unless the user has access
|
|
191
|
+
// to private items.
|
|
192
|
+
//record file
|
|
193
|
+
let recordFileResult = await this.files.recordFile(recordName, null, {
|
|
194
|
+
...request.item.auxFileRequest,
|
|
195
|
+
markers: [PRIVATE_MARKER],
|
|
196
|
+
instances: request.instances,
|
|
197
|
+
userRole: 'system',
|
|
198
|
+
});
|
|
199
|
+
if (recordFileResult.success === false) {
|
|
200
|
+
if (recordFileResult.errorCode === 'file_already_exists') {
|
|
201
|
+
// Retry the request to see if the user has the ability to upload to a file record
|
|
202
|
+
// that has already been made but may not yet be uploaded.
|
|
203
|
+
// If the file record has been made, but not uplaoded, then this will succeed.
|
|
204
|
+
recordFileResult = await this.files.recordFile(recordName, contextResult.context.userId, {
|
|
205
|
+
...request.item.auxFileRequest,
|
|
206
|
+
markers: resourceMarkers,
|
|
207
|
+
instances: request.instances,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (recordFileResult.success === false &&
|
|
211
|
+
recordFileResult.errorCode !== 'file_already_exists') {
|
|
212
|
+
return recordFileResult;
|
|
213
|
+
// if (recordFileResult.errorCode === 'file_already_exists') {
|
|
214
|
+
// // TODO:
|
|
215
|
+
// // If the file already exists and has already been uploaded, then
|
|
216
|
+
// // we should see if we need to update the file record markers to match the package version markers.
|
|
217
|
+
// // if(recordFileResult.existingFileName) {
|
|
218
|
+
// // }
|
|
219
|
+
// } else {
|
|
220
|
+
// return recordFileResult;
|
|
221
|
+
// }
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else if (!isEqual(recordFileResult.markers, [PRIVATE_MARKER])) {
|
|
225
|
+
// System is able to upload the file, but the file record has already been made with different markers and not uploaded.
|
|
226
|
+
// In this case, we want to retry the request but with the user so that we can be sure the user has permission to upload the file.
|
|
227
|
+
// Retry the request to see if the user has the ability to upload to a file record
|
|
228
|
+
// that has already been made but may not yet be uploaded.
|
|
229
|
+
// If the file record has been made, but not uplaoded, then this will succeed.
|
|
230
|
+
recordFileResult = await this.files.recordFile(recordName, contextResult.context.userId, {
|
|
231
|
+
...request.item.auxFileRequest,
|
|
232
|
+
markers: resourceMarkers,
|
|
233
|
+
instances: request.instances,
|
|
234
|
+
});
|
|
235
|
+
if (recordFileResult.success === false &&
|
|
236
|
+
recordFileResult.errorCode !== 'file_already_exists') {
|
|
237
|
+
return recordFileResult;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const address = request.item.address;
|
|
241
|
+
let item;
|
|
242
|
+
if (action === 'create') {
|
|
243
|
+
const createdAtMs = Date.now();
|
|
244
|
+
const sizeInBytes = request.item.auxFileRequest.fileByteLength;
|
|
245
|
+
const fileName = recordFileResult.success === true
|
|
246
|
+
? recordFileResult.fileName
|
|
247
|
+
: recordFileResult.existingFileName;
|
|
248
|
+
if (!fileName) {
|
|
249
|
+
throw new Error('Unable to determine file name for package');
|
|
250
|
+
}
|
|
251
|
+
const sha256 = getHash({
|
|
252
|
+
auxFileName: fileName,
|
|
253
|
+
auxSha256: request.item.auxFileRequest.fileSha256Hex,
|
|
254
|
+
createdAtMs: createdAtMs,
|
|
255
|
+
entitlements: request.item.entitlements,
|
|
256
|
+
description: request.item.description,
|
|
257
|
+
sizeInBytes: sizeInBytes,
|
|
258
|
+
});
|
|
259
|
+
item = {
|
|
260
|
+
id: uuid(),
|
|
261
|
+
address: address,
|
|
262
|
+
entitlements: request.item.entitlements,
|
|
263
|
+
key: request.item.key,
|
|
264
|
+
description: request.item.description,
|
|
265
|
+
auxFileName: fileName,
|
|
266
|
+
auxSha256: request.item.auxFileRequest.fileSha256Hex,
|
|
267
|
+
sha256,
|
|
268
|
+
sizeInBytes,
|
|
269
|
+
createdAtMs,
|
|
270
|
+
createdFile: recordFileResult.success,
|
|
271
|
+
requiresReview: request.item.entitlements.some((e) => entitlementRequiresApproval(e)),
|
|
272
|
+
markers: resourceMarkers,
|
|
273
|
+
};
|
|
274
|
+
const crudResult = await this._store.putItem(recordName, item);
|
|
275
|
+
if (crudResult.success === false) {
|
|
276
|
+
return crudResult;
|
|
277
|
+
}
|
|
278
|
+
await ((_b = this._systemNotifications) === null || _b === void 0 ? void 0 : _b.sendRecordNotification({
|
|
279
|
+
resource: 'package_version_publish',
|
|
280
|
+
action: 'created',
|
|
281
|
+
recordName: recordName,
|
|
282
|
+
resourceId: address,
|
|
283
|
+
timeMs: createdAtMs,
|
|
284
|
+
package: item,
|
|
285
|
+
markers: resourceMarkers,
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
item = {
|
|
290
|
+
...existingItem.item,
|
|
291
|
+
markers: resourceMarkers,
|
|
292
|
+
};
|
|
293
|
+
const crudResult = await this._store.putItem(recordName, item);
|
|
294
|
+
if (crudResult.success === false) {
|
|
295
|
+
return crudResult;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
success: true,
|
|
300
|
+
recordName,
|
|
301
|
+
address: item.address,
|
|
302
|
+
auxFileResult: recordFileResult,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
const span = trace.getActiveSpan();
|
|
307
|
+
if (err instanceof Error) {
|
|
308
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
309
|
+
}
|
|
310
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
311
|
+
console.error(`[${this._name}] Error recording item:`, err);
|
|
312
|
+
return {
|
|
313
|
+
success: false,
|
|
314
|
+
errorCode: 'server_error',
|
|
315
|
+
errorMessage: 'A server error occurred.',
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Gets the item with the given address from the given record.
|
|
321
|
+
* @param request The request to get the item.
|
|
322
|
+
*/
|
|
323
|
+
async getItem(request) {
|
|
324
|
+
var _a, _b;
|
|
325
|
+
try {
|
|
326
|
+
const baseRequest = {
|
|
327
|
+
recordKeyOrRecordName: request.recordName,
|
|
328
|
+
userId: request.userId,
|
|
329
|
+
instances: request.instances,
|
|
330
|
+
};
|
|
331
|
+
const context = await this._policies.constructAuthorizationContext(baseRequest);
|
|
332
|
+
if (context.success === false) {
|
|
333
|
+
return context;
|
|
334
|
+
}
|
|
335
|
+
const result = await this._store.getItemBySpecifier(context.context.recordName, request.address, request.key);
|
|
336
|
+
if (!result.item) {
|
|
337
|
+
return {
|
|
338
|
+
success: false,
|
|
339
|
+
errorCode: 'data_not_found',
|
|
340
|
+
errorMessage: 'The item was not found.',
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
const markers = result.parentMarkers;
|
|
344
|
+
const authorization = await this._policies.authorizeUserAndInstances(context.context, {
|
|
345
|
+
userId: request.userId,
|
|
346
|
+
instances: request.instances,
|
|
347
|
+
resourceKind: this._resourceKind,
|
|
348
|
+
resourceId: request.address,
|
|
349
|
+
action: 'read',
|
|
350
|
+
markers: markers,
|
|
351
|
+
});
|
|
352
|
+
if (authorization.success === false) {
|
|
353
|
+
return authorization;
|
|
354
|
+
}
|
|
355
|
+
const item = {
|
|
356
|
+
id: result.item.id,
|
|
357
|
+
address: result.item.address,
|
|
358
|
+
key: result.item.key,
|
|
359
|
+
auxFileName: result.item.auxFileName,
|
|
360
|
+
createdAtMs: result.item.createdAtMs,
|
|
361
|
+
auxSha256: result.item.auxSha256,
|
|
362
|
+
createdFile: result.item.createdFile,
|
|
363
|
+
entitlements: result.item.entitlements,
|
|
364
|
+
markers: result.item.markers,
|
|
365
|
+
description: result.item.description,
|
|
366
|
+
requiresReview: result.item.requiresReview,
|
|
367
|
+
sha256: result.item.sha256,
|
|
368
|
+
sizeInBytes: result.item.sizeInBytes,
|
|
369
|
+
packageId: result.packageId,
|
|
370
|
+
approved: true,
|
|
371
|
+
approvalType: 'normal',
|
|
372
|
+
};
|
|
373
|
+
if (item.requiresReview) {
|
|
374
|
+
let review = await this.store.getMostRecentPackageVersionReview(item.id);
|
|
375
|
+
item.approved = (_a = review === null || review === void 0 ? void 0 : review.approved) !== null && _a !== void 0 ? _a : false;
|
|
376
|
+
item.approvalType = (_b = review === null || review === void 0 ? void 0 : review.approvalType) !== null && _b !== void 0 ? _b : null;
|
|
377
|
+
}
|
|
378
|
+
const auxFile = item.createdFile
|
|
379
|
+
? await this.files.readFile(context.context.recordName, item.auxFileName, null, undefined, 'system')
|
|
380
|
+
: await this.files.readFile(context.context.recordName, item.auxFileName, context.context.userId);
|
|
381
|
+
return {
|
|
382
|
+
success: true,
|
|
383
|
+
item: item,
|
|
384
|
+
auxFile,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
const span = trace.getActiveSpan();
|
|
389
|
+
if (err instanceof Error) {
|
|
390
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
391
|
+
}
|
|
392
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
393
|
+
console.error(`[${this._name}] Error getting item:`, err);
|
|
394
|
+
return {
|
|
395
|
+
success: false,
|
|
396
|
+
errorCode: 'server_error',
|
|
397
|
+
errorMessage: 'A server error occurred.',
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Deletes the item with the given address from the given record.
|
|
403
|
+
* @param request The request.
|
|
404
|
+
*/
|
|
405
|
+
async eraseItem(request) {
|
|
406
|
+
try {
|
|
407
|
+
const context = await this._policies.constructAuthorizationContext({
|
|
408
|
+
recordKeyOrRecordName: request.recordName,
|
|
409
|
+
userId: request.userId,
|
|
410
|
+
});
|
|
411
|
+
if (context.success === false) {
|
|
412
|
+
return context;
|
|
413
|
+
}
|
|
414
|
+
const result = await this._store.getItemByKey(context.context.recordName, request.address, request.key);
|
|
415
|
+
if (!result.item || !result.parentMarkers) {
|
|
416
|
+
return {
|
|
417
|
+
success: false,
|
|
418
|
+
errorCode: 'data_not_found',
|
|
419
|
+
errorMessage: 'The item was not found.',
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const markers = result.parentMarkers;
|
|
423
|
+
const authorization = await this._policies.authorizeUserAndInstances(context.context, {
|
|
424
|
+
userId: request.userId,
|
|
425
|
+
instances: request.instances,
|
|
426
|
+
resourceKind: this._resourceKind,
|
|
427
|
+
resourceId: request.address,
|
|
428
|
+
action: 'delete',
|
|
429
|
+
markers,
|
|
430
|
+
});
|
|
431
|
+
if (authorization.success === false) {
|
|
432
|
+
return authorization;
|
|
433
|
+
}
|
|
434
|
+
const recordName = context.context.recordName;
|
|
435
|
+
const subscriptionResult = await this._checkSubscriptionMetrics('delete', context.context, authorization);
|
|
436
|
+
if (subscriptionResult.success === false) {
|
|
437
|
+
return subscriptionResult;
|
|
438
|
+
}
|
|
439
|
+
await this._store.deleteItem(recordName, request.address, request.key);
|
|
440
|
+
return {
|
|
441
|
+
success: true,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
catch (err) {
|
|
445
|
+
const span = trace.getActiveSpan();
|
|
446
|
+
if (err instanceof Error) {
|
|
447
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
448
|
+
}
|
|
449
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
450
|
+
console.error(`[${this._name}] Error erasing item:`, err);
|
|
451
|
+
return {
|
|
452
|
+
success: false,
|
|
453
|
+
errorCode: 'server_error',
|
|
454
|
+
errorMessage: 'A server error occurred.',
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Lists items in the given record.
|
|
460
|
+
* @param request The request.
|
|
461
|
+
*/
|
|
462
|
+
async listItems(request) {
|
|
463
|
+
try {
|
|
464
|
+
const baseRequest = {
|
|
465
|
+
recordKeyOrRecordName: request.recordName,
|
|
466
|
+
userId: request.userId,
|
|
467
|
+
instances: request.instances,
|
|
468
|
+
};
|
|
469
|
+
const context = await this._policies.constructAuthorizationContext(baseRequest);
|
|
470
|
+
if (context.success === false) {
|
|
471
|
+
return context;
|
|
472
|
+
}
|
|
473
|
+
const recordName = context.context.recordName;
|
|
474
|
+
const packageRecord = await this._recordStore.getItemByAddress(recordName, request.address);
|
|
475
|
+
if (!packageRecord) {
|
|
476
|
+
return {
|
|
477
|
+
success: false,
|
|
478
|
+
errorCode: 'data_not_found',
|
|
479
|
+
errorMessage: 'The parent item was not found.',
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
const authorization = await this._policies.authorizeUserAndInstances(context.context, {
|
|
483
|
+
userId: request.userId,
|
|
484
|
+
instances: request.instances,
|
|
485
|
+
resourceKind: this._resourceKind,
|
|
486
|
+
action: 'list',
|
|
487
|
+
markers: packageRecord.markers,
|
|
488
|
+
});
|
|
489
|
+
if (authorization.success === false) {
|
|
490
|
+
return authorization;
|
|
491
|
+
}
|
|
492
|
+
const result2 = await this._store.listItems(context.context.recordName, request.address);
|
|
493
|
+
return {
|
|
494
|
+
success: true,
|
|
495
|
+
recordName: context.context.recordName,
|
|
496
|
+
items: result2.items.map((item) => item),
|
|
497
|
+
totalCount: result2.totalCount,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
catch (err) {
|
|
501
|
+
const span = trace.getActiveSpan();
|
|
502
|
+
if (err instanceof Error) {
|
|
503
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
504
|
+
}
|
|
505
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
506
|
+
console.error(`[${this._name}] Error listing items:`, err);
|
|
507
|
+
return {
|
|
508
|
+
success: false,
|
|
509
|
+
errorCode: 'server_error',
|
|
510
|
+
errorMessage: 'A server error occurred.',
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
async reviewItem(request) {
|
|
515
|
+
var _a;
|
|
516
|
+
try {
|
|
517
|
+
const packageVersion = await this.store.getItemById(request.packageVersionId);
|
|
518
|
+
if (!packageVersion.item || !packageVersion.recordName) {
|
|
519
|
+
return {
|
|
520
|
+
success: false,
|
|
521
|
+
errorCode: 'not_found',
|
|
522
|
+
errorMessage: 'The package version was not found.',
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
const baseRequest = {
|
|
526
|
+
recordKeyOrRecordName: packageVersion.recordName,
|
|
527
|
+
userId: request.userId,
|
|
528
|
+
userRole: request.userRole,
|
|
529
|
+
sendNotLoggedIn: true,
|
|
530
|
+
};
|
|
531
|
+
const context = await this._policies.constructAuthorizationContext(baseRequest);
|
|
532
|
+
if (context.success === false) {
|
|
533
|
+
return context;
|
|
534
|
+
}
|
|
535
|
+
if (!isPackageReviewerRole(context.context.userRole)) {
|
|
536
|
+
return {
|
|
537
|
+
success: false,
|
|
538
|
+
errorCode: 'not_authorized',
|
|
539
|
+
errorMessage: 'You are not authorized to submit reviews for package versions.',
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const now = Date.now();
|
|
543
|
+
const reviewId = (_a = request.review.id) !== null && _a !== void 0 ? _a : uuid();
|
|
544
|
+
const result = await this.store.putReviewForVersion({
|
|
545
|
+
id: reviewId,
|
|
546
|
+
packageVersionId: request.packageVersionId,
|
|
547
|
+
approved: request.review.approved,
|
|
548
|
+
approvalType: request.review.approvalType,
|
|
549
|
+
reviewComments: request.review.reviewComments,
|
|
550
|
+
reviewingUserId: context.context.userId,
|
|
551
|
+
reviewStatus: request.review.reviewStatus,
|
|
552
|
+
createdAtMs: now,
|
|
553
|
+
updatedAtMs: now,
|
|
554
|
+
});
|
|
555
|
+
if (result.success === false) {
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
success: true,
|
|
560
|
+
reviewId: reviewId,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
catch (err) {
|
|
564
|
+
const span = trace.getActiveSpan();
|
|
565
|
+
if (err instanceof Error) {
|
|
566
|
+
span === null || span === void 0 ? void 0 : span.recordException(err);
|
|
567
|
+
}
|
|
568
|
+
span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
|
|
569
|
+
console.error(`[${this._name}] Error reviewing item:`, err);
|
|
570
|
+
return {
|
|
571
|
+
success: false,
|
|
572
|
+
errorCode: 'server_error',
|
|
573
|
+
errorMessage: 'A server error occurred.',
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
async _checkSubscriptionMetrics(action, context, authorization, item) {
|
|
578
|
+
var _a, _b;
|
|
579
|
+
const config = await this.config.getSubscriptionConfiguration();
|
|
580
|
+
const metrics = await this.store.getSubscriptionMetrics({
|
|
581
|
+
ownerId: (_a = context.recordOwnerId) !== null && _a !== void 0 ? _a : undefined,
|
|
582
|
+
studioId: (_b = context.recordStudioId) !== null && _b !== void 0 ? _b : undefined,
|
|
583
|
+
});
|
|
584
|
+
const features = getPackageFeatures(config, metrics.subscriptionStatus, metrics.subscriptionId, metrics.subscriptionType, metrics.currentPeriodStartMs, metrics.currentPeriodEndMs);
|
|
585
|
+
if (!features.allowed) {
|
|
586
|
+
return {
|
|
587
|
+
success: false,
|
|
588
|
+
errorCode: 'not_authorized',
|
|
589
|
+
errorMessage: 'Packages are not allowed for this subscription.',
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
if (action === 'create') {
|
|
593
|
+
if (typeof features.maxPackageVersions === 'number') {
|
|
594
|
+
if (metrics.totalItems >= features.maxPackageVersions) {
|
|
595
|
+
return {
|
|
596
|
+
success: false,
|
|
597
|
+
errorCode: 'subscription_limit_reached',
|
|
598
|
+
errorMessage: 'The maximum number of package versions has been reached for your subscription.',
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (typeof features.maxPackageVersionSizeInBytes === 'number' &&
|
|
603
|
+
item &&
|
|
604
|
+
item.auxFileRequest.fileByteLength >=
|
|
605
|
+
features.maxPackageVersionSizeInBytes) {
|
|
606
|
+
return {
|
|
607
|
+
success: false,
|
|
608
|
+
errorCode: 'subscription_limit_reached',
|
|
609
|
+
errorMessage: 'The package version is too large for your subscription.',
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
if (action === 'create' &&
|
|
613
|
+
typeof features.maxPackageBytesTotal === 'number') {
|
|
614
|
+
if (item &&
|
|
615
|
+
metrics.totalPackageVersionBytes +
|
|
616
|
+
item.auxFileRequest.fileByteLength >=
|
|
617
|
+
features.maxPackageBytesTotal) {
|
|
618
|
+
return {
|
|
619
|
+
success: false,
|
|
620
|
+
errorCode: 'subscription_limit_reached',
|
|
621
|
+
errorMessage: 'The maximum size of package versions has been reached for your subscription.',
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return {
|
|
627
|
+
success: true,
|
|
628
|
+
config,
|
|
629
|
+
metrics,
|
|
630
|
+
features,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
__decorate([
|
|
635
|
+
traced(TRACE_NAME)
|
|
636
|
+
], PackageVersionRecordsController.prototype, "recordItem", null);
|
|
637
|
+
__decorate([
|
|
638
|
+
traced(TRACE_NAME)
|
|
639
|
+
], PackageVersionRecordsController.prototype, "getItem", null);
|
|
640
|
+
__decorate([
|
|
641
|
+
traced(TRACE_NAME)
|
|
642
|
+
], PackageVersionRecordsController.prototype, "eraseItem", null);
|
|
643
|
+
__decorate([
|
|
644
|
+
traced(TRACE_NAME)
|
|
645
|
+
], PackageVersionRecordsController.prototype, "listItems", null);
|
|
646
|
+
__decorate([
|
|
647
|
+
traced(TRACE_NAME)
|
|
648
|
+
], PackageVersionRecordsController.prototype, "reviewItem", null);
|
|
649
|
+
/**
|
|
650
|
+
* Determines whether the given entitlement requires approval.
|
|
651
|
+
* @param entitlement The entitlement to test.
|
|
652
|
+
*/
|
|
653
|
+
export function entitlementRequiresApproval(entitlement) {
|
|
654
|
+
return entitlement.scope === 'shared' || entitlement.scope === 'designated';
|
|
655
|
+
}
|
|
656
|
+
//# sourceMappingURL=PackageVersionRecordsController.js.map
|