···
- `bsky.app` is feeling 🦋 according to `https://bsky.app/status.json`
- `reddit.com` is feeling 🤓 according to `https://reddit.com/status.json`
24
-
The Atmosphere works the same way, except we're going to check `at://` instead of `https://`. Each user has a data repo under an `at://` URL. We'll crawl all the `at://`s in the Atmosphere for all the `/status.json` records and aggregate them into our SQLite database.
24
+
The Atmosphere works the same way, except we're going to check `at://` instead of `https://`. Each user has a data repo under an `at://` URL. We'll crawl all the `at://`s in the Atmosphere for all the "status.json" records and aggregate them into our SQLite database.
26
+
> `at://` is the URL scheme of the AT Protocol.
## Step 1. Starting with our ExpressJS app
···
repo: agent.accountDid, // The user
collection: 'app.bsky.actor.profile', // The collection
237
-
rkey: 'self', // The record name
239
+
rkey: 'self', // The record key
We write records using a similar API. Since our goal is to write "status" records, let's look at how that will happen:
246
+
// Generate a time-based key for our record
247
+
const rkey = TID.nextStr()
repo: agent.accountDid, // The user
collection: 'com.example.status', // The collection
247
-
rkey: 'self', // The record name
253
+
rkey, // The record key
record: { // The record value
250
-
updatedAt: new Date().toISOString()
256
+
createdAt: new Date().toISOString()
···
$type: 'com.example.status',
status: req.body?.status,
273
-
updatedAt: new Date().toISOString(),
279
+
createdAt: new Date().toISOString(),
···
collection: 'com.example.status',
287
+
rkey: TID.nextStr(),
···
> ### Why create a schema?
334
-
> Schemas help other applications understand the data your app is creating. By publishing your schemas, you enable compatibility and reduce the chances of bad data affecting your app.
340
+
> Schemas help other applications understand the data your app is creating. By publishing your schemas, you enable compatibility with other apps and reduce the chances of bad data affecting your app.
Let's create our schema in the `/lexicons` folder of our codebase. You can [read more about how to define schemas here](#todo).
···
346
-
"key": "literal:self",
349
-
"required": ["status", "updatedAt"],
355
+
"required": ["status", "createdAt"],
···
···
$type: 'com.example.status',
status: req.body?.status,
390
-
updatedAt: new Date().toISOString(),
396
+
createdAt: new Date().toISOString(),
if (!Status.validateRecord(record).success) {
return res.status(400).json({ error: 'Invalid status' })
···
│ ┌───────────────────────────────────────────┐
418
-
├───┼ 1 PUT /com.example.status/self │
424
+
├───┼ 1 PUT /app.bsky.feed.post/3l244rmrxjx2v │
│ └───────────────────────────────────────────┘
│ ┌───────────────────────────────────────────┐
├───┼ 2 DEL /app.bsky.feed.post/3l244rmrxjx2v │
│ └───────────────────────────────────────────┘
│ ┌───────────────────────────────────────────┐
424
-
├───┼ 3 PUT /app.bsky.actor/self │
430
+
├───┼ 3 PUT /app.bsky.actor.profile/self │
▼ └───────────────────────────────────────────┘
···
// Create our statuses table
462
-
.addColumn('authorDid', 'varchar', (col) => col.primaryKey())
468
+
.addColumn('uri', 'varchar', (col) => col.primaryKey())
469
+
.addColumn('authorDid', 'varchar', (col) => col.notNull())
.addColumn('status', 'varchar', (col) => col.notNull())
464
-
.addColumn('updatedAt', 'varchar', (col) => col.notNull())
471
+
.addColumn('createdAt', 'varchar', (col) => col.notNull())
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
···
490
+
uri: evt.uri.toString(),
485
-
updatedAt: record.updatedAt,
493
+
createdAt: record.createdAt,
indexedAt: new Date().toISOString(),
489
-
oc.column('authorDid').doUpdateSet({
497
+
oc.column('uri').doUpdateSet({
491
-
updatedAt: record.updatedAt,
indexedAt: new Date().toISOString(),
···
<!-- src/pages/home.ts -->
${statuses.map((status, i) => {
const handle = didHandleMap[status.authorDid] || status.authorDid
549
-
const date = ts(status)
<div class="status-line">
···
handler(async (req, res) => {
// Write the status record to the user's repository
592
-
await agent.putRecord({
599
+
const res = await agent.putRecord({
collection: 'com.example.status',
602
+
rkey: TID.nextStr(),
ctx.logger.warn({ err }, 'failed to write record')
return res.status(500).json({ error: 'Failed to write record' })
···
authorDid: agent.accountDid,
610
-
updatedAt: record.updatedAt,
619
+
createdAt: record.createdAt,
indexedAt: new Date().toISOString(),
613
-
.onConflict((oc) =>
614
-
oc.column('authorDid').doUpdateSet({
615
-
status: record.status,
616
-
updatedAt: record.updatedAt,
617
-
indexedAt: new Date().toISOString(),