@heyputer/puter.js 2.1.15 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/puter.cjs +2 -2
- package/index.d.ts +0 -2
- package/package.json +2 -3
- package/src/index.js +100 -82
- package/src/lib/utils.js +42 -55
- package/src/modules/AI.js +8 -204
- package/src/modules/Apps.js +42 -11
- package/src/modules/Auth.js +6 -5
- package/src/modules/Debug.js +4 -4
- package/src/modules/Drivers.js +12 -17
- package/src/modules/FileSystem/index.js +9 -24
- package/src/modules/Hosting.js +5 -4
- package/src/modules/KV.js +67 -11
- package/src/modules/OS.js +6 -5
- package/src/modules/Perms.js +4 -3
- package/src/modules/PuterDialog.js +2 -2
- package/src/modules/UI.js +44 -28
- package/src/modules/UsageLimitDialog.js +208 -0
- package/types/modules/ai.d.ts +0 -10
- package/types/modules/apps.d.ts +24 -15
- package/types/modules/auth.d.ts +3 -1
- package/types/modules/filesystem.d.ts +0 -2
- package/types/modules/kv.d.ts +10 -0
- package/types/modules/networking.d.ts +1 -1
- package/types/modules/os.d.ts +2 -7
- package/types/modules/ui.d.ts +10 -7
- package/types/modules/util.d.ts +0 -1
- package/types/modules/workers.d.ts +9 -10
- package/types/puter.d.ts +1 -7
- package/src/lib/filesystem/APIFS.js +0 -65
- package/src/lib/filesystem/CacheFS.js +0 -243
- package/src/lib/filesystem/PostMessageFS.js +0 -40
- package/src/lib/filesystem/definitions.js +0 -40
- package/src/modules/Threads.js +0 -72
- package/src/services/APIAccess.js +0 -46
- package/src/services/FSRelay.js +0 -20
- package/src/services/Filesystem.js +0 -137
- package/src/services/NoPuterYet.js +0 -20
- package/src/services/XDIncoming.js +0 -44
- package/types/modules/threads.d.ts +0 -27
package/src/modules/AI.js
CHANGED
|
@@ -11,33 +11,6 @@ const normalizeTTSProvider = (value) => {
|
|
|
11
11
|
return value;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
const TOGETHER_IMAGE_MODEL_PREFIXES = [
|
|
15
|
-
'black-forest-labs/',
|
|
16
|
-
'stabilityai/',
|
|
17
|
-
'togethercomputer/',
|
|
18
|
-
'playgroundai/',
|
|
19
|
-
'runwayml/',
|
|
20
|
-
'lightricks/',
|
|
21
|
-
'sg161222/',
|
|
22
|
-
'wavymulder/',
|
|
23
|
-
'prompthero/',
|
|
24
|
-
'bytedance-seed/',
|
|
25
|
-
'hidream-ai/',
|
|
26
|
-
'lykon/',
|
|
27
|
-
'qwen/',
|
|
28
|
-
'rundiffusion/',
|
|
29
|
-
'google/',
|
|
30
|
-
'ideogram/',
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const TOGETHER_IMAGE_MODEL_KEYWORDS = [
|
|
34
|
-
'flux',
|
|
35
|
-
'kling',
|
|
36
|
-
'sd3',
|
|
37
|
-
'stable-diffusion',
|
|
38
|
-
'kolors',
|
|
39
|
-
];
|
|
40
|
-
|
|
41
14
|
const TOGETHER_VIDEO_MODEL_PREFIXES = [
|
|
42
15
|
'minimax/',
|
|
43
16
|
'google/',
|
|
@@ -57,10 +30,11 @@ class AI {
|
|
|
57
30
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
58
31
|
* @param {string} appID - ID of the app to use.
|
|
59
32
|
*/
|
|
60
|
-
constructor (
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
33
|
+
constructor (puter) {
|
|
34
|
+
this.puter = puter;
|
|
35
|
+
this.authToken = puter.authToken;
|
|
36
|
+
this.APIOrigin = puter.APIOrigin;
|
|
37
|
+
this.appID = puter.appID;
|
|
64
38
|
}
|
|
65
39
|
|
|
66
40
|
/**
|
|
@@ -666,7 +640,7 @@ class AI {
|
|
|
666
640
|
let testMode = false;
|
|
667
641
|
|
|
668
642
|
// default driver is openai-completion
|
|
669
|
-
let driver = '
|
|
643
|
+
let driver = 'ai-chat';
|
|
670
644
|
|
|
671
645
|
// Check that the argument is not undefined or null
|
|
672
646
|
if ( ! args ) {
|
|
@@ -765,160 +739,6 @@ class AI {
|
|
|
765
739
|
// convert undefined to empty string so that .startsWith works
|
|
766
740
|
requestParams.model = requestParams.model ?? '';
|
|
767
741
|
|
|
768
|
-
// If model starts with "anthropic/", remove it
|
|
769
|
-
// later on we should standardize the model names to [vendor]/[model]
|
|
770
|
-
// for example: "claude-3-5-sonnet" should become "anthropic/claude-3-5-sonnet"
|
|
771
|
-
// but for now, we want to keep the old behavior
|
|
772
|
-
// so we remove the "anthropic/" prefix if it exists
|
|
773
|
-
if ( requestParams.model && requestParams.model.startsWith('anthropic/') ) {
|
|
774
|
-
requestParams.model = requestParams.model.replace('anthropic/', '');
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// convert to the correct model name if necessary
|
|
778
|
-
if ( requestParams.model === 'claude-3-5-sonnet' ) {
|
|
779
|
-
requestParams.model = 'claude-3-5-sonnet-latest';
|
|
780
|
-
}
|
|
781
|
-
if ( requestParams.model === 'claude-3-7-sonnet' || requestParams.model === 'claude' ) {
|
|
782
|
-
requestParams.model = 'claude-3-7-sonnet-latest';
|
|
783
|
-
}
|
|
784
|
-
if ( requestParams.model === 'claude-sonnet-4' || requestParams.model === 'claude-sonnet-4-latest' ) {
|
|
785
|
-
requestParams.model = 'claude-sonnet-4-20250514';
|
|
786
|
-
}
|
|
787
|
-
if ( requestParams.model === 'claude-opus-4' || requestParams.model === 'claude-opus-4-latest' ) {
|
|
788
|
-
requestParams.model = 'claude-opus-4-20250514';
|
|
789
|
-
}
|
|
790
|
-
if ( requestParams.model === 'mistral' ) {
|
|
791
|
-
requestParams.model = 'mistral-large-latest';
|
|
792
|
-
}
|
|
793
|
-
if ( requestParams.model === 'groq' ) {
|
|
794
|
-
requestParams.model = 'llama3-8b-8192';
|
|
795
|
-
}
|
|
796
|
-
if ( requestParams.model === 'deepseek' ) {
|
|
797
|
-
requestParams.model = 'deepseek-chat';
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
// o1-mini to openrouter:openai/o1-mini
|
|
801
|
-
if ( requestParams.model === 'o1-mini' ) {
|
|
802
|
-
requestParams.model = 'openrouter:openai/o1-mini';
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// if a model is prepended with "openai/", remove it
|
|
806
|
-
if ( requestParams.model && requestParams.model.startsWith('openai/') ) {
|
|
807
|
-
requestParams.model = requestParams.model.replace('openai/', '');
|
|
808
|
-
driver = 'openai-completion';
|
|
809
|
-
}
|
|
810
|
-
// For the following providers, we need to prepend "openrouter:" to the model name so that the backend driver can handle it
|
|
811
|
-
if (
|
|
812
|
-
requestParams.model.startsWith('agentica-org/') ||
|
|
813
|
-
requestParams.model.startsWith('ai21/') ||
|
|
814
|
-
requestParams.model.startsWith('aion-labs/') ||
|
|
815
|
-
requestParams.model.startsWith('alfredpros/') ||
|
|
816
|
-
requestParams.model.startsWith('allenai/') ||
|
|
817
|
-
requestParams.model.startsWith('alpindale/') ||
|
|
818
|
-
requestParams.model.startsWith('amazon/') ||
|
|
819
|
-
requestParams.model.startsWith('anthracite-org/') ||
|
|
820
|
-
requestParams.model.startsWith('arcee-ai/') ||
|
|
821
|
-
requestParams.model.startsWith('arliai/') ||
|
|
822
|
-
requestParams.model.startsWith('baidu/') ||
|
|
823
|
-
requestParams.model.startsWith('bytedance/') ||
|
|
824
|
-
requestParams.model.startsWith('cognitivecomputations/') ||
|
|
825
|
-
requestParams.model.startsWith('cohere/') ||
|
|
826
|
-
requestParams.model.startsWith('deepseek/') ||
|
|
827
|
-
requestParams.model.startsWith('eleutherai/') ||
|
|
828
|
-
requestParams.model.startsWith('google/') ||
|
|
829
|
-
requestParams.model.startsWith('gryphe/') ||
|
|
830
|
-
requestParams.model.startsWith('inception/') ||
|
|
831
|
-
requestParams.model.startsWith('infermatic/') ||
|
|
832
|
-
requestParams.model.startsWith('liquid/') ||
|
|
833
|
-
requestParams.model.startsWith('mancer/') ||
|
|
834
|
-
requestParams.model.startsWith('meta-llama/') ||
|
|
835
|
-
requestParams.model.startsWith('microsoft/') ||
|
|
836
|
-
requestParams.model.startsWith('minimax/') ||
|
|
837
|
-
requestParams.model.startsWith('mistralai/') ||
|
|
838
|
-
requestParams.model.startsWith('moonshotai/') ||
|
|
839
|
-
requestParams.model.startsWith('morph/') ||
|
|
840
|
-
requestParams.model.startsWith('neversleep/') ||
|
|
841
|
-
requestParams.model.startsWith('nousresearch/') ||
|
|
842
|
-
requestParams.model.startsWith('nvidia/') ||
|
|
843
|
-
requestParams.model.startsWith('openrouter/') ||
|
|
844
|
-
requestParams.model.startsWith('perplexity/') ||
|
|
845
|
-
requestParams.model.startsWith('pygmalionai/') ||
|
|
846
|
-
requestParams.model.startsWith('qwen/') ||
|
|
847
|
-
requestParams.model.startsWith('raifle/') ||
|
|
848
|
-
requestParams.model.startsWith('rekaai/') ||
|
|
849
|
-
requestParams.model.startsWith('sao10k/') ||
|
|
850
|
-
requestParams.model.startsWith('sarvamai/') ||
|
|
851
|
-
requestParams.model.startsWith('scb10x/') ||
|
|
852
|
-
requestParams.model.startsWith('shisa-ai/') ||
|
|
853
|
-
requestParams.model.startsWith('sophosympatheia/') ||
|
|
854
|
-
requestParams.model.startsWith('switchpoint/') ||
|
|
855
|
-
requestParams.model.startsWith('tencent/') ||
|
|
856
|
-
requestParams.model.startsWith('thedrummer/') ||
|
|
857
|
-
requestParams.model.startsWith('thudm/') ||
|
|
858
|
-
requestParams.model.startsWith('tngtech/') ||
|
|
859
|
-
requestParams.model.startsWith('undi95/') ||
|
|
860
|
-
requestParams.model.startsWith('x-ai/') ||
|
|
861
|
-
requestParams.model.startsWith('z-ai/')
|
|
862
|
-
) {
|
|
863
|
-
requestParams.model = `openrouter:${ requestParams.model}`;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
// map model to the appropriate driver
|
|
867
|
-
if ( !requestParams.model || requestParams.model.startsWith('gpt-') ) {
|
|
868
|
-
driver = 'openai-completion';
|
|
869
|
-
} else if (
|
|
870
|
-
requestParams.model.startsWith('claude-')
|
|
871
|
-
) {
|
|
872
|
-
driver = 'claude';
|
|
873
|
-
} else if ( requestParams.model === 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo' || requestParams.model === 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo' || requestParams.model === 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo' || requestParams.model === 'google/gemma-2-27b-it' ) {
|
|
874
|
-
driver = 'together-ai';
|
|
875
|
-
} else if ( requestParams.model.startsWith('mistral-') || requestParams.model.startsWith('codestral-') || requestParams.model.startsWith('pixtral-') || requestParams.model.startsWith('magistral-') || requestParams.model.startsWith('devstral-') || requestParams.model.startsWith('mistral-ocr-') || requestParams.model.startsWith('open-mistral-') ) {
|
|
876
|
-
driver = 'mistral';
|
|
877
|
-
} else if ( [
|
|
878
|
-
'distil-whisper-large-v3-en',
|
|
879
|
-
'gemma2-9b-it',
|
|
880
|
-
'gemma-7b-it',
|
|
881
|
-
'llama-3.1-70b-versatile',
|
|
882
|
-
'llama-3.1-8b-instant',
|
|
883
|
-
'llama3-70b-8192',
|
|
884
|
-
'llama3-8b-8192',
|
|
885
|
-
'llama3-groq-70b-8192-tool-use-preview',
|
|
886
|
-
'llama3-groq-8b-8192-tool-use-preview',
|
|
887
|
-
'llama-guard-3-8b',
|
|
888
|
-
'mixtral-8x7b-32768',
|
|
889
|
-
'whisper-large-v3',
|
|
890
|
-
].includes(requestParams.model) ) {
|
|
891
|
-
driver = 'groq';
|
|
892
|
-
} else if ( requestParams.model === 'grok-beta' ) {
|
|
893
|
-
driver = 'xai';
|
|
894
|
-
}
|
|
895
|
-
else if ( requestParams.model.startsWith('grok-') ) {
|
|
896
|
-
driver = 'openrouter';
|
|
897
|
-
}
|
|
898
|
-
else if (
|
|
899
|
-
requestParams.model === 'deepseek-chat' ||
|
|
900
|
-
requestParams.model === 'deepseek-reasoner'
|
|
901
|
-
) {
|
|
902
|
-
driver = 'deepseek';
|
|
903
|
-
}
|
|
904
|
-
else if (
|
|
905
|
-
requestParams.model === 'gemini-1.5-flash' ||
|
|
906
|
-
requestParams.model === 'gemini-2.0-flash' ||
|
|
907
|
-
requestParams.model === 'gemini-2.5-flash' ||
|
|
908
|
-
requestParams.model === 'gemini-2.5-flash-lite' ||
|
|
909
|
-
requestParams.model === 'gemini-2.0-flash-lite' ||
|
|
910
|
-
requestParams.model === 'gemini-3-pro-preview' ||
|
|
911
|
-
requestParams.model === 'gemini-2.5-pro'
|
|
912
|
-
) {
|
|
913
|
-
driver = 'gemini';
|
|
914
|
-
}
|
|
915
|
-
else if ( requestParams.model.startsWith('openrouter:') ) {
|
|
916
|
-
driver = 'openrouter';
|
|
917
|
-
}
|
|
918
|
-
else if ( requestParams.model.startsWith('ollama:') ) {
|
|
919
|
-
driver = 'ollama';
|
|
920
|
-
}
|
|
921
|
-
|
|
922
742
|
// stream flag from userParams
|
|
923
743
|
if ( userParams.stream !== undefined && typeof userParams.stream === 'boolean' ) {
|
|
924
744
|
requestParams.stream = userParams.stream;
|
|
@@ -1020,27 +840,11 @@ class AI {
|
|
|
1020
840
|
}
|
|
1021
841
|
|
|
1022
842
|
const driverHint = typeof options.driver === 'string' ? options.driver : undefined;
|
|
1023
|
-
const providerRaw = typeof options.provider === 'string'
|
|
1024
|
-
? options.provider
|
|
1025
|
-
: (typeof options.service === 'string' ? options.service : undefined);
|
|
1026
|
-
const providerHint = typeof providerRaw === 'string' ? providerRaw.toLowerCase() : undefined;
|
|
1027
|
-
const modelLower = typeof options.model === 'string' ? options.model.toLowerCase() : '';
|
|
1028
|
-
|
|
1029
|
-
const looksLikeTogetherModel =
|
|
1030
|
-
typeof options.model === 'string' &&
|
|
1031
|
-
(TOGETHER_IMAGE_MODEL_PREFIXES.some(prefix => modelLower.startsWith(prefix)) ||
|
|
1032
|
-
TOGETHER_IMAGE_MODEL_KEYWORDS.some(keyword => modelLower.includes(keyword)));
|
|
1033
843
|
|
|
1034
844
|
if ( driverHint ) {
|
|
1035
845
|
AIService = driverHint;
|
|
1036
|
-
} else
|
|
1037
|
-
AIService = '
|
|
1038
|
-
} else if ( providerHint === 'together' || providerHint === 'together-ai' ) {
|
|
1039
|
-
AIService = 'together-image-generation';
|
|
1040
|
-
} else if (options.model === 'gemini-2.5-flash-image-preview' || options.model === "gemini-3-pro-image-preview" ) {
|
|
1041
|
-
AIService = 'gemini-image-generation';
|
|
1042
|
-
} else if ( looksLikeTogetherModel ) {
|
|
1043
|
-
AIService = 'together-image-generation';
|
|
846
|
+
} else {
|
|
847
|
+
AIService = 'ai-image';
|
|
1044
848
|
}
|
|
1045
849
|
// Call the original chat.complete method
|
|
1046
850
|
return await utils.make_driver_method(['prompt'], 'puter-image-generation', AIService, 'generate', {
|
package/src/modules/Apps.js
CHANGED
|
@@ -9,10 +9,42 @@ class Apps {
|
|
|
9
9
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
10
10
|
* @param {string} appID - ID of the app to use.
|
|
11
11
|
*/
|
|
12
|
-
constructor (
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
12
|
+
constructor (puter) {
|
|
13
|
+
this.puter = puter;
|
|
14
|
+
this.authToken = puter.authToken;
|
|
15
|
+
this.APIOrigin = puter.APIOrigin;
|
|
16
|
+
this.appID = puter.appID;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#addUserIterationToApp (app) {
|
|
20
|
+
app.getUsers = async (params) => {
|
|
21
|
+
params = params ?? {};
|
|
22
|
+
return (await puter.drivers.call('app-telemetry', 'app-telemetry', 'get_users', { app_uuid: app.uid, limit: params.limit, offset: params.offset })).result;
|
|
23
|
+
};
|
|
24
|
+
app.users = async function* (pageSize = 100) {
|
|
25
|
+
let offset = 0;
|
|
26
|
+
|
|
27
|
+
while ( true ) {
|
|
28
|
+
const users = await app.getUsers({ limit: pageSize, offset });
|
|
29
|
+
|
|
30
|
+
if ( !users || users.length === 0 ) return;
|
|
31
|
+
|
|
32
|
+
for ( const user of users ) {
|
|
33
|
+
yield user;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
offset += users.length;
|
|
37
|
+
if ( users.length < pageSize ) return;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return app;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#addUserIterationToApps (apps) {
|
|
44
|
+
apps.forEach(app => {
|
|
45
|
+
this.#addUserIterationToApp(app);
|
|
46
|
+
});
|
|
47
|
+
return apps;
|
|
16
48
|
}
|
|
17
49
|
|
|
18
50
|
/**
|
|
@@ -47,7 +79,7 @@ class Apps {
|
|
|
47
79
|
|
|
48
80
|
options.predicate = ['user-can-edit'];
|
|
49
81
|
|
|
50
|
-
return utils.make_driver_method(['uid'], 'puter-apps',
|
|
82
|
+
return this.#addUserIterationToApps(await utils.make_driver_method(['uid'], 'puter-apps', 'es:app', 'select').call(this, options));
|
|
51
83
|
};
|
|
52
84
|
|
|
53
85
|
create = async (...args) => {
|
|
@@ -111,7 +143,7 @@ class Apps {
|
|
|
111
143
|
}
|
|
112
144
|
|
|
113
145
|
// Call the original chat.complete method
|
|
114
|
-
return await utils.make_driver_method(['object'], 'puter-apps',
|
|
146
|
+
return this.#addUserIterationToApp(await utils.make_driver_method(['object'], 'puter-apps', 'es:app', 'create').call(this, options));
|
|
115
147
|
};
|
|
116
148
|
|
|
117
149
|
update = async (...args) => {
|
|
@@ -137,7 +169,7 @@ class Apps {
|
|
|
137
169
|
}
|
|
138
170
|
|
|
139
171
|
// Call the original chat.complete method
|
|
140
|
-
return await utils.make_driver_method(['object'], 'puter-apps',
|
|
172
|
+
return this.#addUserIterationToApp(await utils.make_driver_method(['object'], 'puter-apps', 'es:app', 'update').call(this, options));
|
|
141
173
|
};
|
|
142
174
|
|
|
143
175
|
get = async (...args) => {
|
|
@@ -158,8 +190,7 @@ class Apps {
|
|
|
158
190
|
if ( typeof args[0] === 'object' && args[0] !== null ) {
|
|
159
191
|
options.params = args[0];
|
|
160
192
|
}
|
|
161
|
-
|
|
162
|
-
return utils.make_driver_method(['uid'], 'puter-apps', undefined, 'read').call(this, options);
|
|
193
|
+
return this.#addUserIterationToApp(await utils.make_driver_method(['uid'], 'puter-apps', 'es:app', 'read').call(this, options));
|
|
163
194
|
};
|
|
164
195
|
|
|
165
196
|
delete = async (...args) => {
|
|
@@ -169,7 +200,7 @@ class Apps {
|
|
|
169
200
|
if ( Array.isArray(args) && typeof args[0] === 'string' ) {
|
|
170
201
|
options = { id: { name: args[0] } };
|
|
171
202
|
}
|
|
172
|
-
return utils.make_driver_method(['uid'], 'puter-apps',
|
|
203
|
+
return utils.make_driver_method(['uid'], 'puter-apps', 'es:app', 'delete').call(this, options);
|
|
173
204
|
};
|
|
174
205
|
|
|
175
206
|
getDeveloperProfile = function (...args) {
|
|
@@ -212,4 +243,4 @@ class Apps {
|
|
|
212
243
|
};
|
|
213
244
|
}
|
|
214
245
|
|
|
215
|
-
export default Apps;
|
|
246
|
+
export default Apps;
|
package/src/modules/Auth.js
CHANGED
|
@@ -13,10 +13,11 @@ class Auth {
|
|
|
13
13
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
14
14
|
* @param {string} appID - ID of the app to use.
|
|
15
15
|
*/
|
|
16
|
-
constructor (
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
16
|
+
constructor (puter) {
|
|
17
|
+
this.puter = puter;
|
|
18
|
+
this.authToken = puter.authToken;
|
|
19
|
+
this.APIOrigin = puter.APIOrigin;
|
|
20
|
+
this.appID = puter.appID;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -291,4 +292,4 @@ class Auth {
|
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
294
|
|
|
294
|
-
export default Auth;
|
|
295
|
+
export default Auth;
|
package/src/modules/Debug.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export class Debug {
|
|
2
|
-
constructor (
|
|
3
|
-
this.
|
|
2
|
+
constructor (puter, parameters) {
|
|
3
|
+
this.puter = puter;
|
|
4
4
|
this.parameters = parameters;
|
|
5
5
|
|
|
6
6
|
this._init();
|
|
@@ -14,7 +14,7 @@ export class Debug {
|
|
|
14
14
|
enabled_logs = enabled_logs.split(';');
|
|
15
15
|
for ( const category of enabled_logs ) {
|
|
16
16
|
if ( category === '' ) continue;
|
|
17
|
-
this.
|
|
17
|
+
this.puter.logger.on(category);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
globalThis.addEventListener('message', async e => {
|
|
@@ -32,7 +32,7 @@ export class Debug {
|
|
|
32
32
|
|
|
33
33
|
if ( e.data.cmd === 'log.on' ) {
|
|
34
34
|
console.log('Got instruction to turn logs on!');
|
|
35
|
-
this.
|
|
35
|
+
this.puter.logger.on(e.data.category);
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
}
|
package/src/modules/Drivers.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
class FetchDriverCallBackend {
|
|
2
|
-
constructor ({
|
|
3
|
-
this.
|
|
2
|
+
constructor ({ getAPIOrigin, getAuthToken }) {
|
|
3
|
+
this.getAPIOrigin = getAPIOrigin;
|
|
4
|
+
this.getAuthToken = getAuthToken;
|
|
4
5
|
this.response_handlers = this.constructor.response_handlers;
|
|
5
6
|
}
|
|
6
7
|
|
|
@@ -32,7 +33,7 @@ class FetchDriverCallBackend {
|
|
|
32
33
|
|
|
33
34
|
async call ({ driver, method_name, parameters }) {
|
|
34
35
|
try {
|
|
35
|
-
const resp = await fetch(`${this.
|
|
36
|
+
const resp = await fetch(`${this.getAPIOrigin()}/drivers/call`, {
|
|
36
37
|
headers: {
|
|
37
38
|
'Content-Type': 'text/plain;actually=json',
|
|
38
39
|
},
|
|
@@ -44,7 +45,7 @@ class FetchDriverCallBackend {
|
|
|
44
45
|
: {}),
|
|
45
46
|
method: method_name,
|
|
46
47
|
args: parameters,
|
|
47
|
-
auth_token: this.
|
|
48
|
+
auth_token: this.getAuthToken(),
|
|
48
49
|
}),
|
|
49
50
|
});
|
|
50
51
|
|
|
@@ -131,22 +132,15 @@ class Drivers {
|
|
|
131
132
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
132
133
|
* @param {string} appID - ID of the app to use.
|
|
133
134
|
*/
|
|
134
|
-
constructor (
|
|
135
|
-
this.
|
|
136
|
-
this.
|
|
137
|
-
this.
|
|
135
|
+
constructor (puter) {
|
|
136
|
+
this.puter = puter;
|
|
137
|
+
this.authToken = puter.authToken;
|
|
138
|
+
this.APIOrigin = puter.APIOrigin;
|
|
139
|
+
this.appID = puter.appID;
|
|
138
140
|
|
|
139
141
|
// Driver-specific
|
|
140
142
|
this.drivers_ = {};
|
|
141
143
|
|
|
142
|
-
// TODO: replace with `context` from constructor and test site login
|
|
143
|
-
this.context = {};
|
|
144
|
-
Object.defineProperty(this.context, 'authToken', {
|
|
145
|
-
get: () => this.authToken,
|
|
146
|
-
});
|
|
147
|
-
Object.defineProperty(this.context, 'APIOrigin', {
|
|
148
|
-
get: () => this.APIOrigin,
|
|
149
|
-
});
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
_init ({ puter }) {
|
|
@@ -226,7 +220,8 @@ class Drivers {
|
|
|
226
220
|
|
|
227
221
|
return this.drivers_[key] = new Driver ({
|
|
228
222
|
call_backend: new FetchDriverCallBackend({
|
|
229
|
-
|
|
223
|
+
getAPIOrigin: () => this.APIOrigin,
|
|
224
|
+
getAuthToken: () => this.authToken,
|
|
230
225
|
}),
|
|
231
226
|
// iface: interfaces[iface_name],
|
|
232
227
|
iface_name,
|
|
@@ -20,14 +20,11 @@ import stat from './operations/stat.js';
|
|
|
20
20
|
import symlink from './operations/symlink.js';
|
|
21
21
|
import upload from './operations/upload.js';
|
|
22
22
|
import write from './operations/write.js';
|
|
23
|
-
// Why is this called deleteFSEntry instead of just delete? because delete is
|
|
24
|
-
// a reserved keyword in javascript
|
|
25
|
-
import { AdvancedBase } from '../../../../putility/index.js';
|
|
26
23
|
import FSItem from '../FSItem.js';
|
|
27
24
|
import deleteFSEntry from './operations/deleteFSEntry.js';
|
|
28
25
|
import getReadURL from './operations/getReadUrl.js';
|
|
29
26
|
|
|
30
|
-
export class PuterJSFileSystemModule
|
|
27
|
+
export class PuterJSFileSystemModule {
|
|
31
28
|
|
|
32
29
|
space = space;
|
|
33
30
|
mkdir = mkdir;
|
|
@@ -48,17 +45,6 @@ export class PuterJSFileSystemModule extends AdvancedBase {
|
|
|
48
45
|
|
|
49
46
|
FSItem = FSItem;
|
|
50
47
|
|
|
51
|
-
static NARI_METHODS = {
|
|
52
|
-
// stat: {
|
|
53
|
-
// positional: ['path'],
|
|
54
|
-
// firstarg_options: true,
|
|
55
|
-
// async fn (parameters) {
|
|
56
|
-
// const svc_fs = await this.context.services.aget('filesystem');
|
|
57
|
-
// return svc_fs.filesystem.stat(parameters);
|
|
58
|
-
// }
|
|
59
|
-
// },
|
|
60
|
-
};
|
|
61
|
-
|
|
62
48
|
/**
|
|
63
49
|
* Creates a new instance with the given authentication token, API origin, and app ID,
|
|
64
50
|
* and connects to the socket.
|
|
@@ -68,12 +54,11 @@ export class PuterJSFileSystemModule extends AdvancedBase {
|
|
|
68
54
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
69
55
|
* @param {string} appID - ID of the app to use.
|
|
70
56
|
*/
|
|
71
|
-
constructor (
|
|
72
|
-
|
|
73
|
-
this.authToken =
|
|
74
|
-
this.APIOrigin =
|
|
75
|
-
this.appID =
|
|
76
|
-
this.context = context;
|
|
57
|
+
constructor (puter) {
|
|
58
|
+
this.puter = puter;
|
|
59
|
+
this.authToken = puter.authToken;
|
|
60
|
+
this.APIOrigin = puter.APIOrigin;
|
|
61
|
+
this.appID = puter.appID;
|
|
77
62
|
this.cacheUpdateTimer = null;
|
|
78
63
|
// Connect socket.
|
|
79
64
|
this.initializeSocket();
|
|
@@ -107,7 +92,7 @@ export class PuterJSFileSystemModule extends AdvancedBase {
|
|
|
107
92
|
auth: {
|
|
108
93
|
auth_token: this.authToken,
|
|
109
94
|
},
|
|
110
|
-
autoUnref: this.
|
|
95
|
+
autoUnref: this.puter.env === 'nodejs',
|
|
111
96
|
});
|
|
112
97
|
|
|
113
98
|
this.bindSocketEvents();
|
|
@@ -212,7 +197,7 @@ export class PuterJSFileSystemModule extends AdvancedBase {
|
|
|
212
197
|
this.authToken = authToken;
|
|
213
198
|
|
|
214
199
|
// Check cache timestamp and purge if needed (only in GUI environment)
|
|
215
|
-
if ( this.
|
|
200
|
+
if ( this.puter.env === 'gui' ) {
|
|
216
201
|
this.checkCacheAndPurge();
|
|
217
202
|
// Start background task to update LAST_VALID_TS every 1 second
|
|
218
203
|
this.startCacheUpdateTimer();
|
|
@@ -305,7 +290,7 @@ export class PuterJSFileSystemModule extends AdvancedBase {
|
|
|
305
290
|
* @returns {void}
|
|
306
291
|
*/
|
|
307
292
|
startCacheUpdateTimer () {
|
|
308
|
-
if ( this.
|
|
293
|
+
if ( this.puter.env !== 'gui' ) {
|
|
309
294
|
return;
|
|
310
295
|
}
|
|
311
296
|
|
package/src/modules/Hosting.js
CHANGED
|
@@ -10,10 +10,11 @@ class Hosting {
|
|
|
10
10
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
11
11
|
* @param {string} appID - ID of the app to use.
|
|
12
12
|
*/
|
|
13
|
-
constructor (
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
13
|
+
constructor (puter) {
|
|
14
|
+
this.puter = puter;
|
|
15
|
+
this.authToken = puter.authToken;
|
|
16
|
+
this.APIOrigin = puter.APIOrigin;
|
|
17
|
+
this.appID = puter.appID;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
/**
|
package/src/modules/KV.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import { TeePromise } from '@heyputer/putility/src/libs/promise.js';
|
|
2
1
|
import * as utils from '../lib/utils.js';
|
|
3
2
|
|
|
3
|
+
const createDeferred = () => {
|
|
4
|
+
let resolve;
|
|
5
|
+
let reject;
|
|
6
|
+
const promise = new Promise((res, rej) => {
|
|
7
|
+
resolve = res;
|
|
8
|
+
reject = rej;
|
|
9
|
+
});
|
|
10
|
+
return { promise, resolve, reject };
|
|
11
|
+
};
|
|
12
|
+
|
|
4
13
|
const gui_cache_keys = [
|
|
5
14
|
'has_set_default_app_user_permissions',
|
|
6
15
|
'window_sidebar_width',
|
|
@@ -29,15 +38,16 @@ class KV {
|
|
|
29
38
|
* @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
|
|
30
39
|
* @param {string} appID - ID of the app to use.
|
|
31
40
|
*/
|
|
32
|
-
constructor (
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.
|
|
41
|
+
constructor (puter) {
|
|
42
|
+
this.puter = puter;
|
|
43
|
+
this.authToken = puter.authToken;
|
|
44
|
+
this.APIOrigin = puter.APIOrigin;
|
|
45
|
+
this.appID = puter.appID;
|
|
46
|
+
|
|
47
|
+
this.gui_cached = createDeferred();
|
|
48
|
+
this.gui_cache_init = createDeferred();
|
|
39
49
|
(async () => {
|
|
40
|
-
await this.gui_cache_init;
|
|
50
|
+
await this.gui_cache_init.promise;
|
|
41
51
|
this.gui_cache_init = null;
|
|
42
52
|
const resp = await fetch(`${this.APIOrigin}/drivers/call`, {
|
|
43
53
|
method: 'POST',
|
|
@@ -142,7 +152,7 @@ class KV {
|
|
|
142
152
|
this.gui_cached !== null
|
|
143
153
|
) {
|
|
144
154
|
this.gui_cache_init && this.gui_cache_init.resolve();
|
|
145
|
-
const cache = await this.gui_cached;
|
|
155
|
+
const cache = await this.gui_cached.promise;
|
|
146
156
|
return cache[args[0]];
|
|
147
157
|
}
|
|
148
158
|
|
|
@@ -202,6 +212,52 @@ class KV {
|
|
|
202
212
|
return utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'decr').call(this, options);
|
|
203
213
|
};
|
|
204
214
|
|
|
215
|
+
add = async (...args) => {
|
|
216
|
+
let options = {};
|
|
217
|
+
|
|
218
|
+
// arguments are required
|
|
219
|
+
if ( !args || args.length === 0 ) {
|
|
220
|
+
throw ({ message: 'Arguments are required', code: 'arguments_required' });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
options.key = args[0];
|
|
224
|
+
const provided = args[1];
|
|
225
|
+
const isPathMap = provided && typeof provided === 'object' && !Array.isArray(provided);
|
|
226
|
+
options.pathAndValueMap = provided === undefined ? { '': 1 } : isPathMap ? provided : { '': provided };
|
|
227
|
+
|
|
228
|
+
// key size cannot be larger than MAX_KEY_SIZE
|
|
229
|
+
if ( options.key.length > this.MAX_KEY_SIZE ) {
|
|
230
|
+
throw ({ message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'add').call(this, options);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
update = utils.make_driver_method(['key', 'pathAndValueMap', 'ttl'], 'puter-kvstore', undefined, 'update', {
|
|
237
|
+
preprocess: (args) => {
|
|
238
|
+
if ( args.key === undefined || args.key === null ) {
|
|
239
|
+
throw { message: 'Key cannot be undefined', code: 'key_undefined' };
|
|
240
|
+
}
|
|
241
|
+
if ( args.key.length > this.MAX_KEY_SIZE ) {
|
|
242
|
+
throw { message: `Key size cannot be larger than ${this.MAX_KEY_SIZE}`, code: 'key_too_large' };
|
|
243
|
+
}
|
|
244
|
+
if ( args.pathAndValueMap === undefined || args.pathAndValueMap === null || Array.isArray(args.pathAndValueMap) || typeof args.pathAndValueMap !== 'object' ) {
|
|
245
|
+
throw { message: 'pathAndValueMap must be an object', code: 'path_map_invalid' };
|
|
246
|
+
}
|
|
247
|
+
if ( Object.keys(args.pathAndValueMap).length === 0 ) {
|
|
248
|
+
throw { message: 'pathAndValueMap cannot be empty', code: 'path_map_invalid' };
|
|
249
|
+
}
|
|
250
|
+
if ( args.ttl !== undefined && args.ttl !== null ) {
|
|
251
|
+
const ttl = Number(args.ttl);
|
|
252
|
+
if ( Number.isNaN(ttl) ) {
|
|
253
|
+
throw { message: 'ttl must be a number', code: 'ttl_invalid' };
|
|
254
|
+
}
|
|
255
|
+
args.ttl = ttl;
|
|
256
|
+
}
|
|
257
|
+
return args;
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
|
|
205
261
|
/**
|
|
206
262
|
* Set a time to live (in seconds) on a key. After the time to live has expired, the key will be deleted.
|
|
207
263
|
* Prefer this over expireAt if you want timestamp to be set by the server, to avoid issues with clock drift.
|
|
@@ -323,4 +379,4 @@ function globMatch (pattern, str) {
|
|
|
323
379
|
return re.test(str);
|
|
324
380
|
}
|
|
325
381
|
|
|
326
|
-
export default KV;
|
|
382
|
+
export default KV;
|