@heyputer/puter.js 1.0.1 → 2.0.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/README.md +14 -43
- package/index.d.ts +479 -0
- package/package.json +13 -3
- package/APACHE_LICENSE.txt +0 -201
- package/doc/devlog.md +0 -49
- package/src/bg.png +0 -0
- package/src/bg.webp +0 -0
- package/src/lib/APICallLogger.js +0 -110
- package/src/lib/EventListener.js +0 -51
- package/src/lib/RequestError.js +0 -6
- package/src/lib/filesystem/APIFS.js +0 -73
- package/src/lib/filesystem/CacheFS.js +0 -243
- package/src/lib/filesystem/PostMessageFS.js +0 -40
- package/src/lib/filesystem/definitions.js +0 -39
- package/src/lib/path.js +0 -509
- package/src/lib/polyfills/localStorage.js +0 -92
- package/src/lib/polyfills/xhrshim.js +0 -233
- package/src/lib/socket.io/socket.io.esm.min.js +0 -7
- package/src/lib/socket.io/socket.io.esm.min.js.map +0 -1
- package/src/lib/socket.io/socket.io.js +0 -4385
- package/src/lib/socket.io/socket.io.js.map +0 -1
- package/src/lib/socket.io/socket.io.min.js +0 -7
- package/src/lib/socket.io/socket.io.min.js.map +0 -1
- package/src/lib/socket.io/socket.io.msgpack.min.js +0 -7
- package/src/lib/socket.io/socket.io.msgpack.min.js.map +0 -1
- package/src/lib/utils.js +0 -620
- package/src/lib/xdrpc.js +0 -104
- package/src/modules/AI.js +0 -680
- package/src/modules/Apps.js +0 -215
- package/src/modules/Auth.js +0 -171
- package/src/modules/Debug.js +0 -39
- package/src/modules/Drivers.js +0 -278
- package/src/modules/FSItem.js +0 -139
- package/src/modules/FileSystem/index.js +0 -187
- package/src/modules/FileSystem/operations/copy.js +0 -64
- package/src/modules/FileSystem/operations/deleteFSEntry.js +0 -59
- package/src/modules/FileSystem/operations/getReadUrl.js +0 -42
- package/src/modules/FileSystem/operations/mkdir.js +0 -62
- package/src/modules/FileSystem/operations/move.js +0 -75
- package/src/modules/FileSystem/operations/read.js +0 -46
- package/src/modules/FileSystem/operations/readdir.js +0 -102
- package/src/modules/FileSystem/operations/rename.js +0 -58
- package/src/modules/FileSystem/operations/sign.js +0 -103
- package/src/modules/FileSystem/operations/space.js +0 -40
- package/src/modules/FileSystem/operations/stat.js +0 -95
- package/src/modules/FileSystem/operations/symlink.js +0 -55
- package/src/modules/FileSystem/operations/upload.js +0 -440
- package/src/modules/FileSystem/operations/write.js +0 -65
- package/src/modules/FileSystem/utils/getAbsolutePathForApp.js +0 -21
- package/src/modules/Hosting.js +0 -138
- package/src/modules/KV.js +0 -301
- package/src/modules/OS.js +0 -95
- package/src/modules/Perms.js +0 -109
- package/src/modules/PuterDialog.js +0 -481
- package/src/modules/Threads.js +0 -75
- package/src/modules/UI.js +0 -1555
- package/src/modules/Util.js +0 -38
- package/src/modules/Workers.js +0 -120
- package/src/modules/networking/PSocket.js +0 -87
- package/src/modules/networking/PTLS.js +0 -100
- package/src/modules/networking/PWispHandler.js +0 -89
- package/src/modules/networking/parsers.js +0 -157
- package/src/modules/networking/requests.js +0 -282
- package/src/services/APIAccess.js +0 -46
- package/src/services/FSRelay.js +0 -20
- package/src/services/Filesystem.js +0 -122
- package/src/services/NoPuterYet.js +0 -20
- package/src/services/XDIncoming.js +0 -44
- package/test/ai.test.js +0 -214
- package/test/fs.test.js +0 -798
- package/test/index.html +0 -1183
- package/test/kv.test.js +0 -548
- package/test/txt2speech.test.js +0 -178
- package/webpack.config.js +0 -25
package/src/lib/utils.js
DELETED
|
@@ -1,620 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses a given response text into a JSON object. If the parsing fails due to invalid JSON format,
|
|
3
|
-
* the original response text is returned.
|
|
4
|
-
*
|
|
5
|
-
* @param {string} responseText - The response text to be parsed into JSON. It is expected to be a valid JSON string.
|
|
6
|
-
* @returns {Object|string} The parsed JSON object if the responseText is valid JSON, otherwise returns the original responseText.
|
|
7
|
-
* @example
|
|
8
|
-
* // returns { key: "value" }
|
|
9
|
-
* parseResponse('{"key": "value"}');
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* // returns "Invalid JSON"
|
|
13
|
-
* parseResponse('Invalid JSON');
|
|
14
|
-
*/
|
|
15
|
-
async function parseResponse(target) {
|
|
16
|
-
if ( target.responseType === 'blob' ) {
|
|
17
|
-
// Get content type of the blob
|
|
18
|
-
const contentType = target.getResponseHeader('content-type');
|
|
19
|
-
if ( contentType.startsWith('application/json') ) {
|
|
20
|
-
// If the blob is JSON, parse it
|
|
21
|
-
const text = await target.response.text();
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(text);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
return text;
|
|
26
|
-
}
|
|
27
|
-
}else if ( contentType.startsWith('application/octet-stream') ) {
|
|
28
|
-
// If the blob is an octet stream, return the blob
|
|
29
|
-
return target.response;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Otherwise return an ojbect
|
|
33
|
-
return {
|
|
34
|
-
success: true,
|
|
35
|
-
result: target.response,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
const responseText = target.responseText;
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(responseText);
|
|
41
|
-
} catch (error) {
|
|
42
|
-
return responseText;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* A function that generates a UUID (Universally Unique Identifier) using the version 4 format,
|
|
48
|
-
* which are random UUIDs. It uses the cryptographic number generator available in modern browsers.
|
|
49
|
-
*
|
|
50
|
-
* The generated UUID is a 36 character string (32 alphanumeric characters separated by 4 hyphens).
|
|
51
|
-
* It follows the pattern: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where x is any hexadecimal digit
|
|
52
|
-
* and y is one of 8, 9, A, or B.
|
|
53
|
-
*
|
|
54
|
-
* @returns {string} Returns a new UUID v4 string.
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
*
|
|
58
|
-
* let id = this.#uuidv4(); // Generate a new UUID
|
|
59
|
-
*
|
|
60
|
-
*/
|
|
61
|
-
function uuidv4(){
|
|
62
|
-
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
|
63
|
-
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Initializes and returns an XMLHttpRequest object configured for a specific API endpoint, method, and headers.
|
|
70
|
-
*
|
|
71
|
-
* @param {string} endpoint - The API endpoint to which the request will be sent. This is appended to the API origin URL.
|
|
72
|
-
* @param {string} APIOrigin - The origin URL of the API. This is prepended to the endpoint.
|
|
73
|
-
* @param {string} authToken - The authorization token used for accessing the API. This is included in the request headers.
|
|
74
|
-
* @param {string} [method='post'] - The HTTP method to be used for the request. Defaults to 'post' if not specified.
|
|
75
|
-
* @param {string} [contentType='application/json;charset=UTF-8'] - The content type of the request. Defaults to
|
|
76
|
-
* 'application/json;charset=UTF-8' if not specified.
|
|
77
|
-
*
|
|
78
|
-
* @returns {XMLHttpRequest} The initialized XMLHttpRequest object.
|
|
79
|
-
*/
|
|
80
|
-
function initXhr(endpoint, APIOrigin, authToken, method= "post", contentType = "text/plain;actually=json", responseType = undefined) {
|
|
81
|
-
const xhr = new XMLHttpRequest();
|
|
82
|
-
xhr.open(method, APIOrigin + endpoint, true);
|
|
83
|
-
if (authToken)
|
|
84
|
-
xhr.setRequestHeader("Authorization", "Bearer " + authToken);
|
|
85
|
-
xhr.setRequestHeader("Content-Type", contentType);
|
|
86
|
-
xhr.responseType = responseType ?? '';
|
|
87
|
-
|
|
88
|
-
// Add API call logging if available
|
|
89
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
90
|
-
xhr._puterRequestId = {
|
|
91
|
-
method,
|
|
92
|
-
service: 'xhr',
|
|
93
|
-
operation: endpoint.replace(/^\//, ''),
|
|
94
|
-
params: { endpoint, contentType, responseType }
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return xhr;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Handles an HTTP response by invoking appropriate callback functions and resolving or rejecting a promise.
|
|
103
|
-
*
|
|
104
|
-
* @param {Function} success_cb - An optional callback function for successful responses. It should take a response object
|
|
105
|
-
* as its only argument.
|
|
106
|
-
* @param {Function} error_cb - An optional callback function for error handling. It should take an error object
|
|
107
|
-
* as its only argument.
|
|
108
|
-
* @param {Function} resolve_func - A function used to resolve a promise. It should take a response object
|
|
109
|
-
* as its only argument.
|
|
110
|
-
* @param {Function} reject_func - A function used to reject a promise. It should take an error object
|
|
111
|
-
* as its only argument.
|
|
112
|
-
* @param {Object} response - The HTTP response object from the request. Expected to have 'status' and 'responseText'
|
|
113
|
-
* properties.
|
|
114
|
-
*
|
|
115
|
-
* @returns {void} The function does not return a value but will either resolve or reject a promise based on the
|
|
116
|
-
* response status.
|
|
117
|
-
*/
|
|
118
|
-
async function handle_resp(success_cb, error_cb, resolve_func, reject_func, response){
|
|
119
|
-
const resp = await parseResponse(response);
|
|
120
|
-
// error - unauthorized
|
|
121
|
-
if(response.status === 401){
|
|
122
|
-
// if error callback is provided, call it
|
|
123
|
-
if(error_cb && typeof error_cb === 'function')
|
|
124
|
-
error_cb({status: 401, message: 'Unauthorized'})
|
|
125
|
-
// reject promise
|
|
126
|
-
return reject_func({status: 401, message: 'Unauthorized'})
|
|
127
|
-
}
|
|
128
|
-
// error - other
|
|
129
|
-
else if(response.status !== 200){
|
|
130
|
-
// if error callback is provided, call it
|
|
131
|
-
if(error_cb && typeof error_cb === 'function')
|
|
132
|
-
error_cb(resp)
|
|
133
|
-
// reject promise
|
|
134
|
-
return reject_func(resp)
|
|
135
|
-
}
|
|
136
|
-
// success
|
|
137
|
-
else{
|
|
138
|
-
// This is a driver error
|
|
139
|
-
if(resp.success === false && resp.error?.code === 'permission_denied'){
|
|
140
|
-
let perm = await puter.ui.requestPermission({permission: 'driver:puter-image-generation:generate'});
|
|
141
|
-
// try sending again if permission was granted
|
|
142
|
-
if(perm.granted){
|
|
143
|
-
// todo repeat request
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// if success callback is provided, call it
|
|
147
|
-
if(success_cb && typeof success_cb === 'function')
|
|
148
|
-
success_cb(resp);
|
|
149
|
-
// resolve with success
|
|
150
|
-
return resolve_func(resp);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Handles an error by invoking a specified error callback and then rejecting a promise.
|
|
156
|
-
*
|
|
157
|
-
* @param {Function} error_cb - An optional callback function that is called if it's provided.
|
|
158
|
-
* This function should take an error object as its only argument.
|
|
159
|
-
* @param {Function} reject_func - A function used to reject a promise. It should take an error object
|
|
160
|
-
* as its only argument.
|
|
161
|
-
* @param {Object} error - The error object that is passed to both the error callback and the reject function.
|
|
162
|
-
*
|
|
163
|
-
* @returns {void} The function does not return a value but will call the reject function with the error.
|
|
164
|
-
*/
|
|
165
|
-
function handle_error(error_cb, reject_func, error){
|
|
166
|
-
// if error callback is provided, call it
|
|
167
|
-
if(error_cb && typeof error_cb === 'function')
|
|
168
|
-
error_cb(error)
|
|
169
|
-
// reject promise
|
|
170
|
-
return reject_func(error)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function setupXhrEventHandlers(xhr, success_cb, error_cb, resolve_func, reject_func) {
|
|
174
|
-
// load: success or error
|
|
175
|
-
xhr.addEventListener('load', async function(e){
|
|
176
|
-
// Log the response if API logging is enabled
|
|
177
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled() && this._puterRequestId) {
|
|
178
|
-
const response = await parseResponse(this).catch(() => null);
|
|
179
|
-
globalThis.puter.apiCallLogger.logRequest({
|
|
180
|
-
service: this._puterRequestId.service,
|
|
181
|
-
operation: this._puterRequestId.operation,
|
|
182
|
-
params: this._puterRequestId.params,
|
|
183
|
-
result: this.status >= 400 ? null : response,
|
|
184
|
-
error: this.status >= 400 ? { message: this.statusText, status: this.status } : null
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
return handle_resp(success_cb, error_cb, resolve_func, reject_func, this, xhr);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// error
|
|
191
|
-
xhr.addEventListener('error', function(e){
|
|
192
|
-
// Log the error if API logging is enabled
|
|
193
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled() && this._puterRequestId) {
|
|
194
|
-
globalThis.puter.apiCallLogger.logRequest({
|
|
195
|
-
service: this._puterRequestId.service,
|
|
196
|
-
operation: this._puterRequestId.operation,
|
|
197
|
-
params: this._puterRequestId.params,
|
|
198
|
-
error: {
|
|
199
|
-
message: 'Network error occurred',
|
|
200
|
-
event: e.type
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
return handle_error(error_cb, reject_func, this);
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const NOOP = () => {};
|
|
209
|
-
class Valid {
|
|
210
|
-
static callback (cb) {
|
|
211
|
-
return (cb && typeof cb === 'function') ? cb : undefined;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Makes the hybrid promise/callback function for a particular driver method
|
|
217
|
-
* @param {string[]} arg_defs - argument names (for now; definitions eventually)
|
|
218
|
-
* @param {string} driverInterface - name of the interface
|
|
219
|
-
* @param {string} driverName - name of the driver
|
|
220
|
-
* @param {string} driverMethod - name of the method
|
|
221
|
-
*/
|
|
222
|
-
function make_driver_method(arg_defs, driverInterface, driverName, driverMethod, settings = {}) {
|
|
223
|
-
return async function (...args) {
|
|
224
|
-
let driverArgs = {};
|
|
225
|
-
let options = {};
|
|
226
|
-
|
|
227
|
-
// Check if the first argument is an object and use it as named parameters
|
|
228
|
-
if (args.length === 1 && typeof args[0] === 'object' && !Array.isArray(args[0])) {
|
|
229
|
-
driverArgs = { ...args[0] };
|
|
230
|
-
options = {
|
|
231
|
-
success: driverArgs.success,
|
|
232
|
-
error: driverArgs.error,
|
|
233
|
-
};
|
|
234
|
-
// Remove callback functions from driverArgs if they exist
|
|
235
|
-
delete driverArgs.success;
|
|
236
|
-
delete driverArgs.error;
|
|
237
|
-
} else {
|
|
238
|
-
// Handle as individual arguments
|
|
239
|
-
arg_defs.forEach((argName, index) => {
|
|
240
|
-
driverArgs[argName] = args[index];
|
|
241
|
-
});
|
|
242
|
-
options = {
|
|
243
|
-
success: args[arg_defs.length],
|
|
244
|
-
error: args[arg_defs.length + 1],
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// preprocess
|
|
249
|
-
if(settings.preprocess && typeof settings.preprocess === 'function'){
|
|
250
|
-
driverArgs = settings.preprocess(driverArgs);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return await driverCall(options, driverInterface, driverName, driverMethod, driverArgs, settings);
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async function driverCall (options, driverInterface, driverName, driverMethod, driverArgs, settings) {
|
|
258
|
-
const tp = new TeePromise();
|
|
259
|
-
|
|
260
|
-
driverCall_(
|
|
261
|
-
options,
|
|
262
|
-
tp.resolve.bind(tp),
|
|
263
|
-
tp.reject.bind(tp),
|
|
264
|
-
driverInterface,
|
|
265
|
-
driverName,
|
|
266
|
-
driverMethod,
|
|
267
|
-
driverArgs,
|
|
268
|
-
undefined,
|
|
269
|
-
undefined,
|
|
270
|
-
settings,
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
return await tp;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// This function encapsulates the logic for sending a driver call request
|
|
277
|
-
async function driverCall_(
|
|
278
|
-
options = {},
|
|
279
|
-
resolve_func, reject_func,
|
|
280
|
-
driverInterface, driverName, driverMethod, driverArgs,
|
|
281
|
-
method,
|
|
282
|
-
contentType = 'text/plain;actually=json',
|
|
283
|
-
settings = {},
|
|
284
|
-
) {
|
|
285
|
-
// Generate request ID for logging
|
|
286
|
-
// Store request info for logging
|
|
287
|
-
let requestInfo = null;
|
|
288
|
-
if (globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
289
|
-
requestInfo = {
|
|
290
|
-
interface: driverInterface,
|
|
291
|
-
driver: driverName,
|
|
292
|
-
method: driverMethod,
|
|
293
|
-
args: driverArgs
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// If there is no authToken and the environment is web, try authenticating with Puter
|
|
298
|
-
if(!puter.authToken && puter.env === 'web'){
|
|
299
|
-
try{
|
|
300
|
-
await puter.ui.authenticateWithPuter();
|
|
301
|
-
}catch(e){
|
|
302
|
-
// Log authentication error
|
|
303
|
-
if (requestInfo && globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
304
|
-
globalThis.puter.apiCallLogger.logRequest({
|
|
305
|
-
service: 'drivers',
|
|
306
|
-
operation: `${driverInterface}::${driverMethod}`,
|
|
307
|
-
params: { interface: driverInterface, driver: driverName, method: driverMethod, args: driverArgs },
|
|
308
|
-
error: { code: 'auth_canceled', message: 'Authentication canceled' }
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
return reject_func({
|
|
312
|
-
error: {
|
|
313
|
-
code: 'auth_canceled', message: 'Authentication canceled'
|
|
314
|
-
}
|
|
315
|
-
})
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const success_cb = Valid.callback(options.success) ?? NOOP;
|
|
320
|
-
const error_cb = Valid.callback(options.error) ?? NOOP;
|
|
321
|
-
// create xhr object
|
|
322
|
-
const xhr = initXhr('/drivers/call', puter.APIOrigin, undefined, 'POST', contentType);
|
|
323
|
-
|
|
324
|
-
// Store request info for later logging
|
|
325
|
-
if (requestInfo) {
|
|
326
|
-
xhr._puterDriverRequestInfo = requestInfo;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if ( settings.responseType ) {
|
|
330
|
-
xhr.responseType = settings.responseType;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// ===============================================
|
|
334
|
-
// TO UNDERSTAND THIS CODE, YOU MUST FIRST
|
|
335
|
-
// UNDERSTAND THE FOLLOWING TEXT:
|
|
336
|
-
//
|
|
337
|
-
// Everything between here and the comment reading
|
|
338
|
-
// "=== END OF STREAMING ===" is ONLY for handling
|
|
339
|
-
// requests with content type "application/x-ndjson"
|
|
340
|
-
// ===============================================
|
|
341
|
-
|
|
342
|
-
let is_stream = false;
|
|
343
|
-
let signal_stream_update = null;
|
|
344
|
-
let lastLength = 0;
|
|
345
|
-
let response_complete = false;
|
|
346
|
-
|
|
347
|
-
let buffer = '';
|
|
348
|
-
|
|
349
|
-
// NOTE: linked-list technically would perform better,
|
|
350
|
-
// but in practice there are at most 2-3 lines
|
|
351
|
-
// buffered so this does not matter.
|
|
352
|
-
const lines_received = [];
|
|
353
|
-
|
|
354
|
-
xhr.onreadystatechange = () => {
|
|
355
|
-
if ( xhr.readyState === 2 ) {
|
|
356
|
-
if ( xhr.getResponseHeader("Content-Type") !==
|
|
357
|
-
'application/x-ndjson'
|
|
358
|
-
) return;
|
|
359
|
-
is_stream = true;
|
|
360
|
-
const Stream = async function* Stream () {
|
|
361
|
-
while ( ! response_complete ) {
|
|
362
|
-
const tp = new TeePromise();
|
|
363
|
-
signal_stream_update = tp.resolve.bind(tp);
|
|
364
|
-
await tp;
|
|
365
|
-
if ( response_complete ) break;
|
|
366
|
-
while ( lines_received.length > 0 ) {
|
|
367
|
-
const line = lines_received.shift();
|
|
368
|
-
if ( line.trim() === '' ) continue;
|
|
369
|
-
const lineObject = (JSON.parse(line));
|
|
370
|
-
if (typeof (lineObject.text) === 'string') {
|
|
371
|
-
Object.defineProperty(lineObject, 'toString', {
|
|
372
|
-
enumerable: false,
|
|
373
|
-
value: () => lineObject.text,
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
yield lineObject;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const startedStream = Stream();
|
|
382
|
-
Object.defineProperty(startedStream, 'start', {
|
|
383
|
-
enumerable: false,
|
|
384
|
-
value: async(controller) => {
|
|
385
|
-
const texten = new TextEncoder();
|
|
386
|
-
for await (const part of startedStream) {
|
|
387
|
-
controller.enqueue(texten.encode(part))
|
|
388
|
-
}
|
|
389
|
-
controller.close();
|
|
390
|
-
}
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
return resolve_func(startedStream);
|
|
394
|
-
}
|
|
395
|
-
if ( xhr.readyState === 4 ) {
|
|
396
|
-
response_complete = true;
|
|
397
|
-
if ( is_stream ) {
|
|
398
|
-
signal_stream_update?.();
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
xhr.onprogress = function() {
|
|
404
|
-
if ( ! signal_stream_update ) return;
|
|
405
|
-
|
|
406
|
-
const newText = xhr.responseText.slice(lastLength);
|
|
407
|
-
lastLength = xhr.responseText.length; // Update lastLength to the current length
|
|
408
|
-
|
|
409
|
-
let hasUpdates = false;
|
|
410
|
-
for ( let i = 0; i < newText.length; i++ ) {
|
|
411
|
-
buffer += newText[i];
|
|
412
|
-
if ( newText[i] === '\n' ) {
|
|
413
|
-
hasUpdates = true;
|
|
414
|
-
lines_received.push(buffer);
|
|
415
|
-
buffer = '';
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if ( hasUpdates ) {
|
|
420
|
-
signal_stream_update();
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
// ========================
|
|
425
|
-
// === END OF STREAMING ===
|
|
426
|
-
// ========================
|
|
427
|
-
|
|
428
|
-
// load: success or error
|
|
429
|
-
xhr.addEventListener('load', async function(response){
|
|
430
|
-
if ( is_stream ) {
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
const resp = await parseResponse(response.target);
|
|
434
|
-
|
|
435
|
-
// Log driver call response
|
|
436
|
-
if (this._puterDriverRequestInfo && globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
437
|
-
globalThis.puter.apiCallLogger.logRequest({
|
|
438
|
-
service: 'drivers',
|
|
439
|
-
operation: `${this._puterDriverRequestInfo.interface}::${this._puterDriverRequestInfo.method}`,
|
|
440
|
-
params: { interface: this._puterDriverRequestInfo.interface, driver: this._puterDriverRequestInfo.driver, method: this._puterDriverRequestInfo.method, args: this._puterDriverRequestInfo.args },
|
|
441
|
-
result: response.status >= 400 || resp?.success === false ? null : resp,
|
|
442
|
-
error: response.status >= 400 || resp?.success === false ? resp : null
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// HTTP Error - unauthorized
|
|
447
|
-
if(response.status === 401 || resp?.code === "token_auth_failed"){
|
|
448
|
-
if(resp?.code === "token_auth_failed" && puter.env === 'web'){
|
|
449
|
-
try{
|
|
450
|
-
puter.resetAuthToken();
|
|
451
|
-
await puter.ui.authenticateWithPuter();
|
|
452
|
-
}catch(e){
|
|
453
|
-
return reject_func({
|
|
454
|
-
error: {
|
|
455
|
-
code: 'auth_canceled', message: 'Authentication canceled'
|
|
456
|
-
}
|
|
457
|
-
})
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
// if error callback is provided, call it
|
|
461
|
-
if(error_cb && typeof error_cb === 'function')
|
|
462
|
-
error_cb({status: 401, message: 'Unauthorized'})
|
|
463
|
-
// reject promise
|
|
464
|
-
return reject_func({status: 401, message: 'Unauthorized'})
|
|
465
|
-
}
|
|
466
|
-
// HTTP Error - other
|
|
467
|
-
else if(response.status && response.status !== 200){
|
|
468
|
-
// if error callback is provided, call it
|
|
469
|
-
error_cb(resp)
|
|
470
|
-
// reject promise
|
|
471
|
-
return reject_func(resp)
|
|
472
|
-
}
|
|
473
|
-
// HTTP Success
|
|
474
|
-
else{
|
|
475
|
-
// Driver Error: permission denied
|
|
476
|
-
if(resp.success === false && resp.error?.code === 'permission_denied'){
|
|
477
|
-
let perm = await puter.ui.requestPermission({permission: 'driver:' + driverInterface + ':' + driverMethod});
|
|
478
|
-
// try sending again if permission was granted
|
|
479
|
-
if(perm.granted){
|
|
480
|
-
// repeat request with permission granted
|
|
481
|
-
return driverCall_(options, resolve_func, reject_func, driverInterface, driverMethod, driverArgs, method, contentType, settings);
|
|
482
|
-
}else{
|
|
483
|
-
// if error callback is provided, call it
|
|
484
|
-
error_cb(resp)
|
|
485
|
-
// reject promise
|
|
486
|
-
return reject_func(resp)
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
// Driver Error: other
|
|
490
|
-
else if(resp.success === false){
|
|
491
|
-
// if error callback is provided, call it
|
|
492
|
-
error_cb(resp)
|
|
493
|
-
// reject promise
|
|
494
|
-
return reject_func(resp)
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
let result = resp.result !== undefined ? resp.result : resp;
|
|
498
|
-
if ( settings.transform ) {
|
|
499
|
-
result = await settings.transform(result);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Success: if callback is provided, call it
|
|
503
|
-
if(resolve_func.success)
|
|
504
|
-
success_cb(result);
|
|
505
|
-
// Success: resolve with the result
|
|
506
|
-
return resolve_func(result);
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
// error
|
|
511
|
-
xhr.addEventListener('error', function(e){
|
|
512
|
-
// Log driver call error
|
|
513
|
-
if (this._puterDriverRequestInfo && globalThis.puter?.apiCallLogger?.isEnabled()) {
|
|
514
|
-
globalThis.puter.apiCallLogger.logRequest({
|
|
515
|
-
service: 'drivers',
|
|
516
|
-
operation: `${this._puterDriverRequestInfo.interface}::${this._puterDriverRequestInfo.method}`,
|
|
517
|
-
params: { interface: this._puterDriverRequestInfo.interface, driver: this._puterDriverRequestInfo.driver, method: this._puterDriverRequestInfo.method, args: this._puterDriverRequestInfo.args },
|
|
518
|
-
error: { message: 'Network error occurred', event: e.type }
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
return handle_error(error_cb, reject_func, this);
|
|
522
|
-
})
|
|
523
|
-
|
|
524
|
-
// send request
|
|
525
|
-
xhr.send(JSON.stringify({
|
|
526
|
-
interface: driverInterface,
|
|
527
|
-
driver: driverName,
|
|
528
|
-
test_mode: settings?.test_mode,
|
|
529
|
-
method: driverMethod,
|
|
530
|
-
args: driverArgs,
|
|
531
|
-
auth_token: puter.authToken
|
|
532
|
-
}));
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
class TeePromise {
|
|
536
|
-
static STATUS_PENDING = {};
|
|
537
|
-
static STATUS_RUNNING = {};
|
|
538
|
-
static STATUS_DONE = {};
|
|
539
|
-
constructor () {
|
|
540
|
-
this.status_ = this.constructor.STATUS_PENDING;
|
|
541
|
-
this.donePromise = new Promise((resolve, reject) => {
|
|
542
|
-
this.doneResolve = resolve;
|
|
543
|
-
this.doneReject = reject;
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
get status () {
|
|
547
|
-
return this.status_;
|
|
548
|
-
}
|
|
549
|
-
set status (status) {
|
|
550
|
-
this.status_ = status;
|
|
551
|
-
if ( status === this.constructor.STATUS_DONE ) {
|
|
552
|
-
this.doneResolve();
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
resolve (value) {
|
|
556
|
-
this.status_ = this.constructor.STATUS_DONE;
|
|
557
|
-
this.doneResolve(value);
|
|
558
|
-
}
|
|
559
|
-
awaitDone () {
|
|
560
|
-
return this.donePromise;
|
|
561
|
-
}
|
|
562
|
-
then (fn, rfn) {
|
|
563
|
-
return this.donePromise.then(fn, rfn);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
reject (err) {
|
|
567
|
-
this.status_ = this.constructor.STATUS_DONE;
|
|
568
|
-
this.doneReject(err);
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* @deprecated use then() instead
|
|
573
|
-
*/
|
|
574
|
-
onComplete(fn) {
|
|
575
|
-
return this.then(fn);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
async function blob_to_url (blob) {
|
|
580
|
-
const tp = new TeePromise();
|
|
581
|
-
const reader = new FileReader();
|
|
582
|
-
reader.onloadend = () => tp.resolve(reader.result);
|
|
583
|
-
reader.readAsDataURL(blob);
|
|
584
|
-
return await tp;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function blobToDataUri(blob) {
|
|
588
|
-
return new Promise((resolve, reject) => {
|
|
589
|
-
const reader = new FileReader();
|
|
590
|
-
reader.onload = function(event) {
|
|
591
|
-
resolve(event.target.result);
|
|
592
|
-
};
|
|
593
|
-
reader.onerror = function(error) {
|
|
594
|
-
reject(error);
|
|
595
|
-
};
|
|
596
|
-
reader.readAsDataURL(blob);
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
function arrayBufferToDataUri(arrayBuffer) {
|
|
601
|
-
return new Promise((resolve, reject) => {
|
|
602
|
-
const blob = new Blob([arrayBuffer]);
|
|
603
|
-
const reader = new FileReader();
|
|
604
|
-
reader.onload = function(event) {
|
|
605
|
-
resolve(event.target.result);
|
|
606
|
-
};
|
|
607
|
-
reader.onerror = function(error) {
|
|
608
|
-
reject(error);
|
|
609
|
-
};
|
|
610
|
-
reader.readAsDataURL(blob);
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
export {parseResponse, uuidv4, handle_resp, handle_error, initXhr, setupXhrEventHandlers, driverCall,
|
|
615
|
-
TeePromise,
|
|
616
|
-
make_driver_method,
|
|
617
|
-
blob_to_url,
|
|
618
|
-
arrayBufferToDataUri,
|
|
619
|
-
blobToDataUri,
|
|
620
|
-
};
|