@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.
- package/LICENSE +12 -12
- package/README.md +65 -65
- package/dist/bin/check.cjs +79 -0
- package/dist/bin/check.cjs.map +1 -0
- package/dist/bin/check.d.cts +1 -0
- package/dist/bin/check.d.ts +1 -0
- package/dist/bin/check.js +72 -0
- package/dist/bin/check.js.map +1 -0
- package/dist/chunk-TLDZ32ME.js +356 -0
- package/dist/chunk-TLDZ32ME.js.map +1 -0
- package/dist/chunk-X7RFIMX7.cjs +361 -0
- package/dist/chunk-X7RFIMX7.cjs.map +1 -0
- package/dist/client-FIWQgwNq.d.cts +325 -0
- package/dist/client-FIWQgwNq.d.ts +325 -0
- package/dist/index.cjs +85 -7
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5 -38
- package/dist/index.d.ts +5 -38
- package/dist/index.js +67 -7
- package/dist/index.js.map +1 -0
- package/dist/plugin.cjs +209 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +9 -0
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.js +198 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +27 -8
|
@@ -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"]}
|