@heyputer/puter.js 2.0.12 → 2.0.14

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/src/modules/KV.js CHANGED
@@ -19,7 +19,7 @@ const gui_cache_keys = [
19
19
  ];
20
20
  class KV{
21
21
  MAX_KEY_SIZE = 1024;
22
- MAX_VALUE_SIZE = 400 * 1024;
22
+ MAX_VALUE_SIZE = 399 * 1024;
23
23
 
24
24
  /**
25
25
  * Creates a new instance with the given authentication token, API origin, and app ID,
@@ -50,7 +50,7 @@ class KV{
50
50
  args: {
51
51
  key: gui_cache_keys,
52
52
  },
53
- auth_token: this.authToken
53
+ auth_token: this.authToken,
54
54
  }),
55
55
  });
56
56
  const arr_values = await resp.json();
@@ -95,28 +95,37 @@ class KV{
95
95
  }
96
96
 
97
97
  /**
98
- * Resolves to 'true' on success, or rejects with an error on failure
99
- *
100
- * `key` cannot be undefined or null.
101
- * `key` size cannot be larger than 1mb.
102
- * `value` size cannot be larger than 10mb.
103
- * `expireAt` is a timestamp in sec since epoch. If provided, the key will expire at the given time.
98
+ * @typedef {function(key: string, value: any, expireAt?: number): Promise<boolean>} SetFunction
99
+ * Resolves to 'true' on success, or rejects with an error on failure.
100
+ * @param {string} key - Cannot be undefined or null. Cannot be larger than 1KB.
101
+ * @param {any} value - Cannot be larger than 399KB.
102
+ * @param {number} [expireAt] - Optional expiration time for the key. Note that clients with a clock that is not in sync with the server may experience issues with this method.
103
+ * @memberof KV
104
104
  */
105
+
106
+ /** @type {SetFunction} */
105
107
  set = utils.make_driver_method(['key', 'value', 'expireAt'], 'puter-kvstore', undefined, 'set', {
108
+ /**
109
+ *
110
+ * @param {object} args
111
+ * @param {string} args.key
112
+ * @param {any} args.value
113
+ * @param {number} [args.expireAt]
114
+ * @memberof [KV]
115
+ * @returns
116
+ */
106
117
  preprocess: (args) => {
107
- console.log(args);
108
-
109
118
  // key cannot be undefined or null
110
119
  if ( args.key === undefined || args.key === null ){
111
120
  throw { message: 'Key cannot be undefined', code: 'key_undefined' };
112
121
  }
113
122
  // key size cannot be larger than MAX_KEY_SIZE
114
123
  if ( args.key.length > this.MAX_KEY_SIZE ){
115
- throw { message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' };
124
+ throw { message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' };
116
125
  }
117
126
  // value size cannot be larger than MAX_VALUE_SIZE
118
127
  if ( args.value && args.value.length > this.MAX_VALUE_SIZE ){
119
- throw { message: 'Value size cannot be larger than ' + this.MAX_VALUE_SIZE, code: 'value_too_large' };
128
+ throw { message: `Value size cannot be larger than ${this.MAX_VALUE_SIZE}`, code: 'value_too_large' };
120
129
  }
121
130
  return args;
122
131
  },
@@ -145,7 +154,7 @@ class KV{
145
154
  preprocess: (args) => {
146
155
  // key size cannot be larger than MAX_KEY_SIZE
147
156
  if ( args.key.length > this.MAX_KEY_SIZE ){
148
- throw ({ message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' });
157
+ throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
149
158
  }
150
159
 
151
160
  return args;
@@ -164,11 +173,11 @@ class KV{
164
173
  }
165
174
 
166
175
  options.key = args[0];
167
- options.amount = args[1] ?? 1;
176
+ options.pathAndAmountMap = !args[1] ? { '': 1 } : typeof args[1] === 'number' ? { '': args[1] } : args[1];
168
177
 
169
178
  // key size cannot be larger than MAX_KEY_SIZE
170
179
  if ( options.key.length > this.MAX_KEY_SIZE ){
171
- throw ({ message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' });
180
+ throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
172
181
  }
173
182
 
174
183
  return utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'incr').call(this, options);
@@ -183,37 +192,53 @@ class KV{
183
192
  }
184
193
 
185
194
  options.key = args[0];
186
- options.amount = args[1] ?? 1;
195
+ options.pathAndAmountMap = !args[1] ? { '': 1 } : typeof args[1] === 'number' ? { '': args[1] } : args[1];
187
196
 
188
197
  // key size cannot be larger than MAX_KEY_SIZE
189
198
  if ( options.key.length > this.MAX_KEY_SIZE ){
190
- throw ({ message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' });
199
+ throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
191
200
  }
192
201
 
193
202
  return utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'decr').call(this, options);
194
203
  };
195
204
 
196
- expire = async (...args) => {
205
+ /**
206
+ * Set a time to live (in seconds) on a key. After the time to live has expired, the key will be deleted.
207
+ * Prefer this over expireAt if you want timestamp to be set by the server, to avoid issues with clock drift.
208
+ * @param {string} key - The key to set the expiration on.
209
+ * @param {number} ttl - The ttl
210
+ * @memberof [KV]
211
+ * @returns
212
+ */
213
+ expire = async (key, ttl) => {
197
214
  let options = {};
198
- options.key = args[0];
199
- options.ttl = args[1];
215
+ options.key = key;
216
+ options.ttl = ttl;
200
217
 
201
218
  // key size cannot be larger than MAX_KEY_SIZE
202
219
  if ( options.key.length > this.MAX_KEY_SIZE ){
203
- throw ({ message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' });
220
+ throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
204
221
  }
205
222
 
206
223
  return utils.make_driver_method(['key', 'ttl'], 'puter-kvstore', undefined, 'expire').call(this, options);
207
224
  };
208
225
 
209
- expireAt = async (...args) => {
226
+ /**
227
+ *
228
+ * Set the expiration for a key as a UNIX timestamp (in seconds). After the time has passed, the key will be deleted.
229
+ * Note that clients with a clock that is not in sync with the server may experience issues with this method.
230
+ * @param {string} key - The key to set the expiration on.
231
+ * @param {number} timestamp - The timestamp (in seconds since epoch) when the key will expire.
232
+ * @memberof [KV]
233
+ * @returns
234
+ */
235
+ expireAt = async (key, timestamp) => {
210
236
  let options = {};
211
- options.key = args[0];
212
- options.timestamp = args[1];
213
-
237
+ options.key = key;
238
+ options.timestamp = timestamp;
214
239
  // key size cannot be larger than MAX_KEY_SIZE
215
240
  if ( options.key.length > this.MAX_KEY_SIZE ){
216
- throw ({ message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' });
241
+ throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
217
242
  }
218
243
 
219
244
  return utils.make_driver_method(['key', 'timestamp'], 'puter-kvstore', undefined, 'expireAt').call(this, options);
@@ -225,7 +250,7 @@ class KV{
225
250
  preprocess: (args) => {
226
251
  // key size cannot be larger than this.MAX_KEY_SIZE
227
252
  if ( args.key.length > this.MAX_KEY_SIZE ){
228
- throw ({ message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large' });
253
+ throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
229
254
  }
230
255
 
231
256
  return args;
@@ -294,7 +319,7 @@ function globMatch(pattern, str) {
294
319
  .replace(/\\\]/g, ']') // Replace ] with ]
295
320
  .replace(/\\\^/g, '^'); // Replace ^ with ^
296
321
 
297
- let re = new RegExp('^' + regexPattern + '$');
322
+ let re = new RegExp(`^${regexPattern}$`);
298
323
  return re.test(str);
299
324
  }
300
325
 
package/src/modules/UI.js CHANGED
@@ -275,6 +275,7 @@ class UI extends EventListener {
275
275
  // Bind the message event listener to the window
276
276
  let lastDraggedOverElement = null;
277
277
  (globalThis.document) && window.addEventListener('message', async (e) => {
278
+ if (!e.data) return;
278
279
  // `error`
279
280
  if(e.data.error){
280
281
  throw e.data.error;
@@ -395,6 +396,12 @@ class UI extends EventListener {
395
396
  this.#callbackFunctions[e.data.original_msg_id](appDataItem);
396
397
  }
397
398
  }
399
+ // instancesOpenSucceeded
400
+ else if(e.data.msg === 'instancesOpenSucceeded'){
401
+ if(e.data.original_msg_id && this.#callbackFunctions[e.data.original_msg_id]){
402
+ this.#callbackFunctions[e.data.original_msg_id](e.data.instancesOpen);
403
+ }
404
+ }
398
405
  // readAppDataFileSucceeded
399
406
  else if(e.data.msg === 'readAppDataFileSucceeded'){
400
407
  let appDataItem = new FSItem(e.data.item);
@@ -657,6 +664,12 @@ class UI extends EventListener {
657
664
  })
658
665
  }
659
666
 
667
+ instancesOpen = function(callback) {
668
+ return new Promise((resolve) => {
669
+ this.#postMessageWithCallback('getInstancesOpen', resolve, { });
670
+ })
671
+ }
672
+
660
673
  socialShare = function(url, message, options, callback) {
661
674
  return new Promise((resolve) => {
662
675
  this.#postMessageWithCallback('socialShare', resolve, { url, message, options });
@@ -917,6 +930,18 @@ class UI extends EventListener {
917
930
  })
918
931
  }
919
932
 
933
+ showWindow = function() {
934
+ this.#postMessageWithObject('showWindow');
935
+ }
936
+
937
+ hideWindow = function() {
938
+ this.#postMessageWithObject('hideWindow');
939
+ }
940
+
941
+ toggleWindow = function() {
942
+ this.#postMessageWithObject('toggleWindow');
943
+ }
944
+
920
945
  setMenubar = function(spec) {
921
946
  this.#postMessageWithObject('setMenubar', spec);
922
947
  }
@@ -1541,9 +1566,12 @@ class UI extends EventListener {
1541
1566
  * console.log(`Current language: ${currentLang}`); // e.g., "Current language: fr"
1542
1567
  */
1543
1568
  getLanguage() {
1544
- // In GUI environment, access the global locale directly
1569
+ // resolve with the current language code if in GUI environment
1545
1570
  if(this.env === 'gui'){
1546
- return window.locale;
1571
+ // resolve with the current language code
1572
+ return new Promise((resolve) => {
1573
+ resolve(window.locale);
1574
+ });
1547
1575
  }
1548
1576
 
1549
1577
  return new Promise((resolve) => {
@@ -11,6 +11,10 @@ export class PTLSSocket extends PSocket {
11
11
  super(...args);
12
12
  super.on("open", (async() => {
13
13
  if (!rustls) {
14
+ // Safari exists unfortunately without good ReadableStream support. Until that is fixed we need this.
15
+ if (!globalThis.ReadableByteStreamController) {
16
+ await import( /* webpackIgnore: true */ "https://unpkg.com/web-streams-polyfill@3.0.2/dist/polyfill.js");
17
+ }
14
18
  rustls = (await import( /* webpackIgnore: true */ "https://puter-net.b-cdn.net/rustls.js"))
15
19
  await rustls.default("https://puter-net.b-cdn.net/rustls.wasm")
16
20
  }
@@ -20,7 +20,7 @@ export class XDIncomingService extends putility.concepts.Service {
20
20
  }
21
21
 
22
22
  const data = event.data;
23
-
23
+ if ( ! data ) return;
24
24
  const tag = data.$;
25
25
  if ( ! tag ) return;
26
26
  if ( ! this.tagged_listeners_[tag] ) return;