@naylence/runtime 0.3.5-test.942 → 0.3.5-test.943

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 (31) hide show
  1. package/dist/browser/index.cjs +296 -6
  2. package/dist/browser/index.mjs +296 -6
  3. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
  4. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
  5. package/dist/cjs/naylence/fame/connector/inpage-connector-factory.js +12 -0
  6. package/dist/cjs/naylence/fame/connector/inpage-connector.js +66 -1
  7. package/dist/cjs/naylence/fame/connector/transport-frame.js +101 -0
  8. package/dist/cjs/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
  9. package/dist/cjs/naylence/fame/grants/inpage-connection-grant.js +28 -0
  10. package/dist/cjs/version.js +2 -2
  11. package/dist/esm/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
  12. package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
  13. package/dist/esm/naylence/fame/connector/inpage-connector-factory.js +12 -0
  14. package/dist/esm/naylence/fame/connector/inpage-connector.js +66 -1
  15. package/dist/esm/naylence/fame/connector/transport-frame.js +94 -0
  16. package/dist/esm/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
  17. package/dist/esm/naylence/fame/grants/inpage-connection-grant.js +28 -0
  18. package/dist/esm/version.js +2 -2
  19. package/dist/node/index.cjs +296 -6
  20. package/dist/node/index.mjs +296 -6
  21. package/dist/node/node.cjs +312 -6
  22. package/dist/node/node.mjs +312 -6
  23. package/dist/types/naylence/fame/connector/broadcast-channel-connector-factory.d.ts +2 -0
  24. package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +4 -0
  25. package/dist/types/naylence/fame/connector/inpage-connector-factory.d.ts +2 -0
  26. package/dist/types/naylence/fame/connector/inpage-connector.d.ts +4 -0
  27. package/dist/types/naylence/fame/connector/transport-frame.d.ts +58 -0
  28. package/dist/types/naylence/fame/grants/broadcast-channel-connection-grant.d.ts +6 -0
  29. package/dist/types/naylence/fame/grants/inpage-connection-grant.d.ts +8 -0
  30. package/dist/types/version.d.ts +1 -1
  31. package/package.json +1 -1
@@ -13,12 +13,12 @@ import fastify from 'fastify';
13
13
  import websocketPlugin from '@fastify/websocket';
14
14
 
15
15
  // This file is auto-generated during build - do not edit manually
16
- // Generated from package.json version: 0.3.5-test.942
16
+ // Generated from package.json version: 0.3.5-test.943
17
17
  /**
18
18
  * The package version, injected at build time.
19
19
  * @internal
20
20
  */
21
- const VERSION = '0.3.5-test.942';
21
+ const VERSION = '0.3.5-test.943';
22
22
 
