@pulse-editor/react-api 0.1.1-beta.84 → 0.1.1-beta.86

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,13 +1,4 @@
1
1
  import { OAuthConnectConfig } from "@pulse-editor/shared-utils";
2
- export type OAuthState = {
3
- accessToken?: string;
4
- refreshToken?: string;
5
- tokenType?: string;
6
- scope?: string;
7
- expiresAt?: string | number;
8
- idToken?: string;
9
- [key: string]: any;
10
- };
11
2
  /**
12
3
  * Hook to manage OAuth credentials for a Pulse App.
13
4
  *
@@ -23,14 +14,7 @@ export type OAuthState = {
23
14
  export default function useOAuth(appId: string, provider?: string): {
24
15
  isReady: boolean;
25
16
  isLoading: boolean;
26
- oauth: OAuthState | null;
27
17
  isAuthenticated: boolean;
28
18
  connect: (config: OAuthConnectConfig) => Promise<void>;
29
19
  disconnect: () => Promise<void>;
30
- refetchOAuth: () => Promise<void>;
31
- refreshToken: (params: {
32
- tokenEndpoint: string;
33
- clientId: string;
34
- clientSecret?: string;
35
- }) => Promise<OAuthState | null>;
36
20
  };
package/dist/main.d.ts CHANGED
@@ -14,11 +14,10 @@ import useVideoGen from "./hooks/ai-modality/use-video-gen";
14
14
  import useAppSettings from "./hooks/editor/use-app-settings";
15
15
  import { useArtifact } from "./hooks/editor/use-artifact";
16
16
  import useEditorEnv from "./hooks/editor/use-editor-env";
17
+ import useOAuth from "./hooks/editor/use-oauth";
17
18
  import useOpenApp from "./hooks/editor/use-open-app";
18
19
  import useOpenLink from "./hooks/editor/use-open-link";
19
20
  import useOwnedAppView from "./hooks/editor/use-owned-app-view";
20
- import useOAuth from "./hooks/editor/use-oauth";
21
- export type { OAuthState } from "./hooks/editor/use-oauth";
22
21
  import useSnapshotState from "./hooks/editor/use-snapshot-state";
23
22
  import { useTranslations } from "./hooks/editor/use-translations";
24
23
  import useFileSystem from "./hooks/workspace/use-file-system";
@@ -27,4 +26,4 @@ import useTerminal from "./hooks/workspace/use-terminal";
27
26
  import useWorkspaceInfo from "./hooks/workspace/use-workspace-info";
28
27
  import ReceiveFileProvider from "./providers/receive-file-provider";
29
28
  import SnapshotProvider from "./providers/snapshot-provider";
30
- export { ReceiveFileProvider, SnapshotProvider, useActionEffect, useAgents, useAgentTools, useAppSettings, useArtifact, useEditorEnv, useFile, useFileSystem, useImageGen, useLLM, useLoading, useNotification, useOCR, useOpenApp, useOpenLink, useOAuth, useOwnedAppView, useReceiveFile, useSnapshotState, useSTT, useTerminal, useTheme, useTranslations, useTTS, useVideoGen, useWorkspaceInfo, };
29
+ export { ReceiveFileProvider, SnapshotProvider, useActionEffect, useAgents, useAgentTools, useAppSettings, useArtifact, useEditorEnv, useFile, useFileSystem, useImageGen, useLLM, useLoading, useNotification, useOAuth, useOCR, useOpenApp, useOpenLink, useOwnedAppView, useReceiveFile, useSnapshotState, useSTT, useTerminal, useTheme, useTranslations, useTTS, useVideoGen, useWorkspaceInfo, };
package/dist/main.js CHANGED
@@ -1,4 +1,4 @@
1
- import { InterModuleCommunication, IMCMessageTypeEnum } from '@pulse-editor/shared-utils';
1
+ import { InterModuleCommunication, IMCMessageTypeEnum, OAuthStatusEnum } from '@pulse-editor/shared-utils';
2
2
  import React, { useState, useEffect, useRef, useMemo, useCallback, createContext, useContext } from 'react';
3
3
 
4
4
  var byteToHex = [];
@@ -5704,7 +5704,7 @@ function useActionEffect(params, deps, isExtReady = true) {
5704
5704
  returns: actionInfo.returns,
5705
5705
  });
5706
5706
  // Update receiver
5707
- imc?.updateReceiverHandlerMap(getReceiverHandlerMap(func));
5707
+ imc?.updateReceiverHandlerMap(getReceiverHandlerMap(func, beforeAction, afterAction));
5708
5708
  }
5709
5709
  if (isExtReady) {
5710
5710
  updateAction();
@@ -5737,8 +5737,23 @@ function useActionEffect(params, deps, isExtReady = true) {
5737
5737
  }
5738
5738
  return afterRes !== undefined ? afterRes : res;
5739
5739
  }
5740
- function getReceiverHandlerMap(actionHandlerFunc) {
5740
+ function getReceiverHandlerMap(actionHandlerFunc, beforeActionFunc, afterActionFunc) {
5741
5741
  const receiverHandlerMap = new Map([
5742
+ [
5743
+ IMCMessageTypeEnum.EditorRestoreActionCache,
5744
+ async (_senderWindow, message) => {
5745
+ const { name, input, output } = message.payload;
5746
+ if (params.actionName !== name) {
5747
+ throw new Error("Message ignored by receiver");
5748
+ }
5749
+ if (beforeActionFunc && input !== undefined) {
5750
+ await beforeActionFunc(input);
5751
+ }
5752
+ if (afterActionFunc && output !== undefined) {
5753
+ await afterActionFunc(output);
5754
+ }
5755
+ },
5756
+ ],
5742
5757
  [
5743
5758
  IMCMessageTypeEnum.EditorRunAppAction,
5744
5759
  async (_senderWindow, message) => {
@@ -6271,68 +6286,6 @@ function useEditorEnv() {
6271
6286
  };
6272
6287
  }
6273
6288
 
6274
- function useOpenApp() {
6275
- const receiverHandlerMap = new Map();
6276
- const { imc, isReady } = useIMC(receiverHandlerMap, "open-app");
6277
- async function openApp(appId, location, version) {
6278
- if (!isReady) {
6279
- throw new Error("IMC is not ready");
6280
- }
6281
- await imc?.sendMessage(IMCMessageTypeEnum.EditorOpenApp, {
6282
- appId,
6283
- version,
6284
- location,
6285
- });
6286
- }
6287
- return {
6288
- isReady,
6289
- openApp,
6290
- };
6291
- }
6292
-
6293
- function useOpenLink() {
6294
- const receiverHandlerMap = new Map();
6295
- const { imc, isReady } = useIMC(receiverHandlerMap, "open-link");
6296
- async function openLink(url) {
6297
- if (!isReady) {
6298
- throw new Error("IMC is not ready");
6299
- }
6300
- await imc?.sendMessage(IMCMessageTypeEnum.EditorOpenLink, {
6301
- url: url.toString(),
6302
- });
6303
- }
6304
- return {
6305
- isReady,
6306
- openLink,
6307
- };
6308
- }
6309
-
6310
- function useOwnedAppView() {
6311
- const receiverHandlerMap = new Map([]);
6312
- const { imc, isReady } = useIMC(receiverHandlerMap, "owned-app");
6313
- const runAppAction = useCallback(async (ownedAppViewModel, actionName, args) => {
6314
- if (isReady) {
6315
- const appViewId = ownedAppViewModel.viewId;
6316
- const skillActions = ownedAppViewModel.appConfig.actions || [];
6317
- const action = skillActions.find((a) => a.name === actionName);
6318
- if (!action) {
6319
- throw new Error(`Action ${actionName} not found in owned app ${ownedAppViewModel.appConfig.id}`);
6320
- }
6321
- const result = await imc?.sendMessage(IMCMessageTypeEnum.EditorAppUseOwnedApp, {
6322
- viewId: appViewId,
6323
- actionName,
6324
- args,
6325
- });
6326
- return result;
6327
- }
6328
- return undefined;
6329
- }, [imc, isReady]);
6330
- return {
6331
- isReady,
6332
- runAppAction,
6333
- };
6334
- }
6335
-
6336
6289
  function generateRandomString(length) {
6337
6290
  const array = new Uint8Array(length);
6338
6291
  crypto.getRandomValues(array);
@@ -6351,18 +6304,24 @@ function generateRandomString(length) {
6351
6304
  * @param provider A provider identifier used to namespace the OAuth state.
6352
6305
  */
