···74756. (optionally) set your base in `svelte.config.js` (e.g. for github pages: `base: '/your-repo-name/'`) while keeping it as `''` in development.
7677-78```ts
79const config = {
80 // ...
···93947. setup the correct permissions (see below)
9596-97## how to use
9899### set permissions you request on sign-in in `$lib/atproto/settings.ts` (see commented out examples for more info)
100101- add collections to the collections array
102-- add rpcs to rpcCalls
103- blobs for uploading blobs
104105### change sign up pds
···152 }
153});
154```
00000
···74756. (optionally) set your base in `svelte.config.js` (e.g. for github pages: `base: '/your-repo-name/'`) while keeping it as `''` in development.
76077```ts
78const config = {
79 // ...
···92937. setup the correct permissions (see below)
94095## how to use
9697### set permissions you request on sign-in in `$lib/atproto/settings.ts` (see commented out examples for more info)
9899- add collections to the collections array
100+- rpcs for authenticated proxied requests
101- blobs for uploading blobs
102103### change sign up pds
···150 }
151});
152```
153+154+## todo
155+156+- check if pds supports prompt=create
157+- add lexicon stuff
···1import type { Did, Handle } from '@atcute/lexicons';
2import { user } from './auth.svelte';
3+import type { AllowedCollection } from './settings';
4import {
5 CompositeDidDocumentResolver,
6 CompositeHandleResolver,
···17export function parseUri(uri: string) {
18 const [did, collection, rkey] = uri.replace('at://', '').split('/');
19 return { did, collection, rkey } as {
20+ collection: Collection;
21 rkey: string;
22 did: string;
23 };
···86 did,
87 collection,
88 cursor,
89+ limit = 100,
90 client
91}: {
92 did?: Did;
···113 params: {
114 repo: did,
115 collection,
116+ limit: !limit || limit > 100 ? 100 : limit,
117 cursor: currentCursor
118 }
119 });
···132export async function getRecord({
133 did,
134 collection,
135+ rkey = 'self',
136 client
137}: {
138 did?: Did;
···141 client?: Client;
142}) {
143 did ??= user.did;
0144145 if (!collection) {
146 throw new Error('Missing parameters for getRecord');
···164165export async function putRecord({
166 collection,
167+ rkey = 'self',
168 record
169}: {
170+ collection: AllowedCollection;
171+ rkey?: string;
172 record: Record<string, unknown>;
173}) {
174 if (!user.client || !user.did) throw new Error('No rpc or did');
···187 return response;
188}
189190+export async function deleteRecord({
191+ collection,
192+ rkey = 'self'
193+}: {
194+ collection: AllowedCollection;
195+ rkey: string;
196+}) {
197 if (!user.client || !user.did) throw new Error('No profile or rpc or did');
198199 const response = await user.client.post('com.atproto.repo.deleteRecord', {
···264 return `${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${blob.ref.$link}`;
265}
266267+export function getCDNImageBlobUrl({
268 did,
269 blob
270}: {
···276 };
277 };
278}) {
279+ return `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${blob.ref.$link}@webp`;
280}
281282export async function searchActorsTypeahead(
+27-13
src/lib/atproto/settings.ts
···1export const SITE = 'https://flo-bit.dev';
23-// optionally add action=create/update/delete to only allow those actions for a collection
4-export const collections: string[] = ['xyz.statusphere.status'];
5-// example: only allow create and delete
6-// export const collections: string[] = ['xyz.statusphere.status?action=create&action=update'];
078-export const rpcCalls: Record<string, string | string[]> = {
000000009 // example: allow authenticated proxying to bsky appview to get a users liked posts
10- //'did:web:api.bsky.app#bsky_appview': ['app.bsky.feed.getActorLikes']
11- // https://docs.bsky.app/docs/api/app-bsky-feed-get-actor-likes
12-};
1314-export const blobs = [] as string | string[] | undefined;
1516-// example: allowing video and html uploads
17-// export const blobs = ['video/*', 'text/html'] as string | string[] | undefined;
00001819-// example: allowing all blob types
20-// export const blobs = ['*/*'] as string | string[] | undefined;
002122// which PDS to use for signup
23// ATTENTION: pds.rip is only for development, all accounts get deleted automatically after a week
···1export const SITE = 'https://flo-bit.dev';
23+type Permissions = {
4+ collections: readonly string[];
5+ rpc: Record<string, string | string[]>;
6+ blobs: readonly string[];
7+};
89+export const permissions = {
10+ // collections you can create/delete/update
11+12+ // example: only allow create and delete
13+ // collections: ['xyz.statusphere.status?action=create&action=update'],
14+ collections: ['xyz.statusphere.status'],
15+16+ // what types of authenticated proxied requests you can make to services
17+18 // example: allow authenticated proxying to bsky appview to get a users liked posts
19+ //rpc: {'did:web:api.bsky.app#bsky_appview': ['app.bsky.feed.getActorLikes']}
20+ rpc: {},
02122+ // what types of blobs you can upload to a users PDS
2324+ // example: allowing video and html uploads
25+ // blobs: ['video/*', 'text/html']
26+ // example: allowing all blob types
27+ // blobs: ['*/*']
28+ blobs: ['hello']
29+} as const satisfies Permissions;
3031+// Extract base collection name (before any query params)
32+type ExtractCollectionBase<T extends string> = T extends `${infer Base}?${string}` ? Base : T;
33+34+export type AllowedCollection = ExtractCollectionBase<(typeof permissions.collections)[number]>;
3536// which PDS to use for signup
37// ATTENTION: pds.rip is only for development, all accounts get deleted automatically after a week
+6-1
src/routes/+page.svelte
···1<script lang="ts">
2- import { user, logout } from '$lib/atproto';
3 import Avatar from '$lib/UI/Avatar.svelte';
4 import Button from '$lib/UI/Button.svelte';
5 import { loginModalState } from '$lib/UI/LoginModal.svelte';
000006</script>
78<div class="mx-auto my-4 max-w-3xl px-4 md:my-32">