@fluidframework/id-compressor 3.2.0 → 3.3.0

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 (102) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/api-report/id-compressor.legacy.beta.api.md +0 -49
  3. package/dist/idCompressor.d.ts +69 -19
  4. package/dist/idCompressor.d.ts.map +1 -1
  5. package/dist/idCompressor.js +365 -57
  6. package/dist/idCompressor.js.map +1 -1
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/legacy.d.ts +1 -12
  12. package/dist/packageVersion.d.ts +1 -1
  13. package/dist/packageVersion.js +1 -1
  14. package/dist/packageVersion.js.map +1 -1
  15. package/dist/test/idCompressor.perf.spec.js.map +1 -1
  16. package/dist/test/idCompressor.spec.js.map +1 -1
  17. package/dist/test/idCompressorTestUtilities.d.ts.map +1 -1
  18. package/dist/test/idCompressorTestUtilities.js +8 -3
  19. package/dist/test/idCompressorTestUtilities.js.map +1 -1
  20. package/dist/test/sharding.fuzz.spec.d.ts +6 -0
  21. package/dist/test/sharding.fuzz.spec.d.ts.map +1 -0
  22. package/dist/test/sharding.fuzz.spec.js.map +1 -0
  23. package/dist/test/sharding.spec.d.ts +6 -0
  24. package/dist/test/sharding.spec.d.ts.map +1 -0
  25. package/dist/test/sharding.spec.js.map +1 -0
  26. package/dist/test/snapshots/summary.spec.js.map +1 -1
  27. package/dist/test/types/validateIdCompressorPrevious.generated.js.map +1 -1
  28. package/dist/types/idCompressor.d.ts +108 -2
  29. package/dist/types/idCompressor.d.ts.map +1 -1
  30. package/dist/types/idCompressor.js +15 -0
  31. package/dist/types/idCompressor.js.map +1 -1
  32. package/dist/types/index.d.ts +2 -1
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/types/index.js +3 -0
  35. package/dist/types/index.js.map +1 -1
  36. package/dist/types/persisted-types/0.0.1.d.ts +4 -4
  37. package/dist/types/persisted-types/0.0.1.js.map +1 -1
  38. package/dist/utilities.d.ts +1 -1
  39. package/dist/utilities.js +1 -1
  40. package/dist/utilities.js.map +1 -1
  41. package/lib/idCompressor.d.ts +69 -19
  42. package/lib/idCompressor.d.ts.map +1 -1
  43. package/lib/idCompressor.js +365 -57
  44. package/lib/idCompressor.js.map +1 -1
  45. package/lib/index.d.ts +2 -1
  46. package/lib/index.d.ts.map +1 -1
  47. package/lib/index.js +1 -0
  48. package/lib/index.js.map +1 -1
  49. package/lib/legacy.d.ts +1 -12
  50. package/lib/packageVersion.d.ts +1 -1
  51. package/lib/packageVersion.js +1 -1
  52. package/lib/packageVersion.js.map +1 -1
  53. package/lib/test/idCompressor.perf.spec.js.map +1 -1
  54. package/lib/test/idCompressor.spec.js.map +1 -1
  55. package/lib/test/idCompressorTestUtilities.d.ts.map +1 -1
  56. package/lib/test/idCompressorTestUtilities.js +8 -3
  57. package/lib/test/idCompressorTestUtilities.js.map +1 -1
  58. package/lib/test/sharding.fuzz.spec.d.ts +6 -0
  59. package/lib/test/sharding.fuzz.spec.d.ts.map +1 -0
  60. package/lib/test/sharding.fuzz.spec.js.map +1 -0
  61. package/lib/test/sharding.spec.d.ts +6 -0
  62. package/lib/test/sharding.spec.d.ts.map +1 -0
  63. package/lib/test/sharding.spec.js.map +1 -0
  64. package/lib/test/snapshots/summary.spec.js.map +1 -1
  65. package/lib/test/types/validateIdCompressorPrevious.generated.js.map +1 -1
  66. package/lib/types/idCompressor.d.ts +108 -2
  67. package/lib/types/idCompressor.d.ts.map +1 -1
  68. package/lib/types/idCompressor.js +14 -1
  69. package/lib/types/idCompressor.js.map +1 -1
  70. package/lib/types/index.d.ts +2 -1
  71. package/lib/types/index.d.ts.map +1 -1
  72. package/lib/types/index.js +1 -1
  73. package/lib/types/index.js.map +1 -1
  74. package/lib/types/persisted-types/0.0.1.d.ts +4 -4
  75. package/lib/types/persisted-types/0.0.1.js.map +1 -1
  76. package/lib/utilities.d.ts +1 -1
  77. package/lib/utilities.js +1 -1
  78. package/lib/utilities.js.map +1 -1
  79. package/package.json +42 -9
  80. package/src/idCompressor.ts +497 -73
  81. package/src/index.ts +3 -0
  82. package/src/packageVersion.ts +1 -1
  83. package/src/test/idCompressorTestUtilities.ts +16 -3
  84. package/src/test/snapshots/v2/compressor-with-finalized-range-from-one-client +1 -0
  85. package/src/test/snapshots/v2/compressor-with-finalized-range-from-one-client-client2 +1 -0
  86. package/src/test/snapshots/v2/compressors-with-finalized-ranges-from-two-clients +1 -0
  87. package/src/test/snapshots/v2/compressors-with-finalized-ranges-from-two-clients-client2 +1 -0
  88. package/src/test/snapshots/v2/empty-compressor-summary +1 -0
  89. package/src/test/snapshots/v2/expansion-semantics +1 -0
  90. package/src/test/snapshots/v2/expansion-semantics-client2 +1 -0
  91. package/src/test/snapshots/v3/compressor-with-finalized-range-from-one-client +1 -0
  92. package/src/test/snapshots/v3/compressor-with-finalized-range-from-one-client-client2 +1 -0
  93. package/src/test/snapshots/v3/compressors-with-finalized-ranges-from-two-clients +1 -0
  94. package/src/test/snapshots/v3/compressors-with-finalized-ranges-from-two-clients-client2 +1 -0
  95. package/src/test/snapshots/v3/empty-compressor-summary +1 -0
  96. package/src/test/snapshots/v3/expansion-semantics +1 -0
  97. package/src/test/snapshots/v3/expansion-semantics-client2 +1 -0
  98. package/src/test/types/validateIdCompressorPrevious.generated.ts +13 -1
  99. package/src/types/idCompressor.ts +119 -2
  100. package/src/types/index.ts +10 -1
  101. package/src/types/persisted-types/0.0.1.ts +4 -4
  102. package/src/utilities.ts +1 -1
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ export {
13
13
  serializeIdCompressor,
14
14
  toIdCompressorWithCore,
15
15
  } from "./idCompressor.js";
