@oxy.so/core 7.12.0 → 7.13.0

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.
Files changed (39) hide show
  1. package/dist/cjs/api/apps.js +1 -1
  2. package/dist/cjs/api/auth.js +1 -1
  3. package/dist/cjs/api/billing.js +4 -3
  4. package/dist/cjs/api/devices.js +5 -4
  5. package/dist/cjs/api/follows.js +11 -10
  6. package/dist/cjs/api/privacy.js +8 -7
  7. package/dist/cjs/api/session.js +10 -7
  8. package/dist/cjs/api/topics.js +4 -3
  9. package/dist/cjs/api/users.js +5 -4
  10. package/dist/cjs/i18n/locales/compact/es-ES.generated.js +1 -1
  11. package/dist/cjs/i18n/locales/en-US.js +40 -15
  12. package/dist/cjs/i18n/locales/es-ES.js +40 -15
  13. package/dist/esm/api/apps.js +1 -1
  14. package/dist/esm/api/auth.js +1 -1
  15. package/dist/esm/api/billing.js +4 -3
  16. package/dist/esm/api/devices.js +5 -4
  17. package/dist/esm/api/follows.js +11 -10
  18. package/dist/esm/api/privacy.js +8 -7
  19. package/dist/esm/api/session.js +10 -7
  20. package/dist/esm/api/topics.js +4 -3
  21. package/dist/esm/api/users.js +5 -4
  22. package/dist/esm/i18n/locales/compact/es-ES.generated.js +1 -1
  23. package/dist/esm/i18n/locales/en-US.js +40 -15
  24. package/dist/esm/i18n/locales/es-ES.js +40 -15
  25. package/dist/types/i18n/locales/en-US.d.ts +37 -12
  26. package/dist/types/i18n/locales/es-ES.d.ts +37 -12
  27. package/package.json +2 -2
  28. package/src/api/apps.ts +1 -1
  29. package/src/api/auth.ts +9 -4
  30. package/src/api/billing.ts +12 -5
  31. package/src/api/devices.ts +6 -4
  32. package/src/api/follows.ts +12 -10
  33. package/src/api/privacy.ts +9 -7
  34. package/src/api/session.ts +18 -9
  35. package/src/api/topics.ts +5 -3
  36. package/src/api/users.ts +6 -4
  37. package/src/i18n/locales/compact/es-ES.generated.ts +1 -1
  38. package/src/i18n/locales/en-US.ts +41 -15
  39. package/src/i18n/locales/es-ES.ts +42 -15
@@ -85,7 +85,7 @@ class ConnectedAppsApi {
85
85
  * `ConnectedApp.applicationId`, NOT a credential/client id).
86
86
  */
87
87
  async revoke(applicationId) {
88
- await this.ctx.request('DELETE', `/auth/grants/${applicationId}`, undefined, { cache: false });
88
+ await this.ctx.request('DELETE', `/auth/grants/${enc(applicationId)}`, undefined, { cache: false });
89
89
  this.ctx.oxy.cache.delete('GET:/auth/grants');
90
90
  }
91
91
  /** Resource-bound external MCP connections for the active Oxy account. */