23
23
  /**
24
24
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9733,6 +9733,85 @@ class BoundedAsyncQueue {
9733
9733
  }
9734
9734
  }
9735
9735
 
9736
+ /**
9737
+ * Transport frame layer for multiplexing logical links on physical channels.
9738
+ *
9739
+ * This lightweight framing layer wraps raw FAME payloads to enable multiple
9740
+ * logical connections over a single physical channel (BroadcastChannel or InPage bus).
9741
+ *
9742
+ * The transport frame does NOT modify FAME envelopes - it only wraps the raw
9743
+ * Uint8Array payload at the connector level.
9744
+ */
9745
+ /**
9746
+ * Transport frame version for future compatibility
9747
+ */
9748
+ const TRANSPORT_FRAME_VERSION = 1;
9749
+ /**
9750
+ * Wrap a raw payload in a transport frame
9751
+ *
9752
+ * @param payload - Raw FAME envelope bytes
9753
+ * @param srcNodeId - Local node ID (this connector)
9754
+ * @param dstNodeId - Remote node ID (target connector)
9755
+ * @returns Transport frame ready for transmission
9756
+ */
9757
+ function wrapTransportFrame(payload, srcNodeId, dstNodeId) {
9758
+ return {
9759
+ v: TRANSPORT_FRAME_VERSION,
9760
+ src: srcNodeId,
9761
+ dst: dstNodeId,
9762
+ payload,
9763
+ };
9764
+ }
9765
+ /**
9766
+ * Serialize a transport frame for transmission over the bus
9767
+ *
9768
+ * @param frame - Transport frame to serialize
9769
+ * @returns Serialized frame data ready for postMessage/dispatchEvent
9770
+ */
9771
+ function serializeTransportFrame(frame) {
9772
+ // Convert Uint8Array to regular array for JSON serialization
9773
+ const serializable = {
9774
+ v: frame.v,
9775
+ src: frame.src,
9776
+ dst: frame.dst,
9777
+ payload: Array.from(frame.payload),
9778
+ };
9779
+ return serializable;
9780
+ }
9781
+ /**
9782
+ * Unwrap a transport frame, validating source and destination
9783
+ *
9784
+ * @param raw - Raw data from the bus
9785
+ * @param localNodeId - This connector's node ID
9786
+ * @param remoteNodeId - Expected remote node ID
9787
+ * @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
9788
+ */
9789
+ function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
9790
+ // Validate basic structure
9791
+ if (!raw || typeof raw !== 'object') {
9792
+ return null;
9793
+ }
9794
+ const frame = raw;
9795
+ // Check version
9796
+ if (frame.v !== TRANSPORT_FRAME_VERSION) {
9797
+ return null;
9798
+ }
9799
+ // Check src and dst
9800
+ if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
9801
+ return null;
9802
+ }
9803
+ // Only accept frames addressed to us from the expected remote
9804
+ if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
9805
+ return null;
9806
+ }
9807
+ // Extract payload
9808
+ if (!frame.payload || !Array.isArray(frame.payload)) {
9809
+ return null;
9810
+ }
9811
+ // Convert array back to Uint8Array
9812
+ return Uint8Array.from(frame.payload);
9813
+ }
9814
+
9736
9815
  const logger$_ = getLogger('naylence.fame.connector.broadcast_channel_connector');
9737
9816
  const BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
9738
9817
  const DEFAULT_CHANNEL$7 = 'naylence-fabric';
@@ -9798,9 +9877,20 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9798
9877
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9799
9878
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9800
9879
  this.channel = new BroadcastChannel(this.channelName);
9880
+ // Set local and remote node IDs (defaults to connector ID for backwards compatibility)
9881
+ this.localNodeId =
9882
+ typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
9883
+ ? config.localNodeId.trim()
9884
+ : this.connectorId;
9885
+ this.remoteNodeId =
9886
+ typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
9887
+ ? config.remoteNodeId.trim()
9888
+ : '*'; // Accept from any remote if not specified
9801
9889
  logger$_.debug('broadcast_channel_connector_created', {
9802
9890
  channel: this.channelName,
9803
9891
  connector_id: this.connectorId,
9892
+ local_node_id: this.localNodeId,
9893
+ remote_node_id: this.remoteNodeId,
9804
9894
  inbox_capacity: preferredCapacity,
9805
9895
  timestamp: new Date().toISOString(),
9806
9896
  });
@@ -9833,6 +9923,46 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9833
9923
  if (busMessage.senderId === this.connectorId) {
9834
9924
  return;
9835
9925
  }
9926
+ // Try to unwrap as transport frame
9927
+ const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
9928
+ if (unwrapped) {
9929
+ // Successfully unwrapped transport frame
9930
+ logger$_.debug('broadcast_channel_transport_frame_received', {
9931
+ channel: this.channelName,
9932
+ sender_id: busMessage.senderId,
9933
+ connector_id: this.connectorId,
9934
+ local_node_id: this.localNodeId,
9935
+ remote_node_id: this.remoteNodeId,
9936
+ payload_length: unwrapped.byteLength,
9937
+ });
9938
+ if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
9939
+ return;
9940
+ }
9941
+ try {
9942
+ if (typeof this.inbox.tryEnqueue === 'function') {
9943
+ const accepted = this.inbox.tryEnqueue(unwrapped);
9944
+ if (accepted) {
9945
+ return;
9946
+ }
9947
+ }
9948
+ this.inbox.enqueue(unwrapped);
9949
+ }
9950
+ catch (error) {
9951
+ if (error instanceof QueueFullError) {
9952
+ logger$_.warning('broadcast_channel_receive_queue_full', {
9953
+ channel: this.channelName,
9954
+ });
9955
+ }
9956
+ else {
9957
+ logger$_.error('broadcast_channel_receive_error', {
9958
+ channel: this.channelName,
9959
+ error: error instanceof Error ? error.message : String(error),
9960
+ });
9961
+ }
9962
+ }
9963
+ return;
9964
+ }
9965
+ // Fall back to legacy format (no transport frame)
9836
9966
  const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
