Skip to content

Commit 2b78365

Browse files
committed
add support for Svelte 5's runes
1 parent 8f25984 commit 2b78365

File tree

5 files changed

+155
-12
lines changed

5 files changed

+155
-12
lines changed

.changeset/fresh-oranges-guess.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nostr-dev-kit/ndk-svelte": minor
3+
---
4+
5+
add support for Svelte 5's runes

.github/workflows/deploy.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,14 @@ jobs:
3535
fetch-depth: 0 # Not needed if lastUpdated is not enabled
3636
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
3737
- name: Setup Node
38-
uses: pnpm/action-setup@v3 # Uncomment this if you're using pnpm
38+
uses: actions/setup-node@v4
3939
with:
40-
cache: pnpm # or pnpm / yarn
40+
node-version: '18'
41+
cache: 'pnpm'
42+
- name: Setup PNPM
43+
uses: pnpm/action-setup@v3
44+
with:
45+
version: 8
4146
- name: Setup Pages
4247
uses: actions/configure-pages@v4
4348
- name: Install dependencies

ndk-svelte/package.json

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,37 @@
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",
77
"exports": {
8-
"import": {
9-
"types": "./dist/index.d.mts",
10-
"default": "./dist/index.mjs"
8+
".": {
9+
"import": {
10+
"types": "./dist/index.d.mts",
11+
"default": "./dist/index.mjs"
12+
},
13+
"require": {
14+
"types": "./dist/index.d.ts",
15+
"default": "./dist/index.js"
16+
}
1117
},
12-
"require": {
13-
"types": "./dist/index.d.ts",
14-
"default": "./dist/index.js"
18+
"./svelte5": {
19+
"import": {
20+
"types": "./dist/index.svelte.d.mts",
21+
"default": "./dist/index.svelte.js"
22+
},
23+
"require": {
24+
"types": "./dist/index.svelte.d.ts",
25+
"default": "./dist/index.svelte.js"
26+
}
1527
}
1628
},
1729
"files": [
1830
"dist",
1931
"README.md"
2032
],
2133
"scripts": {
22-
"build": "tsup src/index.ts --format cjs,esm --dts",
34+
"build": "tsup src/index.ts src/index.svelte.ts --format cjs,esm --dts",
2335
"dev": "tsup --watch src src/index.ts --format cjs,esm --dts",
2436
"lint": "prettier --check . && eslint .",
25-
"format": "prettier --write ."
37+
"format": "prettier --write .",
38+
"postbuild": "mv dist/index.svelte.mjs dist/index.svelte.js; mv dist/index.svelte.d.mts dist/index.svelte.d.ts"
2639
},
2740
"keywords": [
2841
"nostr",
@@ -33,12 +46,15 @@
3346
"author": "pablof7z",
3447
"license": "MIT",
3548
"dependencies": {
36-
"@nostr-dev-kit/ndk": "workspace:*",
37-
"svelte": "^4.2.1"
49+
"@nostr-dev-kit/ndk": "workspace:*"
50+
},
51+
"peerDependencies": {
52+
"svelte": "*"
3853
},
3954
"devDependencies": {
4055
"@nostr-dev-kit/eslint-config-custom": "workspace:*",
4156
"@nostr-dev-kit/tsconfig": "workspace:*",
57+
"svelte": "5.0.0-next.272",
4258
"tsup": "^7.2.0"
4359
}
4460
}

ndk-svelte/src/index.svelte.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import NDK, {
2+
type NDKConstructorParams,
3+
NDKEvent,
4+
type NDKFilter,
5+
type NDKRelay,
6+
type NDKRelaySet,
7+
type NDKSubscriptionOptions,
8+
} from "@nostr-dev-kit/ndk";
9+
import { onDestroy } from "svelte";
10+
11+
type ClassWithConvertFunction<T extends NDKEvent> = {
12+
from: (event: NDKEvent) => T | undefined;
13+
};
14+
15+
type NDKSubscribeOptions = NDKSubscriptionOptions & {
16+
autoStart?: boolean;
17+
repostsFilters?: NDKFilter[];
18+
unrefUnsubscribeTimeout?: number;
19+
relaySet?: NDKRelaySet;
20+
skipDeleted?: boolean;
21+
onEose?: () => void;
22+
onEvent?: (event: NDKEvent, relay?: NDKRelay) => void;
23+
};
24+
25+
type Actions = {
26+
unsubscribe?: () => void;
27+
};
28+
29+
class NDKSvelte extends NDK {
30+
constructor(opts?: NDKConstructorParams) {
31+
super(opts);
32+
}
33+
34+
/**
35+
* Subscribes to NDK events and returns a reactive list of events.
36+
* Automatically cleans up the subscription when no longer needed.
37+
*/
38+
public $subscribe = <T extends NDKEvent>(
39+
filters: NDKFilter[],
40+
opts?: NDKSubscribeOptions,
41+
klass?: ClassWithConvertFunction<T>
42+
) => {
43+
// A reactive list for the events
44+
const eventList = $state<T[] & Actions>([]);
45+
const eventMap = new Map<string, T>(); // Map for deduplication
46+
47+
// Process an incoming event
48+
const processEvent = (event: NDKEvent) => {
49+
let e = event;
50+
51+
// Convert the event to a specific class if provided
52+
if (klass) {
53+
const convertedEvent = klass.from(event);
54+
if (!convertedEvent) return;
55+
e = convertedEvent;
56+
e.relay = event.relay;
57+
}
58+
59+
const dedupKey = e.deduplicationKey();
60+
61+
// Avoid duplicate or older events
62+
if (eventMap.has(dedupKey)) {
63+
const existingEvent = eventMap.get(dedupKey)!;
64+
if (existingEvent.created_at! >= e.created_at!) return;
65+
}
66+
67+
eventMap.set(dedupKey, e as T);
68+
69+
// Update the reactive event list inserting the event in the right position according to the created_at timestamp
70+
const pos = eventList.findIndex(event => event.created_at! < e.created_at!);
71+
eventList.splice(pos, 0, e as T);
72+
};
73+
74+
// Create the subscription
75+
const subscription = this.subscribe(
76+
Array.isArray(filters) ? filters : [filters],
77+
opts,
78+
opts?.relaySet,
79+
false
80+
);
81+
82+
// Handle incoming events
83+
subscription.on("event", (event, relay) => {
84+
processEvent(event);
85+
if (opts?.onEvent) opts.onEvent(event, relay);
86+
});
87+
88+
// Handle EOSE
89+
subscription.on("eose", () => {
90+
if (opts?.onEose) opts.onEose();
91+
});
92+
93+
subscription.start();
94+
95+
// Cleanup when the component or context is destroyed
96+
onDestroy(() => {
97+
subscription.stop();
98+
});
99+
100+
eventList.unsubscribe = () => subscription.stop();
101+
102+
return eventList;
103+
}
104+
}
105+
106+
export default NDKSvelte;

package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@
3131
"vitepress-plugin-mermaid": "^2.0.17"
3232
},
3333
"packageManager": "[email protected]",
34+
"workspaces": [
35+
"apps/*",
36+
"packages/*",
37+
"ndk",
38+
"ndk-cache-dexie",
39+
"ndk-cache-redis",
40+
"ndk-cache-nostr",
41+
"ndk-svelte",
42+
"ndk-svelte-components",
43+
"ndk-wallet"
44+
],
3445
"engines": {
3546
"node": ">=16.0"
3647
}

0 commit comments

Comments
 (0)