@sampleapp.ai/sdk 1.0.47 → 1.0.49

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,23 +1,26 @@
1
1
  "use client";
2
2
  import React, { useEffect, useState, useCallback, useRef } from "react";
3
- import { fetchSandboxConfigWithContent, buildConfigFromContent } from "./api";
3
+ import { fetchSandboxConfigWithContent, buildConfigFromContent, } from "./api";
4
4
  import GuardianPlayground from "./guardian/guardian-playground";
5
5
  import { GuardianProvider } from "./guardian/context/guardian-context";
6
6
  import { VmProvider } from "./guardian/context/vm-context";
7
7
  import { Skeleton } from "../ui/skeleton";
8
8
  import { useTreeSelector } from "../../hooks/use-tree-selector";
9
- import { SELECTABLE_NODE_TYPES } from "../../lib/types/tree-config";
10
- import { useFrameParams } from "./guardian/hooks/use-frame-params";
9
+ import { SELECTABLE_NODE_TYPES, } from "../../lib/types/tree-config";
10
+ import { useFrameParams, } from "./guardian/hooks/use-frame-params";
11
11
  /**
12
12
  * Inner component that uses the tree selector hook
13
13
  * Separated to ensure hooks are called after data is loaded
14
14
  */
15
- function SandboxInner({ configWithContent, apiKey, env, themeColor, theme, config }) {
15
+ function SandboxInner({ configWithContent, apiKey, env, themeColor, theme, config, }) {
16
16
  var _a;
17
17
  const [currentConfig, setCurrentConfig] = useState(configWithContent.legacyConfig);
18
18
  // Get frame params for syncing external selection changes
19
19
  const frameParams = useFrameParams();
20
20
  const isFrame = (config === null || config === void 0 ? void 0 : config.isFrame) || frameParams.isFrame;
21
+ const containerClass = isFrame
22
+ ? "h-full w-full bg-white dark:bg-black"
23
+ : "h-screen w-full bg-white dark:bg-black";
21
24
  // Track previous nodeTypes to detect changes
22
25
  const prevNodeTypesRef = useRef({});
23
26
  // Handle selection changes - update the config when user selects different options
@@ -37,7 +40,7 @@ function SandboxInner({ configWithContent, apiKey, env, themeColor, theme, confi
37
40
  config: configWithContent.techStackConfig,
38
41
  allContent: configWithContent.allContent,
39
42
  initialPath: configWithContent.initialSelectionPath,
40
- onSelectionChange: handleSelectionChange
43
+ onSelectionChange: handleSelectionChange,
41
44
  });
42
45
  // Sync frame params with tree selector when in frame mode
43
46
  // This effect listens for changes in URL params (via postMessage or direct URL changes)
@@ -73,12 +76,12 @@ function SandboxInner({ configWithContent, apiKey, env, themeColor, theme, confi
73
76
  const firstUseCase = currentConfig.useCases[0];
74
77
  const firstFramework = (_a = firstUseCase === null || firstUseCase === void 0 ? void 0 : firstUseCase.frameworks[0]) === null || _a === void 0 ? void 0 : _a.key;
75
78
  if (!firstUseCase || !firstFramework) {
76
- return (React.createElement("div", { className: "flex items-center justify-center h-screen bg-white dark:bg-black" },
79
+ return (React.createElement("div", { className: `flex items-center justify-center ${containerClass}` },
77
80
  React.createElement("div", { className: "text-red-500" }, "No use cases or frameworks found")));
78
81
  }
79
82
  return (React.createElement(GuardianProvider, null,
80
83
  React.createElement(VmProvider, null,
81
- React.createElement("div", { className: "h-screen w-screen bg-white dark:bg-black" },
84
+ React.createElement("div", { className: containerClass },
82
85
  React.createElement(GuardianPlayground, { sandboxConfig: currentConfig, sections: sections, onSelect: selectOption, useCase: firstUseCase.id, framework: firstFramework, isFrame: isFrame, apiKey: apiKey, env: env, chatUid: currentConfig.chatUid, theme: theme, hasNetworkView: config === null || config === void 0 ? void 0 : config.hasNetworkView })))));
83
86
  }
84
87
  /**
@@ -108,10 +111,14 @@ function SandboxInner({ configWithContent, apiKey, env, themeColor, theme, confi
108
111
  * />
109
112
  * ```
110
113
  */
111
- export default function Sandbox({ apiKey, sandboxId, env, themeColor, theme = "dark", config }) {
114
+ export default function Sandbox({ apiKey, sandboxId, env, themeColor, theme = "dark", config, }) {
112
115
  // Validate apiKey immediately
116
+ const isFrame = config === null || config === void 0 ? void 0 : config.isFrame;
117
+ const containerClass = isFrame
118
+ ? "h-full w-full bg-white dark:bg-black"
119
+ : "h-screen w-full bg-white dark:bg-black";
113
120
  if (!apiKey || apiKey.trim() === "") {
114
- return (React.createElement("div", { className: "flex items-center justify-center h-screen bg-white dark:bg-black" },
121
+ return (React.createElement("div", { className: `flex items-center justify-center ${containerClass}` },
115
122
  React.createElement("div", { className: "text-red-500" }, "Error: apiKey is required. Please provide a valid API key.")));
116
123
  }
117
124
  const [configWithContent, setConfigWithContent] = useState(null);
@@ -148,11 +155,11 @@ export default function Sandbox({ apiKey, sandboxId, env, themeColor, theme = "d
148
155
  };
149
156
  }, [apiKey, sandboxId, themeColor]);
150
157
  if (loading) {
151
- return (React.createElement("div", { className: "h-screen w-screen bg-white dark:bg-black" },
158
+ return (React.createElement("div", { className: containerClass },
152
159
  React.createElement(Skeleton, { className: "w-full h-full bg-zinc-100 dark:bg-zinc-900" })));
153
160
  }
154
161
  if (error) {
155
- return (React.createElement("div", { className: "flex items-center justify-center h-screen bg-white dark:bg-black" },
162
+ return (React.createElement("div", { className: `flex items-center justify-center ${containerClass}` },
156
163
  React.createElement("div", { className: "text-red-500" },
157
164
  "Error: ",
158
165
  error)));
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import React from "react";
3
- import { DownloadIcon, Check, Copy } from "lucide-react";
3
+ import { DownloadIcon, Check, Copy, Loader2 } from "lucide-react";
4
4
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "./dialog";
5
5
  import vscodeLogo from "../../../../assets/vscode.png";
6
6
  import { handleSandboxDownload } from "../utils";
7
+ import { createApiClient } from "../../../../lib/api-client";
7
8
  // VSCode logo component using imported asset
8
9
  function VSCodeLogo({ className }) {
9
10
  return (React.createElement("img", { src: vscodeLogo, alt: "VSCode", width: 20, height: 20, className: className }));
@@ -11,16 +12,19 @@ function VSCodeLogo({ className }) {
11
12
  export const DownloadAndOpenButtons = ({ downloadUrl, themeColor, gitUrl, browserUrl, sandboxId, apiKey, }) => {
12
13
  const [isModalOpen, setIsModalOpen] = React.useState(false);
13
14
  const [hasCopied, setHasCopied] = React.useState(false);
15
+ const [isCloning, setIsCloning] = React.useState(false);
14
16
  // Build the npx command using the SDK download endpoint
15
17
  // Use default MAIN_APP_URL for SDK (can be overridden via env)
16
- const MAIN_APP_URL = typeof window !== "undefined" && window.SAMPLEAPP_MAIN_URL
18
+ const MAIN_APP_URL = typeof window !== "undefined" &&
19
+ window.SAMPLEAPP_MAIN_URL
17
20
  ? window.SAMPLEAPP_MAIN_URL
18
21
  : "https://sampleapp.ai";
19
22
  const npxCommand = React.useMemo(() => {
20
23
  if (!sandboxId) {
21
24
  return "";
22
25
  }
23
- const apiBaseUrl = typeof window !== "undefined" && window.SAMPLEAPP_API_URL
26
+ const apiBaseUrl = typeof window !== "undefined" &&
27
+ window.SAMPLEAPP_API_URL
24
28
  ? window.SAMPLEAPP_API_URL
25
29
  : MAIN_APP_URL.replace("sampleapp.ai", "api.sampleapp.ai");
26
30
  return `npx sampleappai add "${apiBaseUrl}/api/v1/sdk/download-code?sandbox_id=${sandboxId}"`;
@@ -28,10 +32,32 @@ export const DownloadAndOpenButtons = ({ downloadUrl, themeColor, gitUrl, browse
28
32
  const handleDownload = async () => {
29
33
  await handleSandboxDownload(sandboxId, apiKey, () => setIsModalOpen(true));
30
34
  };
31
- const handleOpenInVSCode = () => {
32
- if (gitUrl) {
35
+ const handleOpenInVSCode = async () => {
36
+ // If we have a sandboxId and apiKey, fetch an authenticated clone URL from the backend
37
+ if (sandboxId && apiKey) {
38
+ setIsCloning(true);
33
39
  try {
34
- window.location.href = `vscode://vscode.git/clone?url=${gitUrl}`;
40
+ const client = createApiClient({ apiKey });
41
+ const { clone_url } = await client.sdk.getCloneUrl(sandboxId);
42
+ window.location.href = `vscode://vscode.git/clone?url=${encodeURIComponent(clone_url)}`;
43
+ }
44
+ catch (err) {
45
+ console.error("Failed to get clone URL:", err);
46
+ // Fall back to direct gitUrl or modal
47
+ if (gitUrl) {
48
+ window.location.href = `vscode://vscode.git/clone?url=${encodeURIComponent(gitUrl)}`;
49
+ }
50
+ else {
51
+ setIsModalOpen(true);
52
+ }
53
+ }
54
+ finally {
55
+ setIsCloning(false);
56
+ }
57
+ }
58
+ else if (gitUrl) {
59
+ try {
60
+ window.location.href = `vscode://vscode.git/clone?url=${encodeURIComponent(gitUrl)}`;
35
61
  }
36
62
  catch (_a) {
37
63
  // Silently fail if vscode:// protocol isn't registered
@@ -59,9 +85,9 @@ export const DownloadAndOpenButtons = ({ downloadUrl, themeColor, gitUrl, browse
59
85
  React.createElement("button", { type: "button", className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md !text-white transition-all hover:opacity-90 active:scale-[0.98]", style: { backgroundColor: themeColor }, onClick: handleDownload },
60
86
  React.createElement(DownloadIcon, { className: "w-3.5 h-3.5 !text-white" }),
61
87
  "Download example"),
62
- React.createElement("button", { type: "button", className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border transition-all hover:opacity-90 active:scale-[0.98] bg-zinc-100 dark:bg-zinc-800 border-zinc-300 dark:border-zinc-700 text-zinc-900 dark:text-white", onClick: handleOpenInVSCode },
63
- React.createElement(VSCodeLogo, { className: "w-3.5 h-3.5" }),
64
- "Integrate in VS Code")),
88
+ React.createElement("button", { type: "button", className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border transition-all hover:opacity-90 active:scale-[0.98] bg-zinc-100 dark:bg-zinc-800 border-zinc-300 dark:border-zinc-700 text-zinc-900 dark:text-white disabled:opacity-50", onClick: handleOpenInVSCode, disabled: isCloning },
89
+ isCloning ? (React.createElement(Loader2, { className: "w-3.5 h-3.5 animate-spin" })) : (React.createElement(VSCodeLogo, { className: "w-3.5 h-3.5" })),
90
+ isCloning ? "Opening..." : "Integrate in VS Code")),
65
91
  React.createElement(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen },
66
92
  React.createElement(DialogContent, { className: "max-w-[90vw] sm:max-w-md w-full" },
67
93
  React.createElement(DialogHeader, null,
package/dist/index.d.ts CHANGED
@@ -120,6 +120,15 @@ declare class ApiClient {
120
120
  * @returns Promise that resolves when download is initiated
121
121
  */
122
122
  downloadCode: (sandboxId: string) => Promise<void>;
123
+ /**
124
+ * Get an authenticated clone URL for a private GitHub repository.
125
+ * Returns an HTTPS URL with a short-lived token (expires in 1 hour)
126
+ * that can be used with vscode://vscode.git/clone or git clone directly.
127
+ *
128
+ * @param sandboxId - The sandbox content UID
129
+ * @returns Clone URL response with authenticated URL
130
+ */
131
+ getCloneUrl: (sandboxId: string) => Promise<CloneUrlResponse>;
123
132
  /**
124
133
  * Start VM endpoint that starts a desktop sandbox, launches Chrome,
125
134
  * navigates to the target URL, and returns a VNC viewer URL
@@ -216,6 +225,10 @@ declare interface ChatButtonProps {
216
225
  onClick?: () => void;
217
226
  }
218
227
 
228
+ declare interface CloneUrlResponse {
229
+ clone_url: string;
230
+ }
231
+
219
232
  declare enum CodeLanguage {
220
233
  JAVASCRIPT = "javascript",
221
234
  TYPESCRIPT = "typescript",
@@ -670,7 +683,7 @@ declare class SampleAppSDK {
670
683
  * />
671
684
  * ```
672
685
  */
673
- export declare function Sandbox({ apiKey, sandboxId, env, themeColor, theme, config }: SandboxProps): default_2.JSX.Element | null;
686
+ export declare function Sandbox({ apiKey, sandboxId, env, themeColor, theme, config, }: SandboxProps): default_2.JSX.Element | null;
674
687
 
675
688
  /**
676
689
  * Configuration fetched from the API for a sandbox