@dcl/sdk 7.25.1-30310486734.commit-5ffe873 → 7.25.1-30365680769.commit-9c1b99d

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 (78) hide show
  1. package/composite-provider.js +4 -9
  2. package/internal/utf8.d.ts +15 -0
  3. package/internal/utf8.js +172 -0
  4. package/network/binary-message-bus.d.ts +3 -6
  5. package/network/binary-message-bus.js +5 -9
  6. package/network/index.d.ts +2 -8
  7. package/network/index.js +3 -16
  8. package/network/message-bus-sync.d.ts +1 -14
  9. package/network/message-bus-sync.js +103 -161
  10. package/network/state.js +5 -3
  11. package/package.json +6 -7
  12. package/src/composite-provider.ts +3 -10
  13. package/src/internal/utf8.ts +167 -0
  14. package/src/network/binary-message-bus.ts +4 -9
  15. package/src/network/index.ts +3 -40
  16. package/src/network/message-bus-sync.ts +110 -174
  17. package/src/network/state.ts +4 -3
  18. package/src/text-codec.ts +59 -12
  19. package/text-codec.d.ts +23 -8
  20. package/text-codec.js +55 -13
  21. package/atom.d.ts +0 -19
  22. package/atom.js +0 -83
  23. package/future.d.ts +0 -8
  24. package/future.js +0 -26
  25. package/network/chunking.d.ts +0 -5
  26. package/network/chunking.js +0 -38
  27. package/network/events/implementation.d.ts +0 -93
  28. package/network/events/implementation.js +0 -221
  29. package/network/events/index.d.ts +0 -42
  30. package/network/events/index.js +0 -43
  31. package/network/events/protocol.d.ts +0 -27
  32. package/network/events/protocol.js +0 -66
  33. package/network/events/registry.d.ts +0 -8
  34. package/network/events/registry.js +0 -3
  35. package/network/server/index.d.ts +0 -14
  36. package/network/server/index.js +0 -219
  37. package/network/server/utils.d.ts +0 -18
  38. package/network/server/utils.js +0 -135
  39. package/server/env-var.d.ts +0 -15
  40. package/server/env-var.js +0 -31
  41. package/server/index.d.ts +0 -2
  42. package/server/index.js +0 -3
  43. package/server/storage/constants.d.ts +0 -79
  44. package/server/storage/constants.js +0 -19
  45. package/server/storage/index.d.ts +0 -45
  46. package/server/storage/index.js +0 -51
  47. package/server/storage/player.d.ts +0 -45
  48. package/server/storage/player.js +0 -198
  49. package/server/storage/scene.d.ts +0 -40
  50. package/server/storage/scene.js +0 -188
  51. package/server/storage/value-cache.d.ts +0 -1
  52. package/server/storage/value-cache.js +0 -52
  53. package/server/storage/write-queue.d.ts +0 -1
  54. package/server/storage/write-queue.js +0 -71
  55. package/server/storage-url.d.ts +0 -13
  56. package/server/storage-url.js +0 -42
  57. package/server/utils.d.ts +0 -35
  58. package/server/utils.js +0 -61
  59. package/src/atom.ts +0 -98
  60. package/src/ethereum-provider/text-encoding.d.ts +0 -4
  61. package/src/future.ts +0 -38
  62. package/src/network/chunking.ts +0 -45
  63. package/src/network/events/implementation.ts +0 -271
  64. package/src/network/events/index.ts +0 -48
  65. package/src/network/events/protocol.ts +0 -94
  66. package/src/network/events/registry.ts +0 -18
  67. package/src/network/server/index.ts +0 -301
  68. package/src/network/server/utils.ts +0 -189
  69. package/src/server/env-var.ts +0 -36
  70. package/src/server/index.ts +0 -12
  71. package/src/server/storage/constants.ts +0 -111
  72. package/src/server/storage/index.ts +0 -74
  73. package/src/server/storage/player.ts +0 -289
  74. package/src/server/storage/scene.ts +0 -270
  75. package/src/server/storage/value-cache.ts +0 -92
  76. package/src/server/storage/write-queue.ts +0 -131
  77. package/src/server/storage-url.ts +0 -49
  78. package/src/server/utils.ts +0 -76
