1
0
forked from Kieran/snort

Service worker precache

Yarn upgrades / cleanup
This commit is contained in:
Kieran 2023-08-26 22:48:15 +01:00
parent 6fae5accde
commit 5cd1ad070a
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
26 changed files with 2885 additions and 4336 deletions

1
.husky/.gitignore vendored
View File

@ -1 +0,0 @@
_

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn workspace @snort/app lint-staged

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1 @@
yarnPath: .yarn/releases/yarn-3.6.1.cjs yarnPath: .yarn/releases/yarn-3.6.3.cjs
npmScopes:
void-cat:
npmRegistryServer: https://git.v0l.io/api/packages/Kieran/npm/

View File

@ -18,9 +18,9 @@
"bracketSameLine": true, "bracketSameLine": true,
"arrowParens": "avoid" "arrowParens": "avoid"
}, },
"packageManager": "yarn@3.6.1", "packageManager": "yarn@3.6.3",
"dependencies": { "dependencies": {
"eslint": "^8.44.0", "eslint": "^8.48.0",
"typescript": "^5.1.6" "typescript": "^5.2.2"
} }
} }

View File

@ -9,5 +9,5 @@ module.exports = {
worker: true, worker: true,
commonjs: true, commonjs: true,
node: false, node: false,
}, }
}; };

View File

@ -31,6 +31,6 @@ declare module "translations/*.json" {
} }
declare module "emojilib" { declare module "emojilib" {
const value: Record<string, Array<string>>; const value: Record<string, string>;
export default value; export default value;
} }

View File

