Update Harbor client and gateway functionality
Build and Deploy Gateway / build-and-push (push) Successful in 35s
Build and Deploy Gateway / deploy (push) Successful in 14s

This commit is contained in:
2026-08-17 15:23:16 +03:00
parent 0b39211fbd
commit 7c255192b0
41 changed files with 1443 additions and 218 deletions
@@ -7,7 +7,10 @@ import {
type StoredState,
} from '../../../shared/contracts/state.js';
import { HarborError } from '../../../shared/errors.js';
import { normalizeRouteRules } from '../../../shared/routingRules.js';
import {
normalizeRouteRules,
ROUTE_RULES_CONTRACT_VERSION,
} from '../../../shared/routingRules.js';
import type { RuntimeCommandResult } from '../connection/index.js';
import { finishRollback } from '../../services/rollback.js';
@@ -29,6 +32,7 @@ interface RouteRulesDependencies {
applyCommand(): Promise<RuntimeCommandResult>;
restoreRunning(): Promise<unknown>;
};
route?: { isGatewayDirect(): boolean };
serialize<T>(operation: () => Promise<T>): Promise<T>;
runOperation<T>(operation: () => Promise<T>): Promise<T>;
}
@@ -36,6 +40,7 @@ interface RouteRulesDependencies {
export function createRouteRulesService(dependencies: RouteRulesDependencies) {
const applyRules = async (previousState: StoredState, routeRules: RouteRule[]) => {
const wasRunning = await dependencies.runtime.isRunning();
const bypassed = dependencies.route?.isGatewayDirect() === true;
const targetProfile = wasRunning
? appliedProfile(previousState)
: desiredProfile(previousState);
@@ -45,13 +50,14 @@ export function createRouteRulesService(dependencies: RouteRulesDependencies) {
const subscriptionConfig = targetProfile
? dependencies.subscription.readConfig(targetProfile.id)
: null;
if (!targetServerId || !subscriptionConfig) {
if (bypassed || !targetServerId || !subscriptionConfig) {
let stateCommitStarted = false;
try {
stateCommitStarted = true;
dependencies.state.update((state) => ({
...state,
routeRules,
...(bypassed ? { appliedRouteRules: [] } : {}),
routeRulesRevision: state.routeRulesRevision + 1,
}));
} catch (error) {
@@ -68,14 +74,17 @@ export function createRouteRulesService(dependencies: RouteRulesDependencies) {
routeRules,
);
const previousConfig = dependencies.config.read();
const configChanged = previousConfig !== JSON.stringify(candidateConfig, null, 2);
let configMutationStarted = false;
let runtimeMutationStarted = false;
let stateCommitStarted = false;
try {
configMutationStarted = true;
dependencies.config.write(candidateConfig);
if (wasRunning) {
if (configChanged) {
configMutationStarted = true;
dependencies.config.write(candidateConfig);
}
if (wasRunning && configChanged) {
const command = await dependencies.runtime.applyCommand();
runtimeMutationStarted = command.mutationStarted;
if (!command.ok) throw command.error;
@@ -103,24 +112,27 @@ export function createRouteRulesService(dependencies: RouteRulesDependencies) {
}
};
const update = (rules: unknown, expectedRulesRevision: unknown, expectedRevision: unknown) => {
const update = (
rules: unknown,
expectedRulesRevision: unknown,
rulesContractVersion: unknown,
) => {
if (rulesContractVersion !== ROUTE_RULES_CONTRACT_VERSION) {
throw new HarborError('REQUEST_INVALID');
}
let routeRules: RouteRule[];
try {
routeRules = normalizeRouteRules(rules, { strict: true }) as RouteRule[];
} catch (cause) {
throw new HarborError('REQUEST_INVALID', { cause });
}
const rulesRevision = expectedRulesRevision ?? expectedRevision;
if (!Number.isSafeInteger(rulesRevision) || Number(rulesRevision) < 0) {
if (!Number.isSafeInteger(expectedRulesRevision) || Number(expectedRulesRevision) < 0) {
throw new HarborError('REQUEST_INVALID');
}
return dependencies.serialize(async () => {
const current = dependencies.state.read();
const currentRevision = expectedRulesRevision == null
? current.revision
: current.routeRulesRevision;
if (currentRevision !== rulesRevision) throw new HarborError('STATE_CONFLICT');
if (current.routeRulesRevision !== expectedRulesRevision) throw new HarborError('STATE_CONFLICT');
if (isDeepStrictEqual(current.routeRules, routeRules)) return;
await dependencies.runOperation(() => applyRules(current, routeRules));
});