@sampleapp.ai/sdk 1.0.48 → 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,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",