@fluidframework/odsp-driver 2.0.0-internal.1.0.0.82693 → 2.0.0-internal.1.1.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/.mocharc.js +12 -0
  2. package/README.md +19 -0
  3. package/dist/contracts.d.ts +1 -0
  4. package/dist/contracts.d.ts.map +1 -1
  5. package/dist/contracts.js.map +1 -1
  6. package/dist/createFile.d.ts +1 -1
  7. package/dist/createFile.d.ts.map +1 -1
  8. package/dist/createFile.js +53 -16
  9. package/dist/createFile.js.map +1 -1
  10. package/dist/createOdspCreateContainerRequest.d.ts +4 -3
  11. package/dist/createOdspCreateContainerRequest.d.ts.map +1 -1
  12. package/dist/createOdspCreateContainerRequest.js +6 -3
  13. package/dist/createOdspCreateContainerRequest.js.map +1 -1
  14. package/dist/fetchSnapshot.d.ts.map +1 -1
  15. package/dist/fetchSnapshot.js +10 -5
  16. package/dist/fetchSnapshot.js.map +1 -1
  17. package/dist/odspDeltaStorageService.d.ts +1 -1
  18. package/dist/odspDeltaStorageService.js +1 -1
  19. package/dist/odspDeltaStorageService.js.map +1 -1
  20. package/dist/odspDocumentService.js +1 -1
  21. package/dist/odspDocumentService.js.map +1 -1
  22. package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  23. package/dist/odspDocumentServiceFactoryCore.js +29 -6
  24. package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
  25. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  26. package/dist/odspDocumentStorageManager.js +5 -3
  27. package/dist/odspDocumentStorageManager.js.map +1 -1
  28. package/dist/odspUtils.d.ts +11 -2
  29. package/dist/odspUtils.d.ts.map +1 -1
  30. package/dist/odspUtils.js +21 -1
  31. package/dist/odspUtils.js.map +1 -1
  32. package/dist/packageVersion.d.ts +1 -1
  33. package/dist/packageVersion.d.ts.map +1 -1
  34. package/dist/packageVersion.js +1 -1
  35. package/dist/packageVersion.js.map +1 -1
  36. package/dist/retryUtils.d.ts.map +1 -1
  37. package/dist/retryUtils.js +8 -4
  38. package/dist/retryUtils.js.map +1 -1
  39. package/lib/contracts.d.ts +1 -0
  40. package/lib/contracts.d.ts.map +1 -1
  41. package/lib/contracts.js.map +1 -1
  42. package/lib/createFile.d.ts +1 -1
  43. package/lib/createFile.d.ts.map +1 -1
  44. package/lib/createFile.js +54 -17
  45. package/lib/createFile.js.map +1 -1
  46. package/lib/createOdspCreateContainerRequest.d.ts +4 -3
  47. package/lib/createOdspCreateContainerRequest.d.ts.map +1 -1
  48. package/lib/createOdspCreateContainerRequest.js +6 -3
  49. package/lib/createOdspCreateContainerRequest.js.map +1 -1
  50. package/lib/fetchSnapshot.d.ts.map +1 -1
  51. package/lib/fetchSnapshot.js +10 -5
  52. package/lib/fetchSnapshot.js.map +1 -1
  53. package/lib/odspDeltaStorageService.d.ts +1 -1
  54. package/lib/odspDeltaStorageService.js +1 -1
  55. package/lib/odspDeltaStorageService.js.map +1 -1
  56. package/lib/odspDocumentService.js +1 -1
  57. package/lib/odspDocumentService.js.map +1 -1
  58. package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  59. package/lib/odspDocumentServiceFactoryCore.js +29 -6
  60. package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
  61. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  62. package/lib/odspDocumentStorageManager.js +5 -3
  63. package/lib/odspDocumentStorageManager.js.map +1 -1
  64. package/lib/odspUtils.d.ts +11 -2
  65. package/lib/odspUtils.d.ts.map +1 -1
  66. package/lib/odspUtils.js +19 -0
  67. package/lib/odspUtils.js.map +1 -1
  68. package/lib/packageVersion.d.ts +1 -1
  69. package/lib/packageVersion.d.ts.map +1 -1
  70. package/lib/packageVersion.js +1 -1
  71. package/lib/packageVersion.js.map +1 -1
  72. package/lib/retryUtils.d.ts.map +1 -1
  73. package/lib/retryUtils.js +9 -5
  74. package/lib/retryUtils.js.map +1 -1
  75. package/package.json +15 -15
  76. package/src/contracts.ts +2 -0
  77. package/src/createFile.ts +75 -15
  78. package/src/createOdspCreateContainerRequest.ts +7 -4
  79. package/src/fetchSnapshot.ts +9 -5
  80. package/src/odspDeltaStorageService.ts +1 -1
  81. package/src/odspDocumentService.ts +1 -1
  82. package/src/odspDocumentServiceFactoryCore.ts +40 -4
  83. package/src/odspDocumentStorageManager.ts +5 -3
  84. package/src/odspUtils.ts +24 -1
  85. package/src/packageVersion.ts +1 -1
  86. package/src/retryUtils.ts +8 -5
