bedrock-portal 2.2.0 → 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/dist/common/start_game.js +1 -1
- package/dist/handlers/Event.js +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +37 -10
- package/dist/rest.d.ts +8 -25
- package/dist/rest.js +67 -57
- package/dist/types/sessiondirectory.d.ts +2 -1
- package/package.json +3 -4
package/dist/handlers/Event.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.default = async (portal, event) => {
|
|
|
11
11
|
return;
|
|
12
12
|
portal.emit('rtaEvent', event);
|
|
13
13
|
const session = await portal.getSession();
|
|
14
|
+
await portal.syncSessionNonces(session);
|
|
14
15
|
portal.emit('sessionUpdated', session);
|
|
15
16
|
debug('Received RTA event, session has been updated', session);
|
|
16
17
|
const sessionMembers = Object.values(session.members).filter(member => member.constants.system.xuid !== portal.host?.profile?.xuid);
|
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export declare class BedrockPortal extends TypedEmitter<PortalEvents> {
|
|
|
131
131
|
options: BedrockPortalOptions;
|
|
132
132
|
session: {
|
|
133
133
|
name: string;
|
|
134
|
+
pmsgId: string;
|
|
135
|
+
nonces: Record<string, string>;
|
|
134
136
|
};
|
|
135
137
|
players: Map<string, Player>;
|
|
136
138
|
peers: Map<string, Host>;
|
|
@@ -173,6 +175,7 @@ export declare class BedrockPortal extends TypedEmitter<PortalEvents> {
|
|
|
173
175
|
* @param payload The payload to update the session with.
|
|
174
176
|
*/
|
|
175
177
|
updateSession(payload: SessionRequest): Promise<void>;
|
|
178
|
+
syncSessionNonces(session: RESTSessionResponse): Promise<void>;
|
|
176
179
|
/**
|
|
177
180
|
* Enables a module for the BedrockPortal instance.
|
|
178
181
|
* @see [Modules](https://github.com/LucienHH/bedrock-portal#modules) for a list of available modules or to create your own.
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Modules = exports.Module = exports.Joinability = exports.BedrockPortal = void 0;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
7
8
|
const debug_1 = __importDefault(require("debug"));
|
|
8
9
|
const uuid_1 = require("uuid");
|
|
9
10
|
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
|
|
@@ -68,7 +69,7 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
68
69
|
};
|
|
69
70
|
this.validateOptions(this.options);
|
|
70
71
|
this.host = new Host_1.default(this, this.options.host instanceof prismarine_auth_1.Authflow ? this.options.host : new prismarine_auth_1.Authflow(this.options.host.username, this.options.host.cache, this.options.host.options, this.options.host.onMsaCode));
|
|
71
|
-
this.session = { name: '' };
|
|
72
|
+
this.session = { name: '', pmsgId: '', nonces: {} };
|
|
72
73
|
this.players = new Map();
|
|
73
74
|
this.peers = new Map();
|
|
74
75
|
this.modules = new Map();
|
|
@@ -84,9 +85,15 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
84
85
|
*/
|
|
85
86
|
async start() {
|
|
86
87
|
this.players = new Map();
|
|
88
|
+
this.session.pmsgId = '';
|
|
89
|
+
this.session.nonces = {};
|
|
87
90
|
await this.host.connect();
|
|
88
91
|
this.session.name = (0, uuid_1.v4)();
|
|
89
92
|
await this.server.listen(this.host.authflow, this.options.webRTCNetworkId);
|
|
93
|
+
const pmsgId = this.server.signaling?.pmsgId;
|
|
94
|
+
if (!pmsgId)
|
|
95
|
+
throw new Error('Failed to determine signaling pmsgId');
|
|
96
|
+
this.session.pmsgId = pmsgId;
|
|
90
97
|
this.server.on('connect', (client) => this.onServerConnection(client));
|
|
91
98
|
const session = await this.createAndPublishSession();
|
|
92
99
|
await this.connectPeers();
|
|
@@ -166,6 +173,29 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
166
173
|
async updateSession(payload) {
|
|
167
174
|
await this.host.rest.updateSession(this.session.name, payload);
|
|
168
175
|
}
|
|
176
|
+
async syncSessionNonces(session) {
|
|
177
|
+
const hostProfile = this.host.profile;
|
|
178
|
+
if (!hostProfile) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const activeXuids = [...new Set(Object.values(session.members)
|
|
182
|
+
.map(member => member.constants.system.xuid)
|
|
183
|
+
.filter(xuid => xuid !== hostProfile.xuid))].sort();
|
|
184
|
+
const nextNonces = Object.fromEntries(activeXuids.map(xuid => [xuid, this.session.nonces[xuid] ?? (0, crypto_1.randomBytes)(8).toString('hex')]));
|
|
185
|
+
const hasChanges = Object.keys(this.session.nonces).length !== activeXuids.length
|
|
186
|
+
|| activeXuids.some(xuid => this.session.nonces[xuid] !== nextNonces[xuid]);
|
|
187
|
+
if (!hasChanges) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
this.session.nonces = nextNonces;
|
|
191
|
+
await this.updateSession({
|
|
192
|
+
properties: {
|
|
193
|
+
custom: {
|
|
194
|
+
nonces: nextNonces,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
}
|
|
169
199
|
/**
|
|
170
200
|
* Enables a module for the BedrockPortal instance.
|
|
171
201
|
* @see [Modules](https://github.com/LucienHH/bedrock-portal#modules) for a list of available modules or to create your own.
|
|
@@ -210,14 +240,8 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
210
240
|
has_editor_packs: false,
|
|
211
241
|
});
|
|
212
242
|
client.once('resource_pack_client_response', () => {
|
|
213
|
-
client.write('voxel_shapes', {
|
|
214
|
-
shapes: [],
|
|
215
|
-
name_map: [],
|
|
216
|
-
custom_shape_count: 0,
|
|
217
|
-
});
|
|
218
243
|
client.write('start_game', start_game_1.start_game);
|
|
219
|
-
client.
|
|
220
|
-
client.once('set_local_player_as_initialized', () => {
|
|
244
|
+
client.once('set_player_game_type', () => {
|
|
221
245
|
client.write('transfer', { server_address: this.options.ip, port: this.options.port });
|
|
222
246
|
});
|
|
223
247
|
});
|
|
@@ -278,6 +302,8 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
278
302
|
createSessionBody() {
|
|
279
303
|
if (!this.host.profile || !this.host.connectionId)
|
|
280
304
|
throw new Error('No session owner');
|
|
305
|
+
if (!this.session.pmsgId)
|
|
306
|
+
throw new Error('No session connection payload id');
|
|
281
307
|
const joinability = constants_1.JoinabilityConfig[this.options.joinability];
|
|
282
308
|
return {
|
|
283
309
|
properties: {
|
|
@@ -306,13 +332,14 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
306
332
|
WebRTCNetworkId: this.options.webRTCNetworkId,
|
|
307
333
|
isHardcore: this.options.world.isHardcore,
|
|
308
334
|
isEditorWorld: this.options.world.isEditor,
|
|
335
|
+
nonces: this.session.nonces,
|
|
309
336
|
SupportedConnections: [
|
|
310
337
|
{
|
|
311
|
-
ConnectionType:
|
|
338
|
+
ConnectionType: 7,
|
|
312
339
|
HostIpAddress: '',
|
|
313
340
|
HostPort: 0,
|
|
314
|
-
WebRTCNetworkId: this.options.webRTCNetworkId,
|
|
315
341
|
NetherNetId: this.options.webRTCNetworkId,
|
|
342
|
+
PmsgId: this.session.pmsgId,
|
|
316
343
|
},
|
|
317
344
|
],
|
|
318
345
|
},
|
package/dist/rest.d.ts
CHANGED
|
@@ -1,35 +1,18 @@
|
|
|
1
|
-
import { AxiosRequestConfig } from 'axios';
|
|
2
1
|
import { Authflow } from 'prismarine-auth';
|
|
3
2
|
import { RESTXblmessageInboxResponse } from './types/xblmessaging';
|
|
4
3
|
import { SessionRequest, RESTSessionResponse, SessionHandlePayload } from './types/sessiondirectory';
|
|
5
4
|
import { RESTSocialPostBulkFriendRequestResponse } from './types/social';
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
type MethodRequestConfig = {
|
|
10
|
-
relyingParty?: string;
|
|
11
|
-
contractVersion?: string;
|
|
12
|
-
params?: AxiosRequestConfig['params'];
|
|
13
|
-
data?: AxiosRequestConfig['data'];
|
|
14
|
-
headers?: RequestHeaders;
|
|
15
|
-
};
|
|
16
|
-
type RequestConfig = MethodRequestConfig & {
|
|
17
|
-
url: string;
|
|
5
|
+
type RestOptions = {
|
|
6
|
+
headers?: HeadersInit;
|
|
18
7
|
};
|
|
19
8
|
export default class Rest {
|
|
20
9
|
auth: Authflow;
|
|
21
|
-
options:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
put(url: string, config?: MethodRequestConfig): Promise<any>;
|
|
28
|
-
delete(url: string, config?: MethodRequestConfig): Promise<any>;
|
|
29
|
-
_request(method: 'GET' | 'POST' | 'PUT' | 'DELETE', config: RequestConfig): Promise<any>;
|
|
30
|
-
sendHandle(payload: SessionHandlePayload): Promise<any>;
|
|
31
|
-
setActivity(sessionName: string): Promise<any>;
|
|
32
|
-
sendInvite(sessionName: string, xuid: string): Promise<any>;
|
|
10
|
+
options: RestOptions;
|
|
11
|
+
constructor(authflow: Authflow, options?: RestOptions);
|
|
12
|
+
private fetchJson;
|
|
13
|
+
sendHandle(payload: SessionHandlePayload): Promise<unknown>;
|
|
14
|
+
setActivity(sessionName: string): Promise<unknown>;
|
|
15
|
+
sendInvite(sessionName: string, xuid: string): Promise<unknown>;
|
|
33
16
|
getSession(sessionName: string): Promise<RESTSessionResponse>;
|
|
34
17
|
updateSession(sessionName: string, payload: SessionRequest): Promise<RESTSessionResponse>;
|
|
35
18
|
updateMemberCount(sessionName: string, count: number, maxCount?: number): Promise<void>;
|
package/dist/rest.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const axios_1 = __importDefault(require("axios"));
|
|
7
3
|
const json_bigint_1 = require("json-bigint");
|
|
8
4
|
const constants_1 = require("./common/constants");
|
|
9
5
|
const util_1 = require("./common/util");
|
|
@@ -14,47 +10,39 @@ class Rest {
|
|
|
14
10
|
this.auth = authflow;
|
|
15
11
|
this.options = options;
|
|
16
12
|
}
|
|
17
|
-
async
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
async post(url, config = {}) {
|
|
21
|
-
return await this._request('POST', { url, ...config });
|
|
22
|
-
}
|
|
23
|
-
async put(url, config = {}) {
|
|
24
|
-
return await this._request('PUT', { url, ...config });
|
|
25
|
-
}
|
|
26
|
-
async delete(url, config = {}) {
|
|
27
|
-
return await this._request('DELETE', { url, ...config });
|
|
28
|
-
}
|
|
29
|
-
async _request(method, config) {
|
|
13
|
+
async fetchJson(url, init = {}) {
|
|
14
|
+
const { contractVersion, headers: requestHeaders, ...requestInit } = init;
|
|
30
15
|
const auth = await this.auth.getXboxToken('http://xboxlive.com');
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
16
|
+
const headers = new Headers({
|
|
17
|
+
'authorization': `XBL3.0 x=${auth.userHash};${auth.XSTSToken}`,
|
|
18
|
+
'accept-language': 'en-US',
|
|
19
|
+
});
|
|
20
|
+
for (const [key, value] of new Headers(this.options.headers).entries()) {
|
|
21
|
+
headers.set(key, value);
|
|
22
|
+
}
|
|
23
|
+
for (const [key, value] of new Headers(requestHeaders).entries()) {
|
|
24
|
+
headers.set(key, value);
|
|
25
|
+
}
|
|
26
|
+
if (requestInit.body !== undefined && !headers.has('content-type')) {
|
|
27
|
+
headers.set('content-type', 'application/json');
|
|
28
|
+
}
|
|
29
|
+
if (contractVersion)
|
|
30
|
+
headers.set('x-xbl-contract-version', contractVersion);
|
|
31
|
+
const response = await fetch(url, {
|
|
32
|
+
...requestInit,
|
|
33
|
+
headers,
|
|
34
|
+
});
|
|
35
|
+
const body = await response.text();
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
const detail = body ? `: ${body}` : '';
|
|
38
|
+
throw new Error(`Request failed with status ${response.status} ${response.statusText}${detail}`);
|
|
39
|
+
}
|
|
40
|
+
return (body ? (0, json_bigint_1.parse)(body) : undefined);
|
|
54
41
|
}
|
|
55
42
|
async sendHandle(payload) {
|
|
56
|
-
return this.
|
|
57
|
-
|
|
43
|
+
return this.fetchJson('https://sessiondirectory.xboxlive.com/handles', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
body: (0, json_bigint_1.stringify)(payload),
|
|
58
46
|
contractVersion: '107',
|
|
59
47
|
});
|
|
60
48
|
}
|
|
@@ -75,14 +63,15 @@ class Rest {
|
|
|
75
63
|
});
|
|
76
64
|
}
|
|
77
65
|
async getSession(sessionName) {
|
|
78
|
-
const response = await this.
|
|
66
|
+
const response = await this.fetchJson(`https://sessiondirectory.xboxlive.com/serviceconfigs/${constants_1.SessionConfig.MinecraftSCID}/sessionTemplates/${constants_1.SessionConfig.MinecraftTemplateName}/sessions/${sessionName}`, {
|
|
79
67
|
contractVersion: '107',
|
|
80
68
|
});
|
|
81
69
|
return response;
|
|
82
70
|
}
|
|
83
71
|
async updateSession(sessionName, payload) {
|
|
84
|
-
const response = await this.
|
|
85
|
-
|
|
72
|
+
const response = await this.fetchJson(`https://sessiondirectory.xboxlive.com/serviceconfigs/${constants_1.SessionConfig.MinecraftSCID}/sessionTemplates/${constants_1.SessionConfig.MinecraftTemplateName}/sessions/${sessionName}`, {
|
|
73
|
+
method: 'PUT',
|
|
74
|
+
body: (0, json_bigint_1.stringify)(payload),
|
|
86
75
|
contractVersion: '107',
|
|
87
76
|
});
|
|
88
77
|
return response;
|
|
@@ -117,48 +106,69 @@ class Rest {
|
|
|
117
106
|
let xuid = input;
|
|
118
107
|
if (!(0, util_1.isXuid)(input)) {
|
|
119
108
|
const target = input === 'me' ? 'me' : `gt(${encodeURIComponent(input)})`;
|
|
120
|
-
const response = await this.
|
|
109
|
+
const response = await this.fetchJson(`https://profile.xboxlive.com/users/${target}/settings`, { contractVersion: '2' });
|
|
121
110
|
xuid = response.profileUsers[0].id;
|
|
122
111
|
}
|
|
123
|
-
const response = await this.
|
|
112
|
+
const response = await this.fetchJson(`https://peoplehub.xboxlive.com/users/me/people/xuids(${xuid})/decoration/detail,preferredcolor`, { contractVersion: '5' });
|
|
124
113
|
return response.people.shift();
|
|
125
114
|
}
|
|
126
115
|
async getProfiles(xuids) {
|
|
127
|
-
const response = await this.
|
|
116
|
+
const response = await this.fetchJson('https://peoplehub.xboxlive.com/users/me/people/batch/decoration/detail,preferredcolor', {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
body: (0, json_bigint_1.stringify)({ xuids }),
|
|
119
|
+
contractVersion: '5',
|
|
120
|
+
});
|
|
128
121
|
return response.people;
|
|
129
122
|
}
|
|
130
123
|
async getXboxFriends() {
|
|
131
|
-
const response = await this.
|
|
124
|
+
const response = await this.fetchJson('https://peoplehub.xboxlive.com/users/me/people/social/decoration/detail,preferredColor,follower', { contractVersion: '5' });
|
|
132
125
|
return response.people;
|
|
133
126
|
}
|
|
134
127
|
async getXboxFollowers() {
|
|
135
|
-
const response = await this.
|
|
128
|
+
const response = await this.fetchJson('https://peoplehub.xboxlive.com/users/me/people/followers/decoration/detail,preferredColor,follower', { contractVersion: '5' });
|
|
136
129
|
return response.people;
|
|
137
130
|
}
|
|
138
131
|
async getFriendRequestsReceived() {
|
|
139
|
-
const response = await this.
|
|
132
|
+
const response = await this.fetchJson('https://peoplehub.xboxlive.com/users/me/people/friendrequests(received)/decoration/detail,preferredColor,follower', { contractVersion: '7' });
|
|
140
133
|
return response.people;
|
|
141
134
|
}
|
|
142
135
|
async acceptFriendRequests(xuids) {
|
|
143
|
-
const response = await this.
|
|
136
|
+
const response = await this.fetchJson('https://social.xboxlive.com/bulk/users/me/people/friends/v2?method=add', {
|
|
137
|
+
method: 'POST',
|
|
138
|
+
body: (0, json_bigint_1.stringify)({ xuids }),
|
|
139
|
+
contractVersion: '3',
|
|
140
|
+
});
|
|
144
141
|
return response;
|
|
145
142
|
}
|
|
146
143
|
async declineFriendRequests(xuids) {
|
|
147
|
-
const response = await this.
|
|
144
|
+
const response = await this.fetchJson('https://social.xboxlive.com/bulk/users/me/people/friends/v2?method=remove', {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
body: (0, json_bigint_1.stringify)({ xuids }),
|
|
147
|
+
contractVersion: '3',
|
|
148
|
+
});
|
|
148
149
|
return response;
|
|
149
150
|
}
|
|
150
151
|
async addXboxFriend(xuid) {
|
|
151
|
-
await this.
|
|
152
|
+
await this.fetchJson(`https://social.xboxlive.com/users/me/people/xuid(${xuid})`, {
|
|
153
|
+
method: 'PUT',
|
|
154
|
+
contractVersion: '2',
|
|
155
|
+
});
|
|
152
156
|
}
|
|
153
157
|
async removeXboxFriend(xuid) {
|
|
154
|
-
await this.
|
|
158
|
+
await this.fetchJson(`https://social.xboxlive.com/users/me/people/xuid(${xuid})`, {
|
|
159
|
+
method: 'DELETE',
|
|
160
|
+
contractVersion: '2',
|
|
161
|
+
});
|
|
155
162
|
}
|
|
156
163
|
async getInboxMessages(inbox) {
|
|
157
|
-
const response = await this.
|
|
164
|
+
const response = await this.fetchJson(`https://xblmessaging.xboxlive.com/network/xbox/users/me/inbox/${inbox}`, { contractVersion: '1' });
|
|
158
165
|
return response;
|
|
159
166
|
}
|
|
160
167
|
async setPresence(xuid) {
|
|
161
|
-
await this.
|
|
168
|
+
await this.fetchJson(`https://userpresence.xboxlive.com/users/xuid(${xuid})/devices/current/titles/current`, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
body: (0, json_bigint_1.stringify)({ state: 'active' }),
|
|
171
|
+
});
|
|
162
172
|
}
|
|
163
173
|
}
|
|
164
174
|
exports.default = Rest;
|
|
@@ -97,7 +97,7 @@ export interface SessionConnection {
|
|
|
97
97
|
HostIpAddress: string;
|
|
98
98
|
HostPort: number;
|
|
99
99
|
NetherNetId: bigint;
|
|
100
|
-
|
|
100
|
+
PmsgId: string;
|
|
101
101
|
}
|
|
102
102
|
export interface SessionRequest {
|
|
103
103
|
properties?: {
|
|
@@ -127,6 +127,7 @@ export interface SessionRequest {
|
|
|
127
127
|
TitleId?: number;
|
|
128
128
|
isHardcore?: boolean;
|
|
129
129
|
isEditorWorld?: boolean;
|
|
130
|
+
nonces?: Record<string, string>;
|
|
130
131
|
SupportedConnections?: SessionConnection[];
|
|
131
132
|
};
|
|
132
133
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bedrock-portal",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Creates a joinable session in Minecraft Bedrock Edition that can route players to their a specified host",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -21,11 +21,10 @@
|
|
|
21
21
|
},
|
|
22
22
|
"homepage": "https://github.com/LucienHH/bedrock-portal#readme",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"axios": "^1.0.0",
|
|
25
24
|
"bedrock-portal-nethernet": "^2.0.0",
|
|
26
25
|
"debug": "^4.3.4",
|
|
27
26
|
"json-bigint": "^1.0.0",
|
|
28
|
-
"prismarine-auth": "
|
|
27
|
+
"prismarine-auth": "^3.1.1",
|
|
29
28
|
"tiny-typed-emitter": "^2.1.0",
|
|
30
29
|
"uuid": "^9.0.0",
|
|
31
30
|
"xbox-message": "^0.2.0",
|
|
@@ -40,6 +39,6 @@
|
|
|
40
39
|
"@typescript-eslint/parser": "^6.17.0",
|
|
41
40
|
"bedrock-portal": "file:.",
|
|
42
41
|
"eslint": "^8.33.0",
|
|
43
|
-
"typescript": "^
|
|
42
|
+
"typescript": "^6.0.3"
|
|
44
43
|
}
|
|
45
44
|
}
|