Fix agent errors
This commit is contained in:
parent
a2c5a8e2ff
commit
8953b0e04d
11 changed files with 52 additions and 37 deletions
|
|
@ -124,11 +124,12 @@ Conventions below.
|
|||
- Do not define svelte event handlers inline, instead name them and put them in the script section of templates
|
||||
- Write a `{#if}`/`{:else if}` chain rather than hoisting display strings into a lookup `Record` in the script section.
|
||||
- Avoid using `as`, except where necessary. Instead, annotate function parameters, and ensure upstream values are typed correctly.
|
||||
- Instead of `getTag(tagName, event.tags)?.[1] || ""`, use `getTagValue(tagName, event.tags)`
|
||||
- To read a tag, use `getTagValue(tagName, event.tags)` (or `getTagValues` for all matches) rather than reaching into the tag array yourself — that means no `getTag(tagName, event.tags)?.[1] || ""` and no `event.tags.find(nthEq(0, tagName))?.[1]`. `getTagValue` is exactly the latter, so the replacement is behavior-preserving, `undefined` included. Reserve `nthEq` for cases with no `getTag*` equivalent, such as `partition(nthEq(0, "imeta"), tags)`.
|
||||
- Do not render a profile's `about` directly (e.g. `profile.about`); use the `ProfileAbout` component instead.
|
||||
- Use `type Props` instead of interface when defining props for svelte components.
|
||||
- When a component's value/prop shape mirrors a subset of an existing type, derive it with `Pick`/`Partial` and `export` that type from the component's `<script module>` (e.g. a `Values` type) for callers to import, instead of re-enumerating its sub-properties.
|
||||
- Avoid pass-through functions except when the wrapper is part of an abstraction. `x => y()` is not ok, but `x => this.impl.y()` is ok, for example.
|
||||
- For durations and timestamps, use `@welshman/lib`'s time helpers and constants (`MINUTE`, `HOUR`, `DAY`, `WEEK`, `MONTH`, `YEAR`) rather than raw milliseconds: `int(5, MINUTE)` for a duration in seconds, `ago(5, MINUTE)` for a past timestamp, `now()` for the current one, and `ms()`/`ms(int(...))` only where a browser API needs milliseconds. So `checkedAt < ago(5, MINUTE)` instead of `checkedAt < Date.now() - 300_000`. Write these count-first (`int(3, MONTH)`, `ago(2, WEEK)`) — the declared parameter order is `(unit, count)`, but the product is the same either way and every call site in this repo reads count-first. Nostr timestamps are seconds, so prefer `now()` over `Date.now()` for anything stored on an event.
|
||||
- When declaring variables in a svelte component, the order should generally be: props, constants derived from props/state, functions declared with `const`, mutable variables declared with `let`, effects, onMount. This order may vary due to dependencies, but should generally be adhered to.
|
||||
|
||||
**Human-First Simplicity:**
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import {addSpace, userSpaceUrls} from "@app/groups"
|
|||
import {relaysMostlyRestricted} from "@app/policies"
|
||||
import {broadcastUserData} from "@app/profiles"
|
||||
import {Push} from "@app/push"
|
||||
import {resyncApplicationData} from "@app/sync"
|
||||
import {syncApplicationData} from "@app/sync"
|
||||
import {notificationSettings, setSpaceNotifications} from "@app/settings"
|
||||
import {deriveSocket} from "@app/relays"
|
||||
|
||||
|
|
@ -193,15 +193,11 @@ export const attemptRelayAccess = async (url: string, claim = "") => {
|
|||
return `Failed to connect`
|
||||
}
|
||||
|
||||
// Relays send their challenge right after the socket opens, so if none shows up
|
||||
// shortly the relay doesn't use auth and we can go ahead and publish.
|
||||
await poll({
|
||||
signal: AbortSignal.timeout(800),
|
||||
signal: AbortSignal.timeout(3000),
|
||||
condition: () => socket.auth.status === AuthStatus.Requested,
|
||||
})
|
||||
|
||||
// Stop at any terminal status — retrying a denied signature or a forbidden response
|
||||
// just re-prompts the user's signer for an answer we already have.
|
||||
for (let i = 0; i < 3 && !authTerminalStatuses.includes(socket.auth.status); i++) {
|
||||
await socket.auth.retryAuth(sign)
|
||||
await waitForAuth(socket)
|
||||
|
|
@ -298,7 +294,7 @@ export class Access {
|
|||
await this.configureNotifications(notifications)
|
||||
await addSpace(this.url)
|
||||
this.clearRestricted()
|
||||
resyncApplicationData()
|
||||
syncApplicationData()
|
||||
broadcastUserData([this.url])
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script lang="ts">
|
||||
import {fromNostrURI} from "@welshman/util"
|
||||
import {nthEq} from "@welshman/lib"
|
||||
import {fromNostrURI, getTagValue} from "@welshman/util"
|
||||
import {
|
||||
parse,
|
||||
truncate,
|
||||
|
|
@ -107,7 +106,7 @@
|
|||
const warning = $derived(
|
||||
warningDismissed
|
||||
? undefined
|
||||
: $userSettingsValues.hide_sensitive && event.tags.find(nthEq(0, "content-warning"))?.[1],
|
||||
: $userSettingsValues.hide_sensitive && getTagValue("content-warning", event.tags),
|
||||
)
|
||||
|
||||
const dropWhile = <T,>(f: (x: T) => boolean, xs: Iterable<T>) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script lang="ts">
|
||||
import cx from "classnames"
|
||||
import {fromNostrURI} from "@welshman/util"
|
||||
import {nthEq} from "@welshman/lib"
|
||||
import {fromNostrURI, getTagValue} from "@welshman/util"
|
||||
import {
|
||||
parse,
|
||||
truncate,
|
||||
|
|
@ -72,7 +71,7 @@
|
|||
const warning = $derived(
|
||||
warningDismissed
|
||||
? undefined
|
||||
: $userSettingsValues.hide_sensitive && event.tags.find(nthEq(0, "content-warning"))?.[1],
|
||||
: $userSettingsValues.hide_sensitive && getTagValue("content-warning", event.tags),
|
||||
)
|
||||
|
||||
const dropWhile = <T,>(f: (x: T) => boolean, xs: Iterable<T>) => {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
sortEventsAsc,
|
||||
} from "@welshman/util"
|
||||
import type {Filter, ManagementRequest, PublishedRoomMeta, TrustedEvent} from "@welshman/util"
|
||||
import {first, simpleCache, sortBy, spec, uniq} from "@welshman/lib"
|
||||
import {ago, first, MINUTE, now, simpleCache, sortBy, spec, uniq} from "@welshman/lib"
|
||||
import {addRoomMember, manageRelay, pubkey, waitForThunkError} from "@welshman/app"
|
||||
import {load} from "@welshman/net"
|
||||
import {get} from "svelte/store"
|
||||
|
|
@ -260,8 +260,8 @@ export const deriveUserIsSpaceAdmin = simpleCache(([url]: [string | undefined])
|
|||
let checkedAt = 0
|
||||
|
||||
return readable(false, set => {
|
||||
if (url && checkedAt < Date.now() - 300_000) {
|
||||
checkedAt = Date.now()
|
||||
if (url && checkedAt < ago(5, MINUTE)) {
|
||||
checkedAt = now()
|
||||
|
||||
manageRelay(url, {method: ManagementMethod.SupportedMethods, params: []})
|
||||
.then(({result}) => set(Boolean(result?.length)))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import {get} from "svelte/store"
|
|||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {goto} from "$app/navigation"
|
||||
import {page} from "$app/stores"
|
||||
import {nthEq} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {getAddress} from "@welshman/util"
|
||||
import {tracker, userMessagingRelayList, getRelay} from "@welshman/app"
|
||||
|
|
@ -206,9 +205,9 @@ export const getEventPath = (event: TrustedEvent, urls: string[]) => {
|
|||
return makeMessagePath(url, event)
|
||||
}
|
||||
|
||||
const address = event.tags.find(nthEq(0, "A"))?.[1]
|
||||
const kind = event.tags.find(nthEq(0, "K"))?.[1]
|
||||
const id = event.tags.find(nthEq(0, "E"))?.[1]
|
||||
const address = getTagValue("A", event.tags)
|
||||
const kind = getTagValue("K", event.tags)
|
||||
const id = getTagValue("E", event.tags)
|
||||
|
||||
if (id && kind) {
|
||||
if (parseInt(kind) === ZAP_GOAL) {
|
||||
|
|
|
|||
|
|
@ -472,17 +472,14 @@ const syncDMs = () => {
|
|||
let unsubscribe: Unsubscriber | undefined
|
||||
|
||||
export const syncApplicationData = () => {
|
||||
unsubscribe?.()
|
||||
|
||||
const unsubscribers = [syncRelays(), syncUserData(), syncSpaces(), syncDMs()]
|
||||
|
||||
unsubscribe = () => unsubscribers.forEach(call)
|
||||
}
|
||||
|
||||
export const stopApplicationDataSync = () => {
|
||||
unsubscribe?.()
|
||||
unsubscribe = undefined
|
||||
}
|
||||
|
||||
export const resyncApplicationData = () => {
|
||||
stopApplicationDataSync()
|
||||
syncApplicationData()
|
||||
return () => {
|
||||
unsubscribe?.()
|
||||
unsubscribe = undefined
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -363,6 +363,29 @@ body.keyboard-open .room__compose {
|
|||
@apply underline;
|
||||
}
|
||||
|
||||
/* date picker. @svelte-plugins/datepicker renders its own markup, so these class
|
||||
names appear nowhere in src/ — don't delete them on a grep. */
|
||||
.picker {
|
||||
--date-picker-foreground: var(--content);
|
||||
--date-picker-background: var(--surface-more);
|
||||
--date-picker-highlight-border: var(--primary);
|
||||
--date-picker-selected-color: var(--primary-content);
|
||||
--date-picker-selected-background: var(--primary);
|
||||
}
|
||||
.date-time-field {
|
||||
@apply bg-surface rounded-2xl px-0;
|
||||
border: var(--border-thin) solid var(--line);
|
||||
}
|
||||
.date-time-field input {
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
border-radius: var(--radius-2xl) !important;
|
||||
border: none !important;
|
||||
background: inherit !important;
|
||||
color: inherit !important;
|
||||
padding: 0.7rem 1rem !important;
|
||||
}
|
||||
|
||||
/* tippy popover */
|
||||
.tippy-target {
|
||||
@apply z-tooltip pointer-events-none fixed inset-0;
|
||||
|
|
|
|||
|
|
@ -39,4 +39,9 @@
|
|||
@import "./space-menu.css";
|
||||
@import "./tooltip.css";
|
||||
|
||||
/* SocketStatusIndicator builds its class as bg-{status.theme}, which the source
|
||||
scanner can't see. These are the themes deriveSocketStatus can return. Kept
|
||||
below every @import, since an @import after another at-rule is invalid. */
|
||||
@source inline("bg-success bg-warning bg-error bg-gray-500");
|
||||
|
||||
@config "../../../tailwind.config.js";
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
import {getSetting, userSettings, notificationSettings} from "@app/settings"
|
||||
import {DUFFLEPUD_URL, DEFAULT_RELAYS, INDEXER_RELAYS, POMADE_SIGNERS} from "@app/env"
|
||||
import {pushState} from "@app/push/adapters/common"
|
||||
import {syncApplicationData, resyncApplicationData, stopApplicationDataSync} from "@app/sync"
|
||||
import {syncApplicationData} from "@app/sync"
|
||||
import * as groups from "@app/groups"
|
||||
import * as comments from "@app/comments"
|
||||
import * as deletes from "@app/deletes"
|
||||
|
|
@ -250,9 +250,7 @@
|
|||
unsubscribers.push(() => defaultSocketPolicies.splice(-policies.length))
|
||||
|
||||
// History, navigation, application data
|
||||
syncApplicationData()
|
||||
|
||||
unsubscribers.push(setupHistory(), setupAnalytics(), stopApplicationDataSync)
|
||||
unsubscribers.push(setupHistory(), setupAnalytics(), syncApplicationData())
|
||||
|
||||
// Initialize keyboard state tracking
|
||||
unsubscribers.push(syncKeyboard())
|
||||
|
|
@ -277,7 +275,7 @@
|
|||
if ($pubkey !== lastPubkey) {
|
||||
lastPubkey = $pubkey
|
||||
Pool.get().clear()
|
||||
resyncApplicationData()
|
||||
syncApplicationData()
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
export default {
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
darkMode: ["selector", '[data-theme="dark"]'],
|
||||
// dynamic socket-status classes (bg-{$status.theme}) the scanner can't see
|
||||
safelist: ["w-4", "h-4", "bg-success", "bg-warning", "bg-error", "bg-gray-500"],
|
||||
theme: {
|
||||
zIndex: {
|
||||
none: 0,
|
||||
|
|
|
|||
Loading…
Reference in a new issue