@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
|
@@ -11,6 +11,7 @@ const index_cjs_js$7 = require('../immutable-api-utils/built-in-copy/date/index.
|
|
|
11
11
|
const index_cjs_js$8 = require('../immutable-api-utils/built-in-copy/console/index.cjs.js');
|
|
12
12
|
const index_cjs_js$9 = require('../immutable-api-utils/built-in-copy/weak-set/index.cjs.js');
|
|
13
13
|
const index_cjs_js$a = require('../json-utils/index.cjs.js');
|
|
14
|
+
const index_cjs_js$b = require('../immutable-api-utils/built-in-copy/reflect/index.cjs.js');
|
|
14
15
|
|
|
15
16
|
function uuidV4() {
|
|
16
17
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
|
|
@@ -82,10 +83,10 @@ const invalidRequest = (deps) => (processId, error) => index_cjs_js$1.freeze({
|
|
|
82
83
|
error,
|
|
83
84
|
});
|
|
84
85
|
|
|
85
|
-
const newMessage = (deps) => (
|
|
86
|
+
const newMessage = (deps) => (message) => index_cjs_js$1.freeze({
|
|
86
87
|
type: ACTION_TYPES.NEW_MESSAGE,
|
|
87
88
|
senderId: deps.getBrokerId(),
|
|
88
|
-
data,
|
|
89
|
+
data: message,
|
|
89
90
|
});
|
|
90
91
|
|
|
91
92
|
const openConnection = (deps) => (processId, security) => {
|
|
@@ -695,7 +696,7 @@ function send(channel, message) {
|
|
|
695
696
|
if (!emittedTypes.includes(message.type)) {
|
|
696
697
|
throw index_cjs_js$6.createError(`Cannot send message to ${state.name} channel. Message type '${message.type}' is not in the emitted actions of channel contract.`);
|
|
697
698
|
}
|
|
698
|
-
const action = channel.actions.newMessage(message
|
|
699
|
+
const action = channel.actions.newMessage(message);
|
|
699
700
|
sendAction(channel, action);
|
|
700
701
|
channel.notifyMessage(message);
|
|
701
702
|
}
|
|
@@ -930,6 +931,7 @@ function createChannel(config, deps) {
|
|
|
930
931
|
getName: () => state.name,
|
|
931
932
|
getTarget: () => state.target,
|
|
932
933
|
isActive: () => state.active,
|
|
934
|
+
getAcceptedTypes: () => state.acceptedActions,
|
|
933
935
|
toJSON: () => ({
|
|
934
936
|
id: state.id,
|
|
935
937
|
name: state.name,
|
|
@@ -1158,12 +1160,22 @@ function handleAccept(context, message) {
|
|
|
1158
1160
|
channel.notifyEvent('open', { origin: message.origin, contract });
|
|
1159
1161
|
}
|
|
1160
1162
|
|
|
1163
|
+
function resolveChannel(registry, message) {
|
|
1164
|
+
const source = message.source;
|
|
1165
|
+
if (source) {
|
|
1166
|
+
const channel = registry.getByWindow(source);
|
|
1167
|
+
if (channel) {
|
|
1168
|
+
return channel;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return registry.getById(message.data.senderId);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1161
1174
|
function handleCancel(context, message) {
|
|
1162
1175
|
const { state, registry, processManager } = context;
|
|
1163
1176
|
const action = message.data;
|
|
1164
|
-
const senderId = action['senderId'];
|
|
1165
1177
|
const processId = action['processId'];
|
|
1166
|
-
const channel = (
|
|
1178
|
+
const channel = (resolveChannel(registry, message) || processManager.get(processId));
|
|
1167
1179
|
if (!channel) {
|
|
1168
1180
|
return;
|
|
1169
1181
|
}
|
|
@@ -1192,12 +1204,11 @@ function handleCancelAcknowledged(context, message) {
|
|
|
1192
1204
|
function handleClose(context, message) {
|
|
1193
1205
|
const { state, registry, processManager } = context;
|
|
1194
1206
|
const action = message.data;
|
|
1195
|
-
const senderId = action.senderId;
|
|
1196
1207
|
if (!('processId' in action)) {
|
|
1197
1208
|
return;
|
|
1198
1209
|
}
|
|
1199
1210
|
const processId = action.processId;
|
|
1200
|
-
const channel =
|
|
1211
|
+
const channel = resolveChannel(registry, message);
|
|
1201
1212
|
if (!channel || !channel.isActive()) {
|
|
1202
1213
|
return;
|
|
1203
1214
|
}
|
|
@@ -1238,9 +1249,7 @@ function handleDeny(context, message) {
|
|
|
1238
1249
|
|
|
1239
1250
|
function handleDestroy(context, message) {
|
|
1240
1251
|
const { registry } = context;
|
|
1241
|
-
const
|
|
1242
|
-
const senderId = action.senderId;
|
|
1243
|
-
const channel = getById(registry, senderId);
|
|
1252
|
+
const channel = resolveChannel(registry, message);
|
|
1244
1253
|
if (!channel) {
|
|
1245
1254
|
return;
|
|
1246
1255
|
}
|
|
@@ -1313,12 +1322,11 @@ function validateMessage(message) {
|
|
|
1313
1322
|
function handleMessage(context, message) {
|
|
1314
1323
|
const { state, registry, logger } = context;
|
|
1315
1324
|
const action = message.data;
|
|
1316
|
-
const senderId = action.senderId;
|
|
1317
1325
|
if (!isActionWithData(action)) {
|
|
1318
1326
|
return;
|
|
1319
1327
|
}
|
|
1320
1328
|
const messageData = action.data;
|
|
1321
|
-
const channel =
|
|
1329
|
+
const channel = resolveChannel(registry, message);
|
|
1322
1330
|
if (!channel || !channel.isActive()) {
|
|
1323
1331
|
return;
|
|
1324
1332
|
}
|
|
@@ -1327,6 +1335,10 @@ function handleMessage(context, message) {
|
|
|
1327
1335
|
logger.info(`${state.name} ignored message from ${channel.getName()}`);
|
|
1328
1336
|
return;
|
|
1329
1337
|
}
|
|
1338
|
+
if (!channel.getAcceptedTypes().includes(messageData.type)) {
|
|
1339
|
+
logger.info(`${state.name} dropped message type '${messageData.type}' not accepted by the ${channel.getName()} channel contract`);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1330
1342
|
channel.notifyMessage(messageData);
|
|
1331
1343
|
}
|
|
1332
1344
|
|
|
@@ -1620,6 +1632,10 @@ function createBroker(config) {
|
|
|
1620
1632
|
assertNoCircularRef(config.settings, 'config.settings');
|
|
1621
1633
|
validateName(config.name);
|
|
1622
1634
|
validateContract(config.contract);
|
|
1635
|
+
const brokerWindow = config.window ?? (typeof window !== 'undefined' ? window : undefined);
|
|
1636
|
+
if (!brokerWindow) {
|
|
1637
|
+
throw index_cjs_js$6.createError('Cannot create broker: no window is available. Pass an explicit `window` in the broker config when running outside a browser environment.');
|
|
1638
|
+
}
|
|
1623
1639
|
const mergedSettings = {
|
|
1624
1640
|
...defaultBrokerSettings,
|
|
1625
1641
|
...config.settings,
|
|
@@ -1633,7 +1649,7 @@ function createBroker(config) {
|
|
|
1633
1649
|
const state = {
|
|
1634
1650
|
id: uuidV4(),
|
|
1635
1651
|
name: config.name,
|
|
1636
|
-
window:
|
|
1652
|
+
window: brokerWindow,
|
|
1637
1653
|
contract: config.contract,
|
|
1638
1654
|
settings: mergedSettings,
|
|
1639
1655
|
logger,
|
|
@@ -1686,9 +1702,7 @@ function createBroker(config) {
|
|
|
1686
1702
|
}
|
|
1687
1703
|
routeMessage(router, routingContext, event);
|
|
1688
1704
|
};
|
|
1689
|
-
|
|
1690
|
-
window.addEventListener('message', onMessage);
|
|
1691
|
-
}
|
|
1705
|
+
brokerWindow.addEventListener('message', onMessage);
|
|
1692
1706
|
const broker = {
|
|
1693
1707
|
id: state.id,
|
|
1694
1708
|
name: state.name,
|
|
@@ -1770,9 +1784,25 @@ const DEFAULT_CONTRACT = index_cjs_js$1.freeze({
|
|
|
1770
1784
|
{ type: 'ACK', description: 'Acknowledgment' },
|
|
1771
1785
|
]),
|
|
1772
1786
|
});
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1787
|
+
|
|
1788
|
+
let instance = null;
|
|
1789
|
+
function resolveBroker() {
|
|
1790
|
+
if (!instance) {
|
|
1791
|
+
instance = createBroker({
|
|
1792
|
+
name: 'default-broker',
|
|
1793
|
+
contract: DEFAULT_CONTRACT,
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
return instance;
|
|
1797
|
+
}
|
|
1798
|
+
const broker = new Proxy({}, {
|
|
1799
|
+
get: (_target, property) => index_cjs_js$b.get(resolveBroker(), property),
|
|
1800
|
+
has: (_target, property) => index_cjs_js$b.has(resolveBroker(), property),
|
|
1801
|
+
ownKeys: () => index_cjs_js$b.ownKeys(resolveBroker()),
|
|
1802
|
+
getOwnPropertyDescriptor: (_target, property) => {
|
|
1803
|
+
const descriptor = index_cjs_js$b.getOwnPropertyDescriptor(resolveBroker(), property);
|
|
1804
|
+
return descriptor ? { ...descriptor, configurable: true } : undefined;
|
|
1805
|
+
},
|
|
1776
1806
|
});
|
|
1777
1807
|
|
|
1778
1808
|
exports.DEFAULT_CONTRACT = DEFAULT_CONTRACT;
|
|
@@ -9,6 +9,7 @@ import { dateNow } from '../immutable-api-utils/built-in-copy/date/index.esm.js'
|
|
|
9
9
|
import { debug, info, log, warn, error } from '../immutable-api-utils/built-in-copy/console/index.esm.js';
|
|
10
10
|
import { createWeakSet } from '../immutable-api-utils/built-in-copy/weak-set/index.esm.js';
|
|
11
11
|
import { createValidator as createValidator$1 } from '../json-utils/index.esm.js';
|
|
12
|
+
import { getOwnPropertyDescriptor, ownKeys, has, get } from '../immutable-api-utils/built-in-copy/reflect/index.esm.js';
|
|
12
13
|
|
|
13
14
|
function uuidV4() {
|
|
14
15
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
|
|
@@ -80,10 +81,10 @@ const invalidRequest = (deps) => (processId, error) => freeze({
|
|
|
80
81
|
error,
|
|
81
82
|
});
|
|
82
83
|
|
|
83
|
-
const newMessage = (deps) => (
|
|
84
|
+
const newMessage = (deps) => (message) => freeze({
|
|
84
85
|
type: ACTION_TYPES.NEW_MESSAGE,
|
|
85
86
|
senderId: deps.getBrokerId(),
|
|
86
|
-
data,
|
|
87
|
+
data: message,
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
const openConnection = (deps) => (processId, security) => {
|
|
@@ -693,7 +694,7 @@ function send(channel, message) {
|
|
|
693
694
|
if (!emittedTypes.includes(message.type)) {
|
|
694
695
|
throw createError(`Cannot send message to ${state.name} channel. Message type '${message.type}' is not in the emitted actions of channel contract.`);
|
|
695
696
|
}
|
|
696
|
-
const action = channel.actions.newMessage(message
|
|
697
|
+
const action = channel.actions.newMessage(message);
|
|
697
698
|
sendAction(channel, action);
|
|
698
699
|
channel.notifyMessage(message);
|
|
699
700
|
}
|
|
@@ -928,6 +929,7 @@ function createChannel(config, deps) {
|
|
|
928
929
|
getName: () => state.name,
|
|
929
930
|
getTarget: () => state.target,
|
|
930
931
|
isActive: () => state.active,
|
|
932
|
+
getAcceptedTypes: () => state.acceptedActions,
|
|
931
933
|
toJSON: () => ({
|
|
932
934
|
id: state.id,
|
|
933
935
|
name: state.name,
|
|
@@ -1156,12 +1158,22 @@ function handleAccept(context, message) {
|
|
|
1156
1158
|
channel.notifyEvent('open', { origin: message.origin, contract });
|
|
1157
1159
|
}
|
|
1158
1160
|
|
|
1161
|
+
function resolveChannel(registry, message) {
|
|
1162
|
+
const source = message.source;
|
|
1163
|
+
if (source) {
|
|
1164
|
+
const channel = registry.getByWindow(source);
|
|
1165
|
+
if (channel) {
|
|
1166
|
+
return channel;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return registry.getById(message.data.senderId);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1159
1172
|
function handleCancel(context, message) {
|
|
1160
1173
|
const { state, registry, processManager } = context;
|
|
1161
1174
|
const action = message.data;
|
|
1162
|
-
const senderId = action['senderId'];
|
|
1163
1175
|
const processId = action['processId'];
|
|
1164
|
-
const channel = (
|
|
1176
|
+
const channel = (resolveChannel(registry, message) || processManager.get(processId));
|
|
1165
1177
|
if (!channel) {
|
|
1166
1178
|
return;
|
|
1167
1179
|
}
|
|
@@ -1190,12 +1202,11 @@ function handleCancelAcknowledged(context, message) {
|
|
|
1190
1202
|
function handleClose(context, message) {
|
|
1191
1203
|
const { state, registry, processManager } = context;
|
|
1192
1204
|
const action = message.data;
|
|
1193
|
-
const senderId = action.senderId;
|
|
1194
1205
|
if (!('processId' in action)) {
|
|
1195
1206
|
return;
|
|
1196
1207
|
}
|
|
1197
1208
|
const processId = action.processId;
|
|
1198
|
-
const channel =
|
|
1209
|
+
const channel = resolveChannel(registry, message);
|
|
1199
1210
|
if (!channel || !channel.isActive()) {
|
|
1200
1211
|
return;
|
|
1201
1212
|
}
|
|
@@ -1236,9 +1247,7 @@ function handleDeny(context, message) {
|
|
|
1236
1247
|
|
|
1237
1248
|
function handleDestroy(context, message) {
|
|
1238
1249
|
const { registry } = context;
|
|
1239
|
-
const
|
|
1240
|
-
const senderId = action.senderId;
|
|
1241
|
-
const channel = getById(registry, senderId);
|
|
1250
|
+
const channel = resolveChannel(registry, message);
|
|
1242
1251
|
if (!channel) {
|
|
1243
1252
|
return;
|
|
1244
1253
|
}
|
|
@@ -1311,12 +1320,11 @@ function validateMessage(message) {
|
|
|
1311
1320
|
function handleMessage(context, message) {
|
|
1312
1321
|
const { state, registry, logger } = context;
|
|
1313
1322
|
const action = message.data;
|
|
1314
|
-
const senderId = action.senderId;
|
|
1315
1323
|
if (!isActionWithData(action)) {
|
|
1316
1324
|
return;
|
|
1317
1325
|
}
|
|
1318
1326
|
const messageData = action.data;
|
|
1319
|
-
const channel =
|
|
1327
|
+
const channel = resolveChannel(registry, message);
|
|
1320
1328
|
if (!channel || !channel.isActive()) {
|
|
1321
1329
|
return;
|
|
1322
1330
|
}
|
|
@@ -1325,6 +1333,10 @@ function handleMessage(context, message) {
|
|
|
1325
1333
|
logger.info(`${state.name} ignored message from ${channel.getName()}`);
|
|
1326
1334
|
return;
|
|
1327
1335
|
}
|
|
1336
|
+
if (!channel.getAcceptedTypes().includes(messageData.type)) {
|
|
1337
|
+
logger.info(`${state.name} dropped message type '${messageData.type}' not accepted by the ${channel.getName()} channel contract`);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1328
1340
|
channel.notifyMessage(messageData);
|
|
1329
1341
|
}
|
|
1330
1342
|
|
|
@@ -1618,6 +1630,10 @@ function createBroker(config) {
|
|
|
1618
1630
|
assertNoCircularRef(config.settings, 'config.settings');
|
|
1619
1631
|
validateName(config.name);
|
|
1620
1632
|
validateContract(config.contract);
|
|
1633
|
+
const brokerWindow = config.window ?? (typeof window !== 'undefined' ? window : undefined);
|
|
1634
|
+
if (!brokerWindow) {
|
|
1635
|
+
throw createError('Cannot create broker: no window is available. Pass an explicit `window` in the broker config when running outside a browser environment.');
|
|
1636
|
+
}
|
|
1621
1637
|
const mergedSettings = {
|
|
1622
1638
|
...defaultBrokerSettings,
|
|
1623
1639
|
...config.settings,
|
|
@@ -1631,7 +1647,7 @@ function createBroker(config) {
|
|
|
1631
1647
|
const state = {
|
|
1632
1648
|
id: uuidV4(),
|
|
1633
1649
|
name: config.name,
|
|
1634
|
-
window:
|
|
1650
|
+
window: brokerWindow,
|
|
1635
1651
|
contract: config.contract,
|
|
1636
1652
|
settings: mergedSettings,
|
|
1637
1653
|
logger,
|
|
@@ -1684,9 +1700,7 @@ function createBroker(config) {
|
|
|
1684
1700
|
}
|
|
1685
1701
|
routeMessage(router, routingContext, event);
|
|
1686
1702
|
};
|
|
1687
|
-
|
|
1688
|
-
window.addEventListener('message', onMessage);
|
|
1689
|
-
}
|
|
1703
|
+
brokerWindow.addEventListener('message', onMessage);
|
|
1690
1704
|
const broker = {
|
|
1691
1705
|
id: state.id,
|
|
1692
1706
|
name: state.name,
|
|
@@ -1768,9 +1782,25 @@ const DEFAULT_CONTRACT = freeze({
|
|
|
1768
1782
|
{ type: 'ACK', description: 'Acknowledgment' },
|
|
1769
1783
|
]),
|
|
1770
1784
|
});
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1785
|
+
|
|
1786
|
+
let instance = null;
|
|
1787
|
+
function resolveBroker() {
|
|
1788
|
+
if (!instance) {
|
|
1789
|
+
instance = createBroker({
|
|
1790
|
+
name: 'default-broker',
|
|
1791
|
+
contract: DEFAULT_CONTRACT,
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
return instance;
|
|
1795
|
+
}
|
|
1796
|
+
const broker = new Proxy({}, {
|
|
1797
|
+
get: (_target, property) => get(resolveBroker(), property),
|
|
1798
|
+
has: (_target, property) => has(resolveBroker(), property),
|
|
1799
|
+
ownKeys: () => ownKeys(resolveBroker()),
|
|
1800
|
+
getOwnPropertyDescriptor: (_target, property) => {
|
|
1801
|
+
const descriptor = getOwnPropertyDescriptor(resolveBroker(), property);
|
|
1802
|
+
return descriptor ? { ...descriptor, configurable: true } : undefined;
|
|
1803
|
+
},
|
|
1774
1804
|
});
|
|
1775
1805
|
|
|
1776
1806
|
export { DEFAULT_CONTRACT, createBroker, createChannel, createLogger, broker as defaultBroker, logAction, logEvent, mergeContracts };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const node_fs = require('node:fs');
|
|
4
|
+
const node_path = require('node:path');
|
|
4
5
|
const index_cjs_js$2 = require('../../../immutable-api-utils/built-in-copy/array/index.cjs.js');
|
|
5
6
|
const index_cjs_js$4 = require('../../../immutable-api-utils/built-in-copy/console/index.cjs.js');
|
|
6
7
|
const index_cjs_js$6 = require('../../../immutable-api-utils/built-in-copy/json/index.cjs.js');
|
|
@@ -271,6 +272,22 @@ function createFileSystemError(message, code, context) {
|
|
|
271
272
|
});
|
|
272
273
|
return error;
|
|
273
274
|
}
|
|
275
|
+
function readFileContent(filePath, encoding = 'utf-8') {
|
|
276
|
+
if (!isSafePath(filePath)) {
|
|
277
|
+
throw createFileSystemError(`Unsafe file path: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read' });
|
|
278
|
+
}
|
|
279
|
+
if (!node_fs.existsSync(filePath)) {
|
|
280
|
+
fsLogger.debug('File not found', { path: filePath });
|
|
281
|
+
throw createFileSystemError(`File not found: ${filePath}`, 'FS_NOT_FOUND', { path: filePath, operation: 'read' });
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
return node_fs.readFileSync(filePath, { encoding });
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
fsLogger.warn('Failed to read file', { path: filePath });
|
|
288
|
+
throw createFileSystemError(`Failed to read file: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read', cause: error });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
274
291
|
function readFileBuffer(filePath) {
|
|
275
292
|
if (!isSafePath(filePath)) {
|
|
276
293
|
throw createFileSystemError(`Unsafe file path: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read' });
|
|
@@ -384,14 +401,59 @@ function removeDirectory(dirPath, options) {
|
|
|
384
401
|
const fsTraversalLogger = createScopedLogger('project-scope:fs:traversal');
|
|
385
402
|
|
|
386
403
|
const fsWriteLogger = createScopedLogger('project-scope:fs:write');
|
|
404
|
+
function ensureDir(dirPath) {
|
|
405
|
+
if (!node_fs.existsSync(dirPath)) {
|
|
406
|
+
fsWriteLogger.debug('Creating directory recursively', { path: dirPath });
|
|
407
|
+
node_fs.mkdirSync(dirPath, { recursive: true });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function writeFileContent(filePath, content, options) {
|
|
411
|
+
try {
|
|
412
|
+
fsWriteLogger.debug('Writing file content', { path: filePath, size: content.length, encoding: options?.encoding ?? 'utf-8' });
|
|
413
|
+
ensureDir(node_path.dirname(filePath));
|
|
414
|
+
node_fs.writeFileSync(filePath, content, {
|
|
415
|
+
encoding: options?.encoding ?? 'utf-8',
|
|
416
|
+
mode: options?.mode,
|
|
417
|
+
});
|
|
418
|
+
fsWriteLogger.debug('File written successfully', { path: filePath });
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
fsWriteLogger.warn('Failed to write file', { path: filePath, error: error instanceof Error ? error.message : String(error) });
|
|
422
|
+
throw createFileSystemError(`Failed to write file: ${filePath}`, 'FS_WRITE_ERROR', { path: filePath, operation: 'write', cause: error });
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function writeJsonFile(filePath, data, options) {
|
|
426
|
+
try {
|
|
427
|
+
fsWriteLogger.debug('Writing JSON file', { path: filePath, indent: options?.indent ?? 2 });
|
|
428
|
+
const indent = options?.indent ?? 2;
|
|
429
|
+
const content = index_cjs_js$6.stringify(data, null, indent) + '\n';
|
|
430
|
+
writeFileContent(filePath, content, options);
|
|
431
|
+
fsWriteLogger.debug('JSON file written successfully', { path: filePath });
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
if (error?.code === 'FS_WRITE_ERROR') {
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
fsWriteLogger.warn('Failed to write JSON file', { path: filePath, error: error instanceof Error ? error.message : String(error) });
|
|
438
|
+
throw createFileSystemError(`Failed to write JSON file: ${filePath}`, 'FS_WRITE_ERROR', {
|
|
439
|
+
path: filePath,
|
|
440
|
+
operation: 'write',
|
|
441
|
+
cause: error,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
387
445
|
|
|
388
446
|
exports.createDirectory = createDirectory;
|
|
389
447
|
exports.createFileSystemError = createFileSystemError;
|
|
448
|
+
exports.ensureDir = ensureDir;
|
|
390
449
|
exports.exists = exists;
|
|
391
450
|
exports.getFileStat = getFileStat;
|
|
392
451
|
exports.isFile = isFile;
|
|
393
452
|
exports.readFileBuffer = readFileBuffer;
|
|
453
|
+
exports.readFileContent = readFileContent;
|
|
394
454
|
exports.readFileIfExists = readFileIfExists;
|
|
395
455
|
exports.readJsonFile = readJsonFile;
|
|
396
456
|
exports.readJsonFileIfExists = readJsonFileIfExists;
|
|
397
457
|
exports.removeDirectory = removeDirectory;
|
|
458
|
+
exports.writeFileContent = writeFileContent;
|
|
459
|
+
exports.writeJsonFile = writeJsonFile;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { existsSync, readFileSync, statSync, lstatSync, mkdirSync, rmSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, statSync, lstatSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
2
3
|
import { isArray } from '../../../immutable-api-utils/built-in-copy/array/index.esm.js';
|
|
3
4
|
import { debug, info, log, warn, error } from '../../../immutable-api-utils/built-in-copy/console/index.esm.js';
|
|
4
5
|
import { stringify, parse } from '../../../immutable-api-utils/built-in-copy/json/index.esm.js';
|
|
@@ -269,6 +270,22 @@ function createFileSystemError(message, code, context) {
|
|
|
269
270
|
});
|
|
270
271
|
return error;
|
|
271
272
|
}
|
|
273
|
+
function readFileContent(filePath, encoding = 'utf-8') {
|
|
274
|
+
if (!isSafePath(filePath)) {
|
|
275
|
+
throw createFileSystemError(`Unsafe file path: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read' });
|
|
276
|
+
}
|
|
277
|
+
if (!existsSync(filePath)) {
|
|
278
|
+
fsLogger.debug('File not found', { path: filePath });
|
|
279
|
+
throw createFileSystemError(`File not found: ${filePath}`, 'FS_NOT_FOUND', { path: filePath, operation: 'read' });
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
return readFileSync(filePath, { encoding });
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
fsLogger.warn('Failed to read file', { path: filePath });
|
|
286
|
+
throw createFileSystemError(`Failed to read file: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read', cause: error });
|
|
287
|
+
}
|
|
288
|
+
}
|
|
272
289
|
function readFileBuffer(filePath) {
|
|
273
290
|
if (!isSafePath(filePath)) {
|
|
274
291
|
throw createFileSystemError(`Unsafe file path: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read' });
|
|
@@ -382,5 +399,46 @@ function removeDirectory(dirPath, options) {
|
|
|
382
399
|
const fsTraversalLogger = createScopedLogger('project-scope:fs:traversal');
|
|
383
400
|
|
|
384
401
|
const fsWriteLogger = createScopedLogger('project-scope:fs:write');
|
|
402
|
+
function ensureDir(dirPath) {
|
|
403
|
+
if (!existsSync(dirPath)) {
|
|
404
|
+
fsWriteLogger.debug('Creating directory recursively', { path: dirPath });
|
|
405
|
+
mkdirSync(dirPath, { recursive: true });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function writeFileContent(filePath, content, options) {
|
|
409
|
+
try {
|
|
410
|
+
fsWriteLogger.debug('Writing file content', { path: filePath, size: content.length, encoding: options?.encoding ?? 'utf-8' });
|
|
411
|
+
ensureDir(dirname(filePath));
|
|
412
|
+
writeFileSync(filePath, content, {
|
|
413
|
+
encoding: options?.encoding ?? 'utf-8',
|
|
414
|
+
mode: options?.mode,
|
|
415
|
+
});
|
|
416
|
+
fsWriteLogger.debug('File written successfully', { path: filePath });
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
fsWriteLogger.warn('Failed to write file', { path: filePath, error: error instanceof Error ? error.message : String(error) });
|
|
420
|
+
throw createFileSystemError(`Failed to write file: ${filePath}`, 'FS_WRITE_ERROR', { path: filePath, operation: 'write', cause: error });
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function writeJsonFile(filePath, data, options) {
|
|
424
|
+
try {
|
|
425
|
+
fsWriteLogger.debug('Writing JSON file', { path: filePath, indent: options?.indent ?? 2 });
|
|
426
|
+
const indent = options?.indent ?? 2;
|
|
427
|
+
const content = stringify(data, null, indent) + '\n';
|
|
428
|
+
writeFileContent(filePath, content, options);
|
|
429
|
+
fsWriteLogger.debug('JSON file written successfully', { path: filePath });
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
if (error?.code === 'FS_WRITE_ERROR') {
|
|
433
|
+
throw error;
|
|
434
|
+
}
|
|
435
|
+
fsWriteLogger.warn('Failed to write JSON file', { path: filePath, error: error instanceof Error ? error.message : String(error) });
|
|
436
|
+
throw createFileSystemError(`Failed to write JSON file: ${filePath}`, 'FS_WRITE_ERROR', {
|
|
437
|
+
path: filePath,
|
|
438
|
+
operation: 'write',
|
|
439
|
+
cause: error,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
}
|
|
385
443
|
|
|
386
|
-
export { createDirectory, createFileSystemError, exists, getFileStat, isFile, readFileBuffer, readFileIfExists, readJsonFile, readJsonFileIfExists, removeDirectory };
|
|
444
|
+
export { createDirectory, createFileSystemError, ensureDir, exists, getFileStat, isFile, readFileBuffer, readFileContent, readFileIfExists, readJsonFile, readJsonFileIfExists, removeDirectory, writeFileContent, writeJsonFile };
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { Mode } from '../../../../_dependencies/@hyperfrontend/project-scope/vfs/index.esm.js';
|
|
2
|
+
import { isAbsolute, join, relative, dirname } from 'node:path';
|
|
2
3
|
|
|
3
4
|
const MODULE_PATH = 'src/hyperfrontend.feature.ts';
|
|
4
|
-
function toContractImportPath(contractPath) {
|
|
5
|
+
function toContractImportPath(contractPath, treeRoot) {
|
|
5
6
|
const withoutExtension = contractPath.replace(/\.(json|ts|js)$/, '');
|
|
6
|
-
|
|
7
|
+
const target = isAbsolute(withoutExtension) ? withoutExtension : join(treeRoot, withoutExtension);
|
|
8
|
+
const specifier = relative(join(treeRoot, dirname(MODULE_PATH)), target)
|
|
9
|
+
.split('\\')
|
|
10
|
+
.join('/');
|
|
11
|
+
return specifier.startsWith('.') ? specifier : `./${specifier}`;
|
|
7
12
|
}
|
|
8
|
-
function buildFeatureModule(config, contract) {
|
|
13
|
+
function buildFeatureModule(config, contract, treeRoot) {
|
|
9
14
|
const handlers = contract.accepted
|
|
10
|
-
.map((action) => `feature.on('${action.type}', (
|
|
15
|
+
.map((action) => `feature.on('${action.type}', (_data: unknown) => {\n // todo: handle ${action.type}\n})`)
|
|
11
16
|
.join('\n\n');
|
|
12
17
|
const emits = contract.emitted.map((action) => `// feature.send('${action.type}', undefined)`).join('\n');
|
|
13
18
|
return `/**
|
|
@@ -20,7 +25,7 @@ function buildFeatureModule(config, contract) {
|
|
|
20
25
|
* @module ${config.name}.feature
|
|
21
26
|
*/
|
|
22
27
|
import { createFeature } from '@hyperfrontend/features/hostee'
|
|
23
|
-
import contract from '${toContractImportPath(config.contract)}'
|
|
28
|
+
import contract from '${toContractImportPath(config.contract, treeRoot)}'
|
|
24
29
|
|
|
25
30
|
/** The ${config.name} feature handle; use it to send and receive contract actions. */
|
|
26
31
|
export const feature = createFeature({ name: '${config.name}', contract })
|
|
@@ -32,7 +37,7 @@ ${emits}
|
|
|
32
37
|
`;
|
|
33
38
|
}
|
|
34
39
|
function generateFeatureModule(config, contract, tree) {
|
|
35
|
-
tree.write(MODULE_PATH, buildFeatureModule(config, contract), { mode: Mode.SkipIfExists });
|
|
40
|
+
tree.write(MODULE_PATH, buildFeatureModule(config, contract, tree.root), { mode: Mode.SkipIfExists });
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
export { MODULE_PATH, toContractImportPath, buildFeatureModule, generateFeatureModule };
|
|
@@ -9,6 +9,7 @@ function generateMetadata(config, contract, tree) {
|
|
|
9
9
|
version: format(parseVersionStrict(config.version)),
|
|
10
10
|
url: config.url,
|
|
11
11
|
contract,
|
|
12
|
+
...(config.protocol !== undefined && { protocol: config.protocol }),
|
|
12
13
|
generatedBy: '@hyperfrontend/features',
|
|
13
14
|
};
|
|
14
15
|
tree.write(METADATA_PATH, `${stringify(metadata, null, 2)}\n`);
|
|
@@ -8,15 +8,25 @@ const ControlType = index_cjs_js.freeze({
|
|
|
8
8
|
Beat: '__hf:beat',
|
|
9
9
|
/** Hostee-to-host content-size announcement. */
|
|
10
10
|
Size: '__hf:size',
|
|
11
|
+
/** Correlated request envelope carrying a consumer request in either direction. */
|
|
12
|
+
Request: '__hf:request',
|
|
13
|
+
/** Correlated response envelope answering a request. */
|
|
14
|
+
Response: '__hf:response',
|
|
11
15
|
});
|
|
12
16
|
function isControlType(type) {
|
|
13
17
|
return type.startsWith(CONTROL_PREFIX);
|
|
14
18
|
}
|
|
15
19
|
function withControlContract(contract) {
|
|
16
20
|
// note: Fresh action literals per direction — sharing references across emitted/accepted trips nexus's circular-reference guard, which flags any repeated object.
|
|
21
|
+
const controlActions = () => [
|
|
22
|
+
{ type: ControlType.Beat },
|
|
23
|
+
{ type: ControlType.Size },
|
|
24
|
+
{ type: ControlType.Request },
|
|
25
|
+
{ type: ControlType.Response },
|
|
26
|
+
];
|
|
17
27
|
return {
|
|
18
|
-
emitted: [...contract.emitted,
|
|
19
|
-
accepted: [...contract.accepted,
|
|
28
|
+
emitted: [...contract.emitted, ...controlActions()],
|
|
29
|
+
accepted: [...contract.accepted, ...controlActions()],
|
|
20
30
|
};
|
|
21
31
|
}
|
|
22
32
|
|
|
@@ -6,15 +6,25 @@ const ControlType = freeze({
|
|
|
6
6
|
Beat: '__hf:beat',
|
|
7
7
|
/** Hostee-to-host content-size announcement. */
|
|
8
8
|
Size: '__hf:size',
|
|
9
|
+
/** Correlated request envelope carrying a consumer request in either direction. */
|
|
10
|
+
Request: '__hf:request',
|
|
11
|
+
/** Correlated response envelope answering a request. */
|
|
12
|
+
Response: '__hf:response',
|
|
9
13
|
});
|
|
10
14
|
function isControlType(type) {
|
|
11
15
|
return type.startsWith(CONTROL_PREFIX);
|
|
12
16
|
}
|
|
13
17
|
function withControlContract(contract) {
|
|
14
18
|
// note: Fresh action literals per direction — sharing references across emitted/accepted trips nexus's circular-reference guard, which flags any repeated object.
|
|
19
|
+
const controlActions = () => [
|
|
20
|
+
{ type: ControlType.Beat },
|
|
21
|
+
{ type: ControlType.Size },
|
|
22
|
+
{ type: ControlType.Request },
|
|
23
|
+
{ type: ControlType.Response },
|
|
24
|
+
];
|
|
15
25
|
return {
|
|
16
|
-
emitted: [...contract.emitted,
|
|
17
|
-
accepted: [...contract.accepted,
|
|
26
|
+
emitted: [...contract.emitted, ...controlActions()],
|
|
27
|
+
accepted: [...contract.accepted, ...controlActions()],
|
|
18
28
|
};
|
|
19
29
|
}
|
|
20
30
|
|