@xeonr/renderer-sdk 1.3.0 → 1.5.1

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,71 +0,0 @@
1
- import { useCallback, useState } from 'react';
2
-
3
- /**
4
- * Hook for surfacing async failures to `<RendererErrorBoundary>` (and from
5
- * there to the host's crash overlay + telemetry).
6
- *
7
- * Renderers shouldn't render their own "Upload not found" / "Failed to
8
- * load" inline UI — those are still crashes from a telemetry standpoint,
9
- * and the host already owns a polished overlay with reload + fallback
10
- * actions. This hook lets a renderer take an error caught in an async
11
- * context (fetch `.catch()`, useEffect cleanup, etc.) and route it to
12
- * the host instead of rendering a half-broken inline state.
13
- *
14
- * Pattern:
15
- *
16
- * ```tsx
17
- * const reportFatal = useReportFatalError();
18
- * useEffect(() => {
19
- * client.getUpload(...).catch(reportFatal);
20
- * }, []);
21
- * ```
22
- *
23
- * Mechanics: we keep an error in component state. When set, the *next*
24
- * render throws it — React's error-handling pipeline catches the throw
25
- * and bubbles to the nearest boundary. From there
26
- * `RendererErrorBoundary.componentDidCatch` reports the crash to the
27
- * host and renders nothing, and the host overlay (Reload / Copy /
28
- * Fallback) takes over the visible iframe area.
29
- *
30
- * Why state-then-throw rather than a direct `throw err`? You can't
31
- * throw to React from async code — React only sees throws that happen
32
- * during render or in event handlers. Routing through state ensures
33
- * the throw lands inside the render phase.
34
- *
35
- * The returned callback is stable across renders so it's safe to drop
36
- * straight into a `.catch()`.
37
- */
38
- export function useReportFatalError(): (err: unknown) => void {
39
- // Generic state slot — we never read the value, only use the
40
- // updater. We narrow to `never` so TypeScript stops us from
41
- // accidentally using it as data anywhere.
42
- const [, setState] = useState<never>();
43
- return useCallback((err: unknown) => {
44
- // Functional updater throws — React invokes it during the next
45
- // render attempt, which puts the throw inside the render phase
46
- // where boundaries can see it.
47
- setState(() => {
48
- if (err instanceof Error) {
49
- throw err;
50
- }
51
- // Wrap non-Error throws so the boundary always sees a real
52
- // Error instance with a meaningful .name / .message. Without
53
- // this, `client.reportCrash` would synthesise a generic
54
- // 'UnknownError' which loses the original payload's shape.
55
- if (typeof err === 'string') {
56
- throw new Error(err);
57
- }
58
- if (err && typeof err === 'object' && 'message' in err && typeof err.message === 'string') {
59
- const wrapped = new Error(err.message);
60
- if ('name' in err && typeof err.name === 'string') {
61
- wrapped.name = err.name;
62
- }
63
- if ('stack' in err && typeof err.stack === 'string') {
64
- wrapped.stack = err.stack;
65
- }
66
- throw wrapped;
67
- }
68
- throw new Error('Unknown renderer error');
69
- });
70
- }, []);
71
- }
package/src/types.ts DELETED
@@ -1,138 +0,0 @@
1
- /**
2
- * config.json schema — lives at the root of a renderer archive.
3
- * Validated server-side on upload; provided to the renderer in the init message.
4
- */
5
- export interface RendererConfig {
6
- version: 1;
7
- /** Permissions the renderer requests from the host. */
8
- permissions?: RendererPermission[];
9
- sandbox?: {
10
- allowPopups?: boolean;
11
- allowForms?: boolean;
12
- allowDownloads?: boolean;
13
- };
14
- /**
15
- * Extra origins this renderer needs to reach via `fetch` / `XMLHttpRequest`
16
- * / WebSocket. Surfaced to the browser as additional entries in the CSP
17
- * `connect-src` directive. The upl.im API + auth hosts are always allowed
18
- * by the renderer-proxy; only list extras here (e.g. a third-party API
19
- * the renderer integrates with).
20
- *
21
- * Each entry is a fully-qualified origin like `https://api.example.com`
22
- * or a wildcarded host like `https://*.example.com`. No paths, no
23
- * trailing slashes. Origins are validated at deploy time.
24
- */
25
- connectHosts?: string[];
26
- /**
27
- * Short build identifier the build pipeline stamps into config.json
28
- * (e.g. the renderer-plugin-vite hash of the output directory).
29
- * Surfaced in crash telemetry as a separate dimension so we can
30
- * distinguish "crashed in build A" from "crashed in build B" even
31
- * when both builds share the same archive_upload_id (the developer
32
- * republished without bumping the archive). Bounded to 64 chars.
33
- */
34
- buildHash?: string;
35
- /**
36
- * When true, the SDK holds `uplim:ack` until the renderer explicitly
37
- * calls `markReady()` from `useRendererClient()`. The host's loading
38
- * overlay stays visible until that signal arrives, so the user
39
- * never sees a blank canvas between bridge ack and the renderer's
40
- * first paint.
41
- *
42
- * Leave unset (or `false`) for fast renderers where the gap is
43
- * invisible — that's the right default and lowest-friction pattern
44
- * (image, code, plain markdown). Set `true` when the renderer takes
45
- * perceptible time to settle (large file fetch, video decode,
46
- * multi-page paginate) and the blank-canvas flash is noticeable.
47
- *
48
- * The SDK auto-acks after 30s (configurable via
49
- * `RendererClientOptions.readyTimeoutMs`) and logs a warning if
50
- * `markReady()` never fires — so a forgotten signal can't trap
51
- * users behind the overlay.
52
- */
53
- deferReady?: boolean;
54
- }
55
-
56
- export type RendererPermission =
57
- | 'createFolder'
58
- | 'openUpload';
59
-
60
- /**
61
- * What resource the renderer is scoped to.
62
- * Sent from host to iframe in the init message.
63
- */
64
- export type RendererScope =
65
- | RendererBucketScope
66
- | RendererFolderScope
67
- | RendererUploadScope
68
- | RendererVirtualFileScope;
69
-
70
- export interface RendererBucketScope {
71
- type: 'bucket';
72
- bucketId: string;
73
- }
74
-
75
- export interface RendererFolderScope {
76
- type: 'folder';
77
- bucketId: string;
78
- folderId: string;
79
- path: string;
80
- }
81
-
82
- export interface RendererUploadScope {
83
- type: 'upload';
84
- bucketId: string;
85
- uploadId: string;
86
- }
87
-
88
- export interface RendererVirtualFileScope {
89
- type: 'virtual-file';
90
- bucketId: string;
91
- folderId?: string;
92
- path: string;
93
- }
94
-
95
- /**
96
- * How the renderer is being displayed within the dashboard entrypoint.
97
- * A single renderer may handle multiple rendering types.
98
- */
99
- export type RenderingType =
100
- | 'bucket-renderer'
101
- | 'folder-renderer'
102
- | 'preview-modal';
103
-
104
- /**
105
- * API adapter compatible with `IUploadAdapterEnv` from `@xeonr/uploads-sdk`.
106
- * Pass this to `getUploadClientWithEnv()` to get a pre-configured API client
107
- * that handles authentication and token refresh automatically.
108
- */
109
- export interface RendererApiAdapter {
110
- hostname?: string;
111
- tokenHelper?: () => Promise<string | null>;
112
- onAuthenticationExpired?: (retryCount: number) => Promise<boolean>;
113
- onAuthenticationFailed?: () => Promise<any>;
114
- }
115
-
116
- /** Payload received by the renderer on initialization. */
117
- export interface InitPayload {
118
- /** Protocol version. */
119
- version: 1;
120
- /** Integration access token scoped to the integration's client. */
121
- token: string;
122
- /** Unix timestamp (ms) when the token expires. */
123
- tokenExpiresAt: number;
124
- /** Current host theme. */
125
- theme: 'light' | 'dark';
126
- /** Which entrypoint was loaded. */
127
- entrypoint: 'dashboard' | 'portal';
128
- /** What resource the renderer is scoped to. */
129
- scope: RendererScope;
130
- /** How the renderer is being displayed (dashboard only). */
131
- renderingType: RenderingType;
132
- /** Base URL for upl.im API calls. */
133
- apiBaseUrl: string;
134
- /** The parsed config.json from the renderer archive. */
135
- config: RendererConfig;
136
- /** Initial hash path to navigate to, derived from the host URL fragment. */
137
- initialPath?: string;
138
- }
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "declaration": true,
7
- "declarationMap": true,
8
- "sourceMap": true,
9
- "outDir": "./dist",
10
- "rootDir": "./src",
11
- "jsx": "react-jsx",
12
- "strict": true,
13
- "esModuleInterop": true,
14
- "skipLibCheck": true,
15
- "forceConsistentCasingInFileNames": true
16
- },
17
- "include": ["src"]
18
- }
@@ -1 +0,0 @@
1
- {"root":["./src/client.ts","./src/index.ts","./src/protocol.ts","./src/types.ts","./src/react/index.ts","./src/react/userendererclient.ts"],"version":"5.9.3"}