#144

Split catalog publishing omits compiled resource documents

Opensdivyanshu90opened 16d ago

I reproduced a compiled resource document disappearing from the split catalog artifacts produced by emitPublish.

The bundle contains the resource and its hook functions, but publication writes only provider and endpoint documents. A consumer of the release artifacts therefore cannot reconstruct the resource definition referenced by bound endpoints: its data schema, rate card, and lifecycle references are missing.

Reproduction

Save this as repro-publish-resource.ts at the repository root and run:

deno run --allow-read --allow-env --allow-write repro-publish-resource.ts

It compiles an in-memory connector and emits into a temporary directory, which it removes afterward. It does not publish a release or make HTTP calls.

import { z } from "zod";
import { compileBundle } from "@shared/compiler";
import { defineProvider, defineResource, defineEndpoint, presets } from "@shared/core";
import { ENGINE_VERSION } from "@monid/connector-engine";
import { emitPublish } from "./scripts/lib.ts";

const bundle = await compileBundle([{
    provider: defineProvider({
        name: "demo", meta: { displayName: "Demo", summary: "Demo provider." },
        auth: { inject: presets.auth.header("x-key") },
        request: { baseUrl: "https://api.demo.test" },
        usage: { model: { kind: "FREE" } },
    }),
    resources: [{ name: "widget", def: defineResource({
        slug: "widget", meta: { displayName: "Widget", summary: "Demo widget." },
        data: z.strictObject({ color: z.string() }),
        usage: { period: { unit: "MONTH", count: 1, anchor: "CREATION_TIME" },
            lines: { rent: { consumes: { credit: "default", amount: 1 } } } },
        lifecycle: {
            verify: async () => ({ active: true }),
            release: async () => ({ released: true }),
        },
    }) }],
    endpoints: [{ name: "create", def: defineEndpoint({
        meta: { displayName: "Create", summary: "Creates a widget.", categories: ["demo-cat"] },
        request: { method: "POST", path: "/create" },
        resources: { provisions: [{ id: "demo/widget", seed: () => ({
            resource: "demo/widget", externalId: "w-1", data: { color: "red" },
        }) }] },
    }) }],
}], {
    compilerVersion: "0.1.0", builtWithEngineVersion: ENGINE_VERSION,
    catalogVersion: "0.0.0-test", generatedAt: "1970-01-01T00:00:00.000Z",
    leafCategories: [{ id: "demo-cat", displayName: "Demo" }],
});
const dir = await Deno.makeTempDir({ prefix: "monid-publish-repro-" });
try {
    const emitted = await emitPublish(bundle, "catalog-v0.0.0-test", dir);
    const manifest = JSON.parse(await Deno.readTextFile(`${dir}/${emitted.manifestKey}`));
    console.log("compiled resources:", Object.keys(bundle.resources ?? {}));
    console.log("published resource entries:", manifest.docs.filter((d: {kind:string}) => d.kind === "resource"));
    const doc = bundle.resources!["demo/widget"];
    try {
        await Deno.stat(`${dir}/publishes/objects/sha256/${doc.hash.replace("sha256:", "")}.json`);
        console.log("resource object exists: true");
    } catch (e) {
        if (!(e instanceof Deno.errors.NotFound)) throw e;
        console.log("resource object exists: false");
    }
} finally { await Deno.remove(dir, { recursive: true }); }

Observed:

compiled resources: [ "demo/widget" ]
published resource entries: []
resource object exists: false

Expected: one kind: "resource" entry containing the resource ID, provider, hash, and object key, plus the complete resource document at that content-addressed key. The emitted document count should include it.

Cause and proposed resolution

scripts/lib.ts::emitPublish loops over bundle.providers, bundle.endpoints, and bundle.fnTable, but never bundle.resources. Emit resource docs using the same hash layout as the other document kinds. Add checks for manifest identity, payload and hash, total count, referenced functions, and deterministic re-emission.

Consumer compatibility

This requires downstream manifest validation and ingestion to recognize resource entries. Open PR #5 proposes a shared publish schema whose document kind enum currently lists only endpoint and provider; it does not emit resource documents. The emitter fix and consumer/schema support need coordination before releasing resource-bearing artifacts. I could verify the producer locally, but the hosted consumer implementation is not available in this checkout.

Activity

0

No activity yet.