fluid-framework 2.90.0 → 2.91.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,252 @@
1
1
  # fluid-framework
2
2
 
3
+ ## 2.91.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Adds withDefault API to allow defining default values for required and optional fields ([#26502](https://github.com/microsoft/FluidFramework/pull/26502)) [44fdd9421e4](https://github.com/microsoft/FluidFramework/commit/44fdd9421e4d0bfa3cdfa9ab3672ebf3c0ad20a6)
8
+
9
+ The `withDefault` API is now available on `SchemaFactoryAlpha`. It allows you to specify default values for fields,
10
+ making them optional in constructors even when the field is marked as required in the schema.
11
+ This provides a better developer experience by reducing boilerplate when creating objects.
12
+
13
+ The `withDefault` API wraps a field schema and defines a default value to use when the field is not provided during
14
+ construction. The default value must be of an allowed type of the field. You can provide defaults in two ways:
15
+ - **A value**: When a value is provided directly, the data is copied for each use to ensure independence between instances
16
+ - **A generator function**: A function that is called each time to produce a fresh value
17
+
18
+ Defaults are evaluated eagerly during node construction.
19
+
20
+ #### Required fields with defaults
21
+
22
+ ```typescript
23
+ import { SchemaFactoryAlpha, TreeAlpha } from "@fluidframework/tree/alpha";
24
+
25
+ const sf = new SchemaFactoryAlpha("example");
26
+
27
+ class Person extends sf.objectAlpha("Person", {
28
+ name: sf.required(sf.string),
29
+ age: sf.withDefault(sf.required(sf.number), -1),
30
+ role: sf.withDefault(sf.required(sf.string), "guest"),
31
+ }) {}
32
+
33
+ // Before: all fields were required
34
+ // const person = new Person({ name: "Alice", age: -1, role: "guest" });
35
+
36
+ // After: fields with defaults are optional
37
+ const person = new Person({ name: "Alice" });
38
+ // person.age === -1
39
+ // person.role === "guest"
40
+
41
+ // You can still provide values to override the defaults
42
+ const admin = new Person({ name: "Bob", age: 30, role: "admin" });
43
+ ```
44
+
45
+ #### Optional fields with custom defaults
46
+
47
+ Optional fields (`sf.optional`) already default to `undefined`, but `withDefault` allows you to specify a different
48
+ default value:
49
+
50
+ ```typescript
51
+ class Config extends sf.object("Config", {
52
+ timeout: sf.withDefault(sf.optional(sf.number), 5000),
53
+ retries: sf.withDefault(sf.optional(sf.number), 3),
54
+ }) {}
55
+
56
+ // All fields are optional, using custom defaults when not provided
57
+ const config = new Config({});
58
+ // config.timeout === 5000
59
+ // config.retries === 3
60
+
61
+ const customConfig = new Config({ timeout: 10000 });
62
+ // customConfig.timeout === 10000
63
+ // customConfig.retries === 3
64
+ ```
65
+
66
+ #### Value defaults vs function defaults
67
+
68
+ When you provide a value directly, the data is copied for each use, ensuring each instance is independent:
69
+
70
+ ```typescript
71
+ class Metadata extends sf.object("Metadata", {
72
+ tags: sf.array(sf.string),
73
+ version: sf.number,
74
+ }) {}
75
+
76
+ class Article extends sf.object("Article", {
77
+ title: sf.required(sf.string),
78
+
79
+ // a node is provided directly, it is copied for each use
80
+ metadata: sf.withDefault(
81
+ sf.optional(Metadata),
82
+ new Metadata({ tags: [], version: 1 }),
83
+ ),
84
+
85
+ // also works with arrays
86
+ authors: sf.withDefault(sf.optional(sf.array(sf.string)), []),
87
+ }) {}
88
+
89
+ const article1 = new Article({ title: "First" });
90
+ const article2 = new Article({ title: "Second" });
91
+
92
+ // each article gets its own independent copy
93
+ assert(article1.metadata !== article2.metadata);
94
+ article1.metadata.version = 2; // Doesn't affect article2
95
+ assert(article2.metadata.version === 1);
96
+ ```
97
+
98
+ Alternatively, you can use generator functions to explicitly create new instances:
99
+
100
+ ```typescript
101
+ class Article extends sf.object("Article", {
102
+ title: sf.required(sf.string),
103
+
104
+ // generators are called each time to create a new instance
105
+ metadata: sf.withDefault(
106
+ sf.optional(Metadata),
107
+ () => new Metadata({ tags: [], version: 1 }),
108
+ ),
109
+ authors: sf.withDefault(sf.optional(sf.array(sf.string)), () => []),
110
+ }) {}
111
+ ```
112
+
113
+ Insertable object literals, arrays, and map objects can be used in place of node instances in both static defaults
114
+ and generator functions:
115
+
116
+ ```typescript
117
+ class Article extends sf.object("Article", {
118
+ title: sf.required(sf.string),
119
+
120
+ // plain object literal instead of new Metadata(...)
121
+ metadata: sf.withDefault(sf.optional(Metadata), () => ({
122
+ tags: [],
123
+ version: 1,
124
+ })),
125
+
126
+ // plain array instead of new ArrayNode(...)
127
+ authors: sf.withDefault(sf.optional(sf.array(sf.string)), () => [
128
+ "anonymous",
129
+ ]),
130
+ }) {}
131
+ ```
132
+
133
+ ##### Dynamic defaults
134
+
135
+ Generator functions are called each time a new node is created, enabling dynamic defaults:
136
+
137
+ ```typescript
138
+ class Document extends sf.object("Document", {
139
+ id: sf.withDefault(sf.required(sf.string), () => crypto.randomUUID()),
140
+ title: sf.required(sf.string),
141
+ }) {}
142
+
143
+ const doc1 = new Document({ title: "First Document" });
144
+ const doc2 = new Document({ title: "Second Document" });
145
+ // doc1.id !== doc2.id (each gets a unique UUID)
146
+ ```
147
+
148
+ Generator functions also work with primitive types:
149
+
150
+ ```typescript
151
+ let counter = 0;
152
+
153
+ class GameState extends sf.object("GameState", {
154
+ playerId: sf.withDefault(
155
+ sf.required(sf.string),
156
+ () => `player-${counter++}`,
157
+ ),
158
+ score: sf.withDefault(sf.required(sf.number), () =>
159
+ Math.floor(Math.random() * 100),
160
+ ),
161
+ isActive: sf.withDefault(sf.required(sf.boolean), () => counter % 2 === 0),
162
+ }) {}
163
+ ```
164
+
165
+ #### Recursive types
166
+
167
+ `withDefaultRecursive` is available for use inside recursive schemas. Use `objectRecursiveAlpha` (rather than
168
+ `objectRecursive`) when defining recursive schemas with defaults, as it correctly makes defaulted fields optional in
169
+ the constructor for all field kinds including `requiredRecursive`. It works the same as `withDefault` but is
170
+ necessary to avoid TypeScript's circular reference limitations.
171
+
172
+ ```typescript
173
+ class TreeNode extends sf.objectRecursiveAlpha("TreeNode", {
174
+ value: sf.number,
175
+ label: SchemaFactoryAlpha.withDefaultRecursive(
176
+ sf.optional(sf.string),
177
+ "untitled",
178
+ ),
179
+ child: sf.optionalRecursive([() => TreeNode]),
180
+ }) {}
181
+
182
+ // `label` is optional in the constructor — the default is used when omitted
183
+ const leaf = new TreeNode({ value: 1 });
184
+ // leaf.label === "untitled"
185
+
186
+ const root = new TreeNode({ value: 0, label: "root", child: leaf });
187
+ // root.label === "root"
188
+ // root.child.label === "untitled"
189
+ ```
190
+
191
+ > **Warning:** Be careful about using the recursive type itself as a default value — this is likely to cause
192
+ > infinite recursion at construction time, since creating the default value would trigger the same default again.
193
+ > Instead, use a primitive or a separate node type as the default:
194
+ >
195
+ > ```typescript
196
+ > const DefaultTag = sf.objectRecursiveAlpha("Tag", {
197
+ > id: sf.number,
198
+ > child: sf.optionalRecursive([() => TreeNode]),
199
+ > });
200
+ >
201
+ > class TreeNode extends sf.objectRecursiveAlpha("TreeNode", {
202
+ > value: sf.number,
203
+ > // ✅ Safe: default is a non-recursive node
204
+ > tag: SchemaFactoryAlpha.withDefaultRecursive(
205
+ > sf.optional(DefaultTag),
206
+ > () => new DefaultTag({ id: 0, child: new DefaultTag({ id: 1 }) }),
207
+ > ),
208
+ > child: sf.optionalRecursive([() => TreeNode]),
209
+ > }) {}
210
+ > ```
211
+ >
212
+ > The following definition for child would cause infinite recursion at construction time:
213
+ >
214
+ > ```typescript
215
+ > child: SchemaFactoryAlpha.withDefaultRecursive(
216
+ > sf.optionalRecursive([() => TreeNode]),
217
+ > () => new TreeNode({ value: 0 }),
218
+ > );
219
+ > ```
220
+
221
+ > The infinite recursion can be solved by passing in undefined explicitly but it is
222
+ > recommended to not use defaults in this case:
223
+ >
224
+ > ```typescript
225
+ > child: SchemaFactoryAlpha.withDefaultRecursive(
226
+ > sf.optionalRecursive([() => TreeNode]),
227
+ > () => new TreeNode({ value: 0, child: undefined }),
228
+ > );
229
+ > ```
230
+
231
+ #### Type safety
232
+
233
+ The default value (or the value returned by a generator function) must be of an allowed type for the field. TypeScript
234
+ enforces this at compile time:
235
+
236
+ ```typescript
237
+ // ✅ Valid: number default for number field
238
+ sf.withDefault(sf.optional(sf.number), 8080);
239
+
240
+ // ✅ Valid: generator returns string for string field
241
+ sf.withDefault(sf.optional(sf.string), () => "localhost");
242
+
243
+ // ❌ TypeScript error: string default for number field
244
+ sf.withDefault(sf.optional(sf.number), "8080");
245
+
246
+ // ❌ TypeScript error: generator returns number for string field
247
+ sf.withDefault(sf.optional(sf.string), () => 8080);
248
+ ```
249
+
3
250
  ## 2.90.0
