worldstate-emitter 2.2.12 → 2.3.0
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/README.md +252 -60
- package/dist/index.d.mts +56 -0
- package/dist/index.mjs +14645 -0
- package/package.json +43 -18
- package/.babelrc.json +0 -4
- package/.commitlintrc.yml +0 -5
- package/.eslintignore +0 -5
- package/.eslintrc.yml +0 -9
- package/.husky/commit-msg +0 -1
- package/.husky/pre-commit +0 -1
- package/.lintstagedrc.yml +0 -9
- package/.mocharc.yml +0 -3
- package/.nvmrc +0 -1
- package/.nycrc.yml +0 -4
- package/.prettierrc +0 -1
- package/.releaserc.yml +0 -1
- package/SECURITY.md +0 -17
- package/handlers/RSS.js +0 -66
- package/handlers/Twitter.js +0 -169
- package/handlers/Worldstate.js +0 -154
- package/handlers/events/arrayLike.js +0 -27
- package/handlers/events/checkOverrides.js +0 -17
- package/handlers/events/cycleLike.js +0 -38
- package/handlers/events/eKeyOverrides.js +0 -40
- package/handlers/events/kuva.js +0 -31
- package/handlers/events/nightwave.js +0 -35
- package/handlers/events/objectLike.js +0 -17
- package/handlers/events/parse.js +0 -82
- package/index.js +0 -96
- package/nodemon.json +0 -9
- package/resources/config.js +0 -8
- package/resources/rssFeeds.json +0 -129
- package/resources/tweeters.json +0 -17
- package/utilities/Cache.js +0 -61
- package/utilities/WSCache.js +0 -96
- package/utilities/env.js +0 -10
- package/utilities/index.js +0 -79
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "worldstate-emitter",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Event emitter for worldstate & other
|
|
3
|
+
"version": "2.3.0",
|
|
4
|
+
"description": "Event emitter for Warframe worldstate & other events - TypeScript support included",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"warframe",
|
|
7
7
|
"worldstate",
|
|
8
8
|
"event",
|
|
9
|
-
"emitter"
|
|
9
|
+
"emitter",
|
|
10
|
+
"typescript",
|
|
11
|
+
"types"
|
|
10
12
|
],
|
|
11
13
|
"homepage": "https://wfcd.github.io/worldstate-emitter/",
|
|
12
14
|
"bugs": {
|
|
@@ -20,50 +22,73 @@
|
|
|
20
22
|
"author": "tobiah <tobiah@protonmail.com>",
|
|
21
23
|
"type": "module",
|
|
22
24
|
"exports": {
|
|
23
|
-
".":
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
27
|
+
"import": "./dist/index.mjs"
|
|
28
|
+
}
|
|
24
29
|
},
|
|
25
|
-
"main": "index.
|
|
30
|
+
"main": "./dist/index.mjs",
|
|
31
|
+
"types": "./dist/index.d.mts",
|
|
26
32
|
"directories": {
|
|
27
33
|
"test": "test/specs"
|
|
28
34
|
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist/",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
29
39
|
"scripts": {
|
|
30
|
-
"build
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
40
|
+
"build": "tsdown",
|
|
41
|
+
"build:docs": "typedoc",
|
|
42
|
+
"precoverage": "npm run build",
|
|
43
|
+
"coverage": "c8 mocha --config .mocharc.integration.yml && npm run report && npx coveralls < coverage/lcov.info",
|
|
44
|
+
"dev": "nodemon --exec tsx test/tester.ts",
|
|
45
|
+
"lint": "biome check",
|
|
46
|
+
"lint:fix": "biome check --write",
|
|
47
|
+
"prepare": "husky",
|
|
48
|
+
"prepublishOnly": "npm run build",
|
|
36
49
|
"report": "c8 report --reporter=text-lcov > coverage/lcov.info",
|
|
37
|
-
"pretest": "npm i --no-save warframe-worldstate-data@^3 warframe-worldstate-parser@^5",
|
|
38
|
-
"test": "
|
|
50
|
+
"pretest": "npm i --no-save warframe-worldstate-data@^3 warframe-worldstate-parser@^5 && npm run build",
|
|
51
|
+
"test": "LOG_LEVEL=silent mocha",
|
|
52
|
+
"test:all": "npm test && npm run test:integration",
|
|
53
|
+
"test:integration": "LOG_LEVEL=silent mocha --config .mocharc.integration.yml"
|
|
39
54
|
},
|
|
40
55
|
"dependencies": {
|
|
41
56
|
"cron": "^4.3.4",
|
|
42
57
|
"rss-feed-emitter": "^3.2.4",
|
|
58
|
+
"sanitize-html": "^2.17.0",
|
|
43
59
|
"twitter": "^1.7.1"
|
|
44
60
|
},
|
|
45
61
|
"devDependencies": {
|
|
62
|
+
"@biomejs/biome": "^2.3.11",
|
|
46
63
|
"@commitlint/cli": "^20.1.0",
|
|
47
64
|
"@commitlint/config-conventional": "^20.0.0",
|
|
48
|
-
"@
|
|
65
|
+
"@types/chai": "^5.2.3",
|
|
66
|
+
"@types/mocha": "^10.0.10",
|
|
67
|
+
"@types/node": "^20.19.28",
|
|
68
|
+
"@types/sanitize-html": "^2.16.0",
|
|
69
|
+
"@types/sinon": "^21.0.0",
|
|
70
|
+
"@types/twitter": "^1.7.4",
|
|
49
71
|
"c8": "^10.1.3",
|
|
50
72
|
"chai": "^6.2.1",
|
|
51
73
|
"husky": "^9.1.7",
|
|
52
|
-
"install-peerdeps": "^3.0.7",
|
|
53
74
|
"lint-staged": "^16.2.7",
|
|
54
75
|
"mocha": "^11.7.5",
|
|
55
76
|
"nodemon": "^3.1.11",
|
|
56
|
-
"
|
|
77
|
+
"sinon": "^21.0.1",
|
|
78
|
+
"tsdown": "^0.19.0",
|
|
79
|
+
"tsx": "^4.21.0",
|
|
80
|
+
"typedoc": "^0.28.15",
|
|
81
|
+
"typescript": "^5.9.3"
|
|
57
82
|
},
|
|
58
83
|
"peerDependencies": {
|
|
59
84
|
"warframe-worldstate-data": "^3.x",
|
|
60
|
-
"warframe-worldstate-parser": "^5.
|
|
85
|
+
"warframe-worldstate-parser": "^5.2.14"
|
|
61
86
|
},
|
|
62
87
|
"optionalDependencies": {
|
|
63
88
|
"winston": "^3.18.3"
|
|
64
89
|
},
|
|
65
90
|
"engines": {
|
|
66
|
-
"node": ">=
|
|
91
|
+
"node": ">=20.10.0"
|
|
67
92
|
},
|
|
68
93
|
"publishConfig": {
|
|
69
94
|
"provenance": true
|
package/.babelrc.json
DELETED
package/.commitlintrc.yml
DELETED
package/.eslintignore
DELETED
package/.eslintrc.yml
DELETED
package/.husky/commit-msg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx --no -- commitlint --edit $1
|
package/.husky/pre-commit
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx lint-staged
|
package/.lintstagedrc.yml
DELETED
package/.mocharc.yml
DELETED
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
lts/jod
|
package/.nycrc.yml
DELETED
package/.prettierrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"@wfcd/eslint-config/prettier"
|
package/.releaserc.yml
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
branches: master
|
package/SECURITY.md
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported Versions
|
|
4
|
-
|
|
5
|
-
All versions are supported, but it's recommended to stay on the always current version.
|
|
6
|
-
There may be known vulnerabilities in development dependencies that are avoidable.
|
|
7
|
-
|
|
8
|
-
| Version | Supported |
|
|
9
|
-
| ------- | ------------------ |
|
|
10
|
-
| 1.x+ | :white_check_mark: |
|
|
11
|
-
| < 1.0 | :x:
|
|
12
|
-
|
|
13
|
-
## Reporting a Vulnerability
|
|
14
|
-
|
|
15
|
-
Vulnerabilities from version updates should have automated PRs from dependabot.
|
|
16
|
-
|
|
17
|
-
If there is a vulnerability in the code itself, please submit an issue (or also a PR if you have the solution), mentioning the vulnerability.
|
package/handlers/RSS.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import RssFeedEmitter from 'rss-feed-emitter';
|
|
2
|
-
|
|
3
|
-
import feeds from '../resources/rssFeeds.json' with { type: 'json' };
|
|
4
|
-
import { logger } from '../utilities/index.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* RSS Emitter, leverages [rss-feed-emitter](https://npmjs.org/package/rss-feed-emitter)
|
|
8
|
-
*/
|
|
9
|
-
export default class RSS {
|
|
10
|
-
/**
|
|
11
|
-
* Set up emitting events for warframe forum entries
|
|
12
|
-
* @param {EventEmitter} eventEmitter Emitter to send events from
|
|
13
|
-
*/
|
|
14
|
-
constructor(eventEmitter) {
|
|
15
|
-
this.logger = logger;
|
|
16
|
-
this.emitter = eventEmitter;
|
|
17
|
-
this.feeder = new RssFeedEmitter({
|
|
18
|
-
userAgent: 'WFCD Feed Notifier',
|
|
19
|
-
skipFirstLoad: true,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
feeds.forEach((feed) => {
|
|
23
|
-
this.feeder.add({ url: feed.url, timeout: 30000 });
|
|
24
|
-
});
|
|
25
|
-
this.logger.debug('RSS Feed active');
|
|
26
|
-
|
|
27
|
-
this.start = Date.now();
|
|
28
|
-
this.feeder.on('error', this.logger.error.bind(this.logger));
|
|
29
|
-
this.feeder.on('new-item', this.handleNew.bind(this));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
handleNew(item) {
|
|
33
|
-
try {
|
|
34
|
-
if (Object.keys(item.image).length) {
|
|
35
|
-
this.logger.debug(`Image: ${JSON.stringify(item.image)}`);
|
|
36
|
-
}
|
|
37
|
-
if (new Date(item.pubDate).getTime() <= this.start) return;
|
|
38
|
-
|
|
39
|
-
const feed = feeds.filter((feedEntry) => feedEntry.url === item.meta.link)[0];
|
|
40
|
-
let firstImg = ((item.description || '').match(/<img.*src="(.*)".*>/i) || [])[1];
|
|
41
|
-
if (!firstImg) {
|
|
42
|
-
firstImg = feed.defaultAttach;
|
|
43
|
-
} else if (firstImg.startsWith('//')) {
|
|
44
|
-
firstImg = firstImg.replace('//', 'https://');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const rssSummary = {
|
|
48
|
-
body: (item.description || '\u200B').replace(/<(?:.|\n)*?>/gm, '').replace(/\n\n+\s*/gm, '\n\n'),
|
|
49
|
-
url: item.link,
|
|
50
|
-
timestamp: item.pubDate,
|
|
51
|
-
description: item.meta.description,
|
|
52
|
-
author: feed.author || {
|
|
53
|
-
name: 'Warframe Forums',
|
|
54
|
-
url: item['rss:link']['#'],
|
|
55
|
-
icon_url: 'https://i.imgur.com/hE2jdpv.png',
|
|
56
|
-
},
|
|
57
|
-
title: item.title,
|
|
58
|
-
image: firstImg,
|
|
59
|
-
id: feed.key,
|
|
60
|
-
};
|
|
61
|
-
this.emitter.emit('rss', rssSummary);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
this.logger.error(error);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
package/handlers/Twitter.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import Twitter from 'twitter';
|
|
2
|
-
|
|
3
|
-
import toWatch from '../resources/tweeters.json' with { type: 'json' };
|
|
4
|
-
import { logger } from '../utilities/index.js';
|
|
5
|
-
import { twiClientInfo, TWITTER_TIMEOUT } from '../utilities/env.js';
|
|
6
|
-
|
|
7
|
-
const determineTweetType = (tweet) => {
|
|
8
|
-
if (tweet.in_reply_to_status_id) {
|
|
9
|
-
return 'reply';
|
|
10
|
-
}
|
|
11
|
-
if (tweet.quoted_status_id) {
|
|
12
|
-
return 'quote';
|
|
13
|
-
}
|
|
14
|
-
if (tweet.retweeted_status) {
|
|
15
|
-
return 'retweet';
|
|
16
|
-
}
|
|
17
|
-
return 'tweet';
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const parseAuthor = (tweet) => ({
|
|
21
|
-
name: tweet.user.name,
|
|
22
|
-
handle: tweet.user.screen_name,
|
|
23
|
-
url: `https://twitter.com/${tweet.user.screen_name}`,
|
|
24
|
-
avatar: `${tweet.user.profile_image_url.replace('_normal.jpg', '.jpg')}`,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const parseQuoted = (tweet, type) =>
|
|
28
|
-
tweet[type]
|
|
29
|
-
? {
|
|
30
|
-
text: tweet[type].full_text,
|
|
31
|
-
author: {
|
|
32
|
-
name: tweet[type].user.name,
|
|
33
|
-
handle: tweet[type].user.screen_name,
|
|
34
|
-
},
|
|
35
|
-
}
|
|
36
|
-
: undefined;
|
|
37
|
-
|
|
38
|
-
const parseTweet = (tweets, watchable) => {
|
|
39
|
-
const [tweet] = tweets;
|
|
40
|
-
const type = determineTweetType(tweet);
|
|
41
|
-
return {
|
|
42
|
-
id: `twitter.${watchable.plain}.${type}`,
|
|
43
|
-
uniqueId: String(tweets[0].id_str),
|
|
44
|
-
text: tweet.full_text,
|
|
45
|
-
url: `https://twitter.com/${tweet.user.screen_name}/status/${tweet.id_str}`,
|
|
46
|
-
mediaUrl: tweet.entities.media ? tweet.entities.media[0].media_url : undefined,
|
|
47
|
-
isReply: typeof tweet.in_reply_to_status_id !== 'undefined',
|
|
48
|
-
author: parseAuthor(tweet),
|
|
49
|
-
quote: parseQuoted(tweet, 'quoted_status'),
|
|
50
|
-
retweet: parseQuoted(tweet, 'retweeted_status'),
|
|
51
|
-
createdAt: new Date(tweet.created_at),
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Twitter event handler
|
|
57
|
-
*/
|
|
58
|
-
export default class TwitterCache {
|
|
59
|
-
/**
|
|
60
|
-
* Create a new Twitter self-updating cache
|
|
61
|
-
* @param {EventEmitter} eventEmitter emitter to push new tweets to
|
|
62
|
-
*/
|
|
63
|
-
constructor(eventEmitter) {
|
|
64
|
-
this.emitter = eventEmitter;
|
|
65
|
-
this.timeout = TWITTER_TIMEOUT;
|
|
66
|
-
this.clientInfoValid = twiClientInfo.consumer_key && twiClientInfo.consumer_secret && twiClientInfo.bearer_token;
|
|
67
|
-
this.initClient(twiClientInfo);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
initClient(clientInfo) {
|
|
71
|
-
try {
|
|
72
|
-
if (this.clientInfoValid) {
|
|
73
|
-
this.client = new Twitter(clientInfo);
|
|
74
|
-
|
|
75
|
-
// don't attempt anything else if authentication fails
|
|
76
|
-
this.toWatch = toWatch;
|
|
77
|
-
this.currentData = undefined;
|
|
78
|
-
this.lastUpdated = Date.now() - 60000;
|
|
79
|
-
this.updateInterval = setInterval(() => this.update(), this.timeout);
|
|
80
|
-
this.update();
|
|
81
|
-
} else {
|
|
82
|
-
logger.warn(`Twitter client not initialized... invalid token: ${clientInfo.bearer_token}`);
|
|
83
|
-
}
|
|
84
|
-
} catch (err) {
|
|
85
|
-
this.client = undefined;
|
|
86
|
-
this.clientInfoValid = false;
|
|
87
|
-
logger.error(err);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Force the cache to update
|
|
93
|
-
* @returns {Promise} the currently updating promise.
|
|
94
|
-
*/
|
|
95
|
-
async update() {
|
|
96
|
-
if (!this.clientInfoValid) return undefined;
|
|
97
|
-
|
|
98
|
-
if (!this.toWatch) {
|
|
99
|
-
logger.verbose('Not processing twitter, no data to watch.');
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!this.client) {
|
|
104
|
-
logger.verbose('Not processing twitter, no client to connect.');
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.updating = this.getParseableData();
|
|
109
|
-
|
|
110
|
-
return this.updating;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Get data able to be parsed from twitter.
|
|
115
|
-
* @returns {Promise.<Array.<Object>>} Tweets
|
|
116
|
-
*/
|
|
117
|
-
async getParseableData() {
|
|
118
|
-
logger.silly('Starting Twitter update...');
|
|
119
|
-
const parsedData = [];
|
|
120
|
-
try {
|
|
121
|
-
await Promise.all(
|
|
122
|
-
this.toWatch.map(async (watchable) => {
|
|
123
|
-
const tweets = await this.client.get('statuses/user_timeline', {
|
|
124
|
-
screen_name: watchable.acc_name,
|
|
125
|
-
tweet_mode: 'extended',
|
|
126
|
-
count: 1,
|
|
127
|
-
});
|
|
128
|
-
const tweet = parseTweet(tweets, watchable);
|
|
129
|
-
parsedData.push(tweet);
|
|
130
|
-
|
|
131
|
-
if (tweet.createdAt.getTime() > this.lastUpdated) {
|
|
132
|
-
this.emitter.emit('tweet', tweet);
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
);
|
|
136
|
-
} catch (error) {
|
|
137
|
-
this.onError(error);
|
|
138
|
-
}
|
|
139
|
-
this.lastUpdated = Date.now();
|
|
140
|
-
return parsedData;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Handle errors that arise while fetching data from twitter
|
|
145
|
-
* @param {Error} error twitter error
|
|
146
|
-
*/
|
|
147
|
-
onError(error) {
|
|
148
|
-
if (error[0] && error[0].code === 32) {
|
|
149
|
-
this.clientInfoValid = false;
|
|
150
|
-
logger.info('wiping twitter client data, could not authenticate...');
|
|
151
|
-
} else {
|
|
152
|
-
logger.debug(JSON.stringify(error));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Get the current data or a promise with the current data
|
|
158
|
-
* @returns {Promise.<Object> | Object} either the current data
|
|
159
|
-
* if it's not updating, or the promise returning the new data
|
|
160
|
-
*/
|
|
161
|
-
async getData() {
|
|
162
|
-
if (!this.clientInfoValid) return undefined;
|
|
163
|
-
|
|
164
|
-
if (this.updating) {
|
|
165
|
-
return this.updating;
|
|
166
|
-
}
|
|
167
|
-
return this.currentData;
|
|
168
|
-
}
|
|
169
|
-
}
|
package/handlers/Worldstate.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import wsData from 'warframe-worldstate-data';
|
|
2
|
-
|
|
3
|
-
import WSCache from '../utilities/WSCache.js';
|
|
4
|
-
import { logger, lastUpdated } from '../utilities/index.js';
|
|
5
|
-
import Cache from '../utilities/Cache.js';
|
|
6
|
-
import { sentientUrl, kuvaUrl, worldstateUrl, externalCron, worldstateCron } from '../resources/config.js';
|
|
7
|
-
|
|
8
|
-
import parseNew from './events/parse.js';
|
|
9
|
-
|
|
10
|
-
const { locales } = wsData;
|
|
11
|
-
const debugEvents = ['arbitration', 'kuva', 'nightwave'];
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Handler for worldstate data
|
|
15
|
-
*/
|
|
16
|
-
export default class Worldstate {
|
|
17
|
-
#emitter;
|
|
18
|
-
#locale;
|
|
19
|
-
#worldStates = {};
|
|
20
|
-
#wsRawCache;
|
|
21
|
-
#kuvaCache;
|
|
22
|
-
#sentientCache;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Set up listening for specific platform and locale if provided.
|
|
26
|
-
* @param {EventEmitter} eventEmitter Emitter to push new worldstate events to
|
|
27
|
-
* @param {string} locale Locale (actually just language) to watch
|
|
28
|
-
*/
|
|
29
|
-
constructor(eventEmitter, locale) {
|
|
30
|
-
this.#emitter = eventEmitter;
|
|
31
|
-
this.#locale = locale;
|
|
32
|
-
logger.debug('starting up worldstate listener...');
|
|
33
|
-
if (locale) {
|
|
34
|
-
logger.debug(`only listening for ${locale}...`);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async init() {
|
|
39
|
-
this.#wsRawCache = await Cache.make(worldstateUrl, worldstateCron);
|
|
40
|
-
this.#kuvaCache = await Cache.make(kuvaUrl, externalCron);
|
|
41
|
-
this.#sentientCache = await Cache.make(sentientUrl, externalCron);
|
|
42
|
-
|
|
43
|
-
await this.setUpRawEmitters();
|
|
44
|
-
this.setupParsedEvents();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Set up emitting raw worldstate data
|
|
49
|
-
*/
|
|
50
|
-
async setUpRawEmitters() {
|
|
51
|
-
this.#worldStates = {};
|
|
52
|
-
|
|
53
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
54
|
-
for await (const locale of locales) {
|
|
55
|
-
if (!this.#locale || this.#locale === locale) {
|
|
56
|
-
this.#worldStates[locale] = new WSCache({
|
|
57
|
-
language: locale,
|
|
58
|
-
kuvaCache: this.#kuvaCache,
|
|
59
|
-
sentientCache: this.#sentientCache,
|
|
60
|
-
eventEmitter: this.#emitter,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/* listen for the raw cache updates so we can emit them from the super emitter */
|
|
66
|
-
this.#wsRawCache.on('update', (dataStr) => {
|
|
67
|
-
this.#emitter.emit('ws:update:raw', { platform: 'pc', data: dataStr });
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
/* when the raw emits happen, parse them and store them on parsed worldstate caches */
|
|
71
|
-
this.#emitter.on('ws:update:raw', ({ data }) => {
|
|
72
|
-
logger.debug('ws:update:raw - updating locales data');
|
|
73
|
-
locales.forEach((locale) => {
|
|
74
|
-
if (!this.#locale || this.#locale === locale) {
|
|
75
|
-
this.#worldStates[locale].data = data;
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Set up listeners for the parsed worldstate updates
|
|
83
|
-
*/
|
|
84
|
-
setupParsedEvents() {
|
|
85
|
-
this.#emitter.on('ws:update:parsed', ({ language, platform, data }) => {
|
|
86
|
-
const packet = { platform, worldstate: data, language };
|
|
87
|
-
this.parseEvents(packet);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Parse new worldstate events
|
|
93
|
-
* @param {Object} worldstate worldstate to find packets from
|
|
94
|
-
* @param {string} platform platform the worldstate corresponds to
|
|
95
|
-
* @param {string} [language='en'] language of the worldstate (defaults to 'en')
|
|
96
|
-
*/
|
|
97
|
-
parseEvents({ worldstate, platform, language = 'en' }) {
|
|
98
|
-
const cycleStart = Date.now();
|
|
99
|
-
const packets = [];
|
|
100
|
-
Object.keys(worldstate).forEach(async (key) => {
|
|
101
|
-
if (worldstate && worldstate[key]) {
|
|
102
|
-
const packet = parseNew({
|
|
103
|
-
data: worldstate[key],
|
|
104
|
-
key,
|
|
105
|
-
language,
|
|
106
|
-
platform,
|
|
107
|
-
cycleStart,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
if (Array.isArray(packet)) {
|
|
111
|
-
if (packet.length) {
|
|
112
|
-
packets.push(...packet.filter((p) => p && p));
|
|
113
|
-
}
|
|
114
|
-
} else if (packet) {
|
|
115
|
-
packets.push(packet);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
lastUpdated[platform][language] = Date.now();
|
|
121
|
-
packets
|
|
122
|
-
.filter((p) => p && p.id && packets)
|
|
123
|
-
.forEach((packet) => {
|
|
124
|
-
this.emit('ws:update:event', packet);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Emit an event with given id
|
|
130
|
-
* @param {string} id Id of the event to emit
|
|
131
|
-
* @param {Object} packet Data packet to emit
|
|
132
|
-
*/
|
|
133
|
-
emit(id, packet) {
|
|
134
|
-
if (debugEvents.includes(packet.key)) logger.warn(packet.key);
|
|
135
|
-
|
|
136
|
-
logger.debug(`ws:update:event - emitting ${packet.id}`);
|
|
137
|
-
delete packet.cycleStart;
|
|
138
|
-
this.#emitter.emit(id, packet);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* get a specific worldstate version
|
|
143
|
-
* @param {string} [language='en'] Locale of the worldsttate
|
|
144
|
-
* @returns {Object} Worldstate corresponding to provided data
|
|
145
|
-
* @throws {Error} when the platform or locale aren't tracked and aren't updated
|
|
146
|
-
*/
|
|
147
|
-
get(language = 'en') {
|
|
148
|
-
logger.debug(`getting worldstate ${language}...`);
|
|
149
|
-
if (this.#worldStates?.[language]) {
|
|
150
|
-
return this.#worldStates?.[language]?.data;
|
|
151
|
-
}
|
|
152
|
-
throw new Error(`Language (${language}) not tracked.\nEnsure that the parameters passed are correct`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { logger } from '../../utilities/index.js';
|
|
2
|
-
|
|
3
|
-
import checkOverrides from './checkOverrides.js';
|
|
4
|
-
import objectLike from './objectLike.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* arrayLike are all just arrays of objectLike
|
|
8
|
-
* @param {Object} deps dependencies for processing
|
|
9
|
-
* @param {Object[]} packets packets to emit
|
|
10
|
-
* @returns {Object|Object[]} object(s) to emit from arrayLike processing
|
|
11
|
-
*/
|
|
12
|
-
export default (deps, packets) => {
|
|
13
|
-
try {
|
|
14
|
-
deps.data.forEach((arrayItem) => {
|
|
15
|
-
const k = checkOverrides(deps.key, arrayItem);
|
|
16
|
-
packets.push(
|
|
17
|
-
objectLike(arrayItem, {
|
|
18
|
-
...deps,
|
|
19
|
-
id: k,
|
|
20
|
-
})
|
|
21
|
-
);
|
|
22
|
-
});
|
|
23
|
-
return packets;
|
|
24
|
-
} catch (err) {
|
|
25
|
-
logger.error(err);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import * as eKeyOverrides from './eKeyOverrides.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Find overrides for the provided key
|
|
5
|
-
* @param {string} key worldsate field to find overrides
|
|
6
|
-
* @param {Object} data data corresponding to the key from provided worldstate
|
|
7
|
-
* @returns {string} overrided key
|
|
8
|
-
*/
|
|
9
|
-
export default (key, data) => {
|
|
10
|
-
if (typeof eKeyOverrides[key] === 'string') {
|
|
11
|
-
return eKeyOverrides[key];
|
|
12
|
-
}
|
|
13
|
-
if (typeof eKeyOverrides[key] === 'function') {
|
|
14
|
-
return eKeyOverrides[key](data);
|
|
15
|
-
}
|
|
16
|
-
return key;
|
|
17
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { between, lastUpdated, fromNow } from '../../utilities/index.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {Object} CycleLike
|
|
5
|
-
* @property {string} state
|
|
6
|
-
* @property {string} key
|
|
7
|
-
* @property {Date} activation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* CylceData parser
|
|
12
|
-
* @param {CycleLike} cycleData data for parsing all cycles like this
|
|
13
|
-
* @param {Deps} deps dependencies for processing
|
|
14
|
-
* @returns {Object[]}
|
|
15
|
-
*/
|
|
16
|
-
export default (cycleData, deps) => {
|
|
17
|
-
const packet = {
|
|
18
|
-
...deps,
|
|
19
|
-
data: cycleData,
|
|
20
|
-
id: `${deps.key.replace('Cycle', '')}.${cycleData.state}`,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const last = new Date(lastUpdated[deps.platform][deps.language]);
|
|
24
|
-
const activation = new Date(cycleData.activation);
|
|
25
|
-
const start = new Date(deps.cycleStart);
|
|
26
|
-
|
|
27
|
-
const packets = [];
|
|
28
|
-
if (between(last, activation, start)) {
|
|
29
|
-
packets.push(packet);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const timePacket = {
|
|
33
|
-
...packet,
|
|
34
|
-
id: `${packet.id}.${Math.round(fromNow(deps.data.expiry) / 60000)}`,
|
|
35
|
-
};
|
|
36
|
-
packets.push(timePacket);
|
|
37
|
-
return packets;
|
|
38
|
-
};
|