6353
6306
  function useOAuth(appId, provider = "default") {
6354
- const { isReady, isLoaded, settings, deleteSetting, refetch } = useAppSettings(appId);
6355
- const keyPrefix = `oauth:${provider}:`;
6356
- const oauthEntries = Object.entries(settings).filter(([k]) => k.startsWith(keyPrefix));
6357
- const oauthRaw = oauthEntries.length > 0
6358
- ? Object.fromEntries(oauthEntries.map(([k, v]) => [k.slice(keyPrefix.length), v]))
6359
- : null;
6360
- const oauth = oauthRaw &&
6361
- Object.values(oauthRaw).some((v) => v !== null && v !== undefined)
6362
- ? oauthRaw
6363
- : null;
6307
+ const { isReady, isLoaded } = useAppSettings(appId);
6308
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
6364
6309
  const receiverHandlerMap = new Map();
6365
6310
  const { imc, isReady: isIMCReady } = useIMC(receiverHandlerMap, "oauth");
6311
+ async function checkAuthStatus() {
6312
+ if (!isIMCReady)
6313
+ return;
6314
+ try {
6315
+ const status = await imc?.sendMessage(IMCMessageTypeEnum.EditorOAuthCheckStatus, { appId, provider });
6316
+ setIsAuthenticated(status === OAuthStatusEnum.Authenticated);
6317
+ }
6318
+ catch {
6319
+ setIsAuthenticated(false);
6320
+ }
6321
+ }
6322
+ useEffect(() => {
6323
+ checkAuthStatus();
6324
+ }, [isIMCReady]);
6366
6325
  /**
6367
6326
  * Initiate the OAuth flow. The editor handles everything:
6368
6327
  * - Dynamic client registration (if `registrationEndpoint` is provided and `clientId` is omitted)
@@ -6388,66 +6347,99 @@ function useOAuth(appId, provider = "default") {
6388
6347
  });
6389
6348
  }
6390
6349
  /**
6391
- * Sign out: removes all stored OAuth tokens for this provider from the
6392
- * editor backend and resets local auth state immediately.
6350
+ * Sign out: sends a disconnect request through the editor to remove
6351
+ * stored OAuth tokens on the backend for this provider.
6393
6352
  */
6394
6353
  async function disconnect() {
6395
- // Collect keys before deletion so we don't rely on stale `oauth`
6396
- const keysToDelete = oauthEntries.map(([k]) => k);
6397
- await Promise.all(keysToDelete.map((key) => deleteSetting(key)));
6398
- }
6399
- /**
6400
- * Re-fetch OAuth state from app settings.
6401
- * Call this after the user completes the OAuth flow in the external window.
6402
- */
6403
- async function refetchOAuth() {
6404
- await refetch();
6354
+ if (!isIMCReady) {
6355
+ throw new Error("IMC is not ready.");
6356
+ }
6357
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorOAuthDisconnect, {
6358
+ appId,
6359
+ provider,
6360
+ });
6361
+ setIsAuthenticated(false);
6405
6362
  }
