A social knowledge tool for researchers built on ATProto
45
fork

Configure Feed

Select the types of activity you want to include in your feed.

formatting and linting

+394 -451
+42 -42
src/modules/atproto/infrastructure/lexicon/index.ts
··· 7 7 type Options as XrpcOptions, 8 8 type AuthVerifier, 9 9 type StreamAuthVerifier, 10 - } from '@atproto/xrpc-server' 11 - import { schemas } from './lexicons.js' 10 + } from '@atproto/xrpc-server'; 11 + import { schemas } from './lexicons.js'; 12 12 13 13 export function createServer(options?: XrpcOptions): Server { 14 - return new Server(options) 14 + return new Server(options); 15 15 } 16 16 17 17 export class Server { 18 - xrpc: XrpcServer 19 - network: NetworkNS 20 - com: ComNS 18 + xrpc: XrpcServer; 19 + network: NetworkNS; 20 + com: ComNS; 21 21 22 22 constructor(options?: XrpcOptions) { 23 - this.xrpc = createXrpcServer(schemas, options) 24 - this.network = new NetworkNS(this) 25 - this.com = new ComNS(this) 23 + this.xrpc = createXrpcServer(schemas, options); 24 + this.network = new NetworkNS(this); 25 + this.com = new ComNS(this); 26 26 } 27 27 } 28 28 29 29 export class NetworkNS { 30 - _server: Server 31 - cosmik: NetworkCosmikNS 30 + _server: Server; 31 + cosmik: NetworkCosmikNS; 32 32 33 33 constructor(server: Server) { 34 - this._server = server 35 - this.cosmik = new NetworkCosmikNS(server) 34 + this._server = server; 35 + this.cosmik = new NetworkCosmikNS(server); 36 36 } 37 37 } 38 38 39 39 export class NetworkCosmikNS { 40 - _server: Server 40 + _server: Server; 41 41 42 42 constructor(server: Server) { 43 - this._server = server 43 + this._server = server; 44 44 } 45 45 } 46 46 47 47 export class ComNS { 48 - _server: Server 49 - atproto: ComAtprotoNS 48 + _server: Server; 49 + atproto: ComAtprotoNS; 50 50 51 51 constructor(server: Server) { 52 - this._server = server 53 - this.atproto = new ComAtprotoNS(server) 52 + this._server = server; 53 + this.atproto = new ComAtprotoNS(server); 54 54 } 55 55 } 56 56 57 57 export class ComAtprotoNS { 58 - _server: Server 59 - repo: ComAtprotoRepoNS 58 + _server: Server; 59 + repo: ComAtprotoRepoNS; 60 60 61 61 constructor(server: Server) { 62 - this._server = server 63 - this.repo = new ComAtprotoRepoNS(server) 62 + this._server = server; 63 + this.repo = new ComAtprotoRepoNS(server); 64 64 } 65 65 } 66 66 67 67 export class ComAtprotoRepoNS { 68 - _server: Server 68 + _server: Server; 69 69 70 70 constructor(server: Server) { 71 - this._server = server 71 + this._server = server; 72 72 } 73 73 } 74 74 75 75 type SharedRateLimitOpts<T> = { 76 - name: string 77 - calcKey?: (ctx: T) => string | null 78 - calcPoints?: (ctx: T) => number 79 - } 76 + name: string; 77 + calcKey?: (ctx: T) => string | null; 78 + calcPoints?: (ctx: T) => number; 79 + }; 80 80 type RouteRateLimitOpts<T> = { 81 - durationMs: number 82 - points: number 83 - calcKey?: (ctx: T) => string | null 84 - calcPoints?: (ctx: T) => number 85 - } 86 - type HandlerOpts = { blobLimit?: number } 87 - type HandlerRateLimitOpts<T> = SharedRateLimitOpts<T> | RouteRateLimitOpts<T> 81 + durationMs: number; 82 + points: number; 83 + calcKey?: (ctx: T) => string | null; 84 + calcPoints?: (ctx: T) => number; 85 + }; 86 + type HandlerOpts = { blobLimit?: number }; 87 + type HandlerRateLimitOpts<T> = SharedRateLimitOpts<T> | RouteRateLimitOpts<T>; 88 88 type ConfigOf<Auth, Handler, ReqCtx> = 89 89 | Handler 90 90 | { 91 - auth?: Auth 92 - opts?: HandlerOpts 93 - rateLimit?: HandlerRateLimitOpts<ReqCtx> | HandlerRateLimitOpts<ReqCtx>[] 94 - handler: Handler 95 - } 91 + auth?: Auth; 92 + opts?: HandlerOpts; 93 + rateLimit?: HandlerRateLimitOpts<ReqCtx> | HandlerRateLimitOpts<ReqCtx>[]; 94 + handler: Handler; 95 + }; 96 96 type ExtractAuth<AV extends AuthVerifier | StreamAuthVerifier> = Extract< 97 97 Awaited<ReturnType<AV>>, 98 98 { credentials: unknown } 99 - > 99 + >;
+9 -9
src/modules/atproto/infrastructure/lexicon/lexicons.ts
··· 6 6 Lexicons, 7 7 ValidationError, 8 8 type ValidationResult, 9 - } from '@atproto/lexicon' 10 - import { type $Typed, is$typed, maybe$typed } from './util.js' 9 + } from '@atproto/lexicon'; 10 + import { type $Typed, is$typed, maybe$typed } from './util.js'; 11 11 12 12 export const schemaDict = { 13 13 NetworkCosmikCard: { ··· 286 286 }, 287 287 }, 288 288 }, 289 - } as const satisfies Record<string, LexiconDoc> 290 - export const schemas = Object.values(schemaDict) satisfies LexiconDoc[] 291 - export const lexicons: Lexicons = new Lexicons(schemas) 289 + } as const satisfies Record<string, LexiconDoc>; 290 + export const schemas = Object.values(schemaDict) satisfies LexiconDoc[]; 291 + export const lexicons: Lexicons = new Lexicons(schemas); 292 292 293 293 export function validate<T extends { $type: string }>( 294 294 v: unknown, 295 295 id: string, 296 296 hash: string, 297 297 requiredType: true, 298 - ): ValidationResult<T> 298 + ): ValidationResult<T>; 299 299 export function validate<T extends { $type?: string }>( 300 300 v: unknown, 301 301 id: string, 302 302 hash: string, 303 303 requiredType?: false, 304 - ): ValidationResult<T> 304 + ): ValidationResult<T>; 305 305 export function validate( 306 306 v: unknown, 307 307 id: string, ··· 315 315 error: new ValidationError( 316 316 `Must be an object with "${hash === 'main' ? id : `${id}#${hash}`}" $type property`, 317 317 ), 318 - } 318 + }; 319 319 } 320 320 321 321 export const ids = { ··· 324 324 NetworkCosmikCollectionLink: 'network.cosmik.collectionLink', 325 325 NetworkCosmikDefs: 'network.cosmik.defs', 326 326 ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', 327 - } as const 327 + } as const;
+12 -12
src/modules/atproto/infrastructure/lexicon/types/com/atproto/repo/strongRef.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon'; 5 + import { CID } from 'multiformats/cid'; 6 + import { validate as _validate } from '../../../../lexicons'; 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util'; 12 12 13 13 const is$typed = _is$typed, 14 - validate = _validate 15 - const id = 'com.atproto.repo.strongRef' 14 + validate = _validate; 15 + const id = 'com.atproto.repo.strongRef'; 16 16 17 17 export interface Main { 18 - $type?: 'com.atproto.repo.strongRef' 19 - cid: string 20 - uri: string 18 + $type?: 'com.atproto.repo.strongRef'; 19 + cid: string; 20 + uri: string; 21 21 } 22 22 23 - const hashMain = 'main' 23 + const hashMain = 'main'; 24 24 25 25 export function isMain<V>(v: V) { 26 - return is$typed(v, id, hashMain) 26 + return is$typed(v, id, hashMain); 27 27 } 28 28 29 29 export function validateMain<V>(v: V) { 30 - return validate<Main & V>(v, id, hashMain) 30 + return validate<Main & V>(v, id, hashMain); 31 31 }
+45 -41
src/modules/atproto/infrastructure/lexicon/types/network/cosmik/card.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - import type * as ComAtprotoRepoStrongRef from '../../com/atproto/repo/strongRef.js' 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon'; 5 + import { CID } from 'multiformats/cid'; 6 + import { validate as _validate } from '../../../lexicons'; 7 + import { 8 + type $Typed, 9 + is$typed as _is$typed, 10 + type OmitKey, 11 + } from '../../../util'; 12 + import type * as ComAtprotoRepoStrongRef from '../../com/atproto/repo/strongRef.js'; 9 13 10 14 const is$typed = _is$typed, 11 - validate = _validate 12 - const id = 'network.cosmik.card' 15 + validate = _validate; 16 + const id = 'network.cosmik.card'; 13 17 14 18 export interface Record { 15 - $type: 'network.cosmik.card' 19 + $type: 'network.cosmik.card'; 16 20 /** The type of card */ 17 - type: 'URL' | 'NOTE' | (string & {}) 18 - content: $Typed<UrlContent> | $Typed<NoteContent> | { $type: string } 21 + type: 'URL' | 'NOTE' | (string & {}); 22 + content: $Typed<UrlContent> | $Typed<NoteContent> | { $type: string }; 19 23 /** Optional URL associated with the card. Required for URL cards, optional for NOTE cards. */ 20 - url?: string 21 - parentCard?: ComAtprotoRepoStrongRef.Main 24 + url?: string; 25 + parentCard?: ComAtprotoRepoStrongRef.Main; 22 26 /** Timestamp when this card was created (usually set by PDS). */ 23 - createdAt?: string 24 - originalCard?: ComAtprotoRepoStrongRef.Main 25 - [k: string]: unknown 27 + createdAt?: string; 28 + originalCard?: ComAtprotoRepoStrongRef.Main; 29 + [k: string]: unknown; 26 30 } 27 31 28 - const hashRecord = 'main' 32 + const hashRecord = 'main'; 29 33 30 34 export function isRecord<V>(v: V) { 31 - return is$typed(v, id, hashRecord) 35 + return is$typed(v, id, hashRecord); 32 36 } 33 37 34 38 export function validateRecord<V>(v: V) { 35 - return validate<Record & V>(v, id, hashRecord, true) 39 + return validate<Record & V>(v, id, hashRecord, true); 36 40 } 37 41 38 42 /** Content structure for a URL card. */ 39 43 export interface UrlContent { 40 - $type?: 'network.cosmik.card#urlContent' 44 + $type?: 'network.cosmik.card#urlContent'; 41 45 /** The URL being saved */ 42 - url: string 43 - metadata?: UrlMetadata 46 + url: string; 47 + metadata?: UrlMetadata; 44 48 } 45 49 46 - const hashUrlContent = 'urlContent' 50 + const hashUrlContent = 'urlContent'; 47 51 48 52 export function isUrlContent<V>(v: V) { 49 - return is$typed(v, id, hashUrlContent) 53 + return is$typed(v, id, hashUrlContent); 50 54 } 51 55 52 56 export function validateUrlContent<V>(v: V) { 53 - return validate<UrlContent & V>(v, id, hashUrlContent) 57 + return validate<UrlContent & V>(v, id, hashUrlContent); 54 58 } 55 59 56 60 /** Content structure for a note card. */ 57 61 export interface NoteContent { 58 - $type?: 'network.cosmik.card#noteContent' 62 + $type?: 'network.cosmik.card#noteContent'; 59 63 /** The note text content */ 60 - text: string 64 + text: string; 61 65 } 62 66 63 - const hashNoteContent = 'noteContent' 67 + const hashNoteContent = 'noteContent'; 64 68 65 69 export function isNoteContent<V>(v: V) { 66 - return is$typed(v, id, hashNoteContent) 70 + return is$typed(v, id, hashNoteContent); 67 71 } 68 72 69 73 export function validateNoteContent<V>(v: V) { 70 - return validate<NoteContent & V>(v, id, hashNoteContent) 74 + return validate<NoteContent & V>(v, id, hashNoteContent); 71 75 } 72 76 73 77 /** Metadata about a URL. */ 74 78 export interface UrlMetadata { 75 - $type?: 'network.cosmik.card#urlMetadata' 79 + $type?: 'network.cosmik.card#urlMetadata'; 76 80 /** Title of the page */ 77 - title?: string 81 + title?: string; 78 82 /** Description of the page */ 79 - description?: string 83 + description?: string; 80 84 /** Author of the content */ 81 - author?: string 85 + author?: string; 82 86 /** When the content was published */ 83 - publishedDate?: string 87 + publishedDate?: string; 84 88 /** Name of the site */ 85 - siteName?: string 89 + siteName?: string; 86 90 /** URL of a representative image */ 87 - imageUrl?: string 91 + imageUrl?: string; 88 92 /** Type of content (e.g., 'video', 'article') */ 89 - type?: string 93 + type?: string; 90 94 /** When the metadata was retrieved */ 91 - retrievedAt?: string 95 + retrievedAt?: string; 92 96 } 93 97 94 - const hashUrlMetadata = 'urlMetadata' 98 + const hashUrlMetadata = 'urlMetadata'; 95 99 96 100 export function isUrlMetadata<V>(v: V) { 97 - return is$typed(v, id, hashUrlMetadata) 101 + return is$typed(v, id, hashUrlMetadata); 98 102 } 99 103 100 104 export function validateUrlMetadata<V>(v: V) { 101 - return validate<UrlMetadata & V>(v, id, hashUrlMetadata) 105 + return validate<UrlMetadata & V>(v, id, hashUrlMetadata); 102 106 }
+21 -17
src/modules/atproto/infrastructure/lexicon/types/network/cosmik/collection.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon'; 5 + import { CID } from 'multiformats/cid'; 6 + import { validate as _validate } from '../../../lexicons'; 7 + import { 8 + type $Typed, 9 + is$typed as _is$typed, 10 + type OmitKey, 11 + } from '../../../util'; 8 12 9 13 const is$typed = _is$typed, 10 - validate = _validate 11 - const id = 'network.cosmik.collection' 14 + validate = _validate; 15 + const id = 'network.cosmik.collection'; 12 16 13 17 export interface Record { 14 - $type: 'network.cosmik.collection' 18 + $type: 'network.cosmik.collection'; 15 19 /** Name of the collection */ 16 - name: string 20 + name: string; 17 21 /** Description of the collection */ 18 - description?: string 22 + description?: string; 19 23 /** Access control for the collection */ 20 - accessType: 'OPEN' | 'CLOSED' | (string & {}) 24 + accessType: 'OPEN' | 'CLOSED' | (string & {}); 21 25 /** List of collaborator DIDs who can add cards to closed collections */ 22 - collaborators?: string[] 26 + collaborators?: string[]; 23 27 /** Timestamp when this collection was created (usually set by PDS). */ 24 - createdAt?: string 28 + createdAt?: string; 25 29 /** Timestamp when this collection was last updated. */ 26 - updatedAt?: string 27 - [k: string]: unknown 30 + updatedAt?: string; 31 + [k: string]: unknown; 28 32 } 29 33 30 - const hashRecord = 'main' 34 + const hashRecord = 'main'; 31 35 32 36 export function isRecord<V>(v: V) { 33 - return is$typed(v, id, hashRecord) 37 + return is$typed(v, id, hashRecord); 34 38 } 35 39 36 40 export function validateRecord<V>(v: V) { 37 - return validate<Record & V>(v, id, hashRecord, true) 41 + return validate<Record & V>(v, id, hashRecord, true); 38 42 }
+22 -18
src/modules/atproto/infrastructure/lexicon/types/network/cosmik/collectionLink.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 8 - import type * as ComAtprotoRepoStrongRef from '../../com/atproto/repo/strongRef.js' 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon'; 5 + import { CID } from 'multiformats/cid'; 6 + import { validate as _validate } from '../../../lexicons'; 7 + import { 8 + type $Typed, 9 + is$typed as _is$typed, 10 + type OmitKey, 11 + } from '../../../util'; 12 + import type * as ComAtprotoRepoStrongRef from '../../com/atproto/repo/strongRef.js'; 9 13 10 14 const is$typed = _is$typed, 11 - validate = _validate 12 - const id = 'network.cosmik.collectionLink' 15 + validate = _validate; 16 + const id = 'network.cosmik.collectionLink'; 13 17 14 18 export interface Record { 15 - $type: 'network.cosmik.collectionLink' 16 - collection: ComAtprotoRepoStrongRef.Main 17 - card: ComAtprotoRepoStrongRef.Main 18 - originalCard?: ComAtprotoRepoStrongRef.Main 19 + $type: 'network.cosmik.collectionLink'; 20 + collection: ComAtprotoRepoStrongRef.Main; 21 + card: ComAtprotoRepoStrongRef.Main; 22 + originalCard?: ComAtprotoRepoStrongRef.Main; 19 23 /** DID of the user who added the card to the collection */ 20 - addedBy: string 24 + addedBy: string; 21 25 /** Timestamp when the card was added to the collection. */ 22 - addedAt: string 26 + addedAt: string; 23 27 /** Timestamp when this link record was created (usually set by PDS). */ 24 - createdAt?: string 25 - [k: string]: unknown 28 + createdAt?: string; 29 + [k: string]: unknown; 26 30 } 27 31 28 - const hashRecord = 'main' 32 + const hashRecord = 'main'; 29 33 30 34 export function isRecord<V>(v: V) { 31 - return is$typed(v, id, hashRecord) 35 + return is$typed(v, id, hashRecord); 32 36 } 33 37 34 38 export function validateRecord<V>(v: V) { 35 - return validate<Record & V>(v, id, hashRecord, true) 39 + return validate<Record & V>(v, id, hashRecord, true); 36 40 }
+16 -12
src/modules/atproto/infrastructure/lexicon/types/network/cosmik/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../lexicons' 7 - import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' 4 + import { type ValidationResult, BlobRef } from '@atproto/lexicon'; 5 + import { CID } from 'multiformats/cid'; 6 + import { validate as _validate } from '../../../lexicons'; 7 + import { 8 + type $Typed, 9 + is$typed as _is$typed, 10 + type OmitKey, 11 + } from '../../../util'; 8 12 9 13 const is$typed = _is$typed, 10 - validate = _validate 11 - const id = 'network.cosmik.defs' 14 + validate = _validate; 15 + const id = 'network.cosmik.defs'; 12 16 13 17 /** Represents an identifier with a type and value. */ 14 18 export interface Identifier { 15 - $type?: 'network.cosmik.defs#identifier' 19 + $type?: 'network.cosmik.defs#identifier'; 16 20 /** The type of identifier (e.g., 'doi', 'at-uri', 'isbn'). */ 17 - type: string 21 + type: string; 18 22 /** The identifier value. */ 19 - value: string 23 + value: string; 20 24 } 21 25 22 - const hashIdentifier = 'identifier' 26 + const hashIdentifier = 'identifier'; 23 27 24 28 export function isIdentifier<V>(v: V) { 25 - return is$typed(v, id, hashIdentifier) 29 + return is$typed(v, id, hashIdentifier); 26 30 } 27 31 28 32 export function validateIdentifier<V>(v: V) { 29 - return validate<Identifier & V>(v, id, hashIdentifier) 33 + return validate<Identifier & V>(v, id, hashIdentifier); 30 34 }
+16 -16
src/modules/atproto/infrastructure/lexicon/util.ts
··· 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 4 5 - import { type ValidationResult } from '@atproto/lexicon' 5 + import { type ValidationResult } from '@atproto/lexicon'; 6 6 7 7 export type OmitKey<T, K extends keyof T> = { 8 - [K2 in keyof T as K2 extends K ? never : K2]: T[K2] 9 - } 8 + [K2 in keyof T as K2 extends K ? never : K2]: T[K2]; 9 + }; 10 10 11 - export type $Typed<V, T extends string = string> = V & { $type: T } 12 - export type Un$Typed<V extends { $type?: string }> = OmitKey<V, '$type'> 11 + export type $Typed<V, T extends string = string> = V & { $type: T }; 12 + export type Un$Typed<V extends { $type?: string }> = OmitKey<V, '$type'>; 13 13 14 14 export type $Type<Id extends string, Hash extends string> = Hash extends 'main' 15 15 ? Id 16 - : `${Id}#${Hash}` 16 + : `${Id}#${Hash}`; 17 17 18 18 function isObject<V>(v: V): v is V & object { 19 - return v != null && typeof v === 'object' 19 + return v != null && typeof v === 'object'; 20 20 } 21 21 22 22 function is$type<Id extends string, Hash extends string>( ··· 31 31 $type.length === id.length + 1 + hash.length && 32 32 $type.charCodeAt(id.length) === 35 /* '#' */ && 33 33 $type.startsWith(id) && 34 - $type.endsWith(hash) 34 + $type.endsWith(hash); 35 35 } 36 36 37 37 export type $TypedObject< ··· 39 39 Id extends string, 40 40 Hash extends string, 41 41 > = V extends { 42 - $type: $Type<Id, Hash> 42 + $type: $Type<Id, Hash>; 43 43 } 44 44 ? V 45 45 : V extends { $type?: string } 46 46 ? V extends { $type?: infer T extends $Type<Id, Hash> } 47 47 ? V & { $type: T } 48 48 : never 49 - : V & { $type: $Type<Id, Hash> } 49 + : V & { $type: $Type<Id, Hash> }; 50 50 51 51 export function is$typed<V, Id extends string, Hash extends string>( 52 52 v: V, 53 53 id: Id, 54 54 hash: Hash, 55 55 ): v is $TypedObject<V, Id, Hash> { 56 - return isObject(v) && '$type' in v && is$type(v.$type, id, hash) 56 + return isObject(v) && '$type' in v && is$type(v.$type, id, hash); 57 57 } 58 58 59 59 export function maybe$typed<V, Id extends string, Hash extends string>( ··· 64 64 return ( 65 65 isObject(v) && 66 66 ('$type' in v ? v.$type === undefined || is$type(v.$type, id, hash) : true) 67 - ) 67 + ); 68 68 } 69 69 70 - export type Validator<R = unknown> = (v: unknown) => ValidationResult<R> 70 + export type Validator<R = unknown> = (v: unknown) => ValidationResult<R>; 71 71 export type ValidatorParam<V extends Validator> = 72 - V extends Validator<infer R> ? R : never 72 + V extends Validator<infer R> ? R : never; 73 73 74 74 /** 75 75 * Utility function that allows to convert a "validate*" utility function into a ··· 77 77 */ 78 78 export function asPredicate<V extends Validator>(validate: V) { 79 79 return function <T>(v: T): v is T & ValidatorParam<V> { 80 - return validate(v).success 81 - } 80 + return validate(v).success; 81 + }; 82 82 }
+27 -9
src/modules/cards/domain/Card.ts
··· 14 14 URL_CARD_CANNOT_HAVE_PARENT: 'URL cards cannot have parent cards', 15 15 URL_CARD_MUST_HAVE_URL: 'URL cards must have a url property', 16 16 URL_CARD_SINGLE_LIBRARY_ONLY: 'URL cards can only be in one library', 17 - URL_CARD_CREATOR_LIBRARY_ONLY: 'URL cards can only be in the library of the creator', 18 - LIBRARY_COUNT_MISMATCH: 'Library count does not match library memberships length', 17 + URL_CARD_CREATOR_LIBRARY_ONLY: 18 + 'URL cards can only be in the library of the creator', 19 + LIBRARY_COUNT_MISMATCH: 20 + 'Library count does not match library memberships length', 19 21 CANNOT_CHANGE_CONTENT_TYPE: 'Cannot change card content to different type', 20 22 ALREADY_IN_LIBRARY: "Card is already in user's library", 21 23 NOT_IN_LIBRARY: "Card is not in user's library", ··· 123 125 ): Result<Card, CardValidationError> { 124 126 // Validate content type matches card type 125 127 if (props.type.value !== props.content.type) { 126 - return err(new CardValidationError(CARD_ERROR_MESSAGES.CARD_TYPE_CONTENT_MISMATCH)); 128 + return err( 129 + new CardValidationError(CARD_ERROR_MESSAGES.CARD_TYPE_CONTENT_MISMATCH), 130 + ); 127 131 } 128 132 129 133 // Validate parent/source card relationships ··· 157 161 ): Result<void, CardValidationError> { 158 162 // URL cards should not have parent cards 159 163 if (props.type.value === CardTypeEnum.URL && props.parentCardId) { 160 - return err(new CardValidationError(CARD_ERROR_MESSAGES.URL_CARD_CANNOT_HAVE_PARENT)); 164 + return err( 165 + new CardValidationError( 166 + CARD_ERROR_MESSAGES.URL_CARD_CANNOT_HAVE_PARENT, 167 + ), 168 + ); 161 169 } 162 170 163 171 // URL cards must have a URL property 164 172 if (props.type.value === CardTypeEnum.URL && !props.url) { 165 - return err(new CardValidationError(CARD_ERROR_MESSAGES.URL_CARD_MUST_HAVE_URL)); 173 + return err( 174 + new CardValidationError(CARD_ERROR_MESSAGES.URL_CARD_MUST_HAVE_URL), 175 + ); 166 176 } 167 177 168 178 // URL cards can only be in one library ··· 172 182 libraryMemberships.length > 1 173 183 ) { 174 184 return err( 175 - new CardValidationError(CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY), 185 + new CardValidationError( 186 + CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY, 187 + ), 176 188 ); 177 189 } 178 190 ··· 186 198 ); 187 199 if (hasNonCreatorMembership) { 188 200 return err( 189 - new CardValidationError(CARD_ERROR_MESSAGES.URL_CARD_CREATOR_LIBRARY_ONLY), 201 + new CardValidationError( 202 + CARD_ERROR_MESSAGES.URL_CARD_CREATOR_LIBRARY_ONLY, 203 + ), 190 204 ); 191 205 } 192 206 } ··· 227 241 link.curatorId.equals(userId), 228 242 ) 229 243 ) { 230 - return err(new CardValidationError(CARD_ERROR_MESSAGES.ALREADY_IN_LIBRARY)); 244 + return err( 245 + new CardValidationError(CARD_ERROR_MESSAGES.ALREADY_IN_LIBRARY), 246 + ); 231 247 } 232 248 233 249 // URL cards can only be in one library 234 250 if (this.isUrlCard && this.props.libraryMemberships.length > 0) { 235 251 return err( 236 - new CardValidationError(CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY), 252 + new CardValidationError( 253 + CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY, 254 + ), 237 255 ); 238 256 } 239 257
+1 -1
src/modules/cards/domain/ICollectionQueryRepository.ts
··· 49 49 curatorId: string, 50 50 options: CollectionQueryOptions, 51 51 ): Promise<PaginatedQueryResult<CollectionQueryResultDTO>>; 52 - 52 + 53 53 getCollectionsContainingCardForUser( 54 54 cardId: string, 55 55 curatorId: string,
+4 -2
src/modules/cards/infrastructure/http/routes/cardRoutes.ts
··· 42 42 ); 43 43 44 44 // GET /api/cards/library/status - Get URL status for my library 45 - router.get('/library/status', authMiddleware.ensureAuthenticated(), (req, res) => 46 - getUrlStatusForMyLibraryController.execute(req, res), 45 + router.get( 46 + '/library/status', 47 + authMiddleware.ensureAuthenticated(), 48 + (req, res) => getUrlStatusForMyLibraryController.execute(req, res), 47 49 ); 48 50 49 51 // GET /api/cards/user/:identifier - Get user's URL cards by identifier
+26 -22
src/modules/cards/infrastructure/repositories/schema/card.sql.ts
··· 10 10 } from 'drizzle-orm/pg-core'; 11 11 import { publishedRecords } from './publishedRecord.sql'; 12 12 13 - export const cards: PgTableWithColumns<any> = pgTable('cards', { 14 - id: uuid('id').primaryKey(), 15 - authorId: text('author_id').notNull(), 16 - type: text('type').notNull(), // URL, NOTE, HIGHLIGHT 17 - contentData: jsonb('content_data').notNull(), 18 - url: text('url'), // Optional URL field for all card types 19 - parentCardId: uuid('parent_card_id').references(() => cards.id), 20 - publishedRecordId: uuid('published_record_id').references( 21 - () => publishedRecords.id, 22 - ), 23 - libraryCount: integer('library_count').notNull().default(0), 24 - createdAt: timestamp('created_at').notNull().defaultNow(), 25 - updatedAt: timestamp('updated_at').notNull().defaultNow(), 26 - }, (table) => { 27 - return { 28 - // Critical for findUsersUrlCardByUrl queries 29 - authorUrlIdx: index('cards_author_url_idx').on(table.authorId, table.url), 30 - 31 - // For general card queries by author 32 - authorIdIdx: index('cards_author_id_idx').on(table.authorId), 33 - }; 34 - }); 13 + export const cards: PgTableWithColumns<any> = pgTable( 14 + 'cards', 15 + { 16 + id: uuid('id').primaryKey(), 17 + authorId: text('author_id').notNull(), 18 + type: text('type').notNull(), // URL, NOTE, HIGHLIGHT 19 + contentData: jsonb('content_data').notNull(), 20 + url: text('url'), // Optional URL field for all card types 21 + parentCardId: uuid('parent_card_id').references(() => cards.id), 22 + publishedRecordId: uuid('published_record_id').references( 23 + () => publishedRecords.id, 24 + ), 25 + libraryCount: integer('library_count').notNull().default(0), 26 + createdAt: timestamp('created_at').notNull().defaultNow(), 27 + updatedAt: timestamp('updated_at').notNull().defaultNow(), 28 + }, 29 + (table) => { 30 + return { 31 + // Critical for findUsersUrlCardByUrl queries 32 + authorUrlIdx: index('cards_author_url_idx').on(table.authorId, table.url), 33 + 34 + // For general card queries by author 35 + authorIdIdx: index('cards_author_id_idx').on(table.authorId), 36 + }; 37 + }, 38 + );
+54 -41
src/modules/cards/infrastructure/repositories/schema/collection.sql.ts
··· 10 10 import { publishedRecords } from './publishedRecord.sql'; 11 11 import { cards } from './card.sql'; 12 12 13 - export const collections = pgTable('collections', { 14 - id: uuid('id').primaryKey(), 15 - authorId: text('author_id').notNull(), 16 - name: text('name').notNull(), 17 - description: text('description'), 18 - accessType: text('access_type').notNull(), // OPEN, CLOSED 19 - cardCount: integer('card_count').notNull().default(0), 20 - createdAt: timestamp('created_at').notNull().defaultNow(), 21 - updatedAt: timestamp('updated_at').notNull().defaultNow(), 22 - publishedRecordId: uuid('published_record_id').references( 23 - () => publishedRecords.id, 24 - ), 25 - }, (table) => { 26 - return { 27 - // Critical for all collection queries by user 28 - authorIdIdx: index('collections_author_id_idx').on(table.authorId), 29 - 30 - // For paginated collection listings (most common sort) 31 - authorUpdatedAtIdx: index('collections_author_updated_at_idx').on(table.authorId, table.updatedAt), 32 - }; 33 - }); 13 + export const collections = pgTable( 14 + 'collections', 15 + { 16 + id: uuid('id').primaryKey(), 17 + authorId: text('author_id').notNull(), 18 + name: text('name').notNull(), 19 + description: text('description'), 20 + accessType: text('access_type').notNull(), // OPEN, CLOSED 21 + cardCount: integer('card_count').notNull().default(0), 22 + createdAt: timestamp('created_at').notNull().defaultNow(), 23 + updatedAt: timestamp('updated_at').notNull().defaultNow(), 24 + publishedRecordId: uuid('published_record_id').references( 25 + () => publishedRecords.id, 26 + ), 27 + }, 28 + (table) => { 29 + return { 30 + // Critical for all collection queries by user 31 + authorIdIdx: index('collections_author_id_idx').on(table.authorId), 32 + 33 + // For paginated collection listings (most common sort) 34 + authorUpdatedAtIdx: index('collections_author_updated_at_idx').on( 35 + table.authorId, 36 + table.updatedAt, 37 + ), 38 + }; 39 + }, 40 + ); 34 41 35 42 // Join table for collection collaborators 36 43 export const collectionCollaborators = pgTable('collection_collaborators', { ··· 42 49 }); 43 50 44 51 // Join table for cards in collections 45 - export const collectionCards = pgTable('collection_cards', { 46 - id: uuid('id').primaryKey(), 47 - collectionId: uuid('collection_id') 48 - .notNull() 49 - .references(() => collections.id, { onDelete: 'cascade' }), 50 - cardId: uuid('card_id') 51 - .notNull() 52 - .references(() => cards.id, { onDelete: 'cascade' }), 53 - addedBy: text('added_by').notNull(), 54 - addedAt: timestamp('added_at').notNull().defaultNow(), 55 - publishedRecordId: uuid('published_record_id').references( 56 - () => publishedRecords.id, 57 - ), 58 - }, (table) => { 59 - return { 60 - // Critical for getCollectionsContainingCardForUser queries 61 - cardIdIdx: index('collection_cards_card_id_idx').on(table.cardId), 62 - collectionIdIdx: index('collection_cards_collection_id_idx').on(table.collectionId), 63 - }; 64 - }); 52 + export const collectionCards = pgTable( 53 + 'collection_cards', 54 + { 55 + id: uuid('id').primaryKey(), 56 + collectionId: uuid('collection_id') 57 + .notNull() 58 + .references(() => collections.id, { onDelete: 'cascade' }), 59 + cardId: uuid('card_id') 60 + .notNull() 61 + .references(() => cards.id, { onDelete: 'cascade' }), 62 + addedBy: text('added_by').notNull(), 63 + addedAt: timestamp('added_at').notNull().defaultNow(), 64 + publishedRecordId: uuid('published_record_id').references( 65 + () => publishedRecords.id, 66 + ), 67 + }, 68 + (table) => { 69 + return { 70 + // Critical for getCollectionsContainingCardForUser queries 71 + cardIdIdx: index('collection_cards_card_id_idx').on(table.cardId), 72 + collectionIdIdx: index('collection_cards_collection_id_idx').on( 73 + table.collectionId, 74 + ), 75 + }; 76 + }, 77 + );
+14 -8
src/modules/cards/tests/application/RemoveCardFromLibraryUseCase.test.ts
··· 51 51 cardPublisher.clear(); 52 52 }); 53 53 54 - const createCard = async (type: CardTypeEnum = CardTypeEnum.URL, creatorId: CuratorId = curatorId) => { 55 - const card = new CardBuilder().withType(type).withCuratorId(creatorId.value).build(); 54 + const createCard = async ( 55 + type: CardTypeEnum = CardTypeEnum.URL, 56 + creatorId: CuratorId = curatorId, 57 + ) => { 58 + const card = new CardBuilder() 59 + .withType(type) 60 + .withCuratorId(creatorId.value) 61 + .build(); 56 62 57 63 if (card instanceof Error) { 58 64 throw new Error(`Failed to create card: ${card.message}`); ··· 65 71 const addCardToLibrary = async (card: any, curatorId: CuratorId) => { 66 72 // For URL cards, can only add to creator's library 67 73 if (card.isUrlCard && !card.curatorId.equals(curatorId)) { 68 - throw new Error('URL cards can only be added to creator\'s library'); 74 + throw new Error("URL cards can only be added to creator's library"); 69 75 } 70 - 76 + 71 77 const addResult = await cardLibraryService.addCardToLibrary( 72 78 card, 73 79 curatorId, ··· 169 175 it('should handle different card types', async () => { 170 176 // Create URL card with curatorId as creator 171 177 const urlCard = await createCard(CardTypeEnum.URL, curatorId); 172 - // Create note card with curatorId as creator 178 + // Create note card with curatorId as creator 173 179 const noteCard = await createCard(CardTypeEnum.NOTE, curatorId); 174 180 175 181 await addCardToLibrary(urlCard, curatorId); ··· 520 526 it('should not delete card when curator is not the owner', async () => { 521 527 // Create card with different owner 522 528 const card = await createCard(CardTypeEnum.NOTE, otherCuratorId); 523 - 529 + 524 530 // Add to other curator's library first 525 531 await addCardToLibrary(card, otherCuratorId); 526 - 532 + 527 533 // Add to current curator's library (note cards can be in multiple libraries) 528 534 await addCardToLibrary(card, curatorId); 529 535 ··· 548 554 it('should not delete card when it still has other library memberships', async () => { 549 555 // Create note card (can be in multiple libraries) 550 556 const card = await createCard(CardTypeEnum.NOTE, curatorId); 551 - 557 + 552 558 // Add to both curator's libraries 553 559 await addCardToLibrary(card, curatorId); 554 560 await addCardToLibrary(card, otherCuratorId);
+6 -2
src/modules/cards/tests/domain/Card.test.ts
··· 151 151 throw new Error('Expected creation to fail but it succeeded'); 152 152 } 153 153 expect(result.isErr()).toBe(true); 154 - expect(result.error.message).toBe(CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY); 154 + expect(result.error.message).toBe( 155 + CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY, 156 + ); 155 157 }); 156 158 157 159 it('should allow NOTE cards to have multiple library memberships', () => { ··· 256 258 throw new Error('Expected creation to fail but it succeeded'); 257 259 } 258 260 expect(result.isErr()).toBe(true); 259 - expect(result.error.message).toBe(CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY); 261 + expect(result.error.message).toBe( 262 + CARD_ERROR_MESSAGES.URL_CARD_SINGLE_LIBRARY_ONLY, 263 + ); 260 264 expect(card.libraryMembershipCount).toBe(1); 261 265 expect(card.isInLibrary(curatorId)).toBe(true); 262 266 expect(card.isInLibrary(otherUserId)).toBe(false);
+12 -3
src/shared/infrastructure/config/EnvironmentConfigService.ts
··· 69 69 process.env.ATPROTO_SERVICE_ENDPOINT || 'https://bsky.social', 70 70 baseUrl: process.env.BASE_URL || 'http://127.0.0.1:3000', 71 71 collections: { 72 - card: environment === 'prod' ? 'network.cosmik.card' : 'network.cosmik.dev.card', 73 - collection: environment === 'prod' ? 'network.cosmik.collection' : 'network.cosmik.dev.collection', 74 - collectionLink: environment === 'prod' ? 'network.cosmik.collectionLink' : 'network.cosmik.dev.collectionLink', 72 + card: 73 + environment === 'prod' 74 + ? 'network.cosmik.card' 75 + : 'network.cosmik.dev.card', 76 + collection: 77 + environment === 'prod' 78 + ? 'network.cosmik.collection' 79 + : 'network.cosmik.dev.collection', 80 + collectionLink: 81 + environment === 'prod' 82 + ? 'network.cosmik.collectionLink' 83 + : 'network.cosmik.dev.collectionLink', 75 84 }, 76 85 }, 77 86 server: {
+22 -65
src/shared/infrastructure/database/migrations/meta/0004_snapshot.json
··· 123 123 "name": "cards_parent_card_id_cards_id_fk", 124 124 "tableFrom": "cards", 125 125 "tableTo": "cards", 126 - "columnsFrom": [ 127 - "parent_card_id" 128 - ], 129 - "columnsTo": [ 130 - "id" 131 - ], 126 + "columnsFrom": ["parent_card_id"], 127 + "columnsTo": ["id"], 132 128 "onDelete": "no action", 133 129 "onUpdate": "no action" 134 130 }, ··· 136 132 "name": "cards_published_record_id_published_records_id_fk", 137 133 "tableFrom": "cards", 138 134 "tableTo": "published_records", 139 - "columnsFrom": [ 140 - "published_record_id" 141 - ], 142 - "columnsTo": [ 143 - "id" 144 - ], 135 + "columnsFrom": ["published_record_id"], 136 + "columnsTo": ["id"], 145 137 "onDelete": "no action", 146 138 "onUpdate": "no action" 147 139 } ··· 200 192 "name": "collection_cards_collection_id_collections_id_fk", 201 193 "tableFrom": "collection_cards", 202 194 "tableTo": "collections", 203 - "columnsFrom": [ 204 - "collection_id" 205 - ], 206 - "columnsTo": [ 207 - "id" 208 - ], 195 + "columnsFrom": ["collection_id"], 196 + "columnsTo": ["id"], 209 197 "onDelete": "cascade", 210 198 "onUpdate": "no action" 211 199 }, ··· 213 201 "name": "collection_cards_card_id_cards_id_fk", 214 202 "tableFrom": "collection_cards", 215 203 "tableTo": "cards", 216 - "columnsFrom": [ 217 - "card_id" 218 - ], 219 - "columnsTo": [ 220 - "id" 221 - ], 204 + "columnsFrom": ["card_id"], 205 + "columnsTo": ["id"], 222 206 "onDelete": "cascade", 223 207 "onUpdate": "no action" 224 208 }, ··· 226 210 "name": "collection_cards_published_record_id_published_records_id_fk", 227 211 "tableFrom": "collection_cards", 228 212 "tableTo": "published_records", 229 - "columnsFrom": [ 230 - "published_record_id" 231 - ], 232 - "columnsTo": [ 233 - "id" 234 - ], 213 + "columnsFrom": ["published_record_id"], 214 + "columnsTo": ["id"], 235 215 "onDelete": "no action", 236 216 "onUpdate": "no action" 237 217 } ··· 271 251 "name": "collection_collaborators_collection_id_collections_id_fk", 272 252 "tableFrom": "collection_collaborators", 273 253 "tableTo": "collections", 274 - "columnsFrom": [ 275 - "collection_id" 276 - ], 277 - "columnsTo": [ 278 - "id" 279 - ], 254 + "columnsFrom": ["collection_id"], 255 + "columnsTo": ["id"], 280 256 "onDelete": "cascade", 281 257 "onUpdate": "no action" 282 258 } ··· 355 331 "name": "collections_published_record_id_published_records_id_fk", 356 332 "tableFrom": "collections", 357 333 "tableTo": "published_records", 358 - "columnsFrom": [ 359 - "published_record_id" 360 - ], 361 - "columnsTo": [ 362 - "id" 363 - ], 334 + "columnsFrom": ["published_record_id"], 335 + "columnsTo": ["id"], 364 336 "onDelete": "no action", 365 337 "onUpdate": "no action" 366 338 } ··· 438 410 "name": "library_memberships_card_id_cards_id_fk", 439 411 "tableFrom": "library_memberships", 440 412 "tableTo": "cards", 441 - "columnsFrom": [ 442 - "card_id" 443 - ], 444 - "columnsTo": [ 445 - "id" 446 - ], 413 + "columnsFrom": ["card_id"], 414 + "columnsTo": ["id"], 447 415 "onDelete": "cascade", 448 416 "onUpdate": "no action" 449 417 }, ··· 451 419 "name": "library_memberships_published_record_id_published_records_id_fk", 452 420 "tableFrom": "library_memberships", 453 421 "tableTo": "published_records", 454 - "columnsFrom": [ 455 - "published_record_id" 456 - ], 457 - "columnsTo": [ 458 - "id" 459 - ], 422 + "columnsFrom": ["published_record_id"], 423 + "columnsTo": ["id"], 460 424 "onDelete": "no action", 461 425 "onUpdate": "no action" 462 426 } ··· 464 428 "compositePrimaryKeys": { 465 429 "library_memberships_card_id_user_id_pk": { 466 430 "name": "library_memberships_card_id_user_id_pk", 467 - "columns": [ 468 - "card_id", 469 - "user_id" 470 - ] 431 + "columns": ["card_id", "user_id"] 471 432 } 472 433 }, 473 434 "uniqueConstraints": {}, ··· 699 660 "name": "auth_refresh_tokens_user_did_users_id_fk", 700 661 "tableFrom": "auth_refresh_tokens", 701 662 "tableTo": "users", 702 - "columnsFrom": [ 703 - "user_did" 704 - ], 705 - "columnsTo": [ 706 - "id" 707 - ], 663 + "columnsFrom": ["user_did"], 664 + "columnsTo": ["id"], 708 665 "onDelete": "no action", 709 666 "onUpdate": "no action" 710 667 } ··· 764 721 "schemas": {}, 765 722 "tables": {} 766 723 } 767 - } 724 + }
+22 -65
src/shared/infrastructure/database/migrations/meta/0005_snapshot.json
··· 122 122 "cards_parent_card_id_cards_id_fk": { 123 123 "name": "cards_parent_card_id_cards_id_fk", 124 124 "tableFrom": "cards", 125 - "columnsFrom": [ 126 - "parent_card_id" 127 - ], 125 + "columnsFrom": ["parent_card_id"], 128 126 "tableTo": "cards", 129 - "columnsTo": [ 130 - "id" 131 - ], 127 + "columnsTo": ["id"], 132 128 "onUpdate": "no action", 133 129 "onDelete": "no action" 134 130 }, 135 131 "cards_published_record_id_published_records_id_fk": { 136 132 "name": "cards_published_record_id_published_records_id_fk", 137 133 "tableFrom": "cards", 138 - "columnsFrom": [ 139 - "published_record_id" 140 - ], 134 + "columnsFrom": ["published_record_id"], 141 135 "tableTo": "published_records", 142 - "columnsTo": [ 143 - "id" 144 - ], 136 + "columnsTo": ["id"], 145 137 "onUpdate": "no action", 146 138 "onDelete": "no action" 147 139 } ··· 199 191 "collection_cards_collection_id_collections_id_fk": { 200 192 "name": "collection_cards_collection_id_collections_id_fk", 201 193 "tableFrom": "collection_cards", 202 - "columnsFrom": [ 203 - "collection_id" 204 - ], 194 + "columnsFrom": ["collection_id"], 205 195 "tableTo": "collections", 206 - "columnsTo": [ 207 - "id" 208 - ], 196 + "columnsTo": ["id"], 209 197 "onUpdate": "no action", 210 198 "onDelete": "cascade" 211 199 }, 212 200 "collection_cards_card_id_cards_id_fk": { 213 201 "name": "collection_cards_card_id_cards_id_fk", 214 202 "tableFrom": "collection_cards", 215 - "columnsFrom": [ 216 - "card_id" 217 - ], 203 + "columnsFrom": ["card_id"], 218 204 "tableTo": "cards", 219 - "columnsTo": [ 220 - "id" 221 - ], 205 + "columnsTo": ["id"], 222 206 "onUpdate": "no action", 223 207 "onDelete": "cascade" 224 208 }, 225 209 "collection_cards_published_record_id_published_records_id_fk": { 226 210 "name": "collection_cards_published_record_id_published_records_id_fk", 227 211 "tableFrom": "collection_cards", 228 - "columnsFrom": [ 229 - "published_record_id" 230 - ], 212 + "columnsFrom": ["published_record_id"], 231 213 "tableTo": "published_records", 232 - "columnsTo": [ 233 - "id" 234 - ], 214 + "columnsTo": ["id"], 235 215 "onUpdate": "no action", 236 216 "onDelete": "no action" 237 217 } ··· 270 250 "collection_collaborators_collection_id_collections_id_fk": { 271 251 "name": "collection_collaborators_collection_id_collections_id_fk", 272 252 "tableFrom": "collection_collaborators", 273 - "columnsFrom": [ 274 - "collection_id" 275 - ], 253 + "columnsFrom": ["collection_id"], 276 254 "tableTo": "collections", 277 - "columnsTo": [ 278 - "id" 279 - ], 255 + "columnsTo": ["id"], 280 256 "onUpdate": "no action", 281 257 "onDelete": "cascade" 282 258 } ··· 354 330 "collections_published_record_id_published_records_id_fk": { 355 331 "name": "collections_published_record_id_published_records_id_fk", 356 332 "tableFrom": "collections", 357 - "columnsFrom": [ 358 - "published_record_id" 359 - ], 333 + "columnsFrom": ["published_record_id"], 360 334 "tableTo": "published_records", 361 - "columnsTo": [ 362 - "id" 363 - ], 335 + "columnsTo": ["id"], 364 336 "onUpdate": "no action", 365 337 "onDelete": "no action" 366 338 } ··· 437 409 "library_memberships_card_id_cards_id_fk": { 438 410 "name": "library_memberships_card_id_cards_id_fk", 439 411 "tableFrom": "library_memberships", 440 - "columnsFrom": [ 441 - "card_id" 442 - ], 412 + "columnsFrom": ["card_id"], 443 413 "tableTo": "cards", 444 - "columnsTo": [ 445 - "id" 446 - ], 414 + "columnsTo": ["id"], 447 415 "onUpdate": "no action", 448 416 "onDelete": "cascade" 449 417 }, 450 418 "library_memberships_published_record_id_published_records_id_fk": { 451 419 "name": "library_memberships_published_record_id_published_records_id_fk", 452 420 "tableFrom": "library_memberships", 453 - "columnsFrom": [ 454 - "published_record_id" 455 - ], 421 + "columnsFrom": ["published_record_id"], 456 422 "tableTo": "published_records", 457 - "columnsTo": [ 458 - "id" 459 - ], 423 + "columnsTo": ["id"], 460 424 "onUpdate": "no action", 461 425 "onDelete": "no action" 462 426 } ··· 464 428 "compositePrimaryKeys": { 465 429 "library_memberships_card_id_user_id_pk": { 466 430 "name": "library_memberships_card_id_user_id_pk", 467 - "columns": [ 468 - "card_id", 469 - "user_id" 470 - ] 431 + "columns": ["card_id", "user_id"] 471 432 } 472 433 }, 473 434 "uniqueConstraints": {}, ··· 698 659 "auth_refresh_tokens_user_did_users_id_fk": { 699 660 "name": "auth_refresh_tokens_user_did_users_id_fk", 700 661 "tableFrom": "auth_refresh_tokens", 701 - "columnsFrom": [ 702 - "user_did" 703 - ], 662 + "columnsFrom": ["user_did"], 704 663 "tableTo": "users", 705 - "columnsTo": [ 706 - "id" 707 - ], 664 + "columnsTo": ["id"], 708 665 "onUpdate": "no action", 709 666 "onDelete": "no action" 710 667 } ··· 764 721 "schemas": {}, 765 722 "tables": {} 766 723 } 767 - } 724 + }
+22 -65
src/shared/infrastructure/database/migrations/meta/0006_snapshot.json
··· 160 160 "name": "cards_parent_card_id_cards_id_fk", 161 161 "tableFrom": "cards", 162 162 "tableTo": "cards", 163 - "columnsFrom": [ 164 - "parent_card_id" 165 - ], 166 - "columnsTo": [ 167 - "id" 168 - ], 163 + "columnsFrom": ["parent_card_id"], 164 + "columnsTo": ["id"], 169 165 "onDelete": "no action", 170 166 "onUpdate": "no action" 171 167 }, ··· 173 169 "name": "cards_published_record_id_published_records_id_fk", 174 170 "tableFrom": "cards", 175 171 "tableTo": "published_records", 176 - "columnsFrom": [ 177 - "published_record_id" 178 - ], 179 - "columnsTo": [ 180 - "id" 181 - ], 172 + "columnsFrom": ["published_record_id"], 173 + "columnsTo": ["id"], 182 174 "onDelete": "no action", 183 175 "onUpdate": "no action" 184 176 } ··· 268 260 "name": "collection_cards_collection_id_collections_id_fk", 269 261 "tableFrom": "collection_cards", 270 262 "tableTo": "collections", 271 - "columnsFrom": [ 272 - "collection_id" 273 - ], 274 - "columnsTo": [ 275 - "id" 276 - ], 263 + "columnsFrom": ["collection_id"], 264 + "columnsTo": ["id"], 277 265 "onDelete": "cascade", 278 266 "onUpdate": "no action" 279 267 }, ··· 281 269 "name": "collection_cards_card_id_cards_id_fk", 282 270 "tableFrom": "collection_cards", 283 271 "tableTo": "cards", 284 - "columnsFrom": [ 285 - "card_id" 286 - ], 287 - "columnsTo": [ 288 - "id" 289 - ], 272 + "columnsFrom": ["card_id"], 273 + "columnsTo": ["id"], 290 274 "onDelete": "cascade", 291 275 "onUpdate": "no action" 292 276 }, ··· 294 278 "name": "collection_cards_published_record_id_published_records_id_fk", 295 279 "tableFrom": "collection_cards", 296 280 "tableTo": "published_records", 297 - "columnsFrom": [ 298 - "published_record_id" 299 - ], 300 - "columnsTo": [ 301 - "id" 302 - ], 281 + "columnsFrom": ["published_record_id"], 282 + "columnsTo": ["id"], 303 283 "onDelete": "no action", 304 284 "onUpdate": "no action" 305 285 } ··· 339 319 "name": "collection_collaborators_collection_id_collections_id_fk", 340 320 "tableFrom": "collection_collaborators", 341 321 "tableTo": "collections", 342 - "columnsFrom": [ 343 - "collection_id" 344 - ], 345 - "columnsTo": [ 346 - "id" 347 - ], 322 + "columnsFrom": ["collection_id"], 323 + "columnsTo": ["id"], 348 324 "onDelete": "cascade", 349 325 "onUpdate": "no action" 350 326 } ··· 460 436 "name": "collections_published_record_id_published_records_id_fk", 461 437 "tableFrom": "collections", 462 438 "tableTo": "published_records", 463 - "columnsFrom": [ 464 - "published_record_id" 465 - ], 466 - "columnsTo": [ 467 - "id" 468 - ], 439 + "columnsFrom": ["published_record_id"], 440 + "columnsTo": ["id"], 469 441 "onDelete": "no action", 470 442 "onUpdate": "no action" 471 443 } ··· 543 515 "name": "library_memberships_card_id_cards_id_fk", 544 516 "tableFrom": "library_memberships", 545 517 "tableTo": "cards", 546 - "columnsFrom": [ 547 - "card_id" 548 - ], 549 - "columnsTo": [ 550 - "id" 551 - ], 518 + "columnsFrom": ["card_id"], 519 + "columnsTo": ["id"], 552 520 "onDelete": "cascade", 553 521 "onUpdate": "no action" 554 522 }, ··· 556 524 "name": "library_memberships_published_record_id_published_records_id_fk", 557 525 "tableFrom": "library_memberships", 558 526 "tableTo": "published_records", 559 - "columnsFrom": [ 560 - "published_record_id" 561 - ], 562 - "columnsTo": [ 563 - "id" 564 - ], 527 + "columnsFrom": ["published_record_id"], 528 + "columnsTo": ["id"], 565 529 "onDelete": "no action", 566 530 "onUpdate": "no action" 567 531 } ··· 569 533 "compositePrimaryKeys": { 570 534 "library_memberships_card_id_user_id_pk": { 571 535 "name": "library_memberships_card_id_user_id_pk", 572 - "columns": [ 573 - "card_id", 574 - "user_id" 575 - ] 536 + "columns": ["card_id", "user_id"] 576 537 } 577 538 }, 578 539 "uniqueConstraints": {}, ··· 804 765 "name": "auth_refresh_tokens_user_did_users_id_fk", 805 766 "tableFrom": "auth_refresh_tokens", 806 767 "tableTo": "users", 807 - "columnsFrom": [ 808 - "user_did" 809 - ], 810 - "columnsTo": [ 811 - "id" 812 - ], 768 + "columnsFrom": ["user_did"], 769 + "columnsTo": ["id"], 813 770 "onDelete": "no action", 814 771 "onUpdate": "no action" 815 772 } ··· 869 826 "schemas": {}, 870 827 "tables": {} 871 828 } 872 - } 829 + }
+1 -1
src/shared/infrastructure/database/migrations/meta/_journal.json
··· 52 52 "breakpoints": true 53 53 } 54 54 ] 55 - } 55 + }