@contrail/extensions-sdk 1.0.18-2 → 1.0.18-4

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.
@@ -1,9 +1,10 @@
1
- import { AppContext } from '../apps/app-context';
1
+ import { AppContext, AppExtensionEvent } from '../apps/app-context';
2
2
  import { EntitiesClientAction } from '../entities/entities-action-handler';
3
3
  import { AppExtensionMessage } from '../extensions/app-extension-message-handler';
4
4
  import { TypesClientAction } from '../types/types-action-handler';
5
5
  export interface RegisterExtensionActions {
6
- init(context: AppContext): void;
6
+ init(context: AppContext): Promise<void>;
7
+ emitEvent(event: AppExtensionEvent): void;
7
8
  }
8
9
  export interface ExtensionActions {
9
10
  close(): void;
@@ -11,6 +12,7 @@ export interface ExtensionActions {
11
12
  sendMessageToTypesClient(message: TypesClientAction): Promise<any>;
12
13
  sendMessageToHost(message: AppExtensionMessage): Promise<any>;
13
14
  }
14
- export declare let EXTENSION_ACTIONS: ExtensionActions;
15
+ export declare let EXTENSION_ACTIONS: ExtensionActions | undefined;
15
16
  export declare function setExtensionActions(actions: ExtensionActions): void;
16
- export declare function getExtensionActions(): ExtensionActions;
17
+ export declare function getExtensionActions(): ExtensionActions | undefined;
18
+ export declare function getExtensionActionsOrThrow(): ExtensionActions;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getExtensionActions = exports.setExtensionActions = exports.EXTENSION_ACTIONS = void 0;
3
+ exports.getExtensionActionsOrThrow = exports.getExtensionActions = exports.setExtensionActions = exports.EXTENSION_ACTIONS = void 0;
4
4
  function setExtensionActions(actions) {
5
5
  exports.EXTENSION_ACTIONS = actions;
6
6
  }
@@ -9,3 +9,11 @@ function getExtensionActions() {
9
9
  return exports.EXTENSION_ACTIONS;
10
10
  }
11
11
  exports.getExtensionActions = getExtensionActions;
12
+ function getExtensionActionsOrThrow() {
13
+ const actions = exports.EXTENSION_ACTIONS;
14
+ if (!actions) {
15
+ throw new Error('Extension is not connected. Ensure AppExtension.registerAppExtension() has resolved before using this API.');
16
+ }
17
+ return actions;
18
+ }
19
+ exports.getExtensionActionsOrThrow = getExtensionActionsOrThrow;
@@ -1,4 +1,26 @@
1
1
  import { User } from '@contrail/entity-types';
2
+ interface Document {
3
+ id: string;
4
+ name: string;
5
+ orgId: string;
6
+ ownedByReference: string;
7
+ size: {
8
+ width: string;
9
+ height: string;
10
+ };
11
+ elements: any[];
12
+ documentElementSortOrder: any;
13
+ modelBindings: any;
14
+ workspaceId: string;
15
+ }
16
+ interface Frame {
17
+ id: string;
18
+ name: string;
19
+ orgId: string;
20
+ ownedByReference: string;
21
+ documentId: string;
22
+ document?: Document;
23
+ }
2
24
  export declare enum VibeIQAppType {
3
25
  BOARDS = "boards",
4
26
  PLAN = "plan",
@@ -52,9 +74,26 @@ export interface BoardContext {
52
74
  workspaceId?: string;
53
75
  }
54
76
  export interface ShowcaseContext {
55
- currentFrame?: any;
56
- frames?: any[];
77
+ id: string;
78
+ name: string;
79
+ orgId: string;
80
+ currentFrame: Frame;
81
+ frames?: Frame[];
82
+ rootWorkspaceId?: string;
83
+ workspaceId?: string;
84
+ previewFileId?: string;
85
+ backingAssortmentId?: string;
86
+ }
87
+ export declare enum AppEventType {
88
+ SelectedElementsChanged = "selected_elements_changed",
89
+ ShowcaseFramesChanged = "showcase_frames_changed",
90
+ ShowcaseCurrentFrameChanged = "showcase_current_frame_changed"
91
+ }
92
+ export interface AppExtensionEvent<T = any> {
93
+ type: AppEventType;
94
+ data: T;
57
95
  }
58
96
  export declare const CONTEXT: AppContext;
59
97
  export declare function setAppContext(context: AppContext): void;
60
98
  export declare function getAppContext(): AppContext;
99
+ export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAppContext = exports.setAppContext = exports.CONTEXT = exports.VibeIQAppType = void 0;
3
+ exports.getAppContext = exports.setAppContext = exports.CONTEXT = exports.AppEventType = exports.VibeIQAppType = void 0;
4
4
  var VibeIQAppType;
5
5
  (function (VibeIQAppType) {
6
6
  VibeIQAppType["BOARDS"] = "boards";
@@ -8,6 +8,12 @@ var VibeIQAppType;
8
8
  VibeIQAppType["SHOWCASE"] = "showcase";
9
9
  VibeIQAppType["ADMIN_CONSOLE"] = "admin_console";
10
10
  })(VibeIQAppType = exports.VibeIQAppType || (exports.VibeIQAppType = {}));
11
+ var AppEventType;
12
+ (function (AppEventType) {
13
+ AppEventType["SelectedElementsChanged"] = "selected_elements_changed";
14
+ AppEventType["ShowcaseFramesChanged"] = "showcase_frames_changed";
15
+ AppEventType["ShowcaseCurrentFrameChanged"] = "showcase_current_frame_changed";
16
+ })(AppEventType = exports.AppEventType || (exports.AppEventType = {}));
11
17
  exports.CONTEXT = {};
12
18
  function setAppContext(context) {
13
19
  Object.assign(exports.CONTEXT, context);
@@ -30,7 +30,7 @@ class BoardsApp {
30
30
  static addElements(elements) {
31
31
  BoardsApp.validateBoardContext();
32
32
  if (elements === null || elements === void 0 ? void 0 : elements.length) {
33
- (0, actions_1.getExtensionActions)().sendMessageToHost({
33
+ (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({
34
34
  command: BoardCommand.ADD_ELEMENTS,
35
35
  data: elements,
36
36
  });
@@ -40,7 +40,7 @@ class BoardsApp {
40
40
  return __awaiter(this, void 0, void 0, function* () {
41
41
  BoardsApp.validateBoardContext();
42
42
  if (frames === null || frames === void 0 ? void 0 : frames.length) {
43
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToHost({
43
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({
44
44
  command: BoardCommand.ADD_FRAMES_FROM_TEMPLATE,
45
45
  data: frames,
46
46
  });
@@ -53,13 +53,13 @@ class BoardsApp {
53
53
  BoardsApp.validateBoardContext();
54
54
  const elementsWithIds = elements.filter((element) => !!element.id);
55
55
  if (elementsWithIds === null || elementsWithIds === void 0 ? void 0 : elementsWithIds.length) {
56
- (0, actions_1.getExtensionActions)().sendMessageToHost({ command: BoardCommand.DELETE_ELEMENTS, data: elementsWithIds });
56
+ (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({ command: BoardCommand.DELETE_ELEMENTS, data: elementsWithIds });
57
57
  }
58
58
  }
59
59
  static modifyElements(changeObjects) {
60
60
  BoardsApp.validateBoardContext();
61
61
  if (changeObjects === null || changeObjects === void 0 ? void 0 : changeObjects.length) {
62
- (0, actions_1.getExtensionActions)().sendMessageToHost({
62
+ (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({
63
63
  command: BoardCommand.MODIFY_ELEMENTS,
64
64
  data: changeObjects,
65
65
  });
@@ -68,7 +68,7 @@ class BoardsApp {
68
68
  static getElements(criteria) {
69
69
  return __awaiter(this, void 0, void 0, function* () {
70
70
  BoardsApp.validateBoardContext();
71
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToHost({
71
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({
72
72
  command: BoardCommand.GET_ELEMENTS,
73
73
  data: criteria,
74
74
  });
@@ -83,7 +83,7 @@ class BoardsApp {
83
83
  entity,
84
84
  elements,
85
85
  };
86
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToHost({
86
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({
87
87
  command: BoardCommand.ADD_CONTENT_TO_ENTITY_FROM_ELEMENTS,
88
88
  data,
89
89
  });
@@ -93,7 +93,7 @@ class BoardsApp {
93
93
  static recolorImages(imageElements, hexCode, hexMap = {}) {
94
94
  return __awaiter(this, void 0, void 0, function* () {
95
95
  BoardsApp.validateBoardContext();
96
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToHost({
96
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToHost({
97
97
  command: BoardCommand.RECOLOR_IMAGES,
98
98
  data: { imageElements, hexCode, hexMap },
99
99
  });
package/lib/apps/plan.js CHANGED
@@ -35,18 +35,18 @@ class PlanApp {
35
35
  static addRows(collectionElements) {
36
36
  PlanApp.validatePlanContext();
37
37
  if (collectionElements === null || collectionElements === void 0 ? void 0 : collectionElements.length) {
38
- const actions = (0, actions_1.getExtensionActions)();
38
+ const actions = (0, actions_1.getExtensionActionsOrThrow)();
39
39
  actions.sendMessageToHost({ command: PlanCommand.ADD_ROWS, data: collectionElements });
40
40
  }
41
41
  }
42
42
  static clearSelectedRows() {
43
43
  PlanApp.validatePlanContext();
44
- const actions = (0, actions_1.getExtensionActions)();
44
+ const actions = (0, actions_1.getExtensionActionsOrThrow)();
45
45
  actions.sendMessageToHost({ command: PlanCommand.CLEAR_SELECTED_ROWS });
46
46
  }
47
47
  static showMessage(message) {
48
48
  PlanApp.validatePlanContext();
49
- const actions = (0, actions_1.getExtensionActions)();
49
+ const actions = (0, actions_1.getExtensionActionsOrThrow)();
50
50
  actions.sendMessageToHost({ command: PlanCommand.SHOW_MESSAGE, data: message });
51
51
  }
52
52
  static validatePlanContext() {
@@ -17,7 +17,7 @@ class EntitiesClientUpdateOptions {
17
17
  class EntitiesClient {
18
18
  get(options) {
19
19
  return __awaiter(this, void 0, void 0, function* () {
20
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
20
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
21
21
  method: entities_action_handler_1.EntitiesClientMethods.GET,
22
22
  options,
23
23
  });
@@ -26,7 +26,7 @@ class EntitiesClient {
26
26
  }
27
27
  create(options) {
28
28
  return __awaiter(this, void 0, void 0, function* () {
29
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
29
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
30
30
  method: entities_action_handler_1.EntitiesClientMethods.CREATE,
31
31
  options,
32
32
  });
@@ -35,7 +35,7 @@ class EntitiesClient {
35
35
  }
36
36
  batchCreate(options) {
37
37
  return __awaiter(this, void 0, void 0, function* () {
38
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
38
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
39
39
  method: entities_action_handler_1.EntitiesClientMethods.BATCH_CREATE,
40
40
  options,
41
41
  });
@@ -44,7 +44,7 @@ class EntitiesClient {
44
44
  }
45
45
  update(options) {
46
46
  return __awaiter(this, void 0, void 0, function* () {
47
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
47
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
48
48
  method: entities_action_handler_1.EntitiesClientMethods.UPDATE,
49
49
  options,
50
50
  });
@@ -53,7 +53,7 @@ class EntitiesClient {
53
53
  }
54
54
  batchUpdate(options) {
55
55
  return __awaiter(this, void 0, void 0, function* () {
56
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
56
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
57
57
  method: entities_action_handler_1.EntitiesClientMethods.BATCH_UPDATE,
58
58
  options,
59
59
  });
@@ -62,7 +62,7 @@ class EntitiesClient {
62
62
  }
63
63
  delete(options) {
64
64
  return __awaiter(this, void 0, void 0, function* () {
65
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
65
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
66
66
  method: entities_action_handler_1.EntitiesClientMethods.DELETE,
67
67
  options,
68
68
  });
@@ -71,7 +71,7 @@ class EntitiesClient {
71
71
  }
72
72
  batchDelete(options) {
73
73
  return __awaiter(this, void 0, void 0, function* () {
74
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToEntitiesClient({
74
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToEntitiesClient({
75
75
  method: entities_action_handler_1.EntitiesClientMethods.BATCH_DELETE,
76
76
  options,
77
77
  });
@@ -1,6 +1,11 @@
1
- import { AppContext } from '../apps/app-context';
1
+ import { AppContext, AppExtensionEvent } from '../apps/app-context';
2
2
  import { AppExtensionMessageHandler } from './app-extension-message-handler';
3
+ export interface RegisterHostWithAppExtensionOptions {
4
+ timeoutMs?: number;
5
+ }
3
6
  export declare class AppExtensionHost {
4
- static registerHostWithAppExtension(iframe: HTMLIFrameElement, context: AppContext, customMessageHandler: AppExtensionMessageHandler): Promise<void>;
7
+ private static appExtension;
8
+ static registerHostWithAppExtension(iframe: HTMLIFrameElement, context: AppContext, customMessageHandler: AppExtensionMessageHandler, options?: RegisterHostWithAppExtensionOptions): Promise<void>;
9
+ static emitEvent(event: AppExtensionEvent): void;
5
10
  private static getExtensionActionsToRunOnHost;
6
11
  }
@@ -13,18 +13,21 @@ exports.AppExtensionHost = void 0;
13
13
  const penpal_1 = require("penpal");
14
14
  const entities_action_handler_1 = require("../entities/entities-action-handler");
15
15
  const types_action_handler_1 = require("../types/types-action-handler");
16
+ const connection_timeout_1 = require("./connection-timeout");
16
17
  class AppExtensionHost {
17
- static registerHostWithAppExtension(iframe, context, customMessageHandler) {
18
+ static registerHostWithAppExtension(iframe, context, customMessageHandler, options) {
18
19
  return __awaiter(this, void 0, void 0, function* () {
19
20
  try {
20
21
  const hostActions = AppExtensionHost.getExtensionActionsToRunOnHost(customMessageHandler);
21
22
  const connection = (0, penpal_1.connectToChild)({ iframe, methods: Object.assign({}, hostActions) });
22
- const iframeWindow = iframe.contentWindow;
23
- iframeWindow.postMessage({ isConnected: true }, iframe.src);
24
23
  console.log('[HostApp] Awaiting connection to app extension...');
25
- const appExtension = yield connection.promise;
24
+ const connectionPromise = (options === null || options === void 0 ? void 0 : options.timeoutMs) !== undefined
25
+ ? (0, connection_timeout_1.withConnectionTimeout)(connection.promise, options.timeoutMs, () => new connection_timeout_1.HostConnectionTimeoutError(options.timeoutMs))
26
+ : connection.promise;
27
+ const appExtension = yield connectionPromise;
26
28
  console.log('[HostApp] Connected to app extension.');
27
- appExtension.init(context);
29
+ AppExtensionHost.appExtension = appExtension;
30
+ yield appExtension.init(context);
28
31
  }
29
32
  catch (error) {
30
33
  console.error('Failed to connect host app with app extension:', error);
@@ -32,6 +35,13 @@ class AppExtensionHost {
32
35
  }
33
36
  });
34
37
  }
38
+ static emitEvent(event) {
39
+ if (!AppExtensionHost.appExtension) {
40
+ console.warn('[HostApp] Cannot emit event: no app extension connected.');
41
+ return;
42
+ }
43
+ AppExtensionHost.appExtension.emitEvent(event);
44
+ }
35
45
  static getExtensionActionsToRunOnHost(customMessageHandler) {
36
46
  return {
37
47
  close() {
@@ -50,3 +60,4 @@ class AppExtensionHost {
50
60
  }
51
61
  }
52
62
  exports.AppExtensionHost = AppExtensionHost;
63
+ AppExtensionHost.appExtension = null;
@@ -1,12 +1,15 @@
1
+ import { AppEventType } from '../apps/app-context';
2
+ export interface RegisterAppExtensionOptions {
3
+ timeoutMs?: number;
4
+ }
1
5
  export declare class AppExtension {
2
6
  private static initPromiseResolver;
3
- private static contextUpdateCallbacks;
4
- private static messageListener;
5
- static registerAppExtension(): Promise<void>;
7
+ private static eventListeners;
8
+ static registerAppExtension(options?: RegisterAppExtensionOptions): Promise<void>;
6
9
  private static getExtensionActions;
7
10
  private static initAppExtension;
11
+ private static handleEvent;
12
+ private static getCurrentValueForEvent;
13
+ static subscribe<T = any>(eventType: AppEventType, listener: (data: T) => void): () => void;
8
14
  static close(): void;
9
- private static setupContextUpdateListener;
10
- static onContextUpdate(callback: () => void): () => void;
11
- static cleanup(): void;
12
15
  }
@@ -13,17 +13,20 @@ exports.AppExtension = void 0;
13
13
  const penpal_1 = require("penpal");
14
14
  const app_context_1 = require("../apps/app-context");
15
15
  const actions_1 = require("../actions/actions");
16
+ const connection_timeout_1 = require("./connection-timeout");
16
17
  class AppExtension {
17
- static registerAppExtension() {
18
+ static registerAppExtension(options) {
18
19
  return __awaiter(this, void 0, void 0, function* () {
19
20
  try {
20
21
  const extensionRegistrationActions = AppExtension.getExtensionActions();
21
22
  const connection = (0, penpal_1.connectToParent)({ methods: Object.assign({}, extensionRegistrationActions) });
22
23
  console.log('[AppExtension] Awaiting connection to host app...');
23
- const hostApp = yield connection.promise;
24
+ const connectionPromise = (options === null || options === void 0 ? void 0 : options.timeoutMs) !== undefined
25
+ ? (0, connection_timeout_1.withConnectionTimeout)(connection.promise, options.timeoutMs, () => new connection_timeout_1.ExtensionConnectionTimeoutError(options.timeoutMs))
26
+ : connection.promise;
27
+ const hostApp = yield connectionPromise;
24
28
  console.log('[AppExtension] Connected to host app.');
25
29
  (0, actions_1.setExtensionActions)(hostApp);
26
- AppExtension.setupContextUpdateListener();
27
30
  yield new Promise((resolve) => {
28
31
  AppExtension.initPromiseResolver = resolve;
29
32
  });
@@ -39,6 +42,9 @@ class AppExtension {
39
42
  init(context) {
40
43
  return AppExtension.initAppExtension(context);
41
44
  },
45
+ emitEvent(event) {
46
+ return AppExtension.handleEvent(event);
47
+ },
42
48
  };
43
49
  }
44
50
  static initAppExtension(context) {
@@ -50,48 +56,75 @@ class AppExtension {
50
56
  }
51
57
  });
52
58
  }
53
- static close() {
54
- (0, actions_1.getExtensionActions)().close();
59
+ static handleEvent(event) {
60
+ var _a, _b, _c, _d, _e, _f, _g;
61
+ const existing = (0, app_context_1.getAppContext)();
62
+ switch (event.type) {
63
+ case app_context_1.AppEventType.SelectedElementsChanged:
64
+ (0, app_context_1.setAppContext)(Object.assign(Object.assign({}, existing), { appContext: Object.assign(Object.assign({}, ((_a = existing.appContext) !== null && _a !== void 0 ? _a : {})), { selectedElements: event.data }) }));
65
+ break;
66
+ case app_context_1.AppEventType.ShowcaseFramesChanged:
67
+ (0, app_context_1.setAppContext)(Object.assign(Object.assign({}, existing), { appContext: Object.assign(Object.assign({}, ((_b = existing.appContext) !== null && _b !== void 0 ? _b : {})), { showcase: Object.assign(Object.assign({}, ((_d = (_c = existing.appContext) === null || _c === void 0 ? void 0 : _c.showcase) !== null && _d !== void 0 ? _d : {})), { frames: event.data }) }) }));
68
+ break;
69
+ case app_context_1.AppEventType.ShowcaseCurrentFrameChanged:
70
+ (0, app_context_1.setAppContext)(Object.assign(Object.assign({}, existing), { appContext: Object.assign(Object.assign({}, ((_e = existing.appContext) !== null && _e !== void 0 ? _e : {})), { showcase: Object.assign(Object.assign({}, ((_g = (_f = existing.appContext) === null || _f === void 0 ? void 0 : _f.showcase) !== null && _g !== void 0 ? _g : {})), { currentFrame: event.data }) }) }));
71
+ break;
72
+ }
73
+ const listeners = AppExtension.eventListeners.get(event.type);
74
+ if (listeners) {
75
+ listeners.forEach((listener) => {
76
+ try {
77
+ listener(event.data);
78
+ }
79
+ catch (error) {
80
+ console.error(`[AppExtension] Error in listener for event "${event.type}":`, error);
81
+ }
82
+ });
83
+ }
55
84
  }
56
- static setupContextUpdateListener() {
57
- if (AppExtension.messageListener) {
58
- return;
85
+ static getCurrentValueForEvent(eventType) {
86
+ var _a, _b, _c, _d, _e;
87
+ const ctx = (0, app_context_1.getAppContext)();
88
+ switch (eventType) {
89
+ case app_context_1.AppEventType.SelectedElementsChanged:
90
+ return (_a = ctx.appContext) === null || _a === void 0 ? void 0 : _a.selectedElements;
91
+ case app_context_1.AppEventType.ShowcaseFramesChanged:
92
+ return (_c = (_b = ctx.appContext) === null || _b === void 0 ? void 0 : _b.showcase) === null || _c === void 0 ? void 0 : _c.frames;
93
+ case app_context_1.AppEventType.ShowcaseCurrentFrameChanged:
94
+ return (_e = (_d = ctx.appContext) === null || _d === void 0 ? void 0 : _d.showcase) === null || _e === void 0 ? void 0 : _e.currentFrame;
59
95
  }
60
- AppExtension.messageListener = (event) => {
61
- var _a, _b, _c;
62
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'vibeiq:context_update' && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.appContext)) {
63
- const existing = (0, app_context_1.getAppContext)();
64
- (0, app_context_1.setAppContext)(Object.assign(Object.assign({}, existing), { appContext: Object.assign(Object.assign({}, ((_c = existing.appContext) !== null && _c !== void 0 ? _c : {})), event.data.appContext) }));
65
- AppExtension.contextUpdateCallbacks.forEach((callback) => {
66
- try {
67
- callback();
68
- }
69
- catch (error) {
70
- console.error('[AppExtension] Error in context update callback:', error);
71
- }
72
- });
73
- }
74
- };
75
- window.addEventListener('message', AppExtension.messageListener);
76
96
  }
77
- static onContextUpdate(callback) {
78
- AppExtension.contextUpdateCallbacks.push(callback);
97
+ static subscribe(eventType, listener) {
98
+ if (!AppExtension.eventListeners.has(eventType)) {
99
+ AppExtension.eventListeners.set(eventType, []);
100
+ }
101
+ AppExtension.eventListeners.get(eventType).push(listener);
102
+ const currentValue = AppExtension.getCurrentValueForEvent(eventType);
103
+ if (currentValue !== undefined) {
104
+ try {
105
+ listener(currentValue);
106
+ }
107
+ catch (error) {
108
+ console.error(`[AppExtension] Error emitting initial value for event "${eventType}":`, error);
109
+ }
110
+ }
79
111
  return () => {
80
- const index = AppExtension.contextUpdateCallbacks.indexOf(callback);
81
- if (index > -1) {
82
- AppExtension.contextUpdateCallbacks.splice(index, 1);
112
+ const listeners = AppExtension.eventListeners.get(eventType);
113
+ if (listeners) {
114
+ const index = listeners.indexOf(listener);
115
+ if (index > -1) {
116
+ listeners.splice(index, 1);
117
+ }
83
118
  }
84
119
  };
85
120
  }
86
- static cleanup() {
87
- if (AppExtension.messageListener) {
88
- window.removeEventListener('message', AppExtension.messageListener);
89
- AppExtension.messageListener = null;
121
+ static close() {
122
+ const actions = (0, actions_1.getExtensionActions)();
123
+ if (actions) {
124
+ actions.close();
90
125
  }
91
- AppExtension.contextUpdateCallbacks = [];
92
126
  }
93
127
  }
94
128
  exports.AppExtension = AppExtension;
95
129
  AppExtension.initPromiseResolver = null;
96
- AppExtension.contextUpdateCallbacks = [];
97
- AppExtension.messageListener = null;
130
+ AppExtension.eventListeners = new Map();
@@ -0,0 +1,7 @@
1
+ export declare class ExtensionConnectionTimeoutError extends Error {
2
+ constructor(timeoutMs: number);
3
+ }
4
+ export declare class HostConnectionTimeoutError extends Error {
5
+ constructor(timeoutMs: number);
6
+ }
7
+ export declare function withConnectionTimeout<T>(promise: Promise<T>, timeoutMs: number, createError: () => Error): Promise<T>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withConnectionTimeout = exports.HostConnectionTimeoutError = exports.ExtensionConnectionTimeoutError = void 0;
4
+ class ExtensionConnectionTimeoutError extends Error {
5
+ constructor(timeoutMs) {
6
+ super(`Extension connection to host timed out after ${timeoutMs}ms. Ensure the host calls registerHostWithAppExtension after the extension iframe has loaded.`);
7
+ this.name = 'ExtensionConnectionTimeoutError';
8
+ Object.setPrototypeOf(this, ExtensionConnectionTimeoutError.prototype);
9
+ }
10
+ }
11
+ exports.ExtensionConnectionTimeoutError = ExtensionConnectionTimeoutError;
12
+ class HostConnectionTimeoutError extends Error {
13
+ constructor(timeoutMs) {
14
+ super(`Host connection to extension timed out after ${timeoutMs}ms. Ensure the extension calls registerAppExtension() on load and the iframe has loaded.`);
15
+ this.name = 'HostConnectionTimeoutError';
16
+ Object.setPrototypeOf(this, HostConnectionTimeoutError.prototype);
17
+ }
18
+ }
19
+ exports.HostConnectionTimeoutError = HostConnectionTimeoutError;
20
+ function withConnectionTimeout(promise, timeoutMs, createError) {
21
+ return new Promise((resolve, reject) => {
22
+ const timer = setTimeout(() => reject(createError()), timeoutMs);
23
+ promise
24
+ .then((value) => {
25
+ clearTimeout(timer);
26
+ resolve(value);
27
+ })
28
+ .catch((err) => {
29
+ clearTimeout(timer);
30
+ reject(err);
31
+ });
32
+ });
33
+ }
34
+ exports.withConnectionTimeout = withConnectionTimeout;
@@ -1,3 +1,4 @@
1
1
  export * from './app-extension-host';
2
2
  export * from './app-extension-message-handler';
3
3
  export * from './app-extension';
4
+ export * from './connection-timeout';
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./app-extension-host"), exports);
18
18
  __exportStar(require("./app-extension-message-handler"), exports);
19
19
  __exportStar(require("./app-extension"), exports);
20
+ __exportStar(require("./connection-timeout"), exports);
@@ -15,7 +15,7 @@ const types_action_handler_1 = require("./types-action-handler");
15
15
  class TypesClient {
16
16
  getType(options) {
17
17
  return __awaiter(this, void 0, void 0, function* () {
18
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToTypesClient({
18
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToTypesClient({
19
19
  method: types_action_handler_1.TypesClientMethods.GET_TYPE,
20
20
  options,
21
21
  });
@@ -24,7 +24,7 @@ class TypesClient {
24
24
  }
25
25
  getByRootAndPath(options) {
26
26
  return __awaiter(this, void 0, void 0, function* () {
27
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToTypesClient({
27
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToTypesClient({
28
28
  method: types_action_handler_1.TypesClientMethods.GET_BY_ROOT_AND_PATH,
29
29
  options,
30
30
  });
@@ -34,7 +34,7 @@ class TypesClient {
34
34
  getProperty(typeId, propertySlug) {
35
35
  return __awaiter(this, void 0, void 0, function* () {
36
36
  const getPropertyOptions = { typeId, propertySlug };
37
- const results = yield (0, actions_1.getExtensionActions)().sendMessageToTypesClient({
37
+ const results = yield (0, actions_1.getExtensionActionsOrThrow)().sendMessageToTypesClient({
38
38
  method: types_action_handler_1.TypesClientMethods.GET_PROPERTY,
39
39
  options: getPropertyOptions,
40
40
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/extensions-sdk",
3
- "version": "1.0.18-2",
3
+ "version": "1.0.18-4",
4
4
  "description": "Client library for interfacing with VibeIQ's services and apps from an extension.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",