@vived/host 5.4.2 → 5.6.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 (129) hide show
  1. package/dist/cjs/BoundaryLog/Adapters/boundaryLogAdapter.js +24 -0
  2. package/dist/cjs/BoundaryLog/Adapters/boundaryLogAdapter.js.map +1 -0
  3. package/dist/cjs/BoundaryLog/Adapters/index.js +18 -0
  4. package/dist/cjs/BoundaryLog/Adapters/index.js.map +1 -0
  5. package/dist/cjs/BoundaryLog/Controllers/clearBoundaryLog.js +15 -0
  6. package/dist/cjs/BoundaryLog/Controllers/clearBoundaryLog.js.map +1 -0
  7. package/dist/cjs/BoundaryLog/Controllers/index.js +18 -0
  8. package/dist/cjs/BoundaryLog/Controllers/index.js.map +1 -0
  9. package/dist/cjs/BoundaryLog/Entities/BoundaryLogEntity.js +45 -0
  10. package/dist/cjs/BoundaryLog/Entities/BoundaryLogEntity.js.map +1 -0
  11. package/dist/cjs/BoundaryLog/Entities/index.js +19 -0
  12. package/dist/cjs/BoundaryLog/Entities/index.js.map +1 -0
  13. package/dist/cjs/BoundaryLog/Entities/snapshotPayload.js +62 -0
  14. package/dist/cjs/BoundaryLog/Entities/snapshotPayload.js.map +1 -0
  15. package/dist/cjs/BoundaryLog/Factories/BoundaryLogFactory.js +62 -0
  16. package/dist/cjs/BoundaryLog/Factories/BoundaryLogFactory.js.map +1 -0
  17. package/dist/cjs/BoundaryLog/Factories/index.js +18 -0
  18. package/dist/cjs/BoundaryLog/Factories/index.js.map +1 -0
  19. package/dist/cjs/BoundaryLog/Mocks/BoundaryLogPMMock.js +16 -0
  20. package/dist/cjs/BoundaryLog/Mocks/BoundaryLogPMMock.js.map +1 -0
  21. package/dist/cjs/BoundaryLog/Mocks/index.js +18 -0
  22. package/dist/cjs/BoundaryLog/Mocks/index.js.map +1 -0
  23. package/dist/cjs/BoundaryLog/PMs/BoundaryLogPM.js +56 -0
  24. package/dist/cjs/BoundaryLog/PMs/BoundaryLogPM.js.map +1 -0
  25. package/dist/cjs/BoundaryLog/PMs/index.js +18 -0
  26. package/dist/cjs/BoundaryLog/PMs/index.js.map +1 -0
  27. package/dist/cjs/BoundaryLog/index.js +23 -0
  28. package/dist/cjs/BoundaryLog/index.js.map +1 -0
  29. package/dist/cjs/Dialog/Entities/DialogQueue.js +36 -21
  30. package/dist/cjs/Dialog/Entities/DialogQueue.js.map +1 -1
  31. package/dist/cjs/Dispatcher/Entities/HostDispatchEntity.js +17 -4
  32. package/dist/cjs/Dispatcher/Entities/HostDispatchEntity.js.map +1 -1
  33. package/dist/cjs/Dispatcher/Mocks/MockHostDispatcher.js +1 -0
  34. package/dist/cjs/Dispatcher/Mocks/MockHostDispatcher.js.map +1 -1
  35. package/dist/cjs/Handler/Entities/HostHandler.js +17 -0
  36. package/dist/cjs/Handler/Entities/HostHandler.js.map +1 -1
  37. package/dist/cjs/StateMachine/Controllers/savePersistentStates.js +1 -1
  38. package/dist/cjs/StateMachine/Controllers/savePersistentStates.js.map +1 -1
  39. package/dist/cjs/StateMachine/Mocks/SavePersistentStatesMock.js +1 -1
  40. package/dist/cjs/StateMachine/Mocks/SavePersistentStatesMock.js.map +1 -1
  41. package/dist/cjs/StateMachine/UCs/SavePersistentStates.js +4 -6
  42. package/dist/cjs/StateMachine/UCs/SavePersistentStates.js.map +1 -1
  43. package/dist/cjs/index.js +1 -0
  44. package/dist/cjs/index.js.map +1 -1
  45. package/dist/esm/BoundaryLog/Adapters/boundaryLogAdapter.js +21 -0
  46. package/dist/esm/BoundaryLog/Adapters/boundaryLogAdapter.js.map +1 -0
  47. package/dist/esm/BoundaryLog/Adapters/index.js +2 -0
  48. package/dist/esm/BoundaryLog/Adapters/index.js.map +1 -0
  49. package/dist/esm/BoundaryLog/Controllers/clearBoundaryLog.js +12 -0
  50. package/dist/esm/BoundaryLog/Controllers/clearBoundaryLog.js.map +1 -0
  51. package/dist/esm/BoundaryLog/Controllers/index.js +2 -0
  52. package/dist/esm/BoundaryLog/Controllers/index.js.map +1 -0
  53. package/dist/esm/BoundaryLog/Entities/BoundaryLogEntity.js +40 -0
  54. package/dist/esm/BoundaryLog/Entities/BoundaryLogEntity.js.map +1 -0
  55. package/dist/esm/BoundaryLog/Entities/index.js +3 -0
  56. package/dist/esm/BoundaryLog/Entities/index.js.map +1 -0
  57. package/dist/esm/BoundaryLog/Entities/snapshotPayload.js +59 -0
  58. package/dist/esm/BoundaryLog/Entities/snapshotPayload.js.map +1 -0
  59. package/dist/esm/BoundaryLog/Factories/BoundaryLogFactory.js +57 -0
  60. package/dist/esm/BoundaryLog/Factories/BoundaryLogFactory.js.map +1 -0
  61. package/dist/esm/BoundaryLog/Factories/index.js +2 -0
  62. package/dist/esm/BoundaryLog/Factories/index.js.map +1 -0
  63. package/dist/esm/BoundaryLog/Mocks/BoundaryLogPMMock.js +11 -0
  64. package/dist/esm/BoundaryLog/Mocks/BoundaryLogPMMock.js.map +1 -0
  65. package/dist/esm/BoundaryLog/Mocks/index.js +2 -0
  66. package/dist/esm/BoundaryLog/Mocks/index.js.map +1 -0
  67. package/dist/esm/BoundaryLog/PMs/BoundaryLogPM.js +51 -0
  68. package/dist/esm/BoundaryLog/PMs/BoundaryLogPM.js.map +1 -0
  69. package/dist/esm/BoundaryLog/PMs/index.js +2 -0
  70. package/dist/esm/BoundaryLog/PMs/index.js.map +1 -0
  71. package/dist/esm/BoundaryLog/index.js +7 -0
  72. package/dist/esm/BoundaryLog/index.js.map +1 -0
  73. package/dist/esm/Dialog/Entities/DialogQueue.js +36 -21
  74. package/dist/esm/Dialog/Entities/DialogQueue.js.map +1 -1
  75. package/dist/esm/Dispatcher/Entities/HostDispatchEntity.js +17 -4
  76. package/dist/esm/Dispatcher/Entities/HostDispatchEntity.js.map +1 -1
  77. package/dist/esm/Dispatcher/Mocks/MockHostDispatcher.js +1 -0
  78. package/dist/esm/Dispatcher/Mocks/MockHostDispatcher.js.map +1 -1
  79. package/dist/esm/Handler/Entities/HostHandler.js +17 -0
  80. package/dist/esm/Handler/Entities/HostHandler.js.map +1 -1
  81. package/dist/esm/StateMachine/Controllers/savePersistentStates.js +1 -1
  82. package/dist/esm/StateMachine/Controllers/savePersistentStates.js.map +1 -1
  83. package/dist/esm/StateMachine/Mocks/SavePersistentStatesMock.js +1 -1
  84. package/dist/esm/StateMachine/Mocks/SavePersistentStatesMock.js.map +1 -1
  85. package/dist/esm/StateMachine/UCs/SavePersistentStates.js +4 -6
  86. package/dist/esm/StateMachine/UCs/SavePersistentStates.js.map +1 -1
  87. package/dist/esm/index.js +1 -0
  88. package/dist/esm/index.js.map +1 -1
  89. package/dist/types/BoundaryLog/Adapters/boundaryLogAdapter.d.ts +4 -0
  90. package/dist/types/BoundaryLog/Adapters/boundaryLogAdapter.d.ts.map +1 -0
  91. package/dist/types/BoundaryLog/Adapters/index.d.ts +2 -0
  92. package/dist/types/BoundaryLog/Adapters/index.d.ts.map +1 -0
  93. package/dist/types/BoundaryLog/Controllers/clearBoundaryLog.d.ts +4 -0
  94. package/dist/types/BoundaryLog/Controllers/clearBoundaryLog.d.ts.map +1 -0
  95. package/dist/types/BoundaryLog/Controllers/index.d.ts +2 -0
  96. package/dist/types/BoundaryLog/Controllers/index.d.ts.map +1 -0
  97. package/dist/types/BoundaryLog/Entities/BoundaryLogEntity.d.ts +37 -0
  98. package/dist/types/BoundaryLog/Entities/BoundaryLogEntity.d.ts.map +1 -0
  99. package/dist/types/BoundaryLog/Entities/index.d.ts +3 -0
  100. package/dist/types/BoundaryLog/Entities/index.d.ts.map +1 -0
  101. package/dist/types/BoundaryLog/Entities/snapshotPayload.d.ts +16 -0
  102. package/dist/types/BoundaryLog/Entities/snapshotPayload.d.ts.map +1 -0
  103. package/dist/types/BoundaryLog/Factories/BoundaryLogFactory.d.ts +17 -0
  104. package/dist/types/BoundaryLog/Factories/BoundaryLogFactory.d.ts.map +1 -0
  105. package/dist/types/BoundaryLog/Factories/index.d.ts +2 -0
  106. package/dist/types/BoundaryLog/Factories/index.d.ts.map +1 -0
  107. package/dist/types/BoundaryLog/Mocks/BoundaryLogPMMock.d.ts +8 -0
  108. package/dist/types/BoundaryLog/Mocks/BoundaryLogPMMock.d.ts.map +1 -0
  109. package/dist/types/BoundaryLog/Mocks/index.d.ts +2 -0
  110. package/dist/types/BoundaryLog/Mocks/index.d.ts.map +1 -0
  111. package/dist/types/BoundaryLog/PMs/BoundaryLogPM.d.ts +18 -0
  112. package/dist/types/BoundaryLog/PMs/BoundaryLogPM.d.ts.map +1 -0
  113. package/dist/types/BoundaryLog/PMs/index.d.ts +2 -0
  114. package/dist/types/BoundaryLog/PMs/index.d.ts.map +1 -0
  115. package/dist/types/BoundaryLog/index.d.ts +7 -0
  116. package/dist/types/BoundaryLog/index.d.ts.map +1 -0
  117. package/dist/types/Dispatcher/Entities/HostDispatchEntity.d.ts +17 -0
  118. package/dist/types/Dispatcher/Entities/HostDispatchEntity.d.ts.map +1 -1
  119. package/dist/types/Dispatcher/Mocks/MockHostDispatcher.d.ts +1 -0
  120. package/dist/types/Dispatcher/Mocks/MockHostDispatcher.d.ts.map +1 -1
  121. package/dist/types/Handler/Entities/HostHandler.d.ts +18 -1
  122. package/dist/types/Handler/Entities/HostHandler.d.ts.map +1 -1
  123. package/dist/types/StateMachine/Mocks/SavePersistentStatesMock.d.ts +1 -1
  124. package/dist/types/StateMachine/Mocks/SavePersistentStatesMock.d.ts.map +1 -1
  125. package/dist/types/StateMachine/UCs/SavePersistentStates.d.ts +1 -1
  126. package/dist/types/StateMachine/UCs/SavePersistentStates.d.ts.map +1 -1
  127. package/dist/types/index.d.ts +1 -0
  128. package/dist/types/index.d.ts.map +1 -1
  129. package/package.json +1 -1
