@profplum700/etsy-nextjs 2.3.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 +338 -0
- package/dist/index.cjs +206 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.esm.js +199 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# @profplum700/etsy-nextjs
|
|
2
|
+
|
|
3
|
+
Next.js integration for the Etsy v3 API client. Seamlessly integrate Etsy into your Next.js applications with Server Components, API Routes, and more.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @profplum700/etsy-nextjs @profplum700/etsy-v3-api-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Server Components support
|
|
14
|
+
- API Routes helpers
|
|
15
|
+
- Automatic rate limiting
|
|
16
|
+
- Built-in caching
|
|
17
|
+
- Cookie-based token storage
|
|
18
|
+
- Edge Runtime compatibility
|
|
19
|
+
- TypeScript support
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### 1. Configure the Server Client
|
|
24
|
+
|
|
25
|
+
Create a configuration file (e.g., `lib/etsy-server.ts`):
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { configureEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
29
|
+
|
|
30
|
+
configureEtsyServerClient({
|
|
31
|
+
apiKey: process.env.ETSY_API_KEY!,
|
|
32
|
+
redirectUri: process.env.ETSY_REDIRECT_URI!,
|
|
33
|
+
scopes: ['listings_r', 'listings_w', 'shops_r'],
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Use in Server Components
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// app/shop/[shopId]/page.tsx
|
|
41
|
+
import { getEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
42
|
+
|
|
43
|
+
export default async function ShopPage({ params }: { params: { shopId: string } }) {
|
|
44
|
+
const client = await getEtsyServerClient();
|
|
45
|
+
const shop = await client.getShop(params.shopId);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div>
|
|
49
|
+
<h1>{shop.title}</h1>
|
|
50
|
+
<p>{shop.announcement}</p>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 3. Create API Routes
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// app/api/etsy/[...path]/route.ts
|
|
60
|
+
import { createEtsyApiRoute } from '@profplum700/etsy-nextjs';
|
|
61
|
+
|
|
62
|
+
export const { GET, POST, PUT, DELETE } = createEtsyApiRoute({
|
|
63
|
+
apiKey: process.env.ETSY_API_KEY!,
|
|
64
|
+
rateLimit: {
|
|
65
|
+
requests: 100,
|
|
66
|
+
window: 60000, // 1 minute
|
|
67
|
+
},
|
|
68
|
+
cache: {
|
|
69
|
+
enabled: true,
|
|
70
|
+
ttl: 300, // 5 minutes
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 4. Use in Client Components
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
'use client';
|
|
79
|
+
|
|
80
|
+
import { EtsyNextClientProvider, useEtsyNextClient } from '@profplum700/etsy-nextjs';
|
|
81
|
+
import { EtsyClient } from '@profplum700/etsy-v3-api-client';
|
|
82
|
+
|
|
83
|
+
const client = new EtsyClient({
|
|
84
|
+
apiKey: process.env.NEXT_PUBLIC_ETSY_API_KEY!,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export default function App({ children }) {
|
|
88
|
+
return (
|
|
89
|
+
<EtsyNextClientProvider client={client} apiEndpoint="/api/etsy">
|
|
90
|
+
{children}
|
|
91
|
+
</EtsyNextClientProvider>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function MyComponent() {
|
|
96
|
+
const { client } = useEtsyNextClient();
|
|
97
|
+
|
|
98
|
+
// Use the client in your component
|
|
99
|
+
const handleFetch = async () => {
|
|
100
|
+
const shop = await client.getShop('123');
|
|
101
|
+
console.log(shop);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return <button onClick={handleFetch}>Fetch Shop</button>;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API Reference
|
|
109
|
+
|
|
110
|
+
### Server-Side
|
|
111
|
+
|
|
112
|
+
#### `configureEtsyServerClient(config)`
|
|
113
|
+
|
|
114
|
+
Configure the global Etsy server client.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
interface EtsyServerClientConfig {
|
|
118
|
+
apiKey: string;
|
|
119
|
+
redirectUri?: string;
|
|
120
|
+
scopes?: string[];
|
|
121
|
+
cookieName?: string;
|
|
122
|
+
encryptionKey?: string;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### `getEtsyServerClient()`
|
|
127
|
+
|
|
128
|
+
Get the configured Etsy server client instance. Use in Server Components and Server Actions.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const client = await getEtsyServerClient();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### `createEtsyServerClient(config)`
|
|
135
|
+
|
|
136
|
+
Create a new Etsy server client with custom configuration.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const client = createEtsyServerClient({
|
|
140
|
+
apiKey: process.env.ETSY_API_KEY!,
|
|
141
|
+
redirectUri: process.env.ETSY_REDIRECT_URI!,
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### `createEtsyApiRoute(config)`
|
|
146
|
+
|
|
147
|
+
Create API route handlers with built-in rate limiting and caching.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
interface EtsyApiRouteConfig {
|
|
151
|
+
apiKey: string;
|
|
152
|
+
redirectUri?: string;
|
|
153
|
+
scopes?: string[];
|
|
154
|
+
rateLimit?: {
|
|
155
|
+
requests: number;
|
|
156
|
+
window: number; // in milliseconds
|
|
157
|
+
};
|
|
158
|
+
cache?: {
|
|
159
|
+
enabled: boolean;
|
|
160
|
+
ttl: number; // in seconds
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Client-Side
|
|
166
|
+
|
|
167
|
+
#### `<EtsyNextClientProvider>`
|
|
168
|
+
|
|
169
|
+
Provider component for client-side Etsy client.
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<EtsyNextClientProvider client={client} apiEndpoint="/api/etsy">
|
|
173
|
+
{children}
|
|
174
|
+
</EtsyNextClientProvider>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### `useEtsyNextClient()`
|
|
178
|
+
|
|
179
|
+
Hook to access the Etsy client in client components.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const { client, apiEndpoint } = useEtsyNextClient();
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Usage Examples
|
|
186
|
+
|
|
187
|
+
### Server Component with Data Fetching
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// app/listings/page.tsx
|
|
191
|
+
import { getEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
192
|
+
|
|
193
|
+
export default async function ListingsPage() {
|
|
194
|
+
const client = await getEtsyServerClient();
|
|
195
|
+
const response = await client.getListingsByShop('123', {
|
|
196
|
+
state: 'active',
|
|
197
|
+
limit: 25,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<div>
|
|
202
|
+
<h1>Listings</h1>
|
|
203
|
+
<ul>
|
|
204
|
+
{response.results.map((listing) => (
|
|
205
|
+
<li key={listing.listing_id}>{listing.title}</li>
|
|
206
|
+
))}
|
|
207
|
+
</ul>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### API Route with Rate Limiting
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// app/api/shop/[shopId]/route.ts
|
|
217
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
218
|
+
import { getEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
219
|
+
|
|
220
|
+
export async function GET(
|
|
221
|
+
request: NextRequest,
|
|
222
|
+
{ params }: { params: { shopId: string } }
|
|
223
|
+
) {
|
|
224
|
+
try {
|
|
225
|
+
const client = await getEtsyServerClient();
|
|
226
|
+
const shop = await client.getShop(params.shopId);
|
|
227
|
+
|
|
228
|
+
return NextResponse.json(shop);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return NextResponse.json(
|
|
231
|
+
{ error: 'Failed to fetch shop' },
|
|
232
|
+
{ status: 500 }
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Server Action
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
'use server';
|
|
242
|
+
|
|
243
|
+
import { getEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
244
|
+
import { revalidatePath } from 'next/cache';
|
|
245
|
+
|
|
246
|
+
export async function updateListing(shopId: string, listingId: string, updates: any) {
|
|
247
|
+
const client = await getEtsyServerClient();
|
|
248
|
+
const result = await client.updateListing(shopId, listingId, updates);
|
|
249
|
+
|
|
250
|
+
// Revalidate the page to show updated data
|
|
251
|
+
revalidatePath(`/listings/${listingId}`);
|
|
252
|
+
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Static Site Generation (SSG)
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// app/shop/[shopId]/page.tsx
|
|
261
|
+
import { getEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
262
|
+
|
|
263
|
+
export async function generateStaticParams() {
|
|
264
|
+
// Generate paths for your shops
|
|
265
|
+
return [
|
|
266
|
+
{ shopId: '123' },
|
|
267
|
+
{ shopId: '456' },
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export default async function ShopPage({ params }: { params: { shopId: string } }) {
|
|
272
|
+
const client = await getEtsyServerClient();
|
|
273
|
+
const shop = await client.getShop(params.shopId);
|
|
274
|
+
|
|
275
|
+
return <div>{shop.title}</div>;
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Incremental Static Regeneration (ISR)
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
// app/listings/page.tsx
|
|
283
|
+
import { getEtsyServerClient } from '@profplum700/etsy-nextjs/server';
|
|
284
|
+
|
|
285
|
+
export const revalidate = 3600; // Revalidate every hour
|
|
286
|
+
|
|
287
|
+
export default async function ListingsPage() {
|
|
288
|
+
const client = await getEtsyServerClient();
|
|
289
|
+
const response = await client.getListingsByShop('123');
|
|
290
|
+
|
|
291
|
+
return <div>{/* Render listings */}</div>;
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Environment Variables
|
|
296
|
+
|
|
297
|
+
```env
|
|
298
|
+
# Required
|
|
299
|
+
ETSY_API_KEY=your_api_key
|
|
300
|
+
|
|
301
|
+
# Optional
|
|
302
|
+
ETSY_REDIRECT_URI=http://localhost:3000/auth/callback
|
|
303
|
+
ETSY_SCOPES=listings_r,listings_w,shops_r
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## TypeScript Support
|
|
307
|
+
|
|
308
|
+
All functions and components are fully typed with TypeScript.
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import type {
|
|
312
|
+
EtsyServerClientConfig,
|
|
313
|
+
EtsyApiRouteConfig,
|
|
314
|
+
} from '@profplum700/etsy-nextjs';
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Best Practices
|
|
318
|
+
|
|
319
|
+
1. **Use Server Components for Data Fetching**: Fetch data on the server to reduce client bundle size and improve performance.
|
|
320
|
+
|
|
321
|
+
2. **Implement Rate Limiting**: Use the built-in rate limiting in API routes to prevent abuse.
|
|
322
|
+
|
|
323
|
+
3. **Cache Responses**: Enable caching for frequently accessed data to reduce API calls.
|
|
324
|
+
|
|
325
|
+
4. **Secure Your Keys**: Never expose your API key in client-side code. Use server-side rendering or API routes.
|
|
326
|
+
|
|
327
|
+
5. **Handle Errors Gracefully**: Always wrap API calls in try-catch blocks and provide user feedback.
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
MIT
|
|
332
|
+
|
|
333
|
+
## Related Packages
|
|
334
|
+
|
|
335
|
+
- [@profplum700/etsy-v3-api-client](../etsy-v3-api-client) - Core API client
|
|
336
|
+
- [@profplum700/etsy-react](../etsy-react) - React hooks
|
|
337
|
+
- [@profplum700/etsy-cli](../etsy-cli) - CLI tool
|
|
338
|
+
- [@profplum700/etsy-admin-ui](../etsy-admin-ui) - Admin dashboard components
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var etsyV3ApiClient = require('@profplum700/etsy-v3-api-client');
|
|
4
|
+
var headers = require('next/headers');
|
|
5
|
+
var server = require('next/server');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
|
|
8
|
+
let serverClientInstance = null;
|
|
9
|
+
let serverClientConfig = null;
|
|
10
|
+
function configureEtsyServerClient(config) {
|
|
11
|
+
serverClientConfig = config;
|
|
12
|
+
}
|
|
13
|
+
async function getEtsyServerClient() {
|
|
14
|
+
if (!serverClientConfig) {
|
|
15
|
+
throw new Error('Etsy server client not configured. Call configureEtsyServerClient() first.');
|
|
16
|
+
}
|
|
17
|
+
if (!serverClientInstance) {
|
|
18
|
+
const { apiKey } = serverClientConfig;
|
|
19
|
+
const cookieStore = await headers.cookies();
|
|
20
|
+
const cookieName = serverClientConfig.cookieName || 'etsy-tokens';
|
|
21
|
+
const tokenData = cookieStore.get(cookieName);
|
|
22
|
+
if (!tokenData) {
|
|
23
|
+
throw new Error('No authentication tokens found in cookies');
|
|
24
|
+
}
|
|
25
|
+
let tokens;
|
|
26
|
+
try {
|
|
27
|
+
tokens = JSON.parse(tokenData.value);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error('Invalid token data in cookies');
|
|
31
|
+
}
|
|
32
|
+
const refreshSave = async (accessToken, refreshToken, expiresAt) => {
|
|
33
|
+
const cookieStore = await headers.cookies();
|
|
34
|
+
const cookieName = serverClientConfig?.cookieName || 'etsy-tokens';
|
|
35
|
+
cookieStore.set(cookieName, JSON.stringify({
|
|
36
|
+
accessToken,
|
|
37
|
+
refreshToken,
|
|
38
|
+
expiresAt: expiresAt.toISOString(),
|
|
39
|
+
}), {
|
|
40
|
+
httpOnly: true,
|
|
41
|
+
secure: process.env.NODE_ENV === 'production',
|
|
42
|
+
sameSite: 'lax',
|
|
43
|
+
maxAge: 60 * 60 * 24 * 90,
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
serverClientInstance = new etsyV3ApiClient.EtsyClient({
|
|
47
|
+
keystring: apiKey,
|
|
48
|
+
accessToken: tokens.accessToken,
|
|
49
|
+
refreshToken: tokens.refreshToken,
|
|
50
|
+
expiresAt: new Date(tokens.expiresAt),
|
|
51
|
+
refreshSave,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return serverClientInstance;
|
|
55
|
+
}
|
|
56
|
+
async function createEtsyServerClient(config) {
|
|
57
|
+
const { apiKey, cookieName } = config;
|
|
58
|
+
const cookieStore = await headers.cookies();
|
|
59
|
+
const tokenCookieName = cookieName || 'etsy-tokens';
|
|
60
|
+
const tokenData = cookieStore.get(tokenCookieName);
|
|
61
|
+
if (!tokenData) {
|
|
62
|
+
throw new Error('No authentication tokens found in cookies');
|
|
63
|
+
}
|
|
64
|
+
let tokens;
|
|
65
|
+
try {
|
|
66
|
+
tokens = JSON.parse(tokenData.value);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error('Invalid token data in cookies');
|
|
70
|
+
}
|
|
71
|
+
const refreshSave = async (accessToken, refreshToken, expiresAt) => {
|
|
72
|
+
const cookieStore = await headers.cookies();
|
|
73
|
+
cookieStore.set(tokenCookieName, JSON.stringify({
|
|
74
|
+
accessToken,
|
|
75
|
+
refreshToken,
|
|
76
|
+
expiresAt: expiresAt.toISOString(),
|
|
77
|
+
}), {
|
|
78
|
+
httpOnly: true,
|
|
79
|
+
secure: process.env.NODE_ENV === 'production',
|
|
80
|
+
sameSite: 'lax',
|
|
81
|
+
maxAge: 60 * 60 * 24 * 90,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
return new etsyV3ApiClient.EtsyClient({
|
|
85
|
+
keystring: apiKey,
|
|
86
|
+
accessToken: tokens.accessToken,
|
|
87
|
+
refreshToken: tokens.refreshToken,
|
|
88
|
+
expiresAt: new Date(tokens.expiresAt),
|
|
89
|
+
refreshSave,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const rateLimitStore = new Map();
|
|
94
|
+
function createEtsyApiRoute(config) {
|
|
95
|
+
const { rateLimit, cache } = config;
|
|
96
|
+
function checkRateLimit(identifier) {
|
|
97
|
+
if (!rateLimit)
|
|
98
|
+
return true;
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const entry = rateLimitStore.get(identifier);
|
|
101
|
+
if (!entry || now > entry.resetTime) {
|
|
102
|
+
rateLimitStore.set(identifier, {
|
|
103
|
+
count: 1,
|
|
104
|
+
resetTime: now + rateLimit.window,
|
|
105
|
+
});
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
if (entry.count >= rateLimit.requests) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
entry.count++;
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
async function handleRequest(request, handler) {
|
|
115
|
+
try {
|
|
116
|
+
if (rateLimit) {
|
|
117
|
+
const identifier = request.headers.get('x-forwarded-for') || 'anonymous';
|
|
118
|
+
if (!checkRateLimit(identifier)) {
|
|
119
|
+
return server.NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const client = await getEtsyServerClient();
|
|
123
|
+
const result = await handler(client, request);
|
|
124
|
+
const response = server.NextResponse.json(result);
|
|
125
|
+
if (cache?.enabled) {
|
|
126
|
+
response.headers.set('Cache-Control', `public, s-maxage=${cache.ttl}, stale-while-revalidate`);
|
|
127
|
+
}
|
|
128
|
+
return response;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error('Etsy API route error:', error);
|
|
132
|
+
if (error instanceof Error) {
|
|
133
|
+
return server.NextResponse.json({ error: error.message }, { status: 500 });
|
|
134
|
+
}
|
|
135
|
+
return server.NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
GET: async (request) => {
|
|
140
|
+
return handleRequest(request, async (_client) => {
|
|
141
|
+
const { searchParams } = new URL(request.url);
|
|
142
|
+
const endpoint = searchParams.get('endpoint');
|
|
143
|
+
if (!endpoint) {
|
|
144
|
+
throw new Error('Endpoint parameter is required');
|
|
145
|
+
}
|
|
146
|
+
const params = {};
|
|
147
|
+
searchParams.forEach((value, key) => {
|
|
148
|
+
if (key !== 'endpoint') {
|
|
149
|
+
params[key] = value;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
return { message: 'GET endpoint', endpoint, params };
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
POST: async (request) => {
|
|
156
|
+
return handleRequest(request, async (_client) => {
|
|
157
|
+
const body = await request.json();
|
|
158
|
+
const { endpoint, data } = body;
|
|
159
|
+
if (!endpoint) {
|
|
160
|
+
throw new Error('Endpoint parameter is required');
|
|
161
|
+
}
|
|
162
|
+
return { message: 'POST endpoint', endpoint, data };
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
PUT: async (request) => {
|
|
166
|
+
return handleRequest(request, async (_client) => {
|
|
167
|
+
const body = await request.json();
|
|
168
|
+
const { endpoint, data } = body;
|
|
169
|
+
if (!endpoint) {
|
|
170
|
+
throw new Error('Endpoint parameter is required');
|
|
171
|
+
}
|
|
172
|
+
return { message: 'PUT endpoint', endpoint, data };
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
DELETE: async (request) => {
|
|
176
|
+
return handleRequest(request, async (_client) => {
|
|
177
|
+
const { searchParams } = new URL(request.url);
|
|
178
|
+
const endpoint = searchParams.get('endpoint');
|
|
179
|
+
if (!endpoint) {
|
|
180
|
+
throw new Error('Endpoint parameter is required');
|
|
181
|
+
}
|
|
182
|
+
return { message: 'DELETE endpoint', endpoint };
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const EtsyNextClientContext = React.createContext(undefined);
|
|
189
|
+
function EtsyNextClientProvider({ client, apiEndpoint, children }) {
|
|
190
|
+
return (React.createElement(EtsyNextClientContext.Provider, { value: { client, apiEndpoint } }, children));
|
|
191
|
+
}
|
|
192
|
+
function useEtsyNextClient() {
|
|
193
|
+
const context = React.useContext(EtsyNextClientContext);
|
|
194
|
+
if (!context) {
|
|
195
|
+
throw new Error('useEtsyNextClient must be used within an EtsyNextClientProvider');
|
|
196
|
+
}
|
|
197
|
+
return context;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
exports.EtsyNextClientProvider = EtsyNextClientProvider;
|
|
201
|
+
exports.configureEtsyServerClient = configureEtsyServerClient;
|
|
202
|
+
exports.createEtsyApiRoute = createEtsyApiRoute;
|
|
203
|
+
exports.createEtsyServerClient = createEtsyServerClient;
|
|
204
|
+
exports.getEtsyServerClient = getEtsyServerClient;
|
|
205
|
+
exports.useEtsyNextClient = useEtsyNextClient;
|
|
206
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/server/client.ts","../../src/server/route.ts","../../src/client/provider.tsx"],"sourcesContent":[null,null,null],"names":["cookies","EtsyClient","NextResponse","createContext","useContext"],"mappings":";;;;;;;AAWA,IAAI,oBAAoB,GAAsB,IAAI;AAClD,IAAI,kBAAkB,GAAkC,IAAI;AAMtD,SAAU,yBAAyB,CAAC,MAA8B,EAAA;IACtE,kBAAkB,GAAG,MAAM;AAC7B;AAMO,eAAe,mBAAmB,GAAA;IACvC,IAAI,CAAC,kBAAkB,EAAE;AACvB,QAAA,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E;IACH;IAGA,IAAI,CAAC,oBAAoB,EAAE;AACzB,QAAA,MAAM,EAAE,MAAM,EAAE,GAAG,kBAAkB;AAGrC,QAAA,MAAM,WAAW,GAAG,MAAMA,eAAO,EAAE;AACnC,QAAA,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,IAAI,aAAa;QACjE,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC;QAE7C,IAAI,CAAC,SAAS,EAAE;AACd,YAAA,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC;QAC9D;AAEA,QAAA,IAAI,MAAwE;AAC5E,QAAA,IAAI;YACF,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;QACtC;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;QAClD;QAGA,MAAM,WAAW,GAAG,OAAO,WAAmB,EAAE,YAAoB,EAAE,SAAe,KAAmB;AACtG,YAAA,MAAM,WAAW,GAAG,MAAMA,eAAO,EAAE;AACnC,YAAA,MAAM,UAAU,GAAG,kBAAkB,EAAE,UAAU,IAAI,aAAa;YAClE,WAAW,CAAC,GAAG,CACb,UAAU,EACV,IAAI,CAAC,SAAS,CAAC;gBACb,WAAW;gBACX,YAAY;AACZ,gBAAA,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;AACnC,aAAA,CAAC,EACF;AACE,gBAAA,QAAQ,EAAE,IAAI;AACd,gBAAA,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;AAC7C,gBAAA,QAAQ,EAAE,KAAK;AACf,gBAAA,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAC1B,aAAA,CACF;AACH,QAAA,CAAC;QAED,oBAAoB,GAAG,IAAIC,0BAAU,CAAC;AACpC,YAAA,SAAS,EAAE,MAAM;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;AACjC,YAAA,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;YACrC,WAAW;AACZ,SAAA,CAAC;IACJ;AAEA,IAAA,OAAO,oBAAoB;AAC7B;AAMO,eAAe,sBAAsB,CAAC,MAA8B,EAAA;AACzE,IAAA,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM;AAGrC,IAAA,MAAM,WAAW,GAAG,MAAMD,eAAO,EAAE;AACnC,IAAA,MAAM,eAAe,GAAG,UAAU,IAAI,aAAa;IACnD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,eAAe,CAAC;IAElD,IAAI,CAAC,SAAS,EAAE;AACd,QAAA,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC;IAC9D;AAEA,IAAA,IAAI,MAAwE;AAC5E,IAAA,IAAI;QACF,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;IACtC;AAAE,IAAA,MAAM;AACN,QAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;IAClD;IAGA,MAAM,WAAW,GAAG,OAAO,WAAmB,EAAE,YAAoB,EAAE,SAAe,KAAmB;AACtG,QAAA,MAAM,WAAW,GAAG,MAAMA,eAAO,EAAE;QACnC,WAAW,CAAC,GAAG,CACb,eAAe,EACf,IAAI,CAAC,SAAS,CAAC;YACb,WAAW;YACX,YAAY;AACZ,YAAA,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;AACnC,SAAA,CAAC,EACF;AACE,YAAA,QAAQ,EAAE,IAAI;AACd,YAAA,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;AAC7C,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAC1B,SAAA,CACF;AACH,IAAA,CAAC;IAED,OAAO,IAAIC,0BAAU,CAAC;AACpB,QAAA,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;AACjC,QAAA,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QACrC,WAAW;AACZ,KAAA,CAAC;AACJ;;AC/GA,MAAM,cAAc,GAAG,IAAI,GAAG,EAA0B;AAMlD,SAAU,kBAAkB,CAAC,MAA0B,EAAA;AAM3D,IAAA,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM;IAGnC,SAAS,cAAc,CAAC,UAAkB,EAAA;AACxC,QAAA,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,IAAI;AAE3B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACtB,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC;QAE5C,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE;AACnC,YAAA,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE;AAC7B,gBAAA,KAAK,EAAE,CAAC;AACR,gBAAA,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC,MAAM;AAClC,aAAA,CAAC;AACF,YAAA,OAAO,IAAI;QACb;QAEA,IAAI,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,QAAQ,EAAE;AACrC,YAAA,OAAO,KAAK;QACd;QAEA,KAAK,CAAC,KAAK,EAAE;AACb,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,eAAe,aAAa,CAC1B,OAAoB,EACpB,OAAuE,EAAA;AAEvE,QAAA,IAAI;YAEF,IAAI,SAAS,EAAE;AACb,gBAAA,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,WAAW;AACxE,gBAAA,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE;AAC/B,oBAAA,OAAOC,mBAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAChC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB;gBACH;YACF;AAGA,YAAA,MAAM,MAAM,GAAG,MAAM,mBAAmB,EAAE;YAG1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;YAG7C,MAAM,QAAQ,GAAGA,mBAAY,CAAC,IAAI,CAAC,MAAM,CAAC;AAE1C,YAAA,IAAI,KAAK,EAAE,OAAO,EAAE;AAClB,gBAAA,QAAQ,CAAC,OAAO,CAAC,GAAG,CAClB,eAAe,EACf,CAAA,iBAAA,EAAoB,KAAK,CAAC,GAAG,CAAA,wBAAA,CAA0B,CACxD;YACH;AAEA,YAAA,OAAO,QAAQ;QACjB;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC;AAE7C,YAAA,IAAI,KAAK,YAAY,KAAK,EAAE;AAC1B,gBAAA,OAAOA,mBAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,EACxB,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB;YACH;AAEA,YAAA,OAAOA,mBAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAClC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB;QACH;IACF;IAEA,OAAO;AACL,QAAA,GAAG,EAAE,OAAO,OAAoB,KAA2B;YACzD,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;gBAChE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;gBAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;gBAE7C,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;gBAGA,MAAM,MAAM,GAA4B,EAAE;gBAC1C,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,KAAI;AAClC,oBAAA,IAAI,GAAG,KAAK,UAAU,EAAE;AACtB,wBAAA,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK;oBACrB;AACF,gBAAA,CAAC,CAAC;gBAKF,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE;AACtD,YAAA,CAAC,CAAC;QACJ,CAAC;AAED,QAAA,IAAI,EAAE,OAAO,OAAoB,KAA2B;YAC1D,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;AAChE,gBAAA,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;AACjC,gBAAA,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI;gBAE/B,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;gBAGA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE;AACrD,YAAA,CAAC,CAAC;QACJ,CAAC;AAED,QAAA,GAAG,EAAE,OAAO,OAAoB,KAA2B;YACzD,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;AAChE,gBAAA,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;AACjC,gBAAA,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI;gBAE/B,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;gBAGA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE;AACpD,YAAA,CAAC,CAAC;QACJ,CAAC;AAED,QAAA,MAAM,EAAE,OAAO,OAAoB,KAA2B;YAC5D,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;gBAChE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;gBAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;gBAE7C,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;AAGA,gBAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE;AACjD,YAAA,CAAC,CAAC;QACJ,CAAC;KACF;AACH;;ACzKA,MAAM,qBAAqB,GAAGC,mBAAa,CAAyC,SAAS,CAAC;AAYxF,SAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,WAAW,EACX,QAAQ,EACoB,EAAA;AAC5B,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,IAC3D,QAAQ,CACsB;AAErC;SAEgB,iBAAiB,GAAA;AAC/B,IAAA,MAAM,OAAO,GAAGC,gBAAU,CAAC,qBAAqB,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC;IACpF;AACA,IAAA,OAAO,OAAO;AAChB;;;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { EtsyClient } from '@profplum700/etsy-v3-api-client';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import React, { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
interface EtsyServerClientConfig {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
redirectUri?: string;
|
|
8
|
+
scopes?: string[];
|
|
9
|
+
cookieName?: string;
|
|
10
|
+
encryptionKey?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function configureEtsyServerClient(config: EtsyServerClientConfig): void;
|
|
13
|
+
declare function getEtsyServerClient(): Promise<EtsyClient>;
|
|
14
|
+
declare function createEtsyServerClient(config: EtsyServerClientConfig): Promise<EtsyClient>;
|
|
15
|
+
|
|
16
|
+
interface EtsyApiRouteConfig {
|
|
17
|
+
apiKey: string;
|
|
18
|
+
redirectUri?: string;
|
|
19
|
+
scopes?: string[];
|
|
20
|
+
rateLimit?: {
|
|
21
|
+
requests: number;
|
|
22
|
+
window: number;
|
|
23
|
+
};
|
|
24
|
+
cache?: {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
ttl: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
declare function createEtsyApiRoute(config: EtsyApiRouteConfig): {
|
|
30
|
+
GET: (request: NextRequest) => Promise<NextResponse>;
|
|
31
|
+
POST: (request: NextRequest) => Promise<NextResponse>;
|
|
32
|
+
PUT: (request: NextRequest) => Promise<NextResponse>;
|
|
33
|
+
DELETE: (request: NextRequest) => Promise<NextResponse>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
interface EtsyNextClientContextValue {
|
|
37
|
+
client: EtsyClient;
|
|
38
|
+
apiEndpoint?: string;
|
|
39
|
+
}
|
|
40
|
+
interface EtsyNextClientProviderProps {
|
|
41
|
+
client: EtsyClient;
|
|
42
|
+
apiEndpoint?: string;
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
}
|
|
45
|
+
declare function EtsyNextClientProvider({ client, apiEndpoint, children }: EtsyNextClientProviderProps): React.JSX.Element;
|
|
46
|
+
declare function useEtsyNextClient(): EtsyNextClientContextValue;
|
|
47
|
+
|
|
48
|
+
export { EtsyNextClientProvider, configureEtsyServerClient, createEtsyApiRoute, createEtsyServerClient, getEtsyServerClient, useEtsyNextClient };
|
|
49
|
+
export type { EtsyApiRouteConfig, EtsyServerClientConfig };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { EtsyClient } from '@profplum700/etsy-v3-api-client';
|
|
2
|
+
import { cookies } from 'next/headers';
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import React, { createContext, useContext } from 'react';
|
|
5
|
+
|
|
6
|
+
let serverClientInstance = null;
|
|
7
|
+
let serverClientConfig = null;
|
|
8
|
+
function configureEtsyServerClient(config) {
|
|
9
|
+
serverClientConfig = config;
|
|
10
|
+
}
|
|
11
|
+
async function getEtsyServerClient() {
|
|
12
|
+
if (!serverClientConfig) {
|
|
13
|
+
throw new Error('Etsy server client not configured. Call configureEtsyServerClient() first.');
|
|
14
|
+
}
|
|
15
|
+
if (!serverClientInstance) {
|
|
16
|
+
const { apiKey } = serverClientConfig;
|
|
17
|
+
const cookieStore = await cookies();
|
|
18
|
+
const cookieName = serverClientConfig.cookieName || 'etsy-tokens';
|
|
19
|
+
const tokenData = cookieStore.get(cookieName);
|
|
20
|
+
if (!tokenData) {
|
|
21
|
+
throw new Error('No authentication tokens found in cookies');
|
|
22
|
+
}
|
|
23
|
+
let tokens;
|
|
24
|
+
try {
|
|
25
|
+
tokens = JSON.parse(tokenData.value);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new Error('Invalid token data in cookies');
|
|
29
|
+
}
|
|
30
|
+
const refreshSave = async (accessToken, refreshToken, expiresAt) => {
|
|
31
|
+
const cookieStore = await cookies();
|
|
32
|
+
const cookieName = serverClientConfig?.cookieName || 'etsy-tokens';
|
|
33
|
+
cookieStore.set(cookieName, JSON.stringify({
|
|
34
|
+
accessToken,
|
|
35
|
+
refreshToken,
|
|
36
|
+
expiresAt: expiresAt.toISOString(),
|
|
37
|
+
}), {
|
|
38
|
+
httpOnly: true,
|
|
39
|
+
secure: process.env.NODE_ENV === 'production',
|
|
40
|
+
sameSite: 'lax',
|
|
41
|
+
maxAge: 60 * 60 * 24 * 90,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
serverClientInstance = new EtsyClient({
|
|
45
|
+
keystring: apiKey,
|
|
46
|
+
accessToken: tokens.accessToken,
|
|
47
|
+
refreshToken: tokens.refreshToken,
|
|
48
|
+
expiresAt: new Date(tokens.expiresAt),
|
|
49
|
+
refreshSave,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return serverClientInstance;
|
|
53
|
+
}
|
|
54
|
+
async function createEtsyServerClient(config) {
|
|
55
|
+
const { apiKey, cookieName } = config;
|
|
56
|
+
const cookieStore = await cookies();
|
|
57
|
+
const tokenCookieName = cookieName || 'etsy-tokens';
|
|
58
|
+
const tokenData = cookieStore.get(tokenCookieName);
|
|
59
|
+
if (!tokenData) {
|
|
60
|
+
throw new Error('No authentication tokens found in cookies');
|
|
61
|
+
}
|
|
62
|
+
let tokens;
|
|
63
|
+
try {
|
|
64
|
+
tokens = JSON.parse(tokenData.value);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error('Invalid token data in cookies');
|
|
68
|
+
}
|
|
69
|
+
const refreshSave = async (accessToken, refreshToken, expiresAt) => {
|
|
70
|
+
const cookieStore = await cookies();
|
|
71
|
+
cookieStore.set(tokenCookieName, JSON.stringify({
|
|
72
|
+
accessToken,
|
|
73
|
+
refreshToken,
|
|
74
|
+
expiresAt: expiresAt.toISOString(),
|
|
75
|
+
}), {
|
|
76
|
+
httpOnly: true,
|
|
77
|
+
secure: process.env.NODE_ENV === 'production',
|
|
78
|
+
sameSite: 'lax',
|
|
79
|
+
maxAge: 60 * 60 * 24 * 90,
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
return new EtsyClient({
|
|
83
|
+
keystring: apiKey,
|
|
84
|
+
accessToken: tokens.accessToken,
|
|
85
|
+
refreshToken: tokens.refreshToken,
|
|
86
|
+
expiresAt: new Date(tokens.expiresAt),
|
|
87
|
+
refreshSave,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const rateLimitStore = new Map();
|
|
92
|
+
function createEtsyApiRoute(config) {
|
|
93
|
+
const { rateLimit, cache } = config;
|
|
94
|
+
function checkRateLimit(identifier) {
|
|
95
|
+
if (!rateLimit)
|
|
96
|
+
return true;
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const entry = rateLimitStore.get(identifier);
|
|
99
|
+
if (!entry || now > entry.resetTime) {
|
|
100
|
+
rateLimitStore.set(identifier, {
|
|
101
|
+
count: 1,
|
|
102
|
+
resetTime: now + rateLimit.window,
|
|
103
|
+
});
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (entry.count >= rateLimit.requests) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
entry.count++;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
async function handleRequest(request, handler) {
|
|
113
|
+
try {
|
|
114
|
+
if (rateLimit) {
|
|
115
|
+
const identifier = request.headers.get('x-forwarded-for') || 'anonymous';
|
|
116
|
+
if (!checkRateLimit(identifier)) {
|
|
117
|
+
return NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const client = await getEtsyServerClient();
|
|
121
|
+
const result = await handler(client, request);
|
|
122
|
+
const response = NextResponse.json(result);
|
|
123
|
+
if (cache?.enabled) {
|
|
124
|
+
response.headers.set('Cache-Control', `public, s-maxage=${cache.ttl}, stale-while-revalidate`);
|
|
125
|
+
}
|
|
126
|
+
return response;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
console.error('Etsy API route error:', error);
|
|
130
|
+
if (error instanceof Error) {
|
|
131
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
132
|
+
}
|
|
133
|
+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
GET: async (request) => {
|
|
138
|
+
return handleRequest(request, async (_client) => {
|
|
139
|
+
const { searchParams } = new URL(request.url);
|
|
140
|
+
const endpoint = searchParams.get('endpoint');
|
|
141
|
+
if (!endpoint) {
|
|
142
|
+
throw new Error('Endpoint parameter is required');
|
|
143
|
+
}
|
|
144
|
+
const params = {};
|
|
145
|
+
searchParams.forEach((value, key) => {
|
|
146
|
+
if (key !== 'endpoint') {
|
|
147
|
+
params[key] = value;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return { message: 'GET endpoint', endpoint, params };
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
POST: async (request) => {
|
|
154
|
+
return handleRequest(request, async (_client) => {
|
|
155
|
+
const body = await request.json();
|
|
156
|
+
const { endpoint, data } = body;
|
|
157
|
+
if (!endpoint) {
|
|
158
|
+
throw new Error('Endpoint parameter is required');
|
|
159
|
+
}
|
|
160
|
+
return { message: 'POST endpoint', endpoint, data };
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
PUT: async (request) => {
|
|
164
|
+
return handleRequest(request, async (_client) => {
|
|
165
|
+
const body = await request.json();
|
|
166
|
+
const { endpoint, data } = body;
|
|
167
|
+
if (!endpoint) {
|
|
168
|
+
throw new Error('Endpoint parameter is required');
|
|
169
|
+
}
|
|
170
|
+
return { message: 'PUT endpoint', endpoint, data };
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
DELETE: async (request) => {
|
|
174
|
+
return handleRequest(request, async (_client) => {
|
|
175
|
+
const { searchParams } = new URL(request.url);
|
|
176
|
+
const endpoint = searchParams.get('endpoint');
|
|
177
|
+
if (!endpoint) {
|
|
178
|
+
throw new Error('Endpoint parameter is required');
|
|
179
|
+
}
|
|
180
|
+
return { message: 'DELETE endpoint', endpoint };
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const EtsyNextClientContext = createContext(undefined);
|
|
187
|
+
function EtsyNextClientProvider({ client, apiEndpoint, children }) {
|
|
188
|
+
return (React.createElement(EtsyNextClientContext.Provider, { value: { client, apiEndpoint } }, children));
|
|
189
|
+
}
|
|
190
|
+
function useEtsyNextClient() {
|
|
191
|
+
const context = useContext(EtsyNextClientContext);
|
|
192
|
+
if (!context) {
|
|
193
|
+
throw new Error('useEtsyNextClient must be used within an EtsyNextClientProvider');
|
|
194
|
+
}
|
|
195
|
+
return context;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export { EtsyNextClientProvider, configureEtsyServerClient, createEtsyApiRoute, createEtsyServerClient, getEtsyServerClient, useEtsyNextClient };
|
|
199
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/server/client.ts","../../src/server/route.ts","../../src/client/provider.tsx"],"sourcesContent":[null,null,null],"names":[],"mappings":";;;;;AAWA,IAAI,oBAAoB,GAAsB,IAAI;AAClD,IAAI,kBAAkB,GAAkC,IAAI;AAMtD,SAAU,yBAAyB,CAAC,MAA8B,EAAA;IACtE,kBAAkB,GAAG,MAAM;AAC7B;AAMO,eAAe,mBAAmB,GAAA;IACvC,IAAI,CAAC,kBAAkB,EAAE;AACvB,QAAA,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E;IACH;IAGA,IAAI,CAAC,oBAAoB,EAAE;AACzB,QAAA,MAAM,EAAE,MAAM,EAAE,GAAG,kBAAkB;AAGrC,QAAA,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE;AACnC,QAAA,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,IAAI,aAAa;QACjE,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC;QAE7C,IAAI,CAAC,SAAS,EAAE;AACd,YAAA,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC;QAC9D;AAEA,QAAA,IAAI,MAAwE;AAC5E,QAAA,IAAI;YACF,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;QACtC;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;QAClD;QAGA,MAAM,WAAW,GAAG,OAAO,WAAmB,EAAE,YAAoB,EAAE,SAAe,KAAmB;AACtG,YAAA,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE;AACnC,YAAA,MAAM,UAAU,GAAG,kBAAkB,EAAE,UAAU,IAAI,aAAa;YAClE,WAAW,CAAC,GAAG,CACb,UAAU,EACV,IAAI,CAAC,SAAS,CAAC;gBACb,WAAW;gBACX,YAAY;AACZ,gBAAA,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;AACnC,aAAA,CAAC,EACF;AACE,gBAAA,QAAQ,EAAE,IAAI;AACd,gBAAA,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;AAC7C,gBAAA,QAAQ,EAAE,KAAK;AACf,gBAAA,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAC1B,aAAA,CACF;AACH,QAAA,CAAC;QAED,oBAAoB,GAAG,IAAI,UAAU,CAAC;AACpC,YAAA,SAAS,EAAE,MAAM;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;AACjC,YAAA,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;YACrC,WAAW;AACZ,SAAA,CAAC;IACJ;AAEA,IAAA,OAAO,oBAAoB;AAC7B;AAMO,eAAe,sBAAsB,CAAC,MAA8B,EAAA;AACzE,IAAA,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM;AAGrC,IAAA,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE;AACnC,IAAA,MAAM,eAAe,GAAG,UAAU,IAAI,aAAa;IACnD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,eAAe,CAAC;IAElD,IAAI,CAAC,SAAS,EAAE;AACd,QAAA,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC;IAC9D;AAEA,IAAA,IAAI,MAAwE;AAC5E,IAAA,IAAI;QACF,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;IACtC;AAAE,IAAA,MAAM;AACN,QAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;IAClD;IAGA,MAAM,WAAW,GAAG,OAAO,WAAmB,EAAE,YAAoB,EAAE,SAAe,KAAmB;AACtG,QAAA,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE;QACnC,WAAW,CAAC,GAAG,CACb,eAAe,EACf,IAAI,CAAC,SAAS,CAAC;YACb,WAAW;YACX,YAAY;AACZ,YAAA,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;AACnC,SAAA,CAAC,EACF;AACE,YAAA,QAAQ,EAAE,IAAI;AACd,YAAA,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;AAC7C,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AAC1B,SAAA,CACF;AACH,IAAA,CAAC;IAED,OAAO,IAAI,UAAU,CAAC;AACpB,QAAA,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;AACjC,QAAA,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QACrC,WAAW;AACZ,KAAA,CAAC;AACJ;;AC/GA,MAAM,cAAc,GAAG,IAAI,GAAG,EAA0B;AAMlD,SAAU,kBAAkB,CAAC,MAA0B,EAAA;AAM3D,IAAA,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM;IAGnC,SAAS,cAAc,CAAC,UAAkB,EAAA;AACxC,QAAA,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,IAAI;AAE3B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACtB,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC;QAE5C,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE;AACnC,YAAA,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE;AAC7B,gBAAA,KAAK,EAAE,CAAC;AACR,gBAAA,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC,MAAM;AAClC,aAAA,CAAC;AACF,YAAA,OAAO,IAAI;QACb;QAEA,IAAI,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,QAAQ,EAAE;AACrC,YAAA,OAAO,KAAK;QACd;QAEA,KAAK,CAAC,KAAK,EAAE;AACb,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,eAAe,aAAa,CAC1B,OAAoB,EACpB,OAAuE,EAAA;AAEvE,QAAA,IAAI;YAEF,IAAI,SAAS,EAAE;AACb,gBAAA,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,WAAW;AACxE,gBAAA,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE;AAC/B,oBAAA,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAChC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB;gBACH;YACF;AAGA,YAAA,MAAM,MAAM,GAAG,MAAM,mBAAmB,EAAE;YAG1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;YAG7C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;AAE1C,YAAA,IAAI,KAAK,EAAE,OAAO,EAAE;AAClB,gBAAA,QAAQ,CAAC,OAAO,CAAC,GAAG,CAClB,eAAe,EACf,CAAA,iBAAA,EAAoB,KAAK,CAAC,GAAG,CAAA,wBAAA,CAA0B,CACxD;YACH;AAEA,YAAA,OAAO,QAAQ;QACjB;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC;AAE7C,YAAA,IAAI,KAAK,YAAY,KAAK,EAAE;AAC1B,gBAAA,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,EACxB,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB;YACH;AAEA,YAAA,OAAO,YAAY,CAAC,IAAI,CACtB,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAClC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB;QACH;IACF;IAEA,OAAO;AACL,QAAA,GAAG,EAAE,OAAO,OAAoB,KAA2B;YACzD,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;gBAChE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;gBAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;gBAE7C,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;gBAGA,MAAM,MAAM,GAA4B,EAAE;gBAC1C,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,KAAI;AAClC,oBAAA,IAAI,GAAG,KAAK,UAAU,EAAE;AACtB,wBAAA,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK;oBACrB;AACF,gBAAA,CAAC,CAAC;gBAKF,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE;AACtD,YAAA,CAAC,CAAC;QACJ,CAAC;AAED,QAAA,IAAI,EAAE,OAAO,OAAoB,KAA2B;YAC1D,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;AAChE,gBAAA,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;AACjC,gBAAA,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI;gBAE/B,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;gBAGA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE;AACrD,YAAA,CAAC,CAAC;QACJ,CAAC;AAED,QAAA,GAAG,EAAE,OAAO,OAAoB,KAA2B;YACzD,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;AAChE,gBAAA,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;AACjC,gBAAA,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI;gBAE/B,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;gBAGA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE;AACpD,YAAA,CAAC,CAAC;QACJ,CAAC;AAED,QAAA,MAAM,EAAE,OAAO,OAAoB,KAA2B;YAC5D,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,OAAO,KAAsB;gBAChE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;gBAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;gBAE7C,IAAI,CAAC,QAAQ,EAAE;AACb,oBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC;gBACnD;AAGA,gBAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE;AACjD,YAAA,CAAC,CAAC;QACJ,CAAC;KACF;AACH;;ACzKA,MAAM,qBAAqB,GAAG,aAAa,CAAyC,SAAS,CAAC;AAYxF,SAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,WAAW,EACX,QAAQ,EACoB,EAAA;AAC5B,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,IAC3D,QAAQ,CACsB;AAErC;SAEgB,iBAAiB,GAAA;AAC/B,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,qBAAqB,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC;IACpF;AACA,IAAA,OAAO,OAAO;AAChB;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@profplum700/etsy-nextjs",
|
|
3
|
+
"version": "2.3.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Next.js integration for Etsy v3 API client",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.esm.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/**/*",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"etsy",
|
|
15
|
+
"api",
|
|
16
|
+
"v3",
|
|
17
|
+
"nextjs",
|
|
18
|
+
"next.js",
|
|
19
|
+
"react",
|
|
20
|
+
"typescript",
|
|
21
|
+
"javascript"
|
|
22
|
+
],
|
|
23
|
+
"author": {
|
|
24
|
+
"name": "profplum700",
|
|
25
|
+
"email": "profplum700@users.noreply.github.com"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/profplum700/etsy-v3-api-client.git",
|
|
31
|
+
"directory": "packages/etsy-nextjs"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/profplum700/etsy-v3-api-client/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/profplum700/etsy-v3-api-client/tree/main/packages/etsy-nextjs#readme",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=20.0.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@profplum700/etsy-v3-api-client": "^2.0.0",
|
|
42
|
+
"next": "^14.0.0 || ^15.0.0",
|
|
43
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
47
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
48
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
49
|
+
"@types/jest": "^30.0.0",
|
|
50
|
+
"@types/node": "^24.1.0",
|
|
51
|
+
"@types/react": "^18.3.18",
|
|
52
|
+
"jest": "^30.0.5",
|
|
53
|
+
"next": "^15.1.4",
|
|
54
|
+
"react": "^18.3.1",
|
|
55
|
+
"rollup": "^4.45.1",
|
|
56
|
+
"rollup-plugin-dts": "^6.1.1",
|
|
57
|
+
"ts-jest": "^29.4.0",
|
|
58
|
+
"typescript": "^5.5.3",
|
|
59
|
+
"@profplum700/etsy-v3-api-client": "2.3.1"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "rollup -c",
|
|
66
|
+
"build:watch": "rollup -c --watch",
|
|
67
|
+
"test": "jest --passWithNoTests",
|
|
68
|
+
"test:watch": "jest --watch",
|
|
69
|
+
"test:coverage": "jest --coverage",
|
|
70
|
+
"lint": "eslint --config ../../eslint.config.mjs .",
|
|
71
|
+
"lint:fix": "eslint --fix --config ../../eslint.config.mjs .",
|
|
72
|
+
"type-check": "tsc --noEmit"
|
|
73
|
+
}
|
|
74
|
+
}
|