Compare commits

..

13 Commits

Author SHA1 Message Date
Jon Staab c691400630 Update version 2026-03-09 16:46:47 -07:00
Jon Staab 6acbfb1181 Fix classified images 2026-03-06 15:01:15 -08:00
Jon Staab 5f7474140f Add StringMultiInput for OTPs 2026-03-06 15:00:17 -08:00
Jon Staab c56d6f4c75 Fix up edit 2026-03-06 14:46:04 -08:00
Jon Staab c874ae50e5 Handle prompt-with-rationale 2026-03-06 14:40:58 -08:00
Jon Staab 25e7cc97f9 Handle profile update errors 2026-03-06 14:18:05 -08:00
Jon Staab 837e4bc537 Move from .env to .env.local 2026-03-06 13:58:03 -08:00
Jon Staab 65fa93d853 Tweak some error messages 2026-03-06 13:37:16 -08:00
Jon Staab 28b0276f17 Refactor pomade, add password reset flow 2026-03-06 11:48:57 -08:00
Jon Staab 10ac15f8a2 Add LogInSelect step for disambiguating pomade sessions 2026-03-06 09:38:36 -08:00
Jon Staab a45633e214 Update pomade implementation 2026-03-05 17:12:40 -08:00
mplorentz a42ba5446a Fix a docker rebuild issue (#88)
The Docker build wasn't making use of docker's cache because the .git directory was being copied into the build context. This means that even if the app did not change, if anything in git changed then docker would rebuild the entire app.

This excludes the .git folder from the docker build, instead relying on the user to pass in the build hash at build time. Which is annoying but I don't think there's a better way around it.

This was annoying me because I am deploying a self-hosted version of flotilla from a git branch via ansible and it was rebuilding flotilla every time.

Co-authored-by: mplorentz <mplorentz@noreply.gitea.coracle.social>
Reviewed-on: #88
Co-authored-by: Matt Lorentz <mplorentz@noreply.coracle.social>
Co-committed-by: Matt Lorentz <mplorentz@noreply.coracle.social>
2026-03-03 19:52:22 +00:00
Jon Staab ccfe1bded5 Bring back some notification badges 2026-02-27 12:25:16 -08:00
42 changed files with 1206 additions and 399 deletions
+1 -2
View File
@@ -7,7 +7,6 @@ build
.git
.gitignore
# Env files (use build args instead; .env.template is copied for defaults)
.env
# Env files (keep .env for build; exclude local overrides)
.env.local
.env.*.local
+1
View File
@@ -1,5 +1,6 @@
# Env
.env
.env.local
# Vite
vite.config.js.timestamp-*
+26
View File
@@ -1,5 +1,31 @@
# Changelog
# 1.6.5
* Attempt to fix permission grant for notifications
* Make sync logic more robust
* Add unban/unallow support
* Improve support for downloading/opening protected images
* Add manual send/receive to wallet
* Show wallet status when wallet is unreachable
* Update nostr signer capacitor plugin
* Fix some safe area insets
* Update NIP 55 signer plugin (fixes Primal login)
* Refine space join dialogs and discover page
* Reopen the last DM that was open when navigating back to chat
* Get rid of ChatEnable interstitial
* Enable auth for relays we're publishing to
* Drag and drop space icons
* Add better muting support
* Add back button to settings menu
* Add page titles
* Improve scroll to event behavior
* Add in-memory search to rooms
* Fix editing messages with html tags
* Fix DM media detection
* Clean up reporting dialogs
* Improve room detail
# 1.6.4
* Clean up modal design
+13 -12
View File
@@ -1,30 +1,31 @@
# Pass the build hash as an argument:
# docker build --build-arg VITE_BUILD_HASH=$(git rev-parse --short HEAD) -t flotilla .
# Stage 1: Build
# Uses .env from build context for config (logo, branding, etc.)
# Optional: docker build --build-arg VITE_BUILD_HASH=$(git rev-parse --short HEAD) -t flotilla .
FROM node:20-slim
FROM node:20-bookworm AS builder
# Install pnpm
RUN npm install -g pnpm@latest
# Set working directory
WORKDIR /app
# Copy package files
COPY package.json pnpm-lock.yaml ./
# Install dependencies
RUN pnpm i
# Copy the rest of the application
# Copy everything (including .env when present) - build.sh will source it
COPY . .
ARG VITE_BUILD_HASH
ENV VITE_BUILD_HASH=${VITE_BUILD_HASH}
# Build the application
ENV NODE_OPTIONS=--max_old_space_size=16384
RUN pnpm run build
# Default to serving the build directory
CMD ["npx", "serve", "build"]
# Stage 2: Runtime
FROM node:20-alpine
WORKDIR /app
# Copy only the built output - no source, no .env, no dev deps
COPY --from=builder /app/build ./build
CMD ["npx", "serve", "build"]
+1 -1
View File
@@ -11,7 +11,7 @@ You can also optionally create an `.env` file and populate it with the following
- `VITE_DEFAULT_PUBKEYS` - A comma-separated list of hex pubkeys for bootstrapping web of trust
- `VITE_PLATFORM_URL` - The url where the app will be hosted
- `VITE_PLATFORM_NAME` - The name of the app
- `VITE_PLATFORM_LOGO` - A logo url for the app
- `VITE_PLATFORM_LOGO` - A logo url for the app. Can be a local path or https link. Must be a PNG file.
- `VITE_PLATFORM_RELAYS` - A list of comma-separated relay urls that will make flotilla operate in "platform mode". Disables all space browse/add/select functionality and makes the first platform relay the home page.
- `VITE_PLATFORM_ACCENT` - A hex color for the app's accent color
- `VITE_PLATFORM_DESCRIPTION` - A description of the app
+2 -2
View File
@@ -7,8 +7,8 @@ android {
applicationId "social.flotilla"
minSdk rootProject.ext.minSdkVersion
targetSdk rootProject.ext.targetSdkVersion
versionCode 40
versionName "1.6.4"
versionCode 41
versionName "1.6.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
+7 -3
View File
@@ -5,6 +5,9 @@ temp_env=$(declare -p -x)
if [ -f .env.template ]; then
source .env.template
fi
if [ -f .env.local ]; then
source .env.local
fi
# Avoid overwriting env vars provided directly
# https://stackoverflow.com/a/69127685/1467342
@@ -14,12 +17,13 @@ if [[ -z $VITE_BUILD_HASH ]]; then
export VITE_BUILD_HASH=$(git rev-parse --short HEAD)
fi
if [[ $VITE_PLATFORM_LOGO =~ ^https://* ]]; then
curl $VITE_PLATFORM_LOGO > static/logo.png
if [[ $VITE_PLATFORM_LOGO =~ ^https:// ]]; then
curl -fSL "$VITE_PLATFORM_LOGO" -o static/logo.png
export VITE_PLATFORM_LOGO=static/logo.png
fi
npx pwa-assets-generator
# Ensure generator uses local path (dotenv may have loaded URL from .env)
VITE_PLATFORM_LOGO="${VITE_PLATFORM_LOGO}" npx pwa-assets-generator
npx vite build
# Replace index.html variables with stuff from our env
+4 -4
View File
@@ -358,14 +358,14 @@
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 31;
CURRENT_PROJECT_VERSION = 32;
DEVELOPMENT_TEAM = S26U9DYW3A;
INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.6.4;
MARKETING_VERSION = 1.6.5;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -385,14 +385,14 @@
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 31;
CURRENT_PROJECT_VERSION = 32;
DEVELOPMENT_TEAM = S26U9DYW3A;
INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.6.4;
MARKETING_VERSION = 1.6.5;
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
+13 -13
View File
@@ -1,6 +1,6 @@
{
"name": "flotilla",
"version": "1.6.4",
"version": "1.6.5",
"private": true,
"scripts": {
"dev": "vite dev",
@@ -11,7 +11,7 @@
"tauri:info": "tauri info",
"tauri:icons": "tauri icon assets/logo.png --output src-tauri/icons",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "./check.sh",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check src && eslint src",
"format": "git diff head --name-only --diff-filter d | grep -E '(js|ts|svelte|css)$' | xargs -r prettier --write",
"format:all": "prettier --write src",
@@ -57,7 +57,7 @@
"@getalby/lightning-tools": "^6.1.0",
"@getalby/sdk": "^5.1.2",
"@noble/curves": "^1.9.7",
"@pomade/core": "^0.1.1",
"@pomade/core": "^0.2.1",
"@poppanator/sveltekit-svg": "^4.2.1",
"@sveltejs/adapter-static": "^3.0.10",
"@tiptap/core": "^2.27.2",
@@ -65,16 +65,16 @@
"@types/throttle-debounce": "^5.0.2",
"@vite-pwa/assets-generator": "^0.2.6",
"@vite-pwa/sveltekit": "^0.6.8",
"@welshman/app": "^0.8.7",
"@welshman/content": "^0.8.7",
"@welshman/editor": "^0.8.7",
"@welshman/feeds": "^0.8.7",
"@welshman/lib": "^0.8.7",
"@welshman/net": "^0.8.7",
"@welshman/router": "^0.8.7",
"@welshman/signer": "^0.8.7",
"@welshman/store": "^0.8.7",
"@welshman/util": "^0.8.7",
"@welshman/app": "^0.8.8",
"@welshman/content": "^0.8.8",
"@welshman/editor": "^0.8.8",
"@welshman/feeds": "^0.8.8",
"@welshman/lib": "^0.8.8",
"@welshman/net": "^0.8.8",
"@welshman/router": "^0.8.8",
"@welshman/signer": "^0.8.8",
"@welshman/store": "^0.8.8",
"@welshman/util": "^0.8.8",
"compressorjs-next": "^1.1.2",
"daisyui": "^4.12.24",
"date-picker-svelte": "^2.17.0",
+364 -138
View File
@@ -57,8 +57,8 @@ importers:
specifier: ^1.9.7
version: 1.9.7
'@pomade/core':
specifier: ^0.1.1
version: 0.1.1(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))
specifier: ^0.2.1
version: 0.2.1(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))
'@poppanator/sveltekit-svg':
specifier: ^4.2.1
version: 4.2.1(rollup@2.80.0)(svelte@5.48.0)(svgo@3.3.2)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))
@@ -81,35 +81,35 @@ importers:
specifier: ^0.6.8
version: 0.6.8(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(@vite-pwa/assets-generator@0.2.6)(vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0))
'@welshman/app':
specifier: ^0.8.7
version: 0.8.7(42dd4e512c88dafddb6d336c46cac054)
specifier: ^0.8.8
version: 0.8.8(b90dd618d8ad3ba87405490e903259ce)
'@welshman/content':
specifier: ^0.8.7
version: 0.8.7(nostr-tools@2.20.0(typescript@5.9.3))
specifier: ^0.8.8
version: 0.8.8(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/editor':
specifier: ^0.8.7
version: 0.8.7(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))
specifier: ^0.8.8
version: 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/feeds':
specifier: ^0.8.7
version: 0.8.7(168ce8cc007592daec2fe2c423b6ba13)
specifier: ^0.8.8
version: 0.8.8(827c582d718d0d373e9315813bab1085)
'@welshman/lib':
specifier: ^0.8.7
version: 0.8.7
specifier: ^0.8.8
version: 0.8.8
'@welshman/net':
specifier: ^0.8.7
version: 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
specifier: ^0.8.8
version: 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/router':
specifier: ^0.8.7
version: 0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))
specifier: ^0.8.8
version: 0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))
'@welshman/signer':
specifier: ^0.8.7
version: 0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
specifier: ^0.8.8
version: 0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/store':
specifier: ^0.8.7
version: 0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)
specifier: ^0.8.8
version: 0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)
'@welshman/util':
specifier: ^0.8.7
version: 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
specifier: ^0.8.8
version: 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
compressorjs-next:
specifier: ^1.1.2
version: 1.1.2
@@ -811,6 +811,36 @@ packages:
peerDependencies:
'@capacitor/core': '>=8.0.0'
'@cbor-extract/cbor-extract-darwin-arm64@2.2.0':
resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==}
cpu: [arm64]
os: [darwin]
'@cbor-extract/cbor-extract-darwin-x64@2.2.0':
resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==}
cpu: [x64]
os: [darwin]
'@cbor-extract/cbor-extract-linux-arm64@2.2.0':
resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==}
cpu: [arm64]
os: [linux]
'@cbor-extract/cbor-extract-linux-arm@2.2.0':
resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==}
cpu: [arm]
os: [linux]
'@cbor-extract/cbor-extract-linux-x64@2.2.0':
resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==}
cpu: [x64]
os: [linux]
'@cbor-extract/cbor-extract-win32-x64@2.2.0':
resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==}
cpu: [x64]
os: [win32]
'@cmdcode/buff@2.2.5':
resolution: {integrity: sha512-+nc3QDoJ+MU/fp+YkX6WuEjJrXLF6ME+eVX1sj5a+MfBKO9LWb4R9Y2zH6APBrySd7nFr48ozscAui7SKvLmXg==}
@@ -1309,12 +1339,46 @@ packages:
'@paralleldrive/cuid2@2.3.1':
resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==}
'@peculiar/asn1-cms@2.6.1':
resolution: {integrity: sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==}
'@peculiar/asn1-csr@2.6.1':
resolution: {integrity: sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==}
'@peculiar/asn1-ecc@2.6.1':
resolution: {integrity: sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==}
'@peculiar/asn1-pfx@2.6.1':
resolution: {integrity: sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==}
'@peculiar/asn1-pkcs8@2.6.1':
resolution: {integrity: sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==}
'@peculiar/asn1-pkcs9@2.6.1':
resolution: {integrity: sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==}
'@peculiar/asn1-rsa@2.6.1':
resolution: {integrity: sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==}
'@peculiar/asn1-schema@2.6.0':
resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==}
'@peculiar/asn1-x509-attr@2.6.1':
resolution: {integrity: sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==}
'@peculiar/asn1-x509@2.6.1':
resolution: {integrity: sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==}
'@peculiar/x509@1.14.3':
resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==}
engines: {node: '>=20.0.0'}
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
'@pomade/core@0.1.1':
resolution: {integrity: sha512-v/lg9nQvL1ReOx1xLmjS70mAO5hW2ZcR9OXl9GdB0rxyg0gBIh45seqzJTDI8ye+MAk7AZRvhn8H6lPE6oohNQ==}
version: 0.1.1
'@pomade/core@0.2.1':
resolution: {integrity: sha512-zXpPQPkhVe7OchmRDe2MbHdUxiCSeUuMwrHOyeOBs/xD1EfY093Mwj6Cu/OLfz0wxivBDSp1GMMmxqKbLWam3Q==}
version: 0.2.1
engines: {node: '>=12.0.0'}
peerDependencies:
'@frostr/bifrost': ^1.0.7
@@ -1903,82 +1967,83 @@ packages:
'@vite-pwa/assets-generator':
optional: true
'@welshman/app@0.8.7':
resolution: {integrity: sha512-P+cCy2o1r/ke5SngNmoK8WoeLmEZ6l2I83mz0QaRHremkb+Q/RN72UBQy+x2lUrUtRzWJ8tNAwXwsqBw0JGxaQ==}
'@welshman/app@0.8.8':
resolution: {integrity: sha512-pyySouAJwGZ2RSC29egiFft38Ctuioodon6xWFxB7HvJ9Llsh5b53qjkrQcAYM7lUAzXwtalf2v4Z3EwYdUObg==}
peerDependencies:
'@pomade/core': ^0.1.1
'@welshman/feeds': 0.8.7
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7
'@welshman/router': 0.8.7
'@welshman/signer': 0.8.7
'@welshman/store': 0.8.7
'@welshman/util': 0.8.7
'@pomade/core': ^0.1.3
'@welshman/feeds': 0.8.8
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8
'@welshman/router': 0.8.8
'@welshman/signer': 0.8.8
'@welshman/store': 0.8.8
'@welshman/util': 0.8.8
svelte: ^4.0.0 || ^5.0.0
'@welshman/content@0.8.7':
resolution: {integrity: sha512-EPeiB+hocVuMjlbWrIBdw7wmcs3jsBjI9o7jld2gsADVLmouYctahFNTSxjkeARnyK+j09ece95hC2MlJNPrbA==}
'@welshman/content@0.8.8':
resolution: {integrity: sha512-5jh2YMoqINzkOEVSDZec6JbAqiC0WThwRuPwJOwiJlAFYQ4LC0MAT1HQ8z9pht/0TXdjYQUu2X+jngqqICNOiw==}
peerDependencies:
nostr-tools: ^2.19.4
'@welshman/editor@0.8.7':
resolution: {integrity: sha512-UZmHmP5zG9Ad1sp6h4uAQYwJ/o1mkfyCbt7tYV5+z7+7YZ2x2gsS59yqDrgr0NV1z9GFZ/axgFatl0L/c5ihKA==}
'@welshman/editor@0.8.8':
resolution: {integrity: sha512-54WD2d6HEEiuoPgl/LeE4eaLtF2/SrYObk+IE9UUrJjoXcK/BK3vt8ltzazvBLR8ntfKOQINc4DhkeuBxiiCpA==}
peerDependencies:
'@welshman/lib': 0.8.7
'@welshman/util': 0.8.7
'@welshman/lib': 0.8.8
'@welshman/util': 0.8.8
nostr-editor: ^1.1.1
nostr-tools: ^2.19.4
'@welshman/feeds@0.8.7':
resolution: {integrity: sha512-mM9mGRje2lXQ2KGTz31gSR0MBWJVIgD8efaf2HCb/dopLzlJ0brSpGUAuGAb+yAfWwZ/wXTzwmYOLdSZT5AyvQ==}
'@welshman/feeds@0.8.8':
resolution: {integrity: sha512-o5JuptpWSNr6wtbM0RfSxTJgZStaNxPz160tE9u0SZzs1/a9sq/Yzesw7s+g0nKukRjBbl70DOqpTqOqfXAEIw==}
peerDependencies:
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7
'@welshman/router': 0.8.7
'@welshman/signer': 0.8.7
'@welshman/util': 0.8.7
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8
'@welshman/router': 0.8.8
'@welshman/signer': 0.8.8
'@welshman/util': 0.8.8
'@welshman/lib@0.8.7':
resolution: {integrity: sha512-/82PNmg7mhf6r1gtY0YaB8xFRCioRRZkZUDPb0UuAZuhBCom6tKhlffzz+ty2n2tHYFTyScMp90WMVtkU/HaDQ==}
'@welshman/lib@0.8.8':
resolution: {integrity: sha512-77ZfVtodV05276ceR8c+JdDFqhOpmy2W6PkgDYbnKstQzKb5TN6wBvcLKxJppTzWMeWbyi2JADsuOYvW1jpOSQ==}
engines: {node: '>=12.0.0'}
'@welshman/net@0.8.7':
resolution: {integrity: sha512-FcVYX1imsYWca32zyU/HhXKly+A4IJzoElmMqe4x501bvpb0QQm8S2nfdCPxtb1lsi2rR1Y5if9jGHwgQGnEtQ==}
'@welshman/net@0.8.8':
resolution: {integrity: sha512-Rug3GzVzyABG21g++cCLOVXdjAieV6rJUZqstE8i/olZvOEWZpZ9R901DoUSDR07U2HTrAwHQrjgb1HmH4jiDQ==}
peerDependencies:
'@welshman/lib': 0.8.7
'@welshman/util': 0.8.7
'@welshman/lib': 0.8.8
'@welshman/util': 0.8.8
'@welshman/router@0.8.7':
resolution: {integrity: sha512-p0jfyqBHnNK9j2ZI3PYHfirdUe5/ll1/jttcj0p4xi822aYoGYv5giriDVt+wnzchki1XRXBGN5lRXfpBi8bbA==}
'@welshman/router@0.8.8':
resolution: {integrity: sha512-j5O7F7KGQtOIvBJctEiUNcLfHBUnhHlYHxUx7ImPPurc1zLzt3JovvJJFubXMQoQ26D01DsK/AA1L5WZNebUhA==}
peerDependencies:
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7
'@welshman/util': 0.8.7
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8
'@welshman/util': 0.8.8
'@welshman/signer@0.8.7':
resolution: {integrity: sha512-RbFuRyJ0KL3Yg3EU8M9v5OADJO+XY/+sNd0CSmbWSwSry1NLlqa8lq/T+2b40x8KtnYMmQyB7Dp9yDQndO0ugA==}
version: 0.8.7
'@welshman/signer@0.8.8':
resolution: {integrity: sha512-rswHrTdc1+yvAno2h3JELzjp+LCfiYfUr8ACvwSSHAqDwrtezppfh0WDEPaYBp2EVSJ6tKMM1sVey0quO63aMw==}
version: 0.8.8
peerDependencies:
'@noble/curves': ^1.9.7
'@noble/hashes': ^2.0.1
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7
'@welshman/util': 0.8.7
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8
'@welshman/util': 0.8.8
nostr-signer-capacitor-plugin: '*'
nostr-tools: ^2.19.4
'@welshman/store@0.8.7':
resolution: {integrity: sha512-ppvq7msnvzgnSlU4FsZmJgA3eSyFy9H6gYSQ91ukspbmkxCdMG2paBPCKU4tKv4fYrv/1ULgaN8gkP1BCG6riQ==}
'@welshman/store@0.8.8':
resolution: {integrity: sha512-mTFueKZi9CtrtvCZT5eT5QaLMs94LxQg4y7oO5PZp9wv8EGSnB9p7XIflM0OfpKwF7c0pu1RdXcjVlvMDsC6QQ==}
peerDependencies:
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7
'@welshman/util': 0.8.7
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8
'@welshman/util': 0.8.8
svelte: ^4.0.0 || ^5.0.0
'@welshman/util@0.8.7':
resolution: {integrity: sha512-UjdQookLypfOxWplxcG0lBzREGgck4n4a+digoRjAe5jRlP6S6xH7uNI8Pl1Qk01D5KB8Ntz/yBdwe6JtkvqYg==}
'@welshman/util@0.8.8':
resolution: {integrity: sha512-SNT1VXab6ce36EVfjs1A2uwWs5elYTI4eXi8SUuj42k8CqNIAtG+bOf/JFIxXNTfl3NSxxZdWzpLLZWBqgpAxQ==}
peerDependencies:
'@noble/curves': ^1.9.7
'@welshman/lib': 0.8.7
'@welshman/lib': 0.8.8
nostr-tools: ^2.19.4
'@xml-tools/parser@1.0.11':
@@ -2083,6 +2148,10 @@ packages:
asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
asn1js@3.0.7:
resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==}
engines: {node: '>=12.0.0'}
astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@@ -2216,6 +2285,13 @@ packages:
caniuse-lite@1.0.30001766:
resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==}
cbor-extract@2.2.0:
resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==}
hasBin: true
cbor-x@1.6.0:
resolution: {integrity: sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==}
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@@ -3430,10 +3506,6 @@ packages:
markdown-it-task-lists@2.1.1:
resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==}
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
hasBin: true
markdown-it@14.1.1:
resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==}
hasBin: true
@@ -3570,6 +3642,10 @@ packages:
encoding:
optional: true
node-gyp-build-optional-packages@5.1.1:
resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==}
hasBin: true
node-html-parser@5.4.2:
resolution: {integrity: sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==}
@@ -4034,6 +4110,13 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
pvtsutils@1.3.6:
resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==}
pvutils@1.1.5:
resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==}
engines: {node: '>=16.0.0'}
q@1.5.1:
resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==}
engines: {node: '>=0.6.0', teleport: '>=0.2.0'}
@@ -4098,6 +4181,9 @@ packages:
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
engines: {node: '>=8'}
reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
reflect.getprototypeof@1.0.10:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'}
@@ -4568,12 +4654,19 @@ packages:
'@swc/wasm':
optional: true
tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tsyringe@4.10.0:
resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==}
engines: {node: '>= 6.0.0'}
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -5755,6 +5848,24 @@ snapshots:
dependencies:
'@capacitor/core': 8.0.1
'@cbor-extract/cbor-extract-darwin-arm64@2.2.0':
optional: true
'@cbor-extract/cbor-extract-darwin-x64@2.2.0':
optional: true
'@cbor-extract/cbor-extract-linux-arm64@2.2.0':
optional: true
'@cbor-extract/cbor-extract-linux-arm@2.2.0':
optional: true
'@cbor-extract/cbor-extract-linux-x64@2.2.0':
optional: true
'@cbor-extract/cbor-extract-win32-x64@2.2.0':
optional: true
'@cmdcode/buff@2.2.5':
dependencies:
'@noble/hashes': 1.8.0
@@ -6233,16 +6344,108 @@ snapshots:
dependencies:
'@noble/hashes': 1.8.0
'@peculiar/asn1-cms@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
'@peculiar/asn1-x509-attr': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-csr@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-ecc@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-pfx@2.6.1':
dependencies:
'@peculiar/asn1-cms': 2.6.1
'@peculiar/asn1-pkcs8': 2.6.1
'@peculiar/asn1-rsa': 2.6.1
'@peculiar/asn1-schema': 2.6.0
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-pkcs8@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-pkcs9@2.6.1':
dependencies:
'@peculiar/asn1-cms': 2.6.1
'@peculiar/asn1-pfx': 2.6.1
'@peculiar/asn1-pkcs8': 2.6.1
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
'@peculiar/asn1-x509-attr': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-rsa@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-schema@2.6.0':
dependencies:
asn1js: 3.0.7
pvtsutils: 1.3.6
tslib: 2.8.1
'@peculiar/asn1-x509-attr@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
asn1js: 3.0.7
tslib: 2.8.1
'@peculiar/asn1-x509@2.6.1':
dependencies:
'@peculiar/asn1-schema': 2.6.0
asn1js: 3.0.7
pvtsutils: 1.3.6
tslib: 2.8.1
'@peculiar/x509@1.14.3':
dependencies:
'@peculiar/asn1-cms': 2.6.1
'@peculiar/asn1-csr': 2.6.1
'@peculiar/asn1-ecc': 2.6.1
'@peculiar/asn1-pkcs9': 2.6.1
'@peculiar/asn1-rsa': 2.6.1
'@peculiar/asn1-schema': 2.6.0
'@peculiar/asn1-x509': 2.6.1
pvtsutils: 1.3.6
reflect-metadata: 0.2.2
tslib: 2.8.1
tsyringe: 4.10.0
'@polka/url@1.0.0-next.29': {}
'@pomade/core@0.1.1(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))':
'@pomade/core@0.2.1(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))':
dependencies:
'@frostr/bifrost': 1.0.7(typescript@5.9.3)
'@noble/hashes': 2.0.1
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/signer': 0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@peculiar/x509': 1.14.3
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/signer': 0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
cbor-x: 1.6.0
hash-wasm: 4.12.0
nostr-tools: 2.20.0(typescript@5.9.3)
zod: 4.3.6
@@ -6828,26 +7031,26 @@ snapshots:
optionalDependencies:
'@vite-pwa/assets-generator': 0.2.6
'@welshman/app@0.8.7(42dd4e512c88dafddb6d336c46cac054)':
'@welshman/app@0.8.8(b90dd618d8ad3ba87405490e903259ce)':
dependencies:
'@pomade/core': 0.1.1(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/feeds': 0.8.7(168ce8cc007592daec2fe2c423b6ba13)
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/router': 0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))
'@welshman/signer': 0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/store': 0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@pomade/core': 0.2.1(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/feeds': 0.8.8(827c582d718d0d373e9315813bab1085)
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/router': 0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))
'@welshman/signer': 0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/store': 0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
fuse.js: 7.1.0
svelte: 5.48.0
throttle-debounce: 5.0.2
'@welshman/content@0.8.7(nostr-tools@2.20.0(typescript@5.9.3))':
'@welshman/content@0.8.8(nostr-tools@2.20.0(typescript@5.9.3))':
dependencies:
'@braintree/sanitize-url': 7.1.1
nostr-tools: 2.20.0(typescript@5.9.3)
'@welshman/editor@0.8.7(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))':
'@welshman/editor@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))))(nostr-tools@2.20.0(typescript@5.9.3))':
dependencies:
'@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
'@tiptap/extension-code': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
@@ -6862,73 +7065,64 @@ snapshots:
'@tiptap/extension-text': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
'@tiptap/pm': 2.27.2
'@tiptap/suggestion': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
'@welshman/lib': 0.8.7
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/lib': 0.8.8
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
nostr-editor: 1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))
nostr-tools: 2.20.0(typescript@5.9.3)
tippy.js: 6.3.7
transitivePeerDependencies:
- '@tiptap/extension-image'
- '@tiptap/extension-link'
- linkifyjs
- prosemirror-markdown
- prosemirror-model
- prosemirror-state
- prosemirror-view
- tiptap-markdown
'@welshman/feeds@0.8.7(168ce8cc007592daec2fe2c423b6ba13)':
'@welshman/feeds@0.8.8(827c582d718d0d373e9315813bab1085)':
dependencies:
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/router': 0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))
'@welshman/signer': 0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/router': 0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))
'@welshman/signer': 0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
trava: 1.2.1
'@welshman/lib@0.8.7':
'@welshman/lib@0.8.8':
dependencies:
'@scure/base': 1.2.6
'@types/events': 3.0.3
events: 3.3.0
'@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)':
'@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)':
dependencies:
'@welshman/lib': 0.8.7
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/lib': 0.8.8
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
events: 3.3.0
isomorphic-ws: 5.0.0(ws@8.18.3)
transitivePeerDependencies:
- ws
'@welshman/router@0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))':
'@welshman/router@0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))':
dependencies:
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/signer@0.8.7(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))':
'@welshman/signer@0.8.8(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))':
dependencies:
'@noble/curves': 1.9.7
'@noble/hashes': 2.0.1
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
nostr-signer-capacitor-plugin: https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1)
nostr-tools: 2.20.0(typescript@5.9.3)
'@welshman/store@0.8.7(@welshman/lib@0.8.7)(@welshman/net@0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)':
'@welshman/store@0.8.8(@welshman/lib@0.8.8)(@welshman/net@0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)':
dependencies:
'@welshman/lib': 0.8.7
'@welshman/net': 0.8.7(@welshman/lib@0.8.7)(@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/util': 0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))
'@welshman/lib': 0.8.8
'@welshman/net': 0.8.8(@welshman/lib@0.8.8)(@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)
'@welshman/util': 0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))
svelte: 5.48.0
'@welshman/util@0.8.7(@noble/curves@1.9.7)(@welshman/lib@0.8.7)(nostr-tools@2.20.0(typescript@5.9.3))':
'@welshman/util@0.8.8(@noble/curves@1.9.7)(@welshman/lib@0.8.8)(nostr-tools@2.20.0(typescript@5.9.3))':
dependencies:
'@noble/curves': 1.9.7
'@types/ws': 8.18.1
'@welshman/lib': 0.8.7
'@welshman/lib': 0.8.8
js-base64: 3.7.8
nostr-tools: 2.20.0(typescript@5.9.3)
nostr-wasm: 0.1.0
@@ -7027,6 +7221,12 @@ snapshots:
asap@2.0.6: {}
asn1js@3.0.7:
dependencies:
pvtsutils: 1.3.6
pvutils: 1.1.5
tslib: 2.8.1
astral-regex@2.0.0: {}
async-function@1.0.0: {}
@@ -7156,6 +7356,22 @@ snapshots:
caniuse-lite@1.0.30001766: {}
cbor-extract@2.2.0:
dependencies:
node-gyp-build-optional-packages: 5.1.1
optionalDependencies:
'@cbor-extract/cbor-extract-darwin-arm64': 2.2.0
'@cbor-extract/cbor-extract-darwin-x64': 2.2.0
'@cbor-extract/cbor-extract-linux-arm': 2.2.0
'@cbor-extract/cbor-extract-linux-arm64': 2.2.0
'@cbor-extract/cbor-extract-linux-x64': 2.2.0
'@cbor-extract/cbor-extract-win32-x64': 2.2.0
optional: true
cbor-x@1.6.0:
optionalDependencies:
cbor-extract: 2.2.0
chalk@2.4.2:
dependencies:
ansi-styles: 3.2.1
@@ -8449,15 +8665,6 @@ snapshots:
markdown-it-task-lists@2.1.1: {}
markdown-it@14.1.0:
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.0
mdurl: 2.0.0
punycode.js: 2.3.1
uc.micro: 2.1.0
markdown-it@14.1.1:
dependencies:
argparse: 2.0.1
@@ -8595,6 +8802,11 @@ snapshots:
dependencies:
whatwg-url: 5.0.0
node-gyp-build-optional-packages@5.1.1:
dependencies:
detect-libc: 2.1.2
optional: true
node-html-parser@5.4.2:
dependencies:
css-select: 4.3.0
@@ -8953,7 +9165,7 @@ snapshots:
prosemirror-markdown@1.13.3:
dependencies:
'@types/markdown-it': 14.1.2
markdown-it: 14.1.0
markdown-it: 14.1.1
prosemirror-model: 1.25.4
prosemirror-menu@1.2.5:
@@ -9013,6 +9225,12 @@ snapshots:
punycode@2.3.1: {}
pvtsutils@1.3.6:
dependencies:
tslib: 2.8.1
pvutils@1.1.5: {}
q@1.5.1: {}
qr-scanner@1.4.2:
@@ -9088,6 +9306,8 @@ snapshots:
indent-string: 4.0.0
strip-indent: 3.0.0
reflect-metadata@0.2.2: {}
reflect.getprototypeof@1.0.10:
dependencies:
call-bind: 1.0.8
@@ -9707,10 +9927,16 @@ snapshots:
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
tslib@1.14.1: {}
tslib@2.6.2: {}
tslib@2.8.1: {}
tsyringe@4.10.0:
dependencies:
tslib: 1.14.1
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
+1 -1
View File
@@ -1,7 +1,7 @@
import dotenv from "dotenv"
import {defineConfig, minimalPreset as preset} from "@vite-pwa/assets-generator/config"
dotenv.config({path: ".env"})
dotenv.config({path: ".env.local"})
dotenv.config({path: ".env.template"})
export default defineConfig({
+4 -19
View File
@@ -15,10 +15,10 @@
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import StringMultiInput from "@lib/components/StringMultiInput.svelte"
import KeyDownload from "@app/components/KeyDownload.svelte"
import {pushToast} from "@app/util/toast"
import {pushModal, clearModals} from "@app/util/modal"
import {POMADE_SIGNERS} from "@app/core/state"
type Props = {
peersByPrefix: Map<string, string>
@@ -32,18 +32,6 @@
} = $session as SessionPomade
const confirmRecovery = async () => {
const otps = input
.split(/\n/)
.map(x => x.trim())
.filter(x => x.match(/^[0-9]{8}$/))
if (otps.length < 2) {
return pushToast({
theme: "error",
message: "Failed to recover, not enough valid recovery codes were provided.",
})
}
const request = await Client.recoverWithChallenge(email, peersByPrefix, otps)
if (!request.ok) {
@@ -82,7 +70,7 @@
const back = () => history.back()
let loading = $state(false)
let input = $state("")
let otps = $state<string[]>([])
</script>
<Modal tag="form" onsubmit={preventDefault(submit)}>
@@ -96,17 +84,14 @@
For security reasons, you may receive three or more emails with recovery codes in them. Please
paste <strong>all</strong> recovery codes into the text box below, on separate lines.
</p>
<textarea
rows={POMADE_SIGNERS.length + 1}
class="textarea textarea-bordered leading-4"
bind:value={input}></textarea>
<StringMultiInput bind:value={otps} placeholder="Enter your recovery codes..." />
</ModalBody>
<ModalFooter>
<Button class="btn btn-link" onclick={back}>
<Icon icon={AltArrowLeft} />
Go back
</Button>
<Button type="submit" class="btn btn-primary" disabled={loading}>
<Button type="submit" class="btn btn-primary" disabled={loading || otps.length < 2}>
<Spinner {loading}>Confirm recovery</Spinner>
<Icon icon={AltArrowRight} />
</Button>
-1
View File
@@ -34,7 +34,6 @@
const onSuccess = async (session: Session) => {
addSession(session)
pushToast({message: "Successfully logged in!"})
setChecked("*")
clearModals()
}
+21 -15
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import {uniq} from "@welshman/lib"
import {Client} from "@pomade/core"
import {loginWithPomade} from "@welshman/app"
import {preventDefault} from "@lib/html"
import Spinner from "@lib/components/Spinner.svelte"
import Button from "@lib/components/Button.svelte"
@@ -17,6 +17,8 @@
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import LogInOTP from "@app/components/LogInOTP.svelte"
import LogInSelect from "@app/components/LogInSelect.svelte"
import {deleteDeactivatedPomadeSessions, loginWithPomade} from "@app/util/pomade"
import {pushModal, clearModals} from "@app/util/modal"
import {setChecked} from "@app/util/notifications"
import {pushToast} from "@app/util/toast"
@@ -37,7 +39,7 @@
try {
const {ok, options, messages, clientSecret} = await Client.loginWithPassword(email, password)
if (!ok) {
if (!ok || options.length === 0) {
console.error(messages)
return pushToast({
@@ -46,21 +48,25 @@
})
}
const [client, peers] = options[0]!
const {clientOptions, ...res} = await Client.selectLogin(clientSecret, client, peers)
if (res.ok && clientOptions) {
loginWithPomade(clientOptions.group.group_pk.slice(2), email, clientOptions)
pushToast({message: "Successfully logged in!"})
setChecked("*")
clearModals()
if (uniq(options.map(o => o.pubkey)).length > 1) {
pushModal(LogInSelect, {email, options, clientSecret})
} else {
console.error(res.messages)
const {client, peers} = options[0]
const {clientOptions, ...res} = await Client.selectLogin(clientSecret, client, peers)
pushToast({
theme: "error",
message: "Sorry, we were unable to log you in.",
})
if (res.ok && clientOptions) {
loginWithPomade(clientOptions, email)
deleteDeactivatedPomadeSessions()
setChecked("*")
clearModals()
} else {
console.error(res.messages)
pushToast({
theme: "error",
message: "Sorry, we were unable to log you in.",
})
}
}
} finally {
loading = false
-1
View File
@@ -57,7 +57,6 @@
}
loginWithNip01(secret)
pushToast({message: "Successfully logged in!"})
setChecked("*")
clearModals()
} catch (e) {
+27 -36
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import {uniq} from "@welshman/lib"
import {Client} from "@pomade/core"
import {loginWithPomade} from "@welshman/app"
import {preventDefault} from "@lib/html"
import Spinner from "@lib/components/Spinner.svelte"
import Button from "@lib/components/Button.svelte"
@@ -13,10 +13,12 @@
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import {clearModals} from "@app/util/modal"
import {setChecked} from "@app/util/notifications"
import StringMultiInput from "@lib/components/StringMultiInput.svelte"
import LogInSelect from "@app/components/LogInSelect.svelte"
import {pushToast} from "@app/util/toast"
import {POMADE_SIGNERS} from "@app/core/state"
import {setChecked} from "@app/util/notifications"
import {pushModal, clearModals} from "@app/util/modal"
import {deleteDeactivatedPomadeSessions, loginWithPomade} from "@app/util/pomade"
type Props = {
email: string
@@ -28,18 +30,6 @@
const back = () => history.back()
const onSubmit = async () => {
const otps = input
.split(/\n/)
.map(x => x.trim())
.filter(x => x.match(/^[0-9]{8}$/))
if (otps.length < 2) {
return pushToast({
theme: "error",
message: "Failed to recover, not enough valid recovery codes were provided.",
})
}
loading = true
try {
@@ -49,7 +39,7 @@
otps,
)
if (!ok) {
if (!ok || options.length === 0) {
console.error(messages)
return pushToast({
@@ -58,28 +48,32 @@
})
}
const [client, peers] = options[0]!
const {clientOptions, ...res} = await Client.selectLogin(clientSecret, client, peers)
if (res.ok && clientOptions) {
loginWithPomade(clientOptions.group.group_pk.slice(2), email, clientOptions)
pushToast({message: "Successfully logged in!"})
setChecked("*")
clearModals()
if (uniq(options.map(o => o.pubkey)).length > 1) {
pushModal(LogInSelect, {email, options, clientSecret})
} else {
console.error(res.messages)
const {client, peers} = options[0]
const {clientOptions, ...res} = await Client.selectLogin(clientSecret, client, peers)
pushToast({
theme: "error",
message: "Sorry, we were unable to log you in.",
})
if (res.ok && clientOptions) {
loginWithPomade(clientOptions, email)
deleteDeactivatedPomadeSessions()
setChecked("*")
clearModals()
} else {
console.error(res.messages)
pushToast({
theme: "error",
message: "Sorry, we were unable to log you in.",
})
}
}
} finally {
loading = false
}
}
let input = $state("")
let otps = $state<string[]>([])
let loading = $state(false)
</script>
@@ -94,17 +88,14 @@
For security reasons, you may receive three or more emails with login codes in them. Please
paste <strong>all</strong> login codes into the text box below, on separate lines.
</p>
<textarea
rows={POMADE_SIGNERS.length + 1}
class="textarea textarea-bordered leading-4"
bind:value={input}></textarea>
<StringMultiInput bind:value={otps} placeholder="Enter your login codes..." />
</ModalBody>
<ModalFooter>
<Button class="btn btn-link" onclick={back} disabled={loading}>
<Icon icon={AltArrowLeft} />
Go back
</Button>
<Button type="submit" class="btn btn-primary" disabled={loading}>
<Button type="submit" class="btn btn-primary" disabled={loading || otps.length < 3}>
<Spinner {loading}>Log In</Spinner>
<Icon icon={AltArrowRight} />
</Button>
+83
View File
@@ -0,0 +1,83 @@
<script lang="ts">
import type {AccountOption} from "@pomade/core"
import {Client} from "@pomade/core"
import {uniqBy} from "@welshman/lib"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import Profile from "@app/components/Profile.svelte"
import {deleteDeactivatedPomadeSessions, loginWithPomade} from "@app/util/pomade"
import {setChecked} from "@app/util/notifications"
import {clearModals} from "@app/util/modal"
import {pushToast} from "@app/util/toast"
interface Props {
email: string
options: AccountOption[]
clientSecret: string
}
const {email, options, clientSecret}: Props = $props()
let loading = $state(false)
const back = () => history.back()
const selectAccount = async ({client, peers}: AccountOption) => {
loading = true
try {
const {clientOptions, ...res} = await Client.selectLogin(clientSecret, client, peers)
if (res.ok && clientOptions) {
loginWithPomade(clientOptions, email)
deleteDeactivatedPomadeSessions()
setChecked("*")
clearModals()
} else {
console.error(res.messages)
pushToast({
theme: "error",
message: "Sorry, we were unable to log you in.",
})
}
} finally {
loading = false
}
}
</script>
<Modal>
<ModalBody>
<ModalHeader>
<ModalTitle>Select Account</ModalTitle>
<ModalSubtitle
>Multiple accounts are associated with {email}. Please select one to continue.</ModalSubtitle>
</ModalHeader>
<div class="flex flex-col gap-2">
{#each uniqBy(o => o.pubkey, options) as option (option.pubkey)}
<Button
onclick={() => selectAccount(option)}
disabled={loading}
class="card2 bg-alt flex w-full items-center p-3 text-left">
<Profile pubkey={option.pubkey} />
</Button>
{/each}
</div>
</ModalBody>
<ModalFooter>
<Button class="btn btn-link" onclick={back} disabled={loading}>
<Icon icon={AltArrowLeft} />
Go back
</Button>
<Spinner {loading} />
</ModalFooter>
</Modal>
+2 -9
View File
@@ -9,8 +9,7 @@
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import {Push} from "@app/util/notifications"
import {kv, db} from "@app/core/storage"
import {logout} from "@app/util/logout"
const back = () => history.back()
@@ -18,13 +17,7 @@
loading = true
try {
await Push.disable()
await kv.clear()
await db.clear()
localStorage.clear()
window.location.href = "/"
await logout()
} catch (e) {
console.error(e)
loading = false
@@ -22,8 +22,8 @@
{#if props.event.content}
<Content {...props} />
{/if}
<div class="grid grid-cols-3 sm:grid-cols-5 lg:grid-cols-9">
{#each images as image (image)}
<div class="grid grid-cols-3 sm:grid-cols-5 lg:grid-cols-9 gap-2">
{#each images as image, i (i + image)}
<ContentLinkBlock event={props.event} value={{url: image}} />
{/each}
</div>
+106
View File
@@ -0,0 +1,106 @@
<script lang="ts">
import {Client} from "@pomade/core"
import type {SessionPomade} from "@welshman/app"
import {session} from "@welshman/app"
import {preventDefault} from "@lib/html"
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
import AltArrowRight from "@assets/icons/alt-arrow-right.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import StringMultiInput from "@lib/components/StringMultiInput.svelte"
import PasswordResetConfirm from "@app/components/PasswordResetConfirm.svelte"
import {pushToast} from "@app/util/toast"
import {pushModal} from "@app/util/modal"
import {getPomadeClient} from "@app/util/pomade"
type Props = {
peersByPrefix: Map<string, string>
}
const {peersByPrefix}: Props = $props()
const {email} = $session as SessionPomade
const confirmRecovery = async () => {
const request = await Client.recoverWithChallenge(email, peersByPrefix, otps)
if (!request.ok) {
console.log(request.messages)
return pushToast({
theme: "error",
message: `Failed to validate email ownership: ${request.messages[0]?.res?.message.toLowerCase()}`,
})
}
const client = await getPomadeClient()
if (!client) {
throw new Error("Unable to get client during password reset flow")
}
const result = await Client.selectRecovery(
request.clientSecret,
await client.getPubkey(),
client.peers,
)
if (!result.ok) {
console.log(result.messages)
return pushToast({
theme: "error",
message: `Failed to validate email ownership: ${result.messages[0]?.res?.message.toLowerCase()}`,
})
}
pushModal(PasswordResetConfirm, {userSecret: result.userSecret})
}
const submit = async () => {
loading = true
try {
await confirmRecovery()
} finally {
loading = false
}
}
const back = () => history.back()
let loading = $state(false)
let otps = $state<string[]>([])
</script>
<Modal tag="form" onsubmit={preventDefault(submit)}>
<ModalBody>
<ModalHeader>
<ModalTitle>Update your Password</ModalTitle>
<ModalSubtitle>Confirm your Email</ModalSubtitle>
</ModalHeader>
<p>Let's start by confirming your email.</p>
<p>
For security reasons, you may receive three or more emails with confirmation codes in them.
Please paste <strong>all</strong> confirmation codes into the text box below, on separate lines.
</p>
<StringMultiInput bind:value={otps} placeholder="Enter your confirmation codes..." />
</ModalBody>
<ModalFooter>
<Button class="btn btn-link" onclick={back}>
<Icon icon={AltArrowLeft} />
Go back
</Button>
<Button type="submit" class="btn btn-primary" disabled={loading || otps.length < 2}>
<Spinner {loading}>Continue</Spinner>
<Icon icon={AltArrowRight} />
</Button>
</ModalFooter>
</Modal>
@@ -0,0 +1,118 @@
<script lang="ts">
import {Client} from "@pomade/core"
import {session} from "@welshman/app"
import type {SessionPomade} from "@welshman/app"
import {preventDefault} from "@lib/html"
import Key from "@assets/icons/key.svg?dataurl"
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
import AltArrowRight from "@assets/icons/alt-arrow-right.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import FieldInline from "@lib/components/FieldInline.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import Button from "@lib/components/Button.svelte"
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import {loginWithPomade, deleteCurrentPomadeSession} from "@app/util/pomade"
import {clearModals} from "@app/util/modal"
import {pushToast} from "@app/util/toast"
type Props = {
userSecret: string
}
const {userSecret}: Props = $props()
const {email} = $session as SessionPomade
const back = () => history.back()
const onSubmit = async () => {
if (password.trim().length < 12) {
return pushToast({
theme: "error",
message: "Password must be at least 12 characters long.",
})
}
loading = true
try {
pushToast({
timeout: 60_000,
message: "Registering your new password, please wait...",
})
const {clientOptions, ...registerRes} = await Client.register(2, 3, userSecret)
if (!registerRes.ok) {
return pushToast({
theme: "error",
message: "Failed to register your new password! Please try again.",
})
}
const setupRes = await new Client(clientOptions).setupRecovery(email, password)
if (!setupRes.ok) {
const message = setupRes.messages[0]?.res?.message || "Please try again."
return pushToast({
theme: "error",
message: `Failed to register your new password! ${message}.`,
})
}
await deleteCurrentPomadeSession()
pushToast({message: "Your password has been updated!"})
loginWithPomade(clientOptions, email)
clearModals()
} catch (e) {
console.error(e)
pushToast({
theme: "error",
message: "Failed to register your new password! Please try again.",
})
} finally {
loading = false
}
}
let password = $state("")
let loading = $state(false)
</script>
<Modal tag="form" onsubmit={preventDefault(onSubmit)}>
<ModalBody>
<ModalHeader>
<ModalTitle>Update your Password</ModalTitle>
<ModalSubtitle>Please provide your new password.</ModalSubtitle>
</ModalHeader>
<FieldInline>
{#snippet label()}
<p>New Password*</p>
{/snippet}
{#snippet input()}
<label class="input input-bordered flex w-full items-center gap-2">
<Icon icon={Key} />
<input type="password" bind:value={password} />
</label>
{/snippet}
</FieldInline>
</ModalBody>
<ModalFooter>
<Button class="btn btn-link" onclick={back}>
<Icon icon={AltArrowLeft} />
Go back
</Button>
<Button class="btn btn-primary" type="submit" disabled={loading || !password}>
<Spinner {loading}>Continue</Spinner>
<Icon icon={AltArrowRight} />
</Button>
</ModalFooter>
</Modal>
+57 -60
View File
@@ -1,51 +1,30 @@
<script lang="ts">
import {onMount} from "svelte"
import {Client} from "@pomade/core"
import type {SessionItem} from "@pomade/core"
import {session, isPomadeSession} from "@welshman/app"
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
import {fly} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Popover from "@lib/components/Popover.svelte"
import TrashBin2 from "@assets/icons/trash-bin-2.svg?dataurl"
import {pushToast} from "@app/util/toast"
import {onMount} from "svelte"
import {loadOtherPomadeSessions} from "@app/util/pomade"
import type {PomadeSessionWithPeers} from "@app/util/pomade"
type SessionWithPeers = SessionItem & {peers: string[]}
let sessions = $state<SessionWithPeers[]>([])
let deletingSession = $state<string | null>(null)
const loadSessions = async () => {
if (!isPomadeSession($session)) return
const client = new Client($session.clientOptions)
const result = await client.listSessions()
const pubkey = await client.getPubkey()
if (result.ok) {
// Group sessions by client pubkey and collect peers
const sessionMap = new Map<string, SessionWithPeers>()
for (const message of result.messages) {
if (!message.res?.items) continue
for (const item of message.res.items) {
const existing = sessionMap.get(item.client)
if (existing) {
existing.peers.push(message.url)
} else if (item.client !== pubkey) {
sessionMap.set(item.client, {...item, peers: [message.url]})
}
}
}
sessions = Array.from(sessionMap.values())
}
const toggleMenu = (client: string) => {
menuClient = menuClient === client ? "" : client
}
const deleteSession = async (sessionItem: SessionWithPeers) => {
if (!isPomadeSession($session)) return
const closeMenu = () => {
menuClient = ""
}
deletingSession = sessionItem.client
let menuClient = $state("")
let sessions = $state<PomadeSessionWithPeers[]>([])
const deleteSession = async (sessionItem: PomadeSessionWithPeers) => {
if (!isPomadeSession($session)) return
try {
const client = new Client($session.clientOptions)
@@ -70,8 +49,6 @@
theme: "error",
message: "Failed to delete session",
})
} finally {
deletingSession = null
}
}
@@ -85,7 +62,9 @@
}
onMount(() => {
loadSessions()
loadOtherPomadeSessions().then(_sessions => {
sessions = _sessions || []
})
})
</script>
@@ -93,28 +72,46 @@
<div class="flex flex-col gap-4 border-t border-solid border-base-100 pt-4">
<strong>Other Sessions</strong>
{#each sessions as sessionItem (sessionItem.client)}
<div class="flex justify-between text-sm">
<div class="flex flex-col gap-1">
<span>{sessionItem.client.slice(0, 8)}</span>
<div class="flex gap-1">
<div class="badge badge-neutral">
Created {formatDate(sessionItem.created_at)}
</div>
<div class="badge badge-neutral">
Last active: {formatDate(sessionItem.last_activity)}
</div>
<div class="flex flex-col gap-2">
<div class="flex justify-between items-center">
<div class="flex gap-3 items-center text-sm">
<span>Session {sessionItem.client.slice(0, 8)}</span>
<span class="opacity-75">
{#if sessionItem.deactivated_at}
Deactivated
{/if}
</span>
</div>
<div class="relative">
<Button
class="btn btn-circle btn-ghost btn-sm"
onclick={() => toggleMenu(sessionItem.client)}>
<Icon icon={MenuDots} />
</Button>
{#if menuClient === sessionItem.client}
<Popover hideOnClick onClose={closeMenu}>
<ul
transition:fly
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
<li>
<Button onclick={() => deleteSession(sessionItem)}>
<Icon icon={TrashBin2} />
Delete Session
</Button>
</li>
</ul>
</Popover>
{/if}
</div>
</div>
<div class="flex gap-1">
<div class="badge badge-neutral">
Created {formatDate(sessionItem.created_at)}
</div>
<div class="badge badge-neutral">
Active {formatDate(sessionItem.last_activity)}
</div>
</div>
<Button
class="btn btn-error btn-sm"
disabled={deletingSession !== null}
onclick={() => deleteSession(sessionItem)}>
{#if deletingSession === sessionItem.client}
<span class="loading loading-spinner"></span>
{:else}
<Icon icon={TrashBin2} />
{/if}
</Button>
</div>
{/each}
</div>
+2 -9
View File
@@ -23,9 +23,8 @@
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import {INDEXER_RELAYS, PLATFORM_NAME, userSpaceUrls} from "@app/core/state"
import {kv, db} from "@app/core/storage"
import {pushToast} from "@app/util/toast"
import {Push} from "@app/util/notifications"
import {logout} from "@app/util/logout"
let progress: number | undefined = $state(undefined)
let confirmText = $state("")
@@ -88,13 +87,7 @@
await sleep(2000)
// Goodbye forever!
await Push.disable()
await kv.clear()
await db.clear()
localStorage.clear()
window.location.href = "/"
await logout()
}
const confirm = async () => {
+33 -6
View File
@@ -1,10 +1,12 @@
<script lang="ts">
import type {Profile} from "@welshman/util"
import {getTag, makeProfile} from "@welshman/util"
import {pubkey, profilesByPubkey} from "@welshman/app"
import {pubkey, profilesByPubkey, waitForThunkError} from "@welshman/app"
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
import {errorMessage} from "@lib/util"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
import {clearModals} from "@app/util/modal"
import {pushToast} from "@app/util/toast"
@@ -17,11 +19,33 @@
const back = () => history.back()
const onsubmit = ({profile, shouldBroadcast}: {profile: Profile; shouldBroadcast: boolean}) => {
updateProfile({profile, shouldBroadcast})
pushToast({message: "Your profile has been updated!"})
clearModals()
const onsubmit = async ({
profile,
shouldBroadcast,
}: {
profile: Profile
shouldBroadcast: boolean
}) => {
loading = true
try {
const error = await waitForThunkError(updateProfile({profile, shouldBroadcast}))
if (error) {
pushToast({
theme: "error",
message: `Failed to update your profile: ${errorMessage(error)}`,
})
} else {
pushToast({message: "Your profile has been updated!"})
clearModals()
}
} finally {
loading = false
}
}
let loading = $state(false)
</script>
<ProfileEditForm {initialValues} {onsubmit}>
@@ -30,6 +54,9 @@
<Icon icon={AltArrowLeft} />
Go Back
</Button>
<Button type="submit" class="btn btn-primary">Save Changes</Button>
<Button type="submit" class="btn btn-primary" disabled={loading}>
<Spinner {loading} />
Save Changes
</Button>
{/snippet}
</ProfileEditForm>
+6 -13
View File
@@ -1,15 +1,8 @@
<script lang="ts">
import type {ClientOptions} from "@pomade/core"
import type {Profile} from "@welshman/util"
import {
makeProfile,
makeSecret,
getPubkey,
RELAYS,
MESSAGING_RELAYS,
makeEvent,
} from "@welshman/util"
import {loginWithNip01, loginWithPomade, publishThunk} from "@welshman/app"
import {makeProfile, makeSecret, RELAYS, MESSAGING_RELAYS, makeEvent} from "@welshman/util"
import {loginWithNip01, publishThunk} from "@welshman/app"
import Key from "@assets/icons/key-minimalistic.svg?dataurl"
import Letter from "@assets/icons/letter.svg?dataurl"
import {getKey, setKey} from "@lib/implicit"
@@ -23,8 +16,6 @@
import SignUpEmail from "@app/components/SignUpEmail.svelte"
import SignUpProfile from "@app/components/SignUpProfile.svelte"
import SignUpComplete from "@app/components/SignUpComplete.svelte"
import {setChecked} from "@app/util/notifications"
import {pushModal, clearModals} from "@app/util/modal"
import {initProfile} from "@app/core/commands"
import {
POMADE_SIGNERS,
@@ -33,6 +24,9 @@
DEFAULT_RELAYS,
DEFAULT_MESSAGING_RELAYS,
} from "@app/core/state"
import {setChecked} from "@app/util/notifications"
import {loginWithPomade} from "@app/util/pomade"
import {pushModal, clearModals} from "@app/util/modal"
setKey("signup.email", "")
setKey("signup.secret", makeSecret())
@@ -73,10 +67,9 @@
complete: () => pushModal(SignUpComplete, {next: flows.email.finalize}),
finalize: () => {
const email = getKey<string>("signup.email")!
const secret = getKey<string>("signup.secret")!
const clientOptions = getKey<ClientOptions>("signup.clientOptions")!
loginWithPomade(getPubkey(secret), email, clientOptions)
loginWithPomade(clientOptions, email)
completeSignup()
},
},
+9 -2
View File
@@ -18,7 +18,7 @@
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
import SignUpEmailConfirm from "@app/components/SignUpEmailConfirm.svelte"
import {pushToast} from "@app/util/toast"
import {pushToast, popToast} from "@app/util/toast"
import {pushModal} from "@app/util/modal"
type Props = {
@@ -40,6 +40,11 @@
loading = true
try {
const toastId = pushToast({
timeout: 60_000,
message: "Creating your account, please wait...",
})
const secret = getKey<string>("signup.secret")!
const {clientOptions, ...registerRes} = await Client.register(2, 3, secret)
@@ -54,7 +59,8 @@
const setupRes = await client.setupRecovery(email, password)
if (!setupRes.ok) {
const message = setupRes.messages[0]?.res?.message || "Please try again."
const message =
setupRes.messages.find(m => m.res && !m.res?.ok)?.res?.message || "Please try again."
return pushToast({
theme: "error",
@@ -74,6 +80,7 @@
setKey("signup.email", email)
setKey("signup.clientOptions", clientOptions)
popToast(toastId)
pushModal(SignUpEmailConfirm, {next})
} catch (e) {
console.error(e)
+1 -1
View File
@@ -256,7 +256,7 @@
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
{/if}
{#each $userRooms as h, i (h)}
<SpaceMenuRoomItem {replaceState} {url} {h} />
<SpaceMenuRoomItem notify {replaceState} {url} {h} />
{/each}
{#if $otherRooms.length > 0}
<div class="h-2"></div>
@@ -3,11 +3,15 @@
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import SpaceMenu from "@app/components/SpaceMenu.svelte"
import {notifications} from "@app/util/notifications"
import {makeSpacePath} from "@app/util/routes"
import {pushDrawer} from "@app/util/modal"
import {deriveSocketStatus} from "@app/core/state"
const {url} = $props()
const path = makeSpacePath(url) + ":mobile"
const status = deriveSocketStatus(url)
const openMenu = () => pushDrawer(SpaceMenu, {url})
@@ -17,5 +21,7 @@
<Icon icon={MenuDots} />
{#if $status.theme !== "success"}
<div class="absolute right-0 top-0 -mr-1 -mt-1 h-2 w-2 rounded-full bg-{$status.theme}"></div>
{:else if $notifications.has(path)}
<div class="absolute right-0 top-0 -mr-1 -mt-1 h-2 w-2 rounded-full bg-primary"></div>
{/if}
</Button>
+7 -2
View File
@@ -4,16 +4,18 @@
import Icon from "@lib/components/Icon.svelte"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import RoomNameWithImage from "@app/components/RoomNameWithImage.svelte"
import {notifications} from "@app/util/notifications"
import {makeRoomPath} from "@app/util/routes"
import {deriveShouldNotify} from "@app/core/state"
interface Props {
url: any
h: any
notify?: boolean
replaceState?: boolean
}
const {url, h, replaceState = false}: Props = $props()
const {url, h, notify = false, replaceState = false}: Props = $props()
const path = makeRoomPath(url, h)
const shouldNotifyForSpace = deriveShouldNotify(url)
@@ -21,7 +23,10 @@
const showDifferenceIcon = $derived($shouldNotifyForRoom !== $shouldNotifyForSpace)
</script>
<SecondaryNavItem href={path} {replaceState}>
<SecondaryNavItem
href={path}
{replaceState}
notification={notify ? $notifications.has(path) : false}>
<RoomNameWithImage {url} {h} />
{#if showDifferenceIcon}
<Icon icon={$shouldNotifyForRoom ? VolumeLoud : VolumeCross} size={4} class="opacity-50" />
@@ -1,5 +1,8 @@
<script lang="ts">
import {makeProfile} from "@welshman/util"
import {getWalletAddress} from "@welshman/util"
import {userProfile, waitForThunkError, session} from "@welshman/app"
import {errorMessage} from "@lib/util"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import Modal from "@lib/components/Modal.svelte"
@@ -9,8 +12,7 @@
import ModalFooter from "@lib/components/ModalFooter.svelte"
import {updateProfile} from "@app/core/commands"
import {clearModals} from "@app/util/modal"
import {userProfile, session} from "@welshman/app"
import {makeProfile} from "@welshman/util"
import {pushToast} from "@app/util/toast"
const lud16 = getWalletAddress($session!.wallet!)
@@ -20,9 +22,13 @@
loading = true
try {
await updateProfile({profile: {...profile, lud16}})
const error = await waitForThunkError(updateProfile({profile: {...profile, lud16}}))
clearModals()
if (error) {
pushToast({theme: "error", message: `Failed to update profile: ${errorMessage(error)}`})
} else {
clearModals()
}
} finally {
loading = false
}
@@ -1,6 +1,7 @@
<script lang="ts">
import {getWalletAddress} from "@welshman/util"
import {session, userProfile} from "@welshman/app"
import {session, waitForThunkError, userProfile} from "@welshman/app"
import {errorMessage} from "@lib/util"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
@@ -17,7 +18,7 @@
const back = () => history.back()
let address = $state($userProfile?.lud16 || "")
let isLoading = $state(false)
let loading = $state(false)
const walletLud16 = $derived($session?.wallet ? getWalletAddress($session.wallet) : undefined)
@@ -28,20 +29,28 @@
}
const save = async () => {
isLoading = true
loading = true
try {
await updateProfile({
profile: {
...$userProfile,
lud06: undefined,
lud16: address.trim() || undefined,
},
})
back()
const error = await waitForThunkError(
updateProfile({
profile: {
...$userProfile,
lud06: undefined,
lud16: address.trim() || undefined,
},
}),
)
if (error) {
pushToast({theme: "error", message: `Failed to update profile: ${errorMessage(error)}`})
} else {
back()
}
} catch (error) {
pushToast({theme: "error", message: "Failed to update profile"})
} finally {
isLoading = false
loading = false
}
}
</script>
@@ -61,7 +70,7 @@
placeholder="user@domain.com"
bind:value={address}
class="input input-bordered flex w-full"
disabled={isLoading} />
disabled={loading} />
<p class="text-xs opacity-75">
You can enter one manually or use your connected wallet's address (if available). Leave
empty to remove your lightning address
@@ -78,7 +87,7 @@
</div>
<p class="text-xs opacity-75">{walletLud16}</p>
</div>
<Button class="btn btn-outline btn-sm" onclick={useWalletAddress} disabled={isLoading}>
<Button class="btn btn-outline btn-sm" onclick={useWalletAddress} disabled={loading}>
Use This
</Button>
</div>
@@ -87,9 +96,9 @@
</div>
</ModalBody>
<ModalFooter>
<Button class="btn btn-neutral" onclick={back} disabled={isLoading}>Cancel</Button>
<Button class="btn btn-primary" onclick={save} disabled={isLoading}>
{#if isLoading}
<Button class="btn btn-neutral" onclick={back} disabled={loading}>Cancel</Button>
<Button class="btn btn-primary" onclick={save} disabled={loading}>
{#if loading}
<span class="loading loading-spinner loading-sm"></span>
{:else}
<Icon icon={CheckCircle} />
+2 -2
View File
@@ -676,7 +676,7 @@ export const initProfile = (profile: Profile) => {
return publishThunk({event, relays: []})
}
export const updateProfile = async ({
export const updateProfile = ({
profile,
shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || []),
}: {
@@ -697,5 +697,5 @@ export const updateProfile = async ({
const event = makeEvent(template.kind, template)
const relays = router.merge(scenarios).getUrls()
await publishThunk({event, relays}).complete
return publishThunk({event, relays})
}
+14
View File
@@ -0,0 +1,14 @@
import {kv, db} from "@app/core/storage"
import {Push} from "@app/util/notifications"
import {deactivateCurrentPomadeSession} from "@app/util/pomade"
export const logout = async () => {
await deactivateCurrentPomadeSession()
await Push.disable()
await kv.clear()
await db.clear()
localStorage.clear()
window.location.href = "/"
}
+37 -3
View File
@@ -12,12 +12,14 @@ import {
repository,
publishThunk,
loadRelay,
relaysByUrl,
waitForThunkError,
userMessagingRelayList,
} from "@welshman/app"
import {
on,
call,
find,
assoc,
poll,
prop,
@@ -44,7 +46,14 @@ import {
Address,
} from "@welshman/util"
import {buildUrl} from "@lib/util"
import {makeSpacePath, makeChatPath, getEventPath, goToEvent} from "@app/util/routes"
import {
makeSpacePath,
makeRoomPath,
makeSpaceChatPath,
makeChatPath,
getEventPath,
goToEvent,
} from "@app/util/routes"
import {
DM_KINDS,
CONTENT_KINDS,
@@ -57,9 +66,11 @@ import {
userSettingsValues,
userGroupList,
getSpaceUrlsFromGroupList,
getSpaceRoomsFromGroupList,
makeCommentFilter,
userSpaceUrls,
shouldNotify,
hasNip29,
device,
} from "@app/core/state"
import {kv} from "@app/core/storage"
@@ -125,6 +136,7 @@ export const allNotifications = derived(
pubkey,
checked,
chatsById,
relaysByUrl,
userGroupList,
deriveEventsByIdByUrl({
tracker,
@@ -135,7 +147,7 @@ export const allNotifications = derived(
identity,
),
),
([$pubkey, $checked, $chatsById, $userGroupList, eventsByIdByUrl]) => {
([$pubkey, $checked, $chatsById, $relaysByUrl, $userGroupList, eventsByIdByUrl]) => {
const hasNotification = (path: string, latestEvent?: TrustedEvent) => {
if (!latestEvent || latestEvent.pubkey === $pubkey) {
return false
@@ -168,12 +180,34 @@ export const allNotifications = derived(
for (const url of getSpaceUrlsFromGroupList($userGroupList)) {
const spacePath = makeSpacePath(url)
const spacePathMobile = spacePath + ":mobile"
const eventsById = eventsByIdByUrl.get(url) || new Map()
const latestEvent = first(sortEventsDesc(eventsById.values()))
if (hasNotification(spacePath, latestEvent)) {
paths.add(spacePath)
}
if (hasNip29($relaysByUrl.get(url))) {
for (const h of getSpaceRoomsFromGroupList(url, $userGroupList)) {
const roomPath = makeRoomPath(url, h)
const latestEvent = find(e => e.tags.some(spec(["h", h])), eventsById.values())
if (hasNotification(roomPath, latestEvent)) {
paths.add(spacePathMobile)
paths.add(spacePath)
paths.add(roomPath)
}
}
} else {
const messagesPath = makeSpaceChatPath(url)
if (hasNotification(messagesPath, first(eventsById.values()))) {
paths.add(spacePathMobile)
paths.add(spacePath)
paths.add(messagesPath)
}
}
}
return paths
@@ -268,7 +302,7 @@ class CapacitorNotifications implements IPushAdapter {
async request(prompt = true) {
let status = await PushNotifications.checkPermissions()
if (prompt && status.receive === "prompt") {
if (prompt && ["prompt", "prompt-with-rationale"].includes(status.receive)) {
status = await PushNotifications.requestPermissions()
}
+78
View File
@@ -0,0 +1,78 @@
import {get} from "svelte/store"
import {Client, type SessionItem, type ClientOptions} from "@pomade/core"
import {ifLet, reject, spec} from "@welshman/lib"
import {session, isPomadeSession, loginWithPomade as _loginWithPomade} from "@welshman/app"
export const getPomadeClient = async () => {
const $session = get(session)
if (isPomadeSession($session)) {
return new Client($session.clientOptions)
}
}
export type PomadeSessionWithPeers = SessionItem & {peers: string[]}
export const loadPomadeSessions = async () => {
const sessionMap = new Map<string, PomadeSessionWithPeers>()
const client = await getPomadeClient()
if (client) {
const result = await client.listSessions()
for (const message of result.messages) {
if (!message.res?.items) continue
for (const item of message.res.items) {
const existing = sessionMap.get(item.client)
if (existing) {
existing.peers.push(message.url)
} else {
sessionMap.set(item.client, {...item, peers: [message.url]})
}
}
}
}
return Array.from(sessionMap.values())
}
export const loadOtherPomadeSessions = async () => {
const client = await getPomadeClient()
if (!client) {
return []
}
return reject(spec({client: await client.getPubkey()}), await loadPomadeSessions())
}
export const deletePomadeSession = async (clientPubkey: string, peers: string[]) =>
ifLet(await getPomadeClient(), client => client.deleteSession(clientPubkey, peers))
export const deactivatePomadeSession = async (clientPubkey: string, peers: string[]) =>
ifLet(await getPomadeClient(), client => client.deactivateSession(clientPubkey, peers))
export const deleteCurrentPomadeSession = async () =>
ifLet(await getPomadeClient(), async client =>
client.deleteSession(await client.getPubkey(), client.peers),
)
export const deactivateCurrentPomadeSession = async () =>
ifLet(await getPomadeClient(), async client =>
client.deactivateSession(await client.getPubkey(), client.peers),
)
export const deleteDeactivatedPomadeSessions = async () => {
const sessions = await loadOtherPomadeSessions()
for (const item of sessions || []) {
if (item.deactivated_at) {
await deletePomadeSession(item.client, item.peers)
}
}
}
export const loginWithPomade = (clientOptions: ClientOptions, email: string) =>
_loginWithPomade(clientOptions.group.group_pk.slice(2), email, clientOptions)
+2 -2
View File
@@ -38,7 +38,7 @@
class:text-base-content={active}
class:bg-base-100={active}>
{@render children?.()}
{#if !active && notification}
{#if notification}
<div class="absolute right-2 top-5 h-2 w-2 rounded-full bg-primary" transition:fade></div>
{/if}
</a>
@@ -48,7 +48,7 @@
class="{restProps.class} relative flex w-full items-center gap-3 text-left transition-all hover:bg-base-100 hover:text-base-content"
class:text-base-content={active}
class:bg-base-100={active}>
{#if !active && notification}
{#if notification}
<div class="absolute right-2 top-5 h-2 w-2 rounded-full bg-primary" transition:fade></div>
{/if}
{@render children?.()}
@@ -0,0 +1,77 @@
<script lang="ts">
import {writable} from "svelte/store"
import type {Writable} from "svelte/store"
import {remove, uniq} from "@welshman/lib"
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
interface Props {
value: string[]
term?: Writable<string>
placeholder?: string
}
let {value = $bindable(), term = writable(""), placeholder = ""}: Props = $props()
const normalizeItem = (text: string) => text.trim()
const addItems = (text: string) => {
const items = text.split(/[\n,]/).map(normalizeItem).filter(Boolean)
if (items.length > 0) {
value = uniq([...value, ...items])
}
term.set("")
}
const removeItem = (item: string) => {
value = remove(item, value)
}
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === "Enter" && $term) {
e.preventDefault()
addItems($term)
}
}
const onPaste = (e: ClipboardEvent) => {
const text = e.clipboardData?.getData("text")
if (text) {
e.preventDefault()
addItems(text)
}
}
const onBlur = () => {
if ($term.trim()) {
addItems($term)
}
}
</script>
<div class="flex flex-col gap-2">
<div>
{#each value as item (item)}
<div class="flex-inline badge badge-neutral mr-1 gap-1">
<Button class="flex items-center" onclick={() => removeItem(item)}>
<Icon icon={CloseCircle} size={4} class="-ml-1 mt-px" />
</Button>
<span>{item}</span>
</div>
{/each}
</div>
<label class="input input-bordered flex w-full items-center gap-2">
<input
bind:value={$term}
class="grow"
type="text"
{placeholder}
onkeydown={onKeyDown}
onpaste={onPaste}
onblur={onBlur} />
</label>
</div>
+39 -15
View File
@@ -1,12 +1,14 @@
<script lang="ts">
import * as nip19 from "nostr-tools/nip19"
import {Client} from "@pomade/core"
import {hexToBytes} from "@welshman/lib"
import {displayPubkey, displayProfile} from "@welshman/util"
import {pubkey, session, displayNip05, deriveProfile} from "@welshman/app"
import {pubkey, session, SessionMethod, displayNip05, deriveProfile} from "@welshman/app"
import {slideAndFade} from "@lib/transition"
import PenNewSquare from "@assets/icons/pen-new-square.svg?dataurl"
import UserRounded from "@assets/icons/user-rounded.svg?dataurl"
import Key from "@assets/icons/key-minimalistic.svg?dataurl"
import Letter from "@assets/icons/letter.svg?dataurl"
import LinkRound from "@assets/icons/link-round.svg?dataurl"
import Copy from "@assets/icons/copy.svg?dataurl"
import Settings from "@assets/icons/settings.svg?dataurl"
@@ -16,15 +18,16 @@
import Icon from "@lib/components/Icon.svelte"
import FieldInline from "@lib/components/FieldInline.svelte"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import ProfileCircle from "@app/components/ProfileCircle.svelte"
import ContentMinimal from "@app/components/ContentMinimal.svelte"
import ProfileEdit from "@app/components/ProfileEdit.svelte"
import ProfileDelete from "@app/components/ProfileDelete.svelte"
import SignerStatus from "@app/components/SignerStatus.svelte"
import PasswordReset from "@app/components/PasswordReset.svelte"
import InfoKeys from "@app/components/InfoKeys.svelte"
import {PLATFORM_NAME} from "@app/core/state"
import {pushModal} from "@app/util/modal"
import {clip} from "@app/util/toast"
import {clip, pushToast} from "@app/util/toast"
const npub = nip19.npubEncode($pubkey!)
const profile = deriveProfile($pubkey!)
@@ -38,9 +41,29 @@
const startDelete = () => pushModal(ProfileDelete)
const startPasswordReset = async () => {
loading = true
try {
const {ok, peersByPrefix} = await Client.requestChallenge($session!.email)
if (!ok) {
pushToast({
theme: "error",
message: "Failed to initiate password reset!",
})
}
pushModal(PasswordReset, {peersByPrefix})
} finally {
loading = false
}
}
const startRecovery = () => pushModal(InfoKeys)
let showAdvanced = false
let loading = $state(false)
let showAdvanced = $state(false)
</script>
<div class="content column gap-4">
@@ -69,10 +92,11 @@
<ContentMinimal event={{content: $profile?.about || "", tags: []}} />
{/key}
</div>
{#if $session?.email}
<div class="card2 bg-alt col-4 shadow-md">
<div class="card2 bg-alt col-4 shadow-md">
{#if $session?.method === SessionMethod.Pomade}
<FieldInline>
{#snippet label()}
<Icon icon={Letter} />
<p>Email Address</p>
{/snippet}
{#snippet input()}
@@ -81,16 +105,8 @@
<input readonly value={$session.email} class="grow" />
</label>
{/snippet}
{#snippet info()}
<p>
Your email and password can only be used to log into {PLATFORM_NAME}.
<Button class="link" onclick={startRecovery}>Start holding your own keys</Button>
</p>
{/snippet}
</FieldInline>
</div>
{/if}
<div class="card2 bg-alt col-4 shadow-md">
{/if}
<FieldInline>
{#snippet label()}
<p class="flex items-center gap-3">
@@ -139,6 +155,14 @@
</FieldInline>
{/if}
<SignerStatus />
{#if $session?.method === SessionMethod.Pomade}
<div class="flex gap-2 justify-end">
<Button class="btn" onclick={startPasswordReset}>
<Spinner {loading}>Update your password</Spinner>
</Button>
<Button class="btn btn-primary" onclick={startRecovery}>Start holding your own keys</Button>
</div>
{/if}
</div>
<div class="card2 bg-alt shadow-md">
<div class="flex items-center justify-between">
+1 -1
View File
@@ -337,7 +337,7 @@
}
const onEditPrevious = () => {
const prev = $events.find(e => e.pubkey === $pubkey)
const prev = $events.toReversed().find(e => e.pubkey === $pubkey)
if (prev && canEditEvent(prev)) {
onEditEvent(prev)
+1 -1
View File
@@ -273,7 +273,7 @@
}
const onEditPrevious = () => {
const prev = $events.find(e => e.pubkey === $pubkey)
const prev = $events.toReversed().find(e => e.pubkey === $pubkey)
if (prev && canEditEvent(prev)) {
onEditEvent(prev)
+1 -1
View File
@@ -2,7 +2,7 @@ import {config} from "dotenv"
import daisyui from "daisyui"
import themes from "daisyui/src/theming/themes"
config({path: ".env"})
config({path: ".env.local"})
config({path: ".env.template"})
/** @type {import('tailwindcss').Config} */
+1 -1
View File
@@ -4,7 +4,7 @@ import {SvelteKitPWA} from "@vite-pwa/sveltekit"
import {sveltekit} from "@sveltejs/kit/vite"
import svg from "@poppanator/sveltekit-svg"
config({path: ".env"})
config({path: ".env.local"})
config({path: ".env.template"})
export default defineConfig({