16
+ export { SerializationVersion } from "./types/index.js";
16
17
  export { type FinalCompressedId, isFinalId } from "./identifiers.js";
17
18
  export {
18
19
  createSessionId,
@@ -31,4 +32,6 @@ export type {
31
32
  SessionId,
32
33
  StableId,
33
34
  IdCreationRange,
35
+ ShardToken,
36
+ ShardSynchronizationToken,
34
37
  } from "./types/index.js";
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/id-compressor";
9
- export const pkgVersion = "3.2.0";
9
+ export const pkgVersion = "3.3.0";
@@ -33,6 +33,7 @@ import {
33
33
  toIdCompressorWithCore,
34
34
  } from "../index.js";
35
35
  import { SessionSpaceNormalizer } from "../sessionSpaceNormalizer.js";
36
+ import { SerializationVersion } from "../types/index.js";
36
37
  import { assertIsSessionId, createSessionId, localIdFromGenCount } from "../utilities.js";
37
38
 
38
39
  import {
@@ -113,7 +114,11 @@ export class CompressorFactory {
113
114
  clusterCapacity = 5,
114
115
  logger?: ITelemetryBaseLogger,
115
116
  ): IdCompressor {
116
- const compressor = createIdCompressor(sessionId, logger) as IdCompressor;
117
+ const compressor = createIdCompressor(
118
+ sessionId,
119
+ SerializationVersion.V3,
120
+ logger,
121
+ ) as IdCompressor;
117
122
  modifyClusterSize(compressor, clusterCapacity);
118
123
  return compressor;
119
124
  }
@@ -732,7 +737,10 @@ export function roundtrip(
732
737
  const capacity: number = getClusterSize(compressor);
733
738
  if (withSession) {
734
739
  const serialized = compressor.serialize(withSession);
735
- const roundtripped = IdCompressor.deserialize({ serialized });
740
+ const roundtripped = IdCompressor.deserialize({
741
+ serialized,
742
+ requestedWriteVersion: SerializationVersion.V3,
743
+ });
736
744
  modifyClusterSize(roundtripped, capacity);
737
745
  return [serialized, roundtripped];
738
746
  } else {
@@ -740,6 +748,7 @@ export function roundtrip(
740
748
  const roundtripped = IdCompressor.deserialize({
741
749
  serialized: nonLocalSerialized,
742
750
  newSessionId: createSessionId(),
751
+ requestedWriteVersion: SerializationVersion.V3,
743
752
  });
744
753
  modifyClusterSize(roundtripped, capacity);
745
754
  return [nonLocalSerialized, roundtripped];
@@ -1085,7 +1094,11 @@ export function createAlwaysFinalizedIdCompressor(
1085
1094
  // This local session is unused, but it needs to not collide with the GhostSession, so allocate a random one.
1086
1095
  // This causes the compressor to serialize non-deterministically even when provided an explicit SessionId.
1087
1096
  // This can be fixed in the future if needed.
1088
- const compressor = createIdCompressor(random.uuid4() as SessionId, logger);
1097
+ const compressor = createIdCompressor(
1098
+ random.uuid4() as SessionId,
1099
+ SerializationVersion.V3,
1100
+ logger,
1101
+ );
1089
1102
  // Permanently put the compressor in a ghost session
1090
1103
  (compressor as IdCompressor).startGhostSession(sessionId);
1091
1104
  return toIdCompressorWithCore(compressor);
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D/pXqCZfUEHBR2USVl4/AABAAAAAAAAAAAAAAAAAFCAQAAAAAAAACRA
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEDpXqCZfUEHBR2USVl4/AAB3r8WOsPYt3ejBGppnQksAQAAAAAAAAAAAAAAAABQgEAAAAAAAAAkQAAAAAAAAPA/AAAAAABQgEAAAAAAAAAkQA==
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEDevxY6w9i3d6MEammdCSwB6V6gmX1BBwUdlElZePwAAQAAAAAAAPA/AAAAAABQgEAAAAAAAAAkQAAAAAAAAAAAAAAAAABQgEAAAAAAAAAkQA==
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D/pXqCZfUEHBR2USVl4/AABAAAAAAAAAAAAAAAAAAAYQAAAAAAAABBA
@@ -0,0 +1 @@
1
+ AAAAAAAAAEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D/pXqCZfUEHBR2USVl4/AABAAAAAAAAAAAAAAAAAAAYQAAAAAAAABBA
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D/pXqCZfUEHBR2USVl4/AABAAAAAAAAAAAAAAAAAFCAQAAAAAAAACRA
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEDpXqCZfUEHBR2USVl4/AAB3r8WOsPYt3ejBGppnQksAQAAAAAAAAAAAAAAAABQgEAAAAAAAAAkQAAAAAAAAPA/AAAAAABQgEAAAAAAAAAkQA==
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEDevxY6w9i3d6MEammdCSwB6V6gmX1BBwUdlElZePwAAQAAAAAAAPA/AAAAAABQgEAAAAAAAAAkQAAAAAAAAAAAAAAAAABQgEAAAAAAAAAkQA==
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D/pXqCZfUEHBR2USVl4/AABAAAAAAAAAAAAAAAAAAAYQAAAAAAAABBA
@@ -0,0 +1 @@
1
+ AAAAAAAACEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D/pXqCZfUEHBR2USVl4/AABAAAAAAAAAAAAAAAAAAAYQAAAAAAAABBA
@@ -7,7 +7,7 @@
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
8
  * Generated by "flub generate typetests" from @fluid-tools/build-cli.
9
9
  *
10
- * Baseline (previous) version: 3.1.0
10
+ * Baseline (previous) version: 3.2.0
11
11
  */
12
12
 
13
13
  import type { TypeOnly, MinimalType, FullType, requireAssignableTo } from "@fluidframework/build-tools";
@@ -24,6 +24,7 @@ declare type MakeUnusedImportErrorsGoAway<T> = TypeOnly<T> | MinimalType<T> | Fu
24
24
  * typeValidation.broken:
25
25
  * "Function_createIdCompressor": {"backCompat": false}
26
26
  */
27
+ // @ts-expect-error compatibility expected to be broken
27
28
  declare type current_as_old_for_Function_createIdCompressor = requireAssignableTo<TypeOnly<typeof current.createIdCompressor>, TypeOnly<typeof old.createIdCompressor>>
28
29
 
29
30
  /*
@@ -33,6 +34,7 @@ declare type current_as_old_for_Function_createIdCompressor = requireAssignableT
33
34
  * typeValidation.broken:
34
35
  * "Function_createSessionId": {"backCompat": false}
35
36
  */
37
+ // @ts-expect-error compatibility expected to be broken
36
38
  declare type current_as_old_for_Function_createSessionId = requireAssignableTo<TypeOnly<typeof current.createSessionId>, TypeOnly<typeof old.createSessionId>>
37
39
 
38
40
  /*
@@ -42,6 +44,7 @@ declare type current_as_old_for_Function_createSessionId = requireAssignableTo<T
42
44
  * typeValidation.broken:
43
45
  * "Function_deserializeIdCompressor": {"backCompat": false}
44
46
  */
47
+ // @ts-expect-error compatibility expected to be broken
45
48
  declare type current_as_old_for_Function_deserializeIdCompressor = requireAssignableTo<TypeOnly<typeof current.deserializeIdCompressor>, TypeOnly<typeof old.deserializeIdCompressor>>
46
49
 
47
50
  /*
@@ -51,6 +54,7 @@ declare type current_as_old_for_Function_deserializeIdCompressor = requireAssign
51
54
  * typeValidation.broken:
52
55
  * "Function_serializeIdCompressor": {"backCompat": false}
53
56
  */
57
+ // @ts-expect-error compatibility expected to be broken
54
58
  declare type current_as_old_for_Function_serializeIdCompressor = requireAssignableTo<TypeOnly<typeof current.serializeIdCompressor>, TypeOnly<typeof old.serializeIdCompressor>>
55
59
 
56
60
  /*
@@ -60,6 +64,7 @@ declare type current_as_old_for_Function_serializeIdCompressor = requireAssignab
60
64
  * typeValidation.broken:
61
65
  * "Interface_IdCreationRange": {"forwardCompat": false}
62
66
  */
67
+ // @ts-expect-error compatibility expected to be broken
63
68
  declare type old_as_current_for_Interface_IdCreationRange = requireAssignableTo<TypeOnly<old.IdCreationRange>, TypeOnly<current.IdCreationRange>>
64
69
 
65
70
  /*
@@ -69,6 +74,7 @@ declare type old_as_current_for_Interface_IdCreationRange = requireAssignableTo<
69
74
  * typeValidation.broken:
70
75
  * "Interface_IdCreationRange": {"backCompat": false}
71
76
  */
77
+ // @ts-expect-error compatibility expected to be broken
72
78
  declare type current_as_old_for_Interface_IdCreationRange = requireAssignableTo<TypeOnly<current.IdCreationRange>, TypeOnly<old.IdCreationRange>>
73
79
 
74
80
  /*
@@ -105,6 +111,7 @@ declare type current_as_old_for_TypeAlias_OpSpaceCompressedId = requireAssignabl
105
111
  * typeValidation.broken:
106
112
  * "TypeAlias_SerializedIdCompressor": {"forwardCompat": false}
107
113
  */
114
+ // @ts-expect-error compatibility expected to be broken
108
115
  declare type old_as_current_for_TypeAlias_SerializedIdCompressor = requireAssignableTo<TypeOnly<old.SerializedIdCompressor>, TypeOnly<current.SerializedIdCompressor>>
109
116
 
110
117
  /*
@@ -114,6 +121,7 @@ declare type old_as_current_for_TypeAlias_SerializedIdCompressor = requireAssign
114
121
  * typeValidation.broken:
115
122
  * "TypeAlias_SerializedIdCompressor": {"backCompat": false}
116
123
  */
124
+ // @ts-expect-error compatibility expected to be broken
117
125
  declare type current_as_old_for_TypeAlias_SerializedIdCompressor = requireAssignableTo<TypeOnly<current.SerializedIdCompressor>, TypeOnly<old.SerializedIdCompressor>>
118
126
 
119
127
  /*
@@ -123,6 +131,7 @@ declare type current_as_old_for_TypeAlias_SerializedIdCompressor = requireAssign
123
131
  * typeValidation.broken:
124
132
  * "TypeAlias_SerializedIdCompressorWithNoSession": {"forwardCompat": false}
125
133
  */
134
+ // @ts-expect-error compatibility expected to be broken
126
135
  declare type old_as_current_for_TypeAlias_SerializedIdCompressorWithNoSession = requireAssignableTo<TypeOnly<old.SerializedIdCompressorWithNoSession>, TypeOnly<current.SerializedIdCompressorWithNoSession>>
127
136
 
128
137
  /*
@@ -132,6 +141,7 @@ declare type old_as_current_for_TypeAlias_SerializedIdCompressorWithNoSession =
132
141
  * typeValidation.broken:
133
142
  * "TypeAlias_SerializedIdCompressorWithNoSession": {"backCompat": false}
134
143
  */
144
+ // @ts-expect-error compatibility expected to be broken
135
145
  declare type current_as_old_for_TypeAlias_SerializedIdCompressorWithNoSession = requireAssignableTo<TypeOnly<current.SerializedIdCompressorWithNoSession>, TypeOnly<old.SerializedIdCompressorWithNoSession>>
136
146
 
137
147
  /*
@@ -141,6 +151,7 @@ declare type current_as_old_for_TypeAlias_SerializedIdCompressorWithNoSession =
141
151
  * typeValidation.broken:
142
152
  * "TypeAlias_SerializedIdCompressorWithOngoingSession": {"forwardCompat": false}
143
153
  */
154
+ // @ts-expect-error compatibility expected to be broken
144
155
  declare type old_as_current_for_TypeAlias_SerializedIdCompressorWithOngoingSession = requireAssignableTo<TypeOnly<old.SerializedIdCompressorWithOngoingSession>, TypeOnly<current.SerializedIdCompressorWithOngoingSession>>
145
156
 
146
157
  /*
@@ -150,6 +161,7 @@ declare type old_as_current_for_TypeAlias_SerializedIdCompressorWithOngoingSessi
150
161
  * typeValidation.broken:
151
162
  * "TypeAlias_SerializedIdCompressorWithOngoingSession": {"backCompat": false}
152
163
  */
164
+ // @ts-expect-error compatibility expected to be broken
153
165
  declare type current_as_old_for_TypeAlias_SerializedIdCompressorWithOngoingSession = requireAssignableTo<TypeOnly<current.SerializedIdCompressorWithOngoingSession>, TypeOnly<old.SerializedIdCompressorWithOngoingSession>>
154
166
 
155
167
  /*
@@ -15,6 +15,28 @@ import type {
15
15
  SerializedIdCompressorWithOngoingSession,
16
16
  } from "./persisted-types/index.js";
17
17
 
18
+ /**
19
+ * Serialization format versions for IdCompressor.
20
+ * @internal
21
+ */
22
+ export const SerializationVersion = {
23
+ /**
24
+ * Base format without sharding support
25
+ */
26
+ V2: 2,
27
+ /**
28
+ * Adds optional sharding state
29
+ */
30
+ V3: 3,
31
+ } as const;
32
+
33
+ /**
34
+ * Type representing valid serialization version values.
35
+ * @internal
36
+ */
37
+ export type SerializationVersion =
38
+ (typeof SerializationVersion)[keyof typeof SerializationVersion];
39
+
18
40
  /**
19
41
  * A distributed UUID generator and compressor.
20
42
  *
@@ -85,6 +107,9 @@ export interface IIdCompressorCore {
85
107
  * range was taken (via this method or `takeUnfinalizedCreationRange`).
86
108
  * @returns the range of IDs, which may be empty. This range must be sent to the server for ordering before
87
109
  * it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.
110
+ * @throws if called on a child (non-root) shard. All shards in a shard tree share a single session, and only
111
+ * the root shard may finalize that session's IDs with the server; a child's IDs are instead reconciled with the
112
+ * root via {@link IIdCompressorCore.synchronizeWithShard} / {@link IIdCompressorCore.disposeShard}.
88
113
  */
89
114
  takeNextCreationRange(): IdCreationRange;
90
115
 
@@ -143,18 +168,110 @@ export interface IIdCompressorCore {
143
168
  beginGhostSession(ghostSessionId: SessionId, ghostSessionCallback: () => void): void;
144
169
 
145
170
  /**
146
- * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`.
171
+ * Shards the ID space of this compressor such that multiple local compressors can safely share it without colliding.
172
+ * This can allow multiple local instantiations of the same compressor to safely share an ID space in scenarios where
173
+ * different threads do not have access to a central ID compressor.
174
+ * @param newShardCount - The number of additional different shards to split this compressor into.
175
+ * Must be a positive safe integer.
176
+ * @throws If `newShardCount` is not a positive safe integer or the resulting stride exceeds the sharding limit.
177
+ * @returns An array of serialized compressors of size `newShardCount`.
178
+ * These can be passed across a marshalling boundary and rehydrated on the other side, and will safely share the ID space of `this`.
179
+ * Note that this method should only be needed when multiple JS runtimes are in play, as sharded compressors essentially
180
+ * attempt to emulate a single static compressor and any code running in the same JS runtime can simply use statics.
181
+ */
182
+ shard(newShardCount: number): SerializedIdCompressorWithOngoingSession[];
183
+
184
+ /**
185
+ * Synchronizes `this` compressor with a child shard. Synchronization will occur for the state of the child at the time `syncToken`
186
+ * was generated, meaning that `this` compressor can use/ingest IDs generated up to that point. Attempts to use IDs from a child shard
187
+ * without first synchronizing will result in an exception.
188
+ *
189
+ * If `syncToken` is a disposal token (its {@link ShardToken.disposed} flag is `true`, as produced by
190
+ * {@link IIdCompressorCore.disposeShard}), this additionally deregisters the child shard and reclaims its subset of the ID space
191
+ * into `this`. Once a shard has been disposed it is no longer safe to use the compressor the token came from, and a shard tree must
192
+ * be disposed from the leaves upwards.
193
+ * @param syncToken - The token for the shard, obtained by calling {@link IIdCompressorCore.getShardSyncToken} (non-destructive
194
+ * synchronization) or {@link IIdCompressorCore.disposeShard} (synchronization plus reclamation of the disposed shard's ID space).
195
+ */
196
+ synchronizeWithShard(syncToken: ShardSynchronizationToken): void;
197
+
198
+ /**
199
+ * Returns undefined if this compressor is not part of a shard group, and otherwise returns a synchronization token for this shard
200
+ * that can be used when calling {@link IIdCompressorCore.synchronizeWithShard}. This does NOT dispose the shard.
201
+ *
202
+ * @returns The sync token if this compressor is part of a sharded group, otherwise undefined.
203
+ * The returned token is serializable and can be passed across marshaling boundaries. This token can be used to synchronize a
204
+ * parent with this compressor by calling {@link IIdCompressorCore.synchronizeWithShard}.
205
+ * Unlike {@link IIdCompressorCore.disposeShard}, this is non-destructive and may be called on a shard that still has active
206
+ * child shards, which allows an intermediate shard to propagate its progress upward to its own parent.
207
+ * @throws If this compressor is the root of the shard tree (only non-root shards can produce a token).
208
+ */
209
+ getShardSyncToken(): ShardSynchronizationToken | undefined;
210
+
211
+ /**
212
+ * Returns undefined if this compressor is not part of a shard group, and otherwise disposes this shard and returns
213
+ * the disposal token for this compressor. If this compressor was part of a shard group, the compressor will no longer be usable.
214
+ *
215
+ * @returns The disposal token if this compressor is part of a sharded group, otherwise undefined.
216
+ * The returned token is serializable and can be passed across marshaling boundaries. Passing it to
217
+ * {@link IIdCompressorCore.synchronizeWithShard} on the parent reclaims this shard's subset of the ID space.
218
+ * @throws If this shard has active child shards.
219
+ * This means that a shard tree must be disposed from the leaves upwards.
220
+ */
221
+ disposeShard(): ShardSynchronizationToken | undefined;
222
+
223
+ /**
224
+ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `deserializeIdCompressor()`.
147
225
  * This includes finalized state as well as un-finalized state and is therefore suitable for use in offline scenarios.
148
226
  */
149
227
  serialize(withSession: true): SerializedIdCompressorWithOngoingSession;
150
228
 
151
229
  /**
152
- * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `IdCompressor.deserialize()`.
230
+ * Returns a persistable form of the current state of this `IdCompressor` which can be rehydrated via `deserializeIdCompressor()`.
153
231
  * This only includes finalized state and is therefore suitable for use in summaries.
154
232
  */
155
233
  serialize(withSession: false): SerializedIdCompressorWithNoSession;
156
234
  }
157
235
 
236
+ /**
237
+ * The state shared by all shard tokens: enough information to identify a shard and its progress
238
+ * through its stride pattern. This is used to track which shard generated which IDs and to manage
239
+ * reclamation of a disposed shard's ID space. The {@link ShardToken.disposed} flag distinguishes a
240
+ * plain synchronization token from a disposal token. The branded {@link ShardSynchronizationToken}
241
+ * is the concrete type handed to consumers.
242
+ * @internal
243
+ */
244
+ export interface ShardToken {
245
+ /**
246
+ * The number of positions filled in this shard's stride pattern.
247
+ * This tracks progress through the stride cycle, not the count of IDs actually generated.
248
+ * For example, when a shard is created, it backfills entries for positions in its stride,
249
+ * so this value may be non-zero even if the shard hasn't generated any IDs yet.
250
+ */
251
+ localGenCount: number;
252
+
253
+ /**
254
+ * Unique identifier for this shard within its parent.
255
+ */
256
+ shardId: SessionId;
257
+
258
+ /**
259
+ * Whether this token also signals disposal of the originating shard. When `true`, passing the token to
260
+ * {@link IIdCompressorCore.synchronizeWithShard} reclaims the shard's ID space in addition to synchronizing.
261
+ * Produced as `false` by {@link IIdCompressorCore.getShardSyncToken} and `true` by {@link IIdCompressorCore.disposeShard}.
262
+ */
263
+ disposed: boolean;
264
+ }
265
+
266
+ /**
267
+ * A {@link ShardToken} that identifies a shard for synchronization (and, when {@link ShardToken.disposed} is `true`,
268
+ * reclamation) via {@link IIdCompressorCore.synchronizeWithShard}.
269
+ * @internal
270
+ */
271
+ export type ShardSynchronizationToken = ShardToken & {
272
+ readonly ShardSynchronizationToken: "c79724e1-9103-4415-95b5-bebb932be404";
273
+ };
274
+
158
275
  /**
159
276
  * A distributed UUID generator and compressor.
160
277
  * `IdCompressor` offers the ability to generate arbitrary non-colliding v4 UUIDs, called stable IDs, while compressing them into small integers
@@ -10,7 +10,16 @@ export type {
10
10
  SerializedIdCompressorWithOngoingSession,
11
11
  } from "./persisted-types/index.js";
12
12
 
13
- export type { IIdCompressorCore, IIdCompressor } from "./idCompressor.js";
13
+ export type {
14
+ IIdCompressorCore,
15
+ IIdCompressor,
16
+ ShardToken,
17
+ ShardSynchronizationToken,
18
+ } from "./idCompressor.js";
19
+ export {
20
+ SerializationVersion,
21
+ type SerializationVersion as SerializationVersionType,
22
+ } from "./idCompressor.js";
14
23
 
15
24
  export type {
16
25
  SessionSpaceCompressedId,
@@ -7,7 +7,7 @@ import type { SessionId } from "../identifiers.js";
7
7
 
8
8
  /**
9
9
  * The serialized contents of an IdCompressor, suitable for persistence in a summary.
10
- * @legacy @beta
10
+ * @internal
11
11
  */
12
12
  export type SerializedIdCompressor = string & {
13
13
  readonly _serializedIdCompressor: "8c73c57c-1cf4-4278-8915-6444cb4f6af5";
@@ -15,7 +15,7 @@ export type SerializedIdCompressor = string & {
15
15
 
16
16
  /**
17
17
  * The serialized contents of an IdCompressor, suitable for persistence in a summary.
18
- * @legacy @beta
18
+ * @internal
19
19
  */
20
20
  export type SerializedIdCompressorWithNoSession = SerializedIdCompressor & {
21
21
  readonly _noLocalState: "3aa2e1e8-cc28-4ea7-bc1a-a11dc3f26dfb";
@@ -23,7 +23,7 @@ export type SerializedIdCompressorWithNoSession = SerializedIdCompressor & {
23
23
 
24
24
  /**
25
25
  * The serialized contents of an IdCompressor, suitable for persistence in a summary.
26
- * @legacy @beta
26
+ * @internal
27
27
  */
28
28
  export type SerializedIdCompressorWithOngoingSession = SerializedIdCompressor & {
29
29
  readonly _hasLocalState: "1281acae-6d14-47e7-bc92-71c8ee0819cb";
@@ -33,7 +33,7 @@ export type SerializedIdCompressorWithOngoingSession = SerializedIdCompressor &
33
33
  * Data describing a range of session-local IDs (from a remote or local session).
34
34
  *
35
35
  * A range is composed of local IDs that were generated.
36
- * @legacy @beta
36
+ * @internal
37
37
  */
38
38
  export interface IdCreationRange {
39
39
  readonly sessionId: SessionId;
package/src/utilities.ts CHANGED
@@ -29,7 +29,7 @@ function isHexadecimalCharacter(charCode: number): boolean {
29
29
 
30
30
  /**
31
31
  * Generate a random session ID
32
- * @legacy @beta
32
+ * @internal
33
33
  */
34
34
  export function createSessionId(): SessionId {
35
35
  return assertIsStableId(v4()) as SessionId;