@@ -974,7 +974,7 @@ class AuthApi {
974
974
  */
975
975
  async checkUsername(username) {
976
976
  // Public availability lookup (pre-session) — skip the bearer preflight.
977
- return this.ctx.request('GET', `/auth/check-username/${username}`, undefined, {
977
+ return this.ctx.request('GET', `/auth/check-username/${encodeURIComponent(username)}`, undefined, {
978
978
  cache: false,
979
979
  skipAuth: true,
980
980
  });
@@ -13,6 +13,7 @@
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.BillingApi = void 0;
15
15
  const client_1 = require("@oxy.so/contracts/client");
16
+ const enc = encodeURIComponent;
16
17
  const SUBSCRIPTION_TTL = 2 * 60 * 1000;
17
18
  const WALLET_TTL = 60 * 1000;
18
19
  class BillingApi {
@@ -76,7 +77,7 @@ class BillingApi {
76
77
  /** A user's subscription (default: the signed-in user's). */
77
78
  async subscription(userId) {
78
79
  const id = this.resolveUserId(userId);
79
- return this.ctx.request('GET', `/subscription/${id}`, undefined, {
80
+ return this.ctx.request('GET', `/subscription/${enc(id)}`, undefined, {
80
81
  cache: true,
81
82
  cacheTTL: SUBSCRIPTION_TTL,
82
83
  });
@@ -84,7 +85,7 @@ class BillingApi {
84
85
  /** A user's wallet (default: the signed-in user's). Cached briefly: the balance moves. */
85
86
  async wallet(userId) {
86
87
  const id = this.resolveUserId(userId);
87
- return this.ctx.request('GET', `/wallet/${id}`, undefined, {
88
+ return this.ctx.request('GET', `/wallet/${enc(id)}`, undefined, {
88
89
  cache: true,
89
90
  cacheTTL: WALLET_TTL,
90
91
  });
@@ -97,7 +98,7 @@ class BillingApi {
97
98
  params.limit = options.limit;
98
99
  if (options.offset)
99
100
  params.offset = options.offset;
100
- return this.ctx.request('GET', `/wallet/transactions/${id}`, params, {
101
+ return this.ctx.request('GET', `/wallet/transactions/${enc(id)}`, params, {
101
102
  cache: false,
102
103
  });
103
104
  }
@@ -4,6 +4,7 @@ exports.DevicesApi = exports.AccountNotOnDeviceError = void 0;
4
4
  const client_1 = require("@oxy.so/contracts/client");
5
5
  const logger_1 = require("../logger");
6
6
  const errorUtils_1 = require("../utils/errorUtils");
7
+ const enc = encodeURIComponent;
7
8
  /**
8
9
  * The server's `401 account_not_on_device` for a PINNED mint: the requested
9
10
  * `accountId` is not (or is no longer) a live account of this device session.
@@ -75,7 +76,7 @@ class DevicesApi {
75
76
  * @param deviceId - The device ID to remove
76
77
  */
77
78
  async remove(deviceId) {
78
- await this.ctx.request('DELETE', `/devices/${deviceId}`, undefined, { cache: false });
79
+ await this.ctx.request('DELETE', `/devices/${enc(deviceId)}`, undefined, { cache: false });
79
80
  }
80
81
  /**
81
82
  * Get device sessions for a given session ID
@@ -85,7 +86,7 @@ class DevicesApi {
85
86
  */
86
87
  async sessions(sessionId) {
87
88
  // Cache disabled by default to ensure fresh session data
88
- return this.ctx.request('GET', `/session/device/sessions/${sessionId}`, undefined, {
89
+ return this.ctx.request('GET', `/session/device/sessions/${enc(sessionId)}`, undefined, {
89
90
  cache: false, // Don't cache sessions - always get fresh data
90
91
  deduplicate: true, // Deduplicate concurrent requests for same sessionId
91
92
  });
@@ -103,7 +104,7 @@ class DevicesApi {
103
104
  urlParams.deviceId = deviceId;
104
105
  if (excludeCurrent)
105
106
  urlParams.excludeCurrent = 'true';
106
- return this.ctx.request('POST', `/session/device/logout-all/${sessionId}`, urlParams, { cache: false });
107
+ return this.ctx.request('POST', `/session/device/logout-all/${enc(sessionId)}`, urlParams, { cache: false });
107
108
  }
108
109
  /**
109
110
  * Update device name
@@ -112,7 +113,7 @@ class DevicesApi {
112
113
  * @returns Updated device object
113
114
  */
114
115
  async rename(sessionId, deviceName) {
115
- return this.ctx.request('PUT', `/session/device/name/${sessionId}`, { deviceName }, { cache: false });
116
+ return this.ctx.request('PUT', `/session/device/name/${enc(sessionId)}`, { deviceName }, { cache: false });
116
117
  }
117
118
  /**
118
119
  * Get security information
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FollowsApi = void 0;
4
4
  const apiUtils_1 = require("../utils/apiUtils");
5
+ const enc = encodeURIComponent;
5
6
  const GRAPH_TTL = 2 * 60 * 1000;
6
7
  const STATUS_TTL = 60 * 1000;
7
8
  /**
@@ -16,7 +17,7 @@ class FollowsApi {
16
17
  // ── People ───────────────────────────────────────────────────────────────
17
18
  /** Follow a user. */
18
19
  async follow(userId) {
19
- const result = await this.ctx.request('POST', `/users/${userId}/follow`, undefined, { cache: false });
20
+ const result = await this.ctx.request('POST', `/users/${enc(userId)}/follow`, undefined, { cache: false });
20
21
  this.invalidate([userId]);
21
22
  return result;
22
23
  }
@@ -30,7 +31,7 @@ class FollowsApi {
30
31
  }
31
32
  /** Unfollow a user. */
32
33
  async unfollow(userId) {
33
- const result = await this.ctx.request('DELETE', `/users/${userId}/follow`, undefined, { cache: false });
34
+ const result = await this.ctx.request('DELETE', `/users/${enc(userId)}/follow`, undefined, { cache: false });
34
35
  this.invalidate([userId]);
35
36
  return result;
36
37
  }
@@ -44,7 +45,7 @@ class FollowsApi {
44
45
  }
45
46
  /** Whether the signed-in user follows `userId`. Cached 1 minute, busted by every write. */
46
47
  async status(userId) {
47
- return this.ctx.request('GET', `/users/${userId}/follow-status`, undefined, {
48
+ return this.ctx.request('GET', `/users/${enc(userId)}/follow-status`, undefined, {
48
49
  cache: true,
49
50
  cacheTTL: STATUS_TTL,
50
51
  });
@@ -74,12 +75,12 @@ class FollowsApi {
74
75
  * `limit`/`offset`/`sort` combination is its own cache entry (2 minutes).
75
76
  */
76
77
  async followers(userId, params) {
77
- const { data, total, hasMore } = await this.userPage(`/users/${userId}/followers`, params);
78
+ const { data, total, hasMore } = await this.userPage(`/users/${enc(userId)}/followers`, params);
78
79
  return { followers: data, total, hasMore };
79
80
  }
80
81
  /** Who a user follows. `sort` as in `followers`. */
81
82
  async following(userId, params) {
82
- const { data, total, hasMore } = await this.userPage(`/users/${userId}/following`, params);
83
+ const { data, total, hasMore } = await this.userPage(`/users/${enc(userId)}/following`, params);
83
84
  return { following: data, total, hasMore };
84
85
  }
85
86
  /**
@@ -87,7 +88,7 @@ class FollowsApi {
87
88
  * `userId`.
88
89
  */
89
90
  async mutuals(userId, params) {
90
- const { data, total, hasMore } = await this.userPage(`/users/${userId}/mutuals`, params);
91
+ const { data, total, hasMore } = await this.userPage(`/users/${enc(userId)}/mutuals`, params);
91
92
  return { mutuals: data, total, hasMore };
92
93
  }
93
94
  /**
@@ -222,16 +223,16 @@ class FollowsApi {
222
223
  const keys = ['GET:/users/me/graph'];
223
224
  const prefixes = ['GET:/profiles/username/', 'GET:/profiles/resolve'];
224
225
  for (const id of targetUserIds) {
225
- keys.push(`GET:/users/${id}/follow-status`);
226
+ keys.push(`GET:/users/${enc(id)}/follow-status`);
226
227
  // Profiles embed the viewer-relative `relationship`.
227
- keys.push(`GET:/users/${id}`);
228
+ keys.push(`GET:/users/${enc(id)}`);
228
229
  // The target gained or lost a follower, and "followers you know" with it.
229
- prefixes.push(`GET:/users/${id}/followers`, `GET:/users/${id}/mutuals`);
230
+ prefixes.push(`GET:/users/${enc(id)}/followers`, `GET:/users/${enc(id)}/mutuals`);
230
231
  }
231
232
  // The viewer's own following list changed.
232
233
  const viewerId = this.ctx.oxy.session.userId;
233
234
  if (viewerId)
234
- prefixes.push(`GET:/users/${viewerId}/following`);
235
+ prefixes.push(`GET:/users/${enc(viewerId)}/following`);
235
236
  this.ctx.http.invalidateCache({ keys, prefixes });
236
237
  }
237
238
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PrivacyApi = void 0;
4
4
  const identityCacheSweep_1 = require("../utils/identityCacheSweep");
5
+ const enc = encodeURIComponent;
5
6
  const LIST_TTL = 60 * 1000;
6
7
  const SETTINGS_TTL = 2 * 60 * 1000;
7
8
  const refId = (ref) => (typeof ref === 'string' ? ref : ref._id);
@@ -13,7 +14,7 @@ class PrivacyApi {
13
14
  /** A user's privacy settings (default: the signed-in user's). */
14
15
  async settings(userId) {
15
16
  const id = await this.resolveUserId(userId);
16
- return this.ctx.request('GET', `/privacy/${id}/privacy`, undefined, {
17
+ return this.ctx.request('GET', `/privacy/${enc(id)}/privacy`, undefined, {
17
18
  cache: true,
18
19
  cacheTTL: SETTINGS_TTL,
19
20
  });
@@ -21,10 +22,10 @@ class PrivacyApi {
21
22
  /** Update privacy settings (default: the signed-in user's). */
22
23
  async updateSettings(settings, userId) {
23
24
  const id = await this.resolveUserId(userId);
24
- const res = await this.ctx.request('PATCH', `/privacy/${id}/privacy`, settings, { cache: false });
25
+ const res = await this.ctx.request('PATCH', `/privacy/${enc(id)}/privacy`, settings, { cache: false });
25
26
  // Privacy settings ride the user DTO, so every identity read goes stale too.
26
27
  (0, identityCacheSweep_1.evictOxyIdentityCache)(this.ctx.http, id);
27
- this.ctx.oxy.cache.delete(`GET:/privacy/${id}/privacy`);
28
+ this.ctx.oxy.cache.delete(`GET:/privacy/${enc(id)}/privacy`);
28
29
  return res;
29
30
  }
30
31
  // ── Blocked ──────────────────────────────────────────────────────────────
@@ -38,14 +39,14 @@ class PrivacyApi {
38
39
  /** Block a user. */
39
40
  async block(userId) {
40
41
  requireId(userId);
41
- const res = await this.ctx.request('POST', `/privacy/blocked/${userId}`, undefined, { cache: false });
42
+ const res = await this.ctx.request('POST', `/privacy/blocked/${enc(userId)}`, undefined, { cache: false });
42
43
  this.invalidate('GET:/privacy/blocked');
43
44
  return res;
44
45
  }
45
46
  /** Unblock a user. */
46
47
  async unblock(userId) {
47
48
  requireId(userId);
48
- const res = await this.ctx.request('DELETE', `/privacy/blocked/${userId}`, undefined, { cache: false });
49
+ const res = await this.ctx.request('DELETE', `/privacy/blocked/${enc(userId)}`, undefined, { cache: false });
49
50
  this.invalidate('GET:/privacy/blocked');
50
51
  return res;
51
52
  }
@@ -71,14 +72,14 @@ class PrivacyApi {
71
72
  /** Restrict a user: limit their interactions without blocking them. */
72
73
  async restrict(userId) {
73
74
  requireId(userId);
74
- const res = await this.ctx.request('POST', `/privacy/restricted/${userId}`, undefined, { cache: false });
75
+ const res = await this.ctx.request('POST', `/privacy/restricted/${enc(userId)}`, undefined, { cache: false });
75
76
  this.invalidate('GET:/privacy/restricted');
76
77
  return res;
77
78
  }
78
79
  /** Lift a restriction. */
79
80
  async unrestrict(userId) {
80
81
  requireId(userId);
81
- const res = await this.ctx.request('DELETE', `/privacy/restricted/${userId}`, undefined, { cache: false });
82
+ const res = await this.ctx.request('DELETE', `/privacy/restricted/${enc(userId)}`, undefined, { cache: false });
82
83
  this.invalidate('GET:/privacy/restricted');
83
84
  return res;
84
85
  }
@@ -12,6 +12,7 @@ const jwt_decode_1 = require("jwt-decode");
12
12
  const userIdentity_1 = require("../utils/userIdentity");
13
13
  const OxyServices_errors_1 = require("../OxyServices.errors");
14
14
  const client_1 = require("@oxy.so/contracts/client");
15
+ const enc = encodeURIComponent;
15
16
  /** How long a refusal (disabled, rate limited, unreachable) is remembered per installation. */
16
17
  const EVIDENCE_REFUSAL_MS = 5000;
17
18
  const unavailable = (reason) => ({
@@ -293,7 +294,7 @@ class SessionApi {
293
294
  : {}),
294
295
  },
295
296
  })
296
- : await this.ctx.request('GET', `/session/validate/${sessionId}`, {
297
+ : await this.ctx.request('GET', `/session/validate/${enc(sessionId)}`, {
297
298
  ...(options.deviceFingerprint
298
299
  ? { deviceFingerprint: options.deviceFingerprint }
299
300
  : {}),
@@ -320,7 +321,7 @@ class SessionApi {
320
321
  const invalid = candidate?.status === 401 && candidate.code === 'OXY_LIVE_SESSION_INVALID_V1';
321
322
  const denied = candidate?.status === 403 && candidate.code === 'OXY_LIVE_SESSION_POLICY_V1';
322
323
  if (invalid)
323
- this.ctx.oxy.cache.delete(`GET:/session/user/${sessionId}`);
324
+ this.ctx.oxy.cache.delete(`GET:/session/user/${enc(sessionId)}`);
324
325
  if (invalid || denied)
325
326
  throw error;
326
327
  throw new OxyServices_errors_1.OxyApiError('Live session authority is unavailable', {
@@ -330,26 +331,28 @@ class SessionApi {
330
331
  });
331
332
  }
332
333
  // The session is gone: drop any user cached for it (#196).
333
- this.ctx.oxy.cache.delete(`GET:/session/user/${sessionId}`);
334
+ this.ctx.oxy.cache.delete(`GET:/session/user/${enc(sessionId)}`);
334
335
  throw error;
335
336
  }
336
337
  }
337
338
  /** The sessions that belong with `sessionId` (same account set). */
338
339
  async list(sessionId) {
339
- return this.ctx.request('GET', `/session/sessions/${sessionId}`, undefined, {
340
+ return this.ctx.request('GET', `/session/sessions/${enc(sessionId)}`, undefined, {
340
341
  cache: false,
341
342
  });
342
343
  }
343
344
  /** Sign out `sessionId`, or — with `targetSessionId` — one of the sessions beside it. */
344
345
  async logout(sessionId, targetSessionId) {
345
346
  const url = targetSessionId
346
- ? `/session/logout/${sessionId}/${targetSessionId}`
347
- : `/session/logout/${sessionId}`;
347
+ ? `/session/logout/${enc(sessionId)}/${enc(targetSessionId)}`
348
+ : `/session/logout/${enc(sessionId)}`;
348
349
  await this.ctx.request('POST', url, undefined, { cache: false });
349
350
  }
350
351
  /** Sign out the other sessions for this account; preserve `sessionId`. */
351
352
  async logoutAll(sessionId) {
352
- await this.ctx.request('POST', `/session/logout-all/${sessionId}`, undefined, { cache: false });
353
+ await this.ctx.request('POST', `/session/logout-all/${enc(sessionId)}`, undefined, {
354
+ cache: false,
355
+ });
353
356
  }
354
357
  /** Decoded claims of the current token, memoised per token string. */
355
358
  claims() {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TopicsApi = void 0;
4
+ const enc = encodeURIComponent;
4
5
  const SHORT = 60 * 1000;
5
6
  const LONG = 5 * 60 * 1000;
6
7
  const EXTRA_LONG = 30 * 60 * 1000;
@@ -44,7 +45,7 @@ class TopicsApi {
44
45
  }
45
46
  /** One topic by slug. */
46
47
  async get(slug) {
47
- return this.ctx.request('GET', `/topics/${slug}`, undefined, {
48
+ return this.ctx.request('GET', `/topics/${enc(slug)}`, undefined, {
48
49
  cache: true,
49
50
  cacheTTL: LONG,
50
51
  });
@@ -63,10 +64,10 @@ class TopicsApi {
63
64
  }
64
65
  /** Update a topic's description and translations. Staff or service only. */
65
66
  async update(slug, data) {
66
- const topic = await this.ctx.request('PATCH', `/topics/${slug}`, data, {
67
+ const topic = await this.ctx.request('PATCH', `/topics/${enc(slug)}`, data, {
67
68
  cache: false,
68
69
  });
69
- this.ctx.oxy.cache.delete(`GET:/topics/${slug}`);
70
+ this.ctx.oxy.cache.delete(`GET:/topics/${enc(slug)}`);
70
71
  return topic;
71
72
  }
72
73
  }
@@ -42,6 +42,7 @@ const accountCacheSweep_1 = require("../utils/accountCacheSweep");
42
42
  const errorUtils_1 = require("../utils/errorUtils");
43
43
  const batchLookup_1 = require("../utils/batchLookup");
44
44
  const logger_1 = require("../logger");
45
+ const enc = encodeURIComponent;
45
46
  const PROFILE_TTL = 5 * 60 * 1000;
46
47
  const SESSION_USER_TTL = 2 * 60 * 1000;
47
48
  const ME_TTL = 60 * 1000;
@@ -61,7 +62,7 @@ class UsersApi {
61
62
  * registry-fresh read that neither serves nor overwrites a cached entry.
62
63
  */
63
64
  async get(userId, options) {
64
- const user = await this.ctx.request('GET', `/users/${userId}`, undefined, {
65
+ const user = await this.ctx.request('GET', `/users/${enc(userId)}`, undefined, {
65
66
  cache: options?.cache ?? true,
66
67
  cacheTTL: PROFILE_TTL,
67
68
  });
@@ -143,7 +144,7 @@ class UsersApi {
143
144
  }
144
145
  /** The user a session belongs to. */
145
146
  async bySession(sessionId) {
146
- const user = await this.ctx.request('GET', `/session/user/${sessionId}`, undefined, {
147
+ const user = await this.ctx.request('GET', `/session/user/${enc(sessionId)}`, undefined, {
147
148
  cache: true,
148
149
  cacheTTL: SESSION_USER_TTL,
149
150
  });
@@ -219,7 +220,7 @@ class UsersApi {
219
220
  const pagination = typeof limitOrPagination === 'number'
220
221
  ? { limit: limitOrPagination }
221
222
  : (limitOrPagination ?? {});
222
- const users = await this.ctx.request('GET', `/profiles/${userId}/similar`, (0, apiUtils_1.buildQueryParams)(pagination), {
223
+ const users = await this.ctx.request('GET', `/profiles/${enc(userId)}/similar`, (0, apiUtils_1.buildQueryParams)(pagination), {
223
224
  cache: true,
224
225
  cacheTTL: PROFILE_TTL,
225
226
  });
@@ -231,7 +232,7 @@ class UsersApi {
231
232
  * account. Cached 5 minutes.
232
233
  */
233
234
  async moderators(communityId) {
234
- const moderators = await this.ctx.request('GET', `/users/${communityId}/moderators`, undefined, { cache: true, cacheTTL: PROFILE_TTL });
235
+ const moderators = await this.ctx.request('GET', `/users/${enc(communityId)}/moderators`, undefined, { cache: true, cacheTTL: PROFILE_TTL });
235
236
  return moderators.map((user) => (0, userIdentity_1.normalizeUserIdentity)(user));
236
237
  }
237
238
  /**