@recordtimelabel/core 0.6.14 → 0.6.16
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 +2 -2
- package/package.json +1 -1
- package/src/index.js +97 -25
package/README.md
CHANGED
|
@@ -17,10 +17,10 @@ During local development an app can consume a sibling checkout with:
|
|
|
17
17
|
"@recordtimelabel/core": "file:../recordtimelabel-core"
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
For release builds, consume a fixed npm package, git tag, or private registry version so builds do not depend on a sibling folder path. The release target is `0.6.
|
|
20
|
+
For release builds, consume a fixed npm package, git tag, or private registry version so builds do not depend on a sibling folder path. The release target is `0.6.16`; verify that its registry tarball and lockfile integrity are available before updating consumers:
|
|
21
21
|
|
|
22
22
|
```json
|
|
23
|
-
"@recordtimelabel/core": "0.6.
|
|
23
|
+
"@recordtimelabel/core": "0.6.16"
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
If this checkout's `package.json` is ahead of the published version, publish the new package before updating consumers to that version.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -147,7 +147,7 @@ export {
|
|
|
147
147
|
selectBestMatchingTwitchVod
|
|
148
148
|
};
|
|
149
149
|
|
|
150
|
-
export const RECORD_TIMELABEL_CORE_VERSION = '0.6.
|
|
150
|
+
export const RECORD_TIMELABEL_CORE_VERSION = '0.6.16';
|
|
151
151
|
export const RTL_SYNC_PROTOCOL_VERSION = 2;
|
|
152
152
|
export const RECORD_TIMELABEL_DURABLE_ENGINE_CAPABILITIES = Object.freeze([
|
|
153
153
|
'fifo-retry-fence',
|
|
@@ -3660,7 +3660,11 @@ const rtlClearBootstrapResumeMeta = (syncMeta) => {
|
|
|
3660
3660
|
};
|
|
3661
3661
|
|
|
3662
3662
|
const rtlRebindSameOwnerWorkspaceEpoch = (workspace, captured, now) => {
|
|
3663
|
-
const ownerUid = rtlNormalizeUid(
|
|
3663
|
+
const ownerUid = rtlNormalizeUid(
|
|
3664
|
+
captured?.localOnly
|
|
3665
|
+
? (captured?.retainedOwnerUid || captured?.ownerUid || captured?.uid)
|
|
3666
|
+
: captured?.uid
|
|
3667
|
+
);
|
|
3664
3668
|
const workspaceEpoch = rtlNormalizeWorkspaceEpoch(captured?.workspaceEpoch, 0);
|
|
3665
3669
|
const next = clone(workspace);
|
|
3666
3670
|
next.ownerUid = ownerUid;
|
|
@@ -4013,6 +4017,7 @@ const rtlSessionContext = (captured, workspace, client) => ({
|
|
|
4013
4017
|
uid: captured?.uid ?? (captured?.hasSession ? null : workspace?.ownerUid ?? null),
|
|
4014
4018
|
ownerUid: captured?.uid ?? (captured?.hasSession ? null : workspace?.ownerUid ?? null),
|
|
4015
4019
|
workspaceEpoch: workspace?.workspaceEpoch ?? captured?.workspaceEpoch ?? 0,
|
|
4020
|
+
localOnly: captured?.localOnly === true,
|
|
4016
4021
|
client: clone(client)
|
|
4017
4022
|
});
|
|
4018
4023
|
|
|
@@ -4386,7 +4391,7 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
4386
4391
|
}
|
|
4387
4392
|
};
|
|
4388
4393
|
|
|
4389
|
-
const normalizeBootstrapResponse = (response) => {
|
|
4394
|
+
const normalizeBootstrapResponse = (response, context = null) => {
|
|
4390
4395
|
if (!rtlEnvelopeSuccess(response)) {
|
|
4391
4396
|
const source = response && typeof response === 'object' ? response : {
|
|
4392
4397
|
message: 'recordtimelabel_bootstrap_failed',
|
|
@@ -4397,6 +4402,14 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
4397
4402
|
}
|
|
4398
4403
|
const remote = rtlEnvelopePayload(response);
|
|
4399
4404
|
if (remote?.localOnly === true) {
|
|
4405
|
+
if (context?.localOnly !== true) {
|
|
4406
|
+
throw toRecordTimeLabelCloudFailureError({
|
|
4407
|
+
code: 'recordtimelabel_invalid_bootstrap_response',
|
|
4408
|
+
reason: 'recordtimelabel_invalid_bootstrap_response',
|
|
4409
|
+
message: 'recordtimelabel_invalid_bootstrap_response',
|
|
4410
|
+
retryable: false
|
|
4411
|
+
});
|
|
4412
|
+
}
|
|
4400
4413
|
const localState = remote.state ?? remote.data;
|
|
4401
4414
|
if (!rtlDurableIsObject(localState)) {
|
|
4402
4415
|
throw toRecordTimeLabelCloudFailureError({
|
|
@@ -4436,7 +4449,7 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
4436
4449
|
const runBootstrapAttempt = async (context, mode) => {
|
|
4437
4450
|
const options = bootstrapAttemptOptions(mode, context);
|
|
4438
4451
|
try {
|
|
4439
|
-
const baseline = normalizeBootstrapResponse(await cloud.bootstrap(context, options));
|
|
4452
|
+
const baseline = normalizeBootstrapResponse(await cloud.bootstrap(context, options), context);
|
|
4440
4453
|
clearBootstrapAttempt(mode, options);
|
|
4441
4454
|
return baseline;
|
|
4442
4455
|
} catch (error) {
|
|
@@ -4534,7 +4547,7 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
4534
4547
|
...createBootstrapAttemptOptions(`${mode}-catchup`)
|
|
4535
4548
|
});
|
|
4536
4549
|
if (rtlEnvelopeSuccess(caught)) {
|
|
4537
|
-
return requireBootstrapRevision(normalizeBootstrapResponse(caught), targetRevision);
|
|
4550
|
+
return requireBootstrapRevision(normalizeBootstrapResponse(caught, context), targetRevision);
|
|
4538
4551
|
}
|
|
4539
4552
|
const failure = normalizeRecordTimeLabelCloudFailure(caught);
|
|
4540
4553
|
if (failure.class !== RECORD_TIMELABEL_CLOUD_FAILURE_CLASSES.BOOTSTRAP_REQUIRED) {
|
|
@@ -4570,6 +4583,9 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
4570
4583
|
const sourceOwnerUid = rtlNormalizeUid(source.ownerUid);
|
|
4571
4584
|
const sourcePending = toArray(source.pendingOperations ?? source.pendingOps);
|
|
4572
4585
|
const sourceHasBoundOperation = sourcePending.some((operation) => rtlNormalizeUid(operation?.ownerUid));
|
|
4586
|
+
const currentUid = captured?.localOnly
|
|
4587
|
+
? (captured?.retainedOwnerUid || captured?.ownerUid || null)
|
|
4588
|
+
: captured?.uid;
|
|
4573
4589
|
const loadedWorkspace = rtlNormalizeDurableWorkspace(
|
|
4574
4590
|
hasDurableShape ? source : {
|
|
4575
4591
|
...source,
|
|
@@ -4578,15 +4594,12 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
4578
4594
|
syncMeta: source.syncMeta || {}
|
|
4579
4595
|
},
|
|
4580
4596
|
{
|
|
4581
|
-
ownerUid:
|
|
4597
|
+
ownerUid: currentUid,
|
|
4582
4598
|
workspaceEpoch: captured?.workspaceEpoch,
|
|
4583
4599
|
client,
|
|
4584
4600
|
now
|
|
4585
4601
|
}
|
|
4586
4602
|
);
|
|
4587
|
-
const currentUid = captured?.localOnly
|
|
4588
|
-
? (captured?.retainedOwnerUid || captured?.ownerUid || null)
|
|
4589
|
-
: captured?.uid;
|
|
4590
4603
|
const currentEpoch = captured?.workspaceEpoch ?? loadedWorkspace.workspaceEpoch;
|
|
4591
4604
|
const anonymousMigration = Boolean(
|
|
4592
4605
|
currentUid &&
|
|
@@ -5343,6 +5356,8 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5343
5356
|
let firstRootObservation = null;
|
|
5344
5357
|
let latestRootObservationRevision = null;
|
|
5345
5358
|
let adapterCatchUpProof = null;
|
|
5359
|
+
let processedRootRevisionProof = null;
|
|
5360
|
+
let inFlightRemoteCallbacks = 0;
|
|
5346
5361
|
const settleReadyIfProven = () => {
|
|
5347
5362
|
if (!isCurrentRemoteReady(readyState) || readyState.settled ||
|
|
5348
5363
|
!firstRootObservation || (adapterReadyExpected && !adapterCatchUpProof)) {
|
|
@@ -5352,12 +5367,32 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5352
5367
|
? workspace.remoteBaseline.revision
|
|
5353
5368
|
: 0;
|
|
5354
5369
|
const proof = adapterCatchUpProof || {};
|
|
5355
|
-
const
|
|
5370
|
+
const proofRev = proof.revision !== undefined ? Number(proof.revision) : null;
|
|
5371
|
+
const proofCaughtUp = proof.caughtUpToRevision !== undefined ? Number(proof.caughtUpToRevision) : null;
|
|
5372
|
+
if (
|
|
5373
|
+
(proofRev !== null && (!Number.isSafeInteger(proofRev) || proofRev < 0)) ||
|
|
5374
|
+
(proofCaughtUp !== null && (!Number.isSafeInteger(proofCaughtUp) || proofCaughtUp < 0))
|
|
5375
|
+
) {
|
|
5376
|
+
readyState.reject(toRecordTimeLabelCloudFailureError({
|
|
5377
|
+
class: RECORD_TIMELABEL_CLOUD_FAILURE_CLASSES.TERMINAL,
|
|
5378
|
+
code: 'invalid_remote_ready_revision',
|
|
5379
|
+
reason: 'invalid_remote_ready_revision',
|
|
5380
|
+
message: 'invalid_remote_ready_revision'
|
|
5381
|
+
}));
|
|
5382
|
+
return;
|
|
5383
|
+
}
|
|
5384
|
+
const rawRevision = Number.isSafeInteger(Number(proof.revision))
|
|
5356
5385
|
? Number(proof.revision)
|
|
5357
5386
|
: baselineRevision;
|
|
5358
|
-
const
|
|
5387
|
+
const rawCaughtUpToRevision = Number.isSafeInteger(Number(proof.caughtUpToRevision))
|
|
5359
5388
|
? Number(proof.caughtUpToRevision)
|
|
5360
|
-
:
|
|
5389
|
+
: rawRevision;
|
|
5390
|
+
const revision = Number.isSafeInteger(processedRootRevisionProof)
|
|
5391
|
+
? Math.max(rawRevision, processedRootRevisionProof)
|
|
5392
|
+
: rawRevision;
|
|
5393
|
+
const caughtUpToRevision = Number.isSafeInteger(processedRootRevisionProof)
|
|
5394
|
+
? Math.max(rawCaughtUpToRevision, processedRootRevisionProof)
|
|
5395
|
+
: rawCaughtUpToRevision;
|
|
5361
5396
|
if (revision < 0 || caughtUpToRevision < 0) {
|
|
5362
5397
|
readyState.reject(toRecordTimeLabelCloudFailureError({
|
|
5363
5398
|
class: RECORD_TIMELABEL_CLOUD_FAILURE_CLASSES.TERMINAL,
|
|
@@ -5372,6 +5407,7 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5372
5407
|
: baselineRevision;
|
|
5373
5408
|
const requiredRevision = Math.max(baselineRevision, observedRevision);
|
|
5374
5409
|
if (revision < requiredRevision || caughtUpToRevision < requiredRevision) {
|
|
5410
|
+
if (inFlightRemoteCallbacks > 0) return;
|
|
5375
5411
|
readyState.reject(toRecordTimeLabelCloudFailureError({
|
|
5376
5412
|
class: RECORD_TIMELABEL_CLOUD_FAILURE_CLASSES.TERMINAL,
|
|
5377
5413
|
code: 'stale_remote_ready_revision',
|
|
@@ -5407,6 +5443,13 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5407
5443
|
return;
|
|
5408
5444
|
}
|
|
5409
5445
|
firstRootObservation = result || {success: true};
|
|
5446
|
+
const rootPersistedRevision = Number(workspace?.remoteBaseline?.revision);
|
|
5447
|
+
if (Number.isSafeInteger(rootPersistedRevision)) {
|
|
5448
|
+
processedRootRevisionProof = Math.max(
|
|
5449
|
+
processedRootRevisionProof ?? 0,
|
|
5450
|
+
rootPersistedRevision
|
|
5451
|
+
);
|
|
5452
|
+
}
|
|
5410
5453
|
if (Number.isSafeInteger(observedRevision) && observedRevision >= 0) {
|
|
5411
5454
|
latestRootObservationRevision = Math.max(
|
|
5412
5455
|
latestRootObservationRevision ?? 0,
|
|
@@ -5448,14 +5491,21 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5448
5491
|
const observedRevision = Number.isSafeInteger(observedRevisionValue) && observedRevisionValue >= 0
|
|
5449
5492
|
? observedRevisionValue
|
|
5450
5493
|
: null;
|
|
5494
|
+
inFlightRemoteCallbacks += 1;
|
|
5451
5495
|
const callbackResult = enqueue(() => processRemote(remoteValue, captured));
|
|
5452
5496
|
if (!firstCallbackResult) firstCallbackResult = callbackResult;
|
|
5453
|
-
callbackResult
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5497
|
+
callbackResult
|
|
5498
|
+
.then((result) => handleRootObservation(result, observedRevision))
|
|
5499
|
+
.catch((error) => {
|
|
5500
|
+
if (isCurrentRemoteReady(readyState) && !readyState.settled) {
|
|
5501
|
+
readyState.reject(error);
|
|
5502
|
+
}
|
|
5503
|
+
logger?.error?.('[RecordTimeLabelCore] durable remote callback failed', error);
|
|
5504
|
+
})
|
|
5505
|
+
.finally(() => {
|
|
5506
|
+
inFlightRemoteCallbacks -= 1;
|
|
5507
|
+
settleReadyIfProven();
|
|
5508
|
+
});
|
|
5459
5509
|
return callbackResult;
|
|
5460
5510
|
};
|
|
5461
5511
|
let disposer;
|
|
@@ -5500,19 +5550,40 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5500
5550
|
}
|
|
5501
5551
|
));
|
|
5502
5552
|
} else {
|
|
5553
|
+
const rawRev = result?.revision;
|
|
5554
|
+
const rawCaughtUp = result?.caughtUpToRevision;
|
|
5555
|
+
if (
|
|
5556
|
+
(rawRev !== undefined && (!Number.isSafeInteger(Number(rawRev)) || Number(rawRev) < 0)) ||
|
|
5557
|
+
(rawCaughtUp !== undefined && (!Number.isSafeInteger(Number(rawCaughtUp)) || Number(rawCaughtUp) < 0))
|
|
5558
|
+
) {
|
|
5559
|
+
readyState.reject(toRecordTimeLabelCloudFailureError({
|
|
5560
|
+
class: RECORD_TIMELABEL_CLOUD_FAILURE_CLASSES.TERMINAL,
|
|
5561
|
+
code: 'invalid_remote_ready_revision',
|
|
5562
|
+
reason: 'invalid_remote_ready_revision',
|
|
5563
|
+
message: 'invalid_remote_ready_revision'
|
|
5564
|
+
}));
|
|
5565
|
+
return;
|
|
5566
|
+
}
|
|
5503
5567
|
const nextProof = result && typeof result === 'object'
|
|
5504
5568
|
? {...result, success: true}
|
|
5505
5569
|
: {success: true};
|
|
5506
5570
|
const currentRevision = Number(adapterCatchUpProof?.revision);
|
|
5507
5571
|
const currentCaughtUp = Number(adapterCatchUpProof?.caughtUpToRevision);
|
|
5572
|
+
const provedRevision = Number.isSafeInteger(processedRootRevisionProof)
|
|
5573
|
+
? processedRootRevisionProof
|
|
5574
|
+
: null;
|
|
5508
5575
|
adapterCatchUpProof = {
|
|
5509
5576
|
...nextProof,
|
|
5510
|
-
|
|
5511
|
-
?
|
|
5512
|
-
:
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5577
|
+
revision: Math.max(
|
|
5578
|
+
Number.isSafeInteger(currentRevision) ? currentRevision : 0,
|
|
5579
|
+
Number.isSafeInteger(Number(nextProof.revision)) ? Number(nextProof.revision) : 0,
|
|
5580
|
+
provedRevision ?? 0
|
|
5581
|
+
),
|
|
5582
|
+
caughtUpToRevision: Math.max(
|
|
5583
|
+
Number.isSafeInteger(currentCaughtUp) ? currentCaughtUp : 0,
|
|
5584
|
+
Number.isSafeInteger(Number(nextProof.caughtUpToRevision)) ? Number(nextProof.caughtUpToRevision) : 0,
|
|
5585
|
+
provedRevision ?? 0
|
|
5586
|
+
)
|
|
5516
5587
|
};
|
|
5517
5588
|
settleReadyIfProven();
|
|
5518
5589
|
}
|
|
@@ -5765,7 +5836,8 @@ export const createRecordTimeLabelSyncEngine = ({
|
|
|
5765
5836
|
}
|
|
5766
5837
|
if (!(await isCurrent(captured))) return {success: false, reason: 'stale_session'};
|
|
5767
5838
|
if (!workspaceMatchesSession(captured)) {
|
|
5768
|
-
resetForSessionIdentity(captured);
|
|
5839
|
+
const transition = resetForSessionIdentity(captured);
|
|
5840
|
+
if (transition?.stale) return transition;
|
|
5769
5841
|
return {success: false, code: 'recordtimelabel_hydration_required'};
|
|
5770
5842
|
}
|
|
5771
5843
|
const blockedFailure = workspace.syncMeta?.terminalFailureBlock;
|