mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-06 21:02:28 +00:00
Fix Netlify build by restoring dist build script and config
- Restore `scripts/build-dist.mjs` to clean `dist/`, build CSS, and copy assets. - Update `package.json` to use the new build script and serve `dist`. - Update `netlify.toml` to publish the `dist` directory. - Update `dist/` artifacts to match current source. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
a432d3d4c0
commit
c862cbc358
72 files changed
+1555
-5883
No files matched your search
Vendored
+32
-177
@@ -5,7 +5,7 @@ import {
|
||||
requestDefaultExtensionPermissions,
|
||||
} from "./nostrClientFacade.js";
|
||||
import { convertEventToVideo as sharedConvertEventToVideo } from "./nostr/index.js";
|
||||
import { normalizeNostrPubkey, sanitizeRelayList } from "./nostr/nip46Client.js";
|
||||
import { normalizeNostrPubkey } from "./nostr/nip46Client.js";
|
||||
import {
|
||||
listVideoViewEvents,
|
||||
subscribeVideoViewEvents,
|
||||
@@ -31,16 +31,11 @@ import { devLogger, userLogger } from "./utils/logger.js";
|
||||
import moderationService from "./services/moderationService.js";
|
||||
import nostrService from "./services/nostrService.js";
|
||||
import { profileCache } from "./state/profileCache.js";
|
||||
import {
|
||||
DEFAULT_NIP07_ENCRYPTION_METHODS,
|
||||
runNip07WithRetry,
|
||||
NIP07_PRIORITY,
|
||||
} from "./nostr/nip07Permissions.js";
|
||||
import { relaySubscriptionService } from "./services/relaySubscriptionService.js";
|
||||
import { runNip07WithRetry, NIP07_PRIORITY } from "./nostr/nip07Permissions.js";
|
||||
|
||||
const SUBSCRIPTION_SET_KIND =
|
||||
getNostrEventSchema(NOTE_TYPES.SUBSCRIPTION_LIST)?.kind ?? 30000;
|
||||
const DECRYPT_TIMEOUT_MS = 15000;
|
||||
const DECRYPT_TIMEOUT_MS = 90000;
|
||||
const DECRYPT_RETRY_DELAY_MS = 10000;
|
||||
|
||||
function normalizeHexPubkey(value) {
|
||||
@@ -334,12 +329,10 @@ class SubscriptionsManager {
|
||||
this.currentUserPubkey = null;
|
||||
this.loaded = false;
|
||||
this.loadingPromise = null;
|
||||
this.backgroundLoading = false;
|
||||
this.subscriptionListView = null;
|
||||
this.lastRunOptions = null;
|
||||
this.lastResult = null;
|
||||
this.lastContainerId = null;
|
||||
this.lastLoadError = null;
|
||||
this.unsubscribeFromNostrUpdates = null;
|
||||
this.pendingRefreshPromise = null;
|
||||
this.scheduledRefreshDetail = null;
|
||||
@@ -348,7 +341,6 @@ class SubscriptionsManager {
|
||||
this.emitter = new TinyEventEmitter();
|
||||
this.decryptRetryTimeoutId = null;
|
||||
this.ensureNostrServiceListener();
|
||||
this.subscriptionKey = null;
|
||||
|
||||
profileCache.subscribe((event, detail) => {
|
||||
if (event === "profileChanged") {
|
||||
@@ -358,9 +350,7 @@ class SubscriptionsManager {
|
||||
} else if (event === "runtimeCleared" && detail.pubkey === this.currentUserPubkey) {
|
||||
this.reset();
|
||||
if (this.currentUserPubkey) {
|
||||
this.loadSubscriptions(this.currentUserPubkey, {
|
||||
allowPermissionPrompt: false,
|
||||
});
|
||||
this.loadSubscriptions(this.currentUserPubkey);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -369,13 +359,12 @@ class SubscriptionsManager {
|
||||
/**
|
||||
* Decrypt the subscription list from kind=30000 (d="subscriptions").
|
||||
*/
|
||||
async loadSubscriptions(userPubkey, options = {}) {
|
||||
async loadSubscriptions(userPubkey) {
|
||||
if (!userPubkey) {
|
||||
userLogger.warn("[SubscriptionsManager] No pubkey => cannot load subs.");
|
||||
return;
|
||||
}
|
||||
|
||||
const allowPermissionPrompt = options?.allowPermissionPrompt !== false;
|
||||
const normalizedUserPubkey = normalizeHexPubkey(userPubkey) || userPubkey;
|
||||
|
||||
// 1. Attempt to load from cache first
|
||||
@@ -390,25 +379,14 @@ class SubscriptionsManager {
|
||||
this.loaded = true;
|
||||
|
||||
// Trigger background update
|
||||
if (!allowPermissionPrompt && !this.backgroundLoading) {
|
||||
this.backgroundLoading = true;
|
||||
this.emitter.emit("change", {
|
||||
action: "background-loading",
|
||||
subscribedPubkeys: Array.from(this.subscribedPubkeys),
|
||||
background: true,
|
||||
});
|
||||
} else if (allowPermissionPrompt) {
|
||||
this.backgroundLoading = false;
|
||||
}
|
||||
|
||||
this.updateFromRelays(userPubkey, { allowPermissionPrompt }).catch((err) => {
|
||||
this.updateFromRelays(userPubkey).catch((err) => {
|
||||
devLogger.warn("[SubscriptionsManager] Background update failed:", err);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. If no cache, must wait for relays
|
||||
await this.updateFromRelays(userPubkey, { allowPermissionPrompt });
|
||||
await this.updateFromRelays(userPubkey);
|
||||
}
|
||||
|
||||
saveToCache(userPubkey) {
|
||||
@@ -424,7 +402,7 @@ class SubscriptionsManager {
|
||||
return this.emitter.on(eventName, handler);
|
||||
}
|
||||
|
||||
scheduleDecryptRetry(userPubkey, error, options = {}) {
|
||||
scheduleDecryptRetry(userPubkey, error) {
|
||||
const normalized = normalizeHexPubkey(userPubkey) || userPubkey;
|
||||
if (!normalized) {
|
||||
return;
|
||||
@@ -437,7 +415,7 @@ class SubscriptionsManager {
|
||||
if (this.currentUserPubkey && this.currentUserPubkey !== normalized) {
|
||||
return;
|
||||
}
|
||||
this.updateFromRelays(normalized, options).catch((retryError) => {
|
||||
this.updateFromRelays(normalized).catch((retryError) => {
|
||||
userLogger.warn("[SubscriptionsManager] Decryption retry failed:", retryError);
|
||||
});
|
||||
}, DECRYPT_RETRY_DELAY_MS);
|
||||
@@ -447,14 +425,11 @@ class SubscriptionsManager {
|
||||
);
|
||||
}
|
||||
|
||||
async updateFromRelays(userPubkey, options = {}) {
|
||||
async updateFromRelays(userPubkey) {
|
||||
if (!userPubkey) return;
|
||||
|
||||
try {
|
||||
const allowPermissionPrompt = options?.allowPermissionPrompt !== false;
|
||||
const wasBackgroundLoading = this.backgroundLoading;
|
||||
const normalizedUserPubkey = normalizeHexPubkey(userPubkey) || userPubkey;
|
||||
this.lastLoadError = null;
|
||||
|
||||
const readRelays = relayManager.getReadRelayUrls();
|
||||
const relayUrls = readRelays.length > 0 ? readRelays : Array.from(DEFAULT_RELAY_URLS);
|
||||
@@ -462,26 +437,8 @@ class SubscriptionsManager {
|
||||
devLogger.warn(
|
||||
"[SubscriptionsManager] No relay URLs available while loading subscriptions.",
|
||||
);
|
||||
if (wasBackgroundLoading) {
|
||||
this.backgroundLoading = false;
|
||||
this.emitter.emit("change", {
|
||||
action: "background-loaded",
|
||||
subscribedPubkeys: Array.from(this.subscribedPubkeys),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!nostrClient?.pool && typeof nostrClient?.ensurePool === "function") {
|
||||
try {
|
||||
await nostrClient.ensurePool();
|
||||
} catch (error) {
|
||||
devLogger.warn(
|
||||
"[SubscriptionsManager] Failed to initialize relay pool for subscription",
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
this.ensureSubscriptionListSubscription(normalizedUserPubkey, relayUrls);
|
||||
|
||||
// Use incremental fetch helper
|
||||
const cachedSnapshot = parseCachedSubscriptionSnapshot(
|
||||
@@ -493,7 +450,7 @@ class SubscriptionsManager {
|
||||
pubkey: normalizedUserPubkey,
|
||||
dTag: SUBSCRIPTION_LIST_IDENTIFIER,
|
||||
relayUrls,
|
||||
since: shouldForceFullFetch ? 0 : (cachedSnapshot.createdAt || 0),
|
||||
since: shouldForceFullFetch ? 0 : undefined,
|
||||
timeoutMs: 12000,
|
||||
});
|
||||
|
||||
@@ -516,7 +473,7 @@ class SubscriptionsManager {
|
||||
pubkey: normalizedSessionActorPubkey,
|
||||
dTag: SUBSCRIPTION_LIST_IDENTIFIER,
|
||||
relayUrls,
|
||||
since: shouldForceSessionFetch ? 0 : (sessionCachedSnapshot.createdAt || 0),
|
||||
since: shouldForceSessionFetch ? 0 : undefined,
|
||||
timeoutMs: 12000,
|
||||
});
|
||||
if (sessionEvents.length) {
|
||||
@@ -559,13 +516,6 @@ class SubscriptionsManager {
|
||||
// This means no updates. We keep what we have.
|
||||
devLogger.log("[SubscriptionsManager] No updates from relays.");
|
||||
}
|
||||
if (wasBackgroundLoading) {
|
||||
this.backgroundLoading = false;
|
||||
this.emitter.emit("change", {
|
||||
action: "background-loaded",
|
||||
subscribedPubkeys: Array.from(this.subscribedPubkeys),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -584,9 +534,7 @@ class SubscriptionsManager {
|
||||
|
||||
let decryptResult;
|
||||
try {
|
||||
const decryptPromise = this.decryptSubscriptionEvent(newest, userPubkey, {
|
||||
allowPermissionPrompt,
|
||||
});
|
||||
const decryptPromise = this.decryptSubscriptionEvent(newest, userPubkey);
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(
|
||||
() => {
|
||||
@@ -605,33 +553,17 @@ class SubscriptionsManager {
|
||||
}
|
||||
|
||||
if (!decryptResult.ok) {
|
||||
this.lastLoadError = decryptResult.error || null;
|
||||
if (decryptResult.error?.code === "subscriptions-decrypt-timeout") {
|
||||
if (!this.loaded && !cachedSnapshot.hasSnapshot) {
|
||||
this.loaded = true;
|
||||
}
|
||||
this.scheduleDecryptRetry(normalizedUserPubkey, decryptResult.error, {
|
||||
allowPermissionPrompt,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!allowPermissionPrompt &&
|
||||
decryptResult.error?.code === "subscriptions-permission-required"
|
||||
) {
|
||||
this.scheduleDecryptRetry(normalizedUserPubkey, decryptResult.error);
|
||||
return;
|
||||
}
|
||||
userLogger.error(
|
||||
"[SubscriptionsManager] Failed to decrypt subscription list:",
|
||||
decryptResult.error,
|
||||
);
|
||||
if (wasBackgroundLoading) {
|
||||
this.backgroundLoading = false;
|
||||
this.emitter.emit("change", {
|
||||
action: "background-loaded",
|
||||
subscribedPubkeys: Array.from(this.subscribedPubkeys),
|
||||
});
|
||||
}
|
||||
if (!this.loaded) {
|
||||
this.subscribedPubkeys.clear();
|
||||
this.subsEventId = null;
|
||||
@@ -651,9 +583,6 @@ class SubscriptionsManager {
|
||||
this.subscribedPubkeys = newSet;
|
||||
this.currentUserPubkey = normalizedUserPubkey;
|
||||
this.loaded = true;
|
||||
if (wasBackgroundLoading) {
|
||||
this.backgroundLoading = false;
|
||||
}
|
||||
|
||||
// Update persistent cache
|
||||
this.saveToCache(normalizedUserPubkey);
|
||||
@@ -681,31 +610,22 @@ class SubscriptionsManager {
|
||||
error
|
||||
);
|
||||
});
|
||||
} else if (wasBackgroundLoading) {
|
||||
this.emitter.emit("change", {
|
||||
action: "background-loaded",
|
||||
subscribedPubkeys: Array.from(this.subscribedPubkeys),
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
this.lastLoadError = err || null;
|
||||
userLogger.error("[SubscriptionsManager] Failed to update subs from relays:", err);
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.stopSubscriptionListSubscription();
|
||||
this.subscribedPubkeys.clear();
|
||||
this.subsEventId = null;
|
||||
this.subsEventCreatedAt = null;
|
||||
this.currentUserPubkey = null;
|
||||
this.loaded = false;
|
||||
this.backgroundLoading = false;
|
||||
this.lastRunOptions = null;
|
||||
this.lastResult = null;
|
||||
this.hasRenderedOnce = false;
|
||||
this.lastLoadError = null;
|
||||
if (this.decryptRetryTimeoutId) {
|
||||
clearTimeout(this.decryptRetryTimeoutId);
|
||||
this.decryptRetryTimeoutId = null;
|
||||
@@ -713,56 +633,7 @@ class SubscriptionsManager {
|
||||
this.emitter.emit("change", { action: "reset", subscribedPubkeys: [] });
|
||||
}
|
||||
|
||||
stopSubscriptionListSubscription() {
|
||||
if (this.subscriptionKey) {
|
||||
relaySubscriptionService.stopSubscription(this.subscriptionKey, "reset");
|
||||
this.subscriptionKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
ensureSubscriptionListSubscription(userPubkey, relays) {
|
||||
const normalized = normalizeHexPubkey(userPubkey);
|
||||
if (!normalized || !nostrClient?.pool) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const key = `subscriptions:${normalized}`;
|
||||
this.subscriptionKey = key;
|
||||
|
||||
const filters = [
|
||||
{
|
||||
kinds: [SUBSCRIPTION_SET_KIND],
|
||||
authors: [normalized],
|
||||
"#d": [SUBSCRIPTION_LIST_IDENTIFIER],
|
||||
},
|
||||
];
|
||||
|
||||
return relaySubscriptionService.ensureSubscription({
|
||||
key,
|
||||
pool: nostrClient.pool,
|
||||
relays,
|
||||
filters,
|
||||
label: "subscription-list",
|
||||
onEvent: (event) => this.handleSubscriptionListEvent(event),
|
||||
});
|
||||
}
|
||||
|
||||
handleSubscriptionListEvent(event) {
|
||||
const normalized = normalizeHexPubkey(event?.pubkey);
|
||||
if (!normalized || normalized !== this.currentUserPubkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateFromRelays(normalized, { allowPermissionPrompt: false })
|
||||
.catch((error) => {
|
||||
devLogger.warn(
|
||||
"[SubscriptionsManager] Failed to refresh after subscription list event",
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async ensureLoaded(actorHex, options = {}) {
|
||||
async ensureLoaded(actorHex) {
|
||||
devLogger.log("[SubscriptionsManager] ensureLoaded start", actorHex);
|
||||
const normalizedActor = normalizeHexPubkey(actorHex) || actorHex;
|
||||
if (!normalizedActor) {
|
||||
@@ -784,7 +655,7 @@ class SubscriptionsManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const loader = this.loadSubscriptions(normalizedActor, options);
|
||||
const loader = this.loadSubscriptions(normalizedActor);
|
||||
this.loadingPromise = loader;
|
||||
|
||||
try {
|
||||
@@ -838,7 +709,7 @@ class SubscriptionsManager {
|
||||
return Array.from(this.subscribedPubkeys);
|
||||
}
|
||||
|
||||
async decryptSubscriptionEvent(event, userPubkey, options = {}) {
|
||||
async decryptSubscriptionEvent(event, userPubkey) {
|
||||
const ciphertext = typeof event?.content === "string" ? event.content : "";
|
||||
if (!ciphertext) {
|
||||
const error = new Error("Subscription event is missing ciphertext content.");
|
||||
@@ -846,7 +717,6 @@ class SubscriptionsManager {
|
||||
return { ok: false, error };
|
||||
}
|
||||
|
||||
const allowPermissionPrompt = options?.allowPermissionPrompt !== false;
|
||||
const hints = extractEncryptionHints(event);
|
||||
const requiresNip44 = hints.includes("nip44") || hints.includes("nip44_v2");
|
||||
const requiresNip04 = !hints.length || hints.includes("nip04") || !requiresNip44;
|
||||
@@ -861,8 +731,7 @@ class SubscriptionsManager {
|
||||
if (
|
||||
!signer ||
|
||||
(!signerHasRequiredDecryptors(signer) &&
|
||||
typeof nostrClient?.ensureActiveSignerForPubkey === "function" &&
|
||||
allowPermissionPrompt)
|
||||
typeof nostrClient?.ensureActiveSignerForPubkey === "function")
|
||||
) {
|
||||
signer = await nostrClient.ensureActiveSignerForPubkey(userPubkey);
|
||||
}
|
||||
@@ -870,11 +739,7 @@ class SubscriptionsManager {
|
||||
const signerHasNip04 = typeof signer?.nip04Decrypt === "function";
|
||||
const signerHasNip44 = typeof signer?.nip44Decrypt === "function";
|
||||
|
||||
const nostrApi = allowPermissionPrompt
|
||||
? typeof window !== "undefined"
|
||||
? window?.nostr
|
||||
: null
|
||||
: null;
|
||||
const nostrApi = typeof window !== "undefined" ? window?.nostr : null;
|
||||
const windowHasNip04 = typeof nostrApi?.nip04?.decrypt === "function";
|
||||
const windowHasNip44 =
|
||||
(nostrApi?.nip44 && typeof nostrApi.nip44.decrypt === "function") ||
|
||||
@@ -884,17 +749,8 @@ class SubscriptionsManager {
|
||||
(!signerHasNip44 && !windowHasNip44 && requiresNip44) ||
|
||||
(!signerHasNip04 && !windowHasNip04 && requiresNip04)
|
||||
) {
|
||||
if (!allowPermissionPrompt) {
|
||||
const error = new Error(
|
||||
"Decrypt permissions are required to read subscriptions."
|
||||
);
|
||||
error.code = "subscriptions-permission-required";
|
||||
return { ok: false, error };
|
||||
}
|
||||
try {
|
||||
const permissionResult = await requestDefaultExtensionPermissions(
|
||||
DEFAULT_NIP07_ENCRYPTION_METHODS,
|
||||
);
|
||||
const permissionResult = await requestDefaultExtensionPermissions();
|
||||
if (!permissionResult?.ok) {
|
||||
const error =
|
||||
permissionResult?.error instanceof Error
|
||||
@@ -942,19 +798,13 @@ class SubscriptionsManager {
|
||||
}
|
||||
|
||||
if (nostrApi) {
|
||||
const decrypterOptions = {
|
||||
priority: NIP07_PRIORITY.HIGH,
|
||||
timeoutMs: 12000,
|
||||
retryMultiplier: 1,
|
||||
};
|
||||
|
||||
if (typeof nostrApi.nip04?.decrypt === "function") {
|
||||
registerDecryptor("nip04", (payload) =>
|
||||
runNip07WithRetry(
|
||||
() => nostrApi.nip04.decrypt(userPubkey, payload),
|
||||
{
|
||||
label: "nip04.decrypt",
|
||||
...decrypterOptions,
|
||||
priority: NIP07_PRIORITY.HIGH,
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -971,7 +821,7 @@ class SubscriptionsManager {
|
||||
() => nip44.decrypt(userPubkey, payload),
|
||||
{
|
||||
label: "nip44.decrypt",
|
||||
...decrypterOptions,
|
||||
priority: NIP07_PRIORITY.HIGH,
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -985,7 +835,7 @@ class SubscriptionsManager {
|
||||
() => nip44v2.decrypt(userPubkey, payload),
|
||||
{
|
||||
label: "nip44.v2.decrypt",
|
||||
...decrypterOptions,
|
||||
priority: NIP07_PRIORITY.HIGH,
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -995,7 +845,7 @@ class SubscriptionsManager {
|
||||
() => nip44v2.decrypt(userPubkey, payload),
|
||||
{
|
||||
label: "nip44.v2.decrypt",
|
||||
...decrypterOptions,
|
||||
priority: NIP07_PRIORITY.HIGH,
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -1129,9 +979,7 @@ class SubscriptionsManager {
|
||||
}
|
||||
|
||||
if (signer.type === "extension") {
|
||||
const permissionResult = await requestDefaultExtensionPermissions(
|
||||
DEFAULT_NIP07_ENCRYPTION_METHODS,
|
||||
);
|
||||
const permissionResult = await requestDefaultExtensionPermissions();
|
||||
if (!permissionResult.ok) {
|
||||
userLogger.warn(
|
||||
"[SubscriptionsManager] Signer permissions denied while updating subscriptions.",
|
||||
@@ -1240,6 +1088,13 @@ class SubscriptionsManager {
|
||||
throw signErr;
|
||||
}
|
||||
|
||||
const sanitizeRelayList = (candidate) =>
|
||||
Array.isArray(candidate)
|
||||
? candidate
|
||||
.map((url) => (typeof url === "string" ? url.trim() : ""))
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
|
||||
const writeRelays = sanitizeRelayList(nostrClient.writeRelays);
|
||||
const fallbackRelays = writeRelays.length
|
||||
? writeRelays
|
||||
|
||||
Reference in new issue
Block a user