@fluidframework/local-driver 2.117.0 → 3.0.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 (86) hide show
  1. package/CHANGELOG.md +42 -2
  2. package/README.md +54 -51
  3. package/{api-extractor.json → api-extractor/api-extractor-model.json} +1 -1
  4. package/api-report/local-driver.legacy.beta.api.md +1 -0
  5. package/dist/auth.js +2 -3
  6. package/dist/auth.js.map +1 -1
  7. package/dist/ephemeralService.js +15 -12
  8. package/dist/ephemeralService.js.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/localCreateDocument.js +1 -2
  14. package/dist/localCreateDocument.js.map +1 -1
  15. package/dist/localDeltaStorageService.js +3 -0
  16. package/dist/localDeltaStorageService.js.map +1 -1
  17. package/dist/localDocumentDeltaConnection.d.ts.map +1 -1
  18. package/dist/localDocumentService.d.ts.map +1 -1
  19. package/dist/localDocumentService.js +11 -2
  20. package/dist/localDocumentService.js.map +1 -1
  21. package/dist/localDocumentServiceFactory.d.ts +9 -0
  22. package/dist/localDocumentServiceFactory.d.ts.map +1 -1
  23. package/dist/localDocumentServiceFactory.js +22 -10
  24. package/dist/localDocumentServiceFactory.js.map +1 -1
  25. package/dist/localDocumentStorageService.d.ts.map +1 -1
  26. package/dist/localDocumentStorageService.js +15 -5
  27. package/dist/localDocumentStorageService.js.map +1 -1
  28. package/dist/localLayerCompatState.d.ts +8 -1
  29. package/dist/localLayerCompatState.d.ts.map +1 -1
  30. package/dist/localLayerCompatState.js +20 -1
  31. package/dist/localLayerCompatState.js.map +1 -1
  32. package/dist/localResolver.js +5 -6
  33. package/dist/localResolver.js.map +1 -1
  34. package/dist/localSessionStorageDb.js +3 -7
  35. package/dist/localSessionStorageDb.js.map +1 -1
  36. package/dist/packageVersion.d.ts +1 -1
  37. package/dist/packageVersion.d.ts.map +1 -1
  38. package/dist/packageVersion.js +1 -1
  39. package/dist/packageVersion.js.map +1 -1
  40. package/lib/alpha.d.ts +1 -1
  41. package/lib/ephemeralService.js +11 -8
  42. package/lib/ephemeralService.js.map +1 -1
  43. package/lib/index.d.ts +1 -1
  44. package/lib/index.d.ts.map +1 -1
  45. package/lib/index.js +1 -1
  46. package/lib/index.js.map +1 -1
  47. package/lib/legacy.d.ts +1 -1
  48. package/lib/localDeltaStorageService.js +3 -0
  49. package/lib/localDeltaStorageService.js.map +1 -1
  50. package/lib/localDocumentDeltaConnection.d.ts.map +1 -1
  51. package/lib/localDocumentService.d.ts.map +1 -1
  52. package/lib/localDocumentService.js +9 -0
  53. package/lib/localDocumentService.js.map +1 -1
  54. package/lib/localDocumentServiceFactory.d.ts +9 -0
  55. package/lib/localDocumentServiceFactory.d.ts.map +1 -1
  56. package/lib/localDocumentServiceFactory.js +23 -11
  57. package/lib/localDocumentServiceFactory.js.map +1 -1
  58. package/lib/localDocumentStorageService.d.ts.map +1 -1
  59. package/lib/localDocumentStorageService.js +16 -6
  60. package/lib/localDocumentStorageService.js.map +1 -1
  61. package/lib/localLayerCompatState.d.ts +8 -1
  62. package/lib/localLayerCompatState.d.ts.map +1 -1
  63. package/lib/localLayerCompatState.js +20 -1
  64. package/lib/localLayerCompatState.js.map +1 -1
  65. package/lib/localResolver.js +3 -4
  66. package/lib/localResolver.js.map +1 -1
  67. package/lib/localSessionStorageDb.js +3 -7
  68. package/lib/localSessionStorageDb.js.map +1 -1
  69. package/lib/packageVersion.d.ts +1 -1
  70. package/lib/packageVersion.d.ts.map +1 -1
  71. package/lib/packageVersion.js +1 -1
  72. package/lib/packageVersion.js.map +1 -1
  73. package/lib/public.d.ts +1 -1
  74. package/package.json +42 -58
  75. package/src/ephemeralService.ts +1 -1
  76. package/src/index.ts +4 -1
  77. package/src/localDocumentServiceFactory.ts +15 -1
  78. package/src/localDocumentStorageService.ts +9 -3
  79. package/src/localLayerCompatState.ts +29 -1
  80. package/src/packageVersion.ts +1 -1
  81. package/tsconfig.json +1 -1
  82. package/alpha.d.ts +0 -11
  83. package/internal.d.ts +0 -11
  84. package/legacy.d.ts +0 -11
  85. /package/api-extractor/{api-extractor.current.json → api-extractor-report.current.json} +0 -0
  86. /package/api-extractor/{api-extractor.legacy.json → api-extractor-report.legacy.json} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"localSessionStorageDb.js","sourceRoot":"","sources":["../src/localSessionStorageDb.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"@fluid-internal/client-utils\";\nimport type { ICollection, IDb } from \"@fluidframework/server-services-core\";\nimport type { ITestDbFactory } from \"@fluidframework/server-test-utils\";\nimport { v4 as uuid } from \"uuid\";\n\n/**\n * A collection for local session storage, where data is stored in the browser\n * Functions include database operations such as queries, insertion and update.\n */\nclass LocalSessionStorageCollection<T> implements ICollection<T> {\n\t/**\n\t * @param collectionName - data type of the collection, e.g. blobs, deltas, trees, etc.\n\t */\n\tconstructor(private readonly collectionName: string) {}\n\n\tpublic aggregate(pipeline: any, options?: any): any {\n\t\tthrow new Error(\"Method Not Implemented\");\n\t}\n\n\tpublic async updateMany(filter: any, set: any, addToSet: any): Promise<void> {\n\t\tthrow new Error(\"Method Not Implemented\");\n\t}\n\tpublic async distinct(key: any, query: any): Promise<any> {\n\t\tthrow new Error(\"Method Not Implemented\");\n\t}\n\tpublic async findAndUpdate(query: any, value: T): Promise<{ value: T; existing: boolean }> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.find}\n\t */\n\t/*\n\t * Each query key consists of several keys separated by '.' e.g: \"operation.sequenceNumber\".\n\t * The hierarchical syntax allows finding nested key patterns.\n\t */\n\tpublic async find(query: any, sort: any): Promise<any[]> {\n\t\t// split the keys and get the corresponding value\n\t\tfunction getValueByKey(propertyBag, key: string): any {\n\t\t\tconst keys = key.split(\".\");\n\t\t\tlet value = propertyBag;\n\t\t\tfor (const splitKey of keys) {\n\t\t\t\tvalue = value[splitKey];\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t// getting keys of the query we are trying to find\n\t\tconst queryKeys = Object.keys(query);\n\t\tlet filteredCollection = this.getAllInternal();\n\t\tfor (const key of queryKeys) {\n\t\t\tif (!query[key]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (query[key].$gt > 0 || query[key].$lt > 0) {\n\t\t\t\tif (query[key].$gt > 0) {\n\t\t\t\t\tfilteredCollection = filteredCollection.filter(\n\t\t\t\t\t\t(value) => getValueByKey(value, key) > query[key].$gt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (query[key].$lt > 0) {\n\t\t\t\t\tfilteredCollection = filteredCollection.filter(\n\t\t\t\t\t\t(value) => getValueByKey(value, key) < query[key].$lt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfilteredCollection = filteredCollection.filter(\n\t\t\t\t\t(value) => getValueByKey(value, key) === query[key],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (sort && Object.keys(sort).length === 1) {\n\t\t\tfunction compare(a, b): number {\n\t\t\t\t// Non null asserting here because of the length check above\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst sortKey = Object.keys(sort)[0]!;\n\t\t\t\treturn sort[sortKey] === 1\n\t\t\t\t\t? getValueByKey(a, sortKey) - getValueByKey(b, sortKey)\n\t\t\t\t\t: getValueByKey(b, sortKey) - getValueByKey(a, sortKey);\n\t\t\t}\n\n\t\t\tfilteredCollection = filteredCollection.sort(compare);\n\t\t}\n\t\treturn filteredCollection;\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.findAll}\n\t */\n\tpublic async findAll(): Promise<any[]> {\n\t\treturn this.getAllInternal();\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.findOne}\n\t */\n\t/*\n\t * Query is expected to have a member \"_id\" which is a string used to find value in the database.\n\t */\n\tpublic async findOne(query: any): Promise<any> {\n\t\treturn this.findOneInternal(query);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.update}\n\t */\n\t/*\n\t * Query is expected to have a member \"_id\" which is a string used to find value in the database.\n\t */\n\tpublic async update(query: any, set: any, addToSet: any): Promise<void> {\n\t\tconst value = this.findOneInternal(query);\n\t\tif (value) {\n\t\t\tfor (const key of Object.keys(set)) {\n\t\t\t\tvalue[key] = set[key];\n\t\t\t}\n\t\t\tthis.insertInternal(value);\n\t\t} else {\n\t\t\tthrow new Error(\"Not found\");\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.upsert}\n\t */\n\t/*\n\t * Query is expected to have a member \"_id\" which is a string used to find value in the database.\n\t */\n\tpublic async upsert(query: any, set: any, addToSet: any): Promise<void> {\n\t\tconst value = this.findOneInternal(query);\n\t\tif (value) {\n\t\t\tfor (const key of Object.keys(set)) {\n\t\t\t\tvalue[key] = set[key];\n\t\t\t}\n\t\t\tthis.insertInternal(value);\n\t\t} else {\n\t\t\tthis.insertInternal(set);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.insertOne}\n\t */\n\t/*\n\t * Value is expected to have a member \"_id\" which is a string used to search in the database.\n\t */\n\tpublic async insertOne(value: any): Promise<any> {\n\t\tconst presentVal = this.findOneInternal(value);\n\t\t// Only raise error when the object is present and the value is not equal.\n\t\tif (presentVal) {\n\t\t\tif (JSON.stringify(presentVal) === JSON.stringify(value)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\"Existing Object!!\");\n\t\t}\n\n\t\treturn this.insertInternal(value);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.findOrCreate}\n\t */\n\t/*\n\t * Value and query are expected to have a member \"_id\" which is a string used to search or insert in the database.\n\t */\n\tpublic async findOrCreate(\n\t\tquery: any,\n\t\tvalue: any,\n\t): Promise<{ value: any; existing: boolean }> {\n\t\tconst existing = this.findOneInternal(query);\n\t\tif (existing) {\n\t\t\treturn { value: existing, existing: true };\n\t\t}\n\t\tthis.insertInternal(value);\n\t\treturn { value, existing: false };\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.insertMany}\n\t */\n\t/*\n\t * Each element in values is expected to have a member \"_id\" which is a string used to insert in the database.\n\t */\n\tpublic async insertMany(values: any[], ordered: boolean): Promise<void> {\n\t\tthis.insertInternal(...values);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.deleteOne}\n\t */\n\tpublic async deleteOne(query: any): Promise<any> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.deleteMany}\n\t */\n\tpublic async deleteMany(query: any): Promise<any> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.createIndex}\n\t */\n\tpublic async createIndex(index: any, unique: boolean): Promise<void> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * Return all values in the database\n\t */\n\tprivate getAllInternal(): any[] {\n\t\tconst values: string[] = [];\n\t\tfor (let i = 0; i < sessionStorage.length; i++) {\n\t\t\tconst key = sessionStorage.key(i);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tif (key!.startsWith(this.collectionName)) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tvalues.push(JSON.parse(sessionStorage.getItem(key!)!));\n\t\t\t}\n\t\t}\n\t\treturn values;\n\t}\n\n\t/**\n\t * Inserts values into the session storge.\n\t * Values are expected to have a member \"_id\" which is a unique id, otherwise will be assigned one\n\t *\n\t * @param values - data to insert to the database\n\t */\n\tprivate insertInternal(...values: any[]): void {\n\t\tfor (const value of values) {\n\t\t\tif (value) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\t\t\tif (!value._id) {\n\t\t\t\t\tvalue._id = uuid();\n\t\t\t\t}\n\t\t\t\tsessionStorage.setItem(`${this.collectionName}-${value._id}`, JSON.stringify(value));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Finds the query in session storage and returns its value.\n\t * Returns null if query is not found.\n\t * Query is expected to have a member \"_id\" which is a unique id.\n\t *\n\t * @param query - what to find in the database\n\t */\n\tprivate findOneInternal(query: any): any {\n\t\tif (query._id) {\n\t\t\tconst json = sessionStorage.getItem(`${this.collectionName}-${query._id}`);\n\t\t\tif (json) {\n\t\t\t\treturn JSON.parse(json);\n\t\t\t}\n\t\t} else {\n\t\t\tconst queryKeys = Object.keys(query);\n\t\t\tfor (let i = 0; i < sessionStorage.length; i++) {\n\t\t\t\tconst ssKey = sessionStorage.key(i);\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tif (!ssKey!.startsWith(this.collectionName)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst value = JSON.parse(sessionStorage.getItem(ssKey!)!);\n\t\t\t\tlet foundMismatch = false;\n\t\t\t\tfor (const qk of queryKeys) {\n\t\t\t\t\tif (value[qk] !== query[qk]) {\n\t\t\t\t\t\tfoundMismatch = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!foundMismatch) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * A database for testing that stores data in the browsers session storage\n */\nclass LocalSessionStorageDb extends EventEmitter implements IDb {\n\tprivate readonly collections = new Map<string, LocalSessionStorageCollection<any>>();\n\tpublic async close(): Promise<void> {}\n\tpublic collection<T>(name: string): ICollection<T> {\n\t\tif (!this.collections.has(name)) {\n\t\t\tthis.collections.set(name, new LocalSessionStorageCollection<T>(name));\n\t\t}\n\t\treturn this.collections.get(name) as LocalSessionStorageCollection<T>;\n\t}\n\n\tpublic async dropCollection(name: string): Promise<boolean> {\n\t\tif (!this.collections.has(name)) {\n\t\t\treturn true;\n\t\t}\n\t\tthis.collections.delete(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * A database factory for testing that stores data in the browsers session storage\n * @internal\n */\nexport class LocalSessionStorageDbFactory implements ITestDbFactory {\n\tpublic readonly testDatabase: IDb = new LocalSessionStorageDb();\n\tpublic async connect(): Promise<IDb> {\n\t\treturn this.testDatabase;\n\t}\n}\n"]}
