feat(channels): emit line and zalo binary attachment fallback notices
This commit is contained in:
@@ -3646,6 +3646,20 @@
|
|||||||
"docs/plans/state.json"
|
"docs/plans/state.json"
|
||||||
],
|
],
|
||||||
"test_status": "pnpm test:run src/skills/planner.test.ts src/cli/skills.test.ts + pnpm typecheck passing"
|
"test_status": "pnpm test:run src/skills/planner.test.ts src/cli/skills.test.ts + pnpm typecheck passing"
|
||||||
|
},
|
||||||
|
"line-zalo-binary-fallback-notices": {
|
||||||
|
"status": "completed",
|
||||||
|
"date": "2026-02-17",
|
||||||
|
"updated": "2026-02-17",
|
||||||
|
"summary": "Improved LINE/Zalo binary attachment handling by emitting recipient-visible fallback messages whenever raw binary upload is unavailable, preventing silent loss while preserving warning logs.",
|
||||||
|
"files_modified": [
|
||||||
|
"src/channels/line/adapter.ts",
|
||||||
|
"src/channels/line/adapter.test.ts",
|
||||||
|
"src/channels/zalo/adapter.ts",
|
||||||
|
"src/channels/zalo/adapter.test.ts",
|
||||||
|
"docs/plans/state.json"
|
||||||
|
],
|
||||||
|
"test_status": "pnpm test:run src/channels/line/adapter.test.ts src/channels/zalo/adapter.test.ts + pnpm typecheck passing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overall_progress": {
|
"overall_progress": {
|
||||||
|
|||||||
@@ -95,9 +95,11 @@ describe('LineAdapter', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledTimes(2);
|
expect(mockFetch).toHaveBeenCalledTimes(3);
|
||||||
const secondBody = JSON.parse(String(mockFetch.mock.calls[1]?.[1]?.body ?? '{}'));
|
const secondBody = JSON.parse(String(mockFetch.mock.calls[1]?.[1]?.body ?? '{}'));
|
||||||
|
const thirdBody = JSON.parse(String(mockFetch.mock.calls[2]?.[1]?.body ?? '{}'));
|
||||||
expect(secondBody.messages?.[0]?.text).toBe('file.txt: https://example.com/file.txt');
|
expect(secondBody.messages?.[0]?.text).toBe('file.txt: https://example.com/file.txt');
|
||||||
|
expect(thirdBody.messages?.[0]?.text).toBe('[LINE] Binary attachment not uploaded yet: attachment (image/png).');
|
||||||
expect(warnSpy).toHaveBeenCalledWith('LINE: skipping attachment data (image/png) — upload not implemented');
|
expect(warnSpy).toHaveBeenCalledWith('LINE: skipping attachment data (image/png) — upload not implemented');
|
||||||
warnSpy.mockRestore();
|
warnSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export class LineAdapter implements ChannelAdapter {
|
|||||||
}
|
}
|
||||||
if (attachment.data) {
|
if (attachment.data) {
|
||||||
console.warn(`LINE: skipping attachment data (${attachment.mimeType}) — upload not implemented`);
|
console.warn(`LINE: skipping attachment data (${attachment.mimeType}) — upload not implemented`);
|
||||||
|
await this.sendPush(peerId, formatBinaryAttachmentNotice('LINE', attachment.filename, attachment.mimeType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,3 +241,9 @@ export class LineAdapter implements ChannelAdapter {
|
|||||||
function escapeRegex(value: string): string {
|
function escapeRegex(value: string): string {
|
||||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatBinaryAttachmentNotice(channel: string, filename?: string, mimeType?: string): string {
|
||||||
|
const name = filename || 'attachment';
|
||||||
|
const type = mimeType || 'application/octet-stream';
|
||||||
|
return `[${channel}] Binary attachment not uploaded yet: ${name} (${type}).`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,9 +81,11 @@ describe('ZaloAdapter', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mockFetch).toHaveBeenCalledTimes(2);
|
expect(mockFetch).toHaveBeenCalledTimes(3);
|
||||||
const secondBody = JSON.parse(String(mockFetch.mock.calls[1]?.[1]?.body ?? '{}'));
|
const secondBody = JSON.parse(String(mockFetch.mock.calls[1]?.[1]?.body ?? '{}'));
|
||||||
|
const thirdBody = JSON.parse(String(mockFetch.mock.calls[2]?.[1]?.body ?? '{}'));
|
||||||
expect(secondBody.message?.text).toBe('file.txt: https://example.com/file.txt');
|
expect(secondBody.message?.text).toBe('file.txt: https://example.com/file.txt');
|
||||||
|
expect(thirdBody.message?.text).toBe('[Zalo] Binary attachment not uploaded yet: attachment (application/pdf).');
|
||||||
expect(warnSpy).toHaveBeenCalledWith('Zalo: skipping attachment data (application/pdf) — upload not implemented');
|
expect(warnSpy).toHaveBeenCalledWith('Zalo: skipping attachment data (application/pdf) — upload not implemented');
|
||||||
warnSpy.mockRestore();
|
warnSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export class ZaloAdapter implements ChannelAdapter {
|
|||||||
}
|
}
|
||||||
if (attachment.data) {
|
if (attachment.data) {
|
||||||
console.warn(`Zalo: skipping attachment data (${attachment.mimeType}) — upload not implemented`);
|
console.warn(`Zalo: skipping attachment data (${attachment.mimeType}) — upload not implemented`);
|
||||||
|
await this.sendText(peerId, formatBinaryAttachmentNotice('Zalo', attachment.filename, attachment.mimeType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,3 +190,9 @@ export class ZaloAdapter implements ChannelAdapter {
|
|||||||
function escapeRegex(value: string): string {
|
function escapeRegex(value: string): string {
|
||||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatBinaryAttachmentNotice(channel: string, filename?: string, mimeType?: string): string {
|
||||||
|
const name = filename || 'attachment';
|
||||||
|
const type = mimeType || 'application/octet-stream';
|
||||||
|
return `[${channel}] Binary attachment not uploaded yet: ${name} (${type}).`;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user