@carlonicora/nestjs-neo4jsonapi 8.15.1 → 8.16.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 (104) hide show
  1. package/dist/bootstrap/app.module.factory.d.ts.map +1 -1
  2. package/dist/bootstrap/app.module.factory.js +9 -0
  3. package/dist/bootstrap/app.module.factory.js.map +1 -1
  4. package/dist/bootstrap/bootstrap.options.d.ts +10 -0
  5. package/dist/bootstrap/bootstrap.options.d.ts.map +1 -1
  6. package/dist/common/helpers/define-entity.d.ts.map +1 -1
  7. package/dist/common/helpers/define-entity.js +3 -0
  8. package/dist/common/helpers/define-entity.js.map +1 -1
  9. package/dist/common/registries/entity-descriptor.registry.d.ts +22 -0
  10. package/dist/common/registries/entity-descriptor.registry.d.ts.map +1 -0
  11. package/dist/common/registries/entity-descriptor.registry.js +51 -0
  12. package/dist/common/registries/entity-descriptor.registry.js.map +1 -0
  13. package/dist/common/registries/index.d.ts +1 -0
  14. package/dist/common/registries/index.d.ts.map +1 -1
  15. package/dist/common/registries/index.js +1 -0
  16. package/dist/common/registries/index.js.map +1 -1
  17. package/dist/core/cors/services/cors.service.d.ts +4 -1
  18. package/dist/core/cors/services/cors.service.d.ts.map +1 -1
  19. package/dist/core/cors/services/cors.service.js +19 -3
  20. package/dist/core/cors/services/cors.service.js.map +1 -1
  21. package/dist/core/neo4j/abstracts/abstract.repository.d.ts +2 -0
  22. package/dist/core/neo4j/abstracts/abstract.repository.d.ts.map +1 -1
  23. package/dist/core/neo4j/abstracts/abstract.repository.js +4 -1
  24. package/dist/core/neo4j/abstracts/abstract.repository.js.map +1 -1
  25. package/dist/core/neo4j/abstracts/abstract.service.d.ts +6 -0
  26. package/dist/core/neo4j/abstracts/abstract.service.d.ts.map +1 -1
  27. package/dist/core/neo4j/abstracts/abstract.service.js +16 -0
  28. package/dist/core/neo4j/abstracts/abstract.service.js.map +1 -1
  29. package/dist/core/neo4j/helpers/build-filter-clauses.d.ts.map +1 -1
  30. package/dist/core/neo4j/helpers/build-filter-clauses.js +8 -1
  31. package/dist/core/neo4j/helpers/build-filter-clauses.js.map +1 -1
  32. package/dist/core/offline/index.d.ts +5 -0
  33. package/dist/core/offline/index.d.ts.map +1 -0
  34. package/dist/core/offline/index.js +21 -0
  35. package/dist/core/offline/index.js.map +1 -0
  36. package/dist/core/offline/offline-request.context.d.ts +12 -0
  37. package/dist/core/offline/offline-request.context.d.ts.map +1 -0
  38. package/dist/core/offline/offline-request.context.js +34 -0
  39. package/dist/core/offline/offline-request.context.js.map +1 -0
  40. package/dist/core/offline/offline-request.interceptor.d.ts +15 -0
  41. package/dist/core/offline/offline-request.interceptor.d.ts.map +1 -0
  42. package/dist/core/offline/offline-request.interceptor.js +43 -0
  43. package/dist/core/offline/offline-request.interceptor.js.map +1 -0
  44. package/dist/core/offline/offline.constants.d.ts +12 -0
  45. package/dist/core/offline/offline.constants.d.ts.map +1 -0
  46. package/dist/core/offline/offline.constants.js +12 -0
  47. package/dist/core/offline/offline.constants.js.map +1 -0
  48. package/dist/core/offline/offline.module.d.ts +12 -0
  49. package/dist/core/offline/offline.module.d.ts.map +1 -0
  50. package/dist/core/offline/offline.module.js +42 -0
  51. package/dist/core/offline/offline.module.js.map +1 -0
  52. package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.d.ts +7 -0
  53. package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.d.ts.map +1 -0
  54. package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.js +12 -0
  55. package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.js.map +1 -0
  56. package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.d.ts +33 -0
  57. package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.d.ts.map +1 -0
  58. package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.js +133 -0
  59. package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.js.map +1 -0
  60. package/dist/foundations/offline-change-set/entities/offline-change-set.d.ts +66 -0
  61. package/dist/foundations/offline-change-set/entities/offline-change-set.d.ts.map +1 -0
  62. package/dist/foundations/offline-change-set/entities/offline-change-set.js +31 -0
  63. package/dist/foundations/offline-change-set/entities/offline-change-set.js.map +1 -0
  64. package/dist/foundations/offline-change-set/entities/offline-change-set.meta.d.ts +3 -0
  65. package/dist/foundations/offline-change-set/entities/offline-change-set.meta.d.ts.map +1 -0
  66. package/dist/foundations/offline-change-set/entities/offline-change-set.meta.js +10 -0
  67. package/dist/foundations/offline-change-set/entities/offline-change-set.meta.js.map +1 -0
  68. package/dist/foundations/offline-change-set/index.d.ts +11 -0
  69. package/dist/foundations/offline-change-set/index.d.ts.map +1 -0
  70. package/dist/foundations/offline-change-set/index.js +27 -0
  71. package/dist/foundations/offline-change-set/index.js.map +1 -0
  72. package/dist/foundations/offline-change-set/merge/deep-equal.d.ts +6 -0
  73. package/dist/foundations/offline-change-set/merge/deep-equal.d.ts.map +1 -0
  74. package/dist/foundations/offline-change-set/merge/deep-equal.js +31 -0
  75. package/dist/foundations/offline-change-set/merge/deep-equal.js.map +1 -0
  76. package/dist/foundations/offline-change-set/merge/merge-blocks.d.ts +37 -0
  77. package/dist/foundations/offline-change-set/merge/merge-blocks.d.ts.map +1 -0
  78. package/dist/foundations/offline-change-set/merge/merge-blocks.js +108 -0
  79. package/dist/foundations/offline-change-set/merge/merge-blocks.js.map +1 -0
  80. package/dist/foundations/offline-change-set/merge/three-way-merge.d.ts +57 -0
  81. package/dist/foundations/offline-change-set/merge/three-way-merge.d.ts.map +1 -0
  82. package/dist/foundations/offline-change-set/merge/three-way-merge.js +201 -0
  83. package/dist/foundations/offline-change-set/merge/three-way-merge.js.map +1 -0
  84. package/dist/foundations/offline-change-set/offline-change-set.module.d.ts +11 -0
  85. package/dist/foundations/offline-change-set/offline-change-set.module.d.ts.map +1 -0
  86. package/dist/foundations/offline-change-set/offline-change-set.module.js +41 -0
  87. package/dist/foundations/offline-change-set/offline-change-set.module.js.map +1 -0
  88. package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.d.ts +26 -0
  89. package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.d.ts.map +1 -0
  90. package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.js +56 -0
  91. package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.js.map +1 -0
  92. package/dist/foundations/offline-change-set/services/offline-change-set.service.d.ts +72 -0
  93. package/dist/foundations/offline-change-set/services/offline-change-set.service.d.ts.map +1 -0
  94. package/dist/foundations/offline-change-set/services/offline-change-set.service.js +333 -0
  95. package/dist/foundations/offline-change-set/services/offline-change-set.service.js.map +1 -0
  96. package/dist/foundations/offline-change-set/services/offline-route-runner.service.d.ts +61 -0
  97. package/dist/foundations/offline-change-set/services/offline-route-runner.service.d.ts.map +1 -0
  98. package/dist/foundations/offline-change-set/services/offline-route-runner.service.js +192 -0
  99. package/dist/foundations/offline-change-set/services/offline-route-runner.service.js.map +1 -0
  100. package/dist/index.d.ts +2 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +3 -0
  103. package/dist/index.js.map +1 -1
  104. package/package.json +1 -1
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mergeBlocks = mergeBlocks;
4
+ const deep_equal_1 = require("./deep-equal");
5
+ /**
6
+ * Block-by-block three-way merge of one rich-text field (BlockNote document).
7
+ *
8
+ * Blocks are compared by id as objects, never turned into text. Starting from the
9
+ * server's blocks (theirs):
10
+ * - a block changed only on the device takes the device's version;
11
+ * - a block removed on one side and untouched on the other is removed;
12
+ * - a block added on the device lands after the block that precedes it on the device;
13
+ * - a block changed on both sides (differently), or removed on one side and changed on
14
+ * the other, is a conflict: the merged document keeps the server's version and its
15
+ * id is listed in `conflictBlockIds`;
16
+ * - order: when only one side moved blocks, the merged document follows that side's order
17
+ * (the blocks' content still merges as above); when both sides moved blocks into different
18
+ * orders, `orderConflict` is true and the server's order is kept.
19
+ *
20
+ * With `prefer: "mine"` (the GM chose this device's version of the field) every conflict
21
+ * resolves to the device's side instead (its block, its removal, its order) and nothing is
22
+ * reported; `prefer: "theirs"` resolves them to the server's side.
23
+ */
24
+ function mergeBlocks(p) {
25
+ const base = new Map(p.base.map((b) => [b.id, b]));
26
+ const mine = new Map(p.mine.map((b) => [b.id, b]));
27
+ const theirs = new Map(p.theirs.map((b) => [b.id, b]));
28
+ const preferMine = p.prefer === "mine";
29
+ const report = p.prefer === undefined;
30
+ const merged = [...p.theirs];
31
+ const conflictBlockIds = [];
32
+ /** Device blocks missing from `merged` that the device's version brings back. */
33
+ const restore = new Set();
34
+ const indexOf = (id) => merged.findIndex((b) => b.id === id);
35
+ const conflict = (id, takeMine) => {
36
+ if (preferMine)
37
+ takeMine();
38
+ else if (report)
39
+ conflictBlockIds.push(id);
40
+ };
41
+ for (const [id, baseBlock] of base) {
42
+ const mineBlock = mine.get(id);
43
+ const theirsBlock = theirs.get(id);
44
+ const mineChanged = mineBlock !== undefined && !(0, deep_equal_1.jsonEqual)(mineBlock, baseBlock);
45
+ const theirsChanged = theirsBlock !== undefined && !(0, deep_equal_1.jsonEqual)(theirsBlock, baseBlock);
46
+ const mineRemoved = mineBlock === undefined;
47
+ const theirsRemoved = theirsBlock === undefined;
48
+ if (mineRemoved) {
49
+ if (theirsRemoved)
50
+ continue;
51
+ if (theirsChanged)
52
+ conflict(id, () => merged.splice(indexOf(id), 1));
53
+ else
54
+ merged.splice(indexOf(id), 1);
55
+ continue;
56
+ }
57
+ if (!mineChanged)
58
+ continue;
59
+ if (theirsRemoved) {
60
+ conflict(id, () => restore.add(id));
61
+ continue;
62
+ }
63
+ if (theirsChanged) {
64
+ if (!(0, deep_equal_1.jsonEqual)(mineBlock, theirsBlock))
65
+ conflict(id, () => (merged[indexOf(id)] = mineBlock));
66
+ continue;
67
+ }
68
+ merged[indexOf(id)] = mineBlock;
69
+ }
70
+ // Order of the blocks every side still holds.
71
+ const common = (list) => list.map((b) => b.id).filter((id) => base.has(id) && mine.has(id) && theirs.has(id));
72
+ const baseOrder = common(p.base);
73
+ const mineOrder = common(p.mine);
74
+ const theirsOrder = common(p.theirs);
75
+ const mineMoved = !(0, deep_equal_1.jsonEqual)(mineOrder, baseOrder);
76
+ const theirsMoved = !(0, deep_equal_1.jsonEqual)(theirsOrder, baseOrder);
77
+ const bothMovedDifferently = mineMoved && theirsMoved && !(0, deep_equal_1.jsonEqual)(mineOrder, theirsOrder);
78
+ const orderConflict = report && bothMovedDifferently;
79
+ if ((mineMoved && !theirsMoved) || (bothMovedDifferently && preferMine)) {
80
+ // The slots those blocks hold in `merged` take the device's order; every other block stays put.
81
+ const commonSet = new Set(mineOrder);
82
+ const byId = new Map(merged.map((b) => [b.id, b]));
83
+ let next = 0;
84
+ for (let index = 0; index < merged.length; index++)
85
+ if (commonSet.has(merged[index].id))
86
+ merged[index] = byId.get(mineOrder[next++]);
87
+ }
88
+ // Blocks the device added (or brings back): each lands after the block that precedes it on the device.
89
+ let previousId;
90
+ for (const mineBlock of p.mine) {
91
+ const id = mineBlock.id;
92
+ if (!base.has(id) || restore.has(id)) {
93
+ const at = indexOf(id);
94
+ if (at !== -1) {
95
+ if (!(0, deep_equal_1.jsonEqual)(merged[at], mineBlock))
96
+ conflict(id, () => (merged[at] = mineBlock));
97
+ }
98
+ else {
99
+ const insertAt = previousId === undefined ? 0 : indexOf(previousId) + 1;
100
+ merged.splice(insertAt, 0, mineBlock);
101
+ }
102
+ }
103
+ if (indexOf(id) !== -1)
104
+ previousId = id;
105
+ }
106
+ return { merged, conflictBlockIds, orderConflict };
107
+ }
108
+ //# sourceMappingURL=merge-blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-blocks.js","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/merge/merge-blocks.ts"],"names":[],"mappings":";;AA2BA,kCAwFC;AAnHD,6CAAyC;AAQzC;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,WAAW,CAAC,CAA8E;IAKxG,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;IACvC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;IAEtC,MAAM,MAAM,GAAY,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,iFAAiF;IACjF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,OAAO,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAE,QAAoB,EAAE,EAAE;QACpD,IAAI,UAAU;YAAE,QAAQ,EAAE,CAAC;aACtB,IAAI,MAAM;YAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,KAAK,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,WAAW,GAAG,SAAS,KAAK,SAAS,IAAI,CAAC,IAAA,sBAAS,EAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAChF,MAAM,aAAa,GAAG,WAAW,KAAK,SAAS,IAAI,CAAC,IAAA,sBAAS,EAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACtF,MAAM,WAAW,GAAG,SAAS,KAAK,SAAS,CAAC;QAC5C,MAAM,aAAa,GAAG,WAAW,KAAK,SAAS,CAAC;QAEhD,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,aAAa;gBAAE,SAAS;YAC5B,IAAI,aAAa;gBAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;gBAChE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACnC,SAAS;QACX,CAAC;QAED,IAAI,CAAC,WAAW;YAAE,SAAS;QAE3B,IAAI,aAAa,EAAE,CAAC;YAClB,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,SAAS;QACX,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,CAAC,IAAA,sBAAS,EAAC,SAAS,EAAE,WAAW,CAAC;gBAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;YAC9F,SAAS;QACX,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC;IAClC,CAAC;IAED,8CAA8C;IAC9C,MAAM,MAAM,GAAG,CAAC,IAAa,EAAE,EAAE,CAC/B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACvF,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,CAAC,IAAA,sBAAS,EAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,CAAC,IAAA,sBAAS,EAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACvD,MAAM,oBAAoB,GAAG,SAAS,IAAI,WAAW,IAAI,CAAC,IAAA,sBAAS,EAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC5F,MAAM,aAAa,GAAG,MAAM,IAAI,oBAAoB,CAAC;IAErD,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,oBAAoB,IAAI,UAAU,CAAC,EAAE,CAAC;QACxE,gGAAgG;QAChG,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE;YAChD,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBAAE,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAE,CAAC;IACtF,CAAC;IAED,uGAAuG;IACvG,IAAI,UAA8B,CAAC;IACnC,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;YACvB,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;gBACd,IAAI,CAAC,IAAA,sBAAS,EAAC,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC;oBAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;YACtF,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBACxE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YAAE,UAAU,GAAG,EAAE,CAAC;IAC1C,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,CAAC;AACrD,CAAC"}
@@ -0,0 +1,57 @@
1
+ /** A JSON:API resource object as the wire carries it (only attributes and relationships are read). */
2
+ export type Resource = {
3
+ type?: string;
4
+ id?: string;
5
+ attributes?: Record<string, unknown>;
6
+ relationships?: Record<string, unknown>;
7
+ [key: string]: unknown;
8
+ };
9
+ /** Whose value a conflicting field takes once the GM has chosen. */
10
+ export type FieldChoice = "mine" | "theirs" | "merged";
11
+ /** The GM's answer to an earlier conflict on this record. */
12
+ export type MergeResolution = {
13
+ /** Per conflicting field (attribute or relationship name). */
14
+ choices?: Record<string, FieldChoice>;
15
+ /** The choice of every conflicting field `choices` does not name ("Keep mine" = "mine"). */
16
+ all?: FieldChoice;
17
+ /** The resource holding the hand-merged values of the fields chosen "merged". */
18
+ merged?: Resource;
19
+ };
20
+ export type ThreeWayMergeResult = {
21
+ /** Every attribute of the server's record, with what the merge settled in place. */
22
+ attributes: Record<string, unknown>;
23
+ /** Every relationship the device sent, with the merged linkage (and edge props in `meta`). */
24
+ relationships: Record<string, unknown>;
25
+ /** Attribute and relationship names the save must write (never one only the server changed). */
26
+ changed: string[];
27
+ /** Attribute and relationship names both sides changed differently (and no choice settles). */
28
+ conflictFields: string[];
29
+ /** Rich-text field → conflicting block ids. */
30
+ conflictBlocks: Record<string, string[]>;
31
+ };
32
+ /**
33
+ * Three-way merge of one record: base (the record at the last sync), mine (the document the
34
+ * device's model built) and theirs (the record on the server now). Only fields the device
35
+ * sent are considered; a field only the server changed is kept and never written.
36
+ *
37
+ * - Only one side changed a field → that side.
38
+ * - Both changed a plain field to different values → conflict.
39
+ * - Both changed a rich-text field → block-by-block merge (`mergeBlocks`, block order included).
40
+ * - Relationships never conflict: ids added or removed on only one side are applied; edge
41
+ * props (`meta`) changed on only one side are applied; when both sides changed the same
42
+ * link's props, the device's win (the GM's later edit).
43
+ * - A relationship missing from theirs (or base) is empty when it is one of
44
+ * `knownRelationships` (the server always answers those, and omits an empty one);
45
+ * otherwise it is unknown and treated as unchanged.
46
+ * - `resolution` settles conflicts with the GM's choices: "mine" → the device's value,
47
+ * "theirs" → the server's (not written), "merged" → the value in `resolution.merged`.
48
+ */
49
+ export declare function threeWayMerge(p: {
50
+ base: Resource;
51
+ mine: Resource;
52
+ theirs: Resource;
53
+ richTextFields: string[];
54
+ knownRelationships?: string[];
55
+ resolution?: MergeResolution;
56
+ }): ThreeWayMergeResult;
57
+ //# sourceMappingURL=three-way-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"three-way-merge.d.ts","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/merge/three-way-merge.ts"],"names":[],"mappings":"AAGA,sGAAsG;AACtG,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AASF,oEAAoE;AACpE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvD,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,4FAA4F;IAC5F,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,iFAAiF;IACjF,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,8FAA8F;IAC9F,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,gGAAgG;IAChG,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+FAA+F;IAC/F,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC1C,CAAC;AAwCF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B,GAAG,mBAAmB,CA6ItB"}
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.threeWayMerge = threeWayMerge;
4
+ const deep_equal_1 = require("./deep-equal");
5
+ const merge_blocks_1 = require("./merge-blocks");
6
+ /** Rich text travels as the JSON string the model wrote. `undefined` when it is not a block array. */
7
+ function parseBlocks(value) {
8
+ if (value === undefined || value === null || value === "")
9
+ return [];
10
+ if (Array.isArray(value))
11
+ return value;
12
+ if (typeof value !== "string")
13
+ return undefined;
14
+ try {
15
+ const parsed = JSON.parse(value);
16
+ return Array.isArray(parsed) ? parsed : undefined;
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ function linkage(rel) {
23
+ if (!rel || typeof rel !== "object" || !("data" in rel))
24
+ return undefined;
25
+ return rel.data ?? null;
26
+ }
27
+ const idsOf = (data) => data == null ? [] : Array.isArray(data) ? data.map((d) => d.id) : [data.id];
28
+ const isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
29
+ /**
30
+ * The edge props a side holds for one linked id: the identifier's `meta`, or (to-one) the
31
+ * relationship's `meta`. `undefined` when that side says nothing about them.
32
+ */
33
+ function propsOf(rel, id) {
34
+ const data = linkage(rel);
35
+ if (data == null)
36
+ return undefined;
37
+ const item = (Array.isArray(data) ? data : [data]).find((d) => d.id === id);
38
+ if (!item)
39
+ return undefined;
40
+ if (isObject(item.meta))
41
+ return item.meta;
42
+ if (!Array.isArray(data) && isObject(rel.meta))
43
+ return rel.meta;
44
+ return undefined;
45
+ }
46
+ /**
47
+ * Three-way merge of one record: base (the record at the last sync), mine (the document the
48
+ * device's model built) and theirs (the record on the server now). Only fields the device
49
+ * sent are considered; a field only the server changed is kept and never written.
50
+ *
51
+ * - Only one side changed a field → that side.
52
+ * - Both changed a plain field to different values → conflict.
53
+ * - Both changed a rich-text field → block-by-block merge (`mergeBlocks`, block order included).
54
+ * - Relationships never conflict: ids added or removed on only one side are applied; edge
55
+ * props (`meta`) changed on only one side are applied; when both sides changed the same
56
+ * link's props, the device's win (the GM's later edit).
57
+ * - A relationship missing from theirs (or base) is empty when it is one of
58
+ * `knownRelationships` (the server always answers those, and omits an empty one);
59
+ * otherwise it is unknown and treated as unchanged.
60
+ * - `resolution` settles conflicts with the GM's choices: "mine" → the device's value,
61
+ * "theirs" → the server's (not written), "merged" → the value in `resolution.merged`.
62
+ */
63
+ function threeWayMerge(p) {
64
+ const base = p.base?.attributes ?? {};
65
+ const mine = p.mine?.attributes ?? {};
66
+ const theirs = p.theirs?.attributes ?? {};
67
+ const choiceOf = (name) => p.resolution ? (p.resolution.choices?.[name] ?? p.resolution.all) : undefined;
68
+ const mergedAttributes = p.resolution?.merged?.attributes ?? {};
69
+ const attributes = { ...theirs };
70
+ const changed = [];
71
+ const conflictFields = [];
72
+ const conflictBlocks = {};
73
+ /** Writes `value` when it differs from the server's. */
74
+ const settle = (field, value, differs) => {
75
+ attributes[field] = value;
76
+ if (differs)
77
+ changed.push(field);
78
+ };
79
+ for (const field of Object.keys(mine)) {
80
+ const b = base[field];
81
+ const m = mine[field];
82
+ const t = theirs[field];
83
+ const isRichText = p.richTextFields.includes(field);
84
+ const blocks = isRichText ? { b: parseBlocks(b), m: parseBlocks(m), t: parseBlocks(t) } : undefined;
85
+ const asBlocks = blocks && blocks.b && blocks.m && blocks.t ? blocks : undefined;
86
+ const same = (x, y, bx, by) => asBlocks ? (0, deep_equal_1.jsonEqual)(bx, by) : (0, deep_equal_1.jsonEqual)(x, y);
87
+ if (same(m, b, asBlocks?.m, asBlocks?.b))
88
+ continue;
89
+ if (same(t, b, asBlocks?.t, asBlocks?.b)) {
90
+ settle(field, m, true);
91
+ continue;
92
+ }
93
+ if (same(m, t, asBlocks?.m, asBlocks?.t))
94
+ continue;
95
+ const choice = choiceOf(field);
96
+ if (asBlocks) {
97
+ const result = (0, merge_blocks_1.mergeBlocks)({ base: asBlocks.b, mine: asBlocks.m, theirs: asBlocks.t });
98
+ const conflicting = result.conflictBlockIds.length > 0 || result.orderConflict;
99
+ if (!conflicting) {
100
+ settle(field, JSON.stringify(result.merged), !(0, deep_equal_1.jsonEqual)(result.merged, asBlocks.t));
101
+ continue;
102
+ }
103
+ if (choice === "mine" || choice === "theirs") {
104
+ const chosen = (0, merge_blocks_1.mergeBlocks)({ base: asBlocks.b, mine: asBlocks.m, theirs: asBlocks.t, prefer: choice });
105
+ settle(field, JSON.stringify(chosen.merged), !(0, deep_equal_1.jsonEqual)(chosen.merged, asBlocks.t));
106
+ continue;
107
+ }
108
+ if (choice === "merged" && field in mergedAttributes) {
109
+ const value = mergedAttributes[field];
110
+ settle(field, value, !(0, deep_equal_1.jsonEqual)(parseBlocks(value) ?? value, asBlocks.t));
111
+ continue;
112
+ }
113
+ attributes[field] = JSON.stringify(result.merged);
114
+ conflictFields.push(field);
115
+ // A conflicting order is a whole-field choice: no block list for it.
116
+ if (!result.orderConflict)
117
+ conflictBlocks[field] = result.conflictBlockIds;
118
+ continue;
119
+ }
120
+ if (choice === "mine")
121
+ settle(field, m, true);
122
+ else if (choice === "theirs")
123
+ continue;
124
+ else if (choice === "merged" && field in mergedAttributes)
125
+ settle(field, mergedAttributes[field], !(0, deep_equal_1.jsonEqual)(mergedAttributes[field], t));
126
+ else
127
+ conflictFields.push(field);
128
+ }
129
+ const relationships = {};
130
+ const baseRels = p.base?.relationships ?? {};
131
+ const theirsRels = p.theirs?.relationships ?? {};
132
+ const known = new Set(p.knownRelationships ?? []);
133
+ for (const [name, mineRel] of Object.entries(p.mine?.relationships ?? {})) {
134
+ const mineData = linkage(mineRel);
135
+ if (mineData === undefined)
136
+ continue;
137
+ const empty = Array.isArray(mineData) ? [] : null;
138
+ const theirsRel = theirsRels[name] ?? (known.has(name) ? { data: empty } : undefined);
139
+ const baseRel = baseRels[name] ?? (known.has(name) ? { data: empty } : undefined);
140
+ const theirsData = linkage(theirsRel);
141
+ const theirsKnown = theirsData !== undefined;
142
+ const baseData = linkage(baseRel);
143
+ const baseIds = baseData === undefined ? (theirsKnown ? idsOf(theirsData) : []) : idsOf(baseData);
144
+ const theirsIds = theirsKnown ? idsOf(theirsData) : baseIds;
145
+ const identifiers = new Map();
146
+ for (const d of [theirsData, mineData]) {
147
+ if (d == null)
148
+ continue;
149
+ for (const item of Array.isArray(d) ? d : [d])
150
+ identifiers.set(item.id, item);
151
+ }
152
+ let resultIds;
153
+ if (Array.isArray(mineData)) {
154
+ const mineIds = mineData.map((d) => d.id);
155
+ const added = mineIds.filter((id) => !baseIds.includes(id));
156
+ const removed = baseIds.filter((id) => !mineIds.includes(id));
157
+ resultIds = [...theirsIds.filter((id) => !removed.includes(id))];
158
+ for (const id of added)
159
+ if (!resultIds.includes(id))
160
+ resultIds.push(id);
161
+ }
162
+ else {
163
+ const mineId = mineData?.id ?? null;
164
+ const baseId = baseIds[0] ?? null;
165
+ const theirsId = theirsIds[0] ?? null;
166
+ const resultId = mineId === baseId ? theirsId : mineId;
167
+ resultIds = resultId === null ? [] : [resultId];
168
+ }
169
+ // Edge props of every link the result keeps.
170
+ let linkChanged = !(0, deep_equal_1.jsonEqual)([...resultIds].sort(), [...theirsIds].sort());
171
+ const finalProps = new Map();
172
+ for (const id of resultIds) {
173
+ const bp = baseIds.includes(id) ? propsOf(baseRel, id) : undefined;
174
+ const mp = propsOf(mineRel, id);
175
+ const tp = theirsIds.includes(id) ? propsOf(theirsRel, id) : undefined;
176
+ const mineChanged = mp !== undefined && !(0, deep_equal_1.jsonEqual)(mp, bp);
177
+ // The device's props when it changed them (also when the server changed them too), else the server's.
178
+ const props = mineChanged ? mp : (tp ?? mp);
179
+ finalProps.set(id, props);
180
+ if (theirsIds.includes(id) && props !== undefined && !(0, deep_equal_1.jsonEqual)(props, tp))
181
+ linkChanged = true;
182
+ }
183
+ const identifierOf = (id) => {
184
+ const { meta: _meta, ...identifier } = identifiers.get(id) ?? { id };
185
+ const props = finalProps.get(id);
186
+ return props === undefined ? identifier : { ...identifier, id, meta: props };
187
+ };
188
+ if (Array.isArray(mineData)) {
189
+ relationships[name] = { ...mineRel, data: resultIds.map(identifierOf) };
190
+ }
191
+ else {
192
+ const { meta: _relMeta, ...rest } = mineRel;
193
+ const data = resultIds.length === 0 ? null : identifierOf(resultIds[0]);
194
+ relationships[name] = data?.meta ? { ...rest, data, meta: data.meta } : { ...rest, data };
195
+ }
196
+ if (linkChanged)
197
+ changed.push(name);
198
+ }
199
+ return { attributes, relationships, changed, conflictFields, conflictBlocks };
200
+ }
201
+ //# sourceMappingURL=three-way-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"three-way-merge.js","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/merge/three-way-merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { OnModuleInit } from "@nestjs/common";
2
+ /**
3
+ * Offline change sets: opens a package of every change a device queued while offline and runs
4
+ * each one through the app's own routes. Loaded by `OfflineModule` when
5
+ * `bootstrap({ offline: { changeSets: true } })`. Declares no controller: the receiving route
6
+ * (`POST /offline-change-sets`) belongs to the app, which calls `OfflineChangeSetService.apply`.
7
+ */
8
+ export declare class OfflineChangeSetModule implements OnModuleInit {
9
+ onModuleInit(): void;
10
+ }
11
+ //# sourceMappingURL=offline-change-set.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline-change-set.module.d.ts","sourceRoot":"","sources":["../../../src/foundations/offline-change-set/offline-change-set.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQtD;;;;;GAKG;AACH,qBAUa,sBAAuB,YAAW,YAAY;IACzD,YAAY;CAGb"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.OfflineChangeSetModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const core_1 = require("@nestjs/core");
12
+ const registry_1 = require("../../common/registries/registry");
13
+ const offline_change_set_1 = require("./entities/offline-change-set");
14
+ const offline_change_set_repository_1 = require("./repositories/offline-change-set.repository");
15
+ const offline_change_set_service_1 = require("./services/offline-change-set.service");
16
+ const offline_route_runner_service_1 = require("./services/offline-route-runner.service");
17
+ /**
18
+ * Offline change sets: opens a package of every change a device queued while offline and runs
19
+ * each one through the app's own routes. Loaded by `OfflineModule` when
20
+ * `bootstrap({ offline: { changeSets: true } })`. Declares no controller: the receiving route
21
+ * (`POST /offline-change-sets`) belongs to the app, which calls `OfflineChangeSetService.apply`.
22
+ */
23
+ let OfflineChangeSetModule = class OfflineChangeSetModule {
24
+ onModuleInit() {
25
+ registry_1.modelRegistry.register(offline_change_set_1.OfflineChangeSetDescriptor.model);
26
+ }
27
+ };
28
+ exports.OfflineChangeSetModule = OfflineChangeSetModule;
29
+ exports.OfflineChangeSetModule = OfflineChangeSetModule = __decorate([
30
+ (0, common_1.Module)({
31
+ imports: [core_1.DiscoveryModule],
32
+ providers: [
33
+ offline_change_set_1.OfflineChangeSetDescriptor.model.serialiser,
34
+ offline_change_set_repository_1.OfflineChangeSetRepository,
35
+ offline_change_set_service_1.OfflineChangeSetService,
36
+ offline_route_runner_service_1.OfflineRouteRunner,
37
+ ],
38
+ exports: [offline_change_set_service_1.OfflineChangeSetService],
39
+ })
40
+ ], OfflineChangeSetModule);
41
+ //# sourceMappingURL=offline-change-set.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline-change-set.module.js","sourceRoot":"","sources":["../../../src/foundations/offline-change-set/offline-change-set.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAsD;AACtD,uCAA+C;AAC/C,+DAAiE;AACjE,sEAA2E;AAC3E,gGAA0F;AAC1F,sFAAgF;AAChF,0FAA6E;AAE7E;;;;;GAKG;AAWI,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACjC,YAAY;QACV,wBAAa,CAAC,QAAQ,CAAC,+CAA0B,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;CACF,CAAA;AAJY,wDAAsB;iCAAtB,sBAAsB;IAVlC,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,sBAAe,CAAC;QAC1B,SAAS,EAAE;YACT,+CAA0B,CAAC,KAAK,CAAC,UAAU;YAC3C,0DAA0B;YAC1B,oDAAuB;YACvB,iDAAkB;SACnB;QACD,OAAO,EAAE,CAAC,oDAAuB,CAAC;KACnC,CAAC;GACW,sBAAsB,CAIlC"}
@@ -0,0 +1,26 @@
1
+ import { ClsService } from "nestjs-cls";
2
+ import { AbstractRepository } from "../../../core/neo4j/abstracts/abstract.repository";
3
+ import { Neo4jService } from "../../../core/neo4j/services/neo4j.service";
4
+ import { SecurityService } from "../../../core/security/services/security.service";
5
+ import { OfflineChangeSet, OfflineChangeSetDescriptor } from "../entities/offline-change-set";
6
+ /**
7
+ * Repository of the stored offline change sets (one `OfflineChangeSet` node of the caller's
8
+ * company per package opened, holding its results). The service uses the inherited,
9
+ * company-scoped `findById` (a package sent again) and `create` (a package just opened), and
10
+ * `deleteOlderThan` (clean-up of old ones); every read and write of a change itself runs
11
+ * through the app's own routes (`OfflineRouteRunner`).
12
+ * The inherited `onModuleInit` creates the id constraint.
13
+ */
14
+ export declare class OfflineChangeSetRepository extends AbstractRepository<OfflineChangeSet, typeof OfflineChangeSetDescriptor.relationships> {
15
+ protected readonly descriptor: import("../../..").EntityDescriptor<OfflineChangeSet, {}>;
16
+ constructor(neo4j: Neo4jService, securityService: SecurityService, clsService: ClsService);
17
+ /**
18
+ * Deletes the request company's stored change sets created before `before`. Without a company
19
+ * in the request it deletes nothing: `buildDefaultMatch()` matches every company's nodes when
20
+ * `$companyId` is null.
21
+ */
22
+ deleteOlderThan(params: {
23
+ before: Date;
24
+ }): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=offline-change-set.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline-change-set.repository.d.ts","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/repositories/offline-change-set.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,kDAAkD,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAE9F;;;;;;;GAOG;AACH,qBACa,0BAA2B,SAAQ,kBAAkB,CAChE,gBAAgB,EAChB,OAAO,0BAA0B,CAAC,aAAa,CAChD;IACC,SAAS,CAAC,QAAQ,CAAC,UAAU,4DAA8B;gBAE/C,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU;IAIzF;;;;OAIG;IACG,eAAe,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAe/D"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.OfflineChangeSetRepository = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const nestjs_cls_1 = require("nestjs-cls");
15
+ const abstract_repository_1 = require("../../../core/neo4j/abstracts/abstract.repository");
16
+ const neo4j_service_1 = require("../../../core/neo4j/services/neo4j.service");
17
+ const security_service_1 = require("../../../core/security/services/security.service");
18
+ const offline_change_set_1 = require("../entities/offline-change-set");
19
+ /**
20
+ * Repository of the stored offline change sets (one `OfflineChangeSet` node of the caller's
21
+ * company per package opened, holding its results). The service uses the inherited,
22
+ * company-scoped `findById` (a package sent again) and `create` (a package just opened), and
23
+ * `deleteOlderThan` (clean-up of old ones); every read and write of a change itself runs
24
+ * through the app's own routes (`OfflineRouteRunner`).
25
+ * The inherited `onModuleInit` creates the id constraint.
26
+ */
27
+ let OfflineChangeSetRepository = class OfflineChangeSetRepository extends abstract_repository_1.AbstractRepository {
28
+ constructor(neo4j, securityService, clsService) {
29
+ super(neo4j, securityService, clsService);
30
+ this.descriptor = offline_change_set_1.OfflineChangeSetDescriptor;
31
+ }
32
+ /**
33
+ * Deletes the request company's stored change sets created before `before`. Without a company
34
+ * in the request it deletes nothing: `buildDefaultMatch()` matches every company's nodes when
35
+ * `$companyId` is null.
36
+ */
37
+ async deleteOlderThan(params) {
38
+ const { nodeName } = this.descriptor.model;
39
+ const query = this.neo4j.initQuery({ serialiser: this.descriptor.model });
40
+ if (!query.queryParams.companyId)
41
+ return;
42
+ query.queryParams = { ...query.queryParams, before: params.before.toISOString() };
43
+ query.query += `
44
+ ${this.buildDefaultMatch()}
45
+ WHERE ${nodeName}.createdAt < datetime($before)
46
+ DETACH DELETE ${nodeName}
47
+ `;
48
+ await this.neo4j.writeOne(query);
49
+ }
50
+ };
51
+ exports.OfflineChangeSetRepository = OfflineChangeSetRepository;
52
+ exports.OfflineChangeSetRepository = OfflineChangeSetRepository = __decorate([
53
+ (0, common_1.Injectable)(),
54
+ __metadata("design:paramtypes", [neo4j_service_1.Neo4jService, security_service_1.SecurityService, nestjs_cls_1.ClsService])
55
+ ], OfflineChangeSetRepository);
56
+ //# sourceMappingURL=offline-change-set.repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline-change-set.repository.js","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/repositories/offline-change-set.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,2CAAwC;AACxC,2FAAuF;AACvF,8EAA0E;AAC1E,uFAAmF;AACnF,uEAA8F;AAE9F;;;;;;;GAOG;AAEI,IAAM,0BAA0B,GAAhC,MAAM,0BAA2B,SAAQ,wCAG/C;IAGC,YAAY,KAAmB,EAAE,eAAgC,EAAE,UAAsB;QACvF,KAAK,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;QAHzB,eAAU,GAAG,+CAA0B,CAAC;IAI3D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,eAAe,CAAC,MAAwB;QAC5C,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS;YAAE,OAAO;QAEzC,KAAK,CAAC,WAAW,GAAG,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAElF,KAAK,CAAC,KAAK,IAAI;QACX,IAAI,CAAC,iBAAiB,EAAE;cAClB,QAAQ;sBACA,QAAQ;KACzB,CAAC;QAEF,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;CACF,CAAA;AA9BY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,mBAAU,GAAE;qCAOQ,4BAAY,EAAmB,kCAAe,EAAc,uBAAU;GAN9E,0BAA0B,CA8BtC"}
@@ -0,0 +1,72 @@
1
+ import type { FastifyRequest } from "fastify";
2
+ import { ClsService } from "nestjs-cls";
3
+ import { JsonApiSingleDocument } from "../../../core/jsonapi/interfaces/jsonapi.document.interface";
4
+ import { JsonApiService } from "../../../core/jsonapi/services/jsonapi.service";
5
+ import { AbstractService, JsonApiDTOData } from "../../../core/neo4j/abstracts/abstract.service";
6
+ import { OfflineChangeSet, OfflineChangeSetDescriptor } from "../entities/offline-change-set";
7
+ import { OfflineChangeSetRepository } from "../repositories/offline-change-set.repository";
8
+ import { OfflineRouteRunner } from "./offline-route-runner.service";
9
+ /**
10
+ * Opens one offline change set (every change the device queued, in one request) and handles
11
+ * each change in `seq` order through the app's own routes, as the caller (`OfflineRouteRunner`).
12
+ *
13
+ * - POST, and any write that names no record, runs as sent.
14
+ * - PUT/PATCH of a record: the current record is read (GET on the record's own path,
15
+ * `<endpoint>/<id>`) and merged with `base` and the device's document (`threeWayMerge`);
16
+ * only the changed fields are written, as a PATCH of the device's document trimmed to them
17
+ * (merged rich text in place). A change carrying `resolution` merges the same way, and each
18
+ * conflicting field takes the GM's choice.
19
+ * - DELETE of a record: refused as "changed on the server" when a descriptor field or a
20
+ * linked id changed since `base`; with `resolution` (delete anyway) it runs without that check.
21
+ * - After a conflict or a could-not-apply, later changes to the same record wait (a custom
22
+ * write `<endpoint>/<id>/...` counts as a change of that record).
23
+ * - A package is opened once: its results are stored under its id (company-scoped) and a
24
+ * package sent again with the same id is answered with them, without running anything.
25
+ *
26
+ * The package is never paged, batched or capped.
27
+ */
28
+ export declare class OfflineChangeSetService extends AbstractService<OfflineChangeSet, typeof OfflineChangeSetDescriptor.relationships> {
29
+ private readonly offlineChangeSetRepository;
30
+ private readonly runner;
31
+ protected readonly descriptor: import("../../..").EntityDescriptor<OfflineChangeSet, {}>;
32
+ private readonly logger;
33
+ constructor(jsonApiService: JsonApiService, offlineChangeSetRepository: OfflineChangeSetRepository, clsService: ClsService, runner: OfflineRouteRunner);
34
+ apply(params: {
35
+ data: JsonApiDTOData;
36
+ request: FastifyRequest;
37
+ }): Promise<JsonApiSingleDocument>;
38
+ /**
39
+ * Removes the company's stored change sets older than `STORED_CHANGE_SET_DAYS`: a device sends a
40
+ * package again only right after a failed answer, never days later. A failed clean-up is
41
+ * logged and never stops the package.
42
+ */
43
+ private removeExpired;
44
+ /** The JSON:API type answering on an endpoint (the type is the endpoint unless a descriptor says otherwise). */
45
+ private typeOfEndpoint;
46
+ /** The record's own path: `<its type's endpoint>/<id>`. */
47
+ private recordPath;
48
+ /** The record a change touches: its record fields, the resource a create posts, or the `<endpoint>/<id>` its path targets. */
49
+ private recordKey;
50
+ private applyChange;
51
+ private runAsSent;
52
+ private toResult;
53
+ private readCurrent;
54
+ /**
55
+ * Relationship names the record's GET always answers when it has a link (the serialiser
56
+ * emits every descriptor relationship and omits only an empty one), so an omitted one is empty.
57
+ */
58
+ private knownRelationships;
59
+ private mergeResolution;
60
+ private applyEdit;
61
+ private applyDelete;
62
+ /**
63
+ * The attributes a change could have touched: the descriptor's fields that go on the wire as
64
+ * stored (no transform, such as a signed URL; not meta; not excluded), minus createdAt/updatedAt
65
+ * and the fields only the server writes (`SERVER_WRITTEN_ATTRIBUTES`, `immutable` fields).
66
+ * `undefined` for an unknown type (every attribute base holds is compared, minus those names).
67
+ */
68
+ private comparableAttributes;
69
+ /** A descriptor field or a linked id of the record differs from `base`. */
70
+ private changedSince;
71
+ }
72
+ //# sourceMappingURL=offline-change-set.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline-change-set.service.d.ts","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/services/offline-change-set.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6DAA6D,CAAC;AACpG,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AACjG,OAAO,EAGL,gBAAgB,EAChB,0BAA0B,EAC3B,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+CAA+C,CAAC;AAC3F,OAAO,EAAsB,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AA+CxF;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,uBAAwB,SAAQ,eAAe,CAC1D,gBAAgB,EAChB,OAAO,0BAA0B,CAAC,aAAa,CAChD;IAMG,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAE3C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,SAAS,CAAC,QAAQ,CAAC,UAAU,4DAA8B;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAGjE,cAAc,EAAE,cAAc,EACb,0BAA0B,EAAE,0BAA0B,EACvE,UAAU,EAAE,UAAU,EACL,MAAM,EAAE,kBAAkB;IAKvC,KAAK,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA2CtG;;;;OAIG;YACW,aAAa;IAS3B,gHAAgH;IAChH,OAAO,CAAC,cAAc;IAItB,2DAA2D;IAC3D,OAAO,CAAC,UAAU;IAMlB,8HAA8H;IAC9H,OAAO,CAAC,SAAS;YAUH,WAAW;YAOX,SAAS;IAKvB,OAAO,CAAC,QAAQ;YASF,WAAW;IAUzB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,eAAe;YAWT,SAAS;YAqDT,WAAW;IAgBzB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAkB5B,2EAA2E;IAC3E,OAAO,CAAC,YAAY;CAgBrB"}