Scratch space for learning atproto app development

Fix for OAuth localhost scopes (#16)

* fix oauth localhost usage

* misc fixes to profile validation and status view

Changed files
+29 -106
src
+20 -98
package-lock.json
···
"@atproto/api": "^0.13.4",
"@atproto/common": "^0.4.1",
"@atproto/identity": "^0.4.0",
-
"@atproto/lexicon": "0.4.1-rc.0",
+
"@atproto/lexicon": "^0.4.2",
"@atproto/oauth-client-node": "^0.1.0",
-
"@atproto/repo": "0.4.2-rc.0",
"@atproto/sync": "^0.1.0",
"@atproto/syntax": "^0.3.0",
"@atproto/xrpc-server": "^0.6.3",
···
"tlds": "^1.234.0"
}
},
-
"node_modules/@atproto/api/node_modules/@atproto/lexicon": {
-
"version": "0.4.1",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.1.tgz",
-
"integrity": "sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==",
-
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/syntax": "^0.3.0",
-
"iso-datestring-validator": "^2.2.2",
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
"node_modules/@atproto/common": {
-
"version": "0.4.1",
-
"resolved": "https://registry.npmjs.org/@atproto/common/-/common-0.4.1.tgz",
-
"integrity": "sha512-uL7kQIcBTbvkBDNfxMXL6lBH4fO2DQpHd2BryJxMtbw/4iEPKe9xBYApwECHhEIk9+zhhpTRZ15FJ3gxTXN82Q==",
+
"version": "0.4.4",
+
"resolved": "https://registry.npmjs.org/@atproto/common/-/common-0.4.4.tgz",
+
"integrity": "sha512-58tMbn6A1Zu296s/l3uIj8z9d7IRHpZvLOfsFRikaQaYrzhJpL2aPY4uFQ8GJcxnsxeUnxBCrQz9we5jVVJI5Q==",
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
+
"@atproto/common-web": "^0.3.1",
"@ipld/dag-cbor": "^7.0.3",
"cbor-x": "^1.5.1",
"iso-datestring-validator": "^2.2.2",
···
}
},
"node_modules/@atproto/common-web": {
-
"version": "0.3.0",
-
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.3.0.tgz",
-
"integrity": "sha512-67VnV6JJyX+ZWyjV7xFQMypAgDmjVaR9ZCuU/QW+mqlqI7fex2uL4Fv+7/jHadgzhuJHVd6OHOvNn0wR5WZYtA==",
+
"version": "0.3.1",
+
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.3.1.tgz",
+
"integrity": "sha512-N7wiTnus5vAr+lT//0y8m/FaHHLJ9LpGuEwkwDAeV3LCiPif4m/FS8x/QOYrx1PdZQwKso95RAPzCGWQBH5j6Q==",
"dependencies": {
"graphemer": "^1.4.0",
"multiformats": "^9.9.0",
"uint8arrays": "3.0.0",
-
"zod": "^3.21.4"
+
"zod": "^3.23.8"
}
},
"node_modules/@atproto/common/node_modules/pino": {
···
"lex": "dist/index.js"
}
},
-
"node_modules/@atproto/lex-cli/node_modules/@atproto/lexicon": {
-
"version": "0.4.1",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.1.tgz",
-
"integrity": "sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==",
-
"dev": true,
-
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/syntax": "^0.3.0",
-
"iso-datestring-validator": "^2.2.2",
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
"node_modules/@atproto/lexicon": {
-
"version": "0.4.1-rc.0",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.1-rc.0.tgz",
-
"integrity": "sha512-CSYO8MWbxTXTLQMEJ1mTXD2pDxIXO2oCK/FVw9T/BeXLMcvwmeVgKAaytd1AGFkapX8IMAAtjBB3cnaltuHwbg==",
+
"version": "0.4.2",
+
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.2.tgz",
+
"integrity": "sha512-CXoOkhcdF3XVUnR2oNgCs2ljWfo/8zUjxL5RIhJW/UNLp/FSl+KpF8Jm5fbk8Y/XXVPGRAsv9OYfxyU/14N/pw==",
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
+
"@atproto/common-web": "^0.3.1",
"@atproto/syntax": "^0.3.0",
"iso-datestring-validator": "^2.2.2",
"multiformats": "^9.9.0",
···
}
},
"node_modules/@atproto/repo": {
-
"version": "0.4.2-rc.0",
-
"resolved": "https://registry.npmjs.org/@atproto/repo/-/repo-0.4.2-rc.0.tgz",
-
"integrity": "sha512-y8zXAR23r6qlsTmbzXaBEHYjvlgeNlAKj9eJ6V17JtT+4FVdW246alhsgSsglJ2Uv/e24RC1r90yNJNRxqDzXw==",
+
"version": "0.5.3",
+
"resolved": "https://registry.npmjs.org/@atproto/repo/-/repo-0.5.3.tgz",
+
"integrity": "sha512-Lbp35SaK5149B9VnE6CVruo/iImNKQ49pPSR+5KuStHDCIyH0z/ynOrEJfpQjTzVu9kdio6bimo5zsl4F2fT2Q==",
"dependencies": {
-
"@atproto/common": "^0.4.1",
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/crypto": "^0.4.0",
-
"@atproto/lexicon": "^0.4.1-rc.0",
+
"@atproto/common": "^0.4.4",
+
"@atproto/common-web": "^0.3.1",
+
"@atproto/crypto": "^0.4.1",
+
"@atproto/lexicon": "^0.4.2",
"@ipld/car": "^3.2.3",
"@ipld/dag-cbor": "^7.0.0",
"multiformats": "^9.9.0",
···
"p-queue": "^6.6.2"
}
},
-
"node_modules/@atproto/sync/node_modules/@atproto/lexicon": {
-
"version": "0.4.1",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.1.tgz",
-
"integrity": "sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==",
-
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/syntax": "^0.3.0",
-
"iso-datestring-validator": "^2.2.2",
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/sync/node_modules/@atproto/repo": {
-
"version": "0.5.0",
-
"resolved": "https://registry.npmjs.org/@atproto/repo/-/repo-0.5.0.tgz",
-
"integrity": "sha512-kZbj4wW5eFrDjkSTS9z+6bT4OTr5K4GrqWukWbfdBJtZPXsRDm75AV0C9ItoHDTdbBXn65TK6kqaJTrf89osCg==",
-
"dependencies": {
-
"@atproto/common": "^0.4.1",
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/crypto": "^0.4.1",
-
"@atproto/lexicon": "^0.4.1",
-
"@ipld/car": "^3.2.3",
-
"@ipld/dag-cbor": "^7.0.0",
-
"multiformats": "^9.9.0",
-
"uint8arrays": "3.0.0",
-
"zod": "^3.23.8"
-
}
-
},
"node_modules/@atproto/syntax": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.0.tgz",
···
"rate-limiter-flexible": "^2.4.1",
"uint8arrays": "3.0.0",
"ws": "^8.12.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/xrpc-server/node_modules/@atproto/lexicon": {
-
"version": "0.4.1",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.1.tgz",
-
"integrity": "sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==",
-
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/syntax": "^0.3.0",
-
"iso-datestring-validator": "^2.2.2",
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/xrpc/node_modules/@atproto/lexicon": {
-
"version": "0.4.1",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.1.tgz",
-
"integrity": "sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==",
-
"dependencies": {
-
"@atproto/common-web": "^0.3.0",
-
"@atproto/syntax": "^0.3.0",
-
"iso-datestring-validator": "^2.2.2",
-
"multiformats": "^9.9.0",
"zod": "^3.23.8"
}
},
+1 -2
package.json
···
"@atproto/common": "^0.4.1",
"@atproto/api": "^0.13.4",
"@atproto/identity": "^0.4.0",
-
"@atproto/lexicon": "0.4.1-rc.0",
+
"@atproto/lexicon": "^0.4.2",
"@atproto/oauth-client-node": "^0.1.0",
-
"@atproto/repo": "0.4.2-rc.0",
"@atproto/sync": "^0.1.0",
"@atproto/syntax": "^0.3.0",
"@atproto/xrpc-server": "^0.6.3",
+2 -1
src/auth/client.ts
···
export const createClient = async (db: Database) => {
const publicUrl = env.PUBLIC_URL
const url = publicUrl || `http://127.0.0.1:${env.PORT}`
+
const enc = encodeURIComponent
return new NodeOAuthClient({
clientMetadata: {
client_name: 'AT Protocol Express App',
client_id: publicUrl
? `${url}/client-metadata.json`
-
: `http://localhost?redirect_uri=${encodeURIComponent(`${url}/oauth/callback`)}`,
+
: `http://localhost?redirect_uri=${enc(`${url}/oauth/callback`)}&scope=${enc('atproto transition:generic')}`,
client_uri: url,
redirect_uris: [`${url}/oauth/callback`],
scope: 'atproto transition:generic',
+4 -3
src/ingester.ts
···
handleEvent: async (evt) => {
// Watch for write events
if (evt.event === 'create' || evt.event === 'update') {
+
const now = new Date()
const record = evt.record
// If the write is a valid status update
···
authorDid: evt.did,
status: record.status,
createdAt: record.createdAt,
-
indexedAt: new Date().toISOString(),
+
indexedAt: now.toISOString(),
})
.onConflict((oc) =>
oc.column('uri').doUpdateSet({
status: record.status,
-
indexedAt: new Date().toISOString(),
+
indexedAt: now.toISOString(),
})
)
.execute()
···
evt.collection === 'xyz.statusphere.status'
) {
// Remove the status from our SQLite
-
await db.deleteFrom('status').where({ uri: evt.uri.toString() })
+
await db.deleteFrom('status').where('uri', '=', evt.uri.toString()).execute()
}
},
onError: (err) => {
+2 -2
src/pages/home.ts
···
}
function ts(status: Status) {
+
const createdAt = new Date(status.createdAt)
const indexedAt = new Date(status.indexedAt)
-
const updatedAt = new Date(status.updatedAt)
-
if (updatedAt > indexedAt) return updatedAt.toDateString()
+
if (createdAt < indexedAt) return createdAt.toDateString()
return indexedAt.toDateString()
}