@scpdemo/test-sdk-card 1.0.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.
- package/README.md +31 -0
- package/dist/index.cjs +304 -0
- package/dist/index.js +269 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types/components/ScPrefixWidgetWrapper.d.ts +5 -0
- package/dist/types/components/ScPrefixWidgetWrapper.d.ts.map +1 -0
- package/dist/types/components/ScPrefixWidgetWrapper.js +5 -0
- package/dist/types/hooks/useScPrefixSdk.d.ts +16 -0
- package/dist/types/hooks/useScPrefixSdk.d.ts.map +1 -0
- package/dist/types/hooks/useScPrefixSdk.js +47 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/lib/api/client.d.ts +8 -0
- package/dist/types/lib/api/client.d.ts.map +1 -0
- package/dist/types/lib/api/client.js +15 -0
- package/dist/types/lib/components/Widget.d.ts +6 -0
- package/dist/types/lib/components/Widget.d.ts.map +1 -0
- package/dist/types/lib/components/Widget.js +54 -0
- package/dist/types/lib/config.d.ts +12 -0
- package/dist/types/lib/config.d.ts.map +1 -0
- package/dist/types/lib/config.js +38 -0
- package/dist/types/lib/index.d.ts +10 -0
- package/dist/types/lib/index.d.ts.map +1 -0
- package/dist/types/lib/index.js +32 -0
- package/dist/types/lib/storage/local-storage.d.ts +9 -0
- package/dist/types/lib/storage/local-storage.d.ts.map +1 -0
- package/dist/types/lib/storage/local-storage.js +35 -0
- package/dist/types/lib/styles/base.d.ts +2 -0
- package/dist/types/lib/styles/base.d.ts.map +1 -0
- package/dist/types/lib/styles/base.js +80 -0
- package/dist/types/lib/types/index.d.ts +23 -0
- package/dist/types/lib/types/index.d.ts.map +1 -0
- package/dist/types/lib/types/index.js +1 -0
- package/dist/types/lib/utils/http-client.d.ts +8 -0
- package/dist/types/lib/utils/http-client.d.ts.map +1 -0
- package/dist/types/lib/utils/http-client.js +21 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @scallop-card/sdk-react
|
|
2
|
+
|
|
3
|
+
This package exposes the React hook (`useScPrefixSdk`) and the iframe wrapper component (`ScPrefixWidgetWrapper`) for embedding the Scallop Card widget that now lives inside the Next.js iframe app.
|
|
4
|
+
|
|
5
|
+
## Embedding the widget
|
|
6
|
+
|
|
7
|
+
1. Deploy the iframe app located at `packages/iframe-app` (or run it locally via `pnpm --filter @scallop-card/iframe-app dev`).
|
|
8
|
+
2. Provide the iframe URL via env (`VITE_SC_PREFIX_IFRAME_URL`, `NEXT_PUBLIC_SC_PREFIX_IFRAME_URL`, `REACT_APP_SC_PREFIX_IFRAME_URL`, or `SC_PREFIX_IFRAME_URL`) or pass it explicitly:
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { ScPrefixWidgetWrapper } from "@scallop-card/sdk-react";
|
|
12
|
+
|
|
13
|
+
export function CardWidget(): JSX.Element {
|
|
14
|
+
return (
|
|
15
|
+
<ScPrefixWidgetWrapper
|
|
16
|
+
style={{ minHeight: "720px" }}
|
|
17
|
+
allow="clipboard-write"
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The component forwards any additional props to the underlying `<iframe>` element, so you can control sizing, permissions, sandboxing, and more.
|
|
24
|
+
|
|
25
|
+
## Server-side API proxy
|
|
26
|
+
|
|
27
|
+
The iframe app hides the raw SDK calls (`scPrefixSubmitRequest`, `scPrefixGetStatus`) behind server-side API routes. Configure your Scallop credentials via environment variables (see `packages/iframe-app/.env.example`).
|
|
28
|
+
|
|
29
|
+
## Hooks
|
|
30
|
+
|
|
31
|
+
`useScPrefixSdk` remains available if you need direct access to the core SDK from React components (for example, to build custom dashboards or orchestration flows).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
ScPrefixWidgetWrapper: () => ScPrefixWidgetWrapper,
|
|
34
|
+
useScPrefixSdk: () => useScPrefixSdk
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(src_exports);
|
|
37
|
+
|
|
38
|
+
// src/hooks/useScPrefixSdk.ts
|
|
39
|
+
var import_react2 = require("react");
|
|
40
|
+
|
|
41
|
+
// src/lib/config.ts
|
|
42
|
+
var SC_PREFIX_DEFAULT_ENDPOINTS = {
|
|
43
|
+
sandbox: "https://sandbox.api.scallopcard.com",
|
|
44
|
+
production: "https://api.scallopcard.com"
|
|
45
|
+
};
|
|
46
|
+
var ScPrefixConfigManager = class _ScPrefixConfigManager {
|
|
47
|
+
static instance;
|
|
48
|
+
config = null;
|
|
49
|
+
constructor() {
|
|
50
|
+
}
|
|
51
|
+
static getInstance() {
|
|
52
|
+
if (!_ScPrefixConfigManager.instance) {
|
|
53
|
+
_ScPrefixConfigManager.instance = new _ScPrefixConfigManager();
|
|
54
|
+
}
|
|
55
|
+
return _ScPrefixConfigManager.instance;
|
|
56
|
+
}
|
|
57
|
+
initialize(config) {
|
|
58
|
+
if (!config.apiKey) {
|
|
59
|
+
throw new Error("SC_PREFIX: API key is required");
|
|
60
|
+
}
|
|
61
|
+
const environment = config.environment ?? "sandbox";
|
|
62
|
+
const apiBaseUrl = config.apiBaseUrl ?? SC_PREFIX_DEFAULT_ENDPOINTS[environment];
|
|
63
|
+
this.config = {
|
|
64
|
+
...config,
|
|
65
|
+
environment,
|
|
66
|
+
apiBaseUrl,
|
|
67
|
+
storageNamespace: config.storageNamespace ?? "sc-prefix-sdk"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
getConfig() {
|
|
71
|
+
if (!this.config) {
|
|
72
|
+
throw new Error("SC_PREFIX: SDK is not initialized");
|
|
73
|
+
}
|
|
74
|
+
return this.config;
|
|
75
|
+
}
|
|
76
|
+
reset() {
|
|
77
|
+
this.config = null;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var ScPrefixConfigSingleton = ScPrefixConfigManager.getInstance();
|
|
81
|
+
|
|
82
|
+
// src/lib/utils/http-client.ts
|
|
83
|
+
var import_axios = __toESM(require("axios"), 1);
|
|
84
|
+
var ScPrefixHttpClient = class {
|
|
85
|
+
client;
|
|
86
|
+
constructor(baseURL, apiKey) {
|
|
87
|
+
this.client = import_axios.default.create({
|
|
88
|
+
baseURL,
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
Authorization: `Bearer ${apiKey}`
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async get(url, config) {
|
|
96
|
+
const response = await this.client.get(url, config);
|
|
97
|
+
return response.data;
|
|
98
|
+
}
|
|
99
|
+
async post(url, body, config) {
|
|
100
|
+
const response = await this.client.post(url, body, config);
|
|
101
|
+
return response.data;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/lib/api/client.ts
|
|
106
|
+
var ScPrefixApiClient = class {
|
|
107
|
+
httpClient;
|
|
108
|
+
constructor() {
|
|
109
|
+
const config = ScPrefixConfigSingleton.getConfig();
|
|
110
|
+
this.httpClient = new ScPrefixHttpClient(
|
|
111
|
+
config.apiBaseUrl ?? "",
|
|
112
|
+
config.apiKey
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
async submit(payload) {
|
|
116
|
+
return this.httpClient.post(
|
|
117
|
+
"/card/requests",
|
|
118
|
+
payload
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
async status(requestId) {
|
|
122
|
+
return this.httpClient.get(
|
|
123
|
+
`/card/requests/${requestId}`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// src/lib/storage/local-storage.ts
|
|
129
|
+
var ScPrefixStorage = class {
|
|
130
|
+
storageKey;
|
|
131
|
+
constructor(config) {
|
|
132
|
+
this.storageKey = `${config.storageNamespace ?? "sc-prefix-sdk"}:cache`;
|
|
133
|
+
}
|
|
134
|
+
setItem(key, value) {
|
|
135
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const payload = JSON.stringify(value);
|
|
139
|
+
window.localStorage.setItem(`${this.storageKey}:${key}`, payload);
|
|
140
|
+
}
|
|
141
|
+
getItem(key) {
|
|
142
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const payload = window.localStorage.getItem(`${this.storageKey}:${key}`);
|
|
146
|
+
if (!payload) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
return JSON.parse(payload);
|
|
151
|
+
} catch {
|
|
152
|
+
window.localStorage.removeItem(`${this.storageKey}:${key}`);
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
removeItem(key) {
|
|
157
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
window.localStorage.removeItem(`${this.storageKey}:${key}`);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// src/lib/components/Widget.tsx
|
|
165
|
+
var import_react = require("react");
|
|
166
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
167
|
+
function resolveIframeUrlFromEnv() {
|
|
168
|
+
const envFromMeta = (() => {
|
|
169
|
+
try {
|
|
170
|
+
return new Function(
|
|
171
|
+
'return typeof import !== "undefined" ? import.meta.env : undefined;'
|
|
172
|
+
)();
|
|
173
|
+
} catch {
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
})() ?? void 0;
|
|
177
|
+
const iframeFromMeta = envFromMeta?.VITE_SC_PREFIX_IFRAME_URL ?? envFromMeta?.NEXT_PUBLIC_SC_PREFIX_IFRAME_URL ?? envFromMeta?.REACT_APP_SC_PREFIX_IFRAME_URL ?? envFromMeta?.SC_PREFIX_IFRAME_URL;
|
|
178
|
+
if (iframeFromMeta) return iframeFromMeta;
|
|
179
|
+
if (typeof process !== "undefined" && typeof process.env !== "undefined") {
|
|
180
|
+
return process.env.NEXT_PUBLIC_SC_PREFIX_IFRAME_URL ?? process.env.REACT_APP_SC_PREFIX_IFRAME_URL ?? process.env.VITE_SC_PREFIX_IFRAME_URL ?? process.env.SC_PREFIX_IFRAME_URL;
|
|
181
|
+
}
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
function resolveIframeUrl(provided) {
|
|
185
|
+
const normalized = provided?.trim() ?? "";
|
|
186
|
+
const resolved = normalized || resolveIframeUrlFromEnv();
|
|
187
|
+
if (!resolved) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
"ScPrefixWidget requires an iframe URL. Provide iframeUrl prop or set SC_PREFIX_IFRAME_URL (NEXT_PUBLIC_*/REACT_APP_/VITE_)."
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return resolved;
|
|
193
|
+
}
|
|
194
|
+
var ScPrefixWidget = (0, import_react.forwardRef)(function ScPrefixWidget2({ iframeUrl, className, title = "Scallop Card Widget", style, ...rest }, ref) {
|
|
195
|
+
const combinedClassName = (0, import_react.useMemo)(() => {
|
|
196
|
+
return ["sc-prefix-widget-frame", className].filter((value) => Boolean(value && value.trim().length > 0)).join(" ");
|
|
197
|
+
}, [className]);
|
|
198
|
+
const mergedStyle = (0, import_react.useMemo)(() => {
|
|
199
|
+
return {
|
|
200
|
+
border: "0",
|
|
201
|
+
width: "100%",
|
|
202
|
+
minHeight: "640px",
|
|
203
|
+
borderRadius: "12px",
|
|
204
|
+
boxShadow: "0 10px 30px rgba(15, 23, 42, 0.08)",
|
|
205
|
+
...style
|
|
206
|
+
};
|
|
207
|
+
}, [style]);
|
|
208
|
+
const resolvedIframeUrl = (0, import_react.useMemo)(() => resolveIframeUrl(iframeUrl), [iframeUrl]);
|
|
209
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
210
|
+
"iframe",
|
|
211
|
+
{
|
|
212
|
+
ref,
|
|
213
|
+
src: resolvedIframeUrl,
|
|
214
|
+
title,
|
|
215
|
+
className: combinedClassName,
|
|
216
|
+
style: mergedStyle,
|
|
217
|
+
scrolling: "no",
|
|
218
|
+
...rest
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// src/lib/index.ts
|
|
224
|
+
var scPrefixStorage = null;
|
|
225
|
+
function scPrefixInitialize(config) {
|
|
226
|
+
ScPrefixConfigSingleton.initialize(config);
|
|
227
|
+
scPrefixStorage = new ScPrefixStorage(config);
|
|
228
|
+
}
|
|
229
|
+
async function scPrefixSubmitRequest(payload) {
|
|
230
|
+
const apiClient = new ScPrefixApiClient();
|
|
231
|
+
const response = await apiClient.submit(payload);
|
|
232
|
+
scPrefixStorage?.setItem(`request:${response.requestId}`, response);
|
|
233
|
+
return response;
|
|
234
|
+
}
|
|
235
|
+
async function scPrefixGetStatus(requestId) {
|
|
236
|
+
const cached = scPrefixStorage?.getItem(
|
|
237
|
+
`request:${requestId}`
|
|
238
|
+
);
|
|
239
|
+
if (cached) {
|
|
240
|
+
return cached;
|
|
241
|
+
}
|
|
242
|
+
const apiClient = new ScPrefixApiClient();
|
|
243
|
+
const response = await apiClient.status(requestId);
|
|
244
|
+
scPrefixStorage?.setItem(`request:${response.requestId}`, response);
|
|
245
|
+
return response;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/hooks/useScPrefixSdk.ts
|
|
249
|
+
function useScPrefixSdk(config) {
|
|
250
|
+
const [state, setState] = (0, import_react2.useState)({ isReady: false });
|
|
251
|
+
(0, import_react2.useEffect)(() => {
|
|
252
|
+
try {
|
|
253
|
+
scPrefixInitialize(config);
|
|
254
|
+
setState((prev) => ({ ...prev, isReady: true, error: void 0 }));
|
|
255
|
+
} catch (error) {
|
|
256
|
+
setState((prev) => ({ ...prev, error }));
|
|
257
|
+
}
|
|
258
|
+
}, [config]);
|
|
259
|
+
const actions = (0, import_react2.useMemo)(
|
|
260
|
+
() => ({
|
|
261
|
+
async submitRequest(payload) {
|
|
262
|
+
try {
|
|
263
|
+
const response = await scPrefixSubmitRequest(payload);
|
|
264
|
+
setState((prev) => ({
|
|
265
|
+
...prev,
|
|
266
|
+
lastRequest: response,
|
|
267
|
+
error: void 0
|
|
268
|
+
}));
|
|
269
|
+
return response;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
setState((prev) => ({ ...prev, error }));
|
|
272
|
+
return void 0;
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
async checkStatus(requestId) {
|
|
276
|
+
try {
|
|
277
|
+
const status = await scPrefixGetStatus(requestId);
|
|
278
|
+
setState((prev) => ({
|
|
279
|
+
...prev,
|
|
280
|
+
lastStatus: status ?? void 0,
|
|
281
|
+
error: void 0
|
|
282
|
+
}));
|
|
283
|
+
return status;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
setState((prev) => ({ ...prev, error }));
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}),
|
|
290
|
+
[]
|
|
291
|
+
);
|
|
292
|
+
return { state, actions };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/components/ScPrefixWidgetWrapper.tsx
|
|
296
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
297
|
+
function ScPrefixWidgetWrapper(props) {
|
|
298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ScPrefixWidget, { ...props });
|
|
299
|
+
}
|
|
300
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
301
|
+
0 && (module.exports = {
|
|
302
|
+
ScPrefixWidgetWrapper,
|
|
303
|
+
useScPrefixSdk
|
|
304
|
+
});
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// src/hooks/useScPrefixSdk.ts
|
|
2
|
+
import { useEffect, useMemo as useMemo2, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// src/lib/config.ts
|
|
5
|
+
var SC_PREFIX_DEFAULT_ENDPOINTS = {
|
|
6
|
+
sandbox: "https://sandbox.api.scallopcard.com",
|
|
7
|
+
production: "https://api.scallopcard.com"
|
|
8
|
+
};
|
|
9
|
+
var ScPrefixConfigManager = class _ScPrefixConfigManager {
|
|
10
|
+
static instance;
|
|
11
|
+
config = null;
|
|
12
|
+
constructor() {
|
|
13
|
+
}
|
|
14
|
+
static getInstance() {
|
|
15
|
+
if (!_ScPrefixConfigManager.instance) {
|
|
16
|
+
_ScPrefixConfigManager.instance = new _ScPrefixConfigManager();
|
|
17
|
+
}
|
|
18
|
+
return _ScPrefixConfigManager.instance;
|
|
19
|
+
}
|
|
20
|
+
initialize(config) {
|
|
21
|
+
if (!config.apiKey) {
|
|
22
|
+
throw new Error("SC_PREFIX: API key is required");
|
|
23
|
+
}
|
|
24
|
+
const environment = config.environment ?? "sandbox";
|
|
25
|
+
const apiBaseUrl = config.apiBaseUrl ?? SC_PREFIX_DEFAULT_ENDPOINTS[environment];
|
|
26
|
+
this.config = {
|
|
27
|
+
...config,
|
|
28
|
+
environment,
|
|
29
|
+
apiBaseUrl,
|
|
30
|
+
storageNamespace: config.storageNamespace ?? "sc-prefix-sdk"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
getConfig() {
|
|
34
|
+
if (!this.config) {
|
|
35
|
+
throw new Error("SC_PREFIX: SDK is not initialized");
|
|
36
|
+
}
|
|
37
|
+
return this.config;
|
|
38
|
+
}
|
|
39
|
+
reset() {
|
|
40
|
+
this.config = null;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var ScPrefixConfigSingleton = ScPrefixConfigManager.getInstance();
|
|
44
|
+
|
|
45
|
+
// src/lib/utils/http-client.ts
|
|
46
|
+
import axios from "axios";
|
|
47
|
+
var ScPrefixHttpClient = class {
|
|
48
|
+
client;
|
|
49
|
+
constructor(baseURL, apiKey) {
|
|
50
|
+
this.client = axios.create({
|
|
51
|
+
baseURL,
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
Authorization: `Bearer ${apiKey}`
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async get(url, config) {
|
|
59
|
+
const response = await this.client.get(url, config);
|
|
60
|
+
return response.data;
|
|
61
|
+
}
|
|
62
|
+
async post(url, body, config) {
|
|
63
|
+
const response = await this.client.post(url, body, config);
|
|
64
|
+
return response.data;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/lib/api/client.ts
|
|
69
|
+
var ScPrefixApiClient = class {
|
|
70
|
+
httpClient;
|
|
71
|
+
constructor() {
|
|
72
|
+
const config = ScPrefixConfigSingleton.getConfig();
|
|
73
|
+
this.httpClient = new ScPrefixHttpClient(
|
|
74
|
+
config.apiBaseUrl ?? "",
|
|
75
|
+
config.apiKey
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
async submit(payload) {
|
|
79
|
+
return this.httpClient.post(
|
|
80
|
+
"/card/requests",
|
|
81
|
+
payload
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
async status(requestId) {
|
|
85
|
+
return this.httpClient.get(
|
|
86
|
+
`/card/requests/${requestId}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/lib/storage/local-storage.ts
|
|
92
|
+
var ScPrefixStorage = class {
|
|
93
|
+
storageKey;
|
|
94
|
+
constructor(config) {
|
|
95
|
+
this.storageKey = `${config.storageNamespace ?? "sc-prefix-sdk"}:cache`;
|
|
96
|
+
}
|
|
97
|
+
setItem(key, value) {
|
|
98
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const payload = JSON.stringify(value);
|
|
102
|
+
window.localStorage.setItem(`${this.storageKey}:${key}`, payload);
|
|
103
|
+
}
|
|
104
|
+
getItem(key) {
|
|
105
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const payload = window.localStorage.getItem(`${this.storageKey}:${key}`);
|
|
109
|
+
if (!payload) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
return JSON.parse(payload);
|
|
114
|
+
} catch {
|
|
115
|
+
window.localStorage.removeItem(`${this.storageKey}:${key}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
removeItem(key) {
|
|
120
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
window.localStorage.removeItem(`${this.storageKey}:${key}`);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/lib/components/Widget.tsx
|
|
128
|
+
import {
|
|
129
|
+
forwardRef,
|
|
130
|
+
useMemo
|
|
131
|
+
} from "react";
|
|
132
|
+
import { jsx } from "react/jsx-runtime";
|
|
133
|
+
function resolveIframeUrlFromEnv() {
|
|
134
|
+
const envFromMeta = (() => {
|
|
135
|
+
try {
|
|
136
|
+
return new Function(
|
|
137
|
+
'return typeof import !== "undefined" ? import.meta.env : undefined;'
|
|
138
|
+
)();
|
|
139
|
+
} catch {
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
})() ?? void 0;
|
|
143
|
+
const iframeFromMeta = envFromMeta?.VITE_SC_PREFIX_IFRAME_URL ?? envFromMeta?.NEXT_PUBLIC_SC_PREFIX_IFRAME_URL ?? envFromMeta?.REACT_APP_SC_PREFIX_IFRAME_URL ?? envFromMeta?.SC_PREFIX_IFRAME_URL;
|
|
144
|
+
if (iframeFromMeta) return iframeFromMeta;
|
|
145
|
+
if (typeof process !== "undefined" && typeof process.env !== "undefined") {
|
|
146
|
+
return process.env.NEXT_PUBLIC_SC_PREFIX_IFRAME_URL ?? process.env.REACT_APP_SC_PREFIX_IFRAME_URL ?? process.env.VITE_SC_PREFIX_IFRAME_URL ?? process.env.SC_PREFIX_IFRAME_URL;
|
|
147
|
+
}
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
function resolveIframeUrl(provided) {
|
|
151
|
+
const normalized = provided?.trim() ?? "";
|
|
152
|
+
const resolved = normalized || resolveIframeUrlFromEnv();
|
|
153
|
+
if (!resolved) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
"ScPrefixWidget requires an iframe URL. Provide iframeUrl prop or set SC_PREFIX_IFRAME_URL (NEXT_PUBLIC_*/REACT_APP_/VITE_)."
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return resolved;
|
|
159
|
+
}
|
|
160
|
+
var ScPrefixWidget = forwardRef(function ScPrefixWidget2({ iframeUrl, className, title = "Scallop Card Widget", style, ...rest }, ref) {
|
|
161
|
+
const combinedClassName = useMemo(() => {
|
|
162
|
+
return ["sc-prefix-widget-frame", className].filter((value) => Boolean(value && value.trim().length > 0)).join(" ");
|
|
163
|
+
}, [className]);
|
|
164
|
+
const mergedStyle = useMemo(() => {
|
|
165
|
+
return {
|
|
166
|
+
border: "0",
|
|
167
|
+
width: "100%",
|
|
168
|
+
minHeight: "640px",
|
|
169
|
+
borderRadius: "12px",
|
|
170
|
+
boxShadow: "0 10px 30px rgba(15, 23, 42, 0.08)",
|
|
171
|
+
...style
|
|
172
|
+
};
|
|
173
|
+
}, [style]);
|
|
174
|
+
const resolvedIframeUrl = useMemo(() => resolveIframeUrl(iframeUrl), [iframeUrl]);
|
|
175
|
+
return /* @__PURE__ */ jsx(
|
|
176
|
+
"iframe",
|
|
177
|
+
{
|
|
178
|
+
ref,
|
|
179
|
+
src: resolvedIframeUrl,
|
|
180
|
+
title,
|
|
181
|
+
className: combinedClassName,
|
|
182
|
+
style: mergedStyle,
|
|
183
|
+
scrolling: "no",
|
|
184
|
+
...rest
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// src/lib/index.ts
|
|
190
|
+
var scPrefixStorage = null;
|
|
191
|
+
function scPrefixInitialize(config) {
|
|
192
|
+
ScPrefixConfigSingleton.initialize(config);
|
|
193
|
+
scPrefixStorage = new ScPrefixStorage(config);
|
|
194
|
+
}
|
|
195
|
+
async function scPrefixSubmitRequest(payload) {
|
|
196
|
+
const apiClient = new ScPrefixApiClient();
|
|
197
|
+
const response = await apiClient.submit(payload);
|
|
198
|
+
scPrefixStorage?.setItem(`request:${response.requestId}`, response);
|
|
199
|
+
return response;
|
|
200
|
+
}
|
|
201
|
+
async function scPrefixGetStatus(requestId) {
|
|
202
|
+
const cached = scPrefixStorage?.getItem(
|
|
203
|
+
`request:${requestId}`
|
|
204
|
+
);
|
|
205
|
+
if (cached) {
|
|
206
|
+
return cached;
|
|
207
|
+
}
|
|
208
|
+
const apiClient = new ScPrefixApiClient();
|
|
209
|
+
const response = await apiClient.status(requestId);
|
|
210
|
+
scPrefixStorage?.setItem(`request:${response.requestId}`, response);
|
|
211
|
+
return response;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/hooks/useScPrefixSdk.ts
|
|
215
|
+
function useScPrefixSdk(config) {
|
|
216
|
+
const [state, setState] = useState({ isReady: false });
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
try {
|
|
219
|
+
scPrefixInitialize(config);
|
|
220
|
+
setState((prev) => ({ ...prev, isReady: true, error: void 0 }));
|
|
221
|
+
} catch (error) {
|
|
222
|
+
setState((prev) => ({ ...prev, error }));
|
|
223
|
+
}
|
|
224
|
+
}, [config]);
|
|
225
|
+
const actions = useMemo2(
|
|
226
|
+
() => ({
|
|
227
|
+
async submitRequest(payload) {
|
|
228
|
+
try {
|
|
229
|
+
const response = await scPrefixSubmitRequest(payload);
|
|
230
|
+
setState((prev) => ({
|
|
231
|
+
...prev,
|
|
232
|
+
lastRequest: response,
|
|
233
|
+
error: void 0
|
|
234
|
+
}));
|
|
235
|
+
return response;
|
|
236
|
+
} catch (error) {
|
|
237
|
+
setState((prev) => ({ ...prev, error }));
|
|
238
|
+
return void 0;
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
async checkStatus(requestId) {
|
|
242
|
+
try {
|
|
243
|
+
const status = await scPrefixGetStatus(requestId);
|
|
244
|
+
setState((prev) => ({
|
|
245
|
+
...prev,
|
|
246
|
+
lastStatus: status ?? void 0,
|
|
247
|
+
error: void 0
|
|
248
|
+
}));
|
|
249
|
+
return status;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
setState((prev) => ({ ...prev, error }));
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}),
|
|
256
|
+
[]
|
|
257
|
+
);
|
|
258
|
+
return { state, actions };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/components/ScPrefixWidgetWrapper.tsx
|
|
262
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
263
|
+
function ScPrefixWidgetWrapper(props) {
|
|
264
|
+
return /* @__PURE__ */ jsx2(ScPrefixWidget, { ...props });
|
|
265
|
+
}
|
|
266
|
+
export {
|
|
267
|
+
ScPrefixWidgetWrapper,
|
|
268
|
+
useScPrefixSdk
|
|
269
|
+
};
|