@fairu/sdk 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/CHANGELOG.md +16 -0
- package/README.md +447 -0
- package/dist/FairuClient-BUObk5LJ.cjs +91 -0
- package/dist/FairuClient-BUObk5LJ.cjs.map +1 -0
- package/dist/FairuClient-CT-IPh8i.js +92 -0
- package/dist/FairuClient-CT-IPh8i.js.map +1 -0
- package/dist/FairuError-D8sSmRAa.js +214 -0
- package/dist/FairuError-D8sSmRAa.js.map +1 -0
- package/dist/FairuError-DWH_Nwk0.cjs +213 -0
- package/dist/FairuError-DWH_Nwk0.cjs.map +1 -0
- package/dist/FairuProvider-BRpRddCI.cjs +51 -0
- package/dist/FairuProvider-BRpRddCI.cjs.map +1 -0
- package/dist/FairuProvider-Tc0vFo5L.js +52 -0
- package/dist/FairuProvider-Tc0vFo5L.js.map +1 -0
- package/dist/FileProxyBuilder-D-jZpAtd.cjs +269 -0
- package/dist/FileProxyBuilder-D-jZpAtd.cjs.map +1 -0
- package/dist/FileProxyBuilder-vHw1zBpJ.js +270 -0
- package/dist/FileProxyBuilder-vHw1zBpJ.js.map +1 -0
- package/dist/FragmentBuilder-BinoxeVS.js +194 -0
- package/dist/FragmentBuilder-BinoxeVS.js.map +1 -0
- package/dist/FragmentBuilder-BuvIC0aT.cjs +193 -0
- package/dist/FragmentBuilder-BuvIC0aT.cjs.map +1 -0
- package/dist/UploadError-CHBJuChw.cjs +81 -0
- package/dist/UploadError-CHBJuChw.cjs.map +1 -0
- package/dist/UploadError-_gEcJqSS.js +82 -0
- package/dist/UploadError-_gEcJqSS.js.map +1 -0
- package/dist/client/FairuClient.d.ts +8 -0
- package/dist/client/FairuClient.d.ts.map +1 -0
- package/dist/client/FairuProvider.d.ts +78 -0
- package/dist/client/FairuProvider.d.ts.map +1 -0
- package/dist/client/cache.d.ts +6 -0
- package/dist/client/cache.d.ts.map +1 -0
- package/dist/client/config.d.ts +77 -0
- package/dist/client/config.d.ts.map +1 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/errors/FairuError.d.ts +107 -0
- package/dist/errors/FairuError.d.ts.map +1 -0
- package/dist/errors/UploadError.d.ts +54 -0
- package/dist/errors/UploadError.d.ts.map +1 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/fileproxy/FileProxyBuilder.d.ts +141 -0
- package/dist/fileproxy/FileProxyBuilder.d.ts.map +1 -0
- package/dist/fileproxy/index.d.ts +4 -0
- package/dist/fileproxy/index.d.ts.map +1 -0
- package/dist/fileproxy/types.d.ts +79 -0
- package/dist/fileproxy/types.d.ts.map +1 -0
- package/dist/fileproxy/useFileProxyUrl.d.ts +91 -0
- package/dist/fileproxy/useFileProxyUrl.d.ts.map +1 -0
- package/dist/fileproxy.cjs +10 -0
- package/dist/fileproxy.cjs.map +1 -0
- package/dist/fileproxy.d.ts +2 -0
- package/dist/fileproxy.js +10 -0
- package/dist/fileproxy.js.map +1 -0
- package/dist/fragments/FragmentBuilder.d.ts +107 -0
- package/dist/fragments/FragmentBuilder.d.ts.map +1 -0
- package/dist/fragments/FragmentRegistry.d.ts +93 -0
- package/dist/fragments/FragmentRegistry.d.ts.map +1 -0
- package/dist/fragments/index.d.ts +5 -0
- package/dist/fragments/index.d.ts.map +1 -0
- package/dist/fragments/predefined/assetFragments.d.ts +39 -0
- package/dist/fragments/predefined/assetFragments.d.ts.map +1 -0
- package/dist/fragments/predefined/copyrightFragments.d.ts +12 -0
- package/dist/fragments/predefined/copyrightFragments.d.ts.map +1 -0
- package/dist/fragments/predefined/folderFragments.d.ts +28 -0
- package/dist/fragments/predefined/folderFragments.d.ts.map +1 -0
- package/dist/fragments/predefined/galleryFragments.d.ts +24 -0
- package/dist/fragments/predefined/galleryFragments.d.ts.map +1 -0
- package/dist/fragments/predefined/index.d.ts +6 -0
- package/dist/fragments/predefined/index.d.ts.map +1 -0
- package/dist/fragments/predefined/licenseFragments.d.ts +12 -0
- package/dist/fragments/predefined/licenseFragments.d.ts.map +1 -0
- package/dist/fragments/types.d.ts +46 -0
- package/dist/fragments/types.d.ts.map +1 -0
- package/dist/fragments.cjs +403 -0
- package/dist/fragments.cjs.map +1 -0
- package/dist/fragments.d.ts +2 -0
- package/dist/fragments.js +403 -0
- package/dist/fragments.js.map +1 -0
- package/dist/generated/graphql.d.ts +3464 -0
- package/dist/generated/graphql.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/mutations/index.d.ts +5 -0
- package/dist/hooks/mutations/index.d.ts.map +1 -0
- package/dist/hooks/mutations/useAssetMutations.d.ts +66 -0
- package/dist/hooks/mutations/useAssetMutations.d.ts.map +1 -0
- package/dist/hooks/mutations/useFolderMutations.d.ts +69 -0
- package/dist/hooks/mutations/useFolderMutations.d.ts.map +1 -0
- package/dist/hooks/mutations/useGalleryMutations.d.ts +39 -0
- package/dist/hooks/mutations/useGalleryMutations.d.ts.map +1 -0
- package/dist/hooks/mutations/useUpdateAsset.d.ts +50 -0
- package/dist/hooks/mutations/useUpdateAsset.d.ts.map +1 -0
- package/dist/hooks/queries/index.d.ts +8 -0
- package/dist/hooks/queries/index.d.ts.map +1 -0
- package/dist/hooks/queries/useAsset.d.ts +46 -0
- package/dist/hooks/queries/useAsset.d.ts.map +1 -0
- package/dist/hooks/queries/useAssets.d.ts +58 -0
- package/dist/hooks/queries/useAssets.d.ts.map +1 -0
- package/dist/hooks/queries/useCopyright.d.ts +51 -0
- package/dist/hooks/queries/useCopyright.d.ts.map +1 -0
- package/dist/hooks/queries/useFolder.d.ts +93 -0
- package/dist/hooks/queries/useFolder.d.ts.map +1 -0
- package/dist/hooks/queries/useGallery.d.ts +101 -0
- package/dist/hooks/queries/useGallery.d.ts.map +1 -0
- package/dist/hooks/queries/useLicense.d.ts +63 -0
- package/dist/hooks/queries/useLicense.d.ts.map +1 -0
- package/dist/hooks/queries/useTenant.d.ts +89 -0
- package/dist/hooks/queries/useTenant.d.ts.map +1 -0
- package/dist/index.cjs +244 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +244 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +596 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.ts +22 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +596 -0
- package/dist/react.js.map +1 -0
- package/dist/upload/index.d.ts +4 -0
- package/dist/upload/index.d.ts.map +1 -0
- package/dist/upload/types.d.ts +96 -0
- package/dist/upload/types.d.ts.map +1 -0
- package/dist/upload/useMultipartUpload.d.ts +67 -0
- package/dist/upload/useMultipartUpload.d.ts.map +1 -0
- package/dist/upload/useUpload.d.ts +64 -0
- package/dist/upload/useUpload.d.ts.map +1 -0
- package/dist/upload.cjs +6 -0
- package/dist/upload.cjs.map +1 -0
- package/dist/upload.d.ts +2 -0
- package/dist/upload.js +6 -0
- package/dist/upload.js.map +1 -0
- package/dist/useFileProxyUrl-BCcux6re.cjs +87 -0
- package/dist/useFileProxyUrl-BCcux6re.cjs.map +1 -0
- package/dist/useFileProxyUrl-D_S1R_7O.js +88 -0
- package/dist/useFileProxyUrl-D_S1R_7O.js.map +1 -0
- package/dist/useMultipartUpload-BKnDbl8h.cjs +423 -0
- package/dist/useMultipartUpload-BKnDbl8h.cjs.map +1 -0
- package/dist/useMultipartUpload-CPK_PgUU.js +424 -0
- package/dist/useMultipartUpload-CPK_PgUU.js.map +1 -0
- package/dist/vanilla.cjs +219 -0
- package/dist/vanilla.cjs.map +1 -0
- package/dist/vanilla.d.ts +94 -0
- package/dist/vanilla.d.ts.map +1 -0
- package/dist/vanilla.js +220 -0
- package/dist/vanilla.js.map +1 -0
- package/package.json +177 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.0.1](https://github.com/sushidev-team/fairu-sdk-typescript/compare/v1.0.0...v1.0.1) (2026-01-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* include generated GraphQL types in repository ([e917822](https://github.com/sushidev-team/fairu-sdk-typescript/commit/e917822299fa527ac82e3e5a1012dcb594e8f2cd))
|
|
9
|
+
|
|
10
|
+
## 1.0.0 (2026-01-04)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* add codegen step to CI workflow ([2802899](https://github.com/sushidev-team/fairu-sdk-typescript/commit/28028995f4978284a879eb5bb034269a0d1cf9fa))
|
|
16
|
+
* add ESLint 9 flat config ([6870d77](https://github.com/sushidev-team/fairu-sdk-typescript/commit/6870d77ba4258665f2b7a46e7cb1a4ab092f222d))
|
package/README.md
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# @fairu/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the Fairu GraphQL API with React hooks and vanilla client support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **React Hooks** for all GraphQL operations (assets, folders, galleries, copyrights, licenses, users, roles, etc.)
|
|
8
|
+
- **Vanilla Client** for Node.js and non-React frameworks
|
|
9
|
+
- **Fragment System** with fluent builder API
|
|
10
|
+
- **Upload Hooks** with progress tracking (simple + multipart)
|
|
11
|
+
- **FileProxy URL Builder** for image transformations
|
|
12
|
+
- **Graphcache** for normalized caching
|
|
13
|
+
- **Full TypeScript support** with generated types from the GraphQL schema
|
|
14
|
+
- **Dynamic Base URL** configuration with environment variable support
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @fairu/sdk urql graphql
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For React applications:
|
|
23
|
+
```bash
|
|
24
|
+
npm install @fairu/sdk urql graphql react react-dom
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### React
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { FairuProvider, useAssets, useUpload } from '@fairu/sdk/react';
|
|
33
|
+
|
|
34
|
+
function App() {
|
|
35
|
+
return (
|
|
36
|
+
<FairuProvider
|
|
37
|
+
url="https://fairu.app/graphql"
|
|
38
|
+
token={process.env.FAIRU_TOKEN}
|
|
39
|
+
>
|
|
40
|
+
<AssetGallery />
|
|
41
|
+
</FairuProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function AssetGallery() {
|
|
46
|
+
const { assets, fetching, error, hasMore, total } = useAssets({
|
|
47
|
+
page: 1,
|
|
48
|
+
perPage: 20
|
|
49
|
+
});
|
|
50
|
+
const { upload, progress, status } = useUpload();
|
|
51
|
+
|
|
52
|
+
if (fetching) return <div>Loading...</div>;
|
|
53
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div>
|
|
57
|
+
<p>{total} assets found</p>
|
|
58
|
+
{assets.map((asset) => (
|
|
59
|
+
<img key={asset.id} src={asset.url} alt={asset.alt} />
|
|
60
|
+
))}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Vanilla TypeScript
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { createVanillaClient } from '@fairu/sdk/vanilla';
|
|
70
|
+
|
|
71
|
+
const client = createVanillaClient({
|
|
72
|
+
url: 'https://fairu.app/graphql',
|
|
73
|
+
token: 'your-token',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Fetch an asset
|
|
77
|
+
const asset = await client.assets.find('asset-id');
|
|
78
|
+
|
|
79
|
+
// List assets with pagination
|
|
80
|
+
const { data, paginatorInfo } = await client.assets.list({
|
|
81
|
+
page: 1,
|
|
82
|
+
perPage: 20,
|
|
83
|
+
folderId: 'folder-id',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Upload a file
|
|
87
|
+
const result = await client.upload.simple(file, {
|
|
88
|
+
folderId: 'folder-id',
|
|
89
|
+
alt: 'My image',
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
Check out the complete example applications:
|
|
96
|
+
|
|
97
|
+
- **[Vite + React Example](./examples/vite-react/)** - Full-featured example with asset browser, gallery viewer, search, and file uploads
|
|
98
|
+
- **[Next.js App Router Example](./examples/nextjs-app/)** - Example using Next.js 15 with App Router and optimized images
|
|
99
|
+
|
|
100
|
+
## API Reference
|
|
101
|
+
|
|
102
|
+
### React Hooks
|
|
103
|
+
|
|
104
|
+
#### Asset Hooks
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import { useAsset, useAssets, useSearch, useMultipleAssets } from '@fairu/sdk/react';
|
|
108
|
+
|
|
109
|
+
// Fetch single asset by ID
|
|
110
|
+
const { asset, fetching, error, refetch } = useAsset('asset-id');
|
|
111
|
+
|
|
112
|
+
// Fetch asset by path
|
|
113
|
+
const { asset } = useAssetByPath('/folder/image.jpg');
|
|
114
|
+
|
|
115
|
+
// Fetch paginated assets
|
|
116
|
+
const { assets, pagination, hasMore, total, refetch } = useAssets({
|
|
117
|
+
page: 1,
|
|
118
|
+
perPage: 20,
|
|
119
|
+
folder: 'folder-id',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Search assets
|
|
123
|
+
const { assets, pagination, hasMore } = useSearch('search query', {
|
|
124
|
+
page: 1,
|
|
125
|
+
perPage: 20,
|
|
126
|
+
orderBy: 'created_at',
|
|
127
|
+
orderDirection: 'DESC',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Fetch multiple assets by IDs
|
|
131
|
+
const { assets, fetching } = useMultipleAssets(['id1', 'id2', 'id3']);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Folder Hooks
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { useFolder, useFolderByPath } from '@fairu/sdk/react';
|
|
138
|
+
|
|
139
|
+
// Browse folder contents (assets + subfolders)
|
|
140
|
+
const { entries, pagination, hasMore } = useFolder({
|
|
141
|
+
folder: 'folder-id',
|
|
142
|
+
page: 1,
|
|
143
|
+
perPage: 50,
|
|
144
|
+
search: 'optional search',
|
|
145
|
+
orderBy: 'name',
|
|
146
|
+
orderDirection: 'ASC',
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Get folder by path
|
|
150
|
+
const { folder } = useFolderByPath('/path/to/folder');
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Gallery Hooks
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { useGallery, useGalleries, useGalleryItems } from '@fairu/sdk/react';
|
|
157
|
+
|
|
158
|
+
// Fetch single gallery
|
|
159
|
+
const { gallery, fetching, error } = useGallery('gallery-id');
|
|
160
|
+
|
|
161
|
+
// Fetch galleries list
|
|
162
|
+
const { galleries, pagination, hasMore, total } = useGalleries({
|
|
163
|
+
tenants: ['tenant-id'],
|
|
164
|
+
page: 1,
|
|
165
|
+
perPage: 20,
|
|
166
|
+
search: 'optional search',
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Fetch gallery items with pagination
|
|
170
|
+
const { galleryName, items, pagination, hasMore } = useGalleryItems('gallery-id', {
|
|
171
|
+
page: 1,
|
|
172
|
+
perPage: 50,
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### Additional Hooks
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import {
|
|
180
|
+
useCopyright, useCopyrights,
|
|
181
|
+
useLicense, useLicenses,
|
|
182
|
+
useTenant, useHealthCheck, useSupportedDomains,
|
|
183
|
+
} from '@fairu/sdk/react';
|
|
184
|
+
|
|
185
|
+
// Copyrights
|
|
186
|
+
const { copyright } = useCopyright('copyright-id');
|
|
187
|
+
const { copyrights, pagination } = useCopyrights({ page: 1, perPage: 20 });
|
|
188
|
+
|
|
189
|
+
// Licenses
|
|
190
|
+
const { license } = useLicense('license-id');
|
|
191
|
+
const { licenses, pagination } = useLicenses({ page: 1, perPage: 20 });
|
|
192
|
+
|
|
193
|
+
// Tenant info
|
|
194
|
+
const { tenant, fetching } = useTenant();
|
|
195
|
+
|
|
196
|
+
// Health check
|
|
197
|
+
const { health } = useHealthCheck();
|
|
198
|
+
|
|
199
|
+
// Supported domains
|
|
200
|
+
const { domains } = useSupportedDomains();
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Mutation Hooks
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { useUpdateAsset, useDeleteAsset } from '@fairu/sdk/react';
|
|
207
|
+
|
|
208
|
+
// Update asset
|
|
209
|
+
const { updateAsset, fetching } = useUpdateAsset();
|
|
210
|
+
await updateAsset({
|
|
211
|
+
id: 'asset-id',
|
|
212
|
+
alt: 'New alt text',
|
|
213
|
+
caption: 'New caption',
|
|
214
|
+
description: 'New description',
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Delete asset
|
|
218
|
+
const { deleteAsset, fetching } = useDeleteAsset();
|
|
219
|
+
const success = await deleteAsset('asset-id');
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Upload Hooks
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
import { useUpload, useMultipartUpload } from '@fairu/sdk/react';
|
|
226
|
+
|
|
227
|
+
// Simple upload (for files < 50MB)
|
|
228
|
+
const { upload, progress, status, error, cancel, reset } = useUpload();
|
|
229
|
+
|
|
230
|
+
const result = await upload(file, {
|
|
231
|
+
folderId: 'folder-id',
|
|
232
|
+
alt: 'Description',
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
console.log('Upload progress:', progress.percentage, '%');
|
|
236
|
+
console.log('Status:', status); // 'idle' | 'uploading' | 'success' | 'error'
|
|
237
|
+
|
|
238
|
+
// Multipart upload (for large files)
|
|
239
|
+
const { upload, progress, partsCompleted, totalParts, cancel } = useMultipartUpload();
|
|
240
|
+
|
|
241
|
+
await upload(largeFile, {
|
|
242
|
+
folderId: 'folder-id',
|
|
243
|
+
chunkSize: 10 * 1024 * 1024, // 10MB chunks
|
|
244
|
+
concurrency: 3, // Upload 3 chunks in parallel
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### FileProxy URL Builder
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { fileProxy, useFileProxyUrl, useResponsiveImageUrl } from '@fairu/sdk/fileproxy';
|
|
252
|
+
|
|
253
|
+
// Build URLs programmatically
|
|
254
|
+
const url = fileProxy('asset-id', 'image.jpg')
|
|
255
|
+
.width(800)
|
|
256
|
+
.height(600)
|
|
257
|
+
.quality(85)
|
|
258
|
+
.format('webp')
|
|
259
|
+
.fit('cover')
|
|
260
|
+
.focal(50, 30, 1.5)
|
|
261
|
+
.build();
|
|
262
|
+
|
|
263
|
+
// React hook for single image
|
|
264
|
+
function AssetImage({ asset }) {
|
|
265
|
+
const url = useFileProxyUrl(asset.id, asset.name, {
|
|
266
|
+
width: 800,
|
|
267
|
+
format: 'webp',
|
|
268
|
+
quality: 85,
|
|
269
|
+
focal: asset.focal_point,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return <img src={url} alt={asset.alt} />;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Responsive images with srcSet
|
|
276
|
+
function ResponsiveImage({ asset }) {
|
|
277
|
+
const { src, srcSet, sizes } = useResponsiveImageUrl(
|
|
278
|
+
asset.id,
|
|
279
|
+
asset.name,
|
|
280
|
+
{
|
|
281
|
+
widths: [400, 800, 1200, 1600],
|
|
282
|
+
sizes: '(max-width: 600px) 100vw, 50vw',
|
|
283
|
+
format: 'webp',
|
|
284
|
+
quality: 80,
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
return <img src={src} srcSet={srcSet} sizes={sizes} alt={asset.alt} />;
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Fragment System
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { FragmentBuilder, fragments } from '@fairu/sdk/fragments';
|
|
296
|
+
|
|
297
|
+
// Use predefined fragments
|
|
298
|
+
const minimalFragment = fragments.asset('minimal');
|
|
299
|
+
const fullFragment = fragments.asset('full');
|
|
300
|
+
|
|
301
|
+
// Build custom fragments
|
|
302
|
+
const customFragment = FragmentBuilder.for('FairuAsset')
|
|
303
|
+
.name('MyAssetFragment')
|
|
304
|
+
.select(['id', 'name', 'url', 'width', 'height', 'blurhash'])
|
|
305
|
+
.with('copyrights', (f) => f.select(['id', 'name', 'email']))
|
|
306
|
+
.build();
|
|
307
|
+
|
|
308
|
+
// Use with hooks
|
|
309
|
+
const { asset } = useAsset('id', { fragment: customFragment });
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Error Handling
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import { FairuError, ValidationError, AuthenticationError, GraphQLError } from '@fairu/sdk';
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
await updateAsset({ id: 'invalid' });
|
|
319
|
+
} catch (error) {
|
|
320
|
+
if (error instanceof ValidationError) {
|
|
321
|
+
console.log('Validation errors:', error.validationErrors);
|
|
322
|
+
// { field: ['error message'] }
|
|
323
|
+
} else if (error instanceof AuthenticationError) {
|
|
324
|
+
console.log('Authentication failed - check your token');
|
|
325
|
+
} else if (error instanceof GraphQLError) {
|
|
326
|
+
console.log('GraphQL error:', error.message);
|
|
327
|
+
} else if (error instanceof FairuError) {
|
|
328
|
+
console.log('General error:', error.message, error.code);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Configuration
|
|
334
|
+
|
|
335
|
+
### React Provider
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
import { FairuProvider } from '@fairu/sdk/react';
|
|
339
|
+
|
|
340
|
+
<FairuProvider
|
|
341
|
+
// GraphQL endpoint (required)
|
|
342
|
+
url="https://fairu.app/graphql"
|
|
343
|
+
|
|
344
|
+
// API token - can be static string or getter function
|
|
345
|
+
token="your-api-token"
|
|
346
|
+
// OR: getToken={() => localStorage.getItem('token')}
|
|
347
|
+
|
|
348
|
+
// FileProxy base URL (optional, default: https://files.fairu.app)
|
|
349
|
+
fileProxyUrl="https://files.fairu.app"
|
|
350
|
+
|
|
351
|
+
// Cache configuration (optional)
|
|
352
|
+
cache={{
|
|
353
|
+
enabled: true,
|
|
354
|
+
}}
|
|
355
|
+
|
|
356
|
+
// Global error handler (optional)
|
|
357
|
+
onError={(error) => {
|
|
358
|
+
console.error('GraphQL Error:', error);
|
|
359
|
+
// Send to error tracking service, show notification, etc.
|
|
360
|
+
}}
|
|
361
|
+
>
|
|
362
|
+
<App />
|
|
363
|
+
</FairuProvider>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Environment Variables
|
|
367
|
+
|
|
368
|
+
The SDK supports environment variables for configuration:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Vite
|
|
372
|
+
VITE_FAIRU_URL=https://fairu.app/graphql
|
|
373
|
+
VITE_FAIRU_TOKEN=your-token
|
|
374
|
+
|
|
375
|
+
# Next.js
|
|
376
|
+
NEXT_PUBLIC_FAIRU_URL=https://fairu.app/graphql
|
|
377
|
+
NEXT_PUBLIC_FAIRU_TOKEN=your-token
|
|
378
|
+
|
|
379
|
+
# Node.js
|
|
380
|
+
FAIRU_URL=https://fairu.app/graphql
|
|
381
|
+
FAIRU_TOKEN=your-token
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## TypeScript
|
|
385
|
+
|
|
386
|
+
All types are exported from the package:
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
import type {
|
|
390
|
+
// Entity types
|
|
391
|
+
FairuAsset,
|
|
392
|
+
FairuFolder,
|
|
393
|
+
FairuGallery,
|
|
394
|
+
FairuCopyright,
|
|
395
|
+
FairuLicense,
|
|
396
|
+
FairuUser,
|
|
397
|
+
FairuRole,
|
|
398
|
+
FairuTenant,
|
|
399
|
+
|
|
400
|
+
// Input types
|
|
401
|
+
FairuFileDto,
|
|
402
|
+
FairuFolderDto,
|
|
403
|
+
FairuGalleryDto,
|
|
404
|
+
|
|
405
|
+
// Enum types
|
|
406
|
+
FairuLicenseType,
|
|
407
|
+
FairuSortingDirection,
|
|
408
|
+
FairuUploadType,
|
|
409
|
+
|
|
410
|
+
// Query/Hook result types
|
|
411
|
+
AssetData,
|
|
412
|
+
AssetListData,
|
|
413
|
+
GalleryData,
|
|
414
|
+
FolderEntryData,
|
|
415
|
+
} from '@fairu/sdk';
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## Package Exports
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// Main exports (types, errors, core utilities)
|
|
422
|
+
import { FairuError, ValidationError } from '@fairu/sdk';
|
|
423
|
+
|
|
424
|
+
// React hooks and provider
|
|
425
|
+
import {
|
|
426
|
+
FairuProvider,
|
|
427
|
+
useAsset,
|
|
428
|
+
useAssets,
|
|
429
|
+
useUpload
|
|
430
|
+
} from '@fairu/sdk/react';
|
|
431
|
+
|
|
432
|
+
// Vanilla client (no React dependency)
|
|
433
|
+
import { createVanillaClient } from '@fairu/sdk/vanilla';
|
|
434
|
+
|
|
435
|
+
// FileProxy utilities
|
|
436
|
+
import { fileProxy, FileProxyBuilder } from '@fairu/sdk/fileproxy';
|
|
437
|
+
|
|
438
|
+
// Fragment system
|
|
439
|
+
import { FragmentBuilder, fragments } from '@fairu/sdk/fragments';
|
|
440
|
+
|
|
441
|
+
// Upload utilities
|
|
442
|
+
import { UploadError } from '@fairu/sdk/upload';
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## License
|
|
446
|
+
|
|
447
|
+
MIT
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const core = require("@urql/core");
|
|
3
|
+
const wonka = require("wonka");
|
|
4
|
+
const FairuError = require("./FairuError-DWH_Nwk0.cjs");
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
url: "https://fairu.app/graphql",
|
|
7
|
+
fileProxyUrl: "https://files.fairu.app",
|
|
8
|
+
retry: {
|
|
9
|
+
maxAttempts: 3,
|
|
10
|
+
delayMs: 1e3,
|
|
11
|
+
retryIf: (error) => {
|
|
12
|
+
return error.message.includes("Network") || error.message.includes("fetch");
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
cache: {
|
|
16
|
+
enabled: true,
|
|
17
|
+
keys: {}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
function createErrorExchange(onError) {
|
|
21
|
+
return core.mapExchange({
|
|
22
|
+
onResult: (result) => {
|
|
23
|
+
if (result.error && onError) {
|
|
24
|
+
const fairuError = FairuError.FairuError.fromCombinedError(result.error);
|
|
25
|
+
onError(fairuError);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function createAuthExchange(config) {
|
|
32
|
+
return ({ forward }) => {
|
|
33
|
+
return (operations$) => {
|
|
34
|
+
return wonka.pipe(
|
|
35
|
+
operations$,
|
|
36
|
+
wonka.map((operation) => {
|
|
37
|
+
let token = null;
|
|
38
|
+
if (config.token) {
|
|
39
|
+
token = config.token;
|
|
40
|
+
} else if (config.getToken) {
|
|
41
|
+
const result = config.getToken();
|
|
42
|
+
if (typeof result === "string" || result === null) {
|
|
43
|
+
token = result;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!token) {
|
|
47
|
+
return operation;
|
|
48
|
+
}
|
|
49
|
+
const fetchOptions = typeof operation.context.fetchOptions === "object" ? operation.context.fetchOptions : {};
|
|
50
|
+
return {
|
|
51
|
+
...operation,
|
|
52
|
+
context: {
|
|
53
|
+
...operation.context,
|
|
54
|
+
fetchOptions: {
|
|
55
|
+
...fetchOptions,
|
|
56
|
+
headers: {
|
|
57
|
+
...fetchOptions.headers,
|
|
58
|
+
Authorization: `Bearer ${token}`
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}),
|
|
64
|
+
forward
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function createFairuClient(config = {}) {
|
|
70
|
+
const url = config.url ?? DEFAULT_CONFIG.url;
|
|
71
|
+
const cacheConfig = { ...DEFAULT_CONFIG.cache, ...config.cache };
|
|
72
|
+
const exchanges = [];
|
|
73
|
+
if (config.token || config.getToken) {
|
|
74
|
+
exchanges.push(createAuthExchange(config));
|
|
75
|
+
}
|
|
76
|
+
if (cacheConfig.enabled) {
|
|
77
|
+
exchanges.push(core.cacheExchange);
|
|
78
|
+
}
|
|
79
|
+
if (config.onError) {
|
|
80
|
+
exchanges.push(createErrorExchange(config.onError));
|
|
81
|
+
}
|
|
82
|
+
exchanges.push(core.fetchExchange);
|
|
83
|
+
return new core.Client({
|
|
84
|
+
url,
|
|
85
|
+
exchanges,
|
|
86
|
+
requestPolicy: "cache-first"
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
90
|
+
exports.createFairuClient = createFairuClient;
|
|
91
|
+
//# sourceMappingURL=FairuClient-BUObk5LJ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FairuClient-BUObk5LJ.cjs","sources":["../src/client/config.ts","../src/client/FairuClient.ts"],"sourcesContent":["/**\n * Configuration options for the Fairu client.\n */\nexport interface FairuClientConfig {\n /**\n * The GraphQL API URL.\n * @default 'https://fairu.app/graphql'\n */\n url?: string;\n\n /**\n * Static API token for authentication.\n */\n token?: string;\n\n /**\n * Function to dynamically get the API token.\n * Useful for token refresh or async token retrieval.\n */\n getToken?: () => string | null | Promise<string | null>;\n\n /**\n * Cache configuration options.\n */\n cache?: CacheConfig;\n\n /**\n * Retry configuration for failed requests.\n */\n retry?: RetryConfig;\n\n /**\n * Callback for handling errors globally.\n */\n onError?: (error: Error) => void;\n\n /**\n * FileProxy base URL for image transformations.\n * @default 'https://files.fairu.app'\n */\n fileProxyUrl?: string;\n}\n\n/**\n * Cache configuration options.\n */\nexport interface CacheConfig {\n /**\n * Whether caching is enabled.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Custom entity keys for cache normalization.\n */\n keys?: Record<string, (data: unknown) => string | null>;\n}\n\n/**\n * Retry configuration options.\n */\nexport interface RetryConfig {\n /**\n * Maximum number of retry attempts.\n * @default 3\n */\n maxAttempts?: number;\n\n /**\n * Delay between retries in milliseconds.\n * @default 1000\n */\n delayMs?: number;\n\n /**\n * Function to determine if an error should trigger a retry.\n */\n retryIf?: (error: Error) => boolean;\n}\n\n/**\n * Default configuration values.\n */\nexport const DEFAULT_CONFIG: Required<\n Pick<FairuClientConfig, 'url' | 'fileProxyUrl'>\n> & {\n retry: Required<RetryConfig>;\n cache: Required<CacheConfig>;\n} = {\n url: 'https://fairu.app/graphql',\n fileProxyUrl: 'https://files.fairu.app',\n retry: {\n maxAttempts: 3,\n delayMs: 1000,\n retryIf: (error: Error) => {\n // Only retry network errors by default\n return error.message.includes('Network') || error.message.includes('fetch');\n },\n },\n cache: {\n enabled: true,\n keys: {},\n },\n};\n","import {\n Client,\n fetchExchange,\n cacheExchange,\n type Exchange,\n type OperationResult,\n type Operation,\n mapExchange,\n} from '@urql/core';\nimport { map, pipe } from 'wonka';\nimport { DEFAULT_CONFIG, type FairuClientConfig } from './config';\nimport { FairuError } from '../errors';\n\n/**\n * Create an error handling exchange.\n */\nfunction createErrorExchange(onError?: (error: Error) => void): Exchange {\n return mapExchange({\n onResult: (result: OperationResult) => {\n if (result.error && onError) {\n const fairuError = FairuError.fromCombinedError(result.error);\n onError(fairuError);\n }\n return result;\n },\n });\n}\n\n/**\n * Create an authentication exchange that adds Bearer token to requests.\n */\nfunction createAuthExchange(config: FairuClientConfig): Exchange {\n return ({ forward }) => {\n return (operations$) => {\n return pipe(\n operations$,\n map((operation: Operation) => {\n let token: string | null = null;\n\n if (config.token) {\n token = config.token;\n } else if (config.getToken) {\n const result = config.getToken();\n if (typeof result === 'string' || result === null) {\n token = result;\n }\n }\n\n if (!token) {\n return operation;\n }\n\n const fetchOptions =\n typeof operation.context.fetchOptions === 'object'\n ? operation.context.fetchOptions\n : {};\n\n return {\n ...operation,\n context: {\n ...operation.context,\n fetchOptions: {\n ...fetchOptions,\n headers: {\n ...(fetchOptions as Record<string, unknown>).headers as Record<string, string>,\n Authorization: `Bearer ${token}`,\n },\n },\n },\n };\n }),\n forward\n );\n };\n };\n}\n\n/**\n * Create a urql client configured for the Fairu GraphQL API.\n */\nexport function createFairuClient(config: FairuClientConfig = {}): Client {\n const url = config.url ?? DEFAULT_CONFIG.url;\n const cacheConfig = { ...DEFAULT_CONFIG.cache, ...config.cache };\n\n const exchanges: Exchange[] = [];\n\n // Auth exchange (adds Bearer token)\n if (config.token || config.getToken) {\n exchanges.push(createAuthExchange(config));\n }\n\n // Cache exchange (if enabled)\n if (cacheConfig.enabled) {\n exchanges.push(cacheExchange);\n }\n\n // Error exchange\n if (config.onError) {\n exchanges.push(createErrorExchange(config.onError));\n }\n\n // Fetch exchange (must be last)\n exchanges.push(fetchExchange);\n\n return new Client({\n url,\n exchanges,\n requestPolicy: 'cache-first',\n });\n}\n\nexport type { Client };\n"],"names":["mapExchange","FairuError","pipe","map","cacheExchange","fetchExchange","Client"],"mappings":";;;;AAoFO,MAAM,iBAKT;AAAA,EACF,KAAK;AAAA,EACL,cAAc;AAAA,EACd,OAAO;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC,UAAiB;AAEzB,aAAO,MAAM,QAAQ,SAAS,SAAS,KAAK,MAAM,QAAQ,SAAS,OAAO;AAAA,IAC5E;AAAA,EAAA;AAAA,EAEF,OAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,CAAA;AAAA,EAAC;AAEX;ACxFA,SAAS,oBAAoB,SAA4C;AACvE,SAAOA,iBAAY;AAAA,IACjB,UAAU,CAAC,WAA4B;AACrC,UAAI,OAAO,SAAS,SAAS;AAC3B,cAAM,aAAaC,WAAAA,WAAW,kBAAkB,OAAO,KAAK;AAC5D,gBAAQ,UAAU;AAAA,MACpB;AACA,aAAO;AAAA,IACT;AAAA,EAAA,CACD;AACH;AAKA,SAAS,mBAAmB,QAAqC;AAC/D,SAAO,CAAC,EAAE,cAAc;AACtB,WAAO,CAAC,gBAAgB;AACtB,aAAOC,MAAAA;AAAAA,QACL;AAAA,QACAC,MAAAA,IAAI,CAAC,cAAyB;AAC5B,cAAI,QAAuB;AAE3B,cAAI,OAAO,OAAO;AAChB,oBAAQ,OAAO;AAAA,UACjB,WAAW,OAAO,UAAU;AAC1B,kBAAM,SAAS,OAAO,SAAA;AACtB,gBAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,sBAAQ;AAAA,YACV;AAAA,UACF;AAEA,cAAI,CAAC,OAAO;AACV,mBAAO;AAAA,UACT;AAEA,gBAAM,eACJ,OAAO,UAAU,QAAQ,iBAAiB,WACtC,UAAU,QAAQ,eAClB,CAAA;AAEN,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,SAAS;AAAA,cACP,GAAG,UAAU;AAAA,cACb,cAAc;AAAA,gBACZ,GAAG;AAAA,gBACH,SAAS;AAAA,kBACP,GAAI,aAAyC;AAAA,kBAC7C,eAAe,UAAU,KAAK;AAAA,gBAAA;AAAA,cAChC;AAAA,YACF;AAAA,UACF;AAAA,QAEJ,CAAC;AAAA,QACD;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAKO,SAAS,kBAAkB,SAA4B,IAAY;AACxE,QAAM,MAAM,OAAO,OAAO,eAAe;AACzC,QAAM,cAAc,EAAE,GAAG,eAAe,OAAO,GAAG,OAAO,MAAA;AAEzD,QAAM,YAAwB,CAAA;AAG9B,MAAI,OAAO,SAAS,OAAO,UAAU;AACnC,cAAU,KAAK,mBAAmB,MAAM,CAAC;AAAA,EAC3C;AAGA,MAAI,YAAY,SAAS;AACvB,cAAU,KAAKC,kBAAa;AAAA,EAC9B;AAGA,MAAI,OAAO,SAAS;AAClB,cAAU,KAAK,oBAAoB,OAAO,OAAO,CAAC;AAAA,EACpD;AAGA,YAAU,KAAKC,kBAAa;AAE5B,SAAO,IAAIC,KAAAA,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA,eAAe;AAAA,EAAA,CAChB;AACH;;;"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { fetchExchange, Client, mapExchange, cacheExchange } from "@urql/core";
|
|
2
|
+
import { pipe, map } from "wonka";
|
|
3
|
+
import { F as FairuError } from "./FairuError-D8sSmRAa.js";
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
url: "https://fairu.app/graphql",
|
|
6
|
+
fileProxyUrl: "https://files.fairu.app",
|
|
7
|
+
retry: {
|
|
8
|
+
maxAttempts: 3,
|
|
9
|
+
delayMs: 1e3,
|
|
10
|
+
retryIf: (error) => {
|
|
11
|
+
return error.message.includes("Network") || error.message.includes("fetch");
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
cache: {
|
|
15
|
+
enabled: true,
|
|
16
|
+
keys: {}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function createErrorExchange(onError) {
|
|
20
|
+
return mapExchange({
|
|
21
|
+
onResult: (result) => {
|
|
22
|
+
if (result.error && onError) {
|
|
23
|
+
const fairuError = FairuError.fromCombinedError(result.error);
|
|
24
|
+
onError(fairuError);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function createAuthExchange(config) {
|
|
31
|
+
return ({ forward }) => {
|
|
32
|
+
return (operations$) => {
|
|
33
|
+
return pipe(
|
|
34
|
+
operations$,
|
|
35
|
+
map((operation) => {
|
|
36
|
+
let token = null;
|
|
37
|
+
if (config.token) {
|
|
38
|
+
token = config.token;
|
|
39
|
+
} else if (config.getToken) {
|
|
40
|
+
const result = config.getToken();
|
|
41
|
+
if (typeof result === "string" || result === null) {
|
|
42
|
+
token = result;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!token) {
|
|
46
|
+
return operation;
|
|
47
|
+
}
|
|
48
|
+
const fetchOptions = typeof operation.context.fetchOptions === "object" ? operation.context.fetchOptions : {};
|
|
49
|
+
return {
|
|
50
|
+
...operation,
|
|
51
|
+
context: {
|
|
52
|
+
...operation.context,
|
|
53
|
+
fetchOptions: {
|
|
54
|
+
...fetchOptions,
|
|
55
|
+
headers: {
|
|
56
|
+
...fetchOptions.headers,
|
|
57
|
+
Authorization: `Bearer ${token}`
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}),
|
|
63
|
+
forward
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function createFairuClient(config = {}) {
|
|
69
|
+
const url = config.url ?? DEFAULT_CONFIG.url;
|
|
70
|
+
const cacheConfig = { ...DEFAULT_CONFIG.cache, ...config.cache };
|
|
71
|
+
const exchanges = [];
|
|
72
|
+
if (config.token || config.getToken) {
|
|
73
|
+
exchanges.push(createAuthExchange(config));
|
|
74
|
+
}
|
|
75
|
+
if (cacheConfig.enabled) {
|
|
76
|
+
exchanges.push(cacheExchange);
|
|
77
|
+
}
|
|
78
|
+
if (config.onError) {
|
|
79
|
+
exchanges.push(createErrorExchange(config.onError));
|
|
80
|
+
}
|
|
81
|
+
exchanges.push(fetchExchange);
|
|
82
|
+
return new Client({
|
|
83
|
+
url,
|
|
84
|
+
exchanges,
|
|
85
|
+
requestPolicy: "cache-first"
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
DEFAULT_CONFIG as D,
|
|
90
|
+
createFairuClient as c
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=FairuClient-CT-IPh8i.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FairuClient-CT-IPh8i.js","sources":["../src/client/config.ts","../src/client/FairuClient.ts"],"sourcesContent":["/**\n * Configuration options for the Fairu client.\n */\nexport interface FairuClientConfig {\n /**\n * The GraphQL API URL.\n * @default 'https://fairu.app/graphql'\n */\n url?: string;\n\n /**\n * Static API token for authentication.\n */\n token?: string;\n\n /**\n * Function to dynamically get the API token.\n * Useful for token refresh or async token retrieval.\n */\n getToken?: () => string | null | Promise<string | null>;\n\n /**\n * Cache configuration options.\n */\n cache?: CacheConfig;\n\n /**\n * Retry configuration for failed requests.\n */\n retry?: RetryConfig;\n\n /**\n * Callback for handling errors globally.\n */\n onError?: (error: Error) => void;\n\n /**\n * FileProxy base URL for image transformations.\n * @default 'https://files.fairu.app'\n */\n fileProxyUrl?: string;\n}\n\n/**\n * Cache configuration options.\n */\nexport interface CacheConfig {\n /**\n * Whether caching is enabled.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Custom entity keys for cache normalization.\n */\n keys?: Record<string, (data: unknown) => string | null>;\n}\n\n/**\n * Retry configuration options.\n */\nexport interface RetryConfig {\n /**\n * Maximum number of retry attempts.\n * @default 3\n */\n maxAttempts?: number;\n\n /**\n * Delay between retries in milliseconds.\n * @default 1000\n */\n delayMs?: number;\n\n /**\n * Function to determine if an error should trigger a retry.\n */\n retryIf?: (error: Error) => boolean;\n}\n\n/**\n * Default configuration values.\n */\nexport const DEFAULT_CONFIG: Required<\n Pick<FairuClientConfig, 'url' | 'fileProxyUrl'>\n> & {\n retry: Required<RetryConfig>;\n cache: Required<CacheConfig>;\n} = {\n url: 'https://fairu.app/graphql',\n fileProxyUrl: 'https://files.fairu.app',\n retry: {\n maxAttempts: 3,\n delayMs: 1000,\n retryIf: (error: Error) => {\n // Only retry network errors by default\n return error.message.includes('Network') || error.message.includes('fetch');\n },\n },\n cache: {\n enabled: true,\n keys: {},\n },\n};\n","import {\n Client,\n fetchExchange,\n cacheExchange,\n type Exchange,\n type OperationResult,\n type Operation,\n mapExchange,\n} from '@urql/core';\nimport { map, pipe } from 'wonka';\nimport { DEFAULT_CONFIG, type FairuClientConfig } from './config';\nimport { FairuError } from '../errors';\n\n/**\n * Create an error handling exchange.\n */\nfunction createErrorExchange(onError?: (error: Error) => void): Exchange {\n return mapExchange({\n onResult: (result: OperationResult) => {\n if (result.error && onError) {\n const fairuError = FairuError.fromCombinedError(result.error);\n onError(fairuError);\n }\n return result;\n },\n });\n}\n\n/**\n * Create an authentication exchange that adds Bearer token to requests.\n */\nfunction createAuthExchange(config: FairuClientConfig): Exchange {\n return ({ forward }) => {\n return (operations$) => {\n return pipe(\n operations$,\n map((operation: Operation) => {\n let token: string | null = null;\n\n if (config.token) {\n token = config.token;\n } else if (config.getToken) {\n const result = config.getToken();\n if (typeof result === 'string' || result === null) {\n token = result;\n }\n }\n\n if (!token) {\n return operation;\n }\n\n const fetchOptions =\n typeof operation.context.fetchOptions === 'object'\n ? operation.context.fetchOptions\n : {};\n\n return {\n ...operation,\n context: {\n ...operation.context,\n fetchOptions: {\n ...fetchOptions,\n headers: {\n ...(fetchOptions as Record<string, unknown>).headers as Record<string, string>,\n Authorization: `Bearer ${token}`,\n },\n },\n },\n };\n }),\n forward\n );\n };\n };\n}\n\n/**\n * Create a urql client configured for the Fairu GraphQL API.\n */\nexport function createFairuClient(config: FairuClientConfig = {}): Client {\n const url = config.url ?? DEFAULT_CONFIG.url;\n const cacheConfig = { ...DEFAULT_CONFIG.cache, ...config.cache };\n\n const exchanges: Exchange[] = [];\n\n // Auth exchange (adds Bearer token)\n if (config.token || config.getToken) {\n exchanges.push(createAuthExchange(config));\n }\n\n // Cache exchange (if enabled)\n if (cacheConfig.enabled) {\n exchanges.push(cacheExchange);\n }\n\n // Error exchange\n if (config.onError) {\n exchanges.push(createErrorExchange(config.onError));\n }\n\n // Fetch exchange (must be last)\n exchanges.push(fetchExchange);\n\n return new Client({\n url,\n exchanges,\n requestPolicy: 'cache-first',\n });\n}\n\nexport type { Client };\n"],"names":[],"mappings":";;;AAoFO,MAAM,iBAKT;AAAA,EACF,KAAK;AAAA,EACL,cAAc;AAAA,EACd,OAAO;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC,UAAiB;AAEzB,aAAO,MAAM,QAAQ,SAAS,SAAS,KAAK,MAAM,QAAQ,SAAS,OAAO;AAAA,IAC5E;AAAA,EAAA;AAAA,EAEF,OAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,CAAA;AAAA,EAAC;AAEX;ACxFA,SAAS,oBAAoB,SAA4C;AACvE,SAAO,YAAY;AAAA,IACjB,UAAU,CAAC,WAA4B;AACrC,UAAI,OAAO,SAAS,SAAS;AAC3B,cAAM,aAAa,WAAW,kBAAkB,OAAO,KAAK;AAC5D,gBAAQ,UAAU;AAAA,MACpB;AACA,aAAO;AAAA,IACT;AAAA,EAAA,CACD;AACH;AAKA,SAAS,mBAAmB,QAAqC;AAC/D,SAAO,CAAC,EAAE,cAAc;AACtB,WAAO,CAAC,gBAAgB;AACtB,aAAO;AAAA,QACL;AAAA,QACA,IAAI,CAAC,cAAyB;AAC5B,cAAI,QAAuB;AAE3B,cAAI,OAAO,OAAO;AAChB,oBAAQ,OAAO;AAAA,UACjB,WAAW,OAAO,UAAU;AAC1B,kBAAM,SAAS,OAAO,SAAA;AACtB,gBAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,sBAAQ;AAAA,YACV;AAAA,UACF;AAEA,cAAI,CAAC,OAAO;AACV,mBAAO;AAAA,UACT;AAEA,gBAAM,eACJ,OAAO,UAAU,QAAQ,iBAAiB,WACtC,UAAU,QAAQ,eAClB,CAAA;AAEN,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,SAAS;AAAA,cACP,GAAG,UAAU;AAAA,cACb,cAAc;AAAA,gBACZ,GAAG;AAAA,gBACH,SAAS;AAAA,kBACP,GAAI,aAAyC;AAAA,kBAC7C,eAAe,UAAU,KAAK;AAAA,gBAAA;AAAA,cAChC;AAAA,YACF;AAAA,UACF;AAAA,QAEJ,CAAC;AAAA,QACD;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAKO,SAAS,kBAAkB,SAA4B,IAAY;AACxE,QAAM,MAAM,OAAO,OAAO,eAAe;AACzC,QAAM,cAAc,EAAE,GAAG,eAAe,OAAO,GAAG,OAAO,MAAA;AAEzD,QAAM,YAAwB,CAAA;AAG9B,MAAI,OAAO,SAAS,OAAO,UAAU;AACnC,cAAU,KAAK,mBAAmB,MAAM,CAAC;AAAA,EAC3C;AAGA,MAAI,YAAY,SAAS;AACvB,cAAU,KAAK,aAAa;AAAA,EAC9B;AAGA,MAAI,OAAO,SAAS;AAClB,cAAU,KAAK,oBAAoB,OAAO,OAAO,CAAC;AAAA,EACpD;AAGA,YAAU,KAAK,aAAa;AAE5B,SAAO,IAAI,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA,eAAe;AAAA,EAAA,CAChB;AACH;"}
|