Merge branch 'dev' into refactor/save-button-positions

This commit is contained in:
Fred KISSIE
2025-12-12 21:42:06 +01:00
7 changed files with 75 additions and 30 deletions

39
.github/workflows/restart-runners.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Restart Runners
on:
schedule:
- cron: '0 0 */7 * *'
permissions:
id-token: write
contents: read
jobs:
ec2-maintenance-prod:
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600
aws-region: ${{ secrets.AWS_REGION }}
- name: Verify AWS identity
run: aws sts get-caller-identity
- name: Start EC2 instance
run: |
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_ARM_RUNNER }}
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_AMD_RUNNER }}
echo "EC2 instances started"
- name: Wait
run: sleep 600
- name: Stop EC2 instance
run: |
aws ec2 stop-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_ARM_RUNNER }}
aws ec2 stop-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_AMD_RUNNER }}
echo "EC2 instances stopped"

24
package-lock.json generated
View File

@@ -75,7 +75,7 @@
"lucide-react": "0.559.0",
"maxmind": "5.0.1",
"moment": "2.30.1",
"next": "15.5.7",
"next": "15.5.9",
"next-intl": "4.5.8",
"next-themes": "0.4.6",
"nextjs-toploader": "3.9.17",
@@ -88,7 +88,7 @@
"pg": "8.16.3",
"posthog-node": "5.17.2",
"qrcode.react": "4.2.0",
"react": "19.2.1",
"react": "19.2.3",
"react-day-picker": "9.12.0",
"react-dom": "19.2.1",
"react-easy-sort": "1.8.0",
@@ -3835,9 +3835,9 @@
}
},
"node_modules/@next/env": {
"version": "15.5.7",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.7.tgz",
"integrity": "sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==",
"version": "15.5.9",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.9.tgz",
"integrity": "sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
@@ -16291,13 +16291,13 @@
}
},
"node_modules/next": {
"version": "15.5.7",
"resolved": "https://registry.npmjs.org/next/-/next-15.5.7.tgz",
"integrity": "sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==",
"version": "15.5.9",
"resolved": "https://registry.npmjs.org/next/-/next-15.5.9.tgz",
"integrity": "sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@next/env": "15.5.7",
"@next/env": "15.5.9",
"@swc/helpers": "0.5.15",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
@@ -19737,9 +19737,9 @@
}
},
"node_modules/react": {
"version": "19.2.1",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
"peer": true,
"engines": {

View File

@@ -99,7 +99,7 @@
"lucide-react": "0.559.0",
"maxmind": "5.0.1",
"moment": "2.30.1",
"next": "15.5.7",
"next": "15.5.9",
"next-intl": "4.5.8",
"next-themes": "0.4.6",
"nextjs-toploader": "3.9.17",
@@ -112,7 +112,7 @@
"pg": "8.16.3",
"posthog-node": "5.17.2",
"qrcode.react": "4.2.0",
"react": "19.2.1",
"react": "19.2.3",
"react-day-picker": "9.12.0",
"react-dom": "19.2.1",
"react-easy-sort": "1.8.0",
@@ -178,4 +178,4 @@
"typescript": "5.9.3",
"typescript-eslint": "8.49.0"
}
}
}

View File

@@ -2,7 +2,6 @@ import path from "path";
import { fileURLToPath } from "url";
// This is a placeholder value replaced by the build process
// export const APP_VERSION = "1.13.0-rc.0";
export const APP_VERSION = "1.13.0";
export const __FILENAME = fileURLToPath(import.meta.url);

View File

@@ -120,11 +120,13 @@ function bigIntToIp(num: bigint, version: IPVersion): string {
* Parses an endpoint string (ip:port) handling both IPv4 and IPv6 addresses.
* IPv6 addresses may be bracketed like [::1]:8080 or unbracketed like ::1:8080.
* For unbracketed IPv6, the last colon-separated segment is treated as the port.
*
*
* @param endpoint The endpoint string to parse (e.g., "192.168.1.1:8080" or "[::1]:8080" or "2607:fea8::1:8080")
* @returns An object with ip and port, or null if parsing fails
*/
export function parseEndpoint(endpoint: string): { ip: string; port: number } | null {
export function parseEndpoint(
endpoint: string
): { ip: string; port: number } | null {
if (!endpoint) return null;
// Check for bracketed IPv6 format: [ip]:port
@@ -138,7 +140,7 @@ export function parseEndpoint(endpoint: string): { ip: string; port: number } |
// Check if this looks like IPv6 (contains multiple colons)
const colonCount = (endpoint.match(/:/g) || []).length;
if (colonCount > 1) {
// This is IPv6 - the port is after the last colon
const lastColonIndex = endpoint.lastIndexOf(":");
@@ -163,7 +165,7 @@ export function parseEndpoint(endpoint: string): { ip: string; port: number } |
/**
* Formats an IP and port into a consistent endpoint string.
* IPv6 addresses are wrapped in brackets for proper parsing.
*
*
* @param ip The IP address (IPv4 or IPv6)
* @param port The port number
* @returns Formatted endpoint string

View File

@@ -84,14 +84,11 @@ LQIDAQAB
-----END PUBLIC KEY-----`;
constructor(private hostMeta: HostMeta) {
setInterval(
async () => {
this.doRecheck = true;
await this.check();
this.doRecheck = false;
},
1000 * this.phoneHomeInterval
);
setInterval(async () => {
this.doRecheck = true;
await this.check();
this.doRecheck = false;
}, 1000 * this.phoneHomeInterval);
}
public listKeys(): LicenseKeyCache[] {
@@ -242,7 +239,9 @@ LQIDAQAB
// First failure: fail silently
logger.error("Error communicating with license server:");
logger.error(e);
logger.error(`Allowing failure. Will retry one more time at next run interval.`);
logger.error(
`Allowing failure. Will retry one more time at next run interval.`
);
// return last known good status
return this.statusCache.get(
this.statusKey

View File

@@ -177,7 +177,13 @@ const CredenzaFooter = ({ className, children, ...props }: CredenzaProps) => {
const CredenzaFooter = isDesktop ? DialogFooter : SheetFooter;
return (
<CredenzaFooter className={cn("mt-8 md:mt-0 -mx-6 px-6 pt-6 border-t border-border", className)} {...props}>
<CredenzaFooter
className={cn(
"mt-8 md:mt-0 -mx-6 px-6 pt-6 border-t border-border",
className
)}
{...props}
>
{children}
</CredenzaFooter>
);