Something went wrong. Try again.
An AT Protocol Personal Data Server written in JavaScript pdsjs.dev
pds atproto
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131/** * The appview's ExtensionHost, over a remote account and the local index. * * Everything `createGitExtension` consumes is here: record reads land on * the PDS over the wire, blob reads stream from it, discovery answers from * the jetstream index, and the write guard arrives once the extension has * been built — the same late binding core's host does, because the guard is * the extension's own creation. */
import { createIndexedDiscovery } from '@pdsjs/appview/discovery';import { createGitExtension } from '@pdsjs/git/extension';
/** The most a JSON request body may weigh, matching core's own bound. */const JSON_BODY_LIMIT = 1_000_000;
/** * @param {Request} request * @returns {Promise<unknown>} the parsed body, or a 413 Response when it * is too large; the caller tells the two apart */async function readJsonBounded(request) { const text = await request.text(); if (new TextEncoder().encode(text).byteLength > JSON_BODY_LIMIT) { return Response.json( { error: 'PayloadTooLarge', message: `Request body exceeds ${JSON_BODY_LIMIT} bytes`, }, { status: 413 }, ); } return JSON.parse(text);}
/** * @param {Object} options * @param {import('./remote.js').RemoteAccount} options.account - the PDS * reached over the wire * @param {import('@pdsjs/appview/store').AppViewStore} options.store - the * record index discovery reads from * @param {string} [options.hostname] - this host's own name, for client * strings * @param {string} [options.plcUrl] - the directory DIDs resolve against * @param {number} [options.blobUploadLimit] - the PDS's blob limit, which * sizes merge uploads * @param {(request: Request) => Promise<string|null>} [options.sessionDid] - * the account session a request carries, for the owner-only procedures * @returns {{host: unknown, extension: import('@pdsjs/core/ports').PdsExtension}} */export function createGitAppViewHost(options) { const { account, store } = options;
/** @type {import('@pdsjs/core/ports').PdsExtension|null} */ let mounted = null;
/** * The record storage git writes through, over the wire. The members the * git package never calls are the ones a remote host cannot serve: the * PDS keeps its own blocks and event log. */ const actorStorage = { getRecord: (/** @type {string} */ uri) => account.getRecord(uri), listRecords: ( /** @type {string} */ collection, /** @type {string|null} */ cursor, /** @type {number} */ limit, ) => account.listRecords(collection, cursor, limit), // The PDS re-encodes and commits what putRecord hands it; a separate // block write has no remote meaning. putBlock: async () => {}, putRecord: async ( /** @type {string} */ uri, /** @type {string} */ _cid, /** @type {string} */ collection, /** @type {string} */ rkey, /** @type {Uint8Array} */ value, ) => account.putRecord(uri, collection, rkey, value, null), // Blobs the record names are linked by the PDS's own write path. linkBlobToRecord: async () => {}, getBlob: async () => null, putBlob: async () => {}, getHandle: () => account.getHandle(), };
const blobs = { get: (/** @type {string} */ did, /** @type {string} */ cid) => account.getBlob(did, cid), getStream: ( /** @type {string} */ did, /** @type {string} */ cid, /** @type {{start: number, end: number}|undefined} */ range, ) => account.getBlobStream(did, cid, range), put: async ( /** @type {string} */ _did, /** @type {Uint8Array} */ data, /** @type {string} */ mimeType, ) => account.uploadBlob(data, mimeType), delete: async () => {}, };
const host = { actorStorage, blobs, get writeGuard() { return mounted?.writeGuard; }, getDid: account.getDid, xrpc: account.xrpc, hostname: options.hostname, plcUrl: options.plcUrl, blobUploadLimit: options.blobUploadLimit ?? 5_242_880, readOnly: false, readAccountSession: async (/** @type {Request} */ request) => options.sessionDid ? options.sessionDid(request) : null, readJsonBounded, };
mounted = createGitExtension({ http: true, browse: true, discovery: createIndexedDiscovery(store), })( /** @type {import('@pdsjs/core/ports').ExtensionHost} */ ( /** @type {unknown} */ (host) ), );
return { host, extension: mounted };}