@fluidframework/debugger 2.91.0 → 2.92.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 (61) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/fluidDebugger.d.ts +1 -1
  3. package/dist/fluidDebugger.d.ts.map +1 -1
  4. package/dist/fluidDebugger.js.map +1 -1
  5. package/dist/fluidDebuggerController.d.ts +4 -3
  6. package/dist/fluidDebuggerController.d.ts.map +1 -1
  7. package/dist/fluidDebuggerController.js +4 -4
  8. package/dist/fluidDebuggerController.js.map +1 -1
  9. package/dist/fluidDebuggerUi.d.ts +1 -1
  10. package/dist/fluidDebuggerUi.d.ts.map +1 -1
  11. package/dist/fluidDebuggerUi.js +25 -25
  12. package/dist/fluidDebuggerUi.js.map +1 -1
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/legacy.d.ts +1 -1
  17. package/dist/messageSchema.d.ts +1 -1
  18. package/dist/messageSchema.d.ts.map +1 -1
  19. package/dist/messageSchema.js.map +1 -1
  20. package/dist/public.d.ts +1 -1
  21. package/dist/sanitize.js.map +1 -1
  22. package/dist/sanitizer.d.ts +1 -1
  23. package/dist/sanitizer.d.ts.map +1 -1
  24. package/dist/sanitizer.js +52 -50
  25. package/dist/sanitizer.js.map +1 -1
  26. package/eslint.config.mts +13 -4
  27. package/internal.d.ts +1 -1
  28. package/legacy.d.ts +1 -1
  29. package/lib/fluidDebugger.d.ts +1 -1
  30. package/lib/fluidDebugger.d.ts.map +1 -1
  31. package/lib/fluidDebugger.js.map +1 -1
  32. package/lib/fluidDebuggerController.d.ts +4 -3
  33. package/lib/fluidDebuggerController.d.ts.map +1 -1
  34. package/lib/fluidDebuggerController.js +4 -4
  35. package/lib/fluidDebuggerController.js.map +1 -1
  36. package/lib/fluidDebuggerUi.d.ts +1 -1
  37. package/lib/fluidDebuggerUi.d.ts.map +1 -1
  38. package/lib/fluidDebuggerUi.js +25 -25
  39. package/lib/fluidDebuggerUi.js.map +1 -1
  40. package/lib/index.d.ts +2 -2
  41. package/lib/index.d.ts.map +1 -1
  42. package/lib/index.js.map +1 -1
  43. package/lib/legacy.d.ts +1 -1
  44. package/lib/messageSchema.d.ts +1 -1
  45. package/lib/messageSchema.d.ts.map +1 -1
  46. package/lib/messageSchema.js.map +1 -1
  47. package/lib/public.d.ts +1 -1
  48. package/lib/sanitize.js.map +1 -1
  49. package/lib/sanitizer.d.ts +1 -1
  50. package/lib/sanitizer.d.ts.map +1 -1
  51. package/lib/sanitizer.js +52 -50
  52. package/lib/sanitizer.js.map +1 -1
  53. package/package.json +13 -22
  54. package/src/fluidDebugger.ts +1 -1
  55. package/src/fluidDebuggerController.ts +10 -8
  56. package/src/fluidDebuggerUi.ts +26 -26
  57. package/src/index.ts +2 -2
  58. package/src/messageSchema.ts +1 -1
  59. package/src/sanitize.ts +1 -1
  60. package/src/sanitizer.ts +49 -47
  61. package/tsconfig.json +1 -1
package/lib/sanitizer.js CHANGED
@@ -80,8 +80,8 @@ class ChunkedOpProcessor {
80
80
  parsed = parsed.contents;
81
81
  }
82
82
  }
