@hydranium/glsp-server 1.0.0-next.10

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 (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/lib/browser/index.d.ts +10 -0
  4. package/lib/browser/index.d.ts.map +1 -0
  5. package/lib/browser/index.js +15 -0
  6. package/lib/browser/index.js.map +1 -0
  7. package/lib/browser/start-glsp-server-in-worker.d.ts +121 -0
  8. package/lib/browser/start-glsp-server-in-worker.d.ts.map +1 -0
  9. package/lib/browser/start-glsp-server-in-worker.js +102 -0
  10. package/lib/browser/start-glsp-server-in-worker.js.map +1 -0
  11. package/lib/command/hydranium-glsp-recording-command.d.ts +132 -0
  12. package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -0
  13. package/lib/command/hydranium-glsp-recording-command.js +159 -0
  14. package/lib/command/hydranium-glsp-recording-command.js.map +1 -0
  15. package/lib/command/index.d.ts +10 -0
  16. package/lib/command/index.d.ts.map +1 -0
  17. package/lib/command/index.js +10 -0
  18. package/lib/command/index.js.map +1 -0
  19. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts +61 -0
  20. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts.map +1 -0
  21. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js +93 -0
  22. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js.map +1 -0
  23. package/lib/computed-bounds/index.d.ts +10 -0
  24. package/lib/computed-bounds/index.d.ts.map +1 -0
  25. package/lib/computed-bounds/index.js +10 -0
  26. package/lib/computed-bounds/index.js.map +1 -0
  27. package/lib/dispatcher/index.d.ts +10 -0
  28. package/lib/dispatcher/index.d.ts.map +1 -0
  29. package/lib/dispatcher/index.js +10 -0
  30. package/lib/dispatcher/index.js.map +1 -0
  31. package/lib/dispatcher/server-action-dispatcher.d.ts +52 -0
  32. package/lib/dispatcher/server-action-dispatcher.d.ts.map +1 -0
  33. package/lib/dispatcher/server-action-dispatcher.js +79 -0
  34. package/lib/dispatcher/server-action-dispatcher.js.map +1 -0
  35. package/lib/index.d.ts +19 -0
  36. package/lib/index.d.ts.map +1 -0
  37. package/lib/index.js +20 -0
  38. package/lib/index.js.map +1 -0
  39. package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts +75 -0
  40. package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts.map +1 -0
  41. package/lib/launcher/abstract-hydranium-glsp-diagram-module.js +100 -0
  42. package/lib/launcher/abstract-hydranium-glsp-diagram-module.js.map +1 -0
  43. package/lib/launcher/glsp-app-module.d.ts +87 -0
  44. package/lib/launcher/glsp-app-module.d.ts.map +1 -0
  45. package/lib/launcher/glsp-app-module.js +71 -0
  46. package/lib/launcher/glsp-app-module.js.map +1 -0
  47. package/lib/launcher/glsp-framework-overrides.d.ts +32 -0
  48. package/lib/launcher/glsp-framework-overrides.d.ts.map +1 -0
  49. package/lib/launcher/glsp-framework-overrides.js +49 -0
  50. package/lib/launcher/glsp-framework-overrides.js.map +1 -0
  51. package/lib/launcher/glsp-server-overrides.d.ts +39 -0
  52. package/lib/launcher/glsp-server-overrides.d.ts.map +1 -0
  53. package/lib/launcher/glsp-server-overrides.js +45 -0
  54. package/lib/launcher/glsp-server-overrides.js.map +1 -0
  55. package/lib/launcher/hydranium-glsp-server.d.ts +62 -0
  56. package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -0
  57. package/lib/launcher/hydranium-glsp-server.js +101 -0
  58. package/lib/launcher/hydranium-glsp-server.js.map +1 -0
  59. package/lib/launcher/index.d.ts +12 -0
  60. package/lib/launcher/index.d.ts.map +1 -0
  61. package/lib/launcher/index.js +22 -0
  62. package/lib/launcher/index.js.map +1 -0
  63. package/lib/logging/glsp-client-logger.d.ts +110 -0
  64. package/lib/logging/glsp-client-logger.d.ts.map +1 -0
  65. package/lib/logging/glsp-client-logger.js +151 -0
  66. package/lib/logging/glsp-client-logger.js.map +1 -0
  67. package/lib/logging/index.d.ts +10 -0
  68. package/lib/logging/index.d.ts.map +1 -0
  69. package/lib/logging/index.js +10 -0
  70. package/lib/logging/index.js.map +1 -0
  71. package/lib/node/index.d.ts +10 -0
  72. package/lib/node/index.d.ts.map +1 -0
  73. package/lib/node/index.js +13 -0
  74. package/lib/node/index.js.map +1 -0
  75. package/lib/node/start-glsp-server.d.ts +122 -0
  76. package/lib/node/start-glsp-server.d.ts.map +1 -0
  77. package/lib/node/start-glsp-server.js +103 -0
  78. package/lib/node/start-glsp-server.js.map +1 -0
  79. package/lib/state/abstract-hydranium-glsp-state.d.ts +333 -0
  80. package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -0
  81. package/lib/state/abstract-hydranium-glsp-state.js +451 -0
  82. package/lib/state/abstract-hydranium-glsp-state.js.map +1 -0
  83. package/lib/state/full-text-hydranium-glsp-state.d.ts +43 -0
  84. package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -0
  85. package/lib/state/full-text-hydranium-glsp-state.js +60 -0
  86. package/lib/state/full-text-hydranium-glsp-state.js.map +1 -0
  87. package/lib/state/hydranium-glsp-index.d.ts +220 -0
  88. package/lib/state/hydranium-glsp-index.d.ts.map +1 -0
  89. package/lib/state/hydranium-glsp-index.js +320 -0
  90. package/lib/state/hydranium-glsp-index.js.map +1 -0
  91. package/lib/state/hydranium-shared-core-services.d.ts +90 -0
  92. package/lib/state/hydranium-shared-core-services.d.ts.map +1 -0
  93. package/lib/state/hydranium-shared-core-services.js +89 -0
  94. package/lib/state/hydranium-shared-core-services.js.map +1 -0
  95. package/lib/state/index.d.ts +17 -0
  96. package/lib/state/index.d.ts.map +1 -0
  97. package/lib/state/index.js +17 -0
  98. package/lib/state/index.js.map +1 -0
  99. package/lib/state/model-ready-timeout-error.d.ts +28 -0
  100. package/lib/state/model-ready-timeout-error.d.ts.map +1 -0
  101. package/lib/state/model-ready-timeout-error.js +36 -0
  102. package/lib/state/model-ready-timeout-error.js.map +1 -0
  103. package/lib/state/reconcile-source-model-write.d.ts +43 -0
  104. package/lib/state/reconcile-source-model-write.d.ts.map +1 -0
  105. package/lib/state/reconcile-source-model-write.js +47 -0
  106. package/lib/state/reconcile-source-model-write.js.map +1 -0
  107. package/lib/state/reconciling-multi-document-glsp-state.d.ts +164 -0
  108. package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -0
  109. package/lib/state/reconciling-multi-document-glsp-state.js +222 -0
  110. package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -0
  111. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +91 -0
  112. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -0
  113. package/lib/state/reconciling-transfer-hydranium-glsp-state.js +129 -0
  114. package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -0
  115. package/lib/storage/hydranium-glsp-storage.d.ts +348 -0
  116. package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -0
  117. package/lib/storage/hydranium-glsp-storage.js +634 -0
  118. package/lib/storage/hydranium-glsp-storage.js.map +1 -0
  119. package/lib/storage/index.d.ts +11 -0
  120. package/lib/storage/index.d.ts.map +1 -0
  121. package/lib/storage/index.js +11 -0
  122. package/lib/storage/index.js.map +1 -0
  123. package/lib/storage/save-conflict-policy.d.ts +56 -0
  124. package/lib/storage/save-conflict-policy.d.ts.map +1 -0
  125. package/lib/storage/save-conflict-policy.js +19 -0
  126. package/lib/storage/save-conflict-policy.js.map +1 -0
  127. package/lib/submission/hydranium-glsp-submission-handler.d.ts +109 -0
  128. package/lib/submission/hydranium-glsp-submission-handler.d.ts.map +1 -0
  129. package/lib/submission/hydranium-glsp-submission-handler.js +157 -0
  130. package/lib/submission/hydranium-glsp-submission-handler.js.map +1 -0
  131. package/lib/submission/index.d.ts +10 -0
  132. package/lib/submission/index.d.ts.map +1 -0
  133. package/lib/submission/index.js +10 -0
  134. package/lib/submission/index.js.map +1 -0
  135. package/lib/testing/glsp-harness.d.ts +170 -0
  136. package/lib/testing/glsp-harness.d.ts.map +1 -0
  137. package/lib/testing/glsp-harness.js +231 -0
  138. package/lib/testing/glsp-harness.js.map +1 -0
  139. package/lib/testing/index.d.ts +11 -0
  140. package/lib/testing/index.d.ts.map +1 -0
  141. package/lib/testing/index.js +13 -0
  142. package/lib/testing/index.js.map +1 -0
  143. package/lib/testing/make-noop-glsp-logger.d.ts +42 -0
  144. package/lib/testing/make-noop-glsp-logger.d.ts.map +1 -0
  145. package/lib/testing/make-noop-glsp-logger.js +47 -0
  146. package/lib/testing/make-noop-glsp-logger.js.map +1 -0
  147. package/lib/util/index.d.ts +10 -0
  148. package/lib/util/index.d.ts.map +1 -0
  149. package/lib/util/index.js +10 -0
  150. package/lib/util/index.js.map +1 -0
  151. package/lib/util/service-identifier.d.ts +46 -0
  152. package/lib/util/service-identifier.d.ts.map +1 -0
  153. package/lib/util/service-identifier.js +47 -0
  154. package/lib/util/service-identifier.js.map +1 -0
  155. package/lib/validation/diagnostic-markers.d.ts +48 -0
  156. package/lib/validation/diagnostic-markers.d.ts.map +1 -0
  157. package/lib/validation/diagnostic-markers.js +68 -0
  158. package/lib/validation/diagnostic-markers.js.map +1 -0
  159. package/lib/validation/hydranium-glsp-model-validator.d.ts +51 -0
  160. package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -0
  161. package/lib/validation/hydranium-glsp-model-validator.js +118 -0
  162. package/lib/validation/hydranium-glsp-model-validator.js.map +1 -0
  163. package/lib/validation/index.d.ts +11 -0
  164. package/lib/validation/index.d.ts.map +1 -0
  165. package/lib/validation/index.js +11 -0
  166. package/lib/validation/index.js.map +1 -0
  167. package/package.json +111 -0
  168. package/src/browser/index.ts +15 -0
  169. package/src/browser/start-glsp-server-in-worker.ts +202 -0
  170. package/src/command/hydranium-glsp-recording-command.ts +183 -0
  171. package/src/command/index.ts +10 -0
  172. package/src/computed-bounds/hydranium-glsp-computed-bounds-action-handler.ts +103 -0
  173. package/src/computed-bounds/index.ts +10 -0
  174. package/src/dispatcher/index.ts +10 -0
  175. package/src/dispatcher/server-action-dispatcher.ts +72 -0
  176. package/src/index.ts +20 -0
  177. package/src/launcher/abstract-hydranium-glsp-diagram-module.ts +117 -0
  178. package/src/launcher/glsp-app-module.ts +106 -0
  179. package/src/launcher/glsp-framework-overrides.ts +51 -0
  180. package/src/launcher/glsp-server-overrides.ts +46 -0
  181. package/src/launcher/hydranium-glsp-server.ts +104 -0
  182. package/src/launcher/index.ts +22 -0
  183. package/src/logging/glsp-client-logger.ts +184 -0
  184. package/src/logging/index.ts +10 -0
  185. package/src/node/index.ts +13 -0
  186. package/src/node/start-glsp-server.ts +214 -0
  187. package/src/state/abstract-hydranium-glsp-state.ts +503 -0
  188. package/src/state/full-text-hydranium-glsp-state.ts +63 -0
  189. package/src/state/hydranium-glsp-index.ts +337 -0
  190. package/src/state/hydranium-shared-core-services.ts +92 -0
  191. package/src/state/index.ts +17 -0
  192. package/src/state/model-ready-timeout-error.ts +33 -0
  193. package/src/state/reconcile-source-model-write.ts +77 -0
  194. package/src/state/reconciling-multi-document-glsp-state.ts +248 -0
  195. package/src/state/reconciling-transfer-hydranium-glsp-state.ts +132 -0
  196. package/src/storage/hydranium-glsp-storage.ts +660 -0
  197. package/src/storage/index.ts +11 -0
  198. package/src/storage/save-conflict-policy.ts +52 -0
  199. package/src/submission/hydranium-glsp-submission-handler.ts +170 -0
  200. package/src/submission/index.ts +10 -0
  201. package/src/testing/glsp-harness.ts +422 -0
  202. package/src/testing/index.ts +14 -0
  203. package/src/testing/make-noop-glsp-logger.ts +66 -0
  204. package/src/util/index.ts +10 -0
  205. package/src/util/service-identifier.ts +49 -0
  206. package/src/validation/diagnostic-markers.ts +93 -0
  207. package/src/validation/hydranium-glsp-model-validator.ts +105 -0
  208. package/src/validation/index.ts +11 -0
@@ -0,0 +1,220 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023-2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import { type GModelElement, GModelIndex } from '@eclipse-glsp/server';
10
+ import { type AstNode, type URI } from '@hydranium/langium';
11
+ import { type ElementKeyProvider, type ServerLanguageServices, type ServerSharedServices } from '@hydranium/core';
12
+ /**
13
+ * GLSP model index extended with an AST-node ↔ id map so adopters can
14
+ * resolve diagram elements back to their source-language nodes during
15
+ * action handling, layout, validation, and submission.
16
+ *
17
+ * Indexing strategy is hookable via {@link doFindId}: the framework default
18
+ * uses {@link ElementKeyProvider.getElementKey} — a document-scoped lookup
19
+ * token built from the node's named ancestors, falling back to positional
20
+ * segments for unnamed nodes. Under the bound default that key is name-based,
21
+ * so a GModel id survives an edit that does not rename the node or an ancestor
22
+ * and changes when one does; the positional strategy is the rename-stable
23
+ * alternative. Adopters with a different stability boundary override
24
+ * {@link doFindId}.
25
+ *
26
+ * **Duplicate-id degrade.** A GModel tree must have unique element ids. Two
27
+ * AST nodes that collide on their stable id — exactly the state the diagram is
28
+ * meant to *mark* — project to two GModel elements with the same id. The GLSP
29
+ * client's sprotty `SGraphIndex.add` throws on such a duplicate inside
30
+ * `SModelFactory.initializeRoot`, aborting the build and blanking the WHOLE
31
+ * diagram. {@link indexRoot} prunes the colliding element(s) from the tree —
32
+ * the same object `ModelSubmissionHandler`
33
+ * submits — so the wire payload stays well-formed for every client and the
34
+ * surviving (first, document-order) element still carries the diagnostic
35
+ * marker. {@link doIndex} keeps a log-and-skip guard for any path that
36
+ * re-indexes a subtree without going through {@link indexRoot}.
37
+ */
38
+ export declare class HydraniumGlspIndex extends GModelIndex {
39
+ protected readonly sharedServices: ServerSharedServices;
40
+ protected idToSemanticNode: Map<string, AstNode>;
41
+ /**
42
+ * The language services of the diagram's OWN document, captured from the
43
+ * source root in {@link indexSourceRoot}. Used only as the fallback for a
44
+ * node that routes nowhere — a synthetic or freshly-built node with no
45
+ * `$document` yet, which a GModel factory legitimately hands us mid-edit.
46
+ *
47
+ * Captured rather than injected because it is the language the loaded
48
+ * document ACTUALLY routes to, which is not necessarily the one the diagram
49
+ * module declared — precisely the drift
50
+ * `AbstractHydraniumGlspState.checkDeclaredLanguage` warns about. (Not
51
+ * a cost argument: {@link HydraniumTypes}.DiagramLanguage is bound
52
+ * `inSingletonScope`, so injecting it would resolve once per session too.)
53
+ */
54
+ protected diagramLanguage?: ServerLanguageServices;
55
+ /**
56
+ * The grammar the diagram module declared, as the last resort behind
57
+ * {@link diagramLanguage}.
58
+ *
59
+ * Order-independent where the captured one is not: GLSP builds every
60
+ * operation handler at `InitializeClientSession`, so a document-less node
61
+ * can reach {@link createId} before the first {@link indexSourceRoot} — and
62
+ * with no language at all that mints an unstable `fallback_<uuid>` where a
63
+ * stable positional key was available. `@optional()` so a harness that binds
64
+ * no diagram module still resolves.
65
+ */
66
+ protected readonly declaredLanguage?: ServerLanguageServices;
67
+ /**
68
+ * Reverse map: the *stable id* of the AST element a GModel element
69
+ * represents → the GModel id(s) that render it. Multi-valued because one
70
+ * element can be drawn as several GModel nodes — placed twice on the same
71
+ * canvas, or projected by several referencing nodes.
72
+ * Populated explicitly by adopters via {@link registerElementId} (the forward
73
+ * {@link idToSemanticNode} keys by GModel id and can't express the same
74
+ * element rendering more than once). Consumed by diagnostic→marker mapping to
75
+ * find every node to mark for a given element.
76
+ *
77
+ * Keyed by the element's stable id (a string), NOT the `AstNode` itself, so
78
+ * it never retains AST node references across rebuilds. Cleared with the
79
+ * forward index in {@link indexSourceRoot}; re-registration each GModel
80
+ * rebuild is idempotent (a Set), and any id no longer drawn is filtered by
81
+ * the consumer's rendered-check, so stale entries are harmless.
82
+ */
83
+ protected elementToIds: Map<string, Set<string>>;
84
+ /**
85
+ * The uris of the documents whose elements can map to a marker on this
86
+ * diagram: the diagram's own document (seeded in {@link indexSourceRoot})
87
+ * plus every document reached through a reference projection (added in
88
+ * {@link registerElementId}). Lets the diagnostic→marker validator resolve
89
+ * only the documents that actually contribute rendered elements rather than
90
+ * every loaded document. Self-maintaining: every {@link registerElementId}
91
+ * caller auto-includes its document.
92
+ */
93
+ protected renderedDocUris: Set<string>;
94
+ /**
95
+ * Return the GModel id assigned to `node`, or — when no id is found and
96
+ * a `fallback` is supplied — the value of `fallback()`. The two-overload
97
+ * shape preserves the caller's narrowing: with a `() => string` fallback
98
+ * the return is `string`; with a `() => string | undefined` (or no
99
+ * fallback) the return is `string | undefined`.
100
+ *
101
+ * A convenience over {@link doFindId}, NOT the id-strategy hook. Framework
102
+ * internals call `doFindId` directly (see {@link indexSourceRoot}), so an
103
+ * override here changes only what external callers of this method see —
104
+ * override `doFindId` to change how nodes are keyed.
105
+ */
106
+ findId(node: AstNode | undefined, fallback: () => string): string;
107
+ findId(node: AstNode | undefined, fallback?: () => string | undefined): string | undefined;
108
+ /**
109
+ * Hook for the adopter id-assignment strategy. Framework default reads
110
+ * {@link ElementKeyProvider.getElementKey} from the language owning `node`,
111
+ * which under the bound default is name-based and falls back to positional
112
+ * segments for unnamed nodes.
113
+ *
114
+ * `keyProvider` is an optional hint: the provider for THIS node, already
115
+ * resolved by the caller. {@link indexSourceRoot} passes it because every
116
+ * node in a containment walk belongs to the root's document by
117
+ * construction, so the per-node lookup would re-derive one known answer N
118
+ * times. An override that ignores the parameter stays correct, at the cost
119
+ * of that lookup.
120
+ */
121
+ protected doFindId(node?: AstNode, keyProvider?: ElementKeyProvider): string | undefined;
122
+ /**
123
+ * The {@link ElementKeyProvider} of the language owning `node`'s document,
124
+ * falling back to the language the diagram document routes to and then to
125
+ * the one its module declared, for a node that routes nowhere.
126
+ *
127
+ * **Resolved per node on the cross-document entry points.** This index is
128
+ * deliberately cross-document — {@link registerElementId} and
129
+ * {@link findElementIds} key elements reached through a reference, and
130
+ * {@link renderedDocUris} exists precisely because those live in other
131
+ * documents. A single captured provider therefore keys foreign nodes under
132
+ * the wrong grammar as soon as two registered languages differ in their key
133
+ * strategy: a plausible-looking id that matches nothing, so selection,
134
+ * marker mapping and element lookup silently miss. Those entry points are a
135
+ * bounded set the adopter calls explicitly; the full-document walk in
136
+ * {@link indexSourceRoot} needs no per-node lookup and does not pay for one.
137
+ */
138
+ protected elementKeyProviderFor(node?: AstNode): ElementKeyProvider | undefined;
139
+ /** Return the GModel id assigned to `node`, falling back to a fresh `fallback_<uuid>`. */
140
+ createId(node?: AstNode): string;
141
+ /**
142
+ * Return the GModel id assigned to `node` or throw if none is available.
143
+ *
144
+ * The failure names the node's type and position rather than its source
145
+ * text. Interpolating `$cstNode.text` would put the user's own model content
146
+ * into a string that reaches a log, a client toast and an adopter's
147
+ * telemetry alike, so the exposure does not depend on which surface
148
+ * receives it. Type and position identify the node for whoever is debugging
149
+ * without carrying any of it, and positions are 1-based so they match what
150
+ * an editor shows.
151
+ */
152
+ assertId(node?: AstNode): string;
153
+ /**
154
+ * Walk the source root and index every reachable AST node with a resolvable
155
+ * id.
156
+ *
157
+ * `uri` is the diagram document's URI, supplied by
158
+ * `AbstractHydraniumGlspState.setSourceRoot`, and is used only to
159
+ * resolve the diagram's language when `root` carries no `$document` —
160
+ * always the case for a synthesised root, and the more authoritative signal
161
+ * either way since it is what the caller declared it was loading.
162
+ *
163
+ * The walk resolves the key provider ONCE and threads it: `streamAllContents`
164
+ * is containment-only, so every node it yields has `root` as its root node
165
+ * and therefore the language just resolved. Looking it up per node would
166
+ * walk the container chain and Langium's whole lookup ladder — declared
167
+ * languageId, file name, extension — for an answer already in hand, on every
168
+ * diagram open and every source-root refresh.
169
+ */
170
+ indexSourceRoot(root: AstNode, uri?: URI | string): void;
171
+ /**
172
+ * Register that the GModel element `id` renders `element` — the reverse of
173
+ * the GModel-id keying. Adopters call this when a GModel element represents
174
+ * an AST element that is *not* keyed by its own id — most importantly a
175
+ * diagram node keyed by its own id while visually standing for the element
176
+ * it references. Additive: registering the same `element` under several ids
177
+ * records every occurrence.
178
+ */
179
+ registerElementId(element: AstNode, id: string): void;
180
+ /** The uris of the documents that contribute elements rendered on this diagram. */
181
+ renderedDocumentUris(): readonly string[];
182
+ /** Record `node`'s document uri (if it has one) as contributing rendered elements. */
183
+ protected addRenderedDocUri(node: AstNode): void;
184
+ /** The GModel ids registered (via {@link registerElementId}) as rendering `element`; empty if none. */
185
+ findElementIds(element?: AstNode): readonly string[];
186
+ /** `keyProvider` is {@link doFindId}'s already-resolved hint; see {@link indexSourceRoot}. */
187
+ protected indexAstNode(node: AstNode, keyProvider?: ElementKeyProvider): void;
188
+ /** Insert an AST node under `id` directly — for adopters that need to seed entries outside the standard walk. */
189
+ indexSemanticElement<T extends AstNode>(id: string, element: T): void;
190
+ /** Look up the AST node previously indexed under `id`. */
191
+ findSemanticElement(id: string): AstNode | undefined;
192
+ findSemanticElement<T extends AstNode>(id: string, guard: (item: unknown) => item is T): T | undefined;
193
+ /**
194
+ * Prune duplicate-id elements from the GModel tree, then index it.
195
+ *
196
+ * {@link GModelIndex.indexRoot} runs on the exact object the submission
197
+ * handler later serializes (`DefaultModelState.updateRoot` assigns
198
+ * `this.root = newRoot` immediately before `this.index.indexRoot(newRoot)`),
199
+ * so removing duplicates here also removes them from the submitted payload —
200
+ * the only place the fix protects every client rather than one tolerant one.
201
+ */
202
+ indexRoot(root: GModelElement): void;
203
+ /**
204
+ * Remove every element whose id was already seen earlier in a depth-first
205
+ * walk; the first occurrence (document order) wins and a dropped element
206
+ * takes its whole subtree with it. Splices in place so the parent's
207
+ * `children` array identity is preserved; logs each drop via the bound
208
+ * logger. The root itself is the first id seen and can never be a duplicate.
209
+ */
210
+ protected pruneDuplicateIds(root: GModelElement): void;
211
+ /**
212
+ * Log-and-skip guard for duplicate GModel ids. {@link indexRoot}'s prune
213
+ * already removes duplicates from the tree before this runs, so in the
214
+ * normal flow this never fires; it stays as a last line of defence for any
215
+ * path that re-indexes a subtree directly (where {@link GModelIndex.doIndex}
216
+ * would otherwise throw).
217
+ */
218
+ protected doIndex(element: GModelElement): void;
219
+ }
220
+ //# sourceMappingURL=hydranium-glsp-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydranium-glsp-index.d.ts","sourceRoot":"","sources":["../../src/state/hydranium-glsp-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,320 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023-2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
10
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
11
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
12
+ 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;
13
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
14
+ };
15
+ var __metadata = (this && this.__metadata) || function (k, v) {
16
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
17
+ };
18
+ import { GModelIndex } from '@eclipse-glsp/server';
19
+ import { inject, injectable, optional } from 'inversify';
20
+ import { AstUtils } from '@hydranium/langium';
21
+ import * as uuid from 'uuid';
22
+ import { HydraniumTypes } from './hydranium-shared-core-services.js';
23
+ /**
24
+ * GLSP model index extended with an AST-node ↔ id map so adopters can
25
+ * resolve diagram elements back to their source-language nodes during
26
+ * action handling, layout, validation, and submission.
27
+ *
28
+ * Indexing strategy is hookable via {@link doFindId}: the framework default
29
+ * uses {@link ElementKeyProvider.getElementKey} — a document-scoped lookup
30
+ * token built from the node's named ancestors, falling back to positional
31
+ * segments for unnamed nodes. Under the bound default that key is name-based,
32
+ * so a GModel id survives an edit that does not rename the node or an ancestor
33
+ * and changes when one does; the positional strategy is the rename-stable
34
+ * alternative. Adopters with a different stability boundary override
35
+ * {@link doFindId}.
36
+ *
37
+ * **Duplicate-id degrade.** A GModel tree must have unique element ids. Two
38
+ * AST nodes that collide on their stable id — exactly the state the diagram is
39
+ * meant to *mark* — project to two GModel elements with the same id. The GLSP
40
+ * client's sprotty `SGraphIndex.add` throws on such a duplicate inside
41
+ * `SModelFactory.initializeRoot`, aborting the build and blanking the WHOLE
42
+ * diagram. {@link indexRoot} prunes the colliding element(s) from the tree —
43
+ * the same object `ModelSubmissionHandler`
44
+ * submits — so the wire payload stays well-formed for every client and the
45
+ * surviving (first, document-order) element still carries the diagnostic
46
+ * marker. {@link doIndex} keeps a log-and-skip guard for any path that
47
+ * re-indexes a subtree without going through {@link indexRoot}.
48
+ */
49
+ let HydraniumGlspIndex = class HydraniumGlspIndex extends GModelIndex {
50
+ sharedServices;
51
+ idToSemanticNode = new Map();
52
+ /**
53
+ * The language services of the diagram's OWN document, captured from the
54
+ * source root in {@link indexSourceRoot}. Used only as the fallback for a
55
+ * node that routes nowhere — a synthetic or freshly-built node with no
56
+ * `$document` yet, which a GModel factory legitimately hands us mid-edit.
57
+ *
58
+ * Captured rather than injected because it is the language the loaded
59
+ * document ACTUALLY routes to, which is not necessarily the one the diagram
60
+ * module declared — precisely the drift
61
+ * `AbstractHydraniumGlspState.checkDeclaredLanguage` warns about. (Not
62
+ * a cost argument: {@link HydraniumTypes}.DiagramLanguage is bound
63
+ * `inSingletonScope`, so injecting it would resolve once per session too.)
64
+ */
65
+ diagramLanguage;
66
+ /**
67
+ * The grammar the diagram module declared, as the last resort behind
68
+ * {@link diagramLanguage}.
69
+ *
70
+ * Order-independent where the captured one is not: GLSP builds every
71
+ * operation handler at `InitializeClientSession`, so a document-less node
72
+ * can reach {@link createId} before the first {@link indexSourceRoot} — and
73
+ * with no language at all that mints an unstable `fallback_<uuid>` where a
74
+ * stable positional key was available. `@optional()` so a harness that binds
75
+ * no diagram module still resolves.
76
+ */
77
+ declaredLanguage;
78
+ /**
79
+ * Reverse map: the *stable id* of the AST element a GModel element
80
+ * represents → the GModel id(s) that render it. Multi-valued because one
81
+ * element can be drawn as several GModel nodes — placed twice on the same
82
+ * canvas, or projected by several referencing nodes.
83
+ * Populated explicitly by adopters via {@link registerElementId} (the forward
84
+ * {@link idToSemanticNode} keys by GModel id and can't express the same
85
+ * element rendering more than once). Consumed by diagnostic→marker mapping to
86
+ * find every node to mark for a given element.
87
+ *
88
+ * Keyed by the element's stable id (a string), NOT the `AstNode` itself, so
89
+ * it never retains AST node references across rebuilds. Cleared with the
90
+ * forward index in {@link indexSourceRoot}; re-registration each GModel
91
+ * rebuild is idempotent (a Set), and any id no longer drawn is filtered by
92
+ * the consumer's rendered-check, so stale entries are harmless.
93
+ */
94
+ elementToIds = new Map();
95
+ /**
96
+ * The uris of the documents whose elements can map to a marker on this
97
+ * diagram: the diagram's own document (seeded in {@link indexSourceRoot})
98
+ * plus every document reached through a reference projection (added in
99
+ * {@link registerElementId}). Lets the diagnostic→marker validator resolve
100
+ * only the documents that actually contribute rendered elements rather than
101
+ * every loaded document. Self-maintaining: every {@link registerElementId}
102
+ * caller auto-includes its document.
103
+ */
104
+ renderedDocUris = new Set();
105
+ findId(node, fallback = () => undefined) {
106
+ return this.doFindId(node) ?? fallback();
107
+ }
108
+ /**
109
+ * Hook for the adopter id-assignment strategy. Framework default reads
110
+ * {@link ElementKeyProvider.getElementKey} from the language owning `node`,
111
+ * which under the bound default is name-based and falls back to positional
112
+ * segments for unnamed nodes.
113
+ *
114
+ * `keyProvider` is an optional hint: the provider for THIS node, already
115
+ * resolved by the caller. {@link indexSourceRoot} passes it because every
116
+ * node in a containment walk belongs to the root's document by
117
+ * construction, so the per-node lookup would re-derive one known answer N
118
+ * times. An override that ignores the parameter stays correct, at the cost
119
+ * of that lookup.
120
+ */
121
+ doFindId(node, keyProvider) {
122
+ return (keyProvider ?? this.elementKeyProviderFor(node))?.getElementKey(node);
123
+ }
124
+ /**
125
+ * The {@link ElementKeyProvider} of the language owning `node`'s document,
126
+ * falling back to the language the diagram document routes to and then to
127
+ * the one its module declared, for a node that routes nowhere.
128
+ *
129
+ * **Resolved per node on the cross-document entry points.** This index is
130
+ * deliberately cross-document — {@link registerElementId} and
131
+ * {@link findElementIds} key elements reached through a reference, and
132
+ * {@link renderedDocUris} exists precisely because those live in other
133
+ * documents. A single captured provider therefore keys foreign nodes under
134
+ * the wrong grammar as soon as two registered languages differ in their key
135
+ * strategy: a plausible-looking id that matches nothing, so selection,
136
+ * marker mapping and element lookup silently miss. Those entry points are a
137
+ * bounded set the adopter calls explicitly; the full-document walk in
138
+ * {@link indexSourceRoot} needs no per-node lookup and does not pay for one.
139
+ */
140
+ elementKeyProviderFor(node) {
141
+ const language = this.sharedServices.ServiceRegistry.getServicesFor(node) ?? this.diagramLanguage ?? this.declaredLanguage;
142
+ return language?.references.ElementKeyProvider;
143
+ }
144
+ /** Return the GModel id assigned to `node`, falling back to a fresh `fallback_<uuid>`. */
145
+ createId(node) {
146
+ return this.findId(node, () => 'fallback_' + uuid.v4());
147
+ }
148
+ /**
149
+ * Return the GModel id assigned to `node` or throw if none is available.
150
+ *
151
+ * The failure names the node's type and position rather than its source
152
+ * text. Interpolating `$cstNode.text` would put the user's own model content
153
+ * into a string that reaches a log, a client toast and an adopter's
154
+ * telemetry alike, so the exposure does not depend on which surface
155
+ * receives it. Type and position identify the node for whoever is debugging
156
+ * without carrying any of it, and positions are 1-based so they match what
157
+ * an editor shows.
158
+ */
159
+ assertId(node) {
160
+ const id = this.findId(node);
161
+ if (!id) {
162
+ const start = node?.$cstNode?.range.start;
163
+ const at = start === undefined ? '' : ` at ${start.line + 1}:${start.character + 1}`;
164
+ throw new Error(`Could not create ID for ${node?.$type ?? 'an absent node'}${at}`);
165
+ }
166
+ return id;
167
+ }
168
+ /**
169
+ * Walk the source root and index every reachable AST node with a resolvable
170
+ * id.
171
+ *
172
+ * `uri` is the diagram document's URI, supplied by
173
+ * `AbstractHydraniumGlspState.setSourceRoot`, and is used only to
174
+ * resolve the diagram's language when `root` carries no `$document` —
175
+ * always the case for a synthesised root, and the more authoritative signal
176
+ * either way since it is what the caller declared it was loading.
177
+ *
178
+ * The walk resolves the key provider ONCE and threads it: `streamAllContents`
179
+ * is containment-only, so every node it yields has `root` as its root node
180
+ * and therefore the language just resolved. Looking it up per node would
181
+ * walk the container chain and Langium's whole lookup ladder — declared
182
+ * languageId, file name, extension — for an answer already in hand, on every
183
+ * diagram open and every source-root refresh.
184
+ */
185
+ indexSourceRoot(root, uri) {
186
+ this.idToSemanticNode.clear();
187
+ this.elementToIds.clear();
188
+ this.renderedDocUris.clear();
189
+ const registry = this.sharedServices.ServiceRegistry;
190
+ this.diagramLanguage = registry.getServicesFor(root) ?? registry.getServicesFor(uri);
191
+ this.addRenderedDocUri(root);
192
+ const keyProvider = this.elementKeyProviderFor(root);
193
+ AstUtils.streamAllContents(root).forEach(node => this.indexAstNode(node, keyProvider));
194
+ }
195
+ /**
196
+ * Register that the GModel element `id` renders `element` — the reverse of
197
+ * the GModel-id keying. Adopters call this when a GModel element represents
198
+ * an AST element that is *not* keyed by its own id — most importantly a
199
+ * diagram node keyed by its own id while visually standing for the element
200
+ * it references. Additive: registering the same `element` under several ids
201
+ * records every occurrence.
202
+ */
203
+ registerElementId(element, id) {
204
+ const key = this.doFindId(element);
205
+ if (key === undefined) {
206
+ return;
207
+ }
208
+ const ids = this.elementToIds.get(key);
209
+ if (ids) {
210
+ ids.add(id);
211
+ }
212
+ else {
213
+ this.elementToIds.set(key, new Set([id]));
214
+ }
215
+ this.addRenderedDocUri(element);
216
+ }
217
+ /** The uris of the documents that contribute elements rendered on this diagram. */
218
+ renderedDocumentUris() {
219
+ return [...this.renderedDocUris];
220
+ }
221
+ /** Record `node`'s document uri (if it has one) as contributing rendered elements. */
222
+ addRenderedDocUri(node) {
223
+ const uri = AstUtils.findRootNode(node).$document?.uri.toString();
224
+ if (uri !== undefined) {
225
+ this.renderedDocUris.add(uri);
226
+ }
227
+ }
228
+ /** The GModel ids registered (via {@link registerElementId}) as rendering `element`; empty if none. */
229
+ findElementIds(element) {
230
+ const key = element ? this.doFindId(element) : undefined;
231
+ const ids = key !== undefined ? this.elementToIds.get(key) : undefined;
232
+ return ids ? [...ids] : [];
233
+ }
234
+ /** `keyProvider` is {@link doFindId}'s already-resolved hint; see {@link indexSourceRoot}. */
235
+ indexAstNode(node, keyProvider) {
236
+ const id = this.doFindId(node, keyProvider);
237
+ if (id) {
238
+ this.indexSemanticElement(id, node);
239
+ }
240
+ }
241
+ /** Insert an AST node under `id` directly — for adopters that need to seed entries outside the standard walk. */
242
+ indexSemanticElement(id, element) {
243
+ this.idToSemanticNode.set(id, element);
244
+ }
245
+ findSemanticElement(id, guard) {
246
+ const semanticNode = this.idToSemanticNode.get(id);
247
+ if (guard) {
248
+ return guard(semanticNode) ? semanticNode : undefined;
249
+ }
250
+ return semanticNode;
251
+ }
252
+ /**
253
+ * Prune duplicate-id elements from the GModel tree, then index it.
254
+ *
255
+ * {@link GModelIndex.indexRoot} runs on the exact object the submission
256
+ * handler later serializes (`DefaultModelState.updateRoot` assigns
257
+ * `this.root = newRoot` immediately before `this.index.indexRoot(newRoot)`),
258
+ * so removing duplicates here also removes them from the submitted payload —
259
+ * the only place the fix protects every client rather than one tolerant one.
260
+ */
261
+ indexRoot(root) {
262
+ this.pruneDuplicateIds(root);
263
+ super.indexRoot(root);
264
+ }
265
+ /**
266
+ * Remove every element whose id was already seen earlier in a depth-first
267
+ * walk; the first occurrence (document order) wins and a dropped element
268
+ * takes its whole subtree with it. Splices in place so the parent's
269
+ * `children` array identity is preserved; logs each drop via the bound
270
+ * logger. The root itself is the first id seen and can never be a duplicate.
271
+ */
272
+ pruneDuplicateIds(root) {
273
+ const seen = new Set([root.id]);
274
+ const visit = (element) => {
275
+ const children = element.children;
276
+ let index = 0;
277
+ while (index < children.length) {
278
+ const child = children[index];
279
+ if (seen.has(child.id)) {
280
+ this.sharedServices.Logger.for('Index').warn('Dropping duplicate element id from submitted graph: ' + child.id);
281
+ children.splice(index, 1); // drop child + subtree; do not advance — the next child shifts into `index`
282
+ }
283
+ else {
284
+ seen.add(child.id);
285
+ visit(child);
286
+ index++;
287
+ }
288
+ }
289
+ };
290
+ visit(root);
291
+ }
292
+ /**
293
+ * Log-and-skip guard for duplicate GModel ids. {@link indexRoot}'s prune
294
+ * already removes duplicates from the tree before this runs, so in the
295
+ * normal flow this never fires; it stays as a last line of defence for any
296
+ * path that re-indexes a subtree directly (where {@link GModelIndex.doIndex}
297
+ * would otherwise throw).
298
+ */
299
+ doIndex(element) {
300
+ if (this.idToElement.has(element.id)) {
301
+ this.sharedServices.Logger.for('Index').error('Duplicate element id in graph: ' + element.id);
302
+ return;
303
+ }
304
+ super.doIndex(element);
305
+ }
306
+ };
307
+ __decorate([
308
+ inject(HydraniumTypes.SharedCoreServices),
309
+ __metadata("design:type", Object)
310
+ ], HydraniumGlspIndex.prototype, "sharedServices", void 0);
311
+ __decorate([
312
+ inject(HydraniumTypes.DiagramLanguage),
313
+ optional(),
314
+ __metadata("design:type", Object)
315
+ ], HydraniumGlspIndex.prototype, "declaredLanguage", void 0);
316
+ HydraniumGlspIndex = __decorate([
317
+ injectable()
318
+ ], HydraniumGlspIndex);
319
+ export { HydraniumGlspIndex };
320
+ //# sourceMappingURL=hydranium-glsp-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydranium-glsp-index.js","sourceRoot":"","sources":["../../src/state/hydranium-glsp-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import type { ServerLanguageServices, ServerSharedServices } from '@hydranium/core';
10
+ import type { ConflictResolver, Tracer } from '@hydranium/protocol';
11
+ /**
12
+ * Inversify service-identifier registry for the framework services the
13
+ * `@hydranium/glsp-server` runtime exposes to `@injectable()` GLSP
14
+ * components. Framework GLSP-side classes are `@injectable()` and need an
15
+ * Inversify token to receive the Langium-style services the rest of the
16
+ * framework hands around via plain constructor arguments.
17
+ *
18
+ * Every token here is a service whose value is **fixed for the container tier
19
+ * that binds it** — process-wide shared services, a per-session conflict
20
+ * policy, the grammar a diagram type edits. That is the whole membership rule,
21
+ * and it is why the registry is short: see below for what deliberately does
22
+ * NOT get a token.
23
+ *
24
+ * Grouped under one object (rather than top-level `Hydranium<Role>` consts)
25
+ * so the token identity is decoupled from the implementation class name.
26
+ * Mirrors GLSP's own `TYPES` registry idiom.
27
+ *
28
+ * Bound by the adopter from their services trees — the app-tier ones directly,
29
+ * the session-tier language by declaring a grammar on the diagram module.
30
+ * Inject with the real service type as the field type.
31
+ *
32
+ * **Split by tier, because GLSP has no language tier.** GLSP's containers are
33
+ * app (per process) -> server (per connection) -> session (per open diagram);
34
+ * Langium's are shared (per process) -> language (per grammar, routed by URI).
35
+ * Only the outermost pair line up. A per-language service therefore CANNOT be
36
+ * bound at the app tier — that container is built before any document exists,
37
+ * so it can only ever hold one grammar's services. The tokens below are split
38
+ * accordingly:
39
+ *
40
+ * - **SharedCoreServices** — the framework's Langium-style shared services
41
+ * tree ({@link ServerSharedServices}); the services-tree root that state /
42
+ * index classes inject. Bound once at the app tier. Carries
43
+ * `ServiceRegistry`, which is how everything below reaches a language.
44
+ * - **DiagramLanguage** — the {@link ServerLanguageServices} of the grammar a
45
+ * diagram type edits, bound at the SESSION tier by
46
+ * `AbstractHydraniumGlspDiagramModule` from its declared `declareLanguage()`.
47
+ * Static (a diagram type has one grammar), so it is safe for the eagerly
48
+ * constructed handlers GLSP builds at `InitializeClientSession`. Read it
49
+ * through `AbstractHydraniumGlspState.diagramLanguage`.
50
+ * - **ConflictResolver** — the policy the GLSP state consults when a write
51
+ * (forward-write, undo, redo, save) races a foreign edit.
52
+ * `HydraniumGlspAppModule` binds it to `options.conflictResolver`
53
+ * when supplied, else a default `ReconcilingConflictResolver` (field-level
54
+ * three-way merge) unless the adopter opts into `ForceConflictResolver`.
55
+ * - **Tracer** — the measure-and-emit observability handle (timing, memory,
56
+ * profiling). Bound per-request, auto-tagged with the requesting class name
57
+ * (mirroring GLSP's `LoggerFactory` caller-tagging), so an `@injectable()`
58
+ * GLSP class that times just injects it and its timing lines carry its own
59
+ * component — no manual `for(...)`. The non-injectable recording command,
60
+ * which can't inject, borrows the state's `tracer` getter instead.
61
+ *
62
+ * **No per-language SERVICE has a token — only the language does.** There is
63
+ * no `ElementKeyProvider`, `NameProvider`, `ScopeProvider` or
64
+ * `CandidateProvider` symbol, because every one of them is keyed by a document
65
+ * that the container cannot know: the target node's, for naming and keying;
66
+ * the one a reference is WRITTEN in, for scope and candidates. A GLSP
67
+ * component asks about several documents over its life — the diagram's own,
68
+ * the element it is editing, a drop target — so an injected provider instance
69
+ * answers as if there were one right answer and the routing decision vanishes
70
+ * from the call site. `this.candidateProvider` reads as language-neutral, and
71
+ * nothing prompts the author to ask which document the reference lives in;
72
+ * that is exactly how a foreign node ends up named under the diagram's
73
+ * grammar, producing a plausible string that matches nothing.
74
+ *
75
+ * So callers name the language they mean: `modelState.diagramLanguage` for a
76
+ * reference written on the canvas, `modelState.languageServicesFor(node)` for
77
+ * anything reached through a reference. `ServiceRegistry.getServicesFor(target)`
78
+ * serves the same purpose where no model state is at hand.
79
+ *
80
+ * The app-tier tokens are bound by `HydraniumGlspAppModule`, the
81
+ * session-tier one by `AbstractHydraniumGlspDiagramModule`. A multi-grammar
82
+ * adopter declares a language per diagram module and needs nothing else.
83
+ */
84
+ export declare const HydraniumTypes: {
85
+ readonly SharedCoreServices: import("inversify").interfaces.ServiceIdentifier<ServerSharedServices>;
86
+ readonly DiagramLanguage: import("inversify").interfaces.ServiceIdentifier<ServerLanguageServices>;
87
+ readonly ConflictResolver: import("inversify").interfaces.ServiceIdentifier<ConflictResolver>;
88
+ readonly Tracer: import("inversify").interfaces.ServiceIdentifier<Tracer>;
89
+ };
90
+ //# sourceMappingURL=hydranium-shared-core-services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydranium-shared-core-services.d.ts","sourceRoot":"","sources":["../../src/state/hydranium-shared-core-services.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AACH,eAAO,MAAM,cAAc;;;;;CAKjB,CAAC"}