@oxy.so/core 7.12.0 → 7.13.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/api/apps.js +1 -1
- package/dist/cjs/api/auth.js +1 -1
- package/dist/cjs/api/billing.js +4 -3
- package/dist/cjs/api/devices.js +5 -4
- package/dist/cjs/api/follows.js +12 -10
- package/dist/cjs/api/privacy.js +8 -7
- package/dist/cjs/api/session.js +10 -7
- package/dist/cjs/api/topics.js +4 -3
- package/dist/cjs/api/users.js +5 -4
- package/dist/cjs/i18n/locales/compact/es-ES.generated.js +1 -1
- package/dist/cjs/i18n/locales/en-US.js +38 -15
- package/dist/cjs/i18n/locales/es-ES.js +38 -15
- package/dist/cjs/utils/identityCacheSweep.js +9 -1
- package/dist/esm/api/apps.js +1 -1
- package/dist/esm/api/auth.js +1 -1
- package/dist/esm/api/billing.js +4 -3
- package/dist/esm/api/devices.js +5 -4
- package/dist/esm/api/follows.js +12 -10
- package/dist/esm/api/privacy.js +8 -7
- package/dist/esm/api/session.js +10 -7
- package/dist/esm/api/topics.js +4 -3
- package/dist/esm/api/users.js +6 -5
- package/dist/esm/i18n/locales/compact/es-ES.generated.js +1 -1
- package/dist/esm/i18n/locales/en-US.js +38 -15
- package/dist/esm/i18n/locales/es-ES.js +38 -15
- package/dist/esm/utils/identityCacheSweep.js +8 -1
- package/dist/types/i18n/locales/en-US.d.ts +35 -12
- package/dist/types/i18n/locales/es-ES.d.ts +35 -12
- package/dist/types/utils/identityCacheSweep.d.ts +5 -0
- package/package.json +2 -2
- package/src/api/apps.ts +1 -1
- package/src/api/auth.ts +9 -4
- package/src/api/billing.ts +12 -5
- package/src/api/devices.ts +6 -4
- package/src/api/follows.ts +21 -10
- package/src/api/privacy.ts +9 -7
- package/src/api/session.ts +18 -9
- package/src/api/topics.ts +5 -3
- package/src/api/users.ts +11 -5
- package/src/i18n/locales/compact/es-ES.generated.ts +1 -1
- package/src/i18n/locales/en-US.ts +39 -15
- package/src/i18n/locales/es-ES.ts +40 -15
- package/src/utils/identityCacheSweep.ts +9 -1
|
@@ -163,6 +163,9 @@ const dict = {
|
|
|
163
163
|
requestExpired: 'This sign-in expired. Send a new email.',
|
|
164
164
|
secondFactorInvalid: "That code isn't right. Try the current one.",
|
|
165
165
|
originNotAllowed: "Sign-in isn't available here.",
|
|
166
|
+
network: "Couldn't reach Oxy. Check your connection and try again.",
|
|
167
|
+
invalidInput: "Something you entered isn't valid. Check it and try again.",
|
|
168
|
+
server: "Oxy couldn't finish this right now. Try again in a moment.",
|
|
166
169
|
generic: 'Something went wrong. Please try again.',
|
|
167
170
|
},
|
|
168
171
|
subtitleToApp: 'to continue to {{app}}',
|
|
@@ -225,6 +228,31 @@ const dict = {
|
|
|
225
228
|
invalidDescription: 'It expired or was already used. Ask for a new email in the app, or type the code from the latest one.',
|
|
226
229
|
},
|
|
227
230
|
},
|
|
231
|
+
actionErrors: {
|
|
232
|
+
updateProfile: "Couldn't update your profile. Please try again.",
|
|
233
|
+
uploadAvatar: "Couldn't upload the picture. Please try again.",
|
|
234
|
+
updateSettings: "Couldn't save your settings. Please try again.",
|
|
235
|
+
updatePrivacy: "Couldn't save your privacy settings. Please try again.",
|
|
236
|
+
updateNotifications: "Couldn't save your notification preferences. Please try again.",
|
|
237
|
+
updatePreferences: "Couldn't save your preferences. Please try again.",
|
|
238
|
+
revokeConnectedApp: "Couldn't disconnect the app. Please try again.",
|
|
239
|
+
switchSession: "Couldn't switch accounts. Please try again.",
|
|
240
|
+
logout: "Couldn't sign out. Please try again.",
|
|
241
|
+
logoutAll: "Couldn't sign out everywhere. Please try again.",
|
|
242
|
+
updateDeviceName: "Couldn't rename the device. Please try again.",
|
|
243
|
+
removeDevice: "Couldn't remove the device. Please try again.",
|
|
244
|
+
},
|
|
245
|
+
usernamePolicy: {
|
|
246
|
+
hint: 'Letters, numbers, - and _. No spaces.',
|
|
247
|
+
required: 'Choose a username.',
|
|
248
|
+
tooShort: 'Use at least {{min}} characters.',
|
|
249
|
+
tooLong: 'Use at most {{max}} characters.',
|
|
250
|
+
noSpaces: "Usernames can't contain spaces. Use - or _ instead.",
|
|
251
|
+
characters: 'Use only letters, numbers, - and _. Start and end with a letter or number, and never put two of - or _ together.',
|
|
252
|
+
onlyNumbers: "A username can't be only numbers. Add a letter.",
|
|
253
|
+
reserved: 'That username is reserved. Choose another one.',
|
|
254
|
+
mustEndInBot: 'A bot account’s username must end in “bot”.',
|
|
255
|
+
},
|
|
228
256
|
signup: {
|
|
229
257
|
title: 'Create your account',
|
|
230
258
|
subtitle: 'Choose your username. Then we confirm your email.',
|
|
@@ -233,7 +261,6 @@ const dict = {
|
|
|
233
261
|
username: {
|
|
234
262
|
label: 'Username',
|
|
235
263
|
placeholder: 'yourname',
|
|
236
|
-
required: 'Choose a username.',
|
|
237
264
|
taken: 'That username is taken.',
|
|
238
265
|
},
|
|
239
266
|
email: {
|
|
@@ -281,7 +308,6 @@ const dict = {
|
|
|
281
308
|
firstPlaceholder: 'Your first name',
|
|
282
309
|
lastLabel: 'Last name',
|
|
283
310
|
lastPlaceholder: 'Your last name',
|
|
284
|
-
saveFailed: 'Could not save your name',
|
|
285
311
|
},
|
|
286
312
|
avatar: {
|
|
287
313
|
title: 'Make It Yours',
|
|
@@ -604,8 +630,6 @@ const dict = {
|
|
|
604
630
|
label: 'Username',
|
|
605
631
|
placeholder: 'Choose a username',
|
|
606
632
|
choose: 'Choose a username',
|
|
607
|
-
required: 'Username is required',
|
|
608
|
-
tooShort: 'Username must be at least 3 characters',
|
|
609
633
|
},
|
|
610
634
|
email: {
|
|
611
635
|
title: 'Email',
|
|
@@ -1260,7 +1284,7 @@ const dict = {
|
|
|
1260
1284
|
},
|
|
1261
1285
|
rules: {
|
|
1262
1286
|
title: 'Username rules',
|
|
1263
|
-
content: 'Usernames
|
|
1287
|
+
content: 'Usernames are 3 to 30 characters long and use letters, numbers, hyphens (-) and underscores (_). They start and end with a letter or number, never put two of - or _ together, and are not only numbers. Spaces are not allowed. Capital letters are kept as you type them, but Alice and alice are the same username.',
|
|
1264
1288
|
},
|
|
1265
1289
|
unique: {
|
|
1266
1290
|
title: 'Why must it be unique?',
|
|
@@ -1839,9 +1863,6 @@ const dict = {
|
|
|
1839
1863
|
label: 'Username',
|
|
1840
1864
|
available: 'Username is available',
|
|
1841
1865
|
taken: 'Username is taken',
|
|
1842
|
-
tooShort: 'Username must be at least 3 characters',
|
|
1843
|
-
invalidChars: 'Only letters, numbers, hyphens, and underscores',
|
|
1844
|
-
mustEndInBot: 'A bot account’s username must end in “bot”',
|
|
1845
1866
|
checkFailed: 'Could not check availability',
|
|
1846
1867
|
},
|
|
1847
1868
|
accountCategory: {
|
|
@@ -1876,16 +1897,15 @@ const dict = {
|
|
|
1876
1897
|
transfer: 'Transfer ownership',
|
|
1877
1898
|
},
|
|
1878
1899
|
errors: {
|
|
1879
|
-
|
|
1900
|
+
emailInvalid: 'Enter a valid email address, like name@example.com.',
|
|
1880
1901
|
missingAccount: 'No account selected.',
|
|
1881
1902
|
noPermission: 'You do not have permission to view members.',
|
|
1882
|
-
userNotFound: 'User not found',
|
|
1883
1903
|
},
|
|
1884
1904
|
invite: {
|
|
1885
|
-
title: '
|
|
1886
|
-
|
|
1905
|
+
title: 'Invite a member',
|
|
1906
|
+
emailLabel: 'Email',
|
|
1887
1907
|
roleLabel: 'Role',
|
|
1888
|
-
submit: '
|
|
1908
|
+
submit: 'Send invitation',
|
|
1889
1909
|
},
|
|
1890
1910
|
removeConfirm: {
|
|
1891
1911
|
title: 'Remove member',
|
|
@@ -1896,8 +1916,9 @@ const dict = {
|
|
|
1896
1916
|
description: 'Transfer ownership of this account to this member? You will be demoted to admin. This cannot be undone.',
|
|
1897
1917
|
},
|
|
1898
1918
|
toasts: {
|
|
1899
|
-
|
|
1900
|
-
|
|
1919
|
+
invited: 'Invitation sent',
|
|
1920
|
+
inviteFailed: "Couldn't send the invitation. Please try again.",
|
|
1921
|
+
invitationUpdateFailed: "Couldn't update the invitation. Please try again.",
|
|
1901
1922
|
removed: 'Member removed',
|
|
1902
1923
|
removeFailed: 'Failed to remove member',
|
|
1903
1924
|
roleUpdated: 'Role updated',
|
|
@@ -1959,6 +1980,7 @@ const dict = {
|
|
|
1959
1980
|
title: 'Delete Account',
|
|
1960
1981
|
warning: 'This action cannot be undone. Your account and all associated data will be permanently deleted.',
|
|
1961
1982
|
confirmLabel: 'Type "{{username}}" to confirm',
|
|
1983
|
+
confirmMismatch: 'That isn\'t your username. Type "{{username}}" exactly.',
|
|
1962
1984
|
confirm: 'Delete Forever',
|
|
1963
1985
|
error: 'Failed to delete account',
|
|
1964
1986
|
handoff: {
|
|
@@ -2373,6 +2395,7 @@ const dict = {
|
|
|
2373
2395
|
request: "Couldn't start the verification. Check the domain and try again.",
|
|
2374
2396
|
notYet: 'Not verified yet. Changes to DNS can take a while to show up.',
|
|
2375
2397
|
remove: "Couldn't remove the domain",
|
|
2398
|
+
invalid: 'Enter just the domain, like example.com — no https://, slashes or spaces.',
|
|
2376
2399
|
},
|
|
2377
2400
|
remove: {
|
|
2378
2401
|
title: 'Remove domain',
|
|
@@ -163,6 +163,9 @@ const dict = {
|
|
|
163
163
|
requestExpired: 'Este inicio de sesión ha caducado. Envía un email nuevo.',
|
|
164
164
|
secondFactorInvalid: 'Ese código no es correcto. Prueba con el actual.',
|
|
165
165
|
originNotAllowed: 'Aquí no se puede iniciar sesión.',
|
|
166
|
+
network: 'No se ha podido conectar con Oxy. Comprueba tu conexión e inténtalo de nuevo.',
|
|
167
|
+
invalidInput: 'Algo de lo que has escrito no es válido. Revísalo e inténtalo de nuevo.',
|
|
168
|
+
server: 'Oxy no ha podido terminar esto ahora. Inténtalo de nuevo en un momento.',
|
|
166
169
|
generic: 'Algo ha ido mal. Inténtalo de nuevo.',
|
|
167
170
|
},
|
|
168
171
|
subtitleToApp: 'para continuar en {{app}}',
|
|
@@ -225,6 +228,31 @@ const dict = {
|
|
|
225
228
|
invalidDescription: 'Ha caducado o ya se ha usado. Pide un email nuevo en la app o escribe el código del último.',
|
|
226
229
|
},
|
|
227
230
|
},
|
|
231
|
+
actionErrors: {
|
|
232
|
+
updateProfile: 'No se ha podido actualizar tu perfil. Inténtalo de nuevo.',
|
|
233
|
+
uploadAvatar: 'No se ha podido subir la foto. Inténtalo de nuevo.',
|
|
234
|
+
updateSettings: 'No se han podido guardar tus ajustes. Inténtalo de nuevo.',
|
|
235
|
+
updatePrivacy: 'No se han podido guardar tus ajustes de privacidad. Inténtalo de nuevo.',
|
|
236
|
+
updateNotifications: 'No se han podido guardar tus preferencias de notificaciones. Inténtalo de nuevo.',
|
|
237
|
+
updatePreferences: 'No se han podido guardar tus preferencias. Inténtalo de nuevo.',
|
|
238
|
+
revokeConnectedApp: 'No se ha podido desconectar la app. Inténtalo de nuevo.',
|
|
239
|
+
switchSession: 'No se ha podido cambiar de cuenta. Inténtalo de nuevo.',
|
|
240
|
+
logout: 'No se ha podido cerrar la sesión. Inténtalo de nuevo.',
|
|
241
|
+
logoutAll: 'No se ha podido cerrar la sesión en todas partes. Inténtalo de nuevo.',
|
|
242
|
+
updateDeviceName: 'No se ha podido cambiar el nombre del dispositivo. Inténtalo de nuevo.',
|
|
243
|
+
removeDevice: 'No se ha podido quitar el dispositivo. Inténtalo de nuevo.',
|
|
244
|
+
},
|
|
245
|
+
usernamePolicy: {
|
|
246
|
+
hint: 'Letras, números, - y _. Sin espacios.',
|
|
247
|
+
required: 'Elige un nombre de usuario.',
|
|
248
|
+
tooShort: 'Usa al menos {{min}} caracteres.',
|
|
249
|
+
tooLong: 'Usa como máximo {{max}} caracteres.',
|
|
250
|
+
noSpaces: 'El nombre de usuario no puede tener espacios. Usa - o _ en su lugar.',
|
|
251
|
+
characters: 'Usa solo letras, números, - y _. Empieza y termina con una letra o un número, y no pongas dos - o _ seguidos.',
|
|
252
|
+
onlyNumbers: 'El nombre de usuario no puede ser solo números. Añade una letra.',
|
|
253
|
+
reserved: 'Ese nombre de usuario está reservado. Elige otro.',
|
|
254
|
+
mustEndInBot: 'El nombre de usuario de una cuenta bot debe terminar en «bot».',
|
|
255
|
+
},
|
|
228
256
|
signup: {
|
|
229
257
|
title: 'Crea tu cuenta',
|
|
230
258
|
subtitle: 'Elige tu nombre de usuario. Después confirmamos tu email.',
|
|
@@ -233,7 +261,6 @@ const dict = {
|
|
|
233
261
|
username: {
|
|
234
262
|
label: 'Nombre de usuario',
|
|
235
263
|
placeholder: 'tunombre',
|
|
236
|
-
required: 'Elige un nombre de usuario.',
|
|
237
264
|
taken: 'Ese nombre de usuario ya está en uso.',
|
|
238
265
|
},
|
|
239
266
|
email: {
|
|
@@ -305,8 +332,6 @@ const dict = {
|
|
|
305
332
|
label: 'Usuario',
|
|
306
333
|
placeholder: 'Elige un usuario',
|
|
307
334
|
choose: 'Elige un usuario',
|
|
308
|
-
required: 'El usuario es obligatorio',
|
|
309
|
-
tooShort: 'El usuario debe tener al menos 3 caracteres',
|
|
310
335
|
},
|
|
311
336
|
email: {
|
|
312
337
|
title: 'Correo electrónico',
|
|
@@ -904,7 +929,6 @@ const dict = {
|
|
|
904
929
|
firstPlaceholder: 'Tu nombre',
|
|
905
930
|
lastLabel: 'Apellidos',
|
|
906
931
|
lastPlaceholder: 'Tus apellidos',
|
|
907
|
-
saveFailed: 'No se pudo guardar tu nombre',
|
|
908
932
|
},
|
|
909
933
|
avatar: {
|
|
910
934
|
title: 'Hazlo tuyo',
|
|
@@ -1260,7 +1284,7 @@ const dict = {
|
|
|
1260
1284
|
},
|
|
1261
1285
|
rules: {
|
|
1262
1286
|
title: 'Reglas del nombre de usuario',
|
|
1263
|
-
content: 'Los nombres de usuario
|
|
1287
|
+
content: 'Los nombres de usuario tienen entre 3 y 30 caracteres y usan letras, números, guiones (-) y guiones bajos (_). Empiezan y terminan con una letra o un número, nunca llevan dos - o _ seguidos y no son solo números. No se permiten espacios. Las mayúsculas se guardan tal como las escribes, pero Alicia y alicia son el mismo nombre de usuario.',
|
|
1264
1288
|
},
|
|
1265
1289
|
unique: {
|
|
1266
1290
|
title: '¿Por qué debe ser único?',
|
|
@@ -1839,9 +1863,6 @@ const dict = {
|
|
|
1839
1863
|
label: 'Nombre de usuario',
|
|
1840
1864
|
available: 'El nombre de usuario está disponible',
|
|
1841
1865
|
taken: 'El nombre de usuario ya está en uso',
|
|
1842
|
-
tooShort: 'El nombre de usuario debe tener al menos 3 caracteres',
|
|
1843
|
-
invalidChars: 'Solo letras, números, guiones y guiones bajos',
|
|
1844
|
-
mustEndInBot: 'El nombre de usuario de una cuenta de bot debe terminar en “bot”',
|
|
1845
1866
|
checkFailed: 'No se pudo comprobar la disponibilidad',
|
|
1846
1867
|
},
|
|
1847
1868
|
accountCategory: {
|
|
@@ -1876,16 +1897,15 @@ const dict = {
|
|
|
1876
1897
|
transfer: 'Transferir propiedad',
|
|
1877
1898
|
},
|
|
1878
1899
|
errors: {
|
|
1879
|
-
|
|
1900
|
+
emailInvalid: 'Introduce un email válido, como nombre@ejemplo.com.',
|
|
1880
1901
|
missingAccount: 'Ninguna cuenta seleccionada.',
|
|
1881
1902
|
noPermission: 'No tienes permiso para ver los miembros.',
|
|
1882
|
-
userNotFound: 'Usuario no encontrado',
|
|
1883
1903
|
},
|
|
1884
1904
|
invite: {
|
|
1885
|
-
title: '
|
|
1886
|
-
|
|
1905
|
+
title: 'Invitar a un miembro',
|
|
1906
|
+
emailLabel: 'Email',
|
|
1887
1907
|
roleLabel: 'Rol',
|
|
1888
|
-
submit: '
|
|
1908
|
+
submit: 'Enviar invitación',
|
|
1889
1909
|
},
|
|
1890
1910
|
removeConfirm: {
|
|
1891
1911
|
title: 'Eliminar miembro',
|
|
@@ -1896,8 +1916,9 @@ const dict = {
|
|
|
1896
1916
|
description: '¿Transferir la propiedad de esta cuenta a este miembro? Pasarás a ser administrador. Esto no se puede deshacer.',
|
|
1897
1917
|
},
|
|
1898
1918
|
toasts: {
|
|
1899
|
-
|
|
1900
|
-
|
|
1919
|
+
invited: 'Invitación enviada',
|
|
1920
|
+
inviteFailed: 'No se ha podido enviar la invitación. Inténtalo de nuevo.',
|
|
1921
|
+
invitationUpdateFailed: 'No se ha podido actualizar la invitación. Inténtalo de nuevo.',
|
|
1901
1922
|
removed: 'Miembro eliminado',
|
|
1902
1923
|
removeFailed: 'No se pudo eliminar el miembro',
|
|
1903
1924
|
roleUpdated: 'Rol actualizado',
|
|
@@ -1959,6 +1980,7 @@ const dict = {
|
|
|
1959
1980
|
title: 'Eliminar cuenta',
|
|
1960
1981
|
warning: 'Esta acción no se puede deshacer. Tu cuenta y todos los datos asociados se eliminarán de forma permanente.',
|
|
1961
1982
|
confirmLabel: 'Escribe "{{username}}" para confirmar',
|
|
1983
|
+
confirmMismatch: 'Ese no es tu nombre de usuario. Escribe "{{username}}" exactamente.',
|
|
1962
1984
|
confirm: 'Eliminar para siempre',
|
|
1963
1985
|
error: 'No se pudo eliminar la cuenta',
|
|
1964
1986
|
handoff: {
|
|
@@ -2373,6 +2395,7 @@ const dict = {
|
|
|
2373
2395
|
request: 'No se pudo empezar la verificación. Revisa el dominio e inténtalo otra vez.',
|
|
2374
2396
|
notYet: 'Aún no está verificado. Los cambios de DNS pueden tardar en aparecer.',
|
|
2375
2397
|
remove: 'No se pudo quitar el dominio',
|
|
2398
|
+
invalid: 'Escribe solo el dominio, como ejemplo.com, sin https://, barras ni espacios.',
|
|
2376
2399
|
},
|
|
2377
2400
|
remove: {
|
|
2378
2401
|
title: 'Quitar dominio',
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
*/
|
|
54
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
55
|
exports.OXY_IDENTITY_CACHE_PREFIXES = void 0;
|
|
56
|
+
exports.oxyUserByIdPath = oxyUserByIdPath;
|
|
56
57
|
exports.oxyUserByIdCacheKey = oxyUserByIdCacheKey;
|
|
57
58
|
exports.evictOxyIdentityCache = evictOxyIdentityCache;
|
|
58
59
|
/**
|
|
@@ -69,12 +70,19 @@ exports.OXY_IDENTITY_CACHE_PREFIXES = [
|
|
|
69
70
|
// `resolveProfile` — keyed by fediverse handle in the query payload.
|
|
70
71
|
'GET:/profiles/resolve',
|
|
71
72
|
];
|
|
73
|
+
/**
|
|
74
|
+
* The path `getUserById` reads, its id encoded. Built in one place so the
|
|
75
|
+
* request and every key that evicts it cannot spell the id differently.
|
|
76
|
+
*/
|
|
77
|
+
function oxyUserByIdPath(userId) {
|
|
78
|
+
return `/users/${encodeURIComponent(userId)}`;
|
|
79
|
+
}
|
|
72
80
|
/**
|
|
73
81
|
* Build the exact cache key `getUserById` reads under. The only identity key
|
|
74
82
|
* derivable from a user id, so the only one that does not need a prefix sweep.
|
|
75
83
|
*/
|
|
76
84
|
function oxyUserByIdCacheKey(userId) {
|
|
77
|
-
return `GET
|
|
85
|
+
return `GET:${oxyUserByIdPath(userId)}`;
|
|
78
86
|
}
|
|
79
87
|
/**
|
|
80
88
|
* Sweep an `OxyServices` GET response cache of everything that could carry the
|
package/dist/esm/api/apps.js
CHANGED
|
@@ -81,7 +81,7 @@ export class ConnectedAppsApi {
|
|
|
81
81
|
* `ConnectedApp.applicationId`, NOT a credential/client id).
|
|
82
82
|
*/
|
|
83
83
|
async revoke(applicationId) {
|
|
84
|
-
await this.ctx.request('DELETE', `/auth/grants/${applicationId}`, undefined, { cache: false });
|
|
84
|
+
await this.ctx.request('DELETE', `/auth/grants/${enc(applicationId)}`, undefined, { cache: false });
|
|
85
85
|
this.ctx.oxy.cache.delete('GET:/auth/grants');
|
|
86
86
|
}
|
|
87
87
|
/** Resource-bound external MCP connections for the active Oxy account. */
|
package/dist/esm/api/auth.js
CHANGED
|
@@ -932,7 +932,7 @@ export class AuthApi {
|
|
|
932
932
|
*/
|
|
933
933
|
async checkUsername(username) {
|
|
934
934
|
// Public availability lookup (pre-session) — skip the bearer preflight.
|
|
935
|
-
return this.ctx.request('GET', `/auth/check-username/${username}`, undefined, {
|
|
935
|
+
return this.ctx.request('GET', `/auth/check-username/${encodeURIComponent(username)}`, undefined, {
|
|
936
936
|
cache: false,
|
|
937
937
|
skipAuth: true,
|
|
938
938
|
});
|
package/dist/esm/api/billing.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* arrive as ISO-8601 strings.
|
|
11
11
|
*/
|
|
12
12
|
import { cancelProductSubscriptionCheck, parseContract, personalPlanCatalogueCheck, personalPlanCheckoutRequestCheck, personalPlanCheckoutResultCheck, productPlanCatalogueCheck, productPlanCheckoutRequestCheck, productSubscriptionCancellationResultCheck, productSubscriptionRenewalRequestCheck, productSubscriptionsResponseCheck, subjectProductAccessCheck, subjectProductAccessQueryCheck, subscriptionCreditGrantsResponseCheck, } from '@oxy.so/contracts/client';
|
|
13
|
+
const enc = encodeURIComponent;
|
|
13
14
|
const SUBSCRIPTION_TTL = 2 * 60 * 1000;
|
|
14
15
|
const WALLET_TTL = 60 * 1000;
|
|
15
16
|
export class BillingApi {
|
|
@@ -73,7 +74,7 @@ export class BillingApi {
|
|
|
73
74
|
/** A user's subscription (default: the signed-in user's). */
|
|
74
75
|
async subscription(userId) {
|
|
75
76
|
const id = this.resolveUserId(userId);
|
|
76
|
-
return this.ctx.request('GET', `/subscription/${id}`, undefined, {
|
|
77
|
+
return this.ctx.request('GET', `/subscription/${enc(id)}`, undefined, {
|
|
77
78
|
cache: true,
|
|
78
79
|
cacheTTL: SUBSCRIPTION_TTL,
|
|
79
80
|
});
|
|
@@ -81,7 +82,7 @@ export class BillingApi {
|
|
|
81
82
|
/** A user's wallet (default: the signed-in user's). Cached briefly: the balance moves. */
|
|
82
83
|
async wallet(userId) {
|
|
83
84
|
const id = this.resolveUserId(userId);
|
|
84
|
-
return this.ctx.request('GET', `/wallet/${id}`, undefined, {
|
|
85
|
+
return this.ctx.request('GET', `/wallet/${enc(id)}`, undefined, {
|
|
85
86
|
cache: true,
|
|
86
87
|
cacheTTL: WALLET_TTL,
|
|
87
88
|
});
|
|
@@ -94,7 +95,7 @@ export class BillingApi {
|
|
|
94
95
|
params.limit = options.limit;
|
|
95
96
|
if (options.offset)
|
|
96
97
|
params.offset = options.offset;
|
|
97
|
-
return this.ctx.request('GET', `/wallet/transactions/${id}`, params, {
|
|
98
|
+
return this.ctx.request('GET', `/wallet/transactions/${enc(id)}`, params, {
|
|
98
99
|
cache: false,
|
|
99
100
|
});
|
|
100
101
|
}
|
package/dist/esm/api/devices.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { checkContract, deviceBackgroundCredentialResponseCheck, deviceJoinCodeResponseCheck, deviceJoinResponseCheck, deviceRegisterResponseCheck, deviceTokenMintResponseCheck, } from '@oxy.so/contracts/client';
|
|
2
2
|
import { logger } from '../logger/index.js';
|
|
3
3
|
import { extractErrorStatus } from '../utils/errorUtils.js';
|
|
4
|
+
const enc = encodeURIComponent;
|
|
4
5
|
/**
|
|
5
6
|
* The server's `401 account_not_on_device` for a PINNED mint: the requested
|
|
6
7
|
* `accountId` is not (or is no longer) a live account of this device session.
|
|
@@ -71,7 +72,7 @@ export class DevicesApi {
|
|
|
71
72
|
* @param deviceId - The device ID to remove
|
|
72
73
|
*/
|
|
73
74
|
async remove(deviceId) {
|
|
74
|
-
await this.ctx.request('DELETE', `/devices/${deviceId}`, undefined, { cache: false });
|
|
75
|
+
await this.ctx.request('DELETE', `/devices/${enc(deviceId)}`, undefined, { cache: false });
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
78
|
* Get device sessions for a given session ID
|
|
@@ -81,7 +82,7 @@ export class DevicesApi {
|
|
|
81
82
|
*/
|
|
82
83
|
async sessions(sessionId) {
|
|
83
84
|
// Cache disabled by default to ensure fresh session data
|
|
84
|
-
return this.ctx.request('GET', `/session/device/sessions/${sessionId}`, undefined, {
|
|
85
|
+
return this.ctx.request('GET', `/session/device/sessions/${enc(sessionId)}`, undefined, {
|
|
85
86
|
cache: false, // Don't cache sessions - always get fresh data
|
|
86
87
|
deduplicate: true, // Deduplicate concurrent requests for same sessionId
|
|
87
88
|
});
|
|
@@ -99,7 +100,7 @@ export class DevicesApi {
|
|
|
99
100
|
urlParams.deviceId = deviceId;
|
|
100
101
|
if (excludeCurrent)
|
|
101
102
|
urlParams.excludeCurrent = 'true';
|
|
102
|
-
return this.ctx.request('POST', `/session/device/logout-all/${sessionId}`, urlParams, { cache: false });
|
|
103
|
+
return this.ctx.request('POST', `/session/device/logout-all/${enc(sessionId)}`, urlParams, { cache: false });
|
|
103
104
|
}
|
|
104
105
|
/**
|
|
105
106
|
* Update device name
|
|
@@ -108,7 +109,7 @@ export class DevicesApi {
|
|
|
108
109
|
* @returns Updated device object
|
|
109
110
|
*/
|
|
110
111
|
async rename(sessionId, deviceName) {
|
|
111
|
-
return this.ctx.request('PUT', `/session/device/name/${sessionId}`, { deviceName }, { cache: false });
|
|
112
|
+
return this.ctx.request('PUT', `/session/device/name/${enc(sessionId)}`, { deviceName }, { cache: false });
|
|
112
113
|
}
|
|
113
114
|
/**
|
|
114
115
|
* Get security information
|
package/dist/esm/api/follows.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { buildPaginationParams, buildQueryParams, buildUrl, } from '../utils/apiUtils.js';
|
|
2
|
+
import { oxyUserByIdCacheKey, oxyUserByIdPath } from '../utils/identityCacheSweep.js';
|
|
2
3
|
const GRAPH_TTL = 2 * 60 * 1000;
|
|
3
4
|
const STATUS_TTL = 60 * 1000;
|
|
4
5
|
/**
|
|
@@ -13,7 +14,7 @@ export class FollowsApi {
|
|
|
13
14
|
// ── People ───────────────────────────────────────────────────────────────
|
|
14
15
|
/** Follow a user. */
|
|
15
16
|
async follow(userId) {
|
|
16
|
-
const result = await this.ctx.request('POST',
|
|
17
|
+
const result = await this.ctx.request('POST', `${oxyUserByIdPath(userId)}/follow`, undefined, { cache: false });
|
|
17
18
|
this.invalidate([userId]);
|
|
18
19
|
return result;
|
|
19
20
|
}
|
|
@@ -27,7 +28,7 @@ export class FollowsApi {
|
|
|
27
28
|
}
|
|
28
29
|
/** Unfollow a user. */
|
|
29
30
|
async unfollow(userId) {
|
|
30
|
-
const result = await this.ctx.request('DELETE',
|
|
31
|
+
const result = await this.ctx.request('DELETE', `${oxyUserByIdPath(userId)}/follow`, undefined, { cache: false });
|
|
31
32
|
this.invalidate([userId]);
|
|
32
33
|
return result;
|
|
33
34
|
}
|
|
@@ -41,7 +42,7 @@ export class FollowsApi {
|
|
|
41
42
|
}
|
|
42
43
|
/** Whether the signed-in user follows `userId`. Cached 1 minute, busted by every write. */
|
|
43
44
|
async status(userId) {
|
|
44
|
-
return this.ctx.request('GET',
|
|
45
|
+
return this.ctx.request('GET', `${oxyUserByIdPath(userId)}/follow-status`, undefined, {
|
|
45
46
|
cache: true,
|
|
46
47
|
cacheTTL: STATUS_TTL,
|
|
47
48
|
});
|
|
@@ -71,12 +72,12 @@ export class FollowsApi {
|
|
|
71
72
|
* `limit`/`offset`/`sort` combination is its own cache entry (2 minutes).
|
|
72
73
|
*/
|
|
73
74
|
async followers(userId, params) {
|
|
74
|
-
const { data, total, hasMore } = await this.userPage(
|
|
75
|
+
const { data, total, hasMore } = await this.userPage(`${oxyUserByIdPath(userId)}/followers`, params);
|
|
75
76
|
return { followers: data, total, hasMore };
|
|
76
77
|
}
|
|
77
78
|
/** Who a user follows. `sort` as in `followers`. */
|
|
78
79
|
async following(userId, params) {
|
|
79
|
-
const { data, total, hasMore } = await this.userPage(
|
|
80
|
+
const { data, total, hasMore } = await this.userPage(`${oxyUserByIdPath(userId)}/following`, params);
|
|
80
81
|
return { following: data, total, hasMore };
|
|
81
82
|
}
|
|
82
83
|
/**
|
|
@@ -84,7 +85,7 @@ export class FollowsApi {
|
|
|
84
85
|
* `userId`.
|
|
85
86
|
*/
|
|
86
87
|
async mutuals(userId, params) {
|
|
87
|
-
const { data, total, hasMore } = await this.userPage(
|
|
88
|
+
const { data, total, hasMore } = await this.userPage(`${oxyUserByIdPath(userId)}/mutuals`, params);
|
|
88
89
|
return { mutuals: data, total, hasMore };
|
|
89
90
|
}
|
|
90
91
|
/**
|
|
@@ -219,16 +220,17 @@ export class FollowsApi {
|
|
|
219
220
|
const keys = ['GET:/users/me/graph'];
|
|
220
221
|
const prefixes = ['GET:/profiles/username/', 'GET:/profiles/resolve'];
|
|
221
222
|
for (const id of targetUserIds) {
|
|
222
|
-
|
|
223
|
+
const user = oxyUserByIdPath(id);
|
|
224
|
+
keys.push(`GET:${user}/follow-status`);
|
|
223
225
|
// Profiles embed the viewer-relative `relationship`.
|
|
224
|
-
keys.push(
|
|
226
|
+
keys.push(oxyUserByIdCacheKey(id));
|
|
225
227
|
// The target gained or lost a follower, and "followers you know" with it.
|
|
226
|
-
prefixes.push(`GET
|
|
228
|
+
prefixes.push(`GET:${user}/followers`, `GET:${user}/mutuals`);
|
|
227
229
|
}
|
|
228
230
|
// The viewer's own following list changed.
|
|
229
231
|
const viewerId = this.ctx.oxy.session.userId;
|
|
230
232
|
if (viewerId)
|
|
231
|
-
prefixes.push(`GET
|
|
233
|
+
prefixes.push(`GET:${oxyUserByIdPath(viewerId)}/following`);
|
|
232
234
|
this.ctx.http.invalidateCache({ keys, prefixes });
|
|
233
235
|
}
|
|
234
236
|
}
|
package/dist/esm/api/privacy.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { evictOxyIdentityCache } from '../utils/identityCacheSweep.js';
|
|
2
|
+
const enc = encodeURIComponent;
|
|
2
3
|
const LIST_TTL = 60 * 1000;
|
|
3
4
|
const SETTINGS_TTL = 2 * 60 * 1000;
|
|
4
5
|
const refId = (ref) => (typeof ref === 'string' ? ref : ref._id);
|
|
@@ -10,7 +11,7 @@ export class PrivacyApi {
|
|
|
10
11
|
/** A user's privacy settings (default: the signed-in user's). */
|
|
11
12
|
async settings(userId) {
|
|
12
13
|
const id = await this.resolveUserId(userId);
|
|
13
|
-
return this.ctx.request('GET', `/privacy/${id}/privacy`, undefined, {
|
|
14
|
+
return this.ctx.request('GET', `/privacy/${enc(id)}/privacy`, undefined, {
|
|
14
15
|
cache: true,
|
|
15
16
|
cacheTTL: SETTINGS_TTL,
|
|
16
17
|
});
|
|
@@ -18,10 +19,10 @@ export class PrivacyApi {
|
|
|
18
19
|
/** Update privacy settings (default: the signed-in user's). */
|
|
19
20
|
async updateSettings(settings, userId) {
|
|
20
21
|
const id = await this.resolveUserId(userId);
|
|
21
|
-
const res = await this.ctx.request('PATCH', `/privacy/${id}/privacy`, settings, { cache: false });
|
|
22
|
+
const res = await this.ctx.request('PATCH', `/privacy/${enc(id)}/privacy`, settings, { cache: false });
|
|
22
23
|
// Privacy settings ride the user DTO, so every identity read goes stale too.
|
|
23
24
|
evictOxyIdentityCache(this.ctx.http, id);
|
|
24
|
-
this.ctx.oxy.cache.delete(`GET:/privacy/${id}/privacy`);
|
|
25
|
+
this.ctx.oxy.cache.delete(`GET:/privacy/${enc(id)}/privacy`);
|
|
25
26
|
return res;
|
|
26
27
|
}
|
|
27
28
|
// ── Blocked ──────────────────────────────────────────────────────────────
|
|
@@ -35,14 +36,14 @@ export class PrivacyApi {
|
|
|
35
36
|
/** Block a user. */
|
|
36
37
|
async block(userId) {
|
|
37
38
|
requireId(userId);
|
|
38
|
-
const res = await this.ctx.request('POST', `/privacy/blocked/${userId}`, undefined, { cache: false });
|
|
39
|
+
const res = await this.ctx.request('POST', `/privacy/blocked/${enc(userId)}`, undefined, { cache: false });
|
|
39
40
|
this.invalidate('GET:/privacy/blocked');
|
|
40
41
|
return res;
|
|
41
42
|
}
|
|
42
43
|
/** Unblock a user. */
|
|
43
44
|
async unblock(userId) {
|
|
44
45
|
requireId(userId);
|
|
45
|
-
const res = await this.ctx.request('DELETE', `/privacy/blocked/${userId}`, undefined, { cache: false });
|
|
46
|
+
const res = await this.ctx.request('DELETE', `/privacy/blocked/${enc(userId)}`, undefined, { cache: false });
|
|
46
47
|
this.invalidate('GET:/privacy/blocked');
|
|
47
48
|
return res;
|
|
48
49
|
}
|
|
@@ -68,14 +69,14 @@ export class PrivacyApi {
|
|
|
68
69
|
/** Restrict a user: limit their interactions without blocking them. */
|
|
69
70
|
async restrict(userId) {
|
|
70
71
|
requireId(userId);
|
|
71
|
-
const res = await this.ctx.request('POST', `/privacy/restricted/${userId}`, undefined, { cache: false });
|
|
72
|
+
const res = await this.ctx.request('POST', `/privacy/restricted/${enc(userId)}`, undefined, { cache: false });
|
|
72
73
|
this.invalidate('GET:/privacy/restricted');
|
|
73
74
|
return res;
|
|
74
75
|
}
|
|
75
76
|
/** Lift a restriction. */
|
|
76
77
|
async unrestrict(userId) {
|
|
77
78
|
requireId(userId);
|
|
78
|
-
const res = await this.ctx.request('DELETE', `/privacy/restricted/${userId}`, undefined, { cache: false });
|
|
79
|
+
const res = await this.ctx.request('DELETE', `/privacy/restricted/${enc(userId)}`, undefined, { cache: false });
|
|
79
80
|
this.invalidate('GET:/privacy/restricted');
|
|
80
81
|
return res;
|
|
81
82
|
}
|
package/dist/esm/api/session.js
CHANGED
|
@@ -9,6 +9,7 @@ import { jwtDecode } from 'jwt-decode';
|
|
|
9
9
|
import { normalizeUserIdentity } from '../utils/userIdentity.js';
|
|
10
10
|
import { OxyApiError } from '../OxyServices.errors.js';
|
|
11
11
|
import { checkContract, holderContextEvidenceV1ResponseCheck } from '@oxy.so/contracts/client';
|
|
12
|
+
const enc = encodeURIComponent;
|
|
12
13
|
/** How long a refusal (disabled, rate limited, unreachable) is remembered per installation. */
|
|
13
14
|
const EVIDENCE_REFUSAL_MS = 5000;
|
|
14
15
|
const unavailable = (reason) => ({
|
|
@@ -290,7 +291,7 @@ export class SessionApi {
|
|
|
290
291
|
: {}),
|
|
291
292
|
},
|
|
292
293
|
})
|
|
293
|
-
: await this.ctx.request('GET', `/session/validate/${sessionId}`, {
|
|
294
|
+
: await this.ctx.request('GET', `/session/validate/${enc(sessionId)}`, {
|
|
294
295
|
...(options.deviceFingerprint
|
|
295
296
|
? { deviceFingerprint: options.deviceFingerprint }
|
|
296
297
|
: {}),
|
|
@@ -317,7 +318,7 @@ export class SessionApi {
|
|
|
317
318
|
const invalid = candidate?.status === 401 && candidate.code === 'OXY_LIVE_SESSION_INVALID_V1';
|
|
318
319
|
const denied = candidate?.status === 403 && candidate.code === 'OXY_LIVE_SESSION_POLICY_V1';
|
|
319
320
|
if (invalid)
|
|
320
|
-
this.ctx.oxy.cache.delete(`GET:/session/user/${sessionId}`);
|
|
321
|
+
this.ctx.oxy.cache.delete(`GET:/session/user/${enc(sessionId)}`);
|
|
321
322
|
if (invalid || denied)
|
|
322
323
|
throw error;
|
|
323
324
|
throw new OxyApiError('Live session authority is unavailable', {
|
|
@@ -327,26 +328,28 @@ export class SessionApi {
|
|
|
327
328
|
});
|
|
328
329
|
}
|
|
329
330
|
// The session is gone: drop any user cached for it (#196).
|
|
330
|
-
this.ctx.oxy.cache.delete(`GET:/session/user/${sessionId}`);
|
|
331
|
+
this.ctx.oxy.cache.delete(`GET:/session/user/${enc(sessionId)}`);
|
|
331
332
|
throw error;
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
/** The sessions that belong with `sessionId` (same account set). */
|
|
335
336
|
async list(sessionId) {
|
|
336
|
-
return this.ctx.request('GET', `/session/sessions/${sessionId}`, undefined, {
|
|
337
|
+
return this.ctx.request('GET', `/session/sessions/${enc(sessionId)}`, undefined, {
|
|
337
338
|
cache: false,
|
|
338
339
|
});
|
|
339
340
|
}
|
|
340
341
|
/** Sign out `sessionId`, or — with `targetSessionId` — one of the sessions beside it. */
|
|
341
342
|
async logout(sessionId, targetSessionId) {
|
|
342
343
|
const url = targetSessionId
|
|
343
|
-
? `/session/logout/${sessionId}/${targetSessionId}`
|
|
344
|
-
: `/session/logout/${sessionId}`;
|
|
344
|
+
? `/session/logout/${enc(sessionId)}/${enc(targetSessionId)}`
|
|
345
|
+
: `/session/logout/${enc(sessionId)}`;
|
|
345
346
|
await this.ctx.request('POST', url, undefined, { cache: false });
|
|
346
347
|
}
|
|
347
348
|
/** Sign out the other sessions for this account; preserve `sessionId`. */
|
|
348
349
|
async logoutAll(sessionId) {
|
|
349
|
-
await this.ctx.request('POST', `/session/logout-all/${sessionId}`, undefined, {
|
|
350
|
+
await this.ctx.request('POST', `/session/logout-all/${enc(sessionId)}`, undefined, {
|
|
351
|
+
cache: false,
|
|
352
|
+
});
|
|
350
353
|
}
|
|
351
354
|
/** Decoded claims of the current token, memoised per token string. */
|
|
352
355
|
claims() {
|
package/dist/esm/api/topics.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const enc = encodeURIComponent;
|
|
1
2
|
const SHORT = 60 * 1000;
|
|
2
3
|
const LONG = 5 * 60 * 1000;
|
|
3
4
|
const EXTRA_LONG = 30 * 60 * 1000;
|
|
@@ -41,7 +42,7 @@ export class TopicsApi {
|
|
|
41
42
|
}
|
|
42
43
|
/** One topic by slug. */
|
|
43
44
|
async get(slug) {
|
|
44
|
-
return this.ctx.request('GET', `/topics/${slug}`, undefined, {
|
|
45
|
+
return this.ctx.request('GET', `/topics/${enc(slug)}`, undefined, {
|
|
45
46
|
cache: true,
|
|
46
47
|
cacheTTL: LONG,
|
|
47
48
|
});
|
|
@@ -60,10 +61,10 @@ export class TopicsApi {
|
|
|
60
61
|
}
|
|
61
62
|
/** Update a topic's description and translations. Staff or service only. */
|
|
62
63
|
async update(slug, data) {
|
|
63
|
-
const topic = await this.ctx.request('PATCH', `/topics/${slug}`, data, {
|
|
64
|
+
const topic = await this.ctx.request('PATCH', `/topics/${enc(slug)}`, data, {
|
|
64
65
|
cache: false,
|
|
65
66
|
});
|
|
66
|
-
this.ctx.oxy.cache.delete(`GET:/topics/${slug}`);
|
|
67
|
+
this.ctx.oxy.cache.delete(`GET:/topics/${enc(slug)}`);
|
|
67
68
|
return topic;
|
|
68
69
|
}
|
|
69
70
|
}
|