@pulse-editor/react-api 0.1.1-beta.83 → 0.1.1-beta.85

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.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Hook to access and update persisted settings for a specific app in the editor.
3
+ * @param appId The ID of the app whose settings should be retrieved and updated.
4
+ * @returns `isReady`, the current `settings` object, and an `updateSettings` function.
5
+ */
6
+ export default function useAppSettings(appId: string): {
7
+ isReady: boolean;
8
+ isLoaded: boolean;
9
+ settings: Record<string, any>;
10
+ refetch: () => Promise<void>;
11
+ updateSettings: (newSettings: Record<string, any>) => Promise<void>;
12
+ deleteSetting: (key: string) => Promise<void>;
13
+ };
@@ -0,0 +1,20 @@
1
+ import { OAuthConnectConfig } from "@pulse-editor/shared-utils";
2
+ /**
3
+ * Hook to manage OAuth credentials for a Pulse App.
4
+ *
5
+ * Handles the full OAuth flow automatically:
6
+ * - Dynamic client registration (RFC 7591) when `registrationEndpoint` is provided
7
+ * - PKCE code challenge generation
8
+ * - Opening the authorization modal
9
+ * - Token exchange and storage (via the Pulse Editor backend)
10
+ *
11
+ * @param appId The ID of the app.
12
+ * @param provider A provider identifier used to namespace the OAuth state.
13
+ */
14
+ export default function useOAuth(appId: string, provider?: string): {
15
+ isReady: boolean;
16
+ isLoading: boolean;
17
+ isAuthenticated: boolean;
18
+ connect: (config: OAuthConnectConfig) => Promise<void>;
19
+ disconnect: () => Promise<void>;
20
+ };
@@ -1 +1,9 @@
1
- export default function useSnapShotState<T>(key: string, initialValue?: T, onRestore?: (value: T) => void): readonly [T, import("react").Dispatch<import("react").SetStateAction<T>>];
1
+ /**
2
+ * A hook that syncs state with a snapshot context,
3
+ * allowing for state restoration across component unmounts and remounts.
4
+ * @param key
5
+ * @param initialValue
6
+ * @param onRestore
7
+ * @returns
8
+ */
9
+ export default function useSnapshotState<T>(key: string, initialValue?: T, onRestore?: (value: T) => void): readonly [T, import("react").Dispatch<import("react").SetStateAction<T>>];
package/dist/main.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import useAgentTools from "./hooks/agent/use-agent-tools";
2
2
  import useAgents from "./hooks/agent/use-agents";
3
+ import useActionEffect from "./hooks/editor/use-action-effect";
3
4
  import useLoading from "./hooks/editor/use-loading";
4
5
  import useNotification from "./hooks/editor/use-notification";
5
- import useActionEffect from "./hooks/editor/use-action-effect";
6
6
  import useTheme from "./hooks/editor/use-theme";
7
7
  import useFile from "./hooks/workspace/use-file";
8
8
  import useImageGen from "./hooks/ai-modality/use-image-gen";
@@ -11,8 +11,10 @@ import useOCR from "./hooks/ai-modality/use-ocr";
11
11
  import useSTT from "./hooks/ai-modality/use-stt";
12
12
  import useTTS from "./hooks/ai-modality/use-tts";
13
13
  import useVideoGen from "./hooks/ai-modality/use-video-gen";
14
+ import useAppSettings from "./hooks/editor/use-app-settings";
14
15
  import { useArtifact } from "./hooks/editor/use-artifact";
15
16
  import useEditorEnv from "./hooks/editor/use-editor-env";
17
+ import useOAuth from "./hooks/editor/use-oauth";
16
18
  import useOpenApp from "./hooks/editor/use-open-app";
17
19
  import useOpenLink from "./hooks/editor/use-open-link";
18
20
  import useOwnedAppView from "./hooks/editor/use-owned-app-view";
@@ -24,4 +26,4 @@ import useTerminal from "./hooks/workspace/use-terminal";
24
26
  import useWorkspaceInfo from "./hooks/workspace/use-workspace-info";
