@naylence/runtime 0.3.5-test.966 → 0.3.6-test.1

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.
Files changed (29) hide show
  1. package/dist/browser/index.cjs +363 -72
  2. package/dist/browser/index.mjs +363 -73
  3. package/dist/cjs/naylence/fame/connector/index.js +2 -1
  4. package/dist/cjs/naylence/fame/connector/inpage-connector-factory.js +36 -0
  5. package/dist/cjs/naylence/fame/connector/inpage-connector.js +213 -18
  6. package/dist/cjs/naylence/fame/connector/inpage-listener.js +67 -8
  7. package/dist/cjs/naylence/fame/util/index.js +3 -1
  8. package/dist/cjs/node.js +4 -1
  9. package/dist/cjs/version.js +2 -2
  10. package/dist/esm/naylence/fame/connector/index.js +1 -1
  11. package/dist/esm/naylence/fame/connector/inpage-connector-factory.js +36 -0
  12. package/dist/esm/naylence/fame/connector/inpage-connector.js +213 -18
  13. package/dist/esm/naylence/fame/connector/inpage-listener.js +67 -8
  14. package/dist/esm/naylence/fame/util/index.js +1 -0
  15. package/dist/esm/node.js +2 -1
  16. package/dist/esm/version.js +2 -2
  17. package/dist/node/index.cjs +363 -72
  18. package/dist/node/index.mjs +363 -73
  19. package/dist/node/node.cjs +320 -28
  20. package/dist/node/node.mjs +319 -29
  21. package/dist/types/naylence/fame/connector/index.d.ts +2 -2
  22. package/dist/types/naylence/fame/connector/inpage-connector-factory.d.ts +6 -0
  23. package/dist/types/naylence/fame/connector/inpage-connector.d.ts +13 -0
  24. package/dist/types/naylence/fame/connector/inpage-listener.d.ts +4 -0
  25. package/dist/types/naylence/fame/grants/inpage-connection-grant.d.ts +2 -0
  26. package/dist/types/naylence/fame/util/index.d.ts +1 -0
  27. package/dist/types/node.d.ts +2 -1
  28. package/dist/types/version.d.ts +1 -1
  29. package/package.json +1 -1
@@ -61,6 +61,26 @@ export class InPageConnector extends BaseAsyncConnector {
61
61
  }
62
62
  return null;
63
63
  }
