openclaw-quiubo 2.6.35 → 2.6.36

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/index.js CHANGED
@@ -9234,6 +9234,28 @@ var QuiuboApiClient = class {
9234
9234
  });
9235
9235
  }
9236
9236
  // ========================================================================
9237
+ // Posts
9238
+ // ========================================================================
9239
+ /**
9240
+ * Create a post as an SDK-owned identity. Returns presigned upload URL and post metadata.
9241
+ */
9242
+ async createPost(opts) {
9243
+ return this.request("POST", "/posts/presign", opts);
9244
+ }
9245
+ /**
9246
+ * List posts by SDK identities (optionally filter by identity)
9247
+ */
9248
+ async listPosts(identityId) {
9249
+ const query = identityId ? `?identity_id=${identityId}` : "";
9250
+ return this.request("GET", `/posts${query}`);
9251
+ }
9252
+ /**
9253
+ * Delete a post authored by an SDK identity
9254
+ */
9255
+ async deletePost(postId) {
9256
+ return this.request("DELETE", `/posts/${postId}`);
9257
+ }
9258
+ // ========================================================================
9237
9259
  // Attachment Upload
9238
9260
  // ========================================================================
9239
9261
  /**
@@ -13440,6 +13462,7 @@ var quiuboPlugin = {
13440
13462
  capabilities: {
13441
13463
  chatTypes: ["group"],
13442
13464
  supportsMedia: true,
13465
+ supportsPosts: true,
13443
13466
  supportsReactions: false,
13444
13467
  supportsThreads: false
13445
13468
  },
@@ -13821,6 +13844,86 @@ var quiuboPlugin = {
13821
13844
  log?.error?.(`[${accountId}] [outbound:sendMedia] SEND FAILED [network] group=${groupId} \u2014 ${msg}`);
13822
13845
  return { ok: false, error: msg };
13823
13846
  }
13847
+ },
13848
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13849
+ async createPost(ctx) {
13850
+ const text = ctx.text || ctx.caption || "";
13851
+ const urls = [];
13852
+ if (ctx.mediaUrl) urls.push(ctx.mediaUrl);
13853
+ if (Array.isArray(ctx.mediaUrls)) urls.push(...ctx.mediaUrls);
13854
+ const accountId = ctx.accountId ?? DEFAULT_ACCOUNT_ID;
13855
+ const log = loggers.get(accountId);
13856
+ let client = clients.get(accountId);
13857
+ let account = accounts.get(accountId);
13858
+ if (!client || !account) {
13859
+ const acct = getChannelConfig(ctx.cfg)?.accounts?.[accountId];
13860
+ if (!acct?.apiKey) {
13861
+ log?.warn?.(`[${accountId}] [outbound:createPost] no account config found`);
13862
+ return { ok: false, error: "No account config found" };
13863
+ }
13864
+ const apiUrl = acct.apiUrl ?? DEFAULT_API_URL;
13865
+ client = new QuiuboApiClient(apiUrl, acct.apiKey);
13866
+ account = { ...acct, accountId };
13867
+ clients.set(accountId, client);
13868
+ accounts.set(accountId, account);
13869
+ }
13870
+ let groupId = resolveOutboundGroupId(ctx);
13871
+ if (!groupId) {
13872
+ groupId = await resolveAnnounceGroupId(accountId, log);
13873
+ }
13874
+ if (!groupId) {
13875
+ log?.error?.(`[${accountId}] [outbound:createPost] no groupId \u2014 ctx keys=${Object.keys(ctx).join(",")}`);
13876
+ return { ok: false, error: "No groupId in outbound context" };
13877
+ }
13878
+ const senderId = account.botIdentityId;
13879
+ if (!senderId) {
13880
+ return { ok: false, error: "No botIdentityId configured" };
13881
+ }
13882
+ let imageBuffer;
13883
+ let imageContentType;
13884
+ for (const url of urls) {
13885
+ const filename = basename(url);
13886
+ const ext = filename.substring(filename.lastIndexOf(".")).toLowerCase();
13887
+ if (ext in IMAGE_MIME_TYPES) {
13888
+ try {
13889
+ imageBuffer = await readFile2(url);
13890
+ imageContentType = IMAGE_MIME_TYPES[ext];
13891
+ if (imageBuffer.length > MAX_IMAGE_BYTES) {
13892
+ log?.warn?.(`[${accountId}] [outbound:createPost] skipping ${filename} \u2014 exceeds 5MB (${imageBuffer.length} bytes)`);
13893
+ imageBuffer = void 0;
13894
+ imageContentType = void 0;
13895
+ continue;
13896
+ }
13897
+ break;
13898
+ } catch (err) {
13899
+ log?.warn?.(`[${accountId}] [outbound:createPost] failed to read ${url}: ${err}`);
13900
+ }
13901
+ }
13902
+ }
13903
+ if (!imageBuffer || !imageContentType) {
13904
+ log?.error?.(`[${accountId}] [outbound:createPost] no valid image found in mediaUrls (posts require an image)`);
13905
+ return { ok: false, error: "Posts require an image \u2014 no valid image found in media URLs" };
13906
+ }
13907
+ log?.info?.(`[${accountId}] [outbound:createPost] groupId=${groupId}, text=${text?.length ?? 0} chars, image=${imageContentType} (${imageBuffer.length} bytes)`);
13908
+ try {
13909
+ const presign = await client.createPost({
13910
+ identityId: senderId,
13911
+ contentType: imageContentType,
13912
+ content: text || void 0,
13913
+ groupId
13914
+ });
13915
+ await client.uploadToPresignedUrl(presign.uploadUrl, imageBuffer, imageContentType);
13916
+ log?.info?.(`[${accountId}] [outbound:createPost] post ${presign.post.id} created in group ${groupId}, image uploaded to ${presign.imageUrl}`);
13917
+ return { ok: true };
13918
+ } catch (error) {
13919
+ if (error instanceof QuiuboApiError) {
13920
+ log?.error?.(`[${accountId}] [outbound:createPost] FAILED [${error.status}] group=${groupId} \u2014 ${error.body}`);
13921
+ return { ok: false, error: `${error.status}: ${error.body}` };
13922
+ }
13923
+ const msg = error instanceof Error ? error.message : String(error);
13924
+ log?.error?.(`[${accountId}] [outbound:createPost] FAILED [network] group=${groupId} \u2014 ${msg}`);
13925
+ return { ok: false, error: msg };
13926
+ }
13824
13927
  }
13825
13928
  },
13826
13929
  // ── gateway adapter ─────────────────────────────────────────────