Experiment to rebuild Diffuse using web applets.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Allow custom applet in output storage configurator

+637 -46
+1
deno.lock
··· 27 27 "npm:iconoir@^7.11.0", 28 28 "npm:idb-keyval@^6.2.1", 29 29 "npm:native-file-system-adapter@^3.0.1", 30 + "npm:sass@^1.87.0", 30 31 "npm:throttle-debounce@^5.0.2", 31 32 "npm:xxh32@^2.0.5" 32 33 ]
+417 -4
package-lock.json
··· 10 10 "iconoir": "^7.11.0", 11 11 "idb-keyval": "^6.2.1", 12 12 "native-file-system-adapter": "^3.0.1", 13 + "sass": "^1.87.0", 13 14 "spellcaster": "icidasset/spellcaster#fix/hyper-data", 14 15 "throttle-debounce": "^5.0.2", 15 16 "xxh32": "^2.0.5" ··· 941 942 "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", 942 943 "dev": true 943 944 }, 945 + "node_modules/@parcel/watcher": { 946 + "version": "2.5.1", 947 + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", 948 + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", 949 + "hasInstallScript": true, 950 + "optional": true, 951 + "dependencies": { 952 + "detect-libc": "^1.0.3", 953 + "is-glob": "^4.0.3", 954 + "micromatch": "^4.0.5", 955 + "node-addon-api": "^7.0.0" 956 + }, 957 + "engines": { 958 + "node": ">= 10.0.0" 959 + }, 960 + "funding": { 961 + "type": "opencollective", 962 + "url": "https://opencollective.com/parcel" 963 + }, 964 + "optionalDependencies": { 965 + "@parcel/watcher-android-arm64": "2.5.1", 966 + "@parcel/watcher-darwin-arm64": "2.5.1", 967 + "@parcel/watcher-darwin-x64": "2.5.1", 968 + "@parcel/watcher-freebsd-x64": "2.5.1", 969 + "@parcel/watcher-linux-arm-glibc": "2.5.1", 970 + "@parcel/watcher-linux-arm-musl": "2.5.1", 971 + "@parcel/watcher-linux-arm64-glibc": "2.5.1", 972 + "@parcel/watcher-linux-arm64-musl": "2.5.1", 973 + "@parcel/watcher-linux-x64-glibc": "2.5.1", 974 + "@parcel/watcher-linux-x64-musl": "2.5.1", 975 + "@parcel/watcher-win32-arm64": "2.5.1", 976 + "@parcel/watcher-win32-ia32": "2.5.1", 977 + "@parcel/watcher-win32-x64": "2.5.1" 978 + } 979 + }, 980 + "node_modules/@parcel/watcher-android-arm64": { 981 + "version": "2.5.1", 982 + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", 983 + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", 984 + "cpu": [ 985 + "arm64" 986 + ], 987 + "optional": true, 988 + "os": [ 989 + "android" 990 + ], 991 + "engines": { 992 + "node": ">= 10.0.0" 993 + }, 994 + "funding": { 995 + "type": "opencollective", 996 + "url": "https://opencollective.com/parcel" 997 + } 998 + }, 999 + "node_modules/@parcel/watcher-darwin-arm64": { 1000 + "version": "2.5.1", 1001 + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", 1002 + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", 1003 + "cpu": [ 1004 + "arm64" 1005 + ], 1006 + "optional": true, 1007 + "os": [ 1008 + "darwin" 1009 + ], 1010 + "engines": { 1011 + "node": ">= 10.0.0" 1012 + }, 1013 + "funding": { 1014 + "type": "opencollective", 1015 + "url": "https://opencollective.com/parcel" 1016 + } 1017 + }, 1018 + "node_modules/@parcel/watcher-darwin-x64": { 1019 + "version": "2.5.1", 1020 + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", 1021 + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", 1022 + "cpu": [ 1023 + "x64" 1024 + ], 1025 + "optional": true, 1026 + "os": [ 1027 + "darwin" 1028 + ], 1029 + "engines": { 1030 + "node": ">= 10.0.0" 1031 + }, 1032 + "funding": { 1033 + "type": "opencollective", 1034 + "url": "https://opencollective.com/parcel" 1035 + } 1036 + }, 1037 + "node_modules/@parcel/watcher-freebsd-x64": { 1038 + "version": "2.5.1", 1039 + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", 1040 + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", 1041 + "cpu": [ 1042 + "x64" 1043 + ], 1044 + "optional": true, 1045 + "os": [ 1046 + "freebsd" 1047 + ], 1048 + "engines": { 1049 + "node": ">= 10.0.0" 1050 + }, 1051 + "funding": { 1052 + "type": "opencollective", 1053 + "url": "https://opencollective.com/parcel" 1054 + } 1055 + }, 1056 + "node_modules/@parcel/watcher-linux-arm-glibc": { 1057 + "version": "2.5.1", 1058 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", 1059 + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", 1060 + "cpu": [ 1061 + "arm" 1062 + ], 1063 + "optional": true, 1064 + "os": [ 1065 + "linux" 1066 + ], 1067 + "engines": { 1068 + "node": ">= 10.0.0" 1069 + }, 1070 + "funding": { 1071 + "type": "opencollective", 1072 + "url": "https://opencollective.com/parcel" 1073 + } 1074 + }, 1075 + "node_modules/@parcel/watcher-linux-arm-musl": { 1076 + "version": "2.5.1", 1077 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", 1078 + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", 1079 + "cpu": [ 1080 + "arm" 1081 + ], 1082 + "optional": true, 1083 + "os": [ 1084 + "linux" 1085 + ], 1086 + "engines": { 1087 + "node": ">= 10.0.0" 1088 + }, 1089 + "funding": { 1090 + "type": "opencollective", 1091 + "url": "https://opencollective.com/parcel" 1092 + } 1093 + }, 1094 + "node_modules/@parcel/watcher-linux-arm64-glibc": { 1095 + "version": "2.5.1", 1096 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", 1097 + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", 1098 + "cpu": [ 1099 + "arm64" 1100 + ], 1101 + "optional": true, 1102 + "os": [ 1103 + "linux" 1104 + ], 1105 + "engines": { 1106 + "node": ">= 10.0.0" 1107 + }, 1108 + "funding": { 1109 + "type": "opencollective", 1110 + "url": "https://opencollective.com/parcel" 1111 + } 1112 + }, 1113 + "node_modules/@parcel/watcher-linux-arm64-musl": { 1114 + "version": "2.5.1", 1115 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", 1116 + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", 1117 + "cpu": [ 1118 + "arm64" 1119 + ], 1120 + "optional": true, 1121 + "os": [ 1122 + "linux" 1123 + ], 1124 + "engines": { 1125 + "node": ">= 10.0.0" 1126 + }, 1127 + "funding": { 1128 + "type": "opencollective", 1129 + "url": "https://opencollective.com/parcel" 1130 + } 1131 + }, 1132 + "node_modules/@parcel/watcher-linux-x64-glibc": { 1133 + "version": "2.5.1", 1134 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", 1135 + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", 1136 + "cpu": [ 1137 + "x64" 1138 + ], 1139 + "optional": true, 1140 + "os": [ 1141 + "linux" 1142 + ], 1143 + "engines": { 1144 + "node": ">= 10.0.0" 1145 + }, 1146 + "funding": { 1147 + "type": "opencollective", 1148 + "url": "https://opencollective.com/parcel" 1149 + } 1150 + }, 1151 + "node_modules/@parcel/watcher-linux-x64-musl": { 1152 + "version": "2.5.1", 1153 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", 1154 + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", 1155 + "cpu": [ 1156 + "x64" 1157 + ], 1158 + "optional": true, 1159 + "os": [ 1160 + "linux" 1161 + ], 1162 + "engines": { 1163 + "node": ">= 10.0.0" 1164 + }, 1165 + "funding": { 1166 + "type": "opencollective", 1167 + "url": "https://opencollective.com/parcel" 1168 + } 1169 + }, 1170 + "node_modules/@parcel/watcher-win32-arm64": { 1171 + "version": "2.5.1", 1172 + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", 1173 + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", 1174 + "cpu": [ 1175 + "arm64" 1176 + ], 1177 + "optional": true, 1178 + "os": [ 1179 + "win32" 1180 + ], 1181 + "engines": { 1182 + "node": ">= 10.0.0" 1183 + }, 1184 + "funding": { 1185 + "type": "opencollective", 1186 + "url": "https://opencollective.com/parcel" 1187 + } 1188 + }, 1189 + "node_modules/@parcel/watcher-win32-ia32": { 1190 + "version": "2.5.1", 1191 + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", 1192 + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", 1193 + "cpu": [ 1194 + "ia32" 1195 + ], 1196 + "optional": true, 1197 + "os": [ 1198 + "win32" 1199 + ], 1200 + "engines": { 1201 + "node": ">= 10.0.0" 1202 + }, 1203 + "funding": { 1204 + "type": "opencollective", 1205 + "url": "https://opencollective.com/parcel" 1206 + } 1207 + }, 1208 + "node_modules/@parcel/watcher-win32-x64": { 1209 + "version": "2.5.1", 1210 + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", 1211 + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", 1212 + "cpu": [ 1213 + "x64" 1214 + ], 1215 + "optional": true, 1216 + "os": [ 1217 + "win32" 1218 + ], 1219 + "engines": { 1220 + "node": ">= 10.0.0" 1221 + }, 1222 + "funding": { 1223 + "type": "opencollective", 1224 + "url": "https://opencollective.com/parcel" 1225 + } 1226 + }, 1227 + "node_modules/@parcel/watcher/node_modules/detect-libc": { 1228 + "version": "1.0.3", 1229 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 1230 + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", 1231 + "optional": true, 1232 + "bin": { 1233 + "detect-libc": "bin/detect-libc.js" 1234 + }, 1235 + "engines": { 1236 + "node": ">=0.10" 1237 + } 1238 + }, 944 1239 "node_modules/@picocss/pico": { 945 1240 "version": "2.1.1", 946 1241 "resolved": "https://registry.npmjs.org/@picocss/pico/-/pico-2.1.1.tgz", ··· 1688 1983 "url": "https://github.com/sponsors/sindresorhus" 1689 1984 } 1690 1985 }, 1986 + "node_modules/braces": { 1987 + "version": "3.0.3", 1988 + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 1989 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 1990 + "optional": true, 1991 + "dependencies": { 1992 + "fill-range": "^7.1.1" 1993 + }, 1994 + "engines": { 1995 + "node": ">=8" 1996 + } 1997 + }, 1691 1998 "node_modules/brotli": { 1692 1999 "version": "1.3.3", 1693 2000 "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", ··· 1765 2072 "version": "4.0.3", 1766 2073 "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", 1767 2074 "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", 1768 - "dev": true, 1769 2075 "dependencies": { 1770 2076 "readdirp": "^4.0.1" 1771 2077 }, ··· 2208 2514 "node": "^12.20 || >= 14.13" 2209 2515 } 2210 2516 }, 2517 + "node_modules/fill-range": { 2518 + "version": "7.1.1", 2519 + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 2520 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 2521 + "optional": true, 2522 + "dependencies": { 2523 + "to-regex-range": "^5.0.1" 2524 + }, 2525 + "engines": { 2526 + "node": ">=8" 2527 + } 2528 + }, 2211 2529 "node_modules/flattie": { 2212 2530 "version": "1.1.1", 2213 2531 "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", ··· 2506 2824 "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", 2507 2825 "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" 2508 2826 }, 2827 + "node_modules/immutable": { 2828 + "version": "5.1.1", 2829 + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz", 2830 + "integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==" 2831 + }, 2509 2832 "node_modules/import-meta-resolve": { 2510 2833 "version": "4.1.0", 2511 2834 "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", ··· 2547 2870 "url": "https://github.com/sponsors/sindresorhus" 2548 2871 } 2549 2872 }, 2873 + "node_modules/is-extglob": { 2874 + "version": "2.1.1", 2875 + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 2876 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 2877 + "optional": true, 2878 + "engines": { 2879 + "node": ">=0.10.0" 2880 + } 2881 + }, 2550 2882 "node_modules/is-fullwidth-code-point": { 2551 2883 "version": "3.0.0", 2552 2884 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", ··· 2556 2888 "node": ">=8" 2557 2889 } 2558 2890 }, 2891 + "node_modules/is-glob": { 2892 + "version": "4.0.3", 2893 + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 2894 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 2895 + "optional": true, 2896 + "dependencies": { 2897 + "is-extglob": "^2.1.1" 2898 + }, 2899 + "engines": { 2900 + "node": ">=0.10.0" 2901 + } 2902 + }, 2559 2903 "node_modules/is-inside-container": { 2560 2904 "version": "1.0.0", 2561 2905 "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", ··· 2572 2916 }, 2573 2917 "funding": { 2574 2918 "url": "https://github.com/sponsors/sindresorhus" 2919 + } 2920 + }, 2921 + "node_modules/is-number": { 2922 + "version": "7.0.0", 2923 + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 2924 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 2925 + "optional": true, 2926 + "engines": { 2927 + "node": ">=0.12.0" 2575 2928 } 2576 2929 }, 2577 2930 "node_modules/is-plain-obj": { ··· 3462 3815 } 3463 3816 ] 3464 3817 }, 3818 + "node_modules/micromatch": { 3819 + "version": "4.0.8", 3820 + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 3821 + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 3822 + "optional": true, 3823 + "dependencies": { 3824 + "braces": "^3.0.3", 3825 + "picomatch": "^2.3.1" 3826 + }, 3827 + "engines": { 3828 + "node": ">=8.6" 3829 + } 3830 + }, 3831 + "node_modules/micromatch/node_modules/picomatch": { 3832 + "version": "2.3.1", 3833 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 3834 + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 3835 + "optional": true, 3836 + "engines": { 3837 + "node": ">=8.6" 3838 + }, 3839 + "funding": { 3840 + "url": "https://github.com/sponsors/jonschlinkert" 3841 + } 3842 + }, 3465 3843 "node_modules/mrmime": { 3466 3844 "version": "2.0.1", 3467 3845 "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", ··· 3538 3916 "url": "https://opencollective.com/unified" 3539 3917 } 3540 3918 }, 3919 + "node_modules/node-addon-api": { 3920 + "version": "7.1.1", 3921 + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", 3922 + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", 3923 + "optional": true 3924 + }, 3541 3925 "node_modules/node-domexception": { 3542 3926 "version": "1.0.0", 3543 3927 "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", ··· 3816 4200 "version": "4.1.2", 3817 4201 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", 3818 4202 "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", 3819 - "dev": true, 3820 4203 "engines": { 3821 4204 "node": ">= 14.18.0" 3822 4205 }, ··· 4097 4480 "fsevents": "~2.3.2" 4098 4481 } 4099 4482 }, 4483 + "node_modules/sass": { 4484 + "version": "1.87.0", 4485 + "resolved": "https://registry.npmjs.org/sass/-/sass-1.87.0.tgz", 4486 + "integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==", 4487 + "dependencies": { 4488 + "chokidar": "^4.0.0", 4489 + "immutable": "^5.0.2", 4490 + "source-map-js": ">=0.6.2 <2.0.0" 4491 + }, 4492 + "bin": { 4493 + "sass": "sass.js" 4494 + }, 4495 + "engines": { 4496 + "node": ">=14.0.0" 4497 + }, 4498 + "optionalDependencies": { 4499 + "@parcel/watcher": "^2.4.1" 4500 + } 4501 + }, 4100 4502 "node_modules/semver": { 4101 4503 "version": "7.7.1", 4102 4504 "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", ··· 4202 4604 "version": "1.2.1", 4203 4605 "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 4204 4606 "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 4205 - "dev": true, 4206 4607 "engines": { 4207 4608 "node": ">=0.10.0" 4208 4609 } ··· 4219 4620 }, 4220 4621 "node_modules/spellcaster": { 4221 4622 "version": "5.0.2", 4222 - "resolved": "git+ssh://git@github.com/icidasset/spellcaster.git#85038476a872463bb8ef4687418cecb1dd4807f1", 4623 + "resolved": "git+ssh://git@github.com/icidasset/spellcaster.git#630230c0950518a39047ea6ef34530b9d64c0c7f", 4223 4624 "dependencies": { 4224 4625 "signal-polyfill": "^0.2.0" 4225 4626 } ··· 4304 4705 }, 4305 4706 "funding": { 4306 4707 "url": "https://github.com/sponsors/SuperchupuDev" 4708 + } 4709 + }, 4710 + "node_modules/to-regex-range": { 4711 + "version": "5.0.1", 4712 + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 4713 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 4714 + "optional": true, 4715 + "dependencies": { 4716 + "is-number": "^7.0.0" 4717 + }, 4718 + "engines": { 4719 + "node": ">=8.0" 4307 4720 } 4308 4721 }, 4309 4722 "node_modules/tr46": {
+1
package.json
··· 5 5 "iconoir": "^7.11.0", 6 6 "idb-keyval": "^6.2.1", 7 7 "native-file-system-adapter": "^3.0.1", 8 + "sass": "^1.87.0", 8 9 "spellcaster": "icidasset/spellcaster#fix/hyper-data", 9 10 "throttle-debounce": "^5.0.2", 10 11 "xxh32": "^2.0.5"
+212 -37
src/applets/configurator/storage/output/applet.astro
··· 8 8 Click or tap on one to activate it. 9 9 </p> 10 10 <div id="options"> 11 - <span class="with-icon"> 12 - <i class="iconoir-bonfire"></i> 13 - <small>Just a moment, loading storage options.</small> 14 - </span> 11 + <p> 12 + <span class="with-icon"> 13 + <i class="iconoir-bonfire"></i> 14 + <small>Just a moment, loading storage options.</small> 15 + </span> 16 + </p> 15 17 </div> 18 + <!-- Warning about cross sync --> 19 + <p> 20 + <small> 21 + <mark style="display: inline-block"> 22 + <span class="with-icon"> 23 + <i class="iconoir-warning-triangle"></i> 24 + Data is currently not synced across different storages! 25 + </span> 26 + </mark> 27 + </small> 28 + </p> 16 29 <div id="iframes"></div> 17 30 </main> 18 31 32 + <style lang="scss"> 33 + @use "@picocss/pico/scss/pico" with ( 34 + $enable-responsive-spacings: true 35 + ); 36 + 37 + @use "@picocss/pico/scss/colors/utilities"; 38 + </style> 39 + 19 40 <style> 20 41 @import "../../../../styles/configurator.css"; 21 42 ··· 26 47 .with-icon { 27 48 align-items: center; 28 49 display: inline-flex; 29 - gap: 10px; 50 + gap: 0.75em; 30 51 } 31 52 32 53 [data-storage] { ··· 37 58 <script> 38 59 // @ts-ignore 39 60 import scope from "astro:scope"; 40 - import * as IDB from "idb-keyval"; 41 61 import { type Signal, computed, effect, signal } from "spellcaster/spellcaster.js"; 42 - import { repeat, text } from "spellcaster/hyperscript.js"; 62 + import { type ElementConfigurator, repeat, text } from "spellcaster/hyperscript.js"; 43 63 import { applets } from "@web-applets/sdk"; 44 64 45 65 import { applet, hs } from "../../../../scripts/theme"; 46 66 import { OutputGetter, OutputSetter } from "../../../core/types"; 47 67 48 - const METHODS = ["browser", "device"] as const; 68 + const METHODS = ["browser", "custom", "device"] as const; 49 69 50 70 type Method = (typeof METHODS)[number]; 51 71 type List<M extends Method = Method> = Map<string, ListItem<M>>; ··· 53 73 54 74 const DEFAULT_METHOD: Method = "browser"; 55 75 const LOCALSTORAGE_KEY = "applets/configurator/storage/output/active-storage"; 76 + const CUSTOM_KEY = "applets/configurator/storage/output/custom-applet"; 77 + 78 + const h = ( 79 + tag: string, 80 + props?: Record<string, any> | Signal<Record<string, any>>, 81 + configure?: ElementConfigurator, 82 + ) => hs(tag, scope, props, configure); 56 83 57 84 //////////////////////////////////////////// 58 85 // SETUP 59 86 //////////////////////////////////////////// 60 87 const context = applets.register(); 88 + 61 89 const container = document.getElementById("iframes"); 62 90 if (!container) throw new Error("Missing iframe container"); 63 91 64 92 // TODO: Should migrate + merge data when switching storages 93 + // Or button to do that? 94 + // 95 + // TODO: Pressing ESC button should hide dialog/modal? 65 96 66 97 // Applet connections 67 98 const storage = { ··· 89 120 switch (method) { 90 121 case "browser": 91 122 await storage.output.indexedDB.sendAction("mount"); 123 + setActive(method); 124 + break; 125 + case "custom": 126 + setModalIsOpen(true); 92 127 break; 93 128 case "device": 94 129 await storage.output.nativeFs.sendAction("mount"); 130 + setActive(method); 95 131 break; 96 132 } 97 133 } ··· 101 137 case "browser": 102 138 await storage.output.indexedDB.sendAction("unmount"); 103 139 break; 140 + case "custom": 141 + const applet = await connectToCustomApplet(); 142 + await applet.sendAction("unmount"); 143 + localStorage.removeItem(CUSTOM_KEY); 144 + break; 104 145 case "device": 105 146 await storage.output.nativeFs.sendAction("unmount"); 106 147 break; ··· 108 149 } 109 150 110 151 //////////////////////////////////////////// 111 - // UI 152 + // UI / LIST 112 153 //////////////////////////////////////////// 113 154 const list = computed<List>(() => { 114 155 const a = active(); ··· 132 173 activated: a === "device", 133 174 }, 134 175 ], 176 + [ 177 + `custom-${a === "custom"}`, 178 + { 179 + title: "Custom applet", 180 + icon: "iconoir-globe", 181 + method: "custom", 182 + activated: a === "custom", 183 + }, 184 + ], 135 185 ]); 136 186 }); 137 187 138 188 const Item = (signal: Signal<ListItem<Method>>) => { 139 189 const item = signal(); 140 190 141 - return hs( 191 + const colorClass = item.activated ? "pico-color-jade-500" : "pico-color-grey-500"; 192 + const icon = item.activated ? "iconoir-check-circle-solid" : "iconoir-check-circle"; 193 + 194 + return h( 142 195 "p", 143 - scope, 144 196 { 145 197 onclick: clickHandler(item.method), 146 198 style: "cursor: pointer", 147 199 }, 148 200 [ 149 - hs("span", scope, { className: "with-icon" }, [ 150 - hs("i", scope, { className: item.icon }), 151 - hs("strong", scope, {}, text(item.title)), 201 + h("span", { className: "with-icon" }, [ 202 + h("i", { className: item.icon }), 203 + h("strong", {}, text(item.title)), 152 204 ]), 153 - hs("br", scope), 154 - hs( 155 - "span", 156 - scope, 157 - { 158 - className: 159 - "with-icon " + (item.activated ? "pico-color-jade-500" : "pico-color-grey-500"), 160 - }, 161 - [ 162 - hs("i", scope, { 163 - className: item.activated ? "iconoir-check-circle-solid" : "iconoir-xmark-circle", 164 - }), 165 - hs("span", scope, {}, text(item.activated ? "Activated" : "Deactivated")), 166 - ], 167 - ), 205 + h("br"), 206 + h("span", { className: `with-icon ${colorClass}` }, [ 207 + h("i", { className: icon }), 208 + h("span", {}, text(item.activated ? "Active" : "Select")), 209 + ]), 168 210 ], 169 211 ); 170 212 }; 171 213 172 - const Options = computed(() => hs("div", scope, { id: "options" }, repeat(list, Item))); 173 - document.getElementById("options")?.replaceWith(Options()); 174 - 175 214 function clickHandler(method: Method) { 176 215 return async () => { 177 216 const currentlyActive = active(); 178 - if (currentlyActive === method) return; 217 + if (currentlyActive === method && currentlyActive !== "custom") return; 179 218 if (currentlyActive) unmountStorageMethod(currentlyActive); 180 - 181 219 await mountStorageMethod(method); 182 - setActive(method); 183 220 }; 184 221 } 185 222 223 + const Options = computed(() => { 224 + return h("div", { id: "options" }, repeat(list, Item)); 225 + }); 226 + 227 + // Add to DOM 228 + document.getElementById("options")?.replaceWith(Options()); 229 + 230 + //////////////////////////////////////////// 231 + // UI / CUSTOM APPLET 232 + //////////////////////////////////////////// 233 + type CustomAppletState = "waiting" | "connecting" | { error: string } | "connected"; 234 + 235 + const [modalIsOpen, setModalIsOpen] = signal(false); 236 + const [customState, setCustomState] = signal<CustomAppletState>("waiting"); 237 + 238 + const Modal = () => { 239 + const Header = h("header", {}, [ 240 + h("button", { 241 + ariaLabel: "Close", 242 + rel: "prev", 243 + onclick: close, 244 + }), 245 + h("p", {}, [ 246 + h("strong", {}, [ 247 + h("span", { className: "with-icon" }, [ 248 + h("i", { className: "iconoir-globe" }), 249 + h("span", {}, text("Load a custom applet")), 250 + ]), 251 + ]), 252 + ]), 253 + ]); 254 + 255 + const Content = h("form", { onsubmit: submit }, [ 256 + h("fieldset", { role: "group" }, [ 257 + h("input", { 258 + type: "url", 259 + name: "url", 260 + placeholder: "https://applets.diffuse.sh/storage/output/indexed-db/", 261 + required: true, 262 + value: localStorage.getItem(CUSTOM_KEY) || "", 263 + }), 264 + h("input", { type: "submit", value: "Connect" }), 265 + ]), 266 + h("p", {}, [ 267 + h("small", { className: "with-icon" }, (element) => { 268 + const comp = computed(() => { 269 + const s = customState(); 270 + 271 + if (s === "connecting") { 272 + return [ 273 + h("i", { className: "iconoir-ev-plug-charging" }), 274 + h("span", {}, text("Connecting ...")), 275 + ]; 276 + } else if (typeof s !== "string") { 277 + return [ 278 + h("i", { className: "iconoir-warning-circle" }), 279 + h("span", {}, text(`Error: ${s.error}`)), 280 + ]; 281 + } 282 + 283 + return [h("span", {}, text("Enter the URL to your applet."))]; 284 + }); 285 + 286 + effect(() => { 287 + element.replaceChildren(...comp()); 288 + }); 289 + }), 290 + ]), 291 + ]); 292 + 293 + return h( 294 + "dialog", 295 + computed(() => ({ open: modalIsOpen() })), 296 + [h("article", {}, [Header, Content])], 297 + ); 298 + }; 299 + 300 + // Events 301 + function close() { 302 + setModalIsOpen(false); 303 + } 304 + 305 + async function submit(event: SubmitEvent) { 306 + event.preventDefault(); 307 + 308 + const input: HTMLInputElement | null = (event.target as HTMLFormElement).querySelector( 309 + `input[type="url"]`, 310 + ); 311 + 312 + if (!input) return; 313 + 314 + const url = input.value; 315 + setCustomState("connecting"); 316 + 317 + const apl = await applet(url, { container }).catch((err) => { 318 + setCustomState({ error: "Failed to connect" }); 319 + throw err; 320 + }); 321 + 322 + let missingAction; 323 + 324 + ["get", "put", "mount", "unmount"].forEach((method) => { 325 + if (!apl.manifest.actions[method]) missingAction = method; 326 + }); 327 + 328 + if (missingAction) { 329 + setCustomState({ error: `Applet is missing a required action: "${missingAction}"` }); 330 + return; 331 + } 332 + 333 + localStorage.setItem(CUSTOM_KEY, url); 334 + await apl.sendAction("mount"); 335 + 336 + setActive("custom"); 337 + setModalIsOpen(false); 338 + setCustomState("waiting"); 339 + } 340 + 341 + // 🛠️ 342 + async function connectToCustomApplet() { 343 + const url = localStorage.getItem(CUSTOM_KEY); 344 + if (!url) throw new Error("Missing custom applet URL"); 345 + return await applet(url, { container }); 346 + } 347 + 348 + // Add to DOM 349 + document.querySelector("main")?.appendChild(Modal()); 350 + 186 351 //////////////////////////////////////////// 187 352 // ACTIONS 188 353 //////////////////////////////////////////// ··· 191 356 192 357 switch (active()) { 193 358 case "browser": { 194 - // TODO 359 + // TODO: Ideally promise returns data 195 360 await storage.output.indexedDB.sendAction("get", args); 196 361 data = storage.output.indexedDB.data as Uint8Array | undefined; 197 362 break; 198 363 } 364 + case "custom": 365 + // TODO: Ideally promise returns data 366 + const a = await connectToCustomApplet(); 367 + await a.sendAction("get", args); 368 + data = a.data as Uint8Array | undefined; 369 + break; 199 370 case "device": { 200 - // TODO 371 + // TODO: Ideally promise returns data 201 372 await storage.output.nativeFs.sendAction("get", args); 202 373 data = storage.output.nativeFs.data as Uint8Array | undefined; 203 374 break; ··· 217 388 switch (active()) { 218 389 case "browser": 219 390 await storage.output.indexedDB.sendAction("put", args); 391 + break; 392 + case "custom": 393 + const a = await connectToCustomApplet(); 394 + await a.sendAction("put", args); 220 395 break; 221 396 case "device": 222 397 await storage.output.nativeFs.sendAction("put", args);
+1
src/applets/orchestrator/storage/applet.astro
··· 1 + <!-- TODO: Button to export all user/output data. --><!-- TODO: Button to import data? --> 1 2 <script> 2 3 import { applets } from "@web-applets/sdk"; 3 4
+1
src/layouts/applet.astro
··· 6 6 <head> 7 7 <meta charset="UTF-8" /> 8 8 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 9 + <meta name="color-scheme" content="light dark" /> 9 10 <link rel="manifest" href="manifest.json" /> 10 11 11 12 <title>{title}</title>
+3 -2
src/pages/index.astro
··· 126 126 <p> 127 127 <em 128 128 >These applets interact with the bytes provided by the data storage applets, or provide 129 - to. This processed data can then be passed on to the UI layer and engine applets.</em 129 + to. This processed data can then be passed on to, for example, the UI layer and engine 130 + applets.</em 130 131 > 131 132 </p> 132 133 ··· 145 146 <p> 146 147 <em 147 148 >Input and output managers of the system. Where input is audio files or streams, and 148 - output is derived data such as a music playlist.</em 149 + output is derived data such as a music playlist and your processed input (tracks).</em 149 150 > 150 151 </p> 151 152
+1 -1
src/scripts/theme.ts
··· 1 1 import type { Applet, AppletEvent } from "@web-applets/sdk"; 2 2 3 3 import { applets } from "@web-applets/sdk"; 4 - import { ElementConfigurator, h } from "spellcaster/hyperscript.js"; 4 + import { type ElementConfigurator, h } from "spellcaster/hyperscript.js"; 5 5 import { effect, isSignal, sample, Signal, signal } from "spellcaster/spellcaster.js"; 6 6 import { xxh32 } from "xxh32"; 7 7
-2
src/styles/configurator.css
··· 1 - @import "@picocss/pico/css/pico.css"; 2 - @import "@picocss/pico/css/pico.colors.css"; 3 1 @import "./icons.css";