+3
-1
src/hooks.server.ts
+3
-1
src/hooks.server.ts
···
26
26
27
27
// set the authed agent
28
28
const authedAgent = new Agent(oauthSession);
29
-
event.locals.authedAgent = authedAgent;
29
+
if (!event.locals.authedAgent) {
30
+
event.locals.authedAgent = authedAgent;
31
+
}
30
32
31
33
// set the authed user with decrypted session DID
32
34
const user = await authedAgent.getProfile({ actor: decrypted });
+3
-3
src/lib/atproto.ts
+3
-3
src/lib/atproto.ts
···
66
66
67
67
const publicUrl = "https://easytodo.link"
68
68
// localhost resolves to either 127.0.0.1 or [::1] (if ipv6)
69
-
const url = dev ? "http://[::1]:5173" : publicUrl;
69
+
const url = dev ? "http://127.0.0.1:5173" : publicUrl;
70
70
71
71
export const atclient = new NodeOAuthClient({
72
72
stateStore: new AuthStateStore(db),
···
77
77
: `http://localhost?redirect_uri=${
78
78
encodeURIComponent(`${url}/oauth/callback`)
79
79
}&scope=${
80
-
encodeURIComponent(`atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task`)
80
+
encodeURIComponent(`atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview`)
81
81
}`,
82
82
client_uri: url,
83
83
redirect_uris: [`${url}/oauth/callback`],
84
-
scope: "atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task",
84
+
scope: "atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview",
85
85
grant_types: ["authorization_code", "refresh_token"],
86
86
application_type: "web",
87
87
token_endpoint_auth_method: "none",
+2
src/lib/stores.svelte.ts
+2
src/lib/stores.svelte.ts
···
38
38
// optional
39
39
duration?: number;
40
40
stopwatchInterval?: number;
41
+
rkey?: string;
41
42
}
42
43
43
44
export type List = {
44
45
id: string;
45
46
title: string;
46
47
tasks: Task[];
48
+
rkey?: string;
47
49
}
48
50
49
51
export const local_lists = persisted<List[]>("local_lists", [
+10
src/lib/utils.ts
+10
src/lib/utils.ts
···
4
4
return generateRandomString(10, alphabet("a-z", "0-9"));
5
5
}
6
6
7
+
export function parseAtUri(uri: string) {
8
+
const regex = /at:\/\/(?<did>did.*)\/(?<lexi>.*)\/(?<rkey>.*)/;
9
+
const groups = regex.exec(uri)?.groups;
10
+
return {
11
+
did: groups?.did,
12
+
lexi: groups?.lexi,
13
+
rkey: groups?.rkey
14
+
}
15
+
}
16
+
7
17
export function formatSecondsToDuration(seconds: number = 0) {
8
18
let hours = Math.floor(seconds / 3600);
9
19
let minutes = Math.floor((seconds - (hours * 3600)) / 60);
+50
-22
src/routes/+page.server.ts
+50
-22
src/routes/+page.server.ts
···
1
1
import { atclient } from "$lib/atproto";
2
2
import type { Task } from "$lib/stores.svelte";
3
+
import { parseAtUri } from "$lib/utils";
3
4
import type { $Typed } from "@atproto/api";
4
5
import type { Create, CreateResult } from "@atproto/api/dist/client/types/com/atproto/repo/applyWrites";
5
6
import { isValidHandle } from "@atproto/syntax";
···
18
19
19
20
// get oauth authorizing url to redirect to
20
21
const redirectUrl = await atclient.authorize(handle, {
21
-
scope: "atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task"
22
+
scope: "atproto repo:link.easytodo.tasks.list repo:link.easytodo.tasks.task rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app%23bsky_appview"
22
23
});
23
24
24
25
if (!redirectUrl) {
···
42
43
43
44
const formData = await request.formData();
44
45
const id = formData.get("id") as string;
46
+
const list_rkey = formData.get("rkey") as string;
45
47
const title = formData.get("title") as string;
46
48
const tasks = JSON.parse(formData.get("tasks") as string) as Task[];
47
-
48
-
const task_records = tasks.map((t) => {
49
-
const { stopwatchInterval, ...rest } = t;
50
-
return {
51
-
$type: "link.easytodo.tasks.task",
52
-
...rest
53
-
}
54
-
});
55
49
56
50
const response = await agent.com.atproto.repo.applyWrites({
57
51
repo: user.did,
58
-
writes: task_records.map((r) => {
59
-
return {
60
-
$type: 'com.atproto.repo.applyWrites#create',
61
-
collection: "link.easytodo.tasks.task",
62
-
value: r
63
-
}
52
+
writes: tasks.map((t) => {
53
+
const { rkey: task_rkey, stopwatchInterval, ...rest } = t;
54
+
if (task_rkey) {
55
+
console.log("UPDATE TASK");
56
+
return {
57
+
$type: 'com.atproto.repo.applyWrites#update',
58
+
collection: "link.easytodo.tasks.task",
59
+
rkey: task_rkey,
60
+
value: {
61
+
$type: "link.easytodo.tasks.task",
62
+
...rest
63
+
}
64
+
}
65
+
}
66
+
else {
67
+
console.log("CREATE TASK");
68
+
return {
69
+
$type: 'com.atproto.repo.applyWrites#create',
70
+
collection: "link.easytodo.tasks.task",
71
+
value: {
72
+
$type: "link.easytodo.tasks.task",
73
+
...rest
74
+
},
75
+
}
76
+
}
64
77
})
65
78
});
66
-
79
+
67
80
if (response.success) {
68
81
console.log(response.data.results);
69
82
const list_record = {
···
76
89
return { cid: t.cid, uri: t.uri }
77
90
})
78
91
};
79
-
const { success, data } = await agent.com.atproto.repo.createRecord({
80
-
repo: user.did,
81
-
collection: "link.easytodo.tasks.list",
82
-
record: list_record
83
-
});
84
92
85
-
return { saveListRecordResult: { success, uri: data.uri }};
93
+
if (list_rkey) {
94
+
const { success, data } = await agent.com.atproto.repo.putRecord({
95
+
rkey: list_rkey,
96
+
repo: user.did,
97
+
collection: "link.easytodo.tasks.list",
98
+
record: list_record
99
+
});
100
+
console.log("UPDATE LIST", { success, uri: data.uri });
101
+
return { saveListRecordResult: { success, rkey: list_rkey, uri: data.uri }};
102
+
}
103
+
else {
104
+
const { success, data } = await agent.com.atproto.repo.createRecord({
105
+
repo: user.did,
106
+
collection: "link.easytodo.tasks.list",
107
+
record: list_record
108
+
});
109
+
const { rkey } = parseAtUri(data.uri);
110
+
console.log("CREATE LIST", { success, rkey, uri: data.uri });
111
+
return { saveListRecordResult: { success, rkey, uri: data.uri }};
112
+
}
113
+
86
114
}
87
115
}
88
116
};