diff --git a/package.json b/package.json index ca26487..638b405 100644 --- a/package.json +++ b/package.json @@ -15,50 +15,50 @@ }, "devDependencies": { "@capacitor/assets": "^3.0.5", - "@eslint/js": "^9.26.0", - "@sentry/cli": "^2.40.0", - "@sveltejs/kit": "^2.5.27", - "@sveltejs/vite-plugin-svelte": "^4.0.0", - "@types/eslint": "^9.6.0", - "autoprefixer": "^10.4.19", + "@eslint/js": "^9.37.0", + "@sentry/cli": "^2.56.1", + "@sveltejs/kit": "^2.46.5", + "@sveltejs/vite-plugin-svelte": "^4.0.4", + "@types/eslint": "^9.6.1", + "autoprefixer": "^10.4.21", "classnames": "^2.5.1", - "eslint": "^9.0.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.45.1", - "globals": "^15.0.0", - "postcss": "^8.4.40", - "prettier": "^3.1.1", - "prettier-plugin-svelte": "^3.2.6", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", - "tailwindcss": "^3.4.7", - "typescript": "^5.5.0", - "typescript-eslint": "^8.0.0", - "vite": "^5.4.4" + "eslint": "^9.37.0", + "eslint-config-prettier": "^9.1.2", + "eslint-plugin-svelte": "^2.46.1", + "globals": "^15.15.0", + "postcss": "^8.5.6", + "prettier": "^3.6.2", + "prettier-plugin-svelte": "^3.4.0", + "svelte": "^5.39.12", + "svelte-check": "^4.3.3", + "tailwindcss": "^3.4.18", + "typescript": "^5.9.3", + "typescript-eslint": "^8.46.1", + "vite": "^5.4.20" }, "type": "module", "dependencies": { "@capacitor-community/safe-area": "7.0.0-alpha.1", - "@capacitor/android": "^7.0.0", - "@capacitor/app": "^7.0.0", - "@capacitor/cli": "^7.0.0", - "@capacitor/core": "^7.0.1", - "@capacitor/filesystem": "^7.0.0", - "@capacitor/ios": "^7.0.0", - "@capacitor/keyboard": "^7.0.0", + "@capacitor/android": "^7.4.3", + "@capacitor/app": "^7.1.0", + "@capacitor/cli": "^7.4.3", + "@capacitor/core": "^7.4.3", + "@capacitor/filesystem": "^7.1.4", + "@capacitor/ios": "^7.4.3", + "@capacitor/keyboard": "^7.0.3", "@capacitor/preferences": "^7.0.2", - "@capacitor/push-notifications": "^7.0.1", + "@capacitor/push-notifications": "^7.0.3", "@capawesome/capacitor-android-dark-mode-support": "^7.0.0", "@capawesome/capacitor-badge": "^7.0.1", - "@getalby/sdk": "^5.1.0", + "@getalby/sdk": "^5.1.2", "@poppanator/sveltekit-svg": "^4.2.1", - "@sentry/browser": "^8.35.0", - "@sveltejs/adapter-static": "^3.0.4", - "@tiptap/core": "^2.12.0", + "@sentry/browser": "^8.55.0", + "@sveltejs/adapter-static": "^3.0.10", + "@tiptap/core": "^2.26.3", "@types/qrcode": "^1.5.5", "@types/throttle-debounce": "^5.0.2", "@vite-pwa/assets-generator": "^0.2.6", - "@vite-pwa/sveltekit": "^0.6.6", + "@vite-pwa/sveltekit": "^0.6.8", "@welshman/app": "^0.5.2", "@welshman/content": "^0.5.2", "@welshman/editor": "^0.5.2", @@ -71,16 +71,16 @@ "@welshman/store": "^0.5.2", "@welshman/util": "^0.5.2", "compressorjs": "^1.2.1", - "daisyui": "^4.12.10", - "date-picker-svelte": "^2.13.0", - "dotenv": "^16.4.5", - "emoji-picker-element": "^1.22.8", - "fuse.js": "^7.0.0", - "husky": "^9.1.6", - "idb": "^8.0.0", + "daisyui": "^4.12.24", + "date-picker-svelte": "^2.16.0", + "dotenv": "^16.6.1", + "emoji-picker-element": "^1.27.0", + "fuse.js": "^7.1.0", + "husky": "^9.1.7", + "idb": "^8.0.3", "nostr-signer-capacitor-plugin": "^0.0.4", - "nostr-tools": "^2.14.2", - "prettier-plugin-tailwindcss": "^0.6.5", + "nostr-tools": "^2.17.0", + "prettier-plugin-tailwindcss": "^0.6.14", "qr-scanner": "^1.4.2", "qrcode": "^1.5.4", "throttle-debounce": "^5.0.2", @@ -93,6 +93,19 @@ ], "onlyBuiltDependencies": [ "sharp" - ] + ], + "overrides": { + "@welshman/app": "link:../welshman/packages/app", + "@welshman/content": "link:../welshman/packages/content", + "@welshman/editor": "link:../welshman/packages/editor", + "@welshman/feeds": "link:../welshman/packages/feeds", + "@welshman/lib": "link:../welshman/packages/lib", + "@welshman/net": "link:../welshman/packages/net", + "@welshman/relay": "link:../welshman/packages/relay", + "@welshman/router": "link:../welshman/packages/router", + "@welshman/signer": "link:../welshman/packages/signer", + "@welshman/store": "link:../welshman/packages/store", + "@welshman/util": "link:../welshman/packages/util" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e54173..b4771ab 100644 Binary files a/pnpm-lock.yaml and b/pnpm-lock.yaml differ diff --git a/src/app/components/ContentLinkBlockImage.svelte b/src/app/components/ContentLinkBlockImage.svelte index 26addce..635d436 100644 --- a/src/app/components/ContentLinkBlockImage.svelte +++ b/src/app/components/ContentLinkBlockImage.svelte @@ -56,7 +56,7 @@ const ciphertext = new Uint8Array(await response.arrayBuffer()) const decryptedData = await decryptFile({ciphertext, key, nonce, algorithm}) - src = URL.createObjectURL(new Blob([decryptedData])) + src = URL.createObjectURL(new Blob([new Uint8Array(decryptedData)])) } } else { src = url diff --git a/src/app/core/commands.ts b/src/app/core/commands.ts index 27928f5..fa57d16 100644 --- a/src/app/core/commands.ts +++ b/src/app/core/commands.ts @@ -744,7 +744,7 @@ export const uploadFile = async (file: File, options: UploadFileOptions = {}) => ["encryption-algorithm", algorithm], ) - file = new File([new Blob([ciphertext])], name, { + file = new File([new Uint8Array(ciphertext)], name, { type: "application/octet-stream", }) } diff --git a/src/app/util/routes.ts b/src/app/util/routes.ts index 117af85..acc7818 100644 --- a/src/app/util/routes.ts +++ b/src/app/util/routes.ts @@ -64,7 +64,7 @@ export const getPrimaryNavItemIndex = ($page: Page) => { case "discover": return urls.length + 2 case "spaces": { - const routeUrl = decodeRelay($page.params.relay) + const routeUrl = decodeRelay($page.params.relay || "") return urls.findIndex(url => url === routeUrl) + 1 } diff --git a/src/lib/components/PageBar.svelte b/src/lib/components/PageBar.svelte index c9bf333..7abe20a 100644 --- a/src/lib/components/PageBar.svelte +++ b/src/lib/components/PageBar.svelte @@ -13,7 +13,7 @@
+ class="flex min-h-12 items-center justify-between gap-4 rounded-xl bg-base-100 px-4 shadow-xl">
{@render props.icon?.()} {@render props.title?.()} diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 3b57e22..b38a714 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -1,4 +1,4 @@ -import {flatten, identity, groupBy} from "@welshman/lib" +import {flatten, noop, identity, groupBy} from "@welshman/lib" import {type StorageProvider} from "@welshman/store" import {Preferences} from "@capacitor/preferences" import {Encoding, Filesystem, Directory} from "@capacitor/filesystem" @@ -38,7 +38,7 @@ export type CollectionOptions = { } export class Collection { - p = Promise.resolve() + #promises = new Map>() constructor(readonly options: CollectionOptions) {} @@ -58,36 +58,38 @@ export class Collection { ) } - #then = async (f: () => Promise) => { - this.p = this.p.then(f).catch(e => { - console.error(e) - }) + #then = (shard: string, f: () => Promise) => { + const oldPromise = this.#promises.get(shard) || Promise.resolve() + const newPromise = oldPromise.then(f) - await this.p + this.#promises.set(shard, newPromise) + + return newPromise } #path = (shard: string) => `collection_${this.options.table}_${shard}.json` - getShard = async (shard: string): Promise => { - try { - const file = await Filesystem.readFile({ - path: this.#path(shard), - directory: Directory.Data, - encoding: Encoding.UTF8, - }) + getShard = (shard: string): Promise => + this.#then(shard, async () => { + try { + const file = await Filesystem.readFile({ + path: this.#path(shard), + directory: Directory.Data, + encoding: Encoding.UTF8, + }) - // Speed things up by parsing only once - return JSON.parse("[" + file.data.toString().split("\n").filter(identity).join(",") + "]") - } catch (err) { - // file doesn't exist, or isn't valid json - return [] - } - } + // Speed things up by parsing only once + return JSON.parse("[" + file.data.toString().split("\n").filter(identity).join(",") + "]") + } catch (err) { + // file doesn't exist, or isn't valid json + return [] + } + }) get = async (): Promise => flatten(await Promise.all(this.options.shards.map(this.getShard))) setShard = (shard: string, items: T[]) => - this.#then(async () => { + this.#then(shard, async () => { await Filesystem.writeFile({ path: this.#path(shard), directory: Directory.Data, @@ -104,7 +106,7 @@ export class Collection { ) addToShard = (shard: string, items: T[]) => - this.#then(async () => { + this.#then(shard, async () => { await Filesystem.appendFile({ path: this.#path(shard), directory: Directory.Data, diff --git a/src/routes/[bech32]/+page.svelte b/src/routes/[bech32]/+page.svelte index 3cc3f37..d7597dc 100644 --- a/src/routes/[bech32]/+page.svelte +++ b/src/routes/[bech32]/+page.svelte @@ -1,6 +1,7 @@ - + diff --git a/src/routes/spaces/[relay]/+layout.svelte b/src/routes/spaces/[relay]/+layout.svelte index 4c5d541..e4705a3 100644 --- a/src/routes/spaces/[relay]/+layout.svelte +++ b/src/routes/spaces/[relay]/+layout.svelte @@ -31,7 +31,7 @@ const {children}: Props = $props() - const url = decodeRelay($page.params.relay) + const url = decodeRelay($page.params.relay!) const rooms = Array.from($userRoomsByUrl.get(url) || []) diff --git a/src/routes/spaces/[relay]/+page.svelte b/src/routes/spaces/[relay]/+page.svelte index 46282b0..9861553 100644 --- a/src/routes/spaces/[relay]/+page.svelte +++ b/src/routes/spaces/[relay]/+page.svelte @@ -26,7 +26,7 @@ import {makeChatPath} from "@app/util/routes" import {pushModal} from "@app/util/modal" - const url = decodeRelay($page.params.relay) + const url = decodeRelay($page.params.relay!) const relay = deriveRelay(url) const joinSpace = () => pushModal(SpaceJoin, {url}) diff --git a/src/routes/spaces/[relay]/[room]/+page.svelte b/src/routes/spaces/[relay]/[room]/+page.svelte index 6f46b97..7990fdf 100644 --- a/src/routes/spaces/[relay]/[room]/+page.svelte +++ b/src/routes/spaces/[relay]/[room]/+page.svelte @@ -5,6 +5,7 @@ import {page} from "$app/stores" import type {Readable} from "svelte/store" import {now, formatTimestampAsDate} from "@welshman/lib" + import type {MakeNonOptional} from "@welshman/lib" import {request} from "@welshman/net" import type {TrustedEvent, EventContent} from "@welshman/util" import { @@ -57,10 +58,10 @@ import {popKey} from "@lib/implicit" import {pushToast} from "@app/util/toast" - const {room} = $page.params + const {room, relay} = $page.params as MakeNonOptional const mounted = now() const lastChecked = $checked[$page.url.pathname] - const url = decodeRelay($page.params.relay) + const url = decodeRelay(relay) const channel = deriveChannel(url, room) const filter = {kinds: [MESSAGE], "#h": [room]} const isFavorite = $derived($userRoomsByUrl.get(url)?.has(room)) diff --git a/src/routes/spaces/[relay]/calendar/+page.svelte b/src/routes/spaces/[relay]/calendar/+page.svelte index 3ed881e..8cdf3fb 100644 --- a/src/routes/spaces/[relay]/calendar/+page.svelte +++ b/src/routes/spaces/[relay]/calendar/+page.svelte @@ -23,7 +23,7 @@ import {makeCalendarFeed} from "@app/core/requests" import {setChecked} from "@app/util/notifications" - const url = decodeRelay($page.params.relay) + const url = decodeRelay($page.params.relay!) const makeEvent = () => pushModal(CalendarEventCreate, {url}) diff --git a/src/routes/spaces/[relay]/calendar/[id]/+page.svelte b/src/routes/spaces/[relay]/calendar/[id]/+page.svelte index 91d78da..f104e5f 100644 --- a/src/routes/spaces/[relay]/calendar/[id]/+page.svelte +++ b/src/routes/spaces/[relay]/calendar/[id]/+page.svelte @@ -2,6 +2,7 @@ import {onMount} from "svelte" import {page} from "$app/stores" import {sortBy, sleep} from "@welshman/lib" + import type {MakeNonOptional} from "@welshman/lib" import {COMMENT, getTagValue} from "@welshman/util" import {request} from "@welshman/net" import {repository} from "@welshman/app" @@ -25,7 +26,7 @@ import {deriveEvent, decodeRelay} from "@app/core/state" import {setChecked} from "@app/util/notifications" - const {relay, id} = $page.params + const {relay, id} = $page.params as MakeNonOptional const url = decodeRelay(relay) const event = deriveEvent(id) const filters = [{kinds: [COMMENT], "#E": [id]}] diff --git a/src/routes/spaces/[relay]/chat/+page.svelte b/src/routes/spaces/[relay]/chat/+page.svelte index 0a8096a..c070b6a 100644 --- a/src/routes/spaces/[relay]/chat/+page.svelte +++ b/src/routes/spaces/[relay]/chat/+page.svelte @@ -36,7 +36,7 @@ const mounted = now() const lastChecked = $checked[$page.url.pathname] - const url = decodeRelay($page.params.relay) + const url = decodeRelay($page.params.relay!) const filter = {kinds: [MESSAGE]} const shouldProtect = canEnforceNip70(url) diff --git a/src/routes/spaces/[relay]/goals/+page.svelte b/src/routes/spaces/[relay]/goals/+page.svelte index c7b097d..0e9a69c 100644 --- a/src/routes/spaces/[relay]/goals/+page.svelte +++ b/src/routes/spaces/[relay]/goals/+page.svelte @@ -20,7 +20,7 @@ import {makeFeed} from "@app/core/requests" import {pushModal} from "@app/util/modal" - const url = decodeRelay($page.params.relay) + const url = decodeRelay($page.params.relay!) const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes)) const goals: TrustedEvent[] = $state([]) const comments: TrustedEvent[] = $state([]) diff --git a/src/routes/spaces/[relay]/goals/[id]/+page.svelte b/src/routes/spaces/[relay]/goals/[id]/+page.svelte index 6d349f9..b7a5bd4 100644 --- a/src/routes/spaces/[relay]/goals/[id]/+page.svelte +++ b/src/routes/spaces/[relay]/goals/[id]/+page.svelte @@ -2,6 +2,7 @@ import {onMount} from "svelte" import {page} from "$app/stores" import {sortBy, sleep} from "@welshman/lib" + import type {MakeNonOptional} from "@welshman/lib" import {COMMENT, getTagValue} from "@welshman/util" import {repository} from "@welshman/app" import {request} from "@welshman/net" @@ -24,7 +25,7 @@ import {deriveEvent, decodeRelay} from "@app/core/state" import {setChecked} from "@app/util/notifications" - const {relay, id} = $page.params + const {relay, id} = $page.params as MakeNonOptional const url = decodeRelay(relay) const event = deriveEvent(id) const filters = [{kinds: [COMMENT], "#E": [id]}] diff --git a/src/routes/spaces/[relay]/threads/+page.svelte b/src/routes/spaces/[relay]/threads/+page.svelte index e93dcaa..053f58d 100644 --- a/src/routes/spaces/[relay]/threads/+page.svelte +++ b/src/routes/spaces/[relay]/threads/+page.svelte @@ -21,7 +21,7 @@ import {makeFeed} from "@app/core/requests" import {pushModal} from "@app/util/modal" - const url = decodeRelay($page.params.relay) + const url = decodeRelay($page.params.relay!) const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes)) const threads: TrustedEvent[] = $state([]) const comments: TrustedEvent[] = $state([]) diff --git a/src/routes/spaces/[relay]/threads/[id]/+page.svelte b/src/routes/spaces/[relay]/threads/[id]/+page.svelte index 28f5c39..bbd19d8 100644 --- a/src/routes/spaces/[relay]/threads/[id]/+page.svelte +++ b/src/routes/spaces/[relay]/threads/[id]/+page.svelte @@ -2,6 +2,7 @@ import {onMount} from "svelte" import {page} from "$app/stores" import {sortBy, sleep} from "@welshman/lib" + import type {MakeNonOptional} from "@welshman/lib" import {COMMENT, getTagValue} from "@welshman/util" import {repository} from "@welshman/app" import {request} from "@welshman/net" @@ -23,7 +24,7 @@ import {deriveEvent, decodeRelay} from "@app/core/state" import {setChecked} from "@app/util/notifications" - const {relay, id} = $page.params + const {relay, id} = $page.params as MakeNonOptional const url = decodeRelay(relay) const event = deriveEvent(id) const filters = [{kinds: [COMMENT], "#E": [id]}]