Update VPN client and gateway behavior
Build and Deploy Gateway / build-and-push (push) Successful in 19s
Build and Deploy Gateway / deploy (push) Successful in 6s

This commit is contained in:
2026-08-11 08:50:44 +03:00
parent 396c5d1917
commit 79ffff194f
35 changed files with 1036 additions and 590 deletions
+30 -20
View File
@@ -260,7 +260,7 @@ function dynamicClassBindings(files) {
}));
}
function bindComponentProps(definition, element, callerEnvironment, dynamicBindings) {
function bindComponentProps(definition, element, callerEnvironment, callerFile, dynamicBindings) {
const supplied = new Map();
for (const attribute of element.openingElement.attributes) {
if (attribute.type === 'JSXSpreadAttribute') {
@@ -277,9 +277,10 @@ function bindComponentProps(definition, element, callerEnvironment, dynamicBindi
callable: ['ArrowFunctionExpression', 'FunctionExpression'].includes(node.type) && producesJsx(node),
node,
environment: callerEnvironment,
file: callerFile,
});
}
supplied.set('children', { node: element.children, environment: callerEnvironment });
supplied.set('children', { node: element.children, environment: callerEnvironment, file: callerFile });
const environment = new Map(dynamicBindings.get(definition.file));
const parameter = definition.node.params?.[0];
if (parameter?.type === 'ObjectPattern') {
@@ -289,7 +290,7 @@ function bindComponentProps(definition, element, callerEnvironment, dynamicBindi
const target = property.value?.type === 'AssignmentPattern' ? property.value.left : property.value;
const localName = target?.name;
const fallback = property.value?.type === 'AssignmentPattern'
? { node: property.value.right, environment: callerEnvironment }
? { node: property.value.right, environment: callerEnvironment, file: definition.file }
: null;
if (sourceName && localName && (supplied.get(sourceName) || fallback)) {
environment.set(localName, supplied.get(sourceName) || fallback);
@@ -309,7 +310,7 @@ function producesJsx(node) {
));
}
function withLocalJsxBindings(node, environment, definitionNodes) {
function withLocalJsxBindings(node, environment, definitionNodes, file) {
const scoped = new Map(environment);
const collect = (value) => {
if (!value || typeof value !== 'object') return;
@@ -323,6 +324,7 @@ function withLocalJsxBindings(node, environment, definitionNodes) {
callable: ['ArrowFunctionExpression', 'FunctionExpression'].includes(value.init?.type),
declaration: value,
environment: scoped,
file,
node: value.init,
});
return;
@@ -336,12 +338,12 @@ function withLocalJsxBindings(node, environment, definitionNodes) {
return scoped;
}
function bindCallParameters(callable, argumentsList, callerEnvironment) {
function bindCallParameters(callable, argumentsList, callerEnvironment, callerFile) {
const environment = new Map(callable.environment);
for (let index = 0; index < callable.node.params.length; index += 1) {
const parameter = callable.node.params[index];
if (parameter?.type === 'Identifier' && argumentsList[index]) {
environment.set(parameter.name, { node: argumentsList[index], environment: callerEnvironment });
environment.set(parameter.name, { node: argumentsList[index], environment: callerEnvironment, file: callerFile });
}
}
return environment;
@@ -361,11 +363,17 @@ export function createStyleWitnesses(sources, { entry = 'App' } = {}) {
const expand = (definition, ancestors, ancestorUnknown, environment, stack) => {
if (stack.includes(definition)) throw new TypeError(`Recursive JSX witness component: ${definition.node.id?.name || definition.file}`);
const nextStack = [...stack, definition];
const entryEnvironment = withLocalJsxBindings(definition.node.body, environment, definitionNodes);
const visit = (node, currentAncestors = ancestors, currentUnknown = ancestorUnknown, currentEnvironment = entryEnvironment) => {
const entryEnvironment = withLocalJsxBindings(definition.node.body, environment, definitionNodes, definition.file);
const visit = (
node,
currentAncestors = ancestors,
currentUnknown = ancestorUnknown,
currentEnvironment = entryEnvironment,
currentFile = definition.file,
) => {
if (!node || typeof node !== 'object') return;
if (Array.isArray(node)) {
for (const child of node) visit(child, currentAncestors, currentUnknown, currentEnvironment);
for (const child of node) visit(child, currentAncestors, currentUnknown, currentEnvironment, currentFile);
return;
}
if (definitionNodes.has(node)) return;
@@ -378,10 +386,11 @@ export function createStyleWitnesses(sources, { entry = 'App' } = {}) {
if (callable?.callable) {
const callEnvironment = withLocalJsxBindings(
callable.node.body,
bindCallParameters(callable, node.arguments, currentEnvironment),
bindCallParameters(callable, node.arguments, currentEnvironment, currentFile),
definitionNodes,
callable.file || currentFile,
);
visit(callable.node.body, currentAncestors, currentUnknown, callEnvironment);
visit(callable.node.body, currentAncestors, currentUnknown, callEnvironment, callable.file || currentFile);
return;
}
}
@@ -401,16 +410,16 @@ export function createStyleWitnesses(sources, { entry = 'App' } = {}) {
if (!documentBody && !appOrBody) {
throw new TypeError(`Unsupported JSX portal target in ${definition.file}`);
}
visit(node.arguments[0], [], false, currentEnvironment);
visit(node.arguments[0], [], false, currentEnvironment, currentFile);
if (appOrBody) {
visit(node.arguments[0], [{ classes: ['app', 'client-app', 'is-gateway-app'], prefixes: [], unknown: false }], false, currentEnvironment);
visit(node.arguments[0], [{ classes: ['app', 'client-app', 'is-gateway-app'], prefixes: [], unknown: false }], false, currentEnvironment, currentFile);
}
return;
}
if (node.type === 'JSXExpressionContainer' && node.expression?.type === 'Identifier') {
const binding = currentEnvironment.get(node.expression.name);
if (binding) {
visit(binding.node, currentAncestors, currentUnknown, binding.environment);
visit(binding.node, currentAncestors, currentUnknown, binding.environment, binding.file || currentFile);
return;
}
}
@@ -419,7 +428,7 @@ export function createStyleWitnesses(sources, { entry = 'App' } = {}) {
const intrinsic = Boolean(name && /^[a-z]/.test(name));
if (intrinsic) {
const initialInfo = elementClassInfo(node.openingElement, currentEnvironment);
const additions = [...imperativeByFile.get(definition.file).entries()]
const additions = [...imperativeByFile.get(currentFile).entries()]
.filter(([target]) => initialInfo.classes.includes(target))
.flatMap(([, classes]) => classes);
const info = elementClassInfo(node.openingElement, currentEnvironment, additions);
@@ -432,26 +441,26 @@ export function createStyleWitnesses(sources, { entry = 'App' } = {}) {
tag: name,
unknown: info.unknown,
});
visit(node.children, [...currentAncestors, info], currentUnknown, currentEnvironment);
visit(node.children, [...currentAncestors, info], currentUnknown, currentEnvironment, currentFile);
return;
}
if (TRANSPARENT_JSX_COMPONENTS.has(name)) {
visit(node.children, currentAncestors, currentUnknown, currentEnvironment);
visit(node.children, currentAncestors, currentUnknown, currentEnvironment, currentFile);
return;
}
const target = definitions.get(name);
if (!target) throw new TypeError(`Unresolved JSX witness component: ${name} in ${definition.file}`);
const targetEnvironment = bindComponentProps(target, node, currentEnvironment, dynamicByFile);
const targetEnvironment = bindComponentProps(target, node, currentEnvironment, currentFile, dynamicByFile);
expand(target, currentAncestors, currentUnknown, targetEnvironment, nextStack);
return;
}
if (node.type === 'JSXFragment') {
visit(node.children, currentAncestors, currentUnknown, currentEnvironment);
visit(node.children, currentAncestors, currentUnknown, currentEnvironment, currentFile);
return;
}
for (const [key, child] of Object.entries(node)) {
if (['loc', 'start', 'end', 'extra', 'comments', 'tokens', 'errors'].includes(key)) continue;
if (child && typeof child === 'object') visit(child, currentAncestors, currentUnknown, currentEnvironment);
if (child && typeof child === 'object') visit(child, currentAncestors, currentUnknown, currentEnvironment, currentFile);
}
};
visit(definition.node.body, ancestors, ancestorUnknown, entryEnvironment);
@@ -521,6 +530,7 @@ const TRANSPARENT_JSX_COMPONENTS = new Set(['React.Fragment']);
const hash = (value) => crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex');
function propertyFamily(property) {
if (property.startsWith('--')) return property;
if (!OBSERVED_PROPERTIES.has(property)) {
throw new TypeError(`Unsupported CSS property in cascade proof: ${property}`);
}