@aephia/atlas-kit 0.6.0-next.165 → 0.6.0-next.166
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/client/context.d.ts.map +1 -1
- package/dist/client/context.js +345 -36
- package/dist/client/context.js.map +1 -1
- package/dist/client/contracts.d.ts +53 -0
- package/dist/client/contracts.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rpc-subscription-provider.d.ts +2 -0
- package/dist/client/rpc-subscription-provider.d.ts.map +1 -1
- package/dist/client/rpc-subscription-provider.js +135 -101
- package/dist/client/rpc-subscription-provider.js.map +1 -1
- package/dist/world/index.d.ts +36 -0
- package/dist/world/index.d.ts.map +1 -1
- package/dist/world/index.js +41 -0
- package/dist/world/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/client/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,OAAO,EAEP,UAAU,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/client/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,OAAO,EAEP,UAAU,EAMV,kBAAkB,EAElB,WAAW,EACX,kBAAkB,EAMlB,8BAA8B,EAC/B,MAAM,gBAAgB,CAAC;AA6SxB,UAAU,4BAA4B;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,OAAO,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,8BAA8B,CAAC,UAAU,CAAC,CAAC;CAC7D;AAED,+EAA+E;AAC/E,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,4BAA4B,CAAC,CA6FvC;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,SAAS,CAAC,EAAE,UAAU,GACrB,UAAU,CAMZ;AA6+DD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAiG1E"}
|
package/dist/client/context.js
CHANGED
|
@@ -89,6 +89,19 @@ function validateDiscoveryFilters(filters) {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
+
function assertDiscriminatorFilter(definition, filters) {
|
|
93
|
+
const discriminator = [...definition.discriminator];
|
|
94
|
+
const present = filters.some((filter) => filter.offset === 0 &&
|
|
95
|
+
filter.bytes.length >= discriminator.length &&
|
|
96
|
+
discriminator.every((byte, index) => filter.bytes[index] === byte));
|
|
97
|
+
if (!present) {
|
|
98
|
+
throw new InvalidDerivationInputError(`The ${definition.type} discovery subscription filter set`, `${filters.length} filter(s) without the account discriminator at offset 0`, 'Add the account discriminator filter at offset 0 so the program subscription streams only this account type.');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function matchesFilters(data, filters) {
|
|
102
|
+
return filters.every((filter) => filter.offset + filter.bytes.length <= data.length &&
|
|
103
|
+
filter.bytes.every((byte, index) => data[filter.offset + index] === byte));
|
|
104
|
+
}
|
|
92
105
|
function copyReadMetaFilters(filters) {
|
|
93
106
|
return Object.freeze(filters.map((filter) => Object.freeze({
|
|
94
107
|
bytes: Object.freeze([...filter.bytes]),
|
|
@@ -286,6 +299,7 @@ function createDataPort(cluster, provider, indexer, subscriptionProvider, defaul
|
|
|
286
299
|
let invalidationSequence = 0;
|
|
287
300
|
let reconciliationGeneration = 0;
|
|
288
301
|
let nextRawReadSequence = 0;
|
|
302
|
+
let nextDiscoverySequence = 0;
|
|
289
303
|
let nextDefinitionId = 0;
|
|
290
304
|
lifecycle.signal.addEventListener('abort', () => {
|
|
291
305
|
cache.clear();
|
|
@@ -557,10 +571,12 @@ function createDataPort(cluster, provider, indexer, subscriptionProvider, defaul
|
|
|
557
571
|
}
|
|
558
572
|
})();
|
|
559
573
|
}
|
|
560
|
-
function sharedDiscovery(programAddress, filters, commitment, discoveryInvalidationGeneration, addressReconciliationGeneration) {
|
|
574
|
+
function sharedDiscovery(programAddress, filters, commitment, discoveryInvalidationGeneration, addressReconciliationGeneration, minimumSequence = 0) {
|
|
561
575
|
const registryKey = discoveryReadKey(programAddress, filters, commitment, discoveryInvalidationGeneration, addressReconciliationGeneration);
|
|
562
576
|
const existing = discoveryReads.get(registryKey);
|
|
563
|
-
|
|
577
|
+
// A stream closing a subscription gap cannot join a discovery that began
|
|
578
|
+
// before its registration or reconnect.
|
|
579
|
+
if (existing !== undefined && existing.sequence >= minimumSequence) {
|
|
564
580
|
return existing;
|
|
565
581
|
}
|
|
566
582
|
let resolveDiscovery;
|
|
@@ -571,6 +587,7 @@ function createDataPort(cluster, provider, indexer, subscriptionProvider, defaul
|
|
|
571
587
|
});
|
|
572
588
|
const read = {
|
|
573
589
|
promise,
|
|
590
|
+
sequence: nextDiscoverySequence++,
|
|
574
591
|
};
|
|
575
592
|
discoveryReads.set(registryKey, read);
|
|
576
593
|
const operation = (async () => {
|
|
@@ -790,6 +807,43 @@ function createDataPort(cluster, provider, indexer, subscriptionProvider, defaul
|
|
|
790
807
|
void promise.then(retainSettledResult, retainSettledResult);
|
|
791
808
|
return promise;
|
|
792
809
|
}
|
|
810
|
+
async function targetedDiscovery(definition, providerFilters, commitment, store, operationInvalidationSequence, signal, minimumSequence = 0) {
|
|
811
|
+
let accounts;
|
|
812
|
+
try {
|
|
813
|
+
const discoveryRead = sharedDiscovery(definition.programAddress, providerFilters, commitment, discoveryInvalidatedAt.get(definition.programAddress) ?? 0, reconciliationGeneration, minimumSequence);
|
|
814
|
+
accounts = await waitForCaller(discoveryRead.promise, signal);
|
|
815
|
+
}
|
|
816
|
+
catch (cause) {
|
|
817
|
+
if (signal?.aborted === true) {
|
|
818
|
+
throw abortReason(signal);
|
|
819
|
+
}
|
|
820
|
+
if (isDisposed()) {
|
|
821
|
+
throw new ContextDisposedError();
|
|
822
|
+
}
|
|
823
|
+
if (cause instanceof SageSdkError) {
|
|
824
|
+
throw cause;
|
|
825
|
+
}
|
|
826
|
+
throw new ProviderError('The configured provider could not discover the requested z.ink accounts. Check the discovery filters and provider connection, then retry.', { accountType: definition.type });
|
|
827
|
+
}
|
|
828
|
+
assertActive();
|
|
829
|
+
const snapshotsByAddress = new Map();
|
|
830
|
+
for (const account of accounts) {
|
|
831
|
+
assertProviderCommitment(account, commitment);
|
|
832
|
+
const snapshot = validateAndTimestamp(definition, copyRawAccount(account), provider.identity);
|
|
833
|
+
const existing = snapshotsByAddress.get(snapshot.address);
|
|
834
|
+
if (existing === undefined || isPreferredSnapshot(snapshot, existing)) {
|
|
835
|
+
snapshotsByAddress.set(snapshot.address, snapshot);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
const snapshots = [...snapshotsByAddress.values()];
|
|
839
|
+
if (store) {
|
|
840
|
+
assertCacheCapacity(snapshots.map((snapshot) => keyFor(definition, snapshot.address)));
|
|
841
|
+
for (const snapshot of snapshots) {
|
|
842
|
+
storeSnapshot(keyFor(definition, snapshot.address), snapshot, operationInvalidationSequence);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return snapshots;
|
|
846
|
+
}
|
|
793
847
|
async function readOptional(definition, address, options) {
|
|
794
848
|
assertActive();
|
|
795
849
|
throwIfAborted(options?.signal);
|
|
@@ -950,40 +1004,7 @@ function createDataPort(cluster, provider, indexer, subscriptionProvider, defaul
|
|
|
950
1004
|
strategy: 'indexer',
|
|
951
1005
|
}));
|
|
952
1006
|
}
|
|
953
|
-
|
|
954
|
-
try {
|
|
955
|
-
const discoveryRead = sharedDiscovery(definition.programAddress, providerFilters, commitment, discoveryInvalidatedAt.get(definition.programAddress) ?? 0, reconciliationGeneration);
|
|
956
|
-
accounts = await waitForCaller(discoveryRead.promise, request.signal);
|
|
957
|
-
}
|
|
958
|
-
catch (cause) {
|
|
959
|
-
if (request.signal?.aborted === true) {
|
|
960
|
-
throw abortReason(request.signal);
|
|
961
|
-
}
|
|
962
|
-
if (isDisposed()) {
|
|
963
|
-
throw new ContextDisposedError();
|
|
964
|
-
}
|
|
965
|
-
if (cause instanceof SageSdkError) {
|
|
966
|
-
throw cause;
|
|
967
|
-
}
|
|
968
|
-
throw new ProviderError('The configured provider could not discover the requested z.ink accounts. Check the discovery filters and provider connection, then retry.', { accountType: definition.type });
|
|
969
|
-
}
|
|
970
|
-
assertActive();
|
|
971
|
-
const snapshotsByAddress = new Map();
|
|
972
|
-
for (const account of accounts) {
|
|
973
|
-
assertProviderCommitment(account, commitment);
|
|
974
|
-
const snapshot = validateAndTimestamp(definition, copyRawAccount(account), provider.identity);
|
|
975
|
-
const existing = snapshotsByAddress.get(snapshot.address);
|
|
976
|
-
if (existing === undefined || isPreferredSnapshot(snapshot, existing)) {
|
|
977
|
-
snapshotsByAddress.set(snapshot.address, snapshot);
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
const snapshots = [...snapshotsByAddress.values()];
|
|
981
|
-
if (request.policy !== 'no-store') {
|
|
982
|
-
assertCacheCapacity(snapshots.map((snapshot) => keyFor(definition, snapshot.address)));
|
|
983
|
-
for (const snapshot of snapshots) {
|
|
984
|
-
storeSnapshot(keyFor(definition, snapshot.address), snapshot, operationInvalidationSequence);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
1007
|
+
const snapshots = await targetedDiscovery(definition, providerFilters, commitment, request.policy !== 'no-store', operationInvalidationSequence, request.signal);
|
|
987
1008
|
const slot = snapshots.reduce((earliest, snapshot) => earliest === undefined || snapshot.slot < earliest
|
|
988
1009
|
? snapshot.slot
|
|
989
1010
|
: earliest, undefined);
|
|
@@ -1301,6 +1322,294 @@ function createDataPort(cluster, provider, indexer, subscriptionProvider, defaul
|
|
|
1301
1322
|
await waitForCaller(registrationDeliveryStarted, registrationLifecycle.signal);
|
|
1302
1323
|
return Object.freeze({ unsubscribe: stop });
|
|
1303
1324
|
},
|
|
1325
|
+
async subscribeDiscovery(definition, request, observer) {
|
|
1326
|
+
assertActive();
|
|
1327
|
+
throwIfAborted(request.signal);
|
|
1328
|
+
const programProvider = subscriptionProvider;
|
|
1329
|
+
if (programProvider?.subscribeProgram === undefined) {
|
|
1330
|
+
throw new ProviderError('This SAGE context has no program subscription provider. Configure a WebSocket subscription provider that implements subscribeProgram, such as createRpcSubscriptionProvider over a Kit transport with programNotifications, before streaming account changes.', { accountType: definition.type });
|
|
1331
|
+
}
|
|
1332
|
+
validateDiscoveryFilters(request.filters);
|
|
1333
|
+
assertDiscriminatorFilter(definition, request.filters);
|
|
1334
|
+
const filters = copyProviderDiscoveryFilters(request.filters);
|
|
1335
|
+
const commitment = requestedCommitment(request);
|
|
1336
|
+
const registrationLifecycle = new AbortController();
|
|
1337
|
+
const { signal } = registrationLifecycle;
|
|
1338
|
+
let registration;
|
|
1339
|
+
let registrationAttempt;
|
|
1340
|
+
let stopPromise;
|
|
1341
|
+
let resolveCompletion;
|
|
1342
|
+
const completion = new Promise((resolve) => {
|
|
1343
|
+
resolveCompletion = resolve;
|
|
1344
|
+
});
|
|
1345
|
+
trackSubscription(completion);
|
|
1346
|
+
const streamErrorMessage = 'The account stream could not process a live z.ink update. Check the WebSocket provider and retry the subscription.';
|
|
1347
|
+
const observerErrorMessage = 'The account stream onSnapshot callback could not process a validated snapshot. Fix the consumer callback before retrying delivery.';
|
|
1348
|
+
// Every map is bounded by the addresses matching the filters, which is
|
|
1349
|
+
// capped at maxDiscoveryResults; transient errors are bounded by code.
|
|
1350
|
+
// The discovery round in which each address was last seen; a reconnect
|
|
1351
|
+
// reports only addresses not seen since its discovery started.
|
|
1352
|
+
const seenInRound = new Map();
|
|
1353
|
+
let discoveryRound = 0;
|
|
1354
|
+
const lastDelivered = new Map();
|
|
1355
|
+
// The snapshot onSnapshot is processing, so a slow callback cannot let
|
|
1356
|
+
// an older slot follow it; a rejected one can still be retried.
|
|
1357
|
+
let inFlight;
|
|
1358
|
+
const pending = new Map();
|
|
1359
|
+
// Removals stay keyed by address: each one is reported exactly once.
|
|
1360
|
+
const pendingRemovals = new Map();
|
|
1361
|
+
const coalesced = new Map();
|
|
1362
|
+
const pendingErrors = new Map();
|
|
1363
|
+
const coalescedErrors = new Map();
|
|
1364
|
+
let notificationRunning = false;
|
|
1365
|
+
let discovering = false;
|
|
1366
|
+
let rediscoveryPending = false;
|
|
1367
|
+
let pendingDiscoverySequence = 0;
|
|
1368
|
+
const emitDiagnostic = (event) => {
|
|
1369
|
+
try {
|
|
1370
|
+
observer.onDiagnostic?.(event);
|
|
1371
|
+
}
|
|
1372
|
+
catch {
|
|
1373
|
+
// Diagnostics never interrupt delivery or transport cleanup.
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
const normalizeError = (cause, message) => cause instanceof SageSdkError
|
|
1377
|
+
? cause
|
|
1378
|
+
: new ProviderError(message, {
|
|
1379
|
+
accountType: definition.type,
|
|
1380
|
+
cause,
|
|
1381
|
+
});
|
|
1382
|
+
const runNotifications = async () => {
|
|
1383
|
+
if (notificationRunning)
|
|
1384
|
+
return;
|
|
1385
|
+
notificationRunning = true;
|
|
1386
|
+
try {
|
|
1387
|
+
while (!signal.aborted && !isDisposed()) {
|
|
1388
|
+
const errorEntry = pendingErrors.entries().next().value;
|
|
1389
|
+
if (errorEntry !== undefined) {
|
|
1390
|
+
pendingErrors.delete(errorEntry[0]);
|
|
1391
|
+
coalescedErrors.delete(errorEntry[0]);
|
|
1392
|
+
try {
|
|
1393
|
+
await observer.onError(errorEntry[1]);
|
|
1394
|
+
}
|
|
1395
|
+
catch {
|
|
1396
|
+
// Consumer observer failures never terminate transport.
|
|
1397
|
+
}
|
|
1398
|
+
continue;
|
|
1399
|
+
}
|
|
1400
|
+
const removal = pendingRemovals.entries().next().value;
|
|
1401
|
+
if (removal !== undefined) {
|
|
1402
|
+
pendingRemovals.delete(removal[0]);
|
|
1403
|
+
try {
|
|
1404
|
+
await observer.onError(removal[1]);
|
|
1405
|
+
}
|
|
1406
|
+
catch {
|
|
1407
|
+
// Consumer observer failures never terminate transport.
|
|
1408
|
+
}
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
const next = pending.entries().next().value;
|
|
1412
|
+
if (next === undefined)
|
|
1413
|
+
return;
|
|
1414
|
+
pending.delete(next[0]);
|
|
1415
|
+
coalesced.delete(next[0]);
|
|
1416
|
+
inFlight = next[1];
|
|
1417
|
+
try {
|
|
1418
|
+
await observer.onSnapshot(next[1]);
|
|
1419
|
+
// A reconnect may have reported the account missing meanwhile.
|
|
1420
|
+
if (seenInRound.has(next[0])) {
|
|
1421
|
+
lastDelivered.set(next[0], next[1]);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
catch (cause) {
|
|
1425
|
+
const error = normalizeError(cause, observerErrorMessage);
|
|
1426
|
+
pendingErrors.set(error.code, error);
|
|
1427
|
+
}
|
|
1428
|
+
finally {
|
|
1429
|
+
inFlight = undefined;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
finally {
|
|
1434
|
+
notificationRunning = false;
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
const reportError = (cause, message) => {
|
|
1438
|
+
if (signal.aborted)
|
|
1439
|
+
return;
|
|
1440
|
+
const error = normalizeError(cause, message);
|
|
1441
|
+
if (pendingErrors.has(error.code)) {
|
|
1442
|
+
const count = (coalescedErrors.get(error.code) ?? 0) + 1;
|
|
1443
|
+
coalescedErrors.set(error.code, count);
|
|
1444
|
+
emitDiagnostic({
|
|
1445
|
+
accountType: definition.type,
|
|
1446
|
+
address: error.address ?? definition.programAddress,
|
|
1447
|
+
coalescedCount: count,
|
|
1448
|
+
errorCode: error.code,
|
|
1449
|
+
kind: 'subscription-error-coalesced',
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
pendingErrors.set(error.code, error);
|
|
1453
|
+
void runNotifications();
|
|
1454
|
+
};
|
|
1455
|
+
const queueSnapshot = (candidate) => {
|
|
1456
|
+
const address = candidate.address;
|
|
1457
|
+
const selected = cachedSnapshot(keyFor(definition, address), commitment) ??
|
|
1458
|
+
candidate;
|
|
1459
|
+
const baseline = pending.get(address) ??
|
|
1460
|
+
(inFlight?.address === address ? inFlight : undefined) ??
|
|
1461
|
+
lastDelivered.get(address);
|
|
1462
|
+
if (baseline !== undefined &&
|
|
1463
|
+
!isPreferredSnapshot(selected, baseline)) {
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
if (pending.has(address)) {
|
|
1467
|
+
const count = (coalesced.get(address) ?? 0) + 1;
|
|
1468
|
+
coalesced.set(address, count);
|
|
1469
|
+
emitDiagnostic({
|
|
1470
|
+
accountType: definition.type,
|
|
1471
|
+
address,
|
|
1472
|
+
coalescedCount: count,
|
|
1473
|
+
kind: 'subscription-snapshot-coalesced',
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
pending.set(address, selected);
|
|
1477
|
+
void runNotifications();
|
|
1478
|
+
};
|
|
1479
|
+
const track = (address, round) => {
|
|
1480
|
+
if (!seenInRound.has(address)) {
|
|
1481
|
+
assertWithinLimit('streamed accounts', seenInRound.size + 1, maxDiscoveryResults);
|
|
1482
|
+
}
|
|
1483
|
+
seenInRound.set(address, round);
|
|
1484
|
+
// A validated sighting supersedes a removal not yet reported.
|
|
1485
|
+
pendingRemovals.delete(address);
|
|
1486
|
+
};
|
|
1487
|
+
const rediscover = () => {
|
|
1488
|
+
pendingDiscoverySequence = nextDiscoverySequence;
|
|
1489
|
+
if (discovering) {
|
|
1490
|
+
rediscoveryPending = true;
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
discovering = true;
|
|
1494
|
+
void (async () => {
|
|
1495
|
+
try {
|
|
1496
|
+
do {
|
|
1497
|
+
rediscoveryPending = false;
|
|
1498
|
+
const minimumSequence = pendingDiscoverySequence;
|
|
1499
|
+
const round = ++discoveryRound;
|
|
1500
|
+
try {
|
|
1501
|
+
const snapshots = await targetedDiscovery(definition, filters, commitment, true, invalidationSequence, signal, minimumSequence);
|
|
1502
|
+
for (const snapshot of snapshots) {
|
|
1503
|
+
track(snapshot.address, round);
|
|
1504
|
+
queueSnapshot(snapshot);
|
|
1505
|
+
}
|
|
1506
|
+
for (const [address, seen] of [...seenInRound]) {
|
|
1507
|
+
if (seen >= round)
|
|
1508
|
+
continue;
|
|
1509
|
+
seenInRound.delete(address);
|
|
1510
|
+
lastDelivered.delete(address);
|
|
1511
|
+
pending.delete(address);
|
|
1512
|
+
coalesced.delete(address);
|
|
1513
|
+
pendingRemovals.set(address, new AccountNotFoundError(definition.type, address));
|
|
1514
|
+
void runNotifications();
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
catch (cause) {
|
|
1518
|
+
reportError(cause, streamErrorMessage);
|
|
1519
|
+
}
|
|
1520
|
+
} while (rediscoveryPending && !signal.aborted && !isDisposed());
|
|
1521
|
+
}
|
|
1522
|
+
finally {
|
|
1523
|
+
discovering = false;
|
|
1524
|
+
}
|
|
1525
|
+
})();
|
|
1526
|
+
};
|
|
1527
|
+
const enqueue = (event) => {
|
|
1528
|
+
if (signal.aborted || isDisposed())
|
|
1529
|
+
return;
|
|
1530
|
+
if (event.kind === 'reconnected') {
|
|
1531
|
+
rediscover();
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
try {
|
|
1535
|
+
assertAccountSize(event.account);
|
|
1536
|
+
const account = copyRawAccount(event.account);
|
|
1537
|
+
assertProviderCommitment(account, commitment);
|
|
1538
|
+
if (!matchesFilters(account.data, filters)) {
|
|
1539
|
+
throw new ProviderError(`The program subscription returned ${account.address}, which does not match the requested filters. Fix the WebSocket provider's program-subscription filters before retrying.`, { accountType: definition.type, address: account.address });
|
|
1540
|
+
}
|
|
1541
|
+
const snapshot = validateAndTimestamp(definition, account, programProvider.identity);
|
|
1542
|
+
track(snapshot.address, discoveryRound);
|
|
1543
|
+
storeSubscriptionSnapshot(keyFor(definition, snapshot.address), snapshot);
|
|
1544
|
+
queueSnapshot(snapshot);
|
|
1545
|
+
}
|
|
1546
|
+
catch (cause) {
|
|
1547
|
+
reportError(cause, streamErrorMessage);
|
|
1548
|
+
}
|
|
1549
|
+
};
|
|
1550
|
+
const abortRegistration = () => registrationLifecycle.abort(request.signal?.aborted === true
|
|
1551
|
+
? request.signal.reason
|
|
1552
|
+
: lifecycle.signal.reason);
|
|
1553
|
+
request.signal?.addEventListener('abort', abortRegistration, {
|
|
1554
|
+
once: true,
|
|
1555
|
+
});
|
|
1556
|
+
lifecycle.signal.addEventListener('abort', abortRegistration, {
|
|
1557
|
+
once: true,
|
|
1558
|
+
});
|
|
1559
|
+
const stop = () => {
|
|
1560
|
+
if (stopPromise !== undefined)
|
|
1561
|
+
return stopPromise;
|
|
1562
|
+
let resolveStop;
|
|
1563
|
+
stopPromise = new Promise((resolve) => {
|
|
1564
|
+
resolveStop = resolve;
|
|
1565
|
+
});
|
|
1566
|
+
registrationLifecycle.abort();
|
|
1567
|
+
request.signal?.removeEventListener('abort', abortRegistration);
|
|
1568
|
+
lifecycle.signal.removeEventListener('abort', abortRegistration);
|
|
1569
|
+
void (async () => {
|
|
1570
|
+
try {
|
|
1571
|
+
if (registration !== undefined) {
|
|
1572
|
+
await registration.unsubscribe();
|
|
1573
|
+
}
|
|
1574
|
+
else {
|
|
1575
|
+
// A late registration is released in the background.
|
|
1576
|
+
void registrationAttempt?.then((late) => late.unsubscribe(), () => undefined);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
catch {
|
|
1580
|
+
// Disposal remains best-effort when a transport is already gone.
|
|
1581
|
+
}
|
|
1582
|
+
finally {
|
|
1583
|
+
resolveCompletion();
|
|
1584
|
+
resolveStop();
|
|
1585
|
+
}
|
|
1586
|
+
})();
|
|
1587
|
+
return stopPromise;
|
|
1588
|
+
};
|
|
1589
|
+
signal.addEventListener('abort', () => void stop(), { once: true });
|
|
1590
|
+
try {
|
|
1591
|
+
registrationAttempt = Promise.resolve().then(() => programProvider.subscribeProgram({
|
|
1592
|
+
commitment,
|
|
1593
|
+
filters,
|
|
1594
|
+
programAddress: definition.programAddress,
|
|
1595
|
+
signal,
|
|
1596
|
+
}, (event) => void enqueue(event)));
|
|
1597
|
+
void registrationAttempt.catch(() => undefined);
|
|
1598
|
+
registration = await waitForCaller(registrationAttempt, signal);
|
|
1599
|
+
}
|
|
1600
|
+
catch (cause) {
|
|
1601
|
+
const wasCancelled = signal.aborted;
|
|
1602
|
+
const cancellationReason = signal.reason;
|
|
1603
|
+
await stop();
|
|
1604
|
+
if (wasCancelled)
|
|
1605
|
+
throw cancellationReason;
|
|
1606
|
+
if (cause instanceof SageSdkError)
|
|
1607
|
+
throw cause;
|
|
1608
|
+
throw new ProviderError('The configured WebSocket provider could not register the requested program subscription. Check the provider connection and retry.', { accountType: definition.type });
|
|
1609
|
+
}
|
|
1610
|
+
rediscover();
|
|
1611
|
+
return Object.freeze({ unsubscribe: stop });
|
|
1612
|
+
},
|
|
1304
1613
|
async readRaw(address, options) {
|
|
1305
1614
|
assertActive();
|
|
1306
1615
|
throwIfAborted(options?.signal);
|