@heyputer/puter.js 2.1.6 → 2.1.8
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/puter.cjs +2 -2
- package/index.d.ts +103 -626
- package/package.json +1 -1
- package/src/index.js +91 -91
- package/src/lib/APICallLogger.js +20 -21
- package/src/lib/EventListener.js +10 -10
- package/src/lib/filesystem/APIFS.js +11 -19
- package/src/lib/filesystem/CacheFS.js +25 -25
- package/src/lib/filesystem/PostMessageFS.js +11 -11
- package/src/lib/filesystem/definitions.js +11 -10
- package/src/lib/path.js +505 -446
- package/src/lib/polyfills/fileReaderPoly.js +40 -0
- package/src/lib/polyfills/localStorage.js +30 -33
- package/src/lib/polyfills/xhrshim.js +206 -207
- package/src/lib/utils.js +160 -151
- package/src/lib/xdrpc.js +9 -9
- package/src/modules/AI.js +416 -290
- package/src/modules/Apps.js +56 -56
- package/src/modules/Auth.js +17 -17
- package/src/modules/Debug.js +1 -1
- package/src/modules/Drivers.js +41 -41
- package/src/modules/FSItem.js +64 -62
- package/src/modules/FileSystem/index.js +22 -23
- package/src/modules/FileSystem/operations/copy.js +7 -7
- package/src/modules/FileSystem/operations/deleteFSEntry.js +14 -12
- package/src/modules/FileSystem/operations/getReadUrl.js +16 -14
- package/src/modules/FileSystem/operations/mkdir.js +11 -11
- package/src/modules/FileSystem/operations/move.js +12 -12
- package/src/modules/FileSystem/operations/read.js +10 -10
- package/src/modules/FileSystem/operations/readdir.js +28 -28
- package/src/modules/FileSystem/operations/rename.js +11 -11
- package/src/modules/FileSystem/operations/sign.js +33 -30
- package/src/modules/FileSystem/operations/space.js +7 -7
- package/src/modules/FileSystem/operations/stat.js +25 -25
- package/src/modules/FileSystem/operations/symlink.js +15 -17
- package/src/modules/FileSystem/operations/upload.js +151 -122
- package/src/modules/FileSystem/operations/write.js +16 -12
- package/src/modules/FileSystem/utils/getAbsolutePathForApp.js +10 -6
- package/src/modules/Hosting.js +29 -29
- package/src/modules/KV.js +23 -23
- package/src/modules/OS.js +15 -15
- package/src/modules/Perms.js +19 -21
- package/src/modules/PuterDialog.js +46 -48
- package/src/modules/Threads.js +17 -20
- package/src/modules/UI.js +156 -156
- package/src/modules/Util.js +3 -3
- package/src/modules/Workers.js +52 -49
- package/src/modules/networking/PSocket.js +38 -38
- package/src/modules/networking/PTLS.js +54 -47
- package/src/modules/networking/PWispHandler.js +49 -47
- package/src/modules/networking/parsers.js +110 -108
- package/src/modules/networking/requests.js +67 -78
- package/src/services/APIAccess.js +9 -9
- package/src/services/FSRelay.js +6 -6
- package/src/services/Filesystem.js +8 -8
- package/src/services/NoPuterYet.js +2 -2
- package/src/services/XDIncoming.js +1 -1
|
@@ -15,16 +15,16 @@ export const UDP = 0x02;
|
|
|
15
15
|
export const textde = new TextDecoder();
|
|
16
16
|
const texten = new TextEncoder();
|
|
17
17
|
export const errors = {
|
|
18
|
-
|
|
19
|
-
,0x03:
|
|
20
|
-
,0x41:
|
|
21
|
-
,0x42:
|
|
22
|
-
,0x43:
|
|
23
|
-
,0x44:
|
|
24
|
-
,0x47:
|
|
25
|
-
,0x48:
|
|
26
|
-
,0x49:
|
|
27
|
-
}
|
|
18
|
+
0x01: 'Reason unspecified or unknown. Returning a more specific reason should be preferred.'
|
|
19
|
+
, 0x03: 'Unexpected stream closure due to a network error.'
|
|
20
|
+
, 0x41: 'Stream creation failed due to invalid information. This could be sent if the destination was a reserved address or the port is invalid.'
|
|
21
|
+
, 0x42: 'Stream creation failed due to an unreachable destination host. This could be sent if the destination is an domain which does not resolve to anything.'
|
|
22
|
+
, 0x43: 'Stream creation timed out due to the destination server not responding.'
|
|
23
|
+
, 0x44: 'Stream creation failed due to the destination server refusing the connection.'
|
|
24
|
+
, 0x47: 'TCP data transfer timed out.'
|
|
25
|
+
, 0x48: 'Stream destination address/domain is intentionally blocked by the proxy server.'
|
|
26
|
+
, 0x49: 'Connection throttled by the server.',
|
|
27
|
+
};
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* @typedef {{packetType: number, streamID: number, streamType?: number, port?: number, hostname?: string, payload?: Uint8Array, reason?: number, remainingBuffer?: number}} ParsedWispPacket
|
|
@@ -32,126 +32,128 @@ export const errors = {
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Parses a wisp packet fully
|
|
35
|
-
*
|
|
36
|
-
* @param {Uint8Array} data
|
|
35
|
+
*
|
|
36
|
+
* @param {Uint8Array} data
|
|
37
37
|
* @returns {ParsedWispPacket} Packet Info
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
|
-
export function parseIncomingPacket(data) {
|
|
40
|
+
export function parseIncomingPacket (data) {
|
|
41
41
|
const view = new DataView(data.buffer, data.byteOffset);
|
|
42
42
|
const packetType = view.getUint8(0);
|
|
43
43
|
const streamID = view.getUint32(1, true);
|
|
44
|
-
switch (packetType) { // Packet payload starts at Offset 5
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
44
|
+
switch ( packetType ) { // Packet payload starts at Offset 5
|
|
45
|
+
case CONNECT:
|
|
46
|
+
const streamType = view.getUint8(5);
|
|
47
|
+
const port = view.getUint16(6, true);
|
|
48
|
+
const hostname = textde.decode(data.subarray(8, data.length));
|
|
49
|
+
return { packetType, streamID, streamType, port, hostname };
|
|
50
|
+
break;
|
|
51
|
+
case DATA:
|
|
52
|
+
const payload = data.subarray(5, data.length);
|
|
53
|
+
return { packetType, streamID, payload };
|
|
54
|
+
break;
|
|
55
|
+
case CONTINUE:
|
|
56
|
+
const remainingBuffer = view.getUint32(5, true);
|
|
57
|
+
return { packetType, streamID, remainingBuffer };
|
|
58
|
+
break;
|
|
59
|
+
case CLOSE:
|
|
60
|
+
const reason = view.getUint8(5);
|
|
61
|
+
return { packetType, streamID, reason };
|
|
62
|
+
break;
|
|
63
|
+
case INFO:
|
|
64
|
+
const infoObj = {};
|
|
65
|
+
infoObj['version_major'] = view.getUint8(5);
|
|
66
|
+
infoObj['version_minor'] = view.getUint8(6);
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
let ptr = 7;
|
|
69
|
+
while ( ptr < data.length ) {
|
|
70
|
+
const extType = view.getUint8(ptr);
|
|
71
|
+
const extLength = view.getUint32(ptr + 1, true);
|
|
72
|
+
const payload = data.subarray(ptr + 5, ptr + 5 + extLength);
|
|
73
|
+
infoObj[extType] = payload;
|
|
74
|
+
ptr += 5 + extLength;
|
|
75
|
+
}
|
|
76
|
+
return { packetType, streamID, infoObj };
|
|
77
|
+
break;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* creates a wisp packet fully
|
|
82
|
-
*
|
|
83
|
-
* @param {ParsedWispPacket} instructions
|
|
82
|
+
*
|
|
83
|
+
* @param {ParsedWispPacket} instructions
|
|
84
84
|
* @returns {Uint8Array} Constructed Packet
|
|
85
85
|
*/
|
|
86
86
|
|
|
87
|
-
export function createWispPacket(instructions) {
|
|
87
|
+
export function createWispPacket (instructions) {
|
|
88
88
|
let size = 5;
|
|
89
|
-
switch (instructions.packetType) { // Pass 1: determine size of packet
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
89
|
+
switch ( instructions.packetType ) { // Pass 1: determine size of packet
|
|
90
|
+
case CONNECT:
|
|
91
|
+
instructions.hostEncoded = texten.encode(instructions.hostname);
|
|
92
|
+
size += 3 + instructions.hostEncoded.length;
|
|
93
|
+
break;
|
|
94
|
+
case DATA:
|
|
95
|
+
size += instructions.payload.byteLength;
|
|
96
|
+
break;
|
|
97
|
+
case CONTINUE:
|
|
98
|
+
size += 4;
|
|
99
|
+
break;
|
|
100
|
+
case CLOSE:
|
|
101
|
+
size += 1;
|
|
102
|
+
break;
|
|
103
|
+
case INFO:
|
|
104
|
+
size += 2;
|
|
105
|
+
if ( instructions.password )
|
|
106
|
+
{
|
|
107
|
+
size += 6;
|
|
108
|
+
}
|
|
109
|
+
if ( instructions.puterAuth ) {
|
|
110
|
+
instructions.passwordEncoded = texten.encode(instructions.puterAuth);
|
|
111
|
+
size += 8 + instructions.passwordEncoded.length;
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
default:
|
|
115
|
+
throw new Error('Not supported');
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
let data = new Uint8Array(size);
|
|
117
119
|
const view = new DataView(data.buffer);
|
|
118
120
|
view.setUint8(0, instructions.packetType);
|
|
119
121
|
view.setUint32(1, instructions.streamID, true);
|
|
120
|
-
switch (instructions.packetType) { // Pass 2: fill out packet
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
122
|
+
switch ( instructions.packetType ) { // Pass 2: fill out packet
|
|
123
|
+
case CONNECT:
|
|
124
|
+
view.setUint8(5, instructions.streamType);
|
|
125
|
+
view.setUint16(6, instructions.port, true);
|
|
126
|
+
data.set(instructions.hostEncoded, 8);
|
|
127
|
+
break;
|
|
128
|
+
case DATA:
|
|
129
|
+
data.set(instructions.payload, 5);
|
|
130
|
+
break;
|
|
131
|
+
case CONTINUE:
|
|
132
|
+
view.setUint32(5, instructions.remainingBuffer, true);
|
|
133
|
+
break;
|
|
134
|
+
case CLOSE:
|
|
135
|
+
view.setUint8(5, instructions.reason);
|
|
136
|
+
break;
|
|
137
|
+
case INFO:
|
|
138
|
+
// WISP 2.0
|
|
139
|
+
view.setUint8(5, 2);
|
|
140
|
+
view.setUint8(6, 0);
|
|
141
|
+
|
|
142
|
+
if ( instructions.password ) {
|
|
143
|
+
// PASSWORD AUTH REQUIRED
|
|
144
|
+
view.setUint8(7, 0x02); // Protocol ID (Password)
|
|
145
|
+
view.setUint32(8, 1, true);
|
|
146
|
+
view.setUint8(12, 0); // Password required? true
|
|
147
|
+
}
|
|
146
148
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
if ( instructions.puterAuth ) {
|
|
150
|
+
// PASSWORD AUTH REQUIRED
|
|
151
|
+
view.setUint8(7, 0x02); // Protocol ID (Password)
|
|
152
|
+
view.setUint32(8, 5 + instructions.passwordEncoded.length, true);
|
|
153
|
+
view.setUint8(12, 0);
|
|
154
|
+
view.setUint16(13, instructions.passwordEncoded.length, true);
|
|
155
|
+
data.set(instructions.passwordEncoded, 15);
|
|
156
|
+
}
|
|
155
157
|
}
|
|
156
158
|
return data;
|
|
157
159
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SO: https://stackoverflow.com/a/76332760/ under CC BY-SA 4.0
|
|
2
|
-
function mergeUint8Arrays(...arrays) {
|
|
2
|
+
function mergeUint8Arrays (...arrays) {
|
|
3
3
|
const totalSize = arrays.reduce((acc, e) => acc + e.length, 0);
|
|
4
4
|
const merged = new Uint8Array(totalSize);
|
|
5
5
|
|
|
@@ -11,18 +11,18 @@ function mergeUint8Arrays(...arrays) {
|
|
|
11
11
|
return merged;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function parseHTTPHead(head) {
|
|
15
|
-
const lines = head.split(
|
|
14
|
+
function parseHTTPHead (head) {
|
|
15
|
+
const lines = head.split('\r\n');
|
|
16
16
|
|
|
17
|
-
const firstLine = lines.shift().split(
|
|
17
|
+
const firstLine = lines.shift().split(' ');
|
|
18
18
|
const status = Number(firstLine[1]);
|
|
19
|
-
const statusText = firstLine.slice(2).join(
|
|
19
|
+
const statusText = firstLine.slice(2).join(' ') || '';
|
|
20
20
|
|
|
21
21
|
const headersArray = [];
|
|
22
|
-
for (const header of lines) {
|
|
23
|
-
const splitHeaders = header.split(
|
|
22
|
+
for ( const header of lines ) {
|
|
23
|
+
const splitHeaders = header.split(': ');
|
|
24
24
|
const key = splitHeaders[0];
|
|
25
|
-
const value = splitHeaders.slice(1).join(
|
|
25
|
+
const value = splitHeaders.slice(1).join(': ');
|
|
26
26
|
headersArray.push([key, value]);
|
|
27
27
|
}
|
|
28
28
|
new Headers(headersArray);
|
|
@@ -32,7 +32,7 @@ function parseHTTPHead(head) {
|
|
|
32
32
|
// Trivial stream based HTTP 1.1 client
|
|
33
33
|
// TODO optional redirect handling
|
|
34
34
|
|
|
35
|
-
export function pFetch(...args) {
|
|
35
|
+
export function pFetch (...args) {
|
|
36
36
|
return new Promise(async (res, rej) => {
|
|
37
37
|
try {
|
|
38
38
|
const reqObj = new Request(...args);
|
|
@@ -41,68 +41,62 @@ export function pFetch(...args) {
|
|
|
41
41
|
|
|
42
42
|
// Socket creation: regular for HTTP, TLS for https
|
|
43
43
|
let socket;
|
|
44
|
-
if (parsedURL.protocol ===
|
|
45
|
-
socket = new puter.net.Socket(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
socket = new puter.net.tls.TLSSocket(
|
|
51
|
-
parsedURL.hostname,
|
|
52
|
-
parsedURL.port || 443,
|
|
53
|
-
);
|
|
44
|
+
if ( parsedURL.protocol === 'http:' ) {
|
|
45
|
+
socket = new puter.net.Socket(parsedURL.hostname,
|
|
46
|
+
parsedURL.port || 80);
|
|
47
|
+
} else if ( parsedURL.protocol === 'https:' ) {
|
|
48
|
+
socket = new puter.net.tls.TLSSocket(parsedURL.hostname,
|
|
49
|
+
parsedURL.port || 443);
|
|
54
50
|
} else {
|
|
55
51
|
const errorMsg = `Failed to fetch. URL scheme "${parsedURL.protocol}" is not supported.`;
|
|
56
|
-
|
|
52
|
+
|
|
57
53
|
// Log the error
|
|
58
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
54
|
+
if ( globalThis.puter?.apiCallLogger?.isEnabled() ) {
|
|
59
55
|
globalThis.puter.apiCallLogger.logRequest({
|
|
60
56
|
service: 'network',
|
|
61
57
|
operation: 'pFetch',
|
|
62
58
|
params: { url: reqObj.url, method: reqObj.method },
|
|
63
|
-
error: { message: errorMsg }
|
|
59
|
+
error: { message: errorMsg },
|
|
64
60
|
});
|
|
65
61
|
}
|
|
66
|
-
|
|
62
|
+
|
|
67
63
|
rej(errorMsg);
|
|
68
64
|
return;
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
// Sending default UA
|
|
72
|
-
if (!headers.get(
|
|
73
|
-
headers.set(
|
|
68
|
+
if ( ! headers.get('user-agent') ) {
|
|
69
|
+
headers.set('user-agent', navigator.userAgent);
|
|
74
70
|
}
|
|
75
71
|
|
|
76
72
|
let reqHead = `${reqObj.method} ${parsedURL.pathname}${parsedURL.search} HTTP/1.1\r\nHost: ${parsedURL.host}\r\nConnection: close\r\n`;
|
|
77
|
-
for (const [key, value] of headers) {
|
|
73
|
+
for ( const [key, value] of headers ) {
|
|
78
74
|
reqHead += `${key}: ${value}\r\n`;
|
|
79
75
|
}
|
|
80
76
|
let requestBody;
|
|
81
|
-
if (reqObj.body) {
|
|
77
|
+
if ( reqObj.body ) {
|
|
82
78
|
requestBody = new Uint8Array(await reqObj.arrayBuffer());
|
|
83
79
|
// If we have a body, we need to set the content length
|
|
84
|
-
if (!headers.has(
|
|
85
|
-
headers.set(
|
|
80
|
+
if ( ! headers.has('content-length') ) {
|
|
81
|
+
headers.set('content-length', requestBody.length);
|
|
86
82
|
} else if (
|
|
87
|
-
headers.get(
|
|
83
|
+
headers.get('content-length') !== String(requestBody.length)
|
|
88
84
|
) {
|
|
89
|
-
return rej(
|
|
90
|
-
"Content-Length header does not match the body length. Please check your request.",
|
|
91
|
-
);
|
|
85
|
+
return rej('Content-Length header does not match the body length. Please check your request.');
|
|
92
86
|
}
|
|
93
87
|
reqHead += `Content-Length: ${requestBody.length}\r\n`;
|
|
94
88
|
}
|
|
95
89
|
|
|
96
|
-
reqHead +=
|
|
90
|
+
reqHead += '\r\n';
|
|
97
91
|
|
|
98
|
-
socket.on(
|
|
92
|
+
socket.on('open', async () => {
|
|
99
93
|
socket.write(reqHead); // Send headers
|
|
100
|
-
if (requestBody) {
|
|
94
|
+
if ( requestBody ) {
|
|
101
95
|
socket.write(requestBody); // Send body if present
|
|
102
96
|
}
|
|
103
97
|
});
|
|
104
98
|
const decoder = new TextDecoder();
|
|
105
|
-
let responseHead =
|
|
99
|
+
let responseHead = '';
|
|
106
100
|
let dataOffset = -1;
|
|
107
101
|
const fullDataParts = [];
|
|
108
102
|
let responseReturned = false;
|
|
@@ -113,9 +107,9 @@ export function pFetch(...args) {
|
|
|
113
107
|
let buffer = new Uint8Array(0);
|
|
114
108
|
|
|
115
109
|
const outStream = new ReadableStream({
|
|
116
|
-
start(controller) {
|
|
110
|
+
start (controller) {
|
|
117
111
|
// This is annoyingly long
|
|
118
|
-
function parseIncomingChunk(data) {
|
|
112
|
+
function parseIncomingChunk (data) {
|
|
119
113
|
// append new data to our rolling buffer
|
|
120
114
|
const tmp = new Uint8Array(buffer.length + data.length);
|
|
121
115
|
tmp.set(buffer, 0);
|
|
@@ -123,11 +117,11 @@ export function pFetch(...args) {
|
|
|
123
117
|
buffer = tmp;
|
|
124
118
|
|
|
125
119
|
// pull out as many complete chunks (or headers) as we can
|
|
126
|
-
while (true) {
|
|
127
|
-
if (currentChunkLeft > 0) {
|
|
120
|
+
while ( true ) {
|
|
121
|
+
if ( currentChunkLeft > 0 ) {
|
|
128
122
|
// we’re in the middle of reading a chunk body
|
|
129
123
|
// need size + 2 bytes (for trailing \r\n)
|
|
130
|
-
if (buffer.length >= currentChunkLeft + 2) {
|
|
124
|
+
if ( buffer.length >= currentChunkLeft + 2 ) {
|
|
131
125
|
// full body + CRLF available
|
|
132
126
|
const chunk = buffer.slice(0, currentChunkLeft);
|
|
133
127
|
controller.enqueue(chunk);
|
|
@@ -146,7 +140,7 @@ export function pFetch(...args) {
|
|
|
146
140
|
// we need to parse the next size line
|
|
147
141
|
// find the first "\r\n"
|
|
148
142
|
let idx = -1;
|
|
149
|
-
for (let i = 0; i + 1 < buffer.length; i++) {
|
|
143
|
+
for ( let i = 0; i + 1 < buffer.length; i++ ) {
|
|
150
144
|
if (
|
|
151
145
|
buffer[i] === 0x0d &&
|
|
152
146
|
buffer[i + 1] === 0x0a
|
|
@@ -155,7 +149,7 @@ export function pFetch(...args) {
|
|
|
155
149
|
break;
|
|
156
150
|
}
|
|
157
151
|
}
|
|
158
|
-
if (idx < 0) {
|
|
152
|
+
if ( idx < 0 ) {
|
|
159
153
|
// we don’t yet have a full size line
|
|
160
154
|
break;
|
|
161
155
|
}
|
|
@@ -165,16 +159,14 @@ export function pFetch(...args) {
|
|
|
165
159
|
.decode(buffer.slice(0, idx))
|
|
166
160
|
.trim();
|
|
167
161
|
currentChunkLeft = parseInt(sizeText, 16);
|
|
168
|
-
if (isNaN(currentChunkLeft)) {
|
|
169
|
-
controller.error(
|
|
170
|
-
"Invalid chunk length from server",
|
|
171
|
-
);
|
|
162
|
+
if ( isNaN(currentChunkLeft) ) {
|
|
163
|
+
controller.error('Invalid chunk length from server');
|
|
172
164
|
}
|
|
173
165
|
// strip off the size line + CRLF
|
|
174
166
|
buffer = buffer.slice(idx + 2);
|
|
175
167
|
|
|
176
168
|
// zero-length => end of stream
|
|
177
|
-
if (currentChunkLeft === 0) {
|
|
169
|
+
if ( currentChunkLeft === 0 ) {
|
|
178
170
|
responseReturned = true;
|
|
179
171
|
controller.close();
|
|
180
172
|
return;
|
|
@@ -182,51 +174,47 @@ export function pFetch(...args) {
|
|
|
182
174
|
}
|
|
183
175
|
}
|
|
184
176
|
}
|
|
185
|
-
socket.on(
|
|
177
|
+
socket.on('data', (data) => {
|
|
186
178
|
// Dataoffset is set to another value once head is returned, its safe to assume all remaining data is body
|
|
187
|
-
if (dataOffset !== -1 && !chunkedTransfer) {
|
|
179
|
+
if ( dataOffset !== -1 && !chunkedTransfer ) {
|
|
188
180
|
controller.enqueue(data);
|
|
189
181
|
ingestedContent += data.length;
|
|
190
182
|
}
|
|
191
183
|
|
|
192
184
|
// We dont have the full responseHead yet
|
|
193
|
-
if (dataOffset === -1) {
|
|
185
|
+
if ( dataOffset === -1 ) {
|
|
194
186
|
fullDataParts.push(data);
|
|
195
187
|
responseHead += decoder.decode(data, { stream: true });
|
|
196
188
|
}
|
|
197
|
-
if (chunkedTransfer) {
|
|
189
|
+
if ( chunkedTransfer ) {
|
|
198
190
|
parseIncomingChunk(data);
|
|
199
191
|
}
|
|
200
192
|
|
|
201
193
|
// See if we have the HEAD of an HTTP/1.1 yet
|
|
202
|
-
if (responseHead.indexOf(
|
|
203
|
-
dataOffset = responseHead.indexOf(
|
|
194
|
+
if ( responseHead.indexOf('\r\n\r\n') !== -1 ) {
|
|
195
|
+
dataOffset = responseHead.indexOf('\r\n\r\n');
|
|
204
196
|
responseHead = responseHead.slice(0, dataOffset);
|
|
205
197
|
const parsedHead = parseHTTPHead(responseHead);
|
|
206
|
-
contentLength = Number(
|
|
207
|
-
parsedHead.headers.get("content-length"),
|
|
208
|
-
);
|
|
198
|
+
contentLength = Number(parsedHead.headers.get('content-length'));
|
|
209
199
|
chunkedTransfer =
|
|
210
|
-
parsedHead.headers.get(
|
|
211
|
-
|
|
212
|
-
|
|
200
|
+
parsedHead.headers.get('transfer-encoding') ===
|
|
201
|
+
'chunked';
|
|
202
|
+
|
|
213
203
|
// Log the response
|
|
214
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
204
|
+
if ( globalThis.puter?.apiCallLogger?.isEnabled() ) {
|
|
215
205
|
globalThis.puter.apiCallLogger.logRequest({
|
|
216
206
|
service: 'network',
|
|
217
207
|
operation: 'pFetch',
|
|
218
208
|
params: { url: reqObj.url, method: reqObj.method },
|
|
219
|
-
result: { status: parsedHead.status, statusText: parsedHead.statusText }
|
|
209
|
+
result: { status: parsedHead.status, statusText: parsedHead.statusText },
|
|
220
210
|
});
|
|
221
211
|
}
|
|
222
|
-
|
|
212
|
+
|
|
223
213
|
// Return initial response object
|
|
224
214
|
res(new Response(outStream, parsedHead));
|
|
225
215
|
|
|
226
|
-
const residualBody = mergeUint8Arrays(
|
|
227
|
-
|
|
228
|
-
).slice(dataOffset + 4);
|
|
229
|
-
if (!chunkedTransfer) {
|
|
216
|
+
const residualBody = mergeUint8Arrays(...fullDataParts).slice(dataOffset + 4);
|
|
217
|
+
if ( ! chunkedTransfer ) {
|
|
230
218
|
// Add any content we have but isn't part of the head into the body stream
|
|
231
219
|
ingestedContent += residualBody.length;
|
|
232
220
|
controller.enqueue(residualBody);
|
|
@@ -241,42 +229,43 @@ export function pFetch(...args) {
|
|
|
241
229
|
!chunkedTransfer
|
|
242
230
|
) {
|
|
243
231
|
// Work around for the close bug for compliant HTTP/1.1 servers
|
|
244
|
-
if (!responseReturned) {
|
|
232
|
+
if ( ! responseReturned ) {
|
|
245
233
|
responseReturned = true;
|
|
246
234
|
controller.close();
|
|
247
235
|
}
|
|
248
236
|
}
|
|
249
237
|
});
|
|
250
|
-
socket.on(
|
|
251
|
-
if (!responseReturned) {
|
|
238
|
+
socket.on('close', () => {
|
|
239
|
+
if ( ! responseReturned ) {
|
|
252
240
|
responseReturned = true;
|
|
253
241
|
controller.close();
|
|
254
242
|
}
|
|
255
243
|
});
|
|
256
|
-
socket.on(
|
|
244
|
+
socket.on('error', (reason) => {
|
|
257
245
|
// Log the error
|
|
258
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
246
|
+
if ( globalThis.puter?.apiCallLogger?.isEnabled() ) {
|
|
259
247
|
globalThis.puter.apiCallLogger.logRequest({
|
|
260
248
|
service: 'network',
|
|
261
249
|
operation: 'pFetch',
|
|
262
250
|
params: { url: reqObj.url, method: reqObj.method },
|
|
263
|
-
error: { message:
|
|
251
|
+
error: { message: `Socket errored with the following reason: ${ reason}` },
|
|
264
252
|
});
|
|
265
253
|
}
|
|
266
|
-
rej(
|
|
254
|
+
rej(`Socket errored with the following reason: ${ reason}`);
|
|
267
255
|
});
|
|
268
256
|
},
|
|
269
257
|
});
|
|
270
258
|
} catch (e) {
|
|
271
259
|
// Log unexpected errors
|
|
272
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
260
|
+
if ( globalThis.puter?.apiCallLogger?.isEnabled() ) {
|
|
273
261
|
globalThis.puter.apiCallLogger.logRequest({
|
|
274
262
|
service: 'network',
|
|
275
263
|
operation: 'pFetch',
|
|
276
264
|
params: { url: reqObj.url, method: reqObj.method },
|
|
277
|
-
error: { message: e.message || e.toString(), stack: e.stack }
|
|
265
|
+
error: { message: e.message || e.toString(), stack: e.stack },
|
|
278
266
|
});
|
|
279
267
|
}
|
|
280
268
|
rej(e);
|
|
281
|
-
}
|
|
269
|
+
}
|
|
270
|
+
});
|
|
282
271
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import putility from
|
|
1
|
+
import putility from '@heyputer/putility';
|
|
2
2
|
|
|
3
3
|
const { TTopics } = putility.traits;
|
|
4
4
|
|
|
@@ -13,12 +13,12 @@ export class APIAccessService extends putility.concepts.Service {
|
|
|
13
13
|
auth_token: {
|
|
14
14
|
post_set (v) {
|
|
15
15
|
this.as(TTopics).pub('update');
|
|
16
|
-
}
|
|
16
|
+
},
|
|
17
17
|
},
|
|
18
18
|
api_origin: {
|
|
19
19
|
post_set () {
|
|
20
20
|
this.as(TTopics).pub('update');
|
|
21
|
-
}
|
|
21
|
+
},
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -27,18 +27,18 @@ export class APIAccessService extends putility.concepts.Service {
|
|
|
27
27
|
const self = this;
|
|
28
28
|
const o = {};
|
|
29
29
|
[
|
|
30
|
-
['auth_token','auth_token'],
|
|
31
|
-
['authToken','auth_token'],
|
|
32
|
-
['APIOrigin','api_origin'],
|
|
33
|
-
['api_origin','api_origin'],
|
|
34
|
-
].forEach(([k1,k2]) => {
|
|
30
|
+
['auth_token', 'auth_token'],
|
|
31
|
+
['authToken', 'auth_token'],
|
|
32
|
+
['APIOrigin', 'api_origin'],
|
|
33
|
+
['api_origin', 'api_origin'],
|
|
34
|
+
].forEach(([k1, k2]) => {
|
|
35
35
|
Object.defineProperty(o, k1, {
|
|
36
36
|
get () {
|
|
37
37
|
return self[k2];
|
|
38
38
|
},
|
|
39
39
|
set (v) {
|
|
40
40
|
return self;
|
|
41
|
-
}
|
|
41
|
+
},
|
|
42
42
|
});
|
|
43
43
|
});
|
|
44
44
|
return o;
|
package/src/services/FSRelay.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import putility from '@heyputer/putility';
|
|
2
2
|
|
|
3
3
|
const example = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
'id': 'f485f1ba-de07-422c-8c4b-c2da057d4a44',
|
|
5
|
+
'uid': 'f485f1ba-de07-422c-8c4b-c2da057d4a44',
|
|
6
|
+
'is_dir': true,
|
|
7
|
+
'immutable': true,
|
|
8
|
+
'name': 'FromParentWindow',
|
|
9
|
+
};
|
|
10
10
|
|
|
11
11
|
export class FSRelayService extends putility.concepts.Service {
|
|
12
12
|
async _init () {
|