@hyperfrontend/features 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/_dependencies/@hyperfrontend/builder/bundle/dependencies/index.cjs.js +1 -0
- package/_dependencies/@hyperfrontend/builder/bundle/dependencies/index.esm.js +1 -0
- package/_dependencies/@hyperfrontend/builder/bundle/dependencies/worker/index.cjs.js +1 -0
- package/_dependencies/@hyperfrontend/builder/bundle/dependencies/worker/index.esm.js +1 -0
- package/_dependencies/@hyperfrontend/builder/bundle/index.cjs.js +12 -10
- package/_dependencies/@hyperfrontend/builder/bundle/index.esm.js +14 -12
- package/_dependencies/@hyperfrontend/builder/bundle/rollup/index.cjs.js +2 -0
- package/_dependencies/@hyperfrontend/builder/bundle/rollup/index.esm.js +2 -0
- package/_dependencies/@hyperfrontend/builder/bundle/rollup/worker/index.cjs.js +2 -0
- package/_dependencies/@hyperfrontend/builder/bundle/rollup/worker/index.esm.js +2 -0
- package/_dependencies/@hyperfrontend/builder/index.cjs.js +87 -53
- package/_dependencies/@hyperfrontend/builder/index.esm.js +89 -55
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/promise/index.cjs.js +4 -0
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/promise/index.esm.js +3 -1
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/reflect/index.cjs.js +10 -0
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/reflect/index.esm.js +6 -0
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/timers/index.cjs.js +5 -0
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/timers/index.esm.js +5 -1
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/typed-arrays/index.cjs.js +2 -2
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/typed-arrays/index.esm.js +2 -2
- package/_dependencies/@hyperfrontend/network-protocol/browser/channel/index.cjs.js +5 -19
- package/_dependencies/@hyperfrontend/network-protocol/browser/channel/index.esm.js +1 -15
- package/_dependencies/@hyperfrontend/network-protocol/browser/data/index.cjs.js +15 -23
- package/_dependencies/@hyperfrontend/network-protocol/browser/data/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/browser/packet/index.cjs.js +6 -14
- package/_dependencies/@hyperfrontend/network-protocol/browser/packet/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/browser/receiver/index.cjs.js +4 -18
- package/_dependencies/@hyperfrontend/network-protocol/browser/receiver/index.esm.js +1 -15
- package/_dependencies/@hyperfrontend/network-protocol/browser/sender/index.cjs.js +5 -19
- package/_dependencies/@hyperfrontend/network-protocol/browser/sender/index.esm.js +2 -16
- package/_dependencies/@hyperfrontend/network-protocol/browser/v1/index.cjs.js +16 -24
- package/_dependencies/@hyperfrontend/network-protocol/browser/v1/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/browser/v2/index.cjs.js +16 -24
- package/_dependencies/@hyperfrontend/network-protocol/browser/v2/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/node/channel/index.cjs.js +3 -17
- package/_dependencies/@hyperfrontend/network-protocol/node/channel/index.esm.js +1 -15
- package/_dependencies/@hyperfrontend/network-protocol/node/data/index.cjs.js +6 -14
- package/_dependencies/@hyperfrontend/network-protocol/node/data/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/node/packet/index.cjs.js +6 -14
- package/_dependencies/@hyperfrontend/network-protocol/node/packet/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/node/receiver/index.cjs.js +3 -17
- package/_dependencies/@hyperfrontend/network-protocol/node/receiver/index.esm.js +1 -15
- package/_dependencies/@hyperfrontend/network-protocol/node/sender/index.cjs.js +2 -16
- package/_dependencies/@hyperfrontend/network-protocol/node/sender/index.esm.js +2 -16
- package/_dependencies/@hyperfrontend/network-protocol/node/v1/index.cjs.js +6 -14
- package/_dependencies/@hyperfrontend/network-protocol/node/v1/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/network-protocol/node/v2/index.cjs.js +6 -14
- package/_dependencies/@hyperfrontend/network-protocol/node/v2/index.esm.js +7 -15
- package/_dependencies/@hyperfrontend/nexus/index.cjs.js +49 -19
- package/_dependencies/@hyperfrontend/nexus/index.esm.js +49 -19
- package/_dependencies/@hyperfrontend/project-scope/core/fs/index.cjs.js +62 -0
- package/_dependencies/@hyperfrontend/project-scope/core/fs/index.esm.js +60 -2
- package/_shared/generators/feature/generate-feature-module/index.esm.js +11 -6
- package/_shared/generators/metadata/generate-metadata/index.esm.js +1 -0
- package/_shared/shared/control/index.cjs.js +12 -2
- package/_shared/shared/control/index.esm.js +12 -2
- package/_shared/shared/request/index.cjs.js +91 -0
- package/_shared/shared/request/index.esm.js +88 -0
- package/_shared/shared/shutdown/index.esm.js +12 -0
- package/bin/hf.js +643 -70
- package/bundle/host/index.iife.js +290 -4041
- package/bundle/host/index.iife.min.js +1 -1
- package/bundle/host/index.umd.js +290 -4041
- package/bundle/host/index.umd.min.js +1 -1
- package/bundle/hostee/index.iife.js +215 -2893
- package/bundle/hostee/index.iife.min.js +1 -1
- package/bundle/hostee/index.umd.js +215 -2893
- package/bundle/hostee/index.umd.min.js +1 -1
- package/cli/args.d.ts +2 -0
- package/cli/args.d.ts.map +1 -1
- package/cli/commands/build.d.ts +8 -5
- package/cli/commands/build.d.ts.map +1 -1
- package/cli/commands/dev.d.ts +7 -2
- package/cli/commands/dev.d.ts.map +1 -1
- package/cli/config/resolve.d.ts +3 -1
- package/cli/config/resolve.d.ts.map +1 -1
- package/cli/index.cjs.js +643 -70
- package/cli/index.d.ts +21 -10
- package/cli/index.esm.js +591 -60
- package/cli/usage.d.ts +1 -1
- package/cli/usage.d.ts.map +1 -1
- package/generators/feature/generate-feature-module.d.ts.map +1 -1
- package/generators/index.cjs.js +435 -42
- package/generators/index.d.ts +9 -8
- package/generators/index.esm.js +404 -30
- package/generators/metadata/generate-metadata.d.ts +4 -4
- package/generators/metadata/generate-metadata.d.ts.map +1 -1
- package/generators/shell/connector-types.d.ts +19 -0
- package/generators/shell/connector-types.d.ts.map +1 -0
- package/generators/shell/generate-shell.d.ts +5 -4
- package/generators/shell/generate-shell.d.ts.map +1 -1
- package/generators/shell/schema-type.d.ts +20 -0
- package/generators/shell/schema-type.d.ts.map +1 -0
- package/generators/shell/source-literal.d.ts +28 -0
- package/generators/shell/source-literal.d.ts.map +1 -1
- package/host/create-shell.d.ts +4 -1
- package/host/create-shell.d.ts.map +1 -1
- package/host/display-modes/dialog.d.ts +1 -1
- package/host/display-modes/dialog.d.ts.map +1 -1
- package/host/display-modes/embedded.d.ts +1 -1
- package/host/display-modes/embedded.d.ts.map +1 -1
- package/host/index.cjs.js +150 -30
- package/host/index.d.ts +53 -38
- package/host/index.d.ts.map +1 -1
- package/host/index.esm.js +129 -9
- package/host/lifecycle.d.ts.map +1 -1
- package/host/plugins.d.ts +1 -34
- package/host/plugins.d.ts.map +1 -1
- package/host/types.d.ts +49 -0
- package/host/types.d.ts.map +1 -1
- package/hostee/index.cjs.js +54 -9
- package/hostee/index.d.ts +41 -1
- package/hostee/index.d.ts.map +1 -1
- package/hostee/index.esm.js +51 -6
- package/hostee/lifecycle.d.ts.map +1 -1
- package/hostee/types.d.ts +40 -0
- package/hostee/types.d.ts.map +1 -1
- package/index.cjs.js +32 -1
- package/index.d.ts +89 -3
- package/index.d.ts.map +1 -1
- package/index.esm.js +32 -1
- package/nx/executors/build/index.cjs.js +14975 -137
- package/nx/executors/build/index.esm.js +14935 -115
- package/nx/executors/serve/executor.d.ts.map +1 -1
- package/nx/executors/serve/index.cjs.js +6594 -80
- package/nx/executors/serve/index.esm.js +6529 -44
- package/nx/generators/feature/index.cjs.js +8751 -108
- package/nx/generators/feature/index.esm.js +8711 -81
- package/package.json +15 -5
- package/server/debug-ui/index.d.ts +2 -0
- package/server/debug-ui/index.d.ts.map +1 -0
- package/server/debug-ui/index.html +15 -0
- package/server/debug-ui/index.iife.js +427 -0
- package/server/debug-ui/index.iife.min.js +1 -0
- package/server/dev-server.d.ts.map +1 -1
- package/server/index.cjs.js +78 -10
- package/server/index.esm.js +78 -11
- package/server/module-dir.d.ts +17 -0
- package/server/module-dir.d.ts.map +1 -0
- package/server/module-dir.stub.d.ts +15 -0
- package/server/module-dir.stub.d.ts.map +1 -0
- package/shared/contract.d.ts +1 -1
- package/shared/contract.d.ts.map +1 -1
- package/shared/control.d.ts +4 -0
- package/shared/control.d.ts.map +1 -1
- package/shared/invert-contract.d.ts +20 -0
- package/shared/invert-contract.d.ts.map +1 -0
- package/shared/request.d.ts +68 -0
- package/shared/request.d.ts.map +1 -0
- package/{nx/shared → shared}/shutdown.d.ts +3 -2
- package/shared/shutdown.d.ts.map +1 -0
- package/shared/types.d.ts +72 -1
- package/shared/types.d.ts.map +1 -1
- package/_shared/nx/shared/context/index.cjs.js +0 -18
- package/_shared/nx/shared/context/index.esm.js +0 -16
- package/nx/shared/shutdown.d.ts.map +0 -1
- package/server/debug-ui/bootstrap.d.ts +0 -2
- package/server/debug-ui/bootstrap.d.ts.map +0 -1
|
@@ -1,120 +1,26 @@
|
|
|
1
1
|
var HyperfrontendFeaturesHostee = (function (exports) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Safe copies of Error built-ins via factory functions.
|
|
6
|
-
*
|
|
7
|
-
* Since constructors cannot be safely captured via Object.assign, this module
|
|
8
|
-
* provides factory functions that use Reflect.construct internally.
|
|
9
|
-
*
|
|
10
|
-
* These references are captured at module initialization time to protect against
|
|
11
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
12
|
-
*
|
|
13
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/error
|
|
14
|
-
*/
|
|
15
4
|
const _Error = globalThis.Error;
|
|
16
|
-
const _Reflect$
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* Use this instead of `new Error()`.
|
|
20
|
-
*
|
|
21
|
-
* @param message - Optional error message.
|
|
22
|
-
* @param options - Optional error options.
|
|
23
|
-
* @returns A new Error instance.
|
|
24
|
-
*
|
|
25
|
-
* @example Creating Error instances
|
|
26
|
-
* ```typescript
|
|
27
|
-
* const error = createError('Operation failed')
|
|
28
|
-
* // With cause for error chaining
|
|
29
|
-
* const wrapped = createError('Request failed', { cause: originalError })
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
const createError = (message, options) => _Reflect$9.construct(_Error, [message, options]);
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Safe copies of Object built-in methods.
|
|
36
|
-
*
|
|
37
|
-
* These references are captured at module initialization time to protect against
|
|
38
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
39
|
-
*
|
|
40
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/object
|
|
41
|
-
*/
|
|
5
|
+
const _Reflect$a = globalThis.Reflect;
|
|
6
|
+
const createError = (message, options) => _Reflect$a.construct(_Error, [message, options]);
|
|
7
|
+
|
|
42
8
|
const _Object = globalThis.Object;
|
|
43
|
-
const _Reflect$
|
|
9
|
+
const _Reflect$9 = globalThis.Reflect;
|
|
44
10
|
const _ObjectPrototype = _Object.prototype;
|
|
45
11
|
const _hasOwnProperty = _ObjectPrototype.hasOwnProperty;
|
|
46
|
-
/**
|
|
47
|
-
* (Safe copy) Prevents modification of existing property attributes and values,
|
|
48
|
-
* and prevents the addition of new properties.
|
|
49
|
-
*/
|
|
50
12
|
const freeze = _Object.freeze;
|
|
51
|
-
/**
|
|
52
|
-
* (Safe copy) Returns the names of the enumerable string properties and methods of an object.
|
|
53
|
-
*/
|
|
54
13
|
const keys = _Object.keys;
|
|
55
|
-
/**
|
|
56
|
-
* (Safe copy) Returns an array of key/values of the enumerable own properties of an object.
|
|
57
|
-
*/
|
|
58
14
|
const entries = _Object.entries;
|
|
59
|
-
|
|
60
|
-
* (Safe copy) Adds a property to an object, or modifies attributes of an existing property.
|
|
61
|
-
*/
|
|
15
|
+
const values = _Object.values;
|
|
62
16
|
const defineProperty = _Object.defineProperty;
|
|
63
|
-
/**
|
|
64
|
-
* (Safe copy) Sets the prototype of a specified object o to object proto or null.
|
|
65
|
-
*/
|
|
66
17
|
const setPrototypeOf = _Object.setPrototypeOf;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
* Checks if an object has a property as its own (not inherited) property.
|
|
70
|
-
*
|
|
71
|
-
* @param obj - The object to check.
|
|
72
|
-
* @param key - The property key to check.
|
|
73
|
-
* @returns True if the object has the property as its own property.
|
|
74
|
-
*
|
|
75
|
-
* @example Checking own properties
|
|
76
|
-
* ```typescript
|
|
77
|
-
* const user = { name: 'Alice' }
|
|
78
|
-
* hasOwn(user, 'name') // => true
|
|
79
|
-
* hasOwn(user, 'toString') // => false (inherited from prototype)
|
|
80
|
-
* ```
|
|
81
|
-
*/
|
|
82
|
-
const hasOwn = (obj, key) => _Reflect$8.apply(_hasOwnProperty, obj, [key]);
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Safe copies of Math built-in methods.
|
|
86
|
-
*
|
|
87
|
-
* These references are captured at module initialization time to protect against
|
|
88
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
89
|
-
*
|
|
90
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/math
|
|
91
|
-
*/
|
|
18
|
+
const hasOwn = (obj, key) => _Reflect$9.apply(_hasOwnProperty, obj, [key]);
|
|
19
|
+
|
|
92
20
|
const _Math = globalThis.Math;
|
|
93
|
-
/**
|
|
94
|
-
* (Safe copy) Returns the absolute value of a number.
|
|
95
|
-
*/
|
|
96
21
|
const abs = _Math.abs;
|
|
97
|
-
/**
|
|
98
|
-
* (Safe copy) Returns a pseudo-random number between 0 and 1.
|
|
99
|
-
* Note: This is NOT cryptographically secure. For secure random values,
|
|
100
|
-
* use crypto.getRandomValues().
|
|
101
|
-
*/
|
|
102
22
|
const random = _Math.random;
|
|
103
23
|
|
|
104
|
-
/**
|
|
105
|
-
* Generates a version 4 UUID.
|
|
106
|
-
*
|
|
107
|
-
* @returns a version 4 UUID.
|
|
108
|
-
*
|
|
109
|
-
* @example Creating unique identifiers for entities
|
|
110
|
-
* ```typescript
|
|
111
|
-
* const userId = uuidV4()
|
|
112
|
-
* // => 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d'
|
|
113
|
-
*
|
|
114
|
-
* const sessionId = uuidV4()
|
|
115
|
-
* // => '9f8e7d6c-5b4a-4321-8765-4321fedcba98'
|
|
116
|
-
* ```
|
|
117
|
-
*/
|
|
118
24
|
function uuidV4() {
|
|
119
25
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
|
|
120
26
|
const randomHex = (random() * 16) | 0;
|
|
@@ -123,17 +29,7 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
123
29
|
});
|
|
124
30
|
}
|
|
125
31
|
|
|
126
|
-
/**
|
|
127
|
-
* Protocol prefix for all action types.
|
|
128
|
-
* This is the Nexus protocol identifier.
|
|
129
|
-
*/
|
|
130
32
|
const PROTOCOL = 'nexus';
|
|
131
|
-
/**
|
|
132
|
-
* Action type string literals for the Nexus protocol.
|
|
133
|
-
*
|
|
134
|
-
* These define the wire format for all connection lifecycle actions.
|
|
135
|
-
* The connection flow behavior is 1:1 with the proven legacy implementation.
|
|
136
|
-
*/
|
|
137
33
|
const ACTION_TYPES = {
|
|
138
34
|
INVALID_REQUEST: `[${PROTOCOL}] invalid-request`,
|
|
139
35
|
REQUEST_CONNECTION: `[${PROTOCOL}] connection-request`,
|
|
@@ -147,66 +43,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
147
43
|
OPEN_CONNECTION: `[${PROTOCOL}] connection-opened`,
|
|
148
44
|
NEW_MESSAGE: `[${PROTOCOL}] new-message`,
|
|
149
45
|
};
|
|
150
|
-
/**
|
|
151
|
-
* Type guards for specific action types
|
|
152
|
-
*
|
|
153
|
-
* @param action - The action to check
|
|
154
|
-
* @returns True if action contains a contract property
|
|
155
|
-
*
|
|
156
|
-
* @example Checking for contract property
|
|
157
|
-
* ```typescript
|
|
158
|
-
* if (isActionWithContract(action)) {
|
|
159
|
-
* console.log(action.contract)
|
|
160
|
-
* }
|
|
161
|
-
* ```
|
|
162
|
-
*/
|
|
163
46
|
const isActionWithContract = (action) => 'contract' in action;
|
|
164
|
-
/**
|
|
165
|
-
* Type guard for actions with data property.
|
|
166
|
-
*
|
|
167
|
-
* @param action - The action to check
|
|
168
|
-
* @returns True if action contains a data property
|
|
169
|
-
*
|
|
170
|
-
* @example Checking for data property
|
|
171
|
-
* ```typescript
|
|
172
|
-
* if (isActionWithData(action)) {
|
|
173
|
-
* processData(action.data)
|
|
174
|
-
* }
|
|
175
|
-
* ```
|
|
176
|
-
*/
|
|
177
47
|
const isActionWithData = (action) => 'data' in action;
|
|
178
|
-
/**
|
|
179
|
-
* Type guard for actions with processId property.
|
|
180
|
-
*
|
|
181
|
-
* @param action - The action to check
|
|
182
|
-
* @returns True if action contains a processId property
|
|
183
|
-
*
|
|
184
|
-
* @example Checking for processId property
|
|
185
|
-
* ```typescript
|
|
186
|
-
* if (isActionWithProcess(action)) {
|
|
187
|
-
* trackProcess(action.processId)
|
|
188
|
-
* }
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
48
|
const isActionWithProcess = (action) => 'processId' in action;
|
|
192
49
|
|
|
193
|
-
/**
|
|
194
|
-
* Creates ACCEPT_CONNECTION action
|
|
195
|
-
*
|
|
196
|
-
* @param deps - Action dependencies (getBrokerId, getContract)
|
|
197
|
-
* @returns Function that takes processId and optional security response, returns frozen action
|
|
198
|
-
*
|
|
199
|
-
* @example Creating accept connection actions
|
|
200
|
-
* ```typescript
|
|
201
|
-
* // Without security
|
|
202
|
-
* const action = acceptConnection(deps)('process-123')
|
|
203
|
-
*
|
|
204
|
-
* // With security negotiation response
|
|
205
|
-
* const secureAction = acceptConnection(deps)('process-123', {
|
|
206
|
-
* negotiated: 'v2'
|
|
207
|
-
* })
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
50
|
const acceptConnection = (deps) => (processId, security) => {
|
|
211
51
|
const base = {
|
|
212
52
|
type: ACTION_TYPES.ACCEPT_CONNECTION,
|
|
@@ -220,57 +60,18 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
220
60
|
return freeze(base);
|
|
221
61
|
};
|
|
222
62
|
|
|
223
|
-
/**
|
|
224
|
-
* Creates a cancel connection action.
|
|
225
|
-
*
|
|
226
|
-
* @param deps - Action dependencies containing broker ID
|
|
227
|
-
* @returns A function that creates a cancel connection action for a process
|
|
228
|
-
*
|
|
229
|
-
* @example Creating cancel connection actions
|
|
230
|
-
* ```typescript
|
|
231
|
-
* const createCancelAction = cancelConnection({ getBrokerId: () => 'broker-1' })
|
|
232
|
-
* const action = createCancelAction('process-123')
|
|
233
|
-
* // => { type: 'CANCEL_CONNECTION', processId: 'process-123', senderId: 'broker-1' }
|
|
234
|
-
* ```
|
|
235
|
-
*/
|
|
236
63
|
const cancelConnection = (deps) => (processId) => freeze({
|
|
237
64
|
type: ACTION_TYPES.CANCEL_CONNECTION,
|
|
238
65
|
processId,
|
|
239
66
|
senderId: deps.getBrokerId(),
|
|
240
67
|
});
|
|
241
68
|
|
|
242
|
-
/**
|
|
243
|
-
* Creates a close connection action.
|
|
244
|
-
*
|
|
245
|
-
* @param deps - Action dependencies containing broker ID
|
|
246
|
-
* @returns A function that creates a close connection action for a process
|
|
247
|
-
*
|
|
248
|
-
* @example Creating close connection actions
|
|
249
|
-
* ```typescript
|
|
250
|
-
* const createCloseAction = closeConnection({ getBrokerId: () => 'broker-1' })
|
|
251
|
-
* const action = createCloseAction('process-123')
|
|
252
|
-
* // => { type: 'CLOSE_CONNECTION', processId: 'process-123', senderId: 'broker-1' }
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
69
|
const closeConnection = (deps) => (processId) => freeze({
|
|
256
70
|
type: ACTION_TYPES.CLOSE_CONNECTION,
|
|
257
71
|
processId,
|
|
258
72
|
senderId: deps.getBrokerId(),
|
|
259
73
|
});
|
|
260
74
|
|
|
261
|
-
/**
|
|
262
|
-
* Creates a deny connection action with an error message.
|
|
263
|
-
*
|
|
264
|
-
* @param deps - Action dependencies containing broker ID
|
|
265
|
-
* @returns A function that creates a deny connection action for a process
|
|
266
|
-
*
|
|
267
|
-
* @example Creating deny connection actions
|
|
268
|
-
* ```typescript
|
|
269
|
-
* const createDenyAction = denyConnection({ getBrokerId: () => 'broker-1' })
|
|
270
|
-
* const action = createDenyAction('process-123', 'Origin not allowed')
|
|
271
|
-
* // => { type: 'DENY_CONNECTION', processId: 'process-123', senderId: 'broker-1', error: 'Origin not allowed' }
|
|
272
|
-
* ```
|
|
273
|
-
*/
|
|
274
75
|
const denyConnection = (deps) => (processId, error) => freeze({
|
|
275
76
|
type: ACTION_TYPES.DENY_CONNECTION,
|
|
276
77
|
processId,
|
|
@@ -278,37 +79,11 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
278
79
|
error,
|
|
279
80
|
});
|
|
280
81
|
|
|
281
|
-
/**
|
|
282
|
-
* Creates a destroy connection action.
|
|
283
|
-
*
|
|
284
|
-
* @param deps - Action dependencies containing broker ID
|
|
285
|
-
* @returns A function that creates a destroy connection action
|
|
286
|
-
*
|
|
287
|
-
* @example Creating destroy connection actions
|
|
288
|
-
* ```typescript
|
|
289
|
-
* const createDestroyAction = destroyConnection({ getBrokerId: () => 'broker-1' })
|
|
290
|
-
* const action = createDestroyAction()
|
|
291
|
-
* // => { type: 'DESTROY_CONNECTION', senderId: 'broker-1' }
|
|
292
|
-
* ```
|
|
293
|
-
*/
|
|
294
82
|
const destroyConnection = (deps) => () => freeze({
|
|
295
83
|
type: ACTION_TYPES.DESTROY_CONNECTION,
|
|
296
84
|
senderId: deps.getBrokerId(),
|
|
297
85
|
});
|
|
298
86
|
|
|
299
|
-
/**
|
|
300
|
-
* Creates an invalid request action with an error message.
|
|
301
|
-
*
|
|
302
|
-
* @param deps - Action dependencies containing broker ID
|
|
303
|
-
* @returns A function that creates an invalid request action for a process
|
|
304
|
-
*
|
|
305
|
-
* @example Creating invalid request actions
|
|
306
|
-
* ```typescript
|
|
307
|
-
* const createInvalidAction = invalidRequest({ getBrokerId: () => 'broker-1' })
|
|
308
|
-
* const action = createInvalidAction('process-123', 'Malformed payload')
|
|
309
|
-
* // => { type: 'INVALID_REQUEST', processId: 'process-123', senderId: 'broker-1', error: 'Malformed payload' }
|
|
310
|
-
* ```
|
|
311
|
-
*/
|
|
312
87
|
const invalidRequest = (deps) => (processId, error) => freeze({
|
|
313
88
|
type: ACTION_TYPES.INVALID_REQUEST,
|
|
314
89
|
processId,
|
|
@@ -316,43 +91,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
316
91
|
error,
|
|
317
92
|
});
|
|
318
93
|
|
|
319
|
-
|
|
320
|
-
* Creates a new message action with data payload.
|
|
321
|
-
*
|
|
322
|
-
* @param deps - Action dependencies containing broker ID
|
|
323
|
-
* @returns A function that creates a new message action with data
|
|
324
|
-
*
|
|
325
|
-
* @example Creating message actions with data
|
|
326
|
-
* ```typescript
|
|
327
|
-
* const createMessageAction = newMessage({ getBrokerId: () => 'broker-1' })
|
|
328
|
-
* const action = createMessageAction({ userId: 123, event: 'login' })
|
|
329
|
-
* // => { type: 'NEW_MESSAGE', senderId: 'broker-1', data: { userId: 123, event: 'login' } }
|
|
330
|
-
* ```
|
|
331
|
-
*/
|
|
332
|
-
const newMessage = (deps) => (data) => freeze({
|
|
94
|
+
const newMessage = (deps) => (message) => freeze({
|
|
333
95
|
type: ACTION_TYPES.NEW_MESSAGE,
|
|
334
96
|
senderId: deps.getBrokerId(),
|
|
335
|
-
data,
|
|
97
|
+
data: message,
|
|
336
98
|
});
|
|
337
99
|
|
|
338
|
-
/**
|
|
339
|
-
* Creates OPEN_CONNECTION action
|
|
340
|
-
*
|
|
341
|
-
* @param deps - Action dependencies (getBrokerId, getContract)
|
|
342
|
-
* @returns Function that takes processId and optional security confirmation, returns frozen action
|
|
343
|
-
*
|
|
344
|
-
* @example Creating open connection actions
|
|
345
|
-
* ```typescript
|
|
346
|
-
* // Without security
|
|
347
|
-
* const action = openConnection(deps)('process-123')
|
|
348
|
-
*
|
|
349
|
-
* // With security confirmation
|
|
350
|
-
* const secureAction = openConnection(deps)('process-123', {
|
|
351
|
-
* active: true,
|
|
352
|
-
* protocol: 'v2'
|
|
353
|
-
* })
|
|
354
|
-
* ```
|
|
355
|
-
*/
|
|
356
100
|
const openConnection = (deps) => (processId, security) => {
|
|
357
101
|
const base = {
|
|
358
102
|
type: ACTION_TYPES.OPEN_CONNECTION,
|
|
@@ -365,24 +109,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
365
109
|
return freeze(base);
|
|
366
110
|
};
|
|
367
111
|
|
|
368
|
-
/**
|
|
369
|
-
* Creates REQUEST_CONNECTION action
|
|
370
|
-
*
|
|
371
|
-
* @param deps - Action dependencies (getBrokerId, getContract)
|
|
372
|
-
* @returns Function that takes processId and optional security request, returns frozen action
|
|
373
|
-
*
|
|
374
|
-
* @example Creating request connection actions
|
|
375
|
-
* ```typescript
|
|
376
|
-
* // Without security
|
|
377
|
-
* const action = requestConnection(deps)('process-123')
|
|
378
|
-
*
|
|
379
|
-
* // With security negotiation
|
|
380
|
-
* const secureAction = requestConnection(deps)('process-123', {
|
|
381
|
-
* supported: ['v2', 'v1', 'none'],
|
|
382
|
-
* preferred: 'v2'
|
|
383
|
-
* })
|
|
384
|
-
* ```
|
|
385
|
-
*/
|
|
386
112
|
const requestConnection = (deps) => (processId, security) => {
|
|
387
113
|
const base = {
|
|
388
114
|
type: ACTION_TYPES.REQUEST_CONNECTION,
|
|
@@ -396,21 +122,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
396
122
|
return freeze(base);
|
|
397
123
|
};
|
|
398
124
|
|
|
399
|
-
/**
|
|
400
|
-
* Creates all action creators bound to the provided dependencies
|
|
401
|
-
*
|
|
402
|
-
* @param deps - Action dependencies (getBrokerId, getContract)
|
|
403
|
-
* @returns Frozen object containing all action creator functions
|
|
404
|
-
*
|
|
405
|
-
* @example Creating action creators
|
|
406
|
-
* ```typescript
|
|
407
|
-
* const actions = createActionCreators({
|
|
408
|
-
* getBrokerId: () => 'broker-123',
|
|
409
|
-
* getContract: () => myContract
|
|
410
|
-
* })
|
|
411
|
-
* const action = actions.requestConnection('process-456')
|
|
412
|
-
* ```
|
|
413
|
-
*/
|
|
414
125
|
const createActionCreators = (deps) => freeze({
|
|
415
126
|
requestConnection: requestConnection(deps),
|
|
416
127
|
acceptConnection: acceptConnection(deps),
|
|
@@ -423,102 +134,26 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
423
134
|
invalidRequest: invalidRequest(deps),
|
|
424
135
|
});
|
|
425
136
|
|
|
426
|
-
/**
|
|
427
|
-
* Safe Map factory with optional groupBy for ES2024+.
|
|
428
|
-
*
|
|
429
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/map
|
|
430
|
-
*/
|
|
431
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
432
137
|
const _Map = globalThis.Map;
|
|
433
|
-
const _Reflect$
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
* Use this instead of `new Map()`.
|
|
437
|
-
*
|
|
438
|
-
* @param iterable - Optional iterable of key-value pairs.
|
|
439
|
-
* @returns A new Map instance.
|
|
440
|
-
*/
|
|
441
|
-
const createMap = (iterable) => _Reflect$7.construct(_Map, iterable ? [iterable] : []);
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* Clears all processes from the registry
|
|
445
|
-
*
|
|
446
|
-
* @param processes - Map storing process to channel mappings
|
|
447
|
-
* @returns Function that clears all processes
|
|
448
|
-
*
|
|
449
|
-
* @example Clearing all processes
|
|
450
|
-
* ```typescript
|
|
451
|
-
* const clear = clearProcesses(processMap)
|
|
452
|
-
* clear() // All processes removed
|
|
453
|
-
* ```
|
|
454
|
-
*/
|
|
138
|
+
const _Reflect$8 = globalThis.Reflect;
|
|
139
|
+
const createMap = (iterable) => _Reflect$8.construct(_Map, iterable ? [iterable] : []);
|
|
140
|
+
|
|
455
141
|
const clearProcesses = (processes) => () => {
|
|
456
142
|
processes.clear();
|
|
457
143
|
};
|
|
458
144
|
|
|
459
|
-
/**
|
|
460
|
-
* Creates a process ID and registers the channel
|
|
461
|
-
*
|
|
462
|
-
* @param processes - Map storing process to channel mappings
|
|
463
|
-
* @returns Function that takes a channel and returns new process ID
|
|
464
|
-
*
|
|
465
|
-
* @example Registering a channel process
|
|
466
|
-
* ```typescript
|
|
467
|
-
* const create = createProcess(processMap)
|
|
468
|
-
* const processId = create(myChannel)
|
|
469
|
-
* ```
|
|
470
|
-
*/
|
|
471
145
|
const createProcess = (processes) => (channel) => {
|
|
472
146
|
const processId = uuidV4();
|
|
473
147
|
processes.set(processId, channel);
|
|
474
148
|
return processId;
|
|
475
149
|
};
|
|
476
150
|
|
|
477
|
-
/**
|
|
478
|
-
* Gets a channel by its process ID
|
|
479
|
-
*
|
|
480
|
-
* @param processes - Map storing process to channel mappings
|
|
481
|
-
* @returns Function that takes processId and returns channel or undefined
|
|
482
|
-
*
|
|
483
|
-
* @example Looking up channel by process ID
|
|
484
|
-
* ```typescript
|
|
485
|
-
* const processes = new Map([['proc-1', channelHandle]])
|
|
486
|
-
* const findChannel = getChannel(processes)
|
|
487
|
-
* const channel = findChannel('proc-1')
|
|
488
|
-
* // => channelHandle or undefined
|
|
489
|
-
* ```
|
|
490
|
-
*/
|
|
491
151
|
const getChannel$1 = (processes) => (processId) => processes.get(processId);
|
|
492
152
|
|
|
493
|
-
/**
|
|
494
|
-
* Removes a process ID from the registry
|
|
495
|
-
*
|
|
496
|
-
* @param processes - Map storing process to channel mappings
|
|
497
|
-
* @returns Function that takes processId and removes it
|
|
498
|
-
*
|
|
499
|
-
* @example Removing a process
|
|
500
|
-
* ```typescript
|
|
501
|
-
* const remove = removeProcess(processMap)
|
|
502
|
-
* remove('some-process-id')
|
|
503
|
-
* ```
|
|
504
|
-
*/
|
|
505
153
|
const removeProcess = (processes) => (processId) => {
|
|
506
154
|
processes.delete(processId);
|
|
507
155
|
};
|
|
508
156
|
|
|
509
|
-
/**
|
|
510
|
-
* Creates a process manager for tracking process IDs to channel mappings
|
|
511
|
-
*
|
|
512
|
-
* @returns Object with process management methods
|
|
513
|
-
*
|
|
514
|
-
* @example Managing channel processes
|
|
515
|
-
* ```typescript
|
|
516
|
-
* const processManager = createProcessManager()
|
|
517
|
-
* const processId = processManager.create(channel)
|
|
518
|
-
* const found = processManager.get(processId)
|
|
519
|
-
* processManager.remove(processId)
|
|
520
|
-
* ```
|
|
521
|
-
*/
|
|
522
157
|
const createProcessManager = () => {
|
|
523
158
|
const processes = createMap();
|
|
524
159
|
return freeze({
|
|
@@ -526,98 +161,27 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
526
161
|
get: getChannel$1(processes),
|
|
527
162
|
remove: removeProcess(processes),
|
|
528
163
|
clear: clearProcesses(processes),
|
|
529
|
-
/**
|
|
530
|
-
* Track an existing process ID with a channel.
|
|
531
|
-
* Useful when receiving a process ID from the remote side that needs to be associated
|
|
532
|
-
* with a local channel instance.
|
|
533
|
-
*
|
|
534
|
-
* @param processId - The process ID to track
|
|
535
|
-
* @param channel - The channel handle to associate with the process ID
|
|
536
|
-
*/
|
|
537
164
|
track: (processId, channel) => {
|
|
538
165
|
processes.set(processId, channel);
|
|
539
166
|
},
|
|
540
|
-
/**
|
|
541
|
-
* Check if a process ID exists in the manager.
|
|
542
|
-
*
|
|
543
|
-
* @param processId - The process ID to check
|
|
544
|
-
* @returns True if the process ID exists, false otherwise
|
|
545
|
-
*/
|
|
546
167
|
has: (processId) => {
|
|
547
168
|
return processes.has(processId);
|
|
548
169
|
},
|
|
549
170
|
});
|
|
550
171
|
};
|
|
551
172
|
|
|
552
|
-
/**
|
|
553
|
-
* Safe copies of Array built-in static methods.
|
|
554
|
-
*
|
|
555
|
-
* These references are captured at module initialization time to protect against
|
|
556
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
557
|
-
*
|
|
558
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/array
|
|
559
|
-
*/
|
|
560
173
|
const _Array = globalThis.Array;
|
|
561
|
-
/**
|
|
562
|
-
* (Safe copy) Determines whether the passed value is an Array.
|
|
563
|
-
*/
|
|
564
174
|
const isArray = _Array.isArray;
|
|
565
|
-
/**
|
|
566
|
-
* (Safe copy) Creates an array from an array-like or iterable object.
|
|
567
|
-
*/
|
|
568
175
|
const from = _Array.from;
|
|
569
176
|
|
|
570
|
-
/**
|
|
571
|
-
* Safe Set factory for protected set construction.
|
|
572
|
-
*
|
|
573
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/set
|
|
574
|
-
*/
|
|
575
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
576
177
|
const _Set = globalThis.Set;
|
|
577
|
-
const _Reflect$
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
* Use this instead of `new Set()`.
|
|
581
|
-
*
|
|
582
|
-
* @param iterable - Optional iterable of values.
|
|
583
|
-
* @returns A new Set instance.
|
|
584
|
-
*/
|
|
585
|
-
const createSet = (iterable) => _Reflect$6.construct(_Set, iterable ? [iterable] : []);
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* Safe WeakMap factory for protected weak map construction.
|
|
589
|
-
*
|
|
590
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/weak-map
|
|
591
|
-
*/
|
|
592
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
178
|
+
const _Reflect$7 = globalThis.Reflect;
|
|
179
|
+
const createSet = (iterable) => _Reflect$7.construct(_Set, iterable ? [iterable] : []);
|
|
180
|
+
|
|
593
181
|
const _WeakMap = globalThis.WeakMap;
|
|
594
|
-
const _Reflect$
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
* Use this instead of `new WeakMap()`.
|
|
598
|
-
*
|
|
599
|
-
* @param iterable - Optional iterable of key-value pairs.
|
|
600
|
-
* @returns A new WeakMap instance.
|
|
601
|
-
*/
|
|
602
|
-
const createWeakMap = (iterable) => _Reflect$5.construct(_WeakMap, iterable ? [iterable] : []);
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Minimal channel structure required for registry operations.
|
|
606
|
-
* Extended with optional methods for use with full ChannelHandle objects.
|
|
607
|
-
*/
|
|
608
|
-
/**
|
|
609
|
-
* Creates a new channel registry with isolated state.
|
|
610
|
-
* All lookup operations are O(1) using WeakMap/Map.
|
|
611
|
-
*
|
|
612
|
-
* @returns Registry functions for managing channels
|
|
613
|
-
*
|
|
614
|
-
* @example Creating and using a registry
|
|
615
|
-
* ```typescript
|
|
616
|
-
* const registry = createRegistry()
|
|
617
|
-
* registry.add({ id: 'ch-1', name: 'main', target: iframe.contentWindow })
|
|
618
|
-
* const channel = registry.getById('ch-1')
|
|
619
|
-
* ```
|
|
620
|
-
*/
|
|
182
|
+
const _Reflect$6 = globalThis.Reflect;
|
|
183
|
+
const createWeakMap = (iterable) => _Reflect$6.construct(_WeakMap, iterable ? [iterable] : []);
|
|
184
|
+
|
|
621
185
|
function createRegistry() {
|
|
622
186
|
const windowMap = createWeakMap();
|
|
623
187
|
const idMap = createMap();
|
|
@@ -664,31 +228,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
664
228
|
});
|
|
665
229
|
}
|
|
666
230
|
|
|
667
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
668
|
-
/**
|
|
669
|
-
* Check if value is an object (not null, not array)
|
|
670
|
-
*
|
|
671
|
-
* @param value - The value to check
|
|
672
|
-
* @returns True if value is a plain object
|
|
673
|
-
*/
|
|
674
231
|
function isObject(value) {
|
|
675
232
|
return value !== null && typeof value === 'object' && !isArray(value);
|
|
676
233
|
}
|
|
677
234
|
|
|
678
|
-
/**
|
|
679
|
-
* Validates a channel contract structure.
|
|
680
|
-
*
|
|
681
|
-
* @param contract - The contract to validate
|
|
682
|
-
* @throws {Error} Error if contract is invalid
|
|
683
|
-
*
|
|
684
|
-
* @example Validating contract structure
|
|
685
|
-
* ```typescript
|
|
686
|
-
* validateContract({
|
|
687
|
-
* emitted: [{ type: 'ping' }],
|
|
688
|
-
* accepted: [{ type: 'pong' }]
|
|
689
|
-
* })
|
|
690
|
-
* ```
|
|
691
|
-
*/
|
|
692
235
|
function validateContract$1(contract) {
|
|
693
236
|
if (!contract) {
|
|
694
237
|
throw createError('Contract cannot be null or undefined');
|
|
@@ -722,27 +265,9 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
722
265
|
}
|
|
723
266
|
}
|
|
724
267
|
|
|
725
|
-
/**
|
|
726
|
-
* Helper to check if a string is empty after trimming
|
|
727
|
-
*
|
|
728
|
-
* @param str - The string to check
|
|
729
|
-
* @returns True if string is empty after trimming
|
|
730
|
-
*/
|
|
731
268
|
function isEmpty(str) {
|
|
732
269
|
return str.trim().length === 0;
|
|
733
270
|
}
|
|
734
|
-
/**
|
|
735
|
-
* Validates a channel or broker name.
|
|
736
|
-
*
|
|
737
|
-
* @param name - The name to validate
|
|
738
|
-
* @throws {Error} Error if name is invalid
|
|
739
|
-
*
|
|
740
|
-
* @example Validating channel name
|
|
741
|
-
* ```typescript
|
|
742
|
-
* validateName('my-channel') // valid
|
|
743
|
-
* validateName('') // throws Error
|
|
744
|
-
* ```
|
|
745
|
-
*/
|
|
746
271
|
function validateName(name) {
|
|
747
272
|
if (name === null || name === undefined) {
|
|
748
273
|
throw createError('Name cannot be null or undefined');
|
|
@@ -755,98 +280,29 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
755
280
|
}
|
|
756
281
|
}
|
|
757
282
|
|
|
758
|
-
/**
|
|
759
|
-
* Protocol registry factory.
|
|
760
|
-
*
|
|
761
|
-
* Creates a registry for managing protocol providers at the broker level.
|
|
762
|
-
*
|
|
763
|
-
* @module security/registry/factory
|
|
764
|
-
*/
|
|
765
|
-
/**
|
|
766
|
-
* Creates a protocol registry for managing security protocol providers.
|
|
767
|
-
*
|
|
768
|
-
* The registry provides a centralized store for protocol providers,
|
|
769
|
-
* allowing channels to retrieve the appropriate provider based on
|
|
770
|
-
* the negotiated protocol version.
|
|
771
|
-
*
|
|
772
|
-
* The 'none' protocol is always considered supported (it requires
|
|
773
|
-
* no provider) and cannot be registered or unregistered.
|
|
774
|
-
*
|
|
775
|
-
* @returns A new protocol registry instance
|
|
776
|
-
*
|
|
777
|
-
* @example Managing protocol providers
|
|
778
|
-
* ```typescript
|
|
779
|
-
* const registry = createProtocolRegistry()
|
|
780
|
-
*
|
|
781
|
-
* // Register v1 protocol
|
|
782
|
-
* registry.register('v1', createProtocol(logger, 60))
|
|
783
|
-
*
|
|
784
|
-
* // Check availability
|
|
785
|
-
* registry.has('v1') // true
|
|
786
|
-
* registry.has('v2') // false
|
|
787
|
-
* registry.has('none') // always true
|
|
788
|
-
*
|
|
789
|
-
* // Get supported versions
|
|
790
|
-
* registry.getSupportedVersions() // ['v1', 'none']
|
|
791
|
-
* ```
|
|
792
|
-
*/
|
|
793
283
|
function createProtocolRegistry() {
|
|
794
284
|
const providers = createMap();
|
|
795
|
-
/**
|
|
796
|
-
* Register a protocol provider.
|
|
797
|
-
*
|
|
798
|
-
* @param version - The protocol version ('v1' or 'v2')
|
|
799
|
-
* @param provider - The protocol provider instance
|
|
800
|
-
*/
|
|
801
285
|
const register = (version, provider) => {
|
|
802
286
|
if (!provider) {
|
|
803
287
|
throw createError(`Cannot register null/undefined provider for ${version}`);
|
|
804
288
|
}
|
|
805
289
|
providers.set(version, provider);
|
|
806
290
|
};
|
|
807
|
-
/**
|
|
808
|
-
* Unregister a protocol provider.
|
|
809
|
-
*
|
|
810
|
-
* @param version - The protocol version to unregister
|
|
811
|
-
*/
|
|
812
291
|
const unregister = (version) => {
|
|
813
292
|
providers.delete(version);
|
|
814
293
|
};
|
|
815
|
-
/**
|
|
816
|
-
* Get a registered protocol provider.
|
|
817
|
-
*
|
|
818
|
-
* Returns undefined for 'none' since it requires no provider.
|
|
819
|
-
*
|
|
820
|
-
* @param version - The protocol version to retrieve
|
|
821
|
-
* @returns The provider if registered, otherwise undefined
|
|
822
|
-
*/
|
|
823
294
|
const get = (version) => {
|
|
824
295
|
if (version === 'none') {
|
|
825
296
|
return undefined;
|
|
826
297
|
}
|
|
827
298
|
return providers.get(version);
|
|
828
299
|
};
|
|
829
|
-
/**
|
|
830
|
-
* Check if a protocol provider is registered.
|
|
831
|
-
*
|
|
832
|
-
* The 'none' protocol is always considered available.
|
|
833
|
-
*
|
|
834
|
-
* @param version - The protocol version to check
|
|
835
|
-
* @returns True if the provider is registered (or 'none')
|
|
836
|
-
*/
|
|
837
300
|
const has = (version) => {
|
|
838
301
|
if (version === 'none') {
|
|
839
302
|
return true;
|
|
840
303
|
}
|
|
841
304
|
return providers.has(version);
|
|
842
305
|
};
|
|
843
|
-
/**
|
|
844
|
-
* Get all supported protocol versions.
|
|
845
|
-
*
|
|
846
|
-
* Returns versions that have registered providers plus 'none'.
|
|
847
|
-
*
|
|
848
|
-
* @returns Array of supported protocol versions
|
|
849
|
-
*/
|
|
850
306
|
const getSupportedVersions = () => {
|
|
851
307
|
const versions = ['none'];
|
|
852
308
|
if (providers.has('v1')) {
|
|
@@ -866,20 +322,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
866
322
|
});
|
|
867
323
|
}
|
|
868
324
|
|
|
869
|
-
/**
|
|
870
|
-
* Merges multiple channel contracts into a single contract
|
|
871
|
-
*
|
|
872
|
-
* @param contracts - The contracts to merge
|
|
873
|
-
* @returns A single merged contract containing all accepted and provided actions
|
|
874
|
-
*
|
|
875
|
-
* @example Merging channel contracts
|
|
876
|
-
* ```typescript
|
|
877
|
-
* const contract1 = { accepted: [{ type: 'a' }], provided: [{ type: 'b' }] }
|
|
878
|
-
* const contract2 = { accepted: [{ type: 'c' }], provided: [{ type: 'd' }] }
|
|
879
|
-
* const merged = mergeContracts(contract1, contract2)
|
|
880
|
-
* // merged = { accepted: [{ type: 'a' }, { type: 'c' }], emitted: [{ type: 'b' }, { type: 'd' }] }
|
|
881
|
-
* ```
|
|
882
|
-
*/
|
|
883
325
|
function mergeContracts(...contracts) {
|
|
884
326
|
const mergedContract = {
|
|
885
327
|
accepted: [],
|
|
@@ -916,38 +358,9 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
916
358
|
info: 1,
|
|
917
359
|
debug: 0,
|
|
918
360
|
};
|
|
919
|
-
/**
|
|
920
|
-
* Validates whether a given string is a valid log level.
|
|
921
|
-
*
|
|
922
|
-
* @param level - The log level to validate
|
|
923
|
-
* @returns True if the level is valid, false otherwise
|
|
924
|
-
*
|
|
925
|
-
* @example Validating log levels
|
|
926
|
-
* ```typescript
|
|
927
|
-
* isValidLogLevel('error') // => true
|
|
928
|
-
* isValidLogLevel('verbose') // => false
|
|
929
|
-
* ```
|
|
930
|
-
*/
|
|
931
361
|
function isValidLogLevel(level) {
|
|
932
362
|
return logLevels.includes(level);
|
|
933
363
|
}
|
|
934
|
-
/**
|
|
935
|
-
* Creates a log level configuration manager for controlling logging behavior.
|
|
936
|
-
* Provides methods to get, set, and evaluate log levels based on priority.
|
|
937
|
-
*
|
|
938
|
-
* @param level - The initial log level (defaults to 'error')
|
|
939
|
-
* @returns A configuration object with log level management methods
|
|
940
|
-
* @throws {Error} When the provided level is not a valid log level
|
|
941
|
-
*
|
|
942
|
-
* @example Managing log levels with priority checks
|
|
943
|
-
* ```typescript
|
|
944
|
-
* const config = createLogLevelConfig('warn')
|
|
945
|
-
* config.shouldLog('error') // => true (error >= warn)
|
|
946
|
-
* config.shouldLog('debug') // => false (debug < warn)
|
|
947
|
-
* config.setLogLevel('debug')
|
|
948
|
-
* config.shouldLog('debug') // => true
|
|
949
|
-
* ```
|
|
950
|
-
*/
|
|
951
364
|
function createLogLevelConfig(level = 'error') {
|
|
952
365
|
if (!isValidLogLevel(level)) {
|
|
953
366
|
throw createError('Cannot create log level configuration with a valid default log level');
|
|
@@ -999,18 +412,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
999
412
|
},
|
|
1000
413
|
];
|
|
1001
414
|
|
|
1002
|
-
/**
|
|
1003
|
-
* Gets the keys from an iterable target based on its data type.
|
|
1004
|
-
*
|
|
1005
|
-
* @param target - The target to get the keys from.
|
|
1006
|
-
* @param dataType - The data type of the target.
|
|
1007
|
-
* @returns The keys from the iterable target.
|
|
1008
|
-
*
|
|
1009
|
-
* @example Extracting keys from object
|
|
1010
|
-
* ```typescript
|
|
1011
|
-
* getKeysFromIterable({ a: 1, b: 2 }, 'object') // ['a', 'b']
|
|
1012
|
-
* ```
|
|
1013
|
-
*/
|
|
1014
415
|
const getKeysFromIterable = (target, dataType) => {
|
|
1015
416
|
if (dataType === 'array')
|
|
1016
417
|
dataType = Array.name;
|
|
@@ -1022,21 +423,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1022
423
|
return iterableClass.getKeys(target);
|
|
1023
424
|
};
|
|
1024
425
|
|
|
1025
|
-
/**
|
|
1026
|
-
* Returns the data type of the target.
|
|
1027
|
-
* Uses native `typeof` operator, however, makes distinction between `null`, `array`, and `object`.
|
|
1028
|
-
* Also, when classes are registered via `registerClass`, it checks if objects are instance of any known registered class.
|
|
1029
|
-
*
|
|
1030
|
-
* @param target - The target to get the data type of.
|
|
1031
|
-
* @returns The data type of the target.
|
|
1032
|
-
*
|
|
1033
|
-
* @example Determining data types
|
|
1034
|
-
* ```typescript
|
|
1035
|
-
* getType([1, 2]) // 'array'
|
|
1036
|
-
* getType({ a: 1 }) // 'object'
|
|
1037
|
-
* getType(null) // 'null'
|
|
1038
|
-
* ```
|
|
1039
|
-
*/
|
|
1040
426
|
const getType = (target) => {
|
|
1041
427
|
if (target === null)
|
|
1042
428
|
return 'null';
|
|
@@ -1052,17 +438,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1052
438
|
return nativeDataType;
|
|
1053
439
|
};
|
|
1054
440
|
|
|
1055
|
-
/**
|
|
1056
|
-
* Returns a list of iterable data types. By default 'array' and 'object' are included.,
|
|
1057
|
-
* but can be extended by using `registerIterableClass`.
|
|
1058
|
-
*
|
|
1059
|
-
* @returns Array of iterable data types.
|
|
1060
|
-
*
|
|
1061
|
-
* @example Listing registered iterable types
|
|
1062
|
-
* ```typescript
|
|
1063
|
-
* getIterableTypes() // ['array', 'object', ...registered types]
|
|
1064
|
-
* ```
|
|
1065
|
-
*/
|
|
1066
441
|
const getIterableTypes = () => registeredIterableClasses.map(({ classRef }) => {
|
|
1067
442
|
const name = classRef.name;
|
|
1068
443
|
if (name === Object.name)
|
|
@@ -1072,109 +447,19 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1072
447
|
return name;
|
|
1073
448
|
});
|
|
1074
449
|
|
|
1075
|
-
/**
|
|
1076
|
-
* Checks if the provided data type is registered as an iterable type.
|
|
1077
|
-
*
|
|
1078
|
-
* @param dataType - The data type to check
|
|
1079
|
-
* @returns `true` if the data type is iterable, otherwise `false`
|
|
1080
|
-
*
|
|
1081
|
-
* @example Checking iterable types
|
|
1082
|
-
* ```typescript
|
|
1083
|
-
* isIterableType('array') // true
|
|
1084
|
-
* isIterableType('object') // true
|
|
1085
|
-
* isIterableType('string') // false
|
|
1086
|
-
* ```
|
|
1087
|
-
*/
|
|
1088
450
|
const isIterableType = (dataType) => getIterableTypes().includes(dataType);
|
|
1089
451
|
|
|
1090
|
-
/**
|
|
1091
|
-
* Checks if the target is iterable.
|
|
1092
|
-
*
|
|
1093
|
-
* @param target - The target to check.
|
|
1094
|
-
* @returns `true` if the target is iterable, `false` otherwise.
|
|
1095
|
-
*
|
|
1096
|
-
* @example Checking if value is iterable
|
|
1097
|
-
* ```typescript
|
|
1098
|
-
* isIterable([1, 2]) // true
|
|
1099
|
-
* isIterable({ a: 1 }) // true
|
|
1100
|
-
* isIterable('string') // false
|
|
1101
|
-
* ```
|
|
1102
|
-
*/
|
|
1103
452
|
const isIterable = (target) => isIterableType(getType(target));
|
|
1104
453
|
|
|
1105
|
-
/**
|
|
1106
|
-
* Safe copies of Date built-in via factory function and static methods.
|
|
1107
|
-
*
|
|
1108
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/date
|
|
1109
|
-
*/
|
|
1110
|
-
/* eslint-disable jsdoc/require-param */
|
|
1111
454
|
const _Date = globalThis.Date;
|
|
1112
|
-
const _Reflect$
|
|
1113
|
-
/**
|
|
1114
|
-
* (Safe copy) Creates a new Date using the captured Date constructor.
|
|
1115
|
-
* Use this instead of `new Date()`. Accepts all standard Date constructor signatures.
|
|
1116
|
-
*
|
|
1117
|
-
* @returns A new Date instance.
|
|
1118
|
-
*
|
|
1119
|
-
* @example Creating Date instances
|
|
1120
|
-
* ```typescript
|
|
1121
|
-
* const now = createDate()
|
|
1122
|
-
* const fromTimestamp = createDate(1704067200000)
|
|
1123
|
-
* const fromString = createDate('2024-01-01T00:00:00Z')
|
|
1124
|
-
* const fromParts = createDate(2024, 0, 1, 12, 30, 0) // Jan 1, 2024 12:30:00
|
|
1125
|
-
* ```
|
|
1126
|
-
*/
|
|
455
|
+
const _Reflect$5 = globalThis.Reflect;
|
|
1127
456
|
function createDate(...args) {
|
|
1128
|
-
return _Reflect$
|
|
1129
|
-
}
|
|
1130
|
-
/**
|
|
1131
|
-
* (Safe copy) Returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
|
|
1132
|
-
*
|
|
1133
|
-
* @example
|
|
1134
|
-
* ```typescript
|
|
1135
|
-
* const timestamp = dateNow()
|
|
1136
|
-
* // => 1704067200000 (example timestamp)
|
|
1137
|
-
* ```
|
|
1138
|
-
*/
|
|
457
|
+
return _Reflect$5.construct(_Date, args);
|
|
458
|
+
}
|
|
1139
459
|
const dateNow = _Date.now;
|
|
1140
|
-
/**
|
|
1141
|
-
* (Safe copy) Parses a string representation of a date.
|
|
1142
|
-
*
|
|
1143
|
-
* @example
|
|
1144
|
-
* ```typescript
|
|
1145
|
-
* const timestamp = dateParse('2024-01-01T00:00:00Z')
|
|
1146
|
-
* // => 1704067200000
|
|
1147
|
-
* ```
|
|
1148
|
-
*/
|
|
1149
460
|
const dateParse = _Date.parse;
|
|
1150
|
-
/**
|
|
1151
|
-
* (Safe copy) Returns the number of milliseconds in a Date object since January 1, 1970 UTC.
|
|
1152
|
-
*
|
|
1153
|
-
* @example
|
|
1154
|
-
* ```typescript
|
|
1155
|
-
* const timestamp = dateUTC(2024, 0, 1, 12, 0, 0)
|
|
1156
|
-
* // => 1704110400000 (Jan 1, 2024 12:00:00 UTC)
|
|
1157
|
-
* ```
|
|
1158
|
-
*/
|
|
1159
461
|
const dateUTC = _Date.UTC;
|
|
1160
462
|
|
|
1161
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1162
|
-
/**
|
|
1163
|
-
* Creates a wrapper function that only executes the wrapped function if the condition function returns true.
|
|
1164
|
-
*
|
|
1165
|
-
* @param func - The function to be conditionally executed.
|
|
1166
|
-
* @param conditionFunc - A function that returns a boolean, determining if `func` should be executed.
|
|
1167
|
-
* @returns A wrapped version of `func` that executes conditionally.
|
|
1168
|
-
*
|
|
1169
|
-
* @example Conditional logging based on flag
|
|
1170
|
-
* ```typescript
|
|
1171
|
-
* let enabled = false
|
|
1172
|
-
* const conditionalLog = createConditionalExecutionFunction(console.log, () => enabled)
|
|
1173
|
-
* conditionalLog('test') // does nothing
|
|
1174
|
-
* enabled = true
|
|
1175
|
-
* conditionalLog('test') // logs 'test'
|
|
1176
|
-
* ```
|
|
1177
|
-
*/
|
|
1178
463
|
function createConditionalExecutionFunction(func, conditionFunc) {
|
|
1179
464
|
return function (...args) {
|
|
1180
465
|
if (conditionFunc()) {
|
|
@@ -1183,77 +468,19 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1183
468
|
};
|
|
1184
469
|
}
|
|
1185
470
|
|
|
1186
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1187
|
-
/**
|
|
1188
|
-
* Creates a wrapper function that silently ignores any errors thrown by the wrapped void function.
|
|
1189
|
-
* This function is specifically for wrapping functions that do not return a value (void functions).
|
|
1190
|
-
* Exceptions are swallowed without any logging or handling.
|
|
1191
|
-
*
|
|
1192
|
-
* @param func - The void function to be wrapped.
|
|
1193
|
-
* @returns A wrapped version of the input function that ignores errors.
|
|
1194
|
-
*
|
|
1195
|
-
* @example Safely parsing invalid JSON
|
|
1196
|
-
* ```typescript
|
|
1197
|
-
* const safeParse = createErrorIgnoringFunction(() => JSON.parse('invalid'))
|
|
1198
|
-
* safeParse() // silently fails without throwing
|
|
1199
|
-
* ```
|
|
1200
|
-
*/
|
|
1201
471
|
function createErrorIgnoringFunction(func) {
|
|
1202
472
|
return function (...args) {
|
|
1203
473
|
try {
|
|
1204
474
|
func(...args);
|
|
1205
475
|
}
|
|
1206
476
|
catch {
|
|
1207
|
-
// Deliberately swallowing/ignoring the exception
|
|
1208
477
|
}
|
|
1209
478
|
};
|
|
1210
479
|
}
|
|
1211
480
|
|
|
1212
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
1213
|
-
/**
|
|
1214
|
-
* A no-operation function (noop) that does nothing regardless of the arguments passed.
|
|
1215
|
-
* It is designed to be as permissive as possible in its typing without using the `Function` keyword.
|
|
1216
|
-
*
|
|
1217
|
-
* @param args - Any arguments passed to the function (ignored)
|
|
1218
|
-
*
|
|
1219
|
-
* @example Using noop as fallback callback
|
|
1220
|
-
* ```typescript
|
|
1221
|
-
* const callback = condition ? handleEvent : noop
|
|
1222
|
-
* callback() // safely does nothing if condition is false
|
|
1223
|
-
* ```
|
|
1224
|
-
*/
|
|
1225
481
|
const noop = (...args) => {
|
|
1226
|
-
// Intentionally does nothing
|
|
1227
482
|
};
|
|
1228
483
|
|
|
1229
|
-
/**
|
|
1230
|
-
* Creates a logger instance with configurable log level filtering.
|
|
1231
|
-
* Each log function is wrapped to respect the current log level setting.
|
|
1232
|
-
*
|
|
1233
|
-
* @param error - Function to handle error-level logs (required)
|
|
1234
|
-
* @param warn - Function to handle warning-level logs (optional, defaults to noop)
|
|
1235
|
-
* @param log - Function to handle standard logs (optional, defaults to noop)
|
|
1236
|
-
* @param info - Function to handle info-level logs (optional, defaults to noop)
|
|
1237
|
-
* @param debug - Function to handle debug-level logs (optional, defaults to noop)
|
|
1238
|
-
* @returns A frozen logger object with log methods, level control, channel, and timing helpers
|
|
1239
|
-
* @throws {ErrorLevelFn} When any provided log function is invalid
|
|
1240
|
-
*
|
|
1241
|
-
* @example Creating a logger with log level filtering
|
|
1242
|
-
* ```typescript
|
|
1243
|
-
* const logger = createLogger(console.error, console.warn, console.log)
|
|
1244
|
-
* logger.setLogLevel('warn')
|
|
1245
|
-
* logger.warn('Connection timeout') // logs
|
|
1246
|
-
* logger.info('Request complete') // suppressed (below 'warn' level)
|
|
1247
|
-
* ```
|
|
1248
|
-
*
|
|
1249
|
-
* @example Channeling and timing
|
|
1250
|
-
* ```typescript
|
|
1251
|
-
* const logger = createLogger(console.error, console.warn, console.log, console.info, console.debug)
|
|
1252
|
-
* logger.setLogLevel('debug')
|
|
1253
|
-
* const build = logger.channel('build')
|
|
1254
|
-
* await build.timedAsync('bundle', async () => bundle())
|
|
1255
|
-
* ```
|
|
1256
|
-
*/
|
|
1257
484
|
function createLogger$1(error, warn = noop, log = noop, info = noop, debug = noop) {
|
|
1258
485
|
if (notValidLogFn(error)) {
|
|
1259
486
|
throw createError(notFnMsg('error'));
|
|
@@ -1288,20 +515,11 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1288
515
|
};
|
|
1289
516
|
return createPrefixedLogger(core, '');
|
|
1290
517
|
}
|
|
1291
|
-
/**
|
|
1292
|
-
* Creates a Logger that prepends `[fullPrefix]` to every log call. When `fullPrefix`
|
|
1293
|
-
* is empty, returns a Logger that delegates directly to the core functions.
|
|
1294
|
-
*
|
|
1295
|
-
* @param core - Shared level-aware log functions and level controls.
|
|
1296
|
-
* @param fullPrefix - Channel chain joined with `:`, or `''` for the root logger.
|
|
1297
|
-
* @returns A frozen Logger that emits with the resolved prefix.
|
|
1298
|
-
*/
|
|
1299
518
|
function createPrefixedLogger(core, fullPrefix) {
|
|
1300
519
|
const tag = fullPrefix ? `[${fullPrefix}]` : '';
|
|
1301
520
|
const prefixed = (fn) => {
|
|
1302
521
|
if (!tag)
|
|
1303
522
|
return fn;
|
|
1304
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1305
523
|
return (...data) => fn(tag, ...data);
|
|
1306
524
|
};
|
|
1307
525
|
const instance = freeze({
|
|
@@ -1322,14 +540,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1322
540
|
});
|
|
1323
541
|
return instance;
|
|
1324
542
|
}
|
|
1325
|
-
/**
|
|
1326
|
-
* Times a sync call, logging completion at debug level or failure at error level.
|
|
1327
|
-
*
|
|
1328
|
-
* @param logger - The logger used to emit the timing message.
|
|
1329
|
-
* @param label - Human-readable label for the timed operation.
|
|
1330
|
-
* @param fn - The synchronous operation to invoke.
|
|
1331
|
-
* @returns The value returned by `fn`.
|
|
1332
|
-
*/
|
|
1333
543
|
function runTimed(logger, label, fn) {
|
|
1334
544
|
const start = dateNow();
|
|
1335
545
|
try {
|
|
@@ -1344,15 +554,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1344
554
|
throw error;
|
|
1345
555
|
}
|
|
1346
556
|
}
|
|
1347
|
-
/**
|
|
1348
|
-
* Times an async call, logging completion at debug level or failure at error level.
|
|
1349
|
-
* On rejection with an `Error` carrying a stack, the stack is also dumped at debug level.
|
|
1350
|
-
*
|
|
1351
|
-
* @param logger - The logger used to emit the timing message.
|
|
1352
|
-
* @param label - Human-readable label for the timed operation.
|
|
1353
|
-
* @param fn - The async operation to invoke.
|
|
1354
|
-
* @returns The value resolved by `fn`'s promise.
|
|
1355
|
-
*/
|
|
1356
557
|
async function runTimedAsync(logger, label, fn) {
|
|
1357
558
|
const start = dateNow();
|
|
1358
559
|
try {
|
|
@@ -1370,144 +571,42 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1370
571
|
throw error;
|
|
1371
572
|
}
|
|
1372
573
|
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Extracts a human-readable message from an unknown thrown value.
|
|
1375
|
-
*
|
|
1376
|
-
* @param error - The unknown value caught from a try/catch or rejected promise.
|
|
1377
|
-
* @returns The error's `message` when it is an `Error`, otherwise its string coercion.
|
|
1378
|
-
*/
|
|
1379
574
|
function describeError(error) {
|
|
1380
575
|
return error instanceof Error ? error.message : String(error);
|
|
1381
576
|
}
|
|
1382
|
-
/**
|
|
1383
|
-
* Validates whether a given value is a valid log function.
|
|
1384
|
-
*
|
|
1385
|
-
* @param fn - The value to validate
|
|
1386
|
-
* @returns True if the value is not a function (invalid), false if it is valid
|
|
1387
|
-
*/
|
|
1388
577
|
function notValidLogFn(fn) {
|
|
1389
578
|
return getType(fn) !== 'function' && fn !== noop;
|
|
1390
579
|
}
|
|
1391
|
-
/**
|
|
1392
|
-
* Generates an error message for invalid log function parameters.
|
|
1393
|
-
*
|
|
1394
|
-
* @param label - The name of the log function that failed validation
|
|
1395
|
-
* @returns A formatted error message string
|
|
1396
|
-
*/
|
|
1397
580
|
function notFnMsg(label) {
|
|
1398
581
|
return `Cannot create a logger when ${label} is not a function`;
|
|
1399
582
|
}
|
|
1400
583
|
|
|
1401
|
-
/**
|
|
1402
|
-
* Safe copies of Console built-in methods.
|
|
1403
|
-
*
|
|
1404
|
-
* These references are captured at module initialization time to protect against
|
|
1405
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
1406
|
-
*
|
|
1407
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/console
|
|
1408
|
-
*/
|
|
1409
584
|
const _console = globalThis.console;
|
|
1410
|
-
/**
|
|
1411
|
-
* (Safe copy) Outputs a message to the console.
|
|
1412
|
-
*/
|
|
1413
585
|
const log = _console.log.bind(_console);
|
|
1414
|
-
/**
|
|
1415
|
-
* (Safe copy) Outputs a warning message to the console.
|
|
1416
|
-
*/
|
|
1417
586
|
const warn = _console.warn.bind(_console);
|
|
1418
|
-
/**
|
|
1419
|
-
* (Safe copy) Outputs an error message to the console.
|
|
1420
|
-
*/
|
|
1421
587
|
const error = _console.error.bind(_console);
|
|
1422
|
-
/**
|
|
1423
|
-
* (Safe copy) Outputs an informational message to the console.
|
|
1424
|
-
*/
|
|
1425
588
|
const info = _console.info.bind(_console);
|
|
1426
|
-
/**
|
|
1427
|
-
* (Safe copy) Outputs a debug message to the console.
|
|
1428
|
-
*/
|
|
1429
589
|
const debug = _console.debug.bind(_console);
|
|
1430
|
-
/**
|
|
1431
|
-
* (Safe copy) Outputs a stack trace to the console.
|
|
1432
|
-
*/
|
|
1433
590
|
_console.trace.bind(_console);
|
|
1434
|
-
/**
|
|
1435
|
-
* (Safe copy) Displays an interactive listing of the properties of a specified object.
|
|
1436
|
-
*/
|
|
1437
591
|
_console.dir.bind(_console);
|
|
1438
|
-
/**
|
|
1439
|
-
* (Safe copy) Displays tabular data as a table.
|
|
1440
|
-
*/
|
|
1441
592
|
_console.table.bind(_console);
|
|
1442
|
-
/**
|
|
1443
|
-
* (Safe copy) Writes an error message to the console if the assertion is false.
|
|
1444
|
-
*/
|
|
1445
593
|
_console.assert.bind(_console);
|
|
1446
|
-
/**
|
|
1447
|
-
* (Safe copy) Clears the console.
|
|
1448
|
-
*/
|
|
1449
594
|
_console.clear.bind(_console);
|
|
1450
|
-
/**
|
|
1451
|
-
* (Safe copy) Logs the number of times that this particular call to count() has been called.
|
|
1452
|
-
*/
|
|
1453
595
|
_console.count.bind(_console);
|
|
1454
|
-
/**
|
|
1455
|
-
* (Safe copy) Resets the counter used with console.count().
|
|
1456
|
-
*/
|
|
1457
596
|
_console.countReset.bind(_console);
|
|
1458
|
-
/**
|
|
1459
|
-
* (Safe copy) Creates a new inline group in the console.
|
|
1460
|
-
*/
|
|
1461
597
|
_console.group.bind(_console);
|
|
1462
|
-
/**
|
|
1463
|
-
* (Safe copy) Creates a new inline group in the console that is initially collapsed.
|
|
1464
|
-
*/
|
|
1465
598
|
_console.groupCollapsed.bind(_console);
|
|
1466
|
-
/**
|
|
1467
|
-
* (Safe copy) Exits the current inline group.
|
|
1468
|
-
*/
|
|
1469
599
|
_console.groupEnd.bind(_console);
|
|
1470
|
-
/**
|
|
1471
|
-
* (Safe copy) Starts a timer with a name specified as an input parameter.
|
|
1472
|
-
*/
|
|
1473
600
|
_console.time.bind(_console);
|
|
1474
|
-
/**
|
|
1475
|
-
* (Safe copy) Stops a timer that was previously started.
|
|
1476
|
-
*/
|
|
1477
601
|
_console.timeEnd.bind(_console);
|
|
1478
|
-
/**
|
|
1479
|
-
* (Safe copy) Logs the current value of a timer that was previously started.
|
|
1480
|
-
*/
|
|
1481
602
|
_console.timeLog.bind(_console);
|
|
1482
603
|
|
|
1483
604
|
const logger = createLogger$1(error, warn, log, info, debug);
|
|
1484
605
|
|
|
1485
606
|
const DEFAULT_PREFIX = '[nexus]';
|
|
1486
|
-
/**
|
|
1487
|
-
* Creates a logger instance configured for nexus.
|
|
1488
|
-
*
|
|
1489
|
-
* If a custom logger is provided, it will be used directly.
|
|
1490
|
-
* Otherwise, a new logger will be created using the logging library.
|
|
1491
|
-
*
|
|
1492
|
-
* @param options - Logger configuration options
|
|
1493
|
-
* @returns Logger instance
|
|
1494
|
-
*
|
|
1495
|
-
* @example Configuring logger options
|
|
1496
|
-
* ```typescript
|
|
1497
|
-
* const logger = createLogger({ level: 'debug', prefix: '[my-channel]' })
|
|
1498
|
-
* logger.debug('Channel initialized')
|
|
1499
|
-
* ```
|
|
1500
|
-
*/
|
|
1501
607
|
function createLogger(options = {}) {
|
|
1502
608
|
return createLoggerInternal(options);
|
|
1503
609
|
}
|
|
1504
|
-
/**
|
|
1505
|
-
* Internal helper to create a logger with given options.
|
|
1506
|
-
*
|
|
1507
|
-
* @param options - Logger configuration options
|
|
1508
|
-
* @returns Configured logger instance
|
|
1509
|
-
* @internal
|
|
1510
|
-
*/
|
|
1511
610
|
const createLoggerInternal = (options) => {
|
|
1512
611
|
const { level = 'error', prefix = DEFAULT_PREFIX, customLogger } = options;
|
|
1513
612
|
if (customLogger)
|
|
@@ -1518,31 +617,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1518
617
|
return nexusLogger;
|
|
1519
618
|
};
|
|
1520
619
|
|
|
1521
|
-
/**
|
|
1522
|
-
* Safe WeakSet factory for protected weak set construction.
|
|
1523
|
-
*
|
|
1524
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/weak-set
|
|
1525
|
-
*/
|
|
1526
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
1527
620
|
const _WeakSet = globalThis.WeakSet;
|
|
1528
|
-
const _Reflect$
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
* Use this instead of `new WeakSet()`.
|
|
1532
|
-
*
|
|
1533
|
-
* @param iterable - Optional iterable of values.
|
|
1534
|
-
* @returns A new WeakSet instance.
|
|
1535
|
-
*/
|
|
1536
|
-
const createWeakSet = (iterable) => _Reflect$3.construct(_WeakSet, iterable ? [iterable] : []);
|
|
1537
|
-
|
|
1538
|
-
/**
|
|
1539
|
-
* Checks whether an object has circular references using WeakSet.
|
|
1540
|
-
* Safe for use with frozen objects since it only reads, never mutates.
|
|
1541
|
-
*
|
|
1542
|
-
* @param value - The value to check
|
|
1543
|
-
* @param seen - WeakSet of already-seen references
|
|
1544
|
-
* @returns True if circular reference detected
|
|
1545
|
-
*/
|
|
621
|
+
const _Reflect$4 = globalThis.Reflect;
|
|
622
|
+
const createWeakSet = (iterable) => _Reflect$4.construct(_WeakSet, iterable ? [iterable] : []);
|
|
623
|
+
|
|
1546
624
|
function hasCircular(value, seen) {
|
|
1547
625
|
if (!isIterable(value))
|
|
1548
626
|
return false;
|
|
@@ -1559,36 +637,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1559
637
|
}
|
|
1560
638
|
return false;
|
|
1561
639
|
}
|
|
1562
|
-
/**
|
|
1563
|
-
* Asserts that the given value does not contain circular references.
|
|
1564
|
-
* Throws an Error if a circular reference is detected.
|
|
1565
|
-
*
|
|
1566
|
-
* Uses WeakSet-based cycle detection that works safely with frozen objects.
|
|
1567
|
-
*
|
|
1568
|
-
* @param value - The value to check for circular references
|
|
1569
|
-
* @param paramName - Name of the parameter for error messaging
|
|
1570
|
-
* @throws {Error} if circular reference is detected
|
|
1571
|
-
*
|
|
1572
|
-
* @example Checking for circular references
|
|
1573
|
-
* ```typescript
|
|
1574
|
-
* const config = { a: 1, b: 2 }
|
|
1575
|
-
* assertNoCircularRef(config, 'config') // OK
|
|
1576
|
-
*
|
|
1577
|
-
* const circular: Record<string, unknown> = { a: 1 }
|
|
1578
|
-
* circular.self = circular
|
|
1579
|
-
* assertNoCircularRef(circular, 'config') // Throws Error
|
|
1580
|
-
* ```
|
|
1581
|
-
*/
|
|
1582
640
|
function assertNoCircularRef(value, paramName) {
|
|
1583
641
|
if (hasCircular(value, createWeakSet())) {
|
|
1584
642
|
throw createError(`Circular reference detected in parameter "${paramName}"`);
|
|
1585
643
|
}
|
|
1586
644
|
}
|
|
1587
645
|
|
|
1588
|
-
/**
|
|
1589
|
-
* Default channel settings.
|
|
1590
|
-
* Accept any origin, queue messages, inherit contract from broker.
|
|
1591
|
-
*/
|
|
1592
646
|
const DEFAULT_CHANNEL_SETTINGS = freeze({
|
|
1593
647
|
origin: '*',
|
|
1594
648
|
queueMessages: true,
|
|
@@ -1596,23 +650,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1596
650
|
contract: undefined,
|
|
1597
651
|
});
|
|
1598
652
|
|
|
1599
|
-
/**
|
|
1600
|
-
* Gracefully closes an active channel connection.
|
|
1601
|
-
*
|
|
1602
|
-
* - Only works if channel is currently active
|
|
1603
|
-
* - Sets channel state to inactive
|
|
1604
|
-
* - Optionally notifies the target window
|
|
1605
|
-
* - Fires 'close' event to subscribers
|
|
1606
|
-
*
|
|
1607
|
-
* @param channel - Channel internals with state and dependencies
|
|
1608
|
-
* @param notify - Whether to notify target window (default: true)
|
|
1609
|
-
*
|
|
1610
|
-
* @example Gracefully closing a connection
|
|
1611
|
-
* ```typescript
|
|
1612
|
-
* disconnect(channel, true) // Close and notify target
|
|
1613
|
-
* disconnect(channel, false) // Close silently
|
|
1614
|
-
* ```
|
|
1615
|
-
*/
|
|
1616
653
|
function disconnect(channel, notify = true) {
|
|
1617
654
|
const state = channel.getState();
|
|
1618
655
|
if (!state.active) {
|
|
@@ -1627,22 +664,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1627
664
|
channel.notifyEvent('close');
|
|
1628
665
|
}
|
|
1629
666
|
|
|
1630
|
-
/**
|
|
1631
|
-
* Cancels a pending connection request.
|
|
1632
|
-
*
|
|
1633
|
-
* - If channel is closed, sends CANCEL_CONNECTION
|
|
1634
|
-
* - If channel is already open, calls disconnect instead
|
|
1635
|
-
* - Fires 'cancel' event to subscribers
|
|
1636
|
-
*
|
|
1637
|
-
* @param channel - Channel internals with state and dependencies
|
|
1638
|
-
* @param notify - Whether to notify target window (default: true)
|
|
1639
|
-
*
|
|
1640
|
-
* @example Canceling a pending connection
|
|
1641
|
-
* ```typescript
|
|
1642
|
-
* cancel(channel, true) // Cancel and notify target
|
|
1643
|
-
* cancel(channel, false) // Cancel silently
|
|
1644
|
-
* ```
|
|
1645
|
-
*/
|
|
1646
667
|
function cancel(channel, notify = true) {
|
|
1647
668
|
const state = channel.getState();
|
|
1648
669
|
if (state.active) {
|
|
@@ -1657,19 +678,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1657
678
|
channel.notifyEvent('cancel');
|
|
1658
679
|
}
|
|
1659
680
|
|
|
1660
|
-
/**
|
|
1661
|
-
* Clears all queued messages from the channel.
|
|
1662
|
-
* Returns a new state object with empty queue (immutable update).
|
|
1663
|
-
*
|
|
1664
|
-
* @param state - Current channel state
|
|
1665
|
-
* @returns New state with cleared message queue
|
|
1666
|
-
*
|
|
1667
|
-
* @example Clearing all queued messages
|
|
1668
|
-
* ```typescript
|
|
1669
|
-
* const clearedState = clearQueue(channelState)
|
|
1670
|
-
* // => { ...channelState, queuedMessages: [] }
|
|
1671
|
-
* ```
|
|
1672
|
-
*/
|
|
1673
681
|
function clearQueue(state) {
|
|
1674
682
|
return freeze({
|
|
1675
683
|
...state,
|
|
@@ -1677,21 +685,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1677
685
|
});
|
|
1678
686
|
}
|
|
1679
687
|
|
|
1680
|
-
/**
|
|
1681
|
-
* Adds a message to the channel's queue.
|
|
1682
|
-
* Returns a new state object with the message appended (immutable update).
|
|
1683
|
-
*
|
|
1684
|
-
* @param state - Current channel state
|
|
1685
|
-
* @param message - Message to queue
|
|
1686
|
-
* @returns New state with message added to queue
|
|
1687
|
-
*
|
|
1688
|
-
* @example Adding a message to the queue
|
|
1689
|
-
* ```typescript
|
|
1690
|
-
* const message = { type: 'data', payload: { userId: 123 } }
|
|
1691
|
-
* const updatedState = queueMessage(channelState, message)
|
|
1692
|
-
* // => { ...channelState, queuedMessages: [...existingMessages, message] }
|
|
1693
|
-
* ```
|
|
1694
|
-
*/
|
|
1695
688
|
function queueMessage(state, message) {
|
|
1696
689
|
return freeze({
|
|
1697
690
|
...state,
|
|
@@ -1699,33 +692,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1699
692
|
});
|
|
1700
693
|
}
|
|
1701
694
|
|
|
1702
|
-
/**
|
|
1703
|
-
* Queues a message for delivery when the channel opens.
|
|
1704
|
-
*
|
|
1705
|
-
* Messages are stored in the channel state and will be sent
|
|
1706
|
-
* automatically when the channel becomes active via the flush operation.
|
|
1707
|
-
*
|
|
1708
|
-
* @param channel - Channel internals with state and dependencies
|
|
1709
|
-
* @param message - Message to queue
|
|
1710
|
-
*
|
|
1711
|
-
* @example Queueing a message
|
|
1712
|
-
* ```typescript
|
|
1713
|
-
* queue(channel, { type: 'GREETING', data: 'Hello' })
|
|
1714
|
-
* ```
|
|
1715
|
-
*/
|
|
1716
695
|
function queue(channel, message) {
|
|
1717
696
|
const state = channel.getState();
|
|
1718
697
|
const newState = queueMessage(state, message);
|
|
1719
698
|
channel.updateState(newState);
|
|
1720
699
|
}
|
|
1721
700
|
|
|
1722
|
-
/**
|
|
1723
|
-
* Action types that should always be sent in plaintext.
|
|
1724
|
-
*
|
|
1725
|
-
* Handshake actions must remain unencrypted because:
|
|
1726
|
-
* - Security negotiation happens during handshake
|
|
1727
|
-
* - Both parties need to read handshake messages before security is established
|
|
1728
|
-
*/
|
|
1729
701
|
const PLAINTEXT_ACTION_TYPES = createSet([
|
|
1730
702
|
ACTION_TYPES.REQUEST_CONNECTION,
|
|
1731
703
|
ACTION_TYPES.ACCEPT_CONNECTION,
|
|
@@ -1734,26 +706,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1734
706
|
ACTION_TYPES.CANCEL_CONNECTION_ACKNOWLEDGED,
|
|
1735
707
|
ACTION_TYPES.OPEN_CONNECTION,
|
|
1736
708
|
]);
|
|
1737
|
-
/**
|
|
1738
|
-
* Sends a raw action to the channel's target window.
|
|
1739
|
-
*
|
|
1740
|
-
* This function routes actions through the security transport when:
|
|
1741
|
-
* - The channel has a security transport configured
|
|
1742
|
-
* - The security transport is ready
|
|
1743
|
-
* - The action type is not a handshake action (handshakes are always plaintext)
|
|
1744
|
-
*
|
|
1745
|
-
* For secure protocols (v1/v2), the action is encrypted and sent as Uint8Array.
|
|
1746
|
-
* For 'none' protocol or handshake actions, the action is sent as plain object.
|
|
1747
|
-
*
|
|
1748
|
-
* @param channel - Channel internals with state and dependencies
|
|
1749
|
-
* @param action - Action to send
|
|
1750
|
-
*
|
|
1751
|
-
* @example Sending an action to the target window
|
|
1752
|
-
* ```typescript
|
|
1753
|
-
* const action = channel.actions.requestConnection(processId)
|
|
1754
|
-
* sendAction(channel, action)
|
|
1755
|
-
* ```
|
|
1756
|
-
*/
|
|
1757
709
|
function sendAction(channel, action) {
|
|
1758
710
|
const state = channel.getState();
|
|
1759
711
|
if (!action || typeof action.type !== 'string') {
|
|
@@ -1768,29 +720,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1768
720
|
state.target.postMessage(action, '*');
|
|
1769
721
|
}
|
|
1770
722
|
|
|
1771
|
-
/**
|
|
1772
|
-
* Sends a typed message through an active channel.
|
|
1773
|
-
*
|
|
1774
|
-
* Message routing behavior:
|
|
1775
|
-
* - If channel is closed and queueMessages is enabled, queues the message
|
|
1776
|
-
* - If channel is closed and queueMessages is disabled, throws error
|
|
1777
|
-
* - If security transport exists but is not ready, queues the message
|
|
1778
|
-
* - If channel is open and security is ready (or protocol is 'none'), sends message
|
|
1779
|
-
*
|
|
1780
|
-
* For secure protocols (v1/v2), the message is routed through the security
|
|
1781
|
-
* transport which encrypts and sends as Uint8Array via postMessage.
|
|
1782
|
-
*
|
|
1783
|
-
* @param channel - Channel internals with state and dependencies
|
|
1784
|
-
* @param message - Message to send with type and data
|
|
1785
|
-
*
|
|
1786
|
-
* @throws {Error} If channel is closed and queueing is disabled
|
|
1787
|
-
* @throws {Error} If message type is not accepted in channel contract
|
|
1788
|
-
*
|
|
1789
|
-
* @example Sending a typed message
|
|
1790
|
-
* ```typescript
|
|
1791
|
-
* send(channel, { type: 'USER_ACTION', data: { userId: 123 } })
|
|
1792
|
-
* ```
|
|
1793
|
-
*/
|
|
1794
723
|
function send(channel, message) {
|
|
1795
724
|
const state = channel.getState();
|
|
1796
725
|
if (!state.active) {
|
|
@@ -1813,24 +742,11 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1813
742
|
if (!emittedTypes.includes(message.type)) {
|
|
1814
743
|
throw createError(`Cannot send message to ${state.name} channel. Message type '${message.type}' is not in the emitted actions of channel contract.`);
|
|
1815
744
|
}
|
|
1816
|
-
const action = channel.actions.newMessage(message
|
|
745
|
+
const action = channel.actions.newMessage(message);
|
|
1817
746
|
sendAction(channel, action);
|
|
1818
747
|
channel.notifyMessage(message);
|
|
1819
748
|
}
|
|
1820
749
|
|
|
1821
|
-
/**
|
|
1822
|
-
* Sends all queued messages and clears the queue.
|
|
1823
|
-
*
|
|
1824
|
-
* Called automatically when a channel opens if queueMessages is enabled.
|
|
1825
|
-
* Messages are sent in FIFO order.
|
|
1826
|
-
*
|
|
1827
|
-
* @param channel - Channel internals with state and dependencies
|
|
1828
|
-
*
|
|
1829
|
-
* @example Flushing queued messages
|
|
1830
|
-
* ```typescript
|
|
1831
|
-
* flush(channel) // Sends all queued messages
|
|
1832
|
-
* ```
|
|
1833
|
-
*/
|
|
1834
750
|
function flush(channel) {
|
|
1835
751
|
const state = channel.getState();
|
|
1836
752
|
for (const message of state.queuedMessages) {
|
|
@@ -1847,20 +763,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1847
763
|
channel.updateState(newState);
|
|
1848
764
|
}
|
|
1849
765
|
|
|
1850
|
-
/**
|
|
1851
|
-
* Initiates the connection handshake for a channel.
|
|
1852
|
-
*
|
|
1853
|
-
* - If channel is already open, does nothing
|
|
1854
|
-
* - If channel has a scheduled activation (pending connection), accepts it
|
|
1855
|
-
* - Otherwise, sends REQUEST_CONNECTION to initiate handshake
|
|
1856
|
-
*
|
|
1857
|
-
* @param channel - Channel internals with state and dependencies
|
|
1858
|
-
*
|
|
1859
|
-
* @example Initiating a connection
|
|
1860
|
-
* ```typescript
|
|
1861
|
-
* connect(channel) // Sends REQUEST_CONNECTION or accepts pending
|
|
1862
|
-
* ```
|
|
1863
|
-
*/
|
|
1864
766
|
function connect(channel) {
|
|
1865
767
|
const state = channel.getState();
|
|
1866
768
|
if (state.active) {
|
|
@@ -1902,24 +804,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1902
804
|
channel.sendAction(requestAction);
|
|
1903
805
|
}
|
|
1904
806
|
|
|
1905
|
-
/**
|
|
1906
|
-
* Immediately destroys a channel and removes it from the broker.
|
|
1907
|
-
*
|
|
1908
|
-
* - Sets channel to inactive immediately
|
|
1909
|
-
* - Optionally notifies the target window
|
|
1910
|
-
* - Removes channel from all registries
|
|
1911
|
-
* - Fires 'destroy' event to subscribers
|
|
1912
|
-
* - This is irreversible - channel cannot be reconnected
|
|
1913
|
-
*
|
|
1914
|
-
* @param channel - Channel internals with state and dependencies
|
|
1915
|
-
* @param notify - Whether to notify target window (default: true)
|
|
1916
|
-
*
|
|
1917
|
-
* @example Destroying a channel
|
|
1918
|
-
* ```typescript
|
|
1919
|
-
* destroy(channel, true) // Destroy and notify target
|
|
1920
|
-
* destroy(channel, false) // Destroy silently
|
|
1921
|
-
* ```
|
|
1922
|
-
*/
|
|
1923
807
|
function destroy(channel, notify = true) {
|
|
1924
808
|
channel.updateState({ active: false });
|
|
1925
809
|
if (notify) {
|
|
@@ -1931,22 +815,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1931
815
|
}
|
|
1932
816
|
}
|
|
1933
817
|
|
|
1934
|
-
/**
|
|
1935
|
-
* Activates a channel by setting it as active and recording connection details.
|
|
1936
|
-
* Returns a new state object (immutable update).
|
|
1937
|
-
*
|
|
1938
|
-
* @param state - Current channel state
|
|
1939
|
-
* @param origin - Origin of the connected channel
|
|
1940
|
-
* @param contract - Negotiated channel contract
|
|
1941
|
-
* @returns New state with channel activated
|
|
1942
|
-
*
|
|
1943
|
-
* @example Activating a channel with contract
|
|
1944
|
-
* ```typescript
|
|
1945
|
-
* const contract = { accepted: [{ type: 'message' }] }
|
|
1946
|
-
* const activeState = activate(channelState, 'https://example.com', contract)
|
|
1947
|
-
* // => { ...channelState, active: true, origin: 'https://example.com', ... }
|
|
1948
|
-
* ```
|
|
1949
|
-
*/
|
|
1950
818
|
function activate(state, origin, contract) {
|
|
1951
819
|
const acceptedActions = (contract.accepted || []).map((action) => action.type);
|
|
1952
820
|
return freeze({
|
|
@@ -1960,21 +828,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
1960
828
|
});
|
|
1961
829
|
}
|
|
1962
830
|
|
|
1963
|
-
/**
|
|
1964
|
-
* Creates the initial state for a new channel.
|
|
1965
|
-
* All collections are empty, all optional fields are null.
|
|
1966
|
-
*
|
|
1967
|
-
* @param name - Channel name/identifier
|
|
1968
|
-
* @param target - Target window for communication
|
|
1969
|
-
* @param settings - Channel settings (queueMessages, debug, logger, etc.)
|
|
1970
|
-
* @returns Fresh channel state object
|
|
1971
|
-
*
|
|
1972
|
-
* @example Creating initial channel state
|
|
1973
|
-
* ```typescript
|
|
1974
|
-
* const state = createInitialState('my-channel', targetWindow, { queueMessages: true })
|
|
1975
|
-
* // => { id: '...', name: 'my-channel', active: false, queuedMessages: [], ... }
|
|
1976
|
-
* ```
|
|
1977
|
-
*/
|
|
1978
831
|
function createInitialState(name, target, settings) {
|
|
1979
832
|
return freeze({
|
|
1980
833
|
id: uuidV4(),
|
|
@@ -2000,26 +853,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2000
853
|
});
|
|
2001
854
|
}
|
|
2002
855
|
|
|
2003
|
-
/**
|
|
2004
|
-
* Implementation of subscribeToEvents that handles both overload signatures.
|
|
2005
|
-
*
|
|
2006
|
-
* @param channel - The channel internals object
|
|
2007
|
-
* @param eventOrHandler - Either an event name or a handler function
|
|
2008
|
-
* @param handler - Handler function when event name is provided
|
|
2009
|
-
* @returns Unsubscribe function to remove the handler
|
|
2010
|
-
*
|
|
2011
|
-
* @example Subscribing to all events with cleanup
|
|
2012
|
-
* ```typescript
|
|
2013
|
-
* const unsubscribe = subscribeToEvents(channel, (event, data) => {
|
|
2014
|
-
* if (event === 'open') {
|
|
2015
|
-
* console.log('Channel opened:', data)
|
|
2016
|
-
* }
|
|
2017
|
-
* })
|
|
2018
|
-
*
|
|
2019
|
-
* // Cleanup when no longer needed
|
|
2020
|
-
* unsubscribe()
|
|
2021
|
-
* ```
|
|
2022
|
-
*/
|
|
2023
856
|
function subscribeToEvents(channel, eventOrHandler, handler) {
|
|
2024
857
|
const isEventSpecific = typeof eventOrHandler === 'string' && typeof handler === 'function';
|
|
2025
858
|
let wrappedHandler;
|
|
@@ -2051,26 +884,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2051
884
|
};
|
|
2052
885
|
}
|
|
2053
886
|
|
|
2054
|
-
/**
|
|
2055
|
-
* Subscribes to incoming messages on the channel.
|
|
2056
|
-
*
|
|
2057
|
-
* Handler will be called with each message received from the target window.
|
|
2058
|
-
*
|
|
2059
|
-
* @param channel - Channel internals with state and dependencies
|
|
2060
|
-
* @param handler - Message handler function
|
|
2061
|
-
* @returns Unsubscribe function to remove the handler
|
|
2062
|
-
*
|
|
2063
|
-
* @throws {Error} If handler is not a function
|
|
2064
|
-
*
|
|
2065
|
-
* @example Subscribing to channel messages
|
|
2066
|
-
* ```typescript
|
|
2067
|
-
* const unsubscribe = subscribeToMessages(channel, (message) => {
|
|
2068
|
-
* console.log('Message:', message.type, message.data)
|
|
2069
|
-
* })
|
|
2070
|
-
*
|
|
2071
|
-
* // Later: unsubscribe()
|
|
2072
|
-
* ```
|
|
2073
|
-
*/
|
|
2074
887
|
function subscribeToMessages(channel, handler) {
|
|
2075
888
|
if (typeof handler !== 'function') {
|
|
2076
889
|
throw createError('Expected callback function.');
|
|
@@ -2085,32 +898,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2085
898
|
};
|
|
2086
899
|
}
|
|
2087
900
|
|
|
2088
|
-
/**
|
|
2089
|
-
* Logs a channel event in a structured format.
|
|
2090
|
-
*
|
|
2091
|
-
* @param logger - Logger instance to use
|
|
2092
|
-
* @param event - Type of channel event that occurred
|
|
2093
|
-
* @param data - Additional data associated with the event
|
|
2094
|
-
*/
|
|
2095
901
|
function logEvent(logger, event, data) {
|
|
2096
902
|
logger.debug(`Channel event:`, event, data);
|
|
2097
903
|
}
|
|
2098
904
|
|
|
2099
|
-
/**
|
|
2100
|
-
* Notifies all event subscribers of a channel event.
|
|
2101
|
-
*
|
|
2102
|
-
* Calls each subscribed event handler with the event type, optional data, and channel JSON.
|
|
2103
|
-
* Errors in handlers are caught and logged to prevent breaking other handlers.
|
|
2104
|
-
*
|
|
2105
|
-
* @param channel - Channel internals with state and dependencies
|
|
2106
|
-
* @param event - Event type that occurred
|
|
2107
|
-
* @param data - Optional event data
|
|
2108
|
-
*
|
|
2109
|
-
* @example Notifying subscribers of an event
|
|
2110
|
-
* ```typescript
|
|
2111
|
-
* notifyEvent(channel, 'open', { timestamp: Date.now() })
|
|
2112
|
-
* ```
|
|
2113
|
-
*/
|
|
2114
905
|
function notifyEvent(channel, event, data) {
|
|
2115
906
|
const state = channel.getState();
|
|
2116
907
|
if (state.logger) {
|
|
@@ -2137,20 +928,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2137
928
|
}
|
|
2138
929
|
}
|
|
2139
930
|
|
|
2140
|
-
/**
|
|
2141
|
-
* Notifies all message subscribers of an incoming message.
|
|
2142
|
-
*
|
|
2143
|
-
* Calls each subscribed message handler with the message data.
|
|
2144
|
-
* Errors in handlers are caught and logged to prevent breaking other handlers.
|
|
2145
|
-
*
|
|
2146
|
-
* @param channel - Channel internals with state and dependencies
|
|
2147
|
-
* @param message - Message that was received
|
|
2148
|
-
*
|
|
2149
|
-
* @example Notifying subscribers of a message
|
|
2150
|
-
* ```typescript
|
|
2151
|
-
* notifyMessage(channel, { type: 'USER_ACTION', data: { userId: 123 } })
|
|
2152
|
-
* ```
|
|
2153
|
-
*/
|
|
2154
931
|
function notifyMessage(channel, message) {
|
|
2155
932
|
const state = channel.getState();
|
|
2156
933
|
for (const handler of state.messageSubscriptions) {
|
|
@@ -2165,26 +942,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2165
942
|
}
|
|
2166
943
|
}
|
|
2167
944
|
|
|
2168
|
-
/**
|
|
2169
|
-
* Creates a new message channel.
|
|
2170
|
-
*
|
|
2171
|
-
* Uses functional programming with closures for encapsulation.
|
|
2172
|
-
* Returns a public handle with methods while keeping state private.
|
|
2173
|
-
*
|
|
2174
|
-
* @param config - Channel configuration (name, target, settings)
|
|
2175
|
-
* @param deps - Dependencies (action creators, process manager, cleanup)
|
|
2176
|
-
* @returns Channel handle with public API
|
|
2177
|
-
*
|
|
2178
|
-
* @example Creating and using a channel
|
|
2179
|
-
* ```typescript
|
|
2180
|
-
* const channel = createChannel(
|
|
2181
|
-
* { name: 'my-channel', target: childWindow },
|
|
2182
|
-
* { actions, processManager, cleanup }
|
|
2183
|
-
* )
|
|
2184
|
-
* channel.connect()
|
|
2185
|
-
* channel.send('greet', { message: 'Hello!' })
|
|
2186
|
-
* ```
|
|
2187
|
-
*/
|
|
2188
945
|
function createChannel(config, deps) {
|
|
2189
946
|
assertNoCircularRef(config.settings, 'config.settings');
|
|
2190
947
|
const settings = { ...DEFAULT_CHANNEL_SETTINGS, ...config.settings };
|
|
@@ -2220,6 +977,7 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2220
977
|
getName: () => state.name,
|
|
2221
978
|
getTarget: () => state.target,
|
|
2222
979
|
isActive: () => state.active,
|
|
980
|
+
getAcceptedTypes: () => state.acceptedActions,
|
|
2223
981
|
toJSON: () => ({
|
|
2224
982
|
id: state.id,
|
|
2225
983
|
name: state.name,
|
|
@@ -2288,72 +1046,18 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2288
1046
|
return freeze(handle);
|
|
2289
1047
|
}
|
|
2290
1048
|
|
|
2291
|
-
/**
|
|
2292
|
-
* Adds a channel to the registry, making it available for lookup
|
|
2293
|
-
* by window, ID, and name.
|
|
2294
|
-
*
|
|
2295
|
-
* @param registry - The channel registry instance
|
|
2296
|
-
* @param channel - Channel to register (must have id, name, target)
|
|
2297
|
-
* @throws {Error} Error if channel is invalid
|
|
2298
|
-
*
|
|
2299
|
-
* @example Registering a channel
|
|
2300
|
-
* ```typescript
|
|
2301
|
-
* const registry = createRegistry()
|
|
2302
|
-
* add(registry, { id: 'ch-1', name: 'main', target: iframe.contentWindow })
|
|
2303
|
-
* ```
|
|
2304
|
-
*/
|
|
2305
1049
|
function add(registry, channel) {
|
|
2306
1050
|
registry.add(channel);
|
|
2307
1051
|
}
|
|
2308
1052
|
|
|
2309
|
-
/**
|
|
2310
|
-
* Finds a channel by its target window.
|
|
2311
|
-
* Uses WeakMap for O(1) lookup that doesn't prevent garbage collection.
|
|
2312
|
-
*
|
|
2313
|
-
* @param registry - The channel registry instance
|
|
2314
|
-
* @param target - The window to look up
|
|
2315
|
-
* @returns Channel if found, undefined otherwise
|
|
2316
|
-
*/
|
|
2317
1053
|
function getByWindow(registry, target) {
|
|
2318
1054
|
return registry.getByWindow(target);
|
|
2319
1055
|
}
|
|
2320
1056
|
|
|
2321
|
-
/**
|
|
2322
|
-
* Removes a channel from the registry, making it unavailable
|
|
2323
|
-
* for all lookup methods.
|
|
2324
|
-
*
|
|
2325
|
-
* @param registry - The channel registry instance
|
|
2326
|
-
* @param channel - Channel to unregister
|
|
2327
|
-
*/
|
|
2328
1057
|
function remove(registry, channel) {
|
|
2329
1058
|
registry.remove(channel);
|
|
2330
1059
|
}
|
|
2331
1060
|
|
|
2332
|
-
/**
|
|
2333
|
-
* Adds a channel to the broker.
|
|
2334
|
-
*
|
|
2335
|
-
* @param state - Current broker state
|
|
2336
|
-
* @param registry - Channel registry for storing and retrieving channels
|
|
2337
|
-
* @param processManager - Process ID manager for tracking communication processes
|
|
2338
|
-
* @param actions - Action creators from broker for managing channel lifecycle
|
|
2339
|
-
* @param name - Unique identifier for the channel
|
|
2340
|
-
* @param target - Target window to communicate with
|
|
2341
|
-
* @param settings - Optional configuration settings for the channel
|
|
2342
|
-
* @returns The created or existing channel
|
|
2343
|
-
*
|
|
2344
|
-
* @example Registering a channel with the broker
|
|
2345
|
-
* ```typescript
|
|
2346
|
-
* const channel = addChannel(
|
|
2347
|
-
* brokerState,
|
|
2348
|
-
* registry,
|
|
2349
|
-
* processManager,
|
|
2350
|
-
* actions,
|
|
2351
|
-
* 'widget-channel',
|
|
2352
|
-
* iframe.contentWindow,
|
|
2353
|
-
* { timeout: 5000 }
|
|
2354
|
-
* )
|
|
2355
|
-
* ```
|
|
2356
|
-
*/
|
|
2357
1061
|
function addChannel(state, registry, processManager, actions, name, target, settings = {}) {
|
|
2358
1062
|
assertNoCircularRef(settings, 'settings');
|
|
2359
1063
|
const existing = getByWindow(registry, target);
|
|
@@ -2380,43 +1084,14 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2380
1084
|
return channel;
|
|
2381
1085
|
}
|
|
2382
1086
|
|
|
2383
|
-
/**
|
|
2384
|
-
* Finds a channel by its unique ID.
|
|
2385
|
-
* Uses Map for O(1) lookup.
|
|
2386
|
-
*
|
|
2387
|
-
* @param registry - The channel registry instance
|
|
2388
|
-
* @param id - The channel ID (UUID) to look up
|
|
2389
|
-
* @returns Channel if found, undefined otherwise
|
|
2390
|
-
*/
|
|
2391
1087
|
function getById(registry, id) {
|
|
2392
1088
|
return registry.getById(id);
|
|
2393
1089
|
}
|
|
2394
1090
|
|
|
2395
|
-
/**
|
|
2396
|
-
* Finds a channel by its name.
|
|
2397
|
-
* Uses Map for O(1) lookup.
|
|
2398
|
-
*
|
|
2399
|
-
* @param registry - The channel registry instance
|
|
2400
|
-
* @param name - The channel name to look up
|
|
2401
|
-
* @returns Channel if found, undefined otherwise
|
|
2402
|
-
*/
|
|
2403
1091
|
function getByName(registry, name) {
|
|
2404
1092
|
return registry.getByName(name);
|
|
2405
1093
|
}
|
|
2406
1094
|
|
|
2407
|
-
/**
|
|
2408
|
-
* Gets a channel by reference (id, name, or window)
|
|
2409
|
-
*
|
|
2410
|
-
* @param registry - Channel registry containing all registered channels
|
|
2411
|
-
* @param reference - Channel identifier (id, name, or window object)
|
|
2412
|
-
* @returns The channel if found, null otherwise
|
|
2413
|
-
*
|
|
2414
|
-
* @example Retrieving channels by name or window
|
|
2415
|
-
* ```typescript
|
|
2416
|
-
* const channelByName = getChannel(registry, 'widget-channel')
|
|
2417
|
-
* const channelByWindow = getChannel(registry, iframe.contentWindow)
|
|
2418
|
-
* ```
|
|
2419
|
-
*/
|
|
2420
1095
|
function getChannel(registry, reference) {
|
|
2421
1096
|
if (typeof reference === 'object' && reference !== null) {
|
|
2422
1097
|
const channel = getByWindow(registry, reference);
|
|
@@ -2429,64 +1104,20 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2429
1104
|
return null;
|
|
2430
1105
|
}
|
|
2431
1106
|
|
|
2432
|
-
/**
|
|
2433
|
-
* Returns all registered channels as an array.
|
|
2434
|
-
* The order is not guaranteed.
|
|
2435
|
-
*
|
|
2436
|
-
* @param registry - The channel registry instance
|
|
2437
|
-
* @returns Array of all registered channels
|
|
2438
|
-
*
|
|
2439
|
-
* @example Listing registered channels
|
|
2440
|
-
* ```typescript
|
|
2441
|
-
* const registry = createRegistry()
|
|
2442
|
-
* const channels = getAll(registry)
|
|
2443
|
-
* channels.forEach(ch => console.log(ch.name))
|
|
2444
|
-
* ```
|
|
2445
|
-
*/
|
|
2446
1107
|
function getAll(registry) {
|
|
2447
1108
|
return registry.getAll();
|
|
2448
1109
|
}
|
|
2449
1110
|
|
|
2450
|
-
/**
|
|
2451
|
-
* Lists all channels in JSON format
|
|
2452
|
-
*
|
|
2453
|
-
* @param registry - Channel registry containing all registered channels
|
|
2454
|
-
* @returns Array of channel JSON representations
|
|
2455
|
-
*
|
|
2456
|
-
* @example Listing all channels as JSON
|
|
2457
|
-
* ```typescript
|
|
2458
|
-
* const channels = listChannels(registry)
|
|
2459
|
-
* // => [{ id: 'abc-123', name: 'widget', state: 'connected' }, ...]
|
|
2460
|
-
* ```
|
|
2461
|
-
*/
|
|
2462
1111
|
function listChannels(registry) {
|
|
2463
1112
|
const channels = getAll(registry);
|
|
2464
1113
|
return channels.map((channel) => channel.toJSON());
|
|
2465
1114
|
}
|
|
2466
1115
|
|
|
2467
|
-
/**
|
|
2468
|
-
* Removes a channel from the broker
|
|
2469
|
-
*
|
|
2470
|
-
* @param registry - Channel registry from which to remove the channel
|
|
2471
|
-
* @param channel - The channel instance to cleanup and remove
|
|
2472
|
-
*
|
|
2473
|
-
* @example Removing a channel from the broker
|
|
2474
|
-
* ```typescript
|
|
2475
|
-
* const channel = getChannel(registry, 'widget-channel')
|
|
2476
|
-
* if (channel) {
|
|
2477
|
-
* removeChannel(registry, channel)
|
|
2478
|
-
* }
|
|
2479
|
-
* ```
|
|
2480
|
-
*/
|
|
2481
1116
|
function removeChannel(registry, channel) {
|
|
2482
1117
|
channel.destroy(false);
|
|
2483
1118
|
remove(registry, channel);
|
|
2484
1119
|
}
|
|
2485
1120
|
|
|
2486
|
-
/**
|
|
2487
|
-
* Default broker settings
|
|
2488
|
-
* Used when settings are partially provided
|
|
2489
|
-
*/
|
|
2490
1121
|
const defaultBrokerSettings = freeze({
|
|
2491
1122
|
whitelist: freeze([]),
|
|
2492
1123
|
blacklist: freeze([]),
|
|
@@ -2494,21 +1125,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2494
1125
|
logLevel: 'error',
|
|
2495
1126
|
});
|
|
2496
1127
|
|
|
2497
|
-
/**
|
|
2498
|
-
* Creates a router map for action types to handlers.
|
|
2499
|
-
*
|
|
2500
|
-
* @param handlers - Map of action types to handler functions
|
|
2501
|
-
* @returns Router map
|
|
2502
|
-
*
|
|
2503
|
-
* @example Creating a router for action handlers
|
|
2504
|
-
* ```typescript
|
|
2505
|
-
* const router = createRouter({
|
|
2506
|
-
* 'OPEN': handleOpen,
|
|
2507
|
-
* 'CLOSE': handleClose,
|
|
2508
|
-
* 'MESSAGE': handleMessage,
|
|
2509
|
-
* })
|
|
2510
|
-
* ```
|
|
2511
|
-
*/
|
|
2512
1128
|
function createRouter(handlers) {
|
|
2513
1129
|
const router = createMap();
|
|
2514
1130
|
entries(handlers).forEach(([type, handler]) => {
|
|
@@ -2517,21 +1133,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2517
1133
|
return router;
|
|
2518
1134
|
}
|
|
2519
1135
|
|
|
2520
|
-
/**
|
|
2521
|
-
* Applies a security policy to a connection request.
|
|
2522
|
-
*
|
|
2523
|
-
* @param policy - The security policy function
|
|
2524
|
-
* @param event - The MessageEvent to validate
|
|
2525
|
-
* @param logger - Logger instance for error reporting
|
|
2526
|
-
* @returns true if policy allows connection, false otherwise
|
|
2527
|
-
*
|
|
2528
|
-
* @example Validating connection requests with security policy
|
|
2529
|
-
* ```typescript
|
|
2530
|
-
* const policy = (event) => event.origin === 'https://trusted.example.com'
|
|
2531
|
-
* const allowed = applyPolicy(policy, messageEvent, logger)
|
|
2532
|
-
* // => true or false
|
|
2533
|
-
* ```
|
|
2534
|
-
*/
|
|
2535
1136
|
function applyPolicy(policy, event, logger) {
|
|
2536
1137
|
try {
|
|
2537
1138
|
const result = policy(event);
|
|
@@ -2543,27 +1144,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2543
1144
|
}
|
|
2544
1145
|
}
|
|
2545
1146
|
|
|
2546
|
-
/**
|
|
2547
|
-
* Handles ACCEPT_CONNECTION action.
|
|
2548
|
-
* Completes connection handshake from the initiator's side.
|
|
2549
|
-
*
|
|
2550
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2551
|
-
* @param message - Message event containing the ACCEPT_CONNECTION action
|
|
2552
|
-
*
|
|
2553
|
-
* @remarks
|
|
2554
|
-
* Side Effects:
|
|
2555
|
-
* - Activates the channel
|
|
2556
|
-
* - Extracts negotiated security protocol (if present)
|
|
2557
|
-
* - Stores negotiated protocol in channel state
|
|
2558
|
-
* - Sends OPEN_CONNECTION to complete handshake (with security confirmation)
|
|
2559
|
-
* - Terminates process after activation
|
|
2560
|
-
* - Fires 'open' lifecycle event
|
|
2561
|
-
*
|
|
2562
|
-
* @example Three-way handshake acceptance
|
|
2563
|
-
* Second step of three-way handshake:
|
|
2564
|
-
* Initiator <- ACCEPT (this handler) <- Responder
|
|
2565
|
-
* Initiator -> OPEN -> Responder
|
|
2566
|
-
*/
|
|
2567
1147
|
function handleAccept(context, message) {
|
|
2568
1148
|
const { state, processManager, logger } = context;
|
|
2569
1149
|
const action = message.data;
|
|
@@ -2626,33 +1206,22 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2626
1206
|
channel.notifyEvent('open', { origin: message.origin, contract });
|
|
2627
1207
|
}
|
|
2628
1208
|
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
* - Terminates process
|
|
2641
|
-
* - Fires 'cancel' lifecycle event
|
|
2642
|
-
*
|
|
2643
|
-
* @example Cancellation flow during connection
|
|
2644
|
-
* Cancel flow (before connection completes):
|
|
2645
|
-
* Side A -> CANCEL_CONNECTION
|
|
2646
|
-
* Side B <- CANCEL (this handler)
|
|
2647
|
-
* Side B -> CANCEL_ACKNOWLEDGED
|
|
2648
|
-
* Both sides fire 'cancel' event
|
|
2649
|
-
*/
|
|
1209
|
+
function resolveChannel(registry, message) {
|
|
1210
|
+
const source = message.source;
|
|
1211
|
+
if (source) {
|
|
1212
|
+
const channel = registry.getByWindow(source);
|
|
1213
|
+
if (channel) {
|
|
1214
|
+
return channel;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return registry.getById(message.data.senderId);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
2650
1220
|
function handleCancel(context, message) {
|
|
2651
1221
|
const { state, registry, processManager } = context;
|
|
2652
1222
|
const action = message.data;
|
|
2653
|
-
const senderId = action['senderId'];
|
|
2654
1223
|
const processId = action['processId'];
|
|
2655
|
-
const channel = (
|
|
1224
|
+
const channel = (resolveChannel(registry, message) || processManager.get(processId));
|
|
2656
1225
|
if (!channel) {
|
|
2657
1226
|
return;
|
|
2658
1227
|
}
|
|
@@ -2666,24 +1235,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2666
1235
|
channel.notifyEvent('cancel', { notify: true });
|
|
2667
1236
|
}
|
|
2668
1237
|
|
|
2669
|
-
/**
|
|
2670
|
-
* Handles CANCEL_CONNECTION_ACKNOWLEDGED action.
|
|
2671
|
-
* Completes cancellation on initiator's side and notifies cancel event.
|
|
2672
|
-
*
|
|
2673
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2674
|
-
* @param message - Message event containing the CANCEL_CONNECTION_ACKNOWLEDGED action
|
|
2675
|
-
*
|
|
2676
|
-
* @remarks
|
|
2677
|
-
* Side Effects:
|
|
2678
|
-
* - Terminates the connection process
|
|
2679
|
-
* - Fires 'cancel' lifecycle event on initiator's side
|
|
2680
|
-
*
|
|
2681
|
-
* @example Initiator-side cancellation acknowledgment
|
|
2682
|
-
* Cancellation acknowledgment (initiator side):
|
|
2683
|
-
* Initiator -> CANCEL_CONNECTION
|
|
2684
|
-
* Initiator <- CANCEL_ACKNOWLEDGED (this handler)
|
|
2685
|
-
* Initiator fires 'cancel' event
|
|
2686
|
-
*/
|
|
2687
1238
|
function handleCancelAcknowledged(context, message) {
|
|
2688
1239
|
const { processManager } = context;
|
|
2689
1240
|
const action = message.data;
|
|
@@ -2696,36 +1247,14 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2696
1247
|
channel.notifyEvent('cancel', { notify: false });
|
|
2697
1248
|
}
|
|
2698
1249
|
|
|
2699
|
-
/**
|
|
2700
|
-
* Handles CLOSE_CONNECTION action.
|
|
2701
|
-
* Gracefully closes an open connection.
|
|
2702
|
-
*
|
|
2703
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2704
|
-
* @param message - Message event containing the CLOSE_CONNECTION action
|
|
2705
|
-
*
|
|
2706
|
-
* @remarks
|
|
2707
|
-
* Side Effects:
|
|
2708
|
-
* - Deactivates the channel
|
|
2709
|
-
* - Sends CLOSE_CONNECTION_ACKNOWLEDGED response
|
|
2710
|
-
* - Terminates process
|
|
2711
|
-
* - Fires 'close' lifecycle event
|
|
2712
|
-
*
|
|
2713
|
-
* @example Graceful disconnect flow
|
|
2714
|
-
* Disconnect flow:
|
|
2715
|
-
* Side A -> CLOSE_CONNECTION (initiates)
|
|
2716
|
-
* Side B <- CLOSE_CONNECTION (this handler)
|
|
2717
|
-
* Side B -> CLOSE_ACKNOWLEDGED
|
|
2718
|
-
* Both sides fire 'close' event
|
|
2719
|
-
*/
|
|
2720
1250
|
function handleClose(context, message) {
|
|
2721
1251
|
const { state, registry, processManager } = context;
|
|
2722
1252
|
const action = message.data;
|
|
2723
|
-
const senderId = action.senderId;
|
|
2724
1253
|
if (!('processId' in action)) {
|
|
2725
1254
|
return;
|
|
2726
1255
|
}
|
|
2727
1256
|
const processId = action.processId;
|
|
2728
|
-
const channel =
|
|
1257
|
+
const channel = resolveChannel(registry, message);
|
|
2729
1258
|
if (!channel || !channel.isActive()) {
|
|
2730
1259
|
return;
|
|
2731
1260
|
}
|
|
@@ -2739,18 +1268,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2739
1268
|
channel.notifyEvent('close', { notify: true });
|
|
2740
1269
|
}
|
|
2741
1270
|
|
|
2742
|
-
/**
|
|
2743
|
-
* Handles CLOSE_CONNECTION_ACKNOWLEDGED action.
|
|
2744
|
-
* Completes close on initiator's side and notifies close event.
|
|
2745
|
-
*
|
|
2746
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2747
|
-
* @param message - Message event containing the CLOSE_CONNECTION_ACKNOWLEDGED action
|
|
2748
|
-
*
|
|
2749
|
-
* @example Handling close acknowledgment
|
|
2750
|
-
* ```typescript
|
|
2751
|
-
* handleCloseAcknowledged(routingContext, closeAcknowledgedEvent)
|
|
2752
|
-
* ```
|
|
2753
|
-
*/
|
|
2754
1271
|
function handleCloseAcknowledged(context, message) {
|
|
2755
1272
|
const { processManager } = context;
|
|
2756
1273
|
const action = message.data;
|
|
@@ -2763,25 +1280,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2763
1280
|
channel.notifyEvent('close', { notify: false });
|
|
2764
1281
|
}
|
|
2765
1282
|
|
|
2766
|
-
/**
|
|
2767
|
-
* Handles DENY_CONNECTION action.
|
|
2768
|
-
* Processes connection denial from remote broker.
|
|
2769
|
-
*
|
|
2770
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2771
|
-
* @param message - Message event containing the DENY_CONNECTION action
|
|
2772
|
-
*
|
|
2773
|
-
* @remarks
|
|
2774
|
-
* Side Effects:
|
|
2775
|
-
* - Terminates the connection process
|
|
2776
|
-
* - Fires 'deny' lifecycle event with error details
|
|
2777
|
-
*
|
|
2778
|
-
* @example Connection denial during handshake
|
|
2779
|
-
* Denial flow (during handshake):
|
|
2780
|
-
* Initiator -> REQUEST_CONNECTION
|
|
2781
|
-
* Responder validates and rejects
|
|
2782
|
-
* Initiator <- DENY_CONNECTION (this handler)
|
|
2783
|
-
* Initiator fires 'deny' event
|
|
2784
|
-
*/
|
|
2785
1283
|
function handleDeny(context, message) {
|
|
2786
1284
|
const { processManager } = context;
|
|
2787
1285
|
const action = message.data;
|
|
@@ -2795,55 +1293,15 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2795
1293
|
channel.notifyEvent('deny', { error, origin: message.origin });
|
|
2796
1294
|
}
|
|
2797
1295
|
|
|
2798
|
-
/**
|
|
2799
|
-
* Handles DESTROY_CONNECTION action.
|
|
2800
|
-
* Immediately destroys a connection without handshake.
|
|
2801
|
-
*
|
|
2802
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2803
|
-
* @param message - Message event containing the DESTROY_CONNECTION action
|
|
2804
|
-
*
|
|
2805
|
-
* @remarks
|
|
2806
|
-
* Side Effects:
|
|
2807
|
-
* - Immediately destroys channel (no acknowledgment)
|
|
2808
|
-
* - Removes channel from registry
|
|
2809
|
-
* - No lifecycle event fired (forceful termination)
|
|
2810
|
-
*
|
|
2811
|
-
* @example Forceful connection termination
|
|
2812
|
-
* Forceful termination (e.g., window unload):
|
|
2813
|
-
* channel.destroy()
|
|
2814
|
-
* -> DESTROY_CONNECTION sent
|
|
2815
|
-
* -> Remote receives (this handler)
|
|
2816
|
-
* -> Channel immediately removed
|
|
2817
|
-
*/
|
|
2818
1296
|
function handleDestroy(context, message) {
|
|
2819
1297
|
const { registry } = context;
|
|
2820
|
-
const
|
|
2821
|
-
const senderId = action.senderId;
|
|
2822
|
-
const channel = getById(registry, senderId);
|
|
1298
|
+
const channel = resolveChannel(registry, message);
|
|
2823
1299
|
if (!channel) {
|
|
2824
1300
|
return;
|
|
2825
1301
|
}
|
|
2826
1302
|
channel.destroy(false);
|
|
2827
1303
|
}
|
|
2828
1304
|
|
|
2829
|
-
/**
|
|
2830
|
-
* Handles INVALID_REQUEST action.
|
|
2831
|
-
* Processes error responses from remote broker.
|
|
2832
|
-
*
|
|
2833
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
2834
|
-
* @param message - Message event containing the INVALID_REQUEST action
|
|
2835
|
-
*
|
|
2836
|
-
* @remarks
|
|
2837
|
-
* Side Effects:
|
|
2838
|
-
* - Fires 'invalid' lifecycle event with error details
|
|
2839
|
-
*
|
|
2840
|
-
* @example Handling protocol violations
|
|
2841
|
-
* Protocol violation detected:
|
|
2842
|
-
* Initiator sends malformed action
|
|
2843
|
-
* Responder detects violation
|
|
2844
|
-
* Initiator <- INVALID_REQUEST (this handler)
|
|
2845
|
-
* Initiator fires 'invalid' event with reason
|
|
2846
|
-
*/
|
|
2847
1305
|
function handleInvalid(context, message) {
|
|
2848
1306
|
const { processManager } = context;
|
|
2849
1307
|
const action = message.data;
|
|
@@ -2887,67 +1345,18 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2887
1345
|
additionalProperties: additionalProperties
|
|
2888
1346
|
};
|
|
2889
1347
|
|
|
2890
|
-
/**
|
|
2891
|
-
* Safe copies of JSON built-in methods.
|
|
2892
|
-
*
|
|
2893
|
-
* These references are captured at module initialization time to protect against
|
|
2894
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
2895
|
-
*
|
|
2896
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/json
|
|
2897
|
-
*/
|
|
2898
1348
|
const _JSON = globalThis.JSON;
|
|
2899
|
-
/**
|
|
2900
|
-
* (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
|
|
2901
|
-
*/
|
|
2902
1349
|
const stringify = _JSON.stringify;
|
|
2903
1350
|
|
|
2904
|
-
/**
|
|
2905
|
-
* Safe copies of Number built-in methods and constants.
|
|
2906
|
-
*
|
|
2907
|
-
* These references are captured at module initialization time to protect against
|
|
2908
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
2909
|
-
*
|
|
2910
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/number
|
|
2911
|
-
*/
|
|
2912
1351
|
const _Number = globalThis.Number;
|
|
2913
1352
|
const _parseInt = globalThis.parseInt;
|
|
2914
1353
|
const _isNaN = globalThis.isNaN;
|
|
2915
1354
|
const _isFinite = globalThis.isFinite;
|
|
2916
|
-
/**
|
|
2917
|
-
* (Safe copy) Determines whether the passed value is an integer.
|
|
2918
|
-
*/
|
|
2919
1355
|
const isInteger = _Number.isInteger;
|
|
2920
|
-
/**
|
|
2921
|
-
* (Safe copy) Parses a string and returns an integer.
|
|
2922
|
-
*/
|
|
2923
1356
|
const parseInt = _parseInt;
|
|
2924
|
-
/**
|
|
2925
|
-
* (Safe copy) Global isNaN function (coerces to number first, less strict than Number.isNaN).
|
|
2926
|
-
*/
|
|
2927
1357
|
const globalIsNaN = _isNaN;
|
|
2928
|
-
/**
|
|
2929
|
-
* (Safe copy) Global isFinite function (coerces to number first, less strict than Number.isFinite).
|
|
2930
|
-
*/
|
|
2931
1358
|
const globalIsFinite = _isFinite;
|
|
2932
1359
|
|
|
2933
|
-
/**
|
|
2934
|
-
* Creates a new validation context.
|
|
2935
|
-
*
|
|
2936
|
-
* @param rootSchema - The root schema being validated against
|
|
2937
|
-
* @param validator - The schema validator function
|
|
2938
|
-
* @param collectAllErrors - Whether to collect all errors (default: true)
|
|
2939
|
-
* @param strictPatterns - Whether to report errors for invalid regex patterns (default: false)
|
|
2940
|
-
* @param patternSafetyChecker - Optional pattern safety checker for ReDoS detection
|
|
2941
|
-
* @returns A new validation context
|
|
2942
|
-
* @example Creating validation context
|
|
2943
|
-
* ```typescript
|
|
2944
|
-
* const schema = { type: 'string' }
|
|
2945
|
-
* const ctx = createValidationContext(schema, validateSchema)
|
|
2946
|
-
* // ctx.path === ''
|
|
2947
|
-
* // ctx.errors === []
|
|
2948
|
-
* // ctx.collectAllErrors === true
|
|
2949
|
-
* ```
|
|
2950
|
-
*/
|
|
2951
1360
|
function createValidationContext(rootSchema, validator, collectAllErrors = true, strictPatterns = false, patternSafetyChecker) {
|
|
2952
1361
|
const definitions = createMap();
|
|
2953
1362
|
if (rootSchema.definitions) {
|
|
@@ -2966,21 +1375,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2966
1375
|
validate: validator,
|
|
2967
1376
|
};
|
|
2968
1377
|
}
|
|
2969
|
-
/**
|
|
2970
|
-
* Creates a child context with updated path.
|
|
2971
|
-
*
|
|
2972
|
-
* @param ctx - Parent context
|
|
2973
|
-
* @param segment - Path segment to append
|
|
2974
|
-
* @returns New context with updated path
|
|
2975
|
-
* @example Creating child context with path
|
|
2976
|
-
* ```typescript
|
|
2977
|
-
* const ctx = createValidationContext(schema, validate)
|
|
2978
|
-
* const childCtx = pushPath(ctx, 'items')
|
|
2979
|
-
* // childCtx.path === '/items'
|
|
2980
|
-
* const nestedCtx = pushPath(childCtx, 0)
|
|
2981
|
-
* // nestedCtx.path === '/items/0'
|
|
2982
|
-
* ```
|
|
2983
|
-
*/
|
|
2984
1378
|
function pushPath(ctx, segment) {
|
|
2985
1379
|
const escapedSegment = String(segment).replace(/~/g, '~0').replace(/\//g, '~1');
|
|
2986
1380
|
return {
|
|
@@ -2988,22 +1382,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
2988
1382
|
path: `${ctx.path}/${escapedSegment}`,
|
|
2989
1383
|
};
|
|
2990
1384
|
}
|
|
2991
|
-
/**
|
|
2992
|
-
* Adds a validation error to the context.
|
|
2993
|
-
*
|
|
2994
|
-
* @param ctx - Validation context
|
|
2995
|
-
* @param message - Human-readable error message
|
|
2996
|
-
* @param instance - The failing value
|
|
2997
|
-
* @param code - Optional error code for programmatic handling
|
|
2998
|
-
* @param params - Optional additional parameters
|
|
2999
|
-
* @example Adding validation error
|
|
3000
|
-
* ```typescript
|
|
3001
|
-
* const ctx = createValidationContext(schema, validate)
|
|
3002
|
-
* addError(ctx, 'Value must be a string', 42, 'type', { expected: 'string' })
|
|
3003
|
-
* // ctx.errors[0].message === 'Value must be a string'
|
|
3004
|
-
* // ctx.errors[0].code === 'type'
|
|
3005
|
-
* ```
|
|
3006
|
-
*/
|
|
3007
1385
|
function addError(ctx, message, instance, code, params) {
|
|
3008
1386
|
ctx.errors.push({
|
|
3009
1387
|
message,
|
|
@@ -3013,42 +1391,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3013
1391
|
params,
|
|
3014
1392
|
});
|
|
3015
1393
|
}
|
|
3016
|
-
/**
|
|
3017
|
-
* Checks if we should continue validation after an error.
|
|
3018
|
-
*
|
|
3019
|
-
* @param ctx - Validation context
|
|
3020
|
-
* @returns true if we should continue, false if we should stop
|
|
3021
|
-
* @example Checking error collection mode
|
|
3022
|
-
* ```typescript
|
|
3023
|
-
* const ctx = createValidationContext(schema, validate, true) // collectAllErrors: true
|
|
3024
|
-
* addError(ctx, 'First error', 'value', 'error')
|
|
3025
|
-
* shouldContinue(ctx) // => true (keep collecting errors)
|
|
3026
|
-
*
|
|
3027
|
-
* const ctx2 = createValidationContext(schema, validate, false) // collectAllErrors: false
|
|
3028
|
-
* addError(ctx2, 'First error', 'value', 'error')
|
|
3029
|
-
* shouldContinue(ctx2) // => false (stop at first error)
|
|
3030
|
-
* ```
|
|
3031
|
-
*/
|
|
3032
1394
|
function shouldContinue(ctx) {
|
|
3033
1395
|
return ctx.collectAllErrors || ctx.errors.length === 0;
|
|
3034
1396
|
}
|
|
3035
1397
|
|
|
3036
|
-
/**
|
|
3037
|
-
* Performs deep equality check for JSON values.
|
|
3038
|
-
*
|
|
3039
|
-
* Used for enum validation and uniqueItems validation.
|
|
3040
|
-
*
|
|
3041
|
-
* @param a - First value to compare
|
|
3042
|
-
* @param b - Second value to compare
|
|
3043
|
-
* @returns true if values are deeply equal, false otherwise
|
|
3044
|
-
* @example Comparing values for equality
|
|
3045
|
-
* ```typescript
|
|
3046
|
-
* isEqual({ name: 'Alice' }, { name: 'Alice' }) // => true
|
|
3047
|
-
* isEqual([1, 2, 3], [1, 2, 3]) // => true
|
|
3048
|
-
* isEqual({ a: 1 }, { a: 2 }) // => false
|
|
3049
|
-
* isEqual([1, 2], [2, 1]) // => false (order matters)
|
|
3050
|
-
* ```
|
|
3051
|
-
*/
|
|
3052
1398
|
function isEqual(a, b) {
|
|
3053
1399
|
if (a === b)
|
|
3054
1400
|
return true;
|
|
@@ -3083,21 +1429,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3083
1429
|
return false;
|
|
3084
1430
|
}
|
|
3085
1431
|
|
|
3086
|
-
/**
|
|
3087
|
-
* Validates array length and uniqueItems constraints.
|
|
3088
|
-
*
|
|
3089
|
-
* @param instance - Array being validated
|
|
3090
|
-
* @param schema - Schema containing array bounds
|
|
3091
|
-
* @param ctx - Validation context
|
|
3092
|
-
* @returns true if validation passes, false otherwise
|
|
3093
|
-
* @example Validating array constraints
|
|
3094
|
-
* ```typescript
|
|
3095
|
-
* const schema = { minItems: 2, maxItems: 5, uniqueItems: true }
|
|
3096
|
-
* validateArrayBounds([1, 2, 3], schema, ctx) // => true
|
|
3097
|
-
* validateArrayBounds([1], schema, ctx) // => false (too few items)
|
|
3098
|
-
* validateArrayBounds([1, 1, 2], schema, ctx) // => false (duplicates)
|
|
3099
|
-
* ```
|
|
3100
|
-
*/
|
|
3101
1432
|
function validateArrayBounds(instance, schema, ctx) {
|
|
3102
1433
|
let valid = true;
|
|
3103
1434
|
if (schema.minItems !== undefined && instance.length < schema.minItems) {
|
|
@@ -3133,23 +1464,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3133
1464
|
return valid;
|
|
3134
1465
|
}
|
|
3135
1466
|
|
|
3136
|
-
/**
|
|
3137
|
-
* Validates 'allOf' keyword - all schemas must match.
|
|
3138
|
-
*
|
|
3139
|
-
* @param instance - Value being validated
|
|
3140
|
-
* @param schema - Schema containing the allOf constraint
|
|
3141
|
-
* @param ctx - Validation context
|
|
3142
|
-
* @returns true if validation passes, false otherwise
|
|
3143
|
-
* @example Validating allOf composition
|
|
3144
|
-
* ```typescript
|
|
3145
|
-
* { type: 'object', required: ['name'] },
|
|
3146
|
-
* { type: 'object', required: ['email'] }
|
|
3147
|
-
* ]
|
|
3148
|
-
* }
|
|
3149
|
-
* validateAllOf({ name: 'Alice', email: 'alice@example.com' }, schema, ctx) // => true
|
|
3150
|
-
* validateAllOf({ name: 'Alice' }, schema, ctx) // => false (missing email)
|
|
3151
|
-
* ```
|
|
3152
|
-
*/
|
|
3153
1467
|
function validateAllOf(instance, schema, ctx) {
|
|
3154
1468
|
const allOf = schema.allOf;
|
|
3155
1469
|
if (!allOf || allOf.length === 0) {
|
|
@@ -3158,7 +1472,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3158
1472
|
let valid = true;
|
|
3159
1473
|
for (let i = 0; i < allOf.length; i++) {
|
|
3160
1474
|
const subSchema = allOf[i];
|
|
3161
|
-
/* istanbul ignore if -- defensive null check for sparse arrays */
|
|
3162
1475
|
if (!subSchema)
|
|
3163
1476
|
continue;
|
|
3164
1477
|
if (!ctx.validate(instance, subSchema, ctx)) {
|
|
@@ -3169,26 +1482,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3169
1482
|
}
|
|
3170
1483
|
return valid;
|
|
3171
1484
|
}
|
|
3172
|
-
/**
|
|
3173
|
-
* Validates 'anyOf' keyword - at least one schema must match.
|
|
3174
|
-
*
|
|
3175
|
-
* @param instance - Value being validated
|
|
3176
|
-
* @param schema - Schema containing the anyOf constraint
|
|
3177
|
-
* @param ctx - Validation context
|
|
3178
|
-
* @returns true if validation passes, false otherwise
|
|
3179
|
-
* @example Validating anyOf composition
|
|
3180
|
-
* ```typescript
|
|
3181
|
-
* const schema = {
|
|
3182
|
-
* anyOf: [
|
|
3183
|
-
* { type: 'string' },
|
|
3184
|
-
* { type: 'number' }
|
|
3185
|
-
* ]
|
|
3186
|
-
* }
|
|
3187
|
-
* validateAnyOf('hello', schema, ctx) // => true
|
|
3188
|
-
* validateAnyOf(42, schema, ctx) // => true
|
|
3189
|
-
* validateAnyOf(true, schema, ctx) // => false (neither string nor number)
|
|
3190
|
-
* ```
|
|
3191
|
-
*/
|
|
3192
1485
|
function validateAnyOf(instance, schema, ctx) {
|
|
3193
1486
|
const anyOf = schema.anyOf;
|
|
3194
1487
|
if (!anyOf || anyOf.length === 0) {
|
|
@@ -3204,26 +1497,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3204
1497
|
addError(ctx, 'Value does not match any of the allowed schemas (anyOf)', instance, 'anyOf');
|
|
3205
1498
|
return false;
|
|
3206
1499
|
}
|
|
3207
|
-
/**
|
|
3208
|
-
* Validates 'oneOf' keyword - exactly one schema must match.
|
|
3209
|
-
*
|
|
3210
|
-
* @param instance - Value being validated
|
|
3211
|
-
* @param schema - Schema containing the oneOf constraint
|
|
3212
|
-
* @param ctx - Validation context
|
|
3213
|
-
* @returns true if validation passes, false otherwise
|
|
3214
|
-
* @example Validating oneOf composition
|
|
3215
|
-
* ```typescript
|
|
3216
|
-
* const schema = {
|
|
3217
|
-
* oneOf: [
|
|
3218
|
-
* { type: 'integer' },
|
|
3219
|
-
* { minimum: 5 }
|
|
3220
|
-
* ]
|
|
3221
|
-
* }
|
|
3222
|
-
* validateOneOf(3, schema, ctx) // => true (matches first only)
|
|
3223
|
-
* validateOneOf(10, schema, ctx) // => false (matches both)
|
|
3224
|
-
* validateOneOf('hi', schema, ctx) // => false (matches neither)
|
|
3225
|
-
* ```
|
|
3226
|
-
*/
|
|
3227
1500
|
function validateOneOf(instance, schema, ctx) {
|
|
3228
1501
|
const oneOf = schema.oneOf;
|
|
3229
1502
|
if (!oneOf || oneOf.length === 0) {
|
|
@@ -3252,20 +1525,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3252
1525
|
}
|
|
3253
1526
|
return false;
|
|
3254
1527
|
}
|
|
3255
|
-
/**
|
|
3256
|
-
* Validates 'not' keyword - schema must NOT match.
|
|
3257
|
-
*
|
|
3258
|
-
* @param instance - Value being validated
|
|
3259
|
-
* @param schema - Schema containing the not constraint
|
|
3260
|
-
* @param ctx - Validation context
|
|
3261
|
-
* @returns true if validation passes, false otherwise
|
|
3262
|
-
* @example Validating not constraint
|
|
3263
|
-
* ```typescript
|
|
3264
|
-
* const schema = { not: { type: 'string' } }
|
|
3265
|
-
* validateNot(42, schema, ctx) // => true (not a string)
|
|
3266
|
-
* validateNot('hello', schema, ctx) // => false (is a string)
|
|
3267
|
-
* ```
|
|
3268
|
-
*/
|
|
3269
1528
|
function validateNot(instance, schema, ctx) {
|
|
3270
1529
|
const not = schema.not;
|
|
3271
1530
|
if (!not) {
|
|
@@ -3280,58 +1539,31 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3280
1539
|
return true;
|
|
3281
1540
|
}
|
|
3282
1541
|
|
|
3283
|
-
/**
|
|
3284
|
-
* Validates object 'dependencies' keyword.
|
|
3285
|
-
*
|
|
3286
|
-
* @param instance - Object being validated
|
|
3287
|
-
* @param schema - Schema containing the dependencies constraint
|
|
3288
|
-
* @param ctx - Validation context
|
|
3289
|
-
* @returns true if validation passes, false otherwise
|
|
3290
|
-
* @example Validating dependent properties
|
|
3291
|
-
* ```typescript
|
|
3292
|
-
* const schema = {
|
|
3293
|
-
* dependencies: {
|
|
3294
|
-
* creditCard: ['billingAddress'], // if creditCard present, billingAddress required
|
|
3295
|
-
* name: { required: ['email'] } // if name present, email required via schema
|
|
3296
|
-
* }
|
|
3297
|
-
* }
|
|
3298
|
-
* validateDependencies({ creditCard: '1234', billingAddress: '123 Main St' }, schema, ctx) // => true
|
|
3299
|
-
* validateDependencies({ creditCard: '1234' }, schema, ctx) // => false (missing billingAddress)
|
|
3300
|
-
* ```
|
|
3301
|
-
*/
|
|
3302
1542
|
function validateDependencies(instance, schema, ctx) {
|
|
3303
1543
|
if (!schema.dependencies) {
|
|
3304
1544
|
return true;
|
|
3305
1545
|
}
|
|
3306
1546
|
let valid = true;
|
|
3307
1547
|
for (const [key, dependency] of entries(schema.dependencies)) {
|
|
3308
|
-
/* istanbul ignore next -- key presence check */
|
|
3309
1548
|
if (!hasOwn(instance, key)) {
|
|
3310
1549
|
continue;
|
|
3311
1550
|
}
|
|
3312
|
-
/* istanbul ignore next -- dependency type check */
|
|
3313
1551
|
if (isArray(dependency)) {
|
|
3314
1552
|
for (const requiredKey of dependency) {
|
|
3315
|
-
/* istanbul ignore next -- required key check */
|
|
3316
1553
|
if (!hasOwn(instance, requiredKey)) {
|
|
3317
1554
|
addError(ctx, `Property '${key}' requires property '${requiredKey}' to also be present`, instance, 'dependencies', {
|
|
3318
1555
|
property: key,
|
|
3319
|
-
/* istanbul ignore next -- required key assignment */
|
|
3320
1556
|
required: requiredKey,
|
|
3321
1557
|
});
|
|
3322
1558
|
valid = false;
|
|
3323
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
3324
1559
|
if (!shouldContinue(ctx))
|
|
3325
1560
|
return false;
|
|
3326
1561
|
}
|
|
3327
1562
|
}
|
|
3328
1563
|
}
|
|
3329
1564
|
else {
|
|
3330
|
-
/* istanbul ignore next -- schema dependency validation */
|
|
3331
1565
|
if (!ctx.validate(instance, dependency, ctx)) {
|
|
3332
|
-
/* istanbul ignore next -- failure path */
|
|
3333
1566
|
valid = false;
|
|
3334
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
3335
1567
|
if (!shouldContinue(ctx))
|
|
3336
1568
|
return false;
|
|
3337
1569
|
}
|
|
@@ -3340,20 +1572,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3340
1572
|
return valid;
|
|
3341
1573
|
}
|
|
3342
1574
|
|
|
3343
|
-
/**
|
|
3344
|
-
* Validates enum constraint.
|
|
3345
|
-
*
|
|
3346
|
-
* @param instance - Value being validated
|
|
3347
|
-
* @param schema - Schema containing the enum constraint
|
|
3348
|
-
* @param ctx - Validation context
|
|
3349
|
-
* @returns true if validation passes, false otherwise
|
|
3350
|
-
* @example Validating enum values
|
|
3351
|
-
* ```typescript
|
|
3352
|
-
* const schema = { enum: ['draft', 'published', 'archived'] }
|
|
3353
|
-
* validateEnum('published', schema, ctx) // => true
|
|
3354
|
-
* validateEnum('deleted', schema, ctx) // => false (not in enum)
|
|
3355
|
-
* ```
|
|
3356
|
-
*/
|
|
3357
1575
|
function validateEnum(instance, schema, ctx) {
|
|
3358
1576
|
if (!schema.enum) {
|
|
3359
1577
|
return true;
|
|
@@ -3370,77 +1588,24 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3370
1588
|
return false;
|
|
3371
1589
|
}
|
|
3372
1590
|
|
|
3373
|
-
/**
|
|
3374
|
-
* Safe RegExp factory for protected regex construction.
|
|
3375
|
-
*
|
|
3376
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/regexp
|
|
3377
|
-
*/
|
|
3378
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
3379
1591
|
const _RegExp = globalThis.RegExp;
|
|
3380
|
-
const _Reflect$
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
* Use this instead of `new RegExp()`.
|
|
3384
|
-
*
|
|
3385
|
-
* @param pattern - The pattern string or RegExp to copy.
|
|
3386
|
-
* @param flags - Optional flags string.
|
|
3387
|
-
* @returns A new RegExp instance.
|
|
3388
|
-
*/
|
|
3389
|
-
const createRegExp = (pattern, flags) => _Reflect$2.construct(_RegExp, [pattern, flags]);
|
|
3390
|
-
|
|
3391
|
-
/**
|
|
3392
|
-
* Safe copies of URL built-ins via factory functions.
|
|
3393
|
-
*
|
|
3394
|
-
* Provides safe references to URL and URLSearchParams.
|
|
3395
|
-
* These references are captured at module initialization time to protect against
|
|
3396
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
3397
|
-
*
|
|
3398
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/url
|
|
3399
|
-
*/
|
|
1592
|
+
const _Reflect$3 = globalThis.Reflect;
|
|
1593
|
+
const createRegExp = (pattern, flags) => _Reflect$3.construct(_RegExp, [pattern, flags]);
|
|
1594
|
+
|
|
3400
1595
|
const _URL = globalThis.URL;
|
|
3401
|
-
const _Reflect$
|
|
3402
|
-
|
|
3403
|
-
* (Safe copy) Creates a new URL using the captured URL constructor.
|
|
3404
|
-
* Use this instead of `new URL()`.
|
|
3405
|
-
*
|
|
3406
|
-
* @param url - The URL string to parse.
|
|
3407
|
-
* @param base - Optional base URL for relative URLs.
|
|
3408
|
-
* @returns A new URL instance.
|
|
3409
|
-
*
|
|
3410
|
-
* @example Creating URL instances
|
|
3411
|
-
* ```typescript
|
|
3412
|
-
* const absolute = createURL('https://example.com/path?query=1')
|
|
3413
|
-
* const relative = createURL('/api/users', 'https://example.com')
|
|
3414
|
-
* // => URL { href: 'https://example.com/api/users' }
|
|
3415
|
-
* ```
|
|
3416
|
-
*/
|
|
3417
|
-
const createURL = (url, base) => _Reflect$1.construct(_URL, [url, base]);
|
|
3418
|
-
/**
|
|
3419
|
-
* (Safe copy) Creates an object URL for the given object.
|
|
3420
|
-
* Use this instead of `URL.createObjectURL()`.
|
|
3421
|
-
*
|
|
3422
|
-
* Note: This is a browser-only API. In Node.js environments, this will throw.
|
|
3423
|
-
*/
|
|
1596
|
+
const _Reflect$2 = globalThis.Reflect;
|
|
1597
|
+
const createURL = (url, base) => _Reflect$2.construct(_URL, [url, base]);
|
|
3424
1598
|
typeof _URL.createObjectURL === 'function'
|
|
3425
1599
|
? _URL.createObjectURL.bind(_URL)
|
|
3426
1600
|
: () => {
|
|
3427
1601
|
throw new Error('URL.createObjectURL is not available in this environment');
|
|
3428
1602
|
};
|
|
3429
|
-
/**
|
|
3430
|
-
* (Safe copy) Revokes an object URL previously created with createObjectURL.
|
|
3431
|
-
* Use this instead of `URL.revokeObjectURL()`.
|
|
3432
|
-
*
|
|
3433
|
-
* Note: This is a browser-only API. In Node.js environments, this will throw.
|
|
3434
|
-
*/
|
|
3435
1603
|
typeof _URL.revokeObjectURL === 'function'
|
|
3436
1604
|
? _URL.revokeObjectURL.bind(_URL)
|
|
3437
1605
|
: () => {
|
|
3438
1606
|
throw new Error('URL.revokeObjectURL is not available in this environment');
|
|
3439
1607
|
};
|
|
3440
1608
|
|
|
3441
|
-
/**
|
|
3442
|
-
* Format validators for common string formats.
|
|
3443
|
-
*/
|
|
3444
1609
|
const formatValidators = {
|
|
3445
1610
|
'date-time': (v) => {
|
|
3446
1611
|
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(v))
|
|
@@ -3530,7 +1695,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3530
1695
|
try {
|
|
3531
1696
|
createURL(v);
|
|
3532
1697
|
return true;
|
|
3533
|
-
/* istanbul ignore next -- URL constructor always throws for invalid URI */
|
|
3534
1698
|
}
|
|
3535
1699
|
catch {
|
|
3536
1700
|
return false;
|
|
@@ -3539,11 +1703,9 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3539
1703
|
'uri-reference': (v) => {
|
|
3540
1704
|
try {
|
|
3541
1705
|
createURL(v, 'http://example.com');
|
|
3542
|
-
/* istanbul ignore next -- success path just returns true */
|
|
3543
1706
|
return true;
|
|
3544
1707
|
}
|
|
3545
1708
|
catch {
|
|
3546
|
-
/* istanbul ignore next -- URL constructor is very permissive with base URL */
|
|
3547
1709
|
return false;
|
|
3548
1710
|
}
|
|
3549
1711
|
},
|
|
@@ -3552,7 +1714,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3552
1714
|
},
|
|
3553
1715
|
regex: (v) => {
|
|
3554
1716
|
try {
|
|
3555
|
-
// eslint-disable-next-line workspace/no-unsafe-regex -- intentionally validating user-provided regex patterns
|
|
3556
1717
|
createRegExp(v);
|
|
3557
1718
|
return true;
|
|
3558
1719
|
}
|
|
@@ -3570,21 +1731,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3570
1731
|
return segments.every((seg) => validSegment.test(seg));
|
|
3571
1732
|
},
|
|
3572
1733
|
};
|
|
3573
|
-
/**
|
|
3574
|
-
* Validates string format constraint.
|
|
3575
|
-
*
|
|
3576
|
-
* @param instance - String being validated
|
|
3577
|
-
* @param schema - Schema containing the format constraint
|
|
3578
|
-
* @param ctx - Validation context
|
|
3579
|
-
* @returns true if validation passes, false otherwise
|
|
3580
|
-
* @example Validating string formats
|
|
3581
|
-
* ```typescript
|
|
3582
|
-
* validateFormat('user@example.com', { format: 'email' }, ctx) // => true
|
|
3583
|
-
* validateFormat('invalid-email', { format: 'email' }, ctx) // => false
|
|
3584
|
-
* validateFormat('2024-01-15', { format: 'date' }, ctx) // => true
|
|
3585
|
-
* validateFormat('192.168.1.1', { format: 'ipv4' }, ctx) // => true
|
|
3586
|
-
* ```
|
|
3587
|
-
*/
|
|
3588
1734
|
function validateFormat(instance, schema, ctx) {
|
|
3589
1735
|
if (!schema.format) {
|
|
3590
1736
|
return true;
|
|
@@ -3602,27 +1748,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3602
1748
|
return true;
|
|
3603
1749
|
}
|
|
3604
1750
|
|
|
3605
|
-
/**
|
|
3606
|
-
* Validates array 'items' keyword.
|
|
3607
|
-
*
|
|
3608
|
-
* @param instance - Array being validated
|
|
3609
|
-
* @param schema - Schema containing the items constraint
|
|
3610
|
-
* @param ctx - Validation context
|
|
3611
|
-
* @returns true if validation passes, false otherwise
|
|
3612
|
-
* @example Single schema for all items
|
|
3613
|
-
* ```typescript
|
|
3614
|
-
* const schema = { items: { type: 'string' } }
|
|
3615
|
-
* validateItems(['a', 'b', 'c'], schema, ctx) // => true
|
|
3616
|
-
* validateItems(['a', 1, 'c'], schema, ctx) // => false (1 is not a string)
|
|
3617
|
-
* ```
|
|
3618
|
-
*
|
|
3619
|
-
* @example Tuple validation
|
|
3620
|
-
* ```typescript
|
|
3621
|
-
* const schema = { items: [{ type: 'string' }, { type: 'number' }] }
|
|
3622
|
-
* validateItems(['name', 42], schema, ctx) // => true
|
|
3623
|
-
* validateItems([42, 'name'], schema, ctx) // => false (wrong types)
|
|
3624
|
-
* ```
|
|
3625
|
-
*/
|
|
3626
1751
|
function validateItems(instance, schema, ctx) {
|
|
3627
1752
|
const items = schema.items;
|
|
3628
1753
|
if (items === undefined) {
|
|
@@ -3632,13 +1757,11 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3632
1757
|
if (isArray(items)) {
|
|
3633
1758
|
for (let i = 0; i < items.length && i < instance.length; i++) {
|
|
3634
1759
|
const itemSchema = items[i];
|
|
3635
|
-
/* istanbul ignore if -- defensive null check for sparse arrays */
|
|
3636
1760
|
if (!itemSchema)
|
|
3637
1761
|
continue;
|
|
3638
1762
|
const itemCtx = pushPath(ctx, i);
|
|
3639
1763
|
if (!ctx.validate(instance[i], itemSchema, itemCtx)) {
|
|
3640
1764
|
valid = false;
|
|
3641
|
-
/* istanbul ignore if -- early exit already tested in validate.spec.ts */
|
|
3642
1765
|
if (!shouldContinue(ctx))
|
|
3643
1766
|
return false;
|
|
3644
1767
|
}
|
|
@@ -3661,24 +1784,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3661
1784
|
}
|
|
3662
1785
|
return valid;
|
|
3663
1786
|
}
|
|
3664
|
-
/**
|
|
3665
|
-
* Validates 'additionalItems' keyword for tuple arrays.
|
|
3666
|
-
*
|
|
3667
|
-
* @param instance - Array being validated
|
|
3668
|
-
* @param schema - Schema containing the additionalItems constraint
|
|
3669
|
-
* @param ctx - Validation context
|
|
3670
|
-
* @param startIndex - Index from which to start checking additional items
|
|
3671
|
-
* @returns true if validation passes, false otherwise
|
|
3672
|
-
*/
|
|
3673
1787
|
function validateAdditionalItems(instance, schema, ctx, startIndex) {
|
|
3674
1788
|
const additionalItems = schema.additionalItems;
|
|
3675
|
-
/* istanbul ignore if -- default case handled in items.spec.ts */
|
|
3676
1789
|
if (additionalItems === undefined) {
|
|
3677
1790
|
return true;
|
|
3678
1791
|
}
|
|
3679
|
-
/* istanbul ignore next -- additionalItems initialization and branching */
|
|
3680
1792
|
let valid = true;
|
|
3681
|
-
/* istanbul ignore next -- additionalItems branching */
|
|
3682
1793
|
if (additionalItems === false) {
|
|
3683
1794
|
if (instance.length > startIndex) {
|
|
3684
1795
|
addError(ctx, `Array has too many items. Expected at most ${startIndex}, got ${instance.length}`, instance, 'additionalItems', {
|
|
@@ -3691,10 +1802,8 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3691
1802
|
else if (typeof additionalItems === 'object') {
|
|
3692
1803
|
for (let i = startIndex; i < instance.length; i++) {
|
|
3693
1804
|
const itemCtx = pushPath(ctx, i);
|
|
3694
|
-
/* istanbul ignore else -- validation failure tested in items.spec.ts */
|
|
3695
1805
|
if (!ctx.validate(instance[i], additionalItems, itemCtx)) {
|
|
3696
1806
|
valid = false;
|
|
3697
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
3698
1807
|
if (!shouldContinue(ctx))
|
|
3699
1808
|
return false;
|
|
3700
1809
|
}
|
|
@@ -3703,22 +1812,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3703
1812
|
return valid;
|
|
3704
1813
|
}
|
|
3705
1814
|
|
|
3706
|
-
/**
|
|
3707
|
-
* Validates number range and multipleOf constraints.
|
|
3708
|
-
*
|
|
3709
|
-
* @param instance - Number being validated
|
|
3710
|
-
* @param schema - Schema containing number constraints
|
|
3711
|
-
* @param ctx - Validation context
|
|
3712
|
-
* @returns true if validation passes, false otherwise
|
|
3713
|
-
* @example Validating number constraints
|
|
3714
|
-
* ```typescript
|
|
3715
|
-
* const schema = { minimum: 0, maximum: 100, multipleOf: 5 }
|
|
3716
|
-
* validateNumberBounds(50, schema, ctx) // => true
|
|
3717
|
-
* validateNumberBounds(-1, schema, ctx) // => false (below minimum)
|
|
3718
|
-
* validateNumberBounds(101, schema, ctx) // => false (above maximum)
|
|
3719
|
-
* validateNumberBounds(17, schema, ctx) // => false (not multiple of 5)
|
|
3720
|
-
* ```
|
|
3721
|
-
*/
|
|
3722
1815
|
function validateNumberBounds(instance, schema, ctx) {
|
|
3723
1816
|
let valid = true;
|
|
3724
1817
|
if (schema.minimum !== undefined) {
|
|
@@ -3765,21 +1858,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3765
1858
|
return valid;
|
|
3766
1859
|
}
|
|
3767
1860
|
|
|
3768
|
-
/**
|
|
3769
|
-
* Validates object bounds constraints (minProperties, maxProperties).
|
|
3770
|
-
*
|
|
3771
|
-
* @param instance - Object being validated
|
|
3772
|
-
* @param schema - Schema containing object bounds
|
|
3773
|
-
* @param ctx - Validation context
|
|
3774
|
-
* @returns true if validation passes, false otherwise
|
|
3775
|
-
* @example Validating object property counts
|
|
3776
|
-
* ```typescript
|
|
3777
|
-
* const schema = { minProperties: 1, maxProperties: 3 }
|
|
3778
|
-
* validateObjectBounds({ a: 1, b: 2 }, schema, ctx) // => true
|
|
3779
|
-
* validateObjectBounds({}, schema, ctx) // => false (no properties)
|
|
3780
|
-
* validateObjectBounds({ a: 1, b: 2, c: 3, d: 4 }, schema, ctx) // => false (too many)
|
|
3781
|
-
* ```
|
|
3782
|
-
*/
|
|
3783
1861
|
function validateObjectBounds(instance, schema, ctx) {
|
|
3784
1862
|
let valid = true;
|
|
3785
1863
|
const propertyCount = keys(instance).length;
|
|
@@ -3804,25 +1882,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3804
1882
|
return valid;
|
|
3805
1883
|
}
|
|
3806
1884
|
|
|
3807
|
-
/**
|
|
3808
|
-
* Validates object 'patternProperties' keyword.
|
|
3809
|
-
*
|
|
3810
|
-
* @param instance - Object being validated
|
|
3811
|
-
* @param schema - Schema containing the patternProperties constraint
|
|
3812
|
-
* @param ctx - Validation context
|
|
3813
|
-
* @returns true if validation passes, false otherwise
|
|
3814
|
-
* @example Validating pattern properties
|
|
3815
|
-
* ```typescript
|
|
3816
|
-
* const schema = {
|
|
3817
|
-
* patternProperties: {
|
|
3818
|
-
* '^x-': { type: 'string' }, // extension properties must be strings
|
|
3819
|
-
* '^\\d+$': { type: 'number' } // numeric keys must have number values
|
|
3820
|
-
* }
|
|
3821
|
-
* }
|
|
3822
|
-
* validatePatternProperties({ 'x-custom': 'value', '42': 100 }, schema, ctx) // => true
|
|
3823
|
-
* validatePatternProperties({ 'x-custom': 123 }, schema, ctx) // => false (should be string)
|
|
3824
|
-
* ```
|
|
3825
|
-
*/
|
|
3826
1885
|
function validatePatternProperties(instance, schema, ctx) {
|
|
3827
1886
|
if (!schema.patternProperties) {
|
|
3828
1887
|
return true;
|
|
@@ -3830,7 +1889,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3830
1889
|
let valid = true;
|
|
3831
1890
|
const patterns = [];
|
|
3832
1891
|
for (const [pattern, patternSchema] of entries(schema.patternProperties)) {
|
|
3833
|
-
/* istanbul ignore if -- patternSafetyChecker branch tested in validate.spec.ts */
|
|
3834
1892
|
if (ctx.patternSafetyChecker) {
|
|
3835
1893
|
const safetyResult = ctx.patternSafetyChecker(pattern);
|
|
3836
1894
|
if (!safetyResult.safe) {
|
|
@@ -3845,21 +1903,15 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3845
1903
|
}
|
|
3846
1904
|
}
|
|
3847
1905
|
try {
|
|
3848
|
-
// eslint-disable-next-line workspace/no-unsafe-regex -- Pattern safety validated above when safePatterns enabled
|
|
3849
1906
|
patterns.push({ regex: createRegExp(pattern), schema: patternSchema });
|
|
3850
1907
|
}
|
|
3851
1908
|
catch (e) {
|
|
3852
|
-
/* istanbul ignore next -- strictPatterns mode verified in validate.spec.ts */
|
|
3853
1909
|
if (ctx.strictPatterns) {
|
|
3854
|
-
/* istanbul ignore next -- error reporting for invalid regex */
|
|
3855
1910
|
addError(ctx, `Invalid regex pattern in patternProperties: ${pattern}`, instance, 'patternProperties', {
|
|
3856
|
-
/* istanbul ignore next -- error message extraction */
|
|
3857
1911
|
pattern,
|
|
3858
|
-
/* istanbul ignore next -- ternary expression */
|
|
3859
1912
|
error: e instanceof Error ? e.message : 'Invalid regex',
|
|
3860
1913
|
});
|
|
3861
1914
|
valid = false;
|
|
3862
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
3863
1915
|
if (!shouldContinue(ctx))
|
|
3864
1916
|
return false;
|
|
3865
1917
|
}
|
|
@@ -3880,25 +1932,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3880
1932
|
return valid;
|
|
3881
1933
|
}
|
|
3882
1934
|
|
|
3883
|
-
/**
|
|
3884
|
-
* Validates object 'properties' keyword.
|
|
3885
|
-
*
|
|
3886
|
-
* @param instance - Object being validated
|
|
3887
|
-
* @param schema - Schema containing the properties constraint
|
|
3888
|
-
* @param ctx - Validation context
|
|
3889
|
-
* @returns true if validation passes, false otherwise
|
|
3890
|
-
* @example Validating object properties
|
|
3891
|
-
* ```typescript
|
|
3892
|
-
* const schema = {
|
|
3893
|
-
* properties: {
|
|
3894
|
-
* name: { type: 'string' },
|
|
3895
|
-
* age: { type: 'integer' }
|
|
3896
|
-
* }
|
|
3897
|
-
* }
|
|
3898
|
-
* validateProperties({ name: 'Alice', age: 30 }, schema, ctx) // => true
|
|
3899
|
-
* validateProperties({ name: 123 }, schema, ctx) // => false (name should be string)
|
|
3900
|
-
* ```
|
|
3901
|
-
*/
|
|
3902
1935
|
function validateProperties(instance, schema, ctx) {
|
|
3903
1936
|
if (!schema.properties) {
|
|
3904
1937
|
return true;
|
|
@@ -3916,20 +1949,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3916
1949
|
}
|
|
3917
1950
|
return valid;
|
|
3918
1951
|
}
|
|
3919
|
-
/**
|
|
3920
|
-
* Validates object 'required' keyword.
|
|
3921
|
-
*
|
|
3922
|
-
* @param instance - Object being validated
|
|
3923
|
-
* @param schema - Schema containing the required constraint
|
|
3924
|
-
* @param ctx - Validation context
|
|
3925
|
-
* @returns true if validation passes, false otherwise
|
|
3926
|
-
* @example Validating required properties
|
|
3927
|
-
* ```typescript
|
|
3928
|
-
* const schema = { required: ['name', 'email'] }
|
|
3929
|
-
* validateRequired({ name: 'Alice', email: 'alice@example.com' }, schema, ctx) // => true
|
|
3930
|
-
* validateRequired({ name: 'Alice' }, schema, ctx) // => false (missing email)
|
|
3931
|
-
* ```
|
|
3932
|
-
*/
|
|
3933
1952
|
function validateRequired(instance, schema, ctx) {
|
|
3934
1953
|
if (!schema.required) {
|
|
3935
1954
|
return true;
|
|
@@ -3945,38 +1964,18 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3945
1964
|
}
|
|
3946
1965
|
return valid;
|
|
3947
1966
|
}
|
|
3948
|
-
/**
|
|
3949
|
-
* Validates object 'additionalProperties' keyword.
|
|
3950
|
-
*
|
|
3951
|
-
* @param instance - Object being validated
|
|
3952
|
-
* @param schema - Schema containing the additionalProperties constraint
|
|
3953
|
-
* @param ctx - Validation context
|
|
3954
|
-
* @returns true if validation passes, false otherwise
|
|
3955
|
-
* @example Validating additional properties
|
|
3956
|
-
* ```typescript
|
|
3957
|
-
* const schema = {
|
|
3958
|
-
* properties: { name: { type: 'string' } },
|
|
3959
|
-
* additionalProperties: false
|
|
3960
|
-
* }
|
|
3961
|
-
* validateAdditionalProperties({ name: 'Alice' }, schema, ctx) // => true
|
|
3962
|
-
* validateAdditionalProperties({ name: 'Alice', extra: 1 }, schema, ctx) // => false
|
|
3963
|
-
* ```
|
|
3964
|
-
*/
|
|
3965
1967
|
function validateAdditionalProperties(instance, schema, ctx) {
|
|
3966
1968
|
const additionalProperties = schema.additionalProperties;
|
|
3967
1969
|
if (additionalProperties === undefined) {
|
|
3968
1970
|
return true;
|
|
3969
1971
|
}
|
|
3970
|
-
/* istanbul ignore next -- definedKeys initialization */
|
|
3971
1972
|
const definedKeys = createSet();
|
|
3972
|
-
/* istanbul ignore next -- schema.properties may not exist */
|
|
3973
1973
|
if (schema.properties) {
|
|
3974
1974
|
for (const key of keys(schema.properties)) {
|
|
3975
1975
|
definedKeys.add(key);
|
|
3976
1976
|
}
|
|
3977
1977
|
}
|
|
3978
1978
|
const patterns = [];
|
|
3979
|
-
/* istanbul ignore next -- patternProperties may not always be present */
|
|
3980
1979
|
if (schema.patternProperties) {
|
|
3981
1980
|
for (const pattern of keys(schema.patternProperties)) {
|
|
3982
1981
|
if (ctx.patternSafetyChecker) {
|
|
@@ -3986,12 +1985,9 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
3986
1985
|
}
|
|
3987
1986
|
}
|
|
3988
1987
|
try {
|
|
3989
|
-
// eslint-disable-next-line workspace/no-unsafe-regex -- Pattern safety validated above when safePatterns enabled
|
|
3990
1988
|
patterns.push(createRegExp(pattern));
|
|
3991
|
-
/* istanbul ignore next -- invalid regex patterns handled in patternProperties validator */
|
|
3992
1989
|
}
|
|
3993
1990
|
catch {
|
|
3994
|
-
// Invalid regex, skip
|
|
3995
1991
|
}
|
|
3996
1992
|
}
|
|
3997
1993
|
}
|
|
@@ -4008,7 +2004,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4008
2004
|
property: key,
|
|
4009
2005
|
});
|
|
4010
2006
|
valid = false;
|
|
4011
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
4012
2007
|
if (!shouldContinue(ctx))
|
|
4013
2008
|
return false;
|
|
4014
2009
|
}
|
|
@@ -4016,7 +2011,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4016
2011
|
const propCtx = pushPath(ctx, key);
|
|
4017
2012
|
if (!ctx.validate(instance[key], additionalProperties, propCtx)) {
|
|
4018
2013
|
valid = false;
|
|
4019
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
4020
2014
|
if (!shouldContinue(ctx))
|
|
4021
2015
|
return false;
|
|
4022
2016
|
}
|
|
@@ -4025,21 +2019,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4025
2019
|
return valid;
|
|
4026
2020
|
}
|
|
4027
2021
|
|
|
4028
|
-
/**
|
|
4029
|
-
* Validates string length and pattern constraints.
|
|
4030
|
-
*
|
|
4031
|
-
* @param instance - String being validated
|
|
4032
|
-
* @param schema - Schema containing string constraints
|
|
4033
|
-
* @param ctx - Validation context
|
|
4034
|
-
* @returns true if validation passes, false otherwise
|
|
4035
|
-
* @example Validating string constraints
|
|
4036
|
-
* ```typescript
|
|
4037
|
-
* const schema = { minLength: 3, maxLength: 10, pattern: '^[a-z]+$' }
|
|
4038
|
-
* validateStringBounds('hello', schema, ctx) // => true
|
|
4039
|
-
* validateStringBounds('hi', schema, ctx) // => false (too short)
|
|
4040
|
-
* validateStringBounds('Hello', schema, ctx) // => false (contains uppercase)
|
|
4041
|
-
* ```
|
|
4042
|
-
*/
|
|
4043
2022
|
function validateStringBounds(instance, schema, ctx) {
|
|
4044
2023
|
let valid = true;
|
|
4045
2024
|
if (schema.minLength !== undefined && instance.length < schema.minLength) {
|
|
@@ -4075,7 +2054,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4075
2054
|
}
|
|
4076
2055
|
}
|
|
4077
2056
|
try {
|
|
4078
|
-
// eslint-disable-next-line workspace/no-unsafe-regex -- Pattern safety validated above when safePatterns enabled
|
|
4079
2057
|
const regex = createRegExp(schema.pattern);
|
|
4080
2058
|
if (!regex.test(instance)) {
|
|
4081
2059
|
addError(ctx, `String does not match pattern: ${schema.pattern}`, instance, 'pattern', {
|
|
@@ -4087,16 +2065,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4087
2065
|
}
|
|
4088
2066
|
}
|
|
4089
2067
|
catch (e) {
|
|
4090
|
-
/* istanbul ignore next -- strictPatterns mode verified in validate.spec.ts */
|
|
4091
2068
|
if (ctx.strictPatterns) {
|
|
4092
|
-
/* istanbul ignore next -- error reporting for invalid regex */
|
|
4093
2069
|
addError(ctx, `Invalid regex pattern: ${schema.pattern}`, instance, 'pattern', {
|
|
4094
2070
|
pattern: schema.pattern,
|
|
4095
|
-
/* istanbul ignore next -- error message extraction ternary */
|
|
4096
2071
|
error: e instanceof Error ? e.message : 'Invalid regex',
|
|
4097
2072
|
});
|
|
4098
2073
|
valid = false;
|
|
4099
|
-
/* istanbul ignore if -- early exit tested in validate.spec.ts */
|
|
4100
2074
|
if (!shouldContinue(ctx))
|
|
4101
2075
|
return false;
|
|
4102
2076
|
}
|
|
@@ -4105,9 +2079,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4105
2079
|
return valid;
|
|
4106
2080
|
}
|
|
4107
2081
|
|
|
4108
|
-
/**
|
|
4109
|
-
* Type checking functions for JSON Schema types.
|
|
4110
|
-
*/
|
|
4111
2082
|
const typeCheckers = {
|
|
4112
2083
|
string: (v) => typeof v === 'string',
|
|
4113
2084
|
number: (v) => typeof v === 'number' && globalIsFinite(v),
|
|
@@ -4117,12 +2088,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4117
2088
|
object: (v) => v !== null && typeof v === 'object' && !isArray(v),
|
|
4118
2089
|
null: (v) => v === null,
|
|
4119
2090
|
};
|
|
4120
|
-
/**
|
|
4121
|
-
* Gets the actual JSON type of a value for error messages.
|
|
4122
|
-
*
|
|
4123
|
-
* @param value - The value to get the type of
|
|
4124
|
-
* @returns The JSON type as a string
|
|
4125
|
-
*/
|
|
4126
2091
|
function getActualType(value) {
|
|
4127
2092
|
if (value === null)
|
|
4128
2093
|
return 'null';
|
|
@@ -4131,28 +2096,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4131
2096
|
const t = typeof value;
|
|
4132
2097
|
if (t === 'number') {
|
|
4133
2098
|
const num = value;
|
|
4134
|
-
/* istanbul ignore next -- NaN/Infinity edge case */
|
|
4135
2099
|
if (!globalIsFinite(num))
|
|
4136
2100
|
return 'number';
|
|
4137
2101
|
return isInteger(num) ? 'integer' : 'number';
|
|
4138
2102
|
}
|
|
4139
2103
|
return t;
|
|
4140
2104
|
}
|
|
4141
|
-
/**
|
|
4142
|
-
* Validates the 'type' keyword.
|
|
4143
|
-
*
|
|
4144
|
-
* @param instance - Value being validated
|
|
4145
|
-
* @param schema - Schema containing the type constraint
|
|
4146
|
-
* @param ctx - Validation context
|
|
4147
|
-
* @returns true if validation passes, false otherwise
|
|
4148
|
-
* @example Validating type constraints
|
|
4149
|
-
* ```typescript
|
|
4150
|
-
* validateType('hello', { type: 'string' }, ctx) // => true
|
|
4151
|
-
* validateType(42, { type: 'integer' }, ctx) // => true
|
|
4152
|
-
* validateType('42', { type: 'integer' }, ctx) // => false
|
|
4153
|
-
* validateType(null, { type: ['string', 'null'] }, ctx) // => true (union type)
|
|
4154
|
-
* ```
|
|
4155
|
-
*/
|
|
4156
2105
|
function validateType(instance, schema, ctx) {
|
|
4157
2106
|
const schemaType = schema.type;
|
|
4158
2107
|
if (schemaType === undefined) {
|
|
@@ -4161,11 +2110,9 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4161
2110
|
const types = isArray(schemaType) ? schemaType : [schemaType];
|
|
4162
2111
|
for (const type of types) {
|
|
4163
2112
|
const checker = typeCheckers[type];
|
|
4164
|
-
/* istanbul ignore if -- defensive check for unknown type */
|
|
4165
2113
|
if (checker && checker(instance)) {
|
|
4166
2114
|
return true;
|
|
4167
2115
|
}
|
|
4168
|
-
/* istanbul ignore if -- defensive fallback for integer/number coercion */
|
|
4169
2116
|
if (type === 'number' && typeCheckers['integer']?.(instance)) {
|
|
4170
2117
|
return true;
|
|
4171
2118
|
}
|
|
@@ -4179,24 +2126,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4179
2126
|
return false;
|
|
4180
2127
|
}
|
|
4181
2128
|
|
|
4182
|
-
/**
|
|
4183
|
-
* Resolves a $ref JSON Pointer to its target schema.
|
|
4184
|
-
*
|
|
4185
|
-
* @param ref - The $ref string (e.g., '#/definitions/Address')
|
|
4186
|
-
* @param ctx - Validation context containing root schema and definitions
|
|
4187
|
-
* @returns The resolved schema, or undefined if not found
|
|
4188
|
-
* @example Resolving schema references
|
|
4189
|
-
* ```typescript
|
|
4190
|
-
* const rootSchema = {
|
|
4191
|
-
* definitions: {
|
|
4192
|
-
* Address: { type: 'object', properties: { street: { type: 'string' } } }
|
|
4193
|
-
* }
|
|
4194
|
-
* }
|
|
4195
|
-
* const ctx = createValidationContext(rootSchema, validate)
|
|
4196
|
-
* resolveRef('#/definitions/Address', ctx)
|
|
4197
|
-
* // => { type: 'object', properties: { street: { type: 'string' } } }
|
|
4198
|
-
* ```
|
|
4199
|
-
*/
|
|
4200
2129
|
function resolveRef(ref, ctx) {
|
|
4201
2130
|
const cached = ctx.definitions.get(ref);
|
|
4202
2131
|
if (cached) {
|
|
@@ -4231,21 +2160,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4231
2160
|
return undefined;
|
|
4232
2161
|
}
|
|
4233
2162
|
|
|
4234
|
-
/**
|
|
4235
|
-
* Validates a value against a JSON Schema.
|
|
4236
|
-
*
|
|
4237
|
-
* @param instance - The value to validate
|
|
4238
|
-
* @param schema - The JSON Schema to validate against
|
|
4239
|
-
* @param options - Validation options
|
|
4240
|
-
* @returns Validation result with valid flag and any errors
|
|
4241
|
-
*
|
|
4242
|
-
* @example Basic validation
|
|
4243
|
-
* ```typescript
|
|
4244
|
-
* const schema = { type: 'string', minLength: 1 }
|
|
4245
|
-
* const result = validate('hello', schema)
|
|
4246
|
-
* console.log(result.valid) // true
|
|
4247
|
-
* ```
|
|
4248
|
-
*/
|
|
4249
2163
|
function validate(instance, schema, options) {
|
|
4250
2164
|
let patternSafetyChecker;
|
|
4251
2165
|
const ctx = createValidationContext(schema, validateSchema, true, false, patternSafetyChecker);
|
|
@@ -4255,25 +2169,9 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4255
2169
|
errors: ctx.errors,
|
|
4256
2170
|
};
|
|
4257
2171
|
}
|
|
4258
|
-
/**
|
|
4259
|
-
* Internal recursive validation function.
|
|
4260
|
-
*
|
|
4261
|
-
* @param instance - Value being validated
|
|
4262
|
-
* @param schema - Schema to validate against
|
|
4263
|
-
* @param ctx - Validation context
|
|
4264
|
-
* @returns true if validation passes, false otherwise
|
|
4265
|
-
* @example Internal recursive validation
|
|
4266
|
-
* ```typescript
|
|
4267
|
-
* const schema = { type: 'object', properties: { count: { type: 'integer' } } }
|
|
4268
|
-
* const ctx = createValidationContext(schema, validateSchema)
|
|
4269
|
-
* validateSchema({ count: 5 }, schema, ctx) // => true
|
|
4270
|
-
* validateSchema({ count: 'five' }, schema, ctx) // => false
|
|
4271
|
-
* ```
|
|
4272
|
-
*/
|
|
4273
2172
|
function validateSchema(instance, schema, ctx) {
|
|
4274
2173
|
if (schema.$ref) {
|
|
4275
2174
|
const resolved = resolveRef(schema.$ref, ctx);
|
|
4276
|
-
/* istanbul ignore if -- $ref resolution failures are tested in resolve-ref.spec.ts */
|
|
4277
2175
|
if (!resolved) {
|
|
4278
2176
|
return true;
|
|
4279
2177
|
}
|
|
@@ -4330,35 +2228,26 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4330
2228
|
}
|
|
4331
2229
|
if (!validateRequired(obj, schema, ctx)) {
|
|
4332
2230
|
valid = false;
|
|
4333
|
-
/* istanbul ignore if -- early exit tested elsewhere */
|
|
4334
2231
|
if (!shouldContinue(ctx))
|
|
4335
2232
|
return false;
|
|
4336
2233
|
}
|
|
4337
|
-
/* istanbul ignore next -- patternProperties validation */
|
|
4338
2234
|
if (!validatePatternProperties(obj, schema, ctx)) {
|
|
4339
2235
|
valid = false;
|
|
4340
|
-
/* istanbul ignore next -- early exit tested elsewhere */
|
|
4341
2236
|
if (!shouldContinue(ctx))
|
|
4342
2237
|
return false;
|
|
4343
2238
|
}
|
|
4344
|
-
/* istanbul ignore next -- additionalProperties validation */
|
|
4345
2239
|
if (!validateAdditionalProperties(obj, schema, ctx)) {
|
|
4346
2240
|
valid = false;
|
|
4347
|
-
/* istanbul ignore next -- early exit tested elsewhere */
|
|
4348
2241
|
if (!shouldContinue(ctx))
|
|
4349
2242
|
return false;
|
|
4350
2243
|
}
|
|
4351
|
-
/* istanbul ignore next -- objectBounds validation */
|
|
4352
2244
|
if (!validateObjectBounds(obj, schema, ctx)) {
|
|
4353
2245
|
valid = false;
|
|
4354
|
-
/* istanbul ignore next -- early exit tested elsewhere */
|
|
4355
2246
|
if (!shouldContinue(ctx))
|
|
4356
2247
|
return false;
|
|
4357
2248
|
}
|
|
4358
|
-
/* istanbul ignore next -- dependencies validation */
|
|
4359
2249
|
if (!validateDependencies(obj, schema, ctx)) {
|
|
4360
2250
|
valid = false;
|
|
4361
|
-
/* istanbul ignore next -- early exit tested elsewhere */
|
|
4362
2251
|
if (!shouldContinue(ctx))
|
|
4363
2252
|
return false;
|
|
4364
2253
|
}
|
|
@@ -4386,51 +2275,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4386
2275
|
return valid;
|
|
4387
2276
|
}
|
|
4388
2277
|
|
|
4389
|
-
/**
|
|
4390
|
-
* Creates a reusable validator function from a JSON Schema.
|
|
4391
|
-
*
|
|
4392
|
-
* @param schema - JSON Schema to validate against
|
|
4393
|
-
* @param options - Validation options
|
|
4394
|
-
* @returns A function that validates data against the schema
|
|
4395
|
-
*
|
|
4396
|
-
* @example Creating reusable validator
|
|
4397
|
-
* ```typescript
|
|
4398
|
-
* const schema = {
|
|
4399
|
-
* type: 'object',
|
|
4400
|
-
* properties: {
|
|
4401
|
-
* name: { type: 'string' },
|
|
4402
|
-
* age: { type: 'integer', minimum: 0 }
|
|
4403
|
-
* },
|
|
4404
|
-
* required: ['name']
|
|
4405
|
-
* }
|
|
4406
|
-
*
|
|
4407
|
-
* const validateUser = createValidator(schema)
|
|
4408
|
-
* const result = validateUser({ name: 'Alice', age: 30 })
|
|
4409
|
-
* console.log(result.valid) // true
|
|
4410
|
-
* ```
|
|
4411
|
-
*/
|
|
4412
2278
|
function createValidator$1(schema, options) {
|
|
4413
2279
|
return (data) => validate(data, schema);
|
|
4414
2280
|
}
|
|
4415
2281
|
|
|
4416
|
-
/**
|
|
4417
|
-
* Creates a validator function from a JSON schema.
|
|
4418
|
-
* Returns a function that validates data against the schema.
|
|
4419
|
-
*
|
|
4420
|
-
* @param schema - JSON Schema to validate against
|
|
4421
|
-
* @returns Validator function that returns validation results
|
|
4422
|
-
*
|
|
4423
|
-
* @example Creating a schema validator
|
|
4424
|
-
* ```typescript
|
|
4425
|
-
* const validateUser = createValidator({
|
|
4426
|
-
* type: 'object',
|
|
4427
|
-
* properties: { name: { type: 'string' } },
|
|
4428
|
-
* required: ['name']
|
|
4429
|
-
* })
|
|
4430
|
-
* const result = validateUser({ name: 'Alice' })
|
|
4431
|
-
* // => { valid: true, errors: [] }
|
|
4432
|
-
* ```
|
|
4433
|
-
*/
|
|
4434
2282
|
function createValidator(schema) {
|
|
4435
2283
|
const validator = createValidator$1(schema);
|
|
4436
2284
|
return (data) => {
|
|
@@ -4446,47 +2294,19 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4446
2294
|
};
|
|
4447
2295
|
}
|
|
4448
2296
|
|
|
4449
|
-
/* istanbul ignore next -- validator initialization happens at module load */
|
|
4450
2297
|
const validateMessageData = createValidator(messageSchema);
|
|
4451
|
-
/**
|
|
4452
|
-
* Validates a user message against the message schema.
|
|
4453
|
-
*
|
|
4454
|
-
* @param message - The message to validate
|
|
4455
|
-
* @returns Validation result with any errors
|
|
4456
|
-
*/
|
|
4457
2298
|
function validateMessage(message) {
|
|
4458
2299
|
return validateMessageData(message);
|
|
4459
2300
|
}
|
|
4460
2301
|
|
|
4461
|
-
/**
|
|
4462
|
-
* Handles NEW_MESSAGE action.
|
|
4463
|
-
* Routes messages to appropriate channel.
|
|
4464
|
-
*
|
|
4465
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
4466
|
-
* @param message - Message event containing the NEW_MESSAGE action
|
|
4467
|
-
*
|
|
4468
|
-
* @remarks
|
|
4469
|
-
* Side Effects:
|
|
4470
|
-
* - Validates message type against contract
|
|
4471
|
-
* - Invokes channel message handlers if validation passes
|
|
4472
|
-
* - Logs and ignores invalid messages
|
|
4473
|
-
*
|
|
4474
|
-
* @example Routing user messages
|
|
4475
|
-
* User message flow:
|
|
4476
|
-
* channel.send('USER_LOGIN', {userId: 123})
|
|
4477
|
-
* -> NEW_MESSAGE action sent
|
|
4478
|
-
* -> Received by remote broker (this handler)
|
|
4479
|
-
* -> Routed to channel's onMessage handlers
|
|
4480
|
-
*/
|
|
4481
2302
|
function handleMessage(context, message) {
|
|
4482
2303
|
const { state, registry, logger } = context;
|
|
4483
2304
|
const action = message.data;
|
|
4484
|
-
const senderId = action.senderId;
|
|
4485
2305
|
if (!isActionWithData(action)) {
|
|
4486
2306
|
return;
|
|
4487
2307
|
}
|
|
4488
2308
|
const messageData = action.data;
|
|
4489
|
-
const channel =
|
|
2309
|
+
const channel = resolveChannel(registry, message);
|
|
4490
2310
|
if (!channel || !channel.isActive()) {
|
|
4491
2311
|
return;
|
|
4492
2312
|
}
|
|
@@ -4495,29 +2315,13 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4495
2315
|
logger.info(`${state.name} ignored message from ${channel.getName()}`);
|
|
4496
2316
|
return;
|
|
4497
2317
|
}
|
|
2318
|
+
if (!channel.getAcceptedTypes().includes(messageData.type)) {
|
|
2319
|
+
logger.info(`${state.name} dropped message type '${messageData.type}' not accepted by the ${channel.getName()} channel contract`);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
4498
2322
|
channel.notifyMessage(messageData);
|
|
4499
2323
|
}
|
|
4500
2324
|
|
|
4501
|
-
/**
|
|
4502
|
-
* Handles OPEN_CONNECTION action.
|
|
4503
|
-
* Completes handshake on responder's side and notifies open event.
|
|
4504
|
-
*
|
|
4505
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
4506
|
-
* @param message - Message event containing the OPEN_CONNECTION action
|
|
4507
|
-
*
|
|
4508
|
-
* @remarks
|
|
4509
|
-
* Side Effects:
|
|
4510
|
-
* - Terminates the connection process
|
|
4511
|
-
* - Extracts security confirmation (if present)
|
|
4512
|
-
* - Marks security as ready if security is active
|
|
4513
|
-
* - Fires 'open' lifecycle event on responder's side
|
|
4514
|
-
* - Fires 'security-ready' event if security transport is active
|
|
4515
|
-
*
|
|
4516
|
-
* @example Completing the three-way handshake
|
|
4517
|
-
* Final step of three-way handshake:
|
|
4518
|
-
* Responder receives OPEN (this handler) from Initiator
|
|
4519
|
-
* Both sides now have active connection
|
|
4520
|
-
*/
|
|
4521
2325
|
function handleOpen(context, message) {
|
|
4522
2326
|
const { state, processManager, logger } = context;
|
|
4523
2327
|
const action = message.data;
|
|
@@ -4545,33 +2349,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4545
2349
|
channel.notifyEvent('open', { origin: message.origin });
|
|
4546
2350
|
}
|
|
4547
2351
|
|
|
4548
|
-
/**
|
|
4549
|
-
* Protocol negotiation logic for security handshake.
|
|
4550
|
-
*
|
|
4551
|
-
* Implements the negotiation algorithm that determines the best
|
|
4552
|
-
* security protocol to use between two communicating parties.
|
|
4553
|
-
*
|
|
4554
|
-
* @module security/negotiation/negotiate
|
|
4555
|
-
*/
|
|
4556
|
-
/**
|
|
4557
|
-
* Negotiates the best security protocol between initiator and responder.
|
|
4558
|
-
*
|
|
4559
|
-
* The algorithm iterates through the initiator's supported protocols
|
|
4560
|
-
* (in preference order) and selects the first one that the responder
|
|
4561
|
-
* also supports. If no overlap is found, falls back to 'none'.
|
|
4562
|
-
*
|
|
4563
|
-
* @param request - The initiator's security negotiation request
|
|
4564
|
-
* @param responderSupported - Protocols supported by the responder
|
|
4565
|
-
* @returns The negotiation result with the selected protocol
|
|
4566
|
-
*
|
|
4567
|
-
* @example Negotiating security protocol
|
|
4568
|
-
* ```typescript
|
|
4569
|
-
* const request = { supported: ['v2', 'v1', 'none'], preferred: 'v2' }
|
|
4570
|
-
* const responderSupported = ['v1', 'none']
|
|
4571
|
-
* const result = negotiateProtocol(request, responderSupported)
|
|
4572
|
-
* // result.negotiated === 'v1' (first match from initiator's list)
|
|
4573
|
-
* ```
|
|
4574
|
-
*/
|
|
4575
2352
|
function negotiateProtocol(request, responderSupported) {
|
|
4576
2353
|
for (const protocol of request.supported) {
|
|
4577
2354
|
if (responderSupported.includes(protocol)) {
|
|
@@ -4586,55 +2363,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4586
2363
|
isPreferred: request.preferred === 'none',
|
|
4587
2364
|
};
|
|
4588
2365
|
}
|
|
4589
|
-
/**
|
|
4590
|
-
* Creates a security negotiation response for the responder.
|
|
4591
|
-
*
|
|
4592
|
-
* Builds a response object containing the negotiated protocol
|
|
4593
|
-
* and optional public parameters for protocol initialization.
|
|
4594
|
-
*
|
|
4595
|
-
* @param negotiated - The negotiated protocol version
|
|
4596
|
-
* @param publicParams - Optional public parameters (e.g., key exchange hints)
|
|
4597
|
-
* @returns A security negotiation response object
|
|
4598
|
-
*
|
|
4599
|
-
* @example Creating responder response
|
|
4600
|
-
* ```typescript
|
|
4601
|
-
* const response = createSecurityResponse('v2', { hint: 'value' })
|
|
4602
|
-
* // { negotiated: 'v2', publicParams: { hint: 'value' } }
|
|
4603
|
-
* ```
|
|
4604
|
-
*/
|
|
4605
2366
|
function createSecurityResponse(negotiated, publicParams) {
|
|
4606
2367
|
const response = { negotiated };
|
|
4607
2368
|
return freeze(response);
|
|
4608
2369
|
}
|
|
4609
2370
|
|
|
4610
|
-
/**
|
|
4611
|
-
* Default supported security protocols for the responder.
|
|
4612
|
-
* Includes 'none' as fallback for backward compatibility.
|
|
4613
|
-
*/
|
|
4614
2371
|
const DEFAULT_RESPONDER_SUPPORTED = ['none'];
|
|
4615
|
-
/**
|
|
4616
|
-
* Handles REQUEST_CONNECTION action.
|
|
4617
|
-
* Creates or retrieves channel and initiates connection handshake.
|
|
4618
|
-
*
|
|
4619
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
4620
|
-
* @param message - Message event containing the REQUEST_CONNECTION action
|
|
4621
|
-
*
|
|
4622
|
-
* @remarks
|
|
4623
|
-
* Side Effects:
|
|
4624
|
-
* - Creates new channel if not found in registry
|
|
4625
|
-
* - Tracks process ID for handshake completion
|
|
4626
|
-
* - Negotiates security protocol if security data present
|
|
4627
|
-
* - Sends ACCEPT_CONNECTION if validation passes
|
|
4628
|
-
* - Sends DENY_CONNECTION if contract or security policy fails
|
|
4629
|
-
*
|
|
4630
|
-
* @example Processing connection requests
|
|
4631
|
-
* Incoming action triggers:
|
|
4632
|
-
* 1. Channel lookup/creation
|
|
4633
|
-
* 2. Contract validation
|
|
4634
|
-
* 3. Security policy check
|
|
4635
|
-
* 4. Security protocol negotiation (if applicable)
|
|
4636
|
-
* 5. ACCEPT_CONNECTION response (or DENY if validation fails)
|
|
4637
|
-
*/
|
|
4638
2372
|
function handleRequest(context, message) {
|
|
4639
2373
|
const { state, registry, processManager, actions, logger } = context;
|
|
4640
2374
|
const action = message.data;
|
|
@@ -4719,22 +2453,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4719
2453
|
});
|
|
4720
2454
|
}
|
|
4721
2455
|
|
|
4722
|
-
/**
|
|
4723
|
-
* Security error handling utilities.
|
|
4724
|
-
*
|
|
4725
|
-
* Provides functions for handling, categorizing, and emitting security-related
|
|
4726
|
-
* errors during message encryption/decryption operations.
|
|
4727
|
-
*
|
|
4728
|
-
* @module security/errors
|
|
4729
|
-
*/
|
|
4730
|
-
/**
|
|
4731
|
-
* Security error class with additional metadata for programmatic handling.
|
|
4732
|
-
*
|
|
4733
|
-
* @example Creating security error
|
|
4734
|
-
* ```typescript
|
|
4735
|
-
* throw new SecurityError('Decryption failed', 'decryption_failed', originalError)
|
|
4736
|
-
* ```
|
|
4737
|
-
*/
|
|
4738
2456
|
class SecurityError extends Error {
|
|
4739
2457
|
code;
|
|
4740
2458
|
originalCause;
|
|
@@ -4746,25 +2464,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4746
2464
|
setPrototypeOf(this, SecurityError.prototype);
|
|
4747
2465
|
}
|
|
4748
2466
|
}
|
|
4749
|
-
/**
|
|
4750
|
-
* Creates security error event data from an error.
|
|
4751
|
-
*
|
|
4752
|
-
* Converts various error types into a standardized SecurityErrorEventData
|
|
4753
|
-
* structure for emitting via channel events.
|
|
4754
|
-
*
|
|
4755
|
-
* @param error - The error to convert
|
|
4756
|
-
* @returns Standardized security error event data
|
|
4757
|
-
*
|
|
4758
|
-
* @example Converting errors to event data
|
|
4759
|
-
* ```typescript
|
|
4760
|
-
* try {
|
|
4761
|
-
* decrypt(payload)
|
|
4762
|
-
* } catch (error) {
|
|
4763
|
-
* const eventData = createSecurityErrorEventData(error)
|
|
4764
|
-
* channel.notifyEvent('security-error', eventData)
|
|
4765
|
-
* }
|
|
4766
|
-
* ```
|
|
4767
|
-
*/
|
|
4768
2467
|
function createSecurityErrorEventData(error) {
|
|
4769
2468
|
if (error instanceof SecurityError) {
|
|
4770
2469
|
return {
|
|
@@ -4786,17 +2485,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4786
2485
|
code: 'unknown',
|
|
4787
2486
|
};
|
|
4788
2487
|
}
|
|
4789
|
-
/**
|
|
4790
|
-
* Categorizes an error into a security error code.
|
|
4791
|
-
*
|
|
4792
|
-
* Analyzes the error message to determine the appropriate category.
|
|
4793
|
-
* This is used when errors from network-protocol are caught.
|
|
4794
|
-
*
|
|
4795
|
-
* @param error - The error to categorize
|
|
4796
|
-
* @returns The appropriate security error code
|
|
4797
|
-
*
|
|
4798
|
-
* @internal
|
|
4799
|
-
*/
|
|
4800
2488
|
function categorizeError(error) {
|
|
4801
2489
|
const message = error.message.toLowerCase();
|
|
4802
2490
|
if (message.includes('decrypt') || message.includes('invalid key') || message.includes('corrupted') || message.includes('cipher')) {
|
|
@@ -4813,21 +2501,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4813
2501
|
}
|
|
4814
2502
|
return 'unknown';
|
|
4815
2503
|
}
|
|
4816
|
-
/**
|
|
4817
|
-
* Logs a security error with appropriate formatting.
|
|
4818
|
-
*
|
|
4819
|
-
* Uses logger.error for actual errors and logger.warn for
|
|
4820
|
-
* retryable/expected failures.
|
|
4821
|
-
*
|
|
4822
|
-
* @param logger - Logger instance to use for output
|
|
4823
|
-
* @param channelName - Name of the channel where error occurred
|
|
4824
|
-
* @param error - The security error event data containing message, code, and optional cause
|
|
4825
|
-
*
|
|
4826
|
-
* @example Logging security errors
|
|
4827
|
-
* ```typescript
|
|
4828
|
-
* logSecurityError(logger, 'my-channel', errorData)
|
|
4829
|
-
* ```
|
|
4830
|
-
*/
|
|
4831
2504
|
function logSecurityError(logger, channelName, error) {
|
|
4832
2505
|
const prefix = `${channelName} security error:`;
|
|
4833
2506
|
if (error.code === 'unknown') {
|
|
@@ -4838,37 +2511,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4838
2511
|
}
|
|
4839
2512
|
}
|
|
4840
2513
|
|
|
4841
|
-
/**
|
|
4842
|
-
* Route encrypted messages through security transport.
|
|
4843
|
-
*
|
|
4844
|
-
* Handles Uint8Array payloads received via postMessage, routing them
|
|
4845
|
-
* through the appropriate channel's security transport for decryption.
|
|
4846
|
-
*
|
|
4847
|
-
* @module broker/routing/route-encrypted-message
|
|
4848
|
-
*/
|
|
4849
|
-
/**
|
|
4850
|
-
* Routes an encrypted message to the appropriate channel for decryption.
|
|
4851
|
-
*
|
|
4852
|
-
* This function handles Uint8Array payloads received via postMessage:
|
|
4853
|
-
* 1. Identifies the target channel based on message origin
|
|
4854
|
-
* 2. Routes the encrypted payload through the channel's security transport
|
|
4855
|
-
* 3. The security transport decrypts and invokes the registered receive handler
|
|
4856
|
-
*
|
|
4857
|
-
* If no matching channel is found or the channel has no security transport,
|
|
4858
|
-
* the message is silently dropped (with optional debug logging).
|
|
4859
|
-
*
|
|
4860
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
4861
|
-
* @param router - Message router for handling decrypted actions
|
|
4862
|
-
* @param event - Message event containing the encrypted Uint8Array payload
|
|
4863
|
-
*
|
|
4864
|
-
* @example Routing encrypted payloads
|
|
4865
|
-
* ```typescript
|
|
4866
|
-
* // In broker's onMessage handler:
|
|
4867
|
-
* if (event.data instanceof Uint8Array) {
|
|
4868
|
-
* routeEncryptedMessage(routingContext, router, event)
|
|
4869
|
-
* }
|
|
4870
|
-
* ```
|
|
4871
|
-
*/
|
|
4872
2514
|
function routeEncryptedMessage(context, router, event) {
|
|
4873
2515
|
const { state, registry, logger } = context;
|
|
4874
2516
|
const origin = event?.origin;
|
|
@@ -4905,19 +2547,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4905
2547
|
channel.notifyEvent('security-error', errorData);
|
|
4906
2548
|
}
|
|
4907
2549
|
}
|
|
4908
|
-
/**
|
|
4909
|
-
* Finds a channel by origin in the registry.
|
|
4910
|
-
*
|
|
4911
|
-
* Since encrypted messages don't contain senderId, we must match
|
|
4912
|
-
* by origin. This works because each channel has a unique target window
|
|
4913
|
-
* and thus a unique origin.
|
|
4914
|
-
*
|
|
4915
|
-
* @param registry - Channel registry to search
|
|
4916
|
-
* @param origin - Origin of the message sender
|
|
4917
|
-
* @returns The matching channel handle, or undefined if not found
|
|
4918
|
-
*
|
|
4919
|
-
* @internal
|
|
4920
|
-
*/
|
|
4921
2550
|
function findChannelByOrigin(registry, origin) {
|
|
4922
2551
|
const allChannels = getAll(registry);
|
|
4923
2552
|
for (const channel of allChannels) {
|
|
@@ -4936,30 +2565,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4936
2565
|
return undefined;
|
|
4937
2566
|
}
|
|
4938
2567
|
|
|
4939
|
-
/**
|
|
4940
|
-
* Logs an action in a structured format.
|
|
4941
|
-
*
|
|
4942
|
-
* @param logger - Logger instance
|
|
4943
|
-
* @param action - Action to log
|
|
4944
|
-
* @param direction - Direction of action ('sent' or 'received')
|
|
4945
|
-
*/
|
|
4946
2568
|
function logAction(logger, action, direction) {
|
|
4947
2569
|
logger.debug(`Action ${direction}:`, action.type, action);
|
|
4948
2570
|
}
|
|
4949
2571
|
|
|
4950
|
-
/**
|
|
4951
|
-
* Routes a message to the appropriate handler.
|
|
4952
|
-
*
|
|
4953
|
-
* @param router - Handler map containing action type to handler mappings
|
|
4954
|
-
* @param context - Routing context with state, registry, actions, and logger
|
|
4955
|
-
* @param message - Incoming message event containing the action to route
|
|
4956
|
-
*
|
|
4957
|
-
* @example Routing actions to handlers
|
|
4958
|
-
* ```typescript
|
|
4959
|
-
* const router = createRouter({ 'MESSAGE': handleMessage })
|
|
4960
|
-
* routeMessage(router, routingContext, incomingEvent)
|
|
4961
|
-
* ```
|
|
4962
|
-
*/
|
|
4963
2572
|
function routeMessage(router, context, message) {
|
|
4964
2573
|
const { logger } = context;
|
|
4965
2574
|
try {
|
|
@@ -4982,26 +2591,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
4982
2591
|
}
|
|
4983
2592
|
}
|
|
4984
2593
|
|
|
4985
|
-
/**
|
|
4986
|
-
* Filters message origin against whitelist/blacklist
|
|
4987
|
-
*
|
|
4988
|
-
* @param origin - The origin to check
|
|
4989
|
-
* @param whitelist - List of allowed origins (takes precedence)
|
|
4990
|
-
* @param blacklist - List of blocked origins
|
|
4991
|
-
* @returns true if origin is allowed, false otherwise
|
|
4992
|
-
*
|
|
4993
|
-
* @example Filtering with a whitelist
|
|
4994
|
-
* ```typescript
|
|
4995
|
-
* filterOrigin('https://app.example.com', ['https://app.example.com'])
|
|
4996
|
-
* // => true
|
|
4997
|
-
* ```
|
|
4998
|
-
*
|
|
4999
|
-
* @example Filtering with a blacklist
|
|
5000
|
-
* ```typescript
|
|
5001
|
-
* filterOrigin('https://untrusted.com', [], ['https://untrusted.com'])
|
|
5002
|
-
* // => false
|
|
5003
|
-
* ```
|
|
5004
|
-
*/
|
|
5005
2594
|
function filterOrigin(origin, whitelist = [], blacklist = []) {
|
|
5006
2595
|
if (whitelist && whitelist.length > 0) {
|
|
5007
2596
|
return whitelist.includes(origin);
|
|
@@ -5012,53 +2601,21 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5012
2601
|
return true;
|
|
5013
2602
|
}
|
|
5014
2603
|
|
|
5015
|
-
/**
|
|
5016
|
-
* Validates that a security policy is a function
|
|
5017
|
-
*
|
|
5018
|
-
* @param policy - The policy to validate
|
|
5019
|
-
* @throws {Error} If policy is not a function
|
|
5020
|
-
*
|
|
5021
|
-
* @example Valid policy function
|
|
5022
|
-
* ```typescript
|
|
5023
|
-
* validatePolicy((event) => event.origin === 'https://trusted.com')
|
|
5024
|
-
* // No error thrown
|
|
5025
|
-
* ```
|
|
5026
|
-
*
|
|
5027
|
-
* @example Invalid policy throws
|
|
5028
|
-
* ```typescript
|
|
5029
|
-
* validatePolicy('not-a-function')
|
|
5030
|
-
* // Throws: Security policy must be a function...
|
|
5031
|
-
* ```
|
|
5032
|
-
*/
|
|
5033
2604
|
function validatePolicy(policy) {
|
|
5034
2605
|
if (typeof policy !== 'function') {
|
|
5035
2606
|
throw createError('Security policy must be a function that returns true or false.');
|
|
5036
2607
|
}
|
|
5037
2608
|
}
|
|
5038
2609
|
|
|
5039
|
-
/**
|
|
5040
|
-
* Creates a message broker instance
|
|
5041
|
-
*
|
|
5042
|
-
* @param config - Broker configuration
|
|
5043
|
-
* @param config.name - Unique name for the broker instance
|
|
5044
|
-
* @param config.contract - Channel contract defining message protocols
|
|
5045
|
-
* @param config.settings - Optional configuration overrides for broker behavior
|
|
5046
|
-
* @returns Broker handle with public API
|
|
5047
|
-
*
|
|
5048
|
-
* @example Creating a message broker
|
|
5049
|
-
* ```typescript
|
|
5050
|
-
* const broker = createBroker({
|
|
5051
|
-
* name: 'app-broker',
|
|
5052
|
-
* contract: { messages: { ping: {}, pong: {} } },
|
|
5053
|
-
* settings: { logLevel: 'warn' },
|
|
5054
|
-
* })
|
|
5055
|
-
* ```
|
|
5056
|
-
*/
|
|
5057
2610
|
function createBroker(config) {
|
|
5058
2611
|
assertNoCircularRef(config.contract, 'config.contract');
|
|
5059
2612
|
assertNoCircularRef(config.settings, 'config.settings');
|
|
5060
2613
|
validateName(config.name);
|
|
5061
2614
|
validateContract$1(config.contract);
|
|
2615
|
+
const brokerWindow = config.window ?? (typeof window !== 'undefined' ? window : undefined);
|
|
2616
|
+
if (!brokerWindow) {
|
|
2617
|
+
throw createError('Cannot create broker: no window is available. Pass an explicit `window` in the broker config when running outside a browser environment.');
|
|
2618
|
+
}
|
|
5062
2619
|
const mergedSettings = {
|
|
5063
2620
|
...defaultBrokerSettings,
|
|
5064
2621
|
...config.settings,
|
|
@@ -5072,7 +2629,7 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5072
2629
|
const state = {
|
|
5073
2630
|
id: uuidV4(),
|
|
5074
2631
|
name: config.name,
|
|
5075
|
-
window:
|
|
2632
|
+
window: brokerWindow,
|
|
5076
2633
|
contract: config.contract,
|
|
5077
2634
|
settings: mergedSettings,
|
|
5078
2635
|
logger,
|
|
@@ -5125,10 +2682,7 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5125
2682
|
}
|
|
5126
2683
|
routeMessage(router, routingContext, event);
|
|
5127
2684
|
};
|
|
5128
|
-
|
|
5129
|
-
if (typeof window !== 'undefined') {
|
|
5130
|
-
window.addEventListener('message', onMessage);
|
|
5131
|
-
}
|
|
2685
|
+
brokerWindow.addEventListener('message', onMessage);
|
|
5132
2686
|
const broker = {
|
|
5133
2687
|
id: state.id,
|
|
5134
2688
|
name: state.name,
|
|
@@ -5197,10 +2751,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5197
2751
|
return freeze(broker);
|
|
5198
2752
|
}
|
|
5199
2753
|
|
|
5200
|
-
/**
|
|
5201
|
-
* Default contract allowing any message type.
|
|
5202
|
-
* Useful for development and prototyping.
|
|
5203
|
-
*/
|
|
5204
2754
|
const DEFAULT_CONTRACT = freeze({
|
|
5205
2755
|
emitted: freeze([
|
|
5206
2756
|
{ type: 'MESSAGE', description: 'Generic message' },
|
|
@@ -5214,49 +2764,36 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5214
2764
|
{ type: 'ACK', description: 'Acknowledgment' },
|
|
5215
2765
|
]),
|
|
5216
2766
|
});
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
2767
|
+
|
|
2768
|
+
const _Reflect$1 = globalThis.Reflect;
|
|
2769
|
+
const get = _Reflect$1.get;
|
|
2770
|
+
const has = _Reflect$1.has;
|
|
2771
|
+
const ownKeys = _Reflect$1.ownKeys;
|
|
2772
|
+
const getOwnPropertyDescriptor = _Reflect$1.getOwnPropertyDescriptor;
|
|
2773
|
+
|
|
2774
|
+
let instance = null;
|
|
2775
|
+
function resolveBroker() {
|
|
2776
|
+
if (!instance) {
|
|
2777
|
+
instance = createBroker({
|
|
2778
|
+
name: 'default-broker',
|
|
2779
|
+
contract: DEFAULT_CONTRACT,
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
return instance;
|
|
2783
|
+
}
|
|
2784
|
+
new Proxy({}, {
|
|
2785
|
+
get: (_target, property) => get(resolveBroker(), property),
|
|
2786
|
+
has: (_target, property) => has(resolveBroker(), property),
|
|
2787
|
+
ownKeys: () => ownKeys(resolveBroker()),
|
|
2788
|
+
getOwnPropertyDescriptor: (_target, property) => {
|
|
2789
|
+
const descriptor = getOwnPropertyDescriptor(resolveBroker(), property);
|
|
2790
|
+
return descriptor ? { ...descriptor, configurable: true } : undefined;
|
|
2791
|
+
},
|
|
5238
2792
|
});
|
|
5239
2793
|
|
|
5240
|
-
// note: Runtime validation shared by the host/hostee factories and the config loader.
|
|
5241
|
-
/**
|
|
5242
|
-
* Narrows an unknown value to a non-null object.
|
|
5243
|
-
*
|
|
5244
|
-
* @param value - The value to test.
|
|
5245
|
-
* @returns `true` when the value is a non-null, non-array object.
|
|
5246
|
-
*/
|
|
5247
2794
|
function isRecord(value) {
|
|
5248
2795
|
return typeof value === 'object' && value !== null && !isArray(value);
|
|
5249
2796
|
}
|
|
5250
|
-
/**
|
|
5251
|
-
* Collects every problem with a single action list (`emitted` or `accepted`).
|
|
5252
|
-
*
|
|
5253
|
-
* Each malformed entry contributes its own message, distinguishing a non-object
|
|
5254
|
-
* entry from one missing a usable `type`, so the caller can report them all at once.
|
|
5255
|
-
*
|
|
5256
|
-
* @param actions - The candidate action list.
|
|
5257
|
-
* @param field - The field name, used to locate problems in messages.
|
|
5258
|
-
* @param issues - The running list of human-readable problems, appended to in place.
|
|
5259
|
-
*/
|
|
5260
2797
|
function collectActionListIssues(actions, field, issues) {
|
|
5261
2798
|
if (!isArray(actions)) {
|
|
5262
2799
|
issues.push(`"${field}" must be an array.`);
|
|
@@ -5270,14 +2807,21 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5270
2807
|
if (typeof action['type'] !== 'string' || action['type'].length === 0) {
|
|
5271
2808
|
issues.push(`"${field}[${index}]" must have a non-empty string "type".`);
|
|
5272
2809
|
}
|
|
2810
|
+
if (action['respondsWith'] !== undefined && (typeof action['respondsWith'] !== 'string' || action['respondsWith'].length === 0)) {
|
|
2811
|
+
issues.push(`"${field}[${index}]" has a "respondsWith" that must be a non-empty string.`);
|
|
2812
|
+
}
|
|
2813
|
+
});
|
|
2814
|
+
}
|
|
2815
|
+
function collectRespondsWithIssues(actions, field, other, otherField, issues) {
|
|
2816
|
+
actions.forEach((action, index) => {
|
|
2817
|
+
if (action.respondsWith === undefined) {
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2820
|
+
if (!other.some((candidate) => candidate.type === action.respondsWith)) {
|
|
2821
|
+
issues.push(`"${field}[${index}]" responds with "${action.respondsWith}", but "${otherField}" has no action of that type.`);
|
|
2822
|
+
}
|
|
5273
2823
|
});
|
|
5274
2824
|
}
|
|
5275
|
-
/**
|
|
5276
|
-
* Names the kind of an unexpected value for an error message.
|
|
5277
|
-
*
|
|
5278
|
-
* @param value - The value to describe.
|
|
5279
|
-
* @returns A short label such as `null`, `an array`, or `a number`.
|
|
5280
|
-
*/
|
|
5281
2825
|
function describeType(value) {
|
|
5282
2826
|
if (value === null) {
|
|
5283
2827
|
return 'null';
|
|
@@ -5287,22 +2831,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5287
2831
|
}
|
|
5288
2832
|
return `a ${typeof value}`;
|
|
5289
2833
|
}
|
|
5290
|
-
/**
|
|
5291
|
-
* Validates an unknown value as a {@link FeatureContract}.
|
|
5292
|
-
*
|
|
5293
|
-
* Reports every malformed action at once rather than stopping at the first, so a
|
|
5294
|
-
* single error message lists all the problems to fix.
|
|
5295
|
-
*
|
|
5296
|
-
* @param contract - The candidate contract, typically parsed from disk.
|
|
5297
|
-
* @returns The validated contract, typed.
|
|
5298
|
-
* @throws {Error} When the value is not an object, or any action is malformed.
|
|
5299
|
-
*
|
|
5300
|
-
* @example Validating a parsed contract file
|
|
5301
|
-
* ```typescript
|
|
5302
|
-
* const contract = validateContract(parse(readFileSync('clock.contract.json', 'utf8')))
|
|
5303
|
-
* contract.emitted.forEach((action) => console.log(action.type))
|
|
5304
|
-
* ```
|
|
5305
|
-
*/
|
|
5306
2834
|
function validateContract(contract) {
|
|
5307
2835
|
if (!isRecord(contract)) {
|
|
5308
2836
|
throw createError(`Invalid contract: expected an object with "emitted" and "accepted" arrays, but got ${describeType(contract)}.`);
|
|
@@ -5310,6 +2838,12 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5310
2838
|
const issues = [];
|
|
5311
2839
|
collectActionListIssues(contract['emitted'], 'emitted', issues);
|
|
5312
2840
|
collectActionListIssues(contract['accepted'], 'accepted', issues);
|
|
2841
|
+
if (issues.length === 0) {
|
|
2842
|
+
const emitted = contract['emitted'];
|
|
2843
|
+
const accepted = contract['accepted'];
|
|
2844
|
+
collectRespondsWithIssues(emitted, 'emitted', accepted, 'accepted', issues);
|
|
2845
|
+
collectRespondsWithIssues(accepted, 'accepted', emitted, 'emitted', issues);
|
|
2846
|
+
}
|
|
5313
2847
|
if (issues.length > 0) {
|
|
5314
2848
|
throw createError(`Invalid contract:\n${issues.map((issue) => ` - ${issue}`).join('\n')}`);
|
|
5315
2849
|
}
|
|
@@ -5319,47 +2853,29 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5319
2853
|
};
|
|
5320
2854
|
}
|
|
5321
2855
|
|
|
5322
|
-
|
|
5323
|
-
* Internal control message types carried on the feature channel and hidden from consumers.
|
|
5324
|
-
*/
|
|
2856
|
+
const CONTROL_PREFIX = '__hf:';
|
|
5325
2857
|
const ControlType = freeze({
|
|
5326
|
-
/** Hostee-to-host liveness beat. */
|
|
5327
2858
|
Beat: '__hf:beat',
|
|
5328
|
-
/** Hostee-to-host content-size announcement. */
|
|
5329
2859
|
Size: '__hf:size',
|
|
2860
|
+
Request: '__hf:request',
|
|
2861
|
+
Response: '__hf:response',
|
|
5330
2862
|
});
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
* @param contract - The consumer-facing feature contract.
|
|
5335
|
-
* @returns A contract that additionally permits the reserved control types.
|
|
5336
|
-
*
|
|
5337
|
-
* @example Building a broker contract that carries the control plane
|
|
5338
|
-
* ```typescript
|
|
5339
|
-
* const broker = createBroker({ name, contract: withControlContract(contract) })
|
|
5340
|
-
* ```
|
|
5341
|
-
*/
|
|
2863
|
+
function isControlType(type) {
|
|
2864
|
+
return type.startsWith(CONTROL_PREFIX);
|
|
2865
|
+
}
|
|
5342
2866
|
function withControlContract(contract) {
|
|
5343
|
-
|
|
2867
|
+
const controlActions = () => [
|
|
2868
|
+
{ type: ControlType.Beat },
|
|
2869
|
+
{ type: ControlType.Size },
|
|
2870
|
+
{ type: ControlType.Request },
|
|
2871
|
+
{ type: ControlType.Response },
|
|
2872
|
+
];
|
|
5344
2873
|
return {
|
|
5345
|
-
emitted: [...contract.emitted,
|
|
5346
|
-
accepted: [...contract.accepted,
|
|
2874
|
+
emitted: [...contract.emitted, ...controlActions()],
|
|
2875
|
+
accepted: [...contract.accepted, ...controlActions()],
|
|
5347
2876
|
};
|
|
5348
2877
|
}
|
|
5349
2878
|
|
|
5350
|
-
/**
|
|
5351
|
-
* Creates an {@link EventEmitter} backed by a plain registry.
|
|
5352
|
-
*
|
|
5353
|
-
* @returns A frozen emitter instance.
|
|
5354
|
-
*
|
|
5355
|
-
* @example Subscribing and emitting
|
|
5356
|
-
* ```typescript
|
|
5357
|
-
* const emitter = createEventEmitter()
|
|
5358
|
-
* const off = emitter.on('open', () => console.log('opened'))
|
|
5359
|
-
* emitter.emit('open')
|
|
5360
|
-
* off()
|
|
5361
|
-
* ```
|
|
5362
|
-
*/
|
|
5363
2879
|
function createEventEmitter() {
|
|
5364
2880
|
const registry = {};
|
|
5365
2881
|
const on = (event, handler) => {
|
|
@@ -5375,111 +2891,111 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5375
2891
|
return freeze({ on, emit });
|
|
5376
2892
|
}
|
|
5377
2893
|
|
|
5378
|
-
/**
|
|
5379
|
-
* Safe Promise factory and bound static methods.
|
|
5380
|
-
*
|
|
5381
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/promise
|
|
5382
|
-
*/
|
|
5383
|
-
/* eslint-disable workspace/lib-require-jsdoc-example */
|
|
5384
2894
|
const _Promise = globalThis.Promise;
|
|
5385
2895
|
const _Reflect = globalThis.Reflect;
|
|
5386
|
-
/**
|
|
5387
|
-
* (Safe copy) Creates a new Promise using the captured Promise constructor.
|
|
5388
|
-
* Use this instead of `new Promise()`.
|
|
5389
|
-
*
|
|
5390
|
-
* @param executor - The executor function.
|
|
5391
|
-
* @returns A new Promise instance.
|
|
5392
|
-
*/
|
|
5393
2896
|
const createPromise = (executor) => _Reflect.construct(_Promise, [executor]);
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
*/
|
|
5397
|
-
_Promise.resolve.bind(_Promise);
|
|
5398
|
-
/**
|
|
5399
|
-
* (Safe copy) Returns a Promise that rejects with the given reason.
|
|
5400
|
-
*/
|
|
5401
|
-
_Promise.reject.bind(_Promise);
|
|
5402
|
-
/**
|
|
5403
|
-
* (Safe copy) Returns a Promise that resolves when all promises resolve.
|
|
5404
|
-
*/
|
|
2897
|
+
const promiseResolve = _Promise.resolve.bind(_Promise);
|
|
2898
|
+
const promiseReject = _Promise.reject.bind(_Promise);
|
|
5405
2899
|
_Promise.all.bind(_Promise);
|
|
5406
|
-
/**
|
|
5407
|
-
* (Safe copy) Returns a Promise that resolves/rejects with the first settled promise.
|
|
5408
|
-
*/
|
|
5409
2900
|
_Promise.race.bind(_Promise);
|
|
5410
|
-
/**
|
|
5411
|
-
* (Safe copy) Returns a Promise that resolves when all promises settle.
|
|
5412
|
-
*/
|
|
5413
2901
|
_Promise.allSettled.bind(_Promise);
|
|
5414
|
-
/**
|
|
5415
|
-
* (Safe copy) Returns a Promise that resolves with the first fulfilled promise.
|
|
5416
|
-
*/
|
|
5417
2902
|
_Promise.any.bind(_Promise);
|
|
5418
|
-
/**
|
|
5419
|
-
* (Safe copy) Creates a Promise along with its resolve and reject functions.
|
|
5420
|
-
* Note: Available only in ES2024+ environments.
|
|
5421
|
-
*/
|
|
5422
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5423
2903
|
_Promise.withResolvers?.bind(_Promise);
|
|
5424
2904
|
|
|
5425
|
-
|
|
5426
|
-
* Safe copies of Timer/Scheduling built-in functions.
|
|
5427
|
-
*
|
|
5428
|
-
* These references are captured at module initialization time to protect against
|
|
5429
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
5430
|
-
*
|
|
5431
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/timers
|
|
5432
|
-
*/
|
|
2905
|
+
const _setTimeout = globalThis.setTimeout;
|
|
5433
2906
|
const _setInterval = globalThis.setInterval;
|
|
2907
|
+
const _clearTimeout = globalThis.clearTimeout;
|
|
5434
2908
|
const _clearInterval = globalThis.clearInterval;
|
|
5435
|
-
|
|
5436
|
-
* (Safe copy) Repeatedly calls a function with a fixed time delay between each call.
|
|
5437
|
-
*
|
|
5438
|
-
* @param callback - Function to call at each interval.
|
|
5439
|
-
* @param delay - Time in milliseconds between calls.
|
|
5440
|
-
* @param args - Additional arguments to pass to the callback.
|
|
5441
|
-
* @returns A numeric ID for the interval.
|
|
5442
|
-
*
|
|
5443
|
-
* @example Setting an interval
|
|
5444
|
-
* ```typescript
|
|
5445
|
-
* let count = 0
|
|
5446
|
-
* const intervalId = setInterval(() => {
|
|
5447
|
-
* count++
|
|
5448
|
-
* if (count >= 5) clearInterval(intervalId)
|
|
5449
|
-
* }, 1000)
|
|
5450
|
-
* ```
|
|
5451
|
-
*/
|
|
2909
|
+
const setTimeout = (callback, delay, ...args) => _setTimeout(callback, delay, ...args);
|
|
5452
2910
|
const setInterval = (callback, delay, ...args) => _setInterval(callback, delay, ...args);
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
* @param id - The identifier of the interval to cancel.
|
|
5457
|
-
*
|
|
5458
|
-
* @example Canceling an interval
|
|
5459
|
-
* ```typescript
|
|
5460
|
-
* const intervalId = setInterval(() => console.log('tick'), 1000)
|
|
5461
|
-
* // Stop after some condition
|
|
5462
|
-
* clearInterval(intervalId)
|
|
5463
|
-
* ```
|
|
5464
|
-
*/
|
|
2911
|
+
const clearTimeout = (id) => {
|
|
2912
|
+
_clearTimeout(id);
|
|
2913
|
+
};
|
|
5465
2914
|
const clearInterval = (id) => {
|
|
5466
2915
|
_clearInterval(id);
|
|
5467
2916
|
};
|
|
5468
2917
|
|
|
5469
|
-
|
|
2918
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
2919
|
+
function createRequestPeer(origin, send) {
|
|
2920
|
+
let pending = {};
|
|
2921
|
+
const handlers = {};
|
|
2922
|
+
let nextCorrelation = 0;
|
|
2923
|
+
const take = (correlationId) => {
|
|
2924
|
+
const entry = pending[correlationId];
|
|
2925
|
+
if (entry) {
|
|
2926
|
+
clearTimeout(entry.timer);
|
|
2927
|
+
delete pending[correlationId];
|
|
2928
|
+
}
|
|
2929
|
+
return entry;
|
|
2930
|
+
};
|
|
2931
|
+
const respond = (request, outcome) => send(ControlType.Response, { correlationId: request.correlationId, from: origin, innerType: request.innerType, ...outcome });
|
|
2932
|
+
const answer = (request) => {
|
|
2933
|
+
const handler = handlers[request.innerType];
|
|
2934
|
+
if (!handler) {
|
|
2935
|
+
respond(request, { ok: false, error: `No handler is registered for '${request.innerType}'.` });
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
promiseResolve()
|
|
2939
|
+
.then(() => handler(request.payload))
|
|
2940
|
+
.then((payload) => respond(request, { ok: true, payload }), (error) => respond(request, { ok: false, error: error instanceof Error ? error.message : `${error}` }));
|
|
2941
|
+
};
|
|
2942
|
+
const settle = (response) => {
|
|
2943
|
+
const entry = take(response.correlationId);
|
|
2944
|
+
if (!entry) {
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
if (response.ok) {
|
|
2948
|
+
entry.resolve(response.payload);
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
entry.reject(createError(response.error ?? `Request '${response.innerType}' failed.`));
|
|
2952
|
+
};
|
|
2953
|
+
const dispatch = (type, data) => {
|
|
2954
|
+
const envelope = (typeof data === 'object' ? data : null);
|
|
2955
|
+
if (!envelope || envelope.from === origin) {
|
|
2956
|
+
return;
|
|
2957
|
+
}
|
|
2958
|
+
if (type === ControlType.Request) {
|
|
2959
|
+
answer(envelope);
|
|
2960
|
+
return;
|
|
2961
|
+
}
|
|
2962
|
+
if (type === ControlType.Response) {
|
|
2963
|
+
settle(envelope);
|
|
2964
|
+
}
|
|
2965
|
+
};
|
|
2966
|
+
const request = (type, data, options) => createPromise((resolve, reject) => {
|
|
2967
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2968
|
+
const correlationId = `${origin}-${(nextCorrelation += 1)}`;
|
|
2969
|
+
const timer = setTimeout(() => {
|
|
2970
|
+
delete pending[correlationId];
|
|
2971
|
+
reject(createError(`Request '${type}' timed out after ${timeoutMs}ms.`));
|
|
2972
|
+
}, timeoutMs);
|
|
2973
|
+
pending[correlationId] = { resolve, reject, timer };
|
|
2974
|
+
send(ControlType.Request, { correlationId, from: origin, innerType: type, payload: data });
|
|
2975
|
+
});
|
|
2976
|
+
const handle = (type, handler) => {
|
|
2977
|
+
if (handlers[type]) {
|
|
2978
|
+
throw createError(`A handler for '${type}' is already registered.`);
|
|
2979
|
+
}
|
|
2980
|
+
handlers[type] = handler;
|
|
2981
|
+
return () => {
|
|
2982
|
+
if (handlers[type] === handler) {
|
|
2983
|
+
delete handlers[type];
|
|
2984
|
+
}
|
|
2985
|
+
};
|
|
2986
|
+
};
|
|
2987
|
+
const rejectAll = (reason) => {
|
|
2988
|
+
const failed = values(pending);
|
|
2989
|
+
pending = {};
|
|
2990
|
+
for (const entry of failed) {
|
|
2991
|
+
clearTimeout(entry.timer);
|
|
2992
|
+
entry.reject(createError(reason));
|
|
2993
|
+
}
|
|
2994
|
+
};
|
|
2995
|
+
return freeze({ request, handle, dispatch, rejectAll });
|
|
2996
|
+
}
|
|
2997
|
+
|
|
5470
2998
|
const BEAT_INTERVAL_MS = 1000;
|
|
5471
|
-
/**
|
|
5472
|
-
* Creates the hostee-side heartbeat emitter.
|
|
5473
|
-
*
|
|
5474
|
-
* @param send - The control-channel send function (receives the reserved beat type).
|
|
5475
|
-
* @returns A start/stop handle for the beat loop.
|
|
5476
|
-
*
|
|
5477
|
-
* @example Pulsing the host while connected
|
|
5478
|
-
* ```typescript
|
|
5479
|
-
* const heartbeat = createHeartbeatEmitter((type) => channel.send(type))
|
|
5480
|
-
* heartbeat.start()
|
|
5481
|
-
* ```
|
|
5482
|
-
*/
|
|
5483
2999
|
function createHeartbeatEmitter(send) {
|
|
5484
3000
|
let timer;
|
|
5485
3001
|
return {
|
|
@@ -5496,24 +3012,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5496
3012
|
};
|
|
5497
3013
|
}
|
|
5498
3014
|
|
|
5499
|
-
/**
|
|
5500
|
-
* Observes an element for size changes and triggers a callback when resized.
|
|
5501
|
-
*
|
|
5502
|
-
* @param element - The element to observe for resize events
|
|
5503
|
-
* @param callback - The function to call when the element is resized
|
|
5504
|
-
* @returns A cleanup function to stop observing the element
|
|
5505
|
-
*
|
|
5506
|
-
* @example Observing element resize
|
|
5507
|
-
* ```typescript
|
|
5508
|
-
* const container = document.getElementById('resizable-panel')
|
|
5509
|
-
* const stopObserving = onElementResize(container, (rect) => {
|
|
5510
|
-
* console.log(`New size: ${rect.width}x${rect.height}`)
|
|
5511
|
-
* })
|
|
5512
|
-
*
|
|
5513
|
-
* // Stop observing when done
|
|
5514
|
-
* stopObserving()
|
|
5515
|
-
* ```
|
|
5516
|
-
*/
|
|
5517
3015
|
function onElementResize(element, callback) {
|
|
5518
3016
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
5519
3017
|
for (const entry of entries) {
|
|
@@ -5530,25 +3028,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5530
3028
|
};
|
|
5531
3029
|
}
|
|
5532
3030
|
|
|
5533
|
-
/**
|
|
5534
|
-
* Converts a CSS object into a CSS string suitable for inline styles or style sheets.
|
|
5535
|
-
* Automatically converts camelCase properties to kebab-case.
|
|
5536
|
-
*
|
|
5537
|
-
* @param cssObj - The CSS object with property-value pairs
|
|
5538
|
-
* @returns A CSS string representation
|
|
5539
|
-
*
|
|
5540
|
-
* @example Converting style object to CSS
|
|
5541
|
-
* ```typescript
|
|
5542
|
-
* const styles = {
|
|
5543
|
-
* backgroundColor: '#f0f0f0',
|
|
5544
|
-
* fontSize: '14px',
|
|
5545
|
-
* marginTop: '8px'
|
|
5546
|
-
* }
|
|
5547
|
-
*
|
|
5548
|
-
* cssObjectToString(styles)
|
|
5549
|
-
* // => 'background-color: #f0f0f0; font-size: 14px; margin-top: 8px; '
|
|
5550
|
-
* ```
|
|
5551
|
-
*/
|
|
5552
3031
|
function cssObjectToString(cssObj) {
|
|
5553
3032
|
const errors = [];
|
|
5554
3033
|
const cssString = entries(cssObj).reduce((prev, [property, value]) => {
|
|
@@ -5568,24 +3047,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5568
3047
|
return cssString;
|
|
5569
3048
|
}
|
|
5570
3049
|
|
|
5571
|
-
/**
|
|
5572
|
-
* Validates whether a string is a valid CSS selector by attempting to query with it.
|
|
5573
|
-
*
|
|
5574
|
-
* @param selector - The CSS selector string to validate
|
|
5575
|
-
* @returns True if the selector is valid, false otherwise
|
|
5576
|
-
*
|
|
5577
|
-
* @example Validating CSS selectors
|
|
5578
|
-
* ```typescript
|
|
5579
|
-
* isValidCssSelector('.my-class')
|
|
5580
|
-
* // => true
|
|
5581
|
-
*
|
|
5582
|
-
* isValidCssSelector('#header nav > ul')
|
|
5583
|
-
* // => true
|
|
5584
|
-
*
|
|
5585
|
-
* isValidCssSelector('[invalid')
|
|
5586
|
-
* // => false
|
|
5587
|
-
* ```
|
|
5588
|
-
*/
|
|
5589
3050
|
function isValidCssSelector(selector) {
|
|
5590
3051
|
try {
|
|
5591
3052
|
document.createDocumentFragment().querySelector(selector);
|
|
@@ -5596,31 +3057,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5596
3057
|
}
|
|
5597
3058
|
}
|
|
5598
3059
|
|
|
5599
|
-
/**
|
|
5600
|
-
* Generates a CSS rule string from a given selector and style declaration.
|
|
5601
|
-
*
|
|
5602
|
-
* This function takes a CSS selector and either a string or a CSSStyleDeclaration object
|
|
5603
|
-
* representing the styles to be applied. It validates the selector and converts the CSS
|
|
5604
|
-
* object to a string if needed. The function then constructs and returns a valid
|
|
5605
|
-
* CSS rule as a string.
|
|
5606
|
-
*
|
|
5607
|
-
* @param selector - The CSS selector to which the styles will be applied
|
|
5608
|
-
* @param css - The styles to apply, either as a string or CSSStyleDeclaration object
|
|
5609
|
-
* @returns A string representing a complete CSS rule
|
|
5610
|
-
* @throws {Error} When the selector is invalid or the css argument is not a valid string or object
|
|
5611
|
-
*
|
|
5612
|
-
* @example With style object
|
|
5613
|
-
* ```typescript
|
|
5614
|
-
* cssRule('.button', { padding: '8px 16px', borderRadius: '4px' })
|
|
5615
|
-
* // => '.button{padding: 8px 16px; border-radius: 4px}'
|
|
5616
|
-
* ```
|
|
5617
|
-
*
|
|
5618
|
-
* @example With CSS string
|
|
5619
|
-
* ```typescript
|
|
5620
|
-
* cssRule('.button:hover', 'background-color: #007bff; color: white')
|
|
5621
|
-
* // => '.button:hover{background-color: #007bff; color: white}'
|
|
5622
|
-
* ```
|
|
5623
|
-
*/
|
|
5624
3060
|
function cssRule(selector, css) {
|
|
5625
3061
|
if (!isValidCssSelector(selector)) {
|
|
5626
3062
|
throw createError('A valid css select must be provided');
|
|
@@ -5634,23 +3070,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5634
3070
|
return `${selector}{${css}}`;
|
|
5635
3071
|
}
|
|
5636
3072
|
|
|
5637
|
-
/**
|
|
5638
|
-
* Creates CSS rules from a styles object, converting each selector-style pair into CSS rule strings.
|
|
5639
|
-
*
|
|
5640
|
-
* @param styles - An object mapping CSS selectors to style objects
|
|
5641
|
-
* @returns A string containing all CSS rules separated by newlines
|
|
5642
|
-
*
|
|
5643
|
-
* @example Creating CSS rules from object
|
|
5644
|
-
* ```typescript
|
|
5645
|
-
* const styles = {
|
|
5646
|
-
* '.card': { padding: '16px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' },
|
|
5647
|
-
* '.card-title': { fontSize: '18px', fontWeight: 'bold' }
|
|
5648
|
-
* }
|
|
5649
|
-
*
|
|
5650
|
-
* cssRules(styles)
|
|
5651
|
-
* // => '.card{padding: 16px; box-shadow: 0 2px 4px rgba(0,0,0,0.1)}\n.card-title{font-size: 18px; font-weight: bold}'
|
|
5652
|
-
* ```
|
|
5653
|
-
*/
|
|
5654
3073
|
function cssRules(styles) {
|
|
5655
3074
|
if (getType(styles) !== 'object')
|
|
5656
3075
|
return '';
|
|
@@ -5663,33 +3082,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5663
3082
|
const labels = createSet();
|
|
5664
3083
|
const labeledStylesheets = createMap();
|
|
5665
3084
|
const stylesheetLabels = createWeakMap();
|
|
5666
|
-
/**
|
|
5667
|
-
* Adds a new stylesheet to the document with optional label.
|
|
5668
|
-
*
|
|
5669
|
-
* @param css - The CSS rules to be added in the new stylesheet
|
|
5670
|
-
* @param label - Optional label for the new stylesheet
|
|
5671
|
-
* @returns A tuple where the first item is the created HTMLStyleElement, and the second item is a cleanup function
|
|
5672
|
-
* @throws {Error} When css is not a string or StyleMap, is empty, or a stylesheet with the same label already exists
|
|
5673
|
-
*
|
|
5674
|
-
* @example CSS string
|
|
5675
|
-
* ```typescript
|
|
5676
|
-
* const [styleElement, removeStyles] = addStylesheet(`
|
|
5677
|
-
* .modal { display: flex; align-items: center; }
|
|
5678
|
-
* .modal-overlay { background: rgba(0, 0, 0, 0.5); }
|
|
5679
|
-
* `, 'modal-styles')
|
|
5680
|
-
*
|
|
5681
|
-
* // Remove when done
|
|
5682
|
-
* removeStyles()
|
|
5683
|
-
* ```
|
|
5684
|
-
*
|
|
5685
|
-
* @example StyleMap object
|
|
5686
|
-
* ```typescript
|
|
5687
|
-
* const [styleElement, removeStyles] = addStylesheet({
|
|
5688
|
-
* '.button': { backgroundColor: '#3498db', padding: '10px 20px' },
|
|
5689
|
-
* '.button:hover': { backgroundColor: '#2980b9' },
|
|
5690
|
-
* })
|
|
5691
|
-
* ```
|
|
5692
|
-
*/
|
|
5693
3085
|
function addStylesheet(css, label) {
|
|
5694
3086
|
if (getType(css) === 'object') {
|
|
5695
3087
|
css = cssRules(css);
|
|
@@ -5704,23 +3096,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5704
3096
|
const removeCallback = () => removeStylesheet(style);
|
|
5705
3097
|
return [style, removeCallback];
|
|
5706
3098
|
}
|
|
5707
|
-
/**
|
|
5708
|
-
* Removes a stylesheet from the document.
|
|
5709
|
-
*
|
|
5710
|
-
* @param {string | HTMLStyleElement} ref - The label or the HTMLStyleElement of the stylesheet to be removed.
|
|
5711
|
-
*
|
|
5712
|
-
* @example By label
|
|
5713
|
-
* ```typescript
|
|
5714
|
-
* addStylesheet('.theme { color: red; }', 'theme-styles')
|
|
5715
|
-
* removeStylesheet('theme-styles')
|
|
5716
|
-
* ```
|
|
5717
|
-
*
|
|
5718
|
-
* @example By element reference
|
|
5719
|
-
* ```typescript
|
|
5720
|
-
* const [styleElement] = addStylesheet('.custom { margin: 0; }')
|
|
5721
|
-
* removeStylesheet(styleElement)
|
|
5722
|
-
* ```
|
|
5723
|
-
*/
|
|
5724
3099
|
function removeStylesheet(ref) {
|
|
5725
3100
|
const isLabel = getType(ref) === 'string';
|
|
5726
3101
|
let style;
|
|
@@ -5738,7 +3113,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5738
3113
|
stylesheets.delete(style);
|
|
5739
3114
|
}
|
|
5740
3115
|
catch {
|
|
5741
|
-
/** Swallow any errors */
|
|
5742
3116
|
}
|
|
5743
3117
|
try {
|
|
5744
3118
|
labels.delete(label);
|
|
@@ -5746,35 +3120,13 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5746
3120
|
stylesheetLabels.delete(style);
|
|
5747
3121
|
}
|
|
5748
3122
|
catch {
|
|
5749
|
-
/** Swallow any errors */
|
|
5750
3123
|
}
|
|
5751
3124
|
}
|
|
5752
3125
|
|
|
5753
|
-
// note: The feature page resets its own body so the embedded UI fills the iframe edge-to-edge with a transparent backdrop; the host cannot touch the cross-origin body itself.
|
|
5754
3126
|
const BODY_RESET_CSS = 'html,body{margin:0;padding:0;background:transparent}';
|
|
5755
|
-
/**
|
|
5756
|
-
* Neutralizes the feature page's body so the embedded UI is neither clipped nor padded.
|
|
5757
|
-
*
|
|
5758
|
-
* @example Resetting the body when a feature initializes
|
|
5759
|
-
* ```typescript
|
|
5760
|
-
* applyBodyReset()
|
|
5761
|
-
* ```
|
|
5762
|
-
*/
|
|
5763
3127
|
function applyBodyReset() {
|
|
5764
3128
|
addStylesheet(BODY_RESET_CSS);
|
|
5765
3129
|
}
|
|
5766
|
-
/**
|
|
5767
|
-
* Creates the hostee-side content-size announcer.
|
|
5768
|
-
*
|
|
5769
|
-
* @param send - The control-channel send function (receives the reserved size type).
|
|
5770
|
-
* @returns A start/stop handle for the size-announcement loop.
|
|
5771
|
-
*
|
|
5772
|
-
* @example Announcing size to the host while connected
|
|
5773
|
-
* ```typescript
|
|
5774
|
-
* const announcer = createSizeAnnouncer((type, data) => channel.send(type, data))
|
|
5775
|
-
* announcer.start()
|
|
5776
|
-
* ```
|
|
5777
|
-
*/
|
|
5778
3130
|
function createSizeAnnouncer(send) {
|
|
5779
3131
|
let cleanup;
|
|
5780
3132
|
const announce = () => send(ControlType.Size, { width: document.body.scrollWidth, height: document.body.scrollHeight });
|
|
@@ -5795,18 +3147,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5795
3147
|
};
|
|
5796
3148
|
}
|
|
5797
3149
|
|
|
5798
|
-
// note: The host connects from a parent window (embedded iframe) or an opener window (popup/standalone); a top-level document has neither.
|
|
5799
|
-
/**
|
|
5800
|
-
* Resolves the window the host is expected to message the feature from.
|
|
5801
|
-
*
|
|
5802
|
-
* @param win - The feature's own window (`globalThis.window` in production).
|
|
5803
|
-
* @returns The parent or opener window, or `null` when running top-level.
|
|
5804
|
-
*
|
|
5805
|
-
* @example Resolving the host window
|
|
5806
|
-
* ```typescript
|
|
5807
|
-
* const hostWindow = resolveHostWindow(window)
|
|
5808
|
-
* ```
|
|
5809
|
-
*/
|
|
5810
3150
|
function resolveHostWindow(win) {
|
|
5811
3151
|
if (win.parent !== win) {
|
|
5812
3152
|
return win.parent;
|
|
@@ -5816,23 +3156,10 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5816
3156
|
}
|
|
5817
3157
|
return null;
|
|
5818
3158
|
}
|
|
5819
|
-
/**
|
|
5820
|
-
* Wires a hostee channel into the emitter and assembles the public handle.
|
|
5821
|
-
*
|
|
5822
|
-
* @param broker - The nexus broker for this feature.
|
|
5823
|
-
* @param hostWindow - The resolved host window, or `null` when unembedded.
|
|
5824
|
-
* @param emitter - The subscription registry backing `handle.on`.
|
|
5825
|
-
* @returns The frozen {@link FeatureHandle}.
|
|
5826
|
-
*
|
|
5827
|
-
* @example Assembling a feature handle around a broker
|
|
5828
|
-
* ```typescript
|
|
5829
|
-
* const handle = createFeatureHandle(broker, resolveHostWindow(window), emitter)
|
|
5830
|
-
* await handle.ready()
|
|
5831
|
-
* ```
|
|
5832
|
-
*/
|
|
5833
3159
|
function createFeatureHandle(broker, hostWindow, emitter) {
|
|
5834
3160
|
let channel = null;
|
|
5835
3161
|
let opened = false;
|
|
3162
|
+
const requests = createRequestPeer('feature', (type, data) => channel?.send(type, data));
|
|
5836
3163
|
if (hostWindow) {
|
|
5837
3164
|
const activeChannel = broker.addChannel('host', hostWindow);
|
|
5838
3165
|
channel = activeChannel;
|
|
@@ -5849,14 +3176,25 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5849
3176
|
emitter.emit('close');
|
|
5850
3177
|
heartbeat.stop();
|
|
5851
3178
|
announcer.stop();
|
|
3179
|
+
requests.rejectAll('The host channel closed before the host responded.');
|
|
5852
3180
|
});
|
|
5853
3181
|
activeChannel.on('deny', (data) => emitter.emit('error', data));
|
|
5854
3182
|
activeChannel.on('invalid', (data) => emitter.emit('error', data));
|
|
5855
|
-
activeChannel.onMessage((message) =>
|
|
3183
|
+
activeChannel.onMessage((message) => {
|
|
3184
|
+
if (isControlType(message.type)) {
|
|
3185
|
+
requests.dispatch(message.type, message.data);
|
|
3186
|
+
return;
|
|
3187
|
+
}
|
|
3188
|
+
emitter.emit(message.type, message.data);
|
|
3189
|
+
});
|
|
5856
3190
|
activeChannel.connect();
|
|
5857
3191
|
}
|
|
5858
3192
|
return freeze({
|
|
5859
3193
|
send: (type, data) => channel?.send(type, data),
|
|
3194
|
+
request: (type, data, options) => channel
|
|
3195
|
+
? requests.request(type, data, options)
|
|
3196
|
+
: promiseReject(createError(`Cannot send request '${type}': the feature is not connected to a host.`)),
|
|
3197
|
+
handle: requests.handle,
|
|
5860
3198
|
on: emitter.on,
|
|
5861
3199
|
ready: () => createPromise((resolve) => {
|
|
5862
3200
|
if (opened) {
|
|
@@ -5869,22 +3207,6 @@ var HyperfrontendFeaturesHostee = (function (exports) {
|
|
|
5869
3207
|
});
|
|
5870
3208
|
}
|
|
5871
3209
|
|
|
5872
|
-
/**
|
|
5873
|
-
* Initializes a feature app on the hostee side and waits for the host connection.
|
|
5874
|
-
*
|
|
5875
|
-
* Creates a nexus broker for the feature, resolves the host window, and returns
|
|
5876
|
-
* a handle for messaging and lifecycle.
|
|
5877
|
-
*
|
|
5878
|
-
* @param options - Feature name and contract.
|
|
5879
|
-
* @returns A handle exposing `send`, `on`, `ready`, and `close`.
|
|
5880
|
-
*
|
|
5881
|
-
* @example Initializing a clock feature
|
|
5882
|
-
* ```typescript
|
|
5883
|
-
* const feature = createFeature({ name: 'clock', contract })
|
|
5884
|
-
* feature.ready().then(() => feature.send('timeUpdated', { time: Date.now() }))
|
|
5885
|
-
* feature.on('setTimezone', (data) => console.log(data))
|
|
5886
|
-
* ```
|
|
5887
|
-
*/
|
|
5888
3210
|
function createFeature(options) {
|
|
5889
3211
|
const contract = withControlContract(validateContract(options.contract));
|
|
5890
3212
|
const emitter = createEventEmitter();
|