|
|
|
@@ -510,6 +510,20 @@ EOF
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
# Language-neutral, offline schema compilation. Snapshot directories must be
|
|
|
|
|
# fixed Nix inputs matching the resource lock's complete dependency closure.
|
|
|
|
|
mkQxBindingSchema = { pkgs, protocol, src, repository, commit, resources ? [ ] }:
|
|
|
|
|
let
|
|
|
|
|
snapshots = pkgs.writeText "qx-binding-snapshots.json" (builtins.toJSON { inherit resources; });
|
|
|
|
|
in pkgs.runCommand "qx-binding-schema.json" { } ''
|
|
|
|
|
${protocol}/bin/quixos-resource-compile \
|
|
|
|
|
--root ${src} --kind package \
|
|
|
|
|
--repository ${pkgs.lib.escapeShellArg repository} \
|
|
|
|
|
--commit ${pkgs.lib.escapeShellArg commit} \
|
|
|
|
|
--checkout-root "$TMPDIR/checkouts" \
|
|
|
|
|
--snapshot-map ${snapshots} --snapshot-only true --schema-out "$out" > /dev/null
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
mkCaminoTsYarnNixifyFlake =
|
|
|
|
|
{
|
|
|
|
|
inputs,
|
|
|
|
@@ -522,6 +536,13 @@ EOF
|
|
|
|
|
nodejsAttr ? "nodejs_24",
|
|
|
|
|
buildCommand ? "yarn build",
|
|
|
|
|
buildEnv ? { },
|
|
|
|
|
# An exact, compiler-produced BindingSchema JSON artifact and a backend.
|
|
|
|
|
# Other language helpers can consume the same schema with their own generator/runtime.
|
|
|
|
|
bindings ? null,
|
|
|
|
|
bindingOptions ? { },
|
|
|
|
|
# A dedicated entrypoint calling SDK serveMigration; never start the
|
|
|
|
|
# normal package server in the isolated migration execution boundary.
|
|
|
|
|
migrationEntrypoint ? null,
|
|
|
|
|
nativeBuildInputs ? [ ],
|
|
|
|
|
devShellPackages ? [ ],
|
|
|
|
|
devShellHook ? "",
|
|
|
|
@@ -530,6 +551,8 @@ EOF
|
|
|
|
|
}:
|
|
|
|
|
flake-utils.lib.eachDefaultSystem (
|
|
|
|
|
system:
|
|
|
|
|
let
|
|
|
|
|
outputsFor = candidateBindings:
|
|
|
|
|
let
|
|
|
|
|
pkgs = import nixpkgs { inherit system; };
|
|
|
|
|
lib = pkgs.lib;
|
|
|
|
@@ -560,6 +583,30 @@ EOF
|
|
|
|
|
attrs
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
bindingConfig = if candidateBindings != null then candidateBindings
|
|
|
|
|
else if bindings == null then null else callOption bindings;
|
|
|
|
|
bindingSchema = if bindingConfig == null then null else bindingConfig.schema or (mkQxBindingSchema {
|
|
|
|
|
inherit pkgs;
|
|
|
|
|
protocol = bindingConfig.generator;
|
|
|
|
|
src = packageRoot;
|
|
|
|
|
inherit (bindingConfig) repository commit;
|
|
|
|
|
resources = bindingConfig.resources or [ ];
|
|
|
|
|
});
|
|
|
|
|
bindingOutput = if bindingConfig == null then "src/gen/qx.ts" else bindingConfig.output or "src/gen/qx.ts";
|
|
|
|
|
bindingOptionsFile = if bindingConfig == null then null else
|
|
|
|
|
pkgs.writeText "qx-typescript-options.json" (builtins.toJSON (bindingConfig.options or bindingOptions));
|
|
|
|
|
bindingCommand = if bindingConfig == null then "" else ''
|
|
|
|
|
mkdir -p ${lib.escapeShellArg (dirOf bindingOutput)}
|
|
|
|
|
${bindingConfig.generator}/bin/quixos-codegen-ts \
|
|
|
|
|
${lib.escapeShellArg (toString bindingSchema)} \
|
|
|
|
|
${lib.escapeShellArg bindingConfig.packageRevisionId} \
|
|
|
|
|
${lib.escapeShellArg bindingOutput} ${bindingOptionsFile}
|
|
|
|
|
'';
|
|
|
|
|
generateBindings = pkgs.writeShellApplication {
|
|
|
|
|
name = "qx-generate-bindings";
|
|
|
|
|
text = bindingCommand;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bundleConfig = if bundle == null then { } else bundle;
|
|
|
|
|
bundleOutfile = bundleConfig.outfile or "server.mjs";
|
|
|
|
|
bundlePlatform = bundleConfig.platform or "node";
|
|
|
|
@@ -611,15 +658,6 @@ EOF
|
|
|
|
|
else ''
|
|
|
|
|
runHook preInstall
|
|
|
|
|
install -Dm755 ${lib.escapeShellArg serverFile} "$out/libexec/${serverLibexecName}/${serverFile}"
|
|
|
|
|
# Browser entrypoints are runtime artifacts too. Package build scripts
|
|
|
|
|
# conventionally emit them as top-level .mjs files in dist/. Install
|
|
|
|
|
# the complete set so adding an entrypoint cannot produce a descriptor
|
|
|
|
|
# that resolves successfully but fails when Web Studio opens the file.
|
|
|
|
|
for browserModule in dist/*.mjs; do
|
|
|
|
|
if [ -f "$browserModule" ]; then
|
|
|
|
|
install -Dm644 "$browserModule" "$out/libexec/${serverLibexecName}/$(basename "$browserModule")"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
${lib.concatMapStringsSep "\n" installExtraFile extraFiles}
|
|
|
|
|
mkdir -p "$out/bin"
|
|
|
|
|
cat > "$out/bin/${serverBin}" <<EOF
|
|
|
|
@@ -630,6 +668,17 @@ EOF
|
|
|
|
|
${lib.optionalString (installConfig ? descriptorPath && descriptorPath != null) ''
|
|
|
|
|
cp ${lib.escapeShellArg descriptorPath} "$out/${descriptorPath}"
|
|
|
|
|
''}
|
|
|
|
|
${lib.optionalString (bindingConfig != null) ''
|
|
|
|
|
install -m 0444 quixos-check.json "$out/quixos-check.json"
|
|
|
|
|
''}
|
|
|
|
|
${lib.optionalString (migrationEntrypoint != null) ''
|
|
|
|
|
install -Dm444 migration.mjs "$out/libexec/${serverLibexecName}/migration.mjs"
|
|
|
|
|
cat > "$out/bin/migrate" <<EOF
|
|
|
|
|
#!${pkgs.runtimeShell}
|
|
|
|
|
exec ${nodejs}/bin/node --max-old-space-size=256 "$out/libexec/${serverLibexecName}/migration.mjs" "\$@"
|
|
|
|
|
EOF
|
|
|
|
|
chmod +x "$out/bin/migrate"
|
|
|
|
|
''}
|
|
|
|
|
runHook postInstall
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
@@ -638,13 +687,26 @@ EOF
|
|
|
|
|
overrideAttrs = old: {
|
|
|
|
|
nativeBuildInputs =
|
|
|
|
|
(old.nativeBuildInputs or [ ])
|
|
|
|
|
++ lib.optional (bundle != null) pkgs.esbuild
|
|
|
|
|
++ lib.optional (bundle != null || migrationEntrypoint != null) pkgs.esbuild
|
|
|
|
|
++ callOption nativeBuildInputs;
|
|
|
|
|
buildPhase = ''
|
|
|
|
|
runHook preBuild
|
|
|
|
|
${exportsFor (callOption buildEnv)}
|
|
|
|
|
${bindingCommand}
|
|
|
|
|
${lib.optionalString (bindingConfig != null) "yarn exec tsc --noEmit"}
|
|
|
|
|
${lib.optionalString (bindingConfig != null) "cp ${lib.escapeShellArg bindingOutput} .qx-checked-bindings"}
|
|
|
|
|
${buildCommand}
|
|
|
|
|
${lib.optionalString (bindingConfig != null) ''
|
|
|
|
|
yarn exec tsc --noEmit
|
|
|
|
|
node ${./check-receipt.mjs} ${lib.escapeShellArg (toString bindingSchema)} \
|
|
|
|
|
${lib.escapeShellArg bindingConfig.packageRevisionId} ${lib.escapeShellArg bindingOutput} \
|
|
|
|
|
${lib.escapeShellArg (toString bindingConfig.generator)} quixos-check.json
|
|
|
|
|
''}
|
|
|
|
|
${bundleCommand}
|
|
|
|
|
${lib.optionalString (migrationEntrypoint != null) ''
|
|
|
|
|
esbuild ${lib.escapeShellArg migrationEntrypoint} --bundle --platform=node --target=node24 --format=esm \
|
|
|
|
|
${bundleAliasArgs} --preserve-symlinks --banner:js=${lib.escapeShellArg nodeRequireBanner} --outfile=migration.mjs
|
|
|
|
|
''}
|
|
|
|
|
runHook postBuild
|
|
|
|
|
'';
|
|
|
|
|
} // lib.optionalAttrs (installServerPhase != null) {
|
|
|
|
@@ -680,10 +742,18 @@ EOF
|
|
|
|
|
packages = [
|
|
|
|
|
nodejs
|
|
|
|
|
project.yarn-freestanding
|
|
|
|
|
] ++ callOption devShellPackages;
|
|
|
|
|
] ++ lib.optional (bindingConfig != null) generateBindings ++ callOption devShellPackages;
|
|
|
|
|
# Explicit command keeps shell entry free of source mutations.
|
|
|
|
|
shellHook = devShellHookBase + callOption devShellHook;
|
|
|
|
|
};
|
|
|
|
|
} // maybeServerOutputs
|
|
|
|
|
} // maybeServerOutputs;
|
|
|
|
|
in (outputsFor null) // {
|
|
|
|
|
# The workspace supplies a compiler-produced schema for the exact
|
|
|
|
|
# candidate graph. Standalone builds may use checked-in authoring types,
|
|
|
|
|
# but only this build path regenerates and witnesses candidate contracts.
|
|
|
|
|
quixosPackages.checkedServer = { schema, generator, packageRevisionId }:
|
|
|
|
|
(outputsFor { inherit schema generator packageRevisionId; }).packages.server;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
in
|
|
|
|
|
{
|
|
|
|
@@ -692,5 +762,6 @@ in
|
|
|
|
|
mkTsPackageServer
|
|
|
|
|
mkSchemaSupport
|
|
|
|
|
mkCaminoSourcePackage
|
|
|
|
|
mkQxBindingSchema
|
|
|
|
|
mkCaminoTsYarnNixifyFlake;
|
|
|
|
|
}
|
|
|
|
|