Hosted ondailyplanet.iovia theHypermedia Protocol

Resource Loading Re-Organization

    Problem

      Six places make the same GRPC call (grpcClient.resources.getResource):

        @shm/shared/resource-loader.tscreateResourceLoader — throws on error, no extra work

        web/loaders.ts:370getResource — returns not-found, no extra work

        web/loaders.ts:407loadResource — throws on error, adds author metadata etc (see below)

        notify/loaders.tsgetResource — returns not-found, no extra work

        notify/loaders.tsloadResource — throws on error, same as web

        desktop/entities.ts:154loadResource — returns not-found, no extra work

      This means that we have duplicate or conflicting logic about processing the GRPC data, across many different locations in the code.

      It is not clear what is the responsibility of a "loader". Does it fetch for related data like authors? Does it handle redirects or not?

      What web loadResource adds (via loadResourcePayload)

        Author metadata (name, avatar for each document.authors)

        Breadcrumb navigation (metadata for each parent path)

        Support documents (docs referenced via embeds/links in content)

        Support queries (results from query blocks in content)

        Directory results (children of home doc and current doc)

        Home document (for site navigation header)

        isLatest flag (compares current version to latest)

      Why It's Confusing

        Same name loadResource means different things (desktop returns raw, web returns with author metadata)

        createResourceLoader throws on error, but desktop's loadResource catches and returns not-found

        Web has both getResource AND loadResource making duplicate GRPC calls

        No clear naming for abstraction levels

    New Pattern: fetch → resolve → load

      Note: this is more about "re-organizing" than "refactoring", so it shouldn't be a very dramatic change. But it should hopefully help us understand what functions are responsible for what.

      fetchResource (lowest level)

        What it does: GRPC call, parse response, return typed result Redirects: Returns {type: 'redirect', redirectTarget} Not found: Returns {type: 'not-found'} Returns: HMResource = document | comment | redirect | not-found

        // Desktop, API endpoints, simple lookups
        const resource = await fetchResource(id)
        if (resource.type === 'document') { /* use resource.document */ }
        if (resource.type === 'redirect') { /* caller decides what to do */ }
        if (resource.type === 'not-found') { /* caller decides what to do */ }
        

      resolveResource (mid level)

        What it does: Fetches and follows redirects until final target Redirects: Follows automatically (recursive) Not found: Throws HMNotFoundError Returns: HMResolvedResource = document | comment (never redirect)

        // When you need final target, don't care about redirect chain
        const resource = await resolveResource(id)
        // resource.type is 'document' or 'comment', never 'redirect'
        

      loadResource (web, highest level)

        What it does: Resolves, triggers P2P discovery on not-found, adds:

          Author metadata (name, avatar for each author uid)

          Breadcrumb navigation (parent path titles)

          Support documents (embedded/referenced docs for rendering)

          Support queries (query block results)

          Directory results (doc children for nav)

          Home document + directory (for site header nav)

          isLatest flag

        Redirects: Follows automatically Not found: Triggers P2P discovery, retries Returns: WebResourcePayload

      loadSiteResource (web, wraps loadResource)

        What it does: Calls loadResource + adds:

          homeMetadata (site name, icon, theme from account root)

          originHomeId (site root account id)

          origin (request origin URL)

          Error fallback (loads home doc even on error so header renders)

        Returns: SiteDocumentPayload