arcane-os 0.1.0-dev.5

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 (248) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/COMMERCIAL-LICENSE.md +13 -0
  3. package/LICENSE +661 -0
  4. package/NOTICE +70 -0
  5. package/README.md +448 -0
  6. package/bin/arcane-test.mjs +741 -0
  7. package/bin/arcane.mjs +5 -0
  8. package/docs/architecture.md +234 -0
  9. package/docs/compatibility.md +36 -0
  10. package/docs/event-manager.md +166 -0
  11. package/docs/platform-targets.md +108 -0
  12. package/docs/publishing.md +203 -0
  13. package/docs/reference/README.md +117 -0
  14. package/docs/reference/arcane-ollama.md +288 -0
  15. package/docs/reference/availability-and-normalization.md +123 -0
  16. package/docs/reference/behavioral-testing.md +86 -0
  17. package/docs/reference/cli.md +569 -0
  18. package/docs/reference/core/README.md +62 -0
  19. package/docs/reference/core/arcane-ai-contracts.md +873 -0
  20. package/docs/reference/core/arcane-api.md +601 -0
  21. package/docs/reference/core/arcane-entities.md +65 -0
  22. package/docs/reference/core/arcane-events.md +134 -0
  23. package/docs/reference/core/ollama-module.md +181 -0
  24. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
  25. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
  26. package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
  27. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
  28. package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
  29. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
  30. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
  31. package/docs/reference/event-manager.md +957 -0
  32. package/docs/reference/inventory/package-api.json +2632 -0
  33. package/docs/reference/inventory/runtime-components.json +934 -0
  34. package/docs/reference/inventory/runtime-entities.json +26 -0
  35. package/docs/reference/inventory/runtime-modules.json +1249 -0
  36. package/docs/reference/protocols.md +242 -0
  37. package/docs/reference/runtime-components.md +1098 -0
  38. package/docs/reference/runtime-entities.md +303 -0
  39. package/docs/reference/runtime-modules.md +2010 -0
  40. package/docs/reference/sdk-api.md +4901 -0
  41. package/docs/roadmap.md +79 -0
  42. package/docs/work-amplification.md +124 -0
  43. package/node_modules/event-pubsub/CHANGELOG.md +55 -0
  44. package/node_modules/event-pubsub/MIGRATION.md +70 -0
  45. package/node_modules/event-pubsub/README.md +363 -0
  46. package/node_modules/event-pubsub/SECURITY.md +37 -0
  47. package/node_modules/event-pubsub/index.js +141 -0
  48. package/node_modules/event-pubsub/licence +21 -0
  49. package/node_modules/event-pubsub/package.json +59 -0
  50. package/node_modules/strong-type/README.md +408 -0
  51. package/node_modules/strong-type/assets/strong-type-header.png +0 -0
  52. package/node_modules/strong-type/index.js +1151 -0
  53. package/node_modules/strong-type/licence +21 -0
  54. package/node_modules/strong-type/node.js +125 -0
  55. package/node_modules/strong-type/package.json +61 -0
  56. package/package.json +95 -0
  57. package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
  58. package/runtime/arcane/components/app-bar.html +468 -0
  59. package/runtime/arcane/components/assistant-panel.html +715 -0
  60. package/runtime/arcane/components/calculator.html +8 -0
  61. package/runtime/arcane/components/chart.html +655 -0
  62. package/runtime/arcane/components/chat.html +1225 -0
  63. package/runtime/arcane/components/conversation-view.html +13 -0
  64. package/runtime/arcane/components/dashboard-config.html +341 -0
  65. package/runtime/arcane/components/data-maintenance.html +112 -0
  66. package/runtime/arcane/components/data-view.html +92 -0
  67. package/runtime/arcane/components/directory-picker.html +197 -0
  68. package/runtime/arcane/components/document-inspector.html +252 -0
  69. package/runtime/arcane/components/file-drop.html +264 -0
  70. package/runtime/arcane/components/file-inspector.html +293 -0
  71. package/runtime/arcane/components/file-manager.html +1715 -0
  72. package/runtime/arcane/components/header.html +142 -0
  73. package/runtime/arcane/components/integration-settings.html +14 -0
  74. package/runtime/arcane/components/local-ai-status.html +360 -0
  75. package/runtime/arcane/components/markdown-document.html +1048 -0
  76. package/runtime/arcane/components/markdown-editor.html +360 -0
  77. package/runtime/arcane/components/media-embed.html +8 -0
  78. package/runtime/arcane/components/modal.html +402 -0
  79. package/runtime/arcane/components/output-panel.html +259 -0
  80. package/runtime/arcane/components/preferences-form.html +135 -0
  81. package/runtime/arcane/components/record-timeline.html +105 -0
  82. package/runtime/arcane/components/relationship-board.html +116 -0
  83. package/runtime/arcane/components/screen-capture.html +8 -0
  84. package/runtime/arcane/components/source-code-viewer.html +441 -0
  85. package/runtime/arcane/components/source-explanation.html +124 -0
  86. package/runtime/arcane/components/speech.html +365 -0
  87. package/runtime/arcane/components/summary-strip.html +177 -0
  88. package/runtime/arcane/components/table.html +77 -0
  89. package/runtime/arcane/components/task-progress.html +282 -0
  90. package/runtime/arcane/components/terminal-workspace.html +65 -0
  91. package/runtime/arcane/components/theme-editor.html +41 -0
  92. package/runtime/arcane/components/theme-switcher.html +46 -0
  93. package/runtime/arcane/components/unified-inbox.html +20 -0
  94. package/runtime/arcane/components/voice-transcription.html +476 -0
  95. package/runtime/arcane/components/weather-widget.html +8 -0
  96. package/runtime/arcane/components/web-navigator.html +239 -0
  97. package/runtime/arcane/css/communications.css +1 -0
  98. package/runtime/arcane/css/dashboard-config.css +45 -0
  99. package/runtime/arcane/css/document-site.css +981 -0
  100. package/runtime/arcane/css/layout.css +438 -0
  101. package/runtime/arcane/css/primitives.css +321 -0
  102. package/runtime/arcane/css/theme.css +112 -0
  103. package/runtime/arcane/css/utility-workspace.css +1 -0
  104. package/runtime/arcane/entities/ApiModelRecord.js +20 -0
  105. package/runtime/arcane/entities/Calculation.js +13 -0
  106. package/runtime/arcane/entities/Chat.js +581 -0
  107. package/runtime/arcane/entities/CommunicationMessage.js +29 -0
  108. package/runtime/arcane/entities/CommunicationThread.js +21 -0
  109. package/runtime/arcane/entities/Document.js +10 -0
  110. package/runtime/arcane/entities/File.js +143 -0
  111. package/runtime/arcane/entities/Image.js +135 -0
  112. package/runtime/arcane/entities/IntentEnvelope.js +834 -0
  113. package/runtime/arcane/entities/Preference.js +83 -0
  114. package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
  115. package/runtime/arcane/entities/TerminalSession.js +46 -0
  116. package/runtime/arcane/entities/Theme.js +107 -0
  117. package/runtime/arcane/entities/User.js +1046 -0
  118. package/runtime/arcane/entities/Weather.js +23 -0
  119. package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
  120. package/runtime/arcane/img/arrow-left.png +0 -0
  121. package/runtime/arcane/img/arrow-right.png +0 -0
  122. package/runtime/arcane/img/doc.svg +5 -0
  123. package/runtime/arcane/img/folder.svg +4 -0
  124. package/runtime/arcane/img/image.svg +5 -0
  125. package/runtime/arcane/img/refresh.png +0 -0
  126. package/runtime/arcane/img/send.svg +9 -0
  127. package/runtime/arcane/img/trash.svg +5 -0
  128. package/runtime/arcane/img/upload.svg +5 -0
  129. package/runtime/arcane/modules/AI.js +2048 -0
  130. package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
  131. package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
  132. package/runtime/arcane/modules/AIResponseLength.js +42 -0
  133. package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
  134. package/runtime/arcane/modules/AnsiText.js +53 -0
  135. package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
  136. package/runtime/arcane/modules/AppDataScope.js +245 -0
  137. package/runtime/arcane/modules/AppearancePreferences.js +28 -0
  138. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
  139. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
  140. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
  141. package/runtime/arcane/modules/AsyncBoundary.js +161 -0
  142. package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
  143. package/runtime/arcane/modules/CalculatorEngine.js +20 -0
  144. package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
  145. package/runtime/arcane/modules/ChartLibrary.js +35 -0
  146. package/runtime/arcane/modules/ChatRecords.js +13 -0
  147. package/runtime/arcane/modules/CommunicationAppController.js +43 -0
  148. package/runtime/arcane/modules/CommunicationHub.js +16 -0
  149. package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
  150. package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
  151. package/runtime/arcane/modules/ComponentContracts.js +586 -0
  152. package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
  153. package/runtime/arcane/modules/ConversationActionItems.js +488 -0
  154. package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
  155. package/runtime/arcane/modules/ConversationTimebox.js +527 -0
  156. package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
  157. package/runtime/arcane/modules/DBLS.js +171 -0
  158. package/runtime/arcane/modules/DBOPFS.js +1154 -0
  159. package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
  160. package/runtime/arcane/modules/DataMaintenance.js +91 -0
  161. package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
  162. package/runtime/arcane/modules/DirectoryPicker.js +109 -0
  163. package/runtime/arcane/modules/DocumentNavigation.js +223 -0
  164. package/runtime/arcane/modules/Errors.js +1025 -0
  165. package/runtime/arcane/modules/GifEncoder.js +29 -0
  166. package/runtime/arcane/modules/HTMLImport.js +114 -0
  167. package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
  168. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
  169. package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
  170. package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
  171. package/runtime/arcane/modules/MD.js +111 -0
  172. package/runtime/arcane/modules/Mail.js +352 -0
  173. package/runtime/arcane/modules/MailTransport.mjs +180 -0
  174. package/runtime/arcane/modules/Marked.min.js +71 -0
  175. package/runtime/arcane/modules/MemoryRecords.js +44 -0
  176. package/runtime/arcane/modules/MessageAdvisory.js +38 -0
  177. package/runtime/arcane/modules/ModelDefinition.js +189 -0
  178. package/runtime/arcane/modules/Ollama.js +74 -0
  179. package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
  180. package/runtime/arcane/modules/OllamaSettings.js +24 -0
  181. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
  182. package/runtime/arcane/modules/PreferenceStore.js +109 -0
  183. package/runtime/arcane/modules/QRCode.min.js +1 -0
  184. package/runtime/arcane/modules/Questionnaire.js +61 -0
  185. package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
  186. package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
  187. package/runtime/arcane/modules/RecordReviewStore.js +94 -0
  188. package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
  189. package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
  190. package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
  191. package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
  192. package/runtime/arcane/modules/ScreenCapture.js +20 -0
  193. package/runtime/arcane/modules/SpeechPlayback.js +581 -0
  194. package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
  195. package/runtime/arcane/modules/SystemAppearance.js +20 -0
  196. package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
  197. package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
  198. package/runtime/arcane/modules/TerminalClient.js +52 -0
  199. package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
  200. package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
  201. package/runtime/arcane/modules/ThemeManager.js +131 -0
  202. package/runtime/arcane/modules/TimeGuard.js +149 -0
  203. package/runtime/arcane/modules/ToolCallRouter.js +83 -0
  204. package/runtime/arcane/modules/WaitForComponent.js +102 -0
  205. package/runtime/arcane/modules/YouTubeMedia.js +16 -0
  206. package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
  207. package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
  208. package/runtime/arcane/modules/uPlot.min.css +1 -0
  209. package/runtime/arcane/security/arcane-network-policy.json +6 -0
  210. package/runtime/strong-type/index.js +352 -0
  211. package/runtime/strong-type/licence +21 -0
  212. package/runtime/strong-type/package.json +45 -0
  213. package/schemas/arcane-app-bundle.schema.json +125 -0
  214. package/schemas/arcane-app.schema.json +329 -0
  215. package/schemas/arcane-lock.schema.json +86 -0
  216. package/schemas/arcane-package.schema.json +224 -0
  217. package/schemas/cli-event.schema.json +122 -0
  218. package/schemas/event-stack.schema.json +152 -0
  219. package/schemas/native-build-plan.schema.json +176 -0
  220. package/schemas/target-adapter.schema.json +117 -0
  221. package/src/app-descriptor.mjs +500 -0
  222. package/src/cli/main.mjs +561 -0
  223. package/src/constants.mjs +31 -0
  224. package/src/dev-server.mjs +718 -0
  225. package/src/doctor.mjs +315 -0
  226. package/src/dom-event-instrumentation.mjs +594 -0
  227. package/src/errors.mjs +75 -0
  228. package/src/event-manager.mjs +1342 -0
  229. package/src/event-queue.mjs +138 -0
  230. package/src/events.mjs +219 -0
  231. package/src/index.mjs +177 -0
  232. package/src/integrated-provider-loader.mjs +432 -0
  233. package/src/native-plan.mjs +698 -0
  234. package/src/native-provider-loader.mjs +1126 -0
  235. package/src/packager/core.mjs +2691 -0
  236. package/src/process.mjs +353 -0
  237. package/src/release-bundle.mjs +2523 -0
  238. package/src/repository.mjs +90 -0
  239. package/src/runtime.mjs +452 -0
  240. package/src/scaffold.mjs +380 -0
  241. package/src/targets/index.mjs +436 -0
  242. package/src/templates/assets/app-icon.png +0 -0
  243. package/src/templates/workspace-template.mjs +388 -0
  244. package/src/testing-loader.mjs +9 -0
  245. package/src/testing.mjs +427 -0
  246. package/src/toolchain.mjs +1335 -0
  247. package/src/update-check.mjs +307 -0
  248. package/src/workspace.mjs +449 -0