1
+ {"version":3,"file":"localSessionStorageDb.js","sourceRoot":"","sources":["../src/localSessionStorageDb.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"@fluid-internal/client-utils\";\nimport type { ICollection, IDb } from \"@fluidframework/server-services-core\";\nimport type { ITestDbFactory } from \"@fluidframework/server-test-utils\";\nimport { v4 as uuid } from \"uuid\";\n\n/**\n * A collection for local session storage, where data is stored in the browser\n * Functions include database operations such as queries, insertion and update.\n */\nclass LocalSessionStorageCollection<T> implements ICollection<T> {\n\t/**\n\t * @param collectionName - data type of the collection, e.g. blobs, deltas, trees, etc.\n\t */\n\tconstructor(private readonly collectionName: string) {}\n\n\tpublic aggregate(pipeline: any, options?: any): any {\n\t\tthrow new Error(\"Method Not Implemented\");\n\t}\n\n\tpublic async updateMany(filter: any, set: any, addToSet: any): Promise<void> {\n\t\tthrow new Error(\"Method Not Implemented\");\n\t}\n\tpublic async distinct(key: any, query: any): Promise<any> {\n\t\tthrow new Error(\"Method Not Implemented\");\n\t}\n\tpublic async findAndUpdate(query: any, value: T): Promise<{ value: T; existing: boolean }> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.find}\n\t */\n\t/*\n\t * Each query key consists of several keys separated by '.' e.g: \"operation.sequenceNumber\".\n\t * The hierarchical syntax allows finding nested key patterns.\n\t */\n\tpublic async find(query: any, sort: any): Promise<any[]> {\n\t\t// split the keys and get the corresponding value\n\t\tfunction getValueByKey(propertyBag, key: string): any {\n\t\t\tconst keys = key.split(\".\");\n\t\t\tlet value = propertyBag;\n\t\t\tfor (const splitKey of keys) {\n\t\t\t\tvalue = value[splitKey];\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t// getting keys of the query we are trying to find\n\t\tconst queryKeys = Object.keys(query);\n\t\tlet filteredCollection = this.getAllInternal();\n\t\tfor (const key of queryKeys) {\n\t\t\tif (!query[key]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (query[key].$gt > 0 || query[key].$lt > 0) {\n\t\t\t\tif (query[key].$gt > 0) {\n\t\t\t\t\tfilteredCollection = filteredCollection.filter(\n\t\t\t\t\t\t(value) => getValueByKey(value, key) > query[key].$gt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (query[key].$lt > 0) {\n\t\t\t\t\tfilteredCollection = filteredCollection.filter(\n\t\t\t\t\t\t(value) => getValueByKey(value, key) < query[key].$lt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfilteredCollection = filteredCollection.filter(\n\t\t\t\t\t(value) => getValueByKey(value, key) === query[key],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (sort && Object.keys(sort).length === 1) {\n\t\t\tfunction compare(a, b): number {\n\t\t\t\t// Non null asserting here because of the length check above\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst sortKey = Object.keys(sort)[0]!;\n\t\t\t\treturn sort[sortKey] === 1\n\t\t\t\t\t? getValueByKey(a, sortKey) - getValueByKey(b, sortKey)\n\t\t\t\t\t: getValueByKey(b, sortKey) - getValueByKey(a, sortKey);\n\t\t\t}\n\n\t\t\tfilteredCollection = filteredCollection.sort(compare);\n\t\t}\n\t\treturn filteredCollection;\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.findAll}\n\t */\n\tpublic async findAll(): Promise<any[]> {\n\t\treturn this.getAllInternal();\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.findOne}\n\t */\n\t/*\n\t * Query is expected to have a member \"_id\" which is a string used to find value in the database.\n\t */\n\tpublic async findOne(query: any): Promise<any> {\n\t\treturn this.findOneInternal(query);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.update}\n\t */\n\t/*\n\t * Query is expected to have a member \"_id\" which is a string used to find value in the database.\n\t */\n\tpublic async update(query: any, set: any, addToSet: any): Promise<void> {\n\t\tconst value = this.findOneInternal(query);\n\t\tif (value) {\n\t\t\tfor (const key of Object.keys(set)) {\n\t\t\t\tvalue[key] = set[key];\n\t\t\t}\n\t\t\tthis.insertInternal(value);\n\t\t} else {\n\t\t\tthrow new Error(\"Not found\");\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.upsert}\n\t */\n\t/*\n\t * Query is expected to have a member \"_id\" which is a string used to find value in the database.\n\t */\n\tpublic async upsert(query: any, set: any, addToSet: any): Promise<void> {\n\t\tconst value = this.findOneInternal(query);\n\t\tif (value) {\n\t\t\tfor (const key of Object.keys(set)) {\n\t\t\t\tvalue[key] = set[key];\n\t\t\t}\n\t\t\tthis.insertInternal(value);\n\t\t} else {\n\t\t\tthis.insertInternal(set);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.insertOne}\n\t */\n\t/*\n\t * Value is expected to have a member \"_id\" which is a string used to search in the database.\n\t */\n\tpublic async insertOne(value: any): Promise<any> {\n\t\tconst presentVal = this.findOneInternal(value);\n\t\t// Only raise error when the object is present and the value is not equal.\n\t\tif (presentVal) {\n\t\t\tif (JSON.stringify(presentVal) === JSON.stringify(value)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\"Existing Object!!\");\n\t\t}\n\n\t\treturn this.insertInternal(value);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.findOrCreate}\n\t */\n\t/*\n\t * Value and query are expected to have a member \"_id\" which is a string used to search or insert in the database.\n\t */\n\tpublic async findOrCreate(\n\t\tquery: any,\n\t\tvalue: any,\n\t): Promise<{ value: any; existing: boolean }> {\n\t\tconst existing = this.findOneInternal(query);\n\t\tif (existing) {\n\t\t\treturn { value: existing, existing: true };\n\t\t}\n\t\tthis.insertInternal(value);\n\t\treturn { value, existing: false };\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.insertMany}\n\t */\n\t/*\n\t * Each element in values is expected to have a member \"_id\" which is a string used to insert in the database.\n\t */\n\tpublic async insertMany(values: any[], ordered: boolean): Promise<void> {\n\t\tthis.insertInternal(...values);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.deleteOne}\n\t */\n\tpublic async deleteOne(query: any): Promise<any> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.deleteMany}\n\t */\n\tpublic async deleteMany(query: any): Promise<any> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/server-services-core#ICollection.createIndex}\n\t */\n\tpublic async createIndex(index: any, unique: boolean): Promise<void> {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\n\t/**\n\t * Return all values in the database\n\t */\n\tprivate getAllInternal(): any[] {\n\t\tconst values: string[] = [];\n\t\tfor (let i = 0; i < sessionStorage.length; i++) {\n\t\t\tconst key = sessionStorage.key(i);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tif (key!.startsWith(this.collectionName)) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tvalues.push(JSON.parse(sessionStorage.getItem(key!)!));\n\t\t\t}\n\t\t}\n\t\treturn values;\n\t}\n\n\t/**\n\t * Inserts values into the session storge.\n\t * Values are expected to have a member \"_id\" which is a unique id, otherwise will be assigned one\n\t *\n\t * @param values - data to insert to the database\n\t */\n\tprivate insertInternal(...values: any[]): void {\n\t\tfor (const value of values) {\n\t\t\tif (value) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\t\t\tif (!value._id) {\n\t\t\t\t\tvalue._id = uuid();\n\t\t\t\t}\n\t\t\t\tsessionStorage.setItem(`${this.collectionName}-${value._id}`, JSON.stringify(value));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Finds the query in session storage and returns its value.\n\t * Returns null if query is not found.\n\t * Query is expected to have a member \"_id\" which is a unique id.\n\t *\n\t * @param query - what to find in the database\n\t */\n\tprivate findOneInternal(query: any): any {\n\t\tif (query._id) {\n\t\t\tconst json = sessionStorage.getItem(`${this.collectionName}-${query._id}`);\n\t\t\tif (json) {\n\t\t\t\treturn JSON.parse(json);\n\t\t\t}\n\t\t} else {\n\t\t\tconst queryKeys = Object.keys(query);\n\t\t\tfor (let i = 0; i < sessionStorage.length; i++) {\n\t\t\t\tconst ssKey = sessionStorage.key(i);\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tif (!ssKey!.startsWith(this.collectionName)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tconst value = JSON.parse(sessionStorage.getItem(ssKey!)!);\n\t\t\t\tlet foundMismatch = false;\n\t\t\t\tfor (const qk of queryKeys) {\n\t\t\t\t\tif (value[qk] !== query[qk]) {\n\t\t\t\t\t\tfoundMismatch = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!foundMismatch) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * A database for testing that stores data in the browsers session storage\n */\nclass LocalSessionStorageDb extends EventEmitter implements IDb {\n\tprivate readonly collections = new Map<string, LocalSessionStorageCollection<any>>();\n\tpublic async close(): Promise<void> {}\n\tpublic collection<T>(name: string): ICollection<T> {\n\t\tif (!this.collections.has(name)) {\n\t\t\tthis.collections.set(name, new LocalSessionStorageCollection<T>(name));\n\t\t}\n\t\treturn this.collections.get(name) as LocalSessionStorageCollection<T>;\n\t}\n\n\tpublic async dropCollection(name: string): Promise<boolean> {\n\t\tif (!this.collections.has(name)) {\n\t\t\treturn true;\n\t\t}\n\t\tthis.collections.delete(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * A database factory for testing that stores data in the browsers session storage\n * @internal\n */\nexport class LocalSessionStorageDbFactory implements ITestDbFactory {\n\tpublic readonly testDatabase: IDb = new LocalSessionStorageDb();\n\tpublic async connect(): Promise<IDb> {\n\t\treturn this.testDatabase;\n\t}\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/local-driver";
8
- export declare const pkgVersion = "2.117.0";
8
+ export declare const pkgVersion = "3.0.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,iCAAiC,CAAC;AACtD,eAAO,MAAM,UAAU,YAAY,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,iCAAiC,CAAC;AACtD,eAAO,MAAM,UAAU,UAAU,CAAC"}
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/local-driver";
11
- exports.pkgVersion = "2.117.0";
11
+ exports.pkgVersion = "3.0.0";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/local-driver\";\nexport const pkgVersion = \"2.117.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,8BAA8B,CAAC;AACzC,QAAA,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/local-driver\";\nexport const pkgVersion = \"3.0.0\";\n"]}
package/lib/alpha.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {
@@ -75,15 +75,15 @@ let defaultEphemeralService;
75
75
  * Narrow an {@link EphemeralService} to it with `EphemeralServiceImplementation.narrow`.
76
76
  */
77
77
  class EphemeralServiceImplementation extends ErasedTypeImplementation {
78
+ // A single server is shared by all containers connected to this service so they can communicate with each other.
79
+ server = LocalDeltaConnectionServer.create(
80
+ // new LocalSessionStorageDbFactory(),
81
+ );
82
+ documentServiceFactory = new LocalDocumentServiceFactory(this.server);
83
+ containers = new Set();
84
+ closed = false;
78
85
  constructor() {
79
86
  super();
80
- // A single server is shared by all containers connected to this service so they can communicate with each other.
81
- this.server = LocalDeltaConnectionServer.create(
82
- // new LocalSessionStorageDbFactory(),
83
- );
84
- this.documentServiceFactory = new LocalDocumentServiceFactory(this.server);
85
- this.containers = new Set();
86
- this.closed = false;
87
87
  this.defaultClient = this.newClient();
88
88
  }
89
89
  newClient(options) {
@@ -93,6 +93,7 @@ class EphemeralServiceImplementation extends ErasedTypeImplementation {
93
93
  };
94
94
  return new EphemeralServiceClientImplementation(finalOptions);
95
95
  }
96
+ defaultClient;
96
97
  async close() {
97
98
  if (this.closed) {
98
99
  return;
@@ -200,6 +201,7 @@ class EphemeralServiceImplementation extends ErasedTypeImplementation {
200
201
  }
201
202
  }
202
203
  class EphemeralServiceClientImplementation extends ServiceClientImplementation {
204
+ service;
203
205
  constructor(options) {
204
206
  super(options, EphemeralServiceContainer);
205
207
  this.service = options.service;
@@ -211,7 +213,7 @@ const containerRuntimeLoader = async (parameters) => {
211
213
  registry: parameters.registry,
212
214
  provideEntryPoint: parameters.provideEntryPoint,
213
215
  existing: parameters.existing,
214
- minVersionForCollab: parameters.minVersionForCollab,
216
+ oldestSupportedClient: parameters.minVersionForCollab,
215
217
  runtimeOptions: { enableRuntimeIdCompressor: "on" },
216
218
  });
217
219
  if (!parameters.existing) {
@@ -246,6 +248,7 @@ let documentIdCounter = 0;
246
248
  * @internal
247
249
  */
248
250
  export class EphemeralServiceContainer extends ServiceContainerBase {
251
+ service;
249
252
  static async createDetached(registry, options, root) {
250
253
  EphemeralServiceImplementation.narrow(options.service);
251
254
  const container = await createDetachedContainer({
@@ -1 +1 @@
1
- {"version":3,"file":"ephemeralService.js","sourceRoot":"","sources":["../src/ephemeralService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tConnectionState,\n\ttype IContainer,\n} from \"@fluidframework/container-definitions/internal\";\nimport {\n\tcreateDetachedContainer,\n\tloadExistingContainer,\n} from \"@fluidframework/container-loader/internal\";\nimport { ContainerRuntime } from \"@fluidframework/container-runtime/internal\";\nimport type { IRequest } from \"@fluidframework/core-interfaces\";\nimport {\n\tErasedTypeImplementation,\n\ttype ErasedBaseType,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tfeatureVersion,\n\ttype DataStoreKind,\n\ttype DataStoreRegistry,\n\ttype FluidContainerAttached,\n\ttype FluidContainerWithService,\n\ttype OldestSupportedServiceClientVersion,\n\ttype Registry,\n\ttype ServiceClient,\n\ttype ServiceOptions,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\ttype ContainerRuntimeLoader,\n\ttype ContainerRuntimeLoaderParams,\n\tmakeCodeLoader,\n\trootDataStoreId,\n\tServiceClientImplementation,\n\tServiceContainerBase,\n} from \"@fluidframework/runtime-utils/internal\";\nimport {\n\tLocalDeltaConnectionServer,\n\ttype ILocalDeltaConnectionServer,\n} from \"@fluidframework/server-local-server\";\nimport { UsageError } from \"@fluidframework/driver-utils/internal\";\n\nimport { LocalDocumentServiceFactory } from \"./localDocumentServiceFactory.js\";\nimport { createLocalResolverCreateNewRequest, LocalResolver } from \"./localResolver.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\n\n/**\n * Starts and returns a new {@link EphemeralService}.\n * @param isDefault - Whether this service should saved as the default service for {@link cleanupEphemeralService} to cleanup.\n * Defaults to true.\n * @remarks\n * The returned service owns an in-memory server and holds the documents created through clients connected to it.\n * {@link cleanupEphemeralService} can be used to ensure the service is properly cleaned up (a no-op if stopped/closed already).\n *\n * As a service, it may start timers which may require an explicit `close` to fully free.\n * @alpha\n */\nexport function startEphemeralService(isDefault = true): EphemeralService {\n\tif (isDefault && defaultEphemeralService) {\n\t\tthrow new UsageError(\"A default EphemeralService is already running\");\n\t}\n\n\tconst service = new EphemeralServiceImplementation();\n\tif (isDefault) {\n\t\tdefaultEphemeralService = service;\n\t}\n\treturn service;\n}\n\n/**\n * Cleans up the service passed in {@link startEphemeralService}, or the {@link getDefaultEphemeralService|default} if none is passed.\n * @remarks\n * This closes the service, and all its containers.\n * This is a good way to ensure the service and its containers leave no lingering timers\n * which could leak memory, trigger asynchronous work or prevent a clean process exit.\n * @alpha\n */\nexport async function cleanupEphemeralService(service?: EphemeralService): Promise<void> {\n\tconst toCleanup = service ?? defaultEphemeralService;\n\tif (toCleanup) {\n\t\t// TODO: we may want to make closing of containers a separate operation which is done here.\n\t\tawait toCleanup.close();\n\t}\n\tif (toCleanup === defaultEphemeralService) {\n\t\tdefaultEphemeralService = undefined;\n\t}\n}\n\n/**\n * Get the default {@link EphemeralService} if one has been {@link startEphemeralService|started}.\n * @throws If no default service is running.\n * @alpha\n */\nexport function getDefaultEphemeralService(): EphemeralService {\n\tif (defaultEphemeralService) {\n\t\treturn defaultEphemeralService;\n\t}\n\tthrow new UsageError(\"No default EphemeralService is running\");\n}\n\n/**\n * Internal Options for creating an {@link EphemeralServiceClient}, extending {@link @fluidframework/driver-definitions#ServiceOptions}\n * with the {@link EphemeralService} the client should connect to.\n * @input\n * @internal\n */\nexport interface EphemeralServiceOptions extends ServiceOptions {\n\t/**\n\t * {@inheritdoc @fluidframework/driver-definitions#ServiceOptions.oldestSupportedClient}\n\t */\n\treadonly oldestSupportedClient: OldestSupportedServiceClientVersion;\n\t/**\n\t * The service instance to connect to.\n\t */\n\treadonly service: EphemeralService;\n}\n\n/**\n * An in-memory Fluid service that can produce connected {@link EphemeralServiceClient}s.\n * @remarks\n * All documents created through clients connected to a given `EphemeralService` are held in-memory by that service.\n * Closing the service (via {@link EphemeralService.close} or {@link cleanupEphemeralService}) closes the connections\n * to any remaining open containers, and cleans up the service's timers.\n *\n * Create one with {@link startEphemeralService}.\n *\n * Most {@link @fluidframework/driver-definitions#ServiceClient} implementations would take in a URL and credentials to connect to a service,\n * but that is not needed for the ephemeral in-memory service.\n * Instead this object representing the actual service instance is provided.\n * @privateRemarks\n * This is separated out from the actual {@link @fluidframework/driver-definitions#ServiceClient} object so that it's possible to create multiple service clients\n * connected to the same service.\n * Doing so is rarely necessary, but would be needed to test multiple clients collaborating on the same\n * document with different `oldestSupportedClient` values.\n * This also exposes a place to put APIs for preloading and exporting document contents in the future.\n *\n * This is an erased type: its only implementation is the module-private {@link EphemeralServiceImplementation}, which holds\n * the mutable server and container state so it does not appear on this public type.\n *\n * TODO: formalize this lifecycle with an interface which documents these stages.\n * Lifecycle:\n * The intended lifecycle of an {@link EphemeralService} follows roughly the same pattern as containers:\n *\n * 1. Open: accepts connections from {@link EphemeralServiceClient}s, which can create and load containers.\n * Might have timers and event registrations which can trigger asynchronous work, and retain the object in memory.\n *\n * 2. Closing: asynchronous transition from open to closed. New use should behave as it closed, but may be cleaning up or saving resources asynchronously.\n * Timers and event registrations may still be active, but should be cleaned up by the time the transition to closed completes.\n *\n * 3. Closed: no longer accepts connections from {@link EphemeralServiceClient}s, and all containers connected to it are closed.\n * Should have no subscriptions to events or timers which could retain it in memory or trigger asynchronous work.\n * The object can still be used in a limited capacity (typically just to inspect its status (e.g. `isClosed`), and to view (but not edit) the final state of any containers which were connected to it before it closed.)\n *\n * Events or errors can cause an open to closing transition. Any nonfunctional state, including error states, should be considered as closed (or closing which will transition to closed),\n * and meet the requirements of closed with regards to timers and events.\n *\n * @alpha @sealed\n */\nexport interface EphemeralService extends ErasedBaseType<readonly [\"EphemeralService\"]> {\n\t/**\n\t * Close this service, which closes all containers connected to it and releases its resources.\n\t * @remarks\n\t * All documents held by this service are discarded, and any timers it (or its containers) were keeping alive\n\t * are cleaned up.\n\t * The returned promise resolves once all asynchronous cleanup (including shutting down the in-memory server)\n\t * has completed.\n\t * Closing is idempotent: calling it again after the service is closed resolves without doing anything.\n\t */\n\tclose(): Promise<void>;\n\n\t/**\n\t * Drives all containers connected to this service toward convergence, processing pending operations and\n\t * waiting for all dirty containers to save.\n\t *\n\t * @param timeoutMilliseconds - The maximum time to wait for containers to quiesce, in milliseconds. Defaults to 30_000.\n\t *\n\t * @privateRemarks\n\t * This is a best-effort implementation simplified from `LoaderContainerTracker.ensureSynchronized`.\n\t * Currently it does not perform receiver-side sequence-number quiescence or wait for join/leave (audience) ops.\n\t * See `LoaderContainerTracker.ensureSynchronized` for the fuller version this is based on.\n\t * For the currently exposed API surface, this should be sufficient,\n\t * but users down casting to internal types might run into some limitations.\n\t */\n\tsynchronize(timeoutMilliseconds?: number): Promise<void>;\n\n\t/**\n\t * Creates and returns a {@link EphemeralServiceClient} for an in-memory, ephemeral Fluid service.\n\t *\n\t * @param options - Options for the client. `oldestSupportedClient` may be omitted because all\n\t * clients are in the same process, so it defaults to the current version. `service` may be omitted to allocate a new\n\t * {@link EphemeralService} dedicated to this client, or provided to connect the client to an existing service instance.\n\t *\n\t * @remarks\n\t * The service is ephemeral and in-memory: all documents are held by the {@link EphemeralService} the client is\n\t * connected to, and live for as long as that service is open — independent of whether any container for them is open.\n\t * A document created and attached (obtaining an `id`) can be loaded by `id` for as long as its service remains open,\n\t * even after every container for it has been closed.\n\t * Closing the service (via {@link EphemeralService.close} or {@link cleanupEphemeralService}) discards all of its\n\t * documents and releases its resources; afterwards those `id`s can no longer be loaded.\n\t *\n\t * When no `service` is provided, a new one is allocated for this client (accessible via {@link EphemeralServiceClient.service}).\n\t * Provide the same {@link EphemeralService} to multiple clients (via `options.service`) to have them collaborate on the\n\t * same documents, and control that service's lifetime explicitly.\n\t *\n\t * Since a service holds timers while open, tests should close the services they use (e.g. via\n\t * {@link cleanupEphemeralService} in an `afterEach`) to avoid lingering timers that can hang test runners.\n\t *\n\t * @privateRemarks\n\t * TODO: We should provide a way to extract (for potential serialization as test data) and load documents into a service.\n\t * This is needed to use this API surface for testing reference documents.\n\t * Ideally we would provide a service agnostic way to do the export, but likely only support loading them into the local service.\n\t * This can be done via an API on FluidContainer (or a free function taking one) to do the export, then adding a\n\t * service specific API (on {@link EphemeralService}) to load from the export format and return the ID of the loaded document.\n\t */\n\tnewClient(options: ServiceOptions): EphemeralServiceClient;\n\n\t/**\n\t * A client connected to this service using the default options.\n\t */\n\treadonly defaultClient: EphemeralServiceClient;\n}\n\n/**\n * The {@link defaultEphemeralService} if one has been {@link startEphemeralService|started}.\n */\nlet defaultEphemeralService: EphemeralServiceImplementation | undefined;\n\n/**\n * The concrete implementation of {@link EphemeralService}.\n * @remarks\n * Kept module-private so its mutable state and internal helpers are not part of the public API.\n * Narrow an {@link EphemeralService} to it with `EphemeralServiceImplementation.narrow`.\n */\nclass EphemeralServiceImplementation\n\textends ErasedTypeImplementation<EphemeralService>\n\timplements EphemeralService\n{\n\t// A single server is shared by all containers connected to this service so they can communicate with each other.\n\tprivate readonly server: ILocalDeltaConnectionServer =\n\t\tLocalDeltaConnectionServer.create(\n\t\t\t// new LocalSessionStorageDbFactory(),\n\t\t);\n\tprivate readonly documentServiceFactory = new LocalDocumentServiceFactory(this.server);\n\tprivate readonly containers = new Set<EphemeralServiceContainer<unknown>>();\n\tprivate closed = false;\n\n\tpublic constructor() {\n\t\tsuper();\n\t\tthis.defaultClient = this.newClient();\n\t}\n\tpublic newClient(options?: Partial<ServiceOptions>): EphemeralServiceClient {\n\t\tconst finalOptions: EphemeralServiceOptions = {\n\t\t\toldestSupportedClient: options?.oldestSupportedClient ?? featureVersion(pkgVersion),\n\t\t\tservice: this,\n\t\t};\n\t\treturn new EphemeralServiceClientImplementation(finalOptions);\n\t}\n\tpublic readonly defaultClient: EphemeralServiceClient;\n\n\tpublic async close(): Promise<void> {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = true;\n\n\t\t// Close every open container via the same public close() path a user would use.\n\t\t// We might want to remove this.\n\t\tconst toClose = [...this.containers];\n\t\tthis.containers.clear();\n\t\tfor (const c of toClose) {\n\t\t\tc.close();\n\t\t}\n\n\t\t// Shut down the in-memory server. Its timers (e.g. the Deli read-client idle `setInterval`) belong to the\n\t\t// server rather than any container, so closing containers alone would leave them running.\n\t\tawait this.server.close();\n\t}\n\n\tpublic async synchronize(timeoutMilliseconds = 30_000): Promise<void> {\n\t\t// Timeout to allow for better errors in the case of hangs.\n\t\tlet timedOut = false;\n\t\tlet deadlineTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst deadline = new Promise<true>((resolve) => {\n\t\t\tdeadlineTimer = setTimeout(() => {\n\t\t\t\ttimedOut = true;\n\t\t\t\tresolve(true);\n\t\t\t}, timeoutMilliseconds);\n\t\t});\n\n\t\ttry {\n\t\t\t// Require two consecutive quiescent passes (no dirty containers and no pending server work),\n\t\t\t// each separated by a macrotask turn, to give late side effects a chance to surface.\n\t\t\tlet clean = 0;\n\t\t\twhile (clean < 2) {\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t`EphemeralService.synchronize timed out after ${timeoutMilliseconds}ms waiting for local containers to quiesce.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Yield a macrotask turn *first*, so the local server's scheduled broadcast send and each\n\t\t\t\t// container's inbound op processing can run before we sample their state below. Sampling\n\t\t\t\t// hasPendingWork() in a tight `while (await ...)` loop instead would starve that scheduled\n\t\t\t\t// send (it is a macrotask, while the await resolves on the microtask queue) and could hang.\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tsetTimeout(resolve, 0);\n\t\t\t\t});\n\n\t\t\t\t// Prune any containers that have closed since the last pass.\n\t\t\t\tfor (const container of [...this.containers]) {\n\t\t\t\t\tif (container.container.closed) {\n\t\t\t\t\t\tthis.containers.delete(container);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst containersToApply = [...this.containers].map((container) => container.container);\n\n\t\t\t\t// Ignore readonly/disconnected dirty containers: they can't send ops, so nothing can be done about them being dirty here.\n\t\t\t\t// Neither state is reachable through the ephemeral service API today, but the checks are cheap and keep this robust to future changes.\n\t\t\t\tconst dirtyContainers = containersToApply.filter((c) => {\n\t\t\t\t\tconst { deltaManager, isDirty, connectionState } = c;\n\t\t\t\t\treturn (\n\t\t\t\t\t\tconnectionState !== ConnectionState.Disconnected &&\n\t\t\t\t\t\tdeltaManager.readOnlyInfo.readonly !== true &&\n\t\t\t\t\t\tisDirty\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\tif (dirtyContainers.length > 0) {\n\t\t\t\t\t// Bound this wait by the shared deadline: a container that never saves (and never\n\t\t\t\t\t// closes) must not block past the overall timeout, since the top-of-loop check can't\n\t\t\t\t\t// run while we are awaiting here.\n\t\t\t\t\tawait Promise.race([\n\t\t\t\t\t\tPromise.all(\n\t\t\t\t\t\t\tdirtyContainers.map(async (c) =>\n\t\t\t\t\t\t\t\tPromise.race([\n\t\t\t\t\t\t\t\t\tnew Promise((resolve) => c.once(\"saved\", resolve)),\n\t\t\t\t\t\t\t\t\tnew Promise((resolve) => c.once(\"closed\", resolve)),\n\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tdeadline,\n\t\t\t\t\t]);\n\n\t\t\t\t\tclean = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Sample pending server work once per pass (the macrotask yield above gave the broadcaster's\n\t\t\t\t// scheduled send a chance to run first).\n\t\t\t\tif (await Promise.race([this.server.hasPendingWork(), deadline])) {\n\t\t\t\t\tclean = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tclean++;\n\t\t\t}\n\t\t} finally {\n\t\t\tclearTimeout(deadlineTimer);\n\t\t}\n\t}\n\n\t/**\n\t * The document service factory for this service.\n\t * @remarks Internal helper for {@link EphemeralServiceContainer}; not part of the public {@link EphemeralService} API.\n\t */\n\tpublic getDocumentServiceFactory(): LocalDocumentServiceFactory {\n\t\tassert(\n\t\t\t!this.closed,\n\t\t\t0xd11 /* Cannot create or load containers on a closed EphemeralService */,\n\t\t);\n\t\treturn this.documentServiceFactory;\n\t}\n\n\t/**\n\t * Registers a newly created container as connected to this service.\n\t * @remarks Internal helper for {@link EphemeralServiceContainer}; not part of the public {@link EphemeralService} API.\n\t */\n\tpublic addContainer(container: EphemeralServiceContainer<unknown>): void {\n\t\tthis.containers.add(container);\n\t}\n\n\t/**\n\t * Removes a now-closed container from this service.\n\t * @remarks Internal helper for {@link EphemeralServiceContainer}; not part of the public {@link EphemeralService} API.\n\t */\n\tpublic removeContainer(container: EphemeralServiceContainer<unknown>): void {\n\t\tthis.containers.delete(container);\n\t}\n}\n\n/**\n * A {@link @fluidframework/driver-definitions#ServiceClient} connected to a specific {@link EphemeralService}.\n * @alpha @sealed\n */\nexport interface EphemeralServiceClient extends ServiceClient {\n\t/**\n\t * The service instance this client is connected to.\n\t */\n\treadonly service: EphemeralService;\n}\n\nclass EphemeralServiceClientImplementation\n\textends ServiceClientImplementation<EphemeralServiceOptions>\n\timplements EphemeralServiceClient\n{\n\tpublic readonly service: EphemeralService;\n\n\tpublic constructor(options: EphemeralServiceOptions) {\n\t\tsuper(options, EphemeralServiceContainer);\n\t\tthis.service = options.service;\n\t}\n}\n\nconst containerRuntimeLoader: ContainerRuntimeLoader = async (\n\tparameters: ContainerRuntimeLoaderParams,\n) => {\n\tconst { runtime } = await ContainerRuntime.loadRuntime2({\n\t\tcontext: parameters.context,\n\t\tregistry: parameters.registry,\n\t\tprovideEntryPoint: parameters.provideEntryPoint,\n\t\texisting: parameters.existing,\n\t\tminVersionForCollab: parameters.minVersionForCollab,\n\t\truntimeOptions: { enableRuntimeIdCompressor: \"on\" },\n\t});\n\tif (!parameters.existing) {\n\t\tassert(\n\t\t\tparameters.newContainerRootType !== undefined,\n\t\t\t0xd12 /* Root data store kind must be provided for new containers */,\n\t\t);\n\t\tconst dataStore = await runtime.createDataStore(parameters.newContainerRootType);\n\t\tconst aliasResult = await dataStore.trySetAlias(rootDataStoreId);\n\t\tassert(\n\t\t\taliasResult === \"Success\",\n\t\t\t0xd13 /* Should be able to set alias on new data store */,\n\t\t);\n\t}\n\treturn runtime;\n};\n\nconst urlResolver = new LocalResolver();\n/**\n * Create a request to open an existing document.\n *\n * @param documentId - the existing document to open.\n * @privateRemarks\n * Like createLocalResolverCreateNewRequest, but without the option to create a new document.\n * TODO: At some point we should avoid specifying the URL in so many places, but the current APIs don't accommodate it yet.\n */\nconst createLoadExistingRequest = (documentId: string): IRequest => {\n\treturn { url: `http://localhost:3000/${documentId}` };\n};\n\nlet documentIdCounter = 0;\n\n/**\n * A Fluid container backed by an ephemeral (in-memory) local service, implementing\n * {@link @fluidframework/driver-definitions#FluidContainerWithService}.\n *\n * @remarks\n * Data is stored in-memory by the {@link EphemeralService} the container's client is connected to (see\n * {@link EphemeralServiceContainer.service}), enabling side-by-side collaboration testing without a real server.\n *\n * @internal\n */\nexport class EphemeralServiceContainer<TData>\n\textends ServiceContainerBase<TData, EphemeralServiceOptions>\n\timplements FluidContainerWithService<TData>\n{\n\tpublic readonly service: EphemeralService;\n\n\tpublic static async createDetached<T>(\n\t\tregistry: DataStoreRegistry<T>,\n\t\toptions: EphemeralServiceOptions,\n\t\troot: DataStoreKind<T>,\n\t): Promise<EphemeralServiceContainer<T>> {\n\t\tEphemeralServiceImplementation.narrow(options.service);\n\t\tconst container: IContainer = await createDetachedContainer({\n\t\t\tcodeDetails: { package: \"1.0\" },\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory: options.service.getDocumentServiceFactory(),\n\t\t\tcodeLoader: makeCodeLoader(\n\t\t\t\tregistry,\n\t\t\t\toptions.oldestSupportedClient,\n\t\t\t\tcontainerRuntimeLoader,\n\t\t\t\troot,\n\t\t\t),\n\t\t});\n\n\t\treturn new EphemeralServiceContainer<T>(\n\t\t\tregistry,\n\t\t\toptions,\n\t\t\tcontainer,\n\t\t\t(await container.getEntryPoint()) as T,\n\t\t\tundefined,\n\t\t);\n\t}\n\n\tpublic static async load<T>(\n\t\tregistry: DataStoreRegistry<T>,\n\t\toptions: EphemeralServiceOptions,\n\t\tid: string,\n\t): Promise<EphemeralServiceContainer<T> & FluidContainerAttached<T>> {\n\t\tEphemeralServiceImplementation.narrow(options.service);\n\t\tconst containerInner = await loadExistingContainer({\n\t\t\trequest: createLoadExistingRequest(id),\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory: options.service.getDocumentServiceFactory(),\n\t\t\tcodeLoader: makeCodeLoader(\n\t\t\t\tregistry,\n\t\t\t\toptions.oldestSupportedClient,\n\t\t\t\tcontainerRuntimeLoader,\n\t\t\t),\n\t\t});\n\n\t\tconst container = new EphemeralServiceContainer<T>(\n\t\t\tregistry,\n\t\t\toptions,\n\t\t\tcontainerInner,\n\t\t\t(await containerInner.getEntryPoint()) as T,\n\t\t\tid,\n\t\t);\n\t\tassert(\n\t\t\tcontainer.id !== undefined,\n\t\t\t0xd14 /* id should be defined when loading a container */,\n\t\t);\n\t\treturn container as typeof container & { id: string };\n\t}\n\n\tprivate constructor(\n\t\tregistry: Registry<Promise<DataStoreKind<TData>>>,\n\t\toptions: EphemeralServiceOptions,\n\t\tcontainer: IContainer,\n\t\tdata: TData,\n\t\tid: string | undefined,\n\t) {\n\t\tsuper(registry, options, container, data, id);\n\t\tthis.service = options.service;\n\t\tEphemeralServiceImplementation.narrow(this.service);\n\t\tthis.service.addContainer(this);\n\t}\n\n\tpublic override close(): void {\n\t\tsuper.close();\n\t\t// Remove this now-closed container from its service's set of open containers.\n\t\tEphemeralServiceImplementation.narrow(this.service);\n\t\tthis.service.removeContainer(this);\n\t}\n\n\tprotected createAttachRequest(): IRequest {\n\t\tconst documentId = (documentIdCounter++).toString();\n\t\treturn createLocalResolverCreateNewRequest(documentId);\n\t}\n}\n"]}
1
+ {"version":3,"file":"ephemeralService.js","sourceRoot":"","sources":["../src/ephemeralService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tConnectionState,\n\ttype IContainer,\n} from \"@fluidframework/container-definitions/internal\";\nimport {\n\tcreateDetachedContainer,\n\tloadExistingContainer,\n} from \"@fluidframework/container-loader/internal\";\nimport { ContainerRuntime } from \"@fluidframework/container-runtime/internal\";\nimport type { IRequest } from \"@fluidframework/core-interfaces\";\nimport {\n\tErasedTypeImplementation,\n\ttype ErasedBaseType,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tfeatureVersion,\n\ttype DataStoreKind,\n\ttype DataStoreRegistry,\n\ttype FluidContainerAttached,\n\ttype FluidContainerWithService,\n\ttype OldestSupportedServiceClientVersion,\n\ttype Registry,\n\ttype ServiceClient,\n\ttype ServiceOptions,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\ttype ContainerRuntimeLoader,\n\ttype ContainerRuntimeLoaderParams,\n\tmakeCodeLoader,\n\trootDataStoreId,\n\tServiceClientImplementation,\n\tServiceContainerBase,\n} from \"@fluidframework/runtime-utils/internal\";\nimport {\n\tLocalDeltaConnectionServer,\n\ttype ILocalDeltaConnectionServer,\n} from \"@fluidframework/server-local-server\";\nimport { UsageError } from \"@fluidframework/driver-utils/internal\";\n\nimport { LocalDocumentServiceFactory } from \"./localDocumentServiceFactory.js\";\nimport { createLocalResolverCreateNewRequest, LocalResolver } from \"./localResolver.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\n\n/**\n * Starts and returns a new {@link EphemeralService}.\n * @param isDefault - Whether this service should saved as the default service for {@link cleanupEphemeralService} to cleanup.\n * Defaults to true.\n * @remarks\n * The returned service owns an in-memory server and holds the documents created through clients connected to it.\n * {@link cleanupEphemeralService} can be used to ensure the service is properly cleaned up (a no-op if stopped/closed already).\n *\n * As a service, it may start timers which may require an explicit `close` to fully free.\n * @alpha\n */\nexport function startEphemeralService(isDefault = true): EphemeralService {\n\tif (isDefault && defaultEphemeralService) {\n\t\tthrow new UsageError(\"A default EphemeralService is already running\");\n\t}\n\n\tconst service = new EphemeralServiceImplementation();\n\tif (isDefault) {\n\t\tdefaultEphemeralService = service;\n\t}\n\treturn service;\n}\n\n/**\n * Cleans up the service passed in {@link startEphemeralService}, or the {@link getDefaultEphemeralService|default} if none is passed.\n * @remarks\n * This closes the service, and all its containers.\n * This is a good way to ensure the service and its containers leave no lingering timers\n * which could leak memory, trigger asynchronous work or prevent a clean process exit.\n * @alpha\n */\nexport async function cleanupEphemeralService(service?: EphemeralService): Promise<void> {\n\tconst toCleanup = service ?? defaultEphemeralService;\n\tif (toCleanup) {\n\t\t// TODO: we may want to make closing of containers a separate operation which is done here.\n\t\tawait toCleanup.close();\n\t}\n\tif (toCleanup === defaultEphemeralService) {\n\t\tdefaultEphemeralService = undefined;\n\t}\n}\n\n/**\n * Get the default {@link EphemeralService} if one has been {@link startEphemeralService|started}.\n * @throws If no default service is running.\n * @alpha\n */\nexport function getDefaultEphemeralService(): EphemeralService {\n\tif (defaultEphemeralService) {\n\t\treturn defaultEphemeralService;\n\t}\n\tthrow new UsageError(\"No default EphemeralService is running\");\n}\n\n/**\n * Internal Options for creating an {@link EphemeralServiceClient}, extending {@link @fluidframework/driver-definitions#ServiceOptions}\n * with the {@link EphemeralService} the client should connect to.\n * @input\n * @internal\n */\nexport interface EphemeralServiceOptions extends ServiceOptions {\n\t/**\n\t * {@inheritdoc @fluidframework/driver-definitions#ServiceOptions.oldestSupportedClient}\n\t */\n\treadonly oldestSupportedClient: OldestSupportedServiceClientVersion;\n\t/**\n\t * The service instance to connect to.\n\t */\n\treadonly service: EphemeralService;\n}\n\n/**\n * An in-memory Fluid service that can produce connected {@link EphemeralServiceClient}s.\n * @remarks\n * All documents created through clients connected to a given `EphemeralService` are held in-memory by that service.\n * Closing the service (via {@link EphemeralService.close} or {@link cleanupEphemeralService}) closes the connections\n * to any remaining open containers, and cleans up the service's timers.\n *\n * Create one with {@link startEphemeralService}.\n *\n * Most {@link @fluidframework/driver-definitions#ServiceClient} implementations would take in a URL and credentials to connect to a service,\n * but that is not needed for the ephemeral in-memory service.\n * Instead this object representing the actual service instance is provided.\n * @privateRemarks\n * This is separated out from the actual {@link @fluidframework/driver-definitions#ServiceClient} object so that it's possible to create multiple service clients\n * connected to the same service.\n * Doing so is rarely necessary, but would be needed to test multiple clients collaborating on the same\n * document with different `oldestSupportedClient` values.\n * This also exposes a place to put APIs for preloading and exporting document contents in the future.\n *\n * This is an erased type: its only implementation is the module-private {@link EphemeralServiceImplementation}, which holds\n * the mutable server and container state so it does not appear on this public type.\n *\n * TODO: formalize this lifecycle with an interface which documents these stages.\n * Lifecycle:\n * The intended lifecycle of an {@link EphemeralService} follows roughly the same pattern as containers:\n *\n * 1. Open: accepts connections from {@link EphemeralServiceClient}s, which can create and load containers.\n * Might have timers and event registrations which can trigger asynchronous work, and retain the object in memory.\n *\n * 2. Closing: asynchronous transition from open to closed. New use should behave as it closed, but may be cleaning up or saving resources asynchronously.\n * Timers and event registrations may still be active, but should be cleaned up by the time the transition to closed completes.\n *\n * 3. Closed: no longer accepts connections from {@link EphemeralServiceClient}s, and all containers connected to it are closed.\n * Should have no subscriptions to events or timers which could retain it in memory or trigger asynchronous work.\n * The object can still be used in a limited capacity (typically just to inspect its status (e.g. `isClosed`), and to view (but not edit) the final state of any containers which were connected to it before it closed.)\n *\n * Events or errors can cause an open to closing transition. Any nonfunctional state, including error states, should be considered as closed (or closing which will transition to closed),\n * and meet the requirements of closed with regards to timers and events.\n *\n * @alpha @sealed\n */\nexport interface EphemeralService extends ErasedBaseType<readonly [\"EphemeralService\"]> {\n\t/**\n\t * Close this service, which closes all containers connected to it and releases its resources.\n\t * @remarks\n\t * All documents held by this service are discarded, and any timers it (or its containers) were keeping alive\n\t * are cleaned up.\n\t * The returned promise resolves once all asynchronous cleanup (including shutting down the in-memory server)\n\t * has completed.\n\t * Closing is idempotent: calling it again after the service is closed resolves without doing anything.\n\t */\n\tclose(): Promise<void>;\n\n\t/**\n\t * Drives all containers connected to this service toward convergence, processing pending operations and\n\t * waiting for all dirty containers to save.\n\t *\n\t * @param timeoutMilliseconds - The maximum time to wait for containers to quiesce, in milliseconds. Defaults to 30_000.\n\t *\n\t * @privateRemarks\n\t * This is a best-effort implementation simplified from `LoaderContainerTracker.ensureSynchronized`.\n\t * Currently it does not perform receiver-side sequence-number quiescence or wait for join/leave (audience) ops.\n\t * See `LoaderContainerTracker.ensureSynchronized` for the fuller version this is based on.\n\t * For the currently exposed API surface, this should be sufficient,\n\t * but users down casting to internal types might run into some limitations.\n\t */\n\tsynchronize(timeoutMilliseconds?: number): Promise<void>;\n\n\t/**\n\t * Creates and returns a {@link EphemeralServiceClient} for an in-memory, ephemeral Fluid service.\n\t *\n\t * @param options - Options for the client. `oldestSupportedClient` may be omitted because all\n\t * clients are in the same process, so it defaults to the current version. `service` may be omitted to allocate a new\n\t * {@link EphemeralService} dedicated to this client, or provided to connect the client to an existing service instance.\n\t *\n\t * @remarks\n\t * The service is ephemeral and in-memory: all documents are held by the {@link EphemeralService} the client is\n\t * connected to, and live for as long as that service is open — independent of whether any container for them is open.\n\t * A document created and attached (obtaining an `id`) can be loaded by `id` for as long as its service remains open,\n\t * even after every container for it has been closed.\n\t * Closing the service (via {@link EphemeralService.close} or {@link cleanupEphemeralService}) discards all of its\n\t * documents and releases its resources; afterwards those `id`s can no longer be loaded.\n\t *\n\t * When no `service` is provided, a new one is allocated for this client (accessible via {@link EphemeralServiceClient.service}).\n\t * Provide the same {@link EphemeralService} to multiple clients (via `options.service`) to have them collaborate on the\n\t * same documents, and control that service's lifetime explicitly.\n\t *\n\t * Since a service holds timers while open, tests should close the services they use (e.g. via\n\t * {@link cleanupEphemeralService} in an `afterEach`) to avoid lingering timers that can hang test runners.\n\t *\n\t * @privateRemarks\n\t * TODO: We should provide a way to extract (for potential serialization as test data) and load documents into a service.\n\t * This is needed to use this API surface for testing reference documents.\n\t * Ideally we would provide a service agnostic way to do the export, but likely only support loading them into the local service.\n\t * This can be done via an API on FluidContainer (or a free function taking one) to do the export, then adding a\n\t * service specific API (on {@link EphemeralService}) to load from the export format and return the ID of the loaded document.\n\t */\n\tnewClient(options: ServiceOptions): EphemeralServiceClient;\n\n\t/**\n\t * A client connected to this service using the default options.\n\t */\n\treadonly defaultClient: EphemeralServiceClient;\n}\n\n/**\n * The {@link defaultEphemeralService} if one has been {@link startEphemeralService|started}.\n */\nlet defaultEphemeralService: EphemeralServiceImplementation | undefined;\n\n/**\n * The concrete implementation of {@link EphemeralService}.\n * @remarks\n * Kept module-private so its mutable state and internal helpers are not part of the public API.\n * Narrow an {@link EphemeralService} to it with `EphemeralServiceImplementation.narrow`.\n */\nclass EphemeralServiceImplementation\n\textends ErasedTypeImplementation<EphemeralService>\n\timplements EphemeralService\n{\n\t// A single server is shared by all containers connected to this service so they can communicate with each other.\n\tprivate readonly server: ILocalDeltaConnectionServer =\n\t\tLocalDeltaConnectionServer.create(\n\t\t\t// new LocalSessionStorageDbFactory(),\n\t\t);\n\tprivate readonly documentServiceFactory = new LocalDocumentServiceFactory(this.server);\n\tprivate readonly containers = new Set<EphemeralServiceContainer<unknown>>();\n\tprivate closed = false;\n\n\tpublic constructor() {\n\t\tsuper();\n\t\tthis.defaultClient = this.newClient();\n\t}\n\tpublic newClient(options?: Partial<ServiceOptions>): EphemeralServiceClient {\n\t\tconst finalOptions: EphemeralServiceOptions = {\n\t\t\toldestSupportedClient: options?.oldestSupportedClient ?? featureVersion(pkgVersion),\n\t\t\tservice: this,\n\t\t};\n\t\treturn new EphemeralServiceClientImplementation(finalOptions);\n\t}\n\tpublic readonly defaultClient: EphemeralServiceClient;\n\n\tpublic async close(): Promise<void> {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = true;\n\n\t\t// Close every open container via the same public close() path a user would use.\n\t\t// We might want to remove this.\n\t\tconst toClose = [...this.containers];\n\t\tthis.containers.clear();\n\t\tfor (const c of toClose) {\n\t\t\tc.close();\n\t\t}\n\n\t\t// Shut down the in-memory server. Its timers (e.g. the Deli read-client idle `setInterval`) belong to the\n\t\t// server rather than any container, so closing containers alone would leave them running.\n\t\tawait this.server.close();\n\t}\n\n\tpublic async synchronize(timeoutMilliseconds = 30_000): Promise<void> {\n\t\t// Timeout to allow for better errors in the case of hangs.\n\t\tlet timedOut = false;\n\t\tlet deadlineTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst deadline = new Promise<true>((resolve) => {\n\t\t\tdeadlineTimer = setTimeout(() => {\n\t\t\t\ttimedOut = true;\n\t\t\t\tresolve(true);\n\t\t\t}, timeoutMilliseconds);\n\t\t});\n\n\t\ttry {\n\t\t\t// Require two consecutive quiescent passes (no dirty containers and no pending server work),\n\t\t\t// each separated by a macrotask turn, to give late side effects a chance to surface.\n\t\t\tlet clean = 0;\n\t\t\twhile (clean < 2) {\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t`EphemeralService.synchronize timed out after ${timeoutMilliseconds}ms waiting for local containers to quiesce.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Yield a macrotask turn *first*, so the local server's scheduled broadcast send and each\n\t\t\t\t// container's inbound op processing can run before we sample their state below. Sampling\n\t\t\t\t// hasPendingWork() in a tight `while (await ...)` loop instead would starve that scheduled\n\t\t\t\t// send (it is a macrotask, while the await resolves on the microtask queue) and could hang.\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tsetTimeout(resolve, 0);\n\t\t\t\t});\n\n\t\t\t\t// Prune any containers that have closed since the last pass.\n\t\t\t\tfor (const container of [...this.containers]) {\n\t\t\t\t\tif (container.container.closed) {\n\t\t\t\t\t\tthis.containers.delete(container);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst containersToApply = [...this.containers].map((container) => container.container);\n\n\t\t\t\t// Ignore readonly/disconnected dirty containers: they can't send ops, so nothing can be done about them being dirty here.\n\t\t\t\t// Neither state is reachable through the ephemeral service API today, but the checks are cheap and keep this robust to future changes.\n\t\t\t\tconst dirtyContainers = containersToApply.filter((c) => {\n\t\t\t\t\tconst { deltaManager, isDirty, connectionState } = c;\n\t\t\t\t\treturn (\n\t\t\t\t\t\tconnectionState !== ConnectionState.Disconnected &&\n\t\t\t\t\t\tdeltaManager.readOnlyInfo.readonly !== true &&\n\t\t\t\t\t\tisDirty\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\tif (dirtyContainers.length > 0) {\n\t\t\t\t\t// Bound this wait by the shared deadline: a container that never saves (and never\n\t\t\t\t\t// closes) must not block past the overall timeout, since the top-of-loop check can't\n\t\t\t\t\t// run while we are awaiting here.\n\t\t\t\t\tawait Promise.race([\n\t\t\t\t\t\tPromise.all(\n\t\t\t\t\t\t\tdirtyContainers.map(async (c) =>\n\t\t\t\t\t\t\t\tPromise.race([\n\t\t\t\t\t\t\t\t\tnew Promise((resolve) => c.once(\"saved\", resolve)),\n\t\t\t\t\t\t\t\t\tnew Promise((resolve) => c.once(\"closed\", resolve)),\n\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tdeadline,\n\t\t\t\t\t]);\n\n\t\t\t\t\tclean = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Sample pending server work once per pass (the macrotask yield above gave the broadcaster's\n\t\t\t\t// scheduled send a chance to run first).\n\t\t\t\tif (await Promise.race([this.server.hasPendingWork(), deadline])) {\n\t\t\t\t\tclean = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tclean++;\n\t\t\t}\n\t\t} finally {\n\t\t\tclearTimeout(deadlineTimer);\n\t\t}\n\t}\n\n\t/**\n\t * The document service factory for this service.\n\t * @remarks Internal helper for {@link EphemeralServiceContainer}; not part of the public {@link EphemeralService} API.\n\t */\n\tpublic getDocumentServiceFactory(): LocalDocumentServiceFactory {\n\t\tassert(\n\t\t\t!this.closed,\n\t\t\t0xd11 /* Cannot create or load containers on a closed EphemeralService */,\n\t\t);\n\t\treturn this.documentServiceFactory;\n\t}\n\n\t/**\n\t * Registers a newly created container as connected to this service.\n\t * @remarks Internal helper for {@link EphemeralServiceContainer}; not part of the public {@link EphemeralService} API.\n\t */\n\tpublic addContainer(container: EphemeralServiceContainer<unknown>): void {\n\t\tthis.containers.add(container);\n\t}\n\n\t/**\n\t * Removes a now-closed container from this service.\n\t * @remarks Internal helper for {@link EphemeralServiceContainer}; not part of the public {@link EphemeralService} API.\n\t */\n\tpublic removeContainer(container: EphemeralServiceContainer<unknown>): void {\n\t\tthis.containers.delete(container);\n\t}\n}\n\n/**\n * A {@link @fluidframework/driver-definitions#ServiceClient} connected to a specific {@link EphemeralService}.\n * @alpha @sealed\n */\nexport interface EphemeralServiceClient extends ServiceClient {\n\t/**\n\t * The service instance this client is connected to.\n\t */\n\treadonly service: EphemeralService;\n}\n\nclass EphemeralServiceClientImplementation\n\textends ServiceClientImplementation<EphemeralServiceOptions>\n\timplements EphemeralServiceClient\n{\n\tpublic readonly service: EphemeralService;\n\n\tpublic constructor(options: EphemeralServiceOptions) {\n\t\tsuper(options, EphemeralServiceContainer);\n\t\tthis.service = options.service;\n\t}\n}\n\nconst containerRuntimeLoader: ContainerRuntimeLoader = async (\n\tparameters: ContainerRuntimeLoaderParams,\n) => {\n\tconst { runtime } = await ContainerRuntime.loadRuntime2({\n\t\tcontext: parameters.context,\n\t\tregistry: parameters.registry,\n\t\tprovideEntryPoint: parameters.provideEntryPoint,\n\t\texisting: parameters.existing,\n\t\toldestSupportedClient: parameters.minVersionForCollab,\n\t\truntimeOptions: { enableRuntimeIdCompressor: \"on\" },\n\t});\n\tif (!parameters.existing) {\n\t\tassert(\n\t\t\tparameters.newContainerRootType !== undefined,\n\t\t\t0xd12 /* Root data store kind must be provided for new containers */,\n\t\t);\n\t\tconst dataStore = await runtime.createDataStore(parameters.newContainerRootType);\n\t\tconst aliasResult = await dataStore.trySetAlias(rootDataStoreId);\n\t\tassert(\n\t\t\taliasResult === \"Success\",\n\t\t\t0xd13 /* Should be able to set alias on new data store */,\n\t\t);\n\t}\n\treturn runtime;\n};\n\nconst urlResolver = new LocalResolver();\n/**\n * Create a request to open an existing document.\n *\n * @param documentId - the existing document to open.\n * @privateRemarks\n * Like createLocalResolverCreateNewRequest, but without the option to create a new document.\n * TODO: At some point we should avoid specifying the URL in so many places, but the current APIs don't accommodate it yet.\n */\nconst createLoadExistingRequest = (documentId: string): IRequest => {\n\treturn { url: `http://localhost:3000/${documentId}` };\n};\n\nlet documentIdCounter = 0;\n\n/**\n * A Fluid container backed by an ephemeral (in-memory) local service, implementing\n * {@link @fluidframework/driver-definitions#FluidContainerWithService}.\n *\n * @remarks\n * Data is stored in-memory by the {@link EphemeralService} the container's client is connected to (see\n * {@link EphemeralServiceContainer.service}), enabling side-by-side collaboration testing without a real server.\n *\n * @internal\n */\nexport class EphemeralServiceContainer<TData>\n\textends ServiceContainerBase<TData, EphemeralServiceOptions>\n\timplements FluidContainerWithService<TData>\n{\n\tpublic readonly service: EphemeralService;\n\n\tpublic static async createDetached<T>(\n\t\tregistry: DataStoreRegistry<T>,\n\t\toptions: EphemeralServiceOptions,\n\t\troot: DataStoreKind<T>,\n\t): Promise<EphemeralServiceContainer<T>> {\n\t\tEphemeralServiceImplementation.narrow(options.service);\n\t\tconst container: IContainer = await createDetachedContainer({\n\t\t\tcodeDetails: { package: \"1.0\" },\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory: options.service.getDocumentServiceFactory(),\n\t\t\tcodeLoader: makeCodeLoader(\n\t\t\t\tregistry,\n\t\t\t\toptions.oldestSupportedClient,\n\t\t\t\tcontainerRuntimeLoader,\n\t\t\t\troot,\n\t\t\t),\n\t\t});\n\n\t\treturn new EphemeralServiceContainer<T>(\n\t\t\tregistry,\n\t\t\toptions,\n\t\t\tcontainer,\n\t\t\t(await container.getEntryPoint()) as T,\n\t\t\tundefined,\n\t\t);\n\t}\n\n\tpublic static async load<T>(\n\t\tregistry: DataStoreRegistry<T>,\n\t\toptions: EphemeralServiceOptions,\n\t\tid: string,\n\t): Promise<EphemeralServiceContainer<T> & FluidContainerAttached<T>> {\n\t\tEphemeralServiceImplementation.narrow(options.service);\n\t\tconst containerInner = await loadExistingContainer({\n\t\t\trequest: createLoadExistingRequest(id),\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory: options.service.getDocumentServiceFactory(),\n\t\t\tcodeLoader: makeCodeLoader(\n\t\t\t\tregistry,\n\t\t\t\toptions.oldestSupportedClient,\n\t\t\t\tcontainerRuntimeLoader,\n\t\t\t),\n\t\t});\n\n\t\tconst container = new EphemeralServiceContainer<T>(\n\t\t\tregistry,\n\t\t\toptions,\n\t\t\tcontainerInner,\n\t\t\t(await containerInner.getEntryPoint()) as T,\n\t\t\tid,\n\t\t);\n\t\tassert(\n\t\t\tcontainer.id !== undefined,\n\t\t\t0xd14 /* id should be defined when loading a container */,\n\t\t);\n\t\treturn container as typeof container & { id: string };\n\t}\n\n\tprivate constructor(\n\t\tregistry: Registry<Promise<DataStoreKind<TData>>>,\n\t\toptions: EphemeralServiceOptions,\n\t\tcontainer: IContainer,\n\t\tdata: TData,\n\t\tid: string | undefined,\n\t) {\n\t\tsuper(registry, options, container, data, id);\n\t\tthis.service = options.service;\n\t\tEphemeralServiceImplementation.narrow(this.service);\n\t\tthis.service.addContainer(this);\n\t}\n\n\tpublic override close(): void {\n\t\tsuper.close();\n\t\t// Remove this now-closed container from its service's set of open containers.\n\t\tEphemeralServiceImplementation.narrow(this.service);\n\t\tthis.service.removeContainer(this);\n\t}\n\n\tprotected createAttachRequest(): IRequest {\n\t\tconst documentId = (documentIdCounter++).toString();\n\t\treturn createLocalResolverCreateNewRequest(documentId);\n\t}\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { createLocalDocumentService, LocalDocumentService } from "./localDocumen
8
8
  export { LocalDocumentServiceFactory } from "./localDocumentServiceFactory.js";
9
9
  export { LocalDocumentStorageService } from "./localDocumentStorageService.js";
10
10
  export { createLocalResolverCreateNewRequest, LocalResolver } from "./localResolver.js";
11
- export { localDriverCompatDetailsForLoader } from "./localLayerCompatState.js";
11
+ export { localDriverCompatDetailsForLoader, localDriverCompatRequirementsForLoader, } from "./localLayerCompatState.js";
12
12
  export { LocalSessionStorageDbFactory } from "./localSessionStorageDb.js";
13
13
  export type { EphemeralService, EphemeralServiceClient, EphemeralServiceOptions, } from "./ephemeralService.js";
14
14
  export { startEphemeralService, cleanupEphemeralService, getDefaultEphemeralService, } from "./ephemeralService.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,mCAAmC,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,YAAY,EACX,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,mCAAmC,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EACN,iCAAiC,EACjC,sCAAsC,GACtC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,YAAY,EACX,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC"}
package/lib/index.js CHANGED
@@ -8,7 +8,7 @@ export { createLocalDocumentService, LocalDocumentService } from "./localDocumen
8
8
  export { LocalDocumentServiceFactory } from "./localDocumentServiceFactory.js";
9
9
  export { LocalDocumentStorageService } from "./localDocumentStorageService.js";
10
10
  export { createLocalResolverCreateNewRequest, LocalResolver } from "./localResolver.js";
11
- export { localDriverCompatDetailsForLoader } from "./localLayerCompatState.js";
11
+ export { localDriverCompatDetailsForLoader, localDriverCompatRequirementsForLoader, } from "./localLayerCompatState.js";
12
12
  export { LocalSessionStorageDbFactory } from "./localSessionStorageDb.js";
13
13
  export { startEphemeralService, cleanupEphemeralService, getDefaultEphemeralService, } from "./ephemeralService.js";
14
14
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,mCAAmC,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAM1E,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { LocalDeltaStorageService } from \"./localDeltaStorageService.js\";\nexport { LocalDocumentDeltaConnection } from \"./localDocumentDeltaConnection.js\";\nexport { createLocalDocumentService, LocalDocumentService } from \"./localDocumentService.js\";\nexport { LocalDocumentServiceFactory } from \"./localDocumentServiceFactory.js\";\nexport { LocalDocumentStorageService } from \"./localDocumentStorageService.js\";\nexport { createLocalResolverCreateNewRequest, LocalResolver } from \"./localResolver.js\";\nexport { localDriverCompatDetailsForLoader } from \"./localLayerCompatState.js\";\nexport { LocalSessionStorageDbFactory } from \"./localSessionStorageDb.js\";\nexport type {\n\tEphemeralService,\n\tEphemeralServiceClient,\n\tEphemeralServiceOptions,\n} from \"./ephemeralService.js\";\nexport {\n\tstartEphemeralService,\n\tcleanupEphemeralService,\n\tgetDefaultEphemeralService,\n} from \"./ephemeralService.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,mCAAmC,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EACN,iCAAiC,EACjC,sCAAsC,GACtC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAM1E,OAAO,EACN,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { LocalDeltaStorageService } from \"./localDeltaStorageService.js\";\nexport { LocalDocumentDeltaConnection } from \"./localDocumentDeltaConnection.js\";\nexport { createLocalDocumentService, LocalDocumentService } from \"./localDocumentService.js\";\nexport { LocalDocumentServiceFactory } from \"./localDocumentServiceFactory.js\";\nexport { LocalDocumentStorageService } from \"./localDocumentStorageService.js\";\nexport { createLocalResolverCreateNewRequest, LocalResolver } from \"./localResolver.js\";\nexport {\n\tlocalDriverCompatDetailsForLoader,\n\tlocalDriverCompatRequirementsForLoader,\n} from \"./localLayerCompatState.js\";\nexport { LocalSessionStorageDbFactory } from \"./localSessionStorageDb.js\";\nexport type {\n\tEphemeralService,\n\tEphemeralServiceClient,\n\tEphemeralServiceOptions,\n} from \"./ephemeralService.js\";\nexport {\n\tstartEphemeralService,\n\tcleanupEphemeralService,\n\tgetDefaultEphemeralService,\n} from \"./ephemeralService.js\";\n"]}
package/lib/legacy.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {
@@ -8,6 +8,9 @@ import { streamFromMessages } from "@fluidframework/driver-utils/internal";
8
8
  * @internal
9
9
  */
10
10
  export class LocalDeltaStorageService {
11
+ tenantId;
12
+ id;
13
+ databaseManager;
11
14
  constructor(tenantId, id, databaseManager) {
12
15
  this.tenantId = tenantId;
13
16
  this.id = id;
@@ -1 +1 @@
1
- {"version":3,"file":"localDeltaStorageService.js","sourceRoot":"","sources":["../src/localDeltaStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAG3E;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IACpC,YACkB,QAAgB,EAChB,EAAU,EACV,eAAiC;QAFjC,aAAQ,GAAR,QAAQ,CAAQ;QAChB,OAAE,GAAF,EAAE,CAAQ;QACV,oBAAe,GAAf,eAAe,CAAkB;IAChD,CAAC;IAEG,aAAa,CACnB,IAAY,EACZ,EAAsB,EACtB,WAAyB,EACzB,UAAoB;QAEpB,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACnD,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,EAAW;QAC9C,MAAM,KAAK,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC/D,KAAK,CAAC,0BAA0B,CAAC,GAAG,EAAE,CAAC;QACvC,KAAK,CAAC,0BAA0B,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,oBAAoB;QAEtE,kFAAkF;QAClF,iBAAiB;QACjB,KAAK,CAAC,0BAA0B,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,MAAM,CAAC,gBAAgB,CAAC;QAEtE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,0BAA0B,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1D,OAAO,QAAQ,CAAC;IACjB,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIDocumentDeltaStorageService,\n\tIStream,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { streamFromMessages } from \"@fluidframework/driver-utils/internal\";\nimport type { IDatabaseManager } from \"@fluidframework/server-services-core\";\n\n/**\n * Provides access to the underlying delta storage on the server for local driver.\n * @internal\n */\nexport class LocalDeltaStorageService implements IDocumentDeltaStorageService {\n\tconstructor(\n\t\tprivate readonly tenantId: string,\n\t\tprivate readonly id: string,\n\t\tprivate readonly databaseManager: IDatabaseManager,\n\t) {}\n\n\tpublic fetchMessages(\n\t\tfrom: number,\n\t\tto: number | undefined,\n\t\tabortSignal?: AbortSignal,\n\t\tcachedOnly?: boolean,\n\t): IStream<ISequencedDocumentMessage[]> {\n\t\treturn streamFromMessages(this.getCore(from, to));\n\t}\n\n\tprivate async getCore(from: number, to?: number): Promise<ISequencedDocumentMessage[]> {\n\t\tconst query = { documentId: this.id, tenantId: this.tenantId };\n\t\tquery[\"operation.sequenceNumber\"] = {};\n\t\tquery[\"operation.sequenceNumber\"].$gt = from - 1; // from is inclusive\n\n\t\t// This looks like a bug. It used to work without setting $lt key. Now it does not\n\t\t// Need follow up\n\t\tquery[\"operation.sequenceNumber\"].$lt = to ?? Number.MAX_SAFE_INTEGER;\n\n\t\tconst allDeltas = await this.databaseManager.getDeltaCollection(this.tenantId, this.id);\n\t\tconst dbDeltas = await allDeltas.find(query, { \"operation.sequenceNumber\": 1 });\n\t\tconst messages = dbDeltas.map((delta) => delta.operation);\n\t\treturn messages;\n\t}\n}\n"]}
1
+ {"version":3,"file":"localDeltaStorageService.js","sourceRoot":"","sources":["../src/localDeltaStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAG3E;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IAElB;IACA;IACA;IAHlB,YACkB,QAAgB,EAChB,EAAU,EACV,eAAiC;QAFjC,aAAQ,GAAR,QAAQ,CAAQ;QAChB,OAAE,GAAF,EAAE,CAAQ;QACV,oBAAe,GAAf,eAAe,CAAkB;IAChD,CAAC;IAEG,aAAa,CACnB,IAAY,EACZ,EAAsB,EACtB,WAAyB,EACzB,UAAoB;QAEpB,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACnD,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,EAAW;QAC9C,MAAM,KAAK,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC/D,KAAK,CAAC,0BAA0B,CAAC,GAAG,EAAE,CAAC;QACvC,KAAK,CAAC,0BAA0B,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,oBAAoB;QAEtE,kFAAkF;QAClF,iBAAiB;QACjB,KAAK,CAAC,0BAA0B,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,MAAM,CAAC,gBAAgB,CAAC;QAEtE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,0BAA0B,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1D,OAAO,QAAQ,CAAC;IACjB,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIDocumentDeltaStorageService,\n\tIStream,\n\tISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { streamFromMessages } from \"@fluidframework/driver-utils/internal\";\nimport type { IDatabaseManager } from \"@fluidframework/server-services-core\";\n\n/**\n * Provides access to the underlying delta storage on the server for local driver.\n * @internal\n */\nexport class LocalDeltaStorageService implements IDocumentDeltaStorageService {\n\tconstructor(\n\t\tprivate readonly tenantId: string,\n\t\tprivate readonly id: string,\n\t\tprivate readonly databaseManager: IDatabaseManager,\n\t) {}\n\n\tpublic fetchMessages(\n\t\tfrom: number,\n\t\tto: number | undefined,\n\t\tabortSignal?: AbortSignal,\n\t\tcachedOnly?: boolean,\n\t): IStream<ISequencedDocumentMessage[]> {\n\t\treturn streamFromMessages(this.getCore(from, to));\n\t}\n\n\tprivate async getCore(from: number, to?: number): Promise<ISequencedDocumentMessage[]> {\n\t\tconst query = { documentId: this.id, tenantId: this.tenantId };\n\t\tquery[\"operation.sequenceNumber\"] = {};\n\t\tquery[\"operation.sequenceNumber\"].$gt = from - 1; // from is inclusive\n\n\t\t// This looks like a bug. It used to work without setting $lt key. Now it does not\n\t\t// Need follow up\n\t\tquery[\"operation.sequenceNumber\"].$lt = to ?? Number.MAX_SAFE_INTEGER;\n\n\t\tconst allDeltas = await this.databaseManager.getDeltaCollection(this.tenantId, this.id);\n\t\tconst dbDeltas = await allDeltas.find(query, { \"operation.sequenceNumber\": 1 });\n\t\tconst messages = dbDeltas.map((delta) => delta.operation);\n\t\treturn messages;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"localDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/localDocumentDeltaConnection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EAAY,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAE5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI/C;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,uBAAuB;IACxE;;;;;;;;;OASG;WACiB,MAAM,CACzB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,eAAe,EAAE,gBAAgB,EACjC,SAAS,SAAQ,EACjB,MAAM,CAAC,EAAE,oBAAoB,GAC3B,OAAO,CAAC,4BAA4B,CAAC;gBAqB5B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB;IAI7E;;OAEG;IACI,MAAM,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAQjD;;;OAGG;IACI,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAIvD;;;;;OAKG;IACI,UAAU,CAChB,IAAI,oBAAc,EAClB,IAAI,2BAA+C,EACnD,OAAO,EAAE,GAAG,GACV,IAAI;CAYP"}
1
+ {"version":3,"file":"localDocumentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/localDocumentDeltaConnection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EAAY,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAE5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI/C;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,uBAAuB;IACxE;;;;;;;;;OASG;WACiB,MAAM,CACzB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,eAAe,EAAE,gBAAgB,EACjC,SAAS,SAAQ,EACjB,MAAM,CAAC,EAAE,oBAAoB,GAC3B,OAAO,CAAC,4BAA4B,CAAC;gBAqB5B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB;IAI7E;;OAEG;IACI,MAAM,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAQjD;;;OAGG;IACI,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAIvD;;;;;OAKG;IACI,UAAU,CAChB,IAAI,EAAE,MAAM,YAAM,EAClB,IAAI,EAAE,aAAa,YAAgC,EACnD,OAAO,EAAE,GAAG,GACV,IAAI;CAYP"}
@@ -1 +1 @@
1
- {"version":3,"file":"localDocumentService.d.ts","sourceRoot":"","sources":["../src/localDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EACX,wBAAwB,EACxB,4BAA4B,EAC5B,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,YAAY,EACZ,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAKvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAGjF;;;GAGG;AACH,qBAAa,oBACZ,SAAQ,iBAAiB,CAAC,sBAAsB,CAChD,YAAW,gBAAgB;aASV,WAAW,EAAE,YAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,2BAA2B;aAC5B,QAAQ,EAAE,wBAAwB;IAClD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAfzB;;;;;OAKG;gBAEc,WAAW,EAAE,YAAY,EACxB,0BAA0B,EAAE,2BAA2B,EACvD,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,2BAA2B,EAAE,GAAG,CAAC,MAAM,EAAE,4BAA4B,CAAC,EACvE,QAAQ,GAAE,wBAA0D,EACnE,oBAAoB,CAAC,8BAAkB,EACvC,MAAM,CAAC,kCAAsB;IAKxC,OAAO,IAAI,IAAI;IAEtB;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAcjE;;OAEG;IACU,qBAAqB,IAAI,OAAO,CAAC,4BAA4B,CAAC;IAW3E;;;OAGG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;CAgCrF;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,WAAW,EAAE,YAAY,EACzB,0BAA0B,EAAE,2BAA2B,EACvD,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,2BAA2B,EAAE,GAAG,CAAC,MAAM,EAAE,4BAA4B,CAAC,EACtE,QAAQ,CAAC,EAAE,wBAAwB,EACnC,oBAAoB,CAAC,EAAE,gBAAgB,EACvC,MAAM,CAAC,EAAE,oBAAoB,GAC3B,gBAAgB,CAYlB"}
1
+ {"version":3,"file":"localDocumentService.d.ts","sourceRoot":"","sources":["../src/localDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EACX,wBAAwB,EACxB,4BAA4B,EAC5B,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,YAAY,EACZ,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAKvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAGjF;;;GAGG;AACH,qBAAa,oBACZ,SAAQ,iBAAiB,CAAC,sBAAsB,CAChD,YAAW,gBAAgB;aASV,WAAW,EAAE,YAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,2BAA2B;aAC5B,QAAQ,EAAE,wBAAwB;IAClD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAfzB;;;;;OAKG;gBAEc,WAAW,EAAE,YAAY,EACxB,0BAA0B,EAAE,2BAA2B,EACvD,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,2BAA2B,EAAE,GAAG,CAAC,MAAM,EAAE,4BAA4B,CAAC,EACvE,QAAQ,GAAE,wBAA0D,EACnE,oBAAoB,CAAC,EAAE,gBAAgB,YAAA,EACvC,MAAM,CAAC,EAAE,oBAAoB,YAAA;IAKxC,OAAO,IAAI,IAAI;IAEtB;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAcjE;;OAEG;IACU,qBAAqB,IAAI,OAAO,CAAC,4BAA4B,CAAC;IAW3E;;;OAGG;IACU,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;CAgCrF;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,WAAW,EAAE,YAAY,EACzB,0BAA0B,EAAE,2BAA2B,EACvD,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,2BAA2B,EAAE,GAAG,CAAC,MAAM,EAAE,4BAA4B,CAAC,EACtE,QAAQ,CAAC,EAAE,wBAAwB,EACnC,oBAAoB,CAAC,EAAE,gBAAgB,EACvC,MAAM,CAAC,EAAE,oBAAoB,GAC3B,gBAAgB,CAYlB"}
@@ -13,6 +13,15 @@ import { LocalDocumentStorageService } from "./localDocumentStorageService.js";
13
13
  * @internal
14
14
  */
15
15
  export class LocalDocumentService extends TypedEventEmitter {
16
+ resolvedUrl;
17
+ localDeltaConnectionServer;
18
+ tokenProvider;
19
+ tenantId;
20
+ documentId;
21
+ documentDeltaConnectionsMap;
22
+ policies;
23
+ innerDocumentService;
24
+ logger;
16
25
  /**
17
26
  * @param localDeltaConnectionServer - delta connection server for ops
18
27
  * @param tokenProvider - token provider
@@ -1 +1 @@
1
- {"version":3,"file":"localDocumentService.js","sourceRoot":"","sources":["../src/localDocumentService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentDeltaConnection,\n\tIDocumentDeltaStorageService,\n\tIDocumentService,\n\tIDocumentServiceEvents,\n\tIDocumentServicePolicies,\n\tIDocumentStorageService,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type { ITokenProvider } from \"@fluidframework/routerlicious-driver\";\nimport type { ILocalDeltaConnectionServer } from \"@fluidframework/server-local-server\";\nimport { GitManager } from \"@fluidframework/server-services-client\";\nimport { TestHistorian } from \"@fluidframework/server-test-utils\";\n\nimport { LocalDeltaStorageService } from \"./localDeltaStorageService.js\";\nimport { LocalDocumentDeltaConnection } from \"./localDocumentDeltaConnection.js\";\nimport { LocalDocumentStorageService } from \"./localDocumentStorageService.js\";\n\n/**\n * Basic implementation of a document service for local use.\n * @internal\n */\nexport class LocalDocumentService\n\textends TypedEventEmitter<IDocumentServiceEvents>\n\timplements IDocumentService\n{\n\t/**\n\t * @param localDeltaConnectionServer - delta connection server for ops\n\t * @param tokenProvider - token provider\n\t * @param tenantId - ID of tenant\n\t * @param documentId - ID of document\n\t */\n\tconstructor(\n\t\tpublic readonly resolvedUrl: IResolvedUrl,\n\t\tprivate readonly localDeltaConnectionServer: ILocalDeltaConnectionServer,\n\t\tprivate readonly tokenProvider: ITokenProvider,\n\t\tprivate readonly tenantId: string,\n\t\tprivate readonly documentId: string,\n\t\tprivate readonly documentDeltaConnectionsMap: Map<string, LocalDocumentDeltaConnection>,\n\t\tpublic readonly policies: IDocumentServicePolicies = { supportGetSnapshotApi: true },\n\t\tprivate readonly innerDocumentService?: IDocumentService,\n\t\tprivate readonly logger?: ITelemetryBaseLogger,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic dispose(): void {}\n\n\t/**\n\t * Creates and returns a document storage service for local use.\n\t */\n\tpublic async connectToStorage(): Promise<IDocumentStorageService> {\n\t\treturn new LocalDocumentStorageService(\n\t\t\tthis.documentId,\n\t\t\tnew GitManager(\n\t\t\t\tnew TestHistorian(this.localDeltaConnectionServer.testDbFactory.testDatabase),\n\t\t\t),\n\t\t\t{\n\t\t\t\tmaximumCacheDurationMs: 432_000_000, // 5 days in ms. Not actually enforced but shouldn't matter for any local driver scenario\n\t\t\t},\n\t\t\tthis.localDeltaConnectionServer,\n\t\t\tthis.resolvedUrl,\n\t\t);\n\t}\n\n\t/**\n\t * Creates and returns a delta storage service for local use.\n\t */\n\tpublic async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n\t\tif (this.innerDocumentService) {\n\t\t\treturn this.innerDocumentService.connectToDeltaStorage();\n\t\t}\n\t\treturn new LocalDeltaStorageService(\n\t\t\tthis.tenantId,\n\t\t\tthis.documentId,\n\t\t\tthis.localDeltaConnectionServer.databaseManager,\n\t\t);\n\t}\n\n\t/**\n\t * Creates and returns a delta stream for local use.\n\t * @param client - client data\n\t */\n\tpublic async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tif (this.policies.storageOnly === true) {\n\t\t\tthrow new Error(\"can't connect to delta stream in storage-only mode\");\n\t\t}\n\t\tif (this.innerDocumentService) {\n\t\t\treturn this.innerDocumentService.connectToDeltaStream(client);\n\t\t}\n\t\tconst ordererToken = await this.tokenProvider.fetchOrdererToken(\n\t\t\tthis.tenantId,\n\t\t\tthis.documentId,\n\t\t);\n\t\tconst documentDeltaConnection = await LocalDocumentDeltaConnection.create(\n\t\t\tthis.tenantId,\n\t\t\tthis.documentId,\n\t\t\tordererToken.jwt,\n\t\t\tclient,\n\t\t\tthis.localDeltaConnectionServer.webSocketServer,\n\t\t\tundefined,\n\t\t\tthis.logger,\n\t\t);\n\t\tconst clientId = documentDeltaConnection.clientId;\n\n\t\t// Add this document service for the clientId in the document service factory.\n\t\tthis.documentDeltaConnectionsMap.set(clientId, documentDeltaConnection);\n\n\t\t// Add a listener to remove this document service when the client is disconnected.\n\t\tdocumentDeltaConnection.on(\"disconnect\", () => {\n\t\t\tthis.documentDeltaConnectionsMap.delete(clientId);\n\t\t});\n\n\t\treturn documentDeltaConnection;\n\t}\n}\n\n/**\n * Creates and returns a document service for local use.\n * @param localDeltaConnectionServer - delta connection server for ops\n * @param tokenProvider - token provider with a single token\n * @param tenantId - ID of tenant\n * @param documentId - ID of document\n * @internal\n */\nexport function createLocalDocumentService(\n\tresolvedUrl: IResolvedUrl,\n\tlocalDeltaConnectionServer: ILocalDeltaConnectionServer,\n\ttokenProvider: ITokenProvider,\n\ttenantId: string,\n\tdocumentId: string,\n\tdocumentDeltaConnectionsMap: Map<string, LocalDocumentDeltaConnection>,\n\tpolicies?: IDocumentServicePolicies,\n\tinnerDocumentService?: IDocumentService,\n\tlogger?: ITelemetryBaseLogger,\n): IDocumentService {\n\treturn new LocalDocumentService(\n\t\tresolvedUrl,\n\t\tlocalDeltaConnectionServer,\n\t\ttokenProvider,\n\t\ttenantId,\n\t\tdocumentId,\n\t\tdocumentDeltaConnectionsMap,\n\t\tpolicies,\n\t\tinnerDocumentService,\n\t\tlogger,\n\t);\n}\n"]}
1
+ {"version":3,"file":"localDocumentService.js","sourceRoot":"","sources":["../src/localDocumentService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentDeltaConnection,\n\tIDocumentDeltaStorageService,\n\tIDocumentService,\n\tIDocumentServiceEvents,\n\tIDocumentServicePolicies,\n\tIDocumentStorageService,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type { ITokenProvider } from \"@fluidframework/routerlicious-driver\";\nimport type { ILocalDeltaConnectionServer } from \"@fluidframework/server-local-server\";\nimport { GitManager } from \"@fluidframework/server-services-client\";\nimport { TestHistorian } from \"@fluidframework/server-test-utils\";\n\nimport { LocalDeltaStorageService } from \"./localDeltaStorageService.js\";\nimport { LocalDocumentDeltaConnection } from \"./localDocumentDeltaConnection.js\";\nimport { LocalDocumentStorageService } from \"./localDocumentStorageService.js\";\n\n/**\n * Basic implementation of a document service for local use.\n * @internal\n */\nexport class LocalDocumentService\n\textends TypedEventEmitter<IDocumentServiceEvents>\n\timplements IDocumentService\n{\n\t/**\n\t * @param localDeltaConnectionServer - delta connection server for ops\n\t * @param tokenProvider - token provider\n\t * @param tenantId - ID of tenant\n\t * @param documentId - ID of document\n\t */\n\tconstructor(\n\t\tpublic readonly resolvedUrl: IResolvedUrl,\n\t\tprivate readonly localDeltaConnectionServer: ILocalDeltaConnectionServer,\n\t\tprivate readonly tokenProvider: ITokenProvider,\n\t\tprivate readonly tenantId: string,\n\t\tprivate readonly documentId: string,\n\t\tprivate readonly documentDeltaConnectionsMap: Map<string, LocalDocumentDeltaConnection>,\n\t\tpublic readonly policies: IDocumentServicePolicies = { supportGetSnapshotApi: true },\n\t\tprivate readonly innerDocumentService?: IDocumentService,\n\t\tprivate readonly logger?: ITelemetryBaseLogger,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic dispose(): void {}\n\n\t/**\n\t * Creates and returns a document storage service for local use.\n\t */\n\tpublic async connectToStorage(): Promise<IDocumentStorageService> {\n\t\treturn new LocalDocumentStorageService(\n\t\t\tthis.documentId,\n\t\t\tnew GitManager(\n\t\t\t\tnew TestHistorian(this.localDeltaConnectionServer.testDbFactory.testDatabase),\n\t\t\t),\n\t\t\t{\n\t\t\t\tmaximumCacheDurationMs: 432_000_000, // 5 days in ms. Not actually enforced but shouldn't matter for any local driver scenario\n\t\t\t},\n\t\t\tthis.localDeltaConnectionServer,\n\t\t\tthis.resolvedUrl,\n\t\t);\n\t}\n\n\t/**\n\t * Creates and returns a delta storage service for local use.\n\t */\n\tpublic async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n\t\tif (this.innerDocumentService) {\n\t\t\treturn this.innerDocumentService.connectToDeltaStorage();\n\t\t}\n\t\treturn new LocalDeltaStorageService(\n\t\t\tthis.tenantId,\n\t\t\tthis.documentId,\n\t\t\tthis.localDeltaConnectionServer.databaseManager,\n\t\t);\n\t}\n\n\t/**\n\t * Creates and returns a delta stream for local use.\n\t * @param client - client data\n\t */\n\tpublic async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tif (this.policies.storageOnly === true) {\n\t\t\tthrow new Error(\"can't connect to delta stream in storage-only mode\");\n\t\t}\n\t\tif (this.innerDocumentService) {\n\t\t\treturn this.innerDocumentService.connectToDeltaStream(client);\n\t\t}\n\t\tconst ordererToken = await this.tokenProvider.fetchOrdererToken(\n\t\t\tthis.tenantId,\n\t\t\tthis.documentId,\n\t\t);\n\t\tconst documentDeltaConnection = await LocalDocumentDeltaConnection.create(\n\t\t\tthis.tenantId,\n\t\t\tthis.documentId,\n\t\t\tordererToken.jwt,\n\t\t\tclient,\n\t\t\tthis.localDeltaConnectionServer.webSocketServer,\n\t\t\tundefined,\n\t\t\tthis.logger,\n\t\t);\n\t\tconst clientId = documentDeltaConnection.clientId;\n\n\t\t// Add this document service for the clientId in the document service factory.\n\t\tthis.documentDeltaConnectionsMap.set(clientId, documentDeltaConnection);\n\n\t\t// Add a listener to remove this document service when the client is disconnected.\n\t\tdocumentDeltaConnection.on(\"disconnect\", () => {\n\t\t\tthis.documentDeltaConnectionsMap.delete(clientId);\n\t\t});\n\n\t\treturn documentDeltaConnection;\n\t}\n}\n\n/**\n * Creates and returns a document service for local use.\n * @param localDeltaConnectionServer - delta connection server for ops\n * @param tokenProvider - token provider with a single token\n * @param tenantId - ID of tenant\n * @param documentId - ID of document\n * @internal\n */\nexport function createLocalDocumentService(\n\tresolvedUrl: IResolvedUrl,\n\tlocalDeltaConnectionServer: ILocalDeltaConnectionServer,\n\ttokenProvider: ITokenProvider,\n\ttenantId: string,\n\tdocumentId: string,\n\tdocumentDeltaConnectionsMap: Map<string, LocalDocumentDeltaConnection>,\n\tpolicies?: IDocumentServicePolicies,\n\tinnerDocumentService?: IDocumentService,\n\tlogger?: ITelemetryBaseLogger,\n): IDocumentService {\n\treturn new LocalDocumentService(\n\t\tresolvedUrl,\n\t\tlocalDeltaConnectionServer,\n\t\ttokenProvider,\n\t\ttenantId,\n\t\tdocumentId,\n\t\tdocumentDeltaConnectionsMap,\n\t\tpolicies,\n\t\tinnerDocumentService,\n\t\tlogger,\n\t);\n}\n"]}
@@ -27,6 +27,15 @@ export declare class LocalDocumentServiceFactory implements IDocumentServiceFact
27
27
  * is currently marked as legacy alpha. So, using unknown here.
28
28
  */
29
29
  readonly ILayerCompatDetails?: unknown;
30
+ /**
31
+ * The requirements that the Loader layer must meet to be compatible with this Local Driver. This is exposed to
32
+ * the Loader layer so that it can validate Loader / Driver compatibility on this Driver's behalf (the Driver has
33
+ * no reference to the Loader to validate it directly).
34
+ * @remarks This is for internal use only.
35
+ * The type of this should be ILayerCompatSupportRequirements. However, ILayerCompatSupportRequirements is
36
+ * internal and this class is currently marked as legacy alpha. So, using unknown here.
37
+ */
38
+ readonly ILayerCompatSupportRequirements?: unknown;
30
39
  createContainer(createNewSummary: ISummaryTree | undefined, resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
31
40
  /**
32
41
  * Creates and returns a document service for testing using the given resolved
@@ -1 +1 @@
1
- {"version":3,"file":"localDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../src/localDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EACX,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACZ,aAAa,EACb,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAOvF;;;GAGG;AACH,qBAAa,2BAA4B,YAAW,uBAAuB;IASzE,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IATvC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CACjC;IAEX;;OAEG;gBAEe,0BAA0B,EAAE,2BAA2B,EACvD,QAAQ,CAAC,sCAA0B,EACnC,oBAAoB,CAAC,8BAAkB;IAGzD;;;;;;OAMG;IACH,SAAgB,mBAAmB,CAAC,EAAE,OAAO,CAAqC;IAErE,eAAe,CAC3B,gBAAgB,EAAE,YAAY,GAAG,SAAS,EAC1C,WAAW,EAAE,YAAY,EACzB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IAU5B;;;;OAIG;IACU,qBAAqB,CACjC,WAAW,EAAE,YAAY,EACzB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IA8B5B;;;;OAIG;IACI,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAQzE;;;;;;OAMG;IACI,UAAU,CAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,GAAG,GACX,IAAI;CAOP"}
1
+ {"version":3,"file":"localDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../src/localDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EACX,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACZ,aAAa,EACb,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAUvF;;;GAGG;AACH,qBAAa,2BAA4B,YAAW,uBAAuB;IASzE,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IATvC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CACjC;IAEX;;OAEG;gBAEe,0BAA0B,EAAE,2BAA2B,EACvD,QAAQ,CAAC,EAAE,wBAAwB,YAAA,EACnC,oBAAoB,CAAC,EAAE,gBAAgB,YAAA;IAGzD;;;;;;OAMG;IACH,SAAgB,mBAAmB,CAAC,EAAE,OAAO,CAAqC;IAElF;;;;;;;OAOG;IACH,SAAgB,+BAA+B,CAAC,EAAE,OAAO,CACjB;IAE3B,eAAe,CAC3B,gBAAgB,EAAE,YAAY,GAAG,SAAS,EAC1C,WAAW,EAAE,YAAY,EACzB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IAU5B;;;;OAIG;IACU,qBAAqB,CACjC,WAAW,EAAE,YAAY,EACzB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IA8B5B;;;;OAIG;IACI,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAQzE;;;;;;OAMG;IACI,UAAU,CAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,GAAG,GACX,IAAI;CAOP"}
@@ -5,12 +5,17 @@
5
5
  import { DefaultTokenProvider } from "@fluidframework/routerlicious-driver/internal";
6
6
  import { createDocument } from "./localCreateDocument.js";
7
7
  import { createLocalDocumentService } from "./localDocumentService.js";
8
- import { localDriverCompatDetailsForLoader } from "./localLayerCompatState.js";
8
+ import { localDriverCompatDetailsForLoader, localDriverCompatRequirementsForLoader, } from "./localLayerCompatState.js";
9
9
  /**
10
10
  * Implementation of document service factory for local use.
11
11
  * @legacy @beta
12
12
  */
13
13
  export class LocalDocumentServiceFactory {
14
+ localDeltaConnectionServer;
15
+ policies;
16
+ innerDocumentService;
17
+ // A map of clientId to LocalDocumentService.
18
+ documentDeltaConnectionsMap = new Map();
14
19
  /**
15
20
  * @param localDeltaConnectionServer - delta connection server for ops
16
21
  */
@@ -18,17 +23,24 @@ export class LocalDocumentServiceFactory {
18
23
  this.localDeltaConnectionServer = localDeltaConnectionServer;
19
24
  this.policies = policies;
20
25
  this.innerDocumentService = innerDocumentService;
21
- // A map of clientId to LocalDocumentService.
22
- this.documentDeltaConnectionsMap = new Map();
23
- /**
24
- * The compatibility details of the Local Driver layer that is exposed to the Loader layer
25
- * for validating Loader-Driver compatibility.
26
- * @remarks This is for internal use only.
27
- * The type of this should be ILayerCompatDetails. However, ILayerCompatDetails is internal and this class
28
- * is currently marked as legacy alpha. So, using unknown here.
29
- */
30
- this.ILayerCompatDetails = localDriverCompatDetailsForLoader;
31
26
  }
27
+ /**
28
+ * The compatibility details of the Local Driver layer that is exposed to the Loader layer
29
+ * for validating Loader-Driver compatibility.
30
+ * @remarks This is for internal use only.
31
+ * The type of this should be ILayerCompatDetails. However, ILayerCompatDetails is internal and this class
32
+ * is currently marked as legacy alpha. So, using unknown here.
33
+ */
34
+ ILayerCompatDetails = localDriverCompatDetailsForLoader;
35
+ /**
36
+ * The requirements that the Loader layer must meet to be compatible with this Local Driver. This is exposed to
37
+ * the Loader layer so that it can validate Loader / Driver compatibility on this Driver's behalf (the Driver has
38
+ * no reference to the Loader to validate it directly).
39
+ * @remarks This is for internal use only.
40
+ * The type of this should be ILayerCompatSupportRequirements. However, ILayerCompatSupportRequirements is
41
+ * internal and this class is currently marked as legacy alpha. So, using unknown here.
42
+ */
43
+ ILayerCompatSupportRequirements = localDriverCompatRequirementsForLoader;
32
44
  async createContainer(createNewSummary, resolvedUrl, logger, clientIsSummarizer) {
33
45
  if (!this.localDeltaConnectionServer) {
34
46
  throw new Error("Provide the localDeltaConnectionServer!!");