@@ -1 +1 @@
1
- {"version":3,"file":"retryUtils.js","sourceRoot":"","sources":["../src/retryUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,GAAqB,EACrB,QAAgB,EAChB,MAAwB,EACxB,aAA0B;IAE1B,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,IAAI,SAAc,CAAC;IACnB,KAAK,IAAI,QAAQ,GAAG,CAAC,GAAI,QAAQ,EAAE,EAAE;QACjC,IAAI,aAAa,KAAK,SAAS,EAAE;YAC7B,aAAa,EAAE,CAAC;SACnB;QACD,IAAI;YACA,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;YAC3B,IAAI,QAAQ,GAAG,CAAC,EAAE;gBACd,MAAM,CAAC,kBAAkB,CACrB;oBACI,SAAS,EAAE,iBAAiB;oBAC5B,QAAQ;oBACR,QAAQ;oBACR,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;iBACtC,EACD,SAAS,CAAC,CAAC;aAClB;YACD,OAAO,MAAM,CAAC;SACjB;QAAC,OAAO,KAAU,EAAE;YACjB,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YAExC,MAAM,cAAc,GAAG,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAG,YAAY,CAAC,MAAK,IAAI,CAAC;YACtD,MAAM,oBAAoB,GAAG,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,SAAS,MAAK,aAAa,CAAC,eAAe,CAAC;YAChF,sEAAsE;YACtE,IAAI,CAAC,CAAC,cAAc,IAAI,oBAAoB,IAAI,QAAQ,CAAC,EAAE;gBACvD,MAAM,KAAK,CAAC;aACf;YAED,+EAA+E;YAC/E,oFAAoF;YACpF,uEAAuE;YACvE,IAAI,QAAQ,KAAK,CAAC,EAAE;gBAChB,MAAM,CAAC,cAAc,CACjB;oBACI,SAAS,EAAE,cAAc,CAAC,CAAC;wBACvB,8BAA8B,CAAC,CAAC,CAAC,oCAAoC;oBACzE,QAAQ;oBACR,QAAQ;oBACR,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,0BAA0B;iBAClE,EACD,KAAK,CAAC,CAAC;gBACX,aAAa;gBACb,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACvB,MAAM,KAAK,CAAC;aACf;YAED,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YACpC,UAAU,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACnD,SAAS,GAAG,KAAK,CAAC;SACrB;KACJ;AACL,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { delay, performance } from \"@fluidframework/common-utils\";\nimport { canRetryOnError } from \"@fluidframework/driver-utils\";\nimport { OdspErrorType } from \"@fluidframework/odsp-driver-definitions\";\nimport { Odsp409Error } from \"./epochTracker\";\n\n/**\n * This method retries only for retriable coherency and service read only errors.\n */\nexport async function runWithRetry<T>(\n api: () => Promise<T>,\n callName: string,\n logger: ITelemetryLogger,\n checkDisposed?: () => void,\n): Promise<T> {\n let retryAfter = 1000;\n const start = performance.now();\n let lastError: any;\n for (let attempts = 1; ; attempts++) {\n if (checkDisposed !== undefined) {\n checkDisposed();\n }\n try {\n const result = await api();\n if (attempts > 1) {\n logger.sendTelemetryEvent(\n {\n eventName: \"MultipleRetries\",\n callName,\n attempts,\n duration: performance.now() - start,\n },\n lastError);\n }\n return result;\n } catch (error: any) {\n const canRetry = canRetryOnError(error);\n\n const coherencyError = error?.[Odsp409Error] === true;\n const serviceReadonlyError = error?.errorType === OdspErrorType.serviceReadOnly;\n // Retry for retriable 409 coherency errors or serviceReadOnly errors.\n if (!(coherencyError || serviceReadonlyError || canRetry)) {\n throw error;\n }\n\n // SPO itself does number of retries internally before returning 409 to client.\n // That multiplied to 5 suggests need to reconsider current design, as client spends\n // too much time / bandwidth doing the same thing without any progress.\n if (attempts === 5) {\n logger.sendErrorEvent(\n {\n eventName: coherencyError ?\n \"CoherencyErrorTooManyRetries\" : \"ServiceReadonlyErrorTooManyRetries\",\n callName,\n attempts,\n duration: performance.now() - start, // record total wait time.\n },\n error);\n // Fail hard.\n error.canRetry = false;\n throw error;\n }\n\n await delay(Math.floor(retryAfter));\n retryAfter += retryAfter / 4 * (1 + Math.random());\n lastError = error;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"retryUtils.js","sourceRoot":"","sources":["../src/retryUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,GAAqB,EACrB,QAAgB,EAChB,MAAwB,EACxB,aAA0B;;IAE1B,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,IAAI,SAAc,CAAC;IACnB,KAAK,IAAI,QAAQ,GAAG,CAAC,GAAI,QAAQ,EAAE,EAAE;QACjC,IAAI,aAAa,KAAK,SAAS,EAAE;YAC7B,aAAa,EAAE,CAAC;SACnB;QACD,IAAI;YACA,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;YAC3B,IAAI,QAAQ,GAAG,CAAC,EAAE;gBACd,MAAM,CAAC,kBAAkB,CACrB;oBACI,SAAS,EAAE,iBAAiB;oBAC5B,QAAQ;oBACR,QAAQ;oBACR,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;iBACtC,EACD,SAAS,CAAC,CAAC;aAClB;YACD,OAAO,MAAM,CAAC;SACjB;QAAC,OAAO,KAAU,EAAE;YACjB,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YAExC,MAAM,cAAc,GAAG,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAG,YAAY,CAAC,MAAK,IAAI,CAAC;YACtD,MAAM,oBAAoB,GAAG,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,SAAS,MAAK,aAAa,CAAC,eAAe,CAAC;YAChF,wGAAwG;YACxG,oGAAoG;YACpG,yBAAyB;YACzB,IAAI,CAAC,CAAC,CAAC,cAAc,IAAI,oBAAoB,CAAC,IAAI,QAAQ,CAAC,EAAE;gBACzD,MAAM,KAAK,CAAC;aACf;YAED,+EAA+E;YAC/E,oFAAoF;YACpF,uEAAuE;YACvE,IAAI,QAAQ,KAAK,CAAC,EAAE;gBAChB,MAAM,CAAC,cAAc,CACjB;oBACI,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC;wBACxD,oCAAoC;oBACxC,QAAQ;oBACR,QAAQ;oBACR,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,0BAA0B;iBAClE,EACD,KAAK,CAAC,CAAC;gBACX,aAAa;gBACb,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACvB,MAAM,KAAK,CAAC;aACf;YAED,UAAU,GAAG,MAAA,sBAAsB,CAAC,KAAK,CAAC,mCAAI,UAAU,CAAC;YACzD,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YACpC,UAAU,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACnD,SAAS,GAAG,KAAK,CAAC;SACrB;KACJ;AACL,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { delay, performance } from \"@fluidframework/common-utils\";\nimport { canRetryOnError, getRetryDelayFromError } from \"@fluidframework/driver-utils\";\nimport { OdspErrorType } from \"@fluidframework/odsp-driver-definitions\";\nimport { Odsp409Error } from \"./epochTracker\";\n\n/**\n * This method retries only for retriable coherency and service read only errors.\n */\nexport async function runWithRetry<T>(\n api: () => Promise<T>,\n callName: string,\n logger: ITelemetryLogger,\n checkDisposed?: () => void,\n): Promise<T> {\n let retryAfter = 1000;\n const start = performance.now();\n let lastError: any;\n for (let attempts = 1; ; attempts++) {\n if (checkDisposed !== undefined) {\n checkDisposed();\n }\n try {\n const result = await api();\n if (attempts > 1) {\n logger.sendTelemetryEvent(\n {\n eventName: \"MultipleRetries\",\n callName,\n attempts,\n duration: performance.now() - start,\n },\n lastError);\n }\n return result;\n } catch (error: any) {\n const canRetry = canRetryOnError(error);\n\n const coherencyError = error?.[Odsp409Error] === true;\n const serviceReadonlyError = error?.errorType === OdspErrorType.serviceReadOnly;\n // Retry for retriable 409 coherency errors or serviceReadOnly errors. These errors are always retriable\n // unless someone specifically set canRetry = false on the error like in fetchSnapshot() flow. So in\n // that case don't retry.\n if (!((coherencyError || serviceReadonlyError) && canRetry)) {\n throw error;\n }\n\n // SPO itself does number of retries internally before returning 409 to client.\n // That multiplied to 5 suggests need to reconsider current design, as client spends\n // too much time / bandwidth doing the same thing without any progress.\n if (attempts === 5) {\n logger.sendErrorEvent(\n {\n eventName: coherencyError ? \"CoherencyErrorTooManyRetries\" :\n \"ServiceReadonlyErrorTooManyRetries\",\n callName,\n attempts,\n duration: performance.now() - start, // record total wait time.\n },\n error);\n // Fail hard.\n error.canRetry = false;\n throw error;\n }\n\n retryAfter = getRetryDelayFromError(error) ?? retryAfter;\n await delay(Math.floor(retryAfter));\n retryAfter += retryAfter / 4 * (1 + Math.random());\n lastError = error;\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/odsp-driver",
3
- "version": "2.0.0-internal.1.0.0.82693",
3
+ "version": "2.0.0-internal.1.1.0",
4
4
  "description": "Socket storage implementation for SPO and ODC",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -61,17 +61,17 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@fluidframework/common-definitions": "^0.20.1",
64
- "@fluidframework/common-utils": "^0.32.1",
65
- "@fluidframework/core-interfaces": "2.0.0-internal.1.0.0.82693",
66
- "@fluidframework/driver-base": "2.0.0-internal.1.0.0.82693",
67
- "@fluidframework/driver-definitions": "2.0.0-internal.1.0.0.82693",
68
- "@fluidframework/driver-utils": "2.0.0-internal.1.0.0.82693",
69
- "@fluidframework/gitresources": "^0.1037.1000-0",
70
- "@fluidframework/odsp-doclib-utils": "2.0.0-internal.1.0.0.82693",
71
- "@fluidframework/odsp-driver-definitions": "2.0.0-internal.1.0.0.82693",
72
- "@fluidframework/protocol-base": "^0.1037.1000-0",
73
- "@fluidframework/protocol-definitions": "^0.1029.1000-0",
74
- "@fluidframework/telemetry-utils": "2.0.0-internal.1.0.0.82693",
64
+ "@fluidframework/common-utils": "^1.0.0",
65
+ "@fluidframework/core-interfaces": "^2.0.0-internal.1.1.0",
66
+ "@fluidframework/driver-base": "^2.0.0-internal.1.1.0",
67
+ "@fluidframework/driver-definitions": "^2.0.0-internal.1.1.0",
68
+ "@fluidframework/driver-utils": "^2.0.0-internal.1.1.0",
69
+ "@fluidframework/gitresources": "^0.1037.1000",
70
+ "@fluidframework/odsp-doclib-utils": "^2.0.0-internal.1.1.0",
71
+ "@fluidframework/odsp-driver-definitions": "^2.0.0-internal.1.1.0",
72
+ "@fluidframework/protocol-base": "^0.1037.1000",
73
+ "@fluidframework/protocol-definitions": "^1.0.0",
74
+ "@fluidframework/telemetry-utils": "^2.0.0-internal.1.1.0",
75
75
  "abort-controller": "^3.0.0",
76
76
  "node-fetch": "^2.6.1",
77
77
  "socket.io-client": "^4.4.1",
@@ -79,9 +79,9 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@fluidframework/build-common": "^0.24.0",
82
- "@fluidframework/build-tools": "^0.3.0-0",
82
+ "@fluidframework/build-tools": "^0.3.1000",
83
83
  "@fluidframework/eslint-config-fluid": "^0.28.2000",
84
- "@fluidframework/mocha-test-setup": "2.0.0-internal.1.0.0.82693",
84
+ "@fluidframework/mocha-test-setup": "^2.0.0-internal.1.1.0",
85
85
  "@fluidframework/odsp-driver-previous": "npm:@fluidframework/odsp-driver@^1.0.0",
86
86
  "@microsoft/api-extractor": "^7.22.2",
87
87
  "@rushstack/eslint-config": "^2.5.1",
@@ -89,7 +89,7 @@
89
89
  "@types/node-fetch": "^2.5.10",
90
90
  "@types/sha.js": "^2.4.0",
91
91
  "concurrently": "^6.2.0",
92
- "copyfiles": "^2.1.0",
92
+ "copyfiles": "^2.4.1",
93
93
  "cross-env": "^7.0.2",
94
94
  "eslint": "~8.6.0",
95
95
  "mocha": "^10.0.0",
package/src/contracts.ts CHANGED
@@ -216,6 +216,8 @@ export interface ICreateFileResponse {
216
216
  itemId: string;
217
217
  itemUrl: string;
218
218
  sequenceNumber: number;
219
+ // sharing object contains shareId, sharingLink data or error in the response
220
+ sharing?: any;
219
221
  sharingLink?: string;
220
222
  sharingLinkErrorReason?: string;
221
223
  }
package/src/createFile.ts CHANGED
@@ -15,6 +15,9 @@ import {
15
15
  InstrumentedStorageTokenFetcher,
16
16
  IOdspResolvedUrl,
17
17
  OdspErrorType,
18
+ ShareLinkInfoType,
19
+ ISharingLinkKind,
20
+ ShareLinkTypes,
18
21
  } from "@fluidframework/odsp-driver-definitions";
19
22
  import { DriverErrorType } from "@fluidframework/driver-definitions";
20
23
  import {
@@ -26,6 +29,7 @@ import {
26
29
  } from "./contracts";
27
30
  import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
28
31
  import {
32
+ buildOdspShareLinkReqParams,
29
33
  createCacheSnapshotKey,
30
34
  getWithRetryForTokenRefresh,
31
35
  INewFileInfo,
@@ -61,6 +65,8 @@ export async function createNewFluidFile(
61
65
  createNewCaching: boolean,
62
66
  forceAccessTokenViaAuthorizationHeader: boolean,
63
67
  isClpCompliantApp?: boolean,
68
+ enableSingleRequestForShareLinkWithCreate?: boolean,
69
+ enableShareLinkWithCreate?: boolean,
64
70
  ): Promise<IOdspResolvedUrl> {
65
71
  // Check for valid filename before the request to create file is actually made.
66
72
  if (isInvalidFileName(newFileInfo.filename)) {
@@ -71,8 +77,7 @@ export async function createNewFluidFile(
71
77
 
72
78
  let itemId: string;
73
79
  let summaryHandle: string = "";
74
- let sharingLink: string | undefined;
75
- let sharingLinkErrorReason: string | undefined;
80
+ let shareLinkInfo: ShareLinkInfoType | undefined;
76
81
  if (createNewSummary === undefined) {
77
82
  itemId = await createNewEmptyFluidFile(
78
83
  getStorageToken, newFileInfo, logger, epochTracker, forceAccessTokenViaAuthorizationHeader);
@@ -87,8 +92,12 @@ export async function createNewFluidFile(
87
92
  );
88
93
  itemId = content.itemId;
89
94
  summaryHandle = content.id;
90
- sharingLink = content.sharingLink;
91
- sharingLinkErrorReason = content.sharingLinkErrorReason;
95
+
96
+ shareLinkInfo = extractShareLinkData(
97
+ newFileInfo.createLinkType,
98
+ content,
99
+ enableSingleRequestForShareLinkWithCreate,
100
+ enableShareLinkWithCreate);
92
101
  }
93
102
 
94
103
  const odspUrl = createOdspUrl({ ...newFileInfo, itemId, dataStorePath: "/" });
@@ -100,15 +109,7 @@ export async function createNewFluidFile(
100
109
  fileEntry.docId = odspResolvedUrl.hashedDocumentId;
101
110
  fileEntry.resolvedUrl = odspResolvedUrl;
102
111
 
103
- if (sharingLink || sharingLinkErrorReason) {
104
- odspResolvedUrl.shareLinkInfo = {
105
- createLink: {
106
- type: newFileInfo.createLinkType,
107
- link: sharingLink,
108
- error: sharingLinkErrorReason,
109
- },
110
- };
111
- }
112
+ odspResolvedUrl.shareLinkInfo = shareLinkInfo;
112
113
 
113
114
  if (createNewSummary !== undefined && createNewCaching) {
114
115
  assert(summaryHandle !== undefined, 0x203 /* "Summary handle is undefined" */);
@@ -120,6 +121,61 @@ export async function createNewFluidFile(
120
121
  return odspResolvedUrl;
121
122
  }
122
123
 
124
+ /**
125
+ * If user requested creation of a sharing link along with the creation of the file by providing either
126
+ * createLinkType (now deprecated) or createLinkScope in the request parameters, extract and save
127
+ * sharing link information from the response if it is available.
128
+ * In case there was an error in creation of the sharing link, error is provided back in the response,
129
+ * and does not impact the creation of file in ODSP.
130
+ * @param requestedSharingLinkKind - Kind of sharing link requested to be created along with the creation of file.
131
+ * @param response - Response object received from the /snapshot api call
132
+ * @returns Sharing link information received in the response from a successful creation of a file.
133
+ */
134
+ function extractShareLinkData(
135
+ requestedSharingLinkKind: ShareLinkTypes | ISharingLinkKind | undefined,
136
+ response: ICreateFileResponse,
137
+ enableSingleRequestForShareLinkWithCreate?: boolean,
138
+ enableShareLinkWithCreate?: boolean,
139
+ ): ShareLinkInfoType | undefined {
140
+ if (!requestedSharingLinkKind) {
141
+ return;
142
+ }
143
+ let shareLinkInfo: ShareLinkInfoType | undefined;
144
+ if (enableSingleRequestForShareLinkWithCreate) {
145
+ const { sharing } = response;
146
+ if (!sharing) {
147
+ return;
148
+ }
149
+ shareLinkInfo = {
150
+ createLink: {
151
+ type: requestedSharingLinkKind,
152
+ link: sharing.sharingLink ? {
153
+ scope: sharing.sharingLink.scope,
154
+ role: sharing.sharingLink.type,
155
+ webUrl: sharing.sharingLink.webUrl,
156
+ ...sharing.sharingLink,
157
+ } : undefined,
158
+ error: sharing.error,
159
+ shareId: sharing.shareId,
160
+ },
161
+ };
162
+ } else if (enableShareLinkWithCreate) {
163
+ const { sharing, sharingLink, sharingLinkErrorReason } = response;
164
+ if (!sharingLink && !sharingLinkErrorReason) {
165
+ return;
166
+ }
167
+ shareLinkInfo = {
168
+ createLink: {
169
+ type: requestedSharingLinkKind,
170
+ link: sharingLink,
171
+ error: sharingLinkErrorReason,
172
+ shareId: sharing?.shareId,
173
+ },
174
+ };
175
+ }
176
+ return shareLinkInfo;
177
+ }
178
+
123
179
  export async function createNewEmptyFluidFile(
124
180
  getStorageToken: InstrumentedStorageTokenFetcher,
125
181
  newFileInfo: INewFileInfo,
@@ -192,8 +248,12 @@ export async function createNewFluidFileFromSummary(
192
248
  `${filePath}/${encodedFilename}`;
193
249
 
194
250
  const containerSnapshot = convertSummaryIntoContainerSnapshot(createNewSummary);
195
- const initialUrl = `${baseUrl}:/opStream/snapshots/snapshot${newFileInfo.createLinkType ?
196
- `?createLinkType=${newFileInfo.createLinkType}` : ""}`;
251
+
252
+ // Build share link parameter based on the createLinkType provided so that the
253
+ // snapshot api can create and return the share link along with creation of file in the response.
254
+ const createShareLinkParam = buildOdspShareLinkReqParams(newFileInfo.createLinkType);
255
+ const initialUrl =
256
+ `${baseUrl}:/opStream/snapshots/snapshot${createShareLinkParam ? `?${createShareLinkParam}` : ""}`;
197
257
 
198
258
  return getWithRetryForTokenRefresh(async (options) => {
199
259
  const storageToken = await getStorageToken(options, "CreateNewFile");
@@ -4,7 +4,8 @@
4
4
  */
5
5
  import { IRequest } from "@fluidframework/core-interfaces";
6
6
  import { DriverHeader } from "@fluidframework/driver-definitions";
7
- import { ShareLinkTypes } from "@fluidframework/odsp-driver-definitions";
7
+ import { ShareLinkTypes, ISharingLinkKind } from "@fluidframework/odsp-driver-definitions";
8
+ import { buildOdspShareLinkReqParams } from "./odspUtils";
8
9
 
9
10
  /**
10
11
  * Create the request object with url and headers for creating a new file on OneDrive Sharepoint
@@ -12,19 +13,21 @@ import { ShareLinkTypes } from "@fluidframework/odsp-driver-definitions";
12
13
  * @param driveId - drive identifier
13
14
  * @param filePath - path where file needs to be created
14
15
  * @param fileName - name of the new file to be created
15
- * @param createLinkType - type of sharing link you would like to create for this file
16
+ * @param createShareLinkType - type of sharing link you would like to create for this file. ShareLinkTypes
17
+ * will be deprecated soon, so for any new implementation please provide createShareLinkType of type ShareLink
16
18
  */
17
19
  export function createOdspCreateContainerRequest(
18
20
  siteUrl: string,
19
21
  driveId: string,
20
22
  filePath: string,
21
23
  fileName: string,
22
- createLinkType?: ShareLinkTypes,
24
+ createShareLinkType?: ShareLinkTypes | ISharingLinkKind,
23
25
  ): IRequest {
26
+ const shareLinkRequestParams = buildOdspShareLinkReqParams(createShareLinkType);
24
27
  const createNewRequest: IRequest = {
25
28
  url: `${siteUrl}?driveId=${encodeURIComponent(
26
29
  driveId,
27
- )}&path=${encodeURIComponent(filePath)}${createLinkType ? `&createLinkType=${createLinkType}` : ""}`,
30
+ )}&path=${encodeURIComponent(filePath)}${shareLinkRequestParams ? `&${shareLinkRequestParams}` : ""}`,
28
31
  headers: {
29
32
  [DriverHeader.createNew]: {
30
33
  fileName,
@@ -252,9 +252,15 @@ async function fetchLatestSnapshotCore(
252
252
  });
253
253
 
254
254
  let parsedSnapshotContents: IOdspResponse<ISnapshotContents> | undefined;
255
+ let contentTypeToRead: string | undefined;
256
+ if (contentType?.indexOf("application/ms-fluid") !== -1) {
257
+ contentTypeToRead = "application/ms-fluid";
258
+ } else if (contentType?.indexOf("application/json") !== -1) {
259
+ contentTypeToRead = "application/json";
260
+ }
255
261
 
256
262
  try {
257
- switch (contentType) {
263
+ switch (contentTypeToRead) {
258
264
  case "application/json": {
259
265
  const text = await odspResponse.content.text();
260
266
  propsToLog.bodySize = text.length;
@@ -549,14 +555,12 @@ export async function downloadSnapshot(
549
555
  };
550
556
  // Decide what snapshot format to fetch as per the feature gate.
551
557
  switch (snapshotFormatFetchType) {
552
- case SnapshotFormatSupportType.JsonAndBinary:
553
- headers.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;
554
- break;
555
558
  case SnapshotFormatSupportType.Binary:
556
559
  headers.accept = `application/ms-fluid; v=${currentReadVersion}`;
557
560
  break;
558
561
  default:
559
- headers.accept = "application/json";
562
+ // By default ask both versions and let the server decide the format.
563
+ headers.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;
560
564
  }
561
565
 
562
566
  const odspResponse = await (epochTracker?.fetch(url, fetchOptions, "treesLatest", true, scenarioName) ??
@@ -31,7 +31,7 @@ export class OdspDeltaStorageService {
31
31
  }
32
32
 
33
33
  /**
34
- * Retrieves ops from cache
34
+ * Retrieves ops from storage
35
35
  * @param from - inclusive
36
36
  * @param to - exclusive
37
37
  * @param telemetryProps - properties to add when issuing telemetry events
@@ -189,7 +189,7 @@ export class OdspDocumentService implements IDocumentService {
189
189
  },
190
190
  () => {
191
191
  assert(this.relayServiceTenantAndSessionId !== undefined,
192
- "relayServiceTenantAndSessionId should be present");
192
+ 0x37b /* relayServiceTenantAndSessionId should be present */);
193
193
  return this.relayServiceTenantAndSessionId;
194
194
  },
195
195
  this.mc.config.getNumber("Fluid.Driver.Odsp.snapshotFormatFetchType"),
@@ -26,6 +26,10 @@ import {
26
26
  HostStoragePolicy,
27
27
  IFileEntry,
28
28
  IOdspUrlParts,
29
+ SharingLinkScope,
30
+ SharingLinkRole,
31
+ ShareLinkTypes,
32
+ ISharingLinkKind,
29
33
  } from "@fluidframework/odsp-driver-definitions";
30
34
  import type { io as SocketIOClientStatic } from "socket.io-client";
31
35
  import { v4 as uuid } from "uuid";
@@ -84,15 +88,13 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
84
88
  }
85
89
  }
86
90
 
91
+ const createShareLinkParam = getSharingLinkParams(this.hostPolicy, searchParams);
87
92
  const newFileInfo: INewFileInfo = {
88
93
  driveId: odspResolvedUrl.driveId,
89
94
  siteUrl: odspResolvedUrl.siteUrl,
90
95
  filePath,
91
96
  filename: odspResolvedUrl.fileName,
92
- // set createLinkType to undefined if enableShareLinkWithCreate is set to false,
93
- // so that share link creation with create file can be enabled
94
- createLinkType: this.hostPolicy.enableShareLinkWithCreate ?
95
- odspResolvedUrl.shareLinkInfo?.createLink?.type : undefined,
97
+ createLinkType: createShareLinkParam,
96
98
  };
97
99
 
98
100
  const odspLogger = createOdspLogger(logger);
@@ -110,6 +112,10 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
110
112
  {
111
113
  eventName: "CreateNew",
112
114
  isWithSummaryUpload: true,
115
+ createShareLinkParam: JSON.stringify(createShareLinkParam),
116
+ enableShareLinkWithCreate: this.hostPolicy.enableShareLinkWithCreate,
117
+ enableSingleRequestForShareLinkWithCreate:
118
+ this.hostPolicy.enableSingleRequestForShareLinkWithCreate,
113
119
  },
114
120
  async (event) => {
115
121
  odspResolvedUrl = await createNewFluidFile(
@@ -127,6 +133,8 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
127
133
  this.hostPolicy.cacheCreateNewSummary ?? true,
128
134
  !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,
129
135
  odspResolvedUrl.isClpCompliantApp,
136
+ this.hostPolicy.enableSingleRequestForShareLinkWithCreate,
137
+ this.hostPolicy.enableShareLinkWithCreate,
130
138
  );
131
139
  const docService = this.createDocumentServiceCore(odspResolvedUrl, odspLogger,
132
140
  cacheAndTracker, clientIsSummarizer);
@@ -223,3 +231,31 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
223
231
  );
224
232
  }
225
233
  }
234
+
235
+ /**
236
+ * Extract the sharing link kind from the resolved URL's query paramerters
237
+ */
238
+ function getSharingLinkParams(
239
+ hostPolicy: HostStoragePolicy,
240
+ searchParams: URLSearchParams,
241
+ ): ShareLinkTypes | ISharingLinkKind | undefined {
242
+ // extract request parameters for creation of sharing link (if provided) if the feature is enabled
243
+ let createShareLinkParam: ShareLinkTypes | ISharingLinkKind | undefined;
244
+ if (hostPolicy.enableSingleRequestForShareLinkWithCreate) {
245
+ const createLinkScope = searchParams.get("createLinkScope");
246
+ const createLinkRole = searchParams.get("createLinkRole");
247
+ if (createLinkScope && SharingLinkScope[createLinkScope]) {
248
+ createShareLinkParam = {
249
+ scope: SharingLinkScope[createLinkScope],
250
+ ...(createLinkRole && SharingLinkRole[createLinkRole] ?
251
+ { role: SharingLinkRole[createLinkRole] } : {}),
252
+ };
253
+ }
254
+ } else if (hostPolicy.enableShareLinkWithCreate) {
255
+ const createLinkType = searchParams.get("createLinkType");
256
+ if (createLinkType && ShareLinkTypes[createLinkType]) {
257
+ createShareLinkParam = ShareLinkTypes[createLinkType || ""];
258
+ }
259
+ }
260
+ return createShareLinkParam;
261
+ }
@@ -228,8 +228,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
228
228
  }
229
229
 
230
230
  // If count is one, we can use the trees/latest API, which returns the latest version and trees in a single request for better performance
231
- // Do it only once - we might get more here due to summarizer - it needs only container tree, not full snapshot.
232
- if (this.firstVersionCall && count === 1 && (blobid === null || blobid === this.documentId)) {
231
+ if (count === 1 && (blobid === null || blobid === this.documentId)) {
233
232
  const hostSnapshotOptions = this.hostPolicy.snapshotOptions;
234
233
  const odspSnapshotCacheValue: ISnapshotContents = await PerformanceEvent.timedExecAsync(
235
234
  this.logger,
@@ -275,7 +274,10 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
275
274
  // Based on the concurrentSnapshotFetch policy:
276
275
  // Either retrieve both the network and cache snapshots concurrently and pick the first to return,
277
276
  // or grab the cache value and then the network value if the cache value returns undefined.
278
- if (this.hostPolicy.concurrentSnapshotFetch && !this.hostPolicy.summarizerClient) {
277
+ // For summarizer which could call this during refreshing of summary parent, always use the cache
278
+ // first. Also for other clients, if it is not critical path which is determined by firstVersionCall,
279
+ // then also check the cache first.
280
+ if (this.firstVersionCall && this.hostPolicy.concurrentSnapshotFetch && !this.hostPolicy.summarizerClient) {
279
281
  const networkSnapshotP = this.fetchSnapshot(hostSnapshotOptions, scenarioName);
280
282
 
281
283
  // Ensure that failures on both paths are ignored initially.
package/src/odspUtils.ts CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  isTokenFromCache,
28
28
  OdspResourceTokenFetchOptions,
29
29
  ShareLinkTypes,
30
+ ISharingLinkKind,
30
31
  TokenFetcher,
31
32
  ICacheEntry,
32
33
  snapshotKey,
@@ -233,8 +234,10 @@ export interface INewFileInfo {
233
234
  * application can request creation of a share link along with the creation of a new file
234
235
  * by passing in an optional param to specify the kind of sharing link
235
236
  * (at the time of adding this comment Sept/2021), odsp only supports csl
237
+ * ShareLinkTypes will deprecated in future. Use ISharingLinkKind instead which specifies both
238
+ * share link type and the role type.
236
239
  */
237
- createLinkType?: ShareLinkTypes;
240
+ createLinkType?: ShareLinkTypes | ISharingLinkKind;
238
241
  }
239
242
 
240
243
  export function getOdspResolvedUrl(resolvedUrl: IResolvedUrl): IOdspResolvedUrl {
@@ -348,3 +351,23 @@ export function createCacheSnapshotKey(odspResolvedUrl: IOdspResolvedUrl): ICach
348
351
  // 80KB is the max body size that we can put in ump post body for server to be able to accept it.
349
352
  // Keeping it 78KB to be a little cautious. As per the telemetry 99p is less than 78KB.
350
353
  export const maxUmpPostBodySize = 79872;
354
+
355
+ /**
356
+ * Build request parameters to request for the creation of a sharing link along with the creation of the file
357
+ * through the /snapshot api call.
358
+ * @param shareLinkType - Kind of sharing link requested
359
+ * @returns A string of request parameters that can be concatenated with the base URI
360
+ */
361
+ export function buildOdspShareLinkReqParams(shareLinkType: ShareLinkTypes | ISharingLinkKind | undefined) {
362
+ if (!shareLinkType) {
363
+ return;
364
+ }
365
+ const scope = (shareLinkType as ISharingLinkKind).scope;
366
+ if (!scope) {
367
+ return `createLinkType=${shareLinkType}`;
368
+ }
369
+ let shareLinkRequestParams = `createLinkScope=${scope}`;
370
+ const role = (shareLinkType as ISharingLinkKind).role;
371
+ shareLinkRequestParams = role ? `${shareLinkRequestParams}&createLinkRole=${role}` : shareLinkRequestParams;
372
+ return shareLinkRequestParams;
373
+ }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/odsp-driver";
9
- export const pkgVersion = "2.0.0-internal.1.0.0.82693";
9
+ export const pkgVersion = "2.0.0-internal.1.1.0";
package/src/retryUtils.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
7
7
  import { delay, performance } from "@fluidframework/common-utils";
8
- import { canRetryOnError } from "@fluidframework/driver-utils";
8
+ import { canRetryOnError, getRetryDelayFromError } from "@fluidframework/driver-utils";
9
9
  import { OdspErrorType } from "@fluidframework/odsp-driver-definitions";
10
10
  import { Odsp409Error } from "./epochTracker";
11
11
 
@@ -43,8 +43,10 @@ export async function runWithRetry<T>(
43
43
 
44
44
  const coherencyError = error?.[Odsp409Error] === true;
45
45
  const serviceReadonlyError = error?.errorType === OdspErrorType.serviceReadOnly;
46
- // Retry for retriable 409 coherency errors or serviceReadOnly errors.
47
- if (!(coherencyError || serviceReadonlyError || canRetry)) {
46
+ // Retry for retriable 409 coherency errors or serviceReadOnly errors. These errors are always retriable
47
+ // unless someone specifically set canRetry = false on the error like in fetchSnapshot() flow. So in
48
+ // that case don't retry.
49
+ if (!((coherencyError || serviceReadonlyError) && canRetry)) {
48
50
  throw error;
49
51
  }
50
52
 
@@ -54,8 +56,8 @@ export async function runWithRetry<T>(
54
56
  if (attempts === 5) {
55
57
  logger.sendErrorEvent(
56
58
  {
57
- eventName: coherencyError ?
58
- "CoherencyErrorTooManyRetries" : "ServiceReadonlyErrorTooManyRetries",
59
+ eventName: coherencyError ? "CoherencyErrorTooManyRetries" :
60
+ "ServiceReadonlyErrorTooManyRetries",
59
61
  callName,
60
62
  attempts,
61
63
  duration: performance.now() - start, // record total wait time.
@@ -66,6 +68,7 @@ export async function runWithRetry<T>(
66
68
  throw error;
67
69
  }
68
70
 
71
+ retryAfter = getRetryDelayFromError(error) ?? retryAfter;
69
72
  await delay(Math.floor(retryAfter));
70
73
  retryAfter += retryAfter / 4 * (1 + Math.random());
71
74
  lastError = error;