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]}]