dignity.js 0.7.1 → 0.8.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.
@@ -3429,7 +3429,7 @@ var require_peer_group = __commonJS({
3429
3429
  var DEFAULT_PEER_GROUP_OPTIONS2 = {
3430
3430
  fanout: 3,
3431
3431
  maxActivePeers: 8,
3432
- maxHops: 6,
3432
+ maxHops: 64,
3433
3433
  relayEnabled: true
3434
3434
  };
3435
3435
  function peerGroupScope2(groupId) {
@@ -3481,6 +3481,327 @@ var require_peer_group = __commonJS({
3481
3481
  }
3482
3482
  });
3483
3483
 
3484
+ // src/cqrs/domain-events.js
3485
+ var require_domain_events = __commonJS({
3486
+ "src/cqrs/domain-events.js"(exports2, module2) {
3487
+ var nacl = require_nacl_fast();
3488
+ var naclUtil = require_nacl_util();
3489
+ var { stableStringify } = require_message_security_service();
3490
+ var DOMAIN_EVENT_SCHEMA_VERSION2 = 1;
3491
+ var OPERATION_KIND_TO_EVENT_KIND = {
3492
+ create: "record:created",
3493
+ update: "record:updated",
3494
+ delete: "record:removed",
3495
+ "transfer-ownership": "ownership:transferred"
3496
+ };
3497
+ function computeContentHash(data) {
3498
+ const canonical = stableStringify(data || {});
3499
+ const bytes = naclUtil.decodeUTF8(canonical);
3500
+ const hash = nacl.hash(bytes);
3501
+ const hex = Array.from(hash, (b) => b.toString(16).padStart(2, "0")).join("");
3502
+ return `sha512:${hex}`;
3503
+ }
3504
+ function canonicalEventBody(event) {
3505
+ return stableStringify({
3506
+ schemaVersion: event.schemaVersion,
3507
+ eventId: event.eventId,
3508
+ groupId: event.groupId,
3509
+ publisherId: event.publisherId,
3510
+ kind: event.kind,
3511
+ collectionName: event.collectionName,
3512
+ id: event.id,
3513
+ payload: event.payload,
3514
+ timestamp: event.timestamp,
3515
+ baseVersion: event.baseVersion,
3516
+ prevHash: event.prevHash || null,
3517
+ newOwnerId: event.newOwnerId || null
3518
+ });
3519
+ }
3520
+ function computeEventHash(event) {
3521
+ const canonical = canonicalEventBody(event);
3522
+ const bytes = naclUtil.decodeUTF8(canonical);
3523
+ const hash = nacl.hash(bytes);
3524
+ const hex = Array.from(hash, (b) => b.toString(16).padStart(2, "0")).join("");
3525
+ return `sha512:${hex}`;
3526
+ }
3527
+ function operationToDomainEvent2(operation, { publisherId, groupId, prevHash, eventIdGenerator }) {
3528
+ if (!operation || !publisherId || !groupId) {
3529
+ throw new Error("operationToDomainEvent requires operation, publisherId, and groupId");
3530
+ }
3531
+ const kind = OPERATION_KIND_TO_EVENT_KIND[operation.kind];
3532
+ if (!kind) {
3533
+ throw new Error(`Unsupported operation kind for domain event: ${operation.kind}`);
3534
+ }
3535
+ const event = {
3536
+ schemaVersion: DOMAIN_EVENT_SCHEMA_VERSION2,
3537
+ eventId: eventIdGenerator ? eventIdGenerator() : `${Date.now()}-${Math.random().toString(16).slice(2)}`,
3538
+ groupId,
3539
+ publisherId,
3540
+ kind,
3541
+ collectionName: operation.collectionName,
3542
+ id: operation.id,
3543
+ payload: operation.payload || {},
3544
+ timestamp: operation.timestamp,
3545
+ baseVersion: operation.baseVersion || null,
3546
+ prevHash: prevHash || null,
3547
+ newOwnerId: operation.newOwnerId || null,
3548
+ eventHash: null,
3549
+ signature: null
3550
+ };
3551
+ event.eventHash = computeEventHash(event);
3552
+ return event;
3553
+ }
3554
+ function signDomainEvent2(event, signingSecretKey) {
3555
+ if (!signingSecretKey) {
3556
+ return { ...event };
3557
+ }
3558
+ const unsigned = { ...event, signature: null };
3559
+ const eventHash = computeEventHash(unsigned);
3560
+ const signature = nacl.sign.detached(
3561
+ naclUtil.decodeUTF8(eventHash),
3562
+ signingSecretKey
3563
+ );
3564
+ return {
3565
+ ...unsigned,
3566
+ eventHash,
3567
+ signature: naclUtil.encodeBase64(signature)
3568
+ };
3569
+ }
3570
+ function verifyDomainEventSignature(event, signingPublicKey) {
3571
+ if (!event || !event.eventHash) {
3572
+ return { ok: false, reason: "missing-event-hash" };
3573
+ }
3574
+ const recomputed = computeEventHash({ ...event, signature: null });
3575
+ if (recomputed !== event.eventHash) {
3576
+ return { ok: false, reason: "event-hash-mismatch" };
3577
+ }
3578
+ if (!event.signature) {
3579
+ return { ok: true, unsigned: true };
3580
+ }
3581
+ if (!signingPublicKey) {
3582
+ return { ok: false, reason: "missing-public-key" };
3583
+ }
3584
+ const keyBytes = typeof signingPublicKey === "string" ? naclUtil.decodeBase64(signingPublicKey) : signingPublicKey;
3585
+ const valid = nacl.sign.detached.verify(
3586
+ naclUtil.decodeUTF8(event.eventHash),
3587
+ naclUtil.decodeBase64(event.signature),
3588
+ keyBytes
3589
+ );
3590
+ return valid ? { ok: true } : { ok: false, reason: "invalid-signature" };
3591
+ }
3592
+ function verifyDomainEvent2(event, { signingPublicKey, supportedVersions } = {}) {
3593
+ if (!event || typeof event !== "object") {
3594
+ return { ok: false, reason: "invalid-event" };
3595
+ }
3596
+ const versions = supportedVersions || [DOMAIN_EVENT_SCHEMA_VERSION2];
3597
+ if (!versions.includes(event.schemaVersion)) {
3598
+ return { ok: false, reason: "unsupported-schema-version", schemaVersion: event.schemaVersion };
3599
+ }
3600
+ if (!event.eventId || !event.groupId || !event.publisherId || !event.kind) {
3601
+ return { ok: false, reason: "missing-required-fields" };
3602
+ }
3603
+ return verifyDomainEventSignature(event, signingPublicKey);
3604
+ }
3605
+ function createEmptyView2(collections = []) {
3606
+ const view = /* @__PURE__ */ new Map();
3607
+ for (const name of collections) {
3608
+ view.set(name, /* @__PURE__ */ new Map());
3609
+ }
3610
+ return view;
3611
+ }
3612
+ function ensureCollectionView(view, collectionName) {
3613
+ if (!view.has(collectionName)) {
3614
+ view.set(collectionName, /* @__PURE__ */ new Map());
3615
+ }
3616
+ return view.get(collectionName);
3617
+ }
3618
+ function applyDomainEventToView2(view, event, { collectionsFilter } = {}) {
3619
+ if (!event || !event.collectionName) {
3620
+ return { applied: false, reason: "invalid-event" };
3621
+ }
3622
+ if (Array.isArray(collectionsFilter) && collectionsFilter.length > 0 && !collectionsFilter.includes(event.collectionName)) {
3623
+ return { applied: false, reason: "collection-filtered" };
3624
+ }
3625
+ const collection = ensureCollectionView(view, event.collectionName);
3626
+ if (event.kind === "record:created") {
3627
+ if (collection.has(event.id)) {
3628
+ return { applied: false, reason: "already-exists" };
3629
+ }
3630
+ collection.set(event.id, {
3631
+ id: event.id,
3632
+ ownerId: event.publisherId,
3633
+ data: { ...event.payload || {} },
3634
+ hash: computeContentHash(event.payload || {}),
3635
+ createdAt: event.timestamp,
3636
+ updatedAt: event.timestamp,
3637
+ deletedAt: null,
3638
+ version: 1
3639
+ });
3640
+ return { applied: true, kind: event.kind };
3641
+ }
3642
+ const current = collection.get(event.id);
3643
+ if (!current || current.deletedAt) {
3644
+ if (event.kind === "record:removed") {
3645
+ return { applied: false, reason: "not-found" };
3646
+ }
3647
+ return { applied: false, reason: "missing-record" };
3648
+ }
3649
+ if (event.kind === "record:updated") {
3650
+ if (typeof event.baseVersion === "number" && current.version !== event.baseVersion) {
3651
+ return { applied: false, reason: "version-conflict", currentVersion: current.version };
3652
+ }
3653
+ current.data = { ...current.data, ...event.payload || {} };
3654
+ current.hash = computeContentHash(current.data);
3655
+ current.updatedAt = event.timestamp;
3656
+ current.version += 1;
3657
+ return { applied: true, kind: event.kind };
3658
+ }
3659
+ if (event.kind === "record:removed") {
3660
+ if (typeof event.baseVersion === "number" && current.version !== event.baseVersion) {
3661
+ return { applied: false, reason: "version-conflict", currentVersion: current.version };
3662
+ }
3663
+ current.deletedAt = event.timestamp;
3664
+ current.version += 1;
3665
+ return { applied: true, kind: event.kind };
3666
+ }
3667
+ if (event.kind === "ownership:transferred") {
3668
+ if (typeof event.baseVersion === "number" && current.version !== event.baseVersion) {
3669
+ return { applied: false, reason: "version-conflict", currentVersion: current.version };
3670
+ }
3671
+ current.ownerId = event.newOwnerId;
3672
+ current.updatedAt = event.timestamp;
3673
+ current.version += 1;
3674
+ return { applied: true, kind: event.kind };
3675
+ }
3676
+ return { applied: false, reason: "unknown-kind" };
3677
+ }
3678
+ function verifyEventChain2(events, { genesisHash = null } = {}) {
3679
+ if (!Array.isArray(events) || events.length === 0) {
3680
+ return { ok: true, length: 0 };
3681
+ }
3682
+ let expectedPrev = genesisHash;
3683
+ for (let index = 0; index < events.length; index += 1) {
3684
+ const event = events[index];
3685
+ const prevHash = event.prevHash || null;
3686
+ if (prevHash !== expectedPrev) {
3687
+ return {
3688
+ ok: false,
3689
+ reason: "chain-break",
3690
+ index,
3691
+ expectedPrev,
3692
+ actualPrev: prevHash
3693
+ };
3694
+ }
3695
+ const hashCheck = verifyDomainEventSignature(event, null);
3696
+ if (!hashCheck.ok) {
3697
+ return { ok: false, reason: hashCheck.reason, index };
3698
+ }
3699
+ expectedPrev = event.eventHash;
3700
+ }
3701
+ return { ok: true, length: events.length, lastHash: expectedPrev };
3702
+ }
3703
+ function buildCheckpoint2(groupId, events, { publisherId } = {}) {
3704
+ const chain = verifyEventChain2(events);
3705
+ return {
3706
+ schemaVersion: DOMAIN_EVENT_SCHEMA_VERSION2,
3707
+ groupId,
3708
+ publisherId: publisherId || null,
3709
+ lastEventHash: chain.lastHash || null,
3710
+ recordCount: events.length,
3711
+ timestamp: Date.now()
3712
+ };
3713
+ }
3714
+ module2.exports = {
3715
+ DOMAIN_EVENT_SCHEMA_VERSION: DOMAIN_EVENT_SCHEMA_VERSION2,
3716
+ OPERATION_KIND_TO_EVENT_KIND,
3717
+ computeEventHash,
3718
+ operationToDomainEvent: operationToDomainEvent2,
3719
+ signDomainEvent: signDomainEvent2,
3720
+ verifyDomainEvent: verifyDomainEvent2,
3721
+ verifyDomainEventSignature,
3722
+ createEmptyView: createEmptyView2,
3723
+ applyDomainEventToView: applyDomainEventToView2,
3724
+ verifyEventChain: verifyEventChain2,
3725
+ buildCheckpoint: buildCheckpoint2
3726
+ };
3727
+ }
3728
+ });
3729
+
3730
+ // src/cqrs/peer-group-tiers.js
3731
+ var require_peer_group_tiers = __commonJS({
3732
+ "src/cqrs/peer-group-tiers.js"(exports2, module2) {
3733
+ var DEFAULT_LIVE_CAP2 = 5e3;
3734
+ var DEFAULT_BULK_INTERVAL_MS2 = 3e4;
3735
+ function assignPeerGroupTier2({ joinIndex, liveCap = DEFAULT_LIVE_CAP2, requestedTier, role }) {
3736
+ if (role === "publisher") {
3737
+ return "live";
3738
+ }
3739
+ if (requestedTier === "live" || requestedTier === "bulk") {
3740
+ if (requestedTier === "live" && joinIndex >= liveCap) {
3741
+ return "bulk";
3742
+ }
3743
+ return requestedTier;
3744
+ }
3745
+ return joinIndex < liveCap ? "live" : "bulk";
3746
+ }
3747
+ function getPeerTier(peer) {
3748
+ return peer?.metadata?.peerGroupTier || peer?.peerGroupTier || null;
3749
+ }
3750
+ function filterPeersByTier2(peers, tier) {
3751
+ if (!tier) {
3752
+ return peers;
3753
+ }
3754
+ return peers.filter((peer) => getPeerTier(peer) === tier);
3755
+ }
3756
+ function countLivePeers(peers) {
3757
+ return peers.filter((peer) => getPeerTier(peer) === "live").length;
3758
+ }
3759
+ function countBulkPeers(peers) {
3760
+ return peers.filter((peer) => getPeerTier(peer) === "bulk").length;
3761
+ }
3762
+ module2.exports = {
3763
+ DEFAULT_LIVE_CAP: DEFAULT_LIVE_CAP2,
3764
+ DEFAULT_BULK_INTERVAL_MS: DEFAULT_BULK_INTERVAL_MS2,
3765
+ assignPeerGroupTier: assignPeerGroupTier2,
3766
+ getPeerTier,
3767
+ filterPeersByTier: filterPeersByTier2,
3768
+ countLivePeers,
3769
+ countBulkPeers
3770
+ };
3771
+ }
3772
+ });
3773
+
3774
+ // src/cqrs/bulk-relay.js
3775
+ var require_bulk_relay = __commonJS({
3776
+ "src/cqrs/bulk-relay.js"(exports2, module2) {
3777
+ var { getPeerTier } = require_peer_group_tiers();
3778
+ var DEFAULT_BULK_RELAY_COUNT2 = 3;
3779
+ function electBulkRelays2(peers, { count = DEFAULT_BULK_RELAY_COUNT2 } = {}) {
3780
+ const bulkPeers = peers.filter((peer) => getPeerTier(peer) === "bulk").map((peer) => peer.peerId || peer).filter(Boolean).sort();
3781
+ return bulkPeers.slice(0, Math.max(0, count));
3782
+ }
3783
+ function isBulkRelay(metadata) {
3784
+ return metadata?.bulkRelay === true;
3785
+ }
3786
+ function applyBulkRelayFlags(peers, relayPeerIds) {
3787
+ const relaySet = new Set(relayPeerIds);
3788
+ return peers.map((peer) => ({
3789
+ ...peer,
3790
+ metadata: {
3791
+ ...peer.metadata || {},
3792
+ bulkRelay: relaySet.has(peer.peerId)
3793
+ }
3794
+ }));
3795
+ }
3796
+ module2.exports = {
3797
+ DEFAULT_BULK_RELAY_COUNT: DEFAULT_BULK_RELAY_COUNT2,
3798
+ electBulkRelays: electBulkRelays2,
3799
+ isBulkRelay,
3800
+ applyBulkRelayFlags
3801
+ };
3802
+ }
3803
+ });
3804
+
3484
3805
  // src/core/dignity-p2p.js
3485
3806
  var require_dignity_p2p = __commonJS({
3486
3807
  "src/core/dignity-p2p.js"(exports2, module2) {
@@ -3501,8 +3822,24 @@ var require_dignity_p2p = __commonJS({
3501
3822
  var {
3502
3823
  DEFAULT_PEER_GROUP_OPTIONS: DEFAULT_PEER_GROUP_OPTIONS2,
3503
3824
  peerGroupScope: peerGroupScope2,
3825
+ parsePeerGroupScope: parsePeerGroupScope2,
3504
3826
  selectFanoutPeers: selectFanoutPeers2
3505
3827
  } = require_peer_group();
3828
+ var {
3829
+ operationToDomainEvent: operationToDomainEvent2,
3830
+ signDomainEvent: signDomainEvent2,
3831
+ verifyDomainEvent: verifyDomainEvent2,
3832
+ applyDomainEventToView: applyDomainEventToView2,
3833
+ createEmptyView: createEmptyView2,
3834
+ buildCheckpoint: buildCheckpoint2
3835
+ } = require_domain_events();
3836
+ var {
3837
+ DEFAULT_LIVE_CAP: DEFAULT_LIVE_CAP2,
3838
+ DEFAULT_BULK_INTERVAL_MS: DEFAULT_BULK_INTERVAL_MS2,
3839
+ assignPeerGroupTier: assignPeerGroupTier2,
3840
+ filterPeersByTier: filterPeersByTier2
3841
+ } = require_peer_group_tiers();
3842
+ var { electBulkRelays: electBulkRelays2 } = require_bulk_relay();
3506
3843
  function computeContentHash(data) {
3507
3844
  const canonical = stableStringify(data || {});
3508
3845
  const bytes = naclUtil.decodeUTF8(canonical);
@@ -3546,6 +3883,10 @@ var require_dignity_p2p = __commonJS({
3546
3883
  this.gossipPublishMinIntervalMs = security && typeof security.gossipPublishMinIntervalMs === "number" ? security.gossipPublishMinIntervalMs : 0;
3547
3884
  this.lastGossipPublishAt = /* @__PURE__ */ new Map();
3548
3885
  this.maxAppliedOperations = security && typeof security.maxAppliedOperations === "number" ? security.maxAppliedOperations : 5e4;
3886
+ this.domainEventLogs = /* @__PURE__ */ new Map();
3887
+ this.lastEventHashByGroup = /* @__PURE__ */ new Map();
3888
+ this.bulkRelayByGroup = /* @__PURE__ */ new Map();
3889
+ this.replicaViews = /* @__PURE__ */ new Map();
3549
3890
  this.state = /* @__PURE__ */ new Map();
3550
3891
  this.appliedOperations = /* @__PURE__ */ new Map();
3551
3892
  this.boundMessageHandler = this.handleIncomingMessage.bind(this);
@@ -3684,6 +4025,7 @@ var require_dignity_p2p = __commonJS({
3684
4025
  payload: { ...data || {} }
3685
4026
  };
3686
4027
  this.applyOperation(operation);
4028
+ await this.maybePublishDomainEvent(operation, options);
3687
4029
  await this.broadcastMessage("operation", operation, {
3688
4030
  broadcastScope: options.broadcastScope || this.resolveBroadcastScope({
3689
4031
  messageType: "operation",
@@ -3761,6 +4103,7 @@ var require_dignity_p2p = __commonJS({
3761
4103
  operation.collaboratorIds = this.normalizeCollaboratorIds(options.collaborators);
3762
4104
  }
3763
4105
  this.applyOperation(operation);
4106
+ await this.maybePublishDomainEvent(operation, options);
3764
4107
  await this.broadcastMessage("operation", operation, {
3765
4108
  broadcastScope: options.broadcastScope || this.resolveBroadcastScope({
3766
4109
  messageType: "operation",
@@ -3815,6 +4158,7 @@ var require_dignity_p2p = __commonJS({
3815
4158
  keepPreviousOwnerAsCollaborator: options.keepAsCollaborator !== false
3816
4159
  };
3817
4160
  this.applyOperation(operation);
4161
+ await this.maybePublishDomainEvent(operation, options);
3818
4162
  await this.broadcastMessage("operation", operation, {
3819
4163
  broadcastScope: options.broadcastScope || this.resolveBroadcastScope({
3820
4164
  messageType: "operation",
@@ -3846,6 +4190,7 @@ var require_dignity_p2p = __commonJS({
3846
4190
  baseVersion: existing.version
3847
4191
  };
3848
4192
  this.applyOperation(operation);
4193
+ await this.maybePublishDomainEvent(operation, options);
3849
4194
  await this.broadcastMessage("operation", operation, {
3850
4195
  broadcastScope: options.broadcastScope || this.resolveBroadcastScope({
3851
4196
  messageType: "operation",
@@ -4136,9 +4481,16 @@ var require_dignity_p2p = __commonJS({
4136
4481
  }
4137
4482
  return [];
4138
4483
  }
4139
- selectPeerGroupFanout(groupId, count, excludePeerIds = []) {
4484
+ selectPeerGroupFanout(groupId, count, excludePeerIds = [], fanoutOptions = {}) {
4140
4485
  const scope = this.peerGroupScopeFor(groupId);
4141
- const peers = this.listPeers(scope, { includeSelf: false });
4486
+ const group = this.peerGroups.get(groupId);
4487
+ let peers = this.listPeers(scope, { includeSelf: false });
4488
+ if (group && group.tiered && fanoutOptions.tier) {
4489
+ peers = filterPeersByTier2(peers, fanoutOptions.tier);
4490
+ }
4491
+ if (fanoutOptions.bulkRelayOnly) {
4492
+ peers = peers.filter((peer) => peer.metadata?.bulkRelay === true);
4493
+ }
4142
4494
  return selectFanoutPeers2({
4143
4495
  peers,
4144
4496
  count,
@@ -4170,15 +4522,45 @@ var require_dignity_p2p = __commonJS({
4170
4522
  throw new Error("joinPeerGroup requires groupId");
4171
4523
  }
4172
4524
  const scope = this.peerGroupScopeFor(groupId);
4525
+ const role = options.role || options.metadata?.role || "subscriber";
4526
+ const tierMode = options.tierMode || "auto";
4527
+ const tiered = options.tiered === true || options.tierMode !== void 0 || options.role !== void 0 || typeof options.liveCap === "number";
4528
+ const liveCap = typeof options.liveCap === "number" ? options.liveCap : DEFAULT_LIVE_CAP2;
4529
+ const existingMembers = this.listPeerGroupMembers(groupId, { includeSelf: false });
4530
+ const existingSubscriberCount = existingMembers.filter((member) => {
4531
+ const memberRole = member.metadata?.peerGroupRole || member.metadata?.role;
4532
+ return memberRole !== "publisher";
4533
+ }).length;
4534
+ let assignedTier = tiered ? assignPeerGroupTier2({
4535
+ joinIndex: existingSubscriberCount,
4536
+ liveCap,
4537
+ requestedTier: tierMode === "auto" ? null : tierMode,
4538
+ role
4539
+ }) : null;
4540
+ const publisherId = options.publisherId || (role === "publisher" ? this.nodeId : null);
4173
4541
  const config = {
4174
4542
  fanout: typeof options.fanout === "number" ? options.fanout : this.defaultPeerGroupFanout,
4175
4543
  maxActivePeers: typeof options.maxActivePeers === "number" ? options.maxActivePeers : this.defaultPeerGroupMaxActivePeers,
4176
4544
  maxHops: typeof options.maxHops === "number" ? options.maxHops : this.defaultGossipMaxHops,
4177
- relayEnabled: options.relayEnabled !== false
4545
+ relayEnabled: options.relayEnabled !== false,
4546
+ tiered,
4547
+ tierMode,
4548
+ liveCap,
4549
+ bulkIntervalMs: typeof options.bulkIntervalMs === "number" ? options.bulkIntervalMs : DEFAULT_BULK_INTERVAL_MS2,
4550
+ domainEvents: options.domainEvents !== false,
4551
+ autoPublishDomainEvents: options.autoPublishDomainEvents !== false,
4552
+ role,
4553
+ publisherId,
4554
+ commandCapable: options.commandCapable !== false,
4555
+ peerGroupTier: assignedTier
4178
4556
  };
4179
4557
  await this.joinDiscovery(scope, {
4180
4558
  metadata: {
4181
4559
  peerGroup: groupId,
4560
+ ...assignedTier ? { peerGroupTier: assignedTier } : {},
4561
+ peerGroupRole: role,
4562
+ ...publisherId ? { publisherId } : {},
4563
+ bulkRelay: false,
4182
4564
  ...options.metadata || {}
4183
4565
  },
4184
4566
  bootstrapPeerIds: options.bootstrapPeerIds,
@@ -4186,9 +4568,61 @@ var require_dignity_p2p = __commonJS({
4186
4568
  ttlMs: options.ttlMs
4187
4569
  });
4188
4570
  this.peerGroups.set(groupId, config);
4189
- this.emit("peergroupjoined", { groupId, config });
4571
+ if (!this.domainEventLogs.has(groupId)) {
4572
+ this.domainEventLogs.set(groupId, []);
4573
+ }
4574
+ if (!this.replicaViews.has(groupId)) {
4575
+ this.replicaViews.set(groupId, createEmptyView2());
4576
+ }
4577
+ this.refreshBulkRelays(groupId);
4578
+ if (tiered && tierMode === "auto" && role === "subscriber") {
4579
+ assignedTier = this.recalculateOwnPeerGroupTier(groupId) || assignedTier;
4580
+ config.peerGroupTier = assignedTier;
4581
+ }
4582
+ this.emit("peergroupjoined", { groupId, config, tier: assignedTier });
4190
4583
  return config;
4191
4584
  }
4585
+ recalculateOwnPeerGroupTier(groupId) {
4586
+ const group = this.peerGroups.get(groupId);
4587
+ if (!group || !group.tiered || group.role !== "subscriber") {
4588
+ return group ? group.peerGroupTier : null;
4589
+ }
4590
+ if (group.tierMode !== "auto") {
4591
+ return group.peerGroupTier;
4592
+ }
4593
+ const scope = this.peerGroupScopeFor(groupId);
4594
+ const members = this.listPeerGroupMembers(groupId, { includeSelf: true });
4595
+ const subscribers = members.filter((member) => {
4596
+ const memberRole = member.metadata?.peerGroupRole || member.metadata?.role;
4597
+ return memberRole !== "publisher";
4598
+ }).map((member) => member.peerId).sort();
4599
+ const joinIndex = subscribers.indexOf(this.nodeId);
4600
+ if (joinIndex < 0) {
4601
+ return group.peerGroupTier;
4602
+ }
4603
+ const newTier = assignPeerGroupTier2({
4604
+ joinIndex,
4605
+ liveCap: group.liveCap,
4606
+ requestedTier: null,
4607
+ role: "subscriber"
4608
+ });
4609
+ if (newTier === group.peerGroupTier) {
4610
+ return newTier;
4611
+ }
4612
+ group.peerGroupTier = newTier;
4613
+ const room = this.discoveryRooms.get(scope);
4614
+ if (room) {
4615
+ room.metadata = {
4616
+ ...room.metadata || {},
4617
+ peerGroupTier: newTier
4618
+ };
4619
+ this.upsertPresence(scope, this.nodeId, room.metadata, room.ttlMs, this.now());
4620
+ this.announcePresence(scope).catch((error) => {
4621
+ this.emit("warning", { type: "tier-announce-failed", groupId, error });
4622
+ });
4623
+ }
4624
+ return newTier;
4625
+ }
4192
4626
  async leavePeerGroup(groupId) {
4193
4627
  if (!groupId) {
4194
4628
  return;
@@ -4196,6 +4630,7 @@ var require_dignity_p2p = __commonJS({
4196
4630
  const scope = this.peerGroupScopeFor(groupId);
4197
4631
  await this.leaveDiscovery(scope);
4198
4632
  this.peerGroups.delete(groupId);
4633
+ this.bulkRelayByGroup.delete(groupId);
4199
4634
  this.emit("peergroupleft", { groupId });
4200
4635
  }
4201
4636
  async publishToPeerGroup(groupId, innerMessageType, innerPayload, options = {}) {
@@ -4218,7 +4653,11 @@ var require_dignity_p2p = __commonJS({
4218
4653
  const fanout = typeof options.fanout === "number" ? options.fanout : group ? group.fanout : this.defaultPeerGroupFanout;
4219
4654
  const maxActivePeers = group ? group.maxActivePeers : this.defaultPeerGroupMaxActivePeers;
4220
4655
  const maxHop = typeof options.maxHops === "number" ? options.maxHops : group ? group.maxHops : this.defaultGossipMaxHops;
4221
- const fanoutPeerIds = this.selectPeerGroupFanout(groupId, fanout, [this.nodeId]);
4656
+ const fanoutOptions = {};
4657
+ if (group && group.tiered && options.tier !== "bulk") {
4658
+ fanoutOptions.tier = options.tier || "live";
4659
+ }
4660
+ const fanoutPeerIds = this.selectPeerGroupFanout(groupId, fanout, [this.nodeId], fanoutOptions);
4222
4661
  if (fanoutPeerIds.length > 0) {
4223
4662
  await this.ensureConnectedToPeers(fanoutPeerIds.slice(0, maxActivePeers));
4224
4663
  await this.enforceConnectionBudget();
@@ -4240,6 +4679,204 @@ var require_dignity_p2p = __commonJS({
4240
4679
  });
4241
4680
  return { gossipId, fanoutPeerIds };
4242
4681
  }
4682
+ async publishPeerGroupBulk(groupId, innerMessageType, innerPayload, options = {}) {
4683
+ const group = this.peerGroups.get(groupId);
4684
+ if (!group && options.allowUnjoined !== true) {
4685
+ throw new Error(`PeerGroup ${groupId} has not been joined`);
4686
+ }
4687
+ if (group && group.role !== "publisher") {
4688
+ throw new Error(`Only publisher can bulk-publish to PeerGroup ${groupId}`);
4689
+ }
4690
+ const fanout = typeof options.fanout === "number" ? options.fanout : group ? group.fanout : this.defaultPeerGroupFanout;
4691
+ const maxActivePeers = group ? group.maxActivePeers : this.defaultPeerGroupMaxActivePeers;
4692
+ const maxHop = typeof options.maxHops === "number" ? options.maxHops : group ? group.maxHops : this.defaultGossipMaxHops;
4693
+ const fanoutPeerIds = this.selectPeerGroupFanout(
4694
+ groupId,
4695
+ fanout,
4696
+ [this.nodeId],
4697
+ { tier: "bulk", bulkRelayOnly: group?.tiered === true }
4698
+ );
4699
+ if (fanoutPeerIds.length > 0) {
4700
+ await this.ensureConnectedToPeers(fanoutPeerIds.slice(0, maxActivePeers));
4701
+ await this.enforceConnectionBudget();
4702
+ }
4703
+ const gossipId = options.gossipId || this.idGenerator();
4704
+ this.markSeenGossip(gossipId);
4705
+ await this.broadcastMessage("peer-group:gossip", {
4706
+ groupId,
4707
+ gossipId,
4708
+ publisherId: this.nodeId,
4709
+ hop: 0,
4710
+ maxHop,
4711
+ deliveryTier: "bulk",
4712
+ innerMessageType,
4713
+ innerPayload
4714
+ }, {
4715
+ broadcastScope: this.peerGroupScopeFor(groupId),
4716
+ fanoutPeerIds
4717
+ });
4718
+ return { gossipId, fanoutPeerIds };
4719
+ }
4720
+ async publishPeerGroupCheckpoint(groupId, options = {}) {
4721
+ const group = this.peerGroups.get(groupId);
4722
+ if (!group) {
4723
+ throw new Error(`PeerGroup ${groupId} has not been joined`);
4724
+ }
4725
+ const events = this.domainEventLogs.get(groupId) || [];
4726
+ const checkpoint = buildCheckpoint2(groupId, events, {
4727
+ publisherId: options.publisherId || group.publisherId || this.nodeId
4728
+ });
4729
+ await this.publishPeerGroupBulk(groupId, "domain:checkpoint", checkpoint, options);
4730
+ this.emit("checkpointpublished", { groupId, checkpoint });
4731
+ return checkpoint;
4732
+ }
4733
+ resolvePublisherGroupIds(options = {}) {
4734
+ if (options.peerGroupId) {
4735
+ return [options.peerGroupId];
4736
+ }
4737
+ const groups = [];
4738
+ for (const [groupId, config] of this.peerGroups.entries()) {
4739
+ if (config.domainEvents && config.autoPublishDomainEvents && config.role === "publisher") {
4740
+ groups.push(groupId);
4741
+ }
4742
+ }
4743
+ return groups;
4744
+ }
4745
+ async maybePublishDomainEvent(operation, options = {}) {
4746
+ const groupIds = this.resolvePublisherGroupIds(options);
4747
+ if (groupIds.length === 0) {
4748
+ return;
4749
+ }
4750
+ for (const groupId of groupIds) {
4751
+ await this.publishDomainEventForOperation(groupId, operation);
4752
+ }
4753
+ }
4754
+ async publishDomainEventForOperation(groupId, operation) {
4755
+ const group = this.peerGroups.get(groupId);
4756
+ if (!group || !group.domainEvents) {
4757
+ return null;
4758
+ }
4759
+ if (group.role !== "publisher") {
4760
+ throw new Error(`Only publisher can emit domain events for PeerGroup ${groupId}`);
4761
+ }
4762
+ const prevHash = this.lastEventHashByGroup.get(groupId) || null;
4763
+ let event = operationToDomainEvent2(operation, {
4764
+ publisherId: this.nodeId,
4765
+ groupId,
4766
+ prevHash,
4767
+ eventIdGenerator: () => this.idGenerator()
4768
+ });
4769
+ if (this.securityService.options.signingEnabled && this.securityService.signingSecretKey) {
4770
+ event = signDomainEvent2(event, this.securityService.signingSecretKey);
4771
+ }
4772
+ const log = this.domainEventLogs.get(groupId) || [];
4773
+ log.push(event);
4774
+ this.domainEventLogs.set(groupId, log);
4775
+ this.lastEventHashByGroup.set(groupId, event.eventHash);
4776
+ this.emit("domainevent", event);
4777
+ if (group.autoPublishDomainEvents) {
4778
+ await this.publishToPeerGroup(groupId, "domain:event", event, { tier: "live" });
4779
+ if (group.tiered) {
4780
+ await this.publishPeerGroupBulk(groupId, "domain:event", event);
4781
+ }
4782
+ }
4783
+ return event;
4784
+ }
4785
+ refreshBulkRelays(groupId) {
4786
+ const group = this.peerGroups.get(groupId);
4787
+ if (!group || !group.tiered) {
4788
+ return [];
4789
+ }
4790
+ const peers = this.listPeerGroupMembers(groupId, { includeSelf: false });
4791
+ const relays = electBulkRelays2(peers);
4792
+ const previous = this.bulkRelayByGroup.get(groupId) || [];
4793
+ this.bulkRelayByGroup.set(groupId, relays);
4794
+ const changed = previous.length !== relays.length || previous.some((id, index) => id !== relays[index]);
4795
+ if (changed) {
4796
+ this.emit("bulkrelaychanged", { groupId, relays, previous });
4797
+ }
4798
+ return relays;
4799
+ }
4800
+ ingestRemoteDomainEvent(event, context = {}) {
4801
+ const groupId = event.groupId || context.groupId;
4802
+ if (!groupId) {
4803
+ return false;
4804
+ }
4805
+ const group = this.peerGroups.get(groupId);
4806
+ if (!group) {
4807
+ return false;
4808
+ }
4809
+ const publisherId = event.publisherId || context.publisherId;
4810
+ if (group.publisherId && publisherId !== group.publisherId) {
4811
+ this.emit("warning", {
4812
+ type: "domain-event-rejected",
4813
+ groupId,
4814
+ reason: "publisher-mismatch",
4815
+ eventId: event.eventId,
4816
+ expectedPublisher: group.publisherId,
4817
+ actualPublisher: publisherId
4818
+ });
4819
+ return false;
4820
+ }
4821
+ let signingPublicKey = null;
4822
+ if (this.securityService.options.signingEnabled && publisherId) {
4823
+ const peerKey = this.securityService.resolvePeerPublicKey(publisherId, null);
4824
+ signingPublicKey = peerKey ? peerKey.signingPublicKey : null;
4825
+ if (!signingPublicKey) {
4826
+ this.emit("warning", {
4827
+ type: "domain-event-rejected",
4828
+ groupId,
4829
+ reason: "missing-publisher-key",
4830
+ eventId: event.eventId,
4831
+ publisherId
4832
+ });
4833
+ return false;
4834
+ }
4835
+ }
4836
+ const verified = verifyDomainEvent2(event, { signingPublicKey });
4837
+ if (!verified.ok) {
4838
+ this.emit("warning", {
4839
+ type: "domain-event-rejected",
4840
+ groupId,
4841
+ reason: verified.reason,
4842
+ eventId: event.eventId
4843
+ });
4844
+ return false;
4845
+ }
4846
+ if (this.securityService.options.signingEnabled && verified.unsigned) {
4847
+ this.emit("warning", {
4848
+ type: "domain-event-rejected",
4849
+ groupId,
4850
+ reason: "unsigned-event",
4851
+ eventId: event.eventId
4852
+ });
4853
+ return false;
4854
+ }
4855
+ const log = this.domainEventLogs.get(groupId) || [];
4856
+ if (log.some((entry) => entry.eventId === event.eventId)) {
4857
+ return false;
4858
+ }
4859
+ const expectedPrev = log.length > 0 ? log[log.length - 1].eventHash : null;
4860
+ if (event.prevHash !== expectedPrev) {
4861
+ this.emit("chainbroken", {
4862
+ groupId,
4863
+ expectedPrev,
4864
+ actualPrev: event.prevHash,
4865
+ eventId: event.eventId
4866
+ });
4867
+ return false;
4868
+ }
4869
+ log.push(event);
4870
+ this.domainEventLogs.set(groupId, log);
4871
+ this.lastEventHashByGroup.set(groupId, event.eventHash);
4872
+ if (!group.commandCapable) {
4873
+ const view = this.replicaViews.get(groupId) || createEmptyView2();
4874
+ applyDomainEventToView2(view, event);
4875
+ this.replicaViews.set(groupId, view);
4876
+ }
4877
+ this.emit("domainevent", event);
4878
+ return true;
4879
+ }
4243
4880
  async publishRecordToPeerGroup(groupId, collectionName, id, options = {}) {
4244
4881
  const collection = this.getCollection(collectionName);
4245
4882
  const raw = collection.get(id);
@@ -4279,15 +4916,26 @@ var require_dignity_p2p = __commonJS({
4279
4916
  publisherId
4280
4917
  });
4281
4918
  const group = this.peerGroups.get(groupId);
4919
+ const deliveryTier = payload.deliveryTier || "live";
4920
+ if (group && group.tiered && group.peerGroupTier === "bulk" && deliveryTier !== "bulk") {
4921
+ return;
4922
+ }
4282
4923
  const configuredMaxHop = group ? group.maxHops : this.defaultGossipMaxHops;
4283
4924
  const maxHop = typeof payloadMaxHop === "number" ? Math.min(payloadMaxHop, configuredMaxHop) : configuredMaxHop;
4284
4925
  if (!group || group.relayEnabled === false || hop >= maxHop) {
4285
4926
  return;
4286
4927
  }
4928
+ const relayOptions = {};
4929
+ if (group.tiered) {
4930
+ relayOptions.tier = deliveryTier === "bulk" ? "bulk" : "live";
4931
+ if (deliveryTier === "bulk") {
4932
+ relayOptions.bulkRelayOnly = true;
4933
+ }
4934
+ }
4287
4935
  const relayPeers = this.selectPeerGroupFanout(groupId, group.fanout, [
4288
4936
  decrypted.senderId,
4289
4937
  this.nodeId
4290
- ]);
4938
+ ], relayOptions);
4291
4939
  if (relayPeers.length === 0) {
4292
4940
  return;
4293
4941
  }
@@ -4299,6 +4947,7 @@ var require_dignity_p2p = __commonJS({
4299
4947
  publisherId,
4300
4948
  hop: hop + 1,
4301
4949
  maxHop,
4950
+ deliveryTier,
4302
4951
  innerMessageType,
4303
4952
  innerPayload
4304
4953
  }, {
@@ -4341,6 +4990,19 @@ var require_dignity_p2p = __commonJS({
4341
4990
  }
4342
4991
  return;
4343
4992
  }
4993
+ if (innerMessageType === "domain:event") {
4994
+ this.ingestRemoteDomainEvent(innerPayload, context);
4995
+ return;
4996
+ }
4997
+ if (innerMessageType === "domain:checkpoint") {
4998
+ this.emit("peergroupmessage", {
4999
+ groupId: context.groupId,
5000
+ senderId: context.senderId,
5001
+ type: "domain:checkpoint",
5002
+ payload: innerPayload
5003
+ });
5004
+ return;
5005
+ }
4344
5006
  if (innerMessageType === "record:snapshot") {
4345
5007
  const { collectionName, record } = innerPayload || {};
4346
5008
  if (collectionName && record) {
@@ -4386,6 +5048,13 @@ var require_dignity_p2p = __commonJS({
4386
5048
  };
4387
5049
  map.set(peerId, next);
4388
5050
  this.trustPeerFromMetadata(peerId, next.metadata);
5051
+ const groupId = parsePeerGroupScope2(scope);
5052
+ if (groupId && this.peerGroups.has(groupId)) {
5053
+ this.refreshBulkRelays(groupId);
5054
+ if (peerId !== this.nodeId) {
5055
+ this.recalculateOwnPeerGroupTier(groupId);
5056
+ }
5057
+ }
4389
5058
  if (!existing) {
4390
5059
  this.emit("peerdiscovered", { scope, peerId, metadata: next.metadata });
4391
5060
  }
@@ -12412,6 +13081,195 @@ var require_indexeddb_persistence = __commonJS({
12412
13081
  }
12413
13082
  });
12414
13083
 
13084
+ // src/cqrs/query-replica.js
13085
+ var require_query_replica = __commonJS({
13086
+ "src/cqrs/query-replica.js"(exports2, module2) {
13087
+ var EventEmitter = require_event_emitter();
13088
+ var {
13089
+ createEmptyView: createEmptyView2,
13090
+ applyDomainEventToView: applyDomainEventToView2,
13091
+ verifyEventChain: verifyEventChain2,
13092
+ verifyDomainEvent: verifyDomainEvent2,
13093
+ DOMAIN_EVENT_SCHEMA_VERSION: DOMAIN_EVENT_SCHEMA_VERSION2
13094
+ } = require_domain_events();
13095
+ var DignityQueryReplica2 = class extends EventEmitter {
13096
+ constructor(dignityP2P, { groupId, collections = [], tierMode = "auto", publisherId = null } = {}) {
13097
+ super();
13098
+ if (!dignityP2P) {
13099
+ throw new Error("DignityQueryReplica requires dignityP2P");
13100
+ }
13101
+ if (!groupId) {
13102
+ throw new Error("DignityQueryReplica requires groupId");
13103
+ }
13104
+ this.dignity = dignityP2P;
13105
+ this.groupId = groupId;
13106
+ this.collections = [...collections];
13107
+ this.tierMode = tierMode;
13108
+ this.publisherId = publisherId;
13109
+ this.view = createEmptyView2(this.collections);
13110
+ this.eventLog = [];
13111
+ this.started = false;
13112
+ this.boundDomainHandler = this.handleDomainEvent.bind(this);
13113
+ this.boundPeerGroupHandler = this.handlePeerGroupMessage.bind(this);
13114
+ }
13115
+ async start(options = {}) {
13116
+ if (this.started) {
13117
+ return this;
13118
+ }
13119
+ await this.dignity.joinPeerGroup(this.groupId, {
13120
+ tierMode: this.tierMode,
13121
+ role: "subscriber",
13122
+ commandCapable: false,
13123
+ domainEvents: true,
13124
+ publisherId: this.publisherId,
13125
+ liveCap: options.liveCap,
13126
+ bulkIntervalMs: options.bulkIntervalMs,
13127
+ bootstrapPeerIds: options.bootstrapPeerIds,
13128
+ metadata: { role: "subscriber", replica: true }
13129
+ });
13130
+ this.dignity.on("domainevent", this.boundDomainHandler);
13131
+ this.dignity.on("peergroupmessage", this.boundPeerGroupHandler);
13132
+ this.started = true;
13133
+ this.emit("started", { groupId: this.groupId });
13134
+ return this;
13135
+ }
13136
+ async stop() {
13137
+ if (!this.started) {
13138
+ return;
13139
+ }
13140
+ this.dignity.off("domainevent", this.boundDomainHandler);
13141
+ this.dignity.off("peergroupmessage", this.boundPeerGroupHandler);
13142
+ await this.dignity.leavePeerGroup(this.groupId);
13143
+ this.started = false;
13144
+ this.emit("stopped", { groupId: this.groupId });
13145
+ }
13146
+ handleDomainEvent(event) {
13147
+ if (!event || event.groupId !== this.groupId) {
13148
+ return;
13149
+ }
13150
+ if (this.publisherId && event.publisherId !== this.publisherId) {
13151
+ return;
13152
+ }
13153
+ this.ingestEvent(event);
13154
+ }
13155
+ handlePeerGroupMessage(message) {
13156
+ if (!message || message.groupId !== this.groupId) {
13157
+ return;
13158
+ }
13159
+ if (message.type === "domain:checkpoint") {
13160
+ this.emit("checkpoint", message.payload);
13161
+ }
13162
+ }
13163
+ ingestEvent(event, { skipChainCheck = false } = {}) {
13164
+ const verified = verifyDomainEvent2(event, {
13165
+ supportedVersions: [DOMAIN_EVENT_SCHEMA_VERSION2]
13166
+ });
13167
+ if (!verified.ok) {
13168
+ this.emit("warning", { type: "domain-event-rejected", reason: verified.reason, event });
13169
+ return false;
13170
+ }
13171
+ if (!skipChainCheck && this.eventLog.length > 0) {
13172
+ const lastHash = this.eventLog[this.eventLog.length - 1].eventHash;
13173
+ if (event.prevHash !== lastHash) {
13174
+ this.emit("chainbroken", {
13175
+ groupId: this.groupId,
13176
+ expectedPrev: lastHash,
13177
+ actualPrev: event.prevHash,
13178
+ eventId: event.eventId
13179
+ });
13180
+ return false;
13181
+ }
13182
+ } else if (!skipChainCheck && this.eventLog.length === 0 && event.prevHash) {
13183
+ this.emit("chainbroken", {
13184
+ groupId: this.groupId,
13185
+ expectedPrev: null,
13186
+ actualPrev: event.prevHash,
13187
+ eventId: event.eventId
13188
+ });
13189
+ return false;
13190
+ }
13191
+ const duplicate = this.eventLog.some((entry) => entry.eventId === event.eventId);
13192
+ if (duplicate) {
13193
+ return false;
13194
+ }
13195
+ const result = applyDomainEventToView2(this.view, event, {
13196
+ collectionsFilter: this.collections.length > 0 ? this.collections : null
13197
+ });
13198
+ if (result.applied || result.reason === "collection-filtered") {
13199
+ this.eventLog.push({ ...event });
13200
+ this.emit("change", { event, result });
13201
+ return true;
13202
+ }
13203
+ this.emit("warning", { type: "domain-event-not-applied", reason: result.reason, event });
13204
+ return false;
13205
+ }
13206
+ read(collectionName, id) {
13207
+ const collection = this.view.get(collectionName);
13208
+ if (!collection) {
13209
+ return null;
13210
+ }
13211
+ const record = collection.get(id);
13212
+ if (!record || record.deletedAt) {
13213
+ return null;
13214
+ }
13215
+ return { ...record, data: { ...record.data } };
13216
+ }
13217
+ list(collectionName, options = {}) {
13218
+ const collection = this.view.get(collectionName);
13219
+ if (!collection) {
13220
+ return [];
13221
+ }
13222
+ const includeDeleted = options.includeDeleted || false;
13223
+ const records = [];
13224
+ for (const record of collection.values()) {
13225
+ if (record.deletedAt && !includeDeleted) {
13226
+ continue;
13227
+ }
13228
+ if (record.deletedAt && includeDeleted) {
13229
+ records.push({
13230
+ id: record.id,
13231
+ ownerId: record.ownerId,
13232
+ deletedAt: record.deletedAt,
13233
+ version: record.version
13234
+ });
13235
+ continue;
13236
+ }
13237
+ records.push({ ...record, data: { ...record.data } });
13238
+ }
13239
+ return records;
13240
+ }
13241
+ verifyChain() {
13242
+ const result = verifyEventChain2(this.eventLog);
13243
+ if (!result.ok) {
13244
+ this.emit("chainbroken", { groupId: this.groupId, ...result });
13245
+ }
13246
+ return result;
13247
+ }
13248
+ getViewStats() {
13249
+ const stats = {
13250
+ groupId: this.groupId,
13251
+ eventCount: this.eventLog.length,
13252
+ collections: {}
13253
+ };
13254
+ for (const [name, collection] of this.view.entries()) {
13255
+ let active = 0;
13256
+ let deleted = 0;
13257
+ for (const record of collection.values()) {
13258
+ if (record.deletedAt) {
13259
+ deleted += 1;
13260
+ } else {
13261
+ active += 1;
13262
+ }
13263
+ }
13264
+ stats.collections[name] = { active, deleted };
13265
+ }
13266
+ return stats;
13267
+ }
13268
+ };
13269
+ module2.exports = DignityQueryReplica2;
13270
+ }
13271
+ });
13272
+
12415
13273
  // src/index.js
12416
13274
  var DignityP2P = require_dignity_p2p();
12417
13275
  var createDefaultSignalingPool = require_create_default_signaling_pool();
@@ -12456,6 +13314,24 @@ var {
12456
13314
  parsePeerGroupScope,
12457
13315
  selectFanoutPeers
12458
13316
  } = require_peer_group();
13317
+ var {
13318
+ DOMAIN_EVENT_SCHEMA_VERSION,
13319
+ operationToDomainEvent,
13320
+ signDomainEvent,
13321
+ verifyDomainEvent,
13322
+ verifyEventChain,
13323
+ buildCheckpoint,
13324
+ createEmptyView,
13325
+ applyDomainEventToView
13326
+ } = require_domain_events();
13327
+ var {
13328
+ DEFAULT_LIVE_CAP,
13329
+ DEFAULT_BULK_INTERVAL_MS,
13330
+ assignPeerGroupTier,
13331
+ filterPeersByTier
13332
+ } = require_peer_group_tiers();
13333
+ var { electBulkRelays, DEFAULT_BULK_RELAY_COUNT } = require_bulk_relay();
13334
+ var DignityQueryReplica = require_query_replica();
12459
13335
  module.exports = {
12460
13336
  DignityP2P,
12461
13337
  createDefaultSignalingPool,
@@ -12489,6 +13365,21 @@ module.exports = {
12489
13365
  DEFAULT_PEER_GROUP_OPTIONS,
12490
13366
  peerGroupScope,
12491
13367
  parsePeerGroupScope,
12492
- selectFanoutPeers
13368
+ selectFanoutPeers,
13369
+ DOMAIN_EVENT_SCHEMA_VERSION,
13370
+ operationToDomainEvent,
13371
+ signDomainEvent,
13372
+ verifyDomainEvent,
13373
+ verifyEventChain,
13374
+ buildCheckpoint,
13375
+ createEmptyView,
13376
+ applyDomainEventToView,
13377
+ DEFAULT_LIVE_CAP,
13378
+ DEFAULT_BULK_INTERVAL_MS,
13379
+ assignPeerGroupTier,
13380
+ filterPeersByTier,
13381
+ electBulkRelays,
13382
+ DEFAULT_BULK_RELAY_COUNT,
13383
+ DignityQueryReplica
12493
13384
  };
12494
13385
  //# sourceMappingURL=dignity.cjs.js.map