@framers/agentos-ext-account-sources 0.9.2 → 0.9.4
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/README.md +16 -13
- package/dist/sync/AccountSourceSync.d.ts +51 -14
- package/dist/sync/AccountSourceSync.d.ts.map +1 -1
- package/dist/sync/AccountSourceSync.js +56 -9
- package/dist/sync/AccountSourceSync.js.map +1 -1
- package/dist/sync/SourceQuota.d.ts +18 -6
- package/dist/sync/SourceQuota.d.ts.map +1 -1
- package/dist/sync/SourceQuota.js +74 -19
- package/dist/sync/SourceQuota.js.map +1 -1
- package/dist/sync/SourceRevocations.d.ts +2 -1
- package/dist/sync/SourceRevocations.d.ts.map +1 -1
- package/dist/sync/SourceRevocations.js +15 -4
- package/dist/sync/SourceRevocations.js.map +1 -1
- package/dist/sync/SqlAccountSourceSyncStore.d.ts +44 -12
- package/dist/sync/SqlAccountSourceSyncStore.d.ts.map +1 -1
- package/dist/sync/SqlAccountSourceSyncStore.js +110 -21
- package/dist/sync/SqlAccountSourceSyncStore.js.map +1 -1
- package/dist/sync/state.d.ts +8 -1
- package/dist/sync/state.d.ts.map +1 -1
- package/dist/sync/state.js +11 -2
- package/dist/sync/state.js.map +1 -1
- package/dist/sync/types.d.ts +6 -1
- package/dist/sync/types.d.ts.map +1 -1
- package/manifest.json +1 -1
- package/package.json +5 -5
|
@@ -138,25 +138,33 @@ export interface SourceSyncSweep {
|
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
140
|
* Thrown by `expire` when it fails after removing at least one source. Each removal committed in a transaction of its
|
|
141
|
-
* own, so `partial` counts them in `removed
|
|
142
|
-
* message this error carries.
|
|
141
|
+
* own, so `partial` counts them in `removed` and names their sources in `sourceIds`, in the order they were removed,
|
|
142
|
+
* with the failure itself in `failed`; `cause` holds the failure, whose message this error carries. The removals stand:
|
|
143
|
+
* a host that counts what `expire` removed adds `partial.removed` in its catch, as `AccountSourceSync.maintain` does.
|
|
143
144
|
*/
|
|
144
145
|
export declare class SourceSyncExpiryError extends Error {
|
|
145
146
|
readonly partial: {
|
|
146
147
|
readonly removed: number;
|
|
147
148
|
readonly failed: number;
|
|
149
|
+
readonly sourceIds: readonly string[];
|
|
148
150
|
};
|
|
149
|
-
|
|
151
|
+
/**
|
|
152
|
+
* @param removed - How many sources were removed before the failure.
|
|
153
|
+
* @param cause - The failure.
|
|
154
|
+
* @param sourceIds - The ids of those sources, in the order they were removed; `expire` always gives them.
|
|
155
|
+
*/
|
|
156
|
+
constructor(removed: number, cause: unknown, sourceIds?: readonly string[]);
|
|
150
157
|
}
|
|
151
158
|
/**
|
|
152
159
|
* Durable synchronization state for account sources on PostgreSQL. Every change to an owner's content runs under
|
|
153
160
|
* that owner's fence (`fence`), and a change made with a handle checks its lease, generation and host liveness in
|
|
154
161
|
* the same transaction. Applying a changed source purges its old copy and every derived result that depends on it
|
|
155
|
-
* before the replacement is written
|
|
156
|
-
*
|
|
157
|
-
* the
|
|
158
|
-
*
|
|
159
|
-
*
|
|
162
|
+
* before the replacement is written; a read that answers gone or a skip withdraws the copy in a commit of its own
|
|
163
|
+
* before purging it, so a purge that fails leaves nothing derived from it deliverable. A read that repeats the text of
|
|
164
|
+
* a copy the store holds is never charged again, one that changes it is charged, by the hash the store keeps of each
|
|
165
|
+
* message's text, its new and changed messages and the text beside them, and with the host's `refresh` binding a read
|
|
166
|
+
* of that very copy keeps it in place. Provider reads, embedding and model calls stay outside the store. The
|
|
167
|
+
* constructor runs no DDL: the host's migration runs `sourceSyncSchema` and core's `sourceDerivationSchema` first.
|
|
160
168
|
*
|
|
161
169
|
* @typeParam Prepared - The host's in-memory value for one document, passed through to its `write` binding.
|
|
162
170
|
*/
|
|
@@ -291,8 +299,10 @@ export declare class SqlAccountSourceSyncStore<Prepared = unknown> {
|
|
|
291
299
|
/**
|
|
292
300
|
* Applies one read result for a work item taken in this cycle, under a live lease and the owner fence. A retry
|
|
293
301
|
* keeps the work unresolved. A document is weighed first: excluded, outside the retained limits or over the
|
|
294
|
-
* indexing allowance with the characters it adds to index, it is recorded as a skip with its reason
|
|
295
|
-
*
|
|
302
|
+
* indexing allowance with the characters it adds to index, it is recorded as a skip with its reason, and so is one
|
|
303
|
+
* whose cache lifetime has ended by the store's clock when it is weighed (`expired`), as a document admitted with
|
|
304
|
+
* seconds of it left and applied again after a longer preparation: an expired read is never refused as malformed. A
|
|
305
|
+
* document that fits replaces the source's old copy in the same transaction (host write, indexing charge and provenance),
|
|
296
306
|
* after the old copy and every result derived from it are purged, evicting this connection's older sources the
|
|
297
307
|
* limits no longer admit. A read that repeats the text and message spans of a copy the store still holds, within
|
|
298
308
|
* its expiry and window, adds nothing to index and is never charged. Any other read of such a copy adds its new and
|
|
@@ -318,6 +328,13 @@ export declare class SqlAccountSourceSyncStore<Prepared = unknown> {
|
|
|
318
328
|
* does not begin with the copy's text, so with the allowance spent it removes the thread's copy, and the thread stays
|
|
319
329
|
* out of the store until a read of it fits the allowance whole.
|
|
320
330
|
*
|
|
331
|
+
* A `gone` result and a skip the provider answers withdraw the old copy before that, in a transaction of their own
|
|
332
|
+
* (`withdraw`), and so does an `expired` skip, before its application runs again: the copy's expiry moves to the
|
|
333
|
+
* store's clock, so from then on `readCurrent` answers it expired and the fence neither commits nor delivers a result
|
|
334
|
+
* derived from it, even when the purge that follows fails, as when the host's `purge` binding throws. A failing
|
|
335
|
+
* binding rolls the rest of the application back; the withdrawn copy is past its expiry, so the next `expire` or
|
|
336
|
+
* `sweepExpired` removes it, as does a later application of the read.
|
|
337
|
+
*
|
|
321
338
|
* @param prepared - The host's prepared value for a document result; null for any other result, and for a document
|
|
322
339
|
* weighed before its preparation.
|
|
323
340
|
* @returns The disposition and the handle later calls use, whose ticket reflects any purge; `pending` with the same
|
|
@@ -329,6 +346,20 @@ export declare class SqlAccountSourceSyncStore<Prepared = unknown> {
|
|
|
329
346
|
* ordered spans of a valid read and an intact copy rule out; nothing is charged or written.
|
|
330
347
|
*/
|
|
331
348
|
applyResult(h: SourceSyncHandle, work: SourceSyncWork, result: SourceSyncReadResult, prepared: Prepared | null): Promise<SourceSyncApplication | null>;
|
|
349
|
+
/** Whether the connection holds a copy of the source within its expiry, read without a lock. */
|
|
350
|
+
private holds;
|
|
351
|
+
/**
|
|
352
|
+
* Withdraws the copy the store holds of a source a read answered `gone` or skipped, in a transaction of its own,
|
|
353
|
+
* before the one that removes it: the copy's expiry, and its dependency's, move to the store's clock. `readCurrent`
|
|
354
|
+
* then answers it expired, so the fence neither commits nor delivers a result derived from it, and `expire` and
|
|
355
|
+
* `sweepExpired` remove it should the removal fail. The handle, the work item and the result are checked as
|
|
356
|
+
* `applyResult` checks them, and a copy already past its expiry is left as it is.
|
|
357
|
+
*
|
|
358
|
+
* @returns True once the copy is withdrawn or none is held within its expiry; null for a stale handle or work item.
|
|
359
|
+
* @throws {SourceSyncFault} `invalid_response` for a result that does not match its work item or a skip reason the
|
|
360
|
+
* store does not know, with nothing withdrawn.
|
|
361
|
+
*/
|
|
362
|
+
private withdraw;
|
|
332
363
|
private summary;
|
|
333
364
|
/**
|
|
334
365
|
* Records the cycle's progress, counted from its stored work and the retained documents.
|
|
@@ -399,7 +430,8 @@ export declare class SqlAccountSourceSyncStore<Prepared = unknown> {
|
|
|
399
430
|
/**
|
|
400
431
|
* The current state of each of the derivation's retained sources, read in the given transaction for the fence's
|
|
401
432
|
* commit and delivery checks; not an authorization answer of its own. An owner the host's `active` binding refuses
|
|
402
|
-
* has no sources, and a connection with a barrier or pending revalidation reads as disconnected.
|
|
433
|
+
* has no sources, and a connection with a barrier or pending revalidation reads as disconnected. A copy a `gone` read
|
|
434
|
+
* or a skip withdrew reads as expired until it is removed.
|
|
403
435
|
*/
|
|
404
436
|
readCurrent(tx: StorageAdapter, derivation: SourceDerivation): Promise<readonly SourceDependencyState[]>;
|
|
405
437
|
/** Removes the host's content and this store's provenance in the affected scope; the fence calls it inside an invalidation. */
|
|
@@ -472,7 +504,7 @@ export declare class SqlAccountSourceSyncStore<Prepared = unknown> {
|
|
|
472
504
|
* @returns How many sources were removed.
|
|
473
505
|
* @throws {Error} `invalid_sync_batch` for another limit, and the failure itself when a removal or the results'
|
|
474
506
|
* expiry fails: once a source was removed, a `SourceSyncExpiryError` with the failure's message, the failure as its
|
|
475
|
-
* `cause` and the removals made before it in `partial`.
|
|
507
|
+
* `cause` and the removals made before it in `partial`, counted in `removed` and named in `sourceIds`.
|
|
476
508
|
*/
|
|
477
509
|
expire(scope: SourceSyncScope, limit?: number): Promise<number>;
|
|
478
510
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlAccountSourceSyncStore.d.ts","sourceRoot":"","sources":["../../src/sync/SqlAccountSourceSyncStore.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SqlAccountSourceSyncStore.d.ts","sourceRoot":"","sources":["../../src/sync/SqlAccountSourceSyncStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,20 +10,34 @@ import { createSourceSyncState, transitionSourceSync, sourceSyncDue, openSourceS
|
|
|
10
10
|
import { sourceSyncTables } from './schema.js';
|
|
11
11
|
/**
|
|
12
12
|
* Thrown by `expire` when it fails after removing at least one source. Each removal committed in a transaction of its
|
|
13
|
-
* own, so `partial` counts them in `removed
|
|
14
|
-
* message this error carries.
|
|
13
|
+
* own, so `partial` counts them in `removed` and names their sources in `sourceIds`, in the order they were removed,
|
|
14
|
+
* with the failure itself in `failed`; `cause` holds the failure, whose message this error carries. The removals stand:
|
|
15
|
+
* a host that counts what `expire` removed adds `partial.removed` in its catch, as `AccountSourceSync.maintain` does.
|
|
15
16
|
*/
|
|
16
17
|
export class SourceSyncExpiryError extends Error {
|
|
17
18
|
partial;
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @param removed - How many sources were removed before the failure.
|
|
21
|
+
* @param cause - The failure.
|
|
22
|
+
* @param sourceIds - The ids of those sources, in the order they were removed; `expire` always gives them.
|
|
23
|
+
*/
|
|
24
|
+
constructor(removed, cause, sourceIds = []) {
|
|
19
25
|
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
20
26
|
this.name = 'SourceSyncExpiryError';
|
|
21
|
-
this.partial = { removed, failed: 1 };
|
|
27
|
+
this.partial = { removed, failed: 1, sourceIds: Object.freeze([...sourceIds]) };
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
class StaleSync extends Error {
|
|
25
31
|
constructor() { super('stale_source_sync'); }
|
|
26
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Thrown inside an application, before anything is written, by a read the store records as an `expired` skip while it
|
|
35
|
+
* still holds the source's copy within its expiry: the copy is withdrawn in a commit of its own and the read applied
|
|
36
|
+
* again, so a purge that fails cannot leave the copy deliverable.
|
|
37
|
+
*/
|
|
38
|
+
class WithdrawFirst extends Error {
|
|
39
|
+
constructor() { super('source_sync_withdraw_first'); }
|
|
40
|
+
}
|
|
27
41
|
const params = (s) => [s.tenantId, s.ownerId, s.connectionId];
|
|
28
42
|
const validNumber = (n) => Number.isSafeInteger(n) && n >= 0;
|
|
29
43
|
const validId = (s) => typeof s === 'string' && s.length > 0 && s.length <= 512;
|
|
@@ -113,11 +127,12 @@ const sameCopy = (stored, read) => sameText(stored, read) && stored.dependency.v
|
|
|
113
127
|
* Durable synchronization state for account sources on PostgreSQL. Every change to an owner's content runs under
|
|
114
128
|
* that owner's fence (`fence`), and a change made with a handle checks its lease, generation and host liveness in
|
|
115
129
|
* the same transaction. Applying a changed source purges its old copy and every derived result that depends on it
|
|
116
|
-
* before the replacement is written
|
|
117
|
-
*
|
|
118
|
-
* the
|
|
119
|
-
*
|
|
120
|
-
*
|
|
130
|
+
* before the replacement is written; a read that answers gone or a skip withdraws the copy in a commit of its own
|
|
131
|
+
* before purging it, so a purge that fails leaves nothing derived from it deliverable. A read that repeats the text of
|
|
132
|
+
* a copy the store holds is never charged again, one that changes it is charged, by the hash the store keeps of each
|
|
133
|
+
* message's text, its new and changed messages and the text beside them, and with the host's `refresh` binding a read
|
|
134
|
+
* of that very copy keeps it in place. Provider reads, embedding and model calls stay outside the store. The
|
|
135
|
+
* constructor runs no DDL: the host's migration runs `sourceSyncSchema` and core's `sourceDerivationSchema` first.
|
|
121
136
|
*
|
|
122
137
|
* @typeParam Prepared - The host's in-memory value for one document, passed through to its `write` binding.
|
|
123
138
|
*/
|
|
@@ -508,7 +523,7 @@ export class SqlAccountSourceSyncStore {
|
|
|
508
523
|
|| !validId(work.sourceId) || typeof text !== 'string' || text.length === 0 || text.length > 1_048_576
|
|
509
524
|
|| typeof doc.contentHash !== 'string' || !doc.contentHash || doc.contentHash.length > 512
|
|
510
525
|
|| doc.cache.kind !== 'cache' || !doc.cache.evidenceId || !validNumber(doc.cache.expiresAt)
|
|
511
|
-
||
|
|
526
|
+
|| !validNumber(doc.activityAt) || doc.activityAt > now
|
|
512
527
|
|| !doc.messages.length || doc.messages.length > 1000)
|
|
513
528
|
fail();
|
|
514
529
|
let end = 0;
|
|
@@ -572,8 +587,10 @@ export class SqlAccountSourceSyncStore {
|
|
|
572
587
|
/**
|
|
573
588
|
* Applies one read result for a work item taken in this cycle, under a live lease and the owner fence. A retry
|
|
574
589
|
* keeps the work unresolved. A document is weighed first: excluded, outside the retained limits or over the
|
|
575
|
-
* indexing allowance with the characters it adds to index, it is recorded as a skip with its reason
|
|
576
|
-
*
|
|
590
|
+
* indexing allowance with the characters it adds to index, it is recorded as a skip with its reason, and so is one
|
|
591
|
+
* whose cache lifetime has ended by the store's clock when it is weighed (`expired`), as a document admitted with
|
|
592
|
+
* seconds of it left and applied again after a longer preparation: an expired read is never refused as malformed. A
|
|
593
|
+
* document that fits replaces the source's old copy in the same transaction (host write, indexing charge and provenance),
|
|
577
594
|
* after the old copy and every result derived from it are purged, evicting this connection's older sources the
|
|
578
595
|
* limits no longer admit. A read that repeats the text and message spans of a copy the store still holds, within
|
|
579
596
|
* its expiry and window, adds nothing to index and is never charged. Any other read of such a copy adds its new and
|
|
@@ -599,6 +616,13 @@ export class SqlAccountSourceSyncStore {
|
|
|
599
616
|
* does not begin with the copy's text, so with the allowance spent it removes the thread's copy, and the thread stays
|
|
600
617
|
* out of the store until a read of it fits the allowance whole.
|
|
601
618
|
*
|
|
619
|
+
* A `gone` result and a skip the provider answers withdraw the old copy before that, in a transaction of their own
|
|
620
|
+
* (`withdraw`), and so does an `expired` skip, before its application runs again: the copy's expiry moves to the
|
|
621
|
+
* store's clock, so from then on `readCurrent` answers it expired and the fence neither commits nor delivers a result
|
|
622
|
+
* derived from it, even when the purge that follows fails, as when the host's `purge` binding throws. A failing
|
|
623
|
+
* binding rolls the rest of the application back; the withdrawn copy is past its expiry, so the next `expire` or
|
|
624
|
+
* `sweepExpired` removes it, as does a later application of the read.
|
|
625
|
+
*
|
|
602
626
|
* @param prepared - The host's prepared value for a document result; null for any other result, and for a document
|
|
603
627
|
* weighed before its preparation.
|
|
604
628
|
* @returns The disposition and the handle later calls use, whose ticket reflects any purge; `pending` with the same
|
|
@@ -610,7 +634,14 @@ export class SqlAccountSourceSyncStore {
|
|
|
610
634
|
* ordered spans of a valid read and an intact copy rule out; nothing is charged or written.
|
|
611
635
|
*/
|
|
612
636
|
async applyResult(h, work, result, prepared) {
|
|
613
|
-
|
|
637
|
+
// The purge below runs in the transaction that records the result, so a binding that throws rolls the copy's
|
|
638
|
+
// invalidation back with it. The withdrawal commits first and survives that rollback. Only this lease writes the
|
|
639
|
+
// connection's copies, so a copy not held at this read cannot appear before the purge.
|
|
640
|
+
if ((result.kind === 'gone' || result.kind === 'skipped') && await this.holds(h.lease.scope, work.sourceId)
|
|
641
|
+
&& await this.withdraw(h, work, result) === null)
|
|
642
|
+
return null;
|
|
643
|
+
// `withdrawn` once the copy of a read the weighing below finds expired has been withdrawn (`WithdrawFirst`).
|
|
644
|
+
const apply = (withdrawn) => this.withHandle(h, async (tx, row) => {
|
|
614
645
|
const s = h.lease.scope;
|
|
615
646
|
await this.currentWork(tx, s, row.checkpoint, work);
|
|
616
647
|
if (result.kind === "skipped" && !skipReasons.includes(result.reason))
|
|
@@ -668,7 +699,18 @@ export class SqlAccountSourceSyncStore {
|
|
|
668
699
|
// a negative or fractional one would mean a malformed copy, and is refused rather than charged.
|
|
669
700
|
if (!validNumber(indexed))
|
|
670
701
|
throw new Error('invalid_source_sync_charge');
|
|
671
|
-
|
|
702
|
+
// A read whose cache lifetime has ended by the time it is weighed is an ordinary expired result, never a
|
|
703
|
+
// malformed one: a document admitted with seconds of its lifetime left and prepared for longer comes back past
|
|
704
|
+
// it, and refusing it as `invalid_response` would end the run with `sync_failed`, which clears the schedule.
|
|
705
|
+
// The skip is terminal, so the cycle commits, and the source is read again when it is listed again. It removes
|
|
706
|
+
// the copy the store holds, which a skip the provider answers withdraws before the purge: the copy still within
|
|
707
|
+
// its expiry is withdrawn the same way, in a commit of its own, and the read applied again.
|
|
708
|
+
if (read.dependency.expiresAt <= now) {
|
|
709
|
+
if (!withdrawn && old !== undefined && old.dependency.expiresAt > now)
|
|
710
|
+
throw new WithdrawFirst();
|
|
711
|
+
disposition = { kind: 'skipped', reason: 'expired' };
|
|
712
|
+
}
|
|
713
|
+
else if (!selected.includes(read)) {
|
|
672
714
|
const reason = selected.length >= Math.min(row.policy.maxRetainedDocuments, maximumDocuments)
|
|
673
715
|
? 'document_limit' : 'held_limit';
|
|
674
716
|
disposition = { kind: 'skipped', reason };
|
|
@@ -739,6 +781,52 @@ export class SqlAccountSourceSyncStore {
|
|
|
739
781
|
await this.putWork(tx, s, { ...work, disposition });
|
|
740
782
|
return { handle: { ...h, ticket }, disposition };
|
|
741
783
|
});
|
|
784
|
+
try {
|
|
785
|
+
return await apply(false);
|
|
786
|
+
}
|
|
787
|
+
catch (error) {
|
|
788
|
+
if (!(error instanceof WithdrawFirst))
|
|
789
|
+
throw error;
|
|
790
|
+
if (await this.withdraw(h, work, { kind: 'skipped', id: work.sourceId, reason: 'expired' }) === null)
|
|
791
|
+
return null;
|
|
792
|
+
return apply(true);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
/** Whether the connection holds a copy of the source within its expiry, read without a lock. */
|
|
796
|
+
async holds(scope, sourceId) {
|
|
797
|
+
return !!await this.db.get(`SELECT 1 FROM ${this.t.documents} WHERE tenant_id=$1 AND owner_id=$2
|
|
798
|
+
AND connection_id=$3 AND source_id=$4 AND expires_at>$5`, [...params(scope), sourceId, this.now()]);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Withdraws the copy the store holds of a source a read answered `gone` or skipped, in a transaction of its own,
|
|
802
|
+
* before the one that removes it: the copy's expiry, and its dependency's, move to the store's clock. `readCurrent`
|
|
803
|
+
* then answers it expired, so the fence neither commits nor delivers a result derived from it, and `expire` and
|
|
804
|
+
* `sweepExpired` remove it should the removal fail. The handle, the work item and the result are checked as
|
|
805
|
+
* `applyResult` checks them, and a copy already past its expiry is left as it is.
|
|
806
|
+
*
|
|
807
|
+
* @returns True once the copy is withdrawn or none is held within its expiry; null for a stale handle or work item.
|
|
808
|
+
* @throws {SourceSyncFault} `invalid_response` for a result that does not match its work item or a skip reason the
|
|
809
|
+
* store does not know, with nothing withdrawn.
|
|
810
|
+
*/
|
|
811
|
+
async withdraw(h, work, result) {
|
|
812
|
+
return this.withHandle(h, async (tx, row) => {
|
|
813
|
+
const s = h.lease.scope;
|
|
814
|
+
await this.currentWork(tx, s, row.checkpoint, work);
|
|
815
|
+
if (result.kind === 'skipped' && !skipReasons.includes(result.reason))
|
|
816
|
+
throw new SourceSyncFault('invalid_response');
|
|
817
|
+
if (result.id !== work.sourceId)
|
|
818
|
+
throw new SourceSyncFault('invalid_response');
|
|
819
|
+
const now = this.now();
|
|
820
|
+
const held = await tx.get(`SELECT document FROM ${this.t.documents}
|
|
821
|
+
WHERE tenant_id=$1 AND owner_id=$2 AND connection_id=$3 AND source_id=$4 AND expires_at>$5`, [...params(s), work.sourceId, now]);
|
|
822
|
+
if (held) {
|
|
823
|
+
const withdrawn = { ...held.document,
|
|
824
|
+
dependency: { ...held.document.dependency, expiresAt: now } };
|
|
825
|
+
await tx.run(`UPDATE ${this.t.documents} SET document=$5::jsonb,expires_at=$6
|
|
826
|
+
WHERE tenant_id=$1 AND owner_id=$2 AND connection_id=$3 AND source_id=$4`, [...params(s), work.sourceId, JSON.stringify(withdrawn), now]);
|
|
827
|
+
}
|
|
828
|
+
return true;
|
|
829
|
+
});
|
|
742
830
|
}
|
|
743
831
|
async summary(tx, scope, cp) {
|
|
744
832
|
const rows = await tx.all(`SELECT work FROM ${this.t.work}
|
|
@@ -941,7 +1029,8 @@ export class SqlAccountSourceSyncStore {
|
|
|
941
1029
|
/**
|
|
942
1030
|
* The current state of each of the derivation's retained sources, read in the given transaction for the fence's
|
|
943
1031
|
* commit and delivery checks; not an authorization answer of its own. An owner the host's `active` binding refuses
|
|
944
|
-
* has no sources, and a connection with a barrier or pending revalidation reads as disconnected.
|
|
1032
|
+
* has no sources, and a connection with a barrier or pending revalidation reads as disconnected. A copy a `gone` read
|
|
1033
|
+
* or a skip withdrew reads as expired until it is removed.
|
|
945
1034
|
*/
|
|
946
1035
|
async readCurrent(tx, derivation) {
|
|
947
1036
|
if (!await this.options.bindings.active(tx, derivation))
|
|
@@ -1207,7 +1296,7 @@ export class SqlAccountSourceSyncStore {
|
|
|
1207
1296
|
* @returns How many sources were removed.
|
|
1208
1297
|
* @throws {Error} `invalid_sync_batch` for another limit, and the failure itself when a removal or the results'
|
|
1209
1298
|
* expiry fails: once a source was removed, a `SourceSyncExpiryError` with the failure's message, the failure as its
|
|
1210
|
-
* `cause` and the removals made before it in `partial`.
|
|
1299
|
+
* `cause` and the removals made before it in `partial`, counted in `removed` and named in `sourceIds`.
|
|
1211
1300
|
*/
|
|
1212
1301
|
async expire(scope, limit = 100) {
|
|
1213
1302
|
if (!Number.isInteger(limit) || limit < 1 || limit > 1000)
|
|
@@ -1215,18 +1304,18 @@ export class SqlAccountSourceSyncStore {
|
|
|
1215
1304
|
const rows = await this.db.all(`SELECT source_id FROM ${this.t.documents}
|
|
1216
1305
|
WHERE tenant_id=$1 AND owner_id=$2 AND connection_id=$3 AND expires_at <= $4
|
|
1217
1306
|
ORDER BY expires_at,source_id LIMIT $5`, [...params(scope), this.now(), limit]);
|
|
1218
|
-
|
|
1307
|
+
const removed = [];
|
|
1219
1308
|
try {
|
|
1220
1309
|
for (const row of rows)
|
|
1221
1310
|
if (await this.expireSource(scope, row.source_id))
|
|
1222
|
-
removed
|
|
1311
|
+
removed.push(row.source_id);
|
|
1223
1312
|
await this.fence.expireResults(scope, limit);
|
|
1224
1313
|
}
|
|
1225
1314
|
catch (error) {
|
|
1226
|
-
// The removals before the failure have committed, so their count
|
|
1227
|
-
throw removed > 0 ? new SourceSyncExpiryError(removed, error) : error;
|
|
1315
|
+
// The removals before the failure have committed, so their count and their sources go to the caller with it.
|
|
1316
|
+
throw removed.length > 0 ? new SourceSyncExpiryError(removed.length, error, removed) : error;
|
|
1228
1317
|
}
|
|
1229
|
-
return removed;
|
|
1318
|
+
return removed.length;
|
|
1230
1319
|
}
|
|
1231
1320
|
/**
|
|
1232
1321
|
* Removes one retained source whose expiry has passed, with every result derived from it, under its owner's row
|