@recordtimelabel/core 0.6.13 → 0.6.15

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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/src/index.js +36 -20
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.13`; verify that its registry tarball and lockfile integrity are available before updating consumers:
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.15`; verify that its registry tarball and lockfile integrity are available before updating consumers:
21
21
 
22
22
  ```json
23
- "@recordtimelabel/core": "0.6.13"
23
+ "@recordtimelabel/core": "0.6.15"
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recordtimelabel/core",
3
- "version": "0.6.13",
3
+ "version": "0.6.15",
4
4
  "type": "module",
5
5
  "description": "Shared RecordTimeLabel data model, merge logic, operations, and sync engine.",
6
6
  "main": "./src/index.js",
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.13';
150
+ export const RECORD_TIMELABEL_CORE_VERSION = '0.6.15';
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(captured?.uid);
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: captured?.uid,
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 &&
@@ -5417,16 +5430,18 @@ export const createRecordTimeLabelSyncEngine = ({
5417
5430
  // have resolved earlier with an older revision.
5418
5431
  const currentRevision = Number(adapterCatchUpProof?.revision);
5419
5432
  const currentCaughtUp = Number(adapterCatchUpProof?.caughtUpToRevision);
5420
- adapterCatchUpProof = {
5421
- ...(adapterCatchUpProof || {}),
5422
- success: true,
5423
- revision: Number.isSafeInteger(currentRevision)
5424
- ? Math.max(currentRevision, observedRevision)
5425
- : observedRevision,
5426
- caughtUpToRevision: Number.isSafeInteger(currentCaughtUp)
5427
- ? Math.max(currentCaughtUp, observedRevision)
5428
- : observedRevision
5429
- };
5433
+ if (adapterCatchUpProof) {
5434
+ adapterCatchUpProof = {
5435
+ ...adapterCatchUpProof,
5436
+ success: true,
5437
+ revision: Number.isSafeInteger(currentRevision)
5438
+ ? Math.max(currentRevision, observedRevision)
5439
+ : observedRevision,
5440
+ caughtUpToRevision: Number.isSafeInteger(currentCaughtUp)
5441
+ ? Math.max(currentCaughtUp, observedRevision)
5442
+ : observedRevision
5443
+ };
5444
+ }
5430
5445
  }
5431
5446
  if (!adapterReadyExpected) {
5432
5447
  adapterCatchUpProof = {
@@ -5763,7 +5778,8 @@ export const createRecordTimeLabelSyncEngine = ({
5763
5778
  }
5764
5779
  if (!(await isCurrent(captured))) return {success: false, reason: 'stale_session'};
5765
5780
  if (!workspaceMatchesSession(captured)) {
5766
- resetForSessionIdentity(captured);
5781
+ const transition = resetForSessionIdentity(captured);
5782
+ if (transition?.stale) return transition;
5767
5783
  return {success: false, code: 'recordtimelabel_hydration_required'};
5768
5784
  }
5769
5785
  const blockedFailure = workspace.syncMeta?.terminalFailureBlock;