@naylence/runtime 0.3.5-test.954 → 0.3.5-test.956
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/browser/index.cjs +115 -24
- package/dist/browser/index.mjs +115 -24
- package/dist/cjs/naylence/fame/channel/flow-controller.js +38 -1
- package/dist/cjs/naylence/fame/connector/base-async-connector.js +6 -4
- package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +54 -3
- package/dist/cjs/naylence/fame/connector/broadcast-channel-listener.js +2 -0
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/channel/flow-controller.js +38 -1
- package/dist/esm/naylence/fame/connector/base-async-connector.js +6 -4
- package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +54 -3
- package/dist/esm/naylence/fame/connector/broadcast-channel-listener.js +2 -0
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +115 -24
- package/dist/node/index.mjs +115 -24
- package/dist/node/node.cjs +115 -24
- package/dist/node/node.mjs +115 -24
- package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +4 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -257,10 +257,12 @@ export class BaseAsyncConnector extends TaskSpawner {
|
|
|
257
257
|
throw new FameTransportClose('Connection closed', 1006);
|
|
258
258
|
}
|
|
259
259
|
// Apply flow control if enabled and not a credit update
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
'credits' in envelope.frame)
|
|
260
|
+
const isCreditUpdateFrame = Boolean(envelope.frame &&
|
|
261
|
+
(envelope.frame.type === 'CreditUpdate' ||
|
|
262
|
+
envelope.frame.type === 'credit_update' ||
|
|
263
|
+
('flowId' in envelope.frame && 'credits' in envelope.frame) ||
|
|
264
|
+
('flow_id' in envelope.frame && 'credits' in envelope.frame)));
|
|
265
|
+
if (this._fcEnabled && !isCreditUpdateFrame) {
|
|
264
266
|
const flowId = envelope.flowId || this._connectorFlowId;
|
|
265
267
|
envelope.flowId = flowId;
|
|
266
268
|
const t0 = this._metrics ? performance.now() : 0;
|
|
@@ -66,6 +66,7 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
66
66
|
? Math.floor(config.inboxCapacity)
|
|
67
67
|
: DEFAULT_INBOX_CAPACITY;
|
|
68
68
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
69
|
+
this.inboxCapacity = preferredCapacity;
|
|
69
70
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
70
71
|
this.channel = new BroadcastChannel(this.channelName);
|
|
71
72
|
logger.debug('broadcast_channel_connector_created', {
|
|
@@ -125,15 +126,27 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
125
126
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
126
127
|
const accepted = this.inbox.tryEnqueue(payload);
|
|
127
128
|
if (accepted) {
|
|
129
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
130
|
+
source: 'listener',
|
|
131
|
+
enqueue_strategy: 'try',
|
|
132
|
+
payload_length: payload.byteLength,
|
|
133
|
+
});
|
|
128
134
|
return;
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
this.inbox.enqueue(payload);
|
|
138
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
139
|
+
source: 'listener',
|
|
140
|
+
enqueue_strategy: 'enqueue',
|
|
141
|
+
payload_length: payload.byteLength,
|
|
142
|
+
});
|
|
132
143
|
}
|
|
133
144
|
catch (error) {
|
|
134
145
|
if (error instanceof QueueFullError) {
|
|
135
146
|
logger.warning('broadcast_channel_receive_queue_full', {
|
|
136
147
|
channel: this.channelName,
|
|
148
|
+
inbox_capacity: this.inboxCapacity,
|
|
149
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
137
150
|
});
|
|
138
151
|
}
|
|
139
152
|
else {
|
|
@@ -144,8 +157,10 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
144
157
|
}
|
|
145
158
|
}
|
|
146
159
|
};
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
if (!config.passive) {
|
|
161
|
+
this.channel.addEventListener('message', this.onMsg);
|
|
162
|
+
this.listenerRegistered = true;
|
|
163
|
+
}
|
|
149
164
|
// Setup visibility change monitoring
|
|
150
165
|
this.visibilityChangeHandler = () => {
|
|
151
166
|
const isHidden = document.hidden;
|
|
@@ -217,15 +232,25 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
217
232
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
218
233
|
const accepted = this.inbox.tryEnqueue(item);
|
|
219
234
|
if (accepted) {
|
|
235
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
236
|
+
enqueue_strategy: 'try',
|
|
237
|
+
item_type: this._describeInboxItem(item),
|
|
238
|
+
});
|
|
220
239
|
return;
|
|
221
240
|
}
|
|
222
241
|
}
|
|
223
242
|
this.inbox.enqueue(item);
|
|
243
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
244
|
+
enqueue_strategy: 'enqueue',
|
|
245
|
+
item_type: this._describeInboxItem(item),
|
|
246
|
+
});
|
|
224
247
|
}
|
|
225
248
|
catch (error) {
|
|
226
249
|
if (error instanceof QueueFullError) {
|
|
227
250
|
logger.warning('broadcast_channel_push_queue_full', {
|
|
228
251
|
channel: this.channelName,
|
|
252
|
+
inbox_capacity: this.inboxCapacity,
|
|
253
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
229
254
|
});
|
|
230
255
|
throw error;
|
|
231
256
|
}
|
|
@@ -248,7 +273,11 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
248
273
|
});
|
|
249
274
|
}
|
|
250
275
|
async _transportReceive() {
|
|
251
|
-
|
|
276
|
+
const item = await this.inbox.dequeue();
|
|
277
|
+
this.logInboxSnapshot('broadcast_channel_inbox_dequeued', {
|
|
278
|
+
item_type: this._describeInboxItem(item),
|
|
279
|
+
});
|
|
280
|
+
return item;
|
|
252
281
|
}
|
|
253
282
|
async _transportClose(code, reason) {
|
|
254
283
|
logger.debug('broadcast_channel_transport_closing', {
|
|
@@ -302,6 +331,28 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
302
331
|
}
|
|
303
332
|
return rawOrEnvelope;
|
|
304
333
|
}
|
|
334
|
+
_describeInboxItem(item) {
|
|
335
|
+
if (item instanceof Uint8Array) {
|
|
336
|
+
return 'bytes';
|
|
337
|
+
}
|
|
338
|
+
if (item.envelope) {
|
|
339
|
+
return 'channel_message';
|
|
340
|
+
}
|
|
341
|
+
if (item.frame) {
|
|
342
|
+
return 'envelope';
|
|
343
|
+
}
|
|
344
|
+
return 'unknown';
|
|
345
|
+
}
|
|
346
|
+
logInboxSnapshot(event, extra = {}) {
|
|
347
|
+
logger.debug(event, {
|
|
348
|
+
channel: this.channelName,
|
|
349
|
+
connector_id: this.connectorId,
|
|
350
|
+
connector_state: this.state,
|
|
351
|
+
inbox_capacity: this.inboxCapacity,
|
|
352
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
353
|
+
...extra,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
305
356
|
_shouldSkipDuplicateAck(senderId, payload) {
|
|
306
357
|
const dedupKey = this._extractAckDedupKey(payload);
|
|
307
358
|
if (!dedupKey) {
|
|
@@ -338,6 +338,7 @@ export class BroadcastChannelListener extends TransportListener {
|
|
|
338
338
|
type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
339
339
|
channelName: this._channelName,
|
|
340
340
|
inboxCapacity: this._inboxCapacity,
|
|
341
|
+
passive: true,
|
|
341
342
|
};
|
|
342
343
|
}
|
|
343
344
|
try {
|
|
@@ -398,6 +399,7 @@ export class BroadcastChannelListener extends TransportListener {
|
|
|
398
399
|
type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
399
400
|
channelName: this._channelName,
|
|
400
401
|
inboxCapacity: this._inboxCapacity,
|
|
402
|
+
passive: true,
|
|
401
403
|
};
|
|
402
404
|
const channelCandidate = candidate.channelName ?? candidate['channel_name'];
|
|
403
405
|
if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {
|
package/dist/esm/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This file is auto-generated during build - do not edit manually
|
|
2
|
-
// Generated from package.json version: 0.3.5-test.
|
|
2
|
+
// Generated from package.json version: 0.3.5-test.956
|
|
3
3
|
/**
|
|
4
4
|
* The package version, injected at build time.
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
|
-
export const VERSION = '0.3.5-test.
|
|
7
|
+
export const VERSION = '0.3.5-test.956';
|
package/dist/node/index.cjs
CHANGED
|
@@ -14,12 +14,12 @@ var fastify = require('fastify');
|
|
|
14
14
|
var websocketPlugin = require('@fastify/websocket');
|
|
15
15
|
|
|
16
16
|
// This file is auto-generated during build - do not edit manually
|
|
17
|
-
// Generated from package.json version: 0.3.5-test.
|
|
17
|
+
// Generated from package.json version: 0.3.5-test.956
|
|
18
18
|
/**
|
|
19
19
|
* The package version, injected at build time.
|
|
20
20
|
* @internal
|
|
21
21
|
*/
|
|
22
|
-
const VERSION = '0.3.5-test.
|
|
22
|
+
const VERSION = '0.3.5-test.956';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -837,7 +837,7 @@ class TaskCancelledError extends Error {
|
|
|
837
837
|
* Provides functionality similar to Python's asyncio TaskSpawner with proper
|
|
838
838
|
* error handling, cancellation, and graceful shutdown capabilities.
|
|
839
839
|
*/
|
|
840
|
-
const logger$
|
|
840
|
+
const logger$1c = getLogger('naylence.fame.util.task_spawner');
|
|
841
841
|
function firstDefined(source, keys) {
|
|
842
842
|
for (const key of keys) {
|
|
843
843
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
@@ -998,7 +998,7 @@ class TaskSpawner {
|
|
|
998
998
|
const taskId = `task-${++this._taskCounter}`;
|
|
999
999
|
const taskName = normalizedOptions.name || `unnamed-${taskId}`;
|
|
1000
1000
|
const timeout = normalizedOptions.timeout ?? this._config.defaultTimeout;
|
|
1001
|
-
logger$
|
|
1001
|
+
logger$1c.debug('starting_background_task', {
|
|
1002
1002
|
task_name: taskName,
|
|
1003
1003
|
task_id: taskId,
|
|
1004
1004
|
});
|
|
@@ -1015,7 +1015,7 @@ class TaskSpawner {
|
|
|
1015
1015
|
task.promise
|
|
1016
1016
|
.then(() => {
|
|
1017
1017
|
if (!this._suppressCompletionLogging) {
|
|
1018
|
-
logger$
|
|
1018
|
+
logger$1c.debug('task_completed_successfully', {
|
|
1019
1019
|
task_name: taskName,
|
|
1020
1020
|
task_id: taskId,
|
|
1021
1021
|
duration_ms: Date.now() - task.startTime,
|
|
@@ -1069,7 +1069,7 @@ class TaskSpawner {
|
|
|
1069
1069
|
error.name === 'AbortError' ||
|
|
1070
1070
|
error.message === 'Task cancelled' ||
|
|
1071
1071
|
error.message === 'Aborted') {
|
|
1072
|
-
logger$
|
|
1072
|
+
logger$1c.debug('task_cancelled', {
|
|
1073
1073
|
task_name: taskName,
|
|
1074
1074
|
note: 'Task cancelled as requested',
|
|
1075
1075
|
});
|
|
@@ -1077,7 +1077,7 @@ class TaskSpawner {
|
|
|
1077
1077
|
}
|
|
1078
1078
|
// Handle timeout
|
|
1079
1079
|
if (error instanceof TaskTimeoutError) {
|
|
1080
|
-
logger$
|
|
1080
|
+
logger$1c.warning('task_timed_out', {
|
|
1081
1081
|
task_name: taskName,
|
|
1082
1082
|
error: error.message,
|
|
1083
1083
|
});
|
|
@@ -1089,7 +1089,7 @@ class TaskSpawner {
|
|
|
1089
1089
|
// Handle known WebSocket shutdown race condition (similar to Python version)
|
|
1090
1090
|
if (error.message.includes("await wasn't used with future") ||
|
|
1091
1091
|
error.message.includes('WebSocket closed during receive')) {
|
|
1092
|
-
logger$
|
|
1092
|
+
logger$1c.debug('task_shutdown_race_condition_handled', {
|
|
1093
1093
|
task_name: taskName,
|
|
1094
1094
|
note: 'Normal WebSocket close timing during shutdown - not an error',
|
|
1095
1095
|
});
|
|
@@ -1099,7 +1099,7 @@ class TaskSpawner {
|
|
|
1099
1099
|
if (error.name === 'FameTransportClose' ||
|
|
1100
1100
|
error.message.includes('normal closure') ||
|
|
1101
1101
|
error.message.includes('Connection closed')) {
|
|
1102
|
-
logger$
|
|
1102
|
+
logger$1c.debug('task_shutdown_completed_normally', {
|
|
1103
1103
|
task_name: taskName,
|
|
1104
1104
|
note: 'Task closed normally during shutdown',
|
|
1105
1105
|
});
|
|
@@ -1112,14 +1112,14 @@ class TaskSpawner {
|
|
|
1112
1112
|
// Log retriable errors as warnings (they'll be retried by upstream logic)
|
|
1113
1113
|
// Log non-retriable errors as errors (fatal failures)
|
|
1114
1114
|
if (isRetriableError) {
|
|
1115
|
-
logger$
|
|
1115
|
+
logger$1c.warning('background_task_failed', {
|
|
1116
1116
|
task_name: taskName,
|
|
1117
1117
|
error: error.message,
|
|
1118
1118
|
retriable: true,
|
|
1119
1119
|
});
|
|
1120
1120
|
}
|
|
1121
1121
|
else {
|
|
1122
|
-
logger$
|
|
1122
|
+
logger$1c.error('background_task_failed', {
|
|
1123
1123
|
task_name: taskName,
|
|
1124
1124
|
error: error.message,
|
|
1125
1125
|
stack: error.stack,
|
|
@@ -1138,11 +1138,11 @@ class TaskSpawner {
|
|
|
1138
1138
|
async shutdownTasks(options = {}) {
|
|
1139
1139
|
const { gracePeriod, cancelHanging, joinTimeout } = normalizeShutdownOptions(options);
|
|
1140
1140
|
if (this._tasks.size === 0) {
|
|
1141
|
-
logger$
|
|
1141
|
+
logger$1c.debug('shutdown_tasks_no_tasks_to_shutdown');
|
|
1142
1142
|
return;
|
|
1143
1143
|
}
|
|
1144
1144
|
this._suppressCompletionLogging = true;
|
|
1145
|
-
logger$
|
|
1145
|
+
logger$1c.debug('shutting_down_tasks', {
|
|
1146
1146
|
task_count: this._tasks.size,
|
|
1147
1147
|
task_names: Array.from(this._tasks.values()).map((t) => t.name),
|
|
1148
1148
|
grace_period_ms: gracePeriod,
|
|
@@ -1157,7 +1157,7 @@ class TaskSpawner {
|
|
|
1157
1157
|
if (cancelHanging) {
|
|
1158
1158
|
const stillRunning = tasks.filter((task) => task.getState() === TaskState.RUNNING && !completed.has(task));
|
|
1159
1159
|
if (stillRunning.length > 0) {
|
|
1160
|
-
logger$
|
|
1160
|
+
logger$1c.debug('tasks_did_not_complete_within_grace_period', {
|
|
1161
1161
|
hanging_count: stillRunning.length,
|
|
1162
1162
|
});
|
|
1163
1163
|
// Wait for them to finish with individual timeouts
|
|
@@ -1167,7 +1167,7 @@ class TaskSpawner {
|
|
|
1167
1167
|
}
|
|
1168
1168
|
catch (error) {
|
|
1169
1169
|
if (error instanceof TaskTimeoutError) {
|
|
1170
|
-
logger$
|
|
1170
|
+
logger$1c.warning('task_did_not_shutdown', {
|
|
1171
1171
|
task_name: task.name || task.id,
|
|
1172
1172
|
join_timeout_ms: joinTimeout,
|
|
1173
1173
|
});
|
|
@@ -1178,7 +1178,7 @@ class TaskSpawner {
|
|
|
1178
1178
|
}
|
|
1179
1179
|
else if (!(error instanceof TaskCancelledError)) {
|
|
1180
1180
|
/* istanbul ignore next - unreachable defensive branch */
|
|
1181
|
-
logger$
|
|
1181
|
+
logger$1c.error('task_raised_during_cancellation', {
|
|
1182
1182
|
task_name: task.name || task.id,
|
|
1183
1183
|
error: error instanceof Error ? error.message : String(error),
|
|
1184
1184
|
});
|
|
@@ -2271,6 +2271,7 @@ function validateKeyCorrelationTtlSec(ttlSec) {
|
|
|
2271
2271
|
* condition/promise and ensure at most one notifier coroutine exists for a
|
|
2272
2272
|
* flow at any time.
|
|
2273
2273
|
*/
|
|
2274
|
+
const logger$1b = getLogger('naylence.fame.flow.flow_controller');
|
|
2274
2275
|
/**
|
|
2275
2276
|
* Simple condition variable implementation for TypeScript/Node.js
|
|
2276
2277
|
* Similar to Python's asyncio.Condition
|
|
@@ -2396,8 +2397,17 @@ class FlowController {
|
|
|
2396
2397
|
// clamp into [0, initialWindow]
|
|
2397
2398
|
const newBalance = Math.max(0, Math.min(this.initialWindow, prev + delta));
|
|
2398
2399
|
this.credits.set(flowId, newBalance);
|
|
2400
|
+
const crossedZero = prev <= 0 && newBalance > 0;
|
|
2401
|
+
logger$1b.debug('flow_controller_add_credits', {
|
|
2402
|
+
flow_id: flowId,
|
|
2403
|
+
delta,
|
|
2404
|
+
prev_balance: prev,
|
|
2405
|
+
new_balance: newBalance,
|
|
2406
|
+
initial_window: this.initialWindow,
|
|
2407
|
+
crossed_zero: crossedZero,
|
|
2408
|
+
});
|
|
2399
2409
|
// wake waiters only if we crossed the zero boundary
|
|
2400
|
-
if (
|
|
2410
|
+
if (crossedZero) {
|
|
2401
2411
|
this.wakeWaiters(flowId);
|
|
2402
2412
|
}
|
|
2403
2413
|
return newBalance;
|
|
@@ -2408,11 +2418,27 @@ class FlowController {
|
|
|
2408
2418
|
async acquire(flowId) {
|
|
2409
2419
|
this.ensureFlow(flowId);
|
|
2410
2420
|
const condition = this.conditions.get(flowId);
|
|
2421
|
+
logger$1b.debug('flow_controller_acquire_attempt', {
|
|
2422
|
+
flow_id: flowId,
|
|
2423
|
+
current_balance: this.credits.get(flowId),
|
|
2424
|
+
});
|
|
2411
2425
|
while (this.credits.get(flowId) <= 0) {
|
|
2426
|
+
logger$1b.debug('flow_controller_waiting_for_credit', {
|
|
2427
|
+
flow_id: flowId,
|
|
2428
|
+
});
|
|
2412
2429
|
await condition.wait();
|
|
2430
|
+
logger$1b.debug('flow_controller_woke_with_credit', {
|
|
2431
|
+
flow_id: flowId,
|
|
2432
|
+
balance_after_wake: this.credits.get(flowId),
|
|
2433
|
+
});
|
|
2413
2434
|
}
|
|
2414
2435
|
const current = this.credits.get(flowId);
|
|
2415
2436
|
this.credits.set(flowId, current - 1);
|
|
2437
|
+
logger$1b.debug('flow_controller_credit_consumed', {
|
|
2438
|
+
flow_id: flowId,
|
|
2439
|
+
prev_balance: current,
|
|
2440
|
+
remaining_balance: current - 1,
|
|
2441
|
+
});
|
|
2416
2442
|
}
|
|
2417
2443
|
/**
|
|
2418
2444
|
* Consume *credits* immediately (non-blocking).
|
|
@@ -2432,6 +2458,12 @@ class FlowController {
|
|
|
2432
2458
|
const current = this.credits.get(flowId);
|
|
2433
2459
|
const remaining = Math.max(current - credits, 0);
|
|
2434
2460
|
this.credits.set(flowId, remaining);
|
|
2461
|
+
logger$1b.debug('flow_controller_consume', {
|
|
2462
|
+
flow_id: flowId,
|
|
2463
|
+
requested: credits,
|
|
2464
|
+
prev_balance: current,
|
|
2465
|
+
remaining_balance: remaining,
|
|
2466
|
+
});
|
|
2435
2467
|
return remaining;
|
|
2436
2468
|
}
|
|
2437
2469
|
/**
|
|
@@ -2452,6 +2484,10 @@ class FlowController {
|
|
|
2452
2484
|
this.windowIds.delete(flowId);
|
|
2453
2485
|
this.credits.set(flowId, this.initialWindow);
|
|
2454
2486
|
this.wakeWaiters(flowId);
|
|
2487
|
+
logger$1b.debug('flow_controller_flow_reset', {
|
|
2488
|
+
flow_id: flowId,
|
|
2489
|
+
reset_balance: this.initialWindow,
|
|
2490
|
+
});
|
|
2455
2491
|
}
|
|
2456
2492
|
/**
|
|
2457
2493
|
* Return `[windowId, flags]` for the next outbound envelope.
|
|
@@ -9299,10 +9335,12 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9299
9335
|
throw new FameTransportClose('Connection closed', 1006);
|
|
9300
9336
|
}
|
|
9301
9337
|
// Apply flow control if enabled and not a credit update
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
'credits' in envelope.frame)
|
|
9338
|
+
const isCreditUpdateFrame = Boolean(envelope.frame &&
|
|
9339
|
+
(envelope.frame.type === 'CreditUpdate' ||
|
|
9340
|
+
envelope.frame.type === 'credit_update' ||
|
|
9341
|
+
('flowId' in envelope.frame && 'credits' in envelope.frame) ||
|
|
9342
|
+
('flow_id' in envelope.frame && 'credits' in envelope.frame)));
|
|
9343
|
+
if (this._fcEnabled && !isCreditUpdateFrame) {
|
|
9306
9344
|
const flowId = envelope.flowId || this._connectorFlowId;
|
|
9307
9345
|
envelope.flowId = flowId;
|
|
9308
9346
|
const t0 = this._metrics ? performance.now() : 0;
|
|
@@ -9797,6 +9835,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9797
9835
|
? Math.floor(config.inboxCapacity)
|
|
9798
9836
|
: DEFAULT_INBOX_CAPACITY$7;
|
|
9799
9837
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
9838
|
+
this.inboxCapacity = preferredCapacity;
|
|
9800
9839
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
9801
9840
|
this.channel = new BroadcastChannel(this.channelName);
|
|
9802
9841
|
logger$_.debug('broadcast_channel_connector_created', {
|
|
@@ -9856,15 +9895,27 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9856
9895
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
9857
9896
|
const accepted = this.inbox.tryEnqueue(payload);
|
|
9858
9897
|
if (accepted) {
|
|
9898
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
9899
|
+
source: 'listener',
|
|
9900
|
+
enqueue_strategy: 'try',
|
|
9901
|
+
payload_length: payload.byteLength,
|
|
9902
|
+
});
|
|
9859
9903
|
return;
|
|
9860
9904
|
}
|
|
9861
9905
|
}
|
|
9862
9906
|
this.inbox.enqueue(payload);
|
|
9907
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
9908
|
+
source: 'listener',
|
|
9909
|
+
enqueue_strategy: 'enqueue',
|
|
9910
|
+
payload_length: payload.byteLength,
|
|
9911
|
+
});
|
|
9863
9912
|
}
|
|
9864
9913
|
catch (error) {
|
|
9865
9914
|
if (error instanceof QueueFullError) {
|
|
9866
9915
|
logger$_.warning('broadcast_channel_receive_queue_full', {
|
|
9867
9916
|
channel: this.channelName,
|
|
9917
|
+
inbox_capacity: this.inboxCapacity,
|
|
9918
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
9868
9919
|
});
|
|
9869
9920
|
}
|
|
9870
9921
|
else {
|
|
@@ -9875,8 +9926,10 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9875
9926
|
}
|
|
9876
9927
|
}
|
|
9877
9928
|
};
|
|
9878
|
-
|
|
9879
|
-
|
|
9929
|
+
if (!config.passive) {
|
|
9930
|
+
this.channel.addEventListener('message', this.onMsg);
|
|
9931
|
+
this.listenerRegistered = true;
|
|
9932
|
+
}
|
|
9880
9933
|
// Setup visibility change monitoring
|
|
9881
9934
|
this.visibilityChangeHandler = () => {
|
|
9882
9935
|
const isHidden = document.hidden;
|
|
@@ -9948,15 +10001,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9948
10001
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
9949
10002
|
const accepted = this.inbox.tryEnqueue(item);
|
|
9950
10003
|
if (accepted) {
|
|
10004
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
10005
|
+
enqueue_strategy: 'try',
|
|
10006
|
+
item_type: this._describeInboxItem(item),
|
|
10007
|
+
});
|
|
9951
10008
|
return;
|
|
9952
10009
|
}
|
|
9953
10010
|
}
|
|
9954
10011
|
this.inbox.enqueue(item);
|
|
10012
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
10013
|
+
enqueue_strategy: 'enqueue',
|
|
10014
|
+
item_type: this._describeInboxItem(item),
|
|
10015
|
+
});
|
|
9955
10016
|
}
|
|
9956
10017
|
catch (error) {
|
|
9957
10018
|
if (error instanceof QueueFullError) {
|
|
9958
10019
|
logger$_.warning('broadcast_channel_push_queue_full', {
|
|
9959
10020
|
channel: this.channelName,
|
|
10021
|
+
inbox_capacity: this.inboxCapacity,
|
|
10022
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
9960
10023
|
});
|
|
9961
10024
|
throw error;
|
|
9962
10025
|
}
|
|
@@ -9979,7 +10042,11 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9979
10042
|
});
|
|
9980
10043
|
}
|
|
9981
10044
|
async _transportReceive() {
|
|
9982
|
-
|
|
10045
|
+
const item = await this.inbox.dequeue();
|
|
10046
|
+
this.logInboxSnapshot('broadcast_channel_inbox_dequeued', {
|
|
10047
|
+
item_type: this._describeInboxItem(item),
|
|
10048
|
+
});
|
|
10049
|
+
return item;
|
|
9983
10050
|
}
|
|
9984
10051
|
async _transportClose(code, reason) {
|
|
9985
10052
|
logger$_.debug('broadcast_channel_transport_closing', {
|
|
@@ -10033,6 +10100,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
10033
10100
|
}
|
|
10034
10101
|
return rawOrEnvelope;
|
|
10035
10102
|
}
|
|
10103
|
+
_describeInboxItem(item) {
|
|
10104
|
+
if (item instanceof Uint8Array) {
|
|
10105
|
+
return 'bytes';
|
|
10106
|
+
}
|
|
10107
|
+
if (item.envelope) {
|
|
10108
|
+
return 'channel_message';
|
|
10109
|
+
}
|
|
10110
|
+
if (item.frame) {
|
|
10111
|
+
return 'envelope';
|
|
10112
|
+
}
|
|
10113
|
+
return 'unknown';
|
|
10114
|
+
}
|
|
10115
|
+
logInboxSnapshot(event, extra = {}) {
|
|
10116
|
+
logger$_.debug(event, {
|
|
10117
|
+
channel: this.channelName,
|
|
10118
|
+
connector_id: this.connectorId,
|
|
10119
|
+
connector_state: this.state,
|
|
10120
|
+
inbox_capacity: this.inboxCapacity,
|
|
10121
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
10122
|
+
...extra,
|
|
10123
|
+
});
|
|
10124
|
+
}
|
|
10036
10125
|
_shouldSkipDuplicateAck(senderId, payload) {
|
|
10037
10126
|
const dedupKey = this._extractAckDedupKey(payload);
|
|
10038
10127
|
if (!dedupKey) {
|
|
@@ -36171,6 +36260,7 @@ class BroadcastChannelListener extends TransportListener {
|
|
|
36171
36260
|
type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
36172
36261
|
channelName: this._channelName,
|
|
36173
36262
|
inboxCapacity: this._inboxCapacity,
|
|
36263
|
+
passive: true,
|
|
36174
36264
|
};
|
|
36175
36265
|
}
|
|
36176
36266
|
try {
|
|
@@ -36231,6 +36321,7 @@ class BroadcastChannelListener extends TransportListener {
|
|
|
36231
36321
|
type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
36232
36322
|
channelName: this._channelName,
|
|
36233
36323
|
inboxCapacity: this._inboxCapacity,
|
|
36324
|
+
passive: true,
|
|
36234
36325
|
};
|
|
36235
36326
|
const channelCandidate = candidate.channelName ?? candidate['channel_name'];
|
|
36236
36327
|
if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {
|