@oxyhq/core 3.2.0 → 3.4.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/AuthManager.js +3 -1
- package/dist/cjs/HttpService.js +89 -0
- package/dist/cjs/OxyServices.js +1 -1
- package/dist/cjs/constants/version.js +1 -1
- package/dist/cjs/i18n/locales/en-US.json +44 -44
- package/dist/cjs/i18n/locales/es-ES.json +44 -44
- package/dist/cjs/i18n/locales/locales/en-US.json +44 -44
- package/dist/cjs/i18n/locales/locales/es-ES.json +44 -44
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/mixins/OxyServices.applications.js +3 -1
- package/dist/cjs/mixins/OxyServices.reputation.js +244 -0
- package/dist/cjs/mixins/OxyServices.workspaces.js +3 -1
- package/dist/cjs/mixins/index.js +2 -2
- package/dist/cjs/utils/accountUtils.js +12 -5
- package/dist/cjs/utils/ssoReturn.js +80 -33
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +3 -1
- package/dist/esm/HttpService.js +89 -0
- package/dist/esm/OxyServices.js +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/i18n/locales/en-US.json +44 -44
- package/dist/esm/i18n/locales/es-ES.json +44 -44
- package/dist/esm/i18n/locales/locales/en-US.json +44 -44
- package/dist/esm/i18n/locales/locales/es-ES.json +44 -44
- package/dist/esm/index.js +4 -0
- package/dist/esm/mixins/OxyServices.applications.js +3 -1
- package/dist/esm/mixins/OxyServices.reputation.js +241 -0
- package/dist/esm/mixins/OxyServices.workspaces.js +3 -1
- package/dist/esm/mixins/index.js +2 -2
- package/dist/esm/utils/accountUtils.js +12 -5
- package/dist/esm/utils/ssoReturn.js +80 -33
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +57 -0
- package/dist/types/OxyServices.d.ts +1 -1
- package/dist/types/constants/version.d.ts +2 -2
- package/dist/types/index.d.ts +2 -1
- package/dist/types/mixins/OxyServices.applications.d.ts +8 -2
- package/dist/types/mixins/OxyServices.features.d.ts +0 -1
- package/dist/types/mixins/OxyServices.reputation.d.ts +436 -0
- package/dist/types/mixins/OxyServices.workspaces.d.ts +8 -2
- package/dist/types/mixins/index.d.ts +2 -2
- package/dist/types/models/interfaces.d.ts +15 -26
- package/dist/types/utils/accountUtils.d.ts +17 -4
- package/dist/types/utils/ssoReturn.d.ts +30 -9
- package/package.json +2 -1
- package/src/AuthManager.ts +3 -1
- package/src/HttpService.ts +91 -0
- package/src/OxyServices.ts +1 -1
- package/src/__tests__/httpServiceCache.test.ts +198 -0
- package/src/constants/version.ts +1 -1
- package/src/i18n/locales/en-US.json +44 -44
- package/src/i18n/locales/es-ES.json +44 -44
- package/src/index.ts +32 -4
- package/src/mixins/OxyServices.applications.ts +8 -2
- package/src/mixins/OxyServices.auth.ts +2 -1
- package/src/mixins/OxyServices.features.ts +0 -1
- package/src/mixins/OxyServices.reputation.ts +674 -0
- package/src/mixins/OxyServices.workspaces.ts +8 -2
- package/src/mixins/__tests__/reputation.test.ts +408 -0
- package/src/mixins/index.ts +3 -3
- package/src/models/interfaces.ts +16 -32
- package/src/utils/__tests__/accountUtils.test.ts +142 -0
- package/src/utils/__tests__/consumeSsoReturn.test.ts +229 -37
- package/src/utils/accountUtils.ts +20 -5
- package/src/utils/ssoReturn.ts +98 -37
- package/dist/cjs/mixins/OxyServices.developer.js +0 -97
- package/dist/cjs/mixins/OxyServices.karma.js +0 -108
- package/dist/esm/mixins/OxyServices.developer.js +0 -94
- package/dist/esm/mixins/OxyServices.karma.js +0 -105
- package/dist/types/mixins/OxyServices.developer.d.ts +0 -106
- package/dist/types/mixins/OxyServices.karma.d.ts +0 -92
- package/src/mixins/OxyServices.karma.ts +0 -111
package/src/utils/ssoReturn.ts
CHANGED
|
@@ -135,9 +135,22 @@ export interface ConsumeSsoReturnDeps {
|
|
|
135
135
|
* location changed via `history.replaceState`, which does NOT itself emit
|
|
136
136
|
* `popstate`. Default: dispatch a real `PopStateEvent` on `window` when
|
|
137
137
|
* present; no-op off-web. Called ONLY after a successful same-origin
|
|
138
|
-
* dest restore (never when the dest is rejected/absent).
|
|
138
|
+
* dest restore on the `ok` path (never when the dest is rejected/absent).
|
|
139
|
+
* NEVER throws.
|
|
139
140
|
*/
|
|
140
141
|
dispatchPopState?: () => void;
|
|
142
|
+
/**
|
|
143
|
+
* Hard, full-document navigation used to leave the internal callback path on
|
|
144
|
+
* every NON-`ok` outcome (`none`/`error`, state-mismatch, missing code,
|
|
145
|
+
* failed exchange, missing sessionId). A SOFT `history.replaceState` +
|
|
146
|
+
* synthetic `popstate` does NOT reliably make Expo Router / TanStack Router
|
|
147
|
+
* re-resolve away from the 404 they have already rendered for the
|
|
148
|
+
* unregistered callback route — so for these outcomes (where there is no
|
|
149
|
+
* in-memory session to preserve) a full navigation is both safe and
|
|
150
|
+
* guaranteed to clear the 404. Default: `window.location.replace(url)` when
|
|
151
|
+
* present; feature-detected end to end so it never throws off-web.
|
|
152
|
+
*/
|
|
153
|
+
hardRedirect?: (url: string) => void;
|
|
141
154
|
}
|
|
142
155
|
|
|
143
156
|
/**
|
|
@@ -164,14 +177,22 @@ export interface ConsumeSsoReturnDeps {
|
|
|
164
177
|
* treated exactly like "no session" (never loops, never rethrows).
|
|
165
178
|
* - On EVERY consumed outcome (ok, none, error, state-mismatch, no-code,
|
|
166
179
|
* failed-exchange, no-sessionId) — not just ok — if the page landed on
|
|
167
|
-
* {@link SSO_CALLBACK_PATH}, the
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
180
|
+
* {@link SSO_CALLBACK_PATH}, the user is taken to a same-origin TARGET so
|
|
181
|
+
* they are never stranded on the internal callback path (which is an
|
|
182
|
+
* unregistered route in every consumer router → a hard 404). The target is
|
|
183
|
+
* the stored DEST when it parses as same-origin (an attacker-planted
|
|
184
|
+
* cross-origin / protocol-relative dest is rejected), ELSE the app root
|
|
185
|
+
* (`origin + '/'`). The DEST key is removed unconditionally.
|
|
186
|
+
* - For the `ok` outcome the target is applied via a SOFT
|
|
187
|
+
* `history.replaceState` + synthetic `popstate` so the freshly exchanged
|
|
188
|
+
* in-memory session the provider is about to commit is preserved (no
|
|
189
|
+
* reload). `popstate` is dispatched only on the `ok` same-origin restore.
|
|
190
|
+
* - For every NON-`ok` outcome there is no in-memory session to preserve, and
|
|
191
|
+
* the consumer router has ALREADY synchronously rendered its 404 for the
|
|
192
|
+
* unregistered callback route — a soft replaceState+popstate does not
|
|
193
|
+
* reliably make it re-resolve. So these outcomes perform a HARD
|
|
194
|
+
* full-document navigation to the target (`hardRedirect`), which is both
|
|
195
|
+
* safe (nothing to lose) and guaranteed to clear the 404 in every router.
|
|
175
196
|
*
|
|
176
197
|
* Total: this function NEVER throws. Off-web it is a no-op returning `null`.
|
|
177
198
|
*
|
|
@@ -214,6 +235,21 @@ export async function consumeSsoReturn(
|
|
|
214
235
|
}
|
|
215
236
|
});
|
|
216
237
|
|
|
238
|
+
// Default: a hard, full-document navigation used to leave the callback path
|
|
239
|
+
// on non-`ok` outcomes. Feature-detected end to end so it never throws in any
|
|
240
|
+
// environment (SSR / native / a stubbed location without `replace`).
|
|
241
|
+
const hardRedirect =
|
|
242
|
+
deps.hardRedirect ??
|
|
243
|
+
((url: string) => {
|
|
244
|
+
if (
|
|
245
|
+
typeof window !== 'undefined' &&
|
|
246
|
+
window.location &&
|
|
247
|
+
typeof window.location.replace === 'function'
|
|
248
|
+
) {
|
|
249
|
+
window.location.replace(url);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
217
253
|
const ret = parseSsoReturnFragment(location.hash);
|
|
218
254
|
if (!ret) {
|
|
219
255
|
// Not an oxy_sso fragment — nothing to do (do NOT touch any flags).
|
|
@@ -241,39 +277,56 @@ export async function consumeSsoReturn(
|
|
|
241
277
|
storage.setItem(ssoAttemptedKey(origin), '1');
|
|
242
278
|
};
|
|
243
279
|
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
280
|
+
// Compute the same-origin TARGET to leave the callback path for. Returns the
|
|
281
|
+
// stored DEST when present AND it parses as same-origin (never honour a
|
|
282
|
+
// cross-origin / protocol-relative dest that could have been planted to
|
|
283
|
+
// redirect the user), ELSE the app root (`origin + '/'`) so the user is never
|
|
284
|
+
// stranded on the internal callback path even when no dest was stored. The
|
|
285
|
+
// DEST key is removed unconditionally. Returns the relative path+search+hash
|
|
286
|
+
// (so it can be fed to either `history.replaceState` or a `hardRedirect`),
|
|
287
|
+
// or `null` when the page is not on the callback path (nothing to leave).
|
|
288
|
+
const consumeCallbackTarget = (): string | null => {
|
|
289
|
+
if (location.pathname !== SSO_CALLBACK_PATH) {
|
|
290
|
+
// Not on the callback path — still drop the dest key (consumed) but there
|
|
291
|
+
// is nothing to navigate away from.
|
|
292
|
+
storage.removeItem(ssoDestKey(origin));
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
const dest = storage.getItem(ssoDestKey(origin));
|
|
296
|
+
storage.removeItem(ssoDestKey(origin));
|
|
297
|
+
if (dest) {
|
|
298
|
+
try {
|
|
299
|
+
const destUrl = new URL(dest, origin);
|
|
300
|
+
if (destUrl.origin === origin) {
|
|
301
|
+
return destUrl.pathname + destUrl.search + destUrl.hash;
|
|
266
302
|
}
|
|
303
|
+
} catch {
|
|
304
|
+
// Malformed stored destination — fall through to the app-root fallback.
|
|
267
305
|
}
|
|
268
306
|
}
|
|
269
|
-
|
|
307
|
+
// No dest, a cross-origin/protocol-relative dest, or an unparseable dest:
|
|
308
|
+
// fall back to the app root so the router always leaves the 404.
|
|
309
|
+
return '/';
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// Non-`ok` outcomes: there is no in-memory session to preserve, and the
|
|
313
|
+
// consumer router has already rendered its 404 for the unregistered callback
|
|
314
|
+
// route — a soft replaceState+popstate does not reliably make it re-resolve.
|
|
315
|
+
// Perform a HARD full-document navigation to the target (safe: nothing to
|
|
316
|
+
// lose; guaranteed: every router leaves the 404). Off the callback path this
|
|
317
|
+
// is a no-op (target is null).
|
|
318
|
+
const leaveCallbackHard = (): void => {
|
|
319
|
+
const target = consumeCallbackTarget();
|
|
320
|
+
if (target !== null) {
|
|
321
|
+
hardRedirect(origin + target);
|
|
322
|
+
}
|
|
270
323
|
};
|
|
271
324
|
|
|
272
325
|
if (ret.kind === 'none' || ret.kind === 'error') {
|
|
273
326
|
// The central IdP had no session (or the bounce failed). Record it so we do
|
|
274
327
|
// not bounce again this tab — the definitive loop breaker.
|
|
275
328
|
markNoSession();
|
|
276
|
-
|
|
329
|
+
leaveCallbackHard();
|
|
277
330
|
return null;
|
|
278
331
|
}
|
|
279
332
|
|
|
@@ -281,7 +334,7 @@ export async function consumeSsoReturn(
|
|
|
281
334
|
// Forged / replayed / stale fragment, or a malformed ok with no code. Treat
|
|
282
335
|
// exactly like "no session": never exchange, never loop.
|
|
283
336
|
markNoSession();
|
|
284
|
-
|
|
337
|
+
leaveCallbackHard();
|
|
285
338
|
return null;
|
|
286
339
|
}
|
|
287
340
|
|
|
@@ -291,17 +344,25 @@ export async function consumeSsoReturn(
|
|
|
291
344
|
} catch (error) {
|
|
292
345
|
onExchangeError?.(error);
|
|
293
346
|
markNoSession();
|
|
294
|
-
|
|
347
|
+
leaveCallbackHard();
|
|
295
348
|
return null;
|
|
296
349
|
}
|
|
297
350
|
|
|
298
351
|
if (!session?.sessionId) {
|
|
299
352
|
markNoSession();
|
|
300
|
-
|
|
353
|
+
leaveCallbackHard();
|
|
301
354
|
return null;
|
|
302
355
|
}
|
|
303
356
|
|
|
304
|
-
|
|
357
|
+
// `ok`: the provider is about to commit the freshly exchanged in-memory
|
|
358
|
+
// session — do NOT hard-redirect (a full navigation would discard it). Use a
|
|
359
|
+
// SOFT `history.replaceState` to the target + a synthetic `popstate` so
|
|
360
|
+
// URL-driven routers re-sync to the restored route without a reload.
|
|
361
|
+
const target = consumeCallbackTarget();
|
|
362
|
+
if (target !== null) {
|
|
363
|
+
history.replaceState(null, '', target);
|
|
364
|
+
dispatchPopState();
|
|
365
|
+
}
|
|
305
366
|
|
|
306
367
|
return session;
|
|
307
368
|
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OxyServicesDeveloperMixin = OxyServicesDeveloperMixin;
|
|
4
|
-
const mixinHelpers_1 = require("./mixinHelpers");
|
|
5
|
-
function OxyServicesDeveloperMixin(Base) {
|
|
6
|
-
return class extends Base {
|
|
7
|
-
constructor(...args) {
|
|
8
|
-
super(...args);
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Get developer apps for the current user
|
|
12
|
-
* @returns Array of developer apps
|
|
13
|
-
*/
|
|
14
|
-
async getDeveloperApps() {
|
|
15
|
-
try {
|
|
16
|
-
const res = await this.makeRequest('GET', '/developer/apps', undefined, {
|
|
17
|
-
cache: true,
|
|
18
|
-
cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM,
|
|
19
|
-
});
|
|
20
|
-
return res.apps || [];
|
|
21
|
-
}
|
|
22
|
-
catch (error) {
|
|
23
|
-
throw this.handleError(error);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Create a new developer app
|
|
28
|
-
* @param data - Developer app configuration
|
|
29
|
-
* @returns Created developer app
|
|
30
|
-
*/
|
|
31
|
-
async createDeveloperApp(data) {
|
|
32
|
-
try {
|
|
33
|
-
const res = await this.makeRequest('POST', '/developer/apps', data, { cache: false });
|
|
34
|
-
return res.app;
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
throw this.handleError(error);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Get a specific developer app
|
|
42
|
-
*/
|
|
43
|
-
async getDeveloperApp(appId) {
|
|
44
|
-
try {
|
|
45
|
-
const res = await this.makeRequest('GET', `/developer/apps/${appId}`, undefined, {
|
|
46
|
-
cache: true,
|
|
47
|
-
cacheTTL: mixinHelpers_1.CACHE_TIMES.LONG,
|
|
48
|
-
});
|
|
49
|
-
return res.app;
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
throw this.handleError(error);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Update a developer app
|
|
57
|
-
* @param appId - The developer app ID
|
|
58
|
-
* @param data - Updated app configuration
|
|
59
|
-
* @returns Updated developer app
|
|
60
|
-
*/
|
|
61
|
-
async updateDeveloperApp(appId, data) {
|
|
62
|
-
try {
|
|
63
|
-
const res = await this.makeRequest('PATCH', `/developer/apps/${appId}`, data, { cache: false });
|
|
64
|
-
return res.app;
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
throw this.handleError(error);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Regenerate API secret for a developer app
|
|
72
|
-
* @param appId - The developer app ID
|
|
73
|
-
* @returns App with new secret
|
|
74
|
-
*/
|
|
75
|
-
async regenerateDeveloperAppSecret(appId) {
|
|
76
|
-
try {
|
|
77
|
-
return await this.makeRequest('POST', `/developer/apps/${appId}/regenerate-secret`, undefined, { cache: false });
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
throw this.handleError(error);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Delete a developer app
|
|
85
|
-
* @param appId - The developer app ID
|
|
86
|
-
* @returns Deletion result
|
|
87
|
-
*/
|
|
88
|
-
async deleteDeveloperApp(appId) {
|
|
89
|
-
try {
|
|
90
|
-
return await this.makeRequest('DELETE', `/developer/apps/${appId}`, undefined, { cache: false });
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
throw this.handleError(error);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OxyServicesKarmaMixin = OxyServicesKarmaMixin;
|
|
4
|
-
const mixinHelpers_1 = require("./mixinHelpers");
|
|
5
|
-
function OxyServicesKarmaMixin(Base) {
|
|
6
|
-
return class extends Base {
|
|
7
|
-
constructor(...args) {
|
|
8
|
-
super(...args);
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Get user karma
|
|
12
|
-
*/
|
|
13
|
-
async getUserKarma(userId) {
|
|
14
|
-
try {
|
|
15
|
-
return await this.makeRequest('GET', `/karma/${userId}`, undefined, {
|
|
16
|
-
cache: true,
|
|
17
|
-
cacheTTL: 2 * 60 * 1000, // 2 minutes cache
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
catch (error) {
|
|
21
|
-
throw this.handleError(error);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Give karma to user
|
|
26
|
-
*/
|
|
27
|
-
async giveKarma(userId, amount, reason) {
|
|
28
|
-
try {
|
|
29
|
-
return await this.makeRequest('POST', `/karma/${userId}/give`, {
|
|
30
|
-
amount,
|
|
31
|
-
reason
|
|
32
|
-
}, { cache: false });
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
throw this.handleError(error);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Get user karma total
|
|
40
|
-
* @param userId - The user ID
|
|
41
|
-
* @returns User karma total
|
|
42
|
-
*/
|
|
43
|
-
async getUserKarmaTotal(userId) {
|
|
44
|
-
try {
|
|
45
|
-
return await this.makeRequest('GET', `/karma/${userId}/total`, undefined, {
|
|
46
|
-
cache: true,
|
|
47
|
-
cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
throw this.handleError(error);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Get user karma history
|
|
56
|
-
* @param userId - The user ID
|
|
57
|
-
* @param limit - Optional limit for results
|
|
58
|
-
* @param offset - Optional offset for pagination
|
|
59
|
-
* @returns User karma history
|
|
60
|
-
*/
|
|
61
|
-
async getUserKarmaHistory(userId, limit, offset) {
|
|
62
|
-
try {
|
|
63
|
-
const params = {};
|
|
64
|
-
if (limit)
|
|
65
|
-
params.limit = limit;
|
|
66
|
-
if (offset)
|
|
67
|
-
params.offset = offset;
|
|
68
|
-
return await this.makeRequest('GET', `/karma/${userId}/history`, params, {
|
|
69
|
-
cache: true,
|
|
70
|
-
cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
throw this.handleError(error);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Get karma leaderboard
|
|
79
|
-
* @returns Karma leaderboard
|
|
80
|
-
*/
|
|
81
|
-
async getKarmaLeaderboard() {
|
|
82
|
-
try {
|
|
83
|
-
return await this.makeRequest('GET', '/karma/leaderboard', undefined, {
|
|
84
|
-
cache: true,
|
|
85
|
-
cacheTTL: mixinHelpers_1.CACHE_TIMES.LONG,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
throw this.handleError(error);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Get karma rules
|
|
94
|
-
* @returns Karma rules
|
|
95
|
-
*/
|
|
96
|
-
async getKarmaRules() {
|
|
97
|
-
try {
|
|
98
|
-
return await this.makeRequest('GET', '/karma/rules', undefined, {
|
|
99
|
-
cache: true,
|
|
100
|
-
cacheTTL: mixinHelpers_1.CACHE_TIMES.EXTRA_LONG, // Rules don't change often
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
throw this.handleError(error);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { CACHE_TIMES } from './mixinHelpers.js';
|
|
2
|
-
export function OxyServicesDeveloperMixin(Base) {
|
|
3
|
-
return class extends Base {
|
|
4
|
-
constructor(...args) {
|
|
5
|
-
super(...args);
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Get developer apps for the current user
|
|
9
|
-
* @returns Array of developer apps
|
|
10
|
-
*/
|
|
11
|
-
async getDeveloperApps() {
|
|
12
|
-
try {
|
|
13
|
-
const res = await this.makeRequest('GET', '/developer/apps', undefined, {
|
|
14
|
-
cache: true,
|
|
15
|
-
cacheTTL: CACHE_TIMES.MEDIUM,
|
|
16
|
-
});
|
|
17
|
-
return res.apps || [];
|
|
18
|
-
}
|
|
19
|
-
catch (error) {
|
|
20
|
-
throw this.handleError(error);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Create a new developer app
|
|
25
|
-
* @param data - Developer app configuration
|
|
26
|
-
* @returns Created developer app
|
|
27
|
-
*/
|
|
28
|
-
async createDeveloperApp(data) {
|
|
29
|
-
try {
|
|
30
|
-
const res = await this.makeRequest('POST', '/developer/apps', data, { cache: false });
|
|
31
|
-
return res.app;
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
throw this.handleError(error);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get a specific developer app
|
|
39
|
-
*/
|
|
40
|
-
async getDeveloperApp(appId) {
|
|
41
|
-
try {
|
|
42
|
-
const res = await this.makeRequest('GET', `/developer/apps/${appId}`, undefined, {
|
|
43
|
-
cache: true,
|
|
44
|
-
cacheTTL: CACHE_TIMES.LONG,
|
|
45
|
-
});
|
|
46
|
-
return res.app;
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
throw this.handleError(error);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Update a developer app
|
|
54
|
-
* @param appId - The developer app ID
|
|
55
|
-
* @param data - Updated app configuration
|
|
56
|
-
* @returns Updated developer app
|
|
57
|
-
*/
|
|
58
|
-
async updateDeveloperApp(appId, data) {
|
|
59
|
-
try {
|
|
60
|
-
const res = await this.makeRequest('PATCH', `/developer/apps/${appId}`, data, { cache: false });
|
|
61
|
-
return res.app;
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
throw this.handleError(error);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Regenerate API secret for a developer app
|
|
69
|
-
* @param appId - The developer app ID
|
|
70
|
-
* @returns App with new secret
|
|
71
|
-
*/
|
|
72
|
-
async regenerateDeveloperAppSecret(appId) {
|
|
73
|
-
try {
|
|
74
|
-
return await this.makeRequest('POST', `/developer/apps/${appId}/regenerate-secret`, undefined, { cache: false });
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
throw this.handleError(error);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Delete a developer app
|
|
82
|
-
* @param appId - The developer app ID
|
|
83
|
-
* @returns Deletion result
|
|
84
|
-
*/
|
|
85
|
-
async deleteDeveloperApp(appId) {
|
|
86
|
-
try {
|
|
87
|
-
return await this.makeRequest('DELETE', `/developer/apps/${appId}`, undefined, { cache: false });
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
throw this.handleError(error);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { CACHE_TIMES } from './mixinHelpers.js';
|
|
2
|
-
export function OxyServicesKarmaMixin(Base) {
|
|
3
|
-
return class extends Base {
|
|
4
|
-
constructor(...args) {
|
|
5
|
-
super(...args);
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Get user karma
|
|
9
|
-
*/
|
|
10
|
-
async getUserKarma(userId) {
|
|
11
|
-
try {
|
|
12
|
-
return await this.makeRequest('GET', `/karma/${userId}`, undefined, {
|
|
13
|
-
cache: true,
|
|
14
|
-
cacheTTL: 2 * 60 * 1000, // 2 minutes cache
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
catch (error) {
|
|
18
|
-
throw this.handleError(error);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Give karma to user
|
|
23
|
-
*/
|
|
24
|
-
async giveKarma(userId, amount, reason) {
|
|
25
|
-
try {
|
|
26
|
-
return await this.makeRequest('POST', `/karma/${userId}/give`, {
|
|
27
|
-
amount,
|
|
28
|
-
reason
|
|
29
|
-
}, { cache: false });
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
throw this.handleError(error);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Get user karma total
|
|
37
|
-
* @param userId - The user ID
|
|
38
|
-
* @returns User karma total
|
|
39
|
-
*/
|
|
40
|
-
async getUserKarmaTotal(userId) {
|
|
41
|
-
try {
|
|
42
|
-
return await this.makeRequest('GET', `/karma/${userId}/total`, undefined, {
|
|
43
|
-
cache: true,
|
|
44
|
-
cacheTTL: CACHE_TIMES.MEDIUM,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
throw this.handleError(error);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Get user karma history
|
|
53
|
-
* @param userId - The user ID
|
|
54
|
-
* @param limit - Optional limit for results
|
|
55
|
-
* @param offset - Optional offset for pagination
|
|
56
|
-
* @returns User karma history
|
|
57
|
-
*/
|
|
58
|
-
async getUserKarmaHistory(userId, limit, offset) {
|
|
59
|
-
try {
|
|
60
|
-
const params = {};
|
|
61
|
-
if (limit)
|
|
62
|
-
params.limit = limit;
|
|
63
|
-
if (offset)
|
|
64
|
-
params.offset = offset;
|
|
65
|
-
return await this.makeRequest('GET', `/karma/${userId}/history`, params, {
|
|
66
|
-
cache: true,
|
|
67
|
-
cacheTTL: CACHE_TIMES.MEDIUM,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
throw this.handleError(error);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Get karma leaderboard
|
|
76
|
-
* @returns Karma leaderboard
|
|
77
|
-
*/
|
|
78
|
-
async getKarmaLeaderboard() {
|
|
79
|
-
try {
|
|
80
|
-
return await this.makeRequest('GET', '/karma/leaderboard', undefined, {
|
|
81
|
-
cache: true,
|
|
82
|
-
cacheTTL: CACHE_TIMES.LONG,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
throw this.handleError(error);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Get karma rules
|
|
91
|
-
* @returns Karma rules
|
|
92
|
-
*/
|
|
93
|
-
async getKarmaRules() {
|
|
94
|
-
try {
|
|
95
|
-
return await this.makeRequest('GET', '/karma/rules', undefined, {
|
|
96
|
-
cache: true,
|
|
97
|
-
cacheTTL: CACHE_TIMES.EXTRA_LONG, // Rules don't change often
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
throw this.handleError(error);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
}
|