@blocklet/sdk 1.17.2-beta-20251112-085154-0103b877 → 1.17.2-beta-20251113-121338-9c917e68
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/lib/service/notification.js +129 -106
- package/package.json +9 -9
|
@@ -57,7 +57,12 @@ const debug = (0, debug_1.default)('@blocklet/sdk:notification');
|
|
|
57
57
|
let client = null;
|
|
58
58
|
let connectionToken = null;
|
|
59
59
|
let connectionTokenTimer = null;
|
|
60
|
-
|
|
60
|
+
let initPromise = null; // 全局 Promise,确保多次调用时等待同一个初始化过程
|
|
61
|
+
const refreshConnectionToken = async (force = false) => {
|
|
62
|
+
// don't refresh token if client is closed
|
|
63
|
+
if (!force && connectionToken === null && connectionTokenTimer === null) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
61
66
|
const accessWallet = (0, wallet_1.getAccessWallet)();
|
|
62
67
|
connectionToken = await accessWallet.signJWT({});
|
|
63
68
|
// refresh token in 12 hours
|
|
@@ -150,121 +155,138 @@ const joinChannelErrorHandler = (name, type, emitters) => async (err) => {
|
|
|
150
155
|
(emitters || [emitter]).forEach((x) => x.emit('error', { message: msg }));
|
|
151
156
|
await debouncedRefreshConnectionToken();
|
|
152
157
|
};
|
|
153
|
-
const initClient =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
.
|
|
178
|
-
.
|
|
179
|
-
.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
158
|
+
const initClient = () => {
|
|
159
|
+
// 如果正在初始化,返回同一个 Promise 等待完成
|
|
160
|
+
if (initPromise) {
|
|
161
|
+
return initPromise;
|
|
162
|
+
}
|
|
163
|
+
// 如果已经初始化完成,直接返回
|
|
164
|
+
if (client) {
|
|
165
|
+
return Promise.resolve();
|
|
166
|
+
}
|
|
167
|
+
// 创建新的初始化 Promise
|
|
168
|
+
initPromise = (async () => {
|
|
169
|
+
try {
|
|
170
|
+
ensureErrorListener();
|
|
171
|
+
const accessWallet = (0, wallet_1.getAccessWallet)();
|
|
172
|
+
const componentDid = process.env.BLOCKLET_COMPONENT_DID;
|
|
173
|
+
const appDid = process.env.BLOCKLET_APP_PID;
|
|
174
|
+
const { publicKey: pk } = accessWallet;
|
|
175
|
+
await refreshConnectionToken(true);
|
|
176
|
+
// Build URL with query parameters directly
|
|
177
|
+
const baseUrl = `ws://${(0, parse_docker_endpoint_1.getServerHost)()}:${process.env.ABT_NODE_SERVICE_PORT}${constants_1.SERVICE_PREFIX}/websocket`;
|
|
178
|
+
const url = `${baseUrl}?token=${encodeURIComponent(connectionToken)}&pk=${encodeURIComponent(pk)}`;
|
|
179
|
+
client = new ws_1.WsClient(url, {
|
|
180
|
+
heartbeatIntervalMs: 10 * 1000,
|
|
181
|
+
});
|
|
182
|
+
client.connect();
|
|
183
|
+
const messageChannel = client.channel(accessWallet.address, () => ({ token: connectionToken, pk }));
|
|
184
|
+
const appPublicChannel = client.channel((0, channel_1.getAppPublicChannel)(appDid), () => ({ token: connectionToken, pk }));
|
|
185
|
+
const componentChannel = client.channel((0, channel_1.getComponentChannel)(appDid, componentDid), () => ({
|
|
186
|
+
token: connectionToken,
|
|
187
|
+
pk,
|
|
188
|
+
apiKey: process.env.BLOCKLET_COMPONENT_API_KEY,
|
|
189
|
+
}));
|
|
190
|
+
const eventBusChannel = client.channel((0, channel_1.getEventBusChannel)(appDid), () => ({ token: connectionToken, pk }));
|
|
191
|
+
messageChannel
|
|
192
|
+
.join()
|
|
193
|
+
.receive('error', joinChannelErrorHandler('message channel', 'error', [messageEmitter, emitter]))
|
|
194
|
+
.receive('timeout', joinChannelErrorHandler('message channel', 'timeout', [messageEmitter, emitter]));
|
|
195
|
+
appPublicChannel
|
|
196
|
+
.join()
|
|
197
|
+
.receive('error', joinChannelErrorHandler('app public channel', 'error'))
|
|
198
|
+
.receive('timeout', joinChannelErrorHandler('app public channel', 'timeout'));
|
|
199
|
+
componentChannel
|
|
200
|
+
.join()
|
|
201
|
+
.receive('error', joinChannelErrorHandler('app component channel', 'error'))
|
|
202
|
+
.receive('timeout', joinChannelErrorHandler('app component channel', 'timeout'));
|
|
203
|
+
eventBusChannel
|
|
204
|
+
.join()
|
|
205
|
+
.receive('error', joinChannelErrorHandler('eventbus channel', 'error'))
|
|
206
|
+
.receive('timeout', joinChannelErrorHandler('eventbus channel', 'timeout'));
|
|
207
|
+
messageChannel.on('message', ({ status, response } = {}) => {
|
|
208
|
+
debug('messageChannel.on', { status, response });
|
|
209
|
+
if (status === 'ok') {
|
|
210
|
+
messageEmitter.emit(response.type, response);
|
|
211
|
+
if (response.type === notification_1.NOTIFICATION_TYPES.HI) {
|
|
212
|
+
emitter.emit(response.type, response);
|
|
213
|
+
}
|
|
198
214
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
console.error('Message channel error', { status, response });
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
eventBusChannel.on('event', ({ status, response } = {}) => {
|
|
206
|
-
debug('eventBusChannel.on', { status, response });
|
|
207
|
-
if (status === 'ok') {
|
|
208
|
-
// ignore events from self
|
|
209
|
-
if (response.source !== process.env.BLOCKLET_COMPONENT_DID) {
|
|
210
|
-
exports._eventBus.emit('event', response);
|
|
215
|
+
else {
|
|
216
|
+
emitError(response);
|
|
217
|
+
console.error('Message channel error', { status, response });
|
|
211
218
|
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
console.error('Event channel error', { status, response });
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
[...Object.keys(constant_1.BlockletInternalEvents), ...Object.keys(constant_1.TeamEvents)].forEach((key) => {
|
|
219
|
-
const event = constant_1.BlockletInternalEvents[key] || constant_1.TeamEvents[key];
|
|
220
|
-
componentChannel.on(event, async ({ status, response } = {}) => {
|
|
221
|
-
debug('componentChannel.on', { event, status, response });
|
|
219
|
+
});
|
|
220
|
+
eventBusChannel.on('event', ({ status, response } = {}) => {
|
|
221
|
+
debug('eventBusChannel.on', { status, response });
|
|
222
222
|
if (status === 'ok') {
|
|
223
|
-
|
|
224
|
-
if (
|
|
225
|
-
|
|
223
|
+
// ignore events from self
|
|
224
|
+
if (response.source !== process.env.BLOCKLET_COMPONENT_DID) {
|
|
225
|
+
exports._eventBus.emit('event', response);
|
|
226
226
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
exports._eventBus.emit('error', response);
|
|
230
|
+
console.error('Event channel error', { status, response });
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
[...Object.keys(constant_1.BlockletInternalEvents), ...Object.keys(constant_1.TeamEvents)].forEach((key) => {
|
|
234
|
+
const event = constant_1.BlockletInternalEvents[key] || constant_1.TeamEvents[key];
|
|
235
|
+
componentChannel.on(event, async ({ status, response } = {}) => {
|
|
236
|
+
debug('componentChannel.on', { event, status, response });
|
|
237
|
+
if (status === 'ok') {
|
|
238
|
+
const { data, sender, time } = response;
|
|
239
|
+
if (!time || new Date(time).getTime() < new Date(process.env.BLOCKLET_START_AT).getTime()) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// verify sender is server
|
|
243
|
+
const tolerance = 600;
|
|
244
|
+
if (!(await Jwt.verify(sender.token, process.env.ABT_NODE_PK, { tolerance }))) {
|
|
245
|
+
const message = `verify sender failed in internal events. event: ${event}, sender: ${JSON.stringify({
|
|
246
|
+
sender,
|
|
247
|
+
decode: Jwt.decode(sender.token),
|
|
248
|
+
now: Date.now(),
|
|
249
|
+
ABT_NODE_PK: process.env.ABT_NODE_PK,
|
|
250
|
+
})}`;
|
|
251
|
+
emitError({ message });
|
|
252
|
+
console.error(message);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
emitter.emit(event, data);
|
|
256
|
+
// Emit team events to event bus
|
|
257
|
+
if (constant_1.TeamEvents[key]) {
|
|
258
|
+
exports._eventBus.emit('event', {
|
|
259
|
+
id: (0, util_1.nanoid)(),
|
|
260
|
+
time: new Date().toISOString(),
|
|
261
|
+
type: `blocklet.${event}`,
|
|
262
|
+
data: { object: data.user },
|
|
263
|
+
});
|
|
264
|
+
}
|
|
239
265
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
exports._eventBus.emit('event', {
|
|
244
|
-
id: (0, util_1.nanoid)(),
|
|
245
|
-
time: new Date().toISOString(),
|
|
246
|
-
type: `blocklet.${event}`,
|
|
247
|
-
data: { object: data.user },
|
|
248
|
-
});
|
|
266
|
+
else {
|
|
267
|
+
emitError(response);
|
|
268
|
+
console.error('Component channel error', { status, response });
|
|
249
269
|
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
appPublicChannel.on(notification_1.NOTIFICATION_TYPES.HI, ({ status, response } = {}) => {
|
|
273
|
+
debug('appPublicChannel.on', { event: notification_1.NOTIFICATION_TYPES.HI, status, response });
|
|
274
|
+
if (status === 'ok') {
|
|
275
|
+
emitter.emit(notification_1.NOTIFICATION_TYPES.HI, response);
|
|
250
276
|
}
|
|
251
277
|
else {
|
|
252
|
-
|
|
253
|
-
console.error('
|
|
278
|
+
emitter.emit('error', response);
|
|
279
|
+
console.error('App public channel error', { status, response });
|
|
254
280
|
}
|
|
255
281
|
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
console.error('App public channel error', { status, response });
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
initPromise = null; // 清除 Promise 以便重试
|
|
285
|
+
console.warn('Failed to init notification service', err);
|
|
286
|
+
throw err;
|
|
287
|
+
}
|
|
288
|
+
})();
|
|
289
|
+
return initPromise;
|
|
268
290
|
};
|
|
269
291
|
const cleanup = () => {
|
|
270
292
|
try {
|
|
@@ -277,6 +299,7 @@ const cleanup = () => {
|
|
|
277
299
|
client = null;
|
|
278
300
|
}
|
|
279
301
|
connectionToken = null;
|
|
302
|
+
initPromise = null;
|
|
280
303
|
}
|
|
281
304
|
catch (err) {
|
|
282
305
|
console.warn('Failed to cleanup notification service', err);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.17.2-beta-
|
|
6
|
+
"version": "1.17.2-beta-20251113-121338-9c917e68",
|
|
7
7
|
"description": "graphql client to read/write data on abt node",
|
|
8
8
|
"homepage": "https://www.arcblock.io/docs/blocklet-sdk-nodejs",
|
|
9
9
|
"main": "lib/index.js",
|
|
@@ -26,19 +26,19 @@
|
|
|
26
26
|
"author": "linchen1987 <linchen.1987@foxmail.com> (http://github.com/linchen1987)",
|
|
27
27
|
"license": "Apache-2.0",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@abtnode/constant": "1.17.2-beta-
|
|
30
|
-
"@abtnode/db-cache": "1.17.2-beta-
|
|
31
|
-
"@abtnode/util": "1.17.2-beta-
|
|
29
|
+
"@abtnode/constant": "1.17.2-beta-20251113-121338-9c917e68",
|
|
30
|
+
"@abtnode/db-cache": "1.17.2-beta-20251113-121338-9c917e68",
|
|
31
|
+
"@abtnode/util": "1.17.2-beta-20251113-121338-9c917e68",
|
|
32
32
|
"@arcblock/did": "^1.27.4",
|
|
33
33
|
"@arcblock/did-connect-js": "^1.27.4",
|
|
34
34
|
"@arcblock/did-ext": "^1.27.4",
|
|
35
35
|
"@arcblock/jwt": "^1.27.4",
|
|
36
36
|
"@arcblock/ws": "^1.27.4",
|
|
37
|
-
"@blocklet/constant": "1.17.2-beta-
|
|
38
|
-
"@blocklet/env": "1.17.2-beta-
|
|
37
|
+
"@blocklet/constant": "1.17.2-beta-20251113-121338-9c917e68",
|
|
38
|
+
"@blocklet/env": "1.17.2-beta-20251113-121338-9c917e68",
|
|
39
39
|
"@blocklet/error": "^0.3.2",
|
|
40
|
-
"@blocklet/meta": "1.17.2-beta-
|
|
41
|
-
"@blocklet/server-js": "1.17.2-beta-
|
|
40
|
+
"@blocklet/meta": "1.17.2-beta-20251113-121338-9c917e68",
|
|
41
|
+
"@blocklet/server-js": "1.17.2-beta-20251113-121338-9c917e68",
|
|
42
42
|
"@blocklet/theme": "^3.2.3",
|
|
43
43
|
"@did-connect/authenticator": "^2.2.8",
|
|
44
44
|
"@did-connect/handler": "^2.2.8",
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
"ts-node": "^10.9.1",
|
|
83
83
|
"typescript": "^5.6.3"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "82362ffba5d50f01774b257b9cd8143adeb7a898"
|
|
86
86
|
}
|