@verentis/sdk 0.2.2 → 0.2.3

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/dist/index.d.cts CHANGED
@@ -62,6 +62,25 @@ interface VerentisTokenRefreshedMessage extends VerentisMessage {
62
62
  requestId: string;
63
63
  token: TokenInfo;
64
64
  }
65
+ /** Single-use credential for the installation's independently registered backend. */
66
+ interface AppBackendCredential {
67
+ delegationId: string;
68
+ backendClientId: string;
69
+ launchCredential: string;
70
+ expiresAt: string;
71
+ }
72
+ interface VerentisBackendCredentialRequest extends VerentisMessage {
73
+ type: 'verentis:backend:request';
74
+ requestId: string;
75
+ sessionId: string;
76
+ }
77
+ interface VerentisBackendCredentialResponse extends VerentisMessage {
78
+ type: 'verentis:backend:response';
79
+ requestId: string;
80
+ sessionId: string;
81
+ credential?: AppBackendCredential;
82
+ error?: string;
83
+ }
65
84
  interface VerentisFileChangedMessage extends VerentisMessage {
66
85
  type: 'verentis:file:changed';
67
86
  path: string;
@@ -99,13 +118,18 @@ interface VerentisDirtyMessage extends VerentisMessage {
99
118
  type: 'verentis:dirty';
100
119
  isDirty: boolean;
101
120
  }
102
- type HostToAppMessage = VerentisInitMessage | VerentisActionInvokeMessage | VerentisTokenRefreshedMessage | VerentisFileChangedMessage | VerentisThemeMessage;
103
- type AppToHostMessage = VerentisReadyMessage | VerentisActionsSetMessage | VerentisActionResultMessage | VerentisTokenRefreshMessage | VerentisNavigateMessage | VerentisResizeMessage | VerentisTitleMessage | VerentisDirtyMessage;
121
+ type HostToAppMessage = VerentisInitMessage | VerentisActionInvokeMessage | VerentisTokenRefreshedMessage | VerentisFileChangedMessage | VerentisThemeMessage | VerentisBackendCredentialResponse;
122
+ type AppToHostMessage = VerentisReadyMessage | VerentisActionsSetMessage | VerentisActionResultMessage | VerentisTokenRefreshMessage | VerentisNavigateMessage | VerentisResizeMessage | VerentisTitleMessage | VerentisDirtyMessage | VerentisBackendCredentialRequest;
104
123
  type AppSurface = 'file' | 'workspace';
105
124
  interface AppContextBase {
106
125
  workspace: WorkspaceInfo;
107
126
  entryPoint?: EntryPointInfo;
108
127
  apiUrl: string;
128
+ installation?: {
129
+ id: string;
130
+ backendClientId: string;
131
+ authorizationGeneration: string;
132
+ };
109
133
  }
110
134
  /** Context for an application opened against a workspace file. */
111
135
  interface FileAppContext extends AppContextBase {
@@ -138,6 +162,8 @@ interface WorkspaceInfo {
138
162
  name: string;
139
163
  }
140
164
  interface FileInfo {
165
+ nodeId?: string;
166
+ branch?: string;
141
167
  path: string;
142
168
  name: string;
143
169
  mimeType: string;
@@ -994,8 +1020,11 @@ type BridgeListener = (data: HostToAppMessage) => void;
994
1020
  * and app-to-host events (navigate, resize, dirty, etc.).
995
1021
  */
996
1022
  declare class Bridge {
1023
+ private readonly expectedHostOrigin?;
997
1024
  private listeners;
998
1025
  private _initResolve;
1026
+ private _initReject;
1027
+ private _initTimer;
999
1028
  private _initPromise;
1000
1029
  private _hostOrigin;
1001
1030
  private _messageHandler;
@@ -1003,7 +1032,8 @@ declare class Bridge {
1003
1032
  private sessionId;
1004
1033
  private actions;
1005
1034
  private requests;
1006
- constructor();
1035
+ private backendRequests;
1036
+ constructor(expectedHostOrigin?: string | undefined);
1007
1037
  /** Post `verentis:ready` to the host to start the handshake */
1008
1038
  sendReady(capabilities?: string[]): void;
1009
1039
  /** Wait for the host to send `verentis:init` with context and token */
@@ -1031,6 +1061,8 @@ declare class Bridge {
1031
1061
  setTitle(title: string): void;
1032
1062
  /** Signal unsaved changes to the host */
1033
1063
  setDirty(isDirty: boolean): void;
1064
+ /** The host, not the app, selects the installation, file, branch and permission ceiling. */
1065
+ requestBackendCredential(): Promise<AppBackendCredential>;
1034
1066
  registerAction(descriptor: HeaderAction, handler: HeaderActionHandler): HeaderActionRegistration;
1035
1067
  private publishActions;
1036
1068
  private invokeAction;
@@ -1119,13 +1151,18 @@ declare class TokenAuth implements AuthStrategy {
1119
1151
  * by requesting a new token from the host when nearing expiry.
1120
1152
  */
1121
1153
  declare class BridgeAuth implements AuthStrategy {
1122
- private readonly hostOrigin;
1154
+ private hostOrigin;
1123
1155
  private _token;
1124
1156
  private _expiresAt;
1125
1157
  private _refreshTimer;
1126
1158
  private _pendingRefresh;
1127
1159
  private _messageHandler;
1160
+ private _requestId;
1161
+ private _refreshReject;
1162
+ private _requestTimer;
1163
+ private _destroyed;
1128
1164
  constructor(hostOrigin: string);
1165
+ setHostOrigin(origin: string): void;
1129
1166
  /** Set the initial token received from the host's `verentis:init` message */
1130
1167
  setToken(info: TokenInfo): void;
1131
1168
  getAuthHeader(): Promise<string | null>;
@@ -1135,6 +1172,7 @@ declare class BridgeAuth implements AuthStrategy {
1135
1172
  private requestRefresh;
1136
1173
  private handleMessage;
1137
1174
  private scheduleRefresh;
1175
+ private failRefresh;
1138
1176
  }
1139
1177
 
1140
1178
  /**
@@ -1164,4 +1202,4 @@ declare class BridgeAuth implements AuthStrategy {
1164
1202
  */
1165
1203
  declare function createVerentisClient(options?: VerentisClientOptions): VerentisClient;
1166
1204
 
1167
- export { ApiError, ApiKeyAuth, type AppContext, type AppSurface, type AppToHostMessage, type ApplicationDisplayOptions, type ApplicationEntryPoint, type ApplicationFileType, type ApplicationLaunchConfig, type ApplicationManifest, type ApplicationSpec, type ArchiveFormat, type AuthOptions, type AuthStrategy, Bridge, BridgeAuth, type CatalogImage, ContextModule, type DeleteFileOptions, type EngineFileType, type EngineRuntime, type EngineTool, EnginesModule, type EntryPointInfo, type ExecuteEngineOptions, type Execution, type ExecutionEngine, type ExecutionEngineListOptions, type ExecutionListOptions, type ExecutionLogs, type ExecutionMode, type ExecutionResult, type ExecutionScopedOptions, type ExecutionStatus, type ExecutionTrigger, ExecutionsModule, type ExtractUploadOptions, type FileAppContext, type FileEntry, type FileInfo, FilesModule, type GetFileOptions, type HeaderAction, type HeaderActionHandler, type HeaderActionRegistration, type HeaderActionResult, type HostToAppMessage, HttpTransport, type Installation, type InstallationDetail, type InstallationLifecycleResult, type InstallationListOptions, type InstallationMode, type InstallationScopedOptions, type InstallationStatus, InstallationsModule, type InstalledPackageDescriptor, type InstalledPackagePayload, type ManifestMetadata, type MimeTypeBinding, type MoveFileOptions, type NamespacedSettings, type NavigateOptions, type OAuthConfig, type PagedResult, type ReadArchiveOptions, type RequestOptions, type ResolveInstallationOptions, type ResourceMimeTypeBinding, type ResourceRegistration, type ResourceScopedOptions, ResourcesModule, type RunFileOptions, type SandboxOptions, type SettingDeclaration, type SettingDeclarationType, type SettingGroup, type SettingItem, type SettingOption, type SettingPresence, SettingsModule, type SettingsScopedOptions, TokenAuth, type TokenInfo, type UpdateInstallationOptions, type VerentisActionInvokeMessage, type VerentisActionResultMessage, type VerentisActionsSetMessage, VerentisClient, type VerentisClientOptions, type VerentisDirtyMessage, type VerentisFileChangedMessage, type VerentisInitMessage, type VerentisMessage, type VerentisNavigateMessage, type VerentisReadyMessage, type VerentisResizeMessage, type VerentisThemeMessage, type VerentisTitleMessage, type VerentisTokenRefreshMessage, type VerentisTokenRefreshedMessage, type WaitOptions, type WorkspaceAppContext, type WorkspaceInfo, type WriteFileOptions, createVerentisClient, findBestMatch, isHeaderAction, isTerminalStatus, matchMimeType };
1205
+ export { ApiError, ApiKeyAuth, type AppBackendCredential, type AppContext, type AppSurface, type AppToHostMessage, type ApplicationDisplayOptions, type ApplicationEntryPoint, type ApplicationFileType, type ApplicationLaunchConfig, type ApplicationManifest, type ApplicationSpec, type ArchiveFormat, type AuthOptions, type AuthStrategy, Bridge, BridgeAuth, type CatalogImage, ContextModule, type DeleteFileOptions, type EngineFileType, type EngineRuntime, type EngineTool, EnginesModule, type EntryPointInfo, type ExecuteEngineOptions, type Execution, type ExecutionEngine, type ExecutionEngineListOptions, type ExecutionListOptions, type ExecutionLogs, type ExecutionMode, type ExecutionResult, type ExecutionScopedOptions, type ExecutionStatus, type ExecutionTrigger, ExecutionsModule, type ExtractUploadOptions, type FileAppContext, type FileEntry, type FileInfo, FilesModule, type GetFileOptions, type HeaderAction, type HeaderActionHandler, type HeaderActionRegistration, type HeaderActionResult, type HostToAppMessage, HttpTransport, type Installation, type InstallationDetail, type InstallationLifecycleResult, type InstallationListOptions, type InstallationMode, type InstallationScopedOptions, type InstallationStatus, InstallationsModule, type InstalledPackageDescriptor, type InstalledPackagePayload, type ManifestMetadata, type MimeTypeBinding, type MoveFileOptions, type NamespacedSettings, type NavigateOptions, type OAuthConfig, type PagedResult, type ReadArchiveOptions, type RequestOptions, type ResolveInstallationOptions, type ResourceMimeTypeBinding, type ResourceRegistration, type ResourceScopedOptions, ResourcesModule, type RunFileOptions, type SandboxOptions, type SettingDeclaration, type SettingDeclarationType, type SettingGroup, type SettingItem, type SettingOption, type SettingPresence, SettingsModule, type SettingsScopedOptions, TokenAuth, type TokenInfo, type UpdateInstallationOptions, type VerentisActionInvokeMessage, type VerentisActionResultMessage, type VerentisActionsSetMessage, type VerentisBackendCredentialRequest, type VerentisBackendCredentialResponse, VerentisClient, type VerentisClientOptions, type VerentisDirtyMessage, type VerentisFileChangedMessage, type VerentisInitMessage, type VerentisMessage, type VerentisNavigateMessage, type VerentisReadyMessage, type VerentisResizeMessage, type VerentisThemeMessage, type VerentisTitleMessage, type VerentisTokenRefreshMessage, type VerentisTokenRefreshedMessage, type WaitOptions, type WorkspaceAppContext, type WorkspaceInfo, type WriteFileOptions, createVerentisClient, findBestMatch, isHeaderAction, isTerminalStatus, matchMimeType };
package/dist/index.d.ts CHANGED
@@ -62,6 +62,25 @@ interface VerentisTokenRefreshedMessage extends VerentisMessage {
62
62
  requestId: string;
63
63
  token: TokenInfo;
64
64
  }
65
+ /** Single-use credential for the installation's independently registered backend. */
66
+ interface AppBackendCredential {
67
+ delegationId: string;
68
+ backendClientId: string;
69
+ launchCredential: string;
70
+ expiresAt: string;
71
+ }
72
+ interface VerentisBackendCredentialRequest extends VerentisMessage {
73
+ type: 'verentis:backend:request';
74
+ requestId: string;
75
+ sessionId: string;
76
+ }
77
+ interface VerentisBackendCredentialResponse extends VerentisMessage {
78
+ type: 'verentis:backend:response';
79
+ requestId: string;
80
+ sessionId: string;
81
+ credential?: AppBackendCredential;
82
+ error?: string;
83
+ }
65
84
  interface VerentisFileChangedMessage extends VerentisMessage {
66
85
  type: 'verentis:file:changed';
67
86
  path: string;
@@ -99,13 +118,18 @@ interface VerentisDirtyMessage extends VerentisMessage {
99
118
  type: 'verentis:dirty';
100
119
  isDirty: boolean;
101
120
  }
102
- type HostToAppMessage = VerentisInitMessage | VerentisActionInvokeMessage | VerentisTokenRefreshedMessage | VerentisFileChangedMessage | VerentisThemeMessage;
103
- type AppToHostMessage = VerentisReadyMessage | VerentisActionsSetMessage | VerentisActionResultMessage | VerentisTokenRefreshMessage | VerentisNavigateMessage | VerentisResizeMessage | VerentisTitleMessage | VerentisDirtyMessage;
121
+ type HostToAppMessage = VerentisInitMessage | VerentisActionInvokeMessage | VerentisTokenRefreshedMessage | VerentisFileChangedMessage | VerentisThemeMessage | VerentisBackendCredentialResponse;
122
+ type AppToHostMessage = VerentisReadyMessage | VerentisActionsSetMessage | VerentisActionResultMessage | VerentisTokenRefreshMessage | VerentisNavigateMessage | VerentisResizeMessage | VerentisTitleMessage | VerentisDirtyMessage | VerentisBackendCredentialRequest;
104
123
  type AppSurface = 'file' | 'workspace';
105
124
  interface AppContextBase {
106
125
  workspace: WorkspaceInfo;
107
126
  entryPoint?: EntryPointInfo;
108
127
  apiUrl: string;
128
+ installation?: {
129
+ id: string;
130
+ backendClientId: string;
131
+ authorizationGeneration: string;
132
+ };
109
133
  }
110
134
  /** Context for an application opened against a workspace file. */
111
135
  interface FileAppContext extends AppContextBase {
@@ -138,6 +162,8 @@ interface WorkspaceInfo {
138
162
  name: string;
139
163
  }
140
164
  interface FileInfo {
165
+ nodeId?: string;
166
+ branch?: string;
141
167
  path: string;
142
168
  name: string;
143
169
  mimeType: string;
@@ -994,8 +1020,11 @@ type BridgeListener = (data: HostToAppMessage) => void;
994
1020
  * and app-to-host events (navigate, resize, dirty, etc.).
995
1021
  */
996
1022
  declare class Bridge {
1023
+ private readonly expectedHostOrigin?;
997
1024
  private listeners;
998
1025
  private _initResolve;
1026
+ private _initReject;
1027
+ private _initTimer;
999
1028
  private _initPromise;
1000
1029
  private _hostOrigin;
1001
1030
  private _messageHandler;
@@ -1003,7 +1032,8 @@ declare class Bridge {
1003
1032
  private sessionId;
1004
1033
  private actions;
1005
1034
  private requests;
1006
- constructor();
1035
+ private backendRequests;
1036
+ constructor(expectedHostOrigin?: string | undefined);
1007
1037
  /** Post `verentis:ready` to the host to start the handshake */
1008
1038
  sendReady(capabilities?: string[]): void;
1009
1039
  /** Wait for the host to send `verentis:init` with context and token */
@@ -1031,6 +1061,8 @@ declare class Bridge {
1031
1061
  setTitle(title: string): void;
1032
1062
  /** Signal unsaved changes to the host */
1033
1063
  setDirty(isDirty: boolean): void;
1064
+ /** The host, not the app, selects the installation, file, branch and permission ceiling. */
1065
+ requestBackendCredential(): Promise<AppBackendCredential>;
1034
1066
  registerAction(descriptor: HeaderAction, handler: HeaderActionHandler): HeaderActionRegistration;
1035
1067
  private publishActions;
1036
1068
  private invokeAction;
@@ -1119,13 +1151,18 @@ declare class TokenAuth implements AuthStrategy {
1119
1151
  * by requesting a new token from the host when nearing expiry.
1120
1152
  */
1121
1153
  declare class BridgeAuth implements AuthStrategy {
1122
- private readonly hostOrigin;
1154
+ private hostOrigin;
1123
1155
  private _token;
1124
1156
  private _expiresAt;
1125
1157
  private _refreshTimer;
1126
1158
  private _pendingRefresh;
1127
1159
  private _messageHandler;
1160
+ private _requestId;
1161
+ private _refreshReject;
1162
+ private _requestTimer;
1163
+ private _destroyed;
1128
1164
  constructor(hostOrigin: string);
1165
+ setHostOrigin(origin: string): void;
1129
1166
  /** Set the initial token received from the host's `verentis:init` message */
1130
1167
  setToken(info: TokenInfo): void;
1131
1168
  getAuthHeader(): Promise<string | null>;
@@ -1135,6 +1172,7 @@ declare class BridgeAuth implements AuthStrategy {
1135
1172
  private requestRefresh;
1136
1173
  private handleMessage;
1137
1174
  private scheduleRefresh;
1175
+ private failRefresh;
1138
1176
  }
1139
1177
 
1140
1178
  /**
@@ -1164,4 +1202,4 @@ declare class BridgeAuth implements AuthStrategy {
1164
1202
  */
1165
1203
  declare function createVerentisClient(options?: VerentisClientOptions): VerentisClient;
1166
1204
 
1167
- export { ApiError, ApiKeyAuth, type AppContext, type AppSurface, type AppToHostMessage, type ApplicationDisplayOptions, type ApplicationEntryPoint, type ApplicationFileType, type ApplicationLaunchConfig, type ApplicationManifest, type ApplicationSpec, type ArchiveFormat, type AuthOptions, type AuthStrategy, Bridge, BridgeAuth, type CatalogImage, ContextModule, type DeleteFileOptions, type EngineFileType, type EngineRuntime, type EngineTool, EnginesModule, type EntryPointInfo, type ExecuteEngineOptions, type Execution, type ExecutionEngine, type ExecutionEngineListOptions, type ExecutionListOptions, type ExecutionLogs, type ExecutionMode, type ExecutionResult, type ExecutionScopedOptions, type ExecutionStatus, type ExecutionTrigger, ExecutionsModule, type ExtractUploadOptions, type FileAppContext, type FileEntry, type FileInfo, FilesModule, type GetFileOptions, type HeaderAction, type HeaderActionHandler, type HeaderActionRegistration, type HeaderActionResult, type HostToAppMessage, HttpTransport, type Installation, type InstallationDetail, type InstallationLifecycleResult, type InstallationListOptions, type InstallationMode, type InstallationScopedOptions, type InstallationStatus, InstallationsModule, type InstalledPackageDescriptor, type InstalledPackagePayload, type ManifestMetadata, type MimeTypeBinding, type MoveFileOptions, type NamespacedSettings, type NavigateOptions, type OAuthConfig, type PagedResult, type ReadArchiveOptions, type RequestOptions, type ResolveInstallationOptions, type ResourceMimeTypeBinding, type ResourceRegistration, type ResourceScopedOptions, ResourcesModule, type RunFileOptions, type SandboxOptions, type SettingDeclaration, type SettingDeclarationType, type SettingGroup, type SettingItem, type SettingOption, type SettingPresence, SettingsModule, type SettingsScopedOptions, TokenAuth, type TokenInfo, type UpdateInstallationOptions, type VerentisActionInvokeMessage, type VerentisActionResultMessage, type VerentisActionsSetMessage, VerentisClient, type VerentisClientOptions, type VerentisDirtyMessage, type VerentisFileChangedMessage, type VerentisInitMessage, type VerentisMessage, type VerentisNavigateMessage, type VerentisReadyMessage, type VerentisResizeMessage, type VerentisThemeMessage, type VerentisTitleMessage, type VerentisTokenRefreshMessage, type VerentisTokenRefreshedMessage, type WaitOptions, type WorkspaceAppContext, type WorkspaceInfo, type WriteFileOptions, createVerentisClient, findBestMatch, isHeaderAction, isTerminalStatus, matchMimeType };
1205
+ export { ApiError, ApiKeyAuth, type AppBackendCredential, type AppContext, type AppSurface, type AppToHostMessage, type ApplicationDisplayOptions, type ApplicationEntryPoint, type ApplicationFileType, type ApplicationLaunchConfig, type ApplicationManifest, type ApplicationSpec, type ArchiveFormat, type AuthOptions, type AuthStrategy, Bridge, BridgeAuth, type CatalogImage, ContextModule, type DeleteFileOptions, type EngineFileType, type EngineRuntime, type EngineTool, EnginesModule, type EntryPointInfo, type ExecuteEngineOptions, type Execution, type ExecutionEngine, type ExecutionEngineListOptions, type ExecutionListOptions, type ExecutionLogs, type ExecutionMode, type ExecutionResult, type ExecutionScopedOptions, type ExecutionStatus, type ExecutionTrigger, ExecutionsModule, type ExtractUploadOptions, type FileAppContext, type FileEntry, type FileInfo, FilesModule, type GetFileOptions, type HeaderAction, type HeaderActionHandler, type HeaderActionRegistration, type HeaderActionResult, type HostToAppMessage, HttpTransport, type Installation, type InstallationDetail, type InstallationLifecycleResult, type InstallationListOptions, type InstallationMode, type InstallationScopedOptions, type InstallationStatus, InstallationsModule, type InstalledPackageDescriptor, type InstalledPackagePayload, type ManifestMetadata, type MimeTypeBinding, type MoveFileOptions, type NamespacedSettings, type NavigateOptions, type OAuthConfig, type PagedResult, type ReadArchiveOptions, type RequestOptions, type ResolveInstallationOptions, type ResourceMimeTypeBinding, type ResourceRegistration, type ResourceScopedOptions, ResourcesModule, type RunFileOptions, type SandboxOptions, type SettingDeclaration, type SettingDeclarationType, type SettingGroup, type SettingItem, type SettingOption, type SettingPresence, SettingsModule, type SettingsScopedOptions, TokenAuth, type TokenInfo, type UpdateInstallationOptions, type VerentisActionInvokeMessage, type VerentisActionResultMessage, type VerentisActionsSetMessage, type VerentisBackendCredentialRequest, type VerentisBackendCredentialResponse, VerentisClient, type VerentisClientOptions, type VerentisDirtyMessage, type VerentisFileChangedMessage, type VerentisInitMessage, type VerentisMessage, type VerentisNavigateMessage, type VerentisReadyMessage, type VerentisResizeMessage, type VerentisThemeMessage, type VerentisTitleMessage, type VerentisTokenRefreshMessage, type VerentisTokenRefreshedMessage, type WaitOptions, type WorkspaceAppContext, type WorkspaceInfo, type WriteFileOptions, createVerentisClient, findBestMatch, isHeaderAction, isTerminalStatus, matchMimeType };
package/dist/index.js CHANGED
@@ -28,6 +28,14 @@ var BridgeAuth = class {
28
28
  _refreshTimer = null;
29
29
  _pendingRefresh = null;
30
30
  _messageHandler;
31
+ _requestId = null;
32
+ _refreshReject = null;
33
+ _requestTimer = null;
34
+ _destroyed = false;
35
+ setHostOrigin(origin) {
36
+ if (!origin || origin === "*" || origin === "null") throw new Error("A trusted host origin is required.");
37
+ this.hostOrigin = origin;
38
+ }
31
39
  /** Set the initial token received from the host's `verentis:init` message */
32
40
  setToken(info) {
33
41
  this._token = info.accessToken;
@@ -42,7 +50,9 @@ var BridgeAuth = class {
42
50
  return `Bearer ${this._token}`;
43
51
  }
44
52
  destroy() {
53
+ this._destroyed = true;
45
54
  if (this._refreshTimer) clearTimeout(this._refreshTimer);
55
+ this.failRefresh("Authentication has been destroyed.");
46
56
  if (typeof window !== "undefined") {
47
57
  window.removeEventListener("message", this._messageHandler);
48
58
  }
@@ -52,11 +62,16 @@ var BridgeAuth = class {
52
62
  }
53
63
  _refreshResolve = null;
54
64
  requestRefresh() {
65
+ if (this._destroyed || this.hostOrigin === "*")
66
+ return Promise.reject(new Error("Authentication is not initialized."));
55
67
  if (this._pendingRefresh) return this._pendingRefresh;
56
68
  const requestId = crypto.randomUUID();
57
- this._pendingRefresh = new Promise((resolve) => {
69
+ this._requestId = requestId;
70
+ this._pendingRefresh = new Promise((resolve, reject) => {
58
71
  this._refreshResolve = resolve;
72
+ this._refreshReject = reject;
59
73
  });
74
+ this._requestTimer = setTimeout(() => this.failRefresh("Token refresh timed out."), 2e4);
60
75
  const message = {
61
76
  type: "verentis:token:refresh",
62
77
  version: 1,
@@ -66,21 +81,35 @@ var BridgeAuth = class {
66
81
  return this._pendingRefresh;
67
82
  }
68
83
  handleMessage(event) {
69
- if (event.origin !== this.hostOrigin) return;
84
+ if (this._destroyed || event.origin !== this.hostOrigin || event.source !== window.parent) return;
70
85
  const data = event.data;
71
- if (data?.type !== "verentis:token:refreshed") return;
86
+ if (data?.version !== 1 || data?.type !== "verentis:token:refreshed" || !this._requestId || data.requestId !== this._requestId || typeof data.token?.accessToken !== "string" || !Number.isFinite(Date.parse(data.token.expiresAt)) || Date.parse(data.token.expiresAt) <= Date.now() + SKEW_MS) return;
87
+ if (this._requestTimer) clearTimeout(this._requestTimer);
88
+ this._requestTimer = null;
89
+ this._requestId = null;
72
90
  this._token = data.token.accessToken;
73
91
  this._expiresAt = new Date(data.token.expiresAt).getTime();
74
92
  this._pendingRefresh = null;
75
93
  this._refreshResolve?.();
76
94
  this._refreshResolve = null;
95
+ this._refreshReject = null;
77
96
  this.scheduleRefresh();
78
97
  }
79
98
  scheduleRefresh() {
80
99
  if (this._refreshTimer) clearTimeout(this._refreshTimer);
81
100
  if (this._expiresAt === 0) return;
82
101
  const delay2 = Math.max(0, this._expiresAt - Date.now() - SKEW_MS);
83
- this._refreshTimer = setTimeout(() => void this.requestRefresh(), delay2);
102
+ this._refreshTimer = setTimeout(() => void this.requestRefresh().catch(() => {
103
+ }), delay2);
104
+ }
105
+ failRefresh(message) {
106
+ if (this._requestTimer) clearTimeout(this._requestTimer);
107
+ this._requestTimer = null;
108
+ this._requestId = null;
109
+ this._pendingRefresh = null;
110
+ this._refreshReject?.(new Error(message));
111
+ this._refreshReject = null;
112
+ this._refreshResolve = null;
84
113
  }
85
114
  };
86
115
 
@@ -752,8 +781,24 @@ function isHeaderAction(value) {
752
781
 
753
782
  // src/transport/bridge.transport.ts
754
783
  var Bridge = class {
784
+ constructor(expectedHostOrigin) {
785
+ this.expectedHostOrigin = expectedHostOrigin;
786
+ this._initPromise = new Promise((resolve, reject) => {
787
+ this._initResolve = resolve;
788
+ this._initReject = reject;
789
+ });
790
+ void this._initPromise.catch(() => {
791
+ });
792
+ this._messageHandler = this.handleMessage.bind(this);
793
+ if (typeof window !== "undefined") {
794
+ window.addEventListener("message", this._messageHandler);
795
+ }
796
+ }
797
+ expectedHostOrigin;
755
798
  listeners = /* @__PURE__ */ new Map();
756
799
  _initResolve;
800
+ _initReject;
801
+ _initTimer;
757
802
  _initPromise;
758
803
  _hostOrigin = null;
759
804
  _messageHandler;
@@ -761,15 +806,7 @@ var Bridge = class {
761
806
  sessionId = null;
762
807
  actions = /* @__PURE__ */ new Map();
763
808
  requests = /* @__PURE__ */ new Set();
764
- constructor() {
765
- this._initPromise = new Promise((resolve) => {
766
- this._initResolve = resolve;
767
- });
768
- this._messageHandler = this.handleMessage.bind(this);
769
- if (typeof window !== "undefined") {
770
- window.addEventListener("message", this._messageHandler);
771
- }
772
- }
809
+ backendRequests = /* @__PURE__ */ new Map();
773
810
  /** Post `verentis:ready` to the host to start the handshake */
774
811
  sendReady(capabilities) {
775
812
  console.info("[Verentis SDK] Sending verentis:ready to host");
@@ -782,6 +819,12 @@ var Bridge = class {
782
819
  }
783
820
  /** Wait for the host to send `verentis:init` with context and token */
784
821
  waitForInit() {
822
+ if (!this._hostOrigin && !this._destroyed && !this._initTimer) {
823
+ this._initTimer = setTimeout(() => {
824
+ this._initReject(new Error("Workspace handshake timed out."));
825
+ this.destroy();
826
+ }, 2e4);
827
+ }
785
828
  return this._initPromise;
786
829
  }
787
830
  /** Get the host origin (available after init) */
@@ -825,6 +868,28 @@ var Bridge = class {
825
868
  setDirty(isDirty) {
826
869
  this.postToHost({ type: "verentis:dirty", version: 1, isDirty });
827
870
  }
871
+ /** The host, not the app, selects the installation, file, branch and permission ceiling. */
872
+ requestBackendCredential() {
873
+ if (this._destroyed || !this.sessionId || !this._hostOrigin)
874
+ return Promise.reject(new Error("An initialized workspace host is required."));
875
+ if (this.backendRequests.size >= 4)
876
+ return Promise.reject(new Error("A backend credential request is already pending."));
877
+ const requestId = crypto.randomUUID();
878
+ return new Promise((resolve, reject) => {
879
+ const timer = setTimeout(() => {
880
+ this.backendRequests.delete(requestId);
881
+ reject(new Error("Backend authorization timed out."));
882
+ }, 2e4);
883
+ this.backendRequests.set(requestId, { resolve, reject, timer });
884
+ try {
885
+ this.postToHost({ type: "verentis:backend:request", version: 1, requestId, sessionId: this.sessionId });
886
+ } catch {
887
+ clearTimeout(timer);
888
+ this.backendRequests.delete(requestId);
889
+ reject(new Error("The workspace host is unavailable."));
890
+ }
891
+ });
892
+ }
828
893
  registerAction(descriptor, handler) {
829
894
  if (!this.sessionId || this._destroyed) throw new Error("Header actions require an initialized workspace host.");
830
895
  if (!isHeaderAction(descriptor)) throw new Error("Invalid header action.");
@@ -901,9 +966,17 @@ var Bridge = class {
901
966
  /** Clean up event listeners */
902
967
  destroy() {
903
968
  this._destroyed = true;
969
+ clearTimeout(this._initTimer);
970
+ this._initTimer = void 0;
971
+ if (!this._hostOrigin) this._initReject(new Error("Bridge has been destroyed."));
904
972
  this.actions.clear();
905
973
  this.requests.clear();
906
974
  this.listeners.clear();
975
+ for (const pending of this.backendRequests.values()) {
976
+ clearTimeout(pending.timer);
977
+ pending.reject(new Error("Bridge has been destroyed."));
978
+ }
979
+ this.backendRequests.clear();
907
980
  if (typeof window !== "undefined") {
908
981
  window.removeEventListener("message", this._messageHandler);
909
982
  }
@@ -913,8 +986,12 @@ var Bridge = class {
913
986
  const data = event.data;
914
987
  if (event.source !== window.parent || data?.version !== 1 || typeof data?.type !== "string" || !data.type.startsWith("verentis:")) return;
915
988
  if (this._hostOrigin && event.origin !== this._hostOrigin) return;
989
+ if (this.expectedHostOrigin && event.origin !== this.expectedHostOrigin) return;
916
990
  if (data.type === "verentis:init") {
917
991
  if (this._hostOrigin) return;
992
+ if (!data.context?.workspace?.id || !data.token || event.origin === "null") return;
993
+ clearTimeout(this._initTimer);
994
+ this._initTimer = void 0;
918
995
  this._hostOrigin = event.origin;
919
996
  this.sessionId = typeof data.sessionId === "string" ? data.sessionId : null;
920
997
  console.info("[Verentis SDK] Received verentis:init from host", {
@@ -925,6 +1002,18 @@ var Bridge = class {
925
1002
  const initData = data;
926
1003
  this._initResolve({ context: initData.context, token: initData.token });
927
1004
  }
1005
+ if (data.type === "verentis:backend:response") {
1006
+ if (!this._hostOrigin || data.sessionId !== this.sessionId) return;
1007
+ const pending = this.backendRequests.get(data.requestId);
1008
+ if (!pending) return;
1009
+ clearTimeout(pending.timer);
1010
+ this.backendRequests.delete(data.requestId);
1011
+ const value = data.credential;
1012
+ if (data.error || !value || typeof value.launchCredential !== "string" || value.launchCredential.length > 512 || !value.launchCredential || typeof value.delegationId !== "string" || typeof value.backendClientId !== "string" || !Number.isFinite(Date.parse(value.expiresAt)) || Date.parse(value.expiresAt) <= Date.now())
1013
+ pending.reject(new Error("Backend authorization was denied or is not configured."));
1014
+ else pending.resolve(value);
1015
+ return;
1016
+ }
928
1017
  if (data.type === "verentis:action:invoke") {
929
1018
  void this.invokeAction(data);
930
1019
  return;
@@ -1110,7 +1199,7 @@ var VerentisClient = class {
1110
1199
  this.bridge.sendReady();
1111
1200
  const { context, token } = await this.bridge.waitForInit();
1112
1201
  const hostOrigin = this.bridge.hostOrigin;
1113
- Object.assign(bridgeAuth, new BridgeAuth(hostOrigin));
1202
+ bridgeAuth.setHostOrigin(hostOrigin);
1114
1203
  bridgeAuth.setToken(token);
1115
1204
  this.context.setFromAppContext(context);
1116
1205
  const http = new HttpTransport(