@dotrino/identity 0.16.1 → 0.17.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/identity",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "Identidad y rating de usuarios compartidos entre apps de Dotrino (vault iframe + postMessage)",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -306,6 +306,22 @@ export class Identity {
306
306
  return result
307
307
  }
308
308
 
309
+ /**
310
+ * Actualiza tu PERFIL (merge): `{ nickname?, avatar?, avatarVisible?, links?, fields? }`.
311
+ * `avatar` = data-URI 250×250 (o null para quitarla); `links`/`fields` = arrays con `visible`
312
+ * por ítem (oculto = no se comparte). No pisa lo que no mandes.
313
+ */
314
+ async updateMe (patch) {
315
+ const result = await this._call('updateMe', { patch })
316
+ if (result?.me) this._me = result.me
317
+ return result
318
+ }
319
+
320
+ /** Tu `me` completo (incluye ocultos). */
321
+ async getMe () { return this._call('getMe') }
322
+ /** Subconjunto PÚBLICO de tu perfil (solo lo visible) — para compartir/publicar. */
323
+ async publicMe () { return this._call('publicMe') }
324
+
309
325
  /** Pubkey ECDH (JWK string) propio para encripción. */
310
326
  async getEncryptionPubkey () {
311
327
  return this._call('getEncryptionPubkey')
package/src/node.js CHANGED
@@ -175,6 +175,9 @@ export class Identity {
175
175
  const result = await this._h('setMyNickname', { nickname })
176
176
  return result
177
177
  }
178
+ async updateMe (patch) { return this._h('updateMe', { patch }) }
179
+ getMe () { return this._h('getMe') }
180
+ publicMe () { return this._h('publicMe') }
178
181
  getEncryptionPubkey () { return this._h('getEncryptionPubkey') }
179
182
  encrypt (recipients, plaintext) { return this._h('encrypt', { recipients, plaintext }) }
180
183
  decrypt (senderEncryptionPubkey, myToken, envelope) {
package/vault/core.js CHANGED
@@ -108,6 +108,33 @@ async function verifyBytes (publicJwkStr, bytes, signatureBase64) {
108
108
  * @returns {Promise<{ handlers:Object, get me():Object, sync:Object|null,
109
109
  * onSyncStatus(fn):void }>}
110
110
  */
111
+ // Sanea un patch de perfil (avatar/links/fields/nickname). Cada link/field lleva `visible`
112
+ // (oculto = no se comparte). Caps de tamaño para no inflar el `me`. Los ids los pone la UI.
113
+ function sanitizeProfilePatch (patch = {}) {
114
+ const out = {}
115
+ if (typeof patch.nickname === 'string') out.nickname = patch.nickname.slice(0, 40)
116
+ if (patch.avatar === null) out.avatar = null
117
+ else if (typeof patch.avatar === 'string') out.avatar = patch.avatar.slice(0, 120000) // ~90KB: data-URI 250x250
118
+ if (typeof patch.avatarVisible === 'boolean') out.avatarVisible = patch.avatarVisible
119
+ if (Array.isArray(patch.links)) {
120
+ out.links = patch.links.slice(0, 12).map((l) => ({
121
+ id: String(l?.id || '').slice(0, 24),
122
+ type: String(l?.type || 'web').slice(0, 16),
123
+ value: String(l?.value || '').slice(0, 200),
124
+ visible: l?.visible !== false
125
+ })).filter((l) => l.value)
126
+ }
127
+ if (Array.isArray(patch.fields)) {
128
+ out.fields = patch.fields.slice(0, 20).map((f) => ({
129
+ id: String(f?.id || '').slice(0, 24),
130
+ label: String(f?.label || '').slice(0, 40),
131
+ value: String(f?.value || '').slice(0, 280),
132
+ visible: f?.visible !== false
133
+ })).filter((f) => f.label || f.value)
134
+ }
135
+ return out
136
+ }
137
+
111
138
  export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null }) {
112
139
  const {
113
140
  initPeerStorage, loadPeers, savePeers, setPeersDirect, upsertPeer, onDirty
@@ -354,6 +381,20 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null })
354
381
 
355
382
  // ----- handlers (idénticos a la versión iframe) -----
356
383
 
384
+ // Merge de un patch de perfil en `me` (preserva lo demás), saneado. Refleja el nombre en la
385
+ // meta del perfil (para el switcher). Devuelve el `me` resultante.
386
+ function applyMeUpdate (patch) {
387
+ const clean = sanitizeProfilePatch(patch || {})
388
+ me = { ...(me || {}), ...clean, publickey: publickeyJwkStr, encryptionPubkey: encPublickeyJwkStr }
389
+ if (clean.avatar === null) delete me.avatar
390
+ saveMe(me)
391
+ if (typeof clean.nickname === 'string') {
392
+ const list = loadProfiles(); const e = list.find((p) => p.id === currentPid)
393
+ if (e && e.name !== clean.nickname) { e.name = clean.nickname; saveProfiles(list) }
394
+ }
395
+ return me
396
+ }
397
+
357
398
  const handlers = {
358
399
  async makeChallenge () {
359
400
  const nonce = crypto.randomUUID()
@@ -656,9 +697,24 @@ export async function createIdentityCore ({ kv: rawKv, peers, makeSync = null })
656
697
  },
657
698
 
658
699
  async setMyNickname ({ nickname }) {
659
- const next = { publickey: publickeyJwkStr, encryptionPubkey: encPublickeyJwkStr, nickname: String(nickname || '').slice(0, 40) }
660
- saveMe(next)
661
- return { me: next }
700
+ return { me: applyMeUpdate({ nickname }) }
701
+ },
702
+
703
+ // Perfil completo (avatar 250x250, links de redes, datos), cada ítem con `visible`
704
+ // (oculto = no se comparte). Merge: no pisa lo que no venga en el patch.
705
+ async updateMe ({ patch } = {}) {
706
+ return { me: applyMeUpdate(patch || {}) }
707
+ },
708
+ async getMe () { return me },
709
+ // Subconjunto PÚBLICO del perfil (solo lo marcado visible) — para compartir/publicar.
710
+ async publicMe () {
711
+ const m = me || {}
712
+ const out = { publickey: m.publickey, encryptionPubkey: m.encryptionPubkey }
713
+ if (m.nickname) out.nickname = m.nickname
714
+ if (m.avatar && m.avatarVisible !== false) out.avatar = m.avatar
715
+ if (Array.isArray(m.links)) { const v = m.links.filter((l) => l.visible !== false).map(({ visible, ...r }) => r); if (v.length) out.links = v }
716
+ if (Array.isArray(m.fields)) { const v = m.fields.filter((f) => f.visible !== false).map(({ visible, ...r }) => r); if (v.length) out.fields = v }
717
+ return out
662
718
  },
663
719
 
664
720
  async getEncryptionPubkey () { return encPublickeyJwkStr },