@embeddable/sdk 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Embeddable Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # @embeddable/sdk
2
+
3
+ A TypeScript/JavaScript SDK with React utilities and hooks for embeddable applications. Built with tree shaking support and modern development practices.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40embeddable%2Fsdk.svg)](https://badge.fury.io/js/%40embeddable%2Fsdk)
6
+ [![CI/CD](https://github.com/CommonNinja/embeddable-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/CommonNinja/embeddable-sdk/actions/workflows/ci.yml)
7
+ [![codecov](https://codecov.io/gh/CommonNinja/embeddable-sdk/branch/main/graph/badge.svg)](https://codecov.io/gh/CommonNinja/embeddable-sdk)
8
+
9
+ ## Features
10
+
11
+ - ๐ŸŒณ **Tree Shaking**: Import only what you need
12
+ - ๐Ÿ“ฆ **TypeScript**: Full TypeScript support with type definitions
13
+ - โš›๏ธ **React Hooks**: Custom hooks for common patterns
14
+ - ๐Ÿ› ๏ธ **Utilities**: Useful utility functions
15
+ - ๐ŸŽจ **Theme Support**: Built-in theme management
16
+ - ๐Ÿ“ฑ **Storage**: Enhanced localStorage utilities
17
+ - ๐ŸŒ **API Client**: Type-safe API client with error handling
18
+ - ๐Ÿงช **Well Tested**: Comprehensive test coverage
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @embeddable/sdk
24
+ # or
25
+ yarn add @embeddable/sdk
26
+ # or
27
+ pnpm add @embeddable/sdk
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ### Import Everything
33
+
34
+ ```typescript
35
+ import { useLocalStorage, debounce } from '@embeddable/sdk';
36
+ ```
37
+
38
+ ### Import Specific Modules (Tree Shaking)
39
+
40
+ ```typescript
41
+ // Import only hooks
42
+ import { useLocalStorage } from '@embeddable/sdk/hooks';
43
+
44
+ // Import only utilities
45
+ import { debounce } from '@embeddable/sdk/utils';
46
+ ```
47
+
48
+ ## API Reference
49
+
50
+ ### Hooks
51
+
52
+ #### `useLocalStorage<T>(key: string, initialValue: T, options?: LocalStorageOptions)`
53
+
54
+ A React hook for localStorage with state synchronization across tabs.
55
+
56
+ ```typescript
57
+ import { useLocalStorage } from '@embeddable/sdk/hooks'
58
+
59
+ function MyComponent() {
60
+ const [user, setUser, removeUser] = useLocalStorage('user', { name: '', email: '' })
61
+
62
+ return (
63
+ <div>
64
+ <input
65
+ value={user.name}
66
+ onChange={(e) => setUser(prev => ({ ...prev, name: e.target.value }))}
67
+ />
68
+ <button onClick={removeUser}>Clear</button>
69
+ </div>
70
+ )
71
+ }
72
+ ```
73
+
74
+ #### `useDebounce<T>(value: T, delay: number)`
75
+
76
+ A React hook that debounces a value.
77
+
78
+ ```typescript
79
+ import { useDebounce } from '@embeddable/sdk/hooks'
80
+
81
+ function SearchInput() {
82
+ const [searchTerm, setSearchTerm] = useState('')
83
+ const debouncedSearchTerm = useDebounce(searchTerm, 300)
84
+
85
+ useEffect(() => {
86
+ if (debouncedSearchTerm) {
87
+ // Perform search
88
+ }
89
+ }, [debouncedSearchTerm])
90
+
91
+ return <input onChange={(e) => setSearchTerm(e.target.value)} />
92
+ }
93
+ ```
94
+
95
+ #### `useApi(config: EmbeddableApiConfig)`
96
+
97
+ A React hook for API calls with loading and error states.
98
+
99
+ ```typescript
100
+ import { useApi } from '@embeddable/sdk/hooks'
101
+
102
+ function DataComponent() {
103
+ const api = useApi({ apiKey: 'your-api-key', baseUrl: 'https://api.example.com' })
104
+
105
+ const fetchData = async () => {
106
+ const response = await api.get('/users')
107
+ if (response.success) {
108
+ console.log(response.data)
109
+ }
110
+ }
111
+
112
+ return (
113
+ <div>
114
+ {api.loading && <div>Loading...</div>}
115
+ {api.error && <div>Error: {api.error}</div>}
116
+ <button onClick={fetchData}>Fetch Data</button>
117
+ </div>
118
+ )
119
+ }
120
+ ```
121
+
122
+ ### Utilities
123
+
124
+ #### `debounce<T>(func: T, wait: number)`
125
+
126
+ Creates a debounced function.
127
+
128
+ ```typescript
129
+ import { debounce } from '@embeddable/sdk/utils';
130
+
131
+ const debouncedSave = debounce(data => {
132
+ // Save data
133
+ }, 500);
134
+ ```
135
+
136
+ #### `createApiClient(config: EmbeddableApiConfig)`
137
+
138
+ Creates a type-safe API client.
139
+
140
+ ```typescript
141
+ import { createApiClient } from '@embeddable/sdk/utils';
142
+
143
+ const api = createApiClient({
144
+ apiKey: 'your-api-key',
145
+ baseUrl: 'https://api.example.com',
146
+ debug: true,
147
+ });
148
+
149
+ const response = await api.get('/users');
150
+ ```
151
+
152
+ #### `storage`
153
+
154
+ Enhanced localStorage utility with serialization support.
155
+
156
+ ```typescript
157
+ import { storage } from '@embeddable/sdk/utils';
158
+
159
+ // Basic usage
160
+ storage.set('user', { name: 'John', age: 30 });
161
+ const user = storage.get('user');
162
+
163
+ // With options
164
+ storage.set('data', complexObject, {
165
+ prefix: 'myapp_',
166
+ serialize: JSON.stringify,
167
+ deserialize: JSON.parse,
168
+ });
169
+ ```
170
+
171
+ ## Types
172
+
173
+ The SDK exports TypeScript types for better development experience:
174
+
175
+ ```typescript
176
+ import type {
177
+ EmbeddableApiConfig,
178
+ ApiResponse,
179
+ Theme,
180
+ ThemeConfig,
181
+ LocalStorageOptions,
182
+ } from '@embeddable/sdk';
183
+ ```
184
+
185
+ ## Development
186
+
187
+ ```bash
188
+ # Install dependencies
189
+ npm install
190
+
191
+ # Run tests
192
+ npm test
193
+
194
+ # Run tests with coverage
195
+ npm run test:coverage
196
+
197
+ # Build the package
198
+ npm run build
199
+
200
+ # Run linter
201
+ npm run lint
202
+
203
+ # Fix linting issues
204
+ npm run lint:fix
205
+
206
+ # Format code with Prettier
207
+ npm run format
208
+
209
+ # Check code formatting
210
+ npm run format:check
211
+
212
+ # Type check
213
+ npm run type-check
214
+ ```
215
+
216
+ ## Contributing
217
+
218
+ 1. Fork the repository
219
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
220
+ 3. Commit your changes using conventional commits (`git commit -m 'feat: add amazing feature'`)
221
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
222
+ 5. Open a Pull Request
223
+
224
+ ## License
225
+
226
+ MIT ยฉ [Embeddable Team](https://github.com/CommonNinja/embeddable-sdk)
227
+
228
+ ## Changelog
229
+
230
+ See [CHANGELOG.md](./CHANGELOG.md) for a list of changes.
@@ -0,0 +1,4 @@
1
+ export { useApi } from './useApi';
2
+ export { useDebounce } from './useDebounce';
3
+ export { useLocalStorage } from './useLocalStorage';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { ApiResponse, EmbeddableApiConfig } from '../types';
2
+
3
+ /**
4
+ * React hook for API calls with loading and error states
5
+ * @param config - API configuration
6
+ * @returns API client with state management
7
+ */
8
+ export declare function useApi(config: EmbeddableApiConfig): {
9
+ get: <T = any>(endpoint: string) => Promise<ApiResponse<T>>;
10
+ post: <T = any>(endpoint: string, body?: any) => Promise<ApiResponse<T>>;
11
+ put: <T = any>(endpoint: string, body?: any) => Promise<ApiResponse<T>>;
12
+ delete: <T = any>(endpoint: string) => Promise<ApiResponse<T>>;
13
+ reset: () => void;
14
+ data: any;
15
+ loading: boolean;
16
+ error: string | null;
17
+ };
18
+ //# sourceMappingURL=useApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useApi.d.ts","sourceRoot":"","sources":["../../src/hooks/useApi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AASjE;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,mBAAmB;UA8DvB,CAAC,kBAAkB,MAAM;WAG/C,CAAC,kBAAkB,MAAM,SAAS,GAAG;UAKrC,CAAC,kBAAkB,MAAM,SAAS,GAAG;aAIf,CAAC,kBAAkB,MAAM;;;aAnFzC,OAAO;WACT,MAAM,GAAG,IAAI;EAoGrB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * React hook that debounces a value
3
+ * @param value - The value to debounce
4
+ * @param delay - The delay in milliseconds
5
+ * @returns The debounced value
6
+ */
7
+ export declare function useDebounce<T>(value: T, delay: number): T;
8
+ //# sourceMappingURL=useDebounce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebounce.d.ts","sourceRoot":"","sources":["../../src/hooks/useDebounce.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAczD"}
@@ -0,0 +1,11 @@
1
+ import { LocalStorageOptions } from '../types';
2
+
3
+ /**
4
+ * React hook for localStorage with state synchronization
5
+ * @param key - The localStorage key
6
+ * @param initialValue - The initial value if key doesn't exist
7
+ * @param options - Storage options
8
+ * @returns [value, setValue, removeValue]
9
+ */
10
+ export declare function useLocalStorage<T>(key: string, initialValue: T, options?: LocalStorageOptions): [T, (value: T | ((prev: T) => T)) => void, () => void];
11
+ //# sourceMappingURL=useLocalStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLocalStorage.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalStorage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,CAAC,EACf,OAAO,GAAE,mBAAwB,GAChC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,MAAM,IAAI,CAAC,CAsDxD"}
package/dist/hooks.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useLocalStorage-C4q-PhVk.cjs");exports.useApi=e.useApi,exports.useDebounce=e.useDebounce,exports.useLocalStorage=e.useLocalStorage;
@@ -0,0 +1 @@
1
+ export * from './hooks/index'
package/dist/hooks.js ADDED
@@ -0,0 +1,6 @@
1
+ import { u, a, b } from "./useLocalStorage-BYg8a4Ry.js";
2
+ export {
3
+ u as useApi,
4
+ a as useDebounce,
5
+ b as useLocalStorage
6
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useLocalStorage-C4q-PhVk.cjs"),o=require("./storage-3dk6ww91.cjs"),r=require("./utils.cjs");exports.useApi=e.useApi,exports.useDebounce=e.useDebounce,exports.useLocalStorage=e.useLocalStorage,exports.createApiClient=o.createApiClient,exports.storage=o.storage,exports.debounce=r.debounce;
@@ -0,0 +1,4 @@
1
+ export * from './hooks';
2
+ export * from './utils';
3
+ export type * from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AAGxB,mBAAmB,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ import { u, a, b } from "./useLocalStorage-BYg8a4Ry.js";
2
+ import { c, s } from "./storage-CRPDfSRn.js";
3
+ import { debounce } from "./utils.js";
4
+ export {
5
+ c as createApiClient,
6
+ debounce,
7
+ s as storage,
8
+ u as useApi,
9
+ a as useDebounce,
10
+ b as useLocalStorage
11
+ };
@@ -0,0 +1 @@
1
+ "use strict";const e={get(e,t={}){try{const{prefix:r="",deserialize:o=JSON.parse}=t,a=r+e,s=localStorage.getItem(a);return null===s?null:o(s)}catch(r){return null}},set(e,t,r={}){try{const{prefix:o="",serialize:a=JSON.stringify}=r,s=o+e,c=a(t);localStorage.setItem(s,c)}catch(o){}},remove(e,t={}){try{const{prefix:r=""}=t,o=r+e;localStorage.removeItem(o)}catch(r){}},clear(e={}){try{const{prefix:t=""}=e;if(!t)return void localStorage.clear();const r=[];for(let e=0;e<localStorage.length;e++){const o=localStorage.key(e);o&&o.startsWith(t)&&r.push(o)}r.forEach((e=>localStorage.removeItem(e)))}catch(t){}},isAvailable(){try{const e="__storage_test__";return localStorage.setItem(e,"test"),localStorage.removeItem(e),!0}catch{return!1}}};exports.createApiClient=function(e){const t=e.baseUrl||"https://api.embeddable.com",r={"Content-Type":"application/json"};e.apiKey&&(r.Authorization=`Bearer ${e.apiKey}`);const o=async(o,a={})=>{try{const e=`${t}${o}`,s=await fetch(e,{...a,headers:{...r,...a.headers}}),c=await s.json();return s.ok?{data:c,success:!0}:{data:null,success:!1,error:c.message||`HTTP ${s.status}`}}catch(s){return e.debug,{data:null,success:!1,error:s instanceof Error?s.message:"Unknown error"}}};return{get:e=>o(e,{method:"GET"}),post:(e,t)=>o(e,{method:"POST",body:t?JSON.stringify(t):void 0}),put:(e,t)=>o(e,{method:"PUT",body:t?JSON.stringify(t):void 0}),delete:e=>o(e,{method:"DELETE"})}},exports.storage=e;
@@ -0,0 +1,147 @@
1
+ function createApiClient(config) {
2
+ const baseUrl = config.baseUrl || "https://api.embeddable.com";
3
+ const headers = {
4
+ "Content-Type": "application/json"
5
+ };
6
+ if (config.apiKey) {
7
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
8
+ }
9
+ const request = async (endpoint, options = {}) => {
10
+ try {
11
+ const url = `${baseUrl}${endpoint}`;
12
+ const response = await fetch(url, {
13
+ ...options,
14
+ headers: {
15
+ ...headers,
16
+ ...options.headers
17
+ }
18
+ });
19
+ const data = await response.json();
20
+ if (!response.ok) {
21
+ return {
22
+ data: null,
23
+ success: false,
24
+ error: data.message || `HTTP ${response.status}`
25
+ };
26
+ }
27
+ return {
28
+ data,
29
+ success: true
30
+ };
31
+ } catch (error) {
32
+ if (config.debug) {
33
+ console.error("API Request failed:", error);
34
+ }
35
+ return {
36
+ data: null,
37
+ success: false,
38
+ error: error instanceof Error ? error.message : "Unknown error"
39
+ };
40
+ }
41
+ };
42
+ return {
43
+ get: (endpoint) => request(endpoint, { method: "GET" }),
44
+ post: (endpoint, body) => request(endpoint, {
45
+ method: "POST",
46
+ body: body ? JSON.stringify(body) : void 0
47
+ }),
48
+ put: (endpoint, body) => request(endpoint, {
49
+ method: "PUT",
50
+ body: body ? JSON.stringify(body) : void 0
51
+ }),
52
+ delete: (endpoint) => request(endpoint, { method: "DELETE" })
53
+ };
54
+ }
55
+ const storage = {
56
+ /**
57
+ * Get an item from localStorage
58
+ * @param key - The key to retrieve
59
+ * @param options - Storage options
60
+ * @returns The parsed value or null if not found
61
+ */
62
+ get(key, options = {}) {
63
+ try {
64
+ const { prefix = "", deserialize = JSON.parse } = options;
65
+ const fullKey = prefix + key;
66
+ const item = localStorage.getItem(fullKey);
67
+ if (item === null) {
68
+ return null;
69
+ }
70
+ return deserialize(item);
71
+ } catch (error) {
72
+ console.warn(`Failed to get item from localStorage: ${key}`, error);
73
+ return null;
74
+ }
75
+ },
76
+ /**
77
+ * Set an item in localStorage
78
+ * @param key - The key to set
79
+ * @param value - The value to store
80
+ * @param options - Storage options
81
+ */
82
+ set(key, value, options = {}) {
83
+ try {
84
+ const { prefix = "", serialize = JSON.stringify } = options;
85
+ const fullKey = prefix + key;
86
+ const serializedValue = serialize(value);
87
+ localStorage.setItem(fullKey, serializedValue);
88
+ } catch (error) {
89
+ console.warn(`Failed to set item in localStorage: ${key}`, error);
90
+ }
91
+ },
92
+ /**
93
+ * Remove an item from localStorage
94
+ * @param key - The key to remove
95
+ * @param options - Storage options
96
+ */
97
+ remove(key, options = {}) {
98
+ try {
99
+ const { prefix = "" } = options;
100
+ const fullKey = prefix + key;
101
+ localStorage.removeItem(fullKey);
102
+ } catch (error) {
103
+ console.warn(`Failed to remove item from localStorage: ${key}`, error);
104
+ }
105
+ },
106
+ /**
107
+ * Clear all items with the given prefix
108
+ * @param options - Storage options
109
+ */
110
+ clear(options = {}) {
111
+ try {
112
+ const { prefix = "" } = options;
113
+ if (!prefix) {
114
+ localStorage.clear();
115
+ return;
116
+ }
117
+ const keysToRemove = [];
118
+ for (let i = 0; i < localStorage.length; i++) {
119
+ const key = localStorage.key(i);
120
+ if (key && key.startsWith(prefix)) {
121
+ keysToRemove.push(key);
122
+ }
123
+ }
124
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
125
+ } catch (error) {
126
+ console.warn("Failed to clear localStorage", error);
127
+ }
128
+ },
129
+ /**
130
+ * Check if localStorage is available
131
+ * @returns True if localStorage is available
132
+ */
133
+ isAvailable() {
134
+ try {
135
+ const testKey = "__storage_test__";
136
+ localStorage.setItem(testKey, "test");
137
+ localStorage.removeItem(testKey);
138
+ return true;
139
+ } catch {
140
+ return false;
141
+ }
142
+ }
143
+ };
144
+ export {
145
+ createApiClient as c,
146
+ storage as s
147
+ };
@@ -0,0 +1,27 @@
1
+ export interface EmbeddableApiConfig {
2
+ apiKey?: string;
3
+ baseUrl?: string;
4
+ debug?: boolean;
5
+ }
6
+ export interface ApiResponse<T = any> {
7
+ data: T;
8
+ success: boolean;
9
+ message?: string;
10
+ error?: string;
11
+ }
12
+ export interface LocalStorageOptions {
13
+ prefix?: string;
14
+ serialize?: (value: any) => string;
15
+ deserialize?: (value: string) => any;
16
+ }
17
+ export type Theme = 'light' | 'dark' | 'auto';
18
+ export interface ThemeConfig {
19
+ theme: Theme;
20
+ colors?: {
21
+ primary?: string;
22
+ secondary?: string;
23
+ background?: string;
24
+ text?: string;
25
+ };
26
+ }
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC;CACtC;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH"}
@@ -0,0 +1,139 @@
1
+ import { useState, useCallback, useEffect } from "react";
2
+ import { c as createApiClient, s as storage } from "./storage-CRPDfSRn.js";
3
+ function useApi(config) {
4
+ const [state, setState] = useState({
5
+ data: null,
6
+ loading: false,
7
+ error: null
8
+ });
9
+ const apiClient = createApiClient(config);
10
+ const request = useCallback(
11
+ async (method, endpoint, body) => {
12
+ setState((prev) => ({ ...prev, loading: true, error: null }));
13
+ try {
14
+ let response;
15
+ switch (method) {
16
+ case "get":
17
+ response = await apiClient.get(endpoint);
18
+ break;
19
+ case "post":
20
+ response = await apiClient.post(endpoint, body);
21
+ break;
22
+ case "put":
23
+ response = await apiClient.put(endpoint, body);
24
+ break;
25
+ case "delete":
26
+ response = await apiClient.delete(endpoint);
27
+ break;
28
+ default:
29
+ throw new Error(`Unsupported method: ${method}`);
30
+ }
31
+ setState({
32
+ data: response.data,
33
+ loading: false,
34
+ error: response.success ? null : response.error || "Unknown error"
35
+ });
36
+ return response;
37
+ } catch (error) {
38
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
39
+ setState({
40
+ data: null,
41
+ loading: false,
42
+ error: errorMessage
43
+ });
44
+ return {
45
+ data: null,
46
+ success: false,
47
+ error: errorMessage
48
+ };
49
+ }
50
+ },
51
+ [apiClient]
52
+ );
53
+ const get = useCallback((endpoint) => request("get", endpoint), [request]);
54
+ const post = useCallback(
55
+ (endpoint, body) => request("post", endpoint, body),
56
+ [request]
57
+ );
58
+ const put = useCallback(
59
+ (endpoint, body) => request("put", endpoint, body),
60
+ [request]
61
+ );
62
+ const del = useCallback((endpoint) => request("delete", endpoint), [request]);
63
+ const reset = useCallback(() => {
64
+ setState({
65
+ data: null,
66
+ loading: false,
67
+ error: null
68
+ });
69
+ }, []);
70
+ return {
71
+ ...state,
72
+ get,
73
+ post,
74
+ put,
75
+ delete: del,
76
+ reset
77
+ };
78
+ }
79
+ function useDebounce(value, delay) {
80
+ const [debouncedValue, setDebouncedValue] = useState(value);
81
+ useEffect(() => {
82
+ const handler = setTimeout(() => {
83
+ setDebouncedValue(value);
84
+ }, delay);
85
+ return () => {
86
+ clearTimeout(handler);
87
+ };
88
+ }, [value, delay]);
89
+ return debouncedValue;
90
+ }
91
+ function useLocalStorage(key, initialValue, options = {}) {
92
+ const [storedValue, setStoredValue] = useState(() => {
93
+ const item = storage.get(key, options);
94
+ return item !== null ? item : initialValue;
95
+ });
96
+ const setValue = useCallback(
97
+ (value) => {
98
+ try {
99
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
100
+ setStoredValue(valueToStore);
101
+ storage.set(key, valueToStore, options);
102
+ } catch (error) {
103
+ console.warn(`Error setting localStorage key "${key}":`, error);
104
+ }
105
+ },
106
+ [key, storedValue, options]
107
+ );
108
+ const removeValue = useCallback(() => {
109
+ try {
110
+ setStoredValue(initialValue);
111
+ storage.remove(key, options);
112
+ } catch (error) {
113
+ console.warn(`Error removing localStorage key "${key}":`, error);
114
+ }
115
+ }, [key, initialValue, options]);
116
+ useEffect(() => {
117
+ const handleStorageChange = (e) => {
118
+ const { prefix = "" } = options;
119
+ const fullKey = prefix + key;
120
+ if (e.key === fullKey && e.newValue !== null) {
121
+ try {
122
+ const { deserialize = JSON.parse } = options;
123
+ const newValue = deserialize(e.newValue);
124
+ setStoredValue(newValue);
125
+ } catch (error) {
126
+ console.warn(`Error parsing localStorage value for key "${key}":`, error);
127
+ }
128
+ }
129
+ };
130
+ window.addEventListener("storage", handleStorageChange);
131
+ return () => window.removeEventListener("storage", handleStorageChange);
132
+ }, [key, options]);
133
+ return [storedValue, setValue, removeValue];
134
+ }
135
+ export {
136
+ useDebounce as a,
137
+ useLocalStorage as b,
138
+ useApi as u
139
+ };
@@ -0,0 +1 @@
1
+ "use strict";const e=require("react"),t=require("./storage-3dk6ww91.cjs");exports.useApi=function(r){const[a,s]=e.useState({data:null,loading:!1,error:null}),n=t.createApiClient(r),o=e.useCallback((async(e,t,r)=>{s((e=>({...e,loading:!0,error:null})));try{let a;switch(e){case"get":a=await n.get(t);break;case"post":a=await n.post(t,r);break;case"put":a=await n.put(t,r);break;case"delete":a=await n.delete(t);break;default:throw new Error(`Unsupported method: ${e}`)}return s({data:a.data,loading:!1,error:a.success?null:a.error||"Unknown error"}),a}catch(a){const e=a instanceof Error?a.message:"Unknown error";return s({data:null,loading:!1,error:e}),{data:null,success:!1,error:e}}}),[n]);return{...a,get:e.useCallback((e=>o("get",e)),[o]),post:e.useCallback(((e,t)=>o("post",e,t)),[o]),put:e.useCallback(((e,t)=>o("put",e,t)),[o]),delete:e.useCallback((e=>o("delete",e)),[o]),reset:e.useCallback((()=>{s({data:null,loading:!1,error:null})}),[])}},exports.useDebounce=function(t,r){const[a,s]=e.useState(t);return e.useEffect((()=>{const e=setTimeout((()=>{s(t)}),r);return()=>{clearTimeout(e)}}),[t,r]),a},exports.useLocalStorage=function(r,a,s={}){const[n,o]=e.useState((()=>{const e=t.storage.get(r,s);return null!==e?e:a})),u=e.useCallback((e=>{try{const a=e instanceof Function?e(n):e;o(a),t.storage.set(r,a,s)}catch(a){}}),[r,n,s]),l=e.useCallback((()=>{try{o(a),t.storage.remove(r,s)}catch(e){}}),[r,a,s]);return e.useEffect((()=>{const e=e=>{const{prefix:t=""}=s,a=t+r;if(e.key===a&&null!==e.newValue)try{const{deserialize:t=JSON.parse}=s,r=t(e.newValue);o(r)}catch(n){}};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[r,s]),[n,u,l]};
@@ -0,0 +1,14 @@
1
+ import { ApiResponse, EmbeddableApiConfig } from '../types';
2
+
3
+ /**
4
+ * Creates an API client with the given configuration
5
+ * @param config - The configuration for the API client
6
+ * @returns API client with common methods
7
+ */
8
+ export declare function createApiClient(config: EmbeddableApiConfig): {
9
+ get: <T = any>(endpoint: string) => Promise<ApiResponse<T>>;
10
+ post: <T = any>(endpoint: string, body?: any) => Promise<ApiResponse<T>>;
11
+ put: <T = any>(endpoint: string, body?: any) => Promise<ApiResponse<T>>;
12
+ delete: <T = any>(endpoint: string) => Promise<ApiResponse<T>>;
13
+ };
14
+ //# sourceMappingURL=apiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/utils/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,mBAAmB;UAoDjD,CAAC,kBAAkB,MAAM;WACxB,CAAC,kBAAkB,MAAM,SAAS,GAAG;UAKtC,CAAC,kBAAkB,MAAM,SAAS,GAAG;aAKlC,CAAC,kBAAkB,MAAM;EAErC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Creates a debounced function that delays invoking func until after wait milliseconds
3
+ * have elapsed since the last time the debounced function was invoked.
4
+ * @param func - The function to debounce
5
+ * @param wait - The number of milliseconds to delay
6
+ * @returns The debounced function
7
+ */
8
+ export declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
9
+ //# sourceMappingURL=debounce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../src/utils/debounce.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxD,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,MAAM,GACX,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAclC"}
@@ -0,0 +1,4 @@
1
+ export { createApiClient } from './apiClient';
2
+ export { debounce } from './debounce';
3
+ export { storage } from './storage';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { LocalStorageOptions } from '../types';
2
+
3
+ /**
4
+ * Enhanced localStorage utility with serialization and error handling
5
+ */
6
+ export declare const storage: {
7
+ /**
8
+ * Get an item from localStorage
9
+ * @param key - The key to retrieve
10
+ * @param options - Storage options
11
+ * @returns The parsed value or null if not found
12
+ */
13
+ get<T = any>(key: string, options?: LocalStorageOptions): T | null;
14
+ /**
15
+ * Set an item in localStorage
16
+ * @param key - The key to set
17
+ * @param value - The value to store
18
+ * @param options - Storage options
19
+ */
20
+ set<T = any>(key: string, value: T, options?: LocalStorageOptions): void;
21
+ /**
22
+ * Remove an item from localStorage
23
+ * @param key - The key to remove
24
+ * @param options - Storage options
25
+ */
26
+ remove(key: string, options?: LocalStorageOptions): void;
27
+ /**
28
+ * Clear all items with the given prefix
29
+ * @param options - Storage options
30
+ */
31
+ clear(options?: LocalStorageOptions): void;
32
+ /**
33
+ * Check if localStorage is available
34
+ * @returns True if localStorage is available
35
+ */
36
+ isAvailable(): boolean;
37
+ };
38
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,OAAO;IAClB;;;;;OAKG;QACC,CAAC,aAAa,MAAM,YAAW,mBAAmB,GAAQ,CAAC,GAAG,IAAI;IAiBtE;;;;;OAKG;QACC,CAAC,aAAa,MAAM,SAAS,CAAC,YAAW,mBAAmB,GAAQ,IAAI;IAW5E;;;;OAIG;gBACS,MAAM,YAAW,mBAAmB,GAAQ,IAAI;IAU5D;;;OAGG;oBACY,mBAAmB,GAAQ,IAAI;IAuB9C;;;OAGG;mBACY,OAAO;CAUvB,CAAC"}
package/dist/utils.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./storage-3dk6ww91.cjs");exports.createApiClient=e.createApiClient,exports.storage=e.storage,exports.debounce=function(e,t){let o;return function(...r){void 0!==o&&clearTimeout(o),o=setTimeout((()=>{o=void 0,e(...r)}),t)}};
@@ -0,0 +1 @@
1
+ export * from './utils/index'
package/dist/utils.js ADDED
@@ -0,0 +1,19 @@
1
+ import { c, s } from "./storage-CRPDfSRn.js";
2
+ function debounce(func, wait) {
3
+ let timeoutId;
4
+ return function debounced(...args) {
5
+ const later = () => {
6
+ timeoutId = void 0;
7
+ func(...args);
8
+ };
9
+ if (timeoutId !== void 0) {
10
+ clearTimeout(timeoutId);
11
+ }
12
+ timeoutId = setTimeout(later, wait);
13
+ };
14
+ }
15
+ export {
16
+ c as createApiClient,
17
+ debounce,
18
+ s as storage
19
+ };
package/package.json ADDED
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "@embeddable/sdk",
3
+ "version": "1.0.0",
4
+ "description": "A TypeScript/JavaScript SDK with React utilities and hooks for embeddable applications",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./hooks": {
16
+ "import": "./dist/hooks/index.js",
17
+ "require": "./dist/hooks/index.cjs",
18
+ "types": "./dist/hooks/index.d.ts"
19
+ },
20
+ "./utils": {
21
+ "import": "./dist/utils/index.js",
22
+ "require": "./dist/utils/index.cjs",
23
+ "types": "./dist/utils/index.d.ts"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "sideEffects": false,
32
+ "scripts": {
33
+ "dev": "vite",
34
+ "build": "tsc && vite build",
35
+ "preview": "vite preview",
36
+ "test": "vitest",
37
+ "test:ui": "vitest --ui",
38
+ "test:coverage": "vitest --coverage",
39
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
40
+ "lint:fix": "eslint . --ext ts,tsx --fix",
41
+ "format": "prettier --write .",
42
+ "format:check": "prettier --check .",
43
+ "type-check": "tsc --noEmit",
44
+ "prepare": "husky install",
45
+ "semantic-release": "semantic-release"
46
+ },
47
+ "keywords": [
48
+ "react",
49
+ "hooks",
50
+ "utilities",
51
+ "typescript",
52
+ "embeddable",
53
+ "sdk",
54
+ "tree-shaking"
55
+ ],
56
+ "author": "Embeddable Team",
57
+ "license": "MIT",
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/CommonNinja/embeddable-sdk.git"
61
+ },
62
+ "bugs": {
63
+ "url": "https://github.com/CommonNinja/embeddable-sdk/issues"
64
+ },
65
+ "homepage": "https://github.com/CommonNinja/embeddable-sdk#readme",
66
+ "peerDependencies": {
67
+ "react": ">=18.2.0",
68
+ "react-dom": ">=18.2.0"
69
+ },
70
+ "devDependencies": {
71
+ "@commitlint/cli": "^18.4.3",
72
+ "@commitlint/config-conventional": "^18.4.3",
73
+ "@semantic-release/changelog": "^6.0.3",
74
+ "@semantic-release/git": "^10.0.1",
75
+ "@semantic-release/github": "^9.2.6",
76
+ "@semantic-release/npm": "^11.0.2",
77
+ "@testing-library/jest-dom": "^6.1.5",
78
+ "@testing-library/react": "^14.1.2",
79
+ "@testing-library/user-event": "^14.5.1",
80
+ "@types/react": "^18.2.43",
81
+ "@types/react-dom": "^18.2.17",
82
+ "@typescript-eslint/eslint-plugin": "^6.14.0",
83
+ "@typescript-eslint/parser": "^6.14.0",
84
+ "@vitejs/plugin-react": "^4.2.1",
85
+ "@vitest/coverage-v8": "^1.0.4",
86
+ "@vitest/ui": "^1.0.4",
87
+ "eslint": "^8.55.0",
88
+ "eslint-config-prettier": "^10.1.5",
89
+ "eslint-plugin-react": "^7.33.2",
90
+ "eslint-plugin-react-hooks": "^4.6.0",
91
+ "eslint-plugin-react-refresh": "^0.4.5",
92
+ "husky": "^8.0.3",
93
+ "jsdom": "^23.0.1",
94
+ "lint-staged": "^15.2.0",
95
+ "prettier": "^3.5.3",
96
+ "react": "^18.2.0",
97
+ "react-dom": "^18.2.0",
98
+ "semantic-release": "^22.0.12",
99
+ "terser": "^5.39.2",
100
+ "typescript": "^5.2.2",
101
+ "vite": "^5.0.8",
102
+ "vite-plugin-dts": "^3.6.4",
103
+ "vitest": "^1.0.4"
104
+ },
105
+ "lint-staged": {
106
+ "*.{ts,tsx,js,jsx,json,md}": [
107
+ "prettier --write"
108
+ ],
109
+ "*.{ts,tsx}": [
110
+ "eslint --fix"
111
+ ]
112
+ },
113
+ "publishConfig": {
114
+ "access": "public"
115
+ }
116
+ }