Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { assert } from "@fluidframework/core-utils/internal";
import type { IIdCompressor } from "@fluidframework/id-compressor";
import { isFinalId } from "@fluidframework/id-compressor/internal";

import type { CodecAndSchema, IJsonCodec } from "../../codec/index.js";
import { brand } from "../../util/index.js";
Expand Down Expand Up @@ -46,15 +47,15 @@ class MajorCodec implements IJsonCodec<Major, EncodedRevisionTag> {
* The assert below will fail in such a scenario. This is addressed in the v2 codec.
*/
assert(
id === "root" || id >= 0,
id === "root" || isFinalId(id),
0x88f /* Expected final id on encode of detached field index revision */,
);
return id;
}

public decode(major: EncodedRevisionTag): RevisionTag {
assert(
major === "root" || major >= 0,
major === "root" || isFinalId(major),
0x890 /* Expected final id on decode of detached field index revision */,
);
return this.revisionTagCodec.decode(major, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { assert } from "@fluidframework/core-utils/internal";
import type { IIdCompressor, StableId } from "@fluidframework/id-compressor";
import { isStableId } from "@fluidframework/id-compressor/internal";
import { isFinalId, isStableId } from "@fluidframework/id-compressor/internal";

import type { CodecAndSchema, IJsonCodec } from "../../codec/index.js";
import type { EncodedRevisionTag, RevisionTagCodec, RevisionTag } from "../rebase/index.js";
Expand All @@ -25,7 +25,7 @@ class MajorCodec implements IJsonCodec<Major> {
assert(major !== undefined, 0xbfb /* Unexpected undefined revision */);
const id = this.revisionTagCodec.encode(major);

if (id !== "root" && id < 0) {
if (id !== "root" && !isFinalId(id)) {
/**
* This code path handles the case where the major revision is not finalized.
* This can happen the SharedTree is being attached to an already attached container.
Expand All @@ -39,7 +39,9 @@ class MajorCodec implements IJsonCodec<Major> {

public decode(major: EncodedRevisionTag | StableId): RevisionTag {
assert(
major === "root" || (typeof major === "string" && isStableId(major)) || major >= 0,
major === "root" ||
(typeof major === "string" && isStableId(major)) ||
(typeof major === "number" && isFinalId(major)),
0xbfd /* Expected root, stable, or final compressed id */,
);
if (typeof major === "string" && isStableId(major)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
OpSpaceCompressedId,
SessionId,
} from "@fluidframework/id-compressor";
import { isFinalId } from "@fluidframework/id-compressor/internal";
import { v5 as uuidV5 } from "uuid";

import { DiscriminatedUnionDispatcher } from "../../../codec/index.js";
Expand Down Expand Up @@ -153,8 +154,10 @@ export function readValue(
const idCompressor = idDecodingContext.idCompressor;
// OpSpaceCompressedIds are negative, and require a session-id to compute their value.
// Due to a bug, we have some special casing for them (see below).
// TODO: isFinalId should probably be exported from id-compressor and that could be used to do the narrowing here.
if (idDecodingContext.isSummary === true && streamValue < 0) {
if (
idDecodingContext.isSummary === true &&
!isFinalId(streamValue as OpSpaceCompressedId)
) {
if (
idDecodingContext.healUnresolvableIdentifiersOnDecode === true &&
idDecodingContext.sharedObjectId !== undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { assert, fail } from "@fluidframework/core-utils/internal";
import { isStableId } from "@fluidframework/id-compressor/internal";
import { isFinalId, isStableId } from "@fluidframework/id-compressor/internal";

import {
type FieldKey,
Expand Down Expand Up @@ -82,8 +82,7 @@ export class NodeShapeBasedEncoder
// This is not the case for forest summaries at the time of writing, so non-finalized ids are instead written using
// their long form (by falling through to the original cursor value).
// A scenario where such ids can appear in the summary is in the attach summary of a tree being attached to an already-attached container.
// TODO: isFinalId should probably be exported from id-compressor and that could be used to do the narrowing here.
if (!context.isSummary || opSpaceId >= 0) {
if (!context.isSummary || isFinalId(opSpaceId)) {
return opSpaceId;
}
}
Expand Down
10 changes: 10 additions & 0 deletions packages/runtime/id-compressor/src/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { OpSpaceCompressedId, SessionSpaceCompressedId } from "./types/inde
/**
* A compressed ID that is stable and unique within the scope of network of compressors (i.e. a document).
* It can only be used/decompressed in the context of the originating document.
* @internal
*/
export type FinalCompressedId = number & {
readonly FinalCompressedId: "5d83d1e2-98b7-4e4e-a889-54c855cfa73d";
Expand All @@ -27,6 +28,15 @@ export type LocalCompressedId = number & {

/**
* Returns true if the supplied ID is a final ID.
* @internal
* @privateRemarks
* This should generally not be necessary to use outside of the id-compressor package. It is exported for backwards compatibility for format
* choices made in SharedTree (so they can more clearly document their intent).
* In general, users of IdCompressor should not care if their ids are finalized or not. They should persist short IDs with the context of the
* originator's session ID if it cannot be guaranteed that the ID is finalized.
*
* Note that the bad assumption that made exporting this function necessary is that all IDs in summaries are finalized. This is not necessarily
* the case when an attach summary is generated for a DDS attaching to an already-attached container.
*/
export function isFinalId(
id: SessionSpaceCompressedId | OpSpaceCompressedId,
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/id-compressor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export {
serializeIdCompressor,
toIdCompressorWithCore,
} from "./idCompressor.js";
export { type FinalCompressedId, isFinalId } from "./identifiers.js";
export {
createSessionId,
assertIsStableId,
Expand Down
Loading