25
27
  import ReceiveFileProvider from "./providers/receive-file-provider";
26
28
  import SnapshotProvider from "./providers/snapshot-provider";
27
- export { ReceiveFileProvider, SnapshotProvider, useAgents, useAgentTools, useArtifact, useEditorEnv, useFile, useFileSystem, useImageGen, useLLM, useLoading, useNotification, useOCR, useOpenApp, useOpenLink, useOwnedAppView, useReceiveFile, useActionEffect, 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 = [];
@@ -492,40 +492,6 @@ function useAgents() {
492
492
  };
493
493
  }
494
494
 
495
- function useLoading() {
496
- const receiverHandlerMap = new Map();
497
- const { imc, isReady } = useIMC(receiverHandlerMap, "loading");
498
- const [isLoading, setIsLoading] = useState(true);
499
- useEffect(() => {
500
- if (isReady) {
501
- imc?.sendMessage(IMCMessageTypeEnum.EditorLoadingApp, {
502
- isLoading,
503
- });
504
- }
505
- }, [isLoading]);
506
- function toggleLoading(isLoading) {
507
- setIsLoading((prev) => isLoading);
508
- }
509
- return {
510
- isReady,
511
- toggleLoading,
512
- };
513
- }
514
-
515
- function useNotification() {
516
- const receiverHandlerMap = new Map();
517
- const { imc, isReady } = useIMC(receiverHandlerMap, "notification");
518
- function openNotification(text, type) {
519
- if (isReady) {
520
- imc?.sendMessage(IMCMessageTypeEnum.EditorShowNotification, {
521
- text,
522
- type,
523
- });
524
- }
525
- }
526
- return { isReady, openNotification };
527
- }
528
-
529
495
  var MANIFEST_EXT = '.json';
530
496
  var BROWSER_LOG_KEY = 'FEDERATION_DEBUG';
531
497
  var NameTransformSymbol = {
@@ -5851,6 +5817,40 @@ function useActionEffect(params, deps, isExtReady = true) {
5851
5817
  };
5852
5818
  }
5853
5819
 
5820
+ function useLoading() {
5821
+ const receiverHandlerMap = new Map();
5822
+ const { imc, isReady } = useIMC(receiverHandlerMap, "loading");
5823
+ const [isLoading, setIsLoading] = useState(true);
5824
+ useEffect(() => {
5825
+ if (isReady) {
5826
+ imc?.sendMessage(IMCMessageTypeEnum.EditorLoadingApp, {
5827
+ isLoading,
5828
+ });
5829
+ }
5830
+ }, [isLoading]);
5831
+ function toggleLoading(isLoading) {
5832
+ setIsLoading((prev) => isLoading);
5833
+ }
5834
+ return {
5835
+ isReady,
5836
+ toggleLoading,
5837
+ };
5838
+ }
5839
+
5840
+ function useNotification() {
5841
+ const receiverHandlerMap = new Map();
5842
+ const { imc, isReady } = useIMC(receiverHandlerMap, "notification");
5843
+ function openNotification(text, type) {
5844
+ if (isReady) {
5845
+ imc?.sendMessage(IMCMessageTypeEnum.EditorShowNotification, {
5846
+ text,
5847
+ type,
5848
+ });
5849
+ }
5850
+ }
5851
+ return { isReady, openNotification };
5852
+ }
5853
+
5854
5854
  function useTheme() {
5855
5855
  const [theme, setTheme] = useState("light");
5856
5856
  const receiverHandlerMap = new Map();
@@ -6182,6 +6182,54 @@ function useVideoGen() {
6182
6182
  };
6183
6183
  }
6184
6184
 
