~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
84 lines · 2.9 KB Raw History
/**
 * Static sites and apps as a server extension: the platform passes the
 * factory to core's `extensions` option. With a site domain the extension
 * serves sites on hostnames under it, backs the account page's sites list
 * and installs apps from manifests; without one it serves the installs
 * listing alone. Materialized queries are the part `queries` turns on.
 *
 * This module must stay free of node-only imports; it runs on Cloudflare
 * Workers.
 */

import { cborEncodeDagCbor, cidToString, createCid } from '@pdsjs/core/repo';
import { createSiteAccountRoutes } from './account.js';
import { createSiteBrowser } from './browser.js';
import { createSiteHandler } from './handler.js';
import { createSiteInstaller } from './installer.js';
import { QUERY_COLLECTION, SITE_COLLECTION } from './lexicons.js';
import { createQueryEngine } from './query.js';

/**
 * @param {Object} [options]
 * @param {string} [options.domain] - apex domain sites serve under; absent, no site is served
 * @param {string} [options.apexName] - site bound to the apex (default "home")
 * @param {boolean} [options.queries] - serve dev.pdsjs.query.run over this repo's dev.pdsjs.query.def records
 * @returns {import('@pdsjs/core/ports').ExtensionFactory}
 */
export function createSitesExtension({
  domain,
  apexName,
  queries = false,
} = {}) {
  return (host) => {
    const { actorStorage, blobs } = host;
    const siteCtx = domain
      ? {
          actorStorage,
          blobs,
          getDid: host.getDid,
          siteDomain: domain,
          apexName: apexName || undefined,
        }
      : null;
    const handleHost = siteCtx ? createSiteHandler(siteCtx) : null;
    const browser = siteCtx ? createSiteBrowser(siteCtx) : null;
    const installer = siteCtx
      ? createSiteInstaller({
          actorStorage,
          blobs,
          getDid: host.getDid,
          createCommit: host.createCommit,
          linkBlob: (cid, uri, time) =>
            actorStorage.linkBlobToRecord(cid, uri, time),
          encodeRecord: async (record) => {
            const bytes = cborEncodeDagCbor(record);
            return { cid: cidToString(await createCid(bytes)), bytes };
          },
        })
      : null;
    const engine = queries
      ? createQueryEngine({ actorStorage, getDid: host.getDid })
      : null;

    return {
      name: 'sites',
      // A query definition names the collection it reads, so with queries
      // on the engine may read any of them.
      collections: engine
        ? ['*']
        : [
            SITE_COLLECTION,
            QUERY_COLLECTION,
            'dev.pdsjs.app.install',
            'dev.pdsjs.app.manifest',
          ],
      routes: {
        ...createSiteAccountRoutes({ host, browser, installer }),
        ...(engine ? engine.routes : {}),
      },
      features: { sites: Boolean(browser) },
      ...(handleHost ? { handleHost } : {}),
      ...(engine ? { onCommit: engine.onCommit } : {}),
    };
  };
}