@serfab/cadre-core 1.19.0 → 1.19.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.
- package/dist/cadre-node.d.ts +65 -2
- package/dist/cadre-node.js +114 -2
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-read-retry.d.ts +19 -16
- package/dist/control-read-retry.js +22 -54
- package/dist/control-read-retry.js.map +1 -1
- package/dist/control-retry.d.ts +50 -6
- package/dist/control-retry.js +53 -6
- package/dist/control-retry.js.map +1 -1
- package/dist/control-write-retry.d.ts +24 -16
- package/dist/control-write-retry.js +58 -30
- package/dist/control-write-retry.js.map +1 -1
- package/dist/edge-node/config.d.ts +8 -2
- package/dist/edge-node/config.js +5 -1
- package/dist/edge-node/config.js.map +1 -1
- package/dist/edge-node/edge-join.js +2 -0
- package/dist/edge-node/edge-join.js.map +1 -1
- package/dist/edge-node/edge-node.d.ts +10 -0
- package/dist/edge-node/edge-node.js +52 -8
- package/dist/edge-node/edge-node.js.map +1 -1
- package/dist/edge-node/options.d.ts +11 -2
- package/dist/edge-node/options.js +11 -4
- package/dist/edge-node/options.js.map +1 -1
- package/dist/edge-node/platform.d.ts +15 -3
- package/dist/edge-node/strands.js +3 -2
- package/dist/edge-node/strands.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/strand-database.d.ts +56 -0
- package/dist/strand-database.js +87 -0
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +67 -2
- package/dist/strand-instance-manager.js +105 -4
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-reconciler.d.ts +13 -1
- package/dist/strand-membership-reconciler.js +18 -7
- package/dist/strand-membership-reconciler.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +16 -2
- package/dist/strand-membership-writer.js +54 -8
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-offline.d.ts +131 -0
- package/dist/strand-offline.js +142 -0
- package/dist/strand-offline.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js.map +1 -1
- package/package.json +8 -8
- package/src/cadre-node.ts +11456 -11329
- package/src/control-read-retry.ts +22 -58
- package/src/control-retry.ts +54 -6
- package/src/control-write-retry.ts +58 -30
- package/src/edge-node/config.ts +11 -2
- package/src/edge-node/edge-join.ts +1 -0
- package/src/edge-node/edge-node.ts +55 -6
- package/src/edge-node/options.ts +20 -4
- package/src/edge-node/platform.ts +15 -3
- package/src/edge-node/strands.ts +3 -2
- package/src/index.ts +917 -898
- package/src/strand-database.ts +466 -352
- package/src/strand-instance-manager.ts +2210 -2092
- package/src/strand-membership-reconciler.ts +24 -7
- package/src/strand-membership-writer.ts +61 -14
- package/src/strand-offline.ts +247 -0
- package/src/types.ts +2960 -2926
package/dist/cadre-node.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Libp2p, PeerId } from '@libp2p/interface';
|
|
2
2
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
|
3
3
|
import type { CadreNodeConfig, StrandInstance, StrandRow, StrandConfig, FoundStrandConfig, FoundStrandResult, FoundStrandOptions, FoundStrandBackgroundResult, SAppConfig, CadreNodeEvents, ControlNetworkSeed, ApplySeedResult, SeedAckMessage, SeedDeliveryTarget, AddDroneOptions, DroneInitResult, OpenInvitation, FormStrandResult, StrandFormationDisclosure, StrandMembershipInvite, ResolveOpts, SelfRegistrationOutcome, ServiceWakeResult, PushPlatform, DeviceTokenRecord, CadreInviteStatus, CadreMachine, CadreOwnerKey, MachineRemovalPlan, MachineRemovalResult, OwnerKeyRemovalPlan, OwnerKeyRemovalResult, RemoveOwnerOptions, CadreRemoval, CadreInvitationReach, CreateCadreInvitationOptions, CreateCadreInvitationResult, RedeemCadreInvitationOptions, RedeemCadreInvitationResult, CreateOwnerGrantOptions, CreateOwnerGrantResult, OwnerGrantStatus, RedeemOwnerGrantOptions, RedeemOwnerGrantResult, JoinWithOwnerGrantResult, ResolveDeviceTokenOpts, PendingJoinStatus } from './types.js';
|
|
4
|
+
import { type StrandLeaveOptions, type StrandOfflineMode } from './strand-offline.js';
|
|
4
5
|
import { type TrustedOwnerStore, type TrustSource } from './trusted-owner-store.js';
|
|
5
6
|
import { type OwnerSign, type OwnerSigner } from './owner-signer.js';
|
|
6
7
|
import { type BootstrapPeerStore } from './bootstrap-peer-store.js';
|
|
@@ -2441,6 +2442,17 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2441
2442
|
* using. Emits `strand:writable` after the timers are settled.
|
|
2442
2443
|
*/
|
|
2443
2444
|
private handleStrandWritable;
|
|
2445
|
+
/**
|
|
2446
|
+
* A status from a strand's offline queue (`StartStrandConfig.offline`). The queue sending counts
|
|
2447
|
+
* as activity ({@link isSendingStatus}), so a check-in window that finds the cohort reachable stays
|
|
2448
|
+
* up while the queue drains, and the idle timer does not cut a drain short. Recorded through the
|
|
2449
|
+
* hibernation manager, not {@link recordStrandActivity}, whose push fan-out would wake other phones.
|
|
2450
|
+
*
|
|
2451
|
+
* Not on a strand being quiesced: activity there wakes it again once the quiesce ends, which would
|
|
2452
|
+
* undo a `hibernateAll` made as the app went to the background. A send that quiesce cuts short was
|
|
2453
|
+
* journaled before it went out, and the next build's restore re-sends it under the same action id.
|
|
2454
|
+
*/
|
|
2455
|
+
private handleOfflineStatus;
|
|
2444
2456
|
private handleStrandIdle;
|
|
2445
2457
|
/**
|
|
2446
2458
|
* Hibernate a strand: release its strand-network resources via the strand
|
|
@@ -2595,6 +2607,24 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2595
2607
|
whenStrandWritable(strandId: string, options?: {
|
|
2596
2608
|
timeoutMs?: number;
|
|
2597
2609
|
}): Promise<StrandInstance>;
|
|
2610
|
+
/**
|
|
2611
|
+
* Switch a strand between offline mode, where a commit resolves once the transaction is queued on
|
|
2612
|
+
* this machine, and online mode (docs/strands.md → "Offline mode"). Affects transactions begun from
|
|
2613
|
+
* now on; one already open keeps the acknowledgement it began with. The mode belongs to the strand:
|
|
2614
|
+
* a hibernating strand takes it at its next build, and it lasts across hibernation and every
|
|
2615
|
+
* rebuild until the process exits, after which the strand starts in `strandOffline.initialMode`.
|
|
2616
|
+
*
|
|
2617
|
+
* @throws StrandOfflineUnavailableError when `CadreNodeConfig.strandOffline` is not configured.
|
|
2618
|
+
* @throws when this node does not run the strand.
|
|
2619
|
+
*/
|
|
2620
|
+
setStrandOfflineMode(strandId: string, mode: StrandOfflineMode): void;
|
|
2621
|
+
/**
|
|
2622
|
+
* A strand's offline mode ({@link setStrandOfflineMode}); `'online'` on a node without
|
|
2623
|
+
* `strandOffline`. The queue's own view, with what it holds, is `strand.database.offline.queueState()`.
|
|
2624
|
+
*
|
|
2625
|
+
* @throws when this node does not run the strand.
|
|
2626
|
+
*/
|
|
2627
|
+
getStrandOfflineMode(strandId: string): StrandOfflineMode;
|
|
2598
2628
|
/**
|
|
2599
2629
|
* Publish a strand row to the shared control database under this node's own
|
|
2600
2630
|
* owner identity, so other cadre members discover it via control-network
|
|
@@ -2845,14 +2875,22 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2845
2875
|
* caller ever needs removal to mean "and erase the local copy", that is a separate purge
|
|
2846
2876
|
* step, not a widening of this method.
|
|
2847
2877
|
*
|
|
2878
|
+
* Refuses while the strand's offline queue on this machine holds transactions, unless
|
|
2879
|
+
* `options.discardQueued` (docs/strands.md → "Leaving a strand with unsent transactions"). The
|
|
2880
|
+
* check and the discard run before the control-plane delete, so a delete refused afterwards
|
|
2881
|
+
* leaves the discarded transactions discarded.
|
|
2882
|
+
*
|
|
2848
2883
|
* @param strandId - The `Strand` row id to remove (as passed to {@link publishStrand}).
|
|
2884
|
+
* @param options - `discardQueued`: withdraw the queued transactions that were never sent, and remove.
|
|
2885
|
+
* @throws StrandQueueNotEmptyError when the queue holds transactions and `discardQueued` is not
|
|
2886
|
+
* set; nothing was removed.
|
|
2849
2887
|
* @throws if the node is not started, has no owner signer wired, the id is blank, or
|
|
2850
2888
|
* the signer is not an enrolled owner (the schema's `Strand.AuthorizedDelete` rejects
|
|
2851
2889
|
* the write and the row survives). A rejection does NOT imply the row survived: the
|
|
2852
2890
|
* local stop runs after the control-plane delete has already committed, so a failure
|
|
2853
2891
|
* there throws over a completed removal.
|
|
2854
2892
|
*/
|
|
2855
|
-
unpublishStrand(strandId: string): Promise<void>;
|
|
2893
|
+
unpublishStrand(strandId: string, options?: StrandLeaveOptions): Promise<void>;
|
|
2856
2894
|
/**
|
|
2857
2895
|
* Seat this party's own strand membership identity key — the `StrandPartyKey` row —
|
|
2858
2896
|
* for `strandId`, minting a fresh one when none is given, and adopting the stored one
|
|
@@ -3400,11 +3438,36 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3400
3438
|
* The other members of the strand are not told, and this party's membership row in the
|
|
3401
3439
|
* strand stays, so a later re-formation reuses the same identity.
|
|
3402
3440
|
*
|
|
3441
|
+
* Refuses while the strand's offline queue on this machine holds transactions, unless
|
|
3442
|
+
* `options.discardQueued` (docs/strands.md → "Leaving a strand with unsent transactions"). The
|
|
3443
|
+
* check and the discard run before the party-wide row is removed, so a removal refused
|
|
3444
|
+
* afterwards leaves the discarded transactions discarded.
|
|
3445
|
+
*
|
|
3446
|
+
* @param options - `discardQueued`: withdraw the queued transactions that were never sent, and leave.
|
|
3447
|
+
* @throws StrandQueueNotEmptyError when the queue holds transactions and `discardQueued` is not
|
|
3448
|
+
* set; nothing was left.
|
|
3403
3449
|
* @throws when a party-wide row exists and this machine cannot sign its removal (not an
|
|
3404
3450
|
* enrolled owner) — {@link stopStrand} stops the strand on this machine only — or when
|
|
3405
3451
|
* the party-wide table cannot be read.
|
|
3406
3452
|
*/
|
|
3407
|
-
forgetJoinedStrand(strandId: string): Promise<void>;
|
|
3453
|
+
forgetJoinedStrand(strandId: string, options?: StrandLeaveOptions): Promise<void>;
|
|
3454
|
+
/**
|
|
3455
|
+
* Before a leave changes anything: refuse while the strand's offline queue holds transactions,
|
|
3456
|
+
* unless the app asked to discard them (docs/strands.md → "Leaving a strand with unsent
|
|
3457
|
+
* transactions"). Transactions Optimystic will not withdraw stay in the journal, named in one
|
|
3458
|
+
* warning, and the leave goes on: they may already be saved, and a cohort that never returns
|
|
3459
|
+
* would otherwise block the leave forever.
|
|
3460
|
+
*
|
|
3461
|
+
* @throws StrandQueueNotEmptyError when the queue holds transactions and `discardQueued` is not set.
|
|
3462
|
+
* @throws when a hibernating strand has to be woken to discard and the wake fails.
|
|
3463
|
+
*/
|
|
3464
|
+
private settleQueueBeforeLeave;
|
|
3465
|
+
/**
|
|
3466
|
+
* Discard from the strand's live queue, waking a hibernating strand first (its queue is back
|
|
3467
|
+
* once a build restores it from the journal), and return what was kept. `undefined` when the
|
|
3468
|
+
* wake built no database (no seed peer has answered), so there was no queue to discard from.
|
|
3469
|
+
*/
|
|
3470
|
+
private discardQueuedForLeave;
|
|
3408
3471
|
/**
|
|
3409
3472
|
* Record `row` as a join from another party when this party's control database names it
|
|
3410
3473
|
* neither as its own strand nor as a party-wide join — the one case nothing else would
|
package/dist/cadre-node.js
CHANGED
|
@@ -9,6 +9,7 @@ import { controlClusterPolicy, CONTROL_REPLICATION_BREADTH, DEFAULT_CHECKIN_WIND
|
|
|
9
9
|
import { generatePrivateKey } from '@optimystic/quereus-plugin-crypto';
|
|
10
10
|
import { ed25519KeyPairFromLibp2p, ed25519PublicKeyFromPrivate, requireEd25519PublicKeyB64 } from './ed25519-key.js';
|
|
11
11
|
import { strandTransportKey } from './strand-transport-key.js';
|
|
12
|
+
import { isSendingStatus, StrandOfflineUnavailableError, StrandQueueNotEmptyError } from './strand-offline.js';
|
|
12
13
|
import { assertScopeKeyCharset, assertStrandScopeKey, controlStorageScope, InvalidStrandIdError, isValidStrandScopeKey } from './storage-scope.js';
|
|
13
14
|
import { generateStrandMemberKey, strandMemberKeyPair } from './strand-member-key.js';
|
|
14
15
|
import { assertNotPreSplitStrand, issueInvite, PreSplitStrandIdentityError, readStrandHeaderSAppId } from './strand-membership-writer.js';
|
|
@@ -5242,6 +5243,23 @@ export class CadreNode {
|
|
|
5242
5243
|
void this.recordReplicaSAppId(strandId);
|
|
5243
5244
|
this.emit('strand:writable', { strandId });
|
|
5244
5245
|
}
|
|
5246
|
+
/**
|
|
5247
|
+
* A status from a strand's offline queue (`StartStrandConfig.offline`). The queue sending counts
|
|
5248
|
+
* as activity ({@link isSendingStatus}), so a check-in window that finds the cohort reachable stays
|
|
5249
|
+
* up while the queue drains, and the idle timer does not cut a drain short. Recorded through the
|
|
5250
|
+
* hibernation manager, not {@link recordStrandActivity}, whose push fan-out would wake other phones.
|
|
5251
|
+
*
|
|
5252
|
+
* Not on a strand being quiesced: activity there wakes it again once the quiesce ends, which would
|
|
5253
|
+
* undo a `hibernateAll` made as the app went to the background. A send that quiesce cuts short was
|
|
5254
|
+
* journaled before it went out, and the next build's restore re-sends it under the same action id.
|
|
5255
|
+
*/
|
|
5256
|
+
handleOfflineStatus(event) {
|
|
5257
|
+
const instance = this.strandManager.getInstance(event.strandId);
|
|
5258
|
+
if (instance && isSendingStatus(event.status) && !this.strandManager.isQuiescing(event.strandId)) {
|
|
5259
|
+
this.hibernationManager.recordActivity(instance);
|
|
5260
|
+
}
|
|
5261
|
+
this.emit('strand:offline-status', event);
|
|
5262
|
+
}
|
|
5245
5263
|
// Hibernation callbacks
|
|
5246
5264
|
async handleStrandIdle(strandId) {
|
|
5247
5265
|
const instance = this.strandManager.getInstance(strandId);
|
|
@@ -5644,6 +5662,31 @@ export class CadreNode {
|
|
|
5644
5662
|
timeoutMs: options?.timeoutMs ?? this.config.strandFirstSync?.timeoutMs
|
|
5645
5663
|
});
|
|
5646
5664
|
}
|
|
5665
|
+
/**
|
|
5666
|
+
* Switch a strand between offline mode, where a commit resolves once the transaction is queued on
|
|
5667
|
+
* this machine, and online mode (docs/strands.md → "Offline mode"). Affects transactions begun from
|
|
5668
|
+
* now on; one already open keeps the acknowledgement it began with. The mode belongs to the strand:
|
|
5669
|
+
* a hibernating strand takes it at its next build, and it lasts across hibernation and every
|
|
5670
|
+
* rebuild until the process exits, after which the strand starts in `strandOffline.initialMode`.
|
|
5671
|
+
*
|
|
5672
|
+
* @throws StrandOfflineUnavailableError when `CadreNodeConfig.strandOffline` is not configured.
|
|
5673
|
+
* @throws when this node does not run the strand.
|
|
5674
|
+
*/
|
|
5675
|
+
setStrandOfflineMode(strandId, mode) {
|
|
5676
|
+
if (!this.config.strandOffline) {
|
|
5677
|
+
throw new StrandOfflineUnavailableError(strandId);
|
|
5678
|
+
}
|
|
5679
|
+
this.strandManager.setOfflineMode(strandId, mode);
|
|
5680
|
+
}
|
|
5681
|
+
/**
|
|
5682
|
+
* A strand's offline mode ({@link setStrandOfflineMode}); `'online'` on a node without
|
|
5683
|
+
* `strandOffline`. The queue's own view, with what it holds, is `strand.database.offline.queueState()`.
|
|
5684
|
+
*
|
|
5685
|
+
* @throws when this node does not run the strand.
|
|
5686
|
+
*/
|
|
5687
|
+
getStrandOfflineMode(strandId) {
|
|
5688
|
+
return this.strandManager.offlineMode(strandId);
|
|
5689
|
+
}
|
|
5647
5690
|
/**
|
|
5648
5691
|
* Publish a strand row to the shared control database under this node's own
|
|
5649
5692
|
* owner identity, so other cadre members discover it via control-network
|
|
@@ -6012,16 +6055,25 @@ export class CadreNode {
|
|
|
6012
6055
|
* caller ever needs removal to mean "and erase the local copy", that is a separate purge
|
|
6013
6056
|
* step, not a widening of this method.
|
|
6014
6057
|
*
|
|
6058
|
+
* Refuses while the strand's offline queue on this machine holds transactions, unless
|
|
6059
|
+
* `options.discardQueued` (docs/strands.md → "Leaving a strand with unsent transactions"). The
|
|
6060
|
+
* check and the discard run before the control-plane delete, so a delete refused afterwards
|
|
6061
|
+
* leaves the discarded transactions discarded.
|
|
6062
|
+
*
|
|
6015
6063
|
* @param strandId - The `Strand` row id to remove (as passed to {@link publishStrand}).
|
|
6064
|
+
* @param options - `discardQueued`: withdraw the queued transactions that were never sent, and remove.
|
|
6065
|
+
* @throws StrandQueueNotEmptyError when the queue holds transactions and `discardQueued` is not
|
|
6066
|
+
* set; nothing was removed.
|
|
6016
6067
|
* @throws if the node is not started, has no owner signer wired, the id is blank, or
|
|
6017
6068
|
* the signer is not an enrolled owner (the schema's `Strand.AuthorizedDelete` rejects
|
|
6018
6069
|
* the write and the row survives). A rejection does NOT imply the row survived: the
|
|
6019
6070
|
* local stop runs after the control-plane delete has already committed, so a failure
|
|
6020
6071
|
* there throws over a completed removal.
|
|
6021
6072
|
*/
|
|
6022
|
-
async unpublishStrand(strandId) {
|
|
6073
|
+
async unpublishStrand(strandId, options) {
|
|
6023
6074
|
const signer = this.requireOwnerSigner(`unpublish strand ${strandId}`);
|
|
6024
6075
|
const trimmed = requireNonBlank(strandId, 'strand id');
|
|
6076
|
+
await this.settleQueueBeforeLeave(trimmed, options);
|
|
6025
6077
|
// One approval: the strand delete and its party key's, each with its tombstone.
|
|
6026
6078
|
const removed = await signer.approve({ partyId: this.partyId, action: `Remove the strand ${trimmed} from the cadre` }, (sign) => this.controlDatabase.deleteStrand(trimmed, signer.publicKey, sign));
|
|
6027
6079
|
// Gate on `removed`: the absent-row no-op wrote nothing, so warning about an
|
|
@@ -6458,6 +6510,14 @@ export class CadreNode {
|
|
|
6458
6510
|
onWritable: (writableStrandId) => this.handleStrandWritable(writableStrandId),
|
|
6459
6511
|
onCommitDurability: (commit) => this.emit('strand:commit-durability', commit),
|
|
6460
6512
|
onCommitHeld: (held) => this.emit('strand:commit-held', held),
|
|
6513
|
+
offline: this.config.strandOffline && {
|
|
6514
|
+
...this.config.strandOffline,
|
|
6515
|
+
onOfflineStatus: (event) => this.handleOfflineStatus(event),
|
|
6516
|
+
onQueueState: (event) => this.emit('strand:queue-state', event),
|
|
6517
|
+
onAppSchemaDeferred: (event) => this.emit('strand:app-schema-deferred', event),
|
|
6518
|
+
onAppSchemaApplied: (event) => this.emit('strand:app-schema-applied', event),
|
|
6519
|
+
onAppSchemaFailed: (event) => this.emit('strand:error', event)
|
|
6520
|
+
},
|
|
6461
6521
|
// Re-announce the delegate to ONE relay before the strand node's reservation
|
|
6462
6522
|
// supervisor re-drives it (see announceDelegateToRelay). Retained with the
|
|
6463
6523
|
// launch config, so a hibernation wake's rebuilt supervisors get it too.
|
|
@@ -7132,18 +7192,70 @@ export class CadreNode {
|
|
|
7132
7192
|
* The other members of the strand are not told, and this party's membership row in the
|
|
7133
7193
|
* strand stays, so a later re-formation reuses the same identity.
|
|
7134
7194
|
*
|
|
7195
|
+
* Refuses while the strand's offline queue on this machine holds transactions, unless
|
|
7196
|
+
* `options.discardQueued` (docs/strands.md → "Leaving a strand with unsent transactions"). The
|
|
7197
|
+
* check and the discard run before the party-wide row is removed, so a removal refused
|
|
7198
|
+
* afterwards leaves the discarded transactions discarded.
|
|
7199
|
+
*
|
|
7200
|
+
* @param options - `discardQueued`: withdraw the queued transactions that were never sent, and leave.
|
|
7201
|
+
* @throws StrandQueueNotEmptyError when the queue holds transactions and `discardQueued` is not
|
|
7202
|
+
* set; nothing was left.
|
|
7135
7203
|
* @throws when a party-wide row exists and this machine cannot sign its removal (not an
|
|
7136
7204
|
* enrolled owner) — {@link stopStrand} stops the strand on this machine only — or when
|
|
7137
7205
|
* the party-wide table cannot be read.
|
|
7138
7206
|
*/
|
|
7139
|
-
async forgetJoinedStrand(strandId) {
|
|
7207
|
+
async forgetJoinedStrand(strandId, options) {
|
|
7140
7208
|
if (!this._running) {
|
|
7141
7209
|
throw new Error('CadreNode not running');
|
|
7142
7210
|
}
|
|
7211
|
+
await this.settleQueueBeforeLeave(strandId, options);
|
|
7143
7212
|
await this.joinedStrands.leave(strandId);
|
|
7144
7213
|
this.forgetStrandPeers(strandId, 'forgetJoinedStrand');
|
|
7145
7214
|
await this.stopStrand(strandId);
|
|
7146
7215
|
}
|
|
7216
|
+
/**
|
|
7217
|
+
* Before a leave changes anything: refuse while the strand's offline queue holds transactions,
|
|
7218
|
+
* unless the app asked to discard them (docs/strands.md → "Leaving a strand with unsent
|
|
7219
|
+
* transactions"). Transactions Optimystic will not withdraw stay in the journal, named in one
|
|
7220
|
+
* warning, and the leave goes on: they may already be saved, and a cohort that never returns
|
|
7221
|
+
* would otherwise block the leave forever.
|
|
7222
|
+
*
|
|
7223
|
+
* @throws StrandQueueNotEmptyError when the queue holds transactions and `discardQueued` is not set.
|
|
7224
|
+
* @throws when a hibernating strand has to be woken to discard and the wake fails.
|
|
7225
|
+
*/
|
|
7226
|
+
async settleQueueBeforeLeave(strandId, options) {
|
|
7227
|
+
const queued = this.strandManager.queuedTransactionIds(strandId);
|
|
7228
|
+
if (queued.length === 0) {
|
|
7229
|
+
return;
|
|
7230
|
+
}
|
|
7231
|
+
if (options?.discardQueued !== true) {
|
|
7232
|
+
throw new StrandQueueNotEmptyError(strandId, queued);
|
|
7233
|
+
}
|
|
7234
|
+
const kept = await this.discardQueuedForLeave(strandId);
|
|
7235
|
+
if (kept === undefined) {
|
|
7236
|
+
console.warn(`[sereus] strand ${strandId}: leaving with ${queued.length} queued transaction(s) not discarded ` +
|
|
7237
|
+
`(${queued.join(', ')}): the strand's database could not be built to reach its queue. They stay in ` +
|
|
7238
|
+
'this machine\'s offline journal and come back if this machine attaches the strand again.');
|
|
7239
|
+
}
|
|
7240
|
+
else if (kept.length > 0) {
|
|
7241
|
+
console.warn(`[sereus] strand ${strandId}: leaving with ${kept.length} queued transaction(s) that could not be ` +
|
|
7242
|
+
`discarded (${kept.join(', ')}): each was sent, or is being sent, and the strand's members may already ` +
|
|
7243
|
+
'hold it. They stay in this machine\'s offline journal and settle if this machine attaches the strand again.');
|
|
7244
|
+
}
|
|
7245
|
+
}
|
|
7246
|
+
/**
|
|
7247
|
+
* Discard from the strand's live queue, waking a hibernating strand first (its queue is back
|
|
7248
|
+
* once a build restores it from the journal), and return what was kept. `undefined` when the
|
|
7249
|
+
* wake built no database (no seed peer has answered), so there was no queue to discard from.
|
|
7250
|
+
*/
|
|
7251
|
+
async discardQueuedForLeave(strandId) {
|
|
7252
|
+
const kept = this.strandManager.discardQueuedTransactions(strandId);
|
|
7253
|
+
if (kept !== undefined) {
|
|
7254
|
+
return kept;
|
|
7255
|
+
}
|
|
7256
|
+
await this.wakeStrand(strandId);
|
|
7257
|
+
return this.strandManager.discardQueuedTransactions(strandId);
|
|
7258
|
+
}
|
|
7147
7259
|
/**
|
|
7148
7260
|
* Record `row` as a join from another party when this party's control database names it
|
|
7149
7261
|
* neither as its own strand nor as a party-wide join — the one case nothing else would
|