83
- catch (e) {
84
- this.debugMsg(e);
83
+ catch (error) {
84
+ this.debugMsg(error);
85
85
  this.debugMsg(message.contents);
86
86
  }
87
87
  this.validateSchemaFn(parsed, chunkedOpContentsSchema);
@@ -103,9 +103,9 @@ class ChunkedOpProcessor {
103
103
  try {
104
104
  return JSON.parse(contentsString);
105
105
  }
106
- catch (e) {
106
+ catch (error) {
107
107
  this.debugMsg(contentsString);
108
- this.debugMsg(e);
108
+ this.debugMsg(error);
109
109
  return undefined;
110
110
  }
111
111
  }
@@ -123,9 +123,9 @@ class ChunkedOpProcessor {
123
123
  stringified = JSON.stringify(contents);
124
124
  assert(stringified.length <= this.concatenatedLength, 0x089 /* "Stringified length of chunk contents > total starting length" */);
125
125
  }
126
- catch (e) {
127
- this.debugMsg(e);
128
- throw e;
126
+ catch (error) {
127
+ this.debugMsg(error);
128
+ throw error;
129
129
  }
130
130
  for (let i = 0; i < this.messages.length; i++) {
131
131
  const substring = stringified.substring(i * chunkSize, (i + 1) * chunkSize);
@@ -147,8 +147,8 @@ class ChunkedOpProcessor {
147
147
  stringifiedParsedContents = JSON.stringify(parsedContents);
148
148
  }
149
149
  }
150
- catch (e) {
151
- this.debugMsg(e);
150
+ catch (error) {
151
+ this.debugMsg(error);
152
152
  }
153
153
  message.contents = stringifiedParsedContents;
154
154
  }
@@ -162,7 +162,7 @@ class ChunkedOpProcessor {
162
162
  this.concatenatedLength = 0;
163
163
  }
164
164
  isPendingProcessing() {
165
- return this.messages.length !== 0;
165
+ return this.messages.length > 0;
166
166
  }
167
167
  }
168
168
  export class Sanitizer {
@@ -229,9 +229,9 @@ export class Sanitizer {
229
229
  getRandomText(len) {
230
230
  let str = "";
231
231
  while (str.length < len) {
232
- str = str + Math.random().toString(36).substring(2);
232
+ str = str + Math.random().toString(36).slice(2);
233
233
  }
234
- return str.substr(0, len);
234
+ return str.slice(0, Math.max(0, len));
235
235
  }
236
236
  /**
237
237
  * Replace text with garbage. FluidObject types are not replaced when not under
@@ -280,7 +280,7 @@ export class Sanitizer {
280
280
  return input;
281
281
  }
282
282
  const keys = Object.keys(input);
283
- keys.forEach((key) => {
283
+ for (const key of keys) {
284
284
  if (this.fullScrub || !excludedKeys.has(key)) {
285
285
  const value = input[key];
286
286
  if (typeof value === "string") {
@@ -293,7 +293,7 @@ export class Sanitizer {
293
293
  input[key] = this.replaceObject(value, excludedKeys);
294
294
  }
295
295
  }
296
- });
296
+ }
297
297
  return input;
298
298
  }
299
299
  /**
@@ -324,26 +324,23 @@ export class Sanitizer {
324
324
  }
325
325
  try {
326
326
  let data = JSON.parse(message.data);
327
- if (!this.objectMatchesSchema(data, joinDataSchema)) {
328
- data = this.replaceAny(data);
329
- }
330
- else {
327
+ if (this.objectMatchesSchema(data, joinDataSchema)) {
331
328
  const user = data.detail.user;
332
329
  user.id = this.replaceText(user.id, TextType.Email);
333
330
  user.email = this.replaceText(user.email, TextType.Email);
334
331
  user.name = this.replaceText(user.name, TextType.Name);
335
332
  }
333
+ else {
334
+ data = this.replaceAny(data);
335
+ }
336
336
  message.data = JSON.stringify(data);
337
337
  }
338
- catch (e) {
339
- this.debugMsg(e);
338
+ catch (error) {
339
+ this.debugMsg(error);
340
340
  }
341
341
  }
342
342
  fixPropose(message) {
343
- if (!this.objectMatchesSchema(message.contents, proposeContentsSchema)) {
344
- message.contents = this.replaceAny(message.contents);
345
- }
346
- else {
343
+ if (this.objectMatchesSchema(message.contents, proposeContentsSchema)) {
347
344
  if (typeof message.contents === "string") {
348
345
  try {
349
346
  const data = JSON.parse(message.contents);
@@ -357,8 +354,8 @@ export class Sanitizer {
357
354
  }
358
355
  }
359
356
  }
360
- catch (e) {
361
- this.debugMsg(e);
357
+ catch (error) {
358
+ this.debugMsg(error);
362
359
  }
363
360
  }
364
361
  else {
@@ -367,9 +364,12 @@ export class Sanitizer {
367
364
  }
368
365
  }
369
366
  }
367
+ else {
368
+ message.contents = this.replaceAny(message.contents);
369
+ }
370
370
  }
371
371
  fixAttachEntries(entries) {
372
- entries.forEach((element) => {
372
+ for (const element of entries) {
373
373
  // Tree type
374
374
  if (element.value.entries) {
375
375
  this.fixAttachEntries(element.value.entries);
@@ -383,11 +383,11 @@ export class Sanitizer {
383
383
  element.value.contents = JSON.stringify(data);
384
384
  }
385
385
  }
386
- catch (e) {
387
- this.debugMsg(e);
386
+ catch (error) {
387
+ this.debugMsg(error);
388
388
  }
389
389
  }
390
- });
390
+ }
391
391
  }
392
392
  /**
393
393
  * Fix the content of an attach in place
@@ -395,16 +395,16 @@ export class Sanitizer {
395
395
  */
396
396
  fixAttachContents(contents) {
397
397
  assert(typeof contents === "object", 0x08b /* "Unexpected type on contents for fix of an attach!" */);
398
- if (!this.objectMatchesSchema(contents, attachContentsSchema)) {
399
- this.replaceObject(contents);
400
- }
401
- else {
398
+ if (this.objectMatchesSchema(contents, attachContentsSchema)) {
402
399
  if (this.fullScrub) {
403
400
  contents.id = this.replaceText(contents.id, TextType.FluidObject);
404
401
  contents.type = this.replaceText(contents.type, TextType.FluidObject);
405
402
  }
406
403
  this.fixAttachEntries(contents.snapshot.entries);
407
404
  }
405
+ else {
406
+ this.replaceObject(contents);
407
+ }
408
408
  }
409
409
  /**
410
410
  * Fix an attach message at the root level or a ContainerMessageType attach. Attach
@@ -424,8 +424,8 @@ export class Sanitizer {
424
424
  this.fixAttachContents(data);
425
425
  message.contents = JSON.stringify(data);
426
426
  }
427
- catch (e) {
428
- this.debugMsg(e);
427
+ catch (error) {
428
+ this.debugMsg(error);
429
429
  return;
430
430
  }
431
431
  }
@@ -448,10 +448,7 @@ export class Sanitizer {
448
448
  */
449
449
  fixOpContentsObject(contents) {
450
450
  // do replacement
451
- if (!this.objectMatchesSchema(contents, opContentsSchema)) {
452
- this.replaceAny(contents);
453
- }
454
- else {
451
+ if (this.objectMatchesSchema(contents, opContentsSchema)) {
455
452
  if (this.fullScrub) {
456
453
  contents.address = this.replaceText(contents.address, TextType.FluidObject);
457
454
  }
@@ -466,8 +463,8 @@ export class Sanitizer {
466
463
  this.fixAttachContents(data);
467
464
  contents.contents.content = JSON.stringify(data);
468
465
  }
469
- catch (e) {
470
- this.debugMsg(e);
466
+ catch (error) {
467
+ this.debugMsg(error);
471
468
  }
472
469
  }
473
470
  else {
@@ -489,9 +486,9 @@ export class Sanitizer {
489
486
  if (this.fullScrub) {
490
487
  innerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);
491
488
  }
492
- innerContent.contents.ops.forEach((deltaOp) => {
489
+ for (const deltaOp of innerContent.contents.ops) {
493
490
  this.fixDeltaOp(deltaOp);
494
- });
491
+ }
495
492
  }
496
493
  else if (this.validator.validate(innerContent, opContentsMergeTreeDeltaOpSchema).valid) {
497
494
  // merge tree delta op
@@ -515,6 +512,9 @@ export class Sanitizer {
515
512
  this.objectMatchesSchema(contents, false);
516
513
  }
517
514
  }
515
+ else {
516
+ this.replaceAny(contents);
517
+ }
518
518
  }
519
519
  fixOp(message) {
520
520
  // handle case where contents is stringified json
@@ -523,8 +523,8 @@ export class Sanitizer {
523
523
  try {
524
524
  msgContents = JSON.parse(message.contents);
525
525
  }
526
- catch (e) {
527
- this.debugMsg(e);
526
+ catch (error) {
527
+ this.debugMsg(error);
528
528
  return;
529
529
  }
530
530
  }
@@ -569,8 +569,8 @@ export class Sanitizer {
569
569
  try {
570
570
  message.contents = JSON.stringify(msgContents);
571
571
  }
572
- catch (e) {
573
- this.debugMsg(e);
572
+ catch (error) {
573
+ this.debugMsg(error);
574
574
  return;
575
575
  }
576
576
  }
@@ -623,10 +623,12 @@ export class Sanitizer {
623
623
  case "noClient":
624
624
  case "summarize":
625
625
  case "summaryAck":
626
- case "summaryNack":
626
+ case "summaryNack": {
627
627
  break;
628
- default:
628
+ }
629
+ default: {
629
630
  this.debugMsg(`Unexpected op type ${message.type}`);
631
+ }
630
632
  }
631
633
  });
632
634
  // make sure we don't miss an incomplete chunked op at the end
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../src/sanitizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAE7D,OAAO,KAAK,SAAS,MAAM,YAAY,CAAC;AAExC,OAAO,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,gCAAgC,EAChC,gCAAgC,EAChC,kCAAkC,EAClC,gBAAgB,EAChB,qBAAqB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,IAAK,QAMJ;AAND,WAAK,QAAQ;IACZ,6CAAO,CAAA;IACP,yCAAK,CAAA;IACL,uCAAI,CAAA;IACJ,qDAAW,CAAA;IACX,2CAAM,CAAA;AACP,CAAC,EANI,QAAQ,KAAR,QAAQ,QAMZ;AAED,sEAAsE;AACtE,uBAAuB;AACvB,MAAM,WAAW,GAAG;IACnB,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,GAAG,EAAE;QACd,OAAO,kBAAkB,CAAC;IAC3B,CAAC;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,kBAAkB;IAoBvB,YACU,gBAAuD,EACvD,KAAc;QADd,qBAAgB,GAAhB,gBAAgB,CAAuC;QACvD,UAAK,GAAL,KAAK,CAAS;QArBxB;;;;WAIG;QACK,aAAQ,GAAG,IAAI,KAAK,EAAO,CAAC;QACpC;;;WAGG;QACK,0BAAqB,GAAG,IAAI,KAAK,EAAO,CAAC;QACzC,gBAAW,GAAG,KAAK,CAAC;QAC5B;;;;WAIG;QACK,uBAAkB,GAAG,CAAC,CAAC;IAK5B,CAAC;IAEJ,QAAQ,CAAC,GAAQ;QAChB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IAED,UAAU,CAAC,OAAY;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE5B,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC3B,6BAA6B;gBAC7B,gDAAgD;gBAChD,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;YAC1B,CAAC;QACF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;QACvD,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,cAAc;QACb,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1F,OAAO,CACN,eAAe,CAAC,OAAO,KAAK,SAAS;YACrC,eAAe,CAAC,OAAO,KAAK,eAAe,CAAC,WAAW,CACvD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,uBAAuB;QACtB,MAAM,cAAc,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CACvD,CAAC,aAAqB,EAAE,YAAiB,EAAE,EAAE;YAC5C,OAAO,aAAa,GAAI,YAAY,CAAC,QAAmB,CAAC;QAC1D,CAAC,EACD,EAAE,CACF,CAAC;QAEF,IAAI,CAAC,kBAAkB,GAAG,cAAc,CAAC,MAAM,CAAC;QAChD,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC9B,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjB,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACH,sBAAsB,CAAC,QAAa;QACnC,gDAAgD;QAChD,MAAM,SAAS,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QAEhE,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACJ,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,CACL,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,kBAAkB,EAC7C,KAAK,CAAC,oEAAoE,CAC1E,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjB,MAAM,CAAC,CAAC;QACT,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;YAE5E,MAAM,cAAc,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YACrD,cAAc,CAAC,QAAQ,GAAG,SAAS,CAAC;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAEjC,IAAI,yBAAyB,CAAC;YAC9B,IAAI,CAAC;gBACJ,qEAAqE;gBACrE,6CAA6C;gBAC7C,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;oBAC3B,MAAM,YAAY,GAAG;wBACpB,IAAI,EAAE,WAAW;wBACjB,QAAQ,EAAE,cAAc;qBACxB,CAAC;oBACF,yBAAyB,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;gBAC1D,CAAC;qBAAM,CAAC;oBACP,yBAAyB,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;gBAC5D,CAAC;YACF,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,OAAO,CAAC,QAAQ,GAAG,yBAAyB,CAAC;QAC9C,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,KAAK;QACJ,MAAM,CACL,IAAI,CAAC,WAAW,EAChB,KAAK,CAAC,uEAAuE,CAC7E,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,EAAO,CAAC;QACjC,IAAI,CAAC,qBAAqB,GAAG,IAAI,KAAK,EAAO,CAAC;QAC9C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,mBAAmB;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;IACnC,CAAC;CACD;AAED,MAAM,OAAO,SAAS;IAuCrB,YACU,QAAqC,EACrC,SAAkB,EAClB,MAAe,EACf,QAAiB,KAAK;QAHtB,aAAQ,GAAR,QAAQ,CAA6B;QACrC,cAAS,GAAT,SAAS,CAAS;QAClB,WAAM,GAAN,MAAM,CAAS;QACf,UAAK,GAAL,KAAK,CAAiB;QA1CvB,cAAS,GAAG,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QAC/C,6EAA6E;QAC7E,2EAA2E;QAC3E,uCAAuC;QAC9B,wBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;QACjD,+EAA+E;QAC/E,kCAAkC;QACzB,0BAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;QACnD,iFAAiF;QACjF,kCAAkC;QACzB,mBAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEpD;;;;;WAKG;QACH,wBAAmB,GAAG,CAAC,MAAW,EAAE,MAAW,EAAW,EAAE;YAC3D,MAAM,MAAM,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACxF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAAG,iBAAiB,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,SAAS,CACrE,MAAM,EACN,SAAS,EACT,CAAC,CACD,EAAE,CAAC;gBAEJ,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBACnC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACzB,CAAC;qBAAM,CAAC;oBACP,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC3B,CAAC;YACF,CAAC;YACD,OAAO,MAAM,CAAC,KAAK,CAAC;QACrB,CAAC,CAAC;QAqCO,mBAAc,GAAG,MAAM,CAAC;QAExB,wBAAmB,GAAG,CAAC,KAAa,EAAU,EAAE;YACxD,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;YACxC,CAAC;YAED,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YAC5C,OAAO,WAAW,CAAC;QACpB,CAAC,CAAC;QArCD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC/C,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,cAAc,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAC/E,CAAC;IAED,QAAQ,CAAC,GAAQ;QAChB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IAED,gBAAgB,CAAC,GAAW;QAC3B,OAAO,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC;IACvC,CAAC;IAED,aAAa,CAAC,GAAW;QACxB,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,OAAO,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACzB,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3B,CAAC;IAcD;;;OAGG;IACH,WAAW,CAAC,KAAc,EAAE,OAAiB,QAAQ,CAAC,OAAO;QAC5D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,IAAI,IAAI,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;YACxC,CAAC;YAED,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAE9E,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YAC5C,OAAO,WAAW,CAAC;QACpB,CAAC;QAED,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,YAAY,CAAC,KAAY;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/B,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACtC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,aAAa;IACZ,kDAAkD;IAClD,KAAoB,EACpB,eAA4B,IAAI,CAAC,mBAAmB;QAGpD,kCAAkC;QAClC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC3C,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACpB,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;gBACzB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC/B,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAC5B,KAAK,EACL,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CACpE,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACjC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;gBACvC,CAAC;qBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBACtC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;gBACtD,CAAC;YACF,CAAC;QACF,CAAC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,KAAU,EAAE,eAA4B,IAAI,CAAC,mBAAmB;QAC1E,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC3C,OAAO,KAAK,CAAC;QACd,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QAChD,CAAC;QAED,2CAA2C;QAC3C,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,CAAC,OAAY;QACnB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EAAE,CAAC;YACrE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC;gBACrD,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC9B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACpD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC1D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxD,CAAC;YAED,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACF,CAAC;IAED,UAAU,CAAC,OAAY;QACtB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,CAAC;YACxE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACP,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1C,IAAI,CAAC;oBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;oBAC1C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;wBACpB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC;wBAChC,IAAI,GAAG,EAAE,IAAI,EAAE,CAAC;4BACf,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;wBAC7D,CAAC;wBACD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;4BACpD,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;wBAC9E,CAAC;oBACF,CAAC;gBACF,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,EACtB,QAAQ,CAAC,WAAW,CACpB,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,gBAAgB,CAAC,OAAc;QAC9B,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,YAAY;YACZ,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC3B,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC9C,CAAC;iBAAM,CAAC;gBACP,mBAAmB;gBACnB,IAAI,CAAC;oBACJ,IAAI,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;wBAChD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC9C,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;wBAChC,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBAC/C,CAAC;gBACF,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;YACF,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,QAAa;QAC9B,MAAM,CACL,OAAO,QAAQ,KAAK,QAAQ,EAC5B,KAAK,CAAC,yDAAyD,CAC/D,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;gBAClE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;YACvE,CAAC;YAED,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClD,CAAC;IACF,CAAC;IAED;;;;;;;;;OASG;IACH,SAAS,CAAC,OAAY;QACrB,iDAAiD;QACjD,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC1C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAC7B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACjB,OAAO;YACR,CAAC;QACF,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;IACF,CAAC;IAED,UAAU,CAAC,OAAY;QACtB,OAAO,CAAC,GAAG;YACV,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ;gBAC9B,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,QAAa;QAChC,iBAAiB;QACjB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC7E,CAAC;YAED,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC/C,MAAM,CACL,YAAY,KAAK,SAAS,EAC1B,KAAK,CAAC,yDAAyD,CAC/D,CAAC;YACF,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACzC,YAAY;gBACZ,sDAAsD;gBACtD,IAAI,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBACnD,IAAI,CAAC;wBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;wBACnD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;wBAC7B,QAAQ,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBAClD,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;oBAClB,CAAC;gBACF,CAAC;qBAAM,CAAC;oBACP,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACnD,CAAC;YACF,CAAC;iBAAM,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC;gBAC7E,SAAS;gBACT,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;oBACpF,YAAY,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,CAAC,WAAW,CAC3C,YAAY,CAAC,QAAQ,CAAC,GAAG,EACzB,QAAQ,CAAC,MAAM,CACf,CAAC;gBACH,CAAC;gBACD,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAC/C,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,CAClD,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CACjC,CAAC;gBACH,CAAC;YACF,CAAC;iBAAM,IACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,gCAAgC,CAAC,CAAC,KAAK,EAC5E,CAAC;gBACF,sBAAsB;gBACtB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;gBACrF,CAAC;gBACD,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;oBAC7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBAC1B,CAAC,CAAC,CAAC;YACJ,CAAC;iBAAM,IACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,gCAAgC,CAAC,CAAC,KAAK,EAC5E,CAAC;gBACF,sBAAsB;gBACtB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;gBACrF,CAAC;gBACD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACxC,CAAC;iBAAM,IACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,kCAAkC,CAAC,CAAC,KAAK,EAC9E,CAAC;gBACF,yBAAyB;gBACzB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;oBACpF,YAAY,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,CAAC,WAAW,CAC3C,YAAY,CAAC,QAAQ,CAAC,GAAG,EACzB,QAAQ,CAAC,MAAM,CACf,CAAC;gBACH,CAAC;gBACD,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAC/C,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,CAClD,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CACjC,CAAC;gBACH,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,mDAAmD;gBACnD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC3C,CAAC;QACF,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAY;QACjB,iDAAiD;QACjD,IAAI,WAAW,CAAC;QAChB,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACJ,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC5C,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACjB,OAAO;YACR,CAAC;QACF,CAAC;aAAM,CAAC;YACP,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;QAChC,CAAC;QAED,iCAAiC;QACjC,QAAQ,WAAW,CAAC,IAAI,EAAE,CAAC;YAC1B,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACf,kFAAkF;gBAClF,oCAAoC;gBACpC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;gBAC5B,MAAM;YACP,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBAClB,4DAA4D;gBAC5D,qDAAqD;gBACrD,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC/C,MAAM;YACP,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBAClB,iFAAiF;gBACjF,uFAAuF;gBACvF,iFAAiF;gBACjF,4DAA4D;gBAC5D,oFAAoF;gBACpF,yEAAyE;gBACzE,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBACnB,mDAAmD;gBACnD,IAAI,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC;gBAC5D,OAAO;YACR,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACT,eAAe;gBACf,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;YACvC,CAAC;QACF,CAAC;QAED,kCAAkC;QAClC,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACJ,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YAChD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACjB,OAAO;YACR,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,OAAY;QACxB,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3C,OAAO;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,uBAAuB,EAAE,CAAC;QAC/D,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,CAAC,cAAc,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,QAAQ;QACP,IAAI,GAAG,GAAG,CAAC,CAAC;QAEZ,IAAI,CAAC;YACJ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC;gBAC7B,uDAAuD;gBACvD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;oBACtB,KAAK,MAAM,CAAC,CAAC,CAAC;wBACb,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;wBACtB,MAAM;oBACP,CAAC;oBACD,KAAK,SAAS,CAAC,CAAC,CAAC;wBAChB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;wBACzB,MAAM;oBACP,CAAC;oBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;wBACf,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;wBACxB,MAAM;oBACP,CAAC;oBACD,KAAK,IAAI,CAAC,CAAC,CAAC;wBACX,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACpB,MAAM;oBACP,CAAC;oBACD,KAAK,WAAW,CAAC,CAAC,CAAC;wBAClB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;wBAC3B,MAAM;oBACP,CAAC;oBACD,KAAK,MAAM,CAAC;oBACZ,KAAK,OAAO,CAAC;oBACb,KAAK,UAAU,CAAC;oBAChB,KAAK,WAAW,CAAC;oBACjB,KAAK,YAAY,CAAC;oBAClB,KAAK,aAAa;wBACjB,MAAM;oBACP;wBACC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtD,CAAC;YACF,CAAC,CAAC,CAAC;YAEH,8DAA8D;YAC9D,MAAM,CACL,CAAC,IAAI,CAAC,cAAc,CAAC,mBAAmB,EAAE,EAC1C,KAAK,CAAC,+CAA+C,CACrD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,QAAQ,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC;QACb,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * This tool cleans up a message.json file downloaded through fluid-fetch to remove\n * user content and user identifying information. Enough information can be retained\n * to allow loading through Fluid Preview, or everything can be scrubbed so that only\n * replay-tool can read the result. Anonymous identifying information such as client\n * IDs are always retained. Object keys are NOT scrubbed, including those that are\n * nested within values (only leaf values are scrubbed).\n *\n * Note: While user content/information is scrubbed, it should not be assumed to be\n * fully anonymized because certain meta-information (such as word lengths and\n * consistent replacement) are preserved.\n *\n * Messages must match known structures when scrubbing for Fluid Preview.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport * as Validator from \"jsonschema\";\n\nimport {\n\tattachContentsSchema,\n\tchunkedOpContentsSchema,\n\tjoinContentsSchema,\n\tjoinDataSchema,\n\topContentsMapSchema,\n\topContentsMergeTreeDeltaOpSchema,\n\topContentsMergeTreeGroupOpSchema,\n\topContentsRegisterCollectionSchema,\n\topContentsSchema,\n\tproposeContentsSchema,\n} from \"./messageSchema.js\";\n\nenum TextType {\n\tGeneric,\n\tEmail,\n\tName,\n\tFluidObject,\n\tMapKey,\n}\n\n// Workaround to jsonschema package not supporting \"false\" as a schema\n// that matches nothing\nconst falseResult = {\n\tvalid: false,\n\ttoString: () => {\n\t\treturn \"Unmatched format\";\n\t},\n};\n\n/**\n * Class that takes chunkedOp messages and can provide their concatenated\n * contents along with re-write sanitized content in-place back into the\n * messages. Assumes sanitized messages are always less than or equal in\n * size to the original message.\n */\nclass ChunkedOpProcessor {\n\t/**\n\t * Message references so we can replace their contents in-place. These can\n\t * be top-level chunkedOp messages, or top-level op messages with a chunkedOp\n\t * within the contents\n\t */\n\tprivate messages = new Array<any>();\n\t/**\n\t * The messages' parsed contents for processing. Should parallel the\n\t * messages member\n\t */\n\tprivate parsedMessageContents = new Array<any>();\n\tprivate writtenBack = false;\n\t/**\n\t * keep track of the total starting length to make sure we don't somehow end\n\t * up with more content than we started with (meaning we may not be able to\n\t * write it back)\n\t */\n\tprivate concatenatedLength = 0;\n\n\tconstructor(\n\t\treadonly validateSchemaFn: (object: any, schema: any) => boolean,\n\t\treadonly debug: boolean,\n\t) {}\n\n\tdebugMsg(msg: any): void {\n\t\tif (this.debug) {\n\t\t\tconsole.error(msg);\n\t\t}\n\t}\n\n\taddMessage(message: any): void {\n\t\tthis.messages.push(message);\n\n\t\tlet parsed;\n\t\ttry {\n\t\t\tparsed = JSON.parse(message.contents);\n\t\t\tif (message.type === \"op\") {\n\t\t\t\t// nested within a regular op\n\t\t\t\t// need to go deeper to get the desired contents\n\t\t\t\tparsed = parsed.contents;\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tthis.debugMsg(e);\n\t\t\tthis.debugMsg(message.contents);\n\t\t}\n\t\tthis.validateSchemaFn(parsed, chunkedOpContentsSchema);\n\t\tthis.parsedMessageContents.push(parsed);\n\t}\n\n\thasAllMessages(): boolean {\n\t\tconst lastMsgContents = this.parsedMessageContents[this.parsedMessageContents.length - 1];\n\t\treturn (\n\t\t\tlastMsgContents.chunkId !== undefined &&\n\t\t\tlastMsgContents.chunkId === lastMsgContents.totalChunks\n\t\t);\n\t}\n\n\t/**\n\t * Gets the concatenated contents of all the messages parsed as JSON.\n\t */\n\tgetConcatenatedContents(): any {\n\t\tconst contentsString = this.parsedMessageContents.reduce(\n\t\t\t(previousValue: string, currentValue: any) => {\n\t\t\t\treturn previousValue + (currentValue.contents as string);\n\t\t\t},\n\t\t\t\"\",\n\t\t);\n\n\t\tthis.concatenatedLength = contentsString.length;\n\t\ttry {\n\t\t\treturn JSON.parse(contentsString);\n\t\t} catch (e) {\n\t\t\tthis.debugMsg(contentsString);\n\t\t\tthis.debugMsg(e);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Write back sanitized contents into the messages. The contents are\n\t * stringified, split up, and written in place to the messages that\n\t * were added earlier. The number of messages is preserved.\n\t * @param contents - Sanitized contents to write back\n\t */\n\twriteSanitizedContents(contents: any): void {\n\t\t// Write back a chunk size equal to the original\n\t\tconst chunkSize = this.parsedMessageContents[0].contents.length;\n\n\t\tlet stringified: string;\n\t\ttry {\n\t\t\tstringified = JSON.stringify(contents);\n\t\t\tassert(\n\t\t\t\tstringified.length <= this.concatenatedLength,\n\t\t\t\t0x089 /* \"Stringified length of chunk contents > total starting length\" */,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.debugMsg(e);\n\t\t\tthrow e;\n\t\t}\n\n\t\tfor (let i = 0; i < this.messages.length; i++) {\n\t\t\tconst substring = stringified.substring(i * chunkSize, (i + 1) * chunkSize);\n\n\t\t\tconst parsedContents = this.parsedMessageContents[i];\n\t\t\tparsedContents.contents = substring;\n\t\t\tconst message = this.messages[i];\n\n\t\t\tlet stringifiedParsedContents;\n\t\t\ttry {\n\t\t\t\t// for nested chunkedOps, we need to recreate the extra nesting layer\n\t\t\t\t// we removed earlier when adding the message\n\t\t\t\tif (message.type === \"op\") {\n\t\t\t\t\tconst nestingLayer = {\n\t\t\t\t\t\ttype: \"chunkedOp\",\n\t\t\t\t\t\tcontents: parsedContents,\n\t\t\t\t\t};\n\t\t\t\t\tstringifiedParsedContents = JSON.stringify(nestingLayer);\n\t\t\t\t} else {\n\t\t\t\t\tstringifiedParsedContents = JSON.stringify(parsedContents);\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tthis.debugMsg(e);\n\t\t\t}\n\n\t\t\tmessage.contents = stringifiedParsedContents;\n\t\t}\n\n\t\tthis.writtenBack = true;\n\t}\n\n\treset(): void {\n\t\tassert(\n\t\t\tthis.writtenBack,\n\t\t\t0x08a /* \"resetting ChunkedOpProcessor that never wrote back its contents\" */,\n\t\t);\n\t\tthis.messages = new Array<any>();\n\t\tthis.parsedMessageContents = new Array<any>();\n\t\tthis.writtenBack = false;\n\t\tthis.concatenatedLength = 0;\n\t}\n\n\tisPendingProcessing(): boolean {\n\t\treturn this.messages.length !== 0;\n\t}\n}\n\nexport class Sanitizer {\n\treadonly validator = new Validator.Validator();\n\t// Represents the keys used to store Fluid object identifiers, snapshot info,\n\t// and other string fields that should not be replaced in contents blobs to\n\t// ensure the messages are still usable\n\treadonly defaultExcludedKeys = new Set<string>();\n\t// Represents the keys used by merge-tree ops their \"seg\" property, where other\n\t// keys represent user information\n\treadonly mergeTreeExcludedKeys = new Set<string>();\n\t// Map of user information to what it was replaced with. Used to ensure the same\n\t// data have the same replacements\n\treadonly replacementMap = new Map<string, string>();\n\n\t/**\n\t * Validate that the provided message matches the provided schema.\n\t * For a full scrub, warn and continue (scrubber should fully sanitize unexpected\n\t * fields for ops), otherwise throw an error because we cannot be sure user\n\t * information is being sufficiently sanitized.\n\t */\n\tobjectMatchesSchema = (object: any, schema: any): boolean => {\n\t\tconst result = schema === false ? falseResult : this.validator.validate(object, schema);\n\t\tif (!result.valid) {\n\t\t\tconst errorMsg = `Bad msg fmt:\\n${result.toString()}\\n${JSON.stringify(\n\t\t\t\tobject,\n\t\t\t\tundefined,\n\t\t\t\t2,\n\t\t\t)}`;\n\n\t\t\tif (this.fullScrub || this.noBail) {\n\t\t\t\tthis.debugMsg(errorMsg);\n\t\t\t} else {\n\t\t\t\tthrow new Error(errorMsg);\n\t\t\t}\n\t\t}\n\t\treturn result.valid;\n\t};\n\n\treadonly chunkProcessor: ChunkedOpProcessor;\n\n\tconstructor(\n\t\treadonly messages: ISequencedDocumentMessage[],\n\t\treadonly fullScrub: boolean,\n\t\treadonly noBail: boolean,\n\t\treadonly debug: boolean = false,\n\t) {\n\t\tthis.defaultExcludedKeys.add(\"type\");\n\t\tthis.defaultExcludedKeys.add(\"id\");\n\t\tthis.defaultExcludedKeys.add(\"pkg\");\n\t\tthis.defaultExcludedKeys.add(\"snapshotFormatVersion\");\n\t\tthis.defaultExcludedKeys.add(\"packageVersion\");\n\t\tthis.mergeTreeExcludedKeys.add(\"nodeType\");\n\t\tthis.chunkProcessor = new ChunkedOpProcessor(this.objectMatchesSchema, debug);\n\t}\n\n\tdebugMsg(msg: any): void {\n\t\tif (this.debug) {\n\t\t\tconsole.error(msg);\n\t\t}\n\t}\n\n\tisFluidObjectKey(key: string): boolean {\n\t\treturn key === \"type\" || key === \"id\";\n\t}\n\n\tgetRandomText(len: number): string {\n\t\tlet str = \"\";\n\t\twhile (str.length < len) {\n\t\t\tstr = str + Math.random().toString(36).substring(2);\n\t\t}\n\t\treturn str.substr(0, len);\n\t}\n\n\treadonly wordTokenRegex = /\\S+/g;\n\n\treadonly replaceRandomTextFn = (match: string): string => {\n\t\tif (this.replacementMap.has(match)) {\n\t\t\treturn this.replacementMap.get(match)!;\n\t\t}\n\n\t\tconst replacement = this.getRandomText(match.length);\n\t\tthis.replacementMap.set(match, replacement);\n\t\treturn replacement;\n\t};\n\n\t/**\n\t * Replace text with garbage. FluidObject types are not replaced when not under\n\t * full scrub mode. All other text is replaced consistently.\n\t */\n\treplaceText(input?: string, type: TextType = TextType.Generic): string | undefined {\n\t\tif (input === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (type === TextType.FluidObject) {\n\t\t\tif (this.replacementMap.has(input)) {\n\t\t\t\treturn this.replacementMap.get(input)!;\n\t\t\t}\n\n\t\t\tconst replacement = this.fullScrub ? this.getRandomText(input.length) : input;\n\n\t\t\tthis.replacementMap.set(input, replacement);\n\t\t\treturn replacement;\n\t\t}\n\n\t\treturn input.replace(this.wordTokenRegex, this.replaceRandomTextFn);\n\t}\n\n\treplaceArray(input: any[]): any[] {\n\t\tfor (let i = 0; i < input.length; i++) {\n\t\t\tconst value = input[i];\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tinput[i] = this.replaceText(value);\n\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\tinput[i] = this.replaceArray(value);\n\t\t\t} else if (typeof value === \"object\") {\n\t\t\t\tinput[i] = this.replaceObject(value);\n\t\t\t}\n\t\t}\n\t\treturn input;\n\t}\n\n\t/**\n\t * (sort of) recurses down the values of a JSON object to sanitize all its strings\n\t * (only checks strings, arrays, and objects)\n\t * @param input - The object to sanitize\n\t * @param excludedKeys - object keys for which to skip replacement when not in fullScrub\n\t */\n\treplaceObject(\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t\tinput: object | null,\n\t\texcludedKeys: Set<string> = this.defaultExcludedKeys,\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t): object | null {\n\t\t// File might contain actual nulls\n\t\tif (input === null || input === undefined) {\n\t\t\treturn input;\n\t\t}\n\n\t\tconst keys = Object.keys(input);\n\t\tkeys.forEach((key) => {\n\t\t\tif (this.fullScrub || !excludedKeys.has(key)) {\n\t\t\t\tconst value = input[key];\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\tinput[key] = this.replaceText(\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tthis.isFluidObjectKey(key) ? TextType.FluidObject : TextType.Generic,\n\t\t\t\t\t);\n\t\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\t\tinput[key] = this.replaceArray(value);\n\t\t\t\t} else if (typeof value === \"object\") {\n\t\t\t\t\tinput[key] = this.replaceObject(value, excludedKeys);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn input;\n\t}\n\n\t/**\n\t * Replacement on an unknown type or a parsed root level object\n\t * without a key\n\t * @param input - The object to sanitize\n\t * @param excludedKeys - object keys for which to skip replacement when not in fullScrub\n\t */\n\treplaceAny(input: any, excludedKeys: Set<string> = this.defaultExcludedKeys): any {\n\t\tif (input === null || input === undefined) {\n\t\t\treturn input;\n\t\t}\n\n\t\tif (typeof input === \"string\") {\n\t\t\treturn this.replaceText(input);\n\t\t} else if (Array.isArray(input)) {\n\t\t\treturn this.replaceArray(input);\n\t\t} else if (typeof input === \"object\") {\n\t\t\treturn this.replaceObject(input, excludedKeys);\n\t\t}\n\n\t\t// Don't run replacement on any other types\n\t\treturn input;\n\t}\n\n\tfixJoin(message: any): void {\n\t\tif (!this.objectMatchesSchema(message.contents, joinContentsSchema)) {\n\t\t\tmessage.contents = this.replaceAny(message.contents);\n\t\t}\n\n\t\ttry {\n\t\t\tlet data = JSON.parse(message.data);\n\t\t\tif (!this.objectMatchesSchema(data, joinDataSchema)) {\n\t\t\t\tdata = this.replaceAny(data);\n\t\t\t} else {\n\t\t\t\tconst user = data.detail.user;\n\t\t\t\tuser.id = this.replaceText(user.id, TextType.Email);\n\t\t\t\tuser.email = this.replaceText(user.email, TextType.Email);\n\t\t\t\tuser.name = this.replaceText(user.name, TextType.Name);\n\t\t\t}\n\n\t\t\tmessage.data = JSON.stringify(data);\n\t\t} catch (e) {\n\t\t\tthis.debugMsg(e);\n\t\t}\n\t}\n\n\tfixPropose(message: any): void {\n\t\tif (!this.objectMatchesSchema(message.contents, proposeContentsSchema)) {\n\t\t\tmessage.contents = this.replaceAny(message.contents);\n\t\t} else {\n\t\t\tif (typeof message.contents === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst data = JSON.parse(message.contents);\n\t\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\t\tconst pkg = data.value?.package;\n\t\t\t\t\t\tif (pkg?.name) {\n\t\t\t\t\t\t\tpkg.name = this.replaceText(pkg.name, TextType.FluidObject);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Array.isArray(pkg?.fluid?.browser?.umd?.files)) {\n\t\t\t\t\t\t\tpkg.fluid.browser.umd.files = this.replaceArray(pkg.fluid.browser.umd.files);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthis.debugMsg(e);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tmessage.contents.value = this.replaceText(\n\t\t\t\t\t\tmessage.contents.value,\n\t\t\t\t\t\tTextType.FluidObject,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfixAttachEntries(entries: any[]): void {\n\t\tentries.forEach((element) => {\n\t\t\t// Tree type\n\t\t\tif (element.value.entries) {\n\t\t\t\tthis.fixAttachEntries(element.value.entries);\n\t\t\t} else {\n\t\t\t\t// Blob (leaf) type\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof element.value.contents === \"string\") {\n\t\t\t\t\t\tlet data = JSON.parse(element.value.contents);\n\t\t\t\t\t\tdata = this.replaceObject(data);\n\t\t\t\t\t\telement.value.contents = JSON.stringify(data);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthis.debugMsg(e);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Fix the content of an attach in place\n\t * @param contents - contents object to fix\n\t */\n\tfixAttachContents(contents: any): any {\n\t\tassert(\n\t\t\ttypeof contents === \"object\",\n\t\t\t0x08b /* \"Unexpected type on contents for fix of an attach!\" */,\n\t\t);\n\t\tif (!this.objectMatchesSchema(contents, attachContentsSchema)) {\n\t\t\tthis.replaceObject(contents);\n\t\t} else {\n\t\t\tif (this.fullScrub) {\n\t\t\t\tcontents.id = this.replaceText(contents.id, TextType.FluidObject);\n\t\t\t\tcontents.type = this.replaceText(contents.type, TextType.FluidObject);\n\t\t\t}\n\n\t\t\tthis.fixAttachEntries(contents.snapshot.entries);\n\t\t}\n\t}\n\n\t/**\n\t * Fix an attach message at the root level or a ContainerMessageType attach. Attach\n\t * messages found within an op message should instead have their contents parsed out\n\t * and sent to fixAttachContents.\n\t * @param message - The attach message to fix\n\t * @param withinOp - If the message is from within an op message (as opposed to being\n\t * an attach message at the root level). Root level attach messages have \"snapshot\"\n\t * under a \"contents\" key, whereas attach messages from within an op message have it\n\t * under a \"content\" key\n\t */\n\tfixAttach(message: any): void {\n\t\t// Handle case where contents is stringified json\n\t\tif (typeof message.contents === \"string\") {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(message.contents);\n\t\t\t\tthis.fixAttachContents(data);\n\t\t\t\tmessage.contents = JSON.stringify(data);\n\t\t\t} catch (e) {\n\t\t\t\tthis.debugMsg(e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.fixAttachContents(message.contents);\n\t\t}\n\t}\n\n\tfixDeltaOp(deltaOp: any): void {\n\t\tdeltaOp.seg =\n\t\t\ttypeof deltaOp.seg === \"string\"\n\t\t\t\t? this.replaceText(deltaOp.seg)\n\t\t\t\t: this.replaceObject(deltaOp.seg, this.mergeTreeExcludedKeys);\n\t}\n\n\t/**\n\t * Fix the contents object for an op message. Does not do extra type handling. Does\n\t * not handle special container message types like \"attach\", \"component\", and\n\t * \"chunkedOp\" (these should be handled by the caller)\n\t * @param contents - The contents object for an op message. If it was a string in the\n\t * message, it must have been converted to an object first\n\t */\n\tfixOpContentsObject(contents: any): void {\n\t\t// do replacement\n\t\tif (!this.objectMatchesSchema(contents, opContentsSchema)) {\n\t\t\tthis.replaceAny(contents);\n\t\t} else {\n\t\t\tif (this.fullScrub) {\n\t\t\t\tcontents.address = this.replaceText(contents.address, TextType.FluidObject);\n\t\t\t}\n\n\t\t\tconst innerContent = contents.contents.content;\n\t\t\tassert(\n\t\t\t\tinnerContent !== undefined,\n\t\t\t\t0x08c /* \"innerContent for fixing op contents is undefined!\" */,\n\t\t\t);\n\t\t\tif (contents.contents.type === \"attach\") {\n\t\t\t\t// attach op\n\t\t\t\t// handle case where inner content is stringified json\n\t\t\t\tif (typeof contents.contents.content === \"string\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = JSON.parse(contents.contents.content);\n\t\t\t\t\t\tthis.fixAttachContents(data);\n\t\t\t\t\t\tcontents.contents.content = JSON.stringify(data);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tthis.debugMsg(e);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.fixAttachContents(contents.contents.content);\n\t\t\t\t}\n\t\t\t} else if (this.validator.validate(innerContent, opContentsMapSchema).valid) {\n\t\t\t\t// map op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t\tinnerContent.contents.key = this.replaceText(\n\t\t\t\t\t\tinnerContent.contents.key,\n\t\t\t\t\t\tTextType.MapKey,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (innerContent.contents.value !== undefined) {\n\t\t\t\t\tinnerContent.contents.value.value = this.replaceAny(\n\t\t\t\t\t\tinnerContent.contents.value.value,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tthis.validator.validate(innerContent, opContentsMergeTreeGroupOpSchema).valid\n\t\t\t) {\n\t\t\t\t// merge tree group op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t}\n\t\t\t\tinnerContent.contents.ops.forEach((deltaOp) => {\n\t\t\t\t\tthis.fixDeltaOp(deltaOp);\n\t\t\t\t});\n\t\t\t} else if (\n\t\t\t\tthis.validator.validate(innerContent, opContentsMergeTreeDeltaOpSchema).valid\n\t\t\t) {\n\t\t\t\t// merge tree delta op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t}\n\t\t\t\tthis.fixDeltaOp(innerContent.contents);\n\t\t\t} else if (\n\t\t\t\tthis.validator.validate(innerContent, opContentsRegisterCollectionSchema).valid\n\t\t\t) {\n\t\t\t\t// register collection op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t\tinnerContent.contents.key = this.replaceText(\n\t\t\t\t\t\tinnerContent.contents.key,\n\t\t\t\t\t\tTextType.MapKey,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (innerContent.contents.value !== undefined) {\n\t\t\t\t\tinnerContent.contents.value.value = this.replaceAny(\n\t\t\t\t\t\tinnerContent.contents.value.value,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// message contents don't match any known op format\n\t\t\t\tthis.objectMatchesSchema(contents, false);\n\t\t\t}\n\t\t}\n\t}\n\n\tfixOp(message: any): void {\n\t\t// handle case where contents is stringified json\n\t\tlet msgContents;\n\t\tif (typeof message.contents === \"string\") {\n\t\t\ttry {\n\t\t\t\tmsgContents = JSON.parse(message.contents);\n\t\t\t} catch (e) {\n\t\t\t\tthis.debugMsg(e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tmsgContents = message.contents;\n\t\t}\n\n\t\t// handle container message types\n\t\tswitch (msgContents.type) {\n\t\t\tcase \"attach\": {\n\t\t\t\t// this one is like a regular attach op, except its contents aren't nested as deep\n\t\t\t\t// run fixAttach directly and return\n\t\t\t\tthis.fixAttach(msgContents);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"component\": {\n\t\t\t\t// this one functionally nests its contents one layer deeper\n\t\t\t\t// bring up the contents object and continue as usual\n\t\t\t\tthis.fixOpContentsObject(msgContents.contents);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"chunkedOp\": {\n\t\t\t\t// this is a (regular?) op split into multiple parts due to size, e.g. because it\n\t\t\t\t// has an attached image, and where the chunkedOp is within the top-level op's contents\n\t\t\t\t// (as opposed to being at the top-level). The contents of the chunks need to be\n\t\t\t\t// concatenated to form the complete stringified json object\n\t\t\t\t// Early return here to skip re-stringify because no changes are made until the last\n\t\t\t\t// chunk, and the ChunkedOpProcessor will handle everything at that point\n\t\t\t\treturn this.fixChunkedOp(message);\n\t\t\t}\n\t\t\tcase \"blobAttach\": {\n\t\t\t\t// TODO: handle this properly once blob api is used\n\t\t\t\tthis.debugMsg(\"TODO: blobAttach ops are skipped/unhandled\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// A regular op\n\t\t\t\tthis.fixOpContentsObject(msgContents);\n\t\t\t}\n\t\t}\n\n\t\t// re-stringify the json if needed\n\t\tif (typeof message.contents === \"string\") {\n\t\t\ttry {\n\t\t\t\tmessage.contents = JSON.stringify(msgContents);\n\t\t\t} catch (e) {\n\t\t\t\tthis.debugMsg(e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Fixes a chunked operation by reassembling and sanitizing the message chunks.\n\t *\n\t * @param message - The top-level chunkedOp message or a top-level op message\n\t * with a chunkedOp inside its contents\n\t */\n\tfixChunkedOp(message: any): void {\n\t\tthis.chunkProcessor.addMessage(message);\n\t\tif (!this.chunkProcessor.hasAllMessages()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst contents = this.chunkProcessor.getConcatenatedContents();\n\t\tthis.fixOpContentsObject(contents);\n\n\t\tthis.chunkProcessor.writeSanitizedContents(contents);\n\t\tthis.chunkProcessor.reset();\n\t}\n\n\tsanitize(): ISequencedDocumentMessage[] {\n\t\tlet seq = 0;\n\n\t\ttry {\n\t\t\tthis.messages.map((message) => {\n\t\t\t\tseq = message.sequenceNumber;\n\t\t\t\t// message types from protocol-definitions' protocol.ts\n\t\t\t\tswitch (message.type) {\n\t\t\t\t\tcase \"join\": {\n\t\t\t\t\t\tthis.fixJoin(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"propose\": {\n\t\t\t\t\t\tthis.fixPropose(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"attach\": {\n\t\t\t\t\t\tthis.fixAttach(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"op\": {\n\t\t\t\t\t\tthis.fixOp(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"chunkedOp\": {\n\t\t\t\t\t\tthis.fixChunkedOp(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"noop\":\n\t\t\t\t\tcase \"leave\":\n\t\t\t\t\tcase \"noClient\":\n\t\t\t\t\tcase \"summarize\":\n\t\t\t\t\tcase \"summaryAck\":\n\t\t\t\t\tcase \"summaryNack\":\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.debugMsg(`Unexpected op type ${message.type}`);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// make sure we don't miss an incomplete chunked op at the end\n\t\t\tassert(\n\t\t\t\t!this.chunkProcessor.isPendingProcessing(),\n\t\t\t\t0x08d /* \"After sanitize, pending incomplete ops!\" */,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.debugMsg(`Error while processing sequenceNumber ${seq}`);\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn this.messages;\n\t}\n}\n"]}
1
+ {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../src/sanitizer.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\n/**\n * This tool cleans up a message.json file downloaded through fluid-fetch to remove\n * user content and user identifying information. Enough information can be retained\n * to allow loading through Fluid Preview, or everything can be scrubbed so that only\n * replay-tool can read the result. Anonymous identifying information such as client\n * IDs are always retained. Object keys are NOT scrubbed, including those that are\n * nested within values (only leaf values are scrubbed).\n *\n * Note: While user content/information is scrubbed, it should not be assumed to be\n * fully anonymized because certain meta-information (such as word lengths and\n * consistent replacement) are preserved.\n *\n * Messages must match known structures when scrubbing for Fluid Preview.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport * as Validator from \"jsonschema\";\n\nimport {\n\tattachContentsSchema,\n\tchunkedOpContentsSchema,\n\tjoinContentsSchema,\n\tjoinDataSchema,\n\topContentsMapSchema,\n\topContentsMergeTreeDeltaOpSchema,\n\topContentsMergeTreeGroupOpSchema,\n\topContentsRegisterCollectionSchema,\n\topContentsSchema,\n\tproposeContentsSchema,\n} from \"./messageSchema.js\";\n\nenum TextType {\n\tGeneric,\n\tEmail,\n\tName,\n\tFluidObject,\n\tMapKey,\n}\n\n// Workaround to jsonschema package not supporting \"false\" as a schema\n// that matches nothing\nconst falseResult = {\n\tvalid: false,\n\ttoString: () => {\n\t\treturn \"Unmatched format\";\n\t},\n};\n\n/**\n * Class that takes chunkedOp messages and can provide their concatenated\n * contents along with re-write sanitized content in-place back into the\n * messages. Assumes sanitized messages are always less than or equal in\n * size to the original message.\n */\nclass ChunkedOpProcessor {\n\t/**\n\t * Message references so we can replace their contents in-place. These can\n\t * be top-level chunkedOp messages, or top-level op messages with a chunkedOp\n\t * within the contents\n\t */\n\tprivate messages = new Array<any>();\n\t/**\n\t * The messages' parsed contents for processing. Should parallel the\n\t * messages member\n\t */\n\tprivate parsedMessageContents = new Array<any>();\n\tprivate writtenBack = false;\n\t/**\n\t * keep track of the total starting length to make sure we don't somehow end\n\t * up with more content than we started with (meaning we may not be able to\n\t * write it back)\n\t */\n\tprivate concatenatedLength = 0;\n\n\tconstructor(\n\t\treadonly validateSchemaFn: (object: any, schema: any) => boolean,\n\t\treadonly debug: boolean,\n\t) {}\n\n\tdebugMsg(msg: any): void {\n\t\tif (this.debug) {\n\t\t\tconsole.error(msg);\n\t\t}\n\t}\n\n\taddMessage(message: any): void {\n\t\tthis.messages.push(message);\n\n\t\tlet parsed;\n\t\ttry {\n\t\t\tparsed = JSON.parse(message.contents);\n\t\t\tif (message.type === \"op\") {\n\t\t\t\t// nested within a regular op\n\t\t\t\t// need to go deeper to get the desired contents\n\t\t\t\tparsed = parsed.contents;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.debugMsg(error);\n\t\t\tthis.debugMsg(message.contents);\n\t\t}\n\t\tthis.validateSchemaFn(parsed, chunkedOpContentsSchema);\n\t\tthis.parsedMessageContents.push(parsed);\n\t}\n\n\thasAllMessages(): boolean {\n\t\tconst lastMsgContents = this.parsedMessageContents[this.parsedMessageContents.length - 1];\n\t\treturn (\n\t\t\tlastMsgContents.chunkId !== undefined &&\n\t\t\tlastMsgContents.chunkId === lastMsgContents.totalChunks\n\t\t);\n\t}\n\n\t/**\n\t * Gets the concatenated contents of all the messages parsed as JSON.\n\t */\n\tgetConcatenatedContents(): any {\n\t\tconst contentsString = this.parsedMessageContents.reduce(\n\t\t\t(previousValue: string, currentValue: any) => {\n\t\t\t\treturn previousValue + (currentValue.contents as string);\n\t\t\t},\n\t\t\t\"\",\n\t\t);\n\n\t\tthis.concatenatedLength = contentsString.length;\n\t\ttry {\n\t\t\treturn JSON.parse(contentsString);\n\t\t} catch (error) {\n\t\t\tthis.debugMsg(contentsString);\n\t\t\tthis.debugMsg(error);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Write back sanitized contents into the messages. The contents are\n\t * stringified, split up, and written in place to the messages that\n\t * were added earlier. The number of messages is preserved.\n\t * @param contents - Sanitized contents to write back\n\t */\n\twriteSanitizedContents(contents: any): void {\n\t\t// Write back a chunk size equal to the original\n\t\tconst chunkSize = this.parsedMessageContents[0].contents.length;\n\n\t\tlet stringified: string;\n\t\ttry {\n\t\t\tstringified = JSON.stringify(contents);\n\t\t\tassert(\n\t\t\t\tstringified.length <= this.concatenatedLength,\n\t\t\t\t0x089 /* \"Stringified length of chunk contents > total starting length\" */,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.debugMsg(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\tfor (let i = 0; i < this.messages.length; i++) {\n\t\t\tconst substring = stringified.substring(i * chunkSize, (i + 1) * chunkSize);\n\n\t\t\tconst parsedContents = this.parsedMessageContents[i];\n\t\t\tparsedContents.contents = substring;\n\t\t\tconst message = this.messages[i];\n\n\t\t\tlet stringifiedParsedContents;\n\t\t\ttry {\n\t\t\t\t// for nested chunkedOps, we need to recreate the extra nesting layer\n\t\t\t\t// we removed earlier when adding the message\n\t\t\t\tif (message.type === \"op\") {\n\t\t\t\t\tconst nestingLayer = {\n\t\t\t\t\t\ttype: \"chunkedOp\",\n\t\t\t\t\t\tcontents: parsedContents,\n\t\t\t\t\t};\n\t\t\t\t\tstringifiedParsedContents = JSON.stringify(nestingLayer);\n\t\t\t\t} else {\n\t\t\t\t\tstringifiedParsedContents = JSON.stringify(parsedContents);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.debugMsg(error);\n\t\t\t}\n\n\t\t\tmessage.contents = stringifiedParsedContents;\n\t\t}\n\n\t\tthis.writtenBack = true;\n\t}\n\n\treset(): void {\n\t\tassert(\n\t\t\tthis.writtenBack,\n\t\t\t0x08a /* \"resetting ChunkedOpProcessor that never wrote back its contents\" */,\n\t\t);\n\t\tthis.messages = new Array<any>();\n\t\tthis.parsedMessageContents = new Array<any>();\n\t\tthis.writtenBack = false;\n\t\tthis.concatenatedLength = 0;\n\t}\n\n\tisPendingProcessing(): boolean {\n\t\treturn this.messages.length > 0;\n\t}\n}\n\nexport class Sanitizer {\n\treadonly validator = new Validator.Validator();\n\t// Represents the keys used to store Fluid object identifiers, snapshot info,\n\t// and other string fields that should not be replaced in contents blobs to\n\t// ensure the messages are still usable\n\treadonly defaultExcludedKeys = new Set<string>();\n\t// Represents the keys used by merge-tree ops their \"seg\" property, where other\n\t// keys represent user information\n\treadonly mergeTreeExcludedKeys = new Set<string>();\n\t// Map of user information to what it was replaced with. Used to ensure the same\n\t// data have the same replacements\n\treadonly replacementMap = new Map<string, string>();\n\n\t/**\n\t * Validate that the provided message matches the provided schema.\n\t * For a full scrub, warn and continue (scrubber should fully sanitize unexpected\n\t * fields for ops), otherwise throw an error because we cannot be sure user\n\t * information is being sufficiently sanitized.\n\t */\n\tobjectMatchesSchema = (object: any, schema: any): boolean => {\n\t\tconst result = schema === false ? falseResult : this.validator.validate(object, schema);\n\t\tif (!result.valid) {\n\t\t\tconst errorMsg = `Bad msg fmt:\\n${result.toString()}\\n${JSON.stringify(\n\t\t\t\tobject,\n\t\t\t\tundefined,\n\t\t\t\t2,\n\t\t\t)}`;\n\n\t\t\tif (this.fullScrub || this.noBail) {\n\t\t\t\tthis.debugMsg(errorMsg);\n\t\t\t} else {\n\t\t\t\tthrow new Error(errorMsg);\n\t\t\t}\n\t\t}\n\t\treturn result.valid;\n\t};\n\n\treadonly chunkProcessor: ChunkedOpProcessor;\n\n\tconstructor(\n\t\treadonly messages: ISequencedDocumentMessage[],\n\t\treadonly fullScrub: boolean,\n\t\treadonly noBail: boolean,\n\t\treadonly debug: boolean = false,\n\t) {\n\t\tthis.defaultExcludedKeys.add(\"type\");\n\t\tthis.defaultExcludedKeys.add(\"id\");\n\t\tthis.defaultExcludedKeys.add(\"pkg\");\n\t\tthis.defaultExcludedKeys.add(\"snapshotFormatVersion\");\n\t\tthis.defaultExcludedKeys.add(\"packageVersion\");\n\t\tthis.mergeTreeExcludedKeys.add(\"nodeType\");\n\t\tthis.chunkProcessor = new ChunkedOpProcessor(this.objectMatchesSchema, debug);\n\t}\n\n\tdebugMsg(msg: any): void {\n\t\tif (this.debug) {\n\t\t\tconsole.error(msg);\n\t\t}\n\t}\n\n\tisFluidObjectKey(key: string): boolean {\n\t\treturn key === \"type\" || key === \"id\";\n\t}\n\n\tgetRandomText(len: number): string {\n\t\tlet str = \"\";\n\t\twhile (str.length < len) {\n\t\t\tstr = str + Math.random().toString(36).slice(2);\n\t\t}\n\t\treturn str.slice(0, Math.max(0, len));\n\t}\n\n\treadonly wordTokenRegex = /\\S+/g;\n\n\treadonly replaceRandomTextFn = (match: string): string => {\n\t\tif (this.replacementMap.has(match)) {\n\t\t\treturn this.replacementMap.get(match)!;\n\t\t}\n\n\t\tconst replacement = this.getRandomText(match.length);\n\t\tthis.replacementMap.set(match, replacement);\n\t\treturn replacement;\n\t};\n\n\t/**\n\t * Replace text with garbage. FluidObject types are not replaced when not under\n\t * full scrub mode. All other text is replaced consistently.\n\t */\n\treplaceText(input?: string, type: TextType = TextType.Generic): string | undefined {\n\t\tif (input === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (type === TextType.FluidObject) {\n\t\t\tif (this.replacementMap.has(input)) {\n\t\t\t\treturn this.replacementMap.get(input)!;\n\t\t\t}\n\n\t\t\tconst replacement = this.fullScrub ? this.getRandomText(input.length) : input;\n\n\t\t\tthis.replacementMap.set(input, replacement);\n\t\t\treturn replacement;\n\t\t}\n\n\t\treturn input.replace(this.wordTokenRegex, this.replaceRandomTextFn);\n\t}\n\n\treplaceArray(input: any[]): any[] {\n\t\tfor (let i = 0; i < input.length; i++) {\n\t\t\tconst value = input[i];\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tinput[i] = this.replaceText(value);\n\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\tinput[i] = this.replaceArray(value);\n\t\t\t} else if (typeof value === \"object\") {\n\t\t\t\tinput[i] = this.replaceObject(value);\n\t\t\t}\n\t\t}\n\t\treturn input;\n\t}\n\n\t/**\n\t * (sort of) recurses down the values of a JSON object to sanitize all its strings\n\t * (only checks strings, arrays, and objects)\n\t * @param input - The object to sanitize\n\t * @param excludedKeys - object keys for which to skip replacement when not in fullScrub\n\t */\n\treplaceObject(\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t\tinput: object | null,\n\t\texcludedKeys: Set<string> = this.defaultExcludedKeys,\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t): object | null {\n\t\t// File might contain actual nulls\n\t\tif (input === null || input === undefined) {\n\t\t\treturn input;\n\t\t}\n\n\t\tconst keys = Object.keys(input);\n\t\tfor (const key of keys) {\n\t\t\tif (this.fullScrub || !excludedKeys.has(key)) {\n\t\t\t\tconst value = input[key];\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\tinput[key] = this.replaceText(\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tthis.isFluidObjectKey(key) ? TextType.FluidObject : TextType.Generic,\n\t\t\t\t\t);\n\t\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\t\tinput[key] = this.replaceArray(value);\n\t\t\t\t} else if (typeof value === \"object\") {\n\t\t\t\t\tinput[key] = this.replaceObject(value, excludedKeys);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn input;\n\t}\n\n\t/**\n\t * Replacement on an unknown type or a parsed root level object\n\t * without a key\n\t * @param input - The object to sanitize\n\t * @param excludedKeys - object keys for which to skip replacement when not in fullScrub\n\t */\n\treplaceAny(input: any, excludedKeys: Set<string> = this.defaultExcludedKeys): any {\n\t\tif (input === null || input === undefined) {\n\t\t\treturn input;\n\t\t}\n\n\t\tif (typeof input === \"string\") {\n\t\t\treturn this.replaceText(input);\n\t\t} else if (Array.isArray(input)) {\n\t\t\treturn this.replaceArray(input);\n\t\t} else if (typeof input === \"object\") {\n\t\t\treturn this.replaceObject(input, excludedKeys);\n\t\t}\n\n\t\t// Don't run replacement on any other types\n\t\treturn input;\n\t}\n\n\tfixJoin(message: any): void {\n\t\tif (!this.objectMatchesSchema(message.contents, joinContentsSchema)) {\n\t\t\tmessage.contents = this.replaceAny(message.contents);\n\t\t}\n\n\t\ttry {\n\t\t\tlet data = JSON.parse(message.data);\n\t\t\tif (this.objectMatchesSchema(data, joinDataSchema)) {\n\t\t\t\tconst user = data.detail.user;\n\t\t\t\tuser.id = this.replaceText(user.id, TextType.Email);\n\t\t\t\tuser.email = this.replaceText(user.email, TextType.Email);\n\t\t\t\tuser.name = this.replaceText(user.name, TextType.Name);\n\t\t\t} else {\n\t\t\t\tdata = this.replaceAny(data);\n\t\t\t}\n\n\t\t\tmessage.data = JSON.stringify(data);\n\t\t} catch (error) {\n\t\t\tthis.debugMsg(error);\n\t\t}\n\t}\n\n\tfixPropose(message: any): void {\n\t\tif (this.objectMatchesSchema(message.contents, proposeContentsSchema)) {\n\t\t\tif (typeof message.contents === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst data = JSON.parse(message.contents);\n\t\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\t\tconst pkg = data.value?.package;\n\t\t\t\t\t\tif (pkg?.name) {\n\t\t\t\t\t\t\tpkg.name = this.replaceText(pkg.name, TextType.FluidObject);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Array.isArray(pkg?.fluid?.browser?.umd?.files)) {\n\t\t\t\t\t\t\tpkg.fluid.browser.umd.files = this.replaceArray(pkg.fluid.browser.umd.files);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.debugMsg(error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tmessage.contents.value = this.replaceText(\n\t\t\t\t\t\tmessage.contents.value,\n\t\t\t\t\t\tTextType.FluidObject,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tmessage.contents = this.replaceAny(message.contents);\n\t\t}\n\t}\n\n\tfixAttachEntries(entries: any[]): void {\n\t\tfor (const element of entries) {\n\t\t\t// Tree type\n\t\t\tif (element.value.entries) {\n\t\t\t\tthis.fixAttachEntries(element.value.entries);\n\t\t\t} else {\n\t\t\t\t// Blob (leaf) type\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof element.value.contents === \"string\") {\n\t\t\t\t\t\tlet data = JSON.parse(element.value.contents);\n\t\t\t\t\t\tdata = this.replaceObject(data);\n\t\t\t\t\t\telement.value.contents = JSON.stringify(data);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.debugMsg(error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Fix the content of an attach in place\n\t * @param contents - contents object to fix\n\t */\n\tfixAttachContents(contents: any): any {\n\t\tassert(\n\t\t\ttypeof contents === \"object\",\n\t\t\t0x08b /* \"Unexpected type on contents for fix of an attach!\" */,\n\t\t);\n\t\tif (this.objectMatchesSchema(contents, attachContentsSchema)) {\n\t\t\tif (this.fullScrub) {\n\t\t\t\tcontents.id = this.replaceText(contents.id, TextType.FluidObject);\n\t\t\t\tcontents.type = this.replaceText(contents.type, TextType.FluidObject);\n\t\t\t}\n\n\t\t\tthis.fixAttachEntries(contents.snapshot.entries);\n\t\t} else {\n\t\t\tthis.replaceObject(contents);\n\t\t}\n\t}\n\n\t/**\n\t * Fix an attach message at the root level or a ContainerMessageType attach. Attach\n\t * messages found within an op message should instead have their contents parsed out\n\t * and sent to fixAttachContents.\n\t * @param message - The attach message to fix\n\t * @param withinOp - If the message is from within an op message (as opposed to being\n\t * an attach message at the root level). Root level attach messages have \"snapshot\"\n\t * under a \"contents\" key, whereas attach messages from within an op message have it\n\t * under a \"content\" key\n\t */\n\tfixAttach(message: any): void {\n\t\t// Handle case where contents is stringified json\n\t\tif (typeof message.contents === \"string\") {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(message.contents);\n\t\t\t\tthis.fixAttachContents(data);\n\t\t\t\tmessage.contents = JSON.stringify(data);\n\t\t\t} catch (error) {\n\t\t\t\tthis.debugMsg(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.fixAttachContents(message.contents);\n\t\t}\n\t}\n\n\tfixDeltaOp(deltaOp: any): void {\n\t\tdeltaOp.seg =\n\t\t\ttypeof deltaOp.seg === \"string\"\n\t\t\t\t? this.replaceText(deltaOp.seg)\n\t\t\t\t: this.replaceObject(deltaOp.seg, this.mergeTreeExcludedKeys);\n\t}\n\n\t/**\n\t * Fix the contents object for an op message. Does not do extra type handling. Does\n\t * not handle special container message types like \"attach\", \"component\", and\n\t * \"chunkedOp\" (these should be handled by the caller)\n\t * @param contents - The contents object for an op message. If it was a string in the\n\t * message, it must have been converted to an object first\n\t */\n\tfixOpContentsObject(contents: any): void {\n\t\t// do replacement\n\t\tif (this.objectMatchesSchema(contents, opContentsSchema)) {\n\t\t\tif (this.fullScrub) {\n\t\t\t\tcontents.address = this.replaceText(contents.address, TextType.FluidObject);\n\t\t\t}\n\n\t\t\tconst innerContent = contents.contents.content;\n\t\t\tassert(\n\t\t\t\tinnerContent !== undefined,\n\t\t\t\t0x08c /* \"innerContent for fixing op contents is undefined!\" */,\n\t\t\t);\n\t\t\tif (contents.contents.type === \"attach\") {\n\t\t\t\t// attach op\n\t\t\t\t// handle case where inner content is stringified json\n\t\t\t\tif (typeof contents.contents.content === \"string\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst data = JSON.parse(contents.contents.content);\n\t\t\t\t\t\tthis.fixAttachContents(data);\n\t\t\t\t\t\tcontents.contents.content = JSON.stringify(data);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis.debugMsg(error);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.fixAttachContents(contents.contents.content);\n\t\t\t\t}\n\t\t\t} else if (this.validator.validate(innerContent, opContentsMapSchema).valid) {\n\t\t\t\t// map op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t\tinnerContent.contents.key = this.replaceText(\n\t\t\t\t\t\tinnerContent.contents.key,\n\t\t\t\t\t\tTextType.MapKey,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (innerContent.contents.value !== undefined) {\n\t\t\t\t\tinnerContent.contents.value.value = this.replaceAny(\n\t\t\t\t\t\tinnerContent.contents.value.value,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tthis.validator.validate(innerContent, opContentsMergeTreeGroupOpSchema).valid\n\t\t\t) {\n\t\t\t\t// merge tree group op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t}\n\t\t\t\tfor (const deltaOp of innerContent.contents.ops) {\n\t\t\t\t\tthis.fixDeltaOp(deltaOp);\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tthis.validator.validate(innerContent, opContentsMergeTreeDeltaOpSchema).valid\n\t\t\t) {\n\t\t\t\t// merge tree delta op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t}\n\t\t\t\tthis.fixDeltaOp(innerContent.contents);\n\t\t\t} else if (\n\t\t\t\tthis.validator.validate(innerContent, opContentsRegisterCollectionSchema).valid\n\t\t\t) {\n\t\t\t\t// register collection op\n\t\t\t\tif (this.fullScrub) {\n\t\t\t\t\tinnerContent.address = this.replaceText(innerContent.address, TextType.FluidObject);\n\t\t\t\t\tinnerContent.contents.key = this.replaceText(\n\t\t\t\t\t\tinnerContent.contents.key,\n\t\t\t\t\t\tTextType.MapKey,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (innerContent.contents.value !== undefined) {\n\t\t\t\t\tinnerContent.contents.value.value = this.replaceAny(\n\t\t\t\t\t\tinnerContent.contents.value.value,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// message contents don't match any known op format\n\t\t\t\tthis.objectMatchesSchema(contents, false);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.replaceAny(contents);\n\t\t}\n\t}\n\n\tfixOp(message: any): void {\n\t\t// handle case where contents is stringified json\n\t\tlet msgContents;\n\t\tif (typeof message.contents === \"string\") {\n\t\t\ttry {\n\t\t\t\tmsgContents = JSON.parse(message.contents);\n\t\t\t} catch (error) {\n\t\t\t\tthis.debugMsg(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tmsgContents = message.contents;\n\t\t}\n\n\t\t// handle container message types\n\t\tswitch (msgContents.type) {\n\t\t\tcase \"attach\": {\n\t\t\t\t// this one is like a regular attach op, except its contents aren't nested as deep\n\t\t\t\t// run fixAttach directly and return\n\t\t\t\tthis.fixAttach(msgContents);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"component\": {\n\t\t\t\t// this one functionally nests its contents one layer deeper\n\t\t\t\t// bring up the contents object and continue as usual\n\t\t\t\tthis.fixOpContentsObject(msgContents.contents);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"chunkedOp\": {\n\t\t\t\t// this is a (regular?) op split into multiple parts due to size, e.g. because it\n\t\t\t\t// has an attached image, and where the chunkedOp is within the top-level op's contents\n\t\t\t\t// (as opposed to being at the top-level). The contents of the chunks need to be\n\t\t\t\t// concatenated to form the complete stringified json object\n\t\t\t\t// Early return here to skip re-stringify because no changes are made until the last\n\t\t\t\t// chunk, and the ChunkedOpProcessor will handle everything at that point\n\t\t\t\treturn this.fixChunkedOp(message);\n\t\t\t}\n\t\t\tcase \"blobAttach\": {\n\t\t\t\t// TODO: handle this properly once blob api is used\n\t\t\t\tthis.debugMsg(\"TODO: blobAttach ops are skipped/unhandled\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// A regular op\n\t\t\t\tthis.fixOpContentsObject(msgContents);\n\t\t\t}\n\t\t}\n\n\t\t// re-stringify the json if needed\n\t\tif (typeof message.contents === \"string\") {\n\t\t\ttry {\n\t\t\t\tmessage.contents = JSON.stringify(msgContents);\n\t\t\t} catch (error) {\n\t\t\t\tthis.debugMsg(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Fixes a chunked operation by reassembling and sanitizing the message chunks.\n\t *\n\t * @param message - The top-level chunkedOp message or a top-level op message\n\t * with a chunkedOp inside its contents\n\t */\n\tfixChunkedOp(message: any): void {\n\t\tthis.chunkProcessor.addMessage(message);\n\t\tif (!this.chunkProcessor.hasAllMessages()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst contents = this.chunkProcessor.getConcatenatedContents();\n\t\tthis.fixOpContentsObject(contents);\n\n\t\tthis.chunkProcessor.writeSanitizedContents(contents);\n\t\tthis.chunkProcessor.reset();\n\t}\n\n\tsanitize(): ISequencedDocumentMessage[] {\n\t\tlet seq = 0;\n\n\t\ttry {\n\t\t\tthis.messages.map((message) => {\n\t\t\t\tseq = message.sequenceNumber;\n\t\t\t\t// message types from protocol-definitions' protocol.ts\n\t\t\t\tswitch (message.type) {\n\t\t\t\t\tcase \"join\": {\n\t\t\t\t\t\tthis.fixJoin(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"propose\": {\n\t\t\t\t\t\tthis.fixPropose(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"attach\": {\n\t\t\t\t\t\tthis.fixAttach(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"op\": {\n\t\t\t\t\t\tthis.fixOp(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"chunkedOp\": {\n\t\t\t\t\t\tthis.fixChunkedOp(message);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"noop\":\n\t\t\t\t\tcase \"leave\":\n\t\t\t\t\tcase \"noClient\":\n\t\t\t\t\tcase \"summarize\":\n\t\t\t\t\tcase \"summaryAck\":\n\t\t\t\t\tcase \"summaryNack\": {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthis.debugMsg(`Unexpected op type ${message.type}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// make sure we don't miss an incomplete chunked op at the end\n\t\t\tassert(\n\t\t\t\t!this.chunkProcessor.isPendingProcessing(),\n\t\t\t\t0x08d /* \"After sanitize, pending incomplete ops!\" */,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.debugMsg(`Error while processing sequenceNumber ${seq}`);\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn this.messages;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/debugger",
3
- "version": "2.91.0",
3
+ "version": "2.92.0",
4
4
  "description": "Fluid Debugger - a tool to play through history of a file",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -47,20 +47,20 @@
47
47
  "main": "lib/index.js",
48
48
  "types": "lib/public.d.ts",
49
49
  "dependencies": {
50
- "@fluidframework/core-utils": "~2.91.0",
51
- "@fluidframework/driver-definitions": "~2.91.0",
52
- "@fluidframework/driver-utils": "~2.91.0",
53
- "@fluidframework/replay-driver": "~2.91.0",
50
+ "@fluidframework/core-utils": "~2.92.0",
51
+ "@fluidframework/driver-definitions": "~2.92.0",
52
+ "@fluidframework/driver-utils": "~2.92.0",
53
+ "@fluidframework/replay-driver": "~2.92.0",
54
54
  "jsonschema": "^1.2.6"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@arethetypeswrong/cli": "^0.18.2",
58
58
  "@biomejs/biome": "~2.4.5",
59
- "@fluid-tools/build-cli": "^0.63.0",
59
+ "@fluid-tools/build-cli": "^0.64.0",
60
60
  "@fluidframework/build-common": "^2.0.3",
61
- "@fluidframework/build-tools": "^0.63.0",
62
- "@fluidframework/debugger-previous": "npm:@fluidframework/debugger@2.83.0",
63
- "@fluidframework/eslint-config-fluid": "~2.91.0",
61
+ "@fluidframework/build-tools": "^0.64.0",
62
+ "@fluidframework/debugger-previous": "npm:@fluidframework/debugger@2.91.0",
63
+ "@fluidframework/eslint-config-fluid": "^9.0.0",
64
64
  "@microsoft/api-extractor": "7.52.11",
65
65
  "@types/node": "~20.19.30",
66
66
  "concurrently": "^9.2.1",
@@ -70,25 +70,13 @@
70
70
  "rimraf": "^6.1.3",
71
71
  "typescript": "~5.4.5"
72
72
  },
73
- "fluidBuild": {
74
- "tasks": {
75
- "build:esnext": [
76
- "...",
77
- "typetests:gen"
78
- ],
79
- "tsc": [
80
- "...",
81
- "typetests:gen"
82
- ]
83
- }
84
- },
85
73
  "typeValidation": {
86
74
  "broken": {},
87
75
  "entrypoint": "legacy"
88
76
  },
89
77
  "scripts": {
90
78
  "api": "fluid-build . --task api",
91
- "api-extractor:commonjs": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./dist",
79
+ "api-extractor:commonjs": "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outDir ./dist",
92
80
  "api-extractor:esnext": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat",
93
81
  "build": "fluid-build . --task build",
94
82
  "build:api-reports": "concurrently \"npm:build:api-reports:*\"",
@@ -97,6 +85,9 @@
97
85
  "build:compile": "fluid-build . --task compile",
98
86
  "build:docs": "api-extractor run --local",
99
87
  "build:esnext": "tsc --project ./tsconfig.json",
88
+ "build:test": "npm run build:test:esm && npm run build:test:cjs",
89
+ "build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
90
+ "build:test:esm": "tsc --project ./src/test/tsconfig.json",
100
91
  "check:are-the-types-wrong": "attw --pack .",
101
92
  "check:biome": "biome check .",
102
93
  "check:exports": "concurrently \"npm:check:exports:*\"",
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import {
6
+ import type {
7
7
  IDocumentService,
8
8
  IDocumentServiceFactory,
9
9
  } from "@fluidframework/driver-definitions/internal";
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { assert, Deferred } from "@fluidframework/core-utils/internal";
7
- import {
7
+ import type {
8
8
  IDocumentDeltaStorageService,
9
9
  IDocumentService,
10
10
  IDocumentStorageService,
@@ -14,15 +14,17 @@ import {
14
14
  ISequencedDocumentMessage,
15
15
  } from "@fluidframework/driver-definitions/internal";
16
16
  import { readAndParse } from "@fluidframework/driver-utils/internal";
17
- import {
18
- FileSnapshotReader,
17
+ import type {
19
18
  IFileSnapshot,
20
19
  ReadDocumentStorageServiceBase,
20
+ } from "@fluidframework/replay-driver/internal";
21
+ import {
22
+ FileSnapshotReader,
21
23
  ReplayController,
22
24
  SnapshotStorage,
23
25
  } from "@fluidframework/replay-driver/internal";
24
26
 
25
- import { IDebuggerController, IDebuggerUI } from "./fluidDebuggerUi.js";
27
+ import type { IDebuggerController, IDebuggerUI } from "./fluidDebuggerUi.js";
26
28
  import { Sanitizer } from "./sanitizer.js";
27
29
 
28
30
  /**
@@ -113,17 +115,17 @@ export class DebugReplayController extends ReplayController implements IDebugger
113
115
  }
114
116
 
115
117
  public onSnapshotFileSelection(file: File): void {
116
- if (!/^snapshot.*\.json/.exec(file.name)) {
118
+ if (!/^snapshot.*\.json/.test(file.name)) {
117
119
  alert(`Incorrect file name: ${file.name}`);
118
120
  return;
119
121
  }
120
- if (/.*_expanded.*/.exec(file.name)) {
122
+ if (/.*_expanded.*/.test(file.name)) {
121
123
  alert(`Incorrect file name - please use non-extended files: ${file.name}`);
122
124
  return;
123
125
  }
124
126
 
125
127
  const reader = new FileReader();
126
- reader.onload = async () => {
128
+ reader.addEventListener("load", () => {
127
129
  if (this.documentStorageService) {
128
130
  const text = reader.result as string;
129
131
  try {
@@ -151,7 +153,7 @@ export class DebugReplayController extends ReplayController implements IDebugger
151
153
  return;
152
154
  }
153
155
  }
154
- };
156
+ });
155
157
  reader.readAsText(file, "utf-8");
156
158
  }
157
159