6185
+ /**
6186
+ * Hook to access and update persisted settings for a specific app in the editor.
6187
+ * @param appId The ID of the app whose settings should be retrieved and updated.
6188
+ * @returns `isReady`, the current `settings` object, and an `updateSettings` function.
6189
+ */
6190
+ function useAppSettings(appId) {
6191
+ const receiverHandlerMap = new Map();
6192
+ const { imc, isReady } = useIMC(receiverHandlerMap, "app-settings");
6193
+ const [settings, setSettings] = useState({});
6194
+ const [isLoaded, setIsLoaded] = useState(false);
6195
+ useEffect(() => {
6196
+ if (isReady) {
6197
+ refetch();
6198
+ }
6199
+ }, [isReady]);
6200
+ async function refetch() {
6201
+ const result = await imc?.sendMessage(IMCMessageTypeEnum.EditorGetAppSettings, { appId });
6202
+ setSettings(result ?? {});
6203
+ setIsLoaded(true);
6204
+ }
6205
+ async function updateSettings(newSettings) {
6206
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorSetAppSettings, {
6207
+ appId,
6208
+ settings: newSettings,
6209
+ });
6210
+ setSettings((prev) => ({ ...prev, ...newSettings }));
6211
+ }
6212
+ async function deleteSetting(key) {
6213
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorDeleteAppSetting, {
6214
+ appId,
6215
+ key,
6216
+ });
6217
+ setSettings((prev) => {
6218
+ const next = { ...prev };
6219
+ delete next[key];
6220
+ return next;
6221
+ });
6222
+ }
6223
+ return {
6224
+ isReady,
6225
+ isLoaded,
6226
+ settings,
6227
+ refetch,
6228
+ updateSettings,
6229
+ deleteSetting,
6230
+ };
6231
+ }
6232
+
6185
6233
  function useArtifact() {
6186
6234
  const receiverHandlerMap = new Map();
6187
6235
  const { imc, isReady } = useIMC(receiverHandlerMap, "artifact");
@@ -6223,6 +6271,101 @@ function useEditorEnv() {
6223
6271
  };
6224
6272
  }
6225
6273
 
