fluid-framework 2.112.0 → 2.113.1
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/CHANGELOG.md +174 -0
- package/api-report/fluid-framework.alpha.api.md +23 -2
- package/dist/alpha.d.ts +3 -0
- package/lib/alpha.d.ts +3 -0
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,179 @@
|
|
|
1
1
|
# fluid-framework
|
|
2
2
|
|
|
3
|
+
## 2.113.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Enable select staged schema upgrades at runtime via view configuration ([#27542](https://github.com/microsoft/FluidFramework/pull/27542)) [44f40e8411](https://github.com/microsoft/FluidFramework/commit/44f40e8411d53bc22939a8f53343863f420bb0de)
|
|
8
|
+
|
|
9
|
+
SharedTree now supports enabling selected staged schema upgrades when initializing or upgrading a document's stored schema.
|
|
10
|
+
This lets applications deploy code that understands a schema change before enabling that change in documents.
|
|
11
|
+
It separates code rollout from feature rollout.
|
|
12
|
+
|
|
13
|
+
#### API
|
|
14
|
+
|
|
15
|
+
Pass `stagedUpgradePolicy` in the configuration object to
|
|
16
|
+
[`ITreeAlpha.viewWith`](https://fluidframework.com/docs/api/tree/viewabletree-interface#viewwith-methodsignature)
|
|
17
|
+
to select which schema upgrades to enable at runtime.
|
|
18
|
+
|
|
19
|
+
Use `StagedSchemaUpgradePolicy.enabledStagedUpgrades(...)` with `SchemaUpgrade` objects from
|
|
20
|
+
[`SchemaFactoryBeta.staged`](https://fluidframework.com/docs/api/tree/schemastaticsbeta-interface#staged-propertysignature)
|
|
21
|
+
or [`SchemaFactoryAlpha.stagedOptional`](https://fluidframework.com/docs/api/tree/schemafactoryalpha-class#stagedoptional-property):
|
|
22
|
+
|
|
23
|
+
The following example defines a staged type, extracts its `SchemaUpgrade` token, and passes it to the view configuration so the staged type is enabled when the schema is upgraded:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
const sf = new SchemaFactoryBeta("my-app");
|
|
27
|
+
|
|
28
|
+
class ChecklistItem extends sf.object("ChecklistItem", { text: sf.string }) {}
|
|
29
|
+
|
|
30
|
+
// `staged` wraps the type so it can be enabled at runtime.
|
|
31
|
+
const stagedChecklist = SchemaFactoryBeta.staged(ChecklistItem);
|
|
32
|
+
// The SchemaUpgrade token identifies this staged type.
|
|
33
|
+
const checklistUpgrade = stagedChecklist.metadata.stagedSchemaUpgrade;
|
|
34
|
+
|
|
35
|
+
class AppSchema extends sf.object("AppSchema", {
|
|
36
|
+
items: sf.array([sf.string, stagedChecklist]),
|
|
37
|
+
}) {}
|
|
38
|
+
|
|
39
|
+
const view = tree.viewWith(
|
|
40
|
+
new TreeViewConfigurationAlpha({
|
|
41
|
+
schema: AppSchema,
|
|
42
|
+
stagedUpgradePolicy:
|
|
43
|
+
StagedSchemaUpgradePolicy.enabledStagedUpgrades(checklistUpgrade),
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
When `stagedUpgradePolicy` is omitted or `undefined`, the default is
|
|
49
|
+
`StagedSchemaUpgradePolicy.restrictive`.
|
|
50
|
+
This excludes all staged schema upgrades, producing the most conservative stored schema.
|
|
51
|
+
|
|
52
|
+
Advanced callers can provide a custom `StagedSchemaUpgradePolicy` object:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const enabledFeatures = new Set<SchemaUpgrade>([checklistUpgrade]);
|
|
56
|
+
|
|
57
|
+
const view = tree.viewWith(
|
|
58
|
+
new TreeViewConfigurationAlpha({
|
|
59
|
+
schema: AppSchema,
|
|
60
|
+
stagedUpgradePolicy: {
|
|
61
|
+
includeStaged: (upgrade) => enabledFeatures.has(upgrade),
|
|
62
|
+
includeStagedOptional: (upgrade) => enabledFeatures.has(upgrade),
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This is useful for fine-grained rollout control or integration tests.
|
|
69
|
+
|
|
70
|
+
#### Pre-built Policies
|
|
71
|
+
|
|
72
|
+
The `StagedSchemaUpgradePolicy` namespace provides convenient pre-built policies:
|
|
73
|
+
- **`restrictive`** (default): excludes all staged upgrades.
|
|
74
|
+
- **`permissive`**: includes all staged upgrades. Useful in tests.
|
|
75
|
+
- **`enabledStagedUpgrades(...)`**: includes only the specified upgrades.
|
|
76
|
+
|
|
77
|
+
#### Production
|
|
78
|
+
|
|
79
|
+
Applications can use feature flags to control when staged schema upgrades are enabled.
|
|
80
|
+
Previously, enabling a staged schema required a code change that removed the staged wrapper.
|
|
81
|
+
With this API, the staged wrapper stays in code while `stagedUpgradePolicy` decides at runtime which documents enable it.
|
|
82
|
+
|
|
83
|
+
For example, an application adding checklist items can deploy clients that understand the new schema first,
|
|
84
|
+
then enable the stored-schema upgrade only where a feature flag is active:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const sf = new SchemaFactoryBeta("example-app");
|
|
88
|
+
|
|
89
|
+
class ChecklistItem extends sf.object("ChecklistItem", {
|
|
90
|
+
text: sf.string,
|
|
91
|
+
}) {}
|
|
92
|
+
|
|
93
|
+
const stagedChecklistItem = SchemaFactoryBeta.staged(ChecklistItem);
|
|
94
|
+
const checklistItemSchemaUpgrade =
|
|
95
|
+
stagedChecklistItem.metadata.stagedSchemaUpgrade;
|
|
96
|
+
|
|
97
|
+
class AppSchema extends sf.object("AppSchema", {
|
|
98
|
+
// `taskItem` allows plain text today; the staged type is added for future rollout.
|
|
99
|
+
taskItem: sf.optional([sf.string, stagedChecklistItem]),
|
|
100
|
+
}) {}
|
|
101
|
+
|
|
102
|
+
const enableChecklistItems = featureFlags.enableChecklistItems;
|
|
103
|
+
|
|
104
|
+
const view = tree.viewWith(
|
|
105
|
+
new TreeViewConfigurationAlpha({
|
|
106
|
+
schema: AppSchema,
|
|
107
|
+
stagedUpgradePolicy: enableChecklistItems
|
|
108
|
+
? StagedSchemaUpgradePolicy.enabledStagedUpgrades(
|
|
109
|
+
checklistItemSchemaUpgrade,
|
|
110
|
+
)
|
|
111
|
+
: undefined,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (view.compatibility.canInitialize) {
|
|
116
|
+
// New documents include the checklist schema only while the rollout is enabled.
|
|
117
|
+
view.initialize(initialContent);
|
|
118
|
+
} else if (view.compatibility.canUpgrade) {
|
|
119
|
+
// Writes the staged type into the stored schema for this document.
|
|
120
|
+
view.upgradeSchema();
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Once a staged schema upgrade has been written to a document's stored schema, that change is permanent.
|
|
125
|
+
If `upgradeSchema` is later called from a view that does not include the previously enabled token,
|
|
126
|
+
it throws a `UsageError` because the new target would narrow the stored schema.
|
|
127
|
+
|
|
128
|
+
In practice, keep the upgrade token configured for as long as any document may have been upgraded.
|
|
129
|
+
Once the staged wrapper is removed from the code, the token is no longer needed.
|
|
130
|
+
|
|
131
|
+
#### Testing
|
|
132
|
+
|
|
133
|
+
Tests can verify that the current application version handles documents with staged types enabled.
|
|
134
|
+
Without such testing, it is hard to confirm that staging prepared the application—not just the schema—for the new types.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const currentView = currentAppTree.viewWith(
|
|
138
|
+
new TreeViewConfiguration({ schema: CurrentAppSchema }),
|
|
139
|
+
);
|
|
140
|
+
currentView.initialize(existingTaskDocument);
|
|
141
|
+
await ensureSynchronized();
|
|
142
|
+
|
|
143
|
+
const nextView = asAlpha(nextAppTree).viewWith(
|
|
144
|
+
new TreeViewConfigurationAlpha({
|
|
145
|
+
schema: AppSchemaWithStagedChecklist,
|
|
146
|
+
stagedUpgradePolicy: StagedSchemaUpgradePolicy.enabledStagedUpgrades(
|
|
147
|
+
checklistItemSchemaUpgrade,
|
|
148
|
+
),
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// The next version can read the document, but the checklist shape is not yet
|
|
153
|
+
// in stored schema and cannot be written.
|
|
154
|
+
assert.throws(() =>
|
|
155
|
+
addChecklistItem(nextView.root, { text: "Review rollout" }),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
nextView.upgradeSchema();
|
|
159
|
+
await ensureSynchronized();
|
|
160
|
+
|
|
161
|
+
// Older clients are now incompatible; the next version can use the staged shape.
|
|
162
|
+
assert.equal(currentView.compatibility.canView, false);
|
|
163
|
+
addChecklistItem(nextView.root, { text: "Review rollout" });
|
|
164
|
+
await validateChecklistScenario(nextView);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
- Fix assert when inserting the same node multiple times ([#27734](https://github.com/microsoft/FluidFramework/pull/27734)) [b509d00166](https://github.com/microsoft/FluidFramework/commit/b509d00166773585c42c60e97ec30a86fbd20cd5)
|
|
168
|
+
|
|
169
|
+
When inserting the same node multiple times in a single array insertion, a `UsageError` is now thrown instead of an assert `0xa2b`.
|
|
170
|
+
|
|
171
|
+
For example, this now throws a `UsageError` with message `A "ArrayNodeTest.Item" node was provided more than once in a single insertion. A node may not be in more than one place in the tree.`:
|
|
172
|
+
|
|
173
|
+
```TypeScript
|
|
174
|
+
array.insertAtEnd(item, item);
|
|
175
|
+
```
|
|
176
|
+
|
|
3
177
|
## 2.112.0
|
|
4
178
|
|
|
5
179
|
### Minor Changes
|
|
@@ -1102,6 +1102,11 @@ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = Im
|
|
|
1102
1102
|
readonly schema: TSchema;
|
|
1103
1103
|
}
|
|
1104
1104
|
|
|
1105
|
+
// @alpha
|
|
1106
|
+
export interface ITreeViewConfigurationAlpha<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> extends ITreeViewConfiguration<TSchema> {
|
|
1107
|
+
readonly stagedUpgradePolicy?: StagedSchemaUpgradePolicy;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1105
1110
|
// @alpha @sealed
|
|
1106
1111
|
export interface JsonArrayNodeSchema extends JsonNodeSchemaBase<NodeKind.Array, "array"> {
|
|
1107
1112
|
readonly items: JsonFieldSchema;
|
|
@@ -1850,6 +1855,22 @@ export interface SnapshotSchemaCompatibilityOptions {
|
|
|
1850
1855
|
readonly versionComparer?: (a: string, b: string) => number;
|
|
1851
1856
|
}
|
|
1852
1857
|
|
|
1858
|
+
// @alpha @input
|
|
1859
|
+
export interface StagedSchemaUpgradePolicy {
|
|
1860
|
+
includeStaged(upgrade: SchemaUpgrade): boolean;
|
|
1861
|
+
includeStagedOptional(upgrade: SchemaUpgrade): boolean;
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
// @alpha
|
|
1865
|
+
export const StagedSchemaUpgradePolicy: StagedSchemaUpgradePolicyFactory;
|
|
1866
|
+
|
|
1867
|
+
// @alpha @sealed
|
|
1868
|
+
export interface StagedSchemaUpgradePolicyFactory {
|
|
1869
|
+
enabledStagedUpgrades(...upgrades: SchemaUpgrade[]): StagedSchemaUpgradePolicy;
|
|
1870
|
+
readonly permissive: StagedSchemaUpgradePolicy;
|
|
1871
|
+
readonly restrictive: StagedSchemaUpgradePolicy;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1853
1874
|
// @beta @system
|
|
1854
1875
|
export namespace System_TableSchema {
|
|
1855
1876
|
// @sealed @system
|
|
@@ -2489,7 +2510,6 @@ export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | Unsa
|
|
|
2489
2510
|
readonly events: Listenable<TreeViewEvents & TreeBranchEvents>;
|
|
2490
2511
|
// (undocumented)
|
|
2491
2512
|
fork(): ReturnType<TreeBranch["fork"]> & TreeViewAlpha<TSchema>;
|
|
2492
|
-
// (undocumented)
|
|
2493
2513
|
initialize(content: InsertableField<TSchema>): void;
|
|
2494
2514
|
// (undocumented)
|
|
2495
2515
|
get root(): ReadableField<TSchema>;
|
|
@@ -2516,11 +2536,12 @@ export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = I
|
|
|
2516
2536
|
|
|
2517
2537
|
// @alpha @sealed
|
|
2518
2538
|
export class TreeViewConfigurationAlpha<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> extends TreeViewConfiguration<TSchema> implements TreeSchema {
|
|
2519
|
-
constructor(props:
|
|
2539
|
+
constructor(props: ITreeViewConfigurationAlpha<TSchema>);
|
|
2520
2540
|
// (undocumented)
|
|
2521
2541
|
readonly definitions: ReadonlyMap<string, SimpleNodeSchema<SchemaType.View> & TreeNodeSchema>;
|
|
2522
2542
|
// (undocumented)
|
|
2523
2543
|
readonly root: FieldSchemaAlpha;
|
|
2544
|
+
readonly stagedUpgradePolicy: StagedSchemaUpgradePolicy;
|
|
2524
2545
|
}
|
|
2525
2546
|
|
|
2526
2547
|
// @public @sealed
|
package/dist/alpha.d.ts
CHANGED
|
@@ -258,6 +258,7 @@ export {
|
|
|
258
258
|
HandleConverter,
|
|
259
259
|
ICodecOptions,
|
|
260
260
|
ITreeAlpha,
|
|
261
|
+
ITreeViewConfigurationAlpha,
|
|
261
262
|
IncrementalEncodingPolicy,
|
|
262
263
|
IndependentViewOptions,
|
|
263
264
|
IndependentViewTelemetryOptions,
|
|
@@ -326,6 +327,8 @@ export {
|
|
|
326
327
|
SimpleObjectNodeSchema,
|
|
327
328
|
SimpleRecordNodeSchema,
|
|
328
329
|
SimpleTreeSchema,
|
|
330
|
+
StagedSchemaUpgradePolicy,
|
|
331
|
+
StagedSchemaUpgradePolicyFactory,
|
|
329
332
|
TextAsTree,
|
|
330
333
|
TransactionCallbackStatusAlpha,
|
|
331
334
|
TransactionConstraintAlpha,
|
package/lib/alpha.d.ts
CHANGED
|
@@ -258,6 +258,7 @@ export {
|
|
|
258
258
|
HandleConverter,
|
|
259
259
|
ICodecOptions,
|
|
260
260
|
ITreeAlpha,
|
|
261
|
+
ITreeViewConfigurationAlpha,
|
|
261
262
|
IncrementalEncodingPolicy,
|
|
262
263
|
IndependentViewOptions,
|
|
263
264
|
IndependentViewTelemetryOptions,
|
|
@@ -326,6 +327,8 @@ export {
|
|
|
326
327
|
SimpleObjectNodeSchema,
|
|
327
328
|
SimpleRecordNodeSchema,
|
|
328
329
|
SimpleTreeSchema,
|
|
330
|
+
StagedSchemaUpgradePolicy,
|
|
331
|
+
StagedSchemaUpgradePolicyFactory,
|
|
329
332
|
TextAsTree,
|
|
330
333
|
TransactionCallbackStatusAlpha,
|
|
331
334
|
TransactionConstraintAlpha,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluid-framework",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.113.1",
|
|
4
4
|
"description": "The main entry point into Fluid Framework public packages",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -57,17 +57,17 @@
|
|
|
57
57
|
"main": "lib/index.js",
|
|
58
58
|
"types": "lib/public.d.ts",
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@fluidframework/container-definitions": "~2.
|
|
61
|
-
"@fluidframework/container-loader": "~2.
|
|
62
|
-
"@fluidframework/core-interfaces": "~2.
|
|
63
|
-
"@fluidframework/core-utils": "~2.
|
|
64
|
-
"@fluidframework/driver-definitions": "~2.
|
|
65
|
-
"@fluidframework/fluid-static": "~2.
|
|
66
|
-
"@fluidframework/map": "~2.
|
|
67
|
-
"@fluidframework/runtime-utils": "~2.
|
|
68
|
-
"@fluidframework/sequence": "~2.
|
|
69
|
-
"@fluidframework/shared-object-base": "~2.
|
|
70
|
-
"@fluidframework/tree": "~2.
|
|
60
|
+
"@fluidframework/container-definitions": "~2.113.1",
|
|
61
|
+
"@fluidframework/container-loader": "~2.113.1",
|
|
62
|
+
"@fluidframework/core-interfaces": "~2.113.1",
|
|
63
|
+
"@fluidframework/core-utils": "~2.113.1",
|
|
64
|
+
"@fluidframework/driver-definitions": "~2.113.1",
|
|
65
|
+
"@fluidframework/fluid-static": "~2.113.1",
|
|
66
|
+
"@fluidframework/map": "~2.113.1",
|
|
67
|
+
"@fluidframework/runtime-utils": "~2.113.1",
|
|
68
|
+
"@fluidframework/sequence": "~2.113.1",
|
|
69
|
+
"@fluidframework/shared-object-base": "~2.113.1",
|
|
70
|
+
"@fluidframework/tree": "~2.113.1"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@arethetypeswrong/cli": "^0.18.2",
|