lemon-model 1.4.0 → 1.5.1
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/esm/upload/engine/engine.js +49 -11
- package/dist/esm/upload/engine/engine.js.map +1 -1
- package/dist/esm/upload/engine/executors.js +2 -2
- package/dist/esm/upload/engine/executors.js.map +1 -1
- package/dist/esm/upload/engine/progress.js +1 -1
- package/dist/esm/upload/testing.js +28 -21
- package/dist/esm/upload/testing.js.map +1 -1
- package/dist/esm/upload/types.js +34 -14
- package/dist/esm/upload/types.js.map +1 -1
- package/dist/upload/engine/engine.d.ts +30 -9
- package/dist/upload/engine/engine.js +49 -11
- package/dist/upload/engine/engine.js.map +1 -1
- package/dist/upload/engine/executors.d.ts +7 -7
- package/dist/upload/engine/executors.js +2 -2
- package/dist/upload/engine/executors.js.map +1 -1
- package/dist/upload/engine/progress.d.ts +1 -1
- package/dist/upload/engine/progress.js +1 -1
- package/dist/upload/testing.d.ts +11 -9
- package/dist/upload/testing.js +29 -22
- package/dist/upload/testing.js.map +1 -1
- package/dist/upload/types.d.ts +105 -76
- package/dist/upload/types.js +36 -16
- package/dist/upload/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -31,14 +31,20 @@ const runPooled = (count, limit, task) => __awaiter(void 0, void 0, void 0, func
|
|
|
31
31
|
yield Promise.all(new Array(size).fill(0).map(() => worker()));
|
|
32
32
|
return results;
|
|
33
33
|
});
|
|
34
|
-
const
|
|
34
|
+
const asContent = (source) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
35
|
return ({
|
|
36
|
-
name: source.name,
|
|
37
36
|
contentType: source.contentType,
|
|
38
37
|
contentSize: source.contentSize,
|
|
38
|
+
width: source.width,
|
|
39
|
+
height: source.height,
|
|
39
40
|
hash: source.hash ? yield source.hash() : undefined,
|
|
40
41
|
});
|
|
41
42
|
});
|
|
43
|
+
const asIntent = (source) => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
return (Object.assign(Object.assign({}, (yield asContent(source))), { name: source.name, thumbnail: source.thumbnail ? yield asContent(source.thumbnail) : undefined }));
|
|
45
|
+
});
|
|
46
|
+
/** bytes this source puts on the wire in total; the thumbnail rides along so the bar counts it */
|
|
47
|
+
const sizeOf = (source) => { var _a, _b; return source.contentSize + ((_b = (_a = source.thumbnail) === null || _a === void 0 ? void 0 : _a.contentSize) !== null && _b !== void 0 ? _b : 0); };
|
|
42
48
|
export class UploadEngine {
|
|
43
49
|
constructor(service, executors, options) {
|
|
44
50
|
this.service = service;
|
|
@@ -50,9 +56,9 @@ export class UploadEngine {
|
|
|
50
56
|
upload(sources, onProgress) {
|
|
51
57
|
var _a, _b;
|
|
52
58
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
-
const tracker = new UploadProgressTracker(sources.map(
|
|
59
|
+
const tracker = new UploadProgressTracker(sources.map(sizeOf), onProgress);
|
|
54
60
|
tracker.publish();
|
|
55
|
-
const list = yield Promise.all(sources.map(
|
|
61
|
+
const list = yield Promise.all(sources.map(asIntent));
|
|
56
62
|
const { list: tickets } = yield this.service.start({ list, transfers: this.kinds });
|
|
57
63
|
const limit = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.concurrency) !== null && _b !== void 0 ? _b : UPLOAD_DEFAULT_CONCURRENCY;
|
|
58
64
|
const receipts = yield runPooled(tickets.length, limit, i => this.transferTracked(tickets[i], sources[i], tracker, i));
|
|
@@ -60,7 +66,7 @@ export class UploadEngine {
|
|
|
60
66
|
sources.forEach((_, i) => tracker.settle(i));
|
|
61
67
|
const pending = receipts.filter((item) => !!item);
|
|
62
68
|
const settled = pending.length ? (yield this.service.complete({ list: pending })).list : [];
|
|
63
|
-
const byId = new Map(settled.filter(
|
|
69
|
+
const byId = new Map(settled.filter(upload => !!upload.id).map((upload) => [upload.id, upload]));
|
|
64
70
|
return tickets.map(ticket => (ticket.upload.id && byId.get(ticket.upload.id)) || ticket.upload);
|
|
65
71
|
});
|
|
66
72
|
}
|
|
@@ -91,14 +97,46 @@ export class UploadEngine {
|
|
|
91
97
|
// rejected at start: nothing was created, nothing to complete
|
|
92
98
|
if (!id)
|
|
93
99
|
return undefined;
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
const receipt = yield this.transferOriginal(id, ticket.transfer, source, onProgress);
|
|
101
|
+
// a failed original has nothing to preview; otherwise the thumbnail rides after it (never with it)
|
|
102
|
+
if (!receipt.failure)
|
|
103
|
+
yield this.transferThumbnail(id, ticket.thumbnailTransfer, source, onProgress);
|
|
104
|
+
return receipt;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
transferOriginal(id, transfer, source, onProgress) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
// no instruction: already stored (dedup, or a stored upload taking only a thumbnail) — complete still confirms it
|
|
110
|
+
if (!transfer)
|
|
96
111
|
return { id };
|
|
97
|
-
const executor = this.executors.find(candidate =>
|
|
112
|
+
const executor = this.executors.find(candidate => candidate.kind === transfer.kind);
|
|
98
113
|
if (!executor)
|
|
99
114
|
return { id, failure: { source: UPLOAD_FAILURE_SOURCE.client, code: UPLOAD_FAILURE_CODE.notAcceptable } };
|
|
100
|
-
// NOTE: `
|
|
101
|
-
return executor.run(id,
|
|
115
|
+
// NOTE: `transfer` must not be logged or stored — it may carry a credential url
|
|
116
|
+
return executor.run(id, transfer, source, onProgress);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* the preview is subordinate: whatever happens here never reaches `complete`.
|
|
121
|
+
* - `UploadCompleteItem` is one per upload, so reporting a thumbnail failure would fail the original.
|
|
122
|
+
* - the server settles the thumbnail by looking at storage at `complete` time, so silence is enough.
|
|
123
|
+
*/
|
|
124
|
+
transferThumbnail(id, transfer, source, onProgress) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
const thumbnail = source.thumbnail;
|
|
127
|
+
if (!transfer || !thumbnail)
|
|
128
|
+
return;
|
|
129
|
+
const executor = this.executors.find(candidate => candidate.kind === transfer.kind);
|
|
130
|
+
if (!executor)
|
|
131
|
+
return;
|
|
132
|
+
// the original's bytes are already counted, so the thumbnail reports on top of them
|
|
133
|
+
const base = source.contentSize;
|
|
134
|
+
try {
|
|
135
|
+
yield executor.run(id, transfer, thumbnail, sent => onProgress(base + sent));
|
|
136
|
+
}
|
|
137
|
+
catch (_a) {
|
|
138
|
+
// swallowed on purpose: see the note above
|
|
139
|
+
}
|
|
102
140
|
});
|
|
103
141
|
}
|
|
104
142
|
}
|
|
@@ -141,7 +179,7 @@ export const asApiFailure = (error) => {
|
|
|
141
179
|
message: match[3],
|
|
142
180
|
};
|
|
143
181
|
};
|
|
144
|
-
/** S3 error `<Code>` -> normalized code
|
|
182
|
+
/** S3 error `<Code>` -> normalized code. unknown codes fall back by status */
|
|
145
183
|
const STORAGE_CODES = {
|
|
146
184
|
SignatureDoesNotMatch: UPLOAD_FAILURE_CODE.signature,
|
|
147
185
|
AccessDenied: UPLOAD_FAILURE_CODE.expired,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../../src/upload/engine/engine.ts"],"names":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../../src/upload/engine/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { UPLOAD_FAILURE_CODE, UPLOAD_FAILURE_SOURCE, UPLOAD_TRANSFER_KIND } from '../types.js';
|
|
11
11
|
import { asApiFailure, asStorageFailure } from './engine.js';
|
|
12
12
|
import { asContentBytes } from './progress.js';
|
|
13
|
-
/**
|
|
13
|
+
/** inline transfer — the only place that knows bytes go to the API as base64 */
|
|
14
14
|
export class InlineExecutor {
|
|
15
15
|
constructor(send,
|
|
16
16
|
/** shell-specific base64 encoder (btoa / Buffer / RN polyfill) */
|
|
@@ -36,7 +36,7 @@ export class InlineExecutor {
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
/**
|
|
39
|
+
/** presigned PUT transfer — raw bytes straight to storage */
|
|
40
40
|
export class PresignedPutExecutor {
|
|
41
41
|
constructor(put) {
|
|
42
42
|
this.put = put;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executors.js","sourceRoot":"","sources":["../../../../src/upload/engine/executors.ts"],"names":[],"mappings":";;;;;;;;;AAgBA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAE5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAS5C,
|
|
1
|
+
{"version":3,"file":"executors.js","sourceRoot":"","sources":["../../../../src/upload/engine/executors.ts"],"names":[],"mappings":";;;;;;;;;AAgBA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAE5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAS5C,gFAAgF;AAChF,MAAM,OAAO,cAAc;IAGvB,YACqB,IAAoB;IACrC,kEAAkE;IACjD,QAAuC;QAFvC,SAAI,GAAJ,IAAI,CAAgB;QAEpB,aAAQ,GAAR,QAAQ,CAA+B;QAL5C,SAAI,GAAG,oBAAoB,CAAC,MAAM,CAAC;IAMhD,CAAC;IAES,GAAG,CACZ,EAAU,EACV,QAA8B,EAC9B,MAA2B,EAC3B,UAA8B;;YAE9B,IAAI,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC,QAAQ,EAAE;gBACxC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,QAAQ,EAAE,EAAE,CAAC;aACxG;YACD,IAAI;gBACA,MAAM,IAAI,GAAsB,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;gBACjF,sEAAsE;gBACtE,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;gBAC5G,OAAO,EAAE,EAAE,EAAE,CAAC;aACjB;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;aAC/C;QACL,CAAC;KAAA;CACJ;AAaD,6DAA6D;AAC7D,MAAM,OAAO,oBAAoB;IAG7B,YAAoC,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QAF/B,SAAI,GAAG,oBAAoB,CAAC,YAAY,CAAC;IAEP,CAAC;IAEtC,GAAG,CACZ,EAAU,EACV,QAAoC,EACpC,MAA2B,EAC3B,UAA8B;;YAE9B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAC/F,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAChE,CAAC;YACF,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;gBAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACzD,6EAA6E;YAC7E,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACtC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACnE,CAAC;KAAA;CACJ"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* - progress is a CLIENT-LOCAL signal: nothing here travels on the wire and no server ever sees it.
|
|
4
4
|
* the server's knowledge of progress differs per transfer kind (a presigned PUT it cannot see at all),
|
|
5
5
|
* so the contract deliberately carries none of it.
|
|
6
|
-
* -
|
|
6
|
+
* - per-file percent + one batch percent. everything is measured in bytes of the ORIGINAL
|
|
7
7
|
* content, never in wire bytes, so the bar means the same thing whichever executor runs.
|
|
8
8
|
*
|
|
9
9
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UPLOAD_STATUS, UPLOAD_STEREO, UPLOAD_TRANSFER_KIND } from './types.js';
|
|
2
|
-
/** a settled image as the server returns it after `complete
|
|
2
|
+
/** a settled image as the server returns it after `complete`, with the preview the client sent */
|
|
3
3
|
export const SAMPLE_UPLOAD_STORED = {
|
|
4
4
|
id: 'up-001',
|
|
5
5
|
status: UPLOAD_STATUS.stored,
|
|
@@ -10,26 +10,9 @@ export const SAMPLE_UPLOAD_STORED = {
|
|
|
10
10
|
url: 'https://cdn.example.com/up-001.png',
|
|
11
11
|
width: 1024,
|
|
12
12
|
height: 768,
|
|
13
|
-
|
|
14
|
-
updatedAt: 1757894401000,
|
|
13
|
+
thumbnail: { url: 'https://cdn.example.com/up-001-thumb.jpg', contentType: 'image/jpeg' },
|
|
15
14
|
};
|
|
16
|
-
/**
|
|
17
|
-
export const SAMPLE_UPLOAD_HEAD = {
|
|
18
|
-
id: 'up-001',
|
|
19
|
-
stereo: UPLOAD_STEREO.image,
|
|
20
|
-
name: 'photo.png',
|
|
21
|
-
contentType: 'image/png',
|
|
22
|
-
contentSize: 123456,
|
|
23
|
-
url: 'https://cdn.example.com/up-001.png',
|
|
24
|
-
width: 1024,
|
|
25
|
-
height: 768,
|
|
26
|
-
};
|
|
27
|
-
/** what a message view carries: both halves of the pair, never one */
|
|
28
|
-
export const SAMPLE_UPLOAD_REFS = {
|
|
29
|
-
uploadIds: ['up-001'],
|
|
30
|
-
upload$$: [SAMPLE_UPLOAD_HEAD],
|
|
31
|
-
};
|
|
32
|
-
/** start slot: inline ticket (roadmap 1) */
|
|
15
|
+
/** start slot: inline ticket */
|
|
33
16
|
export const SAMPLE_UPLOAD_TICKET_INLINE = {
|
|
34
17
|
upload: {
|
|
35
18
|
id: 'up-002',
|
|
@@ -41,7 +24,7 @@ export const SAMPLE_UPLOAD_TICKET_INLINE = {
|
|
|
41
24
|
},
|
|
42
25
|
transfer: { kind: UPLOAD_TRANSFER_KIND.inline, maxBytes: 4000000 },
|
|
43
26
|
};
|
|
44
|
-
/** start slot: presigned ticket
|
|
27
|
+
/** start slot: presigned PUT ticket */
|
|
45
28
|
export const SAMPLE_UPLOAD_TICKET_PRESIGNED = {
|
|
46
29
|
upload: {
|
|
47
30
|
id: 'up-003',
|
|
@@ -60,6 +43,30 @@ export const SAMPLE_UPLOAD_TICKET_PRESIGNED = {
|
|
|
60
43
|
expiresAt: 1757895300000,
|
|
61
44
|
},
|
|
62
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* start slot for an upload that is already `stored` and is only taking a thumbnail.
|
|
48
|
+
* - `transfer` absent + `thumbnailTransfer` present: the original's bytes are immutable.
|
|
49
|
+
* - an engine that returns early on a missing `transfer` silently drops the preview.
|
|
50
|
+
*/
|
|
51
|
+
export const SAMPLE_UPLOAD_TICKET_THUMBNAIL_ONLY = {
|
|
52
|
+
upload: {
|
|
53
|
+
id: 'up-001',
|
|
54
|
+
status: UPLOAD_STATUS.stored,
|
|
55
|
+
stereo: UPLOAD_STEREO.image,
|
|
56
|
+
name: 'photo.png',
|
|
57
|
+
contentType: 'image/png',
|
|
58
|
+
contentSize: 123456,
|
|
59
|
+
url: 'https://cdn.example.com/up-001.png',
|
|
60
|
+
},
|
|
61
|
+
thumbnailTransfer: {
|
|
62
|
+
kind: UPLOAD_TRANSFER_KIND.presignedPut,
|
|
63
|
+
method: 'PUT',
|
|
64
|
+
url: 'https://storage.example.com/up-001-thumb?X-Amz-Signature=masked',
|
|
65
|
+
headers: { 'content-type': 'image/jpeg' },
|
|
66
|
+
maxBytes: 200000,
|
|
67
|
+
expiresAt: 1757895300000,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
63
70
|
/** start slot rejected at validation: no id, nothing to transfer or complete */
|
|
64
71
|
export const SAMPLE_UPLOAD_REJECTED = {
|
|
65
72
|
upload: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../src/upload/testing.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE7E,
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../src/upload/testing.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE7E,kGAAkG;AAClG,MAAM,CAAC,MAAM,oBAAoB,GAAW;IACxC,EAAE,EAAE,QAAQ;IACZ,MAAM,EAAE,aAAa,CAAC,MAAM;IAC5B,MAAM,EAAE,aAAa,CAAC,KAAK;IAC3B,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,MAAM;IACnB,GAAG,EAAE,oCAAoC;IACzC,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,GAAG;IACX,SAAS,EAAE,EAAE,GAAG,EAAE,0CAA0C,EAAE,WAAW,EAAE,YAAY,EAAE;CAC5F,CAAC;AAEF,gCAAgC;AAChC,MAAM,CAAC,MAAM,2BAA2B,GAAiB;IACrD,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,aAAa,CAAC,OAAO;QAC7B,MAAM,EAAE,aAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;KACtB;IACD,QAAQ,EAAE,EAAE,IAAI,EAAE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE;CACrE,CAAC;AAEF,uCAAuC;AACvC,MAAM,CAAC,MAAM,8BAA8B,GAAiB;IACxD,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,aAAa,CAAC,OAAO;QAC7B,MAAM,EAAE,aAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;KACtB;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,oBAAoB,CAAC,YAAY;QACvC,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,2DAA2D;QAChE,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE;QACpE,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,aAAa;KAC3B;CACJ,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAiB;IAC7D,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,aAAa,CAAC,MAAM;QAC5B,MAAM,EAAE,aAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;QACnB,GAAG,EAAE,oCAAoC;KAC5C;IACD,iBAAiB,EAAE;QACf,IAAI,EAAE,oBAAoB,CAAC,YAAY;QACvC,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,iEAAiE;QACtE,OAAO,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE;QACzC,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,aAAa;KAC3B;CACJ,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,sBAAsB,GAAiB;IAChD,MAAM,EAAE;QACJ,MAAM,EAAE,aAAa,CAAC,MAAM;QAC5B,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,OAAO;QACpB,KAAK,EAAE,mCAAmC;KAC7C;CACJ,CAAC"}
|
package/dist/esm/upload/types.js
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* `upload/types.ts`
|
|
3
|
+
* - client <-> server contract for uploading files.
|
|
4
|
+
* - transport-neutral: the client always runs `start` -> transfer -> `complete`; whether the server
|
|
5
|
+
* stores bytes inline (base64 in JSON) or hands out a presigned PUT only changes which
|
|
6
|
+
* `UploadTransfer` variant it issues.
|
|
7
|
+
* - runtime-neutral like `socket/`: no Node, DOM, or AWS SDK types. Storage coordinates
|
|
8
|
+
* (bucket, key, region) never appear here.
|
|
9
|
+
* - model-neutral: nothing here imports or names lemon-core's Model/View/Body/Head layers or the `$`
|
|
10
|
+
* embed marker. two shapes carry the vocabulary instead — `UploadContent` (bytes as declared) and
|
|
11
|
+
* `UploadResource` (bytes as stored, with an address). how a server maps them onto its own model
|
|
12
|
+
* layer, and how it embeds an upload in another record, is the server's concern.
|
|
13
|
+
*
|
|
14
|
+
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
15
|
+
*/
|
|
16
|
+
/** kind of stored content */
|
|
2
17
|
export const UPLOAD_STEREO = {
|
|
3
18
|
image: 'image',
|
|
4
19
|
video: 'video',
|
|
5
|
-
|
|
6
|
-
|
|
20
|
+
audio: 'audio',
|
|
21
|
+
/** any file that is not an image, video or audio */
|
|
22
|
+
file: 'file',
|
|
7
23
|
};
|
|
8
24
|
/** lifecycle of one upload as the client sees it. `url` is meaningful only when `stored` */
|
|
9
25
|
export const UPLOAD_STATUS = {
|
|
@@ -11,19 +27,20 @@ export const UPLOAD_STATUS = {
|
|
|
11
27
|
pending: 'pending',
|
|
12
28
|
/** bytes durable and `url` valid */
|
|
13
29
|
stored: 'stored',
|
|
14
|
-
/** terminal; `error` carries
|
|
30
|
+
/** terminal; `error` carries the server's detail */
|
|
15
31
|
failed: 'failed',
|
|
16
32
|
};
|
|
17
|
-
/** how bytes travel.
|
|
33
|
+
/** how bytes travel. a new transfer method arrives as a new kind; the flow around it does not change */
|
|
18
34
|
export const UPLOAD_TRANSFER_KIND = {
|
|
19
|
-
/** base64
|
|
35
|
+
/** base64 in a JSON body, through the `send` operation */
|
|
20
36
|
inline: 'inline',
|
|
21
|
-
/** HTTP PUT straight to storage
|
|
37
|
+
/** HTTP PUT straight to storage, to a server-issued url with its headers */
|
|
22
38
|
presignedPut: 'presigned-put',
|
|
23
39
|
};
|
|
40
|
+
export const isUploadStored = (upload) => upload.status === UPLOAD_STATUS.stored && typeof upload.id === 'string' && typeof upload.url === 'string';
|
|
24
41
|
/** who produced a failure */
|
|
25
42
|
export const UPLOAD_FAILURE_SOURCE = {
|
|
26
|
-
/**
|
|
43
|
+
/** the upload API answered with an error */
|
|
27
44
|
api: 'api',
|
|
28
45
|
/** the storage endpoint (presigned PUT) answered with an error */
|
|
29
46
|
storage: 'storage',
|
|
@@ -52,18 +69,21 @@ export const UPLOAD_ROUTES = {
|
|
|
52
69
|
complete: { method: 'POST', path: '/complete' },
|
|
53
70
|
read: { method: 'GET', path: '/{id}' },
|
|
54
71
|
};
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
/**
|
|
73
|
+
* shared stereo derivation so an optimistic client tile and the server agree.
|
|
74
|
+
* - classifies by the top-level media type; any other non-empty type is `file`.
|
|
75
|
+
* - classification only: which types a server accepts is that server's own policy.
|
|
76
|
+
*/
|
|
57
77
|
export const uploadStereoOf = (contentType) => {
|
|
58
78
|
const type = contentType.toLowerCase().split(';')[0].trim();
|
|
79
|
+
if (!type)
|
|
80
|
+
return undefined;
|
|
59
81
|
if (type.startsWith('image/'))
|
|
60
82
|
return UPLOAD_STEREO.image;
|
|
61
83
|
if (type.startsWith('video/'))
|
|
62
84
|
return UPLOAD_STEREO.video;
|
|
63
85
|
if (type.startsWith('audio/'))
|
|
64
|
-
return UPLOAD_STEREO.
|
|
65
|
-
|
|
66
|
-
return UPLOAD_STEREO.docs;
|
|
67
|
-
return undefined;
|
|
86
|
+
return UPLOAD_STEREO.audio;
|
|
87
|
+
return UPLOAD_STEREO.file;
|
|
68
88
|
};
|
|
69
89
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/upload/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/upload/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,6BAA6B;AAC7B,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,oDAAoD;IACpD,IAAI,EAAE,MAAM;CACN,CAAC;AAGX,4FAA4F;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,2DAA2D;IAC3D,OAAO,EAAE,SAAS;IAClB,oCAAoC;IACpC,MAAM,EAAE,QAAQ;IAChB,oDAAoD;IACpD,MAAM,EAAE,QAAQ;CACV,CAAC;AAGX,wGAAwG;AACxG,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAChC,0DAA0D;IAC1D,MAAM,EAAE,QAAQ;IAChB,4EAA4E;IAC5E,YAAY,EAAE,eAAe;CACvB,CAAC;AAoEX,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAc,EAA0B,EAAE,CACrE,MAAM,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC;AA0E9G,6BAA6B;AAC7B,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACjC,4CAA4C;IAC5C,GAAG,EAAE,KAAK;IACV,kEAAkE;IAClE,OAAO,EAAE,SAAS;IAClB,sDAAsD;IACtD,MAAM,EAAE,QAAQ;CACV,CAAC;AAGX,oFAAoF;AACpF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAC/B,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,aAAa;IAC1B,aAAa,EAAE,gBAAgB;IAC/B,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACZ,CAAC;AA+CX,qGAAqG;AACrG,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE;IAC5C,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE;IAC/C,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;CAChC,CAAC;AAEX;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,WAAmB,EAA4B,EAAE;IAC5E,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IAC1D,OAAO,aAAa,CAAC,IAAI,CAAC;AAC9B,CAAC,CAAC"}
|
|
@@ -9,23 +9,37 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
11
11
|
*/
|
|
12
|
-
import type { UploadCompleteItem, UploadFailure,
|
|
12
|
+
import type { Upload, UploadCompleteItem, UploadFailure, UploadSupportable, UploadTransfer } from '../types';
|
|
13
13
|
import type { UploadBatchProgressSink, UploadProgressSink } from './progress';
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* one payload of bytes a shell can hand over: the contract's `UploadContent`, with the bytes behind a call.
|
|
16
|
+
* - the contract's `hash` is a string and this one is a call, so this does not extend `UploadContent`.
|
|
17
|
+
*/
|
|
18
|
+
export interface UploadContentSource {
|
|
17
19
|
contentType: string;
|
|
18
20
|
contentSize: number;
|
|
19
|
-
/**
|
|
21
|
+
/** pixel size for image/video; echoed into the intent so a list screen can reserve the box */
|
|
22
|
+
width?: number;
|
|
23
|
+
height?: number;
|
|
24
|
+
/** the whole payload in one call */
|
|
20
25
|
bytes(): Promise<Uint8Array>;
|
|
21
26
|
/** sha256 hex(64) when this shell chooses to hash at send time; omit to skip */
|
|
22
27
|
hash?(): Promise<string | undefined>;
|
|
23
28
|
}
|
|
29
|
+
/** bytes provider; hides DOM `File`, RN uri, Electron path behind one shape */
|
|
30
|
+
export interface UploadSource extends UploadContentSource {
|
|
31
|
+
name: string;
|
|
32
|
+
/** a preview this shell already made. the engine sends it beside the original and never derives one */
|
|
33
|
+
thumbnail?: UploadContentSource;
|
|
34
|
+
}
|
|
24
35
|
/** moves bytes for one transfer kind and reports the receipt the server expects in `complete` */
|
|
25
36
|
export interface UploadTransferExecutor<T extends UploadTransfer = UploadTransfer> {
|
|
26
37
|
readonly kind: T['kind'];
|
|
27
|
-
/**
|
|
28
|
-
|
|
38
|
+
/**
|
|
39
|
+
* `onProgress` is optional to CALL, not to accept: an executor that cannot observe bytes never calls it.
|
|
40
|
+
* - `source` is a payload, not a file: the engine passes `source.thumbnail` here too, and that has no `name`.
|
|
41
|
+
*/
|
|
42
|
+
run(id: string, transfer: T, source: UploadContentSource, onProgress: UploadProgressSink): Promise<UploadCompleteItem>;
|
|
29
43
|
}
|
|
30
44
|
/**
|
|
31
45
|
* transfers in flight at once.
|
|
@@ -38,13 +52,20 @@ export declare class UploadEngine {
|
|
|
38
52
|
private readonly executors;
|
|
39
53
|
private readonly options?;
|
|
40
54
|
private readonly kinds;
|
|
41
|
-
constructor(service:
|
|
55
|
+
constructor(service: UploadSupportable, executors: ReadonlyArray<UploadTransferExecutor>, options?: {
|
|
42
56
|
concurrency?: number;
|
|
43
57
|
});
|
|
44
58
|
/** returns one view per source, in order: `stored`, or `failed` with the reason. `onProgress` gets a snapshot per change */
|
|
45
|
-
upload(sources: ReadonlyArray<UploadSource>, onProgress?: UploadBatchProgressSink): Promise<
|
|
59
|
+
upload(sources: ReadonlyArray<UploadSource>, onProgress?: UploadBatchProgressSink): Promise<Upload[]>;
|
|
46
60
|
private transferTracked;
|
|
47
61
|
private transfer;
|
|
62
|
+
private transferOriginal;
|
|
63
|
+
/**
|
|
64
|
+
* the preview is subordinate: whatever happens here never reaches `complete`.
|
|
65
|
+
* - `UploadCompleteItem` is one per upload, so reporting a thumbnail failure would fail the original.
|
|
66
|
+
* - the server settles the thumbnail by looking at storage at `complete` time, so silence is enough.
|
|
67
|
+
*/
|
|
68
|
+
private transferThumbnail;
|
|
48
69
|
}
|
|
49
70
|
/** normalize an error thrown by the API adapter */
|
|
50
71
|
export declare const asApiFailure: (error: unknown) => UploadFailure;
|
|
@@ -34,14 +34,20 @@ const runPooled = (count, limit, task) => __awaiter(void 0, void 0, void 0, func
|
|
|
34
34
|
yield Promise.all(new Array(size).fill(0).map(() => worker()));
|
|
35
35
|
return results;
|
|
36
36
|
});
|
|
37
|
-
const
|
|
37
|
+
const asContent = (source) => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
38
|
return ({
|
|
39
|
-
name: source.name,
|
|
40
39
|
contentType: source.contentType,
|
|
41
40
|
contentSize: source.contentSize,
|
|
41
|
+
width: source.width,
|
|
42
|
+
height: source.height,
|
|
42
43
|
hash: source.hash ? yield source.hash() : undefined,
|
|
43
44
|
});
|
|
44
45
|
});
|
|
46
|
+
const asIntent = (source) => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
+
return (Object.assign(Object.assign({}, (yield asContent(source))), { name: source.name, thumbnail: source.thumbnail ? yield asContent(source.thumbnail) : undefined }));
|
|
48
|
+
});
|
|
49
|
+
/** bytes this source puts on the wire in total; the thumbnail rides along so the bar counts it */
|
|
50
|
+
const sizeOf = (source) => { var _a, _b; return source.contentSize + ((_b = (_a = source.thumbnail) === null || _a === void 0 ? void 0 : _a.contentSize) !== null && _b !== void 0 ? _b : 0); };
|
|
45
51
|
class UploadEngine {
|
|
46
52
|
constructor(service, executors, options) {
|
|
47
53
|
this.service = service;
|
|
@@ -53,9 +59,9 @@ class UploadEngine {
|
|
|
53
59
|
upload(sources, onProgress) {
|
|
54
60
|
var _a, _b;
|
|
55
61
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
const tracker = new progress_1.UploadProgressTracker(sources.map(
|
|
62
|
+
const tracker = new progress_1.UploadProgressTracker(sources.map(sizeOf), onProgress);
|
|
57
63
|
tracker.publish();
|
|
58
|
-
const list = yield Promise.all(sources.map(
|
|
64
|
+
const list = yield Promise.all(sources.map(asIntent));
|
|
59
65
|
const { list: tickets } = yield this.service.start({ list, transfers: this.kinds });
|
|
60
66
|
const limit = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.concurrency) !== null && _b !== void 0 ? _b : exports.UPLOAD_DEFAULT_CONCURRENCY;
|
|
61
67
|
const receipts = yield runPooled(tickets.length, limit, i => this.transferTracked(tickets[i], sources[i], tracker, i));
|
|
@@ -63,7 +69,7 @@ class UploadEngine {
|
|
|
63
69
|
sources.forEach((_, i) => tracker.settle(i));
|
|
64
70
|
const pending = receipts.filter((item) => !!item);
|
|
65
71
|
const settled = pending.length ? (yield this.service.complete({ list: pending })).list : [];
|
|
66
|
-
const byId = new Map(settled.filter(
|
|
72
|
+
const byId = new Map(settled.filter(upload => !!upload.id).map((upload) => [upload.id, upload]));
|
|
67
73
|
return tickets.map(ticket => (ticket.upload.id && byId.get(ticket.upload.id)) || ticket.upload);
|
|
68
74
|
});
|
|
69
75
|
}
|
|
@@ -94,14 +100,46 @@ class UploadEngine {
|
|
|
94
100
|
// rejected at start: nothing was created, nothing to complete
|
|
95
101
|
if (!id)
|
|
96
102
|
return undefined;
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
const receipt = yield this.transferOriginal(id, ticket.transfer, source, onProgress);
|
|
104
|
+
// a failed original has nothing to preview; otherwise the thumbnail rides after it (never with it)
|
|
105
|
+
if (!receipt.failure)
|
|
106
|
+
yield this.transferThumbnail(id, ticket.thumbnailTransfer, source, onProgress);
|
|
107
|
+
return receipt;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
transferOriginal(id, transfer, source, onProgress) {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
// no instruction: already stored (dedup, or a stored upload taking only a thumbnail) — complete still confirms it
|
|
113
|
+
if (!transfer)
|
|
99
114
|
return { id };
|
|
100
|
-
const executor = this.executors.find(candidate =>
|
|
115
|
+
const executor = this.executors.find(candidate => candidate.kind === transfer.kind);
|
|
101
116
|
if (!executor)
|
|
102
117
|
return { id, failure: { source: types_1.UPLOAD_FAILURE_SOURCE.client, code: types_1.UPLOAD_FAILURE_CODE.notAcceptable } };
|
|
103
|
-
// NOTE: `
|
|
104
|
-
return executor.run(id,
|
|
118
|
+
// NOTE: `transfer` must not be logged or stored — it may carry a credential url
|
|
119
|
+
return executor.run(id, transfer, source, onProgress);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* the preview is subordinate: whatever happens here never reaches `complete`.
|
|
124
|
+
* - `UploadCompleteItem` is one per upload, so reporting a thumbnail failure would fail the original.
|
|
125
|
+
* - the server settles the thumbnail by looking at storage at `complete` time, so silence is enough.
|
|
126
|
+
*/
|
|
127
|
+
transferThumbnail(id, transfer, source, onProgress) {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const thumbnail = source.thumbnail;
|
|
130
|
+
if (!transfer || !thumbnail)
|
|
131
|
+
return;
|
|
132
|
+
const executor = this.executors.find(candidate => candidate.kind === transfer.kind);
|
|
133
|
+
if (!executor)
|
|
134
|
+
return;
|
|
135
|
+
// the original's bytes are already counted, so the thumbnail reports on top of them
|
|
136
|
+
const base = source.contentSize;
|
|
137
|
+
try {
|
|
138
|
+
yield executor.run(id, transfer, thumbnail, sent => onProgress(base + sent));
|
|
139
|
+
}
|
|
140
|
+
catch (_a) {
|
|
141
|
+
// swallowed on purpose: see the note above
|
|
142
|
+
}
|
|
105
143
|
});
|
|
106
144
|
}
|
|
107
145
|
}
|
|
@@ -146,7 +184,7 @@ const asApiFailure = (error) => {
|
|
|
146
184
|
};
|
|
147
185
|
};
|
|
148
186
|
exports.asApiFailure = asApiFailure;
|
|
149
|
-
/** S3 error `<Code>` -> normalized code
|
|
187
|
+
/** S3 error `<Code>` -> normalized code. unknown codes fall back by status */
|
|
150
188
|
const STORAGE_CODES = {
|
|
151
189
|
SignatureDoesNotMatch: types_1.UPLOAD_FAILURE_CODE.signature,
|
|
152
190
|
AccessDenied: types_1.UPLOAD_FAILURE_CODE.expired,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/upload/engine/engine.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/upload/engine/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
9
9
|
*/
|
|
10
|
-
import type { UploadCompleteItem, UploadInlineTransfer, UploadPresignedPutTransfer,
|
|
11
|
-
import type {
|
|
10
|
+
import type { UploadCompleteItem, UploadInlineTransfer, UploadPresignedPutTransfer, UploadSendRequest, Upload } from '../types';
|
|
11
|
+
import type { UploadContentSource, UploadTransferExecutor } from './engine';
|
|
12
12
|
import type { UploadProgressSink, UploadWireProgress } from './progress';
|
|
13
13
|
/**
|
|
14
14
|
* the `send` call as the shell provides it.
|
|
15
15
|
* - a fetch-based API adapter is `(id, body) => service.send(id, body)` and reports nothing;
|
|
16
16
|
* - an `XMLHttpRequest`-based one forwards `upload.onprogress` through `onProgress`.
|
|
17
17
|
*/
|
|
18
|
-
export declare type InlineSendCall = (id: string, body:
|
|
19
|
-
/**
|
|
18
|
+
export declare type InlineSendCall = (id: string, body: UploadSendRequest, onProgress?: UploadWireProgress) => Promise<Upload>;
|
|
19
|
+
/** inline transfer — the only place that knows bytes go to the API as base64 */
|
|
20
20
|
export declare class InlineExecutor implements UploadTransferExecutor<UploadInlineTransfer> {
|
|
21
21
|
private readonly send;
|
|
22
22
|
/** shell-specific base64 encoder (btoa / Buffer / RN polyfill) */
|
|
@@ -25,7 +25,7 @@ export declare class InlineExecutor implements UploadTransferExecutor<UploadInli
|
|
|
25
25
|
constructor(send: InlineSendCall,
|
|
26
26
|
/** shell-specific base64 encoder (btoa / Buffer / RN polyfill) */
|
|
27
27
|
toBase64: (bytes: Uint8Array) => string);
|
|
28
|
-
run(id: string, transfer: UploadInlineTransfer, source:
|
|
28
|
+
run(id: string, transfer: UploadInlineTransfer, source: UploadContentSource, onProgress: UploadProgressSink): Promise<UploadCompleteItem>;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* raw HTTP PUT provided by the shell; `code` = parsed S3 `<Code>`.
|
|
@@ -35,10 +35,10 @@ export declare type RawPut = (url: string, headers: Record<string, string>, body
|
|
|
35
35
|
status: number;
|
|
36
36
|
code?: string;
|
|
37
37
|
}>;
|
|
38
|
-
/**
|
|
38
|
+
/** presigned PUT transfer — raw bytes straight to storage */
|
|
39
39
|
export declare class PresignedPutExecutor implements UploadTransferExecutor<UploadPresignedPutTransfer> {
|
|
40
40
|
private readonly put;
|
|
41
41
|
readonly kind: "presigned-put";
|
|
42
42
|
constructor(put: RawPut);
|
|
43
|
-
run(id: string, transfer: UploadPresignedPutTransfer, source:
|
|
43
|
+
run(id: string, transfer: UploadPresignedPutTransfer, source: UploadContentSource, onProgress: UploadProgressSink): Promise<UploadCompleteItem>;
|
|
44
44
|
}
|
|
@@ -13,7 +13,7 @@ exports.PresignedPutExecutor = exports.InlineExecutor = void 0;
|
|
|
13
13
|
const types_1 = require("../types");
|
|
14
14
|
const engine_1 = require("./engine");
|
|
15
15
|
const progress_1 = require("./progress");
|
|
16
|
-
/**
|
|
16
|
+
/** inline transfer — the only place that knows bytes go to the API as base64 */
|
|
17
17
|
class InlineExecutor {
|
|
18
18
|
constructor(send,
|
|
19
19
|
/** shell-specific base64 encoder (btoa / Buffer / RN polyfill) */
|
|
@@ -40,7 +40,7 @@ class InlineExecutor {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
exports.InlineExecutor = InlineExecutor;
|
|
43
|
-
/**
|
|
43
|
+
/** presigned PUT transfer — raw bytes straight to storage */
|
|
44
44
|
class PresignedPutExecutor {
|
|
45
45
|
constructor(put) {
|
|
46
46
|
this.put = put;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executors.js","sourceRoot":"","sources":["../../../src/upload/engine/executors.ts"],"names":[],"mappings":";;;;;;;;;;;;AAgBA,oCAA4F;AAE5F,qCAA0D;AAE1D,yCAA4C;AAS5C,
|
|
1
|
+
{"version":3,"file":"executors.js","sourceRoot":"","sources":["../../../src/upload/engine/executors.ts"],"names":[],"mappings":";;;;;;;;;;;;AAgBA,oCAA4F;AAE5F,qCAA0D;AAE1D,yCAA4C;AAS5C,gFAAgF;AAChF,MAAa,cAAc;IAGvB,YACqB,IAAoB;IACrC,kEAAkE;IACjD,QAAuC;QAFvC,SAAI,GAAJ,IAAI,CAAgB;QAEpB,aAAQ,GAAR,QAAQ,CAA+B;QAL5C,SAAI,GAAG,4BAAoB,CAAC,MAAM,CAAC;IAMhD,CAAC;IAES,GAAG,CACZ,EAAU,EACV,QAA8B,EAC9B,MAA2B,EAC3B,UAA8B;;YAE9B,IAAI,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC,QAAQ,EAAE;gBACxC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,6BAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,2BAAmB,CAAC,QAAQ,EAAE,EAAE,CAAC;aACxG;YACD,IAAI;gBACA,MAAM,IAAI,GAAsB,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;gBACjF,sEAAsE;gBACtE,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,IAAA,yBAAc,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;gBAC5G,OAAO,EAAE,EAAE,EAAE,CAAC;aACjB;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAA,qBAAY,EAAC,KAAK,CAAC,EAAE,CAAC;aAC/C;QACL,CAAC;KAAA;CACJ;AA3BD,wCA2BC;AAaD,6DAA6D;AAC7D,MAAa,oBAAoB;IAG7B,YAAoC,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QAF/B,SAAI,GAAG,4BAAoB,CAAC,YAAY,CAAC;IAEP,CAAC;IAEtC,GAAG,CACZ,EAAU,EACV,QAAoC,EACpC,MAA2B,EAC3B,UAA8B;;YAE9B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAC/F,UAAU,CAAC,IAAA,yBAAc,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAChE,CAAC;YACF,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;gBAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACzD,6EAA6E;YAC7E,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACtC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAA,yBAAgB,EAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACnE,CAAC;KAAA;CACJ;AAnBD,oDAmBC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* - progress is a CLIENT-LOCAL signal: nothing here travels on the wire and no server ever sees it.
|
|
4
4
|
* the server's knowledge of progress differs per transfer kind (a presigned PUT it cannot see at all),
|
|
5
5
|
* so the contract deliberately carries none of it.
|
|
6
|
-
* -
|
|
6
|
+
* - per-file percent + one batch percent. everything is measured in bytes of the ORIGINAL
|
|
7
7
|
* content, never in wire bytes, so the bar means the same thing whichever executor runs.
|
|
8
8
|
*
|
|
9
9
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* - progress is a CLIENT-LOCAL signal: nothing here travels on the wire and no server ever sees it.
|
|
5
5
|
* the server's knowledge of progress differs per transfer kind (a presigned PUT it cannot see at all),
|
|
6
6
|
* so the contract deliberately carries none of it.
|
|
7
|
-
* -
|
|
7
|
+
* - per-file percent + one batch percent. everything is measured in bytes of the ORIGINAL
|
|
8
8
|
* content, never in wire bytes, so the bar means the same thing whichever executor runs.
|
|
9
9
|
*
|
|
10
10
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
package/dist/upload/testing.d.ts
CHANGED
|
@@ -6,16 +6,18 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
10
|
-
/** a settled image as the server returns it after `complete
|
|
11
|
-
export declare const SAMPLE_UPLOAD_STORED:
|
|
12
|
-
/**
|
|
13
|
-
export declare const SAMPLE_UPLOAD_HEAD: UploadHead;
|
|
14
|
-
/** what a message view carries: both halves of the pair, never one */
|
|
15
|
-
export declare const SAMPLE_UPLOAD_REFS: UploadRefs;
|
|
16
|
-
/** start slot: inline ticket (roadmap 1) */
|
|
9
|
+
import type { Upload, UploadTicket } from './types';
|
|
10
|
+
/** a settled image as the server returns it after `complete`, with the preview the client sent */
|
|
11
|
+
export declare const SAMPLE_UPLOAD_STORED: Upload;
|
|
12
|
+
/** start slot: inline ticket */
|
|
17
13
|
export declare const SAMPLE_UPLOAD_TICKET_INLINE: UploadTicket;
|
|
18
|
-
/** start slot: presigned ticket
|
|
14
|
+
/** start slot: presigned PUT ticket */
|
|
19
15
|
export declare const SAMPLE_UPLOAD_TICKET_PRESIGNED: UploadTicket;
|
|
16
|
+
/**
|
|
17
|
+
* start slot for an upload that is already `stored` and is only taking a thumbnail.
|
|
18
|
+
* - `transfer` absent + `thumbnailTransfer` present: the original's bytes are immutable.
|
|
19
|
+
* - an engine that returns early on a missing `transfer` silently drops the preview.
|
|
20
|
+
*/
|
|
21
|
+
export declare const SAMPLE_UPLOAD_TICKET_THUMBNAIL_ONLY: UploadTicket;
|
|
20
22
|
/** start slot rejected at validation: no id, nothing to transfer or complete */
|
|
21
23
|
export declare const SAMPLE_UPLOAD_REJECTED: UploadTicket;
|
package/dist/upload/testing.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SAMPLE_UPLOAD_REJECTED = exports.
|
|
3
|
+
exports.SAMPLE_UPLOAD_REJECTED = exports.SAMPLE_UPLOAD_TICKET_THUMBNAIL_ONLY = exports.SAMPLE_UPLOAD_TICKET_PRESIGNED = exports.SAMPLE_UPLOAD_TICKET_INLINE = exports.SAMPLE_UPLOAD_STORED = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
|
-
/** a settled image as the server returns it after `complete
|
|
5
|
+
/** a settled image as the server returns it after `complete`, with the preview the client sent */
|
|
6
6
|
exports.SAMPLE_UPLOAD_STORED = {
|
|
7
7
|
id: 'up-001',
|
|
8
8
|
status: types_1.UPLOAD_STATUS.stored,
|
|
@@ -13,26 +13,9 @@ exports.SAMPLE_UPLOAD_STORED = {
|
|
|
13
13
|
url: 'https://cdn.example.com/up-001.png',
|
|
14
14
|
width: 1024,
|
|
15
15
|
height: 768,
|
|
16
|
-
|
|
17
|
-
updatedAt: 1757894401000,
|
|
16
|
+
thumbnail: { url: 'https://cdn.example.com/up-001-thumb.jpg', contentType: 'image/jpeg' },
|
|
18
17
|
};
|
|
19
|
-
/**
|
|
20
|
-
exports.SAMPLE_UPLOAD_HEAD = {
|
|
21
|
-
id: 'up-001',
|
|
22
|
-
stereo: types_1.UPLOAD_STEREO.image,
|
|
23
|
-
name: 'photo.png',
|
|
24
|
-
contentType: 'image/png',
|
|
25
|
-
contentSize: 123456,
|
|
26
|
-
url: 'https://cdn.example.com/up-001.png',
|
|
27
|
-
width: 1024,
|
|
28
|
-
height: 768,
|
|
29
|
-
};
|
|
30
|
-
/** what a message view carries: both halves of the pair, never one */
|
|
31
|
-
exports.SAMPLE_UPLOAD_REFS = {
|
|
32
|
-
uploadIds: ['up-001'],
|
|
33
|
-
upload$$: [exports.SAMPLE_UPLOAD_HEAD],
|
|
34
|
-
};
|
|
35
|
-
/** start slot: inline ticket (roadmap 1) */
|
|
18
|
+
/** start slot: inline ticket */
|
|
36
19
|
exports.SAMPLE_UPLOAD_TICKET_INLINE = {
|
|
37
20
|
upload: {
|
|
38
21
|
id: 'up-002',
|
|
@@ -44,7 +27,7 @@ exports.SAMPLE_UPLOAD_TICKET_INLINE = {
|
|
|
44
27
|
},
|
|
45
28
|
transfer: { kind: types_1.UPLOAD_TRANSFER_KIND.inline, maxBytes: 4000000 },
|
|
46
29
|
};
|
|
47
|
-
/** start slot: presigned ticket
|
|
30
|
+
/** start slot: presigned PUT ticket */
|
|
48
31
|
exports.SAMPLE_UPLOAD_TICKET_PRESIGNED = {
|
|
49
32
|
upload: {
|
|
50
33
|
id: 'up-003',
|
|
@@ -63,6 +46,30 @@ exports.SAMPLE_UPLOAD_TICKET_PRESIGNED = {
|
|
|
63
46
|
expiresAt: 1757895300000,
|
|
64
47
|
},
|
|
65
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* start slot for an upload that is already `stored` and is only taking a thumbnail.
|
|
51
|
+
* - `transfer` absent + `thumbnailTransfer` present: the original's bytes are immutable.
|
|
52
|
+
* - an engine that returns early on a missing `transfer` silently drops the preview.
|
|
53
|
+
*/
|
|
54
|
+
exports.SAMPLE_UPLOAD_TICKET_THUMBNAIL_ONLY = {
|
|
55
|
+
upload: {
|
|
56
|
+
id: 'up-001',
|
|
57
|
+
status: types_1.UPLOAD_STATUS.stored,
|
|
58
|
+
stereo: types_1.UPLOAD_STEREO.image,
|
|
59
|
+
name: 'photo.png',
|
|
60
|
+
contentType: 'image/png',
|
|
61
|
+
contentSize: 123456,
|
|
62
|
+
url: 'https://cdn.example.com/up-001.png',
|
|
63
|
+
},
|
|
64
|
+
thumbnailTransfer: {
|
|
65
|
+
kind: types_1.UPLOAD_TRANSFER_KIND.presignedPut,
|
|
66
|
+
method: 'PUT',
|
|
67
|
+
url: 'https://storage.example.com/up-001-thumb?X-Amz-Signature=masked',
|
|
68
|
+
headers: { 'content-type': 'image/jpeg' },
|
|
69
|
+
maxBytes: 200000,
|
|
70
|
+
expiresAt: 1757895300000,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
66
73
|
/** start slot rejected at validation: no id, nothing to transfer or complete */
|
|
67
74
|
exports.SAMPLE_UPLOAD_REJECTED = {
|
|
68
75
|
upload: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/upload/testing.ts"],"names":[],"mappings":";;;AASA,mCAA6E;AAE7E,
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/upload/testing.ts"],"names":[],"mappings":";;;AASA,mCAA6E;AAE7E,kGAAkG;AACrF,QAAA,oBAAoB,GAAW;IACxC,EAAE,EAAE,QAAQ;IACZ,MAAM,EAAE,qBAAa,CAAC,MAAM;IAC5B,MAAM,EAAE,qBAAa,CAAC,KAAK;IAC3B,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,MAAM;IACnB,GAAG,EAAE,oCAAoC;IACzC,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,GAAG;IACX,SAAS,EAAE,EAAE,GAAG,EAAE,0CAA0C,EAAE,WAAW,EAAE,YAAY,EAAE;CAC5F,CAAC;AAEF,gCAAgC;AACnB,QAAA,2BAA2B,GAAiB;IACrD,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,qBAAa,CAAC,OAAO;QAC7B,MAAM,EAAE,qBAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;KACtB;IACD,QAAQ,EAAE,EAAE,IAAI,EAAE,4BAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE;CACrE,CAAC;AAEF,uCAAuC;AAC1B,QAAA,8BAA8B,GAAiB;IACxD,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,qBAAa,CAAC,OAAO;QAC7B,MAAM,EAAE,qBAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;KACtB;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,4BAAoB,CAAC,YAAY;QACvC,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,2DAA2D;QAChE,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE;QACpE,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,aAAa;KAC3B;CACJ,CAAC;AAEF;;;;GAIG;AACU,QAAA,mCAAmC,GAAiB;IAC7D,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,qBAAa,CAAC,MAAM;QAC5B,MAAM,EAAE,qBAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;QACnB,GAAG,EAAE,oCAAoC;KAC5C;IACD,iBAAiB,EAAE;QACf,IAAI,EAAE,4BAAoB,CAAC,YAAY;QACvC,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,iEAAiE;QACtE,OAAO,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE;QACzC,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,aAAa;KAC3B;CACJ,CAAC;AAEF,gFAAgF;AACnE,QAAA,sBAAsB,GAAiB;IAChD,MAAM,EAAE;QACJ,MAAM,EAAE,qBAAa,CAAC,MAAM;QAC5B,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,OAAO;QACpB,KAAK,EAAE,mCAAmC;KAC7C;CACJ,CAAC"}
|
package/dist/upload/types.d.ts
CHANGED
|
@@ -6,16 +6,20 @@
|
|
|
6
6
|
* `UploadTransfer` variant it issues.
|
|
7
7
|
* - runtime-neutral like `socket/`: no Node, DOM, or AWS SDK types. Storage coordinates
|
|
8
8
|
* (bucket, key, region) never appear here.
|
|
9
|
+
* - model-neutral: nothing here imports or names lemon-core's Model/View/Body/Head layers or the `$`
|
|
10
|
+
* embed marker. two shapes carry the vocabulary instead — `UploadContent` (bytes as declared) and
|
|
11
|
+
* `UploadResource` (bytes as stored, with an address). how a server maps them onto its own model
|
|
12
|
+
* layer, and how it embeds an upload in another record, is the server's concern.
|
|
9
13
|
*
|
|
10
14
|
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
11
15
|
*/
|
|
12
|
-
|
|
13
|
-
/** kind of stored content. same vocabulary as lemon-uploads-api `MediaStereo` minus its internal markers */
|
|
16
|
+
/** kind of stored content */
|
|
14
17
|
export declare const UPLOAD_STEREO: {
|
|
15
18
|
readonly image: "image";
|
|
16
19
|
readonly video: "video";
|
|
17
|
-
readonly
|
|
18
|
-
|
|
20
|
+
readonly audio: "audio";
|
|
21
|
+
/** any file that is not an image, video or audio */
|
|
22
|
+
readonly file: "file";
|
|
19
23
|
};
|
|
20
24
|
export declare type UploadStereo = typeof UPLOAD_STEREO[keyof typeof UPLOAD_STEREO];
|
|
21
25
|
/** lifecycle of one upload as the client sees it. `url` is meaningful only when `stored` */
|
|
@@ -24,76 +28,89 @@ export declare const UPLOAD_STATUS: {
|
|
|
24
28
|
readonly pending: "pending";
|
|
25
29
|
/** bytes durable and `url` valid */
|
|
26
30
|
readonly stored: "stored";
|
|
27
|
-
/** terminal; `error` carries
|
|
31
|
+
/** terminal; `error` carries the server's detail */
|
|
28
32
|
readonly failed: "failed";
|
|
29
33
|
};
|
|
30
34
|
export declare type UploadStatus = typeof UPLOAD_STATUS[keyof typeof UPLOAD_STATUS];
|
|
31
|
-
/** how bytes travel.
|
|
35
|
+
/** how bytes travel. a new transfer method arrives as a new kind; the flow around it does not change */
|
|
32
36
|
export declare const UPLOAD_TRANSFER_KIND: {
|
|
33
|
-
/** base64
|
|
37
|
+
/** base64 in a JSON body, through the `send` operation */
|
|
34
38
|
readonly inline: "inline";
|
|
35
|
-
/** HTTP PUT straight to storage
|
|
39
|
+
/** HTTP PUT straight to storage, to a server-issued url with its headers */
|
|
36
40
|
readonly presignedPut: "presigned-put";
|
|
37
41
|
};
|
|
38
42
|
export declare type UploadTransferKind = typeof UPLOAD_TRANSFER_KIND[keyof typeof UPLOAD_TRANSFER_KIND];
|
|
39
43
|
/**
|
|
40
|
-
*
|
|
41
|
-
* -
|
|
44
|
+
* one payload of bytes as the client declares it. it has no identity and no address of its own.
|
|
45
|
+
* - `contentType` and `contentSize` are required: the server picks the transfer and validates limits
|
|
46
|
+
* from them before any byte moves.
|
|
42
47
|
*/
|
|
43
|
-
export interface
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
name?: string;
|
|
48
|
-
/** MIME type */
|
|
49
|
-
contentType?: string;
|
|
50
|
-
/** size in bytes of the original content */
|
|
51
|
-
contentSize?: number;
|
|
52
|
-
/** stable url to serve; present iff status is `stored` */
|
|
53
|
-
url?: string;
|
|
54
|
-
/** thumbnail url; may arrive after `stored` (server post-processing) */
|
|
55
|
-
thumbnail?: string;
|
|
56
|
-
/** pixel size for image/video */
|
|
48
|
+
export interface UploadContent {
|
|
49
|
+
contentType: string;
|
|
50
|
+
contentSize: number;
|
|
51
|
+
/** pixel size for image/video. declared by the client; the server does not verify it */
|
|
57
52
|
width?: number;
|
|
58
53
|
height?: number;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/** sha256 hex(64) of the content, when known to the server */
|
|
54
|
+
/**
|
|
55
|
+
* sha256 hex(64). optional forever: servers MUST accept uploads without it, MUST verify it when given.
|
|
56
|
+
* on a thumbnail the server MAY verify it the same way for that transfer; completion-time cross-check applies only to the original's hash.
|
|
57
|
+
*/
|
|
64
58
|
hash?: string;
|
|
65
59
|
}
|
|
66
60
|
/**
|
|
67
|
-
*
|
|
68
|
-
* -
|
|
69
|
-
*
|
|
70
|
-
*
|
|
61
|
+
* bytes the server holds, and where to fetch them.
|
|
62
|
+
* - `url` may be time-limited and re-issued on every read: use it when received, never persist it.
|
|
63
|
+
* - the content fields are what the server can vouch for, so every one is optional: a server that
|
|
64
|
+
* only confirmed the object exists (a thumbnail) knows nothing beyond the address.
|
|
71
65
|
*/
|
|
72
|
-
export interface
|
|
73
|
-
|
|
74
|
-
contentType: string;
|
|
75
|
-
contentSize: number;
|
|
76
|
-
/** sha256 hex(64). optional forever: servers MUST accept uploads without it, MUST verify it when given */
|
|
77
|
-
hash?: string;
|
|
66
|
+
export interface UploadResource extends Partial<UploadContent> {
|
|
67
|
+
url: string;
|
|
78
68
|
}
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
/**
|
|
70
|
+
* one upload intent: a slot of `start`.
|
|
71
|
+
* - `id` set = re-issue transfers for an existing upload. for a still-`pending` one (expired ticket)
|
|
72
|
+
* that is both transfers; for a `stored` one it is `thumbnailTransfer` only, because stored bytes
|
|
73
|
+
* are immutable.
|
|
74
|
+
*/
|
|
75
|
+
export interface UploadIntent extends UploadContent {
|
|
76
|
+
id?: string;
|
|
77
|
+
/** file name as the sender picked it */
|
|
78
|
+
name: string;
|
|
79
|
+
/** a preview the client made. the server stores it beside the original and never derives it */
|
|
80
|
+
thumbnail?: UploadContent;
|
|
83
81
|
}
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
/**
|
|
83
|
+
* one upload as the server reports it: the declaration, its lifecycle, and — once `stored` — its address.
|
|
84
|
+
* - the content fields echo the intent. `url` is present iff `status` is `stored` (see `UploadStored`).
|
|
85
|
+
* - a server may answer with more fields than these; a client relies on these only.
|
|
86
|
+
*/
|
|
87
|
+
export interface Upload extends Partial<UploadContent> {
|
|
88
|
+
/** absent only for a slot rejected at `start` validation: nothing was created */
|
|
89
|
+
id?: string;
|
|
90
|
+
status: UploadStatus;
|
|
91
|
+
/** human-readable detail when `failed`; the format is the server's. branch on `status`, not on this string */
|
|
92
|
+
error?: string;
|
|
93
|
+
stereo?: UploadStereo;
|
|
94
|
+
/** file name as the sender picked it */
|
|
95
|
+
name?: string;
|
|
96
|
+
/** url to serve; may be time-limited and re-issued on every read — do not persist it. present iff `stored` */
|
|
97
|
+
url?: string;
|
|
98
|
+
/** preview stored alongside the original: present only once the intent declared one and its bytes arrived */
|
|
99
|
+
thumbnail?: UploadResource;
|
|
88
100
|
}
|
|
89
|
-
/**
|
|
101
|
+
/** an upload whose bytes are durable: it has an `id` and it is an `UploadResource` */
|
|
102
|
+
export declare type UploadStored = Upload & UploadResource & {
|
|
103
|
+
id: string;
|
|
104
|
+
};
|
|
105
|
+
export declare const isUploadStored: (upload: Upload) => upload is UploadStored;
|
|
106
|
+
/** transfer instruction: send base64 through `UploadSupportable.send()` */
|
|
90
107
|
export interface UploadInlineTransfer {
|
|
91
108
|
kind: typeof UPLOAD_TRANSFER_KIND.inline;
|
|
92
109
|
/** max original bytes (before base64) this server accepts inline */
|
|
93
110
|
maxBytes: number;
|
|
94
111
|
}
|
|
95
112
|
/**
|
|
96
|
-
* transfer instruction
|
|
113
|
+
* transfer instruction: PUT the raw bytes to `url` with `headers` verbatim.
|
|
97
114
|
* - `url` is a credential. never log, persist, or put it in an error message.
|
|
98
115
|
* - `expiresAt` is an upper bound only (signing credentials may expire earlier). on 403 re-`start` with `id`.
|
|
99
116
|
*/
|
|
@@ -106,7 +123,7 @@ export interface UploadPresignedPutTransfer {
|
|
|
106
123
|
* - EXCEPT the ones the user agent owns: `content-length` and `host`. `fetch` and
|
|
107
124
|
* `XMLHttpRequest` forbid setting them and the UA fills them from the request itself,
|
|
108
125
|
* so a shell adapter must drop them from this map before sending. The signature still
|
|
109
|
-
* matches because the UA's value is the one that was signed.
|
|
126
|
+
* matches because the UA's value is the one that was signed.
|
|
110
127
|
*/
|
|
111
128
|
headers: Record<string, string>;
|
|
112
129
|
maxBytes: number;
|
|
@@ -114,32 +131,45 @@ export interface UploadPresignedPutTransfer {
|
|
|
114
131
|
expiresAt?: number;
|
|
115
132
|
}
|
|
116
133
|
export declare type UploadTransfer = UploadInlineTransfer | UploadPresignedPutTransfer;
|
|
134
|
+
/**
|
|
135
|
+
* a transfer that carries its own destination, so it can deliver any payload of an upload.
|
|
136
|
+
* - `inline` is not one: it goes through `send`, which addresses the whole upload, so a thumbnail
|
|
137
|
+
* sent that way would overwrite the original.
|
|
138
|
+
* - a new kind is listed here explicitly, never by default.
|
|
139
|
+
*/
|
|
140
|
+
export declare type UploadDirectTransfer = UploadPresignedPutTransfer;
|
|
117
141
|
/**
|
|
118
142
|
* one slot of `start`'s answer.
|
|
119
|
-
* - `upload` is safe to store and log. `transfer`
|
|
120
|
-
*
|
|
143
|
+
* - `upload` is safe to store and log. `transfer` and `thumbnailTransfer` are each consumed once by
|
|
144
|
+
* the executor and dropped.
|
|
145
|
+
* - nothing to send at all = neither `transfer` nor `thumbnailTransfer`: already `stored` (dedup)
|
|
146
|
+
* or `failed` at validation. `transfer` alone may be absent while `thumbnailTransfer` is present —
|
|
147
|
+
* that is a `stored` upload getting a thumbnail added; its bytes are immutable.
|
|
121
148
|
*/
|
|
122
149
|
export interface UploadTicket {
|
|
123
|
-
upload:
|
|
150
|
+
upload: Upload;
|
|
124
151
|
transfer?: UploadTransfer;
|
|
152
|
+
/** the thumbnail's transfer, if the intent declared one and the server can issue it */
|
|
153
|
+
thumbnailTransfer?: UploadDirectTransfer;
|
|
125
154
|
}
|
|
126
|
-
|
|
127
|
-
|
|
155
|
+
/** request of the `start` operation */
|
|
156
|
+
export interface UploadStartRequest {
|
|
157
|
+
list: UploadIntent[];
|
|
128
158
|
/** transfer kinds this client can execute, preferred first. absent = `['inline']` */
|
|
129
159
|
transfers?: UploadTransferKind[];
|
|
130
160
|
}
|
|
131
|
-
/** same length and order as `
|
|
161
|
+
/** same length and order as `UploadStartRequest.list` */
|
|
132
162
|
export interface UploadStartResult {
|
|
133
163
|
list: UploadTicket[];
|
|
134
164
|
}
|
|
135
|
-
/**
|
|
136
|
-
export interface
|
|
165
|
+
/** request of the `send` operation (inline transfer only) */
|
|
166
|
+
export interface UploadSendRequest {
|
|
137
167
|
/** base64 of the whole content; size must match the declared `contentSize` */
|
|
138
168
|
content: string;
|
|
139
169
|
}
|
|
140
170
|
/** who produced a failure */
|
|
141
171
|
export declare const UPLOAD_FAILURE_SOURCE: {
|
|
142
|
-
/**
|
|
172
|
+
/** the upload API answered with an error */
|
|
143
173
|
readonly api: "api";
|
|
144
174
|
/** the storage endpoint (presigned PUT) answered with an error */
|
|
145
175
|
readonly storage: "storage";
|
|
@@ -180,26 +210,27 @@ export interface UploadCompleteItem {
|
|
|
180
210
|
/** set when the transfer did not succeed; the server marks the upload `failed` */
|
|
181
211
|
failure?: UploadFailure;
|
|
182
212
|
}
|
|
183
|
-
|
|
213
|
+
/** request of the `complete` operation */
|
|
214
|
+
export interface UploadCompleteRequest {
|
|
184
215
|
list: UploadCompleteItem[];
|
|
185
216
|
}
|
|
186
|
-
/** same length and order as `
|
|
217
|
+
/** same length and order as `UploadCompleteRequest.list` */
|
|
187
218
|
export interface UploadCompleteResult {
|
|
188
|
-
list:
|
|
219
|
+
list: Upload[];
|
|
189
220
|
}
|
|
190
221
|
/**
|
|
191
|
-
* the four operations.
|
|
222
|
+
* the four operations. a server exposes them over `UPLOAD_ROUTES`; a client adapter implements this to call them.
|
|
192
223
|
* - all four require the caller's normal API auth; a presigned url is the only unauthenticated hop.
|
|
193
224
|
*/
|
|
194
|
-
export interface
|
|
225
|
+
export interface UploadSupportable {
|
|
195
226
|
/** declare intents; get tickets. validation failures come back per slot as `failed`, never as HTTP 4xx */
|
|
196
|
-
start(body:
|
|
227
|
+
start(body: UploadStartRequest): Promise<UploadStartResult>;
|
|
197
228
|
/** inline transfer: deliver the bytes of one pending upload */
|
|
198
|
-
send(id: string, body:
|
|
229
|
+
send(id: string, body: UploadSendRequest): Promise<Upload>;
|
|
199
230
|
/** confirm; the server verifies what it cannot see (presigned) and settles `status`. idempotent */
|
|
200
|
-
complete(body:
|
|
201
|
-
/** re-read
|
|
202
|
-
read(id: string): Promise<
|
|
231
|
+
complete(body: UploadCompleteRequest): Promise<UploadCompleteResult>;
|
|
232
|
+
/** re-read for the current state */
|
|
233
|
+
read(id: string): Promise<Upload>;
|
|
203
234
|
}
|
|
204
235
|
/** HTTP binding relative to the server's upload base path (lemon-core `/{type}/{id}/{cmd}` shape) */
|
|
205
236
|
export declare const UPLOAD_ROUTES: {
|
|
@@ -220,11 +251,9 @@ export declare const UPLOAD_ROUTES: {
|
|
|
220
251
|
readonly path: "/{id}";
|
|
221
252
|
};
|
|
222
253
|
};
|
|
223
|
-
/**
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
export declare const isUploadStored: (view: UploadView) => view is UploadStoredView;
|
|
229
|
-
/** shared stereo derivation so an optimistic client tile and the server agree */
|
|
254
|
+
/**
|
|
255
|
+
* shared stereo derivation so an optimistic client tile and the server agree.
|
|
256
|
+
* - classifies by the top-level media type; any other non-empty type is `file`.
|
|
257
|
+
* - classification only: which types a server accepts is that server's own policy.
|
|
258
|
+
*/
|
|
230
259
|
export declare const uploadStereoOf: (contentType: string) => UploadStereo | undefined;
|
package/dist/upload/types.js
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `upload/types.ts`
|
|
4
|
+
* - client <-> server contract for uploading files.
|
|
5
|
+
* - transport-neutral: the client always runs `start` -> transfer -> `complete`; whether the server
|
|
6
|
+
* stores bytes inline (base64 in JSON) or hands out a presigned PUT only changes which
|
|
7
|
+
* `UploadTransfer` variant it issues.
|
|
8
|
+
* - runtime-neutral like `socket/`: no Node, DOM, or AWS SDK types. Storage coordinates
|
|
9
|
+
* (bucket, key, region) never appear here.
|
|
10
|
+
* - model-neutral: nothing here imports or names lemon-core's Model/View/Body/Head layers or the `$`
|
|
11
|
+
* embed marker. two shapes carry the vocabulary instead — `UploadContent` (bytes as declared) and
|
|
12
|
+
* `UploadResource` (bytes as stored, with an address). how a server maps them onto its own model
|
|
13
|
+
* layer, and how it embeds an upload in another record, is the server's concern.
|
|
14
|
+
*
|
|
15
|
+
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
16
|
+
*/
|
|
2
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.uploadStereoOf = exports.
|
|
4
|
-
/** kind of stored content
|
|
18
|
+
exports.uploadStereoOf = exports.UPLOAD_ROUTES = exports.UPLOAD_FAILURE_CODE = exports.UPLOAD_FAILURE_SOURCE = exports.isUploadStored = exports.UPLOAD_TRANSFER_KIND = exports.UPLOAD_STATUS = exports.UPLOAD_STEREO = void 0;
|
|
19
|
+
/** kind of stored content */
|
|
5
20
|
exports.UPLOAD_STEREO = {
|
|
6
21
|
image: 'image',
|
|
7
22
|
video: 'video',
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
audio: 'audio',
|
|
24
|
+
/** any file that is not an image, video or audio */
|
|
25
|
+
file: 'file',
|
|
10
26
|
};
|
|
11
27
|
/** lifecycle of one upload as the client sees it. `url` is meaningful only when `stored` */
|
|
12
28
|
exports.UPLOAD_STATUS = {
|
|
@@ -14,19 +30,21 @@ exports.UPLOAD_STATUS = {
|
|
|
14
30
|
pending: 'pending',
|
|
15
31
|
/** bytes durable and `url` valid */
|
|
16
32
|
stored: 'stored',
|
|
17
|
-
/** terminal; `error` carries
|
|
33
|
+
/** terminal; `error` carries the server's detail */
|
|
18
34
|
failed: 'failed',
|
|
19
35
|
};
|
|
20
|
-
/** how bytes travel.
|
|
36
|
+
/** how bytes travel. a new transfer method arrives as a new kind; the flow around it does not change */
|
|
21
37
|
exports.UPLOAD_TRANSFER_KIND = {
|
|
22
|
-
/** base64
|
|
38
|
+
/** base64 in a JSON body, through the `send` operation */
|
|
23
39
|
inline: 'inline',
|
|
24
|
-
/** HTTP PUT straight to storage
|
|
40
|
+
/** HTTP PUT straight to storage, to a server-issued url with its headers */
|
|
25
41
|
presignedPut: 'presigned-put',
|
|
26
42
|
};
|
|
43
|
+
const isUploadStored = (upload) => upload.status === exports.UPLOAD_STATUS.stored && typeof upload.id === 'string' && typeof upload.url === 'string';
|
|
44
|
+
exports.isUploadStored = isUploadStored;
|
|
27
45
|
/** who produced a failure */
|
|
28
46
|
exports.UPLOAD_FAILURE_SOURCE = {
|
|
29
|
-
/**
|
|
47
|
+
/** the upload API answered with an error */
|
|
30
48
|
api: 'api',
|
|
31
49
|
/** the storage endpoint (presigned PUT) answered with an error */
|
|
32
50
|
storage: 'storage',
|
|
@@ -55,20 +73,22 @@ exports.UPLOAD_ROUTES = {
|
|
|
55
73
|
complete: { method: 'POST', path: '/complete' },
|
|
56
74
|
read: { method: 'GET', path: '/{id}' },
|
|
57
75
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
/**
|
|
77
|
+
* shared stereo derivation so an optimistic client tile and the server agree.
|
|
78
|
+
* - classifies by the top-level media type; any other non-empty type is `file`.
|
|
79
|
+
* - classification only: which types a server accepts is that server's own policy.
|
|
80
|
+
*/
|
|
61
81
|
const uploadStereoOf = (contentType) => {
|
|
62
82
|
const type = contentType.toLowerCase().split(';')[0].trim();
|
|
83
|
+
if (!type)
|
|
84
|
+
return undefined;
|
|
63
85
|
if (type.startsWith('image/'))
|
|
64
86
|
return exports.UPLOAD_STEREO.image;
|
|
65
87
|
if (type.startsWith('video/'))
|
|
66
88
|
return exports.UPLOAD_STEREO.video;
|
|
67
89
|
if (type.startsWith('audio/'))
|
|
68
|
-
return exports.UPLOAD_STEREO.
|
|
69
|
-
|
|
70
|
-
return exports.UPLOAD_STEREO.docs;
|
|
71
|
-
return undefined;
|
|
90
|
+
return exports.UPLOAD_STEREO.audio;
|
|
91
|
+
return exports.UPLOAD_STEREO.file;
|
|
72
92
|
};
|
|
73
93
|
exports.uploadStereoOf = uploadStereoOf;
|
|
74
94
|
//# sourceMappingURL=types.js.map
|
package/dist/upload/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/upload/types.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/upload/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,6BAA6B;AAChB,QAAA,aAAa,GAAG;IACzB,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,oDAAoD;IACpD,IAAI,EAAE,MAAM;CACN,CAAC;AAGX,4FAA4F;AAC/E,QAAA,aAAa,GAAG;IACzB,2DAA2D;IAC3D,OAAO,EAAE,SAAS;IAClB,oCAAoC;IACpC,MAAM,EAAE,QAAQ;IAChB,oDAAoD;IACpD,MAAM,EAAE,QAAQ;CACV,CAAC;AAGX,wGAAwG;AAC3F,QAAA,oBAAoB,GAAG;IAChC,0DAA0D;IAC1D,MAAM,EAAE,QAAQ;IAChB,4EAA4E;IAC5E,YAAY,EAAE,eAAe;CACvB,CAAC;AAoEJ,MAAM,cAAc,GAAG,CAAC,MAAc,EAA0B,EAAE,CACrE,MAAM,CAAC,MAAM,KAAK,qBAAa,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC;AADjG,QAAA,cAAc,kBACmF;AA0E9G,6BAA6B;AAChB,QAAA,qBAAqB,GAAG;IACjC,4CAA4C;IAC5C,GAAG,EAAE,KAAK;IACV,kEAAkE;IAClE,OAAO,EAAE,SAAS;IAClB,sDAAsD;IACtD,MAAM,EAAE,QAAQ;CACV,CAAC;AAGX,oFAAoF;AACvE,QAAA,mBAAmB,GAAG;IAC/B,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,aAAa;IAC1B,aAAa,EAAE,gBAAgB;IAC/B,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACZ,CAAC;AA+CX,qGAAqG;AACxF,QAAA,aAAa,GAAG;IACzB,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE;IAC5C,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE;IAC/C,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;CAChC,CAAC;AAEX;;;;GAIG;AACI,MAAM,cAAc,GAAG,CAAC,WAAmB,EAA4B,EAAE;IAC5E,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,qBAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,qBAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,qBAAa,CAAC,KAAK,CAAC;IAC1D,OAAO,qBAAa,CAAC,IAAI,CAAC;AAC9B,CAAC,CAAC;AAPW,QAAA,cAAc,kBAOzB"}
|