64
+ static normalizeNodeId(value) {
65
+ if (typeof value !== 'string') {
66
+ return null;
67
+ }
68
+ const trimmed = value.trim();
69
+ return trimmed.length > 0 ? trimmed : null;
70
+ }
71
+ static normalizeTargetNodeId(value) {
72
+ if (typeof value !== 'string') {
73
+ return undefined;
74
+ }
75
+ const trimmed = value.trim();
76
+ if (trimmed.length === 0) {
77
+ return undefined;
78
+ }
79
+ if (trimmed === '*') {
80
+ return '*';
81
+ }
82
+ return trimmed;
83
+ }
64
84
  constructor(config, baseConfig = {}) {
65
85
  ensureBrowserEnvironment();
66
86
  super(baseConfig);
@@ -76,41 +96,68 @@ export class InPageConnector extends BaseAsyncConnector {
76
96
  ? Math.floor(config.inboxCapacity)
77
97
  : DEFAULT_INBOX_CAPACITY;
78
98
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
99
+ this.inboxCapacity = preferredCapacity;
79
100
  this.connectorId = InPageConnector.generateConnectorId();
101
+ const normalizedLocalNodeId = InPageConnector.normalizeNodeId(config.localNodeId);
102
+ if (!normalizedLocalNodeId) {
103
+ throw new Error('InPageConnector requires a non-empty localNodeId');
104
+ }
105
+ this.localNodeId = normalizedLocalNodeId;
106
+ this.targetNodeId = InPageConnector.normalizeTargetNodeId(config.initialTargetNodeId);
80
107
  logger.debug('inpage_connector_initialized', {
81
108
  channel: this.channelName,
82
109
  connector_id: this.connectorId,
110
+ local_node_id: this.localNodeId,
111
+ target_node_id: this.targetNodeId ?? null,
112
+ inbox_capacity: preferredCapacity,
83
113
  });
84
114
  this.onMsg = (event) => {
115
+ if (!this.listenerRegistered) {
116
+ logger.warning('inpage_message_after_unregister', {
117
+ channel: this.channelName,
118
+ connector_id: this.connectorId,
119
+ timestamp: new Date().toISOString(),
120
+ });
121
+ return;
122
+ }
85
123
  const messageEvent = event;
86
124
  const message = messageEvent.data;
87
125
  logger.debug('inpage_raw_event', {
88
126
  channel: this.channelName,
89
127
  connector_id: this.connectorId,
90
- message_type: message && typeof message === 'object' ? message.constructor?.name ?? typeof message : typeof message,
91
- has_sender_id: Boolean(message?.senderId),
92
- payload_type: message && typeof message === 'object'
93
- ? message?.payload instanceof Uint8Array
94
- ? 'Uint8Array'
95
- : message?.payload instanceof ArrayBuffer
96
- ? 'ArrayBuffer'
97
- : typeof message?.payload
128
+ message_type: message && typeof message === 'object'
129
+ ? message.constructor?.name ?? typeof message
98
130
  : typeof message,
99
- payload_constructor: message && typeof message === 'object'
100
- ? message?.payload?.constructor?.name
101
- : undefined,
102
- payload_keys: message && typeof message === 'object' && message?.payload && typeof message?.payload === 'object'
103
- ? Object.keys(message.payload).slice(0, 5)
104
- : undefined,
131
+ has_sender_id: Boolean(message?.senderId),
132
+ has_sender_node_id: Boolean(message?.senderNodeId),
105
133
  });
106
134
  if (!message || typeof message !== 'object') {
107
135
  return;
108
136
  }
109
137
  const busMessage = message;
110
- if (typeof busMessage.senderId !== 'string' || busMessage.senderId.length === 0) {
138
+ const senderId = typeof busMessage.senderId === 'string' && busMessage.senderId.length > 0
139
+ ? busMessage.senderId
140
+ : null;
141
+ const senderNodeId = InPageConnector.normalizeNodeId(busMessage.senderNodeId);
142
+ if (!senderId || !senderNodeId) {
143
+ logger.debug('inpage_message_rejected', {
144
+ channel: this.channelName,
145
+ connector_id: this.connectorId,
146
+ reason: 'missing_sender_metadata',
147
+ });
111
148
  return;
112
149
  }
113
- if (busMessage.senderId === this.connectorId) {
150
+ if (senderId === this.connectorId || senderNodeId === this.localNodeId) {
151
+ logger.debug('inpage_message_rejected', {
152
+ channel: this.channelName,
153
+ connector_id: this.connectorId,
154
+ reason: 'self_echo',
155
+ sender_node_id: senderNodeId,
156
+ });
157
+ return;
158
+ }
159
+ const incomingTargetNodeId = InPageConnector.normalizeTargetNodeId(busMessage.targetNodeId);
160
+ if (!this._shouldAcceptMessageFromBus(senderNodeId, incomingTargetNodeId)) {
114
161
  return;
115
162
  }
116
163
  const payload = InPageConnector.coercePayload(busMessage.payload);
@@ -124,7 +171,9 @@ export class InPageConnector extends BaseAsyncConnector {
124
171
  }
125
172
  logger.debug('inpage_message_received', {
126
173
  channel: this.channelName,
127
- sender_id: busMessage.senderId,
174
+ sender_id: senderId,
175
+ sender_node_id: senderNodeId,
176
+ target_node_id: incomingTargetNodeId ?? null,
128
177
  connector_id: this.connectorId,
129
178
  payload_length: payload.byteLength,
130
179
  });
@@ -132,15 +181,27 @@ export class InPageConnector extends BaseAsyncConnector {
132
181
  if (typeof this.inbox.tryEnqueue === 'function') {
133
182
  const accepted = this.inbox.tryEnqueue(payload);
134
183
  if (accepted) {
184
+ this.logInboxSnapshot('inpage_inbox_enqueued', {
185
+ source: 'listener',
186
+ enqueue_strategy: 'try',
187
+ payload_length: payload.byteLength,
188
+ });
135
189
  return;
136
190
  }
137
191
  }
138
192
  this.inbox.enqueue(payload);
193
+ this.logInboxSnapshot('inpage_inbox_enqueued', {
194
+ source: 'listener',
195
+ enqueue_strategy: 'enqueue',
196
+ payload_length: payload.byteLength,
197
+ });
139
198
  }
140
199
  catch (error) {
141
200
  if (error instanceof QueueFullError) {
142
201
  logger.warning('inpage_receive_queue_full', {
143
202
  channel: this.channelName,
203
+ inbox_capacity: this.inboxCapacity,
204
+ inbox_remaining_capacity: this.inbox.remainingCapacity,
144
205
  });
145
206
  }
146
207
  else {
@@ -247,15 +308,25 @@ export class InPageConnector extends BaseAsyncConnector {
247
308
  if (typeof this.inbox.tryEnqueue === 'function') {
248
309
  const accepted = this.inbox.tryEnqueue(item);
249
310
  if (accepted) {
311
+ this.logInboxSnapshot('inpage_push_enqueued', {
312
+ enqueue_strategy: 'try',
313
+ item_type: this._describeInboxItem(item),
314
+ });
250
315
  return;
251
316
  }
252
317
  }
253
318
  this.inbox.enqueue(item);
319
+ this.logInboxSnapshot('inpage_push_enqueued', {
320
+ enqueue_strategy: 'enqueue',
321
+ item_type: this._describeInboxItem(item),
322
+ });
254
323
  }
255
324
  catch (error) {
256
325
  if (error instanceof QueueFullError) {
257
326
  logger.warning('inpage_push_queue_full', {
258
327
  channel: this.channelName,
328
+ inbox_capacity: this.inboxCapacity,
329
+ inbox_remaining_capacity: this.inbox.remainingCapacity,
259
330
  });
260
331
  throw error;
261
332
  }
@@ -268,25 +339,52 @@ export class InPageConnector extends BaseAsyncConnector {
268
339
  }
269
340
  async _transportSendBytes(data) {
270
341
  ensureBrowserEnvironment();
342
+ const targetNodeId = this.targetNodeId ?? '*';
271
343
  logger.debug('inpage_message_sending', {
272
344
  channel: this.channelName,
273
345
  sender_id: this.connectorId,
346
+ sender_node_id: this.localNodeId,
347
+ target_node_id: targetNodeId,
274
348
  });
275
349
  const event = new MessageEvent(this.channelName, {
276
350
  data: {
277
351
  senderId: this.connectorId,
352
+ senderNodeId: this.localNodeId,
353
+ targetNodeId,
278
354
  payload: data,
279
355
  },
280
356
  });
281
357
  getSharedBus().dispatchEvent(event);
282
358
  }
283
359
  async _transportReceive() {
284
- return await this.inbox.dequeue();
360
+ const item = await this.inbox.dequeue();
361
+ this.logInboxSnapshot('inpage_inbox_dequeued', {
362
+ item_type: this._describeInboxItem(item),
363
+ });
364
+ return item;
285
365
  }
286
366
  async _transportClose(code, reason) {
367
+ logger.debug('inpage_transport_closing', {
368
+ channel: this.channelName,
369
+ connector_id: this.connectorId,
370
+ code,
371
+ reason,
372
+ listener_registered: this.listenerRegistered,
373
+ timestamp: new Date().toISOString(),
374
+ });
287
375
  if (this.listenerRegistered) {
376
+ logger.debug('inpage_removing_listener', {
377
+ channel: this.channelName,
378
+ connector_id: this.connectorId,
379
+ timestamp: new Date().toISOString(),
380
+ });
288
381
  getSharedBus().removeEventListener(this.channelName, this.onMsg);
289
382
  this.listenerRegistered = false;
383
+ logger.debug('inpage_listener_removed', {
384
+ channel: this.channelName,
385
+ connector_id: this.connectorId,
386
+ timestamp: new Date().toISOString(),
387
+ });
290
388
  }
291
389
  if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
292
390
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -304,4 +402,101 @@ export class InPageConnector extends BaseAsyncConnector {
304
402
  }
305
403
  return rawOrEnvelope;
306
404
  }
405
+ _isWildcardTarget() {
406
+ return this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined';
407
+ }
408
+ _shouldAcceptMessageFromBus(senderNodeId, targetNodeId) {
409
+ if (this._isWildcardTarget()) {
410
+ if (targetNodeId &&
411
+ targetNodeId !== '*' &&
412
+ targetNodeId !== this.localNodeId) {
413
+ logger.debug('inpage_message_rejected', {
414
+ channel: this.channelName,
415
+ connector_id: this.connectorId,
416
+ reason: 'wildcard_target_mismatch',
417
+ sender_node_id: senderNodeId,
418
+ target_node_id: targetNodeId,
419
+ local_node_id: this.localNodeId,
420
+ });
421
+ return false;
422
+ }
423
+ return true;
424
+ }
425
+ const expectedSender = this.targetNodeId;
426
+ if (expectedSender && expectedSender !== '*' && senderNodeId !== expectedSender) {
427
+ logger.debug('inpage_message_rejected', {
428
+ channel: this.channelName,
429
+ connector_id: this.connectorId,
430
+ reason: 'unexpected_sender',
431
+ expected_sender_node_id: expectedSender,
432
+ sender_node_id: senderNodeId,
433
+ local_node_id: this.localNodeId,
434
+ });
435
+ return false;
436
+ }
437
+ if (targetNodeId &&
438
+ targetNodeId !== '*' &&
439
+ targetNodeId !== this.localNodeId) {
440
+ logger.debug('inpage_message_rejected', {
441
+ channel: this.channelName,
442
+ connector_id: this.connectorId,
443
+ reason: 'unexpected_target',
444
+ sender_node_id: senderNodeId,
445
+ target_node_id: targetNodeId,
446
+ local_node_id: this.localNodeId,
447
+ });
448
+ return false;
449
+ }
450
+ return true;
451
+ }
452
+ _describeInboxItem(item) {
453
+ if (item instanceof Uint8Array) {
454
+ return 'bytes';
455
+ }
456
+ if (item.envelope) {
457
+ return 'channel_message';
458
+ }
459
+ if (item.frame) {
460
+ return 'envelope';
461
+ }
462
+ return 'unknown';
463
+ }
464
+ logInboxSnapshot(event, extra = {}) {
465
+ logger.debug(event, {
466
+ channel: this.channelName,
467
+ connector_id: this.connectorId,
468
+ connector_state: this.state,
469
+ inbox_capacity: this.inboxCapacity,
470
+ inbox_remaining_capacity: this.inbox.remainingCapacity,
471
+ ...extra,
472
+ });
473
+ }
474
+ setTargetNodeId(nodeId) {
475
+ const normalized = InPageConnector.normalizeNodeId(nodeId);
476
+ if (!normalized) {
477
+ throw new Error('InPageConnector target node id must be a non-empty string');
478
+ }
479
+ if (normalized === '*') {
480
+ this.setWildcardTarget();
481
+ return;
482
+ }
483
+ this.targetNodeId = normalized;
484
+ logger.debug('inpage_target_updated', {
485
+ channel: this.channelName,
486
+ connector_id: this.connectorId,
487
+ local_node_id: this.localNodeId,
488
+ target_node_id: this.targetNodeId,
489
+ target_mode: 'direct',
490
+ });
491
+ }
492
+ setWildcardTarget() {
493
+ this.targetNodeId = '*';
494
+ logger.debug('inpage_target_updated', {
495
+ channel: this.channelName,
496
+ connector_id: this.connectorId,
497
+ local_node_id: this.localNodeId,
498
+ target_node_id: this.targetNodeId,
499
+ target_mode: 'wildcard',
500
+ });
501
+ }
307
502
  }
@@ -278,7 +278,7 @@ export class InPageListener extends TransportListener {
278
278
  node: routingNode,
279
279
  });
280
280
  const selection = defaultGrantSelectionPolicy.selectCallbackGrant(selectionContext);
281
- connectorConfig = this._grantToConnectorConfig(selection.grant);
281
+ connectorConfig = this._buildConnectorConfigForSystem(systemId, this._grantToConnectorConfig(selection.grant));
282
282
  }
283
283
  catch (error) {
284
284
  logger.debug('inpage_listener_grant_selection_failed', {
@@ -286,13 +286,13 @@ export class InPageListener extends TransportListener {
286
286
  system_id: systemId,
287
287
  error: error instanceof Error ? error.message : String(error),
288
288
  });
289
- connectorConfig =
290
- this._extractInPageConnectorConfig(frame) ??
291
- {
292
- type: INPAGE_CONNECTOR_TYPE,
293
- channelName: this._channelName,
294
- inboxCapacity: this._inboxCapacity,
295
- };
289
+ const fallbackConfig = this._extractInPageConnectorConfig(frame) ??
290
+ {
291
+ type: INPAGE_CONNECTOR_TYPE,
292
+ channelName: this._channelName,
293
+ inboxCapacity: this._inboxCapacity,
294
+ };
295
+ connectorConfig = this._buildConnectorConfigForSystem(systemId, fallbackConfig);
296
296
  }
297
297
  try {
298
298
  const connector = await routingNode.createOriginConnector({
@@ -411,6 +411,65 @@ export class InPageListener extends TransportListener {
411
411
  typeof frame === 'object' &&
412
412
  frame.type === 'NodeAttach');
413
413
  }
414
+ _buildConnectorConfigForSystem(systemId, baseConfig) {
415
+ const localNodeId = this._requireLocalNodeId();
416
+ const targetSystemId = this._normalizeNodeId(systemId);
417
+ if (!targetSystemId) {
418
+ throw new Error('InPageListener requires a valid system id for connector creation');
419
+ }
420
+ const candidate = baseConfig ?? null;
421
+ const channelCandidate = candidate && 'channelName' in candidate
422
+ ? candidate.channelName
423
+ : undefined;
424
+ const inboxCandidate = candidate && 'inboxCapacity' in candidate
425
+ ? candidate.inboxCapacity
426
+ : undefined;
427
+ const targetCandidate = candidate && 'initialTargetNodeId' in candidate
428
+ ? candidate.initialTargetNodeId
429
+ : undefined;
430
+ const channelName = typeof channelCandidate === 'string' && channelCandidate.trim().length > 0
431
+ ? channelCandidate.trim()
432
+ : this._channelName;
433
+ const inboxCapacity = typeof inboxCandidate === 'number' &&
434
+ Number.isFinite(inboxCandidate) &&
435
+ inboxCandidate > 0
436
+ ? Math.floor(inboxCandidate)
437
+ : this._inboxCapacity;
438
+ const normalizedTarget = this._normalizeTargetNodeId(targetCandidate);
439
+ return {
440
+ type: INPAGE_CONNECTOR_TYPE,
441
+ channelName,
442
+ inboxCapacity,
443
+ localNodeId,
444
+ initialTargetNodeId: normalizedTarget ?? targetSystemId,
445
+ };
446
+ }
447
+ _requireLocalNodeId() {
448
+ if (!this._routingNode) {
449
+ throw new Error('InPageListener requires routing node context');
450
+ }
451
+ const normalized = this._normalizeNodeId(this._routingNode.id);
452
+ if (!normalized) {
453
+ throw new Error('InPageListener requires routing node with a stable identifier');
454
+ }
455
+ return normalized;
456
+ }
457
+ _normalizeNodeId(value) {
458
+ if (typeof value !== 'string') {
459
+ return null;
460
+ }
461
+ const trimmed = value.trim();
462
+ return trimmed.length > 0 ? trimmed : null;
463
+ }
464
+ _normalizeTargetNodeId(value) {
465
+ if (value === undefined || value === null) {
466
+ return undefined;
467
+ }
468
+ if (value === '*') {
469
+ return '*';
470
+ }
471
+ return this._normalizeNodeId(value) ?? undefined;
472
+ }
414
473
  }
415
474
  export function getInPageListenerInstance() {
416
475
  return _lastInPageListenerInstance;
@@ -25,4 +25,5 @@ export * from './metrics-emitter.js';
25
25
  export * from './util.js';
26
26
  export * from './logicals.js';
27
27
  export * from './ttl-validation.js';
28
+ export { safeImport } from './lazy-import.js';
28
29
  export { normalizeEnvelopeSnapshot } from './logging-types.js';
package/dist/esm/node.js CHANGED
@@ -15,7 +15,8 @@ export * from './naylence/fame/placement/node-placement-strategy-factory.js';
15
15
  export * from './naylence/fame/transport/transport-provisioner.js';
16
16
  export * from './naylence/fame/welcome/index.js';
17
17
  export * from './naylence/fame/sentinel/index.js';
18
- export { HttpStatelessConnector, QueueFullError, DefaultHttpServer, getWebsocketListenerInstance, TransportListener, TRANSPORT_LISTENER_FACTORY_BASE_TYPE, WebSocketListener, HttpListener, getHttpListenerInstance, InPageListener, getInPageListenerInstance, } from './naylence/fame/connector/index.js';
18
+ export { HttpStatelessConnector, QueueFullError, DefaultHttpServer, getWebsocketListenerInstance, TransportListener, TransportListenerFactory, TRANSPORT_LISTENER_FACTORY_BASE_TYPE, WebSocketListener, HttpListener, getHttpListenerInstance, InPageListener, getInPageListenerInstance, } from './naylence/fame/connector/index.js';
19
+ export { safeImport } from './naylence/fame/util/lazy-import.js';
19
20
  export { InProcessFameFabric, InProcessFameFabricFactory, FAME_FABRIC_FACTORY_BASE_TYPE, } from './naylence/fame/fabric/index.js';
20
21
  export { normalizeExtendedFameConfig, } from './naylence/fame/config/index.js';
21
22
  export { createJwksRouter, } from './naylence/fame/http/jwks-api-router.js';
@@ -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.966
2
+ // Generated from package.json version: 0.3.6-test.001
3
3
  /**
4
4
  * The package version, injected at build time.
5
5
  * @internal
6
6
  */
7
- export const VERSION = '0.3.5-test.966';
7
+ export const VERSION = '0.3.6-test.001';