6274
+ function generateRandomString(length) {
6275
+ const array = new Uint8Array(length);
6276
+ crypto.getRandomValues(array);
6277
+ return Array.from(array, (b) => b.toString(16).padStart(2, "0")).join("");
6278
+ }
6279
+ /**
6280
+ * Hook to manage OAuth credentials for a Pulse App.
6281
+ *
6282
+ * Handles the full OAuth flow automatically:
6283
+ * - Dynamic client registration (RFC 7591) when `registrationEndpoint` is provided
6284
+ * - PKCE code challenge generation
6285
+ * - Opening the authorization modal
6286
+ * - Token exchange and storage (via the Pulse Editor backend)
6287
+ *
6288
+ * @param appId The ID of the app.
6289
+ * @param provider A provider identifier used to namespace the OAuth state.
6290
+ */
6291
+ function useOAuth(appId, provider = "default") {
6292
+ const { isReady, isLoaded } = useAppSettings(appId);
6293
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
6294
+ const receiverHandlerMap = new Map();
6295
+ const { imc, isReady: isIMCReady } = useIMC(receiverHandlerMap, "oauth");
6296
+ async function checkAuthStatus() {
6297
+ if (!isIMCReady)
6298
+ return;
6299
+ try {
6300
+ const status = await imc?.sendMessage(IMCMessageTypeEnum.EditorOAuthCheckStatus, { appId, provider });
6301
+ setIsAuthenticated(status === OAuthStatusEnum.Authenticated);
6302
+ }
6303
+ catch {
6304
+ setIsAuthenticated(false);
6305
+ }
6306
+ }
6307
+ useEffect(() => {
6308
+ checkAuthStatus();
6309
+ }, [isIMCReady]);
6310
+ /**
6311
+ * Initiate the OAuth flow. The editor handles everything:
6312
+ * - Dynamic client registration (if `registrationEndpoint` is provided and `clientId` is omitted)
6313
+ * - PKCE (`codeVerifier` is auto-generated if not provided)
6314
+ * - Opening the consent modal and authorization window
6315
+ * - Token exchange and storage
6316
+ */
6317
+ async function connect(config) {
6318
+ if (!isIMCReady) {
6319
+ throw new Error("IMC is not ready.");
6320
+ }
6321
+ // Auto-generate PKCE code verifier if not provided
6322
+ const resolvedConfig = { ...config };
6323
+ if (!resolvedConfig.codeVerifier) {
6324
+ resolvedConfig.codeVerifier = generateRandomString(64);
6325
+ resolvedConfig.codeChallengeMethod =
6326
+ resolvedConfig.codeChallengeMethod ?? "S256";
6327
+ }
6328
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorOAuthConnect, {
6329
+ appId,
6330
+ provider,
6331
+ config: resolvedConfig,
6332
+ });
6333
+ }
6334
+ /**
6335
+ * Sign out: sends a disconnect request through the editor to remove
6336
+ * stored OAuth tokens on the backend for this provider.
6337
+ */
6338
+ async function disconnect() {
6339
+ if (!isIMCReady) {
6340
+ throw new Error("IMC is not ready.");
6341
+ }
6342
+ await imc?.sendMessage(IMCMessageTypeEnum.EditorOAuthDisconnect, {
6343
+ appId,
6344
+ provider,
6345
+ });
6346
+ setIsAuthenticated(false);
6347
+ }
6348
+ // Revalidate OAuth status when the user returns to the tab
6349
+ useEffect(() => {
6350
+ function handleVisibilityChange() {
6351
+ if (document.visibilityState === "visible") {
6352
+ checkAuthStatus();
6353
+ }
6354
+ }
6355
+ document.addEventListener("visibilitychange", handleVisibilityChange);
6356
+ return () => {
6357
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
6358
+ };
6359
+ }, [isIMCReady]);
6360
+ return {
6361
+ isReady,
6362
+ isLoading: !isLoaded,
6363
+ isAuthenticated,
6364
+ connect,
6365
+ disconnect,
6366
+ };
6367
+ }
6368
+
6226
6369
  function useOpenApp() {
6227
6370
  const receiverHandlerMap = new Map();
6228
6371
  const { imc, isReady } = useIMC(receiverHandlerMap, "open-app");
@@ -6315,7 +6458,15 @@ function SnapshotProvider({ children, }) {
6315
6458
  return (React.createElement(SnapshotContext.Provider, { value: { states, setStates } }, children));
6316
6459
  }
6317
6460
 
6318
- function useSnapShotState(key, initialValue, onRestore) {
6461
+ /**
6462
+ * A hook that syncs state with a snapshot context,
6463
+ * allowing for state restoration across component unmounts and remounts.
6464
+ * @param key
6465
+ * @param initialValue
6466
+ * @param onRestore
6467
+ * @returns
6468
+ */
6469
+ function useSnapshotState(key, initialValue, onRestore) {
6319
6470
  const snapshotContext = useContext(SnapshotContext);
6320
6471
  if (!snapshotContext) {
6321
6472
  throw new Error("useSnapShotState must be used within a SnapshotProvider");
@@ -6543,5 +6694,5 @@ function useWorkspaceInfo() {
6543
6694
  };
6544
6695
  }
6545
6696
 
6546
- export { ReceiveFileProvider, SnapshotProvider, useActionEffect, useAgentTools, useAgents, useArtifact, useEditorEnv, useFile, useFileSystem, useImageGen, useLLM, useLoading, useNotification, useOCR, useOpenApp, useOpenLink, useOwnedAppView, useReceiveFile, useSTT, useSnapShotState as useSnapshotState, useTTS, useTerminal, useTheme, useTranslations, useVideoGen, useWorkspaceInfo };
6697
+ export { ReceiveFileProvider, SnapshotProvider, useActionEffect, useAgentTools, useAgents, useAppSettings, useArtifact, useEditorEnv, useFile, useFileSystem, useImageGen, useLLM, useLoading, useNotification, useOAuth, useOCR, useOpenApp, useOpenLink, useOwnedAppView, useReceiveFile, useSTT, useSnapshotState, useTTS, useTerminal, useTheme, useTranslations, useVideoGen, useWorkspaceInfo };
6547
6698
  //# sourceMappingURL=main.js.map