@@ -0,0 +1,51 @@
1
+ import { getSingletonComponent, AppObjectPM } from "@vived/core";
2
+ import { BoundaryLogEntity } from "../Entities";
3
+ export const defaultBoundaryLogVM = {
4
+ records: [],
5
+ count: 0
6
+ };
7
+ export class BoundaryLogPM extends AppObjectPM {
8
+ static get(appObjects) {
9
+ return getSingletonComponent(BoundaryLogPM.type, appObjects);
10
+ }
11
+ }
12
+ BoundaryLogPM.type = "BoundaryLogPM";
13
+ export function makeBoundaryLogPM(appObject) {
14
+ return new BoundaryLogPMImp(appObject);
15
+ }
16
+ class BoundaryLogPMImp extends BoundaryLogPM {
17
+ get boundaryLog() {
18
+ return this.getCachedSingleton(BoundaryLogEntity.type);
19
+ }
20
+ vmsAreEqual(a, b) {
21
+ if (a.count !== b.count)
22
+ return false;
23
+ if (a.records.length !== b.records.length)
24
+ return false;
25
+ for (let i = 0; i < a.records.length; i++) {
26
+ if (a.records[i] !== b.records[i])
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ constructor(appObject) {
32
+ super(appObject, BoundaryLogPM.type);
33
+ this.onEntityChange = () => {
34
+ if (!this.boundaryLog)
35
+ return;
36
+ // Copy the array (new VM identity) but keep record references stable so
37
+ // vmsAreEqual can compare cheaply. Order is insertion order = the order the
38
+ // Requests were observed.
39
+ const records = [...this.boundaryLog.records];
40
+ const vm = {
41
+ records,
42
+ count: records.length
43
+ };
44
+ this.doUpdateView(vm);
45
+ };
46
+ this.onEntityChange();
47
+ this.boundaryLog?.addChangeObserver(this.onEntityChange);
48
+ this.appObjects.registerSingleton(this);
49
+ }
50
+ }
51
+ //# sourceMappingURL=BoundaryLogPM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoundaryLogPM.js","sourceRoot":"","sources":["../../../../src/BoundaryLog/PMs/BoundaryLogPM.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAErB,WAAW,EAEZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAiB,MAAM,aAAa,CAAC;AAY/D,MAAM,CAAC,MAAM,oBAAoB,GAAkB;IACjD,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,OAAgB,aAAc,SAAQ,WAA0B;IAGpE,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9E,CAAC;;AAJM,kBAAI,GAAG,eAAe,CAAC;AAOhC,MAAM,UAAU,iBAAiB,CAAC,SAAoB;IACpD,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,gBAAiB,SAAQ,aAAa;IAC1C,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,kBAAkB,CAAoB,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;IAED,WAAW,CAAC,CAAgB,EAAE,CAAgB;QAC5C,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACtC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QAClD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAiBD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;QAhB/B,mBAAc,GAAG,GAAG,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,WAAW;gBAAE,OAAO;YAE9B,wEAAwE;YACxE,4EAA4E;YAC5E,0BAA0B;YAC1B,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,EAAE,GAAkB;gBACxB,OAAO;gBACP,KAAK,EAAE,OAAO,CAAC,MAAM;aACtB,CAAC;YAEF,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC,CAAC;QAKA,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACzD,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectPM,\r\n AppObjectRepo\r\n} from \"@vived/core\";\r\nimport { BoundaryLogEntity, RequestRecord } from \"../Entities\";\r\n\r\n/**\r\n * The view projection of the Boundary Log: the recorded Requests in observation\r\n * order (each row carries its direction so the view can side Dispatches and\r\n * Handlers independently) plus the total count.\r\n */\r\nexport interface BoundaryLogVM {\r\n records: RequestRecord[];\r\n count: number;\r\n}\r\n\r\nexport const defaultBoundaryLogVM: BoundaryLogVM = {\r\n records: [],\r\n count: 0\r\n};\r\n\r\nexport abstract class BoundaryLogPM extends AppObjectPM<BoundaryLogVM> {\r\n static type = \"BoundaryLogPM\";\r\n\r\n static get(appObjects: AppObjectRepo) {\r\n return getSingletonComponent<BoundaryLogPM>(BoundaryLogPM.type, appObjects);\r\n }\r\n}\r\n\r\nexport function makeBoundaryLogPM(appObject: AppObject): BoundaryLogPM {\r\n return new BoundaryLogPMImp(appObject);\r\n}\r\n\r\nclass BoundaryLogPMImp extends BoundaryLogPM {\r\n private get boundaryLog() {\r\n return this.getCachedSingleton<BoundaryLogEntity>(BoundaryLogEntity.type);\r\n }\r\n\r\n vmsAreEqual(a: BoundaryLogVM, b: BoundaryLogVM): boolean {\r\n if (a.count !== b.count) return false;\r\n if (a.records.length !== b.records.length) return false;\r\n for (let i = 0; i < a.records.length; i++) {\r\n if (a.records[i] !== b.records[i]) return false;\r\n }\r\n return true;\r\n }\r\n\r\n private onEntityChange = () => {\r\n if (!this.boundaryLog) return;\r\n\r\n // Copy the array (new VM identity) but keep record references stable so\r\n // vmsAreEqual can compare cheaply. Order is insertion order = the order the\r\n // Requests were observed.\r\n const records = [...this.boundaryLog.records];\r\n const vm: BoundaryLogVM = {\r\n records,\r\n count: records.length\r\n };\r\n\r\n this.doUpdateView(vm);\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, BoundaryLogPM.type);\r\n\r\n this.onEntityChange();\r\n this.boundaryLog?.addChangeObserver(this.onEntityChange);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
@@ -0,0 +1,2 @@
1
+ export * from "./BoundaryLogPM";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/BoundaryLog/PMs/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC","sourcesContent":["export * from \"./BoundaryLogPM\";\r\n"]}
@@ -0,0 +1,7 @@
1
+ export * from "./Adapters";
2
+ export * from "./Controllers";
3
+ export * from "./Entities";
4
+ export * from "./Factories";
5
+ export * from "./Mocks";
6
+ export * from "./PMs";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/BoundaryLog/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC","sourcesContent":["export * from \"./Adapters\";\r\nexport * from \"./Controllers\";\r\nexport * from \"./Entities\";\r\nexport * from \"./Factories\";\r\nexport * from \"./Mocks\";\r\nexport * from \"./PMs\";\r\n"]}
@@ -19,36 +19,51 @@ class DialogRepoImp extends DialogQueue {
19
19
  this.dialogQueue = [];
20
20
  this.submitDialog = (dialog) => {
21
21
  this.dialogQueue.push(dialog);
22
- if (this.activeDialog === dialog) {
23
- dialog.isOpen = true;
24
- }
25
- dialog.addChangeObserver(this.notifyOnChange);
22
+ dialog.addChangeObserver(this.onDialogChange);
23
+ this.openActiveDialog();
26
24
  this.notifyOnChange();
27
25
  };
28
26
  this.activeDialogHasClosed = () => {
29
27
  const currentActiveDialog = this.activeDialog;
30
- if (currentActiveDialog !== null) {
31
- currentActiveDialog.removeChangeObserver(this.notifyOnChange);
32
- this.filterOutClosedDialogs();
33
- this.dialogQueue.splice(0, 1);
34
- const newActiveDialog = this.activeDialog;
35
- if (newActiveDialog !== null) {
36
- newActiveDialog.isOpen = true;
37
- }
28
+ if (currentActiveDialog === null)
29
+ return;
30
+ // Dismissal comes via two routes: a dialog's own close() (which sets
31
+ // hasBeenClosed) or the host's backdrop/escape path (this method). Mark the
32
+ // active dialog closed here so both routes converge on the same advance.
33
+ currentActiveDialog.hasBeenClosed = true;
34
+ this.advanceQueue();
35
+ };
36
+ /**
37
+ * Observes every queued dialog. When the active dialog closes itself (e.g.
38
+ * via its own close button), advance the queue so the next dialog surfaces;
39
+ * otherwise just forward the change to the queue's own observers.
40
+ */
41
+ this.onDialogChange = () => {
42
+ const currentActiveDialog = this.activeDialog;
43
+ if (currentActiveDialog !== null && currentActiveDialog.hasBeenClosed) {
44
+ this.advanceQueue();
45
+ }
46
+ else {
38
47
  this.notifyOnChange();
39
48
  }
40
49
  };
41
- this.filterOutClosedDialogs = () => {
42
- const dialogsToKeep = [];
43
- this.dialogQueue.forEach((dialog) => {
44
- if (!dialog.hasBeenClosed) {
45
- dialogsToKeep.push(dialog);
46
- }
47
- else {
48
- dialog.removeChangeObserver(this.notifyOnChange);
50
+ /** Drop every closed dialog, then open whatever is now the active dialog. */
51
+ this.advanceQueue = () => {
52
+ this.dialogQueue = this.dialogQueue.filter((dialog) => {
53
+ if (dialog.hasBeenClosed) {
54
+ dialog.removeChangeObserver(this.onDialogChange);
55
+ return false;
49
56
  }
57
+ return true;
50
58
  });
51
- this.dialogQueue = dialogsToKeep;
59
+ this.openActiveDialog();
60
+ this.notifyOnChange();
61
+ };
62
+ this.openActiveDialog = () => {
63
+ const active = this.activeDialog;
64
+ if (active !== null && !active.isOpen) {
65
+ active.isOpen = true;
66
+ }
52
67
  };
53
68
  this.appObjects.registerSingleton(this);
54
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DialogQueue.js","sourceRoot":"","sources":["../../../../src/Dialog/Entities/DialogQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAEf,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB,MAAM,OAAgB,MAAO,SAAQ,eAAe;CAKnD;AAED,MAAM,OAAgB,WAAY,SAAQ,eAAe;IAOvD,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAAc,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC1E,CAAC;;AARM,gBAAI,GAAG,aAAa,CAAC;AAW9B,MAAM,UAAU,eAAe,CAAC,SAAoB;IAClD,OAAO,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,aAAc,SAAQ,WAAW;IAGrC,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,CAAC;IA6CD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAlD7B,gBAAW,GAAa,EAAE,CAAC;QAMnC,iBAAY,GAAG,CAAC,MAAc,EAAQ,EAAE;YACtC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAE9B,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;gBACjC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;YACvB,CAAC;YAED,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAE9C,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,CAAC;QAEF,0BAAqB,GAAG,GAAS,EAAE;YACjC,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,CAAC;YAC9C,IAAI,mBAAmB,KAAK,IAAI,EAAE,CAAC;gBACjC,mBAAmB,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBAE9D,IAAI,CAAC,sBAAsB,EAAE,CAAC;gBAE9B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9B,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC;gBAC1C,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;oBAC7B,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC;gBAChC,CAAC;gBAED,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,CAAC;QACH,CAAC,CAAC;QAEM,2BAAsB,GAAG,GAAG,EAAE;YACpC,MAAM,aAAa,GAAa,EAAE,CAAC;YAEnC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;gBAClC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;oBAC1B,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC;QACnC,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import {\n AppObject,\n AppObjectEntity,\n AppObjectRepo,\n getSingletonComponent\n} from \"@vived/core\";\n\nexport abstract class Dialog extends AppObjectEntity {\n abstract dialogType: string;\n abstract preventOutsideDismiss: boolean;\n abstract isOpen: boolean;\n abstract hasBeenClosed: boolean;\n}\n\nexport abstract class DialogQueue extends AppObjectEntity {\n static type = \"DialogQueue\";\n\n abstract get activeDialog(): Dialog | null;\n abstract submitDialog(dialog: Dialog): void;\n abstract activeDialogHasClosed(): void;\n\n static get(appObjects: AppObjectRepo) {\n return getSingletonComponent<DialogQueue>(DialogQueue.type, appObjects);\n }\n}\n\nexport function makeDialogQueue(appObject: AppObject): DialogQueue {\n return new DialogRepoImp(appObject);\n}\n\nclass DialogRepoImp extends DialogQueue {\n private dialogQueue: Dialog[] = [];\n\n get activeDialog(): Dialog | null {\n return this.dialogQueue.length > 0 ? this.dialogQueue[0] : null;\n }\n\n submitDialog = (dialog: Dialog): void => {\n this.dialogQueue.push(dialog);\n\n if (this.activeDialog === dialog) {\n dialog.isOpen = true;\n }\n\n dialog.addChangeObserver(this.notifyOnChange);\n\n this.notifyOnChange();\n };\n\n activeDialogHasClosed = (): void => {\n const currentActiveDialog = this.activeDialog;\n if (currentActiveDialog !== null) {\n currentActiveDialog.removeChangeObserver(this.notifyOnChange);\n\n this.filterOutClosedDialogs();\n\n this.dialogQueue.splice(0, 1);\n const newActiveDialog = this.activeDialog;\n if (newActiveDialog !== null) {\n newActiveDialog.isOpen = true;\n }\n\n this.notifyOnChange();\n }\n };\n\n private filterOutClosedDialogs = () => {\n const dialogsToKeep: Dialog[] = [];\n\n this.dialogQueue.forEach((dialog) => {\n if (!dialog.hasBeenClosed) {\n dialogsToKeep.push(dialog);\n } else {\n dialog.removeChangeObserver(this.notifyOnChange);\n }\n });\n\n this.dialogQueue = dialogsToKeep;\n };\n\n constructor(appObject: AppObject) {\n super(appObject, DialogQueue.type);\n this.appObjects.registerSingleton(this);\n }\n}\n"]}
1
+ {"version":3,"file":"DialogQueue.js","sourceRoot":"","sources":["../../../../src/Dialog/Entities/DialogQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAEf,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB,MAAM,OAAgB,MAAO,SAAQ,eAAe;CAKnD;AAED,MAAM,OAAgB,WAAY,SAAQ,eAAe;IAOvD,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAAc,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC1E,CAAC;;AARM,gBAAI,GAAG,aAAa,CAAC;AAW9B,MAAM,UAAU,eAAe,CAAC,SAAoB;IAClD,OAAO,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,aAAc,SAAQ,WAAW;IAGrC,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,CAAC;IAyDD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QA9D7B,gBAAW,GAAa,EAAE,CAAC;QAMnC,iBAAY,GAAG,CAAC,MAAc,EAAQ,EAAE;YACtC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAE9B,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAE9C,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,CAAC;QAEF,0BAAqB,GAAG,GAAS,EAAE;YACjC,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,CAAC;YAC9C,IAAI,mBAAmB,KAAK,IAAI;gBAAE,OAAO;YAEzC,qEAAqE;YACrE,4EAA4E;YAC5E,yEAAyE;YACzE,mBAAmB,CAAC,aAAa,GAAG,IAAI,CAAC;YACzC,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC,CAAC;QAEF;;;;WAIG;QACK,mBAAc,GAAG,GAAS,EAAE;YAClC,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,CAAC;YAC9C,IAAI,mBAAmB,KAAK,IAAI,IAAI,mBAAmB,CAAC,aAAa,EAAE,CAAC;gBACtE,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,CAAC;QACH,CAAC,CAAC;QAEF,6EAA6E;QACrE,iBAAY,GAAG,GAAS,EAAE;YAChC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE;gBACpD,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;oBACzB,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;oBACjD,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,CAAC;QAEM,qBAAgB,GAAG,GAAS,EAAE;YACpC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC;YACjC,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACtC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;YACvB,CAAC;QACH,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import {\r\n AppObject,\r\n AppObjectEntity,\r\n AppObjectRepo,\r\n getSingletonComponent\r\n} from \"@vived/core\";\r\n\r\nexport abstract class Dialog extends AppObjectEntity {\r\n abstract dialogType: string;\r\n abstract preventOutsideDismiss: boolean;\r\n abstract isOpen: boolean;\r\n abstract hasBeenClosed: boolean;\r\n}\r\n\r\nexport abstract class DialogQueue extends AppObjectEntity {\r\n static type = \"DialogQueue\";\r\n\r\n abstract get activeDialog(): Dialog | null;\r\n abstract submitDialog(dialog: Dialog): void;\r\n abstract activeDialogHasClosed(): void;\r\n\r\n static get(appObjects: AppObjectRepo) {\r\n return getSingletonComponent<DialogQueue>(DialogQueue.type, appObjects);\r\n }\r\n}\r\n\r\nexport function makeDialogQueue(appObject: AppObject): DialogQueue {\r\n return new DialogRepoImp(appObject);\r\n}\r\n\r\nclass DialogRepoImp extends DialogQueue {\r\n private dialogQueue: Dialog[] = [];\r\n\r\n get activeDialog(): Dialog | null {\r\n return this.dialogQueue.length > 0 ? this.dialogQueue[0] : null;\r\n }\r\n\r\n submitDialog = (dialog: Dialog): void => {\r\n this.dialogQueue.push(dialog);\r\n\r\n dialog.addChangeObserver(this.onDialogChange);\r\n\r\n this.openActiveDialog();\r\n this.notifyOnChange();\r\n };\r\n\r\n activeDialogHasClosed = (): void => {\r\n const currentActiveDialog = this.activeDialog;\r\n if (currentActiveDialog === null) return;\r\n\r\n // Dismissal comes via two routes: a dialog's own close() (which sets\r\n // hasBeenClosed) or the host's backdrop/escape path (this method). Mark the\r\n // active dialog closed here so both routes converge on the same advance.\r\n currentActiveDialog.hasBeenClosed = true;\r\n this.advanceQueue();\r\n };\r\n\r\n /**\r\n * Observes every queued dialog. When the active dialog closes itself (e.g.\r\n * via its own close button), advance the queue so the next dialog surfaces;\r\n * otherwise just forward the change to the queue's own observers.\r\n */\r\n private onDialogChange = (): void => {\r\n const currentActiveDialog = this.activeDialog;\r\n if (currentActiveDialog !== null && currentActiveDialog.hasBeenClosed) {\r\n this.advanceQueue();\r\n } else {\r\n this.notifyOnChange();\r\n }\r\n };\r\n\r\n /** Drop every closed dialog, then open whatever is now the active dialog. */\r\n private advanceQueue = (): void => {\r\n this.dialogQueue = this.dialogQueue.filter((dialog) => {\r\n if (dialog.hasBeenClosed) {\r\n dialog.removeChangeObserver(this.onDialogChange);\r\n return false;\r\n }\r\n return true;\r\n });\r\n\r\n this.openActiveDialog();\r\n this.notifyOnChange();\r\n };\r\n\r\n private openActiveDialog = (): void => {\r\n const active = this.activeDialog;\r\n if (active !== null && !active.isOpen) {\r\n active.isOpen = true;\r\n }\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, DialogQueue.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
@@ -61,23 +61,36 @@ class HostDispatchEntityImp extends HostDispatchEntity {
61
61
  this.setupPayloadVersions = (payloadVersion) => {
62
62
  this.appPayloadVersions = payloadVersion;
63
63
  };
64
+ /**
65
+ * Notify the passive observer, if any. Wrapped so a throwing or slow observer
66
+ * can never alter, delay, or fail the Request's delivery (ADR-0002).
67
+ */
68
+ this.notifyObserver = (request, outcome) => {
69
+ if (!this.requestObserver)
70
+ return;
71
+ try {
72
+ this.requestObserver(request, outcome);
73
+ }
74
+ catch {
75
+ // Passive: an observer failure must never affect dispatch.
76
+ }
77
+ };
64
78
  this.dispatch = (request) => {
65
79
  if (!this.appHandler) {
66
80
  this.error("No app handler has been registered");
81
+ this.notifyObserver(request, "no-app-handler");
67
82
  return;
68
83
  }
69
84
  try {
70
85
  this.appHandler(request);
86
+ this.notifyObserver(request, "delivered");
71
87
  }
72
88
  catch (e) {
73
89
  this.warn(e.message);
90
+ this.notifyObserver(request, "threw");
74
91
  }
75
92
  };
76
93
  this.formRequestAndDispatch = (type, version, payload) => {
77
- if (!this.appHandler) {
78
- this.error("No app handler has been registered");
79
- return;
80
- }
81
94
  const request = {
82
95
  type,
83
96
  version,
@@ -1 +1 @@
1
- {"version":3,"file":"HostDispatchEntity.js","sourceRoot":"","sources":["../../../../src/Dispatcher/Entities/HostDispatchEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObject, AppObjectEntity, AppObjectRepo } from \"@vived/core\";\nimport { Handler, Request } from \"@vived/core\";\n\nexport abstract class HostDispatchEntity extends AppObjectEntity {\n static readonly type = \"HostDispatchEntity\";\n\n abstract appHandlerVersion: number;\n abstract getRequestPayloadVersion(requestType: string): number | undefined;\n abstract registerAppHandler: (appHandler: Handler) => void;\n abstract clearAppHandler: () => void;\n abstract dispatch: (request: Request) => void;\n abstract formRequestAndDispatch: (\n type: string,\n version: number,\n payload?: object | undefined\n ) => void;\n\n static get(appObject: AppObject): HostDispatchEntity | undefined {\n const component = appObject.getComponent<HostDispatchEntity>(\n HostDispatchEntity.type\n );\n if (!component) {\n appObject.appObjectRepo.submitWarning(\n \"AssetEntity.get\",\n \"Unable to find HostDispatchEntity on app object \" + appObject.id\n );\n }\n return component;\n }\n\n static getByID(\n id: string,\n appObjects: AppObjectRepo\n ): HostDispatchEntity | undefined {\n const appObject = appObjects.get(id);\n if (!appObject) {\n appObjects.submitWarning(\n \"AssetEntity.getByID\",\n \"Unable to find app object \" + id\n );\n return;\n }\n return HostDispatchEntity.get(appObject);\n }\n}\n\nexport function makeHostDispatchEntity(\n appObject: AppObject\n): HostDispatchEntity {\n return new HostDispatchEntityImp(appObject);\n}\n\nclass HostDispatchEntityImp extends HostDispatchEntity {\n private appHandler?: Handler;\n\n private _appHandlerVersion = 0;\n public get appHandlerVersion() {\n return this._appHandlerVersion;\n }\n\n private appPayloadVersions = new Map<string, number>();\n\n registerAppHandler = (appHandler: Handler) => {\n this.appHandler = appHandler;\n this.getAppHandlerVersion();\n };\n\n clearAppHandler = () => {\n this.appHandler = undefined;\n };\n\n private getAppHandlerVersion() {\n const type = \"GET_APP_HANDLER_VERSION\";\n const payload = { callback: this.setupVersion };\n\n try {\n this.formRequestAndDispatch(type, 1, payload);\n } catch {\n // All good. this is probably an older app\n }\n }\n\n getRequestPayloadVersion = (requestType: string): number | undefined => {\n return this.appPayloadVersions.get(requestType);\n };\n\n private setupVersion = (version: number) => {\n // Apps before app package version 2.27 will not reach this\n this._appHandlerVersion = version;\n this.getPayloadVersions();\n };\n\n private getPayloadVersions = () => {\n const type = \"GET_APP_PAYLOAD_VERSION\";\n const payload = { callback: this.setupPayloadVersions };\n this.formRequestAndDispatch(type, 2, payload);\n };\n\n private setupPayloadVersions = (payloadVersion: Map<string, number>) => {\n this.appPayloadVersions = payloadVersion;\n };\n\n dispatch = (request: Request) => {\n if (!this.appHandler) {\n this.error(\"No app handler has been registered\");\n return;\n }\n\n try {\n this.appHandler(request);\n } catch (e) {\n this.warn((e as Error).message);\n }\n };\n\n formRequestAndDispatch = (\n type: string,\n version: number,\n payload?: object | undefined\n ) => {\n if (!this.appHandler) {\n this.error(\"No app handler has been registered\");\n return;\n }\n\n const request: Request = {\n type,\n version,\n payload\n };\n\n this.dispatch(request);\n };\n\n constructor(appObject: AppObject) {\n super(appObject, HostDispatchEntity.type);\n }\n}\n"]}
1
+ {"version":3,"file":"HostDispatchEntity.js","sourceRoot":"","sources":["../../../../src/Dispatcher/Entities/HostDispatchEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObject, AppObjectEntity, AppObjectRepo } from \"@vived/core\";\r\nimport { Handler, Request } from \"@vived/core\";\r\n\r\n/**\r\n * The outcome of an outbound Dispatch, as seen at the dispatch chokepoint:\r\n * \"delivered\" (the app handler ran), \"no-app-handler\" (nothing registered to\r\n * receive it), or \"threw\" (the app handler raised).\r\n */\r\nexport type DispatchOutcome = \"delivered\" | \"no-app-handler\" | \"threw\";\r\n\r\n/**\r\n * Passive observer of outbound Dispatches. Notified after each Request is\r\n * dispatched, with the outcome. Purely observational — see the passivity\r\n * contract in ADR-0002: an observer must never alter, delay, or fail delivery.\r\n */\r\nexport type DispatchObserver = (\r\n request: Request,\r\n outcome: DispatchOutcome\r\n) => void;\r\n\r\nexport abstract class HostDispatchEntity extends AppObjectEntity {\r\n static readonly type = \"HostDispatchEntity\";\r\n\r\n abstract appHandlerVersion: number;\r\n abstract getRequestPayloadVersion(requestType: string): number | undefined;\r\n abstract registerAppHandler: (appHandler: Handler) => void;\r\n abstract clearAppHandler: () => void;\r\n abstract dispatch: (request: Request) => void;\r\n abstract formRequestAndDispatch: (\r\n type: string,\r\n version: number,\r\n payload?: object | undefined\r\n ) => void;\r\n\r\n /**\r\n * Optional passive observer of outbound Dispatches (ADR-0002). Unset by\r\n * default, so production hosts pay nothing and behave exactly as before.\r\n */\r\n abstract requestObserver?: DispatchObserver;\r\n\r\n static get(appObject: AppObject): HostDispatchEntity | undefined {\r\n const component = appObject.getComponent<HostDispatchEntity>(\r\n HostDispatchEntity.type\r\n );\r\n if (!component) {\r\n appObject.appObjectRepo.submitWarning(\r\n \"AssetEntity.get\",\r\n \"Unable to find HostDispatchEntity on app object \" + appObject.id\r\n );\r\n }\r\n return component;\r\n }\r\n\r\n static getByID(\r\n id: string,\r\n appObjects: AppObjectRepo\r\n ): HostDispatchEntity | undefined {\r\n const appObject = appObjects.get(id);\r\n if (!appObject) {\r\n appObjects.submitWarning(\r\n \"AssetEntity.getByID\",\r\n \"Unable to find app object \" + id\r\n );\r\n return;\r\n }\r\n return HostDispatchEntity.get(appObject);\r\n }\r\n}\r\n\r\nexport function makeHostDispatchEntity(\r\n appObject: AppObject\r\n): HostDispatchEntity {\r\n return new HostDispatchEntityImp(appObject);\r\n}\r\n\r\nclass HostDispatchEntityImp extends HostDispatchEntity {\r\n private appHandler?: Handler;\r\n\r\n private _appHandlerVersion = 0;\r\n public get appHandlerVersion() {\r\n return this._appHandlerVersion;\r\n }\r\n\r\n private appPayloadVersions = new Map<string, number>();\r\n\r\n registerAppHandler = (appHandler: Handler) => {\r\n this.appHandler = appHandler;\r\n this.getAppHandlerVersion();\r\n };\r\n\r\n clearAppHandler = () => {\r\n this.appHandler = undefined;\r\n };\r\n\r\n private getAppHandlerVersion() {\r\n const type = \"GET_APP_HANDLER_VERSION\";\r\n const payload = { callback: this.setupVersion };\r\n\r\n try {\r\n this.formRequestAndDispatch(type, 1, payload);\r\n } catch {\r\n // All good. this is probably an older app\r\n }\r\n }\r\n\r\n getRequestPayloadVersion = (requestType: string): number | undefined => {\r\n return this.appPayloadVersions.get(requestType);\r\n };\r\n\r\n private setupVersion = (version: number) => {\r\n // Apps before app package version 2.27 will not reach this\r\n this._appHandlerVersion = version;\r\n this.getPayloadVersions();\r\n };\r\n\r\n private getPayloadVersions = () => {\r\n const type = \"GET_APP_PAYLOAD_VERSION\";\r\n const payload = { callback: this.setupPayloadVersions };\r\n this.formRequestAndDispatch(type, 2, payload);\r\n };\r\n\r\n private setupPayloadVersions = (payloadVersion: Map<string, number>) => {\r\n this.appPayloadVersions = payloadVersion;\r\n };\r\n\r\n requestObserver?: DispatchObserver;\r\n\r\n /**\r\n * Notify the passive observer, if any. Wrapped so a throwing or slow observer\r\n * can never alter, delay, or fail the Request's delivery (ADR-0002).\r\n */\r\n private notifyObserver = (request: Request, outcome: DispatchOutcome) => {\r\n if (!this.requestObserver) return;\r\n try {\r\n this.requestObserver(request, outcome);\r\n } catch {\r\n // Passive: an observer failure must never affect dispatch.\r\n }\r\n };\r\n\r\n dispatch = (request: Request) => {\r\n if (!this.appHandler) {\r\n this.error(\"No app handler has been registered\");\r\n this.notifyObserver(request, \"no-app-handler\");\r\n return;\r\n }\r\n\r\n try {\r\n this.appHandler(request);\r\n this.notifyObserver(request, \"delivered\");\r\n } catch (e) {\r\n this.warn((e as Error).message);\r\n this.notifyObserver(request, \"threw\");\r\n }\r\n };\r\n\r\n formRequestAndDispatch = (\r\n type: string,\r\n version: number,\r\n payload?: object | undefined\r\n ) => {\r\n const request: Request = {\r\n type,\r\n version,\r\n payload\r\n };\r\n\r\n this.dispatch(request);\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, HostDispatchEntity.type);\r\n }\r\n}\r\n"]}
@@ -8,6 +8,7 @@ export class MockHostDispatchEntity extends HostDispatchEntity {
8
8
  this.registerAppHandler = jest.fn();
9
9
  this.dispatch = jest.fn();
10
10
  this.formRequestAndDispatch = jest.fn();
11
+ this.requestObserver = undefined;
11
12
  }
12
13
  }
13
14
  //# sourceMappingURL=MockHostDispatcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MockHostDispatcher.js","sourceRoot":"","sources":["../../../../src/Dispatcher/Mocks/MockHostDispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,OAAO,sBAAuB,SAAQ,kBAAkB;IAQ5D,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAR5C,oBAAe,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAC5B,sBAAiB,GAAG,CAAC,CAAC;QACtB,6BAAwB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACrC,uBAAkB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAC/B,aAAQ,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACrB,2BAAsB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IAInC,CAAC;CACF","sourcesContent":["import { AppObject } from \"@vived/core\";\nimport { HostDispatchEntity } from \"../Entities\";\n\nexport class MockHostDispatchEntity extends HostDispatchEntity {\n clearAppHandler = jest.fn();\n appHandlerVersion = 1;\n getRequestPayloadVersion = jest.fn();\n registerAppHandler = jest.fn();\n dispatch = jest.fn();\n formRequestAndDispatch = jest.fn();\n\n constructor(appObject: AppObject) {\n super(appObject, HostDispatchEntity.type);\n }\n}\n"]}
1
+ {"version":3,"file":"MockHostDispatcher.js","sourceRoot":"","sources":["../../../../src/Dispatcher/Mocks/MockHostDispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,OAAO,sBAAuB,SAAQ,kBAAkB;IAS5D,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAT5C,oBAAe,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAC5B,sBAAiB,GAAG,CAAC,CAAC;QACtB,6BAAwB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACrC,uBAAkB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAC/B,aAAQ,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACrB,2BAAsB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACnC,oBAAe,GAAG,SAAS,CAAC;IAI5B,CAAC;CACF","sourcesContent":["import { AppObject } from \"@vived/core\";\r\nimport { HostDispatchEntity } from \"../Entities\";\r\n\r\nexport class MockHostDispatchEntity extends HostDispatchEntity {\r\n clearAppHandler = jest.fn();\r\n appHandlerVersion = 1;\r\n getRequestPayloadVersion = jest.fn();\r\n registerAppHandler = jest.fn();\r\n dispatch = jest.fn();\r\n formRequestAndDispatch = jest.fn();\r\n requestObserver = undefined;\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, HostDispatchEntity.type);\r\n }\r\n}\r\n"]}
@@ -12,17 +12,34 @@ class RequestHandlerImp extends HostHandlerEntity {
12
12
  constructor(appObj) {
13
13
  super(appObj, HostHandlerEntity.type);
14
14
  this.handlers = new Map();
15
+ /**
16
+ * Notify the passive observer, if any. Wrapped so a throwing or slow observer
17
+ * can never alter, delay, or fail the Request (ADR-0002).
18
+ */
19
+ this.notifyObserver = (request, outcome) => {
20
+ if (!this.requestObserver)
21
+ return;
22
+ try {
23
+ this.requestObserver(request, outcome);
24
+ }
25
+ catch {
26
+ // Passive: an observer failure must never affect handling.
27
+ }
28
+ };
15
29
  this.handler = (request) => {
16
30
  const handler = this.handlers.get(request.type);
17
31
  if (!handler) {
18
32
  this.warn(`Unsupported request type received: ${request.type}`);
33
+ this.notifyObserver(request, "unsupported");
19
34
  return;
20
35
  }
21
36
  try {
22
37
  handler.handleRequest(request.version, request.payload);
38
+ this.notifyObserver(request, "handled");
23
39
  }
24
40
  catch (e) {
25
41
  this.warn(`${e}`);
42
+ this.notifyObserver(request, "threw");
26
43
  }
27
44
  };
28
45
  this.registerRequestHandler = (handler) => {
@@ -1 +1 @@
1
- {"version":3,"file":"HostHandler.js","sourceRoot":"","sources":["../../../../src/Handler/Entities/HostHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,eAAe,EAAE,MAAM,aAAa,CAAC;AAQzD,MAAM,OAAgB,iBAAkB,SAAQ,eAAe;IAG7D,MAAM,CAAC,GAAG,CAAC,SAAoB;QAC7B,OAAO,SAAS,CAAC,YAAY,CAAoB,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC3E,CAAC;;AAJM,sBAAI,GAAG,mBAAmB,CAAC;AAUpC,MAAM,UAAU,qBAAqB,CAAC,SAAoB;IACxD,OAAO,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,iBAAkB,SAAQ,iBAAiB;IA4B/C,YAAY,MAAiB;QAC3B,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC;QA5BhC,aAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;QAErD,YAAO,GAAY,CAAC,OAAgB,EAAQ,EAAE;YAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,sCAAsC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;gBAChE,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YAC1D,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC;QAEF,2BAAsB,GAAG,CAAC,OAAuB,EAAQ,EAAE;YACzD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,IAAI,CACP,iDAAiD,OAAO,CAAC,WAAW,yCAAyC,CAC9G,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC,CAAC;IAIF,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAY,WAAmB,EAAE,OAAe;QAC9C,MAAM,GAAG,GAAG,WAAW,OAAO,oBAAoB,WAAW,mBAAmB,CAAC;QACjF,KAAK,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,WAAmB;QAC7B,MAAM,GAAG,GAAG,2BAA2B,WAAW,qBAAqB,CAAC;QACxE,KAAK,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,WAAmB,EAAE,OAAe,EAAE,OAAe;QAC/D,MAAM,GAAG,GAAG,sCAAsC,OAAO,oBAAoB,WAAW,KAAK,OAAO,EAAE,CAAC;QACvG,KAAK,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;CACF","sourcesContent":["import { AppObject, AppObjectEntity } from \"@vived/core\";\nimport { Handler, Request } from \"@vived/core\";\n\nexport interface RequestHandler {\n readonly requestType: string;\n handleRequest: (version: number, payload?: unknown) => void;\n}\n\nexport abstract class HostHandlerEntity extends AppObjectEntity {\n static type = \"HostHandlerEntity\";\n\n static get(appObject: AppObject) {\n return appObject.getComponent<HostHandlerEntity>(HostHandlerEntity.type);\n }\n\n abstract handler: Handler;\n abstract registerRequestHandler: (requestHandler: RequestHandler) => void;\n}\n\nexport function makeHostHandlerEntity(appObject: AppObject): HostHandlerEntity {\n return new RequestHandlerImp(appObject);\n}\n\nclass RequestHandlerImp extends HostHandlerEntity {\n private handlers = new Map<string, RequestHandler>();\n\n handler: Handler = (request: Request): void => {\n const handler = this.handlers.get(request.type);\n\n if (!handler) {\n this.warn(`Unsupported request type received: ${request.type}`);\n return;\n }\n\n try {\n handler.handleRequest(request.version, request.payload);\n } catch (e) {\n this.warn(`${e}`);\n }\n };\n\n registerRequestHandler = (handler: RequestHandler): void => {\n if (this.handlers.has(handler.requestType)) {\n this.warn(\n `More than one handler is being registered for ${handler.requestType}. Previous handler is being overwritten`\n );\n }\n\n this.handlers.set(handler.requestType, handler);\n };\n\n constructor(appObj: AppObject) {\n super(appObj, HostHandlerEntity.type);\n }\n}\n\nexport class UnsupportedRequestVersion extends Error {\n constructor(requestType: string, version: number) {\n const msg = `Version ${version} of request type ${requestType} is not supported`;\n super(msg);\n }\n}\n\nexport class ActionNotImplemented extends Error {\n constructor(requestType: string) {\n const msg = `Action for request type ${requestType} is not implemented`;\n super(msg);\n }\n}\n\nexport class UnableToParsePayload extends Error {\n constructor(requestType: string, version: number, payload: string) {\n const msg = `Unable to parse paylod for version ${version} of request type ${requestType}: ${payload}`;\n super(msg);\n }\n}\n"]}
1
+ {"version":3,"file":"HostHandler.js","sourceRoot":"","sources":["../../../../src/Handler/Entities/HostHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObject, AppObjectEntity } from \"@vived/core\";\r\nimport { Handler, Request } from \"@vived/core\";\r\n\r\nexport interface RequestHandler {\r\n readonly requestType: string;\r\n handleRequest: (version: number, payload?: unknown) => void;\r\n}\r\n\r\n/**\r\n * The outcome of an inbound Request, as seen at the handler chokepoint:\r\n * \"handled\" (a registered handler ran), \"unsupported\" (no handler registered\r\n * for the type), or \"threw\" (the handler raised).\r\n */\r\nexport type HandlerOutcome = \"handled\" | \"unsupported\" | \"threw\";\r\n\r\n/**\r\n * Passive observer of inbound Requests. Notified after each Request is routed,\r\n * with the outcome. Purely observational — see the passivity contract in\r\n * ADR-0002: an observer must never alter, delay, or fail the Request.\r\n */\r\nexport type HandlerObserver = (\r\n request: Request,\r\n outcome: HandlerOutcome\r\n) => void;\r\n\r\nexport abstract class HostHandlerEntity extends AppObjectEntity {\r\n static type = \"HostHandlerEntity\";\r\n\r\n static get(appObject: AppObject) {\r\n return appObject.getComponent<HostHandlerEntity>(HostHandlerEntity.type);\r\n }\r\n\r\n abstract handler: Handler;\r\n abstract registerRequestHandler: (requestHandler: RequestHandler) => void;\r\n\r\n /**\r\n * Optional passive observer of inbound Requests (ADR-0002). Unset by default,\r\n * so production hosts pay nothing and behave exactly as before.\r\n */\r\n abstract requestObserver?: HandlerObserver;\r\n}\r\n\r\nexport function makeHostHandlerEntity(appObject: AppObject): HostHandlerEntity {\r\n return new RequestHandlerImp(appObject);\r\n}\r\n\r\nclass RequestHandlerImp extends HostHandlerEntity {\r\n private handlers = new Map<string, RequestHandler>();\r\n\r\n requestObserver?: HandlerObserver;\r\n\r\n /**\r\n * Notify the passive observer, if any. Wrapped so a throwing or slow observer\r\n * can never alter, delay, or fail the Request (ADR-0002).\r\n */\r\n private notifyObserver = (request: Request, outcome: HandlerOutcome) => {\r\n if (!this.requestObserver) return;\r\n try {\r\n this.requestObserver(request, outcome);\r\n } catch {\r\n // Passive: an observer failure must never affect handling.\r\n }\r\n };\r\n\r\n handler: Handler = (request: Request): void => {\r\n const handler = this.handlers.get(request.type);\r\n\r\n if (!handler) {\r\n this.warn(`Unsupported request type received: ${request.type}`);\r\n this.notifyObserver(request, \"unsupported\");\r\n return;\r\n }\r\n\r\n try {\r\n handler.handleRequest(request.version, request.payload);\r\n this.notifyObserver(request, \"handled\");\r\n } catch (e) {\r\n this.warn(`${e}`);\r\n this.notifyObserver(request, \"threw\");\r\n }\r\n };\r\n\r\n registerRequestHandler = (handler: RequestHandler): void => {\r\n if (this.handlers.has(handler.requestType)) {\r\n this.warn(\r\n `More than one handler is being registered for ${handler.requestType}. Previous handler is being overwritten`\r\n );\r\n }\r\n\r\n this.handlers.set(handler.requestType, handler);\r\n };\r\n\r\n constructor(appObj: AppObject) {\r\n super(appObj, HostHandlerEntity.type);\r\n }\r\n}\r\n\r\nexport class UnsupportedRequestVersion extends Error {\r\n constructor(requestType: string, version: number) {\r\n const msg = `Version ${version} of request type ${requestType} is not supported`;\r\n super(msg);\r\n }\r\n}\r\n\r\nexport class ActionNotImplemented extends Error {\r\n constructor(requestType: string) {\r\n const msg = `Action for request type ${requestType} is not implemented`;\r\n super(msg);\r\n }\r\n}\r\n\r\nexport class UnableToParsePayload extends Error {\r\n constructor(requestType: string, version: number, payload: string) {\r\n const msg = `Unable to parse paylod for version ${version} of request type ${requestType}: ${payload}`;\r\n super(msg);\r\n }\r\n}\r\n"]}
@@ -5,6 +5,6 @@ export function savePersistentStates(appObjects) {
5
5
  appObjects.submitWarning("savePersistentStates", "Unable to find SavePersistentStatesUC");
6
6
  return;
7
7
  }
8
- uc.saveLocally();
8
+ uc.copyToClipboard();
9
9
  }
10
10
  //# sourceMappingURL=savePersistentStates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"savePersistentStates.js","sourceRoot":"","sources":["../../../../src/StateMachine/Controllers/savePersistentStates.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,UAAU,oBAAoB,CAAC,UAAyB;IAC5D,MAAM,EAAE,GAAG,sBAAsB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,UAAU,CAAC,aAAa,CACtB,sBAAsB,EACtB,uCAAuC,CACxC,CAAC;QACF,OAAO;IACT,CAAC;IAED,EAAE,CAAC,WAAW,EAAE,CAAC;AACnB,CAAC","sourcesContent":["import { AppObjectRepo } from \"@vived/core\";\nimport { SavePersistentStatesUC } from \"../UCs/SavePersistentStates\";\n\nexport function savePersistentStates(appObjects: AppObjectRepo) {\n const uc = SavePersistentStatesUC.get(appObjects);\n if (!uc) {\n appObjects.submitWarning(\n \"savePersistentStates\",\n \"Unable to find SavePersistentStatesUC\"\n );\n return;\n }\n\n uc.saveLocally();\n}\n"]}
1
+ {"version":3,"file":"savePersistentStates.js","sourceRoot":"","sources":["../../../../src/StateMachine/Controllers/savePersistentStates.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,UAAU,oBAAoB,CAAC,UAAyB;IAC5D,MAAM,EAAE,GAAG,sBAAsB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,UAAU,CAAC,aAAa,CACtB,sBAAsB,EACtB,uCAAuC,CACxC,CAAC;QACF,OAAO;IACT,CAAC;IAED,EAAE,CAAC,eAAe,EAAE,CAAC;AACvB,CAAC","sourcesContent":["import { AppObjectRepo } from \"@vived/core\";\nimport { SavePersistentStatesUC } from \"../UCs/SavePersistentStates\";\n\nexport function savePersistentStates(appObjects: AppObjectRepo) {\n const uc = SavePersistentStatesUC.get(appObjects);\n if (!uc) {\n appObjects.submitWarning(\n \"savePersistentStates\",\n \"Unable to find SavePersistentStatesUC\"\n );\n return;\n }\n\n uc.copyToClipboard();\n}\n"]}
@@ -2,7 +2,7 @@ import { SavePersistentStatesUC } from "../UCs/SavePersistentStates";
2
2
  export class SavePersistentStatesMock extends SavePersistentStatesUC {
3
3
  constructor(appObject) {
4
4
  super(appObject, SavePersistentStatesUC.type);
5
- this.saveLocally = jest.fn();
5
+ this.copyToClipboard = jest.fn();
6
6
  }
7
7
  }
8
8
  export function makeSavePersistentStatesMock(appObjects) {
@@ -1 +1 @@
1
- {"version":3,"file":"SavePersistentStatesMock.js","sourceRoot":"","sources":["../../../../src/StateMachine/Mocks/SavePersistentStatesMock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,OAAO,wBAAyB,SAAQ,sBAAsB;IAGlE,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAHhD,gBAAW,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IAIxB,CAAC;CACF;AAED,MAAM,UAAU,4BAA4B,CAAC,UAAyB;IACpE,OAAO,IAAI,wBAAwB,CACjC,UAAU,CAAC,WAAW,CAAC,0BAA0B,CAAC,CACnD,CAAC;AACJ,CAAC","sourcesContent":["import { AppObject, AppObjectRepo } from \"@vived/core\";\nimport { SavePersistentStatesUC } from \"../UCs/SavePersistentStates\";\n\nexport class SavePersistentStatesMock extends SavePersistentStatesUC {\n saveLocally = jest.fn();\n\n constructor(appObject: AppObject) {\n super(appObject, SavePersistentStatesUC.type);\n }\n}\n\nexport function makeSavePersistentStatesMock(appObjects: AppObjectRepo) {\n return new SavePersistentStatesMock(\n appObjects.getOrCreate(\"SavePersistentStatesMock\")\n );\n}\n"]}
1
+ {"version":3,"file":"SavePersistentStatesMock.js","sourceRoot":"","sources":["../../../../src/StateMachine/Mocks/SavePersistentStatesMock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,OAAO,wBAAyB,SAAQ,sBAAsB;IAGlE,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAHhD,oBAAe,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IAI5B,CAAC;CACF;AAED,MAAM,UAAU,4BAA4B,CAAC,UAAyB;IACpE,OAAO,IAAI,wBAAwB,CACjC,UAAU,CAAC,WAAW,CAAC,0BAA0B,CAAC,CACnD,CAAC;AACJ,CAAC","sourcesContent":["import { AppObject, AppObjectRepo } from \"@vived/core\";\nimport { SavePersistentStatesUC } from \"../UCs/SavePersistentStates\";\n\nexport class SavePersistentStatesMock extends SavePersistentStatesUC {\n copyToClipboard = jest.fn();\n\n constructor(appObject: AppObject) {\n super(appObject, SavePersistentStatesUC.type);\n }\n}\n\nexport function makeSavePersistentStatesMock(appObjects: AppObjectRepo) {\n return new SavePersistentStatesMock(\n appObjects.getOrCreate(\"SavePersistentStatesMock\")\n );\n}\n"]}
@@ -15,7 +15,7 @@ class SavePersistentStatesUCImp extends SavePersistentStatesUC {
15
15
  }
16
16
  constructor(appObject) {
17
17
  super(appObject, SavePersistentStatesUC.type);
18
- this.saveLocally = () => {
18
+ this.copyToClipboard = () => {
19
19
  if (!this.stateMachine)
20
20
  return;
21
21
  const states = [];
@@ -32,11 +32,9 @@ class SavePersistentStatesUCImp extends SavePersistentStatesUC {
32
32
  }
33
33
  });
34
34
  const statesData = JSON.stringify(states);
35
- const a = document.createElement("a");
36
- const file = new Blob([statesData], { type: "text/plain" });
37
- a.href = URL.createObjectURL(file);
38
- a.download = "persistentStates.json";
39
- a.click();
35
+ navigator.clipboard.writeText(statesData).catch((e) => {
36
+ this.warn(`Unable to copy persistent states to the clipboard: ${e}`);
37
+ });
40
38
  };
41
39
  this.appObjects.registerSingleton(this);
42
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SavePersistentStates.js","sourceRoot":"","sources":["../../../../src/StateMachine/UCs/SavePersistentStates.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAGrB,WAAW,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,OAAgB,sBAAuB,SAAQ,WAAW;IAK9D,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAC1B,sBAAsB,CAAC,IAAI,EAC3B,UAAU,CACX,CAAC;IACJ,CAAC;;AATM,2BAAI,GAAG,wBAAwB,CAAC;AAYzC,MAAM,UAAU,0BAA0B,CACxC,SAAoB;IAEpB,OAAO,IAAI,yBAAyB,CAAC,SAAS,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,yBAA0B,SAAQ,sBAAsB;IAC5D,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAmB,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IA4BD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;QA3BhD,gBAAW,GAAG,GAAS,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,YAAY;gBAAE,OAAO;YAE/B,MAAM,MAAM,GAAuB,EAAE,CAAC;YACtC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;gBACvD,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,IAAI,GAAqB;wBAC7B,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,IAAI,EAAE,KAAK,CAAC,SAAS;wBACrB,EAAE,EAAE,KAAK,CAAC,EAAE;wBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB,CAAC;oBAEF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;YAC5D,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACnC,CAAC,CAAC,QAAQ,GAAG,uBAAuB,CAAC;YACrC,CAAC,CAAC,KAAK,EAAE,CAAC;QACZ,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import {\n getSingletonComponent,\n AppObject,\n AppObjectRepo,\n AppObjectUC\n} from \"@vived/core\";\nimport { HostStateMachine } from \"../Entities\";\nimport { SandboxStateData } from \"./setSandboxStatesFromData\";\n\nexport abstract class SavePersistentStatesUC extends AppObjectUC {\n static type = \"SavePersistentStatesUC\";\n\n abstract saveLocally(): void;\n\n static get(appObjects: AppObjectRepo) {\n return getSingletonComponent<SavePersistentStatesUC>(\n SavePersistentStatesUC.type,\n appObjects\n );\n }\n}\n\nexport function makeSavePersistentStatesUC(\n appObject: AppObject\n): SavePersistentStatesUC {\n return new SavePersistentStatesUCImp(appObject);\n}\n\nclass SavePersistentStatesUCImp extends SavePersistentStatesUC {\n private get stateMachine() {\n return this.getCachedSingleton<HostStateMachine>(HostStateMachine.type);\n }\n\n saveLocally = (): void => {\n if (!this.stateMachine) return;\n\n const states: SandboxStateData[] = [];\n this.stateMachine.states.forEach((stateID) => {\n const state = this.stateMachine?.getStateByID(stateID);\n if (state) {\n const rVal: SandboxStateData = {\n assets: state.assets,\n data: state.stateData,\n id: state.id,\n name: state.name\n };\n\n states.push(rVal);\n }\n });\n\n const statesData = JSON.stringify(states);\n const a = document.createElement(\"a\");\n const file = new Blob([statesData], { type: \"text/plain\" });\n a.href = URL.createObjectURL(file);\n a.download = \"persistentStates.json\";\n a.click();\n };\n\n constructor(appObject: AppObject) {\n super(appObject, SavePersistentStatesUC.type);\n this.appObjects.registerSingleton(this);\n }\n}\n"]}
1
+ {"version":3,"file":"SavePersistentStates.js","sourceRoot":"","sources":["../../../../src/StateMachine/UCs/SavePersistentStates.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EAGrB,WAAW,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,OAAgB,sBAAuB,SAAQ,WAAW;IAK9D,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAC1B,sBAAsB,CAAC,IAAI,EAC3B,UAAU,CACX,CAAC;IACJ,CAAC;;AATM,2BAAI,GAAG,wBAAwB,CAAC;AAYzC,MAAM,UAAU,0BAA0B,CACxC,SAAoB;IAEpB,OAAO,IAAI,yBAAyB,CAAC,SAAS,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,yBAA0B,SAAQ,sBAAsB;IAC5D,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAmB,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IA0BD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAzBhD,oBAAe,GAAG,GAAS,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,YAAY;gBAAE,OAAO;YAE/B,MAAM,MAAM,GAAuB,EAAE,CAAC;YACtC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;gBACvD,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,IAAI,GAAqB;wBAC7B,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,IAAI,EAAE,KAAK,CAAC,SAAS;wBACrB,EAAE,EAAE,KAAK,CAAC,EAAE;wBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB,CAAC;oBAEF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC1C,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACpD,IAAI,CAAC,IAAI,CAAC,sDAAsD,CAAC,EAAE,CAAC,CAAC;YACvE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import {\n getSingletonComponent,\n AppObject,\n AppObjectRepo,\n AppObjectUC\n} from \"@vived/core\";\nimport { HostStateMachine } from \"../Entities\";\nimport { SandboxStateData } from \"./setSandboxStatesFromData\";\n\nexport abstract class SavePersistentStatesUC extends AppObjectUC {\n static type = \"SavePersistentStatesUC\";\n\n abstract copyToClipboard(): void;\n\n static get(appObjects: AppObjectRepo) {\n return getSingletonComponent<SavePersistentStatesUC>(\n SavePersistentStatesUC.type,\n appObjects\n );\n }\n}\n\nexport function makeSavePersistentStatesUC(\n appObject: AppObject\n): SavePersistentStatesUC {\n return new SavePersistentStatesUCImp(appObject);\n}\n\nclass SavePersistentStatesUCImp extends SavePersistentStatesUC {\n private get stateMachine() {\n return this.getCachedSingleton<HostStateMachine>(HostStateMachine.type);\n }\n\n copyToClipboard = (): void => {\n if (!this.stateMachine) return;\n\n const states: SandboxStateData[] = [];\n this.stateMachine.states.forEach((stateID) => {\n const state = this.stateMachine?.getStateByID(stateID);\n if (state) {\n const rVal: SandboxStateData = {\n assets: state.assets,\n data: state.stateData,\n id: state.id,\n name: state.name\n };\n\n states.push(rVal);\n }\n });\n\n const statesData = JSON.stringify(states);\n navigator.clipboard.writeText(statesData).catch((e) => {\n this.warn(`Unable to copy persistent states to the clipboard: ${e}`);\n });\n };\n\n constructor(appObject: AppObject) {\n super(appObject, SavePersistentStatesUC.type);\n this.appObjects.registerSingleton(this);\n }\n}\n"]}
package/dist/esm/index.js CHANGED
@@ -2,6 +2,7 @@ export * from "./Apps";
2
2
  export * from "./AppSandbox";
3
3
  export * from "./AssetPlugin";
4
4
  export * from "./Assets";
5
+ export * from "./BoundaryLog";
5
6
  export * from "./Cache";
6
7
  export * from "./ChallengeResults";
7
8
  export * from "./Dialog";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC","sourcesContent":["export * from \"./Apps\";\nexport * from \"./AppSandbox\";\nexport * from \"./AssetPlugin\";\nexport * from \"./Assets\";\nexport * from \"./Cache\";\nexport * from \"./ChallengeResults\";\nexport * from \"./Dialog\";\nexport * from \"./Dispatcher\";\nexport * from \"./Events\";\nexport * from \"./Handler\";\nexport * from \"./Logger\";\nexport * from \"./Snackbar\";\nexport * from \"./StateMachine\";\nexport * from \"./ThemeColors\";\nexport * from \"./VivedAPI\";\nexport * from \"./ZSpaceHost\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC","sourcesContent":["export * from \"./Apps\";\r\nexport * from \"./AppSandbox\";\r\nexport * from \"./AssetPlugin\";\r\nexport * from \"./Assets\";\r\nexport * from \"./BoundaryLog\";\r\nexport * from \"./Cache\";\r\nexport * from \"./ChallengeResults\";\r\nexport * from \"./Dialog\";\r\nexport * from \"./Dispatcher\";\r\nexport * from \"./Events\";\r\nexport * from \"./Handler\";\r\nexport * from \"./Logger\";\r\nexport * from \"./Snackbar\";\r\nexport * from \"./StateMachine\";\r\nexport * from \"./ThemeColors\";\r\nexport * from \"./VivedAPI\";\r\nexport * from \"./ZSpaceHost\";\r\n"]}
@@ -0,0 +1,4 @@
1
+ import { SingletonPmAdapter } from "@vived/core";
2
+ import { BoundaryLogVM } from "../PMs/BoundaryLogPM";
3
+ export declare const boundaryLogAdapter: SingletonPmAdapter<BoundaryLogVM>;
4
+ //# sourceMappingURL=boundaryLogAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundaryLogAdapter.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Adapters/boundaryLogAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAEL,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,kBAAkB,EAAE,kBAAkB,CAAC,aAAa,CA8BhE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./boundaryLogAdapter";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { AppObjectRepo } from "@vived/core";
2
+ /** Clears the Boundary Log on demand (the tab's Clear action). */
3
+ export declare function clearBoundaryLog(appObjects: AppObjectRepo): void;
4
+ //# sourceMappingURL=clearBoundaryLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clearBoundaryLog.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Controllers/clearBoundaryLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,QAUzD"}
@@ -0,0 +1,2 @@
1
+ export * from "./clearBoundaryLog";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Controllers/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { AppObject, AppObjectEntity, AppObjectRepo, Request } from "@vived/core";
2
+ import { PayloadSnapshot } from "./snapshotPayload";
3
+ /** Which way a recorded Request crossed the host↔App boundary. */
4
+ export type RequestDirection = "dispatch" | "handler";
5
+ /**
6
+ * What happened to a recorded Request. Outbound (Dispatch) records use
7
+ * "delivered" | "no-app-handler" | "threw"; inbound (Handler) records use
8
+ * "handled" | "unsupported" | "threw".
9
+ */
10
+ export type RequestOutcome = "delivered" | "no-app-handler" | "handled" | "unsupported" | "threw";
11
+ /**
12
+ * One captured entry in the Boundary Log: the observed Request plus its
13
+ * direction, a frozen payload snapshot, the time it was observed, and its
14
+ * outcome. Distinct from the live wire Request it was captured from.
15
+ */
16
+ export interface RequestRecord {
17
+ direction: RequestDirection;
18
+ type: string;
19
+ version: number;
20
+ payload: PayloadSnapshot;
21
+ timestamp: number;
22
+ outcome: RequestOutcome;
23
+ }
24
+ /**
25
+ * The Boundary Log: a passive, chronological recording of every Request
26
+ * observed crossing the host↔App boundary. Accumulates unbounded within a
27
+ * session and is only reset by an explicit clear() — never by traffic itself.
28
+ */
29
+ export declare abstract class BoundaryLogEntity extends AppObjectEntity {
30
+ static type: string;
31
+ static get(appObjects: AppObjectRepo): BoundaryLogEntity | undefined;
32
+ abstract records: RequestRecord[];
33
+ abstract recordTraffic: (direction: RequestDirection, request: Request, outcome: RequestOutcome) => void;
34
+ abstract clear: () => void;
35
+ }
36
+ export declare function makeBoundaryLogEntity(appObject: AppObject): BoundaryLogEntity;
37
+ //# sourceMappingURL=BoundaryLogEntity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoundaryLogEntity.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Entities/BoundaryLogEntity.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,eAAe,EACf,aAAa,EACb,OAAO,EACR,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAmB,MAAM,mBAAmB,CAAC;AAErE,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,CAAC;AAEtD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,gBAAgB,GAChB,SAAS,GACT,aAAa,GACb,OAAO,CAAC;AAEZ;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED;;;;GAIG;AACH,8BAAsB,iBAAkB,SAAQ,eAAe;IAC7D,MAAM,CAAC,IAAI,SAAuB;IAElC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa;IAOpC,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;IAElC,QAAQ,CAAC,aAAa,EAAE,CACtB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,cAAc,KACpB,IAAI,CAAC;IAEV,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,iBAAiB,CAE7E"}
@@ -0,0 +1,3 @@
1
+ export * from "./BoundaryLogEntity";
2
+ export * from "./snapshotPayload";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Entities/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * A best-effort, one-level-deep structural snapshot of a Request payload, taken
3
+ * at the moment the Request crosses the host↔App boundary. It never throws:
4
+ * callbacks, circular references, and throwing getters are all rendered as
5
+ * previews rather than expanded or serialized. Nested objects/arrays are marked
6
+ * (not recursed), so what a developer inspects is exactly what was sent —
7
+ * frozen, safe to render, and cheap to build.
8
+ */
9
+ export interface PayloadSnapshot {
10
+ /** True when the payload was undefined/null or carried no own-enumerable keys. */
11
+ isEmpty: boolean;
12
+ /** Own-enumerable key → one-level preview string. */
13
+ fields: Record<string, string>;
14
+ }
15
+ export declare function snapshotPayload(payload: unknown): PayloadSnapshot;
16
+ //# sourceMappingURL=snapshotPayload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshotPayload.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Entities/snapshotPayload.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,OAAO,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAkCD,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,CAwBjE"}
@@ -0,0 +1,17 @@
1
+ import { AppObject, AppObjectRepo, DomainFactory } from "@vived/core";
2
+ /**
3
+ * Sets up the Boundary Log and wires its passive observers into the per-App
4
+ * communication entities (ADR-0002). The observers are attached in finalSetup,
5
+ * after every entity exists but before the App mounts — so the host-internal
6
+ * version-negotiation dispatches fired at registration are captured too.
7
+ */
8
+ export declare class BoundaryLogFactory extends DomainFactory {
9
+ readonly factoryName = "BoundaryLogFactory";
10
+ constructor(appObject: AppObject);
11
+ setupEntities(): void;
12
+ setupUCs(): void;
13
+ setupPMs(): void;
14
+ finalSetup(): void;
15
+ }
16
+ export declare function makeBoundaryLogFactory(appObjects: AppObjectRepo): BoundaryLogFactory;
17
+ //# sourceMappingURL=BoundaryLogFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoundaryLogFactory.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Factories/BoundaryLogFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAOtE;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;IACnD,QAAQ,CAAC,WAAW,wBAAwB;gBAEhC,SAAS,EAAE,SAAS;IAIhC,aAAa,IAAI,IAAI;IAIrB,QAAQ,IAAI,IAAI;IAIhB,QAAQ,IAAI,IAAI;IAIhB,UAAU,IAAI,IAAI;CA+BnB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,aAAa,GACxB,kBAAkB,CAGpB"}
@@ -0,0 +1,2 @@
1
+ export * from "./BoundaryLogFactory";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/BoundaryLog/Factories/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { AppObject, AppObjectRepo } from "@vived/core";
2
+ import { BoundaryLogPM } from "../PMs";
3
+ export declare class BoundaryLogPMMock extends BoundaryLogPM {
4
+ vmsAreEqual: jest.Mock<any, any, any>;
5
+ constructor(appObject: AppObject);
6
+ }
7
+ export declare function makeBoundaryLogPMMock(appObjects: AppObjectRepo): BoundaryLogPMMock;
8
+ //# sourceMappingURL=BoundaryLogPMMock.d.ts.map