@superblocksteam/shared 0.9611.0 → 2.0.0-SNAPSHOT.4665a67985a1ea20
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/socket/heartbeat.d.ts +10 -0
- package/dist/socket/heartbeat.d.ts.map +1 -1
- package/dist/socket/heartbeat.js +5 -0
- package/dist/socket/heartbeat.js.map +1 -1
- package/dist/socket/heartbeat.test.js +36 -0
- package/dist/socket/heartbeat.test.js.map +1 -1
- package/dist/socket/socket.d.ts +1 -0
- package/dist/socket/socket.d.ts.map +1 -1
- package/dist/socket/socket.js +8 -1
- package/dist/socket/socket.js.map +1 -1
- package/dist/socket/socket.test.js +33 -0
- package/dist/socket/socket.test.js.map +1 -1
- package/dist/utils/attachment-upload.d.ts +9 -0
- package/dist/utils/attachment-upload.d.ts.map +1 -1
- package/dist/utils/attachment-upload.js +26 -0
- package/dist/utils/attachment-upload.js.map +1 -1
- package/dist/utils/attachment-upload.test.js +19 -0
- package/dist/utils/attachment-upload.test.js.map +1 -1
- package/dist-esm/socket/heartbeat.d.ts +10 -0
- package/dist-esm/socket/heartbeat.d.ts.map +1 -1
- package/dist-esm/socket/heartbeat.js +5 -0
- package/dist-esm/socket/heartbeat.js.map +1 -1
- package/dist-esm/socket/heartbeat.test.js +36 -0
- package/dist-esm/socket/heartbeat.test.js.map +1 -1
- package/dist-esm/socket/socket.d.ts +1 -0
- package/dist-esm/socket/socket.d.ts.map +1 -1
- package/dist-esm/socket/socket.js +8 -1
- package/dist-esm/socket/socket.js.map +1 -1
- package/dist-esm/socket/socket.test.js +33 -0
- package/dist-esm/socket/socket.test.js.map +1 -1
- package/dist-esm/utils/attachment-upload.d.ts +9 -0
- package/dist-esm/utils/attachment-upload.d.ts.map +1 -1
- package/dist-esm/utils/attachment-upload.js +25 -0
- package/dist-esm/utils/attachment-upload.js.map +1 -1
- package/dist-esm/utils/attachment-upload.test.js +20 -1
- package/dist-esm/utils/attachment-upload.test.js.map +1 -1
- package/package.json +1 -1
- package/src/socket/heartbeat.test.ts +44 -0
- package/src/socket/heartbeat.ts +15 -0
- package/src/socket/socket.test.ts +43 -0
- package/src/socket/socket.ts +10 -1
- package/src/utils/attachment-upload.test.ts +22 -0
- package/src/utils/attachment-upload.ts +28 -0
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { ATTACHMENT_CONTENT_MISMATCH_CODE, buildAttachmentUploadMetadata, buildAttachmentUploadFormData, createUploadedAttachmentFromServer, getTextAttachmentType, parseUserFacingUploadError, isOfficeXml, normalizeAttachmentMimeType, toAttachmentUploadDescriptor } from './attachment-upload.js';
|
|
2
|
+
import { ATTACHMENT_CONTENT_MISMATCH_CODE, buildAttachmentUploadMetadata, buildAttachmentUploadFormData, createUploadedAttachmentFromServer, getAttachmentMimeTypeFromFileName, getTextAttachmentType, parseUserFacingUploadError, isOfficeXml, normalizeAttachmentMimeType, toAttachmentUploadDescriptor } from './attachment-upload.js';
|
|
3
|
+
describe('getAttachmentMimeTypeFromFileName', () => {
|
|
4
|
+
test.each([
|
|
5
|
+
['logo.png', 'image/png'],
|
|
6
|
+
['logo.PNG', 'image/png'],
|
|
7
|
+
['photo.jpg', 'image/jpeg'],
|
|
8
|
+
['photo.jpeg', 'image/jpeg'],
|
|
9
|
+
['animation.gif', 'image/gif'],
|
|
10
|
+
['shot.webp', 'image/webp'],
|
|
11
|
+
['report.pdf', 'application/pdf'],
|
|
12
|
+
['server.log', 'text/plain'],
|
|
13
|
+
['rows.csv', 'text/csv'],
|
|
14
|
+
['config.json', 'application/json']
|
|
15
|
+
])('reads %s as %s', (fileName, expected) => {
|
|
16
|
+
expect(getAttachmentMimeTypeFromFileName(fileName)).toBe(expected);
|
|
17
|
+
});
|
|
18
|
+
test.each(['app.exe', 'archive.dmg', 'noextension', ''])('has no type for %s', (fileName) => {
|
|
19
|
+
expect(getAttachmentMimeTypeFromFileName(fileName)).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
3
22
|
describe('toAttachmentUploadDescriptor', () => {
|
|
4
23
|
test('preserves explicit names for non-File uploads', () => {
|
|
5
24
|
const descriptor = toAttachmentUploadDescriptor({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-upload.test.js","sourceRoot":"","sources":["../../src/utils/attachment-upload.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"attachment-upload.test.js","sourceRoot":"","sources":["../../src/utils/attachment-upload.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -101,6 +101,50 @@ describe('SocketHeartbeat', () => {
|
|
|
101
101
|
subject.stop();
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
+
// A refusal is the only outcome where the peer stated why, and a refusal does
|
|
105
|
+
// not clear the counts around it. A silence afterwards overwrites `lastError`
|
|
106
|
+
// with its own generic cause, so the stated one has to be kept apart or the
|
|
107
|
+
// death report attributes a timeout's message to the refusal it still counts.
|
|
108
|
+
it('keeps the refusal reason when a later silence overwrites lastError', async () => {
|
|
109
|
+
const { refuseLast, subject } = heartbeat();
|
|
110
|
+
subject.start();
|
|
111
|
+
subject.recordReceive();
|
|
112
|
+
|
|
113
|
+
await elapse(INTERVAL_MS);
|
|
114
|
+
refuseLast(new Error('sandbox is shutting down (code 7)'));
|
|
115
|
+
await elapse(1);
|
|
116
|
+
|
|
117
|
+
// The beat after it is never answered at all, so it times out.
|
|
118
|
+
await elapse(INTERVAL_MS);
|
|
119
|
+
await elapse(TIMEOUT_MS + 1);
|
|
120
|
+
|
|
121
|
+
expect(subject.account).toMatchObject({
|
|
122
|
+
lastRefusalError: 'sandbox is shutting down (code 7)',
|
|
123
|
+
refusals: 1
|
|
124
|
+
});
|
|
125
|
+
expect(subject.account.lastError).not.toBe('sandbox is shutting down (code 7)');
|
|
126
|
+
subject.stop();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// An answered beat settles the account outright, so a refusal it supersedes
|
|
130
|
+
// must not keep explaining a connection that has since proved healthy.
|
|
131
|
+
it('drops the refusal reason once a beat is answered', async () => {
|
|
132
|
+
const { answerLast, refuseLast, subject } = heartbeat();
|
|
133
|
+
subject.start();
|
|
134
|
+
subject.recordReceive();
|
|
135
|
+
|
|
136
|
+
await elapse(INTERVAL_MS);
|
|
137
|
+
refuseLast(new Error('sandbox is shutting down (code 7)'));
|
|
138
|
+
await elapse(1);
|
|
139
|
+
|
|
140
|
+
await elapse(INTERVAL_MS);
|
|
141
|
+
answerLast();
|
|
142
|
+
await elapse(1);
|
|
143
|
+
|
|
144
|
+
expect(subject.account.lastRefusalError).toBeUndefined();
|
|
145
|
+
subject.stop();
|
|
146
|
+
});
|
|
147
|
+
|
|
104
148
|
// A refusal is an answer: the peer is reachable and the request channel works,
|
|
105
149
|
// so whatever is wrong is not the connection. Spending the grace meant for a
|
|
106
150
|
// starved pong on one would tear a working socket down over an
|
package/src/socket/heartbeat.ts
CHANGED
|
@@ -76,6 +76,16 @@ export type HeartbeatAccount = {
|
|
|
76
76
|
*/
|
|
77
77
|
readonly lapses: number;
|
|
78
78
|
readonly lastError?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Why the peer refused, kept apart from {@link HeartbeatAccount.lastError}.
|
|
81
|
+
*
|
|
82
|
+
* A refusal is the only outcome where the peer said why, and it clears none
|
|
83
|
+
* of the counts around it - so a silence after one leaves `refusals` standing
|
|
84
|
+
* while overwriting `lastError` with its own generic cause. A report reading
|
|
85
|
+
* only `lastError` would then attribute a timeout's message to the refusal.
|
|
86
|
+
* Cleared by an answered beat, which settles the whole account.
|
|
87
|
+
*/
|
|
88
|
+
readonly lastRefusalError?: string;
|
|
79
89
|
readonly lastReceivedAt?: number;
|
|
80
90
|
readonly lastSuccessAt?: number;
|
|
81
91
|
/**
|
|
@@ -411,6 +421,7 @@ export class SocketHeartbeat {
|
|
|
411
421
|
this.state.lastSuccessAt = Date.now();
|
|
412
422
|
this.lost = false;
|
|
413
423
|
delete this.state.lastError;
|
|
424
|
+
delete this.state.lastRefusalError;
|
|
414
425
|
return 'success';
|
|
415
426
|
}
|
|
416
427
|
|
|
@@ -429,6 +440,10 @@ export class SocketHeartbeat {
|
|
|
429
440
|
// silence that counter is the only thing left that can end one.
|
|
430
441
|
this.state.refusals += 1;
|
|
431
442
|
this.state.lastError = describe(error);
|
|
443
|
+
// Kept apart because the next unanswered beat overwrites `lastError`
|
|
444
|
+
// without clearing `refusals`, and the peer's own reason is the one thing
|
|
445
|
+
// in this account that was stated rather than inferred.
|
|
446
|
+
this.state.lastRefusalError = this.state.lastError;
|
|
432
447
|
return 'refused';
|
|
433
448
|
}
|
|
434
449
|
// Saturating rather than growing: this is what the caller reports as the
|
|
@@ -7,6 +7,49 @@ import { ISocketWithClientAuth } from './socketWithClientAuth.js';
|
|
|
7
7
|
const PING_TIMEOUT_CLOSE_REASON = 'Ping timeout';
|
|
8
8
|
|
|
9
9
|
describe('ISocket', () => {
|
|
10
|
+
it('preserves safe fields from structured handler errors', async () => {
|
|
11
|
+
let messageHandler: ((event: { data: string }) => void) | undefined;
|
|
12
|
+
const ws = {
|
|
13
|
+
addEventListener: vi.fn((event: string, handler: (event: { data: string }) => void) => {
|
|
14
|
+
if (event === 'message') {
|
|
15
|
+
messageHandler = handler;
|
|
16
|
+
}
|
|
17
|
+
}),
|
|
18
|
+
close: vi.fn(),
|
|
19
|
+
send: vi.fn()
|
|
20
|
+
};
|
|
21
|
+
new ISocket(
|
|
22
|
+
ws as never,
|
|
23
|
+
{
|
|
24
|
+
editor: {
|
|
25
|
+
save: [
|
|
26
|
+
async () => {
|
|
27
|
+
throw { code: 2, status: 503, message: 'checkpoint unavailable', details: 'do not expose' };
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
} as never,
|
|
32
|
+
[],
|
|
33
|
+
{ onClose: vi.fn() }
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
messageHandler?.({
|
|
37
|
+
data: JSON.stringify({ request: { id: 1, method: 'editor.save', payload: {} } })
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await vi.waitFor(() => {
|
|
41
|
+
expect(ws.send).toHaveBeenCalledWith(
|
|
42
|
+
JSON.stringify({
|
|
43
|
+
response: {
|
|
44
|
+
payload: null,
|
|
45
|
+
id: 1,
|
|
46
|
+
error: { code: 2, status: 503, message: 'checkpoint unavailable' }
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
10
53
|
it('clears abort cleanup when a no-response timeout rejects the request', async () => {
|
|
11
54
|
vi.useFakeTimers();
|
|
12
55
|
try {
|
package/src/socket/socket.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface SocketMessage<RequestPayload = unknown, ResponsePayload = unkno
|
|
|
40
40
|
export interface SocketError {
|
|
41
41
|
message: string;
|
|
42
42
|
code: number;
|
|
43
|
+
status?: number;
|
|
43
44
|
stack?: string;
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -220,10 +221,18 @@ export class ISocket<ImplementedMethods, CallableMethods, RequestContext extends
|
|
|
220
221
|
// call the first handler in the chain
|
|
221
222
|
response = await generateNextFn(0)();
|
|
222
223
|
} catch (error) {
|
|
224
|
+
const structuredError =
|
|
225
|
+
typeof error === 'object' && error !== null && 'message' in error && typeof error.message === 'string' ? error : undefined;
|
|
223
226
|
const socketError =
|
|
224
227
|
error instanceof SocketErrorException
|
|
225
228
|
? { code: error.code, message: error.message, stack: error.stack }
|
|
226
|
-
:
|
|
229
|
+
: structuredError && !(structuredError instanceof Error)
|
|
230
|
+
? {
|
|
231
|
+
code: 'code' in structuredError && typeof structuredError.code === 'number' ? structuredError.code : 3,
|
|
232
|
+
status: 'status' in structuredError && typeof structuredError.status === 'number' ? structuredError.status : undefined,
|
|
233
|
+
message: structuredError.message
|
|
234
|
+
}
|
|
235
|
+
: { code: 3, message: String(error), stack: error instanceof Error ? error.stack : undefined };
|
|
227
236
|
this.logger.error(JSON.stringify(socketError));
|
|
228
237
|
return this.respondError(message.request.id, socketError, error);
|
|
229
238
|
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
buildAttachmentUploadMetadata,
|
|
6
6
|
buildAttachmentUploadFormData,
|
|
7
7
|
createUploadedAttachmentFromServer,
|
|
8
|
+
getAttachmentMimeTypeFromFileName,
|
|
8
9
|
getTextAttachmentType,
|
|
9
10
|
parseUserFacingUploadError,
|
|
10
11
|
isOfficeXml,
|
|
@@ -12,6 +13,27 @@ import {
|
|
|
12
13
|
toAttachmentUploadDescriptor
|
|
13
14
|
} from './attachment-upload.js';
|
|
14
15
|
|
|
16
|
+
describe('getAttachmentMimeTypeFromFileName', () => {
|
|
17
|
+
test.each([
|
|
18
|
+
['logo.png', 'image/png'],
|
|
19
|
+
['logo.PNG', 'image/png'],
|
|
20
|
+
['photo.jpg', 'image/jpeg'],
|
|
21
|
+
['photo.jpeg', 'image/jpeg'],
|
|
22
|
+
['animation.gif', 'image/gif'],
|
|
23
|
+
['shot.webp', 'image/webp'],
|
|
24
|
+
['report.pdf', 'application/pdf'],
|
|
25
|
+
['server.log', 'text/plain'],
|
|
26
|
+
['rows.csv', 'text/csv'],
|
|
27
|
+
['config.json', 'application/json']
|
|
28
|
+
])('reads %s as %s', (fileName, expected) => {
|
|
29
|
+
expect(getAttachmentMimeTypeFromFileName(fileName)).toBe(expected);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test.each(['app.exe', 'archive.dmg', 'noextension', ''])('has no type for %s', (fileName) => {
|
|
33
|
+
expect(getAttachmentMimeTypeFromFileName(fileName)).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
15
37
|
describe('toAttachmentUploadDescriptor', () => {
|
|
16
38
|
test('preserves explicit names for non-File uploads', () => {
|
|
17
39
|
const descriptor = toAttachmentUploadDescriptor({
|
|
@@ -291,6 +291,34 @@ function getTextLikeMimeTypeFromFileName(fileName: string | undefined): string |
|
|
|
291
291
|
return textAttachmentType ? TEXT_ATTACHMENT_MIME_TYPES[textAttachmentType] : undefined;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Names the media type for a file that arrives with nothing but a name, as it
|
|
296
|
+
* does when a caller points at a path instead of handing over the bytes.
|
|
297
|
+
*
|
|
298
|
+
* Derived from {@link MIME_TYPE_FILE_EXTENSIONS} rather than a general-purpose
|
|
299
|
+
* MIME database so the answer stays inside what attachments actually accept:
|
|
300
|
+
* a wider lookup would name a type for `.exe` that upload then refuses.
|
|
301
|
+
*/
|
|
302
|
+
export function getAttachmentMimeTypeFromFileName(fileName?: string): string | undefined {
|
|
303
|
+
const normalizedFileName = normalizeNonEmptyString(fileName)?.toLowerCase();
|
|
304
|
+
if (!normalizedFileName) {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const [mimeType, extension] of Object.entries(MIME_TYPE_FILE_EXTENSIONS)) {
|
|
309
|
+
// '.jpeg' resolves through the text-like pass below only if listed there,
|
|
310
|
+
// so both spellings are matched here against the canonical extension.
|
|
311
|
+
if (normalizedFileName.endsWith(extension)) {
|
|
312
|
+
return mimeType === 'image/jpg' ? 'image/jpeg' : mimeType;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (normalizedFileName.endsWith('.jpeg')) {
|
|
316
|
+
return 'image/jpeg';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return getTextLikeMimeTypeFromFileName(normalizedFileName);
|
|
320
|
+
}
|
|
321
|
+
|
|
294
322
|
function isProviderSafeTextMimeType(mimeType: string): boolean {
|
|
295
323
|
return mimeType.startsWith('text/') || mimeType === 'application/json';
|
|
296
324
|
}
|