@ -33,6 +33,7 @@
"use-long-press": "^2.0.3", "use-long-press": "^2.0.3",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"workbox-core": "^6.4.2", "workbox-core": "^6.4.2",
"workbox-precaching": "^7.0.0",
"workbox-routing": "^6.4.2", "workbox-routing": "^6.4.2",
"workbox-strategies": "^6.4.2" "workbox-strategies": "^6.4.2"
}, },
@ -70,9 +71,9 @@
"@babel/plugin-syntax-import-assertions": "^7.20.0", "@babel/plugin-syntax-import-assertions": "^7.20.0",
"@babel/preset-env": "^7.21.5", "@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6", "@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.22.5",
"@babel/runtime": "^7.22.6", "@babel/runtime": "^7.22.6",
"@formatjs/cli": "^6.0.1", "@formatjs/cli": "^6.1.3",
"@formatjs/ts-transformer": "^3.13.3",
"@jest/globals": "^29.6.1", "@jest/globals": "^29.6.1",
"@types/debug": "^4.1.8", "@types/debug": "^4.1.8",
"@types/jest": "^29.5.1", "@types/jest": "^29.5.1",
@ -87,31 +88,27 @@
"@webbtc/webln-types": "^1.0.10", "@webbtc/webln-types": "^1.0.10",
"@webpack-cli/generators": "^3.0.4", "@webpack-cli/generators": "^3.0.4",
"@webscopeio/react-textarea-autocomplete": "^4.9.2", "@webscopeio/react-textarea-autocomplete": "^4.9.2",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.3",
"babel-plugin-formatjs": "^10.5.1",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.3", "css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^5.0.0", "css-minimizer-webpack-plugin": "^5.0.0",
"customize-cra": "^1.0.0", "eslint": "^8.48.0",
"eslint": "^8.44.0",
"eslint-plugin-formatjs": "^4.10.1",
"eslint-webpack-plugin": "^4.0.1", "eslint-webpack-plugin": "^4.0.1",
"html-webpack-plugin": "^5.5.1", "html-webpack-plugin": "^5.5.1",
"husky": ">=6",
"jest": "^29.5.0", "jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0", "jest-environment-jsdom": "^29.5.0",
"lint-staged": ">=10",
"mini-css-extract-plugin": "^2.7.5", "mini-css-extract-plugin": "^2.7.5",
"prettier": "2.8.3", "prettier": "2.8.3",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"source-map-loader": "^4.0.1", "source-map-loader": "^4.0.1",
"terser-webpack-plugin": "^5.3.9", "terser-webpack-plugin": "^5.3.9",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"typescript": "^5.1.6", "ts-loader": "^9.4.4",
"webpack": "^5.82.1", "typescript": "^5.2.2",
"webpack": "^5.88.2",
"webpack-bundle-analyzer": "^4.8.0", "webpack-bundle-analyzer": "^4.8.0",
"webpack-cli": "^5.1.1", "webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.0", "webpack-dev-server": "^4.15.1",
"workbox-webpack-plugin": "^6.5.4" "workbox-webpack-plugin": "^6.5.4"
}, },
"lint-staged": { "lint-staged": {

View File

@ -1,4 +1,4 @@
import { EventKind, NostrEvent, RequestBuilder, TaggedRawEvent } from "@snort/system"; import { EventKind, NostrEvent, RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { RefreshFeedCache, TWithCreated } from "./RefreshFeedCache"; import { RefreshFeedCache, TWithCreated } from "./RefreshFeedCache";
import { LoginSession } from "Login"; import { LoginSession } from "Login";
import { unixNow } from "SnortUtils"; import { unixNow } from "SnortUtils";
@ -21,7 +21,7 @@ export class NotificationsCache extends RefreshFeedCache<NostrEvent> {
} }
} }
async onEvent(evs: readonly TaggedRawEvent[]) { async onEvent(evs: readonly TaggedNostrEvent[]) {
const filtered = evs.filter(a => this.#kinds.includes(a.kind) && a.tags.some(b => b[0] === "p")); const filtered = evs.filter(a => this.#kinds.includes(a.kind) && a.tags.some(b => b[0] === "p"));
if (filtered.length > 0) { if (filtered.length > 0) {
await this.bulkSet(filtered); await this.bulkSet(filtered);

View File

@ -1,12 +1,12 @@
import { FeedCache } from "@snort/shared"; import { FeedCache } from "@snort/shared";
import { RequestBuilder, TaggedRawEvent } from "@snort/system"; import { RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { LoginSession } from "Login"; import { LoginSession } from "Login";
export type TWithCreated<T> = T & { created_at: number }; export type TWithCreated<T> = T & { created_at: number };
export abstract class RefreshFeedCache<T> extends FeedCache<TWithCreated<T>> { export abstract class RefreshFeedCache<T> extends FeedCache<TWithCreated<T>> {
abstract buildSub(session: LoginSession, rb: RequestBuilder): void; abstract buildSub(session: LoginSession, rb: RequestBuilder): void;
abstract onEvent(evs: Readonly<Array<TaggedRawEvent>>): void; abstract onEvent(evs: Readonly<Array<TaggedNostrEvent>>): void;
/** /**
* Get latest event * Get latest event

View File

@ -1,19 +0,0 @@
import Hls from "hls.js";
import { HTMLProps, useEffect, useRef } from "react";
export function LiveVideoPlayer(props: HTMLProps<HTMLVideoElement> & { stream: string }) {
const video = useRef<HTMLVideoElement>(null);
useEffect(() => {
if (props.stream && video.current && !video.current.src && Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(props.stream);
hls.attachMedia(video.current);
return () => hls.destroy();
}
}, [video, props]);
return (
<div>
<video ref={video} {...props} controls={true} />
</div>
);
}

View File

@ -1,5 +1,5 @@
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { HexKey, Lists, NostrPrefix, TaggedRawEvent, encodeTLV } from "@snort/system"; import { HexKey, Lists, NostrPrefix, TaggedNostrEvent, encodeTLV } from "@snort/system";
import { Menu, MenuItem } from "@szhsin/react-menu"; import { Menu, MenuItem } from "@szhsin/react-menu";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
@ -26,7 +26,7 @@ export interface NoteTranslation {
} }
interface NosteContextMenuProps { interface NosteContextMenuProps {
ev: TaggedRawEvent; ev: TaggedNostrEvent;
setShowReactions(b: boolean): void; setShowReactions(b: boolean): void;
react(content: string): Promise<void>; react(content: string): Promise<void>;
onTranslated?: (t: NoteTranslation) => void; onTranslated?: (t: NoteTranslation) => void;

View File

@ -33,7 +33,7 @@ const UserItem = (metadata: MetadataCache) => {
return ( return (
<div key={pubkey} className="user-item"> <div key={pubkey} className="user-item">
<div className="user-picture"> <div className="user-picture">
<Avatar user={metadata} /> <Avatar pubkey={pubkey} user={metadata} />
</div> </div>
<div className="user-details"> <div className="user-details">
<strong>{display_name || rest.name}</strong> <strong>{display_name || rest.name}</strong>

View File

@ -145,7 +145,7 @@ function ProfileDmActions({ id }: { id: string }) {
const blocked = isBlocked(pubkey); const blocked = isBlocked(pubkey);
return ( return (
<> <>
<Avatar user={profile} size={210} /> <Avatar pubkey={pubkey} user={profile} size={210} />
<h2>{getDisplayName(profile, pubkey)}</h2> <h2>{getDisplayName(profile, pubkey)}</h2>
<p> <p>
<Text content={truncAbout(profile?.about) ?? ""} tags={[]} creator={pubkey} disableMedia={true} depth={0} /> <Text content={truncAbout(profile?.about) ?? ""} tags={[]} creator={pubkey} disableMedia={true} depth={0} />

View File

@ -39,7 +39,8 @@ const PreferencesPage = () => {
useEffect(() => { useEffect(() => {
(async () => { (async () => {
setEmoji((await searchEmoji("")).map(a => ({ name: a.name, char: a.char }))); const allEmoji = await searchEmoji("");
setEmoji(allEmoji.map(a => ({ name: a.name, char: a.char })));
})(); })();
}, []); }, []);

View File

@ -9,7 +9,7 @@ import {
SystemInterface, SystemInterface,
TLVEntry, TLVEntry,
TLVEntryType, TLVEntryType,
TaggedRawEvent, TaggedNostrEvent,
UserMetadata, UserMetadata,
encodeTLVEntries, encodeTLVEntries,
} from "@snort/system"; } from "@snort/system";
@ -61,7 +61,7 @@ export interface ChatSystem {
* Create a request for this system to get updates * Create a request for this system to get updates
*/ */
subscription(id: string): RequestBuilder | undefined; subscription(id: string): RequestBuilder | undefined;
onEvent(evs: readonly TaggedRawEvent[]): Promise<void> | void; onEvent(evs: readonly TaggedNostrEvent[]): Promise<void> | void;
listChats(pk: string): Array<Chat>; listChats(pk: string): Array<Chat>;
} }

View File

@ -1,5 +1,5 @@
import { ExternalStore, FeedCache, dedupe } from "@snort/shared"; import { ExternalStore, FeedCache, dedupe } from "@snort/shared";
import { RequestBuilder, NostrEvent, EventKind, SystemInterface, TaggedRawEvent } from "@snort/system"; import { RequestBuilder, NostrEvent, EventKind, SystemInterface, TaggedNostrEvent } from "@snort/system";
import { unwrap } from "SnortUtils"; import { unwrap } from "SnortUtils";
import { Chat, ChatSystem, ChatType, lastReadInChat } from "chat"; import { Chat, ChatSystem, ChatType, lastReadInChat } from "chat";
@ -31,7 +31,7 @@ export class Nip29ChatSystem extends ExternalStore<Array<Chat>> implements ChatS
return rb; return rb;
} }
async onEvent(evs: readonly TaggedRawEvent[]) { async onEvent(evs: readonly TaggedNostrEvent[]) {
const msg = evs.filter(a => a.kind === EventKind.SimpleChatMessage && a.tags.some(b => b[0] === "g")); const msg = evs.filter(a => a.kind === EventKind.SimpleChatMessage && a.tags.some(b => b[0] === "g"));
if (msg.length > 0) { if (msg.length > 0) {
await this.#cache.bulkSet(msg); await this.#cache.bulkSet(msg);

View File

@ -7,6 +7,7 @@ import * as ReactDOM from "react-dom/client";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { EventPublisher, NostrSystem, ProfileLoaderService, Nip7Signer, PowWorker } from "@snort/system"; import { EventPublisher, NostrSystem, ProfileLoaderService, Nip7Signer, PowWorker } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import * as serviceWorkerRegistration from "serviceWorkerRegistration"; import * as serviceWorkerRegistration from "serviceWorkerRegistration";
import { IntlProvider } from "IntlProvider"; import { IntlProvider } from "IntlProvider";
@ -34,7 +35,6 @@ import DebugPage from "Pages/Debug";
import { db } from "Db"; import { db } from "Db";
import { preload, RelayMetrics, UserCache, UserRelays } from "Cache"; import { preload, RelayMetrics, UserCache, UserRelays } from "Cache";
import { LoginStore } from "Login"; import { LoginStore } from "Login";
import { SnortContext } from "@snort/system-react";
/** /**
* Singleton nostr system * Singleton nostr system
@ -66,9 +66,6 @@ export const ProfileLoader = new ProfileLoaderService(System, UserCache);
*/ */
export const DefaultPowWorker = new PowWorker("/pow.js"); export const DefaultPowWorker = new PowWorker("/pow.js");
// @ts-expect-error Setting webpack nonce
window.__webpack_nonce__ = "ZmlhdGphZiBzYWlkIHNub3J0LnNvY2lhbCBpcyBwcmV0dHkgZ29vZCwgd2UgbWFkZSBpdCE=";
serviceWorkerRegistration.register(); serviceWorkerRegistration.register();
export const router = createBrowserRouter([ export const router = createBrowserRouter([

View File

@ -1,22 +1,14 @@
/// <reference lib="webworker" /> /// <reference lib="webworker" />
declare const self: ServiceWorkerGlobalScope; declare const self: ServiceWorkerGlobalScope & {
__WB_MANIFEST: (string | PrecacheEntry)[]
};
import { clientsClaim } from "workbox-core"; import { clientsClaim } from "workbox-core";
import { registerRoute } from "workbox-routing"; import {PrecacheEntry, precacheAndRoute} from 'workbox-precaching';
import { CacheFirst } from "workbox-strategies";
precacheAndRoute(self.__WB_MANIFEST);
clientsClaim(); clientsClaim();
const staticTypes = ["image", "video", "audio", "script", "style", "font"];
const paths = ["/"];
registerRoute(
({ request, url }) =>
url.origin === self.location.origin && (staticTypes.includes(request.destination) || paths.includes(url.pathname)),
new CacheFirst({
cacheName: "static-content",
})
);
self.addEventListener("message", event => { self.addEventListener("message", event => {
if (event.data && event.data.type === "SKIP_WAITING") { if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting(); self.skipWaiting();

View File

@ -5,6 +5,7 @@
"module": "es2020", "module": "es2020",
"jsx": "react-jsx", "jsx": "react-jsx",
"moduleResolution": "node", "moduleResolution": "node",
"sourceMap": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"strict": true, "strict": true,
"skipLibCheck": true, "skipLibCheck": true,

View File

@ -7,16 +7,14 @@ const ESLintPlugin = require("eslint-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin"); const CopyPlugin = require("copy-webpack-plugin");
const WorkboxPlugin = require('workbox-webpack-plugin');
const IntlTsTransformer =require('@formatjs/ts-transformer');
const isProduction = process.env.NODE_ENV == "production"; const isProduction = process.env.NODE_ENV == "production";
const config = { const config = {
entry: { entry: {
main: "./src/index.tsx", main: "./src/index.tsx",
sw: {
import: "./src/service-worker.ts",
filename: "service-worker.js",
},
pow: { pow: {
import: require.resolve("@snort/system/dist/pow-worker.js"), import: require.resolve("@snort/system/dist/pow-worker.js"),
filename: "pow.js", filename: "pow.js",
@ -49,17 +47,20 @@ const config = {
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: "public/index.html", template: "public/index.html",
favicon: "public/favicon.ico", favicon: "public/favicon.ico",
excludeChunks: ["sw", "pow"], excludeChunks: ["pow"],
}), }),
new ESLintPlugin({ new ESLintPlugin({
extensions: ["js", "mjs", "jsx", "ts", "tsx"], extensions: ["js", "mjs", "jsx", "ts", "tsx"],
eslintPath: require.resolve("eslint"), eslintPath: require.resolve("eslint"),
failOnError: !isProduction, failOnError: true,
cache: true, cache: true,
}), }),
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: isProduction ? "[name].[chunkhash].css" : "[name].css", filename: isProduction ? "[name].[chunkhash].css" : "[name].css",
}), }),
new WorkboxPlugin.InjectManifest({
swSrc: "./src/service-worker.ts"
}),
], ],
module: { module: {
rules: [ rules: [
@ -68,9 +69,19 @@ const config = {
exclude: /@babel(?:\/|\\{1,2})runtime/, exclude: /@babel(?:\/|\\{1,2})runtime/,
test: /\.(js|mjs|jsx|ts|tsx|css)$/, test: /\.(js|mjs|jsx|ts|tsx|css)$/,
loader: require.resolve("source-map-loader"), loader: require.resolve("source-map-loader"),
options: {
filterSourceMappingUrl: (url, resourcePath) => {
// disable warning for missing @scure-bip39 sourcemaps
if (/.*\/.yarn\/cache\/@scure-bip39.*/.test(resourcePath)) {
return false
}
return true
}
}
}, },
{ {
test: /\.tsx?$/i, test: /\.tsx?$/i,
exclude: ["/node_modules/"],
use: [ use: [
{ {
loader: require.resolve("babel-loader"), loader: require.resolve("babel-loader"),
@ -78,23 +89,27 @@ const config = {
babelrc: false, babelrc: false,
configFile: false, configFile: false,
presets: [ presets: [
"@babel/preset-env", ["@babel/preset-env"],
["@babel/preset-react", { runtime: "automatic" }], ["@babel/preset-react", { runtime: "automatic" }],
"@babel/preset-typescript",
],
plugins: [
[
"formatjs",
{
idInterpolationPattern: "[sha512:contenthash:base64:6]",
ast: true,
},
],
], ],
}, },
}, },
{
loader: require.resolve("ts-loader"),
options: {
getCustomTransformers() {
return {
before: [
IntlTsTransformer.transform({
overrideIdFn: '[sha512:contenthash:base64:6]',
ast: true
}),
]
};
},
}
}
], ],
exclude: ["/node_modules/"],
}, },
{ {
test: /\.css$/i, test: /\.css$/i,
@ -107,12 +122,9 @@ const config = {
], ],
}, },
optimization: { optimization: {
usedExports: true,
chunkIds: "deterministic", chunkIds: "deterministic",
minimize: isProduction, minimize: isProduction,
minimizer: [ minimizer: [
"...",
// same as https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js
new TerserPlugin({ new TerserPlugin({
terserOptions: { terserOptions: {
parse: { parse: {
@ -128,12 +140,7 @@ const config = {
safari10: true, safari10: true,
}, },
keep_classnames: isProduction, keep_classnames: isProduction,
keep_fnames: isProduction, keep_fnames: isProduction
output: {
ecma: 5,
comments: false,
ascii_only: true,
},
}, },
}), }),
new CssMinimizerPlugin(), new CssMinimizerPlugin(),
@ -143,6 +150,7 @@ const config = {
aliasFields: ["browser"], aliasFields: ["browser"],
extensions: ["...", ".tsx", ".ts", ".jsx", ".js"], extensions: ["...", ".tsx", ".ts", ".jsx", ".js"],
modules: ["...", __dirname, path.resolve(__dirname, "src")], modules: ["...", __dirname, path.resolve(__dirname, "src")],
fallback: { crypto: false }
}, },
}; };

View File

@ -11,15 +11,15 @@
"build": "rm -rf dist && tsc" "build": "rm -rf dist && tsc"
}, },
"dependencies": { "dependencies": {
"@noble/curves": "^1.1.0", "@noble/curves": "^1.2.0",
"@noble/hashes": "^1.3.1", "@noble/hashes": "^1.3.2",
"@scure/base": "^1.1.1", "@scure/base": "^1.1.2",
"debug": "^4.3.4", "debug": "^4.3.4",
"dexie": "^3.2.4", "dexie": "^3.2.4",
"light-bolt11-decoder": "^3.0.0" "light-bolt11-decoder": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/debug": "^4.1.8", "@types/debug": "^4.1.8",
"typescript": "^5.1.6" "typescript": "^5.2.2"
} }
} }

View File

@ -21,6 +21,6 @@
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.14", "@types/react": "^18.2.14",
"typescript": "^5.1.6" "typescript": "^5.2.2"
} }
} }

View File

@ -24,12 +24,12 @@
"jest": "^29.5.0", "jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0", "jest-environment-jsdom": "^29.5.0",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"typescript": "^5.1.6" "typescript": "^5.2.2"
}, },
"dependencies": { "dependencies": {
"@noble/curves": "^1.0.0", "@noble/curves": "^1.2.0",
"@noble/hashes": "^1.3.1", "@noble/hashes": "^1.3.2",
"@scure/base": "^1.1.1", "@scure/base": "^1.1.2",
"@snort/shared": "^1.0.4", "@snort/shared": "^1.0.4",
"@stablelib/xchacha20": "^1.0.1", "@stablelib/xchacha20": "^1.0.1",
"debug": "^4.3.4", "debug": "^4.3.4",

6622
yarn.lock

File diff suppressed because it is too large Load Diff