tangled
alpha
login
or
join now
stevedylan.dev
/
sequoia
49
fork
atom
A CLI for publishing standard.site documents to ATProto
sequoia.pub
standard
site
lexicon
cli
publishing
49
fork
atom
overview
issues
5
pulls
pipelines
chore: applied formatting
stevedylan.dev
3 weeks ago
bcb1730f
efa2989a
1/1
lint.yml
success
6s
+80
-28
3 changed files
expand all
collapse all
unified
split
docs
src
index.ts
lib
path-redirect.ts
routes
subscribe.ts
+15
-8
docs/src/index.ts
···
12
13
const app = new Hono<{ Bindings: Bindings }>();
14
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
15
app.route("/oauth", auth);
16
app.route("/subscribe", subscribe);
17
-
app.use("/subscribe", cors({
18
-
origin: (origin) => origin,
19
-
credentials: true,
20
-
}));
21
-
app.use("/subscribe/*", cors({
22
-
origin: (origin) => origin,
23
-
credentials: true,
24
-
}));
25
26
app.get("/api/health", (c) => {
27
return c.json({ status: "ok" });
···
12
13
const app = new Hono<{ Bindings: Bindings }>();
14
15
+
app.use(
16
+
"/subscribe",
17
+
cors({
18
+
origin: (origin) => origin,
19
+
credentials: true,
20
+
}),
21
+
);
22
+
app.use(
23
+
"/subscribe/*",
24
+
cors({
25
+
origin: (origin) => origin,
26
+
credentials: true,
27
+
}),
28
+
);
29
+
30
app.route("/oauth", auth);
31
app.route("/subscribe", subscribe);
0
0
0
0
0
0
0
0
32
33
app.get("/api/health", (c) => {
34
return c.json({ status: "ok" });
+1
-4
docs/src/lib/path-redirect.ts
···
19
const OriginalRequest = globalThis.Request;
20
21
globalThis.Request = class extends OriginalRequest {
22
-
constructor(
23
-
input: RequestInfo | URL,
24
-
init?: RequestInit,
25
-
) {
26
super(input, sanitizeInit(init));
27
if (init?.redirect === "error") {
28
errorRedirectRequests.add(this);
···
19
const OriginalRequest = globalThis.Request;
20
21
globalThis.Request = class extends OriginalRequest {
22
+
constructor(input: RequestInfo | URL, init?: RequestInit) {
0
0
0
23
super(input, sanitizeInit(init));
24
if (init?.redirect === "error") {
25
errorRedirectRequests.add(this);
+64
-16
docs/src/routes/subscribe.ts
···
12
// Cache the vocs-generated stylesheet href across requests (changes on rebuild).
13
let _vocsStyleHref: string | null = null;
14
15
-
async function getVocsStyleHref(assets: Fetcher, baseUrl: string): Promise<string> {
0
0
0
16
if (_vocsStyleHref) return _vocsStyleHref;
17
try {
18
const indexUrl = new URL("/", baseUrl).toString();
···
105
const session = await client.restore(did);
106
const agent = new Agent(session);
107
108
-
const existingUri = await findExistingSubscription(agent, did, publicationUri);
0
0
0
0
109
if (existingUri) {
110
-
return c.json({ subscribed: true, existing: true, recordUri: existingUri });
0
0
0
0
111
}
112
113
const result = await agent.com.atproto.repo.createRecord({
···
119
},
120
});
121
122
-
return c.json({ subscribed: true, existing: false, recordUri: result.data.uri });
0
0
0
0
123
} catch (error) {
124
console.error("Subscribe POST error:", error);
125
// Treat expired/missing session as unauthenticated
···
141
const styleHref = await getVocsStyleHref(c.env.ASSETS, c.req.url);
142
143
if (!publicationUri || !publicationUri.startsWith("at://")) {
144
-
return c.html(renderError("Missing or invalid publication URI.", styleHref), 400);
0
0
0
145
}
146
147
const did = getSessionDid(c);
···
154
const session = await client.restore(did);
155
const agent = new Agent(session);
156
157
-
const existingUri = await findExistingSubscription(agent, did, publicationUri);
0
0
0
0
158
if (existingUri) {
159
-
return c.html(renderSuccess(publicationUri, existingUri, true, styleHref));
0
0
160
}
161
162
const result = await agent.com.atproto.repo.createRecord({
···
168
},
169
});
170
171
-
return c.html(renderSuccess(publicationUri, result.data.uri, false, styleHref));
0
0
172
} catch (error) {
173
console.error("Subscribe GET error:", error);
174
// Session expired - ask the user to sign in again
175
-
return c.html(renderHandleForm(publicationUri, styleHref, "Session expired. Please sign in again."));
0
0
0
0
0
0
176
}
177
});
178
···
190
191
if (!handle || !publicationUri) {
192
const styleHref = await getVocsStyleHref(c.env.ASSETS, c.req.url);
193
-
return c.html(renderError("Missing handle or publication URI.", styleHref), 400);
0
0
0
194
}
195
196
const returnTo = `${c.env.CLIENT_URL}/subscribe?publicationUri=${encodeURIComponent(publicationUri)}`;
···
205
// HTML rendering
206
// ============================================================================
207
208
-
function renderHandleForm(publicationUri: string, styleHref: string, error?: string): string {
0
0
0
0
209
const errorHtml = error
210
? `<p class="vocs_Paragraph error">${escapeHtml(error)}</p>`
211
: "";
212
213
-
return page(`
0
214
<h1 class="vocs_H1 vocs_Heading">Subscribe on Bluesky</h1>
215
<p class="vocs_Paragraph">Enter your Bluesky handle to subscribe to this publication.</p>
216
${errorHtml}
···
226
/>
227
<button type="submit" class="vocs_Button_button vocs_Button_button_accent">Continue on Bluesky</button>
228
</form>
229
-
`, styleHref);
0
0
230
}
231
232
function renderSuccess(
···
240
: "You've successfully subscribed!";
241
const escapedPublicationUri = escapeHtml(publicationUri);
242
const escapedRecordUri = escapeHtml(recordUri);
243
-
return page(`
0
244
<h1 class="vocs_H1 vocs_Heading">Subscribed ✓</h1>
245
<p class="vocs_Paragraph">${msg}</p>
246
<p class="vocs_Paragraph"><small>Publication: <code class="vocs_Code"><a href="https://pds.ls/${escapedPublicationUri}">${escapedPublicationUri}</a></code></small></p>
247
<p class="vocs_Paragraph"><small>Record: <code class="vocs_Code"><a href="https://pds.ls/${escapedRecordUri}">${escapedRecordUri}</a></code></small></p>
248
-
`, styleHref);
0
0
249
}
250
251
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);
0
0
0
253
}
254
255
function page(body: string, styleHref: string): string {
···
12
// Cache the vocs-generated stylesheet href across requests (changes on rebuild).
13
let _vocsStyleHref: string | null = null;
14
15
+
async function getVocsStyleHref(
16
+
assets: Fetcher,
17
+
baseUrl: string,
18
+
): Promise<string> {
19
if (_vocsStyleHref) return _vocsStyleHref;
20
try {
21
const indexUrl = new URL("/", baseUrl).toString();
···
108
const session = await client.restore(did);
109
const agent = new Agent(session);
110
111
+
const existingUri = await findExistingSubscription(
112
+
agent,
113
+
did,
114
+
publicationUri,
115
+
);
116
if (existingUri) {
117
+
return c.json({
118
+
subscribed: true,
119
+
existing: true,
120
+
recordUri: existingUri,
121
+
});
122
}
123
124
const result = await agent.com.atproto.repo.createRecord({
···
130
},
131
});
132
133
+
return c.json({
134
+
subscribed: true,
135
+
existing: false,
136
+
recordUri: result.data.uri,
137
+
});
138
} catch (error) {
139
console.error("Subscribe POST error:", error);
140
// Treat expired/missing session as unauthenticated
···
156
const styleHref = await getVocsStyleHref(c.env.ASSETS, c.req.url);
157
158
if (!publicationUri || !publicationUri.startsWith("at://")) {
159
+
return c.html(
160
+
renderError("Missing or invalid publication URI.", styleHref),
161
+
400,
162
+
);
163
}
164
165
const did = getSessionDid(c);
···
172
const session = await client.restore(did);
173
const agent = new Agent(session);
174
175
+
const existingUri = await findExistingSubscription(
176
+
agent,
177
+
did,
178
+
publicationUri,
179
+
);
180
if (existingUri) {
181
+
return c.html(
182
+
renderSuccess(publicationUri, existingUri, true, styleHref),
183
+
);
184
}
185
186
const result = await agent.com.atproto.repo.createRecord({
···
192
},
193
});
194
195
+
return c.html(
196
+
renderSuccess(publicationUri, result.data.uri, false, styleHref),
197
+
);
198
} catch (error) {
199
console.error("Subscribe GET error:", error);
200
// Session expired - ask the user to sign in again
201
+
return c.html(
202
+
renderHandleForm(
203
+
publicationUri,
204
+
styleHref,
205
+
"Session expired. Please sign in again.",
206
+
),
207
+
);
208
}
209
});
210
···
222
223
if (!handle || !publicationUri) {
224
const styleHref = await getVocsStyleHref(c.env.ASSETS, c.req.url);
225
+
return c.html(
226
+
renderError("Missing handle or publication URI.", styleHref),
227
+
400,
228
+
);
229
}
230
231
const returnTo = `${c.env.CLIENT_URL}/subscribe?publicationUri=${encodeURIComponent(publicationUri)}`;
···
240
// HTML rendering
241
// ============================================================================
242
243
+
function renderHandleForm(
244
+
publicationUri: string,
245
+
styleHref: string,
246
+
error?: string,
247
+
): string {
248
const errorHtml = error
249
? `<p class="vocs_Paragraph error">${escapeHtml(error)}</p>`
250
: "";
251
252
+
return page(
253
+
`
254
<h1 class="vocs_H1 vocs_Heading">Subscribe on Bluesky</h1>
255
<p class="vocs_Paragraph">Enter your Bluesky handle to subscribe to this publication.</p>
256
${errorHtml}
···
266
/>
267
<button type="submit" class="vocs_Button_button vocs_Button_button_accent">Continue on Bluesky</button>
268
</form>
269
+
`,
270
+
styleHref,
271
+
);
272
}
273
274
function renderSuccess(
···
282
: "You've successfully subscribed!";
283
const escapedPublicationUri = escapeHtml(publicationUri);
284
const escapedRecordUri = escapeHtml(recordUri);
285
+
return page(
286
+
`
287
<h1 class="vocs_H1 vocs_Heading">Subscribed ✓</h1>
288
<p class="vocs_Paragraph">${msg}</p>
289
<p class="vocs_Paragraph"><small>Publication: <code class="vocs_Code"><a href="https://pds.ls/${escapedPublicationUri}">${escapedPublicationUri}</a></code></small></p>
290
<p class="vocs_Paragraph"><small>Record: <code class="vocs_Code"><a href="https://pds.ls/${escapedRecordUri}">${escapedRecordUri}</a></code></small></p>
291
+
`,
292
+
styleHref,
293
+
);
294
}
295
296
function renderError(message: string, styleHref: string): string {
297
+
return page(
298
+
`<h1 class="vocs_H1 vocs_Heading">Error</h1><p class="vocs_Paragraph error">${escapeHtml(message)}</p>`,
299
+
styleHref,
300
+
);
301
}
302
303
function page(body: string, styleHref: string): string {