valyrian.js 7.2.11 → 8.0.0
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/README.md +6 -6
- package/dist/flux-store/index.d.ts +32 -0
- package/dist/flux-store/index.d.ts.map +1 -0
- package/dist/flux-store/index.js +258 -0
- package/dist/flux-store/index.js.map +7 -0
- package/dist/flux-store/index.min.js +1 -0
- package/dist/flux-store/index.min.js.map +1 -0
- package/dist/flux-store/index.mjs +237 -0
- package/dist/flux-store/index.mjs.map +7 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +42 -75
- package/dist/hooks/index.js.map +2 -2
- package/dist/hooks/index.min.js +1 -0
- package/dist/hooks/index.min.js.map +1 -0
- package/dist/hooks/index.mjs +43 -76
- package/dist/hooks/index.mjs.map +2 -2
- package/dist/index.d.ts +52 -54
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +397 -328
- package/dist/index.js.map +3 -3
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +397 -328
- package/dist/index.mjs.map +3 -3
- package/dist/native-store/index.d.ts +14 -0
- package/dist/native-store/index.d.ts.map +1 -0
- package/dist/native-store/index.js +103 -0
- package/dist/native-store/index.js.map +7 -0
- package/dist/native-store/index.min.js +1 -0
- package/dist/native-store/index.min.js.map +1 -0
- package/dist/native-store/index.mjs +82 -0
- package/dist/native-store/index.mjs.map +7 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +223 -86
- package/dist/node/index.js.map +4 -4
- package/dist/node/index.mjs +223 -86
- package/dist/node/index.mjs.map +4 -4
- package/dist/node/node.sw.js +152 -0
- package/dist/node/utils/inline.d.ts.map +1 -1
- package/dist/node/utils/node.sw.js +152 -0
- package/dist/node/utils/session-storage.d.ts +22 -0
- package/dist/node/utils/session-storage.d.ts.map +1 -0
- package/dist/node/utils/sw.d.ts.map +1 -1
- package/dist/node/utils/tree-adapter.d.ts +9 -0
- package/dist/node/utils/tree-adapter.d.ts.map +1 -1
- package/dist/pulse-store/index.d.ts +13 -0
- package/dist/pulse-store/index.d.ts.map +1 -0
- package/dist/pulse-store/index.js +143 -0
- package/dist/pulse-store/index.js.map +7 -0
- package/dist/pulse-store/index.min.js +1 -0
- package/dist/pulse-store/index.min.js.map +1 -0
- package/dist/pulse-store/index.mjs +122 -0
- package/dist/pulse-store/index.mjs.map +7 -0
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +68 -89
- package/dist/request/index.js.map +2 -2
- package/dist/request/index.min.js +1 -0
- package/dist/request/index.min.js.map +1 -0
- package/dist/request/index.mjs +68 -89
- package/dist/request/index.mjs.map +2 -2
- package/dist/router/index.d.ts +32 -31
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +256 -104
- package/dist/router/index.js.map +3 -3
- package/dist/router/index.min.js +1 -0
- package/dist/router/index.min.js.map +1 -0
- package/dist/router/index.mjs +256 -104
- package/dist/router/index.mjs.map +3 -3
- package/dist/signals/index.d.ts +6 -0
- package/dist/signals/index.d.ts.map +1 -0
- package/dist/signals/index.js +92 -0
- package/dist/signals/index.js.map +7 -0
- package/dist/signals/index.min.js +1 -0
- package/dist/signals/index.min.js.map +1 -0
- package/dist/signals/index.mjs +71 -0
- package/dist/signals/index.mjs.map +7 -0
- package/dist/suspense/index.d.ts +6 -0
- package/dist/suspense/index.d.ts.map +1 -0
- package/dist/suspense/index.js +67 -0
- package/dist/suspense/index.js.map +7 -0
- package/dist/suspense/index.min.js +1 -0
- package/dist/suspense/index.min.js.map +1 -0
- package/dist/suspense/index.mjs +46 -0
- package/dist/suspense/index.mjs.map +7 -0
- package/dist/sw/index.min.js +1 -0
- package/dist/sw/index.min.js.map +1 -0
- package/dist/translate/index.d.ts +19 -0
- package/dist/translate/index.d.ts.map +1 -0
- package/dist/translate/index.js +150 -0
- package/dist/translate/index.js.map +7 -0
- package/dist/translate/index.min.js +1 -0
- package/dist/translate/index.min.js.map +1 -0
- package/dist/translate/index.mjs +129 -0
- package/dist/translate/index.mjs.map +7 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/deep-freeze.d.ts +3 -0
- package/dist/utils/deep-freeze.d.ts.map +1 -0
- package/dist/utils/getter-setter.d.ts +3 -0
- package/dist/utils/getter-setter.d.ts.map +1 -0
- package/dist/utils/has-changed.d.ts +2 -0
- package/dist/utils/has-changed.d.ts.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +138 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/index.min.js +1 -0
- package/dist/utils/index.min.js.map +1 -0
- package/dist/utils/index.mjs +115 -0
- package/dist/utils/index.mjs.map +7 -0
- package/lib/flux-store/index.ts +301 -0
- package/lib/hooks/index.ts +52 -101
- package/lib/index.ts +479 -719
- package/lib/native-store/index.ts +106 -0
- package/lib/node/index.ts +5 -3
- package/lib/node/utils/icons.ts +5 -5
- package/lib/node/utils/inline.ts +17 -17
- package/lib/node/utils/node.sw.js +152 -0
- package/lib/node/utils/session-storage.ts +117 -0
- package/lib/node/utils/sw.ts +35 -11
- package/lib/node/utils/tree-adapter.ts +99 -52
- package/lib/pulse-store/index.ts +181 -0
- package/lib/request/index.ts +86 -116
- package/lib/router/index.ts +358 -170
- package/lib/signals/index.ts +98 -0
- package/lib/suspense/index.ts +57 -0
- package/lib/translate/index.ts +156 -0
- package/lib/utils/deep-freeze.ts +54 -0
- package/lib/utils/getter-setter.ts +40 -0
- package/lib/utils/has-changed.ts +43 -0
- package/lib/utils/index.ts +3 -0
- package/package.json +38 -50
- package/tsconfig.json +1 -1
- package/dist/dataset/index.d.ts +0 -24
- package/dist/dataset/index.d.ts.map +0 -1
- package/dist/dataset/index.js +0 -178
- package/dist/dataset/index.js.map +0 -7
- package/dist/dataset/index.mjs +0 -157
- package/dist/dataset/index.mjs.map +0 -7
- package/dist/node/node.sw.tpl +0 -133
- package/dist/node/utils/node.sw.tpl +0 -133
- package/dist/proxy-signal/index.d.ts +0 -23
- package/dist/proxy-signal/index.d.ts.map +0 -1
- package/dist/proxy-signal/index.js +0 -138
- package/dist/proxy-signal/index.js.map +0 -7
- package/dist/proxy-signal/index.mjs +0 -117
- package/dist/proxy-signal/index.mjs.map +0 -7
- package/dist/signal/index.d.ts +0 -20
- package/dist/signal/index.d.ts.map +0 -1
- package/dist/signal/index.js +0 -95
- package/dist/signal/index.js.map +0 -7
- package/dist/signal/index.mjs +0 -74
- package/dist/signal/index.mjs.map +0 -7
- package/dist/store/index.d.ts +0 -16
- package/dist/store/index.d.ts.map +0 -1
- package/dist/store/index.js +0 -93
- package/dist/store/index.js.map +0 -7
- package/dist/store/index.mjs +0 -72
- package/dist/store/index.mjs.map +0 -7
- package/lib/dataset/index.ts +0 -193
- package/lib/index.d.ts +0 -0
- package/lib/interfaces.ts.bak +0 -141
- package/lib/node/utils/node.sw.tpl +0 -133
- package/lib/proxy-signal/index.ts +0 -187
- package/lib/signal/index.ts +0 -161
- package/lib/store/index.ts +0 -101
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isNodeJs } from "valyrian.js";
|
|
2
|
+
|
|
3
|
+
/* eslint-disable no-console */
|
|
4
|
+
export enum StorageType {
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
Session = "session",
|
|
7
|
+
// eslint-disable-next-line no-unused-vars
|
|
8
|
+
Local = "local"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface NativeStorageInterface {
|
|
12
|
+
state: Record<string, any>;
|
|
13
|
+
// eslint-disable-next-line no-unused-vars
|
|
14
|
+
set(key: string, value: any): void;
|
|
15
|
+
// eslint-disable-next-line no-unused-vars
|
|
16
|
+
get(key: string): any;
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
delete(key: string): void;
|
|
19
|
+
load(): void;
|
|
20
|
+
clear(): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ids = new Set<string>();
|
|
24
|
+
|
|
25
|
+
function getStorage(storageType: StorageType) {
|
|
26
|
+
if (isNodeJs && typeof localStorage === "undefined") {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`localStorage and sessionStorage are not available in Node.js, to use it in your project, you need to "import "valyrian.js/node"`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return storageType === StorageType.Session ? sessionStorage : localStorage;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function createNativeStore<T>(
|
|
35
|
+
key: string,
|
|
36
|
+
definition: Record<string, any> = {},
|
|
37
|
+
storageType: StorageType = StorageType.Local,
|
|
38
|
+
reuseIfExist = false
|
|
39
|
+
): NativeStorageInterface & T {
|
|
40
|
+
const nativeStore = getStorage(storageType);
|
|
41
|
+
|
|
42
|
+
if (ids.has(key)) {
|
|
43
|
+
if (reuseIfExist) {
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
console.warn(`Store with key ${key} already exists and will be reused`);
|
|
46
|
+
} else {
|
|
47
|
+
throw new Error(`Store with key ${key} already exists`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
ids.add(key);
|
|
51
|
+
|
|
52
|
+
const id = key;
|
|
53
|
+
|
|
54
|
+
const Store: NativeStorageInterface = {
|
|
55
|
+
state: {},
|
|
56
|
+
set(key, value) {
|
|
57
|
+
try {
|
|
58
|
+
this.state[key] = value;
|
|
59
|
+
nativeStore.setItem(id, JSON.stringify(this.state));
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error("Error setting item in storage:", e);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
get(key) {
|
|
65
|
+
if (Object.keys(this.state).length === 0) {
|
|
66
|
+
this.load();
|
|
67
|
+
}
|
|
68
|
+
return this.state[key];
|
|
69
|
+
},
|
|
70
|
+
delete(key) {
|
|
71
|
+
try {
|
|
72
|
+
Reflect.deleteProperty(this.state, key);
|
|
73
|
+
nativeStore.setItem(id, JSON.stringify(this.state));
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.error("Error deleting item in storage:", e);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
load() {
|
|
79
|
+
try {
|
|
80
|
+
const state = nativeStore.getItem(id);
|
|
81
|
+
if (!state) {
|
|
82
|
+
this.state = {};
|
|
83
|
+
nativeStore.setItem(id, JSON.stringify(this.state));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.state = JSON.parse(state);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error("Error loading state from storage:", e);
|
|
89
|
+
this.state = {};
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
clear() {
|
|
93
|
+
try {
|
|
94
|
+
this.state = {};
|
|
95
|
+
nativeStore.removeItem(id);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
console.error("Error clearing storage:", e);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
...definition
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
Store.load();
|
|
104
|
+
|
|
105
|
+
return Store as NativeStorageInterface & T;
|
|
106
|
+
}
|
package/lib/node/index.ts
CHANGED
|
@@ -2,17 +2,19 @@ import { document, domToHtml, domToHyperscript, htmlToDom, htmlToHyperscript } f
|
|
|
2
2
|
import { mount, unmount } from "valyrian.js";
|
|
3
3
|
|
|
4
4
|
import FormData from "form-data";
|
|
5
|
-
// import fetch from "node-fetch";
|
|
6
5
|
import { icons } from "./utils/icons";
|
|
7
6
|
import { inline } from "./utils/inline";
|
|
8
7
|
import { sw } from "./utils/sw";
|
|
8
|
+
import { SessionStorage } from "./utils/session-storage";
|
|
9
9
|
|
|
10
10
|
global.FormData = FormData as any;
|
|
11
11
|
global.document = document as any;
|
|
12
|
+
global.sessionStorage = new SessionStorage();
|
|
13
|
+
global.localStorage = new SessionStorage();
|
|
12
14
|
|
|
13
15
|
function render(...args: any[]) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const Component = () => args;
|
|
17
|
+
const result = mount("div", Component);
|
|
16
18
|
unmount();
|
|
17
19
|
return result;
|
|
18
20
|
}
|
package/lib/node/utils/icons.ts
CHANGED
|
@@ -33,7 +33,7 @@ interface IconsOptions {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export async function icons(source: string, configuration?: IconsOptions) {
|
|
36
|
-
|
|
36
|
+
const options = {
|
|
37
37
|
...icons.options,
|
|
38
38
|
...(configuration || {})
|
|
39
39
|
};
|
|
@@ -49,20 +49,20 @@ export async function icons(source: string, configuration?: IconsOptions) {
|
|
|
49
49
|
const { favicons } = await import("favicons");
|
|
50
50
|
|
|
51
51
|
try {
|
|
52
|
-
|
|
52
|
+
const response = await favicons(source, options);
|
|
53
53
|
|
|
54
54
|
if (options.iconsPath) {
|
|
55
|
-
for (
|
|
55
|
+
for (const i in response.images) {
|
|
56
56
|
fs.writeFileSync(options.iconsPath + response.images[i].name, response.images[i].contents);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
for (
|
|
59
|
+
for (const i in response.files) {
|
|
60
60
|
fs.writeFileSync(options.iconsPath + response.files[i].name, response.files[i].contents);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
if (options.linksViewPath) {
|
|
65
|
-
|
|
65
|
+
const html = `
|
|
66
66
|
function Links(){
|
|
67
67
|
return ${htmlToHyperscript(response.html.join(""))};
|
|
68
68
|
}
|
package/lib/node/utils/inline.ts
CHANGED
|
@@ -12,13 +12,13 @@ export async function inline(
|
|
|
12
12
|
options: Record<string, any> = {}
|
|
13
13
|
) {
|
|
14
14
|
if (typeof file === "string") {
|
|
15
|
-
|
|
15
|
+
const ext = file.split(".").pop();
|
|
16
16
|
if (ext && /(js|cjs|jsx|mjs|ts|tsx)/.test(ext)) {
|
|
17
17
|
if (/(ts|tsx)/.test(ext) && !options.noValidate) {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const declarationDir = options.declarationDir;
|
|
19
|
+
const emitDeclaration = !!declarationDir;
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const tscProgOptions = {
|
|
22
22
|
basePath: process.cwd(), // always required, used for relative paths
|
|
23
23
|
configFilePath: "tsconfig.json", // config to inherit from (optional)
|
|
24
24
|
files: [file],
|
|
@@ -53,7 +53,7 @@ export async function inline(
|
|
|
53
53
|
tsc.build(tscProgOptions);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
const esbuildOptions = {
|
|
57
57
|
entryPoints: [file],
|
|
58
58
|
bundle: "bundle" in options ? options.bundle : true,
|
|
59
59
|
sourcemap: "external",
|
|
@@ -72,14 +72,14 @@ export async function inline(
|
|
|
72
72
|
...(options.esbuild || {})
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
const result = await esbuild.build(esbuildOptions);
|
|
76
76
|
if (result.outputFiles?.length !== 2) {
|
|
77
77
|
throw new Error(result.errors.join("\n"));
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (options.compact) {
|
|
81
81
|
const terser = await import("terser");
|
|
82
|
-
|
|
82
|
+
const result2 = await terser.minify(result.outputFiles[1].text, {
|
|
83
83
|
sourceMap: {
|
|
84
84
|
content: result.outputFiles[0].text.toString()
|
|
85
85
|
},
|
|
@@ -97,16 +97,16 @@ export async function inline(
|
|
|
97
97
|
throw new Error("Unknown error");
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const mapBase64 = Buffer.from(result2.map.toString()).toString("base64");
|
|
101
|
+
const suffix = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${mapBase64}`;
|
|
102
102
|
return { raw: result2.code, map: suffix, file };
|
|
103
103
|
} else {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const mapBase64 = Buffer.from(result.outputFiles[0].text.toString()).toString("base64");
|
|
105
|
+
const suffix = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${mapBase64}`;
|
|
106
106
|
return { raw: result.outputFiles[1].text, map: suffix, file };
|
|
107
107
|
}
|
|
108
108
|
} else if (ext && /(css|scss|styl)/.test(ext)) {
|
|
109
|
-
|
|
109
|
+
const result = await new CleanCSS({
|
|
110
110
|
sourceMap: true,
|
|
111
111
|
level: {
|
|
112
112
|
1: {
|
|
@@ -133,18 +133,18 @@ inline.uncss = async function (
|
|
|
133
133
|
css: string,
|
|
134
134
|
options: Record<string, any> = {}
|
|
135
135
|
) {
|
|
136
|
-
|
|
136
|
+
const html = await Promise.all(renderedHtml);
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
const contents = html.map((item) => {
|
|
139
139
|
return {
|
|
140
140
|
raw: item,
|
|
141
141
|
extension: "html"
|
|
142
142
|
};
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
const purgecss = new PurgeCSS();
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
const output = await purgecss.purge({
|
|
148
148
|
fontFace: true,
|
|
149
149
|
keyframes: true,
|
|
150
150
|
variables: true,
|
|
@@ -154,7 +154,7 @@ inline.uncss = async function (
|
|
|
154
154
|
css: [{ raw: css }]
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
const cleanCss = await new CleanCSS({
|
|
158
158
|
sourceMap: false,
|
|
159
159
|
level: {
|
|
160
160
|
1: {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// eslint-disable-next-line no-console
|
|
2
|
+
const Log = console.log;
|
|
3
|
+
|
|
4
|
+
const config = {
|
|
5
|
+
version: "v1.2::",
|
|
6
|
+
name: "Valyrian.js",
|
|
7
|
+
// Critical resources and offline page
|
|
8
|
+
urls: ["/"]
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const cacheName = config.version + config.name;
|
|
12
|
+
const MAX_CACHE_SIZE = 50; // Max cache size
|
|
13
|
+
|
|
14
|
+
// Send messages to clients (controlled pages)
|
|
15
|
+
function sendMessageToClients(message) {
|
|
16
|
+
self.clients.matchAll().then((clients) => {
|
|
17
|
+
clients.forEach((client) => {
|
|
18
|
+
client.postMessage(message);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Limit the cache size by deleting the oldest entries
|
|
24
|
+
function limitCacheSize(name, size) {
|
|
25
|
+
caches.open(name).then((cache) => {
|
|
26
|
+
cache.keys().then((keys) => {
|
|
27
|
+
if (keys.length > size) {
|
|
28
|
+
cache.delete(keys[0]).then(() => {
|
|
29
|
+
limitCacheSize(name, size);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function fetchRequest(event) {
|
|
37
|
+
Log("WORKER: fetch event for " + event.request.url);
|
|
38
|
+
try {
|
|
39
|
+
// Clone the request to store it in the cache
|
|
40
|
+
const fetchRequest = event.request.clone();
|
|
41
|
+
const response = await fetch(fetchRequest);
|
|
42
|
+
|
|
43
|
+
// Verify if the response is valid
|
|
44
|
+
if (response && response.status === 200 && response.type === "basic") {
|
|
45
|
+
// Clone the response to store it in the cache
|
|
46
|
+
const responseToCache = response.clone();
|
|
47
|
+
const cache = await caches.open(cacheName);
|
|
48
|
+
cache.put(event.request, responseToCache);
|
|
49
|
+
|
|
50
|
+
// Limit the cache size
|
|
51
|
+
limitCacheSize(cacheName, MAX_CACHE_SIZE);
|
|
52
|
+
|
|
53
|
+
Log("WORKER: fetch response stored in cache.", event.request.url);
|
|
54
|
+
}
|
|
55
|
+
return response;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
Log("WORKER: fetch request failed.", error);
|
|
58
|
+
|
|
59
|
+
// Try to serve the cached response if available
|
|
60
|
+
const cachedResponse = await caches.match(event.request);
|
|
61
|
+
if (cachedResponse) {
|
|
62
|
+
Log("WORKER: fetch request failed, responding with cache.");
|
|
63
|
+
return cachedResponse;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Send the offline page if no cache is available
|
|
67
|
+
const cache = await caches.open(cacheName);
|
|
68
|
+
const offlineResponse = await cache.match("/offline.html");
|
|
69
|
+
if (offlineResponse) {
|
|
70
|
+
return offlineResponse;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Generic offline page
|
|
74
|
+
return new Response("<h1>Offline</h1>", {
|
|
75
|
+
status: 503,
|
|
76
|
+
statusText: "Service Unavailable",
|
|
77
|
+
headers: new Headers({
|
|
78
|
+
"Content-Type": "text/html"
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
self.addEventListener("fetch", (event) => {
|
|
85
|
+
// Ignore requests with the "only-if-cached" cache mode
|
|
86
|
+
if (event.request.cache === "only-if-cached" && event.request.mode !== "same-origin") {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
Log("WORKER: fetch event in progress.", event.request.url);
|
|
91
|
+
|
|
92
|
+
// Ignore requests that are not GET
|
|
93
|
+
if (event.request.method !== "GET") {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// If the request is for the API, use the network first
|
|
98
|
+
if (event.request.url.includes("/api/")) {
|
|
99
|
+
event.respondWith(fetchRequest(event));
|
|
100
|
+
} else {
|
|
101
|
+
// Use the cache first for other requests
|
|
102
|
+
event.respondWith(
|
|
103
|
+
caches.match(event.request).then((response) => {
|
|
104
|
+
if (response) {
|
|
105
|
+
Log("WORKER: returning from cache.", event.request.url);
|
|
106
|
+
return response;
|
|
107
|
+
}
|
|
108
|
+
return fetchRequest(event);
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
self.addEventListener("install", (event) => {
|
|
115
|
+
Log("WORKER: installing version", cacheName);
|
|
116
|
+
event.waitUntil(
|
|
117
|
+
caches
|
|
118
|
+
.open(cacheName)
|
|
119
|
+
.then((cache) => {
|
|
120
|
+
return cache.addAll(config.urls);
|
|
121
|
+
})
|
|
122
|
+
.then(() => {
|
|
123
|
+
Log("WORKER: install completed.");
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
self.addEventListener("activate", (event) => {
|
|
129
|
+
Log("WORKER: activating new version", cacheName);
|
|
130
|
+
|
|
131
|
+
event.waitUntil(
|
|
132
|
+
caches.keys().then((keys) =>
|
|
133
|
+
Promise.all(
|
|
134
|
+
keys
|
|
135
|
+
// Filter the caches that belong to this app version
|
|
136
|
+
.filter((key) => key !== cacheName)
|
|
137
|
+
.map((key) => caches.delete(key))
|
|
138
|
+
).then(() => {
|
|
139
|
+
Log("WORKER: old caches cleared.");
|
|
140
|
+
// Notify clients about the new version
|
|
141
|
+
sendMessageToClients({ type: "NEW_VERSION" });
|
|
142
|
+
})
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Listen for messages from clients
|
|
148
|
+
self.addEventListener("message", (event) => {
|
|
149
|
+
if (event.data && event.data.type === "SKIP_WAITING") {
|
|
150
|
+
self.skipWaiting();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
export class SessionStorage {
|
|
5
|
+
private storage: { [key: string]: string };
|
|
6
|
+
private limit: number;
|
|
7
|
+
private persist: boolean;
|
|
8
|
+
private filePath: string;
|
|
9
|
+
private directory: string = ".session-storage";
|
|
10
|
+
|
|
11
|
+
constructor({ persist = false, filePath = "./sessionData.json" }: { persist?: boolean; filePath?: string } = {}) {
|
|
12
|
+
this.storage = {};
|
|
13
|
+
this.limit = 5 * 1024 * 1024; // 5MB storage limit
|
|
14
|
+
this.persist = persist;
|
|
15
|
+
this.filePath = path.resolve(this.directory, filePath);
|
|
16
|
+
|
|
17
|
+
if (!fs.existsSync(this.directory)) {
|
|
18
|
+
fs.mkdirSync(this.directory, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Load data from file if persistence is enabled
|
|
22
|
+
if (this.persist) {
|
|
23
|
+
this.loadFromFile();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Calculate total size in bytes of stored data
|
|
28
|
+
private getStorageSize(): number {
|
|
29
|
+
return new TextEncoder().encode(JSON.stringify(this.storage)).length;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check if storage limit is exceeded
|
|
33
|
+
private checkSizeLimit(): void {
|
|
34
|
+
const size = this.getStorageSize();
|
|
35
|
+
if (size > this.limit) {
|
|
36
|
+
throw new DOMException("Storage limit exceeded", "QuotaExceededError");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Store value under the specified key
|
|
41
|
+
setItem(key: string | null | undefined, value: string | null | undefined): void {
|
|
42
|
+
if (key === null || key === undefined) {
|
|
43
|
+
throw new TypeError("Failed to execute 'setItem' on 'Storage': 1 argument required, but only 0 present.");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (value === null) {
|
|
47
|
+
value = "null"; // Convert null to "null"
|
|
48
|
+
} else if (value === undefined) {
|
|
49
|
+
value = "undefined"; // Convert undefined to "undefined"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.storage[key] = String(value); // Store as string
|
|
53
|
+
this.checkSizeLimit(); // Check storage limit
|
|
54
|
+
if (this.persist) {
|
|
55
|
+
this.saveToFile(); // Save to file if persistence is enabled
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Retrieve value stored under the specified key
|
|
60
|
+
getItem(key: string | null | undefined): string | null {
|
|
61
|
+
if (key === null || key === undefined) {
|
|
62
|
+
throw new TypeError("Failed to execute 'getItem' on 'Storage': 1 argument required, but only 0 present.");
|
|
63
|
+
}
|
|
64
|
+
return this.storage[key] || null; // Return null if key doesn't exist
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Remove the value under the specified key
|
|
68
|
+
removeItem(key: string | null | undefined): void {
|
|
69
|
+
if (key === null || key === undefined) {
|
|
70
|
+
throw new TypeError("Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present.");
|
|
71
|
+
}
|
|
72
|
+
delete this.storage[key];
|
|
73
|
+
if (this.persist) {
|
|
74
|
+
this.saveToFile(); // Save to file if persistence is enabled
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Clear all stored values
|
|
79
|
+
clear(): void {
|
|
80
|
+
this.storage = {};
|
|
81
|
+
if (this.persist) {
|
|
82
|
+
this.saveToFile(); // Save to file if persistence is enabled
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Return the number of stored items
|
|
87
|
+
get length(): number {
|
|
88
|
+
return Object.keys(this.storage).length;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Return the key at the specified index
|
|
92
|
+
key(index: number): string | null {
|
|
93
|
+
const keys = Object.keys(this.storage);
|
|
94
|
+
return keys[index] || null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Save data to a file (only if persistence is enabled)
|
|
98
|
+
private saveToFile(): void {
|
|
99
|
+
try {
|
|
100
|
+
fs.writeFileSync(this.filePath, JSON.stringify(this.storage), "utf-8");
|
|
101
|
+
} catch (error) {
|
|
102
|
+
throw new Error(`Error saving data to file: ${(error as any).message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Load data from a file (only if persistence is enabled)
|
|
107
|
+
private loadFromFile(): void {
|
|
108
|
+
try {
|
|
109
|
+
if (fs.existsSync(this.filePath)) {
|
|
110
|
+
const data = fs.readFileSync(this.filePath, "utf-8");
|
|
111
|
+
this.storage = JSON.parse(data || "{}");
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new Error(`Error loading data from file: ${(error as any).message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
package/lib/node/utils/sw.ts
CHANGED
|
@@ -2,17 +2,15 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
4
|
export function sw(file: string, options = {}) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
options
|
|
15
|
-
);
|
|
5
|
+
const swfiletemplate = path.resolve(__dirname, "./node.sw.js");
|
|
6
|
+
const swTpl = fs.readFileSync(swfiletemplate, "utf8");
|
|
7
|
+
const opt = {
|
|
8
|
+
version: "v1::",
|
|
9
|
+
name: "Valyrian.js",
|
|
10
|
+
urls: ["/"],
|
|
11
|
+
debug: false,
|
|
12
|
+
...options
|
|
13
|
+
};
|
|
16
14
|
let contents = swTpl
|
|
17
15
|
.replace("v1::", "v" + opt.version + "::")
|
|
18
16
|
.replace("Valyrian.js", opt.name)
|
|
@@ -24,3 +22,29 @@ export function sw(file: string, options = {}) {
|
|
|
24
22
|
|
|
25
23
|
fs.writeFileSync(file, contents, "utf8");
|
|
26
24
|
}
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
sw("sw.js", {
|
|
28
|
+
version: "1",
|
|
29
|
+
name: "Valyrian.js",
|
|
30
|
+
urls: ["/", "/index.html"],
|
|
31
|
+
debug: false
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// On the client side
|
|
36
|
+
if ("serviceWorker" in navigator) {
|
|
37
|
+
navigator.serviceWorker.register("/service-worker.js");
|
|
38
|
+
|
|
39
|
+
navigator.serviceWorker.addEventListener("message", (event) => {
|
|
40
|
+
if (event.data && event.data.type === "NEW_VERSION") {
|
|
41
|
+
// Notify the user about the new version and ask if they want to update
|
|
42
|
+
if (confirm("Hay una nueva versión disponible. ¿Deseas actualizar?")) {
|
|
43
|
+
// Send a message to the service worker to skip the waiting
|
|
44
|
+
navigator.serviceWorker.controller.postMessage({ type: "SKIP_WAITING" });
|
|
45
|
+
window.location.reload();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
*/
|