k2-im 0.2.2 → 0.2.3
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/chat-kit-pinia.d.ts
CHANGED
|
@@ -3254,9 +3254,9 @@ interface TextMessageOptions {
|
|
|
3254
3254
|
mentions?: readonly MentionInput[];
|
|
3255
3255
|
replyToMessageId?: string;
|
|
3256
3256
|
}
|
|
3257
|
-
/**
|
|
3257
|
+
/** 可主动分享的名片。未知 wire 类别只保留接收,不能放进发送入参。 */
|
|
3258
3258
|
type ContactCardInput = Omit<ImContactBody, 'kind' | 'rawKind'> & {
|
|
3259
|
-
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel'>;
|
|
3259
|
+
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel' | 'robot'>;
|
|
3260
3260
|
};
|
|
3261
3261
|
/** 名片发送附加数据;回复关系与其它可发送消息使用同一稳定消息 id。 */
|
|
3262
3262
|
interface ContactMessageOptions {
|
package/dist/chat-kit.d.ts
CHANGED
|
@@ -3355,9 +3355,9 @@ interface TextMessageOptions {
|
|
|
3355
3355
|
mentions?: readonly MentionInput[];
|
|
3356
3356
|
replyToMessageId?: string;
|
|
3357
3357
|
}
|
|
3358
|
-
/**
|
|
3358
|
+
/** 可主动分享的名片。未知 wire 类别只保留接收,不能放进发送入参。 */
|
|
3359
3359
|
type ContactCardInput = Omit<ImContactBody, 'kind' | 'rawKind'> & {
|
|
3360
|
-
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel'>;
|
|
3360
|
+
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel' | 'robot'>;
|
|
3361
3361
|
};
|
|
3362
3362
|
/** 名片发送附加数据;回复关系与其它可发送消息使用同一稳定消息 id。 */
|
|
3363
3363
|
interface ContactMessageOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -3888,9 +3888,9 @@ interface TextMessageOptions {
|
|
|
3888
3888
|
mentions?: readonly MentionInput[];
|
|
3889
3889
|
replyToMessageId?: string;
|
|
3890
3890
|
}
|
|
3891
|
-
/**
|
|
3891
|
+
/** 可主动分享的名片。未知 wire 类别只保留接收,不能放进发送入参。 */
|
|
3892
3892
|
type ContactCardInput = Omit<ImContactBody, 'kind' | 'rawKind'> & {
|
|
3893
|
-
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel'>;
|
|
3893
|
+
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel' | 'robot'>;
|
|
3894
3894
|
};
|
|
3895
3895
|
/** 名片发送附加数据;回复关系与其它可发送消息使用同一稳定消息 id。 */
|
|
3896
3896
|
interface ContactMessageOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{encodeConversationKey as e}from"../conversation-identity.js";import{assertOutgoingContentBodyMatchesType as t}from"../mapping/content-body.js";import{normalizeStoredVideoBody as n}from"../mapping/video-body.js";import{createDefaultSendStrategyRegistry as o}from"../message-flow/send/send-strategy-registry.js";import{classifyAckFailure as s}from"../mapping/message-mapper.js";import{computeSortKey as r,computeMessageSortKey as a,resolveMessageTimestamp as i}from"../mapping/sort.js";import{describeUnsupportedConversation as d}from"../message-flow/conversation-support.js";import{newClientMessageId as c}from"../mapping/message-id.js";const u=/* @__PURE__ */new Set([32768,0]),p=/* @__PURE__ */new Set([33281,33299]),l=33298,y=/* @__PURE__ */new Set([...p,l]);function f(e){if(e instanceof Uint8Array)return e.slice();if(Array.isArray(e))return e.map(e=>f(e));if(null!==e&&"object"==typeof e){const t={};for(const[n,o]of Object.entries(e))t[n]=f(o);return t}return e}function v(e){return f(e)}function g(e){return f(e)}function m(m,b={}){const I=b.ackTimeoutMs??3e4,T=b.maxAttempts??5,h=m.now??(()=>Date.now()),M=m.sendStrategies??o(),w=/* @__PURE__ */new Map,S=/* @__PURE__ */new Map,A=/* @__PURE__ */new Map,x=/* @__PURE__ */new Map;let C=0;const E=/* @__PURE__ */new Set,k=/* @__PURE__ */new Map,q=/* @__PURE__ */new Set,O=/* @__PURE__ */new Set,F=/* @__PURE__ */new Set,j=/* @__PURE__ */new Map;function P(t){return e(t)}function R(e,t){return e.createdAt!==t.createdAt?e.createdAt-t.createdAt:e.id<t.id?-1:e.id>t.id?1:0}function U(e){const t=P(e),n=S.get(t);if(void 0!==n)return n;let o=0;for(const t of m.domainState.getMessagesByConversation({conversationType:e.conversationType,conversationId:e.conversationId}))o=Math.max(o,i(t));for(const e of w.values())P(e)===t&&(o=Math.max(o,e.createdAt));return S.set(t,o),o}function K(e,t){const n=P(e);t>(S.get(n)??U(e))&&S.set(n,t)}function D(e){const t=U(e),n=Math.max(h(),t+1);return S.set(P(e),n),{id:c(),createdAt:n}}function N(e,t){m.onUpdated?.({messageId:e.id,conversation:{conversationType:e.conversationType,conversationId:e.conversationId},state:t,...void 0===e.lastError?{}:{failure:{reason:e.lastError.reason,retryable:e.lastError.retryable}}})}function $(e){void 0!==m.storage&&m.storage.saveOutboxMessage(v(e)).catch(e=>m.onStorageError?.("Outbox 落盘失败",e))}function B(e){void 0!==m.storage&&m.storage.removeOutboxMessage(e).catch(e=>m.onStorageError?.("Outbox 删除失败",e))}function L(e){const t=A.get(e);void 0!==t&&(clearTimeout(t),A.delete(e))}function z(e,t,n){const o=!0===n?.authoritativeFailure?{authoritativeOutboxFailure:!0}:void 0,s=n?.entry??w.get(e);if(void 0===s)return;const i=m.domainState.getConversationMessage(s,e);if(void 0!==i)return void m.domainState.upsertMessages([{...i,...t}],"live",o);const d={...{id:s.id,conversationId:s.conversationId,conversationType:s.conversationType,senderId:m.getSelfId(),contentType:s.contentType,body:g(s.body),createdAt:s.createdAt,sortKey:r(s.createdAt,s.id),status:s.status,receipt:"unread",encryption:f(s.encryption),failure:void 0===s.lastError?void 0:f(s.lastError),...void 0!==s.mention?{mention:f(s.mention)}:{},...void 0!==s.refMessageId?{refMessageId:s.refMessageId}:{}},...t};m.domainState.upsertMessages([{...d,sortKey:a(d)}],"live",o)}function G(e,t){L(e);const n=w.get(e);void 0!==n&&(n.status="failed",n.lastError=t,z(e,{status:"failed",failure:t}),$(n),N(n,"failed"),J(e))}async function H(e){if(x.has(e.id))return;if(E.has(P(e)))return void G(e.id,{code:-4,reason:"unknown",displayCode:"unknown",message:"会话成员关系已终止,消息不会继续发送",retryable:!1});const t=/* @__PURE__ */Symbol("outbox-dispatch");x.set(e.id,t);const n=C;try{const t=M.resolve(e.conversationType);if(void 0===t)return void G(e.id,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.dispatch"),retryable:!1});let o;try{const s={selfId:m.getSelfId(),crypto:m.crypto,resolveEncryptionKey:m.resolvePublicKey},r=void 0===t.buildOutgoingFrames?t.buildOutgoingFrame(e,s):t.buildOutgoingFrames(e,s);if(r instanceof Uint8Array)o=[r];else if(Array.isArray(r))o=r;else{const e=await r;o=e instanceof Uint8Array?[e]:e}if(n!==C)return;if(0===o.length||o.some(e=>!(e instanceof Uint8Array)))throw new Error(`发送策略返回了非法帧序列(conversationType=${e.conversationType})`)}catch{if(n!==C)return;return e.attempts+=1,void G(e.id,{code:-2,reason:"unknown"})}if(E.has(P(e)))return void G(e.id,{code:-4,reason:"unknown",displayCode:"unknown",message:"会话成员关系已终止,消息不会继续发送",retryable:!1});if(!m.isAuthenticated())return e.status="pending",z(e.id,{status:"pending"}),$(e),void N(e,"queued");e.status="sending",e.attempts+=1,z(e.id,{status:"sending"}),$(e),N(e,"sending");for(const e of o)m.sendFrame(e);L(e.id),A.set(e.id,setTimeout(()=>G(e.id,{code:-1,reason:"timeout"}),I))}finally{x.get(e.id)===t&&x.delete(e.id)}}function J(e){const t=j.get(e);void 0!==t&&(j.delete(e),t())}function Q(e){const t=w.get(e);return void 0===t||"sending"!==t.status?Promise.resolve():new Promise(t=>j.set(e,t))}function V(e){return("pending"===e.status||"failed"===e.status)&&!("failed"===e.status&&!1===e.lastError?.retryable)&&"manual"!==e.resumePolicy&&(e.attempts<T||O.has(e.id))&&void 0!==M.resolve(e.conversationType)}function W(e,t){let n;for(const o of w.values())!t.has(o.id)&&P(o)===e&&V(o)&&(void 0===n||R(o,n)<0)&&(n=o);return n}function X(e,t=!1){const n=P(e);t&&F.add(n),k.has(n)?q.add(n):Y(n)}async function Y(e){const t=/* @__PURE__ */Symbol("outbox-drain"),n=C;k.set(e,t);try{do{q.delete(e);const t=/* @__PURE__ */new Set;for(;n===C&&m.isAuthenticated();){const o=W(e,t);if(void 0===o)break;if(t.add(o.id),O.delete(o.id),await H(o),n!==C)return;F.has(e)&&await Q(o.id)}}while(n===C&&q.has(e)&&m.isAuthenticated())}finally{k.get(e)===t&&(k.delete(e),F.delete(e))}}function Z(e,t=!1){t&&F.add(e),k.has(e)?q.add(e):Y(e)}function _(e){const t={code:-2,reason:"unknown",displayCode:"sendCanceled",retryable:!1};e.lastError=t,z(e.id,{status:"failed",failure:t}),O.delete(e.id),w.delete(e.id),B(e.id),N(e,"canceled"),J(e.id)}return{allocateMessageIdentity:D,enqueueText(e){const{id:t,createdAt:n}=D(e),o={encrypted:e.encrypted??!1},s=void 0!==M.resolve(e.conversationType),a=s&&m.isAuthenticated(),i={id:t,conversationId:e.conversationId,conversationType:e.conversationType,senderId:m.getSelfId(),contentType:"text",body:{text:e.text},createdAt:n,sortKey:r(n,t),status:"pending",receipt:"unread",encryption:f(o),...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}},c={id:t,conversationId:e.conversationId,conversationType:e.conversationType,contentType:"text",body:{text:e.text},encryption:f(o),status:"pending",attempts:0,createdAt:n,...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}};return w.set(t,c),$(c),N(c,"queued"),m.domainState.upsertMessages([i],"live",{newOutgoing:!0}),s?(a&&X(c),v(c)):(G(t,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.enqueueText"),retryable:!1}),v(c))},enqueueContact(e){const t=e.contact.targetId.trim(),n=e.contact.displayName.trim();if(""===t)throw new Error("outbox.enqueueContact: targetId 不能为空");if(""===n)throw new Error("outbox.enqueueContact: displayName 不能为空");if("individual"!==e.contact.kind&&"group"!==e.contact.kind&&"channel"!==e.contact.kind)throw new Error(`outbox.enqueueContact: 不支持发送 ${String(e.contact.kind)} 名片`);const{id:o,createdAt:s}=D(e),a={encrypted:e.encrypted??!1},i=void 0!==M.resolve(e.conversationType),c=i&&m.isAuthenticated(),u={contact:{...e.contact,targetId:t,displayName:n}},p={id:o,conversationId:e.conversationId,conversationType:e.conversationType,senderId:m.getSelfId(),contentType:"contact",body:g(u),createdAt:s,sortKey:r(s,o),status:"pending",receipt:"unread",encryption:f(a),...void 0===e.refMessageId?{}:{refMessageId:e.refMessageId}},l={id:o,conversationId:e.conversationId,conversationType:e.conversationType,contentType:"contact",body:g(u),encryption:f(a),status:"pending",attempts:0,createdAt:s,...void 0===e.refMessageId?{}:{refMessageId:e.refMessageId}};return w.set(o,l),$(l),N(l,"queued"),m.domainState.upsertMessages([p],"live",{newOutgoing:!0}),i?(c&&X(l),v(l)):(G(o,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.enqueueContact"),retryable:!1}),v(l))},enqueueMedia(e){const{id:n,createdAt:o}=e,s=g(e.body);t(e.contentType,s,"outbox.enqueueMedia"),K(e,o);const a=void 0!==M.resolve(e.conversationType),i=a&&m.isAuthenticated(),c={id:n,conversationId:e.conversationId,conversationType:e.conversationType,senderId:m.getSelfId(),contentType:e.contentType,body:g(s),createdAt:o,sortKey:r(o,n),status:"pending",receipt:"unread",encryption:f(e.encryption),...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}},u={id:n,conversationId:e.conversationId,conversationType:e.conversationType,contentType:e.contentType,body:s,encryption:f(e.encryption),status:"pending",attempts:0,createdAt:o,...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}};return w.set(n,u),$(u),N(u,"queued"),m.domainState.upsertMessages([c],"live",{newOutgoing:!0!==e.optimisticAlreadyCreated}),a?(i&&X(u),v(u)):(G(n,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.enqueueMedia"),retryable:!1}),X(u,!0),v(u))},onChatAck(e){L(e.id);const t=w.get(e.id);if(void 0!==t)if(u.has(e.errcode))w.delete(e.id),B(e.id),z(e.id,{status:"sent",serverTime:e.serverTime>0?e.serverTime:void 0,...void 0===e.extensions?{}:{extensions:{...m.domainState.getConversationMessage(t,e.id)?.extensions,...e.extensions}}},{entry:t}),N(t,"sent"),J(e.id);else{t.status="failed",t.lastError=e.failure??s(e.errcode);const n="direct"===t.conversationType&&p.has(e.errcode),o="direct"===t.conversationType&&e.errcode===l;n?t.lastError={...t.lastError,displayCode:"contactRequired",retryable:!1}:o&&(t.lastError={...t.lastError,displayCode:"messageRefused",retryable:!1}),z(e.id,{status:"failed",failure:t.lastError},{authoritativeFailure:!0}),n?m.domainState.appendDirectContactRequiredNotice(t.conversationId,t.id):o&&m.domainState.appendDirectMessageRefusedNotice(t.conversationId,t.id),$(t),N(t,"failed"),J(e.id)}else u.has(e.errcode)||function(e){if(!y.has(e.errcode))return;const t=m.getSelfId(),n=m.domainState.getMessagesById(e.id).filter(e=>"direct"===e.conversationType&&e.senderId===t);if(n.length>1)throw new Error(`DIRECT 终态 ACK 消息 ID 存在多会话歧义:${e.id}`);const o=n[0];if(void 0===o)return;const r=p.has(e.errcode),a=e.errcode===l;let i=e.failure??s(e.errcode);r?i={...i,displayCode:"contactRequired",retryable:!1}:a&&(i={...i,displayCode:"messageRefused",retryable:!1}),m.domainState.upsertMessages([{...o,status:"failed",failure:i}],"live",{authoritativeOutboxFailure:!0}),r?m.domainState.appendDirectContactRequiredNotice(o.conversationId,o.id):a&&m.domainState.appendDirectMessageRefusedNotice(o.conversationId,o.id)}(e)},onAuthenticated(){!function(){const e=/* @__PURE__ */new Set;for(const t of w.values())V(t)&&e.add(P(t));for(const t of e)Z(t,!0)}()},retry(e){const t=w.get(e);return void 0===t?{accepted:!1,reason:"not-found"}:"sending"===t.status||x.has(e)?{accepted:!1,reason:"in-flight"}:"failed"===t.status&&!1===t.lastError?.retryable?{accepted:!1,reason:"not-retryable"}:"failed"===t.status||"pending"===t.status&&"manual"===t.resumePolicy?("manual"===t.resumePolicy&&(t.resumePolicy="automatic",$(t)),O.add(t.id),X(t),{accepted:!0}):{accepted:!1,reason:"invalid-state"}},cancel(e){const t=w.get(e);return void 0===t?{accepted:!1,reason:"not-found"}:"sending"===t.status||x.has(e)?{accepted:!1,reason:"in-flight"}:"pending"!==t.status?{accepted:!1,reason:"invalid-state"}:t.attempts>0?{accepted:!1,reason:"delivery-uncertain"}:(_(t),{accepted:!0})},markConversationTerminated(e,t){const n=P(e);E.add(n);for(const e of[...w.values()])P(e)===n&&("pending"!==e.status||0!==e.attempts||x.has(e.id)?G(e.id,{code:-4,reason:"unknown",displayCode:"unknown",message:`会话成员关系已终止:${t}`,retryable:!1}):_(e))},clearConversationTerminated(e){const t=P(e);E.delete(t),Z(t)},markForLogout(e){for(const t of w.values())if("pending"===t.status||"sending"===t.status||"failed"===t.status){if(L(t.id),t.resumePolicy="manual","fail"===e.policy){const e={code:-2,reason:"unknown",displayCode:"sessionLoggedOut",retryable:!0};t.status="failed",t.lastError=e,z(t.id,{status:"failed",failure:e}),N(t,"failed")}$(t),J(t.id)}},getPending:()=>[...w.values()].map(v),reset(e){e?.discardInFlight&&(C+=1,x.clear(),k.clear(),q.clear(),F.clear());for(const e of[...A.keys()])L(e);for(const e of w.values())"sending"===e.status&&(e.status="pending",z(e.id,{status:"pending"}),$(e),N(e,"queued"),J(e.id))},async hydrate(e=()=>!0){if(void 0!==m.storage&&e())try{const o=await m.storage.getOutbox();if(!e())return;for(const s of o){if(!e())return;const o=v(s);if("sent"===o.status){B(o.id);continue}try{t(o.contentType,o.body,`outbox.hydrate(${o.id})`),void 0!==o.body.video&&(o.body={...o.body,video:n(o.body.video)})}catch(t){if(m.onStorageError?.(`Outbox 持久化条目正文损坏,已删除(id=${o.id})`,t),!e())return;if(B(o.id),void 0!==m.domainState.getConversationMessage(o,o.id)){const e={code:-2,reason:"unknown",displayCode:"unknown",message:"发送账本正文损坏,已停止重试",retryable:!1};z(o.id,{status:"failed",failure:e},{authoritativeFailure:!0,entry:o})}continue}const r="sending"===o.status?"pending":o.status,a={...o,status:r};if(w.set(o.id,a),K(a,a.createdAt),N(a,"pending"===r?"queued":r),!e())return;void 0!==m.domainState.getConversationMessage(o,o.id)&&z(o.id,{status:r,failure:void 0===o.lastError?void 0:f(o.lastError)})}}catch(t){e()&&m.onStorageError?.("Outbox 回读失败",t)}}}}export{m as createOutboxManager};
|
|
1
|
+
import{encodeConversationKey as e}from"../conversation-identity.js";import{assertOutgoingContentBodyMatchesType as t}from"../mapping/content-body.js";import{normalizeStoredVideoBody as n}from"../mapping/video-body.js";import{createDefaultSendStrategyRegistry as o}from"../message-flow/send/send-strategy-registry.js";import{classifyAckFailure as r}from"../mapping/message-mapper.js";import{computeSortKey as s,computeMessageSortKey as a,resolveMessageTimestamp as i}from"../mapping/sort.js";import{describeUnsupportedConversation as d}from"../message-flow/conversation-support.js";import{newClientMessageId as c}from"../mapping/message-id.js";const u=/* @__PURE__ */new Set([32768,0]),p=/* @__PURE__ */new Set([33281,33299]),l=33298,y=/* @__PURE__ */new Set([...p,l]);function f(e){if(e instanceof Uint8Array)return e.slice();if(Array.isArray(e))return e.map(e=>f(e));if(null!==e&&"object"==typeof e){const t={};for(const[n,o]of Object.entries(e))t[n]=f(o);return t}return e}function v(e){return f(e)}function g(e){return f(e)}function m(m,b={}){const I=b.ackTimeoutMs??3e4,T=b.maxAttempts??5,h=m.now??(()=>Date.now()),M=m.sendStrategies??o(),w=/* @__PURE__ */new Map,S=/* @__PURE__ */new Map,A=/* @__PURE__ */new Map,x=/* @__PURE__ */new Map;let C=0;const E=/* @__PURE__ */new Set,k=/* @__PURE__ */new Map,q=/* @__PURE__ */new Set,O=/* @__PURE__ */new Set,F=/* @__PURE__ */new Set,j=/* @__PURE__ */new Map;function P(t){return e(t)}function R(e,t){return e.createdAt!==t.createdAt?e.createdAt-t.createdAt:e.id<t.id?-1:e.id>t.id?1:0}function U(e){const t=P(e),n=S.get(t);if(void 0!==n)return n;let o=0;for(const t of m.domainState.getMessagesByConversation({conversationType:e.conversationType,conversationId:e.conversationId}))o=Math.max(o,i(t));for(const e of w.values())P(e)===t&&(o=Math.max(o,e.createdAt));return S.set(t,o),o}function K(e,t){const n=P(e);t>(S.get(n)??U(e))&&S.set(n,t)}function D(e){const t=U(e),n=Math.max(h(),t+1);return S.set(P(e),n),{id:c(),createdAt:n}}function N(e,t){m.onUpdated?.({messageId:e.id,conversation:{conversationType:e.conversationType,conversationId:e.conversationId},state:t,...void 0===e.lastError?{}:{failure:{reason:e.lastError.reason,retryable:e.lastError.retryable}}})}function $(e){void 0!==m.storage&&m.storage.saveOutboxMessage(v(e)).catch(e=>m.onStorageError?.("Outbox 落盘失败",e))}function B(e){void 0!==m.storage&&m.storage.removeOutboxMessage(e).catch(e=>m.onStorageError?.("Outbox 删除失败",e))}function L(e){const t=A.get(e);void 0!==t&&(clearTimeout(t),A.delete(e))}function z(e,t,n){const o=!0===n?.authoritativeFailure?{authoritativeOutboxFailure:!0}:void 0,r=n?.entry??w.get(e);if(void 0===r)return;const i=m.domainState.getConversationMessage(r,e);if(void 0!==i)return void m.domainState.upsertMessages([{...i,...t}],"live",o);const d={...{id:r.id,conversationId:r.conversationId,conversationType:r.conversationType,senderId:m.getSelfId(),contentType:r.contentType,body:g(r.body),createdAt:r.createdAt,sortKey:s(r.createdAt,r.id),status:r.status,receipt:"unread",encryption:f(r.encryption),failure:void 0===r.lastError?void 0:f(r.lastError),...void 0!==r.mention?{mention:f(r.mention)}:{},...void 0!==r.refMessageId?{refMessageId:r.refMessageId}:{}},...t};m.domainState.upsertMessages([{...d,sortKey:a(d)}],"live",o)}function G(e,t){L(e);const n=w.get(e);void 0!==n&&(n.status="failed",n.lastError=t,z(e,{status:"failed",failure:t}),$(n),N(n,"failed"),J(e))}async function H(e){if(x.has(e.id))return;if(E.has(P(e)))return void G(e.id,{code:-4,reason:"unknown",displayCode:"unknown",message:"会话成员关系已终止,消息不会继续发送",retryable:!1});const t=/* @__PURE__ */Symbol("outbox-dispatch");x.set(e.id,t);const n=C;try{const t=M.resolve(e.conversationType);if(void 0===t)return void G(e.id,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.dispatch"),retryable:!1});let o;try{const r={selfId:m.getSelfId(),crypto:m.crypto,resolveEncryptionKey:m.resolvePublicKey},s=void 0===t.buildOutgoingFrames?t.buildOutgoingFrame(e,r):t.buildOutgoingFrames(e,r);if(s instanceof Uint8Array)o=[s];else if(Array.isArray(s))o=s;else{const e=await s;o=e instanceof Uint8Array?[e]:e}if(n!==C)return;if(0===o.length||o.some(e=>!(e instanceof Uint8Array)))throw new Error(`发送策略返回了非法帧序列(conversationType=${e.conversationType})`)}catch{if(n!==C)return;return e.attempts+=1,void G(e.id,{code:-2,reason:"unknown"})}if(E.has(P(e)))return void G(e.id,{code:-4,reason:"unknown",displayCode:"unknown",message:"会话成员关系已终止,消息不会继续发送",retryable:!1});if(!m.isAuthenticated())return e.status="pending",z(e.id,{status:"pending"}),$(e),void N(e,"queued");e.status="sending",e.attempts+=1,z(e.id,{status:"sending"}),$(e),N(e,"sending");for(const e of o)m.sendFrame(e);L(e.id),A.set(e.id,setTimeout(()=>G(e.id,{code:-1,reason:"timeout"}),I))}finally{x.get(e.id)===t&&x.delete(e.id)}}function J(e){const t=j.get(e);void 0!==t&&(j.delete(e),t())}function Q(e){const t=w.get(e);return void 0===t||"sending"!==t.status?Promise.resolve():new Promise(t=>j.set(e,t))}function V(e){return("pending"===e.status||"failed"===e.status)&&!("failed"===e.status&&!1===e.lastError?.retryable)&&"manual"!==e.resumePolicy&&(e.attempts<T||O.has(e.id))&&void 0!==M.resolve(e.conversationType)}function W(e,t){let n;for(const o of w.values())!t.has(o.id)&&P(o)===e&&V(o)&&(void 0===n||R(o,n)<0)&&(n=o);return n}function X(e,t=!1){const n=P(e);t&&F.add(n),k.has(n)?q.add(n):Y(n)}async function Y(e){const t=/* @__PURE__ */Symbol("outbox-drain"),n=C;k.set(e,t);try{do{q.delete(e);const t=/* @__PURE__ */new Set;for(;n===C&&m.isAuthenticated();){const o=W(e,t);if(void 0===o)break;if(t.add(o.id),O.delete(o.id),await H(o),n!==C)return;F.has(e)&&await Q(o.id)}}while(n===C&&q.has(e)&&m.isAuthenticated())}finally{k.get(e)===t&&(k.delete(e),F.delete(e))}}function Z(e,t=!1){t&&F.add(e),k.has(e)?q.add(e):Y(e)}function _(e){const t={code:-2,reason:"unknown",displayCode:"sendCanceled",retryable:!1};e.lastError=t,z(e.id,{status:"failed",failure:t}),O.delete(e.id),w.delete(e.id),B(e.id),N(e,"canceled"),J(e.id)}return{allocateMessageIdentity:D,enqueueText(e){const{id:t,createdAt:n}=D(e),o={encrypted:e.encrypted??!1},r=void 0!==M.resolve(e.conversationType),a=r&&m.isAuthenticated(),i={id:t,conversationId:e.conversationId,conversationType:e.conversationType,senderId:m.getSelfId(),contentType:"text",body:{text:e.text},createdAt:n,sortKey:s(n,t),status:"pending",receipt:"unread",encryption:f(o),...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}},c={id:t,conversationId:e.conversationId,conversationType:e.conversationType,contentType:"text",body:{text:e.text},encryption:f(o),status:"pending",attempts:0,createdAt:n,...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}};return w.set(t,c),$(c),N(c,"queued"),m.domainState.upsertMessages([i],"live",{newOutgoing:!0}),r?(a&&X(c),v(c)):(G(t,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.enqueueText"),retryable:!1}),v(c))},enqueueContact(e){const t=e.contact.targetId.trim(),n=e.contact.displayName.trim();if(""===t)throw new Error("outbox.enqueueContact: targetId 不能为空");if(""===n)throw new Error("outbox.enqueueContact: displayName 不能为空");if("individual"!==e.contact.kind&&"group"!==e.contact.kind&&"channel"!==e.contact.kind&&"robot"!==e.contact.kind)throw new Error(`outbox.enqueueContact: 不支持发送 ${String(e.contact.kind)} 名片`);const{id:o,createdAt:r}=D(e),a={encrypted:e.encrypted??!1},i=void 0!==M.resolve(e.conversationType),c=i&&m.isAuthenticated(),u={contact:{...e.contact,targetId:t,displayName:n}},p={id:o,conversationId:e.conversationId,conversationType:e.conversationType,senderId:m.getSelfId(),contentType:"contact",body:g(u),createdAt:r,sortKey:s(r,o),status:"pending",receipt:"unread",encryption:f(a),...void 0===e.refMessageId?{}:{refMessageId:e.refMessageId}},l={id:o,conversationId:e.conversationId,conversationType:e.conversationType,contentType:"contact",body:g(u),encryption:f(a),status:"pending",attempts:0,createdAt:r,...void 0===e.refMessageId?{}:{refMessageId:e.refMessageId}};return w.set(o,l),$(l),N(l,"queued"),m.domainState.upsertMessages([p],"live",{newOutgoing:!0}),i?(c&&X(l),v(l)):(G(o,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.enqueueContact"),retryable:!1}),v(l))},enqueueMedia(e){const{id:n,createdAt:o}=e,r=g(e.body);t(e.contentType,r,"outbox.enqueueMedia"),K(e,o);const a=void 0!==M.resolve(e.conversationType),i=a&&m.isAuthenticated(),c={id:n,conversationId:e.conversationId,conversationType:e.conversationType,senderId:m.getSelfId(),contentType:e.contentType,body:g(r),createdAt:o,sortKey:s(o,n),status:"pending",receipt:"unread",encryption:f(e.encryption),...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}},u={id:n,conversationId:e.conversationId,conversationType:e.conversationType,contentType:e.contentType,body:r,encryption:f(e.encryption),status:"pending",attempts:0,createdAt:o,...void 0!==e.mention?{mention:f(e.mention)}:{},...void 0!==e.refMessageId?{refMessageId:e.refMessageId}:{}};return w.set(n,u),$(u),N(u,"queued"),m.domainState.upsertMessages([c],"live",{newOutgoing:!0!==e.optimisticAlreadyCreated}),a?(i&&X(u),v(u)):(G(n,{code:-3,reason:"unsupported",displayCode:"conversationUnsupported",params:{type:e.conversationType},message:d(e.conversationType,"outbox.enqueueMedia"),retryable:!1}),X(u,!0),v(u))},onChatAck(e){L(e.id);const t=w.get(e.id);if(void 0!==t)if(u.has(e.errcode))w.delete(e.id),B(e.id),z(e.id,{status:"sent",serverTime:e.serverTime>0?e.serverTime:void 0,...void 0===e.extensions?{}:{extensions:{...m.domainState.getConversationMessage(t,e.id)?.extensions,...e.extensions}}},{entry:t}),N(t,"sent"),J(e.id);else{t.status="failed",t.lastError=e.failure??r(e.errcode);const n="direct"===t.conversationType&&p.has(e.errcode),o="direct"===t.conversationType&&e.errcode===l;n?t.lastError={...t.lastError,displayCode:"contactRequired",retryable:!1}:o&&(t.lastError={...t.lastError,displayCode:"messageRefused",retryable:!1}),z(e.id,{status:"failed",failure:t.lastError},{authoritativeFailure:!0}),n?m.domainState.appendDirectContactRequiredNotice(t.conversationId,t.id):o&&m.domainState.appendDirectMessageRefusedNotice(t.conversationId,t.id),$(t),N(t,"failed"),J(e.id)}else u.has(e.errcode)||function(e){if(!y.has(e.errcode))return;const t=m.getSelfId(),n=m.domainState.getMessagesById(e.id).filter(e=>"direct"===e.conversationType&&e.senderId===t);if(n.length>1)throw new Error(`DIRECT 终态 ACK 消息 ID 存在多会话歧义:${e.id}`);const o=n[0];if(void 0===o)return;const s=p.has(e.errcode),a=e.errcode===l;let i=e.failure??r(e.errcode);s?i={...i,displayCode:"contactRequired",retryable:!1}:a&&(i={...i,displayCode:"messageRefused",retryable:!1}),m.domainState.upsertMessages([{...o,status:"failed",failure:i}],"live",{authoritativeOutboxFailure:!0}),s?m.domainState.appendDirectContactRequiredNotice(o.conversationId,o.id):a&&m.domainState.appendDirectMessageRefusedNotice(o.conversationId,o.id)}(e)},onAuthenticated(){!function(){const e=/* @__PURE__ */new Set;for(const t of w.values())V(t)&&e.add(P(t));for(const t of e)Z(t,!0)}()},retry(e){const t=w.get(e);return void 0===t?{accepted:!1,reason:"not-found"}:"sending"===t.status||x.has(e)?{accepted:!1,reason:"in-flight"}:"failed"===t.status&&!1===t.lastError?.retryable?{accepted:!1,reason:"not-retryable"}:"failed"===t.status||"pending"===t.status&&"manual"===t.resumePolicy?("manual"===t.resumePolicy&&(t.resumePolicy="automatic",$(t)),O.add(t.id),X(t),{accepted:!0}):{accepted:!1,reason:"invalid-state"}},cancel(e){const t=w.get(e);return void 0===t?{accepted:!1,reason:"not-found"}:"sending"===t.status||x.has(e)?{accepted:!1,reason:"in-flight"}:"pending"!==t.status?{accepted:!1,reason:"invalid-state"}:t.attempts>0?{accepted:!1,reason:"delivery-uncertain"}:(_(t),{accepted:!0})},markConversationTerminated(e,t){const n=P(e);E.add(n);for(const e of[...w.values()])P(e)===n&&("pending"!==e.status||0!==e.attempts||x.has(e.id)?G(e.id,{code:-4,reason:"unknown",displayCode:"unknown",message:`会话成员关系已终止:${t}`,retryable:!1}):_(e))},clearConversationTerminated(e){const t=P(e);E.delete(t),Z(t)},markForLogout(e){for(const t of w.values())if("pending"===t.status||"sending"===t.status||"failed"===t.status){if(L(t.id),t.resumePolicy="manual","fail"===e.policy){const e={code:-2,reason:"unknown",displayCode:"sessionLoggedOut",retryable:!0};t.status="failed",t.lastError=e,z(t.id,{status:"failed",failure:e}),N(t,"failed")}$(t),J(t.id)}},getPending:()=>[...w.values()].map(v),reset(e){e?.discardInFlight&&(C+=1,x.clear(),k.clear(),q.clear(),F.clear());for(const e of[...A.keys()])L(e);for(const e of w.values())"sending"===e.status&&(e.status="pending",z(e.id,{status:"pending"}),$(e),N(e,"queued"),J(e.id))},async hydrate(e=()=>!0){if(void 0!==m.storage&&e())try{const o=await m.storage.getOutbox();if(!e())return;for(const r of o){if(!e())return;const o=v(r);if("sent"===o.status){B(o.id);continue}try{t(o.contentType,o.body,`outbox.hydrate(${o.id})`),void 0!==o.body.video&&(o.body={...o.body,video:n(o.body.video)})}catch(t){if(m.onStorageError?.(`Outbox 持久化条目正文损坏,已删除(id=${o.id})`,t),!e())return;if(B(o.id),void 0!==m.domainState.getConversationMessage(o,o.id)){const e={code:-2,reason:"unknown",displayCode:"unknown",message:"发送账本正文损坏,已停止重试",retryable:!1};z(o.id,{status:"failed",failure:e},{authoritativeFailure:!0,entry:o})}continue}const s="sending"===o.status?"pending":o.status,a={...o,status:s};if(w.set(o.id,a),K(a,a.createdAt),N(a,"pending"===s?"queued":s),!e())return;void 0!==m.domainState.getConversationMessage(o,o.id)&&z(o.id,{status:s,failure:void 0===o.lastError?void 0:f(o.lastError)})}}catch(t){e()&&m.onStorageError?.("Outbox 回读失败",t)}}}}export{m as createOutboxManager};
|
package/dist/sdk.d.ts
CHANGED
|
@@ -2917,9 +2917,9 @@ interface TextMessageOptions {
|
|
|
2917
2917
|
mentions?: readonly MentionInput[];
|
|
2918
2918
|
replyToMessageId?: string;
|
|
2919
2919
|
}
|
|
2920
|
-
/**
|
|
2920
|
+
/** 可主动分享的名片。未知 wire 类别只保留接收,不能放进发送入参。 */
|
|
2921
2921
|
type ContactCardInput = Omit<ImContactBody, 'kind' | 'rawKind'> & {
|
|
2922
|
-
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel'>;
|
|
2922
|
+
kind: Extract<ImContactBody['kind'], 'individual' | 'group' | 'channel' | 'robot'>;
|
|
2923
2923
|
};
|
|
2924
2924
|
/** 名片发送附加数据;回复关系与其它可发送消息使用同一稳定消息 id。 */
|
|
2925
2925
|
interface ContactMessageOptions {
|