@ewanc26/supporters 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,113 +2,12 @@
2
2
 
3
3
  SvelteKit component library for displaying Ko-fi supporters, backed by an ATProto PDS.
4
4
 
5
- Ko-fi's webhook pushes payment events to your endpoint. Each event is stored as a record under the `uk.ewancroft.kofi.supporter` lexicon on your PDS, with a TID rkey derived from the transaction timestamp. The component reads those records and renders them.
6
-
7
- ---
8
-
9
- ## How it works
10
-
11
- 1. Ko-fi POSTs a webhook event to `/webhook` on each transaction
12
- 2. The handler verifies the `verification_token`, respects `is_public`, and calls `appendEvent`
13
- 3. `appendEvent` writes a record to your PDS under `uk.ewancroft.kofi.supporter`
14
- 4. `readStore` fetches all records and aggregates them into `KofiSupporter` objects
15
- 5. Pass the result to `<KofiSupporters>` or `<LunarContributors>`
16
-
17
- ---
18
-
19
- ## Setup
20
-
21
- ### 1. Environment variables
22
-
23
- ```env
24
- # Required — copy from ko-fi.com/manage/webhooks → Advanced → Verification Token
25
- KOFI_VERIFICATION_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
26
-
27
- # Required — your ATProto identity and a dedicated app password
28
- ATPROTO_DID=did:plc:yourdidhex
29
- ATPROTO_PDS_URL=https://your-pds.example.com
30
- ATPROTO_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
31
- ```
32
-
33
- Generate an app password at your PDS under **Settings → App Passwords**.
34
-
35
- ### 2. Register the webhook
36
-
37
- Go to **ko-fi.com/manage/webhooks** and set your webhook URL to:
38
-
39
- ```
40
- https://your-domain.com/webhook
41
- ```
42
-
43
- ### 3. Add the route
44
-
45
- Copy `src/routes/webhook/+server.ts` into your SvelteKit app's routes directory.
46
-
47
- ### 4. Use the component
48
-
49
- ```ts
50
- // +page.server.ts
51
- import { readStore } from '@ewanc26/supporters';
52
-
53
- export const load = async () => ({
54
- supporters: await readStore()
55
- });
56
- ```
57
-
58
- ```svelte
59
- <!-- +page.svelte -->
60
- <script lang="ts">
61
- import { KofiSupporters } from '@ewanc26/supporters';
62
- let { data } = $props();
63
- </script>
64
-
65
- <KofiSupporters supporters={data.supporters} />
66
- ```
67
-
68
- ---
69
-
70
- ## Components
71
-
72
- ### `<KofiSupporters>`
73
-
74
- Displays all supporters with emoji type badges (☕ donation, ⭐ subscription, 🎨 commission, 🛍️ shop order).
75
-
76
- | Prop | Type | Default |
77
- |---|---|---|
78
- | `supporters` | `KofiSupporter[]` | `[]` |
79
- | `heading` | `string` | `'Supporters'` |
80
- | `description` | `string` | `'People who support my work on Ko-fi.'` |
81
- | `filter` | `KofiEventType[]` | `undefined` (show all) |
82
- | `loading` | `boolean` | `false` |
83
- | `error` | `string \| null` | `null` |
84
-
85
- ### `<LunarContributors>`
86
-
87
- Convenience wrapper around `<KofiSupporters>` pre-filtered to `Subscription` events.
88
-
89
- ---
90
-
91
- ## Importing historical data
92
-
93
- Export your transaction history from **ko-fi.com/manage/transactions → Export CSV**, then:
94
-
95
5
  ```bash
96
- ATPROTO_DID=... ATPROTO_PDS_URL=... ATPROTO_APP_PASSWORD=... \
97
- node node_modules/@ewanc26/supporters/scripts/import-history.mjs transactions.csv --dry-run
6
+ pnpm add @ewanc26/supporters
98
7
  ```
99
8
 
