@snappy-stack/sdk 0.1.4 → 0.1.6

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.
@@ -0,0 +1,356 @@
1
+ // src/client.ts
2
+ var SnappyClient = class {
3
+ config;
4
+ constructor(config) {
5
+ if (!config || !config.token || typeof config.token !== "string") {
6
+ throw new Error("SNAPPY_SDK_ECONFIG: A valid string token is required");
7
+ }
8
+ if (config.baseUrl && typeof config.baseUrl !== "string") {
9
+ throw new Error("SNAPPY_SDK_ECONFIG: baseUrl must be a valid string");
10
+ }
11
+ this.config = {
12
+ baseUrl: "https://core.wicky.id",
13
+ ...config
14
+ };
15
+ }
16
+ async fetch(endpoint, options = {}) {
17
+ const chain = options.chain || "tenant";
18
+ const url = `${this.config.baseUrl}${endpoint}`;
19
+ const headers = {
20
+ "Content-Type": "application/json",
21
+ ...options.headers || {}
22
+ };
23
+ headers["Authorization"] = `Bearer ${this.config.token}`;
24
+ if (chain !== "admin" && this.config.sessionToken) {
25
+ headers["X-Session-Token"] = this.config.sessionToken;
26
+ }
27
+ let lastError = null;
28
+ const maxRetries = 3;
29
+ const startOverall = Date.now();
30
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
31
+ try {
32
+ if (attempt > 0) {
33
+ const delay = Math.pow(2, attempt - 1) * 1e3;
34
+ await new Promise((resolve) => setTimeout(resolve, delay));
35
+ }
36
+ const response = await globalThis.fetch(url, {
37
+ ...options,
38
+ headers,
39
+ credentials: chain === "admin" ? "include" : "omit"
40
+ });
41
+ const latency = Date.now() - (attempt === 0 ? startOverall : Date.now());
42
+ if (response.status === 503 && attempt < maxRetries) {
43
+ continue;
44
+ }
45
+ if (response.status === 429) {
46
+ throw new Error("SNAPPY_SDK_E429: Too many requests. Rate limit exceeded.");
47
+ }
48
+ if (response.status === 401 || response.status === 402 || response.status === 403) {
49
+ const isBrowser = typeof window !== "undefined";
50
+ if (response.status === 403) {
51
+ if (chain === "admin") {
52
+ throw new Error("SNAPPY_SDK_E403: Admin access required");
53
+ }
54
+ const error = await response.json().catch(() => ({ error: "Forbidden" }));
55
+ throw new Error(`SNAPPY_SDK_E403: ${error.error || "Project is INACTIVE"}`);
56
+ }
57
+ if (isBrowser && !options.skipRedirect && !window.location.pathname.startsWith("/suspended")) {
58
+ if (response.status === 402) {
59
+ window.location.href = "/suspended?error=project_suspended";
60
+ } else if (response.status === 401 && chain === "tenant" && !window.location.pathname.startsWith("/login")) {
61
+ window.location.href = "/login?error=session_expired";
62
+ }
63
+ }
64
+ const errorMsg = response.status === 401 ? "Unauthorized: Session expired" : response.status === 402 ? "Forbidden: Project suspended" : "Forbidden";
65
+ throw new Error(`SNAPPY_SDK_E${response.status}: ${errorMsg}`);
66
+ }
67
+ if (!response.ok) {
68
+ const error = await response.json().catch(() => ({ error: "Unknown error" }));
69
+ throw new Error(`SNAPPY_SDK_E${response.status}: ${error.error || response.statusText}`);
70
+ }
71
+ const data = await response.json();
72
+ return { ...data, _latency: Date.now() - startOverall };
73
+ } catch (e) {
74
+ lastError = e;
75
+ if (attempt === maxRetries || e.message.includes("SNAPPY_SDK_E")) {
76
+ throw e;
77
+ }
78
+ }
79
+ }
80
+ throw lastError || new Error("SNAPPY_SDK_E500: Unknown error");
81
+ }
82
+ content = {
83
+ getCollections: () => {
84
+ return this.fetch("/v1/content/_collections");
85
+ },
86
+ collection: (slug) => ({
87
+ getAll: (params = {}) => {
88
+ const isStudio = !!this.config.sessionToken;
89
+ const base = isStudio ? "/v1/studio/content" : "/v1/content";
90
+ const query = new URLSearchParams({
91
+ locale: params.locale || this.config.locale || "en",
92
+ status: params.status || "PUBLISHED",
93
+ limit: (params.limit || 20).toString(),
94
+ offset: (params.offset || 0).toString()
95
+ }).toString();
96
+ return this.fetch(`${base}/${slug}?${query}`);
97
+ },
98
+ getOne: (id, locale) => {
99
+ const isStudio = !!this.config.sessionToken;
100
+ const base = isStudio ? "/v1/studio/content" : "/v1/content";
101
+ const l = locale || this.config.locale || "en";
102
+ return this.fetch(`${base}/${slug}/${id}?locale=${l}`);
103
+ },
104
+ create: (data) => {
105
+ return this.fetch(`/v1/content/${slug}`, {
106
+ method: "POST",
107
+ body: JSON.stringify(data)
108
+ });
109
+ },
110
+ update: (id, data) => {
111
+ return this.fetch(`/v1/content/${slug}/${id}`, {
112
+ method: "PATCH",
113
+ body: JSON.stringify(data)
114
+ });
115
+ },
116
+ publish: (id, version) => {
117
+ return this.fetch(`/v1/content/${slug}/${id}/publish`, {
118
+ method: "POST",
119
+ body: JSON.stringify({ version })
120
+ });
121
+ },
122
+ delete: (id) => {
123
+ return this.fetch(`/v1/content/${slug}/${id}`, {
124
+ method: "DELETE"
125
+ });
126
+ }
127
+ }),
128
+ global: (slug) => ({
129
+ get: (locale) => {
130
+ const l = locale || this.config.locale || "en";
131
+ return this.fetch(`/v1/globals/${slug}?locale=${l}`);
132
+ },
133
+ update: (data, locale) => {
134
+ const l = locale || this.config.locale || "en";
135
+ return this.fetch(`/v1/globals/${slug}?locale=${l}`, {
136
+ method: "PATCH",
137
+ body: JSON.stringify(data)
138
+ });
139
+ }
140
+ })
141
+ };
142
+ profile = {
143
+ get: () => this.fetch("/v1/profile"),
144
+ update: (data) => this.fetch("/v1/profile", {
145
+ method: "PATCH",
146
+ body: JSON.stringify(data)
147
+ }),
148
+ updateSocial: (data) => {
149
+ return this.fetch("/v1/profile/socials", {
150
+ method: "PATCH",
151
+ body: JSON.stringify(data)
152
+ });
153
+ },
154
+ deleteSocial: (id) => {
155
+ return this.fetch(`/v1/profile/socials/${id}`, {
156
+ method: "DELETE"
157
+ });
158
+ },
159
+ updateSettings: (data) => {
160
+ return this.fetch("/v1/settings", {
161
+ method: "PATCH",
162
+ body: JSON.stringify(data)
163
+ });
164
+ }
165
+ };
166
+ collection(slug) {
167
+ return this.content.collection(slug);
168
+ }
169
+ global(slug) {
170
+ return this.content.global(slug);
171
+ }
172
+ media = {
173
+ stats: () => this.fetch("/v1/media/stats"),
174
+ list: (params = {}) => {
175
+ const searchParams = {
176
+ limit: (params.limit || 50).toString(),
177
+ offset: (params.offset || 0).toString()
178
+ };
179
+ if (params.folder) {
180
+ searchParams.folder = params.folder;
181
+ }
182
+ const query = new URLSearchParams(searchParams).toString();
183
+ return this.fetch(`/v1/media?${query}`);
184
+ },
185
+ getOne: (id) => this.fetch(`/v1/media/${id}`),
186
+ process: (data) => {
187
+ return this.fetch("/v1/media/process", {
188
+ method: "POST",
189
+ body: JSON.stringify(data)
190
+ });
191
+ },
192
+ confirm: (id) => {
193
+ return this.fetch("/v1/media/confirm", {
194
+ method: "POST",
195
+ body: JSON.stringify({ id })
196
+ });
197
+ },
198
+ renameFolder: (old_name, new_name) => {
199
+ return this.fetch("/v1/media/folder/rename", {
200
+ method: "POST",
201
+ body: JSON.stringify({ old_name, new_name })
202
+ });
203
+ },
204
+ delete: (id) => {
205
+ return this.fetch(`/v1/media/${id}`, {
206
+ method: "DELETE"
207
+ });
208
+ }
209
+ };
210
+ reviews = {
211
+ list: (status) => this.fetch(`/v1/reviews${status ? `?status=${status}` : ""}`),
212
+ getOne: (id) => this.fetch(`/v1/reviews/${id}`),
213
+ create: (data) => {
214
+ return this.fetch("/v1/reviews", {
215
+ method: "POST",
216
+ body: JSON.stringify(data)
217
+ });
218
+ },
219
+ submit: (id, data) => {
220
+ return this.fetch(`/v1/reviews/${id}/submit`, {
221
+ method: "POST",
222
+ body: JSON.stringify(data)
223
+ });
224
+ },
225
+ delete: (id) => {
226
+ return this.fetch(`/v1/reviews/${id}`, {
227
+ method: "DELETE"
228
+ });
229
+ }
230
+ };
231
+ releases = {
232
+ getAll: () => this.fetch("/v1/releases"),
233
+ create: (data) => this.fetch("/v1/releases", { method: "POST", body: JSON.stringify(data) }),
234
+ publish: (id) => this.fetch(`/v1/releases/${id}/publish`, { method: "POST" })
235
+ };
236
+ async heartbeat() {
237
+ return this.fetch("/v1/heartbeat");
238
+ }
239
+ async search(query, locale) {
240
+ const l = locale || this.config.locale || "en";
241
+ return this.fetch(`/v1/search?q=${encodeURIComponent(query)}&locale=${l}`);
242
+ }
243
+ admin = {
244
+ getStats: () => this.fetch("/v1/projects/stats", { chain: "admin" }),
245
+ getCollections: () => this.fetch("/v1/content/_collections", { chain: "admin" }),
246
+ getProjects: () => this.fetch("/v1/projects", { chain: "admin" }),
247
+ getProject: (slug) => this.fetch(`/v1/projects/${slug}`, { chain: "admin" }),
248
+ updateProject: (slug, updates) => this.fetch(`/v1/projects/${slug}`, {
249
+ method: "PATCH",
250
+ body: JSON.stringify(updates),
251
+ chain: "admin"
252
+ }),
253
+ updateStatus: (slug, status) => this.fetch(`/v1/projects/${slug}/status`, {
254
+ method: "PATCH",
255
+ body: JSON.stringify({ status }),
256
+ chain: "admin"
257
+ }),
258
+ updatePayment: (slug, status) => this.fetch(`/v1/projects/${slug}/payment`, {
259
+ method: "PATCH",
260
+ body: JSON.stringify({ status }),
261
+ chain: "admin"
262
+ }),
263
+ rotateLicense: (slug) => this.fetch(`/v1/projects/${slug}/rotate-token`, {
264
+ method: "POST",
265
+ chain: "admin"
266
+ }),
267
+ deleteProject: (slug) => this.fetch(`/v1/projects/${slug}`, {
268
+ method: "DELETE",
269
+ chain: "admin"
270
+ }),
271
+ inviteUser: (email, permissions, projectSlug) => this.fetch("/v1/auth/invite", {
272
+ method: "POST",
273
+ body: JSON.stringify({ email, permissions, projectSlug }),
274
+ chain: "admin"
275
+ }),
276
+ getMe: () => this.fetch("/v1/auth/me", { chain: "admin" }),
277
+ getProjectToken: (slug) => this.fetch(`/v1/projects/${slug}`, { chain: "admin" }),
278
+ getOrders: () => this.fetch("/v1/orders", { chain: "admin" }),
279
+ getPPDBSubmissions: () => this.fetch("/v1/ppdb/config", { chain: "admin" }),
280
+ getReviews: (status) => this.fetch(`/v1/reviews${status ? `?status=${status}` : ""}`, { chain: "admin" }),
281
+ getProjectUsers: (slug) => this.fetch(`/v1/projects/${slug}/users`, { chain: "admin" }),
282
+ manageUser: (slug, userId, permissions) => this.fetch(`/v1/projects/${slug}/users`, {
283
+ method: "POST",
284
+ body: JSON.stringify({ userId, permissions }),
285
+ chain: "admin"
286
+ }),
287
+ revokeUser: (slug, userId) => this.fetch(`/v1/projects/${slug}/users/${userId}`, {
288
+ method: "DELETE",
289
+ chain: "admin"
290
+ })
291
+ };
292
+ /**
293
+ * Get the SNAPPY Score for the current project
294
+ */
295
+ async getScore() {
296
+ return this.fetch("/v1/score");
297
+ }
298
+ };
299
+ var SnappyPublicClient = class {
300
+ baseUrl;
301
+ constructor(config = {}) {
302
+ this.baseUrl = config.baseUrl || "https://core.wicky.id";
303
+ }
304
+ async fetch(endpoint, options = {}) {
305
+ const url = `${this.baseUrl}${endpoint}`;
306
+ const start = Date.now();
307
+ const response = await globalThis.fetch(url, {
308
+ ...options,
309
+ headers: {
310
+ "Content-Type": "application/json",
311
+ ...options.headers || {}
312
+ }
313
+ });
314
+ if (!response.ok) {
315
+ const error = await response.json().catch(() => ({ error: "Unknown error" }));
316
+ throw new Error(`SNAPPY_PUBLIC_SDK_E${response.status}: ${error.error || response.statusText}`);
317
+ }
318
+ const data = await response.json();
319
+ return { ...data, _latency: Date.now() - start };
320
+ }
321
+ reviews = {
322
+ getOne: (id) => this.fetch(`/v1/reviews/${id}`),
323
+ submit: (id, data) => {
324
+ return this.fetch(`/v1/reviews/${id}/submit`, {
325
+ method: "POST",
326
+ body: JSON.stringify(data)
327
+ });
328
+ }
329
+ };
330
+ ppdb = {
331
+ submit: (data) => {
332
+ return this.fetch("/v1/ppdb/submit", {
333
+ method: "POST",
334
+ body: JSON.stringify(data)
335
+ });
336
+ }
337
+ };
338
+ orders = {
339
+ submit: (data) => {
340
+ return this.fetch("/v1/orders/submit", {
341
+ method: "POST",
342
+ body: JSON.stringify(data)
343
+ });
344
+ }
345
+ };
346
+ };
347
+ function createClient(config) {
348
+ return new SnappyClient(config);
349
+ }
350
+ function createPublicClient(config = {}) {
351
+ return new SnappyPublicClient(config);
352
+ }
353
+
354
+ export { SnappyClient, SnappyPublicClient, createClient, createPublicClient };
355
+ //# sourceMappingURL=chunk-TLDZ32ME.js.map
356
+ //# sourceMappingURL=chunk-TLDZ32ME.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-TLDZ32ME.js","sourcesContent":["import type { \r\n SnappyConfig, \r\n SnappyList, \r\n SnappyOne, \r\n Entry, \r\n Global, \r\n Media, \r\n Project, \r\n User, \r\n Review, \r\n ReviewStatus,\r\n Heartbeat \r\n} from './types.js';\r\n\r\nexport { SnappyConfig };\r\n\r\nexport class SnappyClient {\r\n private config: SnappyConfig;\r\n\r\n constructor(config: SnappyConfig) {\r\n if (!config || !config.token || typeof config.token !== 'string') {\r\n throw new Error('SNAPPY_SDK_ECONFIG: A valid string token is required');\r\n }\r\n\r\n if (config.baseUrl && typeof config.baseUrl !== 'string') {\r\n throw new Error('SNAPPY_SDK_ECONFIG: baseUrl must be a valid string');\r\n }\r\n \r\n this.config = {\r\n baseUrl: 'https://core.wicky.id',\r\n ...config\r\n };\r\n }\r\n\r\n private async fetch<T>(endpoint: string, options: RequestInit & { skipRedirect?: boolean; chain?: 'tenant' | 'admin' } = {}): Promise<T & { _latency: number }> {\r\n const chain = options.chain || 'tenant';\r\n const url = `${this.config.baseUrl}${endpoint}`;\r\n \r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...((options.headers as any) || {}),\r\n };\r\n\r\n headers['Authorization'] = `Bearer ${this.config.token}`;\r\n \r\n if (chain !== 'admin' && this.config.sessionToken) {\r\n headers['X-Session-Token'] = this.config.sessionToken;\r\n }\r\n\r\n let lastError: Error | null = null;\r\n const maxRetries = 3;\r\n const startOverall = Date.now();\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n try {\r\n if (attempt > 0) {\r\n const delay = Math.pow(2, attempt - 1) * 1000;\r\n await new Promise(resolve => setTimeout(resolve, delay));\r\n }\r\n\r\n const response = await globalThis.fetch(url, { \r\n ...options, \r\n headers, \r\n credentials: chain === 'admin' ? 'include' : 'omit' \r\n } as any);\r\n\r\n const latency = Date.now() - (attempt === 0 ? startOverall : Date.now()); // Relative to attempt start for internal, or overall\r\n \r\n if (response.status === 503 && attempt < maxRetries) {\r\n continue; // Retry on 503\r\n }\r\n\r\n if (response.status === 429) {\r\n throw new Error('SNAPPY_SDK_E429: Too many requests. Rate limit exceeded.');\r\n }\r\n\r\n if (response.status === 401 || response.status === 402 || response.status === 403) {\r\n const isBrowser = typeof window !== 'undefined';\r\n \r\n if (response.status === 403) {\r\n if (chain === 'admin') {\r\n throw new Error('SNAPPY_SDK_E403: Admin access required');\r\n }\r\n const error = await response.json().catch(() => ({ error: 'Forbidden' }));\r\n throw new Error(`SNAPPY_SDK_E403: ${error.error || 'Project is INACTIVE'}`);\r\n }\r\n\r\n if (isBrowser && !options.skipRedirect && !window.location.pathname.startsWith('/suspended')) {\r\n if (response.status === 402) {\r\n window.location.href = '/suspended?error=project_suspended';\r\n } else if (response.status === 401 && chain === 'tenant' && !window.location.pathname.startsWith('/login')) {\r\n window.location.href = '/login?error=session_expired';\r\n }\r\n }\r\n\r\n const errorMsg = response.status === 401 ? 'Unauthorized: Session expired' : \r\n response.status === 402 ? 'Forbidden: Project suspended' : \r\n 'Forbidden';\r\n \r\n throw new Error(`SNAPPY_SDK_E${response.status}: ${errorMsg}`);\r\n }\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ error: 'Unknown error' }));\r\n throw new Error(`SNAPPY_SDK_E${response.status}: ${error.error || response.statusText}`);\r\n }\r\n\r\n const data = await response.json();\r\n return { ...data, _latency: Date.now() - startOverall };\r\n } catch (e: any) {\r\n lastError = e;\r\n if (attempt === maxRetries || e.message.includes('SNAPPY_SDK_E')) {\r\n throw e;\r\n }\r\n }\r\n }\r\n\r\n throw lastError || new Error('SNAPPY_SDK_E500: Unknown error');\r\n }\r\n\r\n content = {\r\n getCollections: (): Promise<SnappyList<any>> => {\r\n return this.fetch('/v1/content/_collections');\r\n },\r\n collection: (slug: string) => ({\r\n getAll: (params: { locale?: string; status?: string; limit?: number; offset?: number } = {}): Promise<SnappyList<Entry>> => {\r\n const isStudio = !!this.config.sessionToken;\r\n const base = isStudio ? '/v1/studio/content' : '/v1/content';\r\n const query = new URLSearchParams({\r\n locale: params.locale || this.config.locale || 'en',\r\n status: params.status || 'PUBLISHED',\r\n limit: (params.limit || 20).toString(),\r\n offset: (params.offset || 0).toString(),\r\n }).toString();\r\n return this.fetch(`${base}/${slug}?${query}`);\r\n },\r\n getOne: (id: string, locale?: string): Promise<SnappyOne<Entry>> => {\r\n const isStudio = !!this.config.sessionToken;\r\n const base = isStudio ? '/v1/studio/content' : '/v1/content';\r\n const l = locale || this.config.locale || 'en';\r\n return this.fetch(`${base}/${slug}/${id}?locale=${l}`);\r\n },\r\n create: (data: any): Promise<SnappyOne<Entry>> => {\r\n return this.fetch(`/v1/content/${slug}`, {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n },\r\n update: (id: string, data: any): Promise<SnappyOne<Entry>> => {\r\n return this.fetch(`/v1/content/${slug}/${id}`, {\r\n method: 'PATCH',\r\n body: JSON.stringify(data),\r\n });\r\n },\r\n publish: (id: string, version: number): Promise<SnappyOne<Entry>> => {\r\n return this.fetch(`/v1/content/${slug}/${id}/publish`, {\r\n method: 'POST',\r\n body: JSON.stringify({ version }),\r\n });\r\n },\r\n delete: (id: string): Promise<SnappyOne<any>> => {\r\n return this.fetch(`/v1/content/${slug}/${id}`, {\r\n method: 'DELETE',\r\n });\r\n }\r\n }),\r\n global: (slug: string) => ({\r\n get: (locale?: string): Promise<SnappyOne<Global>> => {\r\n const l = locale || this.config.locale || 'en';\r\n return this.fetch(`/v1/globals/${slug}?locale=${l}`);\r\n },\r\n update: (data: any, locale?: string): Promise<SnappyOne<Global>> => {\r\n const l = locale || this.config.locale || 'en';\r\n return this.fetch(`/v1/globals/${slug}?locale=${l}`, {\r\n method: 'PATCH',\r\n body: JSON.stringify(data),\r\n });\r\n }\r\n })\r\n };\r\n\r\n profile = {\r\n get: (): Promise<SnappyOne<any>> => this.fetch('/v1/profile'),\r\n update: (data: any): Promise<SnappyOne<any>> => this.fetch('/v1/profile', {\r\n method: 'PATCH',\r\n body: JSON.stringify(data)\r\n }),\r\n updateSocial: (data: { id?: string; platform: string; url: string; sort_order?: number }): Promise<SnappyOne<any>> => {\r\n return this.fetch('/v1/profile/socials', {\r\n method: 'PATCH',\r\n body: JSON.stringify(data)\r\n });\r\n },\r\n deleteSocial: (id: string): Promise<SnappyOne<any>> => {\r\n return this.fetch(`/v1/profile/socials/${id}`, {\r\n method: 'DELETE'\r\n });\r\n },\r\n updateSettings: (data: any): Promise<SnappyOne<any>> => {\r\n return this.fetch('/v1/settings', {\r\n method: 'PATCH',\r\n body: JSON.stringify(data)\r\n });\r\n }\r\n };\r\n\r\n collection(slug: string) { return this.content.collection(slug); }\r\n global(slug: string) { return this.content.global(slug); }\r\n\r\n media = {\r\n stats: (): Promise<SnappyOne<{ used_bytes: number; file_count: number }>> => this.fetch('/v1/media/stats'),\r\n list: (params: { folder?: string; limit?: number; offset?: number } = {}): Promise<SnappyList<Media>> => {\r\n const searchParams: Record<string, string> = {\r\n limit: (params.limit || 50).toString(),\r\n offset: (params.offset || 0).toString(),\r\n };\r\n if (params.folder) {\r\n searchParams.folder = params.folder;\r\n }\r\n const query = new URLSearchParams(searchParams).toString();\r\n return this.fetch(`/v1/media?${query}`);\r\n },\r\n getOne: (id: string): Promise<SnappyOne<Media>> => this.fetch(`/v1/media/${id}`),\r\n process: (data: { filename: string; mime_type: string; size: number; folder?: string }): Promise<SnappyOne<{ id: string; uploadUrl: string; filename: string }>> => {\r\n return this.fetch('/v1/media/process', {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n },\r\n confirm: (id: string): Promise<SnappyOne<Media>> => {\r\n return this.fetch('/v1/media/confirm', {\r\n method: 'POST',\r\n body: JSON.stringify({ id }),\r\n });\r\n },\r\n renameFolder: (old_name: string, new_name: string): Promise<SnappyOne<{ updated: number }>> => {\r\n return this.fetch('/v1/media/folder/rename', {\r\n method: 'POST',\r\n body: JSON.stringify({ old_name, new_name }),\r\n });\r\n },\r\n delete: (id: string): Promise<void> => {\r\n return this.fetch(`/v1/media/${id}`, {\r\n method: 'DELETE',\r\n });\r\n }\r\n };\r\n\r\n reviews = {\r\n list: (status?: string): Promise<SnappyList<Review>> => this.fetch(`/v1/reviews${status ? `?status=${status}` : ''}`),\r\n getOne: (id: string): Promise<SnappyOne<Review>> => this.fetch(`/v1/reviews/${id}`),\r\n create: (data: { entry_id?: string; expires_in?: string }): Promise<SnappyOne<Review>> => {\r\n return this.fetch('/v1/reviews', {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n },\r\n submit: (id: string, data: { author_name: string; rating: number; content: string }): Promise<SnappyOne<{ message: string }>> => {\r\n return this.fetch(`/v1/reviews/${id}/submit`, {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n },\r\n delete: (id: string): Promise<SnappyOne<{ message: string }>> => {\r\n return this.fetch(`/v1/reviews/${id}`, {\r\n method: 'DELETE',\r\n });\r\n }\r\n };\r\n\r\n releases = {\r\n getAll: (): Promise<SnappyList<any>> => this.fetch('/v1/releases'),\r\n create: (data: any): Promise<SnappyOne<any>> => this.fetch('/v1/releases', { method: 'POST', body: JSON.stringify(data) }),\r\n publish: (id: string) => this.fetch(`/v1/releases/${id}/publish`, { method: 'POST' })\r\n };\r\n\r\n async heartbeat(): Promise<SnappyOne<Heartbeat>> {\r\n return this.fetch('/v1/heartbeat');\r\n }\r\n\r\n async search(query: string, locale?: string): Promise<SnappyList<any>> {\r\n const l = locale || this.config.locale || 'en';\r\n return this.fetch(`/v1/search?q=${encodeURIComponent(query)}&locale=${l}`);\r\n }\r\n\r\n admin = {\r\n getStats: () => this.fetch('/v1/projects/stats', { chain: 'admin' }),\r\n getCollections: () => this.fetch('/v1/content/_collections', { chain: 'admin' }),\r\n getProjects: (): Promise<SnappyList<Project>> => this.fetch('/v1/projects', { chain: 'admin' }),\r\n getProject: (slug: string): Promise<SnappyOne<Project>> => this.fetch(`/v1/projects/${slug}`, { chain: 'admin' }),\r\n updateProject: (slug: string, updates: any) => this.fetch(`/v1/projects/${slug}`, {\r\n method: 'PATCH',\r\n body: JSON.stringify(updates),\r\n chain: 'admin'\r\n }),\r\n updateStatus: (slug: string, status: string) => this.fetch(`/v1/projects/${slug}/status`, {\r\n method: 'PATCH',\r\n body: JSON.stringify({ status }),\r\n chain: 'admin'\r\n }),\r\n updatePayment: (slug: string, status: string) => this.fetch(`/v1/projects/${slug}/payment`, {\r\n method: 'PATCH',\r\n body: JSON.stringify({ status }),\r\n chain: 'admin'\r\n }),\r\n rotateLicense: (slug: string) => this.fetch(`/v1/projects/${slug}/rotate-token`, {\r\n method: 'POST',\r\n chain: 'admin'\r\n }),\r\n deleteProject: (slug: string) => this.fetch(`/v1/projects/${slug}`, {\r\n method: 'DELETE',\r\n chain: 'admin'\r\n }),\r\n inviteUser: (email: string, permissions: string[], projectSlug: string) => this.fetch('/v1/auth/invite', {\r\n method: 'POST',\r\n body: JSON.stringify({ email, permissions, projectSlug }),\r\n chain: 'admin'\r\n }),\r\n getMe: (): Promise<SnappyOne<User>> => this.fetch('/v1/auth/me', { chain: 'admin' }),\r\n getProjectToken: (slug: string) => this.fetch(`/v1/projects/${slug}`, { chain: 'admin' }),\r\n getOrders: () => this.fetch('/v1/orders', { chain: 'admin' }),\r\n getPPDBSubmissions: () => this.fetch('/v1/ppdb/config', { chain: 'admin' }),\r\n getReviews: (status?: string) => this.fetch(`/v1/reviews${status ? `?status=${status}` : ''}`, { chain: 'admin' }),\r\n getProjectUsers: (slug: string) => this.fetch(`/v1/projects/${slug}/users`, { chain: 'admin' }),\r\n manageUser: (slug: string, userId: string, permissions: string[]) => this.fetch(`/v1/projects/${slug}/users`, {\r\n method: 'POST',\r\n body: JSON.stringify({ userId, permissions }),\r\n chain: 'admin'\r\n }),\r\n revokeUser: (slug: string, userId: string) => this.fetch(`/v1/projects/${slug}/users/${userId}`, {\r\n method: 'DELETE',\r\n chain: 'admin'\r\n })\r\n };\r\n\r\n /**\r\n * Get the SNAPPY Score for the current project\r\n */\r\n async getScore(): Promise<{ score: number; warning?: string; blocked: boolean }> {\r\n return this.fetch('/v1/score');\r\n }\r\n}\r\n\r\nexport class SnappyPublicClient {\r\n private baseUrl: string;\r\n\r\n constructor(config: { baseUrl?: string } = {}) {\r\n this.baseUrl = config.baseUrl || 'https://core.wicky.id';\r\n }\r\n\r\n private async fetch<T>(endpoint: string, options: RequestInit = {}): Promise<T & { _latency: number }> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const start = Date.now();\r\n\r\n const response = await globalThis.fetch(url, {\r\n ...options,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...(options.headers || {}),\r\n }\r\n } as any);\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ error: 'Unknown error' }));\r\n throw new Error(`SNAPPY_PUBLIC_SDK_E${response.status}: ${error.error || response.statusText}`);\r\n }\r\n\r\n const data = await response.json();\r\n return { ...data, _latency: Date.now() - start };\r\n }\r\n\r\n reviews = {\r\n getOne: (id: string): Promise<SnappyOne<ReviewStatus>> => this.fetch(`/v1/reviews/${id}`),\r\n submit: (id: string, data: { author_name: string; rating: number; content: string }): Promise<SnappyOne<{ message: string }>> => {\r\n return this.fetch(`/v1/reviews/${id}/submit`, {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n }\r\n };\r\n\r\n ppdb = {\r\n submit: (data: any): Promise<SnappyOne<{ message: string }>> => {\r\n // Stub for future PPDB implementation\r\n return this.fetch('/v1/ppdb/submit', {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n }\r\n };\r\n\r\n orders = {\r\n submit: (data: any): Promise<SnappyOne<{ message: string }>> => {\r\n // Stub for future commerce implementation\r\n return this.fetch('/v1/orders/submit', {\r\n method: 'POST',\r\n body: JSON.stringify(data),\r\n });\r\n }\r\n };\r\n}\r\n\r\nexport function createClient(config: SnappyConfig) {\r\n return new SnappyClient(config);\r\n}\r\n\r\nexport function createPublicClient(config: { baseUrl?: string } = {}) {\r\n return new SnappyPublicClient(config);\r\n}\r\n"]}