9837
9967
  if (!payload) {
9838
9968
  logger$_.debug('broadcast_channel_payload_rejected', {
@@ -9971,10 +10101,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9971
10101
  logger$_.debug('broadcast_channel_message_sending', {
9972
10102
  channel: this.channelName,
9973
10103
  sender_id: this.connectorId,
9974
- });
10104
+ local_node_id: this.localNodeId,
10105
+ remote_node_id: this.remoteNodeId,
10106
+ });
10107
+ // Only use transport framing if both localNodeId and remoteNodeId are explicitly set
10108
+ // (not using default values). This ensures backwards compatibility.
10109
+ const useTransportFrame = this.localNodeId !== this.connectorId ||
10110
+ this.remoteNodeId !== '*';
10111
+ let payload;
10112
+ if (useTransportFrame) {
10113
+ // Wrap payload in transport frame
10114
+ const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
10115
+ payload = serializeTransportFrame(frame);
10116
+ }
10117
+ else {
10118
+ // Legacy format: send raw payload
10119
+ payload = data;
10120
+ }
9975
10121
  this.channel.postMessage({
9976
10122
  senderId: this.connectorId,
9977
- payload: data,
10123
+ payload,
9978
10124
  });
9979
10125
  }
9980
10126
  async _transportReceive() {
@@ -10267,6 +10413,14 @@ function isBroadcastChannelConnectionGrant(candidate) {
10267
10413
  record.inboxCapacity <= 0)) {
10268
10414
  return false;
10269
10415
  }
10416
+ if (record.localNodeId !== undefined &&
10417
+ (typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
10418
+ return false;
10419
+ }
10420
+ if (record.remoteNodeId !== undefined &&
10421
+ (typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
10422
+ return false;
10423
+ }
10270
10424
  return true;
10271
10425
  }
10272
10426
  function normalizeBroadcastChannelConnectionGrant(candidate) {
@@ -10300,6 +10454,20 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
10300
10454
  }
10301
10455
  result.inboxCapacity = Math.floor(inboxValue);
10302
10456
  }
10457
+ const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
10458
+ if (localNodeIdValue !== undefined) {
10459
+ if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
10460
+ throw new TypeError('BroadcastChannelConnectionGrant "localNodeId" must be a non-empty string when provided');
10461
+ }
10462
+ result.localNodeId = localNodeIdValue.trim();
10463
+ }
10464
+ const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
10465
+ if (remoteNodeIdValue !== undefined) {
10466
+ if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
10467
+ throw new TypeError('BroadcastChannelConnectionGrant "remoteNodeId" must be a non-empty string when provided');
10468
+ }
10469
+ result.remoteNodeId = remoteNodeIdValue.trim();
10470
+ }
10303
10471
  return result;
10304
10472
  }
