@heyputer/puter.js 2.1.4 → 2.1.7

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.
Files changed (57) hide show
  1. package/dist/puter.cjs +2 -2
  2. package/index.d.ts +41 -15
  3. package/package.json +1 -1
  4. package/src/index.js +116 -79
  5. package/src/lib/APICallLogger.js +20 -21
  6. package/src/lib/EventListener.js +10 -10
  7. package/src/lib/filesystem/APIFS.js +11 -19
  8. package/src/lib/filesystem/CacheFS.js +25 -25
  9. package/src/lib/filesystem/PostMessageFS.js +11 -11
  10. package/src/lib/filesystem/definitions.js +11 -10
  11. package/src/lib/path.js +505 -446
  12. package/src/lib/polyfills/fileReaderPoly.js +40 -0
  13. package/src/lib/polyfills/localStorage.js +30 -33
  14. package/src/lib/polyfills/xhrshim.js +206 -207
  15. package/src/lib/utils.js +160 -151
  16. package/src/lib/xdrpc.js +9 -9
  17. package/src/modules/AI.js +473 -292
  18. package/src/modules/Apps.js +56 -56
  19. package/src/modules/Auth.js +17 -17
  20. package/src/modules/Debug.js +1 -1
  21. package/src/modules/Drivers.js +41 -41
  22. package/src/modules/FSItem.js +64 -62
  23. package/src/modules/FileSystem/index.js +22 -23
  24. package/src/modules/FileSystem/operations/copy.js +7 -7
  25. package/src/modules/FileSystem/operations/deleteFSEntry.js +14 -12
  26. package/src/modules/FileSystem/operations/getReadUrl.js +16 -14
  27. package/src/modules/FileSystem/operations/mkdir.js +11 -11
  28. package/src/modules/FileSystem/operations/move.js +12 -12
  29. package/src/modules/FileSystem/operations/read.js +10 -10
  30. package/src/modules/FileSystem/operations/readdir.js +28 -28
  31. package/src/modules/FileSystem/operations/rename.js +11 -11
  32. package/src/modules/FileSystem/operations/sign.js +33 -30
  33. package/src/modules/FileSystem/operations/space.js +7 -7
  34. package/src/modules/FileSystem/operations/stat.js +25 -25
  35. package/src/modules/FileSystem/operations/symlink.js +15 -17
  36. package/src/modules/FileSystem/operations/upload.js +151 -122
  37. package/src/modules/FileSystem/operations/write.js +16 -12
  38. package/src/modules/FileSystem/utils/getAbsolutePathForApp.js +10 -6
  39. package/src/modules/Hosting.js +29 -29
  40. package/src/modules/KV.js +23 -23
  41. package/src/modules/OS.js +15 -15
  42. package/src/modules/Perms.js +19 -21
  43. package/src/modules/PuterDialog.js +46 -48
  44. package/src/modules/Threads.js +17 -20
  45. package/src/modules/UI.js +156 -156
  46. package/src/modules/Util.js +3 -3
  47. package/src/modules/Workers.js +52 -49
  48. package/src/modules/networking/PSocket.js +38 -38
  49. package/src/modules/networking/PTLS.js +54 -47
  50. package/src/modules/networking/PWispHandler.js +49 -47
  51. package/src/modules/networking/parsers.js +110 -108
  52. package/src/modules/networking/requests.js +67 -78
  53. package/src/services/APIAccess.js +9 -9
  54. package/src/services/FSRelay.js +6 -6
  55. package/src/services/Filesystem.js +8 -8
  56. package/src/services/NoPuterYet.js +2 -2
  57. package/src/services/XDIncoming.js +1 -1
