fullstacked 0.12.0-1169 → 0.12.0-1173

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.
@@ -0,0 +1,318 @@
1
+ import { toByteArray } from "../base64";
2
+ import { bridge } from "../bridge";
3
+ import {
4
+ deserializeArgs,
5
+ getLowestKeyIdAvailable,
6
+ serializeArgs
7
+ } from "../bridge/serialization";
8
+ import core_message from "../core_message";
9
+
10
+ const te = new TextEncoder();
11
+
12
+ type ResponseSimplified = {
13
+ statusCode: number;
14
+ statusMessage: string;
15
+ headers: Record<string, string>;
16
+ body: string | Uint8Array | AsyncIterableIterator<string | Uint8Array>;
17
+ };
18
+
19
+ const activeFetchRequests = new Map<
20
+ number,
21
+ {
22
+ resolve: (response: ResponseSimplified) => void;
23
+ reject: (error: string) => void;
24
+ }
25
+ >();
26
+
27
+ let addedListener = false;
28
+ function receivedResponse(base64Data: string) {
29
+ const data = toByteArray(base64Data);
30
+ const args = deserializeArgs(data);
31
+
32
+ const id = args.at(0);
33
+ const fetchRequest = activeFetchRequests.get(id);
34
+
35
+ const [statusCode, statusMessage, headersStr, body] = args.slice(1);
36
+
37
+ const response: ResponseSimplified = {
38
+ statusCode,
39
+ statusMessage,
40
+ headers: headersStr ? JSON.parse(headersStr) : {},
41
+ body
42
+ };
43
+
44
+ if (statusCode >= 400) {
45
+ fetchRequest.reject(JSON.stringify(response));
46
+ } else {
47
+ fetchRequest.resolve(response);
48
+ }
49
+
50
+ activeFetchRequests.delete(id);
51
+ }
52
+
53
+ // 15
54
+ export default function core_fetch(
55
+ url: string,
56
+ options?: Partial<FetchOptions>
57
+ ): Promise<FetchResponse & { body: Uint8Array }>;
58
+ export default function core_fetch(
59
+ url: string,
60
+ options?: Partial<FetchOptions> & { encoding: "utf8" }
61
+ ): Promise<FetchResponse & { body: string }>;
62
+ export default function core_fetch(
63
+ url: string,
64
+ options?: Partial<FetchOptions> & { stream?: boolean; encoding?: "utf8" }
65
+ ) {
66
+ const method = options?.method || "GET";
67
+
68
+ const headers = options?.headers ? JSON.stringify(options.headers) : "";
69
+
70
+ const body = options?.body
71
+ ? typeof options.body === "string"
72
+ ? te.encode(options.body)
73
+ : options.body
74
+ : new Uint8Array();
75
+
76
+ const timeout = options?.timeout || 10;
77
+
78
+ const requestId = getLowestKeyIdAvailable(activeFetchRequests);
79
+
80
+ const payload = new Uint8Array([
81
+ 15,
82
+
83
+ ...serializeArgs([
84
+ requestId,
85
+ method,
86
+ url,
87
+ headers,
88
+ body,
89
+ timeout,
90
+ options?.encoding === "utf8"
91
+ ])
92
+ ]);
93
+
94
+ if (!addedListener) {
95
+ core_message.addListener("fetch-response", receivedResponse);
96
+ addedListener = true;
97
+ }
98
+
99
+ return new Promise<ResponseSimplified>((resolve, reject) => {
100
+ activeFetchRequests.set(requestId, {
101
+ resolve,
102
+ reject
103
+ });
104
+ bridge(payload);
105
+ });
106
+ }
107
+
108
+ const activeFetch2Requests = new Map<
109
+ number,
110
+ {
111
+ url: string;
112
+ resolveResponse(response: Response): void;
113
+ resolveStream?(param: { done: boolean; chunk: Uint8Array }): void;
114
+ }
115
+ >();
116
+
117
+ let addedListener2 = false;
118
+ function receivedResponse2(base64Data: string) {
119
+ const data = toByteArray(base64Data);
120
+ const args = deserializeArgs(data);
121
+
122
+ const id = args.at(0);
123
+ const request = activeFetch2Requests.get(id);
124
+
125
+ if (request.resolveStream) {
126
+ const [done, chunk] = args.slice(1);
127
+ request.resolveStream({ done, chunk });
128
+ if (done) {
129
+ activeFetch2Requests.delete(id);
130
+ }
131
+ return;
132
+ }
133
+
134
+ const [status, statusText, headersStr] = args.slice(1);
135
+
136
+ const ok = status <= 299;
137
+
138
+ let finished = false;
139
+ const read = async () => {
140
+ if (finished) {
141
+ return { done: true };
142
+ }
143
+
144
+ const { done, chunk } = await new Promise<{
145
+ done: boolean;
146
+ chunk: Uint8Array;
147
+ }>((resolve) => {
148
+ request.resolveStream = resolve;
149
+ });
150
+ finished = done;
151
+
152
+ return { done: false, value: chunk };
153
+ };
154
+
155
+ const it = {
156
+ next: read
157
+ } as AsyncIterator<Uint8Array>;
158
+
159
+ const responseIterator = {
160
+ [Symbol.asyncIterator]() {
161
+ return it;
162
+ }
163
+ };
164
+
165
+ const readBody = async () => {
166
+ if (!ok) {
167
+ return te.encode(statusText);
168
+ }
169
+ let body = new Uint8Array();
170
+ for await (const chunk of responseIterator) {
171
+ const buffer = new Uint8Array(body.byteLength + chunk.byteLength);
172
+ buffer.set(body, 0);
173
+ buffer.set(chunk, body.length);
174
+ body = buffer;
175
+ }
176
+ return body;
177
+ };
178
+
179
+ const response: Response = {
180
+ url: request.url,
181
+ redirected: false,
182
+ type: "default",
183
+ bodyUsed: false,
184
+ ok,
185
+ status,
186
+ statusText,
187
+ headers: objectToHeaders(JSON.parse(headersStr || "{}")),
188
+
189
+ body: iteratorToStream(it),
190
+
191
+ bytes: readBody,
192
+ arrayBuffer: async () => {
193
+ const data = await readBody();
194
+ return data.buffer;
195
+ },
196
+ blob: async () => {
197
+ const body = await readBody();
198
+ return new Blob([body]);
199
+ },
200
+ text: async () => {
201
+ const body = await readBody();
202
+ return new TextDecoder().decode(body);
203
+ },
204
+ json: async () => {
205
+ const body = await readBody();
206
+ return JSON.parse(new TextDecoder().decode(body));
207
+ },
208
+
209
+ // not implemented
210
+ clone: () => null,
211
+ formData: async () => null
212
+ };
213
+
214
+ request.resolveResponse(response);
215
+ }
216
+
217
+ export function core_fetch2(request: Request): Promise<Response>;
218
+ export function core_fetch2(
219
+ url: string | URL,
220
+ options?: RequestInit
221
+ ): Promise<Response>;
222
+ export async function core_fetch2(
223
+ urlOrRequest: string | URL | Request,
224
+ options?: RequestInit
225
+ ): Promise<Response> {
226
+ if (!addedListener2) {
227
+ core_message.addListener("fetch2-response", receivedResponse2);
228
+ addedListener2 = true;
229
+ }
230
+
231
+ if (urlOrRequest instanceof Request) {
232
+ const bodyReader = urlOrRequest.body?.getReader();
233
+ const body = bodyReader ? (await bodyReader.read()).value : "";
234
+
235
+ options = {
236
+ method: urlOrRequest.method,
237
+ headers: urlOrRequest.headers,
238
+ signal: urlOrRequest.signal,
239
+ body
240
+ };
241
+
242
+ return fetch2(urlOrRequest.url, options);
243
+ }
244
+
245
+ const url =
246
+ urlOrRequest instanceof URL ? urlOrRequest.toString() : urlOrRequest;
247
+
248
+ return fetch2(url, options);
249
+ }
250
+
251
+ // 16
252
+ function fetch2(url: string, options?: RequestInit): Promise<Response> {
253
+ const id = getLowestKeyIdAvailable(activeFetch2Requests);
254
+
255
+ const headers = options?.headers
256
+ ? options.headers instanceof Headers
257
+ ? JSON.stringify(headersToObject(options.headers))
258
+ : JSON.stringify(options.headers)
259
+ : "";
260
+ const body = options?.body
261
+ ? typeof options.body === "string"
262
+ ? te.encode(options.body)
263
+ : options.body
264
+ : new Uint8Array();
265
+
266
+ if (options?.signal) {
267
+ options.signal.onabort = () => {
268
+ console.log("ABORT REQUEST");
269
+ // cancel
270
+ };
271
+ }
272
+
273
+ const payload = new Uint8Array([
274
+ 16,
275
+
276
+ ...serializeArgs([id, options?.method || "GET", url, headers, body])
277
+ ]);
278
+
279
+ return new Promise<Response>((resolve) => {
280
+ activeFetch2Requests.set(id, {
281
+ url,
282
+ resolveResponse: resolve
283
+ });
284
+ bridge(payload);
285
+ });
286
+ }
287
+
288
+ function objectToHeaders(o: Record<string, string>) {
289
+ const headers = new Headers();
290
+ Object.entries(o).forEach(([n, v]) => {
291
+ headers.set(n, v);
292
+ });
293
+ return headers;
294
+ }
295
+
296
+ const headersToObject = (h: Headers) => {
297
+ const obj = {};
298
+ for (const [n, v] of h.entries()) {
299
+ obj[n] = v;
300
+ }
301
+ return obj;
302
+ };
303
+
304
+ // https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#convert_an_iterator_or_async_iterator_to_a_stream
305
+ function iteratorToStream(iterator: AsyncIterator<Uint8Array>) {
306
+ return new ReadableStream({
307
+ async pull(controller) {
308
+ const { value, done } = await iterator.next();
309
+
310
+ if (value) {
311
+ controller.enqueue(value);
312
+ }
313
+ if (done) {
314
+ controller.close();
315
+ }
316
+ }
317
+ });
318
+ }
package/lib/fs/fs.ts ADDED
@@ -0,0 +1,157 @@
1
+ import { bridge } from "../bridge";
2
+ import { serializeArgs } from "../bridge/serialization";
3
+
4
+ const te = new TextEncoder();
5
+
6
+ // 2
7
+ export function readFile(path: string): Promise<Uint8Array>;
8
+ export function readFile(
9
+ path: string,
10
+ options: { encoding: "utf8" }
11
+ ): Promise<string>;
12
+ export function readFile(path: string, options?: { encoding: "utf8" }) {
13
+ const payload = new Uint8Array([
14
+ 2,
15
+ ...serializeArgs([path, options?.encoding === "utf8"])
16
+ ]);
17
+
18
+ const transformer = ([stringOrBuffer]) => stringOrBuffer;
19
+
20
+ return bridge(payload, transformer);
21
+ }
22
+
23
+ // 3
24
+ export function writeFile(
25
+ path: string,
26
+ data: string | Uint8Array,
27
+ origin = ""
28
+ ): Promise<boolean> {
29
+ if (typeof data === "string") {
30
+ data = te.encode(data);
31
+ }
32
+
33
+ const payload = new Uint8Array([3, ...serializeArgs([path, data, origin])]);
34
+
35
+ return bridge(payload, ([success]) => success);
36
+ }
37
+
38
+ // 4
39
+ export function unlink(path: string, origin = ""): Promise<boolean> {
40
+ const payload = new Uint8Array([4, ...serializeArgs([path, origin])]);
41
+
42
+ return bridge(payload, ([success]) => success);
43
+ }
44
+
45
+ export type FileInfo = {
46
+ name: string;
47
+ isDirectory: boolean;
48
+ };
49
+
50
+ // 5
51
+ export function readdir(
52
+ path: string,
53
+ options?: { recursive?: boolean; withFileTypes?: false }
54
+ ): Promise<string[]>;
55
+ export function readdir(
56
+ path: string,
57
+ options?: { recursive?: boolean; withFileTypes: true }
58
+ ): Promise<FileInfo[]>;
59
+ export function readdir(
60
+ path: string,
61
+ options?: { recursive?: boolean; withFileTypes?: boolean }
62
+ ) {
63
+ const payload = new Uint8Array([
64
+ 5,
65
+ ...serializeArgs([path, !!options?.recursive, !!options?.withFileTypes])
66
+ ]);
67
+
68
+ const transformer = (items: string[] | (string | boolean)[]) => {
69
+ if (options?.withFileTypes) {
70
+ const dirents: FileInfo[] = [];
71
+ for (let i = 0; i < items.length; i = i + 2) {
72
+ dirents.push({
73
+ name: items[i] as string,
74
+ isDirectory: items[i + 1] as boolean
75
+ });
76
+ }
77
+ return dirents;
78
+ }
79
+
80
+ return items;
81
+ };
82
+
83
+ return bridge(payload, transformer);
84
+ }
85
+
86
+ // 6
87
+ export function mkdir(path: string, origin = ""): Promise<boolean> {
88
+ const payload = new Uint8Array([6, ...serializeArgs([path, origin])]);
89
+
90
+ return bridge(payload, ([success]) => success);
91
+ }
92
+
93
+ // 7
94
+ export function rmdir(path: string, origin = ""): Promise<boolean> {
95
+ const payload = new Uint8Array([7, ...serializeArgs([path, origin])]);
96
+
97
+ return bridge(payload, ([success]) => success);
98
+ }
99
+
100
+ // 8
101
+ export function exists(path: string): Promise<{ isFile: boolean }> {
102
+ const payload = new Uint8Array([8, ...serializeArgs([path])]);
103
+
104
+ const transformer = ([exists, isFile]: [boolean, boolean]) => {
105
+ if (!exists) return undefined;
106
+ return { isFile };
107
+ };
108
+
109
+ return bridge(payload, transformer);
110
+ }
111
+
112
+ // 9
113
+ export function rename(
114
+ oldPath: string,
115
+ newPath: string,
116
+ origin = ""
117
+ ): Promise<boolean> {
118
+ const payload = new Uint8Array([
119
+ 9,
120
+ ...serializeArgs([oldPath, newPath, origin])
121
+ ]);
122
+
123
+ return bridge(payload, ([success]) => success);
124
+ }
125
+
126
+ type FileStats = {
127
+ name: string;
128
+ size: number;
129
+ modTime: number;
130
+ isDirectory: boolean;
131
+ };
132
+
133
+ // 10
134
+ export function stat(path: string): Promise<FileStats> {
135
+ const payload = new Uint8Array([10, ...serializeArgs([path])]);
136
+
137
+ const transformer = (responseArgs: any[]) => {
138
+ if (!responseArgs.length) return null;
139
+
140
+ const [name, size, atimeMs, mtimeMs, ctimeMs, isDirectory] =
141
+ responseArgs;
142
+
143
+ return {
144
+ name,
145
+ size,
146
+ atimeMs,
147
+ mtimeMs,
148
+ ctimeMs,
149
+ atime: new Date(atimeMs),
150
+ mtime: new Date(mtimeMs),
151
+ ctime: new Date(ctimeMs),
152
+ isDirectory
153
+ };
154
+ };
155
+
156
+ return bridge(payload, transformer);
157
+ }
@@ -0,0 +1,3 @@
1
+ import * as fs from "./fs";
2
+ export default fs;
3
+ export * from "./fs";
@@ -0,0 +1,208 @@
1
+ declare module "fs" {
2
+ export type FileInfo = {
3
+ name: string;
4
+ isDirectory: boolean;
5
+ };
6
+ export type FileStats = {
7
+ name: string;
8
+ size: number;
9
+ modTime: number;
10
+ isDirectory: boolean;
11
+ };
12
+
13
+ export function readFile(path: string): Promise<Uint8Array>;
14
+ export function readFile(
15
+ path: string,
16
+ options: {
17
+ encoding: "utf8";
18
+ }
19
+ ): Promise<string>;
20
+ export function writeFile(
21
+ path: string,
22
+ data: string | Uint8Array
23
+ ): Promise<boolean>;
24
+ export function unlink(path: string): Promise<boolean>;
25
+ export function readdir(
26
+ path: string,
27
+ options?: {
28
+ recursive?: boolean;
29
+ withFileTypes?: false;
30
+ }
31
+ ): Promise<string[]>;
32
+ export function readdir(
33
+ path: string,
34
+ options?: {
35
+ recursive?: boolean;
36
+ withFileTypes: true;
37
+ }
38
+ ): Promise<FileInfo[]>;
39
+ export function mkdir(path: string): Promise<boolean>;
40
+ export function rmdir(path: string): Promise<boolean>;
41
+ export function exists(path: string): Promise<{
42
+ isFile: boolean;
43
+ }>;
44
+ export function rename(oldPath: string, newPath: string): Promise<boolean>;
45
+ export function stat(path: string): Promise<FileStats>;
46
+
47
+ var fs: {
48
+ readFile(path: string): Promise<Uint8Array>;
49
+ readFile(
50
+ path: string,
51
+ options: {
52
+ encoding: "utf8";
53
+ }
54
+ ): Promise<string>;
55
+ writeFile(path: string, data: string | Uint8Array): Promise<boolean>;
56
+ unlink(path: string): Promise<boolean>;
57
+ readdir(
58
+ path: string,
59
+ options?: {
60
+ recursive?: boolean;
61
+ withFileTypes?: false;
62
+ }
63
+ ): Promise<string[]>;
64
+ readdir(
65
+ path: string,
66
+ options?: {
67
+ recursive?: boolean;
68
+ withFileTypes: true;
69
+ }
70
+ ): Promise<FileInfo[]>;
71
+ mkdir(path: string): Promise<boolean>;
72
+ rmdir(path: string): Promise<boolean>;
73
+ exists(path: string): Promise<{
74
+ isFile: boolean;
75
+ }>;
76
+ rename(oldPath: string, newPath: string): Promise<boolean>;
77
+ stat(path: string): Promise<FileStats>;
78
+ };
79
+ export default fs;
80
+ }
81
+
82
+ type FetchOptions = {
83
+ method: "GET" | "POST" | "PUT" | "DELETE";
84
+ headers: Record<string, string>;
85
+ body: string | Uint8Array;
86
+ timeout: number;
87
+ stream: boolean;
88
+ };
89
+
90
+ type FetchResponse = {
91
+ statusCode: number;
92
+ statusMessage: string;
93
+ headers: Record<string, string>;
94
+ };
95
+
96
+ declare module "fetch" {
97
+ export default function core_fetch(
98
+ url: string,
99
+ options?: Partial<FetchOptions>
100
+ ): Promise<FetchResponse & { body: Uint8Array }>;
101
+ export default function core_fetch(
102
+ url: string,
103
+ options?: Partial<FetchOptions> & { encoding: "utf8" }
104
+ ): Promise<FetchResponse & { body: string }>;
105
+
106
+ export function core_fetch2(request: Request): Promise<Response>;
107
+ export function core_fetch2(
108
+ url: string | URL,
109
+ options?: RequestInit
110
+ ): Promise<Response>;
111
+ }
112
+
113
+ declare module "platform" {
114
+ export enum Platform {
115
+ NODE = "node",
116
+ APPLE = "apple",
117
+ ANDROID = "android",
118
+ DOCKER = "docker",
119
+ WINDOWS = "windows",
120
+ WASM = "wasm"
121
+ }
122
+
123
+ const platform: Platform;
124
+ export default platform;
125
+ }
126
+
127
+ declare module "archive" {
128
+ type FileEntries<T extends string | Uint8Array> = {
129
+ [filePath: string]: {
130
+ isDir: boolean;
131
+ contents: T;
132
+ };
133
+ };
134
+
135
+ export function unzip(
136
+ entry: string | Uint8Array
137
+ ): Promise<FileEntries<Uint8Array>>;
138
+ export function unzip(
139
+ entry: string | Uint8Array,
140
+ out: string
141
+ ): Promise<boolean>;
142
+
143
+ export function zip(
144
+ entry: FileEntries<string | Uint8Array>
145
+ ): Promise<Uint8Array>;
146
+ export function zip(entry: string): Promise<Uint8Array>;
147
+ export function zip(
148
+ entry: string,
149
+ out: null | undefined,
150
+ skip: string[]
151
+ ): Promise<Uint8Array>;
152
+ export function zip(
153
+ entry: FileEntries<string | Uint8Array> | string,
154
+ out: string,
155
+ skip?: string[]
156
+ ): Promise<boolean>;
157
+
158
+ var archive: {
159
+ unzip(entry: string | Uint8Array): Promise<FileEntries<Uint8Array>>;
160
+ unzip(entry: string | Uint8Array, out: string): Promise<boolean>;
161
+ zip(entry: FileEntries<string | Uint8Array>): Promise<Uint8Array>;
162
+ zip(entry: string): Promise<Uint8Array>;
163
+ zip(
164
+ entry: string,
165
+ out: null | undefined,
166
+ skip: string[]
167
+ ): Promise<Uint8Array>;
168
+ zip(
169
+ entry: FileEntries<string | Uint8Array> | string,
170
+ out: string,
171
+ skip?: string[]
172
+ ): Promise<boolean>;
173
+ };
174
+ export default archive;
175
+ }
176
+
177
+ declare module "connect" {
178
+ export type Data = string | number | boolean | Uint8Array;
179
+
180
+ type DataChannelCallback = (data: Data[]) => void;
181
+
182
+ type DataChannel = {
183
+ send(...args: Data[]): void;
184
+ on(callback: DataChannelCallback): void;
185
+ off(callback: DataChannelCallback): void;
186
+ };
187
+
188
+ type DataChannelRawCallback = (data: Uint8Array) => void;
189
+
190
+ type DataChannelRaw = {
191
+ send(buffer: Uint8Array): void;
192
+ on(callback: DataChannelRawCallback): void;
193
+ off(callback: DataChannelRawCallback): void;
194
+ };
195
+
196
+ export function connect(
197
+ name: string,
198
+ port: number,
199
+ host: string,
200
+ stream: true
201
+ ): Promise<DataChannelRaw>;
202
+ export function connect(
203
+ name: string,
204
+ port: number,
205
+ host?: string,
206
+ stream?: boolean
207
+ ): Promise<DataChannel>;
208
+ }
@@ -0,0 +1,14 @@
1
+ export enum Platform {
2
+ NODE = "node",
3
+ APPLE = "apple",
4
+ ANDROID = "android",
5
+ DOCKER = "docker",
6
+ WINDOWS = "windows",
7
+ WASM = "wasm",
8
+ LINUX_GTK = "linux-gtk",
9
+ LINUX_QT = "linux-qt",
10
+ ELECTRON = "electron"
11
+ }
12
+
13
+ const platform = await (await fetch("/platform")).text();
14
+ export default platform;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullstacked",
3
- "version": "0.12.0-1169",
3
+ "version": "0.12.0-1173",
4
4
  "scripts": {
5
5
  "build": "node build.js",
6
6
  "start": "npm run build && node index.js --lib ../../core/bin --root ~/FullStacked --config ~/.config/fullstacked --editor ../../out/editor",