100
- ---
101
-
102
- ## Lexicon
9
+ Full documentation at **[docs.ewancroft.uk](https://docs.ewancroft.uk/projects/supporters)**.
103
10
 
104
- Records are stored under `uk.ewancroft.kofi.supporter` (see `lexicons/`). Each record contains:
105
-
106
- ```ts
107
- {
108
- name: string // display name from Ko-fi
109
- type: string // "Donation" | "Subscription" | "Commission" | "Shop Order"
110
- tier?: string // subscription tier name, if applicable
111
- }
112
- ```
11
+ ## Licence
113
12
 
114
- rkeys are TIDs derived from the transaction timestamp via [`@ewanc26/tid`](https://npmjs.com/package/@ewanc26/tid).
13
+ See the root [LICENSE](../../LICENSE).
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Fetches Ko-fi supporter events as a chronological timeline.
3
+ *
4
+ * Unlike readStore (which aggregates per-person), this returns every
5
+ * individual event record ordered most-recent-first.
6
+ *
7
+ * No auth required — records are publicly readable.
8
+ *
9
+ * @param did - The ATProto DID to read records from.
10
+ */
11
+ import type { KofiEventType } from './types.js';
12
+ export type { KofiEventType };
13
+ export interface KofiSupportEvent {
14
+ rkey: string;
15
+ name: string;
16
+ type: KofiEventType;
17
+ tier?: string;
18
+ date: Date;
19
+ }
20
+ export declare function fetchEvents(did: string): Promise<KofiSupportEvent[]>;
package/dist/events.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Fetches Ko-fi supporter events as a chronological timeline.
3
+ *
4
+ * Unlike readStore (which aggregates per-person), this returns every
5
+ * individual event record ordered most-recent-first.
6
+ *
7
+ * No auth required — records are publicly readable.
8
+ *
9
+ * @param did - The ATProto DID to read records from.
10
+ */
11
+ import { AtpAgent } from '@atproto/api';
12
+ import { decodeTid } from '@ewanc26/tid';
13
+ const COLLECTION = 'uk.ewancroft.kofi.supporter';
14
+ async function resolvePdsUrl(did) {
15
+ const res = await fetch(`https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(did)}`);
16
+ if (!res.ok)
17
+ throw new Error(`Failed to resolve PDS for ${did}: ${res.status}`);
18
+ const data = (await res.json());
19
+ if (!data.pds)
20
+ throw new Error(`No PDS found in identity document for ${did}`);
21
+ return data.pds;
22
+ }
23
+ export async function fetchEvents(did) {
24
+ const pdsUrl = await resolvePdsUrl(did);
25
+ const agent = new AtpAgent({ service: pdsUrl });
26
+ const events = [];
27
+ let cursor;
28
+ do {
29
+ const res = await agent.com.atproto.repo.listRecords({
30
+ repo: did,
31
+ collection: COLLECTION,
32
+ limit: 100,
33
+ cursor
34
+ });
35
+ for (const record of res.data.records) {
36
+ const value = record.value;
37
+ const rkey = record.uri.split('/').pop() ?? '';
38
+ let date;
39
+ try {
40
+ date = decodeTid(rkey).date;
41
+ }
42
+ catch {
43
+ date = new Date(0);
44
+ }
45
+ events.push({ rkey, name: value.name, type: value.type, tier: value.tier, date });
46
+ }
47
+ cursor = res.data.cursor;
48
+ } while (cursor);
49
+ return events.sort((a, b) => b.date.getTime() - a.date.getTime());
50
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { default as KofiSupporters } from './KofiSupporters.svelte';
2
+ export { fetchEvents } from './events.js';
3
+ export type { KofiSupportEvent } from './events.js';
2
4
  export { default as LunarContributors } from './LunarContributors.svelte';
3
5
  export { readStore, appendEvent } from './store.js';
4
6
  export type { KofiEventRecord } from './store.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { default as KofiSupporters } from './KofiSupporters.svelte';
2
+ export { fetchEvents } from './events.js';
2
3
  export { default as LunarContributors } from './LunarContributors.svelte';
3
4
  export { readStore, appendEvent } from './store.js';
4
5
  export { parseWebhook, WebhookError } from './webhook.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ewanc26/supporters",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "SvelteKit component library for displaying Ko-fi supporters, backed by an ATProto PDS.",
5
5
  "author": "Ewan Croft",
6
6
  "license": "AGPL-3.0-only",
@@ -32,20 +32,20 @@
32
32
  "svelte": "^5.0.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@atproto/api": "^0.18.1",
36
- "@sveltejs/adapter-auto": "^7.0.0",
37
- "@sveltejs/kit": "^2.50.2",
35
+ "@atproto/api": "^0.19.3",
36
+ "@sveltejs/adapter-auto": "^7.0.1",
37
+ "@sveltejs/kit": "^2.55.0",
38
38
  "@sveltejs/package": "^2.5.7",
39
39
  "@sveltejs/vite-plugin-svelte": "^6.2.4",
40
40
  "@tailwindcss/typography": "^0.5.19",
41
- "@tailwindcss/vite": "^4.1.18",
41
+ "@tailwindcss/vite": "^4.2.1",
42
42
  "prettier": "^3.8.1",
43
- "prettier-plugin-svelte": "^3.4.1",
43
+ "prettier-plugin-svelte": "^3.5.1",
44
44
  "prettier-plugin-tailwindcss": "^0.7.2",
45
- "publint": "^0.3.17",
46
- "svelte": "^5.51.0",
47
- "svelte-check": "^4.4.2",
48
- "tailwindcss": "^4.1.18",
45
+ "publint": "^0.3.18",
46
+ "svelte": "^5.53.11",
47
+ "svelte-check": "^4.4.5",
48
+ "tailwindcss": "^4.2.1",
49
49
  "typescript": "^5.9.3",
50
50
  "vite": "^7.3.1"
51
51
  },