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