4
251
 
5
252
  ### Minor Changes
@@ -307,6 +307,15 @@ export abstract class ErasedBaseType<out Name = unknown> {
307
307
  protected abstract brand(dummy: never): Name;
308
308
  }
309
309
 
310
+ // @alpha
311
+ export type ErasedNode<TExtra, Identifier extends string> = TExtra & TreeNode & WithType<Identifier>;
312
+
313
+ // @alpha
314
+ export type ErasedSchema<NodeType extends TreeNode> = TreeNodeSchema<NodeType extends WithType<infer Identifier> ? Identifier : string, NodeKind, NodeType, never, false>;
315
+
316
+ // @alpha
317
+ export type ErasedSchemaSubclassable<TExtra, Identifier extends string> = TreeNodeSchemaClass<Identifier, NodeKind, ErasedNode<TExtra, Identifier>, never, false>;
318
+
310
319
  // @public @sealed
311
320
  export abstract class ErasedType<out Name = unknown> {
312
321
  static [Symbol.hasInstance](value: never): value is never;
@@ -356,6 +365,18 @@ type FieldHasDefault<T extends ImplicitFieldSchema> = [T] extends [
356
365
  FieldSchema<FieldKind.Optional | FieldKind.Identifier>
357
366
  ] ? true : false;
358
367
 
368
+ // @alpha @system
369
+ export type FieldHasDefaultAlpha<T extends ImplicitFieldSchema> = [
370
+ T
371
+ ] extends [FieldSchemaAlpha<infer Kind, infer _Types, infer _Meta, infer TProps>] ? Kind extends FieldKind.Optional | FieldKind.Identifier ? true : TProps extends {
372
+ defaultProvider: DefaultProvider;
373
+ } ? true : false : FieldHasDefault<T>;
374
+
375
+ // @alpha @sealed @system
376
+ export type FieldHasDefaultAlphaUnsafe<T extends System_Unsafe.ImplicitFieldSchemaUnsafe> = T extends FieldSchemaAlphaUnsafe<infer Kind, System_Unsafe.ImplicitAllowedTypesUnsafe, unknown, infer TProps> ? Kind extends FieldKind.Optional | FieldKind.Identifier ? true : TProps extends {
377
+ defaultProvider: DefaultProvider;
378
+ } ? true : false : System_Unsafe.FieldHasDefaultUnsafe<T>;
379
+
359
380
  // @public
360
381
  export enum FieldKind {
361
382
  Identifier = 2,
@@ -391,7 +412,7 @@ export class FieldSchema<out Kind extends FieldKind = FieldKind, out Types exten
391
412
  }
392
413
 
393
414
  // @alpha @sealed
394
- export class FieldSchemaAlpha<Kind extends FieldKind = FieldKind, Types extends ImplicitAllowedTypes = ImplicitAllowedTypes, TCustomMetadata = unknown> extends FieldSchema<Kind, Types, TCustomMetadata> implements SimpleFieldSchema<SchemaType.View> {
415
+ export class FieldSchemaAlpha<Kind extends FieldKind = FieldKind, Types extends ImplicitAllowedTypes = ImplicitAllowedTypes, TCustomMetadata = unknown, TProps extends FieldPropsAlpha<TCustomMetadata> | undefined = FieldPropsAlpha<TCustomMetadata> | undefined> extends FieldSchema<Kind, Types, TCustomMetadata> implements SimpleFieldSchema<SchemaType.View> {
395
416
  protected constructor(kind: Kind, types: Types, props?: FieldPropsAlpha<TCustomMetadata>);
396
417
  readonly allowedTypesFull: AllowedTypesFull;
397
418
  // (undocumented)
@@ -403,7 +424,7 @@ export class FieldSchemaAlpha<Kind extends FieldKind = FieldKind, Types extends
403
424
  }
404
425
 
405
426
  // @alpha @sealed @system
406
- export interface FieldSchemaAlphaUnsafe<out Kind extends FieldKind, out Types extends System_Unsafe.ImplicitAllowedTypesUnsafe, out TCustomMetadata = unknown> extends FieldSchemaAlpha<Kind, any, TCustomMetadata>, System_Unsafe.FieldSchemaUnsafe<Kind, Types, TCustomMetadata> {
427
+ export interface FieldSchemaAlphaUnsafe<out Kind extends FieldKind, out Types extends System_Unsafe.ImplicitAllowedTypesUnsafe, out TCustomMetadata = unknown, out TProps extends FieldPropsAlpha<TCustomMetadata> | undefined = undefined> extends FieldSchemaAlpha<Kind, any, TCustomMetadata, TProps>, System_Unsafe.FieldSchemaUnsafe<Kind, Types, TCustomMetadata> {
407
428
  readonly allowedTypes: Types;
408
429
  }
409
430
 
@@ -838,6 +859,22 @@ type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<Implicit
838
859
  readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
839
860
  }>;
840
861
 
862
+ // @alpha @system
863
+ export type InsertableObjectFromSchemaRecordAlpha<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = RestrictiveStringRecord<ImplicitFieldSchema> extends T ? {
864
+ arbitraryKey: "arbitraryValue";
865
+ } extends T ? Record<string, never> : never : FlattenKeys<{
866
+ readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
867
+ } & {
868
+ readonly [Property in keyof T as FieldHasDefaultAlpha<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
869
+ }>;
870
+
871
+ // @alpha @system
872
+ export type InsertableObjectFromSchemaRecordAlphaUnsafe<T extends RestrictiveStringRecord<System_Unsafe.ImplicitFieldSchemaUnsafe>> = {
873
+ readonly [Property in keyof T as FieldHasDefaultAlphaUnsafe<T[Property & string]> extends false ? Property : never]: System_Unsafe.InsertableTreeFieldFromImplicitFieldUnsafe<T[Property & string]>;
874
+ } & {
875
+ readonly [Property in keyof T as FieldHasDefaultAlphaUnsafe<T[Property & string]> extends true ? Property : never]?: System_Unsafe.InsertableTreeFieldFromImplicitFieldUnsafe<T[Property & string]>;
876
+ };
877
+
841
878
  // @public
842
879
  export type InsertableTreeFieldFromImplicitField<TSchemaInput extends ImplicitFieldSchema, TSchema = UnionToIntersection<TSchemaInput>> = [TSchema] extends [FieldSchema<infer Kind, infer Types>] ? ApplyKindInput<InsertableTreeNodeFromImplicitAllowedTypes<Types>, Kind, true> : [TSchema] extends [ImplicitAllowedTypes] ? InsertableTreeNodeFromImplicitAllowedTypes<TSchema> : never;
843
880
 
@@ -1169,6 +1206,9 @@ export enum NodeKind {
1169
1206
  Record = 4
1170
1207
  }
1171
1208
 
1209
+ // @alpha @sealed
1210
+ export type NodeProvider<T> = T | (() => T);
1211
+
1172
1212
  // @public @sealed
1173
1213
  export interface NodeSchemaMetadata<out TCustomMetadata = unknown> {
1174
1214
  readonly custom?: TCustomMetadata | undefined;
@@ -1199,7 +1239,7 @@ export type ObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFie
1199
1239
  };
1200
1240
 
1201
1241
  // @alpha @sealed
1202
- export interface ObjectNodeSchema<out TName extends string = string, in out T extends RestrictiveStringRecord<ImplicitFieldSchema> = RestrictiveStringRecord<ImplicitFieldSchema>, ImplicitlyConstructable extends boolean = boolean, out TCustomMetadata = unknown> extends TreeNodeSchemaClass<TName, NodeKind.Object, TreeObjectNode<T, TName>, InsertableObjectFromSchemaRecord<T>, ImplicitlyConstructable, T, never, TCustomMetadata>, SimpleObjectNodeSchema<SchemaType.View, TCustomMetadata> {
1242
+ export interface ObjectNodeSchema<out TName extends string = string, in out T extends RestrictiveStringRecord<ImplicitFieldSchema> = RestrictiveStringRecord<ImplicitFieldSchema>, ImplicitlyConstructable extends boolean = boolean, out TCustomMetadata = unknown> extends TreeNodeSchemaClass<TName, NodeKind.Object, TreeObjectNode<T, TName>, object & InsertableObjectFromSchemaRecordAlpha<T>, ImplicitlyConstructable, T, never, TCustomMetadata>, SimpleObjectNodeSchema<SchemaType.View, TCustomMetadata> {
1203
1243
  readonly fields: ReadonlyMap<string, FieldSchemaAlpha & SimpleObjectFieldSchema>;
1204
1244
  }
1205
1245
 
@@ -1208,6 +1248,11 @@ export const ObjectNodeSchema: {
1208
1248
  readonly [Symbol.hasInstance]: (value: TreeNodeSchema) => value is ObjectNodeSchema<string, RestrictiveStringRecord<ImplicitFieldSchema>, boolean, unknown>;
1209
1249
  };
1210
1250
 
1251
+ // @alpha @sealed
1252
+ export type ObjectNodeSchemaWorkaround<TName extends string = string, T extends RestrictiveStringRecord<ImplicitFieldSchema> = RestrictiveStringRecord<ImplicitFieldSchema>, ImplicitlyConstructable extends boolean = boolean, TCustomMetadata = unknown> = ObjectNodeSchema<TName, T, ImplicitlyConstructable, TCustomMetadata> & {
1253
+ readonly createFromInsertable: unknown;
1254
+ };
1255
+
1211
1256
  // @beta @input
1212
1257
  export interface ObjectSchemaOptions<TCustomMetadata = unknown> extends NodeSchemaOptions<TCustomMetadata> {
1213
1258
  readonly allowUnknownOptionalFields?: boolean;
@@ -1393,28 +1438,39 @@ export const SchemaFactory_base: SchemaStatics & (new () => SchemaStatics);
1393
1438
  export class SchemaFactoryAlpha<out TScope extends string | undefined = string | undefined, TName extends number | string = string> extends SchemaFactoryBeta<TScope, TName> {
1394
1439
  arrayAlpha<const Name extends TName, const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): ArrayNodeCustomizableSchema<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
1395
1440
  arrayRecursive<const Name extends TName, const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): ArrayNodeCustomizableSchemaUnsafe<ScopedSchemaName<TScope, Name>, T, TCustomMetadata>;
1396
- static readonly identifier: <const TCustomMetadata = unknown>(props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Identifier, LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, TCustomMetadata>;
1441
+ static readonly identifier: <const TCustomMetadata = unknown>(props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Identifier, LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1397
1442
  static readonly leaves: readonly [LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"number", number> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"boolean", boolean> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"null", null> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"handle", IFluidHandle_2<unknown>> & SimpleLeafNodeSchema<SchemaType>];
1398
1443
  readonly leaves: readonly [LeafSchema<"string", string> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"number", number> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"boolean", boolean> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"null", null> & SimpleLeafNodeSchema<SchemaType>, LeafSchema<"handle", IFluidHandle_2<unknown>> & SimpleLeafNodeSchema<SchemaType>];
1399
1444
  mapAlpha<Name extends TName, const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): MapNodeCustomizableSchema<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
1400
1445
  mapRecursive<Name extends TName, const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): MapNodeCustomizableSchemaUnsafe<ScopedSchemaName<TScope, Name>, T, TCustomMetadata>;
1401
- objectAlpha<const Name extends TName, const T extends RestrictiveStringRecord<ImplicitFieldSchema>, const TCustomMetadata = unknown>(name: Name, fields: T, options?: ObjectSchemaOptionsAlpha<TCustomMetadata>): ObjectNodeSchema<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata> & {
1402
- readonly createFromInsertable: unknown;
1403
- };
1446
+ objectAlpha<const Name extends TName, const T extends RestrictiveStringRecord<ImplicitFieldSchema>, const TCustomMetadata = unknown>(name: Name, fields: T, options?: ObjectSchemaOptionsAlpha<TCustomMetadata>): ObjectNodeSchemaWorkaround<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
1404
1447
  objectRecursive<const Name extends TName, const T extends RestrictiveStringRecord<System_Unsafe.ImplicitFieldSchemaUnsafe>, const TCustomMetadata = unknown>(name: Name, t: T, options?: ObjectSchemaOptionsAlpha<TCustomMetadata>): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, System_Unsafe.TreeObjectNodeUnsafe<T, ScopedSchemaName<TScope, Name>>, object & System_Unsafe.InsertableObjectFromSchemaRecordUnsafe<T>, false, T, never, TCustomMetadata> & SimpleObjectNodeSchema<SchemaType.View, TCustomMetadata> & Pick<ObjectNodeSchema, "fields">;
1405
- static readonly optional: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Optional, T, TCustomMetadata>;
1406
- readonly optional: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Optional, T, TCustomMetadata>;
1407
- static readonly optionalRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Optional, T, TCustomMetadata>;
1408
- readonly optionalRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Optional, T, TCustomMetadata>;
1448
+ objectRecursiveAlpha<const Name extends TName, const T extends RestrictiveStringRecord<System_Unsafe.ImplicitFieldSchemaUnsafe>, const TCustomMetadata = unknown>(name: Name, t: T, options?: ObjectSchemaOptionsAlpha<TCustomMetadata>): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, System_Unsafe.TreeObjectNodeUnsafe<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecordAlphaUnsafe<T>, false, T, never, TCustomMetadata> & SimpleObjectNodeSchema<SchemaType.View, TCustomMetadata> & Pick<ObjectNodeSchema, "fields">;
1449
+ static readonly optional: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Optional, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1450
+ readonly optional: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Optional, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1451
+ static readonly optionalRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Optional, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1452
+ readonly optionalRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Optional, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1409
1453
  recordAlpha<const Name extends TName, const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): RecordNodeCustomizableSchema<ScopedSchemaName<TScope, Name>, T, true, TCustomMetadata>;
1410
1454
  recordRecursive<Name extends TName, const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptionsAlpha<TCustomMetadata>): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Record, TreeRecordNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Record, unknown>, {
1411
1455
  readonly [x: string]: System_Unsafe.InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>;
1412
1456
  }, false, T, undefined, TCustomMetadata>;
1413
- static readonly required: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Required, T, TCustomMetadata>;
1414
- readonly required: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Required, T, TCustomMetadata>;
1415
- static readonly requiredRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Required, T, TCustomMetadata>;
1416
- readonly requiredRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Required, T, TCustomMetadata>;
1457
+ static readonly required: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Required, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1458
+ readonly required: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlpha<FieldKind.Required, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1459
+ static readonly requiredRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Required, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1460
+ readonly requiredRecursive: <const T extends System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldPropsAlpha<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchemaAlphaUnsafe<FieldKind.Required, T, TCustomMetadata, FieldPropsAlpha<TCustomMetadata>>;
1417
1461
  scopedFactoryAlpha<const T extends TName, TNameInner extends number | string = string>(name: T): SchemaFactoryAlpha<ScopedSchemaName<TScope, T>, TNameInner>;
1462
+ readonly withDefault: <Kind extends FieldKind, Types extends ImplicitAllowedTypes, TCustomMetadata = unknown>(fieldSchema: FieldSchema<Kind, Types, TCustomMetadata>, defaultValue: NodeProvider<ApplyKindInput_2<InsertableTreeNodeFromImplicitAllowedTypes_2<Types>, Kind, true>>) => FieldSchemaAlpha<Kind, Types, TCustomMetadata, FieldPropsAlpha<TCustomMetadata> & {
1463
+ defaultProvider: DefaultProvider;
1464
+ }>;
1465
+ static readonly withDefault: <Kind extends FieldKind, Types extends ImplicitAllowedTypes, TCustomMetadata = unknown>(fieldSchema: FieldSchema<Kind, Types, TCustomMetadata>, defaultValue: NodeProvider<ApplyKindInput_2<InsertableTreeNodeFromImplicitAllowedTypes_2<Types>, Kind, true>>) => FieldSchemaAlpha<Kind, Types, TCustomMetadata, FieldPropsAlpha<TCustomMetadata> & {
1466
+ defaultProvider: DefaultProvider;
1467
+ }>;
1468
+ readonly withDefaultRecursive: <Kind extends FieldKind, Types extends System_Unsafe.ImplicitAllowedTypesUnsafe, TCustomMetadata = unknown>(fieldSchema: System_Unsafe.FieldSchemaUnsafe<Kind, Types, TCustomMetadata>, defaultValue: unknown) => FieldSchemaAlphaUnsafe<Kind, Types, TCustomMetadata, FieldPropsAlpha<TCustomMetadata> & {
1469
+ defaultProvider: DefaultProvider;
1470
+ }>;
1471
+ static readonly withDefaultRecursive: <Kind extends FieldKind, Types extends System_Unsafe.ImplicitAllowedTypesUnsafe, TCustomMetadata = unknown>(fieldSchema: System_Unsafe.FieldSchemaUnsafe<Kind, Types, TCustomMetadata>, defaultValue: unknown) => FieldSchemaAlphaUnsafe<Kind, Types, TCustomMetadata, FieldPropsAlpha<TCustomMetadata> & {
1472
+ defaultProvider: DefaultProvider;
1473
+ }>;
1418
1474
  }
1419
1475
 
1420
1476
  // @beta
@@ -1458,6 +1514,16 @@ export interface SchemaStatics {
1458
1514
  readonly string: LeafSchema<"string", string>;
1459
1515
  }
1460
1516
 
1517
+ // @alpha @sealed @system
1518
+ export interface SchemaStaticsAlpha {
1519
+ readonly withDefault: <Kind extends FieldKind, Types extends ImplicitAllowedTypes, TCustomMetadata = unknown>(fieldSchema: FieldSchema<Kind, Types, TCustomMetadata>, defaultValue: NodeProvider<InsertableTreeFieldFromImplicitField<FieldSchema<Kind, Types>>>) => FieldSchemaAlpha<Kind, Types, TCustomMetadata, FieldPropsAlpha<TCustomMetadata> & {
1520
+ defaultProvider: DefaultProvider;
1521
+ }>;
1522
+ withDefaultRecursive: <Kind extends FieldKind, Types extends System_Unsafe.ImplicitAllowedTypesUnsafe, TCustomMetadata = unknown>(fieldSchema: System_Unsafe.FieldSchemaUnsafe<Kind, Types, TCustomMetadata>, defaultValue: Unenforced<NodeProvider<System_Unsafe.InsertableTreeFieldFromImplicitFieldUnsafe<System_Unsafe.FieldSchemaUnsafe<Kind, Types>>>>) => FieldSchemaAlphaUnsafe<Kind, Types, TCustomMetadata, FieldPropsAlpha<TCustomMetadata> & {
1523
+ defaultProvider: DefaultProvider;
1524
+ }>;
1525
+ }
1526
+
1461
1527
  // @beta @sealed @system
1462
1528
  export interface SchemaStaticsBeta {
1463
1529
  readonly staged: <const T extends LazyItem<TreeNodeSchema>>(t: T | AnnotatedAllowedType<T>) => AnnotatedAllowedType<T>;
package/dist/alpha.d.ts CHANGED
@@ -209,8 +209,13 @@ export {
209
209
  CreateIndependentTreeAlphaOptions,
210
210
  DirtyTreeMap,
211
211
  DirtyTreeStatus,
212
+ ErasedNode,
213
+ ErasedSchema,
214
+ ErasedSchemaSubclassable,
212
215
  FactoryContent,
213
216
  FactoryContentObject,
217
+ FieldHasDefaultAlpha,
218
+ FieldHasDefaultAlphaUnsafe,
214
219
  FieldPropsAlpha,
215
220
  FieldSchemaAlpha,
216
221
  FieldSchemaAlphaUnsafe,
@@ -228,6 +233,8 @@ export {
228
233
  Insertable,
229
234
  InsertableContent,
230
235
  InsertableField,
236
+ InsertableObjectFromSchemaRecordAlpha,
237
+ InsertableObjectFromSchemaRecordAlphaUnsafe,
231
238
  JsonArrayNodeSchema,
232
239
  JsonAsTree,
233
240
  JsonCompatibleReadOnly,
@@ -253,8 +260,10 @@ export {
253
260
  MapNodePojoEmulationSchema,
254
261
  MapNodeSchema,
255
262
  NoChangeConstraint,
263
+ NodeProvider,
256
264
  NodeSchemaOptionsAlpha,
257
265
  ObjectNodeSchema,
266
+ ObjectNodeSchemaWorkaround,
258
267
  ObjectSchemaOptionsAlpha,
259
268
  ObservationResults,
260
269
  ReadSchema,
@@ -267,6 +276,7 @@ export {
267
276
  RevertibleAlphaFactory,
268
277
  RunTransactionParams,
269
278
  SchemaFactoryAlpha,
279
+ SchemaStaticsAlpha,
270
280
  SchemaType,
271
281
  SharedTreeFormatOptions,
272
282
  SharedTreeOptions,
package/lib/alpha.d.ts CHANGED
@@ -209,8 +209,13 @@ export {
209
209
  CreateIndependentTreeAlphaOptions,
210
210
  DirtyTreeMap,
211
211
  DirtyTreeStatus,
212
+ ErasedNode,
213
+ ErasedSchema,
214
+ ErasedSchemaSubclassable,
212
215
  FactoryContent,
213
216
  FactoryContentObject,
217
+ FieldHasDefaultAlpha,
218
+ FieldHasDefaultAlphaUnsafe,
214
219
  FieldPropsAlpha,
215
220
  FieldSchemaAlpha,
216
221
  FieldSchemaAlphaUnsafe,
@@ -228,6 +233,8 @@ export {
228
233
  Insertable,
229
234
  InsertableContent,
230
235
  InsertableField,
236
+ InsertableObjectFromSchemaRecordAlpha,
237
+ InsertableObjectFromSchemaRecordAlphaUnsafe,
231
238
  JsonArrayNodeSchema,
232
239
  JsonAsTree,
233
240
  JsonCompatibleReadOnly,
@@ -253,8 +260,10 @@ export {
253
260
  MapNodePojoEmulationSchema,
254
261
  MapNodeSchema,
255
262
  NoChangeConstraint,
263
+ NodeProvider,
256
264
  NodeSchemaOptionsAlpha,
257
265
  ObjectNodeSchema,
266
+ ObjectNodeSchemaWorkaround,
258
267
  ObjectSchemaOptionsAlpha,
259
268
  ObservationResults,
260
269
  ReadSchema,
@@ -267,6 +276,7 @@ export {
267
276
  RevertibleAlphaFactory,
268
277
  RunTransactionParams,
269
278
  SchemaFactoryAlpha,
279
+ SchemaStaticsAlpha,
270
280
  SchemaType,
271
281
  SharedTreeFormatOptions,
272
282
  SharedTreeOptions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluid-framework",
3
- "version": "2.90.0",
3
+ "version": "2.91.0",
4
4
  "description": "The main entry point into Fluid Framework public packages",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -57,25 +57,25 @@
57
57
  "main": "lib/index.js",
58
58
  "types": "lib/public.d.ts",
59
59
  "dependencies": {
60
- "@fluidframework/container-definitions": "~2.90.0",
61
- "@fluidframework/container-loader": "~2.90.0",
62
- "@fluidframework/core-interfaces": "~2.90.0",
63
- "@fluidframework/core-utils": "~2.90.0",
64
- "@fluidframework/driver-definitions": "~2.90.0",
65
- "@fluidframework/fluid-static": "~2.90.0",
66
- "@fluidframework/map": "~2.90.0",
67
- "@fluidframework/runtime-utils": "~2.90.0",
68
- "@fluidframework/sequence": "~2.90.0",
69
- "@fluidframework/shared-object-base": "~2.90.0",
70
- "@fluidframework/tree": "~2.90.0"
60
+ "@fluidframework/container-definitions": "~2.91.0",
61
+ "@fluidframework/container-loader": "~2.91.0",
62
+ "@fluidframework/core-interfaces": "~2.91.0",
63
+ "@fluidframework/core-utils": "~2.91.0",
64
+ "@fluidframework/driver-definitions": "~2.91.0",
65
+ "@fluidframework/fluid-static": "~2.91.0",
66
+ "@fluidframework/map": "~2.91.0",
67
+ "@fluidframework/runtime-utils": "~2.91.0",
68
+ "@fluidframework/sequence": "~2.91.0",
69
+ "@fluidframework/shared-object-base": "~2.91.0",
70
+ "@fluidframework/tree": "~2.91.0"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@arethetypeswrong/cli": "^0.18.2",
74
- "@biomejs/biome": "~1.9.3",
74
+ "@biomejs/biome": "~2.4.5",
75
75
  "@fluid-tools/build-cli": "^0.63.0",
76
76
  "@fluidframework/build-common": "^2.0.3",
77
77
  "@fluidframework/build-tools": "^0.63.0",
78
- "@fluidframework/eslint-config-fluid": "~2.90.0",
78
+ "@fluidframework/eslint-config-fluid": "~2.91.0",
79
79
  "@microsoft/api-extractor": "7.52.11",
80
80
  "@types/node": "~20.19.30",
81
81
  "concurrently": "^9.2.1",