@@ -1,219 +0,0 @@
1
- import { CrdtMessageType, ProcessMessageResultType, PutNetworkComponentOperation } from '@dcl/ecs';
2
- import * as components from '@dcl/ecs/dist/components';
3
- import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer';
4
- import { CommsMessage } from '../binary-message-bus';
5
- import { chunkCrdtMessages } from '../chunking';
6
- import * as utils from './utils';
7
- import { AUTH_SERVER_PEER_ID, DEBUG_NETWORK_MESSAGES } from '../message-bus-sync';
8
- export const LIVEKIT_MAX_SIZE = 12;
9
- export function createServerValidator(config) {
10
- const { engine, binaryMessageBus } = config;
11
- // Initialize components for network operations and transform fixing
12
- const NetworkEntity = components.NetworkEntity(engine);
13
- const CreatedBy = components.CreatedBy(engine);
14
- const NetworkParent = components.NetworkParent(engine);
15
- // Type guard to check if component supports corrections (both LWW and GrowOnlySet)
16
- function supportsCorrections(component) {
17
- return ((component.componentType === 0 /* ComponentType.LastWriteWinElementSet */ ||
18
- component.componentType === 1 /* ComponentType.GrowOnlyValueSet */) &&
19
- 'getCrdtState' in component);
20
- }
21
- function findExistingNetworkEntity(message) {
22
- // Look for existing network entity mapping (don't create new ones)
23
- for (const [entityId, networkData] of engine.getEntitiesWith(NetworkEntity)) {
24
- if (networkData.networkId === message.networkId && networkData.entityId === message.entityId) {
25
- return entityId;
26
- }
27
- }
28
- // Return null if not found
29
- return null;
30
- }
31
- function findOrCreateNetworkEntity(message, sender, isServer) {
32
- // Look for existing network entity mapping first
33
- const existingEntity = findExistingNetworkEntity(message);
34
- if (existingEntity) {
35
- return existingEntity;
36
- }
37
- // Create new entity and network mapping
38
- const newEntityId = engine.addEntity();
39
- NetworkEntity.createOrReplace(newEntityId, {
40
- networkId: message.networkId,
41
- entityId: message.entityId
42
- });
43
- if (isServer) {
44
- CreatedBy.createOrReplace(newEntityId, { address: sender });
45
- }
46
- DEBUG_NETWORK_MESSAGES() &&
47
- console.log(`[DEBUG] Created new entity ${newEntityId} for network ${message.networkId}:${message.entityId}`);
48
- return newEntityId;
49
- }
50
- function convertNetworkToRegularMessage(networkMessage, localEntityId, forceCorrections = false) {
51
- const buffer = new ReadWriteByteBuffer();
52
- try {
53
- // Use the well-tested networkMessageToLocal utility with transform fixing for Unity
54
- const message = utils.networkMessageToLocal(networkMessage, localEntityId, buffer, NetworkParent, forceCorrections);
55
- return { ...message, messageBuffer: buffer.toBinary() };
56
- }
57
- catch (error) {
58
- DEBUG_NETWORK_MESSAGES() && console.error('Error converting network message:', error);
59
- return null;
60
- }
61
- }
62
- function validateMessagePermissions(message, sender, _localEntityId) {
63
- // Basic checks
64
- if (!sender || sender === AUTH_SERVER_PEER_ID) {
65
- return false; // Server shouldn't send messages to itself
66
- }
67
- if (message.type === CrdtMessageType.DELETE_ENTITY) {
68
- // TODO: how to handle this case ?
69
- }
70
- if (message.type === CrdtMessageType.PUT_COMPONENT || message.type === CrdtMessageType.DELETE_COMPONENT) {
71
- const component = engine.getComponent(message.componentId);
72
- const buf = 'data' in message ? new ReadWriteByteBuffer(message.data) : null;
73
- const value = buf ? component.schema.deserialize(buf) : null;
74
- const dryRunCRDT = component.__dry_run_updateFromCrdt(message);
75
- const validCRDT = [
76
- ProcessMessageResultType.StateUpdatedData,
77
- ProcessMessageResultType.StateUpdatedTimestamp,
78
- ProcessMessageResultType.EntityDeleted
79
- ].includes(dryRunCRDT);
80
- const createdBy = CreatedBy.getOrNull(message.entityId);
81
- const validMessage = validCRDT &&
82
- component.__run_validateBeforeChange(message.entityId, value, sender, createdBy?.address ?? AUTH_SERVER_PEER_ID);
83
- return !!validMessage;
84
- }
85
- // For now, basic validation - in the future this will check component sync permissions
86
- // TODO: Check if sender owns the entity
87
- // TODO: Check component sync mode ('all' | 'owner' | 'server')
88
- // TODO: Run component custom validation
89
- return true;
90
- }
91
- function broadcastBatchedMessages(messages, excludeSender) {
92
- if (messages.length === 0)
93
- return;
94
- // Build the complete buffer with all messages
95
- const networkBuffer = new ReadWriteByteBuffer();
96
- for (const message of messages) {
97
- // Skip oversized messages upfront
98
- if (message.messageBuffer.byteLength / 1024 > LIVEKIT_MAX_SIZE) {
99
- console.error(`Message too large (${message.messageBuffer.byteLength} bytes), skipping message from ${excludeSender}`);
100
- continue;
101
- }
102
- networkBuffer.writeBuffer(message.messageBuffer, false);
103
- }
104
- // Use the chunking function to split into proper chunks
105
- const chunks = chunkCrdtMessages(networkBuffer.toBinary(), LIVEKIT_MAX_SIZE);
106
- for (const chunk of chunks) {
107
- binaryMessageBus.emit(CommsMessage.CRDT, chunk);
108
- }
109
- DEBUG_NETWORK_MESSAGES() &&
110
- console.log(`Total: ${messages.length} messages in ${chunks.length} chunks from ${excludeSender}`);
111
- }
112
- function sendCorrectionToSender(networkMessage, sender, localEntityId) {
113
- try {
114
- // Only handle component messages (PUT/DELETE), not entity deletion
115
- if (networkMessage.type === CrdtMessageType.DELETE_ENTITY_NETWORK) {
116
- DEBUG_NETWORK_MESSAGES() && console.log('[AUTHORITATIVE] Cannot send authoritative message for entity deletion');
117
- return;
118
- }
119
- // Safe to access componentId and timestamp now
120
- const component = engine.getComponent(networkMessage.componentId);
121
- // Only proceed if component supports authoritative messages (LWW or GrowOnlySet)
122
- if (!supportsCorrections(component)) {
123
- DEBUG_NETWORK_MESSAGES() && console.log('[AUTHORITATIVE] Component does not support authoritative messages');
124
- return;
125
- }
126
- const serverCRDTState = component.getCrdtState(localEntityId);
127
- if (serverCRDTState) {
128
- // Create authoritative message using PUT_COMPONENT_NETWORK
129
- // Each client will convert this to AUTHORITATIVE_PUT_COMPONENT with proper entity mapping
130
- const correctionBuffer = new ReadWriteByteBuffer();
131
- PutNetworkComponentOperation.write(networkMessage.entityId, // Use original network entity ID
132
- serverCRDTState.timestamp, networkMessage.componentId, networkMessage.networkId, serverCRDTState.data, correctionBuffer);
133
- // Send authoritative message directly to the sender
134
- binaryMessageBus.emit(CommsMessage.CRDT_AUTHORITATIVE, correctionBuffer.toBinary(), [sender]);
135
- DEBUG_NETWORK_MESSAGES() &&
136
- console.log(`[AUTHORITATIVE] Sent authoritative message to ${sender} for entity ${localEntityId} component ${networkMessage.componentId} with timestamp ${networkMessage.timestamp}`);
137
- }
138
- }
139
- catch (error) {
140
- DEBUG_NETWORK_MESSAGES() && console.error('Error sending correction:', error);
141
- }
142
- }
143
- return {
144
- findExistingNetworkEntity,
145
- // transform Network messages to CRDT Common Messages.
146
- processClientMessages: function processClientMessages(value, sender, forceCorrections = false) {
147
- // console.log(`[CLIENT] Processing message from ${sender}, ${value.length} bytes`)
148
- // Collect all regular messages in a single buffer for batched application
149
- const combinedBuffer = new ReadWriteByteBuffer();
150
- // Clients process network messages from server and convert them to regular messages
151
- for (const message of utils.readMessages(value)) {
152
- // Only process network messages in client message handler
153
- if (utils.isNetworkMessage(message)) {
154
- const networkMessage = message;
155
- // Find or create network entity mapping
156
- const localEntityId = findOrCreateNetworkEntity(networkMessage, sender, false);
157
- // Convert network message to regular message or correction message
158
- const regularMessage = convertNetworkToRegularMessage(networkMessage, localEntityId, forceCorrections);
159
- if (regularMessage?.messageBuffer.byteLength) {
160
- combinedBuffer.writeBuffer(regularMessage.messageBuffer, false);
161
- }
162
- }
163
- }
164
- return combinedBuffer.toBinary();
165
- },
166
- // Sever Code: process message, handle permissions, and broadcast if needed.
167
- processServerMessages: function processServerMessages(value, sender) {
168
- // console.log(`[SERVER] Processing message from ${sender}, ${value.length} bytes`)
169
- // Collect all valid messages for batched broadcasting
170
- const messagesToBroadcast = [];
171
- const regularMessagesBuffer = new ReadWriteByteBuffer();
172
- for (const message of utils.readMessages(value)) {
173
- try {
174
- // Only process network messages in server message handler
175
- if (utils.isNetworkMessage(message)) {
176
- const networkMessage = message;
177
- // 1. Find or create network entity mapping
178
- const localEntityId = findOrCreateNetworkEntity(networkMessage, sender, true);
179
- // 2. Convert network message to regular message and collect for local application
180
- const regularMessage = convertNetworkToRegularMessage(networkMessage, localEntityId);
181
- // 3. Basic permission validation
182
- if (!validateMessagePermissions(regularMessage, sender, localEntityId)) {
183
- // Send correction back to sender with server's authoritative state
184
- sendCorrectionToSender(networkMessage, sender, localEntityId);
185
- continue;
186
- }
187
- // 4. Collect valid message for batched broadcasting
188
- messagesToBroadcast.push(networkMessage);
189
- if (regularMessage?.messageBuffer.byteLength) {
190
- regularMessagesBuffer.writeBuffer(regularMessage.messageBuffer, false);
191
- }
192
- }
193
- }
194
- catch (error) {
195
- DEBUG_NETWORK_MESSAGES() && console.error('Error processing server message:', error);
196
- }
197
- }
198
- // Batch broadcast all valid messages together
199
- broadcastBatchedMessages(messagesToBroadcast, sender);
200
- return regularMessagesBuffer.toBinary();
201
- },
202
- // engine changes that needs to be broadcasted.
203
- convertRegularToNetworkMessage: function convertRegularToNetworkMessage(regularMessage) {
204
- const groupedBuffer = new ReadWriteByteBuffer();
205
- // First pass: Convert all regular messages to network format and group them into one big buffer
206
- for (const message of utils.readMessages(regularMessage)) {
207
- // Only convert regular messages that have network data
208
- const networkData = NetworkEntity.getOrNull(message.entityId);
209
- if (networkData && !utils.isNetworkMessage(message)) {
210
- utils.localMessageToNetwork(message, networkData, groupedBuffer);
211
- }
212
- }
213
- // Second pass: Use the new chunking function that respects message boundaries
214
- const totalData = groupedBuffer.toBinary();
215
- return chunkCrdtMessages(totalData, LIVEKIT_MAX_SIZE);
216
- }
217
- };
218
- }
219
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmV0d29yay9zZXJ2ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUdMLGVBQWUsRUFFZix3QkFBd0IsRUFFeEIsNEJBQTRCLEVBQzdCLE1BQU0sVUFBVSxDQUFBO0FBQ2pCLE9BQU8sS0FBSyxVQUFVLE1BQU0sMEJBQTBCLENBQUE7QUFDdEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0NBQXdDLENBQUE7QUFDNUUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBQ3BELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUMvQyxPQUFPLEtBQUssS0FBSyxNQUFNLFNBQVMsQ0FBQTtBQUNoQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQVNqRixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxFQUFFLENBQUE7QUFPbEMsTUFBTSxVQUFVLHFCQUFxQixDQUFDLE1BQThCO0lBQ2xFLE1BQU0sRUFBRSxNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxNQUFNLENBQUE7SUFFM0Msb0VBQW9FO0lBQ3BFLE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDdEQsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUM5QyxNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBRXRELG1GQUFtRjtJQUNuRixTQUFTLG1CQUFtQixDQUMxQixTQUFpQztRQUVqQyxPQUFPLENBQ0wsQ0FBQyxTQUFTLENBQUMsYUFBYSxpREFBeUM7WUFDL0QsU0FBUyxDQUFDLGFBQWEsMkNBQW1DLENBQUM7WUFDN0QsY0FBYyxJQUFJLFNBQVMsQ0FD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QkFBcUIsQ0FBQyxPQUFPLEVBQUUsV0FBVyxFQUFFLGFBQWEsQ0FBQyxDQUFBO2lCQUNqRTthQUNGO1lBRUQsOEVBQThFO1lBQzlFLE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtZQUMxQyxPQUFPLGlCQUFpQixDQUFDLFNBQVMsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFBO1FBQ3ZELENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElFbmdpbmUsXG4gIEVudGl0eSxcbiAgQ3JkdE1lc3NhZ2VUeXBlLFxuICBDcmR0TWVzc2FnZUJvZHksXG4gIFByb2Nlc3NNZXNzYWdlUmVzdWx0VHlwZSxcbiAgQ29tcG9uZW50VHlwZSxcbiAgUHV0TmV0d29ya0NvbXBvbmVudE9wZXJhdGlvblxufSBmcm9tICdAZGNsL2VjcydcbmltcG9ydCAqIGFzIGNvbXBvbmVudHMgZnJvbSAnQGRjbC9lY3MvZGlzdC9jb21wb25lbnRzJ1xuaW1wb3J0IHsgUmVhZFdyaXRlQnl0ZUJ1ZmZlciB9IGZyb20gJ0BkY2wvZWNzL2Rpc3Qvc2VyaWFsaXphdGlvbi9CeXRlQnVmZmVyJ1xuaW1wb3J0IHsgQ29tbXNNZXNzYWdlIH0gZnJvbSAnLi4vYmluYXJ5LW1lc3NhZ2UtYnVzJ1xuaW1wb3J0IHsgY2h1bmtDcmR0TWVzc2FnZXMgfSBmcm9tICcuLi9jaHVua2luZydcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBBVVRIX1NFUlZFUl9QRUVSX0lELCBERUJVR19ORVRXT1JLX01FU1NBR0VTIH0gZnJvbSAnLi4vbWVzc2FnZS1idXMtc3luYydcbmltcG9ydCB7IHR5cGUgQmluYXJ5TWVzc2FnZUJ1cyB9IGZyb20gJy4uL2JpbmFyeS1tZXNzYWdlLWJ1cydcbmltcG9ydCB7XG4gIExhc3RXcml0ZVdpbkVsZW1lbnRTZXRDb21wb25lbnREZWZpbml0aW9uLFxuICBHcm93T25seVZhbHVlU2V0Q29tcG9uZW50RGVmaW5pdGlvbixcbiAgQ29tcG9uZW50RGVmaW5pdGlvbixcbiAgSW50ZXJuYWxCYXNlQ29tcG9uZW50XG59IGZyb20gJ0BkY2wvZWNzL2Rpc3QvZW5naW5lL2NvbXBvbmVudCdcblxuZXhwb3J0IGNvbnN0IExJVkVLSVRfTUFYX1NJWkUgPSAxMlxuXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZlclZhbGlkYXRpb25Db25maWcge1xuICBlbmdpbmU6IElFbmdpbmVcbiAgYmluYXJ5TWVzc2FnZUJ1czogUmV0dXJuVHlwZTx0eXBlb2YgQmluYXJ5TWVzc2FnZUJ1cz5cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNlcnZlclZhbGlkYXRvcihjb25maWc6IFNlcnZlclZhbGlkYXRpb25Db25maWcpIHtcbiAgY29uc3QgeyBlbmdpbmUsIGJpbmFyeU1lc3NhZ2VCdXMgfSA9IGNvbmZpZ1xuXG4gIC8vIEluaXRpYWxpemUgY29tcG9uZW50cyBmb3IgbmV0d29yayBvcGVyYXRpb25zIGFuZCB0cmFuc2Zvcm0gZml4aW5nXG4gIGNvbnN0IE5ldHdvcmtFbnRpdHkgPSBjb21wb25lbnRzLk5ldHdvcmtFbnRpdHkoZW5naW5lKVxuICBjb25zdCBDcmVhdGVkQnkgPSBjb21wb25lbnRzLkNyZWF0ZWRCeShlbmdpbmUpXG4gIGNvbnN0IE5ldHdvcmtQYXJlbnQgPSBjb21wb25lbnRzLk5ldHdvcmtQYXJlbnQoZW5naW5lKVxuXG4gIC8vIFR5cGUgZ3VhcmQgdG8gY2hlY2sgaWYgY29tcG9uZW50IHN1cHBvcnRzIGNvcnJlY3Rpb25zIChib3RoIExXVyBhbmQgR3Jvd09ubHlTZXQpXG4gIGZ1bmN0aW9uIHN1cHBvcnRzQ29ycmVjdGlvbnM8VD4oXG4gICAgY29tcG9uZW50OiBDb21wb25lbnREZWZpbml0aW9uPFQ+XG4gICk6IGNvbXBvbmVudCBpcyBMYXN0V3JpdGVXaW5FbGVtZW50U2V0Q29tcG9uZW50RGVmaW5pdGlvbjxUPiB8IEdyb3dPbmx5VmFsdWVTZXRDb21wb25lbnREZWZpbml0aW9uPFQ+IHtcbiAgICByZXR1cm4gKFxuICAgICAgKGNvbXBvbmVudC5jb21wb25lbnRUeXBlID09PSBDb21wb25lbnRUeXBlLkxhc3RXcml0ZVdpbkVsZW1lbnRTZXQgfHxcbiAgICAgICAgY29tcG9uZW50LmNvbXBvbmVudFR5cGUgPT09IENvbXBvbmVudFR5cGUuR3Jvd09ubHlWYWx1ZVNldCkgJiZcbiAgICAgICdnZXRDcmR0U3RhdGUnIGluIGNvbXBvbmVudFxuICAgIClcbiAgfVxuXG4gIGZ1bmN0aW9uIGZpbmRFeGlzdGluZ05ldHdvcmtFbnRpdHkobWVzc2FnZTogdXRpbHMuTmV0d29ya01lc3NhZ2UpOiBFbnRpdHkgfCBudWxsIHtcbiAgICAvLyBMb29rIGZvciBleGlzdGluZyBuZXR3b3JrIGVudGl0eSBtYXBwaW5nIChkb24ndCBjcmVhdGUgbmV3IG9uZXMpXG4gICAgZm9yIChjb25zdCBbZW50aXR5SWQsIG5ldHdvcmtEYXRhXSBvZiBlbmdpbmUuZ2V0RW50aXRpZXNXaXRoKE5ldHdvcmtFbnRpdHkpKSB7XG4gICAgICBpZiAobmV0d29ya0RhdGEubmV0d29ya0lkID09PSBtZXNzYWdlLm5ldHdvcmtJZCAmJiBuZXR3b3JrRGF0YS5lbnRpdHlJZCA9PT0gbWVzc2FnZS5lbnRpdHlJZCkge1xuICAgICAgICByZXR1cm4gZW50aXR5SWRcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gUmV0dXJuIG51bGwgaWYgbm90IGZvdW5kXG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIGZ1bmN0aW9uIGZpbmRPckNyZWF0ZU5ldHdvcmtFbnRpdHkobWVzc2FnZTogdXRpbHMuTmV0d29ya01lc3NhZ2UsIHNlbmRlcjogc3RyaW5nLCBpc1NlcnZlcjogYm9vbGVhbik6IEVudGl0eSB7XG4gICAgLy8gTG9vayBmb3IgZXhpc3RpbmcgbmV0d29yayBlbnRpdHkgbWFwcGluZyBmaXJzdFxuICAgIGNvbnN0IGV4aXN0aW5nRW50aXR5ID0gZmluZEV4aXN0aW5nTmV0d29ya0VudGl0eShtZXNzYWdlKVxuXG4gICAgaWYgKGV4aXN0aW5nRW50aXR5KSB7XG4gICAgICByZXR1cm4gZXhpc3RpbmdFbnRpdHlcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgbmV3IGVudGl0eSBhbmQgbmV0d29yayBtYXBwaW5nXG4gICAgY29uc3QgbmV3RW50aXR5SWQgPSBlbmdpbmUuYWRkRW50aXR5KClcbiAgICBOZXR3b3JrRW50aXR5LmNyZWF0ZU9yUmVwbGFjZShuZXdFbnRpdHlJZCwge1xuICAgICAgbmV0d29ya0lkOiBtZXNzYWdlLm5ldHdvcmtJZCxcbiAgICAgIGVudGl0eUlkOiBtZXNzYWdlLmVudGl0eUlkXG4gICAgfSlcblxuICAgIGlmIChpc1NlcnZlcikge1xuICAgICAgQ3JlYXRlZEJ5LmNyZWF0ZU9yUmVwbGFjZShuZXdFbnRpdHlJZCwgeyBhZGRyZXNzOiBzZW5kZXIgfSlcbiAgICB9XG5cbiAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKGBbREVCVUddIENyZWF0ZWQgbmV3IGVudGl0eSAke25ld0VudGl0eUlkfSBmb3IgbmV0d29yayAke21lc3NhZ2UubmV0d29ya0lkfToke21lc3NhZ2UuZW50aXR5SWR9YClcbiAgICByZXR1cm4gbmV3RW50aXR5SWRcbiAgfVxuXG4gIGZ1bmN0aW9uIGNvbnZlcnROZXR3b3JrVG9SZWd1bGFyTWVzc2FnZShcbiAgICBuZXR3b3JrTWVzc2FnZTogdXRpbHMuTmV0d29ya01lc3NhZ2UsXG4gICAgbG9jYWxFbnRpdHlJZDogRW50aXR5LFxuICAgIGZvcmNlQ29ycmVjdGlvbnMgPSBmYWxzZVxuICApOiAoQ3JkdE1lc3NhZ2VCb2R5ICYgeyBtZXNzYWdlQnVmZmVyOiBVaW50OEFycmF5IH0pIHwgbnVsbCB7XG4gICAgY29uc3QgYnVmZmVyID0gbmV3IFJlYWRXcml0ZUJ5dGVCdWZmZXIoKVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFVzZSB0aGUgd2VsbC10ZXN0ZWQgbmV0d29ya01lc3NhZ2VUb0xvY2FsIHV0aWxpdHkgd2l0aCB0cmFuc2Zvcm0gZml4aW5nIGZvciBVbml0eVxuICAgICAgY29uc3QgbWVzc2FnZSA9IHV0aWxzLm5ldHdvcmtNZXNzYWdlVG9Mb2NhbChcbiAgICAgICAgbmV0d29ya01lc3NhZ2UsXG4gICAgICAgIGxvY2FsRW50aXR5SWQsXG4gICAgICAgIGJ1ZmZlcixcbiAgICAgICAgTmV0d29ya1BhcmVudCxcbiAgICAgICAgZm9yY2VDb3JyZWN0aW9uc1xuICAgICAgKVxuICAgICAgcmV0dXJuIHsgLi4ubWVzc2FnZSwgbWVzc2FnZUJ1ZmZlcjogYnVmZmVyLnRvQmluYXJ5KCkgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5lcnJvcignRXJyb3IgY29udmVydGluZyBuZXR3b3JrIG1lc3NhZ2U6JywgZXJyb3IpXG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHZhbGlkYXRlTWVzc2FnZVBlcm1pc3Npb25zKG1lc3NhZ2U6IHV0aWxzLlJlZ3VsYXJNZXNzYWdlLCBzZW5kZXI6IHN0cmluZywgX2xvY2FsRW50aXR5SWQ6IEVudGl0eSk6IGJvb2xlYW4ge1xuICAgIC8vIEJhc2ljIGNoZWNrc1xuICAgIGlmICghc2VuZGVyIHx8IHNlbmRlciA9PT0gQVVUSF9TRVJWRVJfUEVFUl9JRCkge1xuICAgICAgcmV0dXJuIGZhbHNlIC8vIFNlcnZlciBzaG91bGRuJ3Qgc2VuZCBtZXNzYWdlcyB0byBpdHNlbGZcbiAgICB9XG5cbiAgICBpZiAobWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0VOVElUWSkge1xuICAgICAgLy8gVE9ETzogaG93IHRvIGhhbmRsZSB0aGlzIGNhc2UgP1xuICAgIH1cblxuICAgIGlmIChtZXNzYWdlLnR5cGUgPT09IENyZHRNZXNzYWdlVHlwZS5QVVRfQ09NUE9ORU5UIHx8IG1lc3NhZ2UudHlwZSA9PT0gQ3JkdE1lc3NhZ2VUeXBlLkRFTEVURV9DT01QT05FTlQpIHtcbiAgICAgIGNvbnN0IGNvbXBvbmVudCA9IGVuZ2luZS5nZXRDb21wb25lbnQobWVzc2FnZS5jb21wb25lbnRJZCkgYXMgSW50ZXJuYWxCYXNlQ29tcG9uZW50PHVua25vd24+XG4gICAgICBjb25zdCBidWYgPSAnZGF0YScgaW4gbWVzc2FnZSA/IG5ldyBSZWFkV3JpdGVCeXRlQnVmZmVyKG1lc3NhZ2UuZGF0YSkgOiBudWxsXG4gICAgICBjb25zdCB2YWx1ZSA9IGJ1ZiA/IGNvbXBvbmVudC5zY2hlbWEuZGVzZXJpYWxpemUoYnVmKSA6IG51bGxcbiAgICAgIGNvbnN0IGRyeVJ1bkNSRFQgPSBjb21wb25lbnQuX19kcnlfcnVuX3VwZGF0ZUZyb21DcmR0KG1lc3NhZ2UpXG4gICAgICBjb25zdCB2YWxpZENSRFQgPSBbXG4gICAgICAgIFByb2Nlc3NNZXNzYWdlUmVzdWx0VHlwZS5TdGF0ZVVwZGF0ZWREYXRhLFxuICAgICAgICBQcm9jZXNzTWVzc2FnZVJlc3VsdFR5cGUuU3RhdGVVcGRhdGVkVGltZXN0YW1wLFxuICAgICAgICBQcm9jZXNzTWVzc2FnZVJlc3VsdFR5cGUuRW50aXR5RGVsZXRlZFxuICAgICAgXS5pbmNsdWRlcyhkcnlSdW5DUkRUKVxuICAgICAgY29uc3QgY3JlYXRlZEJ5ID0gQ3JlYXRlZEJ5LmdldE9yTnVsbChtZXNzYWdlLmVudGl0eUlkKVxuICAgICAgY29uc3QgdmFsaWRNZXNzYWdlID1cbiAgICAgICAgdmFsaWRDUkRUICYmXG4gICAgICAgIGNvbXBvbmVudC5fX3J1bl92YWxpZGF0ZUJlZm9yZUNoYW5nZShtZXNzYWdlLmVudGl0eUlkLCB2YWx1ZSwgc2VuZGVyLCBjcmVhdGVkQnk/LmFkZHJlc3MgPz8gQVVUSF9TRVJWRVJfUEVFUl9JRClcblxuICAgICAgcmV0dXJuICEhdmFsaWRNZXNzYWdlXG4gICAgfVxuXG4gICAgLy8gRm9yIG5vdywgYmFzaWMgdmFsaWRhdGlvbiAtIGluIHRoZSBmdXR1cmUgdGhpcyB3aWxsIGNoZWNrIGNvbXBvbmVudCBzeW5jIHBlcm1pc3Npb25zXG4gICAgLy8gVE9ETzogQ2hlY2sgaWYgc2VuZGVyIG93bnMgdGhlIGVudGl0eVxuICAgIC8vIFRPRE86IENoZWNrIGNvbXBvbmVudCBzeW5jIG1vZGUgKCdhbGwnIHwgJ293bmVyJyB8ICdzZXJ2ZXInKVxuICAgIC8vIFRPRE86IFJ1biBjb21wb25lbnQgY3VzdG9tIHZhbGlkYXRpb25cbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgZnVuY3Rpb24gYnJvYWRjYXN0QmF0Y2hlZE1lc3NhZ2VzKG1lc3NhZ2VzOiB1dGlscy5OZXR3b3JrTWVzc2FnZVtdLCBleGNsdWRlU2VuZGVyOiBzdHJpbmcpIHtcbiAgICBpZiAobWVzc2FnZXMubGVuZ3RoID09PSAwKSByZXR1cm5cblxuICAgIC8vIEJ1aWxkIHRoZSBjb21wbGV0ZSBidWZmZXIgd2l0aCBhbGwgbWVzc2FnZXNcbiAgICBjb25zdCBuZXR3b3JrQnVmZmVyID0gbmV3IFJlYWRXcml0ZUJ5dGVCdWZmZXIoKVxuICAgIGZvciAoY29uc3QgbWVzc2FnZSBvZiBtZXNzYWdlcykge1xuICAgICAgLy8gU2tpcCBvdmVyc2l6ZWQgbWVzc2FnZXMgdXBmcm9udFxuICAgICAgaWYgKG1lc3NhZ2UubWVzc2FnZUJ1ZmZlci5ieXRlTGVuZ3RoIC8gMTAyNCA+IExJVkVLSVRfTUFYX1NJWkUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICBgTWVzc2FnZSB0b28gbGFyZ2UgKCR7bWVzc2FnZS5tZXNzYWdlQnVmZmVyLmJ5dGVMZW5ndGh9IGJ5dGVzKSwgc2tpcHBpbmcgbWVzc2FnZSBmcm9tICR7ZXhjbHVkZVNlbmRlcn1gXG4gICAgICAgIClcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIG5ldHdvcmtCdWZmZXIud3JpdGVCdWZmZXIobWVzc2FnZS5tZXNzYWdlQnVmZmVyLCBmYWxzZSlcbiAgICB9XG5cbiAgICAvLyBVc2UgdGhlIGNodW5raW5nIGZ1bmN0aW9uIHRvIHNwbGl0IGludG8gcHJvcGVyIGNodW5rc1xuICAgIGNvbnN0IGNodW5rcyA9IGNodW5rQ3JkdE1lc3NhZ2VzKG5ldHdvcmtCdWZmZXIudG9CaW5hcnkoKSwgTElWRUtJVF9NQVhfU0laRSlcblxuICAgIGZvciAoY29uc3QgY2h1bmsgb2YgY2h1bmtzKSB7XG4gICAgICBiaW5hcnlNZXNzYWdlQnVzLmVtaXQoQ29tbXNNZXNzYWdlLkNSRFQsIGNodW5rKVxuICAgIH1cbiAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKGBUb3RhbDogJHttZXNzYWdlcy5sZW5ndGh9IG1lc3NhZ2VzIGluICR7Y2h1bmtzLmxlbmd0aH0gY2h1bmtzIGZyb20gJHtleGNsdWRlU2VuZGVyfWApXG4gIH1cblxuICBmdW5jdGlvbiBzZW5kQ29ycmVjdGlvblRvU2VuZGVyKG5ldHdvcmtNZXNzYWdlOiB1dGlscy5OZXR3b3JrTWVzc2FnZSwgc2VuZGVyOiBzdHJpbmcsIGxvY2FsRW50aXR5SWQ6IEVudGl0eSkge1xuICAgIHRyeSB7XG4gICAgICAvLyBPbmx5IGhhbmRsZSBjb21wb25lbnQgbWVzc2FnZXMgKFBVVC9ERUxFVEUpLCBub3QgZW50aXR5IGRlbGV0aW9uXG4gICAgICBpZiAobmV0d29ya01lc3NhZ2UudHlwZSA9PT0gQ3JkdE1lc3NhZ2VUeXBlLkRFTEVURV9FTlRJVFlfTkVUV09SSykge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tBVVRIT1JJVEFUSVZFXSBDYW5ub3Qgc2VuZCBhdXRob3JpdGF0aXZlIG1lc3NhZ2UgZm9yIGVudGl0eSBkZWxldGlvbicpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyBTYWZlIHRvIGFjY2VzcyBjb21wb25lbnRJZCBhbmQgdGltZXN0YW1wIG5vd1xuICAgICAgY29uc3QgY29tcG9uZW50ID0gZW5naW5lLmdldENvbXBvbmVudChuZXR3b3JrTWVzc2FnZS5jb21wb25lbnRJZClcblxuICAgICAgLy8gT25seSBwcm9jZWVkIGlmIGNvbXBvbmVudCBzdXBwb3J0cyBhdXRob3JpdGF0aXZlIG1lc3NhZ2VzIChMV1cgb3IgR3Jvd09ubHlTZXQpXG4gICAgICBpZiAoIXN1cHBvcnRzQ29ycmVjdGlvbnMoY29tcG9uZW50KSkge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tBVVRIT1JJVEFUSVZFXSBDb21wb25lbnQgZG9lcyBub3Qgc3VwcG9ydCBhdXRob3JpdGF0aXZlIG1lc3NhZ2VzJylcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHNlcnZlckNSRFRTdGF0ZSA9IGNvbXBvbmVudC5nZXRDcmR0U3RhdGUobG9jYWxFbnRpdHlJZClcblxuICAgICAgaWYgKHNlcnZlckNSRFRTdGF0ZSkge1xuICAgICAgICAvLyBDcmVhdGUgYXV0aG9yaXRhdGl2ZSBtZXNzYWdlIHVzaW5nIFBVVF9DT01QT05FTlRfTkVUV09SS1xuICAgICAgICAvLyBFYWNoIGNsaWVudCB3aWxsIGNvbnZlcnQgdGhpcyB0byBBVVRIT1JJVEFUSVZFX1BVVF9DT01QT05FTlQgd2l0aCBwcm9wZXIgZW50aXR5IG1hcHBpbmdcbiAgICAgICAgY29uc3QgY29ycmVjdGlvbkJ1ZmZlciA9IG5ldyBSZWFkV3JpdGVCeXRlQnVmZmVyKClcbiAgICAgICAgUHV0TmV0d29ya0NvbXBvbmVudE9wZXJhdGlvbi53cml0ZShcbiAgICAgICAgICBuZXR3b3JrTWVzc2FnZS5lbnRpdHlJZCwgLy8gVXNlIG9yaWdpbmFsIG5ldHdvcmsgZW50aXR5IElEXG4gICAgICAgICAgc2VydmVyQ1JEVFN0YXRlLnRpbWVzdGFtcCxcbiAgICAgICAgICBuZXR3b3JrTWVzc2FnZS5jb21wb25lbnRJZCxcbiAgICAgICAgICBuZXR3b3JrTWVzc2FnZS5uZXR3b3JrSWQsXG4gICAgICAgICAgc2VydmVyQ1JEVFN0YXRlLmRhdGEsXG4gICAgICAgICAgY29ycmVjdGlvbkJ1ZmZlclxuICAgICAgICApXG4gICAgICAgIC8vIFNlbmQgYXV0aG9yaXRhdGl2ZSBtZXNzYWdlIGRpcmVjdGx5IHRvIHRoZSBzZW5kZXJcbiAgICAgICAgYmluYXJ5TWVzc2FnZUJ1cy5lbWl0KENvbW1zTWVzc2FnZS5DUkRUX0FVVEhPUklUQVRJVkUsIGNvcnJlY3Rpb25CdWZmZXIudG9CaW5hcnkoKSwgW3NlbmRlcl0pXG5cbiAgICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBgW0FVVEhPUklUQVRJVkVdIFNlbnQgYXV0aG9yaXRhdGl2ZSBtZXNzYWdlIHRvICR7c2VuZGVyfSBmb3IgZW50aXR5ICR7bG9jYWxFbnRpdHlJZH0gY29tcG9uZW50ICR7bmV0d29ya01lc3NhZ2UuY29tcG9uZW50SWR9IHdpdGggdGltZXN0YW1wICR7bmV0d29ya01lc3NhZ2UudGltZXN0YW1wfWBcbiAgICAgICAgICApXG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmVycm9yKCdFcnJvciBzZW5kaW5nIGNvcnJlY3Rpb246JywgZXJyb3IpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBmaW5kRXhpc3RpbmdOZXR3b3JrRW50aXR5LFxuICAgIC8vIHRyYW5zZm9ybSBOZXR3b3JrIG1lc3NhZ2VzIHRvIENSRFQgQ29tbW9uIE1lc3NhZ2VzLlxuICAgIHByb2Nlc3NDbGllbnRNZXNzYWdlczogZnVuY3Rpb24gcHJvY2Vzc0NsaWVudE1lc3NhZ2VzKHZhbHVlOiBVaW50OEFycmF5LCBzZW5kZXI6IHN0cmluZywgZm9yY2VDb3JyZWN0aW9ucyA9IGZhbHNlKSB7XG4gICAgICAvLyBjb25zb2xlLmxvZyhgW0NMSUVOVF0gUHJvY2Vzc2luZyBtZXNzYWdlIGZyb20gJHtzZW5kZXJ9LCAke3ZhbHVlLmxlbmd0aH0gYnl0ZXNgKVxuXG4gICAgICAvLyBDb2xsZWN0IGFsbCByZWd1bGFyIG1lc3NhZ2VzIGluIGEgc2luZ2xlIGJ1ZmZlciBmb3IgYmF0Y2hlZCBhcHBsaWNhdGlvblxuICAgICAgY29uc3QgY29tYmluZWRCdWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcigpXG5cbiAgICAgIC8vIENsaWVudHMgcHJvY2VzcyBuZXR3b3JrIG1lc3NhZ2VzIGZyb20gc2VydmVyIGFuZCBjb252ZXJ0IHRoZW0gdG8gcmVndWxhciBtZXNzYWdlc1xuICAgICAgZm9yIChjb25zdCBtZXNzYWdlIG9mIHV0aWxzLnJlYWRNZXNzYWdlcyh2YWx1ZSkpIHtcbiAgICAgICAgLy8gT25seSBwcm9jZXNzIG5ldHdvcmsgbWVzc2FnZXMgaW4gY2xpZW50IG1lc3NhZ2UgaGFuZGxlclxuICAgICAgICBpZiAodXRpbHMuaXNOZXR3b3JrTWVzc2FnZShtZXNzYWdlKSkge1xuICAgICAgICAgIGNvbnN0IG5ldHdvcmtNZXNzYWdlID0gbWVzc2FnZSBhcyB1dGlscy5OZXR3b3JrTWVzc2FnZVxuXG4gICAgICAgICAgLy8gRmluZCBvciBjcmVhdGUgbmV0d29yayBlbnRpdHkgbWFwcGluZ1xuICAgICAgICAgIGNvbnN0IGxvY2FsRW50aXR5SWQgPSBmaW5kT3JDcmVhdGVOZXR3b3JrRW50aXR5KG5ldHdvcmtNZXNzYWdlLCBzZW5kZXIsIGZhbHNlKVxuXG4gICAgICAgICAgLy8gQ29udmVydCBuZXR3b3JrIG1lc3NhZ2UgdG8gcmVndWxhciBtZXNzYWdlIG9yIGNvcnJlY3Rpb24gbWVzc2FnZVxuICAgICAgICAgIGNvbnN0IHJlZ3VsYXJNZXNzYWdlID0gY29udmVydE5ldHdvcmtUb1JlZ3VsYXJNZXNzYWdlKG5ldHdvcmtNZXNzYWdlLCBsb2NhbEVudGl0eUlkLCBmb3JjZUNvcnJlY3Rpb25zKVxuXG4gICAgICAgICAgaWYgKHJlZ3VsYXJNZXNzYWdlPy5tZXNzYWdlQnVmZmVyLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbWJpbmVkQnVmZmVyLndyaXRlQnVmZmVyKHJlZ3VsYXJNZXNzYWdlLm1lc3NhZ2VCdWZmZXIsIGZhbHNlKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIGNvbWJpbmVkQnVmZmVyLnRvQmluYXJ5KClcbiAgICB9LFxuICAgIC8vIFNldmVyIENvZGU6IHByb2Nlc3MgbWVzc2FnZSwgaGFuZGxlIHBlcm1pc3Npb25zLCBhbmQgYnJvYWRjYXN0IGlmIG5lZWRlZC5cbiAgICBwcm9jZXNzU2VydmVyTWVzc2FnZXM6IGZ1bmN0aW9uIHByb2Nlc3NTZXJ2ZXJNZXNzYWdlcyh2YWx1ZTogVWludDhBcnJheSwgc2VuZGVyOiBzdHJpbmcpIHtcbiAgICAgIC8vIGNvbnNvbGUubG9nKGBbU0VSVkVSXSBQcm9jZXNzaW5nIG1lc3NhZ2UgZnJvbSAke3NlbmRlcn0sICR7dmFsdWUubGVuZ3RofSBieXRlc2ApXG5cbiAgICAgIC8vIENvbGxlY3QgYWxsIHZhbGlkIG1lc3NhZ2VzIGZvciBiYXRjaGVkIGJyb2FkY2FzdGluZ1xuICAgICAgY29uc3QgbWVzc2FnZXNUb0Jyb2FkY2FzdDogdXRpbHMuTmV0d29ya01lc3NhZ2VbXSA9IFtdXG4gICAgICBjb25zdCByZWd1bGFyTWVzc2FnZXNCdWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcigpXG5cbiAgICAgIGZvciAoY29uc3QgbWVzc2FnZSBvZiB1dGlscy5yZWFkTWVzc2FnZXModmFsdWUpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gT25seSBwcm9jZXNzIG5ldHdvcmsgbWVzc2FnZXMgaW4gc2VydmVyIG1lc3NhZ2UgaGFuZGxlclxuICAgICAgICAgIGlmICh1dGlscy5pc05ldHdvcmtNZXNzYWdlKG1lc3NhZ2UpKSB7XG4gICAgICAgICAgICBjb25zdCBuZXR3b3JrTWVzc2FnZSA9IG1lc3NhZ2UgYXMgdXRpbHMuTmV0d29ya01lc3NhZ2VcbiAgICAgICAgICAgIC8vIDEuIEZpbmQgb3IgY3JlYXRlIG5ldHdvcmsgZW50aXR5IG1hcHBpbmdcbiAgICAgICAgICAgIGNvbnN0IGxvY2FsRW50aXR5SWQgPSBmaW5kT3JDcmVhdGVOZXR3b3JrRW50aXR5KG5ldHdvcmtNZXNzYWdlLCBzZW5kZXIsIHRydWUpXG5cbiAgICAgICAgICAgIC8vIDIuIENvbnZlcnQgbmV0d29yayBtZXNzYWdlIHRvIHJlZ3VsYXIgbWVzc2FnZSBhbmQgY29sbGVjdCBmb3IgbG9jYWwgYXBwbGljYXRpb25cbiAgICAgICAgICAgIGNvbnN0IHJlZ3VsYXJNZXNzYWdlID0gY29udmVydE5ldHdvcmtUb1JlZ3VsYXJNZXNzYWdlKG5ldHdvcmtNZXNzYWdlLCBsb2NhbEVudGl0eUlkKVxuXG4gICAgICAgICAgICAvLyAzLiBCYXNpYyBwZXJtaXNzaW9uIHZhbGlkYXRpb25cbiAgICAgICAgICAgIGlmICghdmFsaWRhdGVNZXNzYWdlUGVybWlzc2lvbnMocmVndWxhck1lc3NhZ2UgYXMgYW55LCBzZW5kZXIsIGxvY2FsRW50aXR5SWQpKSB7XG4gICAgICAgICAgICAgIC8vIFNlbmQgY29ycmVjdGlvbiBiYWNrIHRvIHNlbmRlciB3aXRoIHNlcnZlcidzIGF1dGhvcml0YXRpdmUgc3RhdGVcbiAgICAgICAgICAgICAgc2VuZENvcnJlY3Rpb25Ub1NlbmRlcihuZXR3b3JrTWVzc2FnZSwgc2VuZGVyLCBsb2NhbEVudGl0eUlkKVxuICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyA0LiBDb2xsZWN0IHZhbGlkIG1lc3NhZ2UgZm9yIGJhdGNoZWQgYnJvYWRjYXN0aW5nXG4gICAgICAgICAgICBtZXNzYWdlc1RvQnJvYWRjYXN0LnB1c2gobmV0d29ya01lc3NhZ2UpXG5cbiAgICAgICAgICAgIGlmIChyZWd1bGFyTWVzc2FnZT8ubWVzc2FnZUJ1ZmZlci5ieXRlTGVuZ3RoKSB7XG4gICAgICAgICAgICAgIHJlZ3VsYXJNZXNzYWdlc0J1ZmZlci53cml0ZUJ1ZmZlcihyZWd1bGFyTWVzc2FnZS5tZXNzYWdlQnVmZmVyLCBmYWxzZSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHByb2Nlc3Npbmcgc2VydmVyIG1lc3NhZ2U6JywgZXJyb3IpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIEJhdGNoIGJyb2FkY2FzdCBhbGwgdmFsaWQgbWVzc2FnZXMgdG9nZXRoZXJcbiAgICAgIGJyb2FkY2FzdEJhdGNoZWRNZXNzYWdlcyhtZXNzYWdlc1RvQnJvYWRjYXN0LCBzZW5kZXIpXG4gICAgICByZXR1cm4gcmVndWxhck1lc3NhZ2VzQnVmZmVyLnRvQmluYXJ5KClcbiAgICB9LFxuICAgIC8vIGVuZ2luZSBjaGFuZ2VzIHRoYXQgbmVlZHMgdG8gYmUgYnJvYWRjYXN0ZWQuXG4gICAgY29udmVydFJlZ3VsYXJUb05ldHdvcmtNZXNzYWdlOiBmdW5jdGlvbiBjb252ZXJ0UmVndWxhclRvTmV0d29ya01lc3NhZ2UocmVndWxhck1lc3NhZ2U6IFVpbnQ4QXJyYXkpOiBVaW50OEFycmF5W10ge1xuICAgICAgY29uc3QgZ3JvdXBlZEJ1ZmZlciA9IG5ldyBSZWFkV3JpdGVCeXRlQnVmZmVyKClcblxuICAgICAgLy8gRmlyc3QgcGFzczogQ29udmVydCBhbGwgcmVndWxhciBtZXNzYWdlcyB0byBuZXR3b3JrIGZvcm1hdCBhbmQgZ3JvdXAgdGhlbSBpbnRvIG9uZSBiaWcgYnVmZmVyXG4gICAgICBmb3IgKGNvbnN0IG1lc3NhZ2Ugb2YgdXRpbHMucmVhZE1lc3NhZ2VzKHJlZ3VsYXJNZXNzYWdlKSkge1xuICAgICAgICAvLyBPbmx5IGNvbnZlcnQgcmVndWxhciBtZXNzYWdlcyB0aGF0IGhhdmUgbmV0d29yayBkYXRhXG4gICAgICAgIGNvbnN0IG5ldHdvcmtEYXRhID0gTmV0d29ya0VudGl0eS5nZXRPck51bGwobWVzc2FnZS5lbnRpdHlJZClcblxuICAgICAgICBpZiAobmV0d29ya0RhdGEgJiYgIXV0aWxzLmlzTmV0d29ya01lc3NhZ2UobWVzc2FnZSkpIHtcbiAgICAgICAgICB1dGlscy5sb2NhbE1lc3NhZ2VUb05ldHdvcmsobWVzc2FnZSwgbmV0d29ya0RhdGEsIGdyb3VwZWRCdWZmZXIpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gU2Vjb25kIHBhc3M6IFVzZSB0aGUgbmV3IGNodW5raW5nIGZ1bmN0aW9uIHRoYXQgcmVzcGVjdHMgbWVzc2FnZSBib3VuZGFyaWVzXG4gICAgICBjb25zdCB0b3RhbERhdGEgPSBncm91cGVkQnVmZmVyLnRvQmluYXJ5KClcbiAgICAgIHJldHVybiBjaHVua0NyZHRNZXNzYWdlcyh0b3RhbERhdGEsIExJVkVLSVRfTUFYX1NJWkUpXG4gICAgfVxuICB9XG59XG4iXX0=
@@ -1,18 +0,0 @@
1
- import { Entity } from '@dcl/ecs/dist/engine';
2
- import { NetworkParent } from '@dcl/ecs';
3
- import { ReceiveMessage } from '@dcl/ecs/dist/runtime/types';
4
- import { ReceiveNetworkMessage } from '@dcl/ecs/dist/systems/crdt/types';
5
- import { ByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer';
6
- import { CrdtMessageBody, DeleteComponentMessage, DeleteComponentNetworkMessage, DeleteEntityMessage, DeleteEntityNetworkMessage, PutComponentMessage, AuthoritativePutComponentMessage, PutNetworkComponentMessage } from '@dcl/ecs/dist/serialization/crdt/types';
7
- import { INetowrkEntityType } from '@dcl/ecs/dist/components/types';
8
- export type NetworkMessage = (PutNetworkComponentMessage | DeleteComponentNetworkMessage | DeleteEntityNetworkMessage) & {
9
- messageBuffer: Uint8Array;
10
- };
11
- export type RegularMessage = (PutComponentMessage | AuthoritativePutComponentMessage | DeleteComponentMessage | DeleteEntityMessage) & {
12
- messageBuffer: Uint8Array;
13
- };
14
- export declare function readMessages(data: Uint8Array): (NetworkMessage | RegularMessage)[];
15
- export declare function isNetworkMessage(message: ReceiveMessage): message is ReceiveNetworkMessage;
16
- export declare function networkMessageToLocal(message: ReceiveNetworkMessage, localEntityId: Entity, destinationBuffer: ByteBuffer, networkParentComponent?: typeof NetworkParent, forceCorrections?: boolean): CrdtMessageBody;
17
- export declare function localMessageToNetwork(message: ReceiveMessage, network: INetowrkEntityType, destinationBuffer: ByteBuffer): void;
18
- export declare function fixTransformParent(message: ReceiveMessage, parent?: Entity): Uint8Array;
@@ -1,135 +0,0 @@
1
- import { CrdtMessageProtocol } from '@dcl/ecs';
2
- import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer';
3
- import { AuthoritativePutComponentOperation, PutComponentOperation } from '@dcl/ecs/dist/serialization/crdt';
4
- import { CrdtMessageType } from '@dcl/ecs/dist/serialization/crdt/types';
5
- import { DeleteComponent } from '@dcl/ecs/dist/serialization/crdt/deleteComponent';
6
- import { DeleteEntity } from '@dcl/ecs/dist/serialization/crdt/deleteEntity';
7
- import { PutNetworkComponentOperation } from '@dcl/ecs/dist/serialization/crdt/network/putComponentNetwork';
8
- import { DeleteComponentNetwork } from '@dcl/ecs/dist/serialization/crdt/network/deleteComponentNetwork';
9
- import { DeleteEntityNetwork } from '@dcl/ecs/dist/serialization/crdt/network/deleteEntityNetwork';
10
- import { TransformSchema, COMPONENT_ID as TransformComponentId } from '@dcl/ecs/dist/components/manual/Transform';
11
- export function readMessages(data) {
12
- const buffer = new ReadWriteByteBuffer(data);
13
- const messages = [];
14
- let header;
15
- while ((header = CrdtMessageProtocol.getHeader(buffer))) {
16
- const offset = buffer.currentReadOffset();
17
- let message = undefined;
18
- // Network messages
19
- if (header.type === CrdtMessageType.DELETE_COMPONENT_NETWORK) {
20
- message = DeleteComponentNetwork.read(buffer);
21
- }
22
- else if (header.type === CrdtMessageType.PUT_COMPONENT_NETWORK) {
23
- message = PutNetworkComponentOperation.read(buffer);
24
- }
25
- else if (header.type === CrdtMessageType.DELETE_ENTITY_NETWORK) {
26
- message = DeleteEntityNetwork.read(buffer);
27
- }
28
- // Regular messages
29
- else if (header.type === CrdtMessageType.PUT_COMPONENT) {
30
- message = PutComponentOperation.read(buffer);
31
- }
32
- else if (header.type === CrdtMessageType.AUTHORITATIVE_PUT_COMPONENT) {
33
- message = AuthoritativePutComponentOperation.read(buffer);
34
- }
35
- else if (header.type === CrdtMessageType.DELETE_COMPONENT) {
36
- message = DeleteComponent.read(buffer);
37
- }
38
- else if (header.type === CrdtMessageType.DELETE_ENTITY) {
39
- message = DeleteEntity.read(buffer);
40
- }
41
- else {
42
- // consume unknown messages
43
- buffer.incrementReadOffset(header.length);
44
- }
45
- if (message) {
46
- messages.push({
47
- ...message,
48
- messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
49
- });
50
- }
51
- }
52
- return messages;
53
- }
54
- export function isNetworkMessage(message) {
55
- return [
56
- CrdtMessageType.DELETE_COMPONENT_NETWORK,
57
- CrdtMessageType.DELETE_ENTITY_NETWORK,
58
- CrdtMessageType.PUT_COMPONENT_NETWORK
59
- ].includes(message.type);
60
- }
61
- export function networkMessageToLocal(message, localEntityId, destinationBuffer,
62
- // Optional network parent component for transform fixing
63
- networkParentComponent,
64
- // Force corrections - converts PUT_COMPONENT_NETWORK to authoritative_PUT_COMPONENT
65
- forceCorrections = false) {
66
- if (message.type === CrdtMessageType.PUT_COMPONENT_NETWORK) {
67
- let messageData = message.data;
68
- // Fix transform parent if needed for Unity/engine processing
69
- if (message.componentId === TransformComponentId && networkParentComponent) {
70
- const parentNetwork = networkParentComponent.getOrNull(localEntityId);
71
- messageData = fixTransformParent(message, parentNetwork?.entityId);
72
- }
73
- if (forceCorrections) {
74
- // Use AUTHORITATIVE_PUT_COMPONENT for forced state updates
75
- AuthoritativePutComponentOperation.write(localEntityId, message.timestamp, message.componentId, messageData, destinationBuffer);
76
- return {
77
- type: CrdtMessageType.AUTHORITATIVE_PUT_COMPONENT,
78
- componentId: message.componentId,
79
- timestamp: message.timestamp,
80
- data: messageData,
81
- entityId: localEntityId
82
- };
83
- }
84
- else {
85
- // Normal PUT_COMPONENT conversion
86
- PutComponentOperation.write(localEntityId, message.timestamp, message.componentId, messageData, destinationBuffer);
87
- return {
88
- type: CrdtMessageType.PUT_COMPONENT,
89
- componentId: message.componentId,
90
- timestamp: message.timestamp,
91
- data: messageData,
92
- entityId: localEntityId
93
- };
94
- }
95
- }
96
- else if (message.type === CrdtMessageType.DELETE_COMPONENT_NETWORK) {
97
- DeleteComponent.write(localEntityId, message.componentId, message.timestamp, destinationBuffer);
98
- return {
99
- type: CrdtMessageType.DELETE_COMPONENT,
100
- componentId: message.componentId,
101
- timestamp: message.timestamp,
102
- entityId: localEntityId
103
- };
104
- }
105
- else if (message.type === CrdtMessageType.DELETE_ENTITY_NETWORK) {
106
- DeleteEntity.write(localEntityId, destinationBuffer);
107
- return {
108
- type: CrdtMessageType.DELETE_ENTITY,
109
- entityId: localEntityId
110
- };
111
- }
112
- throw 1;
113
- }
114
- export function localMessageToNetwork(message, network, destinationBuffer) {
115
- if (message.type === CrdtMessageType.PUT_COMPONENT) {
116
- PutNetworkComponentOperation.write(network.entityId, message.timestamp, message.componentId, network.networkId, message.data, destinationBuffer);
117
- }
118
- else if (message.type === CrdtMessageType.DELETE_COMPONENT) {
119
- DeleteComponentNetwork.write(network.entityId, message.componentId, message.timestamp, network.networkId, destinationBuffer);
120
- }
121
- else if (message.type === CrdtMessageType.DELETE_ENTITY) {
122
- DeleteEntityNetwork.write(network.entityId, network.networkId, destinationBuffer);
123
- }
124
- }
125
- export function fixTransformParent(message, parent) {
126
- const buffer = new ReadWriteByteBuffer();
127
- const transform = 'data' in message && TransformSchema.deserialize(new ReadWriteByteBuffer(message.data));
128
- if (!transform)
129
- throw new Error('Invalid parent transform');
130
- // Generate new transform raw data with the parent
131
- const newTransform = { ...transform, parent };
132
- TransformSchema.serialize(newTransform, buffer);
133
- return buffer.toBinary();
134
- }
135
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmV0d29yay9zZXJ2ZXIvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLG1CQUFtQixFQUFpQixNQUFNLFVBQVUsQ0FBQTtBQUc3RCxPQUFPLEVBQWMsbUJBQW1CLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQTtBQUN4RixPQUFPLEVBQUUsa0NBQWtDLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQTtBQUM1RyxPQUFPLEVBSUwsZUFBZSxFQVFoQixNQUFNLHdDQUF3QyxDQUFBO0FBQy9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxrREFBa0QsQ0FBQTtBQUNsRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sK0NBQStDLENBQUE7QUFFNUUsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sOERBQThELENBQUE7QUFDM0csT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0saUVBQWlFLENBQUE7QUFDeEcsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sOERBQThELENBQUE7QUFDbEcsT0FBTyxFQUFFLGVBQWUsRUFBRSxZQUFZLElBQUksb0JBQW9CLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQTtBQWdCakgsTUFBTSxVQUFVLFlBQVksQ0FBQyxJQUFnQjtJQUMzQyxNQUFNLE1BQU0sR0FBRyxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFBO0lBQzVDLE1BQU0sUUFBUSxHQUF3QyxFQUFFLENBQUE7SUFDeEQsSUFBSSxNQUFnQyxDQUFBO0lBQ3BDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsbUJBQW1CLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUU7UUFDdkQsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixFQUFFLENBQUE7UUFDekMsSUFBSSxPQUFPLEdBQTRCLFNBQVMsQ0FBQTtRQUVoRCxtQkFBbUI7UUFDbkIs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QUE7SUFFM0Qsa0RBQWtEO0lBQ2xELE1BQU0sWUFBWSxHQUFHLEVBQUUsR0FBRyxTQUFTLEVBQUUsTUFBTSxFQUFFLENBQUE7SUFDN0MsZUFBZSxDQUFDLFNBQVMsQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLENBQUE7SUFDL0MsT0FBTyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUE7QUFDMUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEVudGl0eSB9IGZyb20gJ0BkY2wvZWNzL2Rpc3QvZW5naW5lJ1xuaW1wb3J0IHsgQ3JkdE1lc3NhZ2VQcm90b2NvbCwgTmV0d29ya1BhcmVudCB9IGZyb20gJ0BkY2wvZWNzJ1xuaW1wb3J0IHsgUmVjZWl2ZU1lc3NhZ2UgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3J1bnRpbWUvdHlwZXMnXG5pbXBvcnQgeyBSZWNlaXZlTmV0d29ya01lc3NhZ2UgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3N5c3RlbXMvY3JkdC90eXBlcydcbmltcG9ydCB7IEJ5dGVCdWZmZXIsIFJlYWRXcml0ZUJ5dGVCdWZmZXIgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3NlcmlhbGl6YXRpb24vQnl0ZUJ1ZmZlcidcbmltcG9ydCB7IEF1dGhvcml0YXRpdmVQdXRDb21wb25lbnRPcGVyYXRpb24sIFB1dENvbXBvbmVudE9wZXJhdGlvbiB9IGZyb20gJ0BkY2wvZWNzL2Rpc3Qvc2VyaWFsaXphdGlvbi9jcmR0J1xuaW1wb3J0IHtcbiAgQ3JkdE1lc3NhZ2UsXG4gIENyZHRNZXNzYWdlQm9keSxcbiAgQ3JkdE1lc3NhZ2VIZWFkZXIsXG4gIENyZHRNZXNzYWdlVHlwZSxcbiAgRGVsZXRlQ29tcG9uZW50TWVzc2FnZSxcbiAgRGVsZXRlQ29tcG9uZW50TmV0d29ya01lc3NhZ2UsXG4gIERlbGV0ZUVudGl0eU1lc3NhZ2UsXG4gIERlbGV0ZUVudGl0eU5ldHdvcmtNZXNzYWdlLFxuICBQdXRDb21wb25lbnRNZXNzYWdlLFxuICBBdXRob3JpdGF0aXZlUHV0Q29tcG9uZW50TWVzc2FnZSxcbiAgUHV0TmV0d29ya0NvbXBvbmVudE1lc3NhZ2Vcbn0gZnJvbSAnQGRjbC9lY3MvZGlzdC9zZXJpYWxpemF0aW9uL2NyZHQvdHlwZXMnXG5pbXBvcnQgeyBEZWxldGVDb21wb25lbnQgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3NlcmlhbGl6YXRpb24vY3JkdC9kZWxldGVDb21wb25lbnQnXG5pbXBvcnQgeyBEZWxldGVFbnRpdHkgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3NlcmlhbGl6YXRpb24vY3JkdC9kZWxldGVFbnRpdHknXG5pbXBvcnQgeyBJTmV0b3dya0VudGl0eVR5cGUgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L2NvbXBvbmVudHMvdHlwZXMnXG5pbXBvcnQgeyBQdXROZXR3b3JrQ29tcG9uZW50T3BlcmF0aW9uIH0gZnJvbSAnQGRjbC9lY3MvZGlzdC9zZXJpYWxpemF0aW9uL2NyZHQvbmV0d29yay9wdXRDb21wb25lbnROZXR3b3JrJ1xuaW1wb3J0IHsgRGVsZXRlQ29tcG9uZW50TmV0d29yayB9IGZyb20gJ0BkY2wvZWNzL2Rpc3Qvc2VyaWFsaXphdGlvbi9jcmR0L25ldHdvcmsvZGVsZXRlQ29tcG9uZW50TmV0d29yaydcbmltcG9ydCB7IERlbGV0ZUVudGl0eU5ldHdvcmsgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3NlcmlhbGl6YXRpb24vY3JkdC9uZXR3b3JrL2RlbGV0ZUVudGl0eU5ldHdvcmsnXG5pbXBvcnQgeyBUcmFuc2Zvcm1TY2hlbWEsIENPTVBPTkVOVF9JRCBhcyBUcmFuc2Zvcm1Db21wb25lbnRJZCB9IGZyb20gJ0BkY2wvZWNzL2Rpc3QvY29tcG9uZW50cy9tYW51YWwvVHJhbnNmb3JtJ1xuXG5leHBvcnQgdHlwZSBOZXR3b3JrTWVzc2FnZSA9IChcbiAgfCBQdXROZXR3b3JrQ29tcG9uZW50TWVzc2FnZVxuICB8IERlbGV0ZUNvbXBvbmVudE5ldHdvcmtNZXNzYWdlXG4gIHwgRGVsZXRlRW50aXR5TmV0d29ya01lc3NhZ2VcbikgJiB7IG1lc3NhZ2VCdWZmZXI6IFVpbnQ4QXJyYXkgfVxuXG5leHBvcnQgdHlwZSBSZWd1bGFyTWVzc2FnZSA9IChcbiAgfCBQdXRDb21wb25lbnRNZXNzYWdlXG4gIHwgQXV0aG9yaXRhdGl2ZVB1dENvbXBvbmVudE1lc3NhZ2VcbiAgfCBEZWxldGVDb21wb25lbnRNZXNzYWdlXG4gIHwgRGVsZXRlRW50aXR5TWVzc2FnZVxuKSAmIHtcbiAgbWVzc2FnZUJ1ZmZlcjogVWludDhBcnJheVxufVxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRNZXNzYWdlcyhkYXRhOiBVaW50OEFycmF5KTogKE5ldHdvcmtNZXNzYWdlIHwgUmVndWxhck1lc3NhZ2UpW10ge1xuICBjb25zdCBidWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcihkYXRhKVxuICBjb25zdCBtZXNzYWdlczogKE5ldHdvcmtNZXNzYWdlIHwgUmVndWxhck1lc3NhZ2UpW10gPSBbXVxuICBsZXQgaGVhZGVyOiBDcmR0TWVzc2FnZUhlYWRlciB8IG51bGxcbiAgd2hpbGUgKChoZWFkZXIgPSBDcmR0TWVzc2FnZVByb3RvY29sLmdldEhlYWRlcihidWZmZXIpKSkge1xuICAgIGNvbnN0IG9mZnNldCA9IGJ1ZmZlci5jdXJyZW50UmVhZE9mZnNldCgpXG4gICAgbGV0IG1lc3NhZ2U6IENyZHRNZXNzYWdlIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG5cbiAgICAvLyBOZXR3b3JrIG1lc3NhZ2VzXG4gICAgaWYgKGhlYWRlci50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0NPTVBPTkVOVF9ORVRXT1JLKSB7XG4gICAgICBtZXNzYWdlID0gRGVsZXRlQ29tcG9uZW50TmV0d29yay5yZWFkKGJ1ZmZlcikhXG4gICAgfSBlbHNlIGlmIChoZWFkZXIudHlwZSA9PT0gQ3JkdE1lc3NhZ2VUeXBlLlBVVF9DT01QT05FTlRfTkVUV09SSykge1xuICAgICAgbWVzc2FnZSA9IFB1dE5ldHdvcmtDb21wb25lbnRPcGVyYXRpb24ucmVhZChidWZmZXIpIVxuICAgIH0gZWxzZSBpZiAoaGVhZGVyLnR5cGUgPT09IENyZHRNZXNzYWdlVHlwZS5ERUxFVEVfRU5USVRZX05FVFdPUkspIHtcbiAgICAgIG1lc3NhZ2UgPSBEZWxldGVFbnRpdHlOZXR3b3JrLnJlYWQoYnVmZmVyKSFcbiAgICB9XG4gICAgLy8gUmVndWxhciBtZXNzYWdlc1xuICAgIGVsc2UgaWYgKGhlYWRlci50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuUFVUX0NPTVBPTkVOVCkge1xuICAgICAgbWVzc2FnZSA9IFB1dENvbXBvbmVudE9wZXJhdGlvbi5yZWFkKGJ1ZmZlcikhXG4gICAgfSBlbHNlIGlmIChoZWFkZXIudHlwZSA9PT0gQ3JkdE1lc3NhZ2VUeXBlLkFVVEhPUklUQVRJVkVfUFVUX0NPTVBPTkVOVCkge1xuICAgICAgbWVzc2FnZSA9IEF1dGhvcml0YXRpdmVQdXRDb21wb25lbnRPcGVyYXRpb24ucmVhZChidWZmZXIpIVxuICAgIH0gZWxzZSBpZiAoaGVhZGVyLnR5cGUgPT09IENyZHRNZXNzYWdlVHlwZS5ERUxFVEVfQ09NUE9ORU5UKSB7XG4gICAgICBtZXNzYWdlID0gRGVsZXRlQ29tcG9uZW50LnJlYWQoYnVmZmVyKSFcbiAgICB9IGVsc2UgaWYgKGhlYWRlci50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0VOVElUWSkge1xuICAgICAgbWVzc2FnZSA9IERlbGV0ZUVudGl0eS5yZWFkKGJ1ZmZlcikhXG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGNvbnN1bWUgdW5rbm93biBtZXNzYWdlc1xuICAgICAgYnVmZmVyLmluY3JlbWVudFJlYWRPZmZzZXQoaGVhZGVyLmxlbmd0aClcbiAgICB9XG5cbiAgICBpZiAobWVzc2FnZSkge1xuICAgICAgbWVzc2FnZXMucHVzaCh7XG4gICAgICAgIC4uLm1lc3NhZ2UsXG4gICAgICAgIG1lc3NhZ2VCdWZmZXI6IGJ1ZmZlci5idWZmZXIoKS5zdWJhcnJheShvZmZzZXQsIGJ1ZmZlci5jdXJyZW50UmVhZE9mZnNldCgpKVxuICAgICAgfSlcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG1lc3NhZ2VzXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc05ldHdvcmtNZXNzYWdlKG1lc3NhZ2U6IFJlY2VpdmVNZXNzYWdlKTogbWVzc2FnZSBpcyBSZWNlaXZlTmV0d29ya01lc3NhZ2Uge1xuICByZXR1cm4gW1xuICAgIENyZHRNZXNzYWdlVHlwZS5ERUxFVEVfQ09NUE9ORU5UX05FVFdPUkssXG4gICAgQ3JkdE1lc3NhZ2VUeXBlLkRFTEVURV9FTlRJVFlfTkVUV09SSyxcbiAgICBDcmR0TWVzc2FnZVR5cGUuUFVUX0NPTVBPTkVOVF9ORVRXT1JLXG4gIF0uaW5jbHVkZXMobWVzc2FnZS50eXBlKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbmV0d29ya01lc3NhZ2VUb0xvY2FsKFxuICBtZXNzYWdlOiBSZWNlaXZlTmV0d29ya01lc3NhZ2UsXG4gIGxvY2FsRW50aXR5SWQ6IEVudGl0eSxcbiAgZGVzdGluYXRpb25CdWZmZXI6IEJ5dGVCdWZmZXIsXG4gIC8vIE9wdGlvbmFsIG5ldHdvcmsgcGFyZW50IGNvbXBvbmVudCBmb3IgdHJhbnNmb3JtIGZpeGluZ1xuICBuZXR3b3JrUGFyZW50Q29tcG9uZW50PzogdHlwZW9mIE5ldHdvcmtQYXJlbnQsXG4gIC8vIEZvcmNlIGNvcnJlY3Rpb25zIC0gY29udmVydHMgUFVUX0NPTVBPTkVOVF9ORVRXT1JLIHRvIGF1dGhvcml0YXRpdmVfUFVUX0NPTVBPTkVOVFxuICBmb3JjZUNvcnJlY3Rpb25zID0gZmFsc2Vcbik6IENyZHRNZXNzYWdlQm9keSB7XG4gIGlmIChtZXNzYWdlLnR5cGUgPT09IENyZHRNZXNzYWdlVHlwZS5QVVRfQ09NUE9ORU5UX05FVFdPUkspIHtcbiAgICBsZXQgbWVzc2FnZURhdGEgPSBtZXNzYWdlLmRhdGFcblxuICAgIC8vIEZpeCB0cmFuc2Zvcm0gcGFyZW50IGlmIG5lZWRlZCBmb3IgVW5pdHkvZW5naW5lIHByb2Nlc3NpbmdcbiAgICBpZiAobWVzc2FnZS5jb21wb25lbnRJZCA9PT0gVHJhbnNmb3JtQ29tcG9uZW50SWQgJiYgbmV0d29ya1BhcmVudENvbXBvbmVudCkge1xuICAgICAgY29uc3QgcGFyZW50TmV0d29yayA9IG5ldHdvcmtQYXJlbnRDb21wb25lbnQuZ2V0T3JOdWxsKGxvY2FsRW50aXR5SWQpXG4gICAgICBtZXNzYWdlRGF0YSA9IGZpeFRyYW5zZm9ybVBhcmVudChtZXNzYWdlLCBwYXJlbnROZXR3b3JrPy5lbnRpdHlJZClcbiAgICB9XG4gICAgaWYgKGZvcmNlQ29ycmVjdGlvbnMpIHtcbiAgICAgIC8vIFVzZSBBVVRIT1JJVEFUSVZFX1BVVF9DT01QT05FTlQgZm9yIGZvcmNlZCBzdGF0ZSB1cGRhdGVzXG4gICAgICBBdXRob3JpdGF0aXZlUHV0Q29tcG9uZW50T3BlcmF0aW9uLndyaXRlKFxuICAgICAgICBsb2NhbEVudGl0eUlkLFxuICAgICAgICBtZXNzYWdlLnRpbWVzdGFtcCxcbiAgICAgICAgbWVzc2FnZS5jb21wb25lbnRJZCxcbiAgICAgICAgbWVzc2FnZURhdGEsXG4gICAgICAgIGRlc3RpbmF0aW9uQnVmZmVyXG4gICAgICApXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0eXBlOiBDcmR0TWVzc2FnZVR5cGUuQVVUSE9SSVRBVElWRV9QVVRfQ09NUE9ORU5ULFxuICAgICAgICBjb21wb25lbnRJZDogbWVzc2FnZS5jb21wb25lbnRJZCxcbiAgICAgICAgdGltZXN0YW1wOiBtZXNzYWdlLnRpbWVzdGFtcCxcbiAgICAgICAgZGF0YTogbWVzc2FnZURhdGEsXG4gICAgICAgIGVudGl0eUlkOiBsb2NhbEVudGl0eUlkXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE5vcm1hbCBQVVRfQ09NUE9ORU5UIGNvbnZlcnNpb25cbiAgICAgIFB1dENvbXBvbmVudE9wZXJhdGlvbi53cml0ZShsb2NhbEVudGl0eUlkLCBtZXNzYWdlLnRpbWVzdGFtcCwgbWVzc2FnZS5jb21wb25lbnRJZCwgbWVzc2FnZURhdGEsIGRlc3RpbmF0aW9uQnVmZmVyKVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogQ3JkdE1lc3NhZ2VUeXBlLlBVVF9DT01QT05FTlQsXG4gICAgICAgIGNvbXBvbmVudElkOiBtZXNzYWdlLmNvbXBvbmVudElkLFxuICAgICAgICB0aW1lc3RhbXA6IG1lc3NhZ2UudGltZXN0YW1wLFxuICAgICAgICBkYXRhOiBtZXNzYWdlRGF0YSxcbiAgICAgICAgZW50aXR5SWQ6IGxvY2FsRW50aXR5SWRcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0NPTVBPTkVOVF9ORVRXT1JLKSB7XG4gICAgRGVsZXRlQ29tcG9uZW50LndyaXRlKGxvY2FsRW50aXR5SWQsIG1lc3NhZ2UuY29tcG9uZW50SWQsIG1lc3NhZ2UudGltZXN0YW1wLCBkZXN0aW5hdGlvbkJ1ZmZlcilcbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogQ3JkdE1lc3NhZ2VUeXBlLkRFTEVURV9DT01QT05FTlQsXG4gICAgICBjb21wb25lbnRJZDogbWVzc2FnZS5jb21wb25lbnRJZCxcbiAgICAgIHRpbWVzdGFtcDogbWVzc2FnZS50aW1lc3RhbXAsXG4gICAgICBlbnRpdHlJZDogbG9jYWxFbnRpdHlJZFxuICAgIH1cbiAgfSBlbHNlIGlmIChtZXNzYWdlLnR5cGUgPT09IENyZHRNZXNzYWdlVHlwZS5ERUxFVEVfRU5USVRZX05FVFdPUkspIHtcbiAgICBEZWxldGVFbnRpdHkud3JpdGUobG9jYWxFbnRpdHlJZCwgZGVzdGluYXRpb25CdWZmZXIpXG4gICAgcmV0dXJuIHtcbiAgICAgIHR5cGU6IENyZHRNZXNzYWdlVHlwZS5ERUxFVEVfRU5USVRZLFxuICAgICAgZW50aXR5SWQ6IGxvY2FsRW50aXR5SWRcbiAgICB9XG4gIH1cbiAgdGhyb3cgMVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbG9jYWxNZXNzYWdlVG9OZXR3b3JrKFxuICBtZXNzYWdlOiBSZWNlaXZlTWVzc2FnZSxcbiAgbmV0d29yazogSU5ldG93cmtFbnRpdHlUeXBlLFxuICBkZXN0aW5hdGlvbkJ1ZmZlcjogQnl0ZUJ1ZmZlclxuKSB7XG4gIGlmIChtZXNzYWdlLnR5cGUgPT09IENyZHRNZXNzYWdlVHlwZS5QVVRfQ09NUE9ORU5UKSB7XG4gICAgUHV0TmV0d29ya0NvbXBvbmVudE9wZXJhdGlvbi53cml0ZShcbiAgICAgIG5ldHdvcmsuZW50aXR5SWQsXG4gICAgICBtZXNzYWdlLnRpbWVzdGFtcCxcbiAgICAgIG1lc3NhZ2UuY29tcG9uZW50SWQsXG4gICAgICBuZXR3b3JrLm5ldHdvcmtJZCxcbiAgICAgIG1lc3NhZ2UuZGF0YSxcbiAgICAgIGRlc3RpbmF0aW9uQnVmZmVyXG4gICAgKVxuICB9IGVsc2UgaWYgKG1lc3NhZ2UudHlwZSA9PT0gQ3JkdE1lc3NhZ2VUeXBlLkRFTEVURV9DT01QT05FTlQpIHtcbiAgICBEZWxldGVDb21wb25lbnROZXR3b3JrLndyaXRlKFxuICAgICAgbmV0d29yay5lbnRpdHlJZCxcbiAgICAgIG1lc3NhZ2UuY29tcG9uZW50SWQsXG4gICAgICBtZXNzYWdlLnRpbWVzdGFtcCxcbiAgICAgIG5ldHdvcmsubmV0d29ya0lkLFxuICAgICAgZGVzdGluYXRpb25CdWZmZXJcbiAgICApXG4gIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0VOVElUWSkge1xuICAgIERlbGV0ZUVudGl0eU5ldHdvcmsud3JpdGUobmV0d29yay5lbnRpdHlJZCwgbmV0d29yay5uZXR3b3JrSWQsIGRlc3RpbmF0aW9uQnVmZmVyKVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmaXhUcmFuc2Zvcm1QYXJlbnQobWVzc2FnZTogUmVjZWl2ZU1lc3NhZ2UsIHBhcmVudD86IEVudGl0eSk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBidWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcigpXG4gIGNvbnN0IHRyYW5zZm9ybSA9ICdkYXRhJyBpbiBtZXNzYWdlICYmIFRyYW5zZm9ybVNjaGVtYS5kZXNlcmlhbGl6ZShuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcihtZXNzYWdlLmRhdGEpKVxuXG4gIGlmICghdHJhbnNmb3JtKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcGFyZW50IHRyYW5zZm9ybScpXG5cbiAgLy8gR2VuZXJhdGUgbmV3IHRyYW5zZm9ybSByYXcgZGF0YSB3aXRoIHRoZSBwYXJlbnRcbiAgY29uc3QgbmV3VHJhbnNmb3JtID0geyAuLi50cmFuc2Zvcm0sIHBhcmVudCB9XG4gIFRyYW5zZm9ybVNjaGVtYS5zZXJpYWxpemUobmV3VHJhbnNmb3JtLCBidWZmZXIpXG4gIHJldHVybiBidWZmZXIudG9CaW5hcnkoKVxufVxuIl19
@@ -1,15 +0,0 @@
1
- /**
2
- * EnvVar provides methods to fetch environment variables from the
3
- * Server Side Storage service. This module only works when running
4
- * on server-side scenes.
5
- */
6
- export declare const EnvVar: {
7
- /**
8
- * Fetches a specific environment variable by key as plain text.
9
- *
10
- * @param key - The name of the environment variable to fetch
11
- * @returns A promise that resolves to the plain text value, or empty string if not found
12
- * @throws Error if not running on a server-side scene
13
- */
14
- get(key: string): Promise<string>;
15
- };
package/server/env-var.js DELETED
@@ -1,31 +0,0 @@
1
- import { getStorageServerUrl } from './storage-url';
2
- import { assertIsServer, wrapSignedFetch } from './utils';
3
- const MODULE_NAME = 'EnvVar';
4
- /**
5
- * EnvVar provides methods to fetch environment variables from the
6
- * Server Side Storage service. This module only works when running
7
- * on server-side scenes.
8
- */
9
- export const EnvVar = {
10
- /**
11
- * Fetches a specific environment variable by key as plain text.
12
- *
13
- * @param key - The name of the environment variable to fetch
14
- * @returns A promise that resolves to the plain text value, or empty string if not found
15
- * @throws Error if not running on a server-side scene
16
- */
17
- async get(key) {
18
- assertIsServer(MODULE_NAME);
19
- const baseUrl = await getStorageServerUrl();
20
- const url = `${baseUrl}/env/${encodeURIComponent(key)}`;
21
- const [error, data] = await wrapSignedFetch({
22
- url
23
- });
24
- if (error) {
25
- console.error(`Failed to fetch environment variable '${key}': ${error}`);
26
- return '';
27
- }
28
- return data?.value ?? '';
29
- }
30
- };
31
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LXZhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zZXJ2ZXIvZW52LXZhci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDbkQsT0FBTyxFQUFFLGNBQWMsRUFBRSxlQUFlLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFFekQsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFBO0FBRTVCOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxNQUFNLEdBQUc7SUFDcEI7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFXO1FBQ25CLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUUzQixNQUFNLE9BQU8sR0FBRyxNQUFNLG1CQUFtQixFQUFFLENBQUE7UUFDM0MsTUFBTSxHQUFHLEdBQUcsR0FBRyxPQUFPLFFBQVEsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQTtRQUV2RCxNQUFNLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLE1BQU0sZUFBZSxDQUFvQjtZQUM3RCxHQUFHO1NBQ0osQ0FBQyxDQUFBO1FBRUYsSUFBSSxLQUFLLEVBQUU7WUFDVCxPQUFPLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxHQUFHLE1BQU0sS0FBSyxFQUFFLENBQUMsQ0FBQTtZQUN4RSxPQUFPLEVBQUUsQ0FBQTtTQUNWO1FBRUQsT0FBTyxJQUFJLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQTtJQUMxQixDQUFDO0NBQ0YsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldFN0b3JhZ2VTZXJ2ZXJVcmwgfSBmcm9tICcuL3N0b3JhZ2UtdXJsJ1xuaW1wb3J0IHsgYXNzZXJ0SXNTZXJ2ZXIsIHdyYXBTaWduZWRGZXRjaCB9IGZyb20gJy4vdXRpbHMnXG5cbmNvbnN0IE1PRFVMRV9OQU1FID0gJ0VudlZhcidcblxuLyoqXG4gKiBFbnZWYXIgcHJvdmlkZXMgbWV0aG9kcyB0byBmZXRjaCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZnJvbSB0aGVcbiAqIFNlcnZlciBTaWRlIFN0b3JhZ2Ugc2VydmljZS4gVGhpcyBtb2R1bGUgb25seSB3b3JrcyB3aGVuIHJ1bm5pbmdcbiAqIG9uIHNlcnZlci1zaWRlIHNjZW5lcy5cbiAqL1xuZXhwb3J0IGNvbnN0IEVudlZhciA9IHtcbiAgLyoqXG4gICAqIEZldGNoZXMgYSBzcGVjaWZpYyBlbnZpcm9ubWVudCB2YXJpYWJsZSBieSBrZXkgYXMgcGxhaW4gdGV4dC5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFRoZSBuYW1lIG9mIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZSB0byBmZXRjaFxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcGxhaW4gdGV4dCB2YWx1ZSwgb3IgZW1wdHkgc3RyaW5nIGlmIG5vdCBmb3VuZFxuICAgKiBAdGhyb3dzIEVycm9yIGlmIG5vdCBydW5uaW5nIG9uIGEgc2VydmVyLXNpZGUgc2NlbmVcbiAgICovXG4gIGFzeW5jIGdldChrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgYXNzZXJ0SXNTZXJ2ZXIoTU9EVUxFX05BTUUpXG5cbiAgICBjb25zdCBiYXNlVXJsID0gYXdhaXQgZ2V0U3RvcmFnZVNlcnZlclVybCgpXG4gICAgY29uc3QgdXJsID0gYCR7YmFzZVVybH0vZW52LyR7ZW5jb2RlVVJJQ29tcG9uZW50KGtleSl9YFxuXG4gICAgY29uc3QgW2Vycm9yLCBkYXRhXSA9IGF3YWl0IHdyYXBTaWduZWRGZXRjaDx7IHZhbHVlOiBzdHJpbmcgfT4oe1xuICAgICAgdXJsXG4gICAgfSlcblxuICAgIGlmIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGZldGNoIGVudmlyb25tZW50IHZhcmlhYmxlICcke2tleX0nOiAke2Vycm9yfWApXG4gICAgICByZXR1cm4gJydcbiAgICB9XG5cbiAgICByZXR1cm4gZGF0YT8udmFsdWUgPz8gJydcbiAgfVxufVxuIl19
package/server/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export { EnvVar } from './env-var';
2
- export { Storage, IStorage, ISceneStorage, IPlayerStorage, GetOptions, GetValuesOptions, GetValuesResult, SetOptions, StorageOptions } from './storage';
package/server/index.js DELETED
@@ -1,3 +0,0 @@
1
- export { EnvVar } from './env-var';
2
- export { Storage } from './storage';
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2VydmVyL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDbEMsT0FBTyxFQUNMLE9BQU8sRUFTUixNQUFNLFdBQVcsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IEVudlZhciB9IGZyb20gJy4vZW52LXZhcidcbmV4cG9ydCB7XG4gIFN0b3JhZ2UsXG4gIElTdG9yYWdlLFxuICBJU2NlbmVTdG9yYWdlLFxuICBJUGxheWVyU3RvcmFnZSxcbiAgR2V0T3B0aW9ucyxcbiAgR2V0VmFsdWVzT3B0aW9ucyxcbiAgR2V0VmFsdWVzUmVzdWx0LFxuICBTZXRPcHRpb25zLFxuICBTdG9yYWdlT3B0aW9uc1xufSBmcm9tICcuL3N0b3JhZ2UnXG4iXX0=
@@ -1,79 +0,0 @@
1
- export declare const MODULE_NAME = "Storage";
2
- /**
3
- * Options for getValues pagination and filtering.
4
- */
5
- export interface GetValuesOptions {
6
- prefix?: string;
7
- limit?: number;
8
- offset?: number;
9
- }
10
- /**
11
- * Result of getValues with pagination metadata.
12
- */
13
- export interface GetValuesResult {
14
- /** Key-value entries for the current page. */
15
- data: Array<{
16
- key: string;
17
- value: unknown;
18
- }>;
19
- pagination: {
20
- offset: number;
21
- total: number;
22
- };
23
- }
24
- /**
25
- * Per-call options for Storage get().
26
- */
27
- export interface GetOptions {
28
- /**
29
- * When true, bypasses the read cache and forces a network read (the result
30
- * still refreshes the cache). Concurrent gets for the same key still share
31
- * one in-flight request. Default: false.
32
- */
33
- fresh?: boolean;
34
- }
35
- /**
36
- * Per-call options for Storage set().
37
- */
38
- export interface SetOptions {
39
- /**
40
- * When true, skips the network write if the serialized value matches the
41
- * last value known to be stored for this key (from a previous successful
42
- * set() or get()). Overrides the configured default. Default: true.
43
- */
44
- skipIfUnchanged?: boolean;
45
- }
46
- /**
47
- * Module-wide configuration for Storage, applied to both scene-scoped and
48
- * player-scoped storage via Storage.configure().
49
- */
50
- export interface StorageOptions {
51
- /**
52
- * Default for set()'s skipIfUnchanged when not passed per call. A skip only
53
- * suppresses a proven no-op: the exact serialized value was confirmed stored
54
- * by a previous network round-trip within cacheMaxAgeMs. Default: true.
55
- */
56
- skipIfUnchanged?: boolean;
57
- /**
58
- * When true, get() serves values from the local cache within cacheMaxAgeMs,
59
- * including confirmed "not found" results, without a network request.
60
- * Out-of-band writers (e.g. CLI storage commands) may not be visible for up
61
- * to cacheMaxAgeMs; pass { fresh: true } per call to force a network read.
62
- * Default: true.
63
- */
64
- cacheReads?: boolean;
65
- /**
66
- * Max cache entries per scope (scene / player) before oldest entries are
67
- * evicted. Entries hold the serialized value body, so memory scales with
68
- * value size — this bounds entry count, not bytes. Default: 512.
69
- */
70
- cacheMaxEntries?: number;
71
- /**
72
- * Max age of a cache entry in milliseconds, bounding both read-cache
73
- * staleness and write-dedup trust; older entries are treated as unknown.
74
- * The default is deliberately short so out-of-band writers (CLI storage
75
- * commands, dashboards) become visible within a minute, while still
76
- * absorbing hot per-frame reads. Default: 60000 (1 minute).
77
- */
78
- cacheMaxAgeMs?: number;
79
- }
@@ -1,19 +0,0 @@
1
- export const MODULE_NAME = 'Storage';
2
- /**
3
- * Default values for the resolved storage configuration.
4
- * @internal
5
- */
6
- export const DEFAULT_STORAGE_CONFIG = {
7
- skipIfUnchanged: true,
8
- cacheReads: true,
9
- cacheMaxEntries: 512,
10
- cacheMaxAgeMs: 60 * 1000
11
- };
12
- /**
13
- * Creates a mutable config object, later mutated by Storage.configure().
14
- * @internal
15
- */
16
- export function createStorageConfig(overrides) {
17
- return { ...DEFAULT_STORAGE_CONFIG, ...overrides };
18
- }
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci9zdG9yYWdlL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsU0FBUyxDQUFBO0FBNkZwQzs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBaUM7SUFDbEUsZUFBZSxFQUFFLElBQUk7SUFDckIsVUFBVSxFQUFFLElBQUk7SUFDaEIsZUFBZSxFQUFFLEdBQUc7SUFDcEIsYUFBYSxFQUFFLEVBQUUsR0FBRyxJQUFJO0NBQ3pCLENBQUE7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBQUMsU0FBMEI7SUFDNUQsT0FBTyxFQUFFLEdBQUcsc0JBQXNCLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQTtBQUNwRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IE1PRFVMRV9OQU1FID0gJ1N0b3JhZ2UnXG5cbi8qKlxuICogT3B0aW9ucyBmb3IgZ2V0VmFsdWVzIHBhZ2luYXRpb24gYW5kIGZpbHRlcmluZy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZXRWYWx1ZXNPcHRpb25zIHtcbiAgcHJlZml4Pzogc3RyaW5nXG4gIGxpbWl0PzogbnVtYmVyXG4gIG9mZnNldD86IG51bWJlclxufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBnZXRWYWx1ZXMgd2l0aCBwYWdpbmF0aW9uIG1ldGFkYXRhLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdldFZhbHVlc1Jlc3VsdCB7XG4gIC8qKiBLZXktdmFsdWUgZW50cmllcyBmb3IgdGhlIGN1cnJlbnQgcGFnZS4gKi9cbiAgZGF0YTogQXJyYXk8eyBrZXk6IHN0cmluZzsgdmFsdWU6IHVua25vd24gfT5cbiAgcGFnaW5hdGlvbjoge1xuICAgIG9mZnNldDogbnVtYmVyXG4gICAgdG90YWw6IG51bWJlclxuICB9XG59XG5cbi8qKlxuICogUGVyLWNhbGwgb3B0aW9ucyBmb3IgU3RvcmFnZSBnZXQoKS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZXRPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZW4gdHJ1ZSwgYnlwYXNzZXMgdGhlIHJlYWQgY2FjaGUgYW5kIGZvcmNlcyBhIG5ldHdvcmsgcmVhZCAodGhlIHJlc3VsdFxuICAgKiBzdGlsbCByZWZyZXNoZXMgdGhlIGNhY2hlKS4gQ29uY3VycmVudCBnZXRzIGZvciB0aGUgc2FtZSBrZXkgc3RpbGwgc2hhcmVcbiAgICogb25lIGluLWZsaWdodCByZXF1ZXN0LiBEZWZhdWx0OiBmYWxzZS5cbiAgICovXG4gIGZyZXNoPzogYm9vbGVhblxufVxuXG4vKipcbiAqIFBlci1jYWxsIG9wdGlvbnMgZm9yIFN0b3JhZ2Ugc2V0KCkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2V0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGVuIHRydWUsIHNraXBzIHRoZSBuZXR3b3JrIHdyaXRlIGlmIHRoZSBzZXJpYWxpemVkIHZhbHVlIG1hdGNoZXMgdGhlXG4gICAqIGxhc3QgdmFsdWUga25vd24gdG8gYmUgc3RvcmVkIGZvciB0aGlzIGtleSAoZnJvbSBhIHByZXZpb3VzIHN1Y2Nlc3NmdWxcbiAgICogc2V0KCkgb3IgZ2V0KCkpLiBPdmVycmlkZXMgdGhlIGNvbmZpZ3VyZWQgZGVmYXVsdC4gRGVmYXVsdDogdHJ1ZS5cbiAgICovXG4gIHNraXBJZlVuY2hhbmdlZD86IGJvb2xlYW5cbn1cblxuLyoqXG4gKiBNb2R1bGUtd2lkZSBjb25maWd1cmF0aW9uIGZvciBTdG9yYWdlLCBhcHBsaWVkIHRvIGJvdGggc2NlbmUtc2NvcGVkIGFuZFxuICogcGxheWVyLXNjb3BlZCBzdG9yYWdlIHZpYSBTdG9yYWdlLmNvbmZpZ3VyZSgpLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0b3JhZ2VPcHRpb25zIHtcbiAgLyoqXG4gICAqIERlZmF1bHQgZm9yIHNldCgpJ3Mgc2tpcElmVW5jaGFuZ2VkIHdoZW4gbm90IHBhc3NlZCBwZXIgY2FsbC4gQSBza2lwIG9ubHlcbiAgICogc3VwcHJlc3NlcyBhIHByb3ZlbiBuby1vcDogdGhlIGV4YWN0IHNlcmlhbGl6ZWQgdmFsdWUgd2FzIGNvbmZpcm1lZCBzdG9yZWRcbiAgICogYnkgYSBwcmV2aW91cyBuZXR3b3JrIHJvdW5kLXRyaXAgd2l0aGluIGNhY2hlTWF4QWdlTXMuIERlZmF1bHQ6IHRydWUuXG4gICAqL1xuICBza2lwSWZVbmNoYW5nZWQ/OiBib29sZWFuXG4gIC8qKlxuICAgKiBXaGVuIHRydWUsIGdldCgpIHNlcnZlcyB2YWx1ZXMgZnJvbSB0aGUgbG9jYWwgY2FjaGUgd2l0aGluIGNhY2hlTWF4QWdlTXMsXG4gICAqIGluY2x1ZGluZyBjb25maXJtZWQgXCJub3QgZm91bmRcIiByZXN1bHRzLCB3aXRob3V0IGEgbmV0d29yayByZXF1ZXN0LlxuICAgKiBPdXQtb2YtYmFuZCB3cml0ZXJzIChlLmcuIENMSSBzdG9yYWdlIGNvbW1hbmRzKSBtYXkgbm90IGJlIHZpc2libGUgZm9yIHVwXG4gICAqIHRvIGNhY2hlTWF4QWdlTXM7IHBhc3MgeyBmcmVzaDogdHJ1ZSB9IHBlciBjYWxsIHRvIGZvcmNlIGEgbmV0d29yayByZWFkLlxuICAgKiBEZWZhdWx0OiB0cnVlLlxuICAgKi9cbiAgY2FjaGVSZWFkcz86IGJvb2xlYW5cbiAgLyoqXG4gICAqIE1heCBjYWNoZSBlbnRyaWVzIHBlciBzY29wZSAoc2NlbmUgLyBwbGF5ZXIpIGJlZm9yZSBvbGRlc3QgZW50cmllcyBhcmVcbiAgICogZXZpY3RlZC4gRW50cmllcyBob2xkIHRoZSBzZXJpYWxpemVkIHZhbHVlIGJvZHksIHNvIG1lbW9yeSBzY2FsZXMgd2l0aFxuICAgKiB2YWx1ZSBzaXplIOKAlCB0aGlzIGJvdW5kcyBlbnRyeSBjb3VudCwgbm90IGJ5dGVzLiBEZWZhdWx0OiA1MTIuXG4gICAqL1xuICBjYWNoZU1heEVudHJpZXM/OiBudW1iZXJcbiAgLyoqXG4gICAqIE1heCBhZ2Ugb2YgYSBjYWNoZSBlbnRyeSBpbiBtaWxsaXNlY29uZHMsIGJvdW5kaW5nIGJvdGggcmVhZC1jYWNoZVxuICAgKiBzdGFsZW5lc3MgYW5kIHdyaXRlLWRlZHVwIHRydXN0OyBvbGRlciBlbnRyaWVzIGFyZSB0cmVhdGVkIGFzIHVua25vd24uXG4gICAqIFRoZSBkZWZhdWx0IGlzIGRlbGliZXJhdGVseSBzaG9ydCBzbyBvdXQtb2YtYmFuZCB3cml0ZXJzIChDTEkgc3RvcmFnZVxuICAgKiBjb21tYW5kcywgZGFzaGJvYXJkcykgYmVjb21lIHZpc2libGUgd2l0aGluIGEgbWludXRlLCB3aGlsZSBzdGlsbFxuICAgKiBhYnNvcmJpbmcgaG90IHBlci1mcmFtZSByZWFkcy4gRGVmYXVsdDogNjAwMDAgKDEgbWludXRlKS5cbiAgICovXG4gIGNhY2hlTWF4QWdlTXM/OiBudW1iZXJcbn1cblxuLyoqXG4gKiBGdWxseS1yZXNvbHZlZCBzdG9yYWdlIGNvbmZpZ3VyYXRpb24gc2hhcmVkIGJ5IHNjZW5lIGFuZCBwbGF5ZXIgc3RvcmFnZS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0b3JhZ2VDb25maWdTdGF0ZSB7XG4gIHNraXBJZlVuY2hhbmdlZDogYm9vbGVhblxuICBjYWNoZVJlYWRzOiBib29sZWFuXG4gIGNhY2hlTWF4RW50cmllczogbnVtYmVyXG4gIGNhY2hlTWF4QWdlTXM6IG51bWJlclxufVxuXG4vKipcbiAqIERlZmF1bHQgdmFsdWVzIGZvciB0aGUgcmVzb2x2ZWQgc3RvcmFnZSBjb25maWd1cmF0aW9uLlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX1NUT1JBR0VfQ09ORklHOiBSZWFkb25seTxTdG9yYWdlQ29uZmlnU3RhdGU+ID0ge1xuICBza2lwSWZVbmNoYW5nZWQ6IHRydWUsXG4gIGNhY2hlUmVhZHM6IHRydWUsXG4gIGNhY2hlTWF4RW50cmllczogNTEyLFxuICBjYWNoZU1heEFnZU1zOiA2MCAqIDEwMDBcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbXV0YWJsZSBjb25maWcgb2JqZWN0LCBsYXRlciBtdXRhdGVkIGJ5IFN0b3JhZ2UuY29uZmlndXJlKCkuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVN0b3JhZ2VDb25maWcob3ZlcnJpZGVzPzogU3RvcmFnZU9wdGlvbnMpOiBTdG9yYWdlQ29uZmlnU3RhdGUge1xuICByZXR1cm4geyAuLi5ERUZBVUxUX1NUT1JBR0VfQ09ORklHLCAuLi5vdmVycmlkZXMgfVxufVxuIl19