Build Camino packages from explicit contract inputs
Project source-free capability contracts and keep exact source provenance in package assembly. Reuse compiled groups across unrelated graph and dependency implementation edits. Keep React public inputs separate from workspace query lowering and retain explicit type-companion dependencies. Allow independent execution-package checks, scope resource compilation to declared dependencies, and memoize source closure traversal. Document generic-specialization limits and measured Reader rebuild behavior. Verified protocol, artifact, package, React, and managed activation checks; retained-Git independent/workspace artifact equality and incompatible type dependency rejection; nix fmt -- --check and lint. One-off Reader measurements recompiled 1 of 13 groups for a child edit and 0 for a workspace QX default edit.
This commit is contained in:
+11
-2
@@ -8,9 +8,9 @@ receipts. It has no migration step or package-defined shell hooks.
|
|||||||
```nix
|
```nix
|
||||||
# Inside a per-system flake output:
|
# Inside a per-system flake output:
|
||||||
quixosPackages.checkedArtifacts =
|
quixosPackages.checkedArtifacts =
|
||||||
{ plan, generator, core, sharedRuntime, typescript, packageRevisionId }:
|
{ buildContract, sourceDigest, generator, core, sharedRuntime, typescript, packageRevisionId, ... }:
|
||||||
helpers.mkCaminoArtifacts {
|
helpers.mkCaminoArtifacts {
|
||||||
inherit pkgs plan core sharedRuntime typescript packageRevisionId;
|
inherit pkgs buildContract sourceDigest core sharedRuntime typescript packageRevisionId;
|
||||||
protocol = generator;
|
protocol = generator;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
portable = {
|
portable = {
|
||||||
@@ -22,6 +22,15 @@ quixosPackages.checkedArtifacts =
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`buildContract` is a canonical, source-free capability slice. `sourceDigest`
|
||||||
|
records the exact selected package source in the final installation manifest;
|
||||||
|
it does not enter the reusable compilation group. Ordinary source dependencies,
|
||||||
|
SDKs and React props companions remain explicit Nix inputs. Raw QX and resource
|
||||||
|
lock files enter through the checked contract and evaluated recipe, and are
|
||||||
|
excluded from the implementation source tree. The `plan` argument on the low-level
|
||||||
|
helper is a composition convenience for fixtures; it is projected before building.
|
||||||
|
Package recipes receive the contract directly and can be checked without a workspace.
|
||||||
|
|
||||||
The handler entry exports `registry = createRegistry(handlers)` from the generated
|
The handler entry exports `registry = createRegistry(handlers)` from the generated
|
||||||
bindings. One registry contains many exports. The builder always supplies a server
|
bindings. One registry contains many exports. The builder always supplies a server
|
||||||
implementation for the generated process service. A service-only package instead
|
implementation for the generated process service. A service-only package instead
|
||||||
|
|||||||
+48
-7
@@ -2,7 +2,25 @@
|
|||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
src,
|
src,
|
||||||
plan,
|
plan ? null,
|
||||||
|
buildContract ?
|
||||||
|
(import ./package-context.nix {
|
||||||
|
inherit
|
||||||
|
pkgs
|
||||||
|
protocol
|
||||||
|
plan
|
||||||
|
packageRevisionId
|
||||||
|
;
|
||||||
|
}).buildContract,
|
||||||
|
sourceDigest ?
|
||||||
|
(import ./package-context.nix {
|
||||||
|
inherit
|
||||||
|
pkgs
|
||||||
|
protocol
|
||||||
|
plan
|
||||||
|
packageRevisionId
|
||||||
|
;
|
||||||
|
}).sourceDigest,
|
||||||
protocol,
|
protocol,
|
||||||
core,
|
core,
|
||||||
sharedRuntime,
|
sharedRuntime,
|
||||||
@@ -20,15 +38,15 @@ let
|
|||||||
config = pkgs.writeText "camino-artifact-build.json" (
|
config = pkgs.writeText "camino-artifact-build.json" (
|
||||||
builtins.toJSON {
|
builtins.toJSON {
|
||||||
inherit
|
inherit
|
||||||
plan
|
buildContract
|
||||||
compiler
|
compiler
|
||||||
packageRevisionId
|
packageRevisionId
|
||||||
core
|
core
|
||||||
sharedRuntime
|
sharedRuntime
|
||||||
nodeModules
|
nodeModules
|
||||||
service
|
service
|
||||||
group
|
|
||||||
;
|
;
|
||||||
|
group = true;
|
||||||
components =
|
components =
|
||||||
if components == null then
|
if components == null then
|
||||||
null
|
null
|
||||||
@@ -39,7 +57,10 @@ let
|
|||||||
bindingOutput = components.bindingOutput or "src/gen/client.ts";
|
bindingOutput = components.bindingOutput or "src/gen/client.ts";
|
||||||
contracts = components.contracts or [ ];
|
contracts = components.contracts or [ ];
|
||||||
};
|
};
|
||||||
source = src;
|
source = import ./implementation-source.nix {
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
inherit src;
|
||||||
|
};
|
||||||
portable =
|
portable =
|
||||||
if portable == null then
|
if portable == null then
|
||||||
null
|
null
|
||||||
@@ -71,7 +92,27 @@ let
|
|||||||
serviceAdapter = ./portable-service.mjs;
|
serviceAdapter = ./portable-service.mjs;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
compiled = pkgs.runCommand "camino-compiled-artifacts" { passthru.buildConfig = config; } ''
|
||||||
|
${pkgs.nodejs_24}/bin/node ${./.}/build-artifacts.mjs ${config}
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
pkgs.runCommand "camino-checked-artifacts" { passthru.buildConfig = config; } ''
|
if group then
|
||||||
${pkgs.nodejs_24}/bin/node ${./.}/build-artifacts.mjs ${config}
|
compiled
|
||||||
''
|
else
|
||||||
|
(import ./assemble-package.nix {
|
||||||
|
inherit pkgs;
|
||||||
|
artifacts = [ compiled ];
|
||||||
|
context = {
|
||||||
|
inherit
|
||||||
|
buildContract
|
||||||
|
sourceDigest
|
||||||
|
packageRevisionId
|
||||||
|
sharedRuntime
|
||||||
|
;
|
||||||
|
generator = protocol;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
// {
|
||||||
|
caminoGroup = compiled;
|
||||||
|
buildConfig = config;
|
||||||
|
}
|
||||||
|
|||||||
+14
-20
@@ -6,9 +6,10 @@ import { buildService } from "./build-service.mjs";
|
|||||||
|
|
||||||
const config = JSON.parse(await fs.readFile(process.argv[2], "utf8"));
|
const config = JSON.parse(await fs.readFile(process.argv[2], "utf8"));
|
||||||
const compiler = await import(pathToFileURL(config.compiler));
|
const compiler = await import(pathToFileURL(config.compiler));
|
||||||
const plan = JSON.parse(await fs.readFile(config.plan, "utf8"));
|
const contract = JSON.parse(await fs.readFile(config.buildContract, "utf8"));
|
||||||
const pkg = plan.definition.packages.find((pkg) => pkg.revision === config.packageRevisionId);
|
compiler.checkPackageBuildContract(contract);
|
||||||
if (!pkg || compiler.hexDigest(plan.definition) !== plan.digest) throw Error("Invalid package assembly context");
|
const pkg = contract.definition.package;
|
||||||
|
if (pkg.revision !== config.packageRevisionId) throw Error("Invalid package assembly context");
|
||||||
const output = process.env.out;
|
const output = process.env.out;
|
||||||
if (!output) throw Error("Package assembly requires an output directory");
|
if (!output) throw Error("Package assembly requires an output directory");
|
||||||
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
||||||
@@ -23,18 +24,17 @@ const recordFile = async (name, mediaType) => {
|
|||||||
};
|
};
|
||||||
await fs.mkdir(path.join(output, "share/quixos/generated"), { recursive: true });
|
await fs.mkdir(path.join(output, "share/quixos/generated"), { recursive: true });
|
||||||
for (const root of config.groups) {
|
for (const root of config.groups) {
|
||||||
const manifest = compiler.parsePackageArtifacts(
|
const manifest = compiler.parseArtifactGroup(
|
||||||
JSON.parse(await fs.readFile(path.join(root, "share/quixos/package-artifacts.json"), "utf8")),
|
JSON.parse(await fs.readFile(path.join(root, "share/quixos/package-artifacts.json"), "utf8")),
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
manifest.packageRevisionId !== pkg.revision ||
|
manifest.packageRevisionId !== pkg.revision ||
|
||||||
manifest.bindingDigest !== pkg.bindingDigest ||
|
manifest.bindingDigest !== contract.digest ||
|
||||||
manifest.sourceDigest !== pkg.sourceDigest ||
|
JSON.stringify(manifest.versions) !== JSON.stringify(contract.definition.versions)
|
||||||
JSON.stringify(manifest.versions) !== JSON.stringify(plan.definition.versions)
|
|
||||||
)
|
)
|
||||||
throw Error("Artifact group belongs to a different checked package");
|
throw Error("Artifact group belongs to a different checked package");
|
||||||
const receipt = JSON.parse(await fs.readFile(path.join(root, "share/quixos/build-receipt.json"), "utf8"));
|
const receipt = JSON.parse(await fs.readFile(path.join(root, "share/quixos/build-receipt.json"), "utf8"));
|
||||||
const expected = compiler.expectedArtifactReceipt(plan, manifest, generatorDigest);
|
const expected = compiler.expectedGroupReceipt(contract, manifest, generatorDigest);
|
||||||
if (JSON.stringify(receipt) !== JSON.stringify(expected.receipt))
|
if (JSON.stringify(receipt) !== JSON.stringify(expected.receipt))
|
||||||
throw Error("Artifact group has an invalid build receipt");
|
throw Error("Artifact group has an invalid build receipt");
|
||||||
const read = await compiler.artifactFileReader({ [pkg.revision]: root });
|
const read = await compiler.artifactFileReader({ [pkg.revision]: root });
|
||||||
@@ -80,24 +80,18 @@ if (!implementations.some((entry) => entry.compatibility === "quixos-service-v1"
|
|||||||
const manifest = compiler.parsePackageArtifacts({
|
const manifest = compiler.parsePackageArtifacts({
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
packageRevisionId: pkg.revision,
|
packageRevisionId: pkg.revision,
|
||||||
bindingDigest: pkg.bindingDigest,
|
bindingDigest: contract.digest,
|
||||||
sourceDigest: pkg.sourceDigest,
|
sourceDigest: config.sourceDigest,
|
||||||
versions: plan.definition.versions,
|
versions: contract.definition.versions,
|
||||||
implementations,
|
implementations,
|
||||||
...(components.length ? { components } : {}),
|
...(components.length ? { components } : {}),
|
||||||
});
|
});
|
||||||
const { receipt, sources } = compiler.expectedArtifactReceipt(plan, manifest, generatorDigest);
|
const { receipt, sources } = compiler.expectedPackageReceipt(contract, manifest, config.sourceDigest, generatorDigest);
|
||||||
for (const [name, bytes] of sources) {
|
for (const [name, bytes] of sources) {
|
||||||
const actual = await fs.readFile(path.join(output, name));
|
const actual = await fs.readFile(path.join(output, name));
|
||||||
if (!Buffer.from(bytes).equals(actual)) throw Error("Assembly lacks checked generated source " + name);
|
if (!Buffer.from(bytes).equals(actual)) throw Error("Assembly lacks checked generated source " + name);
|
||||||
}
|
}
|
||||||
await fs.writeFile(path.join(output, "share/quixos/package-artifacts.json"), JSON.stringify(manifest, null, 2));
|
await fs.writeFile(path.join(output, "share/quixos/package-artifacts.json"), JSON.stringify(manifest, null, 2));
|
||||||
await fs.writeFile(path.join(output, "share/quixos/build-receipt.json"), JSON.stringify(receipt, null, 2));
|
await fs.writeFile(path.join(output, "share/quixos/build-receipt.json"), JSON.stringify(receipt, null, 2));
|
||||||
// Check package coverage with the same public validator used at installation.
|
// Source selection is attested here; compilation groups retain their own receipt.
|
||||||
const packagePlan = { definition: { ...plan.definition, packages: [pkg] }, digest: "" };
|
compiler.checkPackageCoverage({ ...pkg, bindingDigest: contract.digest, sourceDigest: config.sourceDigest }, manifest);
|
||||||
packagePlan.digest = compiler.hexDigest(packagePlan.definition);
|
|
||||||
await compiler.checkExecutionWorld(
|
|
||||||
packagePlan,
|
|
||||||
[manifest],
|
|
||||||
await compiler.artifactFileReader({ [pkg.revision]: output }),
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -8,7 +8,12 @@ let
|
|||||||
config = pkgs.writeText "camino-package-assembly.json" (
|
config = pkgs.writeText "camino-package-assembly.json" (
|
||||||
builtins.toJSON {
|
builtins.toJSON {
|
||||||
inherit groups;
|
inherit groups;
|
||||||
inherit (context) plan packageRevisionId sharedRuntime;
|
inherit (context)
|
||||||
|
buildContract
|
||||||
|
sourceDigest
|
||||||
|
packageRevisionId
|
||||||
|
sharedRuntime
|
||||||
|
;
|
||||||
compiler = "${context.generator}/libexec/quixos-protocol/execution-world.mjs";
|
compiler = "${context.generator}/libexec/quixos-protocol/execution-world.mjs";
|
||||||
node = "${pkgs.nodejs_24}/bin/node";
|
node = "${pkgs.nodejs_24}/bin/node";
|
||||||
esbuild = "${pkgs.esbuild}/bin/esbuild";
|
esbuild = "${pkgs.esbuild}/bin/esbuild";
|
||||||
|
|||||||
+11
-11
@@ -10,9 +10,10 @@ import { execFileSync } from "node:child_process";
|
|||||||
import { pathToFileURL } from "node:url";
|
import { pathToFileURL } from "node:url";
|
||||||
const config = JSON.parse(await fs.readFile(process.argv[2], "utf8"));
|
const config = JSON.parse(await fs.readFile(process.argv[2], "utf8"));
|
||||||
const compiler = await import(pathToFileURL(config.compiler));
|
const compiler = await import(pathToFileURL(config.compiler));
|
||||||
const plan = JSON.parse(await fs.readFile(config.plan, "utf8"));
|
const contract = JSON.parse(await fs.readFile(config.buildContract, "utf8"));
|
||||||
const pkg = plan.definition.packages.find((p) => p.revision === config.packageRevisionId);
|
compiler.checkPackageBuildContract(contract);
|
||||||
if (!pkg || compiler.hexDigest(plan.definition) !== plan.digest) throw Error("Invalid checked execution plan/package");
|
const pkg = contract.definition.package;
|
||||||
|
if (pkg.revision !== config.packageRevisionId) throw Error("Invalid build contract package");
|
||||||
const output = process.env.out;
|
const output = process.env.out;
|
||||||
if (!output) throw Error("Missing Nix output");
|
if (!output) throw Error("Missing Nix output");
|
||||||
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
||||||
@@ -86,8 +87,8 @@ for (const { target, mode, settings } of builds) {
|
|||||||
const bindingPath = relative(settings.bindingOutput);
|
const bindingPath = relative(settings.bindingOutput);
|
||||||
const source =
|
const source =
|
||||||
mode === "remote"
|
mode === "remote"
|
||||||
? compiler.generateRemoteTypeScriptBindings(plan.definition.bindingSchema, pkg.revision)
|
? compiler.generateRemoteTypeScriptBindings(contract.definition.bindings, pkg.revision)
|
||||||
: compiler.generatePortableTypeScriptBindings(plan.definition.bindingSchema, pkg.revision, {
|
: compiler.generatePortableTypeScriptBindings(contract.definition.bindings, pkg.revision, {
|
||||||
target: executionTarget,
|
target: executionTarget,
|
||||||
});
|
});
|
||||||
await fs.mkdir(path.dirname(path.join(work, bindingPath)), { recursive: true });
|
await fs.mkdir(path.dirname(path.join(work, bindingPath)), { recursive: true });
|
||||||
@@ -179,22 +180,21 @@ for (const { target, mode, settings } of builds) {
|
|||||||
const components =
|
const components =
|
||||||
config.group && !config.components
|
config.group && !config.components
|
||||||
? []
|
? []
|
||||||
: await buildComponents({ config, compiler, plan, pkg, output, recordFile, generated });
|
: await buildComponents({ config, compiler, contract, pkg, output, recordFile, generated });
|
||||||
if (!config.group || config.service.entry)
|
if (!config.group || config.service.entry)
|
||||||
await buildService({ config, compiler, pkg, output, coreServer, sharedFiles, implementations, recordFile });
|
await buildService({ config, compiler, pkg, output, coreServer, sharedFiles, implementations, recordFile });
|
||||||
|
|
||||||
const manifest = compiler.parsePackageArtifacts({
|
const manifest = compiler.parseArtifactGroup({
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
packageRevisionId: pkg.revision,
|
packageRevisionId: pkg.revision,
|
||||||
bindingDigest: pkg.bindingDigest,
|
bindingDigest: contract.digest,
|
||||||
sourceDigest: pkg.sourceDigest,
|
versions: contract.definition.versions,
|
||||||
versions: plan.definition.versions,
|
|
||||||
implementations,
|
implementations,
|
||||||
...(components.length ? { components } : {}),
|
...(components.length ? { components } : {}),
|
||||||
});
|
});
|
||||||
for (const { file, source } of generated.values())
|
for (const { file, source } of generated.values())
|
||||||
if ((await fs.readFile(file, "utf8")) !== source) throw Error("Generated bindings changed during build");
|
if ((await fs.readFile(file, "utf8")) !== source) throw Error("Generated bindings changed during build");
|
||||||
const { receipt, sources } = compiler.expectedArtifactReceipt(plan, manifest, generatorDigest);
|
const { receipt, sources } = compiler.expectedGroupReceipt(contract, manifest, generatorDigest);
|
||||||
for (const [file, bytes] of sources)
|
for (const [file, bytes] of sources)
|
||||||
if (!Buffer.from(bytes).equals(await fs.readFile(path.join(output, file))))
|
if (!Buffer.from(bytes).equals(await fs.readFile(path.join(output, file))))
|
||||||
throw Error("Receipt generation differs from compiled bindings");
|
throw Error("Receipt generation differs from compiled bindings");
|
||||||
|
|||||||
+5
-11
@@ -5,7 +5,7 @@ import { createHash } from "node:crypto";
|
|||||||
import { execFileSync } from "node:child_process";
|
import { execFileSync } from "node:child_process";
|
||||||
import { pathToFileURL } from "node:url";
|
import { pathToFileURL } from "node:url";
|
||||||
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
||||||
export async function buildComponents({ config, compiler, plan, pkg, output, recordFile, generated }) {
|
export async function buildComponents({ config, compiler, contract, pkg, output, recordFile, generated }) {
|
||||||
const settings = config.components;
|
const settings = config.components;
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
if (pkg.components?.length) throw Error("Declared components require checked component build settings");
|
if (pkg.components?.length) throw Error("Declared components require checked component build settings");
|
||||||
@@ -108,7 +108,7 @@ export async function buildComponents({ config, compiler, plan, pkg, output, rec
|
|||||||
sharedAliases.push("--alias:" + name + "=" + shim, "--external:" + url);
|
sharedAliases.push("--alias:" + name + "=" + shim, "--external:" + url);
|
||||||
}
|
}
|
||||||
const bindingPath = compiler.artifactPath(settings.bindingOutput),
|
const bindingPath = compiler.artifactPath(settings.bindingOutput),
|
||||||
bindings = compiler.generateComponentClientBindings(plan, pkg.revision),
|
bindings = contract.definition.component,
|
||||||
assets = compiler.componentAssetDeclarations();
|
assets = compiler.componentAssetDeclarations();
|
||||||
await fs.mkdir(path.dirname(path.join(work, bindingPath)), { recursive: true });
|
await fs.mkdir(path.dirname(path.join(work, bindingPath)), { recursive: true });
|
||||||
await fs.writeFile(path.join(work, bindingPath), bindings);
|
await fs.writeFile(path.join(work, bindingPath), bindings);
|
||||||
@@ -126,10 +126,9 @@ export async function buildComponents({ config, compiler, plan, pkg, output, rec
|
|||||||
for (const root of settings.contracts ?? []) {
|
for (const root of settings.contracts ?? []) {
|
||||||
const companion = JSON.parse(await fs.readFile(path.join(root, "react-contracts.json"), "utf8"));
|
const companion = JSON.parse(await fs.readFile(path.join(root, "react-contracts.json"), "utf8"));
|
||||||
if (companion.schemaVersion !== 1) throw Error("Unsupported React props companion");
|
if (companion.schemaVersion !== 1) throw Error("Unsupported React props companion");
|
||||||
const contracts = plan.definition.workspace.interfaceImports.filter(
|
const contracts = contract.definition.moduleInterfaces.filter(
|
||||||
(iface) =>
|
(iface) =>
|
||||||
iface.revisionId === companion.interfaceRevisionId ||
|
iface.revisionId === companion.interfaceRevisionId || iface.definitionId === companion.interfaceRevisionId,
|
||||||
iface.application?.definitionId === companion.interfaceRevisionId,
|
|
||||||
);
|
);
|
||||||
if (!contracts.length) continue;
|
if (!contracts.length) continue;
|
||||||
for (const [memberId, entry] of Object.entries(companion.members)) {
|
for (const [memberId, entry] of Object.entries(companion.members)) {
|
||||||
@@ -139,12 +138,7 @@ export async function buildComponents({ config, compiler, plan, pkg, output, rec
|
|||||||
`import type {${entry.export} as ${alias}} from ${JSON.stringify(path.join(root, "types", compiler.artifactPath(entry.path)))};`,
|
`import type {${entry.export} as ${alias}} from ${JSON.stringify(path.join(root, "types", compiler.artifactPath(entry.path)))};`,
|
||||||
);
|
);
|
||||||
for (const iface of contracts) {
|
for (const iface of contracts) {
|
||||||
if (
|
if (!iface.members.includes(memberId)) throw Error("Props companion names an unknown module member");
|
||||||
!(iface.template?.members ?? iface.members).some(
|
|
||||||
(member) => member.kind === "module" && member.id === memberId,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
throw Error("Props companion names an unknown module member");
|
|
||||||
const key = JSON.stringify([iface.revisionId, memberId]);
|
const key = JSON.stringify([iface.revisionId, memberId]);
|
||||||
if (seenProps.has(key)) throw Error("Duplicate React props companion for " + key);
|
if (seenProps.has(key)) throw Error("Duplicate React props companion for " + key);
|
||||||
seenProps.add(key);
|
seenProps.add(key);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# QX and recursive pins enter through the checked contract and build recipe.
|
||||||
|
# The compiler receives authored implementation files, not resource provenance.
|
||||||
|
{ lib, src }:
|
||||||
|
builtins.path {
|
||||||
|
path = src;
|
||||||
|
name = "camino-implementation-source";
|
||||||
|
filter =
|
||||||
|
path: type:
|
||||||
|
let
|
||||||
|
name = builtins.baseNameOf path;
|
||||||
|
in
|
||||||
|
if type == "directory" then
|
||||||
|
!(builtins.elem name [
|
||||||
|
".git"
|
||||||
|
".jj"
|
||||||
|
"node_modules"
|
||||||
|
])
|
||||||
|
else
|
||||||
|
!(builtins.elem name [
|
||||||
|
"flake.nix"
|
||||||
|
"flake.lock"
|
||||||
|
"quixos.lock"
|
||||||
|
"quixos.check.json"
|
||||||
|
"quixos.react.json"
|
||||||
|
"yarn-project.nix"
|
||||||
|
"components.nix"
|
||||||
|
"contracts.nix"
|
||||||
|
])
|
||||||
|
&& !(lib.hasSuffix ".qx" name);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# The selected protocol owns semantic projection; builders receive its result.
|
||||||
|
args@{ protocol, ... }: import "${protocol}/share/package-context.nix" args
|
||||||
+17
-2
@@ -8,8 +8,23 @@
|
|||||||
let
|
let
|
||||||
config = pkgs.writeText "camino-react-contracts.json" (
|
config = pkgs.writeText "camino-react-contracts.json" (
|
||||||
builtins.toJSON {
|
builtins.toJSON {
|
||||||
source = src;
|
source = import ./implementation-source.nix {
|
||||||
interface = context.interface;
|
inherit (pkgs) lib;
|
||||||
|
inherit src;
|
||||||
|
};
|
||||||
|
interface = builtins.toFile "camino-interface-contract.json" (
|
||||||
|
builtins.unsafeDiscardStringContext (
|
||||||
|
builtins.toJSON (
|
||||||
|
let
|
||||||
|
resource = builtins.fromJSON (builtins.readFile context.interface);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
kind = resource.kind;
|
||||||
|
revision = builtins.removeAttrs resource.revision [ "source" ];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
inherit members dependencies;
|
inherit members dependencies;
|
||||||
reactSdk = context.reactSdk or null;
|
reactSdk = context.reactSdk or null;
|
||||||
node = "${pkgs.nodejs_24}/bin/node";
|
node = "${pkgs.nodejs_24}/bin/node";
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ let
|
|||||||
group = import ./artifacts.nix {
|
group = import ./artifacts.nix {
|
||||||
inherit pkgs src;
|
inherit pkgs src;
|
||||||
inherit (context)
|
inherit (context)
|
||||||
plan
|
buildContract
|
||||||
core
|
core
|
||||||
sharedRuntime
|
sharedRuntime
|
||||||
typescript
|
typescript
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ let
|
|||||||
group = import ./artifacts.nix {
|
group = import ./artifacts.nix {
|
||||||
inherit pkgs src;
|
inherit pkgs src;
|
||||||
inherit (context)
|
inherit (context)
|
||||||
plan
|
buildContract
|
||||||
core
|
core
|
||||||
sharedRuntime
|
sharedRuntime
|
||||||
typescript
|
typescript
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ let
|
|||||||
group = import ./artifacts.nix {
|
group = import ./artifacts.nix {
|
||||||
inherit pkgs src service;
|
inherit pkgs src service;
|
||||||
inherit (context)
|
inherit (context)
|
||||||
plan
|
buildContract
|
||||||
core
|
core
|
||||||
sharedRuntime
|
sharedRuntime
|
||||||
typescript
|
typescript
|
||||||
|
|||||||
Reference in New Issue
Block a user