@@ -0,0 +1,1623 @@
1
+ const PROJECTION_LEDGER_SCHEMA_VERSION = '1.0.0';
2
+ const DEFAULT_PROJECTION_LEDGER_CAPACITY = 500;
3
+ const MAX_PROJECTION_LEDGER_CAPACITY = 5000;
4
+ const MAX_PROJECTION_LEDGER_DEPTH = 24;
5
+ const MAX_PROJECTION_LEDGER_NODES = 5000;
6
+ const MAX_PROJECTION_LEDGER_ARRAY_ITEMS = 1000;
7
+ const MAX_PROJECTION_LEDGER_OBJECT_KEYS = 1000;
8
+ const MAX_PROJECTION_LEDGER_OBJECT_KEY_LENGTH = 256;
9
+ const MAX_PROJECTION_LEDGER_STRING_LENGTH = 16000;
10
+ const MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS = 64000;
11
+ const MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES = 128000;
12
+ const MAX_PROJECTION_LEDGER_KEY_LENGTH = 256;
13
+ const MIN_PROJECTION_LEDGER_STORED_CHARACTERS = 128000;
14
+ const DEFAULT_PROJECTION_LEDGER_STORED_CHARACTERS = 4000000;
15
+ const MAX_PROJECTION_LEDGER_STORED_CHARACTERS = 16000000;
16
+ const MIN_PROJECTION_LEDGER_STORED_UTF8_BYTES = 256000;
17
+ const DEFAULT_PROJECTION_LEDGER_STORED_UTF8_BYTES = 8000000;
18
+ const MAX_PROJECTION_LEDGER_STORED_UTF8_BYTES = 32000000;
19
+ const MIN_PROJECTION_LEDGER_STORED_NODES = 10000;
20
+ const DEFAULT_PROJECTION_LEDGER_STORED_NODES = 500000;
21
+ const MAX_PROJECTION_LEDGER_STORED_NODES = 2000000;
22
+
23
+ const PROJECTION_LEDGER_STATUSES = Object.freeze(
24
+ {
25
+ ACTIVE_TARGET_CONFLICT: 'active-target-conflict',
26
+ ALREADY_REVOKED: 'already-revoked',
27
+ CAPACITY_REACHED: 'capacity-reached',
28
+ EXISTS: 'exists',
29
+ NOT_FOUND: 'not-found',
30
+ REVOKED: 'revoked',
31
+ SOURCE_CONFLICT: 'source-conflict',
32
+ SOURCE_REVOKED: 'source-revoked',
33
+ STORED: 'stored'
34
+ }
35
+ );
36
+
37
+ const PROJECTION_LEDGER_REASON_CODES = Object.freeze(
38
+ {
39
+ INVALID_INPUT: 'INVALID_INPUT'
40
+ }
41
+ );
42
+
43
+ const PROJECTION_LEDGER_LIMITS = Object.freeze(
44
+ {
45
+ defaultCapacity: DEFAULT_PROJECTION_LEDGER_CAPACITY,
46
+ maximumCapacity: MAX_PROJECTION_LEDGER_CAPACITY,
47
+ maximumDepth: MAX_PROJECTION_LEDGER_DEPTH,
48
+ maximumNodes: MAX_PROJECTION_LEDGER_NODES,
49
+ maximumArrayItems: MAX_PROJECTION_LEDGER_ARRAY_ITEMS,
50
+ maximumObjectKeys: MAX_PROJECTION_LEDGER_OBJECT_KEYS,
51
+ maximumObjectKeyLength: MAX_PROJECTION_LEDGER_OBJECT_KEY_LENGTH,
52
+ maximumStringLength: MAX_PROJECTION_LEDGER_STRING_LENGTH,
53
+ maximumTotalCharacters: MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS,
54
+ maximumTotalUtf8Bytes: MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES,
55
+ maximumLedgerKeyLength: MAX_PROJECTION_LEDGER_KEY_LENGTH,
56
+ minimumStoredCharacters: MIN_PROJECTION_LEDGER_STORED_CHARACTERS,
57
+ defaultStoredCharacters: DEFAULT_PROJECTION_LEDGER_STORED_CHARACTERS,
58
+ maximumStoredCharacters: MAX_PROJECTION_LEDGER_STORED_CHARACTERS,
59
+ minimumStoredUtf8Bytes: MIN_PROJECTION_LEDGER_STORED_UTF8_BYTES,
60
+ defaultStoredUtf8Bytes: DEFAULT_PROJECTION_LEDGER_STORED_UTF8_BYTES,
61
+ maximumStoredUtf8Bytes: MAX_PROJECTION_LEDGER_STORED_UTF8_BYTES,
62
+ minimumStoredNodes: MIN_PROJECTION_LEDGER_STORED_NODES,
63
+ defaultStoredNodes: DEFAULT_PROJECTION_LEDGER_STORED_NODES,
64
+ maximumStoredNodes: MAX_PROJECTION_LEDGER_STORED_NODES
65
+ }
66
+ );
67
+
68
+ const PROHIBITED_PROJECTION_LEDGER_KEYS = new Set(
69
+ [
70
+ '__proto__',
71
+ 'constructor',
72
+ 'prototype'
73
+ ]
74
+ );
75
+
76
+ const PROJECTION_INPUT_KEYS = new Set(
77
+ [
78
+ 'sourceKey',
79
+ 'targetKey',
80
+ 'identity',
81
+ 'payload'
82
+ ]
83
+ );
84
+
85
+ const REVOCATION_INPUT_KEYS = new Set(
86
+ [
87
+ 'projectionId',
88
+ 'payload'
89
+ ]
90
+ );
91
+
92
+ const OPTIONS_KEYS = new Set(
93
+ [
94
+ 'capacity',
95
+ 'maximumStoredCharacters',
96
+ 'maximumStoredUtf8Bytes',
97
+ 'maximumStoredNodes'
98
+ ]
99
+ );
100
+
101
+ class ProjectionLedgerError extends TypeError {
102
+ constructor(reasonCode, message) {
103
+ super(message);
104
+ this.name = 'ProjectionLedgerError';
105
+ this.reasonCode = reasonCode;
106
+ }
107
+ }
108
+
109
+ function invalidProjectionLedgerBoundary(label, detail) {
110
+ return new ProjectionLedgerError(
111
+ PROJECTION_LEDGER_REASON_CODES.INVALID_INPUT,
112
+ `${label} ${detail}`
113
+ );
114
+ }
115
+
116
+ function readProjectionLedgerPrototype(value, label) {
117
+ try {
118
+ return Object.getPrototypeOf(value);
119
+ } catch (error) {
120
+ throw invalidProjectionLedgerBoundary(
121
+ label,
122
+ 'could not be inspected safely.'
123
+ );
124
+ }
125
+ }
126
+
127
+ function readProjectionLedgerOwnKeys(value, label) {
128
+ try {
129
+ return Reflect.ownKeys(value);
130
+ } catch (error) {
131
+ throw invalidProjectionLedgerBoundary(
132
+ label,
133
+ 'could not be inspected safely.'
134
+ );
135
+ }
136
+ }
137
+
138
+ function readProjectionLedgerOwnDescriptor(value, key, label) {
139
+ try {
140
+ return Reflect.getOwnPropertyDescriptor(value, key);
141
+ } catch (error) {
142
+ throw invalidProjectionLedgerBoundary(
143
+ label,
144
+ 'could not be inspected safely.'
145
+ );
146
+ }
147
+ }
148
+
149
+ function readProjectionLedgerDescriptors(value, keys, label) {
150
+ const descriptors = Object.create(null);
151
+
152
+ for (const key of keys) {
153
+ const descriptor = readProjectionLedgerOwnDescriptor(value, key, label);
154
+
155
+ if (!descriptor) {
156
+ throw invalidProjectionLedgerBoundary(
157
+ label,
158
+ 'changed while it was being inspected.'
159
+ );
160
+ }
161
+
162
+ Object.defineProperty(
163
+ descriptors,
164
+ key,
165
+ {
166
+ configurable: true,
167
+ enumerable: true,
168
+ value: descriptor,
169
+ writable: true
170
+ }
171
+ );
172
+ }
173
+
174
+ return descriptors;
175
+ }
176
+
177
+ function inspectProjectionLedgerArray(value, label) {
178
+ try {
179
+ return Array.isArray(value);
180
+ } catch (error) {
181
+ throw invalidProjectionLedgerBoundary(
182
+ label,
183
+ 'could not be inspected safely.'
184
+ );
185
+ }
186
+ }
187
+
188
+ function assertProjectionLedgerDataDescriptor(descriptor, label) {
189
+ if (!descriptor
190
+ || Object.hasOwn(descriptor, 'get')
191
+ || Object.hasOwn(descriptor, 'set')) {
192
+ throw invalidProjectionLedgerBoundary(
193
+ label,
194
+ 'contains an accessor property.'
195
+ );
196
+ }
197
+
198
+ if (!descriptor.enumerable) {
199
+ throw invalidProjectionLedgerBoundary(
200
+ label,
201
+ 'contains a hidden property.'
202
+ );
203
+ }
204
+ }
205
+
206
+ function incrementProjectionLedgerNodeCount(label, state) {
207
+ state.nodes += 1;
208
+
209
+ if (state.nodes > MAX_PROJECTION_LEDGER_NODES) {
210
+ throw invalidProjectionLedgerBoundary(
211
+ label,
212
+ 'contains too many values.'
213
+ );
214
+ }
215
+ }
216
+
217
+ function projectionLedgerUtf8ByteLength(value) {
218
+ let bytes = 0;
219
+
220
+ for (let index = 0; index < value.length; index += 1) {
221
+ const codeUnit = value.charCodeAt(index);
222
+
223
+ if (codeUnit <= 0x7f) {
224
+ bytes += 1;
225
+ } else if (codeUnit <= 0x7ff) {
226
+ bytes += 2;
227
+ } else if (codeUnit >= 0xd800
228
+ && codeUnit <= 0xdbff
229
+ && index + 1 < value.length) {
230
+ const nextCodeUnit = value.charCodeAt(index + 1);
231
+
232
+ if (nextCodeUnit >= 0xdc00 && nextCodeUnit <= 0xdfff) {
233
+ bytes += 4;
234
+ index += 1;
235
+ } else {
236
+ bytes += 3;
237
+ }
238
+ } else {
239
+ bytes += 3;
240
+ }
241
+ }
242
+
243
+ return bytes;
244
+ }
245
+
246
+ function consumeProjectionLedgerStringBudget(value, label, state) {
247
+ state.characters += value.length;
248
+ state.utf8Bytes += projectionLedgerUtf8ByteLength(value);
249
+
250
+ if (state.characters > MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS) {
251
+ throw invalidProjectionLedgerBoundary(
252
+ label,
253
+ 'exceeds the cumulative character budget.'
254
+ );
255
+ }
256
+
257
+ if (state.utf8Bytes > MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES) {
258
+ throw invalidProjectionLedgerBoundary(
259
+ label,
260
+ 'exceeds the cumulative UTF-8 byte budget.'
261
+ );
262
+ }
263
+ }
264
+
265
+ function precheckProjectionLedgerArrayKeys(keys, length, label) {
266
+ if (keys.length > MAX_PROJECTION_LEDGER_ARRAY_ITEMS + 1) {
267
+ throw invalidProjectionLedgerBoundary(
268
+ label,
269
+ 'contains too many array properties.'
270
+ );
271
+ }
272
+
273
+ for (const key of keys) {
274
+ if (typeof key !== 'string') {
275
+ throw invalidProjectionLedgerBoundary(
276
+ label,
277
+ 'contains a symbol key.'
278
+ );
279
+ }
280
+
281
+ if (key === 'length') {
282
+ continue;
283
+ }
284
+
285
+ if (!/^(?:0|[1-9][0-9]*)$/.test(key)
286
+ || Number(key) >= length) {
287
+ throw invalidProjectionLedgerBoundary(
288
+ label,
289
+ 'contains a non-index array property.'
290
+ );
291
+ }
292
+ }
293
+ }
294
+
295
+ function precheckProjectionLedgerObjectKeys(keys, label) {
296
+ if (keys.length > MAX_PROJECTION_LEDGER_OBJECT_KEYS) {
297
+ throw invalidProjectionLedgerBoundary(
298
+ label,
299
+ 'contains too many object keys.'
300
+ );
301
+ }
302
+
303
+ for (const key of keys) {
304
+ if (typeof key !== 'string') {
305
+ throw invalidProjectionLedgerBoundary(
306
+ label,
307
+ 'contains a symbol key.'
308
+ );
309
+ }
310
+
311
+ if (key.length > MAX_PROJECTION_LEDGER_OBJECT_KEY_LENGTH) {
312
+ throw invalidProjectionLedgerBoundary(
313
+ label,
314
+ 'contains an object key that is too long.'
315
+ );
316
+ }
317
+
318
+ if (PROHIBITED_PROJECTION_LEDGER_KEYS.has(key)) {
319
+ throw invalidProjectionLedgerBoundary(
320
+ label,
321
+ 'contains a prohibited object key.'
322
+ );
323
+ }
324
+ }
325
+ }
326
+
327
+ function assertProjectionLedgerKeysUnchanged(expectedKeys, actualKeys, label) {
328
+ if (expectedKeys.length !== actualKeys.length) {
329
+ throw invalidProjectionLedgerBoundary(
330
+ label,
331
+ 'changed while it was being inspected.'
332
+ );
333
+ }
334
+
335
+ const expectedKeySet = new Set(expectedKeys);
336
+
337
+ for (const key of actualKeys) {
338
+ if (!expectedKeySet.has(key)) {
339
+ throw invalidProjectionLedgerBoundary(
340
+ label,
341
+ 'changed while it was being inspected.'
342
+ );
343
+ }
344
+ }
345
+ }
346
+
347
+ function cloneProjectionLedgerArray(value, label, depth, state) {
348
+ const prototype = readProjectionLedgerPrototype(value, label);
349
+
350
+ if (prototype !== Array.prototype) {
351
+ throw invalidProjectionLedgerBoundary(
352
+ label,
353
+ 'must contain only ordinary arrays.'
354
+ );
355
+ }
356
+
357
+ const lengthDescriptor = readProjectionLedgerOwnDescriptor(
358
+ value,
359
+ 'length',
360
+ label
361
+ );
362
+
363
+ if (!lengthDescriptor
364
+ || Object.hasOwn(lengthDescriptor, 'get')
365
+ || Object.hasOwn(lengthDescriptor, 'set')
366
+ || !Number.isInteger(lengthDescriptor.value)
367
+ || lengthDescriptor.value < 0) {
368
+ throw invalidProjectionLedgerBoundary(
369
+ label,
370
+ 'contains an invalid array length.'
371
+ );
372
+ }
373
+
374
+ const length = lengthDescriptor.value;
375
+
376
+ if (length > MAX_PROJECTION_LEDGER_ARRAY_ITEMS) {
377
+ throw invalidProjectionLedgerBoundary(
378
+ label,
379
+ 'contains too many array items.'
380
+ );
381
+ }
382
+
383
+ const keys = readProjectionLedgerOwnKeys(value, label);
384
+ precheckProjectionLedgerArrayKeys(keys, length, label);
385
+ const descriptors = readProjectionLedgerDescriptors(value, keys, label);
386
+ const verifiedKeys = readProjectionLedgerOwnKeys(value, label);
387
+ precheckProjectionLedgerArrayKeys(verifiedKeys, length, label);
388
+ assertProjectionLedgerKeysUnchanged(keys, verifiedKeys, label);
389
+
390
+ for (const key of keys) {
391
+ if (key === 'length') {
392
+ continue;
393
+ }
394
+
395
+ assertProjectionLedgerDataDescriptor(descriptors[key], label);
396
+ }
397
+
398
+ const output = [];
399
+
400
+ for (let index = 0; index < length; index += 1) {
401
+ const descriptor = descriptors[String(index)];
402
+
403
+ if (!descriptor) {
404
+ throw invalidProjectionLedgerBoundary(
405
+ label,
406
+ 'contains a sparse array item.'
407
+ );
408
+ }
409
+
410
+ output.push(
411
+ cloneProjectionLedgerNode(
412
+ descriptor.value,
413
+ `${label} item`,
414
+ depth + 1,
415
+ state
416
+ )
417
+ );
418
+ }
419
+
420
+ return output;
421
+ }
422
+
423
+ function cloneProjectionLedgerRecord(value, label, depth, state) {
424
+ const prototype = readProjectionLedgerPrototype(value, label);
425
+
426
+ if (prototype !== Object.prototype && prototype !== null) {
427
+ throw invalidProjectionLedgerBoundary(
428
+ label,
429
+ 'must contain only plain objects.'
430
+ );
431
+ }
432
+
433
+ const keys = readProjectionLedgerOwnKeys(value, label);
434
+ precheckProjectionLedgerObjectKeys(keys, label);
435
+ const descriptors = readProjectionLedgerDescriptors(value, keys, label);
436
+ const verifiedKeys = readProjectionLedgerOwnKeys(value, label);
437
+ precheckProjectionLedgerObjectKeys(verifiedKeys, label);
438
+ assertProjectionLedgerKeysUnchanged(keys, verifiedKeys, label);
439
+
440
+ const output = Object.create(null);
441
+
442
+ for (const key of keys) {
443
+ consumeProjectionLedgerStringBudget(key, label, state);
444
+ const descriptor = descriptors[key];
445
+ assertProjectionLedgerDataDescriptor(descriptor, label);
446
+ Object.defineProperty(
447
+ output,
448
+ key,
449
+ {
450
+ configurable: true,
451
+ enumerable: true,
452
+ value: cloneProjectionLedgerNode(
453
+ descriptor.value,
454
+ `${label} child`,
455
+ depth + 1,
456
+ state
457
+ ),
458
+ writable: true
459
+ }
460
+ );
461
+ }
462
+
463
+ return output;
464
+ }
465
+
466
+ function cloneProjectionLedgerNode(value, label, depth, state) {
467
+ incrementProjectionLedgerNodeCount(label, state);
468
+
469
+ if (depth > MAX_PROJECTION_LEDGER_DEPTH) {
470
+ throw invalidProjectionLedgerBoundary(
471
+ label,
472
+ 'is nested too deeply.'
473
+ );
474
+ }
475
+
476
+ if (value === null || typeof value === 'boolean') {
477
+ return value;
478
+ }
479
+
480
+ if (typeof value === 'string') {
481
+ if (value.length > MAX_PROJECTION_LEDGER_STRING_LENGTH) {
482
+ throw invalidProjectionLedgerBoundary(
483
+ label,
484
+ 'contains a string that is too long.'
485
+ );
486
+ }
487
+
488
+ consumeProjectionLedgerStringBudget(value, label, state);
489
+
490
+ return value;
491
+ }
492
+
493
+ if (typeof value === 'number') {
494
+ if (!Number.isFinite(value)) {
495
+ throw invalidProjectionLedgerBoundary(
496
+ label,
497
+ 'contains a non-finite number.'
498
+ );
499
+ }
500
+
501
+ return value;
502
+ }
503
+
504
+ if (typeof value !== 'object') {
505
+ throw invalidProjectionLedgerBoundary(
506
+ label,
507
+ 'contains an unsupported value type.'
508
+ );
509
+ }
510
+
511
+ if (state.ancestors.has(value)) {
512
+ throw invalidProjectionLedgerBoundary(
513
+ label,
514
+ 'contains a cyclic reference.'
515
+ );
516
+ }
517
+
518
+ state.ancestors.add(value);
519
+
520
+ try {
521
+ if (inspectProjectionLedgerArray(value, label)) {
522
+ return cloneProjectionLedgerArray(value, label, depth, state);
523
+ }
524
+
525
+ return cloneProjectionLedgerRecord(value, label, depth, state);
526
+ } finally {
527
+ state.ancestors.delete(value);
528
+ }
529
+ }
530
+
531
+ function cloneProjectionLedgerValueWithMetrics(value, label) {
532
+ const state = {
533
+ ancestors: new WeakSet(),
534
+ characters: 0,
535
+ nodes: 0,
536
+ utf8Bytes: 0
537
+ };
538
+ const clonedValue = cloneProjectionLedgerNode(
539
+ value,
540
+ label,
541
+ 0,
542
+ state
543
+ );
544
+
545
+ return {
546
+ value: clonedValue,
547
+ metrics: {
548
+ characters: state.characters,
549
+ nodes: state.nodes,
550
+ utf8Bytes: state.utf8Bytes
551
+ }
552
+ };
553
+ }
554
+
555
+ function cloneProjectionLedgerValue(value, label = 'Value') {
556
+ return cloneProjectionLedgerValueWithMetrics(value, label).value;
557
+ }
558
+
559
+ function isProjectionLedgerRecord(value) {
560
+ if (!value || typeof value !== 'object') {
561
+ return false;
562
+ }
563
+
564
+ if (inspectProjectionLedgerArray(value, 'Record')) {
565
+ return false;
566
+ }
567
+
568
+ const prototype = readProjectionLedgerPrototype(value, 'Record');
569
+ return prototype === Object.prototype || prototype === null;
570
+ }
571
+
572
+ function stableProjectionLedgerValue(value) {
573
+ if (Array.isArray(value)) {
574
+ const output = [];
575
+
576
+ for (const item of value) {
577
+ output.push(stableProjectionLedgerValue(item));
578
+ }
579
+
580
+ return output;
581
+ }
582
+
583
+ if (value && typeof value === 'object') {
584
+ const output = Object.create(null);
585
+ const keys = Object.keys(value).sort();
586
+
587
+ for (const key of keys) {
588
+ output[key] = stableProjectionLedgerValue(value[key]);
589
+ }
590
+
591
+ return output;
592
+ }
593
+
594
+ return value;
595
+ }
596
+
597
+ function canonicalProjectionLedgerTextFromSafeValue(value) {
598
+ return JSON.stringify(stableProjectionLedgerValue(value));
599
+ }
600
+
601
+ function createProjectionLedgerFingerprintFromSafeValue(value) {
602
+ const text = canonicalProjectionLedgerTextFromSafeValue(value);
603
+ let hash = 2166136261;
604
+
605
+ for (let index = 0; index < text.length; index += 1) {
606
+ hash ^= text.charCodeAt(index);
607
+ hash = Math.imul(hash, 16777619);
608
+ }
609
+
610
+ return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, '0')}`;
611
+ }
612
+
613
+ function createProjectionLedgerFingerprint(value) {
614
+ const safeValue = cloneProjectionLedgerValue(value, 'Fingerprint value');
615
+ return createProjectionLedgerFingerprintFromSafeValue(safeValue);
616
+ }
617
+
618
+ function deepFreezeProjectionLedgerValue(value) {
619
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
620
+ return value;
621
+ }
622
+
623
+ if (Array.isArray(value)) {
624
+ for (const item of value) {
625
+ deepFreezeProjectionLedgerValue(item);
626
+ }
627
+ } else {
628
+ for (const key of Object.keys(value)) {
629
+ deepFreezeProjectionLedgerValue(value[key]);
630
+ }
631
+ }
632
+
633
+ return Object.freeze(value);
634
+ }
635
+
636
+ function immutableProjectionLedgerRecord(record, label) {
637
+ const cloned = cloneProjectionLedgerValueWithMetrics(record, label);
638
+
639
+ return {
640
+ record: deepFreezeProjectionLedgerValue(cloned.value),
641
+ metrics: Object.freeze(cloned.metrics)
642
+ };
643
+ }
644
+
645
+ function cloneProjectionLedgerRecordForOutput(record, label) {
646
+ if (!record) {
647
+ return null;
648
+ }
649
+
650
+ return cloneProjectionLedgerValue(record, label);
651
+ }
652
+
653
+ function normalizeProjectionLedgerKey(value, label) {
654
+ if (typeof value !== 'string') {
655
+ throw invalidProjectionLedgerBoundary(label, 'must be a string.');
656
+ }
657
+
658
+ const normalized = value.normalize('NFKC').trim();
659
+
660
+ if (!normalized) {
661
+ throw invalidProjectionLedgerBoundary(label, 'must not be empty.');
662
+ }
663
+
664
+ if (normalized.length > MAX_PROJECTION_LEDGER_KEY_LENGTH) {
665
+ throw invalidProjectionLedgerBoundary(label, 'is too long.');
666
+ }
667
+
668
+ if (/[\u0000-\u001f\u007f-\u009f]/.test(normalized)) {
669
+ throw invalidProjectionLedgerBoundary(
670
+ label,
671
+ 'contains a control character.'
672
+ );
673
+ }
674
+
675
+ return normalized;
676
+ }
677
+
678
+ function assertProjectionLedgerRecord(value, label) {
679
+ if (!isProjectionLedgerRecord(value)) {
680
+ throw invalidProjectionLedgerBoundary(label, 'must be a plain object.');
681
+ }
682
+ }
683
+
684
+ function assertProjectionLedgerRecordKeys(record, allowedKeys, requiredKeys, label) {
685
+ for (const key of Object.keys(record)) {
686
+ if (!allowedKeys.has(key)) {
687
+ throw invalidProjectionLedgerBoundary(
688
+ label,
689
+ `contains unsupported key ${key}.`
690
+ );
691
+ }
692
+ }
693
+
694
+ for (const key of requiredKeys) {
695
+ if (!Object.hasOwn(record, key)) {
696
+ throw invalidProjectionLedgerBoundary(
697
+ label,
698
+ `requires ${key}.`
699
+ );
700
+ }
701
+ }
702
+ }
703
+
704
+ function normalizeProjectionLedgerBudget(
705
+ options,
706
+ key,
707
+ defaultValue,
708
+ minimum,
709
+ maximum,
710
+ label
711
+ ) {
712
+ const value = Object.hasOwn(options, key)
713
+ ? options[key]
714
+ : defaultValue;
715
+
716
+ if (!Number.isInteger(value) || value < minimum || value > maximum) {
717
+ throw invalidProjectionLedgerBoundary(
718
+ label,
719
+ `must be an integer from ${minimum} through ${maximum}.`
720
+ );
721
+ }
722
+
723
+ return value;
724
+ }
725
+
726
+ function normalizeProjectionLedgerOptions(options) {
727
+ const safeOptions = cloneProjectionLedgerValue(options, 'Ledger options');
728
+ assertProjectionLedgerRecord(safeOptions, 'Ledger options');
729
+ assertProjectionLedgerRecordKeys(
730
+ safeOptions,
731
+ OPTIONS_KEYS,
732
+ [],
733
+ 'Ledger options'
734
+ );
735
+ return {
736
+ capacity: normalizeProjectionLedgerBudget(
737
+ safeOptions,
738
+ 'capacity',
739
+ DEFAULT_PROJECTION_LEDGER_CAPACITY,
740
+ 1,
741
+ MAX_PROJECTION_LEDGER_CAPACITY,
742
+ 'Ledger capacity'
743
+ ),
744
+ maximumStoredCharacters: normalizeProjectionLedgerBudget(
745
+ safeOptions,
746
+ 'maximumStoredCharacters',
747
+ DEFAULT_PROJECTION_LEDGER_STORED_CHARACTERS,
748
+ MIN_PROJECTION_LEDGER_STORED_CHARACTERS,
749
+ MAX_PROJECTION_LEDGER_STORED_CHARACTERS,
750
+ 'Ledger maximumStoredCharacters'
751
+ ),
752
+ maximumStoredUtf8Bytes: normalizeProjectionLedgerBudget(
753
+ safeOptions,
754
+ 'maximumStoredUtf8Bytes',
755
+ DEFAULT_PROJECTION_LEDGER_STORED_UTF8_BYTES,
756
+ MIN_PROJECTION_LEDGER_STORED_UTF8_BYTES,
757
+ MAX_PROJECTION_LEDGER_STORED_UTF8_BYTES,
758
+ 'Ledger maximumStoredUtf8Bytes'
759
+ ),
760
+ maximumStoredNodes: normalizeProjectionLedgerBudget(
761
+ safeOptions,
762
+ 'maximumStoredNodes',
763
+ DEFAULT_PROJECTION_LEDGER_STORED_NODES,
764
+ MIN_PROJECTION_LEDGER_STORED_NODES,
765
+ MAX_PROJECTION_LEDGER_STORED_NODES,
766
+ 'Ledger maximumStoredNodes'
767
+ )
768
+ };
769
+ }
770
+
771
+ function formatProjectionLedgerSequence(sequence) {
772
+ return String(sequence).padStart(6, '0');
773
+ }
774
+
775
+ /**
776
+ * Keeps append-only projection and revocation events in bounded page memory.
777
+ *
778
+ * Inputs and outputs are descriptor-safe JSON-like values. The ledger does not
779
+ * persist, communicate, authorize, or attach domain meaning to either key.
780
+ * Operations are asynchronous for adapter compatibility but complete entirely
781
+ * in memory before their returned promise settles. Capacity counts projection
782
+ * slots; each slot includes one reserved revocation event, so every projection
783
+ * can always be revoked and total events cannot exceed twice the capacity.
784
+ * Ledger-wide character, UTF-8 byte, and node budgets count committed records
785
+ * plus worst-case reserved revocations before any new projection is accepted.
786
+ * Constructor options are `capacity`, `maximumStoredCharacters`,
787
+ * `maximumStoredUtf8Bytes`, and `maximumStoredNodes`; their defaults are 500,
788
+ * 4,000,000, 8,000,000, and 500,000. `remainingCapacity` reports unused
789
+ * projection slots, while the `remainingStored*` getters include reservations.
790
+ */
791
+ class RevocableProjectionLedger {
792
+ #activeProjectionByTarget = new Map();
793
+ #capacity;
794
+ #maximumStoredCharacters;
795
+ #maximumStoredNodes;
796
+ #maximumStoredUtf8Bytes;
797
+ #projectionById = new Map();
798
+ #projectionBySource = new Map();
799
+ #projectionRecords = [];
800
+ #reservedRevocationCharacters = 0;
801
+ #reservedRevocationNodes = 0;
802
+ #reservedRevocationUtf8Bytes = 0;
803
+ #revocationByProjectionId = new Map();
804
+ #revocationRecords = [];
805
+ #sequence = 0;
806
+ #storedCharacters = 0;
807
+ #storedNodes = 0;
808
+ #storedUtf8Bytes = 0;
809
+
810
+ constructor(options = {}) {
811
+ const settings = normalizeProjectionLedgerOptions(options);
812
+ this.#capacity = settings.capacity;
813
+ this.#maximumStoredCharacters = settings.maximumStoredCharacters;
814
+ this.#maximumStoredUtf8Bytes = settings.maximumStoredUtf8Bytes;
815
+ this.#maximumStoredNodes = settings.maximumStoredNodes;
816
+ }
817
+
818
+ get capacity() {
819
+ return this.#capacity;
820
+ }
821
+
822
+ get eventCount() {
823
+ return this.#projectionRecords.length + this.#revocationRecords.length;
824
+ }
825
+
826
+ get eventCapacity() {
827
+ return this.#capacity * 2;
828
+ }
829
+
830
+ get maximumStoredCharacters() {
831
+ return this.#maximumStoredCharacters;
832
+ }
833
+
834
+ get maximumStoredUtf8Bytes() {
835
+ return this.#maximumStoredUtf8Bytes;
836
+ }
837
+
838
+ get maximumStoredNodes() {
839
+ return this.#maximumStoredNodes;
840
+ }
841
+
842
+ get storedCharacters() {
843
+ return this.#storedCharacters;
844
+ }
845
+
846
+ get storedUtf8Bytes() {
847
+ return this.#storedUtf8Bytes;
848
+ }
849
+
850
+ get storedNodes() {
851
+ return this.#storedNodes;
852
+ }
853
+
854
+ get reservedRevocationCharacters() {
855
+ return this.#reservedRevocationCharacters;
856
+ }
857
+
858
+ get reservedRevocationUtf8Bytes() {
859
+ return this.#reservedRevocationUtf8Bytes;
860
+ }
861
+
862
+ get reservedRevocationNodes() {
863
+ return this.#reservedRevocationNodes;
864
+ }
865
+
866
+ get remainingStoredCharacters() {
867
+ return this.#maximumStoredCharacters
868
+ - this.#storedCharacters
869
+ - this.#reservedRevocationCharacters;
870
+ }
871
+
872
+ get remainingStoredUtf8Bytes() {
873
+ return this.#maximumStoredUtf8Bytes
874
+ - this.#storedUtf8Bytes
875
+ - this.#reservedRevocationUtf8Bytes;
876
+ }
877
+
878
+ get remainingStoredNodes() {
879
+ return this.#maximumStoredNodes
880
+ - this.#storedNodes
881
+ - this.#reservedRevocationNodes;
882
+ }
883
+
884
+ get remainingCapacity() {
885
+ return this.#capacity - this.#projectionRecords.length;
886
+ }
887
+
888
+ #projectionBudgetResult(metrics) {
889
+ if (metrics.characters + MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS
890
+ > this.remainingStoredCharacters) {
891
+ return {
892
+ status: PROJECTION_LEDGER_STATUSES.CAPACITY_REACHED,
893
+ capacity: this.#capacity,
894
+ capacityReason: 'stored-character-budget',
895
+ maximumStoredCharacters: this.#maximumStoredCharacters,
896
+ remainingStoredCharacters: this.remainingStoredCharacters,
897
+ remainingCapacity: this.remainingCapacity,
898
+ idempotent: false
899
+ };
900
+ }
901
+
902
+ if (metrics.utf8Bytes + MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES
903
+ > this.remainingStoredUtf8Bytes) {
904
+ return {
905
+ status: PROJECTION_LEDGER_STATUSES.CAPACITY_REACHED,
906
+ capacity: this.#capacity,
907
+ capacityReason: 'stored-utf8-budget',
908
+ maximumStoredUtf8Bytes: this.#maximumStoredUtf8Bytes,
909
+ remainingStoredUtf8Bytes: this.remainingStoredUtf8Bytes,
910
+ remainingCapacity: this.remainingCapacity,
911
+ idempotent: false
912
+ };
913
+ }
914
+
915
+ if (metrics.nodes + MAX_PROJECTION_LEDGER_NODES
916
+ > this.remainingStoredNodes) {
917
+ return {
918
+ status: PROJECTION_LEDGER_STATUSES.CAPACITY_REACHED,
919
+ capacity: this.#capacity,
920
+ capacityReason: 'stored-node-budget',
921
+ maximumStoredNodes: this.#maximumStoredNodes,
922
+ remainingStoredNodes: this.remainingStoredNodes,
923
+ remainingCapacity: this.remainingCapacity,
924
+ idempotent: false
925
+ };
926
+ }
927
+
928
+ return null;
929
+ }
930
+
931
+ #assertRevocationBudget(metrics) {
932
+ const charactersAfter = this.#storedCharacters
933
+ + metrics.characters
934
+ + this.#reservedRevocationCharacters
935
+ - MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS;
936
+ const utf8BytesAfter = this.#storedUtf8Bytes
937
+ + metrics.utf8Bytes
938
+ + this.#reservedRevocationUtf8Bytes
939
+ - MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES;
940
+ const nodesAfter = this.#storedNodes
941
+ + metrics.nodes
942
+ + this.#reservedRevocationNodes
943
+ - MAX_PROJECTION_LEDGER_NODES;
944
+
945
+ if (this.#reservedRevocationCharacters
946
+ < MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS
947
+ || this.#reservedRevocationUtf8Bytes
948
+ < MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES
949
+ || this.#reservedRevocationNodes < MAX_PROJECTION_LEDGER_NODES
950
+ || charactersAfter > this.#maximumStoredCharacters
951
+ || utf8BytesAfter > this.#maximumStoredUtf8Bytes
952
+ || nodesAfter > this.#maximumStoredNodes) {
953
+ throw new Error(
954
+ 'Projection ledger revocation reservation invariant failed.'
955
+ );
956
+ }
957
+ }
958
+
959
+ async appendProjection(input) {
960
+ const safeInput = cloneProjectionLedgerValue(
961
+ input,
962
+ 'Projection input'
963
+ );
964
+ assertProjectionLedgerRecord(safeInput, 'Projection input');
965
+ assertProjectionLedgerRecordKeys(
966
+ safeInput,
967
+ PROJECTION_INPUT_KEYS,
968
+ PROJECTION_INPUT_KEYS,
969
+ 'Projection input'
970
+ );
971
+
972
+ const sourceKey = normalizeProjectionLedgerKey(
973
+ safeInput.sourceKey,
974
+ 'Projection sourceKey'
975
+ );
976
+ const targetKey = normalizeProjectionLedgerKey(
977
+ safeInput.targetKey,
978
+ 'Projection targetKey'
979
+ );
980
+ assertProjectionLedgerRecord(
981
+ safeInput.identity,
982
+ 'Projection identity'
983
+ );
984
+ const identityText = canonicalProjectionLedgerTextFromSafeValue(
985
+ safeInput.identity
986
+ );
987
+ const existingForSource = this.#projectionBySource.get(sourceKey);
988
+
989
+ if (existingForSource) {
990
+ const revocation = this.#revocationByProjectionId.get(
991
+ existingForSource.id
992
+ );
993
+
994
+ if (revocation) {
995
+ return {
996
+ status: PROJECTION_LEDGER_STATUSES.SOURCE_REVOKED,
997
+ record: cloneProjectionLedgerRecordForOutput(
998
+ existingForSource,
999
+ 'Projection record'
1000
+ ),
1001
+ revocationRecord: cloneProjectionLedgerRecordForOutput(
1002
+ revocation,
1003
+ 'Revocation record'
1004
+ ),
1005
+ idempotent: false,
1006
+ remainingCapacity: this.remainingCapacity
1007
+ };
1008
+ }
1009
+
1010
+ const sameIdentity = canonicalProjectionLedgerTextFromSafeValue(
1011
+ existingForSource.identity
1012
+ ) === identityText;
1013
+
1014
+ if (existingForSource.targetKey === targetKey && sameIdentity) {
1015
+ return {
1016
+ status: PROJECTION_LEDGER_STATUSES.EXISTS,
1017
+ record: cloneProjectionLedgerRecordForOutput(
1018
+ existingForSource,
1019
+ 'Projection record'
1020
+ ),
1021
+ idempotent: true,
1022
+ remainingCapacity: this.remainingCapacity
1023
+ };
1024
+ }
1025
+
1026
+ return {
1027
+ status: PROJECTION_LEDGER_STATUSES.SOURCE_CONFLICT,
1028
+ record: cloneProjectionLedgerRecordForOutput(
1029
+ existingForSource,
1030
+ 'Projection record'
1031
+ ),
1032
+ idempotent: false,
1033
+ remainingCapacity: this.remainingCapacity
1034
+ };
1035
+ }
1036
+
1037
+ const activeForTarget = this.#activeProjectionByTarget.get(targetKey);
1038
+
1039
+ if (activeForTarget) {
1040
+ return {
1041
+ status: PROJECTION_LEDGER_STATUSES.ACTIVE_TARGET_CONFLICT,
1042
+ record: cloneProjectionLedgerRecordForOutput(
1043
+ activeForTarget,
1044
+ 'Projection record'
1045
+ ),
1046
+ idempotent: false,
1047
+ remainingCapacity: this.remainingCapacity
1048
+ };
1049
+ }
1050
+
1051
+ if (this.remainingCapacity === 0) {
1052
+ return {
1053
+ status: PROJECTION_LEDGER_STATUSES.CAPACITY_REACHED,
1054
+ capacity: this.#capacity,
1055
+ capacityReason: 'projection-slots',
1056
+ remainingCapacity: 0,
1057
+ idempotent: false
1058
+ };
1059
+ }
1060
+
1061
+ const sequence = this.#sequence + 1;
1062
+ const draft = {
1063
+ schemaVersion: PROJECTION_LEDGER_SCHEMA_VERSION,
1064
+ id: `projection-${formatProjectionLedgerSequence(sequence)}`,
1065
+ sequence,
1066
+ kind: 'projection',
1067
+ sourceKey,
1068
+ targetKey,
1069
+ identity: safeInput.identity,
1070
+ identityFingerprint: createProjectionLedgerFingerprintFromSafeValue(
1071
+ safeInput.identity
1072
+ ),
1073
+ payload: safeInput.payload
1074
+ };
1075
+ const immutableRecord = immutableProjectionLedgerRecord(
1076
+ {
1077
+ ...draft,
1078
+ fingerprint: createProjectionLedgerFingerprintFromSafeValue(draft)
1079
+ },
1080
+ 'Projection record'
1081
+ );
1082
+ const record = immutableRecord.record;
1083
+ const budgetResult = this.#projectionBudgetResult(
1084
+ immutableRecord.metrics
1085
+ );
1086
+
1087
+ if (budgetResult) {
1088
+ return budgetResult;
1089
+ }
1090
+
1091
+ let recordAppended = false;
1092
+
1093
+ try {
1094
+ this.#projectionRecords.push(record);
1095
+ recordAppended = true;
1096
+ this.#projectionById.set(record.id, record);
1097
+ this.#projectionBySource.set(record.sourceKey, record);
1098
+ this.#activeProjectionByTarget.set(record.targetKey, record);
1099
+ } catch (error) {
1100
+ if (this.#projectionById.get(record.id) === record) {
1101
+ this.#projectionById.delete(record.id);
1102
+ }
1103
+
1104
+ if (this.#projectionBySource.get(record.sourceKey) === record) {
1105
+ this.#projectionBySource.delete(record.sourceKey);
1106
+ }
1107
+
1108
+ if (this.#activeProjectionByTarget.get(record.targetKey) === record) {
1109
+ this.#activeProjectionByTarget.delete(record.targetKey);
1110
+ }
1111
+
1112
+ if (recordAppended
1113
+ && this.#projectionRecords[this.#projectionRecords.length - 1]
1114
+ === record) {
1115
+ this.#projectionRecords.pop();
1116
+ }
1117
+
1118
+ throw error;
1119
+ }
1120
+
1121
+ this.#storedCharacters += immutableRecord.metrics.characters;
1122
+ this.#storedUtf8Bytes += immutableRecord.metrics.utf8Bytes;
1123
+ this.#storedNodes += immutableRecord.metrics.nodes;
1124
+ this.#reservedRevocationCharacters
1125
+ += MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS;
1126
+ this.#reservedRevocationUtf8Bytes
1127
+ += MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES;
1128
+ this.#reservedRevocationNodes += MAX_PROJECTION_LEDGER_NODES;
1129
+ this.#sequence = sequence;
1130
+
1131
+ return {
1132
+ status: PROJECTION_LEDGER_STATUSES.STORED,
1133
+ record: cloneProjectionLedgerRecordForOutput(
1134
+ record,
1135
+ 'Projection record'
1136
+ ),
1137
+ idempotent: false,
1138
+ remainingCapacity: this.remainingCapacity
1139
+ };
1140
+ }
1141
+
1142
+ async appendRevocation(input) {
1143
+ const safeInput = cloneProjectionLedgerValue(
1144
+ input,
1145
+ 'Revocation input'
1146
+ );
1147
+ assertProjectionLedgerRecord(safeInput, 'Revocation input');
1148
+ assertProjectionLedgerRecordKeys(
1149
+ safeInput,
1150
+ REVOCATION_INPUT_KEYS,
1151
+ REVOCATION_INPUT_KEYS,
1152
+ 'Revocation input'
1153
+ );
1154
+ const projectionId = normalizeProjectionLedgerKey(
1155
+ safeInput.projectionId,
1156
+ 'Revocation projectionId'
1157
+ );
1158
+ const projection = this.#projectionById.get(projectionId);
1159
+
1160
+ if (!projection) {
1161
+ return {
1162
+ status: PROJECTION_LEDGER_STATUSES.NOT_FOUND,
1163
+ projectionId,
1164
+ idempotent: false,
1165
+ remainingCapacity: this.remainingCapacity
1166
+ };
1167
+ }
1168
+
1169
+ const existingRevocation = this.#revocationByProjectionId.get(
1170
+ projectionId
1171
+ );
1172
+
1173
+ if (existingRevocation) {
1174
+ return {
1175
+ status: PROJECTION_LEDGER_STATUSES.ALREADY_REVOKED,
1176
+ record: cloneProjectionLedgerRecordForOutput(
1177
+ existingRevocation,
1178
+ 'Revocation record'
1179
+ ),
1180
+ projection: cloneProjectionLedgerRecordForOutput(
1181
+ projection,
1182
+ 'Projection record'
1183
+ ),
1184
+ idempotent: true,
1185
+ remainingCapacity: this.remainingCapacity
1186
+ };
1187
+ }
1188
+
1189
+ const sequence = this.#sequence + 1;
1190
+ const draft = {
1191
+ schemaVersion: PROJECTION_LEDGER_SCHEMA_VERSION,
1192
+ id: `projection-revocation-${formatProjectionLedgerSequence(sequence)}`,
1193
+ sequence,
1194
+ kind: 'projection-revocation',
1195
+ projectionId: projection.id,
1196
+ sourceKey: projection.sourceKey,
1197
+ targetKey: projection.targetKey,
1198
+ payload: safeInput.payload
1199
+ };
1200
+ const immutableRecord = immutableProjectionLedgerRecord(
1201
+ {
1202
+ ...draft,
1203
+ fingerprint: createProjectionLedgerFingerprintFromSafeValue(draft)
1204
+ },
1205
+ 'Revocation record'
1206
+ );
1207
+ const record = immutableRecord.record;
1208
+ this.#assertRevocationBudget(immutableRecord.metrics);
1209
+ let recordAppended = false;
1210
+
1211
+ try {
1212
+ this.#revocationRecords.push(record);
1213
+ recordAppended = true;
1214
+ this.#revocationByProjectionId.set(projection.id, record);
1215
+ this.#activeProjectionByTarget.delete(projection.targetKey);
1216
+ } catch (error) {
1217
+ if (this.#revocationByProjectionId.get(projection.id) === record) {
1218
+ this.#revocationByProjectionId.delete(projection.id);
1219
+ }
1220
+
1221
+ if (!this.#activeProjectionByTarget.has(projection.targetKey)) {
1222
+ this.#activeProjectionByTarget.set(
1223
+ projection.targetKey,
1224
+ projection
1225
+ );
1226
+ }
1227
+
1228
+ if (recordAppended
1229
+ && this.#revocationRecords[this.#revocationRecords.length - 1]
1230
+ === record) {
1231
+ this.#revocationRecords.pop();
1232
+ }
1233
+
1234
+ throw error;
1235
+ }
1236
+
1237
+ this.#storedCharacters += immutableRecord.metrics.characters;
1238
+ this.#storedUtf8Bytes += immutableRecord.metrics.utf8Bytes;
1239
+ this.#storedNodes += immutableRecord.metrics.nodes;
1240
+ this.#reservedRevocationCharacters
1241
+ -= MAX_PROJECTION_LEDGER_TOTAL_CHARACTERS;
1242
+ this.#reservedRevocationUtf8Bytes
1243
+ -= MAX_PROJECTION_LEDGER_TOTAL_UTF8_BYTES;
1244
+ this.#reservedRevocationNodes -= MAX_PROJECTION_LEDGER_NODES;
1245
+ this.#sequence = sequence;
1246
+
1247
+ return {
1248
+ status: PROJECTION_LEDGER_STATUSES.REVOKED,
1249
+ record: cloneProjectionLedgerRecordForOutput(
1250
+ record,
1251
+ 'Revocation record'
1252
+ ),
1253
+ projection: cloneProjectionLedgerRecordForOutput(
1254
+ projection,
1255
+ 'Projection record'
1256
+ ),
1257
+ idempotent: false,
1258
+ remainingCapacity: this.remainingCapacity
1259
+ };
1260
+ }
1261
+
1262
+ async getProjection(id) {
1263
+ const normalizedId = normalizeProjectionLedgerKey(id, 'Projection id');
1264
+ return cloneProjectionLedgerRecordForOutput(
1265
+ this.#projectionById.get(normalizedId),
1266
+ 'Projection record'
1267
+ );
1268
+ }
1269
+
1270
+ async getProjectionBySourceKey(sourceKey) {
1271
+ const normalizedSourceKey = normalizeProjectionLedgerKey(
1272
+ sourceKey,
1273
+ 'Projection sourceKey'
1274
+ );
1275
+ return cloneProjectionLedgerRecordForOutput(
1276
+ this.#projectionBySource.get(normalizedSourceKey),
1277
+ 'Projection record'
1278
+ );
1279
+ }
1280
+
1281
+ async listProjectionRecords() {
1282
+ const output = [];
1283
+
1284
+ for (const record of this.#projectionRecords) {
1285
+ output.push(
1286
+ cloneProjectionLedgerRecordForOutput(
1287
+ record,
1288
+ 'Projection record'
1289
+ )
1290
+ );
1291
+ }
1292
+
1293
+ return output;
1294
+ }
1295
+
1296
+ async listRevocationRecords() {
1297
+ const output = [];
1298
+
1299
+ for (const record of this.#revocationRecords) {
1300
+ output.push(
1301
+ cloneProjectionLedgerRecordForOutput(
1302
+ record,
1303
+ 'Revocation record'
1304
+ )
1305
+ );
1306
+ }
1307
+
1308
+ return output;
1309
+ }
1310
+
1311
+ async listEffectiveProjections() {
1312
+ const output = [];
1313
+
1314
+ for (const record of this.#projectionRecords) {
1315
+ if (!this.#revocationByProjectionId.has(record.id)) {
1316
+ output.push(
1317
+ cloneProjectionLedgerRecordForOutput(
1318
+ record,
1319
+ 'Projection record'
1320
+ )
1321
+ );
1322
+ }
1323
+ }
1324
+
1325
+ return output;
1326
+ }
1327
+ }
1328
+
1329
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE =
1330
+ RevocableProjectionLedger.prototype;
1331
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE_KEYS = Object.freeze(
1332
+ Reflect.ownKeys(PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE)
1333
+ );
1334
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_CONSTRUCTOR_DESCRIPTOR =
1335
+ Reflect.getOwnPropertyDescriptor(
1336
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE,
1337
+ 'constructor'
1338
+ );
1339
+ const REVOCABLE_PROJECTION_LEDGER_GETTER_NAMES = Object.freeze(
1340
+ [
1341
+ 'capacity',
1342
+ 'eventCount',
1343
+ 'eventCapacity',
1344
+ 'maximumStoredCharacters',
1345
+ 'maximumStoredUtf8Bytes',
1346
+ 'maximumStoredNodes',
1347
+ 'storedCharacters',
1348
+ 'storedUtf8Bytes',
1349
+ 'storedNodes',
1350
+ 'reservedRevocationCharacters',
1351
+ 'reservedRevocationUtf8Bytes',
1352
+ 'reservedRevocationNodes',
1353
+ 'remainingStoredCharacters',
1354
+ 'remainingStoredUtf8Bytes',
1355
+ 'remainingStoredNodes',
1356
+ 'remainingCapacity'
1357
+ ]
1358
+ );
1359
+ const REVOCABLE_PROJECTION_LEDGER_METHOD_NAMES = Object.freeze(
1360
+ [
1361
+ 'appendProjection',
1362
+ 'appendRevocation',
1363
+ 'getProjection',
1364
+ 'getProjectionBySourceKey',
1365
+ 'listProjectionRecords',
1366
+ 'listRevocationRecords',
1367
+ 'listEffectiveProjections'
1368
+ ]
1369
+ );
1370
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_GETTER_DESCRIPTORS = Object.freeze(
1371
+ REVOCABLE_PROJECTION_LEDGER_GETTER_NAMES.reduce(
1372
+ function capturePristineLedgerGetterDescriptors(output, getterName) {
1373
+ output[getterName] = Reflect.getOwnPropertyDescriptor(
1374
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE,
1375
+ getterName
1376
+ );
1377
+ return output;
1378
+ },
1379
+ Object.create(null)
1380
+ )
1381
+ );
1382
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_EVENT_COUNT_DESCRIPTOR =
1383
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_GETTER_DESCRIPTORS.eventCount;
1384
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_EVENT_COUNT =
1385
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_EVENT_COUNT_DESCRIPTOR.get;
1386
+ const PRISTINE_REVOCABLE_PROJECTION_LEDGER_METHOD_DESCRIPTORS = Object.freeze(
1387
+ REVOCABLE_PROJECTION_LEDGER_METHOD_NAMES.reduce(
1388
+ function capturePristineLedgerMethodDescriptors(output, methodName) {
1389
+ output[methodName] = Reflect.getOwnPropertyDescriptor(
1390
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE,
1391
+ methodName
1392
+ );
1393
+ return output;
1394
+ },
1395
+ Object.create(null)
1396
+ )
1397
+ );
1398
+
1399
+ function sameProjectionLedgerDataDescriptor(current, pristine) {
1400
+ return Boolean(current)
1401
+ && Boolean(pristine)
1402
+ && current.value === pristine.value
1403
+ && current.writable === pristine.writable
1404
+ && current.enumerable === pristine.enumerable
1405
+ && current.configurable === pristine.configurable;
1406
+ }
1407
+
1408
+ function sameProjectionLedgerAccessorDescriptor(current, pristine) {
1409
+ return Boolean(current)
1410
+ && Boolean(pristine)
1411
+ && current.get === pristine.get
1412
+ && current.set === pristine.set
1413
+ && current.enumerable === pristine.enumerable
1414
+ && current.configurable === pristine.configurable;
1415
+ }
1416
+
1417
+ function sameProjectionLedgerKeyList(current, pristine) {
1418
+ if (!Array.isArray(current) || current.length !== pristine.length) {
1419
+ return false;
1420
+ }
1421
+ for (let index = 0; index < pristine.length; index += 1) {
1422
+ if (current[index] !== pristine[index]) {
1423
+ return false;
1424
+ }
1425
+ }
1426
+ return true;
1427
+ }
1428
+
1429
+ function invalidProjectionLedgerPort(detail) {
1430
+ throw invalidProjectionLedgerBoundary('Projection ledger port', detail);
1431
+ }
1432
+
1433
+ function assertPristineRevocableProjectionLedger(value) {
1434
+ let prototype;
1435
+ let ownKeys;
1436
+ let prototypeKeys;
1437
+ let constructorDescriptor;
1438
+ const getterDescriptors = Object.create(null);
1439
+ const methodDescriptors = Object.create(null);
1440
+ try {
1441
+ prototype = Object.getPrototypeOf(value);
1442
+ ownKeys = Reflect.ownKeys(value);
1443
+ prototypeKeys = Reflect.ownKeys(
1444
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE
1445
+ );
1446
+ constructorDescriptor = Reflect.getOwnPropertyDescriptor(
1447
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE,
1448
+ 'constructor'
1449
+ );
1450
+ for (const getterName of REVOCABLE_PROJECTION_LEDGER_GETTER_NAMES) {
1451
+ getterDescriptors[getterName] = Reflect.getOwnPropertyDescriptor(
1452
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE,
1453
+ getterName
1454
+ );
1455
+ }
1456
+ for (const methodName of REVOCABLE_PROJECTION_LEDGER_METHOD_NAMES) {
1457
+ methodDescriptors[methodName] = Reflect.getOwnPropertyDescriptor(
1458
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE,
1459
+ methodName
1460
+ );
1461
+ }
1462
+ } catch (error) {
1463
+ invalidProjectionLedgerPort('could not be inspected safely.');
1464
+ }
1465
+ if (prototype !== PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE
1466
+ || !Array.isArray(ownKeys)
1467
+ || ownKeys.length !== 0
1468
+ || typeof PRISTINE_REVOCABLE_PROJECTION_LEDGER_EVENT_COUNT !== 'function'
1469
+ || !sameProjectionLedgerKeyList(
1470
+ prototypeKeys,
1471
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_PROTOTYPE_KEYS
1472
+ )
1473
+ || !sameProjectionLedgerDataDescriptor(
1474
+ constructorDescriptor,
1475
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_CONSTRUCTOR_DESCRIPTOR
1476
+ )) {
1477
+ invalidProjectionLedgerPort('requires an unmodified concrete producer.');
1478
+ }
1479
+ for (const getterName of REVOCABLE_PROJECTION_LEDGER_GETTER_NAMES) {
1480
+ if (!sameProjectionLedgerAccessorDescriptor(
1481
+ getterDescriptors[getterName],
1482
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_GETTER_DESCRIPTORS[getterName]
1483
+ )) {
1484
+ invalidProjectionLedgerPort('requires unmodified producer getters.');
1485
+ }
1486
+ }
1487
+ for (const methodName of REVOCABLE_PROJECTION_LEDGER_METHOD_NAMES) {
1488
+ if (!sameProjectionLedgerDataDescriptor(
1489
+ methodDescriptors[methodName],
1490
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_METHOD_DESCRIPTORS[methodName]
1491
+ )) {
1492
+ invalidProjectionLedgerPort('requires unmodified producer methods.');
1493
+ }
1494
+ }
1495
+ }
1496
+
1497
+ function readPristineProjectionLedgerEventCount(value) {
1498
+ assertPristineRevocableProjectionLedger(value);
1499
+ const eventCount = PRISTINE_REVOCABLE_PROJECTION_LEDGER_EVENT_COUNT.call(value);
1500
+ if (!Number.isSafeInteger(eventCount) || eventCount < 0) {
1501
+ invalidProjectionLedgerPort('returned an invalid event count.');
1502
+ }
1503
+ return eventCount;
1504
+ }
1505
+
1506
+ function probePristineRevocableProjectionLedger(value) {
1507
+ try {
1508
+ return readPristineProjectionLedgerEventCount(value);
1509
+ } catch (error) {
1510
+ if (error instanceof ProjectionLedgerError) {
1511
+ throw error;
1512
+ }
1513
+ invalidProjectionLedgerPort('failed its private-brand probe.');
1514
+ }
1515
+ }
1516
+
1517
+ function callPristineProjectionLedgerMethod(value, methodName, args) {
1518
+ assertPristineRevocableProjectionLedger(value);
1519
+ return Reflect.apply(
1520
+ PRISTINE_REVOCABLE_PROJECTION_LEDGER_METHOD_DESCRIPTORS[methodName].value,
1521
+ value,
1522
+ args
1523
+ );
1524
+ }
1525
+
1526
+ function callPristineProjectionLedgerMutation(
1527
+ value,
1528
+ methodName,
1529
+ input,
1530
+ label
1531
+ ) {
1532
+ const safeInput = cloneProjectionLedgerValue(input, label);
1533
+ return callPristineProjectionLedgerMethod(
1534
+ value,
1535
+ methodName,
1536
+ [safeInput]
1537
+ );
1538
+ }
1539
+
1540
+ function createRevocableProjectionLedgerPortAdapter(value) {
1541
+ probePristineRevocableProjectionLedger(value);
1542
+
1543
+ function readEventCount() {
1544
+ return readPristineProjectionLedgerEventCount(value);
1545
+ }
1546
+
1547
+ function appendProjection(input) {
1548
+ return callPristineProjectionLedgerMutation(
1549
+ value,
1550
+ 'appendProjection',
1551
+ input,
1552
+ 'Projection adapter input'
1553
+ );
1554
+ }
1555
+
1556
+ function appendRevocation(input) {
1557
+ return callPristineProjectionLedgerMutation(
1558
+ value,
1559
+ 'appendRevocation',
1560
+ input,
1561
+ 'Revocation adapter input'
1562
+ );
1563
+ }
1564
+
1565
+ function getProjection(id) {
1566
+ return callPristineProjectionLedgerMethod(value, 'getProjection', [id]);
1567
+ }
1568
+
1569
+ function getProjectionBySourceKey(sourceKey) {
1570
+ return callPristineProjectionLedgerMethod(
1571
+ value,
1572
+ 'getProjectionBySourceKey',
1573
+ [sourceKey]
1574
+ );
1575
+ }
1576
+
1577
+ function listProjectionRecords() {
1578
+ return callPristineProjectionLedgerMethod(value, 'listProjectionRecords', []);
1579
+ }
1580
+
1581
+ function listRevocationRecords() {
1582
+ return callPristineProjectionLedgerMethod(value, 'listRevocationRecords', []);
1583
+ }
1584
+
1585
+ function listEffectiveProjections() {
1586
+ return callPristineProjectionLedgerMethod(value, 'listEffectiveProjections', []);
1587
+ }
1588
+
1589
+ return Object.freeze(
1590
+ {
1591
+ appendProjection,
1592
+ appendRevocation,
1593
+ getProjection,
1594
+ getProjectionBySourceKey,
1595
+ listProjectionRecords,
1596
+ listRevocationRecords,
1597
+ listEffectiveProjections,
1598
+ readEventCount
1599
+ }
1600
+ );
1601
+ }
1602
+
1603
+ export {
1604
+ DEFAULT_PROJECTION_LEDGER_CAPACITY,
1605
+ DEFAULT_PROJECTION_LEDGER_STORED_CHARACTERS,
1606
+ DEFAULT_PROJECTION_LEDGER_STORED_NODES,
1607
+ DEFAULT_PROJECTION_LEDGER_STORED_UTF8_BYTES,
1608
+ MAX_PROJECTION_LEDGER_CAPACITY,
1609
+ MAX_PROJECTION_LEDGER_STORED_CHARACTERS,
1610
+ MAX_PROJECTION_LEDGER_STORED_NODES,
1611
+ MAX_PROJECTION_LEDGER_STORED_UTF8_BYTES,
1612
+ PROJECTION_LEDGER_LIMITS,
1613
+ PROJECTION_LEDGER_REASON_CODES,
1614
+ PROJECTION_LEDGER_SCHEMA_VERSION,
1615
+ PROJECTION_LEDGER_STATUSES,
1616
+ ProjectionLedgerError,
1617
+ RevocableProjectionLedger,
1618
+ cloneProjectionLedgerValue,
1619
+ createRevocableProjectionLedgerPortAdapter,
1620
+ createProjectionLedgerFingerprint
1621
+ };
1622
+
1623
+ export default RevocableProjectionLedger;