@heyputer/puter.js 2.0.2 → 2.0.3
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.js +4 -0
- package/package.json +6 -2
- package/src/index.js +165 -165
- package/src/safeLoadPuter.cjs +29 -0
- package/APACHE_LICENSE.txt +0 -201
- package/doc/devlog.md +0 -49
- package/index.d.ts +0 -479
- package/src/entry.js +0 -9
- 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/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import putility from '@heyputer/putility';
|
|
2
2
|
|
|
3
|
+
import kvjs from '@heyputer/kv.js';
|
|
3
4
|
import APICallLogger from './lib/APICallLogger.js';
|
|
4
5
|
import path from './lib/path.js';
|
|
5
|
-
import localStorageMemory from './lib/polyfills/localStorage.js'
|
|
6
|
-
import xhrshim from './lib/polyfills/xhrshim.js'
|
|
6
|
+
import localStorageMemory from './lib/polyfills/localStorage.js';
|
|
7
|
+
import xhrshim from './lib/polyfills/xhrshim.js';
|
|
7
8
|
import * as utils from './lib/utils.js';
|
|
8
9
|
import AI from './modules/AI.js';
|
|
9
10
|
import Apps from './modules/Apps.js';
|
|
@@ -15,7 +16,7 @@ import FSItem from './modules/FSItem.js';
|
|
|
15
16
|
import Hosting from './modules/Hosting.js';
|
|
16
17
|
import KV from './modules/KV.js';
|
|
17
18
|
import { PSocket } from './modules/networking/PSocket.js';
|
|
18
|
-
import { PTLSSocket } from
|
|
19
|
+
import { PTLSSocket } from './modules/networking/PTLS.js';
|
|
19
20
|
import { pFetch } from './modules/networking/requests.js';
|
|
20
21
|
import OS from './modules/OS.js';
|
|
21
22
|
import Perms from './modules/Perms.js';
|
|
@@ -28,14 +29,13 @@ import { FilesystemService } from './services/Filesystem.js';
|
|
|
28
29
|
import { FSRelayService } from './services/FSRelay.js';
|
|
29
30
|
import { NoPuterYetService } from './services/NoPuterYet.js';
|
|
30
31
|
import { XDIncomingService } from './services/XDIncoming.js';
|
|
31
|
-
import kvjs from '@heyputer/kv.js';
|
|
32
32
|
|
|
33
33
|
// TODO: This is for a safe-guard below; we should check if we can
|
|
34
34
|
// generalize this behavior rather than hard-coding it.
|
|
35
35
|
// (using defaultGUIOrigin breaks locally-hosted apps)
|
|
36
36
|
const PROD_ORIGIN = 'https://puter.com';
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
const puterInit = (function() {
|
|
39
39
|
'use strict';
|
|
40
40
|
|
|
41
41
|
class Puter{
|
|
@@ -58,7 +58,7 @@ export default globalThis.puter = (function() {
|
|
|
58
58
|
puterAuthState = {
|
|
59
59
|
isPromptOpen: false,
|
|
60
60
|
authGranted: null,
|
|
61
|
-
resolver: null
|
|
61
|
+
resolver: null,
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
// Holds the unique app instance ID that is provided by the host environment
|
|
@@ -78,12 +78,12 @@ export default globalThis.puter = (function() {
|
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Puter.js Modules
|
|
81
|
-
*
|
|
81
|
+
*
|
|
82
82
|
* These are the modules you see on docs.puter.com; for example:
|
|
83
83
|
* - puter.fs
|
|
84
84
|
* - puter.kv
|
|
85
85
|
* - puter.ui
|
|
86
|
-
*
|
|
86
|
+
*
|
|
87
87
|
* initSubmodules is called from the constructor of this class.
|
|
88
88
|
*/
|
|
89
89
|
initSubmodules = function(){
|
|
@@ -108,14 +108,13 @@ export default globalThis.puter = (function() {
|
|
|
108
108
|
|
|
109
109
|
// Path
|
|
110
110
|
this.path = path;
|
|
111
|
-
}
|
|
111
|
+
};
|
|
112
112
|
|
|
113
113
|
// --------------------------------------------
|
|
114
114
|
// Constructor
|
|
115
115
|
// --------------------------------------------
|
|
116
|
-
constructor(
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
constructor() {
|
|
117
|
+
|
|
119
118
|
// Initialize the cache using kv.js
|
|
120
119
|
this._cache = new kvjs();
|
|
121
120
|
|
|
@@ -131,57 +130,57 @@ export default globalThis.puter = (function() {
|
|
|
131
130
|
this.context = context;
|
|
132
131
|
context.services = this.services;
|
|
133
132
|
|
|
134
|
-
|
|
135
133
|
// Holds the query parameters found in the current URL
|
|
136
134
|
let URLParams = new URLSearchParams(globalThis.location?.search);
|
|
137
135
|
|
|
138
136
|
// Figure out the environment in which the SDK is running
|
|
139
|
-
if (URLParams.has('puter.app_instance_id')) {
|
|
137
|
+
if ( URLParams.has('puter.app_instance_id') ) {
|
|
140
138
|
this.env = 'app';
|
|
141
|
-
} else if(globalThis.puter_gui_enabled === true)
|
|
139
|
+
} else if ( globalThis.puter_gui_enabled === true )
|
|
140
|
+
{
|
|
142
141
|
this.env = 'gui';
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
}
|
|
143
|
+
else if ( globalThis.WorkerGlobalScope ) {
|
|
144
|
+
if ( globalThis.ServiceWorkerGlobalScope ) {
|
|
145
|
+
this.env = 'service-worker';
|
|
146
|
+
if ( !globalThis.XMLHttpRequest ) {
|
|
147
|
+
globalThis.XMLHttpRequest = xhrshim;
|
|
148
148
|
}
|
|
149
|
-
if (!globalThis.location) {
|
|
150
|
-
globalThis.location = new URL(
|
|
149
|
+
if ( !globalThis.location ) {
|
|
150
|
+
globalThis.location = new URL('https://puter.site/');
|
|
151
151
|
}
|
|
152
152
|
// XHRShimGlobalize here
|
|
153
153
|
} else {
|
|
154
|
-
this.env = 'web-worker'
|
|
154
|
+
this.env = 'web-worker';
|
|
155
155
|
}
|
|
156
|
-
if (!globalThis.localStorage) {
|
|
156
|
+
if ( !globalThis.localStorage ) {
|
|
157
157
|
globalThis.localStorage = localStorageMemory;
|
|
158
158
|
}
|
|
159
|
-
} else if (globalThis.process) {
|
|
159
|
+
} else if ( globalThis.process ) {
|
|
160
160
|
this.env = 'nodejs';
|
|
161
|
-
if (!globalThis.localStorage) {
|
|
161
|
+
if ( !globalThis.localStorage ) {
|
|
162
162
|
globalThis.localStorage = localStorageMemory;
|
|
163
163
|
}
|
|
164
|
-
if (!globalThis.XMLHttpRequest) {
|
|
165
|
-
globalThis.XMLHttpRequest = xhrshim
|
|
164
|
+
if ( !globalThis.XMLHttpRequest ) {
|
|
165
|
+
globalThis.XMLHttpRequest = xhrshim;
|
|
166
166
|
}
|
|
167
|
-
if (!globalThis.location) {
|
|
168
|
-
globalThis.location = new URL(
|
|
167
|
+
if ( !globalThis.location ) {
|
|
168
|
+
globalThis.location = new URL('https://nodejs.puter.site/');
|
|
169
169
|
}
|
|
170
|
-
if (!globalThis.addEventListener) {
|
|
171
|
-
globalThis.addEventListener = () => {
|
|
170
|
+
if ( !globalThis.addEventListener ) {
|
|
171
|
+
globalThis.addEventListener = () => {
|
|
172
|
+
}; // API Stub
|
|
172
173
|
}
|
|
173
174
|
} else {
|
|
174
175
|
this.env = 'web';
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
177
|
|
|
179
178
|
// There are some specific situations where puter is definitely loaded in GUI mode
|
|
180
179
|
// we're going to check for those situations here so that we don't break anything unintentionally
|
|
181
180
|
// if navigator URL's hostname is 'puter.com'
|
|
182
|
-
if(this.env !== 'gui'){
|
|
181
|
+
if ( this.env !== 'gui' ){
|
|
183
182
|
// Retrieve the hostname from the URL: Remove the trailing dot if it exists. This is to handle the case where the URL is, for example, `https://puter.com.` (note the trailing dot).
|
|
184
|
-
// This is necessary because the trailing dot can cause the hostname to not match the expected value.
|
|
183
|
+
// This is necessary because the trailing dot can cause the hostname to not match the expected value.
|
|
185
184
|
let hostname = location.hostname.replace(/\.$/, '');
|
|
186
185
|
|
|
187
186
|
// Create a new URL object with the URL string
|
|
@@ -191,45 +190,45 @@ export default globalThis.puter = (function() {
|
|
|
191
190
|
const gui_hostname = url.hostname;
|
|
192
191
|
|
|
193
192
|
// If the hostname matches the GUI hostname, then the SDK is running in the GUI environment
|
|
194
|
-
if(hostname === gui_hostname){
|
|
193
|
+
if ( hostname === gui_hostname ){
|
|
195
194
|
this.env = 'gui';
|
|
196
195
|
}
|
|
197
196
|
}
|
|
198
197
|
|
|
199
198
|
// Get the 'args' from the URL. This is used to pass arguments to the app.
|
|
200
|
-
if(URLParams.has('puter.args')){
|
|
199
|
+
if ( URLParams.has('puter.args') ){
|
|
201
200
|
this.args = JSON.parse(decodeURIComponent(URLParams.get('puter.args')));
|
|
202
|
-
}else{
|
|
201
|
+
} else {
|
|
203
202
|
this.args = {};
|
|
204
203
|
}
|
|
205
204
|
|
|
206
205
|
// Try to extract appInstanceID from the URL. appInstanceID is included in every messaage
|
|
207
206
|
// sent to the host environment. This is used to help host environment identify the app
|
|
208
207
|
// instance that sent the message and communicate back to it.
|
|
209
|
-
if(URLParams.has('puter.app_instance_id')){
|
|
208
|
+
if ( URLParams.has('puter.app_instance_id') ){
|
|
210
209
|
this.appInstanceID = decodeURIComponent(URLParams.get('puter.app_instance_id'));
|
|
211
210
|
}
|
|
212
211
|
|
|
213
212
|
// Try to extract parentInstanceID from the URL. If another app launched this app instance, parentInstanceID
|
|
214
213
|
// holds its instance ID, and is used to communicate with that parent app.
|
|
215
|
-
if(URLParams.has('puter.parent_instance_id')){
|
|
214
|
+
if ( URLParams.has('puter.parent_instance_id') ){
|
|
216
215
|
this.parentInstanceID = decodeURIComponent(URLParams.get('puter.parent_instance_id'));
|
|
217
216
|
}
|
|
218
217
|
|
|
219
218
|
// Try to extract `puter.app.id` from the URL. `puter.app.id` is the unique ID of the app.
|
|
220
219
|
// App ID is useful for identifying the app when communicating with the Puter API, among other things.
|
|
221
|
-
if(URLParams.has('puter.app.id')){
|
|
220
|
+
if ( URLParams.has('puter.app.id') ){
|
|
222
221
|
this.appID = decodeURIComponent(URLParams.get('puter.app.id'));
|
|
223
222
|
}
|
|
224
|
-
|
|
223
|
+
|
|
225
224
|
// Extract app name (added later)
|
|
226
|
-
if(URLParams.has('puter.app.name')){
|
|
225
|
+
if ( URLParams.has('puter.app.name') ){
|
|
227
226
|
this.appName = decodeURIComponent(URLParams.get('puter.app.name'));
|
|
228
227
|
}
|
|
229
228
|
|
|
230
229
|
// Construct this App's AppData path based on the appID. AppData path is used to store files that are specific to this app.
|
|
231
230
|
// The default AppData path is `~/AppData/<appID>`.
|
|
232
|
-
if(this.appID){
|
|
231
|
+
if ( this.appID ){
|
|
233
232
|
this.appDataPath = `~/AppData/${this.appID}`;
|
|
234
233
|
}
|
|
235
234
|
|
|
@@ -239,9 +238,9 @@ export default globalThis.puter = (function() {
|
|
|
239
238
|
// is constructed as `https://api.<puter.domain>`.
|
|
240
239
|
// This should only be done when the SDK is running in 'app' mode.
|
|
241
240
|
this.APIOrigin = this.defaultAPIOrigin;
|
|
242
|
-
if(URLParams.has('puter.api_origin') && this.env === 'app'){
|
|
241
|
+
if ( URLParams.has('puter.api_origin') && this.env === 'app' ){
|
|
243
242
|
this.APIOrigin = decodeURIComponent(URLParams.get('puter.api_origin'));
|
|
244
|
-
}else if(URLParams.has('puter.domain') && this.env === 'app'){
|
|
243
|
+
} else if ( URLParams.has('puter.domain') && this.env === 'app' ){
|
|
245
244
|
this.APIOrigin = 'https://api.' + URLParams.get('puter.domain');
|
|
246
245
|
}
|
|
247
246
|
|
|
@@ -251,10 +250,9 @@ export default globalThis.puter = (function() {
|
|
|
251
250
|
let logger = new putility.libs.log.ConsoleLogger();
|
|
252
251
|
|
|
253
252
|
// logs can be toggled based on categories
|
|
254
|
-
logger = new putility.libs.log.CategorizedToggleLogger(
|
|
255
|
-
{ delegate: logger });
|
|
253
|
+
logger = new putility.libs.log.CategorizedToggleLogger({ delegate: logger });
|
|
256
254
|
const cat_logger = logger;
|
|
257
|
-
|
|
255
|
+
|
|
258
256
|
// create facade for easy logging
|
|
259
257
|
this.logger = new putility.libs.log.LoggerFacade({
|
|
260
258
|
impl: logger,
|
|
@@ -263,7 +261,7 @@ export default globalThis.puter = (function() {
|
|
|
263
261
|
|
|
264
262
|
// Initialize API call logger
|
|
265
263
|
this.apiCallLogger = new APICallLogger({
|
|
266
|
-
enabled: false // Disabled by default
|
|
264
|
+
enabled: false, // Disabled by default
|
|
267
265
|
});
|
|
268
266
|
|
|
269
267
|
// === START :: Services === //
|
|
@@ -285,17 +283,16 @@ export default globalThis.puter = (function() {
|
|
|
285
283
|
svc_apiAccess.auth_token = this.authToken;
|
|
286
284
|
svc_apiAccess.api_origin = this.APIOrigin;
|
|
287
285
|
[
|
|
288
|
-
['authToken','auth_token'],
|
|
289
|
-
['APIOrigin','api_origin'],
|
|
290
|
-
].forEach(([k1,k2]) => {
|
|
286
|
+
['authToken', 'auth_token'],
|
|
287
|
+
['APIOrigin', 'api_origin'],
|
|
288
|
+
].forEach(([k1, k2]) => {
|
|
291
289
|
Object.defineProperty(this, k1, {
|
|
292
|
-
get
|
|
290
|
+
get() {
|
|
293
291
|
return svc_apiAccess[k2];
|
|
294
292
|
},
|
|
295
|
-
set
|
|
293
|
+
set(v) {
|
|
296
294
|
svc_apiAccess[k2] = v;
|
|
297
|
-
|
|
298
|
-
}
|
|
295
|
+
},
|
|
299
296
|
});
|
|
300
297
|
});
|
|
301
298
|
})();
|
|
@@ -303,27 +300,27 @@ export default globalThis.puter = (function() {
|
|
|
303
300
|
// === Start :: Modules === //
|
|
304
301
|
|
|
305
302
|
// The SDK is running in the Puter GUI (i.e. 'gui')
|
|
306
|
-
if(this.env === 'gui'){
|
|
303
|
+
if ( this.env === 'gui' ){
|
|
307
304
|
this.authToken = window.auth_token;
|
|
308
305
|
// initialize submodules
|
|
309
306
|
this.initSubmodules();
|
|
310
307
|
}
|
|
311
308
|
// Loaded in an iframe in the Puter GUI (i.e. 'app')
|
|
312
309
|
// When SDK is loaded in App mode the initiation process should start when the DOM is ready
|
|
313
|
-
else if (this.env === 'app') {
|
|
310
|
+
else if ( this.env === 'app' ) {
|
|
314
311
|
this.authToken = decodeURIComponent(URLParams.get('puter.auth.token'));
|
|
315
312
|
// initialize submodules
|
|
316
313
|
this.initSubmodules();
|
|
317
314
|
// If the authToken is already set in localStorage, then we don't need to show the dialog
|
|
318
315
|
try {
|
|
319
|
-
if(localStorage.getItem('puter.auth.token')){
|
|
316
|
+
if ( localStorage.getItem('puter.auth.token') ){
|
|
320
317
|
this.setAuthToken(localStorage.getItem('puter.auth.token'));
|
|
321
318
|
}
|
|
322
319
|
// if appID is already set in localStorage, then we don't need to show the dialog
|
|
323
|
-
if(localStorage.getItem('puter.app.id')){
|
|
320
|
+
if ( localStorage.getItem('puter.app.id') ){
|
|
324
321
|
this.setAppID(localStorage.getItem('puter.app.id'));
|
|
325
322
|
}
|
|
326
|
-
} catch
|
|
323
|
+
} catch( error ) {
|
|
327
324
|
// Handle the error here
|
|
328
325
|
console.error('Error accessing localStorage:', error);
|
|
329
326
|
}
|
|
@@ -331,23 +328,23 @@ export default globalThis.puter = (function() {
|
|
|
331
328
|
// SDK was loaded in a 3rd-party website.
|
|
332
329
|
// When SDK is loaded in GUI the initiation process should start when the DOM is ready. This is because
|
|
333
330
|
// the SDK needs to show a dialog to the user to ask for permission to access their Puter account.
|
|
334
|
-
else if(this.env === 'web') {
|
|
331
|
+
else if ( this.env === 'web' ) {
|
|
335
332
|
// initialize submodules
|
|
336
333
|
this.initSubmodules();
|
|
337
|
-
try{
|
|
334
|
+
try {
|
|
338
335
|
// If the authToken is already set in localStorage, then we don't need to show the dialog
|
|
339
|
-
if(localStorage.getItem('puter.auth.token')){
|
|
336
|
+
if ( localStorage.getItem('puter.auth.token') ){
|
|
340
337
|
this.setAuthToken(localStorage.getItem('puter.auth.token'));
|
|
341
338
|
}
|
|
342
339
|
// if appID is already set in localStorage, then we don't need to show the dialog
|
|
343
|
-
if(localStorage.getItem('puter.app.id')){
|
|
340
|
+
if ( localStorage.getItem('puter.app.id') ){
|
|
344
341
|
this.setAppID(localStorage.getItem('puter.app.id'));
|
|
345
342
|
}
|
|
346
|
-
} catch
|
|
343
|
+
} catch( error ) {
|
|
347
344
|
// Handle the error here
|
|
348
345
|
console.error('Error accessing localStorage:', error);
|
|
349
346
|
}
|
|
350
|
-
} else if (this.env === 'web-worker' || this.env === 'service-worker' || this.env === 'nodejs') {
|
|
347
|
+
} else if ( this.env === 'web-worker' || this.env === 'service-worker' || this.env === 'nodejs' ) {
|
|
351
348
|
this.initSubmodules();
|
|
352
349
|
}
|
|
353
350
|
|
|
@@ -364,7 +361,7 @@ export default globalThis.puter = (function() {
|
|
|
364
361
|
|
|
365
362
|
this.logger.impl = logger;
|
|
366
363
|
})();
|
|
367
|
-
|
|
364
|
+
|
|
368
365
|
// Lock to prevent multiple requests to `/rao`
|
|
369
366
|
this.lock_rao_ = new putility.libs.promise.Lock();
|
|
370
367
|
// Promise that resolves when it's okay to request `/rao`
|
|
@@ -388,14 +385,14 @@ export default globalThis.puter = (function() {
|
|
|
388
385
|
},
|
|
389
386
|
body: JSON.stringify({}),
|
|
390
387
|
})).json());
|
|
391
|
-
return `${wispServer}/${wispToken}
|
|
388
|
+
return `${wispServer}/${wispToken}/`;
|
|
392
389
|
},
|
|
393
390
|
Socket: PSocket,
|
|
394
391
|
tls: {
|
|
395
|
-
TLSSocket: PTLSSocket
|
|
392
|
+
TLSSocket: PTLSSocket,
|
|
396
393
|
},
|
|
397
|
-
fetch: pFetch
|
|
398
|
-
}
|
|
394
|
+
fetch: pFetch,
|
|
395
|
+
};
|
|
399
396
|
|
|
400
397
|
this.workers = new WorkersHandler(this.authToken);
|
|
401
398
|
|
|
@@ -408,13 +405,13 @@ export default globalThis.puter = (function() {
|
|
|
408
405
|
* Makes a request to `/rao`. This method aquires a lock to prevent
|
|
409
406
|
* multiple requests, and is effectively idempotent.
|
|
410
407
|
*/
|
|
411
|
-
async request_rao_
|
|
408
|
+
async request_rao_() {
|
|
412
409
|
await this.p_can_request_rao_;
|
|
413
|
-
|
|
410
|
+
|
|
414
411
|
if ( this.env === 'gui' ) {
|
|
415
412
|
return;
|
|
416
413
|
}
|
|
417
|
-
|
|
414
|
+
|
|
418
415
|
// setAuthToken is called more than once when auth completes, which
|
|
419
416
|
// causes multiple requests to /rao. This lock prevents that.
|
|
420
417
|
await this.lock_rao_.acquire();
|
|
@@ -429,11 +426,11 @@ export default globalThis.puter = (function() {
|
|
|
429
426
|
method: 'POST',
|
|
430
427
|
headers: {
|
|
431
428
|
Authorization: `Bearer ${this.authToken}`,
|
|
432
|
-
Origin: location.origin // This is ignored in the browser but needed for workers and nodejs
|
|
433
|
-
}
|
|
429
|
+
Origin: location.origin, // This is ignored in the browser but needed for workers and nodejs
|
|
430
|
+
},
|
|
434
431
|
});
|
|
435
432
|
return await resp.json();
|
|
436
|
-
} catch
|
|
433
|
+
} catch( e ) {
|
|
437
434
|
had_error = true;
|
|
438
435
|
console.error(e);
|
|
439
436
|
} finally {
|
|
@@ -443,8 +440,8 @@ export default globalThis.puter = (function() {
|
|
|
443
440
|
this.rao_requested_ = true;
|
|
444
441
|
}
|
|
445
442
|
}
|
|
446
|
-
|
|
447
|
-
registerModule
|
|
443
|
+
|
|
444
|
+
registerModule(name, cls, parameters = {}) {
|
|
448
445
|
const instance = new cls(this.context, parameters);
|
|
449
446
|
this.modules_.push(name);
|
|
450
447
|
this[name] = instance;
|
|
@@ -460,24 +457,24 @@ export default globalThis.puter = (function() {
|
|
|
460
457
|
}
|
|
461
458
|
}
|
|
462
459
|
|
|
463
|
-
setAppID = function
|
|
460
|
+
setAppID = function(appID) {
|
|
464
461
|
// save to localStorage
|
|
465
|
-
try{
|
|
462
|
+
try {
|
|
466
463
|
localStorage.setItem('puter.app.id', appID);
|
|
467
|
-
} catch
|
|
464
|
+
} catch( error ) {
|
|
468
465
|
// Handle the error here
|
|
469
466
|
console.error('Error accessing localStorage:', error);
|
|
470
467
|
}
|
|
471
468
|
this.appID = appID;
|
|
472
|
-
}
|
|
469
|
+
};
|
|
473
470
|
|
|
474
|
-
setAuthToken = function
|
|
471
|
+
setAuthToken = function(authToken) {
|
|
475
472
|
this.authToken = authToken;
|
|
476
473
|
// If the SDK is running on a 3rd-party site or an app, then save the authToken in localStorage
|
|
477
|
-
if(this.env === 'web' || this.env === 'app'){
|
|
478
|
-
try{
|
|
474
|
+
if ( this.env === 'web' || this.env === 'app' ){
|
|
475
|
+
try {
|
|
479
476
|
localStorage.setItem('puter.auth.token', authToken);
|
|
480
|
-
} catch
|
|
477
|
+
} catch( error ) {
|
|
481
478
|
// Handle the error here
|
|
482
479
|
console.error('Error accessing localStorage:', error);
|
|
483
480
|
}
|
|
@@ -486,41 +483,41 @@ export default globalThis.puter = (function() {
|
|
|
486
483
|
this.updateSubmodules();
|
|
487
484
|
// rao
|
|
488
485
|
this.request_rao_();
|
|
489
|
-
}
|
|
486
|
+
};
|
|
490
487
|
|
|
491
|
-
setAPIOrigin = function
|
|
488
|
+
setAPIOrigin = function(APIOrigin) {
|
|
492
489
|
this.APIOrigin = APIOrigin;
|
|
493
490
|
// reinitialize submodules
|
|
494
491
|
this.updateSubmodules();
|
|
495
|
-
}
|
|
492
|
+
};
|
|
496
493
|
|
|
497
|
-
resetAuthToken = function
|
|
494
|
+
resetAuthToken = function() {
|
|
498
495
|
this.authToken = null;
|
|
499
496
|
// If the SDK is running on a 3rd-party site or an app, then save the authToken in localStorage
|
|
500
|
-
if(this.env === 'web' || this.env === 'app'){
|
|
501
|
-
try{
|
|
497
|
+
if ( this.env === 'web' || this.env === 'app' ){
|
|
498
|
+
try {
|
|
502
499
|
localStorage.removeItem('puter.auth.token');
|
|
503
|
-
} catch
|
|
500
|
+
} catch( error ) {
|
|
504
501
|
// Handle the error here
|
|
505
502
|
console.error('Error accessing localStorage:', error);
|
|
506
503
|
}
|
|
507
504
|
}
|
|
508
505
|
// reinitialize submodules
|
|
509
506
|
this.updateSubmodules();
|
|
510
|
-
}
|
|
507
|
+
};
|
|
511
508
|
|
|
512
509
|
exit = function(statusCode = 0) {
|
|
513
|
-
if (statusCode && (typeof statusCode !== 'number')) {
|
|
510
|
+
if ( statusCode && (typeof statusCode !== 'number') ) {
|
|
514
511
|
console.warn('puter.exit() requires status code to be a number. Treating it as 1');
|
|
515
512
|
statusCode = 1;
|
|
516
513
|
}
|
|
517
514
|
|
|
518
515
|
globalThis.parent.postMessage({
|
|
519
|
-
msg:
|
|
516
|
+
msg: 'exit',
|
|
520
517
|
appInstanceID: this.appInstanceID,
|
|
521
518
|
statusCode,
|
|
522
519
|
}, '*');
|
|
523
|
-
}
|
|
520
|
+
};
|
|
524
521
|
|
|
525
522
|
/**
|
|
526
523
|
* A function that generates a domain-safe name by combining a random adjective, a random noun, and a random number (between 0 and 9999).
|
|
@@ -532,29 +529,29 @@ export default globalThis.puter = (function() {
|
|
|
532
529
|
*
|
|
533
530
|
*/
|
|
534
531
|
randName = function(separateWith = '-'){
|
|
535
|
-
const first_adj = ['helpful','sensible', 'loyal', 'honest', 'clever', 'capable','calm', 'smart', 'genius', 'bright', 'charming', 'creative', 'diligent', 'elegant', 'fancy',
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const nouns = ['street', 'roof', 'floor', 'tv', 'idea', 'morning', 'game', 'wheel', 'shoe', 'bag', 'clock', 'pencil', 'pen',
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
532
|
+
const first_adj = ['helpful', 'sensible', 'loyal', 'honest', 'clever', 'capable', 'calm', 'smart', 'genius', 'bright', 'charming', 'creative', 'diligent', 'elegant', 'fancy',
|
|
533
|
+
'colorful', 'avid', 'active', 'gentle', 'happy', 'intelligent', 'jolly', 'kind', 'lively', 'merry', 'nice', 'optimistic', 'polite',
|
|
534
|
+
'quiet', 'relaxed', 'silly', 'victorious', 'witty', 'young', 'zealous', 'strong', 'brave', 'agile', 'bold'];
|
|
535
|
+
|
|
536
|
+
const nouns = ['street', 'roof', 'floor', 'tv', 'idea', 'morning', 'game', 'wheel', 'shoe', 'bag', 'clock', 'pencil', 'pen',
|
|
537
|
+
'magnet', 'chair', 'table', 'house', 'dog', 'room', 'book', 'car', 'cat', 'tree',
|
|
538
|
+
'flower', 'bird', 'fish', 'sun', 'moon', 'star', 'cloud', 'rain', 'snow', 'wind', 'mountain',
|
|
539
|
+
'river', 'lake', 'sea', 'ocean', 'island', 'bridge', 'road', 'train', 'plane', 'ship', 'bicycle',
|
|
540
|
+
'horse', 'elephant', 'lion', 'tiger', 'bear', 'zebra', 'giraffe', 'monkey', 'snake', 'rabbit', 'duck',
|
|
541
|
+
'goose', 'penguin', 'frog', 'crab', 'shrimp', 'whale', 'octopus', 'spider', 'ant', 'bee', 'butterfly', 'dragonfly',
|
|
542
|
+
'ladybug', 'snail', 'camel', 'kangaroo', 'koala', 'panda', 'piglet', 'sheep', 'wolf', 'fox', 'deer', 'mouse', 'seal',
|
|
543
|
+
'chicken', 'cow', 'dinosaur', 'puppy', 'kitten', 'circle', 'square', 'garden', 'otter', 'bunny', 'meerkat', 'harp'];
|
|
547
544
|
|
|
548
545
|
// return a random combination of first_adj + noun + number (between 0 and 9999)
|
|
549
546
|
// e.g. clever-idea-123
|
|
550
547
|
return first_adj[Math.floor(Math.random() * first_adj.length)] + separateWith + nouns[Math.floor(Math.random() * nouns.length)] + separateWith + Math.floor(Math.random() * 10000);
|
|
551
|
-
}
|
|
548
|
+
};
|
|
552
549
|
|
|
553
550
|
getUser = function(...args){
|
|
554
551
|
let options;
|
|
555
|
-
|
|
552
|
+
|
|
556
553
|
// If first argument is an object, it's the options
|
|
557
|
-
if (typeof args[0] === 'object' && args[0] !== null) {
|
|
554
|
+
if ( typeof args[0] === 'object' && args[0] !== null ) {
|
|
558
555
|
options = args[0];
|
|
559
556
|
} else {
|
|
560
557
|
// Otherwise, we assume separate arguments are provided
|
|
@@ -563,43 +560,43 @@ export default globalThis.puter = (function() {
|
|
|
563
560
|
error: args[1],
|
|
564
561
|
};
|
|
565
562
|
}
|
|
566
|
-
|
|
563
|
+
|
|
567
564
|
return new Promise((resolve, reject) => {
|
|
568
565
|
const xhr = utils.initXhr('/whoami', this.APIOrigin, this.authToken, 'get');
|
|
569
566
|
// set up event handlers for load and error events
|
|
570
567
|
utils.setupXhrEventHandlers(xhr, options.success, options.error, resolve, reject);
|
|
571
|
-
|
|
568
|
+
|
|
572
569
|
xhr.send();
|
|
573
|
-
})
|
|
574
|
-
}
|
|
570
|
+
});
|
|
571
|
+
};
|
|
575
572
|
|
|
576
573
|
print = function(...args){
|
|
577
574
|
// Check if the last argument is an options object with escapeHTML or code property
|
|
578
575
|
let options = {};
|
|
579
|
-
if(args.length > 0 && typeof args[args.length - 1] === 'object' && args[args.length - 1] !== null &&
|
|
580
|
-
|
|
576
|
+
if ( args.length > 0 && typeof args[args.length - 1] === 'object' && args[args.length - 1] !== null &&
|
|
577
|
+
('escapeHTML' in args[args.length - 1] || 'code' in args[args.length - 1]) ) {
|
|
581
578
|
options = args.pop();
|
|
582
579
|
}
|
|
583
|
-
|
|
584
|
-
for(let arg of args){
|
|
580
|
+
|
|
581
|
+
for ( let arg of args ){
|
|
585
582
|
// Escape HTML if the option is set to true or if code option is true
|
|
586
|
-
if((options.escapeHTML === true || options.code === true) && typeof arg === 'string') {
|
|
583
|
+
if ( (options.escapeHTML === true || options.code === true) && typeof arg === 'string' ) {
|
|
587
584
|
arg = arg.replace(/&/g, '&')
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
585
|
+
.replace(/</g, '<')
|
|
586
|
+
.replace(/>/g, '>')
|
|
587
|
+
.replace(/"/g, '"')
|
|
588
|
+
.replace(/'/g, ''');
|
|
592
589
|
}
|
|
593
|
-
|
|
590
|
+
|
|
594
591
|
// Wrap in code/pre tags if code option is true
|
|
595
|
-
if(options.code === true) {
|
|
592
|
+
if ( options.code === true ) {
|
|
596
593
|
arg = `<code><pre>${arg}</pre></code>`;
|
|
597
594
|
}
|
|
598
|
-
|
|
595
|
+
|
|
599
596
|
document.body.innerHTML += arg;
|
|
600
597
|
}
|
|
601
|
-
}
|
|
602
|
-
|
|
598
|
+
};
|
|
599
|
+
|
|
603
600
|
/**
|
|
604
601
|
* Configures API call logging settings
|
|
605
602
|
* @param {Object} config - Configuration options for API call logging
|
|
@@ -607,32 +604,32 @@ export default globalThis.puter = (function() {
|
|
|
607
604
|
* @param {boolean} config.enabled - Enable/disable API call logging
|
|
608
605
|
*/
|
|
609
606
|
configureAPILogging = function(config = {}){
|
|
610
|
-
if (this.apiCallLogger) {
|
|
607
|
+
if ( this.apiCallLogger ) {
|
|
611
608
|
this.apiCallLogger.updateConfig(config);
|
|
612
609
|
}
|
|
613
610
|
return this;
|
|
614
|
-
}
|
|
615
|
-
|
|
611
|
+
};
|
|
612
|
+
|
|
616
613
|
/**
|
|
617
614
|
* Enables API call logging with optional configuration
|
|
618
615
|
* @param {Object} config - Optional configuration to apply when enabling
|
|
619
616
|
*/
|
|
620
617
|
enableAPILogging = function(config = {}) {
|
|
621
|
-
if (this.apiCallLogger) {
|
|
618
|
+
if ( this.apiCallLogger ) {
|
|
622
619
|
this.apiCallLogger.updateConfig({ ...config, enabled: true });
|
|
623
620
|
}
|
|
624
621
|
return this;
|
|
625
|
-
}
|
|
626
|
-
|
|
622
|
+
};
|
|
623
|
+
|
|
627
624
|
/**
|
|
628
625
|
* Disables API call logging
|
|
629
626
|
*/
|
|
630
627
|
disableAPILogging = function() {
|
|
631
|
-
if (this.apiCallLogger) {
|
|
628
|
+
if ( this.apiCallLogger ) {
|
|
632
629
|
this.apiCallLogger.disable();
|
|
633
630
|
}
|
|
634
631
|
return this;
|
|
635
|
-
}
|
|
632
|
+
};
|
|
636
633
|
|
|
637
634
|
/**
|
|
638
635
|
* Initializes network connectivity monitoring to purge cache when connection is lost
|
|
@@ -640,8 +637,8 @@ export default globalThis.puter = (function() {
|
|
|
640
637
|
*/
|
|
641
638
|
initNetworkMonitoring = function() {
|
|
642
639
|
// Only initialize in environments that support navigator.onLine and window events
|
|
643
|
-
if (typeof globalThis.navigator === 'undefined' ||
|
|
644
|
-
typeof globalThis.addEventListener !== 'function') {
|
|
640
|
+
if ( typeof globalThis.navigator === 'undefined' ||
|
|
641
|
+
typeof globalThis.addEventListener !== 'function' ) {
|
|
645
642
|
return;
|
|
646
643
|
}
|
|
647
644
|
|
|
@@ -651,13 +648,13 @@ export default globalThis.puter = (function() {
|
|
|
651
648
|
// Function to handle network state changes
|
|
652
649
|
const handleNetworkChange = () => {
|
|
653
650
|
const isOnline = navigator.onLine;
|
|
654
|
-
|
|
651
|
+
|
|
655
652
|
// If we went from online to offline, purge the cache
|
|
656
|
-
if (wasOnline && !isOnline) {
|
|
653
|
+
if ( wasOnline && !isOnline ) {
|
|
657
654
|
console.log('Network connection lost - purging cache');
|
|
658
655
|
this.purgeCache();
|
|
659
656
|
}
|
|
660
|
-
|
|
657
|
+
|
|
661
658
|
// Update the previous state
|
|
662
659
|
wasOnline = isOnline;
|
|
663
660
|
};
|
|
@@ -668,13 +665,13 @@ export default globalThis.puter = (function() {
|
|
|
668
665
|
|
|
669
666
|
// Also listen for visibility change as an additional indicator
|
|
670
667
|
// (some browsers don't fire offline events reliably)
|
|
671
|
-
if (typeof document !== 'undefined') {
|
|
668
|
+
if ( typeof document !== 'undefined' ) {
|
|
672
669
|
document.addEventListener('visibilitychange', () => {
|
|
673
670
|
// Small delay to allow network state to update
|
|
674
671
|
setTimeout(handleNetworkChange, 100);
|
|
675
672
|
});
|
|
676
673
|
}
|
|
677
|
-
}
|
|
674
|
+
};
|
|
678
675
|
|
|
679
676
|
/**
|
|
680
677
|
* Purges all cached data
|
|
@@ -682,17 +679,17 @@ export default globalThis.puter = (function() {
|
|
|
682
679
|
*/
|
|
683
680
|
purgeCache = function() {
|
|
684
681
|
try {
|
|
685
|
-
if (this._cache && typeof this._cache.flushall === 'function') {
|
|
682
|
+
if ( this._cache && typeof this._cache.flushall === 'function' ) {
|
|
686
683
|
this._cache.flushall();
|
|
687
684
|
console.log('Cache purged successfully');
|
|
688
685
|
} else {
|
|
689
686
|
console.warn('Cache purge failed: cache instance not available');
|
|
690
687
|
}
|
|
691
|
-
} catch
|
|
688
|
+
} catch( error ) {
|
|
692
689
|
console.error('Error purging cache:', error);
|
|
693
690
|
}
|
|
694
|
-
}
|
|
695
|
-
|
|
691
|
+
};
|
|
692
|
+
|
|
696
693
|
}
|
|
697
694
|
|
|
698
695
|
// Create a new Puter object and return it
|
|
@@ -700,18 +697,21 @@ export default globalThis.puter = (function() {
|
|
|
700
697
|
|
|
701
698
|
// Return the Puter object
|
|
702
699
|
return puterobj;
|
|
703
|
-
}
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
export const puter = puterInit();
|
|
703
|
+
export default puter;
|
|
704
704
|
|
|
705
|
-
globalThis.addEventListener('message', async (event) => {
|
|
705
|
+
globalThis.addEventListener && globalThis.addEventListener('message', async (event) => {
|
|
706
706
|
// if the message is not from Puter, then ignore it
|
|
707
|
-
if(event.origin !== puter.defaultGUIOrigin) return;
|
|
707
|
+
if ( event.origin !== puter.defaultGUIOrigin ) return;
|
|
708
708
|
|
|
709
|
-
if(event.data.msg && event.data.msg === 'requestOrigin'){
|
|
709
|
+
if ( event.data.msg && event.data.msg === 'requestOrigin' ){
|
|
710
710
|
event.source.postMessage({
|
|
711
|
-
msg:
|
|
712
|
-
}, '*');
|
|
711
|
+
msg: 'originResponse',
|
|
712
|
+
}, '*');
|
|
713
713
|
}
|
|
714
|
-
else if (event.data.msg === 'puter.token') {
|
|
714
|
+
else if ( event.data.msg === 'puter.token' ) {
|
|
715
715
|
// puterDialog.close();
|
|
716
716
|
// Set the authToken property
|
|
717
717
|
puter.setAuthToken(event.data.token);
|
|
@@ -725,16 +725,16 @@ globalThis.addEventListener('message', async (event) => {
|
|
|
725
725
|
// resolve();
|
|
726
726
|
|
|
727
727
|
// Call onAuth callback
|
|
728
|
-
if(puter.onAuth && typeof puter.onAuth === 'function'){
|
|
728
|
+
if ( puter.onAuth && typeof puter.onAuth === 'function' ){
|
|
729
729
|
puter.getUser().then((user) => {
|
|
730
|
-
puter.onAuth(user)
|
|
730
|
+
puter.onAuth(user);
|
|
731
731
|
});
|
|
732
732
|
}
|
|
733
733
|
|
|
734
734
|
puter.puterAuthState.isPromptOpen = false;
|
|
735
735
|
// Resolve or reject any waiting promises.
|
|
736
|
-
if (puter.puterAuthState.resolver) {
|
|
737
|
-
if (puter.puterAuthState.authGranted) {
|
|
736
|
+
if ( puter.puterAuthState.resolver ) {
|
|
737
|
+
if ( puter.puterAuthState.authGranted ) {
|
|
738
738
|
puter.puterAuthState.resolver.resolve();
|
|
739
739
|
} else {
|
|
740
740
|
puter.puterAuthState.resolver.reject();
|
|
@@ -742,4 +742,4 @@ globalThis.addEventListener('message', async (event) => {
|
|
|
742
742
|
puter.puterAuthState.resolver = null;
|
|
743
743
|
};
|
|
744
744
|
}
|
|
745
|
-
})
|
|
745
|
+
});
|