@openfin/node-adapter 45.100.113 → 45.100.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/out/node-adapter.js +256 -111
  2. package/package.json +3 -3
@@ -293,6 +293,26 @@ class EmitterBase extends Base {
293
293
  }
294
294
  _EmitterBase_emitterAccessor = new WeakMap(), _EmitterBase_deregisterOnceListeners = new WeakMap();
295
295
 
296
+ const V8Error = Error;
297
+ function isCallSiteArray(stack) {
298
+ if (!Array.isArray(stack) || stack.length === 0) {
299
+ return Array.isArray(stack);
300
+ }
301
+ const first = stack[0];
302
+ return typeof first === 'object' && first !== null && typeof first.getFileName === 'function';
303
+ }
304
+ function isStackFrameLine(line) {
305
+ return /^\s*at\s/.test(line) || line.includes('@');
306
+ }
307
+ /**
308
+ * Split a native `error.stack` string into frames and drop the dummy Error header plus `framesToRemove` frames.
309
+ * Safari/Firefox ignore V8's Error.prepareStackTrace, so `.stack` stays a string and `.slice(n)` would cut characters.
310
+ */
311
+ function stackStringToFrames(stack, framesToRemove) {
312
+ const lines = stack.split('\n').filter((line) => line.length > 0);
313
+ const start = lines[0] !== undefined && !isStackFrameLine(lines[0]) ? 1 : 0;
314
+ return lines.slice(start + framesToRemove);
315
+ }
296
316
  class DisconnectedError extends Error {
297
317
  constructor(readyState) {
298
318
  super(`Expected websocket state OPEN but found ${readyState}`);
@@ -329,17 +349,17 @@ class DeserializedError extends Error {
329
349
  class RuntimeError extends Error {
330
350
  static trimEndCallSites(err, takeUntilRegex) {
331
351
  // save original props
332
- const length = Error.stackTraceLimit;
352
+ const length = V8Error.stackTraceLimit;
333
353
  // eslint-disable-next-line no-underscore-dangle
334
- const _prepareStackTrace = Error.prepareStackTrace;
354
+ const _prepareStackTrace = V8Error.prepareStackTrace;
335
355
  // This will be called when we access the `stack` property
336
- Error.prepareStackTrace = (_, stack) => stack;
356
+ V8Error.prepareStackTrace = (_, stack) => stack;
337
357
  // in channel errors, the error was already serialized so we need to handle both string and CallSite[]
338
358
  const isString = typeof err.stack === 'string';
339
359
  const stack = (isString ? err.stack?.split('\n') : err.stack) ?? [];
340
360
  // restore original props
341
- Error.prepareStackTrace = _prepareStackTrace;
342
- Error.stackTraceLimit = length;
361
+ V8Error.prepareStackTrace = _prepareStackTrace;
362
+ V8Error.stackTraceLimit = length;
343
363
  // stack is optional in non chromium contexts
344
364
  if (stack.length) {
345
365
  const newStack = [];
@@ -361,31 +381,47 @@ class RuntimeError extends Error {
361
381
  }
362
382
  }
363
383
  static getCallSite(callsToRemove = 0) {
364
- const length = Error.stackTraceLimit;
384
+ const length = V8Error.stackTraceLimit;
365
385
  const realCallsToRemove = callsToRemove + 1; // remove this call;
366
- Error.stackTraceLimit = length + realCallsToRemove;
386
+ const limit = typeof length === 'number' && Number.isFinite(length) ? length : 10;
367
387
  // eslint-disable-next-line no-underscore-dangle
368
- const _prepareStackTrace = Error.prepareStackTrace;
369
- // This will be called when we access the `stack` property
370
- Error.prepareStackTrace = (_, stack) => stack;
371
- // stack is optional in non chromium contexts
372
- const stack = new Error().stack?.slice(realCallsToRemove) ?? [];
373
- Error.prepareStackTrace = _prepareStackTrace;
374
- Error.stackTraceLimit = length;
375
- return stack;
388
+ const _prepareStackTrace = V8Error.prepareStackTrace;
389
+ try {
390
+ V8Error.stackTraceLimit = limit + realCallsToRemove;
391
+ // V8 only: accessing `.stack` invokes this and returns CallSite[]. Safari/Firefox ignore it.
392
+ V8Error.prepareStackTrace = (_, stack) => stack;
393
+ const rawStack = new Error().stack;
394
+ if (Array.isArray(rawStack)) {
395
+ return rawStack.slice(realCallsToRemove);
396
+ }
397
+ if (typeof rawStack === 'string' && rawStack.length > 0) {
398
+ return stackStringToFrames(rawStack, realCallsToRemove);
399
+ }
400
+ return [];
401
+ }
402
+ finally {
403
+ V8Error.prepareStackTrace = _prepareStackTrace;
404
+ V8Error.stackTraceLimit = length;
405
+ }
376
406
  }
377
407
  static prepareStackTrace(err, callSites) {
378
- if (typeof Error.prepareStackTrace === 'function') {
379
- return Error.prepareStackTrace(err, callSites);
380
- }
381
- // TODO: this is just a first iteration, we can make this "nicer" at some point
382
- // const EXCLUSIONS = ['IpcRenderer', 'Object.onMessage', 'Transport.onmessage', 'MessageReceiver.onmessage'];
383
- let stackTrace = `${err.name || 'Error'}: ${err.message || ''}\n`;
384
- stackTrace += callSites
385
- .map((line) => ` at ${line}`)
386
- // .filter((line) => !EXCLUSIONS.some((l) => line.includes(l)))
387
- .join('\n');
388
- return stackTrace;
408
+ const header = `${err.name || 'Error'}: ${err.message || ''}`;
409
+ const frames = typeof callSites === 'string' ? stackStringToFrames(callSites, 0) : callSites;
410
+ if (!Array.isArray(frames) || frames.length === 0) {
411
+ return header;
412
+ }
413
+ if (isCallSiteArray(frames)) {
414
+ const prepare = V8Error.prepareStackTrace;
415
+ // Only V8 CallSite[] may be passed to a user-supplied Error.prepareStackTrace.
416
+ if (typeof prepare === 'function') {
417
+ return prepare(err, frames);
418
+ }
419
+ // TODO: this is just a first iteration, we can make this "nicer" at some point
420
+ // const EXCLUSIONS = ['IpcRenderer', 'Object.onMessage', 'Transport.onmessage', 'MessageReceiver.onmessage'];
421
+ return `${header}\n${frames.map((line) => ` at ${line}`).join('\n')}`;
422
+ }
423
+ // Native Safari/Firefox frames already include their engine's format (`func@file:line:col`).
424
+ return `${header}\n${frames.join('\n')}`;
389
425
  }
390
426
  /*
391
427
 
@@ -2314,6 +2350,47 @@ class Application extends EmitterBase {
2314
2350
  constructor(wire, identity) {
2315
2351
  super(wire, 'application', identity.uuid);
2316
2352
  this.identity = identity;
2353
+ /**
2354
+ * @experimental
2355
+ * Retrieves a performance snapshot for all Windows, Views and Frames in the Application.
2356
+ *
2357
+ * By default, all custom marks and measures are collected, along with navigation/paint entries
2358
+ * and resource timing (`resources` defaults to `true`). Pass `include` to restrict custom
2359
+ * marks/measures to matching names (string substring or RegExp). Pass `browser: true` to also
2360
+ * include hereio internal runtime metrics.
2361
+ *
2362
+ * See also [MDN | Performance Mark API](https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark)
2363
+ *
2364
+ * Note - only currently running WebContents will be captured, and performance entries can only be
2365
+ * captured for the current navigation of each.
2366
+ */
2367
+ this.getPerformanceStats = async (options = {}) => {
2368
+ /**
2369
+ * Returns a filter object compatible with JSON.stringify (regexs stringify to `{}`).
2370
+ * @param include Array of strings or regexps.
2371
+ */
2372
+ const getSerializableFilterObject = (include) => {
2373
+ return include.map((filter) => {
2374
+ if (filter instanceof RegExp) {
2375
+ return {
2376
+ type: 'regex',
2377
+ expression: filter.source,
2378
+ flags: filter.flags
2379
+ };
2380
+ }
2381
+ return filter;
2382
+ });
2383
+ };
2384
+ const { include, resources = true, browser = false } = options;
2385
+ const result = await this.wire.sendAction('get-application-performance-stats', {
2386
+ ...this.identity,
2387
+ // Omit `include` when unspecified so the runtime collects all custom marks/measures.
2388
+ ...(include !== undefined ? { include: getSerializableFilterObject(include) } : {}),
2389
+ resources,
2390
+ browser
2391
+ });
2392
+ return result.payload.data;
2393
+ };
2317
2394
  this.window = new _Window(this.wire, {
2318
2395
  uuid: this.identity.uuid,
2319
2396
  name: this.identity.uuid
@@ -12881,6 +12958,45 @@ class PrivateChannelProvider {
12881
12958
  }
12882
12959
  }
12883
12960
 
12961
+ /**
12962
+ * The default FDC3 user channels advertised by the Interop Broker.
12963
+ */
12964
+ const defaultColorChannels = {
12965
+ 'fdc3.channel.1': { name: 'Channel 1', color: 'red', glyph: '1' },
12966
+ 'fdc3.channel.2': { name: 'Channel 2', color: 'orange', glyph: '2' },
12967
+ 'fdc3.channel.3': { name: 'Channel 3', color: 'yellow', glyph: '3' },
12968
+ 'fdc3.channel.4': { name: 'Channel 4', color: 'green', glyph: '4' },
12969
+ 'fdc3.channel.5': { name: 'Channel 5', color: 'cyan', glyph: '5' },
12970
+ 'fdc3.channel.6': { name: 'Channel 6', color: 'blue', glyph: '6' },
12971
+ 'fdc3.channel.7': { name: 'Channel 7', color: 'magenta', glyph: '7' },
12972
+ 'fdc3.channel.8': { name: 'Channel 8', color: 'purple', glyph: '8' }
12973
+ };
12974
+ const legacyColorChannelIds = {
12975
+ red: 'fdc3.channel.1',
12976
+ orange: 'fdc3.channel.2',
12977
+ yellow: 'fdc3.channel.3',
12978
+ green: 'fdc3.channel.4',
12979
+ teal: 'fdc3.channel.5',
12980
+ blue: 'fdc3.channel.6',
12981
+ pink: 'fdc3.channel.7',
12982
+ // Legacy indigo (workspace) and purple (core) intentionally converge on the same FDC3 purple channel.
12983
+ indigo: 'fdc3.channel.8',
12984
+ purple: 'fdc3.channel.8'
12985
+ };
12986
+ /**
12987
+ * Converts a legacy color-named channel ID to its canonical FDC3 user-channel ID.
12988
+ * The removed legacy gray channel resolves to no channel.
12989
+ */
12990
+ function normalizeColorChannelId(colorChannelId) {
12991
+ if (colorChannelId === 'gray') {
12992
+ return undefined;
12993
+ }
12994
+ if (Object.prototype.hasOwnProperty.call(legacyColorChannelIds, colorChannelId)) {
12995
+ return legacyColorChannelIds[colorChannelId];
12996
+ }
12997
+ return colorChannelId;
12998
+ }
12999
+
12884
13000
  var __classPrivateFieldSet$9 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
12885
13001
  if (kind === "m") throw new TypeError("Private method is not writable");
12886
13002
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
@@ -12893,50 +13009,7 @@ var __classPrivateFieldGet$9 = (undefined && undefined.__classPrivateFieldGet) |
12893
13009
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12894
13010
  };
12895
13011
  var _InteropBroker_fdc3Info, _InteropBroker_contextGroups, _InteropBroker_providerPromise;
12896
- const defaultContextGroups = [
12897
- {
12898
- id: 'green',
12899
- displayMetadata: {
12900
- color: '#00CC88',
12901
- name: 'green'
12902
- }
12903
- },
12904
- {
12905
- id: 'purple',
12906
- displayMetadata: {
12907
- color: '#8C61FF',
12908
- name: 'purple'
12909
- }
12910
- },
12911
- {
12912
- id: 'orange',
12913
- displayMetadata: {
12914
- color: '#FF8C4C',
12915
- name: 'orange'
12916
- }
12917
- },
12918
- {
12919
- id: 'red',
12920
- displayMetadata: {
12921
- color: '#FF5E60',
12922
- name: 'red'
12923
- }
12924
- },
12925
- {
12926
- id: 'pink',
12927
- displayMetadata: {
12928
- color: '#FF8FB8',
12929
- name: 'pink'
12930
- }
12931
- },
12932
- {
12933
- id: 'yellow',
12934
- displayMetadata: {
12935
- color: '#E9FF8F',
12936
- name: 'yellow'
12937
- }
12938
- }
12939
- ];
13012
+ const defaultContextGroups = Object.entries(defaultColorChannels).map(([id, displayMetadata]) => ({ id, displayMetadata }));
12940
13013
  /**
12941
13014
  * {@link https://developers.openfin.co/of-docs/docs/enable-color-linking}
12942
13015
  *
@@ -12966,17 +13039,19 @@ const defaultContextGroups = [
12966
13039
  * "interopBrokerConfiguration": {
12967
13040
  * "contextGroups": [
12968
13041
  * {
12969
- * "id": "green",
13042
+ * "id": "fdc3.channel.4",
12970
13043
  * "displayMetadata": {
12971
- * "color": "#00CC88",
12972
- * "name": "green"
13044
+ * "color": "green",
13045
+ * "name": "Channel 4",
13046
+ * "glyph": "4"
12973
13047
  * }
12974
13048
  * },
12975
13049
  * {
12976
- * "id": "purple",
13050
+ * "id": "fdc3.channel.8",
12977
13051
  * "displayMetadata": {
12978
- * "color": "#8C61FF",
12979
- * "name": "purple"
13052
+ * "color": "purple",
13053
+ * "name": "Channel 8",
13054
+ * "glyph": "8"
12980
13055
  * }
12981
13056
  * },
12982
13057
  * ]
@@ -13139,9 +13214,13 @@ class InteropBroker extends Base {
13139
13214
  this.wire.sendAction('interop-broker-set-context-for-group').catch((e) => {
13140
13215
  // don't expose, analytics-only call
13141
13216
  });
13142
- const contextGroupState = this.contextGroupsById.get(contextGroupId);
13217
+ const normalizedContextGroupId = this.normalizeContextGroupId(contextGroupId);
13218
+ if (normalizedContextGroupId === undefined) {
13219
+ return;
13220
+ }
13221
+ const contextGroupState = this.contextGroupsById.get(normalizedContextGroupId);
13143
13222
  if (!contextGroupState) {
13144
- throw new Error(`Unable to set context for context group that isn't in the context group mapping: ${contextGroupId}.`);
13223
+ throw new Error(`Unable to set context for context group that isn't in the context group mapping: ${normalizedContextGroupId}.`);
13145
13224
  }
13146
13225
  const contextIntegrityCheckResult = InteropBroker.checkContextIntegrity(context);
13147
13226
  if (contextIntegrityCheckResult.isValid === false) {
@@ -13149,8 +13228,8 @@ class InteropBroker extends Base {
13149
13228
  }
13150
13229
  const broadcastedContextType = context.type;
13151
13230
  contextGroupState.set(broadcastedContextType, context);
13152
- this.lastContextMap.set(contextGroupId, broadcastedContextType);
13153
- const clientsInSameContextGroup = Array.from(this.interopClients.values()).filter((connectedClient) => connectedClient.contextGroupId === contextGroupId);
13231
+ this.lastContextMap.set(normalizedContextGroupId, broadcastedContextType);
13232
+ const clientsInSameContextGroup = Array.from(this.interopClients.values()).filter((connectedClient) => connectedClient.contextGroupId === normalizedContextGroupId);
13154
13233
  clientsInSameContextGroup.forEach((client) => {
13155
13234
  for (const [, handlerInfo] of client.contextHandlers) {
13156
13235
  if (InteropBroker.isContextTypeCompatible(broadcastedContextType, handlerInfo.contextType)) {
@@ -13196,10 +13275,20 @@ class InteropBroker extends Base {
13196
13275
  * @param joinContextGroupOptions - Id of the Context Group and identity of the entity to join to the group.
13197
13276
  * @param senderIdentity - Identity of the client sender.
13198
13277
  */
13199
- async joinContextGroup({ contextGroupId, target }, senderIdentity) {
13278
+ async joinContextGroup({ contextGroupId: requestedContextGroupId, target }, senderIdentity) {
13200
13279
  this.wire.sendAction('interop-broker-join-context-group').catch((e) => {
13201
13280
  // don't expose, analytics-only call
13202
13281
  });
13282
+ const contextGroupId = this.normalizeContextGroupId(requestedContextGroupId);
13283
+ if (contextGroupId === undefined) {
13284
+ if (target) {
13285
+ await this.removeFromContextGroup({ target }, senderIdentity);
13286
+ }
13287
+ else {
13288
+ await this.removeClientFromContextGroup(senderIdentity);
13289
+ }
13290
+ return;
13291
+ }
13203
13292
  if (this.sessionContextGroupMap.has(contextGroupId)) {
13204
13293
  throw new Error(BROKER_ERRORS.joinSessionContextGroupWithJoinContextGroup);
13205
13294
  }
@@ -13241,10 +13330,15 @@ class InteropBroker extends Base {
13241
13330
  * @param addClientToContextGroupOptions - Contains the contextGroupId
13242
13331
  * @param clientIdentity - Identity of the client sender.
13243
13332
  */
13244
- async addClientToContextGroup({ contextGroupId }, clientIdentity) {
13333
+ async addClientToContextGroup({ contextGroupId: requestedContextGroupId }, clientIdentity) {
13245
13334
  this.wire.sendAction('interop-broker-add-client-to-context-group').catch((e) => {
13246
13335
  // don't expose, analytics-only call
13247
13336
  });
13337
+ const contextGroupId = this.normalizeContextGroupId(requestedContextGroupId);
13338
+ if (contextGroupId === undefined) {
13339
+ await this.removeClientFromContextGroup(clientIdentity);
13340
+ return;
13341
+ }
13248
13342
  const clientSubscriptionState = this.getClientState(clientIdentity);
13249
13343
  if (!clientSubscriptionState) {
13250
13344
  throw new Error(`Client with Identity: ${clientIdentity.uuid} ${clientIdentity.name} not in Client State Map`);
@@ -13343,6 +13437,9 @@ class InteropBroker extends Base {
13343
13437
  clientState.contextGroupId = undefined;
13344
13438
  }
13345
13439
  await this.setCurrentContextGroupInClientOptions(clientIdentity, null);
13440
+ if (previousContextGroupId === undefined) {
13441
+ return;
13442
+ }
13346
13443
  // All settled will suppress uncaught exceptions. We don't want to await this because it could
13347
13444
  // result in the operation hanging.
13348
13445
  Promise.allSettled(this.channel.publish('client-changed-context-group', {
@@ -13380,7 +13477,11 @@ class InteropBroker extends Base {
13380
13477
  this.wire.sendAction('interop-broker-get-info-for-context-group').catch((e) => {
13381
13478
  // don't expose, analytics-only call
13382
13479
  });
13383
- return this.getContextGroups().find((contextGroup) => contextGroup.id === contextGroupId);
13480
+ const normalizedContextGroupId = this.normalizeContextGroupId(contextGroupId);
13481
+ if (normalizedContextGroupId === undefined) {
13482
+ return undefined;
13483
+ }
13484
+ return this.getContextGroups().find((contextGroup) => contextGroup.id === normalizedContextGroupId);
13384
13485
  }
13385
13486
  // Used by platform windows to get all clients for a context group.
13386
13487
  /**
@@ -13396,8 +13497,12 @@ class InteropBroker extends Base {
13396
13497
  this.wire.sendAction('interop-broker-get-all-clients-in-context-group').catch((e) => {
13397
13498
  // don't expose, analytics-only call
13398
13499
  });
13500
+ const normalizedContextGroupId = this.normalizeContextGroupId(contextGroupId);
13501
+ if (normalizedContextGroupId === undefined) {
13502
+ return [];
13503
+ }
13399
13504
  const clientsInContextGroup = Array.from(this.interopClients.values())
13400
- .filter((connectedClient) => connectedClient.contextGroupId === contextGroupId)
13505
+ .filter((connectedClient) => connectedClient.contextGroupId === normalizedContextGroupId)
13401
13506
  .map((subscriptionState) => {
13402
13507
  return subscriptionState.clientIdentity;
13403
13508
  });
@@ -13844,8 +13949,9 @@ class InteropBroker extends Base {
13844
13949
  }
13845
13950
  // Used to restore interop broker state in snapshots.
13846
13951
  applySnapshot(snapshot, options) {
13847
- const contextGroupStates = snapshot?.interopSnapshotDetails?.contextGroupStates;
13848
- if (contextGroupStates) {
13952
+ const incomingContextGroupStates = snapshot?.interopSnapshotDetails?.contextGroupStates;
13953
+ if (incomingContextGroupStates) {
13954
+ const contextGroupStates = this.normalizeContextGroupStates(incomingContextGroupStates);
13849
13955
  if (!options?.closeExistingWindows) {
13850
13956
  this.updateExistingClients(contextGroupStates);
13851
13957
  }
@@ -13990,6 +14096,23 @@ class InteropBroker extends Base {
13990
14096
  });
13991
14097
  return newObject;
13992
14098
  }
14099
+ normalizeContextGroupStates(incomingContextGroupStates) {
14100
+ const normalizedContextGroupStates = {};
14101
+ for (const [contextGroupId, contexts] of Object.entries(incomingContextGroupStates)) {
14102
+ const normalizedContextGroupId = this.normalizeContextGroupId(contextGroupId);
14103
+ if (normalizedContextGroupId !== undefined) {
14104
+ normalizedContextGroupStates[normalizedContextGroupId] = {
14105
+ ...normalizedContextGroupStates[normalizedContextGroupId],
14106
+ ...contexts
14107
+ };
14108
+ }
14109
+ }
14110
+ return normalizedContextGroupStates;
14111
+ }
14112
+ normalizeContextGroupId(contextGroupId) {
14113
+ const usesDefaultColorChannels = Object.keys(defaultColorChannels).every((defaultContextGroupId) => this.contextGroupsById.has(defaultContextGroupId));
14114
+ return usesDefaultColorChannels ? normalizeColorChannelId(contextGroupId) : contextGroupId;
14115
+ }
13993
14116
  // Util to check a client identity.
13994
14117
  static hasEndpointId(target) {
13995
14118
  return target.endpointId !== undefined;
@@ -14053,8 +14176,14 @@ class InteropBroker extends Base {
14053
14176
  clientIdentity
14054
14177
  };
14055
14178
  // Only allow the client to join a contextGroup that actually exists.
14056
- if (payload?.currentContextGroup && this.contextGroupsById.has(payload.currentContextGroup)) {
14057
- clientSubscriptionState.contextGroupId = payload?.currentContextGroup;
14179
+ const currentContextGroup = payload?.currentContextGroup
14180
+ ? this.normalizeContextGroupId(payload.currentContextGroup)
14181
+ : undefined;
14182
+ if (currentContextGroup && this.contextGroupsById.has(currentContextGroup)) {
14183
+ clientSubscriptionState.contextGroupId = currentContextGroup;
14184
+ if (currentContextGroup !== payload.currentContextGroup) {
14185
+ await this.setCurrentContextGroupInClientOptions(clientIdentity, currentContextGroup);
14186
+ }
14058
14187
  }
14059
14188
  this.interopClients.set(clientIdentity.endpointId, clientSubscriptionState);
14060
14189
  });
@@ -14624,7 +14753,7 @@ class InteropClient extends Base {
14624
14753
  *
14625
14754
  * getLastFocusedView()
14626
14755
  * .then(lastFocusedViewIdentity => {
14627
- * joinViewToContextGroup('red', lastFocusedViewIdentity)
14756
+ * joinViewToContextGroup('fdc3.channel.1', lastFocusedViewIdentity)
14628
14757
  * })
14629
14758
  * ```
14630
14759
  */
@@ -14674,7 +14803,7 @@ class InteropClient extends Base {
14674
14803
  *
14675
14804
  * @example
14676
14805
  * ```js
14677
- * fin.me.interop.getAllClientsInContextGroup('red')
14806
+ * fin.me.interop.getAllClientsInContextGroup('fdc3.channel.1')
14678
14807
  * .then(clientsInContextGroup => {
14679
14808
  * console.log(clientsInContextGroup)
14680
14809
  * })
@@ -14698,7 +14827,7 @@ class InteropClient extends Base {
14698
14827
  *
14699
14828
  * @example
14700
14829
  * ```js
14701
- * fin.me.interop.getInfoForContextGroup('red')
14830
+ * fin.me.interop.getInfoForContextGroup('fdc3.channel.1')
14702
14831
  * .then(contextGroupInfo => {
14703
14832
  * console.log(contextGroupInfo.displayMetadata.name)
14704
14833
  * console.log(contextGroupInfo.displayMetadata.color)
@@ -14787,12 +14916,12 @@ class InteropClient extends Base {
14787
14916
  *
14788
14917
  * @example
14789
14918
  * ```js
14790
- * await fin.me.interop.joinContextGroup('yellow');
14919
+ * await fin.me.interop.joinContextGroup('fdc3.channel.3');
14791
14920
  * await fin.me.interop.setContext({ type: 'instrument', id: { ticker: 'FOO' }});
14792
14921
  * const currentContext = await fin.me.interop.getCurrentContext();
14793
14922
  *
14794
14923
  * // with a specific context
14795
- * await fin.me.interop.joinContextGroup('yellow');
14924
+ * await fin.me.interop.joinContextGroup('fdc3.channel.3');
14796
14925
  * await fin.me.interop.setContext({ type: 'country', id: { ISOALPHA3: 'US' }});
14797
14926
  * await fin.me.interop.setContext({ type: 'instrument', id: { ticker: 'FOO' }});
14798
14927
  * const currentContext = await fin.me.interop.getCurrentContext('country');
@@ -15458,15 +15587,18 @@ class FDC3ModuleBase {
15458
15587
  async joinChannel(channelId) {
15459
15588
  this.wire.recordAnalytic('fdc3-join-channel');
15460
15589
  try {
15590
+ const contextGroup = await this.client.getInfoForContextGroup(channelId);
15591
+ if (!contextGroup) {
15592
+ console.error(`No User Channel was found with the ID "${channelId}". If this is an App Channel, use getOrCreateChannel instead.`);
15593
+ throw new Error(ChannelError.NoChannelFound);
15594
+ }
15461
15595
  return await this.client.joinContextGroup(channelId);
15462
15596
  }
15463
15597
  catch (error) {
15464
- if (error.message === BROKER_ERRORS.joinSessionContextGroupWithJoinContextGroup) {
15465
- console.error('The Channel you have tried to join is an App Channel. Custom Channels can only be defined by the Interop Broker through code or manifest configuration. Please use getOrCreateChannel.');
15466
- }
15467
- else {
15468
- console.error(error.message);
15598
+ if (error.message === ChannelError.NoChannelFound) {
15599
+ throw new Error(ChannelError.NoChannelFound);
15469
15600
  }
15601
+ console.error(error.message);
15470
15602
  if (error.message.startsWith('Attempting to join a context group that does not exist')) {
15471
15603
  throw new Error(ChannelError.NoChannelFound);
15472
15604
  }
@@ -16146,7 +16278,7 @@ class InteropModule extends Base {
16146
16278
  * @example
16147
16279
  * ```js
16148
16280
  * const interopConfig = {
16149
- * currentContextGroup: 'green'
16281
+ * currentContextGroup: 'fdc3.channel.4'
16150
16282
  * }
16151
16283
  *
16152
16284
  * const interopBroker = await fin.Interop.init('openfin');
@@ -17142,6 +17274,30 @@ class BufferReader {
17142
17274
  }
17143
17275
  }
17144
17276
 
17277
+ /**
17278
+ * Optional `platform` avoids stubbing os.platform in tests.
17279
+ * On macOS, the RVM appends --security-realm=standalone_app_<hash> for
17280
+ * standalone-app launches (see RuntimeManagerMac), overriding the
17281
+ * manifest realm. Accept these standalone_app_* realms as valid when the
17282
+ * runtime version matches so port discovery succeeds on macOS.
17283
+ */
17284
+ function matchRuntimeInstance(config, message, platform = os__namespace.platform()) {
17285
+ const args = config.runtime.arguments || '';
17286
+ const realm = config.runtime.securityRealm || (args.split('--security-realm=')[1] || '').split(' ')[0];
17287
+ if (config.runtime.version && realm) {
17288
+ const versionMatch = config.runtime.version === message.requestedVersion;
17289
+ const realmMatch = realm === message.securityRealm ||
17290
+ (platform === 'darwin' &&
17291
+ typeof message.securityRealm === 'string' &&
17292
+ message.securityRealm.startsWith('standalone_app_'));
17293
+ return versionMatch && realmMatch;
17294
+ }
17295
+ if (config.runtime.version) {
17296
+ return config.runtime.version === message.requestedVersion && !message.securityRealm;
17297
+ }
17298
+ return false;
17299
+ }
17300
+
17145
17301
  /* eslint-disable @typescript-eslint/naming-convention */
17146
17302
  const launcher = new Launcher();
17147
17303
  // value for message_type
@@ -17156,17 +17312,6 @@ var DiscoverState;
17156
17312
  DiscoverState[DiscoverState["HELLO"] = 1] = "HELLO";
17157
17313
  DiscoverState[DiscoverState["PORT_MESSAGE"] = 2] = "PORT_MESSAGE";
17158
17314
  })(DiscoverState || (DiscoverState = {}));
17159
- function matchRuntimeInstance(config, message) {
17160
- const args = config.runtime.arguments || '';
17161
- const realm = config.runtime.securityRealm || (args.split('--security-realm=')[1] || '').split(' ')[0];
17162
- if (config.runtime.version && realm) {
17163
- return config.runtime.version === message.requestedVersion && realm === message.securityRealm;
17164
- }
17165
- if (config.runtime.version) {
17166
- return config.runtime.version === message.requestedVersion && !message.securityRealm;
17167
- }
17168
- return false;
17169
- }
17170
17315
  function generateManifest(config) {
17171
17316
  const manifest = {
17172
17317
  devtools_port: config.devToolsPort,
@@ -17447,7 +17592,7 @@ class NodeEnvironment extends BaseEnvironment {
17447
17592
  };
17448
17593
  }
17449
17594
  getAdapterVersionSync() {
17450
- return "45.100.113";
17595
+ return "45.100.115";
17451
17596
  }
17452
17597
  observeBounds(element, onChange) {
17453
17598
  throw new Error('Method not implemented.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfin/node-adapter",
3
- "version": "45.100.113",
3
+ "version": "45.100.115",
4
4
  "description": "See README.md",
5
5
  "main": "out/node-adapter.js",
6
6
  "types": "out/node-adapter.d.ts",
@@ -18,9 +18,9 @@
18
18
  "dependencies": {
19
19
  "@types/node": "^20.14.2",
20
20
  "es-toolkit": "^1.39.3",
21
- "ws": "^7.5.10",
21
+ "ws": "^7.5.11",
22
22
  "tslib": "2.8.1",
23
- "@openfin/core": "45.100.113"
23
+ "@openfin/core": "45.100.115"
24
24
  },
25
25
  "scripts": {
26
26
  "prebuild": "rimraf ./out",