this repo has no description

needs some serious refactoring

+295 -24
+2
.gitignore
··· 7 7 .env 8 8 .env.local 9 9 tap.db 10 + tap.db-shm 11 + tap.db-wal 10 12 leaderboards.db
+1 -1
drizzle.config.ts
··· 5 5 out: "./migrations", 6 6 dialect: "sqlite", 7 7 dbCredentials: { 8 - url: "./leaderboards.sqlite", 8 + url: "./leaderboards.db", 9 9 }, 10 10 });
+12
lexicons.json
··· 1 + { 2 + "version": 1, 3 + "lexicons": [ 4 + "com.atproto.repo.strongRef" 5 + ], 6 + "resolutions": { 7 + "com.atproto.repo.strongRef": { 8 + "uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.repo.strongRef", 9 + "cid": "bafyreifrkdbnkvfjujntdaeigolnrjj3srrs53tfixjhmacclps72qlov4" 10 + } 11 + } 12 + }
+25
lexicons/com/atproto/repo/strongRef.json
··· 1 + { 2 + "id": "com.atproto.repo.strongRef", 3 + "defs": { 4 + "main": { 5 + "type": "object", 6 + "required": [ 7 + "uri", 8 + "cid" 9 + ], 10 + "properties": { 11 + "cid": { 12 + "type": "string", 13 + "format": "cid" 14 + }, 15 + "uri": { 16 + "type": "string", 17 + "format": "at-uri" 18 + } 19 + } 20 + } 21 + }, 22 + "$type": "com.atproto.lexicon.schema", 23 + "lexicon": 1, 24 + "description": "A URI with a content-hash fingerprint." 25 + }
+31
lexicons/dev/npmx/feed/like.json
··· 1 + { 2 + "defs": { 3 + "main": { 4 + "description": "A like of a package on npmx", 5 + "key": "tid", 6 + "record": { 7 + "properties": { 8 + "createdAt": { 9 + "format": "datetime", 10 + "type": "string" 11 + }, 12 + "subject": { 13 + "description": "A strong reference to the dev.npmx.package record. If the package does not have a record in an atproto repo, this is not included.", 14 + "type": "ref", 15 + "ref": "com.atproto.repo.strongRef" 16 + }, 17 + "subjectRef": { 18 + "description": "The npmx URL to the package to allow for counting of packages that do not have a record in an atproto repo.", 19 + "type": "string", 20 + "format": "uri" 21 + } 22 + }, 23 + "required": ["createdAt", "subjectRef"], 24 + "type": "object" 25 + }, 26 + "type": "record" 27 + } 28 + }, 29 + "id": "dev.npmx.feed.like", 30 + "lexicon": 1 31 + }
+2 -1
migrations/0000_first_paper_doll.sql migrations/0000_dashing_jack_power.sql
··· 3 3 `at_uri` text NOT NULL, 4 4 `subject_ref` text NOT NULL, 5 5 `did` text NOT NULL, 6 - `created_at` integer 6 + `createdAt` integer, 7 + `indexedAt` integer 7 8 ); 8 9 --> statement-breakpoint 9 10 CREATE UNIQUE INDEX `likes_at_uri_unique` ON `likes` (`at_uri`);--> statement-breakpoint
+10 -3
migrations/meta/0000_snapshot.json
··· 1 1 { 2 2 "version": "6", 3 3 "dialect": "sqlite", 4 - "id": "2b8e4b14-3a46-4ffb-91d3-63f954259ccc", 4 + "id": "061090c3-1410-40d5-9146-4170bde219c2", 5 5 "prevId": "00000000-0000-0000-0000-000000000000", 6 6 "tables": { 7 7 "likes": { ··· 35 35 "notNull": true, 36 36 "autoincrement": false 37 37 }, 38 - "created_at": { 39 - "name": "created_at", 38 + "createdAt": { 39 + "name": "createdAt", 40 + "type": "integer", 41 + "primaryKey": false, 42 + "notNull": false, 43 + "autoincrement": false 44 + }, 45 + "indexedAt": { 46 + "name": "indexedAt", 40 47 "type": "integer", 41 48 "primaryKey": false, 42 49 "notNull": false,
+2 -2
migrations/meta/_journal.json
··· 5 5 { 6 6 "idx": 0, 7 7 "version": "6", 8 - "when": 1770329214386, 9 - "tag": "0000_first_paper_doll", 8 + "when": 1770333242819, 9 + "tag": "0000_dashing_jack_power", 10 10 "breakpoints": true 11 11 } 12 12 ]
+11 -8
package.json
··· 5 5 "build": "nitro build --preset preset", 6 6 "dev": "nitro dev", 7 7 "preview": "node .output/server/index.mjs", 8 - "drizzle:generate": "drizzle-kit generate" 8 + "drizzle:generate": "drizzle-kit generate", 9 + "drizzle:migrate": "drizzle-kit migrate", 10 + "generate:lexicons": "lex build --lexicons lexicons --out server/utils/types/lexicons --clear" 11 + }, 12 + "dependencies": { 13 + "@atproto/lex": "^0.0.14", 14 + "@atproto/tap": "^0.2.2", 15 + "better-sqlite3": "^12.6.2", 16 + "dotenv": "^17.2.4", 17 + "drizzle-orm": "^0.45.1", 18 + "node": "link:@libsql/client/node" 9 19 }, 10 20 "devDependencies": { 11 21 "@types/better-sqlite3": "^7.6.13", ··· 13 23 "h3": "^1.15.4", 14 24 "nitropack": "^2.12.4", 15 25 "tsx": "^4.21.0" 16 - }, 17 - "dependencies": { 18 - "@atproto/tap": "^0.2.2", 19 - "better-sqlite3": "^12.6.2", 20 - "dotenv": "^17.2.4", 21 - "drizzle-orm": "^0.45.1", 22 - "node": "link:@libsql/client/node" 23 26 } 24 27 }
+3
pnpm-lock.yaml
··· 8 8 9 9 .: 10 10 dependencies: 11 + '@atproto/lex': 12 + specifier: ^0.0.14 13 + version: 0.0.14 11 14 '@atproto/tap': 12 15 specifier: ^0.2.2 13 16 version: 0.2.2
+1 -1
pnpm-workspace.yaml
··· 1 1 onlyBuiltDependencies: 2 - - '@parcel/watcher' 2 + - "@parcel/watcher" 3 3 - better-sqlite3 4 4 - core-js 5 5 - esbuild
+2 -1
schema.ts server/utils/db/schema.ts
··· 7 7 atUri: text("at_uri").notNull().unique(), 8 8 subjectRef: text("subject_ref").notNull(), 9 9 repo: text("did").notNull(), 10 - createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn( 10 + createdAt: integer("createdAt", { mode: "timestamp" }), 11 + indexedAt: integer("indexedAt", { mode: "timestamp" }).$defaultFn( 11 12 () => new Date(), 12 13 ), 13 14 },
+51 -4
server/api/tap/webhook.post.ts
··· 1 - import { parseTapEvent, assureAdminAuth } from "@atproto/tap"; 1 + import { parseTapEvent, assureAdminAuth, RecordEvent } from "@atproto/tap"; 2 + import { db } from "../../utils/db/database"; 3 + import { likes, NewLike } from "../../utils/db/schema"; 4 + import * as dev from "../../utils/types/lexicons/dev"; 5 + import { drizzle } from "drizzle-orm/better-sqlite3"; 6 + 7 + // const db = drizzle(process.env.DATABASE_URL ?? "leaderboards.db"); 2 8 3 9 export default defineEventHandler(async (event) => { 4 10 const adminPassword = useRuntimeConfig(event).tapAdminPassword; ··· 25 31 26 32 const body = await readBody(event); 27 33 const tapEvent = parseTapEvent(body); 28 - // Do something with tapEvent like saving it to a database 29 - console.log("Tap event received:", tapEvent); 30 - return { message: "Tap event received successfully" }; 34 + switch (tapEvent.type) { 35 + case "identity": 36 + //Just logging these for now 37 + console.log("Identity event received:", tapEvent); 38 + break; 39 + case "record": 40 + const recordEvent: RecordEvent = tapEvent; 41 + const atUri = `at://${recordEvent.did}/${recordEvent.collection}/${recordEvent.rkey}`; 42 + const likeRecord = dev.npmx.feed.like.$validate(recordEvent.record); 43 + if (!likeRecord) { 44 + console.log("Invalid like record:", recordEvent); 45 + break; 46 + } 47 + if (recordEvent.collection !== "dev.npmx.feed.like") { 48 + console.log("Skipping event:", recordEvent); 49 + break; 50 + } 51 + 52 + switch (recordEvent.action) { 53 + case "create": 54 + const newLike: NewLike = { 55 + atUri, 56 + subjectRef: likeRecord.subjectRef, 57 + repo: recordEvent.did, 58 + createdAt: new Date(likeRecord.createdAt), 59 + }; 60 + await db.insert(likes).values(newLike); 61 + console.log("new like added"); 62 + break; 63 + case "update": 64 + // const updatedLike: NewLike = {}; 65 + // db.update(likes).where(eq(likes.id, tapEvent.record.id)).set({ 66 + // score: tapEvent.record.score, 67 + // updatedAt: tapEvent.record.updatedAt, 68 + // }); 69 + break; 70 + case "delete": 71 + // db.delete(likes).where(eq(likes.id, tapEvent.record.id)); 72 + break; 73 + } 74 + break; 75 + } 76 + 77 + return {}; 31 78 });
+1 -1
server/routes/index.ts
··· 1 - import { eventHandler } from "h3" 1 + import { eventHandler } from "h3"; 2 2 3 3 // Learn more: https://nitro.build/guide/routing 4 4 export default eventHandler((event) => {
server/utils/database.ts server/utils/db/database.ts
+5
server/utils/types/lexicons/com.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * as atproto from './com/atproto.js'
+5
server/utils/types/lexicons/com/atproto.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * as repo from './atproto/repo.js'
+5
server/utils/types/lexicons/com/atproto/repo.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * as strongRef from './repo/strongRef.js'
+41
server/utils/types/lexicons/com/atproto/repo/strongRef.defs.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + import { l } from '@atproto/lex' 6 + 7 + const $nsid = 'com.atproto.repo.strongRef' 8 + 9 + export { $nsid } 10 + 11 + type Main = { 12 + $type?: 'com.atproto.repo.strongRef' 13 + cid: l.CidString 14 + uri: l.AtUriString 15 + } 16 + 17 + export type { Main } 18 + 19 + const main = l.typedObject<Main>( 20 + $nsid, 21 + 'main', 22 + l.object({ 23 + cid: l.string({ format: 'cid' }), 24 + uri: l.string({ format: 'at-uri' }), 25 + }), 26 + ) 27 + 28 + export { main } 29 + 30 + export const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main), 31 + $build = /*#__PURE__*/ main.build.bind(main), 32 + $type = /*#__PURE__*/ main.$type 33 + export const $assert = /*#__PURE__*/ main.assert.bind(main), 34 + $check = /*#__PURE__*/ main.check.bind(main), 35 + $cast = /*#__PURE__*/ main.cast.bind(main), 36 + $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main), 37 + $matches = /*#__PURE__*/ main.matches.bind(main), 38 + $parse = /*#__PURE__*/ main.parse.bind(main), 39 + $safeParse = /*#__PURE__*/ main.safeParse.bind(main), 40 + $validate = /*#__PURE__*/ main.validate.bind(main), 41 + $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main)
+6
server/utils/types/lexicons/com/atproto/repo/strongRef.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * from './strongRef.defs.js' 6 + export * as $defs from './strongRef.defs.js'
+5
server/utils/types/lexicons/dev.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * as npmx from './dev/npmx.js'
+5
server/utils/types/lexicons/dev/npmx.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * as feed from './npmx/feed.js'
+5
server/utils/types/lexicons/dev/npmx/feed.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * as like from './feed/like.js'
+56
server/utils/types/lexicons/dev/npmx/feed/like.defs.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + import { l } from '@atproto/lex' 6 + import * as RepoStrongRef from '../../../com/atproto/repo/strongRef.defs.js' 7 + 8 + const $nsid = 'dev.npmx.feed.like' 9 + 10 + export { $nsid } 11 + 12 + /** A like of a package on npmx */ 13 + type Main = { 14 + $type: 'dev.npmx.feed.like' 15 + createdAt: l.DatetimeString 16 + 17 + /** 18 + * A strong reference to the dev.npmx.package record. If the package does not have a record in an atproto repo, this is not included. 19 + */ 20 + subject?: RepoStrongRef.Main 21 + 22 + /** 23 + * The npmx URL to the package to allow for counting of packages that do not have a record in an atproto repo. 24 + */ 25 + subjectRef: l.UriString 26 + } 27 + 28 + export type { Main } 29 + 30 + /** A like of a package on npmx */ 31 + const main = l.record<'tid', Main>( 32 + 'tid', 33 + $nsid, 34 + l.object({ 35 + createdAt: l.string({ format: 'datetime' }), 36 + subject: l.optional( 37 + l.ref<RepoStrongRef.Main>((() => RepoStrongRef.main) as any), 38 + ), 39 + subjectRef: l.string({ format: 'uri' }), 40 + }), 41 + ) 42 + 43 + export { main } 44 + 45 + export const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main), 46 + $build = /*#__PURE__*/ main.build.bind(main), 47 + $type = /*#__PURE__*/ main.$type 48 + export const $assert = /*#__PURE__*/ main.assert.bind(main), 49 + $check = /*#__PURE__*/ main.check.bind(main), 50 + $cast = /*#__PURE__*/ main.cast.bind(main), 51 + $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main), 52 + $matches = /*#__PURE__*/ main.matches.bind(main), 53 + $parse = /*#__PURE__*/ main.parse.bind(main), 54 + $safeParse = /*#__PURE__*/ main.safeParse.bind(main), 55 + $validate = /*#__PURE__*/ main.validate.bind(main), 56 + $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main)
+6
server/utils/types/lexicons/dev/npmx/feed/like.ts
··· 1 + /* 2 + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. 3 + */ 4 + 5 + export * from './like.defs.js' 6 + export * as $defs from './like.defs.js'
+2 -2
tsconfig.json
··· 27 27 28 28 // Libs & paths 29 29 "lib": ["ESNext", "DOM"], 30 - "baseUrl": ".", 31 - }, 30 + "baseUrl": "." 31 + } 32 32 }