6406
- // Revalidate OAuth state when the user returns to the tab
6363
+ // Revalidate OAuth status when the user returns to the tab
6407
6364
  useEffect(() => {
6408
6365
  function handleVisibilityChange() {
6409
6366
  if (document.visibilityState === "visible") {
6410
- refetch();
6367
+ checkAuthStatus();
6411
6368
  }
6412
6369
  }
6413
6370
  document.addEventListener("visibilitychange", handleVisibilityChange);
6414
6371
  return () => {
6415
6372
  document.removeEventListener("visibilitychange", handleVisibilityChange);
6416
6373
  };
6417
- }, [isReady]);
6418
- /**
6419
- * Refresh the access token using the stored refresh token.
6420
- * The editor backend exchanges the refresh token with the OAuth provider
6421
- * and persists the new tokens automatically.
6422
- */
6423
- async function refreshToken(params) {
6424
- if (!isIMCReady) {
6425
- throw new Error("IMC is not ready.");
6426
- }
6427
- if (!oauth?.refreshToken) {
6428
- throw new Error("No refresh token available.");
6374
+ }, [isIMCReady]);
6375
+ return {
6376
+ isReady,
6377
+ isLoading: !isLoaded,
6378
+ isAuthenticated,
6379
+ connect,
6380
+ disconnect,
6381
+ };
6382
+ }
6383
+
6384
+ function useOpenApp() {
6385
+ const receiverHandlerMap = new Map();
6386
+ const { imc, isReady } = useIMC(receiverHandlerMap, "open-app");
6387
+ async function openApp(appId, location, version) {
6388
+ if (!isReady) {
6389
+ throw new Error("IMC is not ready");
6429
6390
  }
6430
- const result = await imc?.sendMessage(IMCMessageTypeEnum.EditorOAuthRefreshToken, {
6391
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorOpenApp, {
6431
6392
  appId,
6432
- provider,
6433
- tokenEndpoint: params.tokenEndpoint,
6434
- refreshToken: oauth.refreshToken,
6435
- clientId: params.clientId,
6436
- clientSecret: params.clientSecret,
6393
+ version,
6394
+ location,
6437
6395
  });
6438
- // Re-fetch settings to sync local state
6439
- await refetchOAuth();
6440
- return result ?? null;
6441
6396
  }
6442
6397
  return {
6443
6398
  isReady,
6444
- isLoading: !isLoaded,
6445
- oauth,
6446
- isAuthenticated: Boolean(oauth?.accessToken),
6447
- connect,
6448
- disconnect,
6449
- refetchOAuth,
6450
- refreshToken,
6399
+ openApp,
6400
+ };
6401
+ }
6402
+
6403
+ function useOpenLink() {
6404
+ const receiverHandlerMap = new Map();
6405
+ const { imc, isReady } = useIMC(receiverHandlerMap, "open-link");
6406
+ async function openLink(url) {
6407
+ if (!isReady) {
6408
+ throw new Error("IMC is not ready");
6409
+ }
6410
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorOpenLink, {
6411
+ url: url.toString(),
6412
+ });
6413
+ }
6414
+ return {
6415
+ isReady,
6416
+ openLink,
6417
+ };
6418
+ }
6419
+
6420
+ function useOwnedAppView() {
6421
+ const receiverHandlerMap = new Map([]);
6422
+ const { imc, isReady } = useIMC(receiverHandlerMap, "owned-app");
6423
+ const runAppAction = useCallback(async (ownedAppViewModel, actionName, args) => {
6424
+ if (isReady) {
6425
+ const appViewId = ownedAppViewModel.viewId;
6426
+ const skillActions = ownedAppViewModel.appConfig.actions || [];
6427
+ const action = skillActions.find((a) => a.name === actionName);
6428
+ if (!action) {
6429
+ throw new Error(`Action ${actionName} not found in owned app ${ownedAppViewModel.appConfig.id}`);
6430
+ }
6431
+ const result = await imc?.sendMessage(IMCMessageTypeEnum.EditorAppUseOwnedApp, {
6432
+ viewId: appViewId,
6433
+ actionName,
6434
+ args,
6435
+ });
6436
+ return result;
6437
+ }
6438
+ return undefined;
6439
+ }, [imc, isReady]);
6440
+ return {
6441
+ isReady,
6442
+ runAppAction,
6451
6443
  };
6452
6444
  }
6453
6445