| 12 |
12 |
|
// Cache the vocs-generated stylesheet href across requests (changes on rebuild). |
| 13 |
13 |
|
let _vocsStyleHref: string | null = null; |
| 14 |
14 |
|
|
| 15 |
|
- |
async function getVocsStyleHref(assets: Fetcher, baseUrl: string): Promise<string> { |
|
15 |
+ |
async function getVocsStyleHref( |
|
16 |
+ |
assets: Fetcher, |
|
17 |
+ |
baseUrl: string, |
|
18 |
+ |
): Promise<string> { |
| 16 |
19 |
|
if (_vocsStyleHref) return _vocsStyleHref; |
| 17 |
20 |
|
try { |
| 18 |
21 |
|
const indexUrl = new URL("/", baseUrl).toString(); |
|
| 105 |
108 |
|
const session = await client.restore(did); |
| 106 |
109 |
|
const agent = new Agent(session); |
| 107 |
110 |
|
|
| 108 |
|
- |
const existingUri = await findExistingSubscription(agent, did, publicationUri); |
|
111 |
+ |
const existingUri = await findExistingSubscription( |
|
112 |
+ |
agent, |
|
113 |
+ |
did, |
|
114 |
+ |
publicationUri, |
|
115 |
+ |
); |
| 109 |
116 |
|
if (existingUri) { |
| 110 |
|
- |
return c.json({ subscribed: true, existing: true, recordUri: existingUri }); |
|
117 |
+ |
return c.json({ |
|
118 |
+ |
subscribed: true, |
|
119 |
+ |
existing: true, |
|
120 |
+ |
recordUri: existingUri, |
|
121 |
+ |
}); |
| 111 |
122 |
|
} |
| 112 |
123 |
|
|
| 113 |
124 |
|
const result = await agent.com.atproto.repo.createRecord({ |
|
| 119 |
130 |
|
}, |
| 120 |
131 |
|
}); |
| 121 |
132 |
|
|
| 122 |
|
- |
return c.json({ subscribed: true, existing: false, recordUri: result.data.uri }); |
|
133 |
+ |
return c.json({ |
|
134 |
+ |
subscribed: true, |
|
135 |
+ |
existing: false, |
|
136 |
+ |
recordUri: result.data.uri, |
|
137 |
+ |
}); |
| 123 |
138 |
|
} catch (error) { |
| 124 |
139 |
|
console.error("Subscribe POST error:", error); |
| 125 |
140 |
|
// Treat expired/missing session as unauthenticated |
|
| 141 |
156 |
|
const styleHref = await getVocsStyleHref(c.env.ASSETS, c.req.url); |
| 142 |
157 |
|
|
| 143 |
158 |
|
if (!publicationUri || !publicationUri.startsWith("at://")) { |
| 144 |
|
- |
return c.html(renderError("Missing or invalid publication URI.", styleHref), 400); |
|
159 |
+ |
return c.html( |
|
160 |
+ |
renderError("Missing or invalid publication URI.", styleHref), |
|
161 |
+ |
400, |
|
162 |
+ |
); |
| 145 |
163 |
|
} |
| 146 |
164 |
|
|
| 147 |
165 |
|
const did = getSessionDid(c); |
|
| 154 |
172 |
|
const session = await client.restore(did); |
| 155 |
173 |
|
const agent = new Agent(session); |
| 156 |
174 |
|
|
| 157 |
|
- |
const existingUri = await findExistingSubscription(agent, did, publicationUri); |
|
175 |
+ |
const existingUri = await findExistingSubscription( |
|
176 |
+ |
agent, |
|
177 |
+ |
did, |
|
178 |
+ |
publicationUri, |
|
179 |
+ |
); |
| 158 |
180 |
|
if (existingUri) { |
| 159 |
|
- |
return c.html(renderSuccess(publicationUri, existingUri, true, styleHref)); |
|
181 |
+ |
return c.html( |
|
182 |
+ |
renderSuccess(publicationUri, existingUri, true, styleHref), |
|
183 |
+ |
); |
| 160 |
184 |
|
} |
| 161 |
185 |
|
|
| 162 |
186 |
|
const result = await agent.com.atproto.repo.createRecord({ |
|
| 168 |
192 |
|
}, |
| 169 |
193 |
|
}); |
| 170 |
194 |
|
|
| 171 |
|
- |
return c.html(renderSuccess(publicationUri, result.data.uri, false, styleHref)); |
|
195 |
+ |
return c.html( |
|
196 |
+ |
renderSuccess(publicationUri, result.data.uri, false, styleHref), |
|
197 |
+ |
); |
| 172 |
198 |
|
} catch (error) { |
| 173 |
199 |
|
console.error("Subscribe GET error:", error); |
| 174 |
200 |
|
// Session expired - ask the user to sign in again |
| 175 |
|
- |
return c.html(renderHandleForm(publicationUri, styleHref, "Session expired. Please sign in again.")); |
|
201 |
+ |
return c.html( |
|
202 |
+ |
renderHandleForm( |
|
203 |
+ |
publicationUri, |
|
204 |
+ |
styleHref, |
|
205 |
+ |
"Session expired. Please sign in again.", |
|
206 |
+ |
), |
|
207 |
+ |
); |
| 176 |
208 |
|
} |
| 177 |
209 |
|
}); |
| 178 |
210 |
|
|
|
| 190 |
222 |
|
|
| 191 |
223 |
|
if (!handle || !publicationUri) { |
| 192 |
224 |
|
const styleHref = await getVocsStyleHref(c.env.ASSETS, c.req.url); |
| 193 |
|
- |
return c.html(renderError("Missing handle or publication URI.", styleHref), 400); |
|
225 |
+ |
return c.html( |
|
226 |
+ |
renderError("Missing handle or publication URI.", styleHref), |
|
227 |
+ |
400, |
|
228 |
+ |
); |
| 194 |
229 |
|
} |
| 195 |
230 |
|
|
| 196 |
231 |
|
const returnTo = `${c.env.CLIENT_URL}/subscribe?publicationUri=${encodeURIComponent(publicationUri)}`; |
|
| 205 |
240 |
|
// HTML rendering |
| 206 |
241 |
|
// ============================================================================ |
| 207 |
242 |
|
|
| 208 |
|
- |
function renderHandleForm(publicationUri: string, styleHref: string, error?: string): string { |
|
243 |
+ |
function renderHandleForm( |
|
244 |
+ |
publicationUri: string, |
|
245 |
+ |
styleHref: string, |
|
246 |
+ |
error?: string, |
|
247 |
+ |
): string { |
| 209 |
248 |
|
const errorHtml = error |
| 210 |
249 |
|
? `<p class="vocs_Paragraph error">${escapeHtml(error)}</p>` |
| 211 |
250 |
|
: ""; |
| 212 |
251 |
|
|
| 213 |
|
- |
return page(` |
|
252 |
+ |
return page( |
|
253 |
+ |
` |
| 214 |
254 |
|
<h1 class="vocs_H1 vocs_Heading">Subscribe on Bluesky</h1> |
| 215 |
255 |
|
<p class="vocs_Paragraph">Enter your Bluesky handle to subscribe to this publication.</p> |
| 216 |
256 |
|
${errorHtml} |
|
| 226 |
266 |
|
/> |
| 227 |
267 |
|
<button type="submit" class="vocs_Button_button vocs_Button_button_accent">Continue on Bluesky</button> |
| 228 |
268 |
|
</form> |
| 229 |
|
- |
`, styleHref); |
|
269 |
+ |
`, |
|
270 |
+ |
styleHref, |
|
271 |
+ |
); |
| 230 |
272 |
|
} |
| 231 |
273 |
|
|
| 232 |
274 |
|
function renderSuccess( |
|
| 240 |
282 |
|
: "You've successfully subscribed!"; |
| 241 |
283 |
|
const escapedPublicationUri = escapeHtml(publicationUri); |
| 242 |
284 |
|
const escapedRecordUri = escapeHtml(recordUri); |
| 243 |
|
- |
return page(` |
|
285 |
+ |
return page( |
|
286 |
+ |
` |
| 244 |
287 |
|
<h1 class="vocs_H1 vocs_Heading">Subscribed ✓</h1> |
| 245 |
288 |
|
<p class="vocs_Paragraph">${msg}</p> |
| 246 |
289 |
|
<p class="vocs_Paragraph"><small>Publication: <code class="vocs_Code"><a href="https://pds.ls/${escapedPublicationUri}">${escapedPublicationUri}</a></code></small></p> |
| 247 |
290 |
|
<p class="vocs_Paragraph"><small>Record: <code class="vocs_Code"><a href="https://pds.ls/${escapedRecordUri}">${escapedRecordUri}</a></code></small></p> |
| 248 |
|
- |
`, styleHref); |
|
291 |
+ |
`, |
|
292 |
+ |
styleHref, |
|
293 |
+ |
); |
| 249 |
294 |
|
} |
| 250 |
295 |
|
|
| 251 |
296 |
|
function renderError(message: string, styleHref: string): string { |
| 252 |
|
- |
return page(`<h1 class="vocs_H1 vocs_Heading">Error</h1><p class="vocs_Paragraph error">${escapeHtml(message)}</p>`, styleHref); |
|
297 |
+ |
return page( |
|
298 |
+ |
`<h1 class="vocs_H1 vocs_Heading">Error</h1><p class="vocs_Paragraph error">${escapeHtml(message)}</p>`, |
|
299 |
+ |
styleHref, |
|
300 |
+ |
); |
| 253 |
301 |
|
} |
| 254 |
302 |
|
|
| 255 |
303 |
|
function page(body: string, styleHref: string): string { |