@casual-simulation/aux-common 2.0.16 → 2.0.21
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/aux-format-2/AuxStateHelpers.d.ts +11 -1
- package/aux-format-2/AuxStateHelpers.js +20 -5
- package/aux-format-2/AuxStateHelpers.js.map +1 -1
- package/aux-format-2/AuxWeaveHelpers.d.ts +0 -1
- package/aux-format-2/AuxWeaveHelpers.js +1 -15
- package/aux-format-2/AuxWeaveHelpers.js.map +1 -1
- package/aux-format-2/AuxWeaveReducer.js +6 -6
- package/aux-format-2/AuxWeaveReducer.js.map +1 -1
- package/bots/Bot.d.ts +46 -0
- package/bots/Bot.js +6 -0
- package/bots/Bot.js.map +1 -1
- package/bots/BotCalculations.d.ts +29 -1
- package/bots/BotCalculations.js +94 -14
- package/bots/BotCalculations.js.map +1 -1
- package/bots/BotEvents.d.ts +30 -1
- package/bots/BotEvents.js +8 -0
- package/bots/BotEvents.js.map +1 -1
- package/bots/test/BotCalculationContextTests.js +11 -4
- package/bots/test/BotCalculationContextTests.js.map +1 -1
- package/package.json +5 -3
- package/partitions/MemoryPartition.js +23 -6
- package/partitions/MemoryPartition.js.map +1 -1
- package/partitions/RemoteYjsPartition.js +2 -2
- package/partitions/RemoteYjsPartition.js.map +1 -1
- package/partitions/YjsPartition.js +2 -2
- package/partitions/YjsPartition.js.map +1 -1
- package/partitions/test/PartitionTests.js +93 -19
- package/partitions/test/PartitionTests.js.map +1 -1
- package/runtime/AuxGlobalContext.d.ts +2 -2
- package/runtime/AuxGlobalContext.js.map +1 -1
- package/runtime/AuxLibrary.d.ts +29 -2
- package/runtime/AuxLibrary.js +391 -17
- package/runtime/AuxLibrary.js.map +1 -1
- package/runtime/AuxLibraryDefinitions.def +243 -8
- package/runtime/AuxRuntime.d.ts +3 -0
- package/runtime/AuxRuntime.js +31 -10
- package/runtime/AuxRuntime.js.map +1 -1
- package/runtime/RuntimeBot.d.ts +6 -0
- package/runtime/RuntimeBot.js +123 -6
- package/runtime/RuntimeBot.js.map +1 -1
- package/runtime/Transpiler.js +3 -3
- package/runtime/Transpiler.js.map +1 -1
- package/runtime/Utils.d.ts +6 -0
- package/runtime/Utils.js +30 -0
- package/runtime/Utils.js.map +1 -1
- package/runtime/test/TestScriptBotFactory.js +6 -3
- package/runtime/test/TestScriptBotFactory.js.map +1 -1
- package/test/YjsTestHelpers.js.map +1 -1
- package/yjs/YjsHelpers.d.ts +1 -1
package/runtime/AuxLibrary.js
CHANGED
|
@@ -11,8 +11,8 @@ import { DEBUG_STRING, debugStringifyFunction, } from './AuxGlobalContext';
|
|
|
11
11
|
import { hasValue, trimTag, isBot, BOT_SPACE_TAG, toast as toastMessage, showJoinCode as calcShowJoinCode, requestFullscreen, exitFullscreen, html as htmlMessage, hideHtml as hideHtmlMessage, setClipboard as calcSetClipboard, tweenTo as calcTweenTo, showChat as calcShowChat, hideChat as calcHideChat, runScript, enableAR as calcEnableAR, disableAR as calcDisableAR, enableVR as calcEnableVR, disableVR as calcDisableVR, showUploadAuxFile as calcShowUploadAuxFile, openQRCodeScanner as calcOpenQRCodeScanner, showQRCode as calcShowQRCode, openBarcodeScanner as calcOpenBarcodeScanner, showBarcode as calcShowBarcode, importAUX as calcImportAUX, showInputForTag as calcShowInputForTag, showInput as calcShowInput, replaceDragBot as calcReplaceDragBot, goToDimension as calcGoToDimension, goToURL as calcGoToURL, openURL as calcOpenURL, checkout as calcCheckout, playSound as calcPlaySound, bufferSound as calcBufferSound, cancelSound as calcCancelSound, setupServer as calcSetupServer, shell as calcShell, backupToGithub as calcBackupToGithub, backupAsDownload as calcBackupAsDownload, finishCheckout as calcFinishCheckout, markHistory as calcMarkHistory, browseHistory as calcBrowseHistory, restoreHistoryMark as calcRestoreHistoryMark, loadFile as calcLoadFile, saveFile as calcSaveFile, reject as calcReject, localFormAnimation as calcLocalFormAnimation, webhook as calcWebhook, superShout as calcSuperShout, share as calcShare, registerPrefix as calcRegisterPrefix, createCertificate as calcCreateCertificate, signTag as calcSignTag, revokeCertificate as calcRevokeCertificate, localPositionTween as calcLocalPositionTween, localRotationTween as calcLocalRotationTween, showUploadFiles as calcShowUploadFiles, download, loadSimulation, unloadSimulation, getUploadState, addState, getPortalTag, KNOWN_PORTALS, openConsole, tagsOnBot, getOriginalObject, getBotSpace, trimEvent, CREATE_ACTION_NAME, CREATE_ANY_ACTION_NAME, DESTROY_ACTION_NAME, ORIGINAL_OBJECT, unlockSpace, getRemoteCount, getServers, getRemotes, action, getServerStatuses, setSpacePassword, exportGpioPin, unexportGpioPin, setGpioPin, getGpioPin, rpioInitPin, rpioExitPin, rpioOpenPin, rpioModePin, rpioReadPin, rpioReadSequencePin, rpioWritePin, rpioWriteSequencePin, rpioReadpadPin, rpioWritepadPin, rpioPudPin, rpioPollPin, rpioClosePin, rpioI2CBeginPin, rpioI2CSetSlaveAddressPin, rpioI2CSetBaudRatePin, rpioI2CSetClockDividerPin, rpioI2CReadPin, rpioI2CWritePin,
|
|
12
12
|
// rpioI2CReadRegisterRestartPin,
|
|
13
13
|
// rpioI2CWriteReadRestartPin,
|
|
14
|
-
rpioI2CEndPin, rpioPWMSetClockDividerPin, rpioPWMSetRangePin, rpioPWMSetDataPin, rpioSPIBeginPin, rpioSPIChipSelectPin, rpioSPISetCSPolarityPin, rpioSPISetClockDividerPin, rpioSPISetDataModePin, rpioSPITransferPin, rpioSPIWritePin, rpioSPIEndPin, serialConnectPin, serialOpenPin, serialStreamPin, serialUpdatePin, serialWritePin, serialReadPin, serialClosePin, serialFlushPin, serialDrainPin, serialPausePin, serialResumePin, calculateAnchorPoint, calculateAnchorPointOffset, getBotPosition as calcGetBotPosition, isRuntimeBot, SET_TAG_MASK_SYMBOL, CLEAR_TAG_MASKS_SYMBOL, getBotScale, EDIT_TAG_SYMBOL, EDIT_TAG_MASK_SYMBOL, circleWipe, addDropSnap as calcAddDropSnap, animateToPosition, beginAudioRecording as calcBeginAudioRecording, endAudioRecording as calcEndAudioRecording, beginRecording as calcBeginRecording, endRecording as calcEndRecording, speakText as calcSpeakText, getVoices as calcGetVoices, getGeolocation as calcGetGeolocation, cancelAnimation, disablePOV, enablePOV, enableCustomDragging as calcEnableCustomDragging, MINI_PORTAL, registerCustomApp, setAppOutput, unregisterCustomApp, requestAuthData as calcRequestAuthData, createBot, defineGlobalBot as calcDefineGlobalBot, TEMPORARY_BOT_PARTITION_ID, publishRecord as calcPublishRecord, DEFAULT_RECORD_SPACE, getRecords as calcGetRecords, requestPermanentAuthToken as calcRequestPermanentAuthToken, deleteRecord, } from '../bots';
|
|
15
|
-
import { sortBy, every } from 'lodash';
|
|
14
|
+
rpioI2CEndPin, rpioPWMSetClockDividerPin, rpioPWMSetRangePin, rpioPWMSetDataPin, rpioSPIBeginPin, rpioSPIChipSelectPin, rpioSPISetCSPolarityPin, rpioSPISetClockDividerPin, rpioSPISetDataModePin, rpioSPITransferPin, rpioSPIWritePin, rpioSPIEndPin, serialConnectPin, serialOpenPin, serialStreamPin, serialUpdatePin, serialWritePin, serialReadPin, serialClosePin, serialFlushPin, serialDrainPin, serialPausePin, serialResumePin, calculateAnchorPoint, calculateAnchorPointOffset, getBotPosition as calcGetBotPosition, isRuntimeBot, SET_TAG_MASK_SYMBOL, CLEAR_TAG_MASKS_SYMBOL, getBotScale, EDIT_TAG_SYMBOL, EDIT_TAG_MASK_SYMBOL, circleWipe, addDropSnap as calcAddDropSnap, animateToPosition, beginAudioRecording as calcBeginAudioRecording, endAudioRecording as calcEndAudioRecording, beginRecording as calcBeginRecording, endRecording as calcEndRecording, speakText as calcSpeakText, getVoices as calcGetVoices, getGeolocation as calcGetGeolocation, cancelAnimation, disablePOV, enablePOV, enableCustomDragging as calcEnableCustomDragging, MINI_PORTAL, registerCustomApp, setAppOutput, unregisterCustomApp, requestAuthData as calcRequestAuthData, createBot, defineGlobalBot as calcDefineGlobalBot, TEMPORARY_BOT_PARTITION_ID, publishRecord as calcPublishRecord, DEFAULT_RECORD_SPACE, getRecords as calcGetRecords, requestPermanentAuthToken as calcRequestPermanentAuthToken, deleteRecord, convertToString, GET_TAG_MASKS_SYMBOL, isBotLink, parseBotLink, createBotLink, convertGeolocationToWhat3Words as calcConvertGeolocationToWhat3Words, } from '../bots';
|
|
15
|
+
import { sortBy, every, cloneDeep, union, isEqual, flatMap } from 'lodash';
|
|
16
16
|
import { remote as calcRemote, } from '@casual-simulation/causal-trees';
|
|
17
17
|
import { RanOutOfEnergyError } from './AuxResults';
|
|
18
18
|
import '../polyfill/Array.first.polyfill';
|
|
@@ -22,7 +22,7 @@ import { sha256 as hashSha256, sha512 as hashSha512, hmac } from 'hash.js';
|
|
|
22
22
|
import stableStringify from '@casual-simulation/fast-json-stable-stringify';
|
|
23
23
|
import { encrypt as realEncrypt, decrypt as realDecrypt, keypair as realKeypair, sign as realSign, verify as realVerify, asymmetricKeypair as realAsymmetricKeypair, asymmetricEncrypt as realAsymmetricEncrypt, asymmetricDecrypt as realAsymmetricDecrypt, isAsymmetricKeypair, isAsymmetricEncrypted, isEncrypted, } from '@casual-simulation/crypto';
|
|
24
24
|
import { tagValueHash } from '../aux-format-2/AuxOpTypes';
|
|
25
|
-
import {
|
|
25
|
+
import { apply, del, insert, isTagEdit, preserve } from '../aux-format-2';
|
|
26
26
|
import { Euler, Vector3, Plane, Ray, } from '@casual-simulation/three';
|
|
27
27
|
import mime from 'mime';
|
|
28
28
|
import TWEEN from '@tweenjs/tween.js';
|
|
@@ -31,12 +31,94 @@ import './BlobPolyfill';
|
|
|
31
31
|
import { Fragment, h } from 'preact';
|
|
32
32
|
import htm from 'htm';
|
|
33
33
|
import { fromByteArray, toByteArray } from 'base64-js';
|
|
34
|
+
import expect, { iterableEquality } from '@casual-simulation/expect';
|
|
34
35
|
const _html = htm.bind(h);
|
|
35
36
|
const html = ((...args) => {
|
|
36
37
|
return _html(...args);
|
|
37
38
|
});
|
|
38
39
|
html.h = h;
|
|
39
40
|
html.f = Fragment;
|
|
41
|
+
/**
|
|
42
|
+
* The status codes that should be used to retry web requests.
|
|
43
|
+
*/
|
|
44
|
+
const DEFUALT_RETRY_STATUS_CODES = [
|
|
45
|
+
408,
|
|
46
|
+
429,
|
|
47
|
+
500,
|
|
48
|
+
502,
|
|
49
|
+
503,
|
|
50
|
+
504,
|
|
51
|
+
0, // Network Failure / CORS
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* The time to wait until another web request retry unless specified by the webhook options.
|
|
55
|
+
* Defaults to 3 seconds.
|
|
56
|
+
*/
|
|
57
|
+
const DEFAULT_RETRY_AFTER_MS = 3 * 1000;
|
|
58
|
+
/**
|
|
59
|
+
* The maximum amount of time to wait before giving up on a set of requests.
|
|
60
|
+
* Defaults to 1 minute.
|
|
61
|
+
*/
|
|
62
|
+
const MAX_RETRY_AFTER_MS = 60 * 60 * 1000;
|
|
63
|
+
/**
|
|
64
|
+
* The maximum number of times that a web request should be retried for.
|
|
65
|
+
*/
|
|
66
|
+
const MAX_RETRY_COUNT = 10;
|
|
67
|
+
const botsEquality = function (first, second) {
|
|
68
|
+
if (isRuntimeBot(first) && isRuntimeBot(second)) {
|
|
69
|
+
expect(getBotSnapshot(first)).toEqual(getBotSnapshot(second));
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
};
|
|
74
|
+
expect.extend({
|
|
75
|
+
toEqual(received, expected) {
|
|
76
|
+
// Copied from https://github.com/facebook/jest/blob/7bb400c373a6f90ba956dd25fe24ee4d4788f41e/packages/expect/src/matchers.ts#L580
|
|
77
|
+
// Added the testBots matcher to make testing against bots easier.
|
|
78
|
+
const matcherName = 'toEqual';
|
|
79
|
+
const options = {
|
|
80
|
+
comment: 'deep equality',
|
|
81
|
+
isNot: this.isNot,
|
|
82
|
+
promise: this.promise,
|
|
83
|
+
};
|
|
84
|
+
const pass = this.equals(received, expected, [
|
|
85
|
+
botsEquality,
|
|
86
|
+
iterableEquality,
|
|
87
|
+
]);
|
|
88
|
+
const message = pass
|
|
89
|
+
? () => this.utils.matcherHint(matcherName, undefined, undefined, options) +
|
|
90
|
+
'\n\n' +
|
|
91
|
+
`Expected: not ${this.utils.printExpected(expected)}\n` +
|
|
92
|
+
(this.utils.stringify(expected) !==
|
|
93
|
+
this.utils.stringify(received)
|
|
94
|
+
? `Received: ${this.utils.printReceived(received)}`
|
|
95
|
+
: '')
|
|
96
|
+
: () => this.utils.matcherHint(matcherName, undefined, undefined, options) +
|
|
97
|
+
'\n\n' +
|
|
98
|
+
this.utils.printDiffOrStringify(expected, received, 'Expected', 'Received', this.expand !== false);
|
|
99
|
+
// Passing the actual and expected objects so that a custom reporter
|
|
100
|
+
// could access them, for example in order to display a custom visual diff,
|
|
101
|
+
// or create a different error message
|
|
102
|
+
return { actual: received, expected, message, name: matcherName, pass };
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
function getBotSnapshot(bot) {
|
|
106
|
+
var _a;
|
|
107
|
+
let b = {
|
|
108
|
+
id: bot.id,
|
|
109
|
+
space: bot.space,
|
|
110
|
+
tags: typeof bot.tags.toJSON === 'function'
|
|
111
|
+
? bot.tags.toJSON()
|
|
112
|
+
: bot.tags,
|
|
113
|
+
};
|
|
114
|
+
let masks = isRuntimeBot(bot)
|
|
115
|
+
? bot[GET_TAG_MASKS_SYMBOL]()
|
|
116
|
+
: cloneDeep((_a = bot.masks) !== null && _a !== void 0 ? _a : {});
|
|
117
|
+
if (Object.keys(masks).length > 0) {
|
|
118
|
+
b.masks = masks;
|
|
119
|
+
}
|
|
120
|
+
return b;
|
|
121
|
+
}
|
|
40
122
|
/**
|
|
41
123
|
* Creates a library that includes the default functions and APIs.
|
|
42
124
|
* @param context The global context that should be used.
|
|
@@ -48,6 +130,14 @@ export function createDefaultLibrary(context) {
|
|
|
48
130
|
};
|
|
49
131
|
const webhookFunc = makeMockableFunction(webhook, 'webhook');
|
|
50
132
|
webhookFunc.post = makeMockableFunction(webhook.post, 'webhook.post');
|
|
133
|
+
const shoutImpl = shout;
|
|
134
|
+
const shoutProxy = new Proxy(shoutImpl, {
|
|
135
|
+
get(target, name, reciever) {
|
|
136
|
+
return (arg) => {
|
|
137
|
+
return shout(name, arg);
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
});
|
|
51
141
|
return {
|
|
52
142
|
api: {
|
|
53
143
|
getBots,
|
|
@@ -57,6 +147,10 @@ export function createDefaultLibrary(context) {
|
|
|
57
147
|
getBotPosition,
|
|
58
148
|
getID,
|
|
59
149
|
getJSON,
|
|
150
|
+
getFormattedJSON,
|
|
151
|
+
getSnapshot,
|
|
152
|
+
diffSnapshots,
|
|
153
|
+
applyDiffToSnapshot,
|
|
60
154
|
getTag,
|
|
61
155
|
setTag,
|
|
62
156
|
setTagMask,
|
|
@@ -71,9 +165,12 @@ export function createDefaultLibrary(context) {
|
|
|
71
165
|
subtractMods,
|
|
72
166
|
destroy,
|
|
73
167
|
changeState,
|
|
168
|
+
getLink: createBotLinkApi,
|
|
169
|
+
getBotLinks,
|
|
170
|
+
updateBotLinks,
|
|
74
171
|
superShout,
|
|
75
172
|
priorityShout,
|
|
76
|
-
shout,
|
|
173
|
+
shout: shoutProxy,
|
|
77
174
|
whisper,
|
|
78
175
|
byTag,
|
|
79
176
|
byID,
|
|
@@ -107,6 +204,7 @@ export function createDefaultLibrary(context) {
|
|
|
107
204
|
clearWatchPortal,
|
|
108
205
|
assert,
|
|
109
206
|
assertEqual,
|
|
207
|
+
expect,
|
|
110
208
|
html,
|
|
111
209
|
os: {
|
|
112
210
|
sleep,
|
|
@@ -199,12 +297,16 @@ export function createDefaultLibrary(context) {
|
|
|
199
297
|
publishRecord: makeMockableFunction(publishRecord, 'os.publishRecord'),
|
|
200
298
|
getRecords: makeMockableFunction(getRecords, 'os.getRecords'),
|
|
201
299
|
destroyRecord: makeMockableFunction(destroyRecord, 'os.destroyRecord'),
|
|
300
|
+
convertGeolocationToWhat3Words,
|
|
202
301
|
setupInst: setupServer,
|
|
203
302
|
remotes,
|
|
204
303
|
instances: servers,
|
|
205
304
|
remoteCount: serverRemoteCount,
|
|
206
305
|
totalRemoteCount: totalRemoteCount,
|
|
207
306
|
instStatuses: serverStatuses,
|
|
307
|
+
get vars() {
|
|
308
|
+
return context.global;
|
|
309
|
+
},
|
|
208
310
|
},
|
|
209
311
|
portal: {
|
|
210
312
|
registerPrefix,
|
|
@@ -472,11 +574,14 @@ export function createDefaultLibrary(context) {
|
|
|
472
574
|
* @param second The second value to test.
|
|
473
575
|
*/
|
|
474
576
|
function assertEqual(first, second) {
|
|
475
|
-
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
577
|
+
expect(first).toEqual(second);
|
|
578
|
+
// const json = getFormattedJSON(getAssertionValue(first));
|
|
579
|
+
// const json2 = getFormattedJSON(getAssertionValue(second));
|
|
580
|
+
// if (json !== json2) {
|
|
581
|
+
// throw new Error(
|
|
582
|
+
// `Assertion failed.\n\nExpected: ${json2}\nReceived: ${json}`
|
|
583
|
+
// );
|
|
584
|
+
// }
|
|
480
585
|
}
|
|
481
586
|
/**
|
|
482
587
|
* Gets a list of all the bots.
|
|
@@ -646,10 +751,37 @@ export function createDefaultLibrary(context) {
|
|
|
646
751
|
};
|
|
647
752
|
}
|
|
648
753
|
else if (hasValue(filter)) {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
754
|
+
if (isBotLink(filter)) {
|
|
755
|
+
const ids = parseBotLink(filter);
|
|
756
|
+
if (ids.length === 0) {
|
|
757
|
+
return (bot) => {
|
|
758
|
+
let val = bot.tags[tag];
|
|
759
|
+
return val === filter;
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
else if (ids.length === 1) {
|
|
763
|
+
return (bot) => {
|
|
764
|
+
let val = bot.tags[tag];
|
|
765
|
+
return (ids[0] === val ||
|
|
766
|
+
(isBotLink(val) &&
|
|
767
|
+
parseBotLink(val).some((id) => id === ids[0])));
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
return (bot) => {
|
|
772
|
+
let val = bot.tags[tag];
|
|
773
|
+
const valIds = parseBotLink(val);
|
|
774
|
+
return (!!valIds &&
|
|
775
|
+
ids.every((id1) => valIds.some((id2) => id1 === id2)));
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
return (bot) => {
|
|
781
|
+
let val = bot.tags[tag];
|
|
782
|
+
return hasValue(val) && filter === val;
|
|
783
|
+
};
|
|
784
|
+
}
|
|
653
785
|
}
|
|
654
786
|
else if (filter === null) {
|
|
655
787
|
return (bot) => {
|
|
@@ -922,15 +1054,123 @@ export function createDefaultLibrary(context) {
|
|
|
922
1054
|
return stableStringify(data);
|
|
923
1055
|
}
|
|
924
1056
|
/**
|
|
925
|
-
* Gets JSON for the given data.
|
|
1057
|
+
* Gets formatted JSON for the given data.
|
|
926
1058
|
* @param data The data.
|
|
927
1059
|
*/
|
|
928
|
-
function
|
|
1060
|
+
function getFormattedJSON(data) {
|
|
929
1061
|
if (hasValue(data === null || data === void 0 ? void 0 : data[ORIGINAL_OBJECT])) {
|
|
930
1062
|
return stableStringify(data[ORIGINAL_OBJECT], { space: 2 });
|
|
931
1063
|
}
|
|
932
1064
|
return stableStringify(data, { space: 2 });
|
|
933
1065
|
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Gets a snapshot of the data that the bots contain.
|
|
1068
|
+
* This is useful for getting all the tags and masks that are attached to the given bots.
|
|
1069
|
+
* @param bots The array of bots to get the snapshot for.
|
|
1070
|
+
*/
|
|
1071
|
+
function getSnapshot(bots) {
|
|
1072
|
+
var _a;
|
|
1073
|
+
if (!Array.isArray(bots)) {
|
|
1074
|
+
return getSnapshot([bots]);
|
|
1075
|
+
}
|
|
1076
|
+
let state = {};
|
|
1077
|
+
for (let bot of bots) {
|
|
1078
|
+
let b = (state[bot.id] = {
|
|
1079
|
+
id: bot.id,
|
|
1080
|
+
tags: Object.assign({}, (typeof bot.tags.toJSON === 'function'
|
|
1081
|
+
? bot.tags.toJSON()
|
|
1082
|
+
: bot.tags)),
|
|
1083
|
+
});
|
|
1084
|
+
if (bot.space) {
|
|
1085
|
+
b.space = bot.space;
|
|
1086
|
+
}
|
|
1087
|
+
let masks = isRuntimeBot(bot)
|
|
1088
|
+
? bot[GET_TAG_MASKS_SYMBOL]()
|
|
1089
|
+
: cloneDeep((_a = bot.masks) !== null && _a !== void 0 ? _a : {});
|
|
1090
|
+
if (Object.keys(masks).length > 0) {
|
|
1091
|
+
b.masks = masks;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
return state;
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Calculates the difference between the two given snapshots.
|
|
1098
|
+
* @param first The first snapshot.
|
|
1099
|
+
* @param second The second snapshot.
|
|
1100
|
+
*/
|
|
1101
|
+
function diffSnapshots(first, second) {
|
|
1102
|
+
const allIds = union(Object.keys(first), Object.keys(second));
|
|
1103
|
+
let diff = {};
|
|
1104
|
+
for (let id of allIds) {
|
|
1105
|
+
const inFirst = id in first;
|
|
1106
|
+
const inSecond = id in second;
|
|
1107
|
+
if (inFirst && inSecond) {
|
|
1108
|
+
// possibly updated
|
|
1109
|
+
const firstBot = first[id];
|
|
1110
|
+
const secondBot = second[id];
|
|
1111
|
+
if (firstBot && secondBot) {
|
|
1112
|
+
let botDiff = {};
|
|
1113
|
+
let tagsDiff = diffTags(firstBot.tags, secondBot.tags);
|
|
1114
|
+
if (!!tagsDiff) {
|
|
1115
|
+
botDiff.tags = tagsDiff;
|
|
1116
|
+
}
|
|
1117
|
+
const firstBotMasks = firstBot.masks || {};
|
|
1118
|
+
const secondBotMasks = secondBot.masks || {};
|
|
1119
|
+
let masksDiff = {};
|
|
1120
|
+
let hasMasksDiff = false;
|
|
1121
|
+
const allMaskSpaces = union(Object.keys(firstBotMasks), Object.keys(secondBotMasks));
|
|
1122
|
+
for (let space of allMaskSpaces) {
|
|
1123
|
+
const firstMasks = firstBotMasks[space] || {};
|
|
1124
|
+
const secondMasks = secondBotMasks[space] || {};
|
|
1125
|
+
let tagsDiff = diffTags(firstMasks, secondMasks);
|
|
1126
|
+
if (!!tagsDiff) {
|
|
1127
|
+
hasMasksDiff = true;
|
|
1128
|
+
masksDiff[space] = tagsDiff;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
if (hasMasksDiff) {
|
|
1132
|
+
botDiff.masks = masksDiff;
|
|
1133
|
+
}
|
|
1134
|
+
if (!!tagsDiff || hasMasksDiff) {
|
|
1135
|
+
diff[id] = botDiff;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
else if (inFirst) {
|
|
1140
|
+
// deleted
|
|
1141
|
+
diff[id] = null;
|
|
1142
|
+
}
|
|
1143
|
+
else if (inSecond) {
|
|
1144
|
+
// added
|
|
1145
|
+
diff[id] = second[id];
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return diff;
|
|
1149
|
+
function diffTags(firstTags, secondTags) {
|
|
1150
|
+
let tagsDiff = {};
|
|
1151
|
+
let hasTagsDiff = false;
|
|
1152
|
+
const allTags = union(Object.keys(firstTags), Object.keys(secondTags));
|
|
1153
|
+
for (let tag of allTags) {
|
|
1154
|
+
const firstValue = firstTags[tag];
|
|
1155
|
+
const secondValue = secondTags[tag];
|
|
1156
|
+
if (!isEqual(firstValue, secondValue)) {
|
|
1157
|
+
// updated, deleted, or added
|
|
1158
|
+
hasTagsDiff = true;
|
|
1159
|
+
tagsDiff[tag] = hasValue(secondValue) ? secondValue : null;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
return hasTagsDiff ? tagsDiff : null;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Applies the given delta to the given snapshot and returns the result.
|
|
1167
|
+
* This is essentially the opposite of diffSnapshots().
|
|
1168
|
+
* @param snapshot The snapshot that the diff should be applied to.
|
|
1169
|
+
* @param diff The delta that should be applied to the snapshot.
|
|
1170
|
+
*/
|
|
1171
|
+
function applyDiffToSnapshot(snapshot, diff) {
|
|
1172
|
+
return apply(snapshot, diff);
|
|
1173
|
+
}
|
|
934
1174
|
// Actions
|
|
935
1175
|
/**
|
|
936
1176
|
* Shows a toast message to the user.
|
|
@@ -1917,6 +2157,15 @@ export function createDefaultLibrary(context) {
|
|
|
1917
2157
|
const event = deleteRecord(token, address, space, task.taskId);
|
|
1918
2158
|
return addAsyncAction(task, event);
|
|
1919
2159
|
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Converts the given geolocation to a what3words (https://what3words.com/) address.
|
|
2162
|
+
* @param location The latitude and longitude that should be converted to a 3 word address.
|
|
2163
|
+
*/
|
|
2164
|
+
function convertGeolocationToWhat3Words(location) {
|
|
2165
|
+
const task = context.createTask();
|
|
2166
|
+
const event = calcConvertGeolocationToWhat3Words(location, task.taskId);
|
|
2167
|
+
return addAsyncAction(task, event);
|
|
2168
|
+
}
|
|
1920
2169
|
/**
|
|
1921
2170
|
* Sends an event to the server to setup a new instance if it does not exist.
|
|
1922
2171
|
* @param inst The instance.
|
|
@@ -2718,8 +2967,46 @@ export function createDefaultLibrary(context) {
|
|
|
2718
2967
|
* @param options The options that should be used to send the webhook.
|
|
2719
2968
|
*/
|
|
2720
2969
|
function webhook(options) {
|
|
2970
|
+
if (options.retryCount > 0) {
|
|
2971
|
+
return _retryWebhook(options);
|
|
2972
|
+
}
|
|
2973
|
+
else {
|
|
2974
|
+
return _webhook(options);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
function _retryWebhook(options) {
|
|
2978
|
+
var _a, _b, _c, _d;
|
|
2979
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2980
|
+
const retryCount = Math.min(options.retryCount, MAX_RETRY_COUNT);
|
|
2981
|
+
const timeToWait = Math.max(0, Math.min((_a = options.retryAfterMs) !== null && _a !== void 0 ? _a : DEFAULT_RETRY_AFTER_MS, MAX_RETRY_AFTER_MS));
|
|
2982
|
+
const statusCodes = (_b = options.retryStatusCodes) !== null && _b !== void 0 ? _b : DEFUALT_RETRY_STATUS_CODES;
|
|
2983
|
+
let retries = 0;
|
|
2984
|
+
while (true) {
|
|
2985
|
+
try {
|
|
2986
|
+
return yield _webhook(options);
|
|
2987
|
+
}
|
|
2988
|
+
catch (err) {
|
|
2989
|
+
if (retries >= retryCount) {
|
|
2990
|
+
throw err;
|
|
2991
|
+
}
|
|
2992
|
+
else if (!statusCodes.includes((_d = (_c = err.response) === null || _c === void 0 ? void 0 : _c.status) !== null && _d !== void 0 ? _d : 0)) {
|
|
2993
|
+
throw err;
|
|
2994
|
+
}
|
|
2995
|
+
yield sleep(timeToWait);
|
|
2996
|
+
retries += 1;
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
});
|
|
3000
|
+
}
|
|
3001
|
+
function _webhook(options) {
|
|
2721
3002
|
const task = context.createTask();
|
|
2722
|
-
const event = calcWebhook(
|
|
3003
|
+
const event = calcWebhook({
|
|
3004
|
+
method: options.method,
|
|
3005
|
+
url: options.url,
|
|
3006
|
+
responseShout: options.responseShout,
|
|
3007
|
+
data: options.data,
|
|
3008
|
+
headers: options.headers,
|
|
3009
|
+
}, task.taskId);
|
|
2723
3010
|
return addAsyncAction(task, event);
|
|
2724
3011
|
}
|
|
2725
3012
|
/**
|
|
@@ -4172,7 +4459,7 @@ export function createDefaultLibrary(context) {
|
|
|
4172
4459
|
destroyChildren(id);
|
|
4173
4460
|
}
|
|
4174
4461
|
function destroyChildren(id) {
|
|
4175
|
-
const children = getBots('creator', id);
|
|
4462
|
+
const children = getBots(byTag('creator', createBotLink([id])));
|
|
4176
4463
|
for (let child of children) {
|
|
4177
4464
|
destroyBot(child);
|
|
4178
4465
|
}
|
|
@@ -4198,6 +4485,93 @@ export function createDefaultLibrary(context) {
|
|
|
4198
4485
|
}
|
|
4199
4486
|
whisper(bot, `${groupName}${stateName}OnEnter`, arg);
|
|
4200
4487
|
}
|
|
4488
|
+
/**
|
|
4489
|
+
* Creates a tag value that can be used to link to the given bots.
|
|
4490
|
+
* @param bots The bots that the link should point to.
|
|
4491
|
+
*/
|
|
4492
|
+
function createBotLinkApi(...bots) {
|
|
4493
|
+
let targets = flatMap(bots);
|
|
4494
|
+
let result = [];
|
|
4495
|
+
for (let t of targets) {
|
|
4496
|
+
if (isBot(t)) {
|
|
4497
|
+
result.push(t.id);
|
|
4498
|
+
}
|
|
4499
|
+
else {
|
|
4500
|
+
let links = parseBotLink(t);
|
|
4501
|
+
if (links) {
|
|
4502
|
+
result.push(...links);
|
|
4503
|
+
}
|
|
4504
|
+
else {
|
|
4505
|
+
result.push(t);
|
|
4506
|
+
}
|
|
4507
|
+
}
|
|
4508
|
+
}
|
|
4509
|
+
return createBotLink(result);
|
|
4510
|
+
}
|
|
4511
|
+
/**
|
|
4512
|
+
* Gets the list of bot links that are stored in this bot's tags.
|
|
4513
|
+
* @param bot The bot to get the links for.
|
|
4514
|
+
*/
|
|
4515
|
+
function getBotLinks(bot) {
|
|
4516
|
+
let links = [];
|
|
4517
|
+
for (let tag of Object.keys(bot.tags)) {
|
|
4518
|
+
const val = bot.tags[tag];
|
|
4519
|
+
const ids = parseBotLink(val);
|
|
4520
|
+
if (ids) {
|
|
4521
|
+
links.push({
|
|
4522
|
+
tag,
|
|
4523
|
+
botIDs: ids,
|
|
4524
|
+
});
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
return links;
|
|
4528
|
+
}
|
|
4529
|
+
/**
|
|
4530
|
+
* Updates all the links in the given bot using the given ID map.
|
|
4531
|
+
* Useful if you know that the links in the given bot are outdated and you know which IDs map to the new IDs.
|
|
4532
|
+
* @param bot The bot to update.
|
|
4533
|
+
* @param idMap The map of old IDs to new IDs that should be used.
|
|
4534
|
+
*/
|
|
4535
|
+
function updateBotLinks(bot, idMap) {
|
|
4536
|
+
let map;
|
|
4537
|
+
if (idMap instanceof Map) {
|
|
4538
|
+
map = idMap;
|
|
4539
|
+
}
|
|
4540
|
+
else if (typeof idMap === 'object') {
|
|
4541
|
+
map = new Map();
|
|
4542
|
+
for (let key in idMap) {
|
|
4543
|
+
const newId = idMap[key];
|
|
4544
|
+
if (typeof newId === 'string') {
|
|
4545
|
+
map.set(key, newId);
|
|
4546
|
+
}
|
|
4547
|
+
else if (isBot(newId)) {
|
|
4548
|
+
map.set(key, newId.id);
|
|
4549
|
+
}
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
else {
|
|
4553
|
+
return;
|
|
4554
|
+
}
|
|
4555
|
+
for (let tag of Object.keys(bot.tags)) {
|
|
4556
|
+
const val = bot.tags[tag];
|
|
4557
|
+
const ids = parseBotLink(val);
|
|
4558
|
+
if (ids) {
|
|
4559
|
+
const mapped = ids.map((id) => {
|
|
4560
|
+
if (map.has(id)) {
|
|
4561
|
+
const newId = map.get(id);
|
|
4562
|
+
if (typeof newId === 'string') {
|
|
4563
|
+
return newId;
|
|
4564
|
+
}
|
|
4565
|
+
else if (isBot(newId)) {
|
|
4566
|
+
return newId.id;
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
return id;
|
|
4570
|
+
});
|
|
4571
|
+
bot.tags[tag] = createBotLink(mapped);
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4201
4575
|
/**
|
|
4202
4576
|
* Shouts the given event to every bot in every loaded simulation.
|
|
4203
4577
|
* @param eventName The name of the event to shout.
|