10305
10473
  function broadcastChannelGrantToConnectorConfig(grant) {
@@ -10313,6 +10481,12 @@ function broadcastChannelGrantToConnectorConfig(grant) {
10313
10481
  if (normalized.inboxCapacity !== undefined) {
10314
10482
  config.inboxCapacity = normalized.inboxCapacity;
10315
10483
  }
10484
+ if (normalized.localNodeId) {
10485
+ config.localNodeId = normalized.localNodeId;
10486
+ }
10487
+ if (normalized.remoteNodeId) {
10488
+ config.remoteNodeId = normalized.remoteNodeId;
10489
+ }
10316
10490
  return config;
10317
10491
  }
10318
10492
 
@@ -20259,9 +20433,20 @@ class InPageConnector extends BaseAsyncConnector {
20259
20433
  : DEFAULT_INBOX_CAPACITY$6;
20260
20434
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
20261
20435
  this.connectorId = InPageConnector.generateConnectorId();
20436
+ // Set local and remote node IDs (defaults to connector ID for backwards compatibility)
20437
+ this.localNodeId =
20438
+ typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
20439
+ ? config.localNodeId.trim()
20440
+ : this.connectorId;
20441
+ this.remoteNodeId =
20442
+ typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
20443
+ ? config.remoteNodeId.trim()
20444
+ : '*'; // Accept from any remote if not specified
20262
20445
  logger$G.debug('inpage_connector_initialized', {
20263
20446
  channel: this.channelName,
20264
20447
  connector_id: this.connectorId,
20448
+ local_node_id: this.localNodeId,
20449
+ remote_node_id: this.remoteNodeId,
20265
20450
  });
20266
20451
  this.onMsg = (event) => {
20267
20452
  const messageEvent = event;
@@ -20295,6 +20480,43 @@ class InPageConnector extends BaseAsyncConnector {
20295
20480
  if (busMessage.senderId === this.connectorId) {
20296
20481
  return;
20297
20482
  }
20483
+ // Try to unwrap as transport frame
20484
+ const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
20485
+ if (unwrapped) {
20486
+ // Successfully unwrapped transport frame
20487
+ logger$G.debug('inpage_transport_frame_received', {
20488
+ channel: this.channelName,
20489
+ sender_id: busMessage.senderId,
20490
+ connector_id: this.connectorId,
20491
+ local_node_id: this.localNodeId,
20492
+ remote_node_id: this.remoteNodeId,
20493
+ payload_length: unwrapped.byteLength,
20494
+ });
20495
+ try {
20496
+ if (typeof this.inbox.tryEnqueue === 'function') {
20497
+ const accepted = this.inbox.tryEnqueue(unwrapped);
20498
+ if (accepted) {
20499
+ return;
20500
+ }
20501
+ }
20502
+ this.inbox.enqueue(unwrapped);
20503
+ }
20504
+ catch (error) {
20505
+ if (error instanceof QueueFullError) {
20506
+ logger$G.warning('inpage_receive_queue_full', {
20507
+ channel: this.channelName,
20508
+ });
20509
+ }
20510
+ else {
20511
+ logger$G.error('inpage_receive_error', {
20512
+ channel: this.channelName,
20513
+ error: error instanceof Error ? error.message : String(error),
20514
+ });
20515
+ }
20516
+ }
20517
+ return;
20518
+ }
20519
+ // Fall back to legacy format (no transport frame)
20298
20520
  const payload = InPageConnector.coercePayload(busMessage.payload);
20299
20521
  if (!payload) {
20300
20522
  logger$G.debug('inpage_payload_rejected', {
@@ -20453,11 +20675,27 @@ class InPageConnector extends BaseAsyncConnector {
20453
20675
  logger$G.debug('inpage_message_sending', {
20454
20676
  channel: this.channelName,
20455
20677
  sender_id: this.connectorId,
20456
- });
20678
+ local_node_id: this.localNodeId,
20679
+ remote_node_id: this.remoteNodeId,
20680
+ });
20681
+ // Only use transport framing if both localNodeId and remoteNodeId are explicitly set
20682
+ // (not using default values). This ensures backwards compatibility.
20683
+ const useTransportFrame = this.localNodeId !== this.connectorId ||
20684
+ this.remoteNodeId !== '*';
20685
+ let payload;
20686
+ if (useTransportFrame) {
20687
+ // Wrap payload in transport frame
20688
+ const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
20689
+ payload = serializeTransportFrame(frame);
20690
+ }
20691
+ else {
20692
+ // Legacy format: send raw payload
20693
+ payload = data;
20694
+ }
20457
20695
  const event = new MessageEvent(this.channelName, {
20458
20696
  data: {
20459
20697
  senderId: this.connectorId,
20460
- payload: data,
20698
+ payload,
20461
20699
  },
20462
20700
  });
20463
20701
  getSharedBus$1().dispatchEvent(event);
@@ -27822,6 +28060,14 @@ function isInPageConnectionGrant(candidate) {
27822
28060
  record.inboxCapacity <= 0)) {
27823
28061
  return false;
27824
28062
  }
28063
+ if (record.localNodeId !== undefined &&
28064
+ (typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
28065
+ return false;
28066
+ }
28067
+ if (record.remoteNodeId !== undefined &&
28068
+ (typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
28069
+ return false;
28070
+ }
27825
28071
  return true;
27826
28072
  }
27827
28073
  function normalizeInPageConnectionGrant(candidate) {
@@ -27855,6 +28101,20 @@ function normalizeInPageConnectionGrant(candidate) {
27855
28101
  }
27856
28102
  result.inboxCapacity = Math.floor(inboxValue);
27857
28103
  }
28104
+ const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
28105
+ if (localNodeIdValue !== undefined) {
28106
+ if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
28107
+ throw new TypeError('InPageConnectionGrant "localNodeId" must be a non-empty string when provided');
28108
+ }
28109
+ result.localNodeId = localNodeIdValue.trim();
28110
+ }
28111
+ const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
28112
+ if (remoteNodeIdValue !== undefined) {
28113
+ if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
28114
+ throw new TypeError('InPageConnectionGrant "remoteNodeId" must be a non-empty string when provided');
28115
+ }
28116
+ result.remoteNodeId = remoteNodeIdValue.trim();
28117
+ }
27858
28118
  return result;
27859
28119
  }
27860
28120
  function inPageGrantToConnectorConfig(grant) {
@@ -27868,6 +28128,12 @@ function inPageGrantToConnectorConfig(grant) {
27868
28128
  if (normalized.inboxCapacity !== undefined) {
27869
28129
  config.inboxCapacity = normalized.inboxCapacity;
27870
28130
  }
28131
+ if (normalized.localNodeId) {
28132
+ config.localNodeId = normalized.localNodeId;
28133
+ }
28134
+ if (normalized.remoteNodeId) {
28135
+ config.remoteNodeId = normalized.remoteNodeId;
28136
+ }
27871
28137
  return config;
27872
28138
  }
27873
28139
 
@@ -28494,6 +28760,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28494
28760
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
28495
28761
  channelName,
28496
28762
  inboxCapacity,
28763
+ localNodeId: normalized.localNodeId,
28764
+ remoteNodeId: normalized.remoteNodeId,
28497
28765
  };
28498
28766
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
28499
28767
  if (options.authorization) {
@@ -28555,6 +28823,16 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28555
28823
  if (candidate.authorizationContext !== undefined) {
28556
28824
  normalized.authorizationContext = candidate.authorizationContext;
28557
28825
  }
28826
+ // Handle localNodeId
28827
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
28828
+ if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
28829
+ normalized.localNodeId = localNodeId.trim();
28830
+ }
28831
+ // Handle remoteNodeId
28832
+ const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
28833
+ if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
28834
+ normalized.remoteNodeId = remoteNodeId.trim();
28835
+ }
28558
28836
  normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$5;
28559
28837
  normalized.inboxCapacity =
28560
28838
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
@@ -29118,6 +29396,8 @@ class InPageConnectorFactory extends ConnectorFactory {
29118
29396
  type: INPAGE_CONNECTOR_TYPE,
29119
29397
  channelName,
29120
29398
  inboxCapacity,
29399
+ localNodeId: normalized.localNodeId,
29400
+ remoteNodeId: normalized.remoteNodeId,
29121
29401
  };
29122
29402
  const connector = new InPageConnector(connectorConfig, baseConfig);
29123
29403
  if (options.authorization) {
@@ -29186,6 +29466,16 @@ class InPageConnectorFactory extends ConnectorFactory {
29186
29466
  if (candidate.authorizationContext !== undefined) {
29187
29467
  normalized.authorizationContext = candidate.authorizationContext;
29188
29468
  }
29469
+ // Handle localNodeId
29470
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
29471
+ if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
29472
+ normalized.localNodeId = localNodeId.trim();
29473
+ }
29474
+ // Handle remoteNodeId
29475
+ const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
29476
+ if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
29477
+ normalized.remoteNodeId = remoteNodeId.trim();
29478
+ }
29189
29479
  normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$3;
29190
29480
  normalized.inboxCapacity =
29191
29481
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$3;