+13
-6
src/lib/atproto.ts
+13
-6
src/lib/atproto.ts
···
6
6
export interface Bundle {
7
7
description?: string;
8
8
assets: Record<string, { $type: "blob"; ref: { $link: string }; mimeType: string; size: number }>;
9
+
fallback?: {
10
+
path: string;
11
+
status?: number;
12
+
};
9
13
createdAt: string;
10
14
}
11
15
···
55
59
});
56
60
57
61
if (isXRPCErrorPayload(data)) throw new Error("couldn't load records");
58
-
return data;
62
+
return data as any as Omit<typeof data, "value"> & { value: Bundle };
59
63
}
60
64
61
-
async updateBundle(rkey: string, description: string, files: File[]) {
62
-
const bundle: Bundle = { description, assets: {}, createdAt: new Date().toISOString() };
63
-
65
+
async uploadFiles(files: File[]) {
66
+
const assets: Bundle["assets"] = {};
64
67
for (const file of files) {
65
68
if (!(file instanceof File)) continue;
66
69
···
68
71
if (isXRPCErrorPayload(data)) throw new Error("couldn't upload file");
69
72
70
73
const filepath = file.webkitRelativePath?.replace(/^.+\//, "") ?? file.name;
71
-
bundle.assets[filepath] = {
74
+
assets[filepath] = {
72
75
$type: "blob",
73
76
ref: data.blob.ref,
74
77
mimeType: file.type,
···
76
79
};
77
80
}
78
81
82
+
return assets;
83
+
}
84
+
85
+
async updateBundle(rkey: string, bundle: Bundle) {
79
86
const { data } = await this.#client.post("com.atproto.repo.putRecord", {
80
87
input: {
81
88
repo: this.#did,
82
89
collection: "com.jakelazaroff.test",
83
90
rkey,
84
-
record: bundle as any,
91
+
record: { ...(bundle as any), createdAt: new Date().toISOString() },
85
92
},
86
93
});
87
94
if (isXRPCErrorPayload(data)) throw new Error("couldn't deploy");
+27
-9
src/routes/~/sites/[name]/+page.svelte
+27
-9
src/routes/~/sites/[name]/+page.svelte
···
7
7
8
8
let { params, data } = $props();
9
9
10
-
const atp = client(data.session);
10
+
let rkey = $derived(data.record.uri.split("/").at(-1) ?? "");
11
+
const atp = $derived(client(data.session));
11
12
12
13
const defaultDescription = "Uploaded from website";
13
14
···
28
29
const form = e.currentTarget;
29
30
const formdata = new FormData(form);
30
31
31
-
const rkey = formdata.get("rkey");
32
-
if (typeof rkey !== "string") throw new Error("invalid rkey");
33
-
34
32
let description = formdata.get("description");
35
33
if (typeof description !== "string" || !description) description = defaultDescription;
36
34
37
35
const files = formdata.getAll("files").filter(entry => entry instanceof File);
38
-
await atp.updateBundle(rkey, description, files);
36
+
const assets = await atp.uploadFiles(files);
37
+
38
+
await atp.updateBundle(rkey, { ...(data.record.value as any), assets });
39
39
invalidate(`rkey:${rkey}`);
40
40
form.reset();
41
+
}
42
+
43
+
async function updateBundle(e: SubmitEvent & { currentTarget: HTMLFormElement }) {
44
+
e.preventDefault();
45
+
const form = e.currentTarget;
46
+
const formdata = new FormData(form);
47
+
48
+
// todo: implement me
41
49
}
42
50
</script>
43
51
···
93
101
<Icon name="toggle" />
94
102
<span>Settings</span>
95
103
</h3>
96
-
<form>
104
+
<form onsubmit={updateBundle}>
97
105
<fieldset>
98
106
<legend>Fallback</legend>
99
107
<label>
100
108
<span>path</span>
101
-
<input name="fallback_path" />
109
+
<input name="fallback_path" group={data.record.value.fallback?.path} />
102
110
</label>
103
111
<label>
104
112
<span>200</span>
105
-
<input type="radio" name="fallback_status" value="200" />
113
+
<input
114
+
type="radio"
115
+
name="fallback_status"
116
+
value="200"
117
+
group={data.record.value.fallback?.status}
118
+
/>
106
119
</label>
107
120
<label>
108
121
<span>404</span>
109
-
<input type="radio" name="fallback_status" value="404" />
122
+
<input
123
+
type="radio"
124
+
name="fallback_status"
125
+
value="404"
126
+
group={data.record.value.fallback?.status}
127
+
/>
110
128
</label>
111
129
</fieldset>
112
130
<button>save</button>