@@ -13,7 +13,7 @@ const readdir = async function (...args) {
13
13
  let options;
14
14
 
15
15
  // If first argument is an object, it's the options
16
- if (typeof args[0] === 'object' && args[0] !== null) {
16
+ if ( typeof args[0] === 'object' && args[0] !== null ) {
17
17
  options = args[0];
18
18
  } else {
19
19
  // Otherwise, we assume separate arguments are provided
@@ -26,25 +26,25 @@ const readdir = async function (...args) {
26
26
 
27
27
  return new Promise(async (resolve, reject) => {
28
28
  // consistency levels
29
- if(!options.consistency){
29
+ if ( ! options.consistency ) {
30
30
  options.consistency = 'strong';
31
31
  }
32
32
 
33
33
  // Either path or uid is required
34
- if(!options.path && !options.uid){
34
+ if ( !options.path && !options.uid ) {
35
35
  throw new Error({ code: 'NO_PATH_OR_UID', message: 'Either path or uid must be provided.' });
36
36
  }
37
37
 
38
38
  // Generate cache key based on path or uid
39
39
  let cacheKey;
40
- if(options.path){
41
- cacheKey = 'readdir:' + options.path;
40
+ if ( options.path ) {
41
+ cacheKey = `readdir:${ options.path}`;
42
42
  }
43
43
 
44
- if(options.consistency === 'eventual'){
44
+ if ( options.consistency === 'eventual' ) {
45
45
  // Check cache
46
46
  const cachedResult = await puter._cache.get(cacheKey);
47
- if(cachedResult){
47
+ if ( cachedResult ) {
48
48
  resolve(cachedResult);
49
49
  return;
50
50
  }
@@ -62,17 +62,17 @@ const readdir = async function (...args) {
62
62
  // Check if there's already an in-flight request for the same parameters
63
63
  const existingEntry = inflightRequests.get(deduplicationKey);
64
64
  const now = Date.now();
65
-
66
- if (existingEntry) {
65
+
66
+ if ( existingEntry ) {
67
67
  const timeSinceRequest = now - existingEntry.timestamp;
68
-
68
+
69
69
  // Only reuse the request if it's within the deduplication window
70
- if (timeSinceRequest < DEDUPLICATION_WINDOW_MS) {
70
+ if ( timeSinceRequest < DEDUPLICATION_WINDOW_MS ) {
71
71
  // Wait for the existing request and return its result
72
72
  try {
73
73
  const result = await existingEntry.promise;
74
74
  resolve(result);
75
- } catch (error) {
75
+ } catch ( error ) {
76
76
  reject(error);
77
77
  }
78
78
  return;
@@ -84,12 +84,12 @@ const readdir = async function (...args) {
84
84
 
85
85
  // Create a promise for this request and store it to deduplicate concurrent calls
86
86
  const requestPromise = new Promise(async (resolveRequest, rejectRequest) => {
87
- // If auth token is not provided and we are in the web environment,
87
+ // If auth token is not provided and we are in the web environment,
88
88
  // try to authenticate with Puter
89
- if(!puter.authToken && puter.env === 'web'){
90
- try{
89
+ if ( !puter.authToken && puter.env === 'web' ) {
90
+ try {
91
91
  await puter.ui.authenticateWithPuter();
92
- }catch(e){
92
+ } catch (e) {
93
93
  // if authentication fails, throw an error
94
94
  rejectRequest('Authentication failed.');
95
95
  return;
@@ -97,26 +97,26 @@ const readdir = async function (...args) {
97
97
  }
98
98
 
99
99
  // create xhr object
100
- const xhr = utils.initXhr('/readdir', this.APIOrigin, undefined, "post", "text/plain;actually=json");
100
+ const xhr = utils.initXhr('/readdir', this.APIOrigin, undefined, 'post', 'text/plain;actually=json');
101
101
 
102
102
  // set up event handlers for load and error events
103
103
  utils.setupXhrEventHandlers(xhr, options.success, options.error, async (result) => {
104
104
  // Calculate the size of the result for cache eligibility check
105
105
  const resultSize = JSON.stringify(result).length;
106
-
106
+
107
107
  // Cache the result if it's not bigger than MAX_CACHE_SIZE
108
108
  const MAX_CACHE_SIZE = 100 * 1024 * 1024;
109
109
 
110
- if(resultSize <= MAX_CACHE_SIZE){
110
+ if ( resultSize <= MAX_CACHE_SIZE ) {
111
111
  // UPSERT the cache
112
112
  puter._cache.set(cacheKey, result);
113
113
  }
114
114
 
115
115
  // set each individual item's cache
116
- for(const item of result){
117
- puter._cache.set('item:' + item.path, item);
116
+ for ( const item of result ) {
117
+ puter._cache.set(`item:${ item.path}`, item);
118
118
  }
119
-
119
+
120
120
  resolveRequest(result);
121
121
  }, rejectRequest);
122
122
 
@@ -124,13 +124,13 @@ const readdir = async function (...args) {
124
124
  const payload = {
125
125
  no_thumbs: options.no_thumbs,
126
126
  no_assocs: options.no_assocs,
127
- auth_token: this.authToken
127
+ auth_token: this.authToken,
128
128
  };
129
129
 
130
130
  // Add either uid or path to the payload
131
- if (options.uid) {
131
+ if ( options.uid ) {
132
132
  payload.uid = options.uid;
133
- } else if (options.path) {
133
+ } else if ( options.path ) {
134
134
  payload.path = getAbsolutePathForApp(options.path);
135
135
  }
136
136
 
@@ -148,11 +148,11 @@ const readdir = async function (...args) {
148
148
  const result = await requestPromise;
149
149
  inflightRequests.delete(deduplicationKey);
150
150
  resolve(result);
151
- } catch (error) {
151
+ } catch ( error ) {
152
152
  inflightRequests.delete(deduplicationKey);
153
153
  reject(error);
154
154
  }
155
- })
156
- }
155
+ });
156
+ };
157
157
 
158
158
  export default readdir;
@@ -5,7 +5,7 @@ const rename = function (...args) {
5
5
  let options;
6
6
 
7
7
  // If first argument is an object, it's the options
8
- if (typeof args[0] === 'object' && args[0] !== null) {
8
+ if ( typeof args[0] === 'object' && args[0] !== null ) {
9
9
  options = args[0];
10
10
  } else {
11
11
  // Otherwise, we assume separate arguments are provided
@@ -19,12 +19,12 @@ const rename = function (...args) {
19
19
  }
20
20
 
21
21
  return new Promise(async (resolve, reject) => {
22
- // If auth token is not provided and we are in the web environment,
22
+ // If auth token is not provided and we are in the web environment,
23
23
  // try to authenticate with Puter
24
- if(!puter.authToken && puter.env === 'web'){
25
- try{
24
+ if ( !puter.authToken && puter.env === 'web' ) {
25
+ try {
26
26
  await puter.ui.authenticateWithPuter();
27
- }catch(e){
27
+ } catch (e) {
28
28
  // if authentication fails, throw an error
29
29
  reject('Authentication failed.');
30
30
  }
@@ -40,18 +40,18 @@ const rename = function (...args) {
40
40
  original_client_socket_id: options.excludeSocketID || options.original_client_socket_id,
41
41
  new_name: options.new_name || options.newName,
42
42
  };
43
-
44
- if (options.uid !== undefined) {
43
+
44
+ if ( options.uid !== undefined ) {
45
45
  dataToSend.uid = options.uid;
46
- } else if (options.path !== undefined) {
46
+ } else if ( options.path !== undefined ) {
47
47
  // If dirPath is not provided or it's not starting with a slash, it means it's a relative path
48
48
  // in that case, we need to prepend the app's root directory to it
49
49
  dataToSend.path = getAbsolutePathForApp(options.path);
50
50
  }
51
-
51
+
52
52
  xhr.send(JSON.stringify(dataToSend));
53
53
 
54
- })
55
- }
54
+ });
55
+ };
56
56
 
57
57
  export default rename;
@@ -12,7 +12,7 @@ import * as utils from '../../../lib/utils.js';
12
12
  * @throws {Error} If the AJAX request fails.
13
13
  * @async
14
14
  */
15
- const sign = function(...args){
15
+ const sign = function (...args) {
16
16
  let options;
17
17
 
18
18
  // Otherwise, we assume separate arguments are provided
@@ -25,79 +25,82 @@ const sign = function(...args){
25
25
  };
26
26
 
27
27
  return new Promise(async (resolve, reject) => {
28
- // If auth token is not provided and we are in the web environment,
28
+ // If auth token is not provided and we are in the web environment,
29
29
  // try to authenticate with Puter
30
- if(!puter.authToken && puter.env === 'web'){
31
- try{
30
+ if ( !puter.authToken && puter.env === 'web' ) {
31
+ try {
32
32
  await puter.ui.authenticateWithPuter();
33
- }catch(e){
33
+ } catch (e) {
34
34
  // if authentication fails, throw an error
35
35
  reject('Authentication failed.');
36
36
  }
37
37
  }
38
38
 
39
-
40
39
  let items = options.items;
41
40
 
42
41
  // if only a single item is passed, convert it to array
43
42
  // so that the code below can work with arrays
44
- if(!Array.isArray(items)){
45
- items = [items]
43
+ if ( ! Array.isArray(items) ) {
44
+ items = [items];
46
45
  }
47
46
 
48
47
  // create xhr object
49
48
  const xhr = utils.initXhr('/sign', this.APIOrigin, this.authToken);
50
49
 
51
50
  // response
52
- xhr.addEventListener('load', async function(e){
51
+ xhr.addEventListener('load', async function (e) {
53
52
  const resp = await utils.parseResponse(this);
54
53
  // error
55
- if(this.status !== 200){
54
+ if ( this.status !== 200 ) {
56
55
  // if error callback is provided, call it
57
- if(options.error && typeof options.error === 'function')
58
- options.error(resp)
56
+ if ( options.error && typeof options.error === 'function' )
57
+ {
58
+ options.error(resp);
59
+ }
59
60
  // reject promise
60
- return reject(resp)
61
+ return reject(resp);
61
62
  }
62
63
  // success
63
- else{
64
+ else {
64
65
  let res = resp;
65
66
  let result;
66
67
  let token = res.token;
67
68
  // if only a single item was passed, return a single object
68
- if(items.length == 1){
69
- result = {...(res.signatures[0])};
69
+ if ( items.length == 1 ) {
70
+ result = { ...(res.signatures[0]) };
70
71
  }
71
72
  // if multiple items were passed, return an array of objects
72
- else{
73
- let obj=[];
74
- for(let i=0; i<res.signatures.length; i++){
75
- obj.push({...res.signatures[i]});
73
+ else {
74
+ let obj = [];
75
+ for ( let i = 0; i < res.signatures.length; i++ ) {
76
+ obj.push({ ...res.signatures[i] });
76
77
  }
77
78
  result = obj;
78
79
  }
79
80
 
80
81
  // if success callback is provided, call it
81
- if(options.success && typeof options.success === 'function')
82
- options.success({token: token, items: result});
82
+ if ( options.success && typeof options.success === 'function' )
83
+ {
84
+ options.success({ token: token, items: result });
85
+ }
83
86
  // resolve with success
84
- return resolve({token: token, items: result});
87
+ return resolve({ token: token, items: result });
85
88
  }
86
89
  });
87
90
 
88
- xhr.upload.addEventListener('progress', function(e){
89
- })
91
+ xhr.upload.addEventListener('progress', function (e) {
92
+ });
90
93
 
91
94
  // error
92
- xhr.addEventListener('error', function(e){
95
+ xhr.addEventListener('error', function (e) {
93
96
  return utils.handle_error(options.error, reject, this);
94
- })
97
+ });
95
98
 
96
99
  xhr.send(JSON.stringify({
97
100
  app_uid: options.app_uid,
98
- items: items
101
+ items: items,
99
102
  }));
100
- })
101
- }
103
+ });
104
+ };
102
105
 
103
106
  export default sign;
@@ -4,7 +4,7 @@ const space = function (...args) {
4
4
  let options;
5
5
 
6
6
  // If first argument is an object, it's the options
7
- if (typeof args[0] === 'object' && args[0] !== null) {
7
+ if ( typeof args[0] === 'object' && args[0] !== null ) {
8
8
  options = args[0];
9
9
  } else {
10
10
  // Otherwise, we assume separate arguments are provided
@@ -16,12 +16,12 @@ const space = function (...args) {
16
16
  }
17
17
 
18
18
  return new Promise(async (resolve, reject) => {
19
- // If auth token is not provided and we are in the web environment,
19
+ // If auth token is not provided and we are in the web environment,
20
20
  // try to authenticate with Puter
21
- if(!puter.authToken && puter.env === 'web'){
22
- try{
21
+ if ( !puter.authToken && puter.env === 'web' ) {
22
+ try {
23
23
  await puter.ui.authenticateWithPuter();
24
- }catch(e){
24
+ } catch (e) {
25
25
  // if authentication fails, throw an error
26
26
  reject('Authentication failed.');
27
27
  }
@@ -34,7 +34,7 @@ const space = function (...args) {
34
34
  utils.setupXhrEventHandlers(xhr, options.success, options.error, resolve, reject);
35
35
 
36
36
  xhr.send();
37
- })
38
- }
37
+ });
38
+ };
39
39
 
40
40
  export default space;
@@ -13,7 +13,7 @@ const stat = async function (...args) {
13
13
  let options;
14
14
 
15
15
  // If first argument is an object, it's the options
16
- if (typeof args[0] === 'object' && args[0] !== null) {
16
+ if ( typeof args[0] === 'object' && args[0] !== null ) {
17
17
  options = args[0];
18
18
  } else {
19
19
  // Otherwise, we assume separate arguments are provided
@@ -28,20 +28,20 @@ const stat = async function (...args) {
28
28
 
29
29
  return new Promise(async (resolve, reject) => {
30
30
  // consistency levels
31
- if(!options.consistency){
31
+ if ( ! options.consistency ) {
32
32
  options.consistency = 'strong';
33
33
  }
34
34
 
35
35
  // Generate cache key based on path or uid
36
36
  let cacheKey;
37
- if(options.path){
38
- cacheKey = 'item:' + options.path;
37
+ if ( options.path ) {
38
+ cacheKey = `item:${ options.path}`;
39
39
  }
40
40
 
41
- if(options.consistency === 'eventual' && !options.returnSubdomains && !options.returnPermissions && !options.returnVersions && !options.returnSize){
41
+ if ( options.consistency === 'eventual' && !options.returnSubdomains && !options.returnPermissions && !options.returnVersions && !options.returnSize ) {
42
42
  // Check cache
43
43
  const cachedResult = await puter._cache.get(cacheKey);
44
- if(cachedResult){
44
+ if ( cachedResult ) {
45
45
  resolve(cachedResult);
46
46
  return;
47
47
  }
@@ -61,17 +61,17 @@ const stat = async function (...args) {
61
61
  // Check if there's already an in-flight request for the same parameters
62
62
  const existingEntry = inflightRequests.get(deduplicationKey);
63
63
  const now = Date.now();
64
-
65
- if (existingEntry) {
64
+
65
+ if ( existingEntry ) {
66
66
  const timeSinceRequest = now - existingEntry.timestamp;
67
-
67
+
68
68
  // Only reuse the request if it's within the deduplication window
69
- if (timeSinceRequest < DEDUPLICATION_WINDOW_MS) {
69
+ if ( timeSinceRequest < DEDUPLICATION_WINDOW_MS ) {
70
70
  // Wait for the existing request and return its result
71
71
  try {
72
72
  const result = await existingEntry.promise;
73
73
  resolve(result);
74
- } catch (error) {
74
+ } catch ( error ) {
75
75
  reject(error);
76
76
  }
77
77
  return;
@@ -83,12 +83,12 @@ const stat = async function (...args) {
83
83
 
84
84
  // Create a promise for this request and store it to deduplicate concurrent calls
85
85
  const requestPromise = new Promise(async (resolveRequest, rejectRequest) => {
86
- // If auth token is not provided and we are in the web environment,
86
+ // If auth token is not provided and we are in the web environment,
87
87
  // try to authenticate with Puter
88
- if(!puter.authToken && puter.env === 'web'){
89
- try{
88
+ if ( !puter.authToken && puter.env === 'web' ) {
89
+ try {
90
90
  await puter.ui.authenticateWithPuter();
91
- }catch(e){
91
+ } catch (e) {
92
92
  // if authentication fails, throw an error
93
93
  rejectRequest('Authentication failed.');
94
94
  return;
@@ -96,33 +96,33 @@ const stat = async function (...args) {
96
96
  }
97
97
 
98
98
  // create xhr object
99
- const xhr = utils.initXhr('/stat', this.APIOrigin, undefined, "post", "text/plain;actually=json");
99
+ const xhr = utils.initXhr('/stat', this.APIOrigin, undefined, 'post', 'text/plain;actually=json');
100
100
 
101
101
  // set up event handlers for load and error events
102
102
  utils.setupXhrEventHandlers(xhr, options.success, options.error, async (result) => {
103
103
  // Calculate the size of the result for cache eligibility check
104
104
  const resultSize = JSON.stringify(result).length;
105
-
105
+
106
106
  // Cache the result if it's not bigger than MAX_CACHE_SIZE
107
107
  const MAX_CACHE_SIZE = 20 * 1024 * 1024;
108
108
 
109
- if(resultSize <= MAX_CACHE_SIZE){
109
+ if ( resultSize <= MAX_CACHE_SIZE ) {
110
110
  // UPSERT the cache
111
111
  puter._cache.set(cacheKey, result);
112
112
  }
113
-
113
+
114
114
  resolveRequest(result);
115
115
  }, rejectRequest);
116
116
 
117
117
  let dataToSend = {};
118
- if (options.uid !== undefined) {
118
+ if ( options.uid !== undefined ) {
119
119
  dataToSend.uid = options.uid;
120
- } else if (options.path !== undefined) {
120
+ } else if ( options.path !== undefined ) {
121
121
  // If dirPath is not provided or it's not starting with a slash, it means it's a relative path
122
122
  // in that case, we need to prepend the app's root directory to it
123
123
  dataToSend.path = getAbsolutePathForApp(options.path);
124
124
  }
125
-
125
+
126
126
  dataToSend.return_subdomains = options.returnSubdomains;
127
127
  dataToSend.return_permissions = options.returnPermissions;
128
128
  dataToSend.return_versions = options.returnVersions;
@@ -143,11 +143,11 @@ const stat = async function (...args) {
143
143
  const result = await requestPromise;
144
144
  inflightRequests.delete(deduplicationKey);
145
145
  resolve(result);
146
- } catch (error) {
146
+ } catch ( error ) {
147
147
  inflightRequests.delete(deduplicationKey);
148
148
  reject(error);
149
149
  }
150
- })
151
- }
150
+ });
151
+ };
152
152
 
153
153
  export default stat;
@@ -4,13 +4,12 @@ import pathLib from '../../../lib/path.js';
4
4
  // This only works for absolute symlinks for now
5
5
  const symlink = async function (target, linkPath) {
6
6
 
7
-
8
- // If auth token is not provided and we are in the web environment,
7
+ // If auth token is not provided and we are in the web environment,
9
8
  // try to authenticate with Puter
10
- if(!puter.authToken && puter.env === 'web'){
11
- try{
9
+ if ( !puter.authToken && puter.env === 'web' ) {
10
+ try {
12
11
  await puter.ui.authenticateWithPuter();
13
- }catch(e){
12
+ } catch (e) {
14
13
  // if authentication fails, throw an error
15
14
  throw 'Authentication failed.';
16
15
  }
@@ -20,36 +19,35 @@ const symlink = async function (target, linkPath) {
20
19
  linkPath = getAbsolutePathForApp(linkPath);
21
20
  target = getAbsolutePathForApp(target);
22
21
  const name = pathLib.basename(linkPath);
23
- const linkDir = pathLib.dirname(linkPath)
22
+ const linkDir = pathLib.dirname(linkPath);
24
23
 
25
24
  const op =
26
25
  {
27
- op: 'symlink',
28
- path: linkDir,
29
- name: name,
30
- target: target
26
+ op: 'symlink',
27
+ path: linkDir,
28
+ name: name,
29
+ target: target,
31
30
  };
32
31
 
33
32
  const formData = new FormData();
34
33
  formData.append('operation', JSON.stringify(op));
35
34
 
36
35
  try {
37
- const response = await fetch(this.APIOrigin + "/batch", {
36
+ const response = await fetch(`${this.APIOrigin }/batch`, {
38
37
  method: 'POST',
39
38
  headers: { 'Authorization': `Bearer ${puter.authToken}` },
40
- body: formData
39
+ body: formData,
41
40
  });
42
- if (response.status !== 200) {
41
+ if ( response.status !== 200 ) {
43
42
  const error = await response.text();
44
- console.error("[symlink] fetch error: ", error);
43
+ console.error('[symlink] fetch error: ', error);
45
44
  throw error;
46
45
  }
47
46
  } catch (e) {
48
- console.error("[symlink] fetch error: ", e);
47
+ console.error('[symlink] fetch error: ', e);
49
48
  throw e;
50
49
  }
51
-
52
50
 
53
- }
51
+ };
54
52
 
55
53
  export default symlink;