diff --git a/.gitignore b/.gitignore index 88adc8c..76e2732 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ bin frontend/dist frontend/node_modules build/linux/appimage/build -build/windows/nsis/MicrosoftEdgeWebview2Setup.exe \ No newline at end of file +build/windows/nsis/MicrosoftEdgeWebview2Setup.exeide diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..80d6960 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,33 @@ +version: '3' + +includes: + common: ./build/Taskfile.yml + windows: ./build/windows/Taskfile.yml + darwin: ./build/darwin/Taskfile.yml + linux: ./build/linux/Taskfile.yml + +vars: + APP_NAME: "core-ide" + BIN_DIR: "bin" + VITE_PORT: '{{.WAILS_VITE_PORT | default 9247}}' + +tasks: + build: + summary: Builds the application + cmds: + - task: "{{OS}}:build" + + package: + summary: Packages a production build of the application + cmds: + - task: "{{OS}}:package" + + run: + summary: Runs the application + cmds: + - task: "{{OS}}:run" + + dev: + summary: Runs the application in development mode + cmds: + - wails3 dev -config ./build/config.yml -port {{.VITE_PORT}} diff --git a/build/Taskfile.yml b/build/Taskfile.yml index a060314..202b709 100644 --- a/build/Taskfile.yml +++ b/build/Taskfile.yml @@ -14,19 +14,20 @@ tasks: - package.json - package-lock.json generates: - - node_modules/* + - node_modules preconditions: - sh: npm version msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/" cmds: - - npm install + - npm install --legacy-peer-deps build:frontend: - label: build:frontend (PRODUCTION={{.PRODUCTION}}) + label: build:frontend (DEV={{.DEV}}) summary: Build the frontend project dir: frontend sources: - "**/*" + - exclude: node_modules/**/* generates: - dist/**/* deps: @@ -38,10 +39,9 @@ tasks: cmds: - npm run {{.BUILD_COMMAND}} -q env: - PRODUCTION: '{{.PRODUCTION | default "false"}}' + PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}' vars: - BUILD_COMMAND: '{{if eq .PRODUCTION "true"}}build{{else}}build:dev{{end}}' - + BUILD_COMMAND: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}' generate:bindings: label: generate:bindings (BUILD_FLAGS={{.BUILD_FLAGS}}) @@ -51,25 +51,26 @@ tasks: sources: - "**/*.[jt]s" - exclude: frontend/**/* - - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output + - frontend/bindings/**/* - "**/*.go" - go.mod - go.sum generates: - frontend/bindings/**/* cmds: - - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=false -ts -i + - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts generate:icons: summary: Generates Windows `.ico` and Mac `.icns` files from an image dir: build sources: - "appicon.png" + - "appicon.icon" generates: - "darwin/icons.icns" - "windows/icon.ico" cmds: - - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico + - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin dev:frontend: summary: Runs the frontend in development mode @@ -77,9 +78,7 @@ tasks: deps: - task: install:frontend:deps cmds: - - npm run dev -- --port {{.VITE_PORT}} - vars: - VITE_PORT: '{{.VITE_PORT | default "5173"}}' + - npm run dev -- --port {{.VITE_PORT}} --strictPort update:build-assets: summary: Updates the build assets diff --git a/build/android/Taskfile.yml b/build/android/Taskfile.yml new file mode 100644 index 0000000..aca62e4 --- /dev/null +++ b/build/android/Taskfile.yml @@ -0,0 +1,237 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +vars: + APP_ID: '{{.APP_ID | default "com.wails.app"}}' + MIN_SDK: '21' + TARGET_SDK: '34' + NDK_VERSION: 'r26d' + +tasks: + install:deps: + summary: Check and install Android development dependencies + cmds: + - go run build/android/scripts/deps/install_deps.go + env: + TASK_FORCE_YES: '{{if .YES}}true{{else}}false{{end}}' + prompt: This will check and install Android development dependencies. Continue? + + build: + summary: Creates a build of the application for Android + deps: + - task: common:go:mod:tidy + - task: generate:android:bindings + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + PRODUCTION: + ref: .PRODUCTION + - task: common:generate:icons + cmds: + - echo "Building Android app {{.APP_NAME}}..." + - task: compile:go:shared + vars: + ARCH: '{{.ARCH | default "arm64"}}' + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,android -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags android,debug -buildvcs=false -gcflags=all="-l"{{end}}' + env: + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + compile:go:shared: + summary: Compile Go code to shared library (.so) + cmds: + - | + NDK_ROOT="${ANDROID_NDK_HOME:-$ANDROID_HOME/ndk/{{.NDK_VERSION}}}" + if [ ! -d "$NDK_ROOT" ]; then + echo "Error: Android NDK not found at $NDK_ROOT" + echo "Please set ANDROID_NDK_HOME or install NDK {{.NDK_VERSION}} via Android Studio" + exit 1 + fi + + # Determine toolchain based on host OS + case "$(uname -s)" in + Darwin) HOST_TAG="darwin-x86_64" ;; + Linux) HOST_TAG="linux-x86_64" ;; + *) echo "Unsupported host OS"; exit 1 ;; + esac + + TOOLCHAIN="$NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAG" + + # Set compiler based on architecture + case "{{.ARCH}}" in + arm64) + export CC="$TOOLCHAIN/bin/aarch64-linux-android{{.MIN_SDK}}-clang" + export CXX="$TOOLCHAIN/bin/aarch64-linux-android{{.MIN_SDK}}-clang++" + export GOARCH=arm64 + JNI_DIR="arm64-v8a" + ;; + amd64|x86_64) + export CC="$TOOLCHAIN/bin/x86_64-linux-android{{.MIN_SDK}}-clang" + export CXX="$TOOLCHAIN/bin/x86_64-linux-android{{.MIN_SDK}}-clang++" + export GOARCH=amd64 + JNI_DIR="x86_64" + ;; + *) + echo "Unsupported architecture: {{.ARCH}}" + exit 1 + ;; + esac + + export CGO_ENABLED=1 + export GOOS=android + + mkdir -p {{.BIN_DIR}} + mkdir -p build/android/app/src/main/jniLibs/$JNI_DIR + + go build -buildmode=c-shared {{.BUILD_FLAGS}} \ + -o build/android/app/src/main/jniLibs/$JNI_DIR/libwails.so + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,android -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags android,debug -buildvcs=false -gcflags=all="-l"{{end}}' + + compile:go:all-archs: + summary: Compile Go code for all Android architectures (fat APK) + cmds: + - task: compile:go:shared + vars: + ARCH: arm64 + - task: compile:go:shared + vars: + ARCH: amd64 + + package: + summary: Packages a production build of the application into an APK + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: assemble:apk + + package:fat: + summary: Packages a production build for all architectures (fat APK) + cmds: + - task: compile:go:all-archs + - task: assemble:apk + + assemble:apk: + summary: Assembles the APK using Gradle + cmds: + - | + cd build/android + ./gradlew assembleDebug + cp app/build/outputs/apk/debug/app-debug.apk "../../{{.BIN_DIR}}/{{.APP_NAME}}.apk" + echo "APK created: {{.BIN_DIR}}/{{.APP_NAME}}.apk" + + assemble:apk:release: + summary: Assembles a release APK using Gradle + cmds: + - | + cd build/android + ./gradlew assembleRelease + cp app/build/outputs/apk/release/app-release-unsigned.apk "../../{{.BIN_DIR}}/{{.APP_NAME}}-release.apk" + echo "Release APK created: {{.BIN_DIR}}/{{.APP_NAME}}-release.apk" + + generate:android:bindings: + internal: true + summary: Generates bindings for Android + sources: + - "**/*.go" + - go.mod + - go.sum + generates: + - frontend/bindings/**/* + cmds: + - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true + env: + GOOS: android + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default "arm64"}}' + + ensure-emulator: + internal: true + summary: Ensure Android Emulator is running + silent: true + cmds: + - | + # Check if an emulator is already running + if adb devices | grep -q "emulator"; then + echo "Emulator already running" + exit 0 + fi + + # Get first available AVD + AVD_NAME=$(emulator -list-avds | head -1) + if [ -z "$AVD_NAME" ]; then + echo "No Android Virtual Devices found." + echo "Create one using: Android Studio > Tools > Device Manager" + exit 1 + fi + + echo "Starting emulator: $AVD_NAME" + emulator -avd "$AVD_NAME" -no-snapshot-load & + + # Wait for emulator to boot (max 60 seconds) + echo "Waiting for emulator to boot..." + adb wait-for-device + + for i in {1..60}; do + BOOT_COMPLETED=$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r') + if [ "$BOOT_COMPLETED" = "1" ]; then + echo "Emulator booted successfully" + exit 0 + fi + sleep 1 + done + + echo "Emulator boot timeout" + exit 1 + preconditions: + - sh: command -v adb + msg: "adb not found. Please install Android SDK and add platform-tools to PATH" + - sh: command -v emulator + msg: "emulator not found. Please install Android SDK and add emulator to PATH" + + deploy-emulator: + summary: Deploy to Android Emulator + deps: [package] + cmds: + - adb uninstall {{.APP_ID}} 2>/dev/null || true + - adb install "{{.BIN_DIR}}/{{.APP_NAME}}.apk" + - adb shell am start -n {{.APP_ID}}/.MainActivity + + run: + summary: Run the application in Android Emulator + deps: + - task: ensure-emulator + - task: build + vars: + ARCH: x86_64 + cmds: + - task: assemble:apk + - adb uninstall {{.APP_ID}} 2>/dev/null || true + - adb install "{{.BIN_DIR}}/{{.APP_NAME}}.apk" + - adb shell am start -n {{.APP_ID}}/.MainActivity + + logs: + summary: Stream Android logcat filtered to this app + cmds: + - adb logcat -v time | grep -E "(Wails|{{.APP_NAME}})" + + logs:all: + summary: Stream all Android logcat (verbose) + cmds: + - adb logcat -v time + + clean: + summary: Clean build artifacts + cmds: + - rm -rf {{.BIN_DIR}} + - rm -rf build/android/app/build + - rm -rf build/android/app/src/main/jniLibs/*/libwails.so + - rm -rf build/android/.gradle diff --git a/build/android/app/build.gradle b/build/android/app/build.gradle new file mode 100644 index 0000000..78fdbf7 --- /dev/null +++ b/build/android/app/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'com.android.application' +} + +android { + namespace 'com.wails.app' + compileSdk 34 + + buildFeatures { + buildConfig = true + } + + defaultConfig { + applicationId "com.wails.app" + minSdk 21 + targetSdk 34 + versionCode 1 + versionName "1.0" + + // Configure supported ABIs + ndk { + abiFilters 'arm64-v8a', 'x86_64' + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + debuggable true + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + // Source sets configuration + sourceSets { + main { + // JNI libraries are in jniLibs folder + jniLibs.srcDirs = ['src/main/jniLibs'] + // Assets for the WebView + assets.srcDirs = ['src/main/assets'] + } + } + + // Packaging options + packagingOptions { + // Don't strip Go symbols in debug builds + doNotStrip '*/arm64-v8a/libwails.so' + doNotStrip '*/x86_64/libwails.so' + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.webkit:webkit:1.9.0' + implementation 'com.google.android.material:material:1.11.0' +} diff --git a/build/android/app/proguard-rules.pro b/build/android/app/proguard-rules.pro new file mode 100644 index 0000000..8b88c3d --- /dev/null +++ b/build/android/app/proguard-rules.pro @@ -0,0 +1,12 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. + +# Keep native methods +-keepclasseswithmembernames class * { + native ; +} + +# Keep Wails bridge classes +-keep class com.wails.app.WailsBridge { *; } +-keep class com.wails.app.WailsJSBridge { *; } diff --git a/build/android/app/src/main/AndroidManifest.xml b/build/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6c7982a --- /dev/null +++ b/build/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + diff --git a/build/android/app/src/main/java/com/wails/app/MainActivity.java b/build/android/app/src/main/java/com/wails/app/MainActivity.java new file mode 100644 index 0000000..3067fee --- /dev/null +++ b/build/android/app/src/main/java/com/wails/app/MainActivity.java @@ -0,0 +1,198 @@ +package com.wails.app; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.util.Log; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.webkit.WebViewAssetLoader; +import com.wails.app.BuildConfig; + +/** + * MainActivity hosts the WebView and manages the Wails application lifecycle. + * It uses WebViewAssetLoader to serve assets from the Go library without + * requiring a network server. + */ +public class MainActivity extends AppCompatActivity { + private static final String TAG = "WailsActivity"; + private static final String WAILS_SCHEME = "https"; + private static final String WAILS_HOST = "wails.localhost"; + + private WebView webView; + private WailsBridge bridge; + private WebViewAssetLoader assetLoader; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Initialize the native Go library + bridge = new WailsBridge(this); + bridge.initialize(); + + // Set up WebView + setupWebView(); + + // Load the application + loadApplication(); + } + + @SuppressLint("SetJavaScriptEnabled") + private void setupWebView() { + webView = findViewById(R.id.webview); + + // Configure WebView settings + WebSettings settings = webView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setDomStorageEnabled(true); + settings.setDatabaseEnabled(true); + settings.setAllowFileAccess(false); + settings.setAllowContentAccess(false); + settings.setMediaPlaybackRequiresUserGesture(false); + settings.setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW); + + // Enable debugging in debug builds + if (BuildConfig.DEBUG) { + WebView.setWebContentsDebuggingEnabled(true); + } + + // Set up asset loader for serving local assets + assetLoader = new WebViewAssetLoader.Builder() + .setDomain(WAILS_HOST) + .addPathHandler("/", new WailsPathHandler(bridge)) + .build(); + + // Set up WebView client to intercept requests + webView.setWebViewClient(new WebViewClient() { + @Nullable + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + String url = request.getUrl().toString(); + Log.d(TAG, "Intercepting request: " + url); + + // Handle wails.localhost requests + if (request.getUrl().getHost() != null && + request.getUrl().getHost().equals(WAILS_HOST)) { + + // For wails API calls (runtime, capabilities, etc.), we need to pass the full URL + // including query string because WebViewAssetLoader.PathHandler strips query params + String path = request.getUrl().getPath(); + if (path != null && path.startsWith("/wails/")) { + // Get full path with query string for runtime calls + String fullPath = path; + String query = request.getUrl().getQuery(); + if (query != null && !query.isEmpty()) { + fullPath = path + "?" + query; + } + Log.d(TAG, "Wails API call detected, full path: " + fullPath); + + // Call bridge directly with full path + byte[] data = bridge.serveAsset(fullPath, request.getMethod(), "{}"); + if (data != null && data.length > 0) { + java.io.InputStream inputStream = new java.io.ByteArrayInputStream(data); + java.util.Map headers = new java.util.HashMap<>(); + headers.put("Access-Control-Allow-Origin", "*"); + headers.put("Cache-Control", "no-cache"); + headers.put("Content-Type", "application/json"); + + return new WebResourceResponse( + "application/json", + "UTF-8", + 200, + "OK", + headers, + inputStream + ); + } + // Return error response if data is null + return new WebResourceResponse( + "application/json", + "UTF-8", + 500, + "Internal Error", + new java.util.HashMap<>(), + new java.io.ByteArrayInputStream("{}".getBytes()) + ); + } + + // For regular assets, use the asset loader + return assetLoader.shouldInterceptRequest(request.getUrl()); + } + + return super.shouldInterceptRequest(view, request); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + Log.d(TAG, "Page loaded: " + url); + // Inject Wails runtime + bridge.injectRuntime(webView, url); + } + }); + + // Add JavaScript interface for Go communication + webView.addJavascriptInterface(new WailsJSBridge(bridge, webView), "wails"); + } + + private void loadApplication() { + // Load the main page from the asset server + String url = WAILS_SCHEME + "://" + WAILS_HOST + "/"; + Log.d(TAG, "Loading URL: " + url); + webView.loadUrl(url); + } + + /** + * Execute JavaScript in the WebView from the Go side + */ + public void executeJavaScript(final String js) { + runOnUiThread(() -> { + if (webView != null) { + webView.evaluateJavascript(js, null); + } + }); + } + + @Override + protected void onResume() { + super.onResume(); + if (bridge != null) { + bridge.onResume(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (bridge != null) { + bridge.onPause(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (bridge != null) { + bridge.shutdown(); + } + if (webView != null) { + webView.destroy(); + } + } + + @Override + public void onBackPressed() { + if (webView != null && webView.canGoBack()) { + webView.goBack(); + } else { + super.onBackPressed(); + } + } +} diff --git a/build/android/app/src/main/java/com/wails/app/WailsBridge.java b/build/android/app/src/main/java/com/wails/app/WailsBridge.java new file mode 100644 index 0000000..3dab652 --- /dev/null +++ b/build/android/app/src/main/java/com/wails/app/WailsBridge.java @@ -0,0 +1,214 @@ +package com.wails.app; + +import android.content.Context; +import android.util.Log; +import android.webkit.WebView; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * WailsBridge manages the connection between the Java/Android side and the Go native library. + * It handles: + * - Loading and initializing the native Go library + * - Serving asset requests from Go + * - Passing messages between JavaScript and Go + * - Managing callbacks for async operations + */ +public class WailsBridge { + private static final String TAG = "WailsBridge"; + + static { + // Load the native Go library + System.loadLibrary("wails"); + } + + private final Context context; + private final AtomicInteger callbackIdGenerator = new AtomicInteger(0); + private final ConcurrentHashMap pendingAssetCallbacks = new ConcurrentHashMap<>(); + private final ConcurrentHashMap pendingMessageCallbacks = new ConcurrentHashMap<>(); + private WebView webView; + private volatile boolean initialized = false; + + // Native methods - implemented in Go + private static native void nativeInit(WailsBridge bridge); + private static native void nativeShutdown(); + private static native void nativeOnResume(); + private static native void nativeOnPause(); + private static native void nativeOnPageFinished(String url); + private static native byte[] nativeServeAsset(String path, String method, String headers); + private static native String nativeHandleMessage(String message); + private static native String nativeGetAssetMimeType(String path); + + public WailsBridge(Context context) { + this.context = context; + } + + /** + * Initialize the native Go library + */ + public void initialize() { + if (initialized) { + return; + } + + Log.i(TAG, "Initializing Wails bridge..."); + try { + nativeInit(this); + initialized = true; + Log.i(TAG, "Wails bridge initialized successfully"); + } catch (Exception e) { + Log.e(TAG, "Failed to initialize Wails bridge", e); + } + } + + /** + * Shutdown the native Go library + */ + public void shutdown() { + if (!initialized) { + return; + } + + Log.i(TAG, "Shutting down Wails bridge..."); + try { + nativeShutdown(); + initialized = false; + } catch (Exception e) { + Log.e(TAG, "Error during shutdown", e); + } + } + + /** + * Called when the activity resumes + */ + public void onResume() { + if (initialized) { + nativeOnResume(); + } + } + + /** + * Called when the activity pauses + */ + public void onPause() { + if (initialized) { + nativeOnPause(); + } + } + + /** + * Serve an asset from the Go asset server + * @param path The URL path requested + * @param method The HTTP method + * @param headers The request headers as JSON + * @return The asset data, or null if not found + */ + public byte[] serveAsset(String path, String method, String headers) { + if (!initialized) { + Log.w(TAG, "Bridge not initialized, cannot serve asset: " + path); + return null; + } + + Log.d(TAG, "Serving asset: " + path); + try { + return nativeServeAsset(path, method, headers); + } catch (Exception e) { + Log.e(TAG, "Error serving asset: " + path, e); + return null; + } + } + + /** + * Get the MIME type for an asset + * @param path The asset path + * @return The MIME type string + */ + public String getAssetMimeType(String path) { + if (!initialized) { + return "application/octet-stream"; + } + + try { + String mimeType = nativeGetAssetMimeType(path); + return mimeType != null ? mimeType : "application/octet-stream"; + } catch (Exception e) { + Log.e(TAG, "Error getting MIME type for: " + path, e); + return "application/octet-stream"; + } + } + + /** + * Handle a message from JavaScript + * @param message The message from JavaScript (JSON) + * @return The response to send back to JavaScript (JSON) + */ + public String handleMessage(String message) { + if (!initialized) { + Log.w(TAG, "Bridge not initialized, cannot handle message"); + return "{\"error\":\"Bridge not initialized\"}"; + } + + Log.d(TAG, "Handling message from JS: " + message); + try { + return nativeHandleMessage(message); + } catch (Exception e) { + Log.e(TAG, "Error handling message", e); + return "{\"error\":\"" + e.getMessage() + "\"}"; + } + } + + /** + * Inject the Wails runtime JavaScript into the WebView. + * Called when the page finishes loading. + * @param webView The WebView to inject into + * @param url The URL that finished loading + */ + public void injectRuntime(WebView webView, String url) { + this.webView = webView; + // Notify Go side that page has finished loading so it can inject the runtime + Log.d(TAG, "Page finished loading: " + url + ", notifying Go side"); + if (initialized) { + nativeOnPageFinished(url); + } + } + + /** + * Execute JavaScript in the WebView (called from Go side) + * @param js The JavaScript code to execute + */ + public void executeJavaScript(String js) { + if (webView != null) { + webView.post(() -> webView.evaluateJavascript(js, null)); + } + } + + /** + * Called from Go when an event needs to be emitted to JavaScript + * @param eventName The event name + * @param eventData The event data (JSON) + */ + public void emitEvent(String eventName, String eventData) { + String js = String.format("window.wails && window.wails._emit('%s', %s);", + escapeJsString(eventName), eventData); + executeJavaScript(js); + } + + private String escapeJsString(String str) { + return str.replace("\\", "\\\\") + .replace("'", "\\'") + .replace("\n", "\\n") + .replace("\r", "\\r"); + } + + // Callback interfaces + public interface AssetCallback { + void onAssetReady(byte[] data, String mimeType); + void onAssetError(String error); + } + + public interface MessageCallback { + void onResponse(String response); + void onError(String error); + } +} diff --git a/build/android/app/src/main/java/com/wails/app/WailsJSBridge.java b/build/android/app/src/main/java/com/wails/app/WailsJSBridge.java new file mode 100644 index 0000000..98ae5b2 --- /dev/null +++ b/build/android/app/src/main/java/com/wails/app/WailsJSBridge.java @@ -0,0 +1,142 @@ +package com.wails.app; + +import android.util.Log; +import android.webkit.JavascriptInterface; +import android.webkit.WebView; +import com.wails.app.BuildConfig; + +/** + * WailsJSBridge provides the JavaScript interface that allows the web frontend + * to communicate with the Go backend. This is exposed to JavaScript as the + * `window.wails` object. + * + * Similar to iOS's WKScriptMessageHandler but using Android's addJavascriptInterface. + */ +public class WailsJSBridge { + private static final String TAG = "WailsJSBridge"; + + private final WailsBridge bridge; + private final WebView webView; + + public WailsJSBridge(WailsBridge bridge, WebView webView) { + this.bridge = bridge; + this.webView = webView; + } + + /** + * Send a message to Go and return the response synchronously. + * Called from JavaScript: wails.invoke(message) + * + * @param message The message to send (JSON string) + * @return The response from Go (JSON string) + */ + @JavascriptInterface + public String invoke(String message) { + Log.d(TAG, "Invoke called: " + message); + return bridge.handleMessage(message); + } + + /** + * Send a message to Go asynchronously. + * The response will be sent back via a callback. + * Called from JavaScript: wails.invokeAsync(callbackId, message) + * + * @param callbackId The callback ID to use for the response + * @param message The message to send (JSON string) + */ + @JavascriptInterface + public void invokeAsync(final String callbackId, final String message) { + Log.d(TAG, "InvokeAsync called: " + message); + + // Handle in background thread to not block JavaScript + new Thread(() -> { + try { + String response = bridge.handleMessage(message); + sendCallback(callbackId, response, null); + } catch (Exception e) { + Log.e(TAG, "Error in async invoke", e); + sendCallback(callbackId, null, e.getMessage()); + } + }).start(); + } + + /** + * Log a message from JavaScript to Android's logcat + * Called from JavaScript: wails.log(level, message) + * + * @param level The log level (debug, info, warn, error) + * @param message The message to log + */ + @JavascriptInterface + public void log(String level, String message) { + switch (level.toLowerCase()) { + case "debug": + Log.d(TAG + "/JS", message); + break; + case "info": + Log.i(TAG + "/JS", message); + break; + case "warn": + Log.w(TAG + "/JS", message); + break; + case "error": + Log.e(TAG + "/JS", message); + break; + default: + Log.v(TAG + "/JS", message); + break; + } + } + + /** + * Get the platform name + * Called from JavaScript: wails.platform() + * + * @return "android" + */ + @JavascriptInterface + public String platform() { + return "android"; + } + + /** + * Check if we're running in debug mode + * Called from JavaScript: wails.isDebug() + * + * @return true if debug build, false otherwise + */ + @JavascriptInterface + public boolean isDebug() { + return BuildConfig.DEBUG; + } + + /** + * Send a callback response to JavaScript + */ + private void sendCallback(String callbackId, String result, String error) { + final String js; + if (error != null) { + js = String.format( + "window.wails && window.wails._callback('%s', null, '%s');", + escapeJsString(callbackId), + escapeJsString(error) + ); + } else { + js = String.format( + "window.wails && window.wails._callback('%s', %s, null);", + escapeJsString(callbackId), + result != null ? result : "null" + ); + } + + webView.post(() -> webView.evaluateJavascript(js, null)); + } + + private String escapeJsString(String str) { + if (str == null) return ""; + return str.replace("\\", "\\\\") + .replace("'", "\\'") + .replace("\n", "\\n") + .replace("\r", "\\r"); + } +} diff --git a/build/android/app/src/main/java/com/wails/app/WailsPathHandler.java b/build/android/app/src/main/java/com/wails/app/WailsPathHandler.java new file mode 100644 index 0000000..326fa9b --- /dev/null +++ b/build/android/app/src/main/java/com/wails/app/WailsPathHandler.java @@ -0,0 +1,118 @@ +package com.wails.app; + +import android.net.Uri; +import android.util.Log; +import android.webkit.WebResourceResponse; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.webkit.WebViewAssetLoader; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * WailsPathHandler implements WebViewAssetLoader.PathHandler to serve assets + * from the Go asset server. This allows the WebView to load assets without + * using a network server, similar to iOS's WKURLSchemeHandler. + */ +public class WailsPathHandler implements WebViewAssetLoader.PathHandler { + private static final String TAG = "WailsPathHandler"; + + private final WailsBridge bridge; + + public WailsPathHandler(WailsBridge bridge) { + this.bridge = bridge; + } + + @Nullable + @Override + public WebResourceResponse handle(@NonNull String path) { + Log.d(TAG, "Handling path: " + path); + + // Normalize path + if (path.isEmpty() || path.equals("/")) { + path = "/index.html"; + } + + // Get asset from Go + byte[] data = bridge.serveAsset(path, "GET", "{}"); + + if (data == null || data.length == 0) { + Log.w(TAG, "Asset not found: " + path); + return null; // Return null to let WebView handle 404 + } + + // Determine MIME type + String mimeType = bridge.getAssetMimeType(path); + Log.d(TAG, "Serving " + path + " with type " + mimeType + " (" + data.length + " bytes)"); + + // Create response + InputStream inputStream = new ByteArrayInputStream(data); + Map headers = new HashMap<>(); + headers.put("Access-Control-Allow-Origin", "*"); + headers.put("Cache-Control", "no-cache"); + + return new WebResourceResponse( + mimeType, + "UTF-8", + 200, + "OK", + headers, + inputStream + ); + } + + /** + * Determine MIME type from file extension + */ + private String getMimeType(String path) { + String lowerPath = path.toLowerCase(); + + if (lowerPath.endsWith(".html") || lowerPath.endsWith(".htm")) { + return "text/html"; + } else if (lowerPath.endsWith(".js") || lowerPath.endsWith(".mjs")) { + return "application/javascript"; + } else if (lowerPath.endsWith(".css")) { + return "text/css"; + } else if (lowerPath.endsWith(".json")) { + return "application/json"; + } else if (lowerPath.endsWith(".png")) { + return "image/png"; + } else if (lowerPath.endsWith(".jpg") || lowerPath.endsWith(".jpeg")) { + return "image/jpeg"; + } else if (lowerPath.endsWith(".gif")) { + return "image/gif"; + } else if (lowerPath.endsWith(".svg")) { + return "image/svg+xml"; + } else if (lowerPath.endsWith(".ico")) { + return "image/x-icon"; + } else if (lowerPath.endsWith(".woff")) { + return "font/woff"; + } else if (lowerPath.endsWith(".woff2")) { + return "font/woff2"; + } else if (lowerPath.endsWith(".ttf")) { + return "font/ttf"; + } else if (lowerPath.endsWith(".eot")) { + return "application/vnd.ms-fontobject"; + } else if (lowerPath.endsWith(".xml")) { + return "application/xml"; + } else if (lowerPath.endsWith(".txt")) { + return "text/plain"; + } else if (lowerPath.endsWith(".wasm")) { + return "application/wasm"; + } else if (lowerPath.endsWith(".mp3")) { + return "audio/mpeg"; + } else if (lowerPath.endsWith(".mp4")) { + return "video/mp4"; + } else if (lowerPath.endsWith(".webm")) { + return "video/webm"; + } else if (lowerPath.endsWith(".webp")) { + return "image/webp"; + } + + return "application/octet-stream"; + } +} diff --git a/build/android/app/src/main/res/layout/activity_main.xml b/build/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..f278384 --- /dev/null +++ b/build/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/build/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..9409abe Binary files /dev/null and b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/build/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..9409abe Binary files /dev/null and b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/build/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..5b6acc0 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/build/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..5b6acc0 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..1c2c664 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..1c2c664 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..be557d8 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..be557d8 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4507f32 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..4507f32 Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/build/android/app/src/main/res/values/colors.xml b/build/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..dd33f3b --- /dev/null +++ b/build/android/app/src/main/res/values/colors.xml @@ -0,0 +1,8 @@ + + + #3574D4 + #2C5FB8 + #1B2636 + #FFFFFFFF + #FF000000 + diff --git a/build/android/app/src/main/res/values/strings.xml b/build/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..3ed9e47 --- /dev/null +++ b/build/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Wails App + diff --git a/build/android/app/src/main/res/values/themes.xml b/build/android/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..be8a282 --- /dev/null +++ b/build/android/app/src/main/res/values/themes.xml @@ -0,0 +1,14 @@ + + + + diff --git a/build/android/build.gradle b/build/android/build.gradle new file mode 100644 index 0000000..d7fbab3 --- /dev/null +++ b/build/android/build.gradle @@ -0,0 +1,4 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '8.7.3' apply false +} diff --git a/build/android/gradle.properties b/build/android/gradle.properties new file mode 100644 index 0000000..b9d4426 --- /dev/null +++ b/build/android/gradle.properties @@ -0,0 +1,26 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/build/optimize-your-build#parallel +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true diff --git a/build/android/gradle/wrapper/gradle-wrapper.jar b/build/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f8e1ee3 Binary files /dev/null and b/build/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/build/android/gradle/wrapper/gradle-wrapper.properties b/build/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..23449a2 --- /dev/null +++ b/build/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/build/android/gradlew b/build/android/gradlew new file mode 100644 index 0000000..adff685 --- /dev/null +++ b/build/android/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/build/android/gradlew.bat b/build/android/gradlew.bat new file mode 100644 index 0000000..c4bdd3a --- /dev/null +++ b/build/android/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/build/android/main_android.go b/build/android/main_android.go new file mode 100644 index 0000000..70a7164 --- /dev/null +++ b/build/android/main_android.go @@ -0,0 +1,11 @@ +//go:build android + +package main + +import "github.com/wailsapp/wails/v3/pkg/application" + +func init() { + // Register main function to be called when the Android app initializes + // This is necessary because in c-shared build mode, main() is not automatically called + application.RegisterAndroidMain(main) +} diff --git a/build/android/scripts/deps/install_deps.go b/build/android/scripts/deps/install_deps.go new file mode 100644 index 0000000..d9dfedf --- /dev/null +++ b/build/android/scripts/deps/install_deps.go @@ -0,0 +1,151 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" +) + +func main() { + fmt.Println("Checking Android development dependencies...") + fmt.Println() + + errors := []string{} + + // Check Go + if !checkCommand("go", "version") { + errors = append(errors, "Go is not installed. Install from https://go.dev/dl/") + } else { + fmt.Println("✓ Go is installed") + } + + // Check ANDROID_HOME + androidHome := os.Getenv("ANDROID_HOME") + if androidHome == "" { + androidHome = os.Getenv("ANDROID_SDK_ROOT") + } + if androidHome == "" { + // Try common default locations + home, _ := os.UserHomeDir() + possiblePaths := []string{ + filepath.Join(home, "Android", "Sdk"), + filepath.Join(home, "Library", "Android", "sdk"), + "/usr/local/share/android-sdk", + } + for _, p := range possiblePaths { + if _, err := os.Stat(p); err == nil { + androidHome = p + break + } + } + } + + if androidHome == "" { + errors = append(errors, "ANDROID_HOME not set. Install Android Studio and set ANDROID_HOME environment variable") + } else { + fmt.Printf("✓ ANDROID_HOME: %s\n", androidHome) + } + + // Check adb + if !checkCommand("adb", "version") { + if androidHome != "" { + platformTools := filepath.Join(androidHome, "platform-tools") + errors = append(errors, fmt.Sprintf("adb not found. Add %s to PATH", platformTools)) + } else { + errors = append(errors, "adb not found. Install Android SDK Platform-Tools") + } + } else { + fmt.Println("✓ adb is installed") + } + + // Check emulator + if !checkCommand("emulator", "-list-avds") { + if androidHome != "" { + emulatorPath := filepath.Join(androidHome, "emulator") + errors = append(errors, fmt.Sprintf("emulator not found. Add %s to PATH", emulatorPath)) + } else { + errors = append(errors, "emulator not found. Install Android Emulator via SDK Manager") + } + } else { + fmt.Println("✓ Android Emulator is installed") + } + + // Check NDK + ndkHome := os.Getenv("ANDROID_NDK_HOME") + if ndkHome == "" && androidHome != "" { + // Look for NDK in default location + ndkDir := filepath.Join(androidHome, "ndk") + if entries, err := os.ReadDir(ndkDir); err == nil { + for _, entry := range entries { + if entry.IsDir() { + ndkHome = filepath.Join(ndkDir, entry.Name()) + break + } + } + } + } + + if ndkHome == "" { + errors = append(errors, "Android NDK not found. Install NDK via Android Studio > SDK Manager > SDK Tools > NDK (Side by side)") + } else { + fmt.Printf("✓ Android NDK: %s\n", ndkHome) + } + + // Check Java + if !checkCommand("java", "-version") { + errors = append(errors, "Java not found. Install JDK 11+ (OpenJDK recommended)") + } else { + fmt.Println("✓ Java is installed") + } + + // Check for AVD (Android Virtual Device) + if checkCommand("emulator", "-list-avds") { + cmd := exec.Command("emulator", "-list-avds") + output, err := cmd.Output() + if err == nil && len(strings.TrimSpace(string(output))) > 0 { + avds := strings.Split(strings.TrimSpace(string(output)), "\n") + fmt.Printf("✓ Found %d Android Virtual Device(s)\n", len(avds)) + } else { + fmt.Println("⚠ No Android Virtual Devices found. Create one via Android Studio > Tools > Device Manager") + } + } + + fmt.Println() + + if len(errors) > 0 { + fmt.Println("❌ Missing dependencies:") + for _, err := range errors { + fmt.Printf(" - %s\n", err) + } + fmt.Println() + fmt.Println("Setup instructions:") + fmt.Println("1. Install Android Studio: https://developer.android.com/studio") + fmt.Println("2. Open SDK Manager and install:") + fmt.Println(" - Android SDK Platform (API 34)") + fmt.Println(" - Android SDK Build-Tools") + fmt.Println(" - Android SDK Platform-Tools") + fmt.Println(" - Android Emulator") + fmt.Println(" - NDK (Side by side)") + fmt.Println("3. Set environment variables:") + if runtime.GOOS == "darwin" { + fmt.Println(" export ANDROID_HOME=$HOME/Library/Android/sdk") + } else { + fmt.Println(" export ANDROID_HOME=$HOME/Android/Sdk") + } + fmt.Println(" export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator") + fmt.Println("4. Create an AVD via Android Studio > Tools > Device Manager") + os.Exit(1) + } + + fmt.Println("✓ All Android development dependencies are installed!") +} + +func checkCommand(name string, args ...string) bool { + cmd := exec.Command(name, args...) + cmd.Stdout = nil + cmd.Stderr = nil + return cmd.Run() == nil +} diff --git a/build/android/settings.gradle b/build/android/settings.gradle new file mode 100644 index 0000000..a3f3ec3 --- /dev/null +++ b/build/android/settings.gradle @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "WailsApp" +include ':app' diff --git a/build/appicon.icon/Assets/wails_icon_vector.svg b/build/appicon.icon/Assets/wails_icon_vector.svg new file mode 100644 index 0000000..b099222 --- /dev/null +++ b/build/appicon.icon/Assets/wails_icon_vector.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/build/appicon.icon/icon.json b/build/appicon.icon/icon.json new file mode 100644 index 0000000..ecf1849 --- /dev/null +++ b/build/appicon.icon/icon.json @@ -0,0 +1,51 @@ +{ + "fill" : { + "automatic-gradient" : "extended-gray:1.00000,1.00000" + }, + "groups" : [ + { + "layers" : [ + { + "fill-specializations" : [ + { + "appearance" : "dark", + "value" : { + "solid" : "srgb:0.92143,0.92145,0.92144,1.00000" + } + }, + { + "appearance" : "tinted", + "value" : { + "solid" : "srgb:0.83742,0.83744,0.83743,1.00000" + } + } + ], + "image-name" : "wails_icon_vector.svg", + "name" : "wails_icon_vector", + "position" : { + "scale" : 1.25, + "translation-in-points" : [ + 36.890625, + 4.96875 + ] + } + } + ], + "shadow" : { + "kind" : "neutral", + "opacity" : 0.5 + }, + "specular" : true, + "translucency" : { + "enabled" : true, + "value" : 0.5 + } + } + ], + "supported-platforms" : { + "circles" : [ + "watchOS" + ], + "squares" : "shared" + } +} \ No newline at end of file diff --git a/build/config.yml b/build/config.yml index b803219..accd08b 100644 --- a/build/config.yml +++ b/build/config.yml @@ -30,15 +30,15 @@ dev_mode: - .gitkeep watched_extension: - "*.go" + - "*.js" + - "*.ts" git_ignore: true executes: - cmd: wails3 task common:install:frontend:deps type: once - cmd: wails3 task common:dev:frontend type: background - - cmd: go mod tidy - type: blocking - - cmd: wails3 task build + - cmd: wails3 build DEV=true type: blocking - cmd: wails3 task run type: primary diff --git a/build/darwin/Taskfile.yml b/build/darwin/Taskfile.yml index 47d6a4a..e4a2d03 100644 --- a/build/darwin/Taskfile.yml +++ b/build/darwin/Taskfile.yml @@ -3,22 +3,45 @@ version: '3' includes: common: ../Taskfile.yml +vars: + # Signing configuration - edit these values for your project + # SIGN_IDENTITY: "Developer ID Application: Your Company (TEAMID)" + # KEYCHAIN_PROFILE: "my-notarize-profile" + # ENTITLEMENTS: "build/darwin/entitlements.plist" + + # Docker image for cross-compilation (used when building on non-macOS) + CROSS_IMAGE: wails-cross + tasks: build: - summary: Creates a production build of the application + summary: Builds the application + cmds: + - task: '{{if eq OS "darwin"}}build:native{{else}}build:docker{{end}}' + vars: + ARCH: '{{.ARCH}}' + DEV: '{{.DEV}}' + OUTPUT: '{{.OUTPUT}}' + EXTRA_TAGS: '{{.EXTRA_TAGS}}' + vars: + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + + build:native: + summary: Builds the application natively on macOS + internal: true deps: - task: common:go:mod:tidy - task: common:build:frontend vars: BUILD_FLAGS: ref: .BUILD_FLAGS - PRODUCTION: - ref: .PRODUCTION + DEV: + ref: .DEV - task: common:generate:icons cmds: - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} vars: - BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}' DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' env: @@ -28,7 +51,47 @@ tasks: CGO_CFLAGS: "-mmacosx-version-min=10.15" CGO_LDFLAGS: "-mmacosx-version-min=10.15" MACOSX_DEPLOYMENT_TARGET: "10.15" - PRODUCTION: '{{.PRODUCTION | default "false"}}' + + build:docker: + summary: Cross-compiles for macOS using Docker (for Linux/Windows hosts) + internal: true + deps: + - task: common:build:frontend + - task: common:generate:icons + preconditions: + - sh: docker info > /dev/null 2>&1 + msg: "Docker is required for cross-compilation. Please install Docker." + - sh: docker image inspect {{.CROSS_IMAGE}} > /dev/null 2>&1 + msg: | + Docker image '{{.CROSS_IMAGE}}' not found. + Build it first: wails3 task setup:docker + cmds: + - docker run --rm -v "{{.ROOT_DIR}}:/app" {{.GO_CACHE_MOUNT}} {{.REPLACE_MOUNTS}} -e APP_NAME="{{.APP_NAME}}" {{if .EXTRA_TAGS}}-e EXTRA_TAGS="{{.EXTRA_TAGS}}"{{end}} {{.CROSS_IMAGE}} darwin {{.DOCKER_ARCH}} + - docker run --rm -v "{{.ROOT_DIR}}:/app" alpine chown -R $(id -u):$(id -g) /app/bin + - mkdir -p {{.BIN_DIR}} + - mv "bin/{{.APP_NAME}}-darwin-{{.DOCKER_ARCH}}" "{{.OUTPUT}}" + vars: + DOCKER_ARCH: '{{if eq .ARCH "arm64"}}arm64{{else if eq .ARCH "amd64"}}amd64{{else}}arm64{{end}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + # Mount Go module cache for faster builds + GO_CACHE_MOUNT: + sh: 'echo "-v ${GOPATH:-$HOME/go}/pkg/mod:/go/pkg/mod"' + # Extract replace directives from go.mod and create -v mounts for each + # Handles both relative (=> ../) and absolute (=> /) paths + REPLACE_MOUNTS: + sh: | + grep -E '^replace .* => ' go.mod 2>/dev/null | while read -r line; do + path=$(echo "$line" | sed -E 's/^replace .* => //' | tr -d '\r') + # Convert relative paths to absolute + if [ "${path#/}" = "$path" ]; then + path="$(cd "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")" + fi + # Only mount if directory exists + if [ -d "$path" ]; then + echo "-v $path:$path:ro" + fi + done | tr '\n' ' ' build:universal: summary: Builds darwin universal binary (arm64 + amd64) @@ -37,22 +100,31 @@ tasks: vars: ARCH: amd64 OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" - PRODUCTION: '{{.PRODUCTION | default "true"}}' - task: build vars: ARCH: arm64 OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" - PRODUCTION: '{{.PRODUCTION | default "true"}}' + cmds: + - task: '{{if eq OS "darwin"}}build:universal:lipo:native{{else}}build:universal:lipo:go{{end}}' + + build:universal:lipo:native: + summary: Creates universal binary using native lipo (macOS) + internal: true cmds: - lipo -create -output "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" - rm "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + build:universal:lipo:go: + summary: Creates universal binary using wails3 tool lipo (Linux/Windows) + internal: true + cmds: + - wails3 tool lipo -output "{{.BIN_DIR}}/{{.APP_NAME}}" -input "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" -input "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + - rm -f "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + package: - summary: Packages a production build of the application into a `.app` bundle + summary: Packages the application into a `.app` bundle deps: - task: build - vars: - PRODUCTION: "true" cmds: - task: create:app:bundle @@ -67,19 +139,70 @@ tasks: create:app:bundle: summary: Creates an `.app` bundle cmds: - - mkdir -p {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/{MacOS,Resources} - - cp build/darwin/icons.icns {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources - - cp {{.BIN_DIR}}/{{.APP_NAME}} {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS - - cp build/darwin/Info.plist {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents - - codesign --force --deep --sign - {{.BIN_DIR}}/{{.APP_NAME}}.app + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS" + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources" + - cp build/darwin/icons.icns "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources" + - | + if [ -f build/darwin/Assets.car ]; then + cp build/darwin/Assets.car "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources" + fi + - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS" + - cp build/darwin/Info.plist "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents" + - task: '{{if eq OS "darwin"}}codesign:adhoc{{else}}codesign:skip{{end}}' + + codesign:adhoc: + summary: Ad-hoc signs the app bundle (macOS only) + internal: true + cmds: + - codesign --force --deep --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.app" + + codesign:skip: + summary: Skips codesigning when cross-compiling + internal: true + cmds: + - 'echo "Skipping codesign (not available on {{OS}}). Sign the .app on macOS before distribution."' run: - deps: - - task: build cmds: - - mkdir -p {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/{MacOS,Resources} - - cp build/darwin/icons.icns {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources - - cp {{.BIN_DIR}}/{{.APP_NAME}} {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS - - cp build/darwin/Info.dev.plist {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Info.plist - - codesign --force --deep --sign - {{.BIN_DIR}}/{{.APP_NAME}}.dev.app + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS" + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources" + - cp build/darwin/icons.icns "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources" + - | + if [ -f build/darwin/Assets.car ]; then + cp build/darwin/Assets.car "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources" + fi + - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS" + - cp "build/darwin/Info.dev.plist" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Info.plist" + - codesign --force --deep --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" - '{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS/{{.APP_NAME}}' + + sign: + summary: Signs the application bundle with Developer ID + desc: | + Signs the .app bundle for distribution. + Configure SIGN_IDENTITY in the vars section at the top of this file. + deps: + - task: package + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.app" --identity "{{.SIGN_IDENTITY}}" {{if .ENTITLEMENTS}}--entitlements {{.ENTITLEMENTS}}{{end}} + preconditions: + - sh: '[ -n "{{.SIGN_IDENTITY}}" ]' + msg: "SIGN_IDENTITY is required. Set it in the vars section at the top of build/darwin/Taskfile.yml" + + sign:notarize: + summary: Signs and notarizes the application bundle + desc: | + Signs the .app bundle and submits it for notarization. + Configure SIGN_IDENTITY and KEYCHAIN_PROFILE in the vars section at the top of this file. + + Setup (one-time): + wails3 signing credentials --apple-id "you@email.com" --team-id "TEAMID" --password "app-specific-password" --profile "my-profile" + deps: + - task: package + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.app" --identity "{{.SIGN_IDENTITY}}" {{if .ENTITLEMENTS}}--entitlements {{.ENTITLEMENTS}}{{end}} --notarize --keychain-profile {{.KEYCHAIN_PROFILE}} + preconditions: + - sh: '[ -n "{{.SIGN_IDENTITY}}" ]' + msg: "SIGN_IDENTITY is required. Set it in the vars section at the top of build/darwin/Taskfile.yml" + - sh: '[ -n "{{.KEYCHAIN_PROFILE}}" ]' + msg: "KEYCHAIN_PROFILE is required. Set it in the vars section at the top of build/darwin/Taskfile.yml" diff --git a/build/docker/Dockerfile.cross b/build/docker/Dockerfile.cross new file mode 100644 index 0000000..a3c01f2 --- /dev/null +++ b/build/docker/Dockerfile.cross @@ -0,0 +1,203 @@ +# Cross-compile Wails v3 apps to any platform +# +# Darwin: Zig + macOS SDK +# Linux: Native GCC when host matches target, Zig for cross-arch +# Windows: Zig + bundled mingw +# +# Usage: +# docker build -t wails-cross -f Dockerfile.cross . +# docker run --rm -v $(pwd):/app wails-cross darwin arm64 +# docker run --rm -v $(pwd):/app wails-cross darwin amd64 +# docker run --rm -v $(pwd):/app wails-cross linux amd64 +# docker run --rm -v $(pwd):/app wails-cross linux arm64 +# docker run --rm -v $(pwd):/app wails-cross windows amd64 +# docker run --rm -v $(pwd):/app wails-cross windows arm64 + +FROM golang:1.25-bookworm + +ARG TARGETARCH + +# Install base tools, GCC, and GTK/WebKit dev packages +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl xz-utils nodejs npm pkg-config gcc libc6-dev \ + libgtk-3-dev libwebkit2gtk-4.1-dev \ + libgtk-4-dev libwebkitgtk-6.0-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install Zig - automatically selects correct binary for host architecture +ARG ZIG_VERSION=0.14.0 +RUN ZIG_ARCH=$(case "${TARGETARCH}" in arm64) echo "aarch64" ;; *) echo "x86_64" ;; esac) && \ + curl -L "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-${ZIG_ARCH}-${ZIG_VERSION}.tar.xz" \ + | tar -xJ -C /opt \ + && ln -s /opt/zig-linux-${ZIG_ARCH}-${ZIG_VERSION}/zig /usr/local/bin/zig + +# Download macOS SDK (required for darwin targets) +ARG MACOS_SDK_VERSION=14.5 +RUN curl -L "https://github.com/joseluisq/macosx-sdks/releases/download/${MACOS_SDK_VERSION}/MacOSX${MACOS_SDK_VERSION}.sdk.tar.xz" \ + | tar -xJ -C /opt \ + && mv /opt/MacOSX${MACOS_SDK_VERSION}.sdk /opt/macos-sdk + +ENV MACOS_SDK_PATH=/opt/macos-sdk + +# Create Zig CC wrappers for cross-compilation targets +# Darwin and Windows use Zig; Linux uses native GCC (run with --platform for cross-arch) + +# Darwin arm64 +COPY <<'ZIGWRAP' /usr/local/bin/zcc-darwin-arm64 +#!/bin/sh +ARGS="" +SKIP_NEXT=0 +for arg in "$@"; do + if [ $SKIP_NEXT -eq 1 ]; then + SKIP_NEXT=0 + continue + fi + case "$arg" in + -target) SKIP_NEXT=1 ;; + -mmacosx-version-min=*) ;; + *) ARGS="$ARGS $arg" ;; + esac +done +exec zig cc -fno-sanitize=all -target aarch64-macos-none -isysroot /opt/macos-sdk -I/opt/macos-sdk/usr/include -L/opt/macos-sdk/usr/lib -F/opt/macos-sdk/System/Library/Frameworks -w $ARGS +ZIGWRAP +RUN chmod +x /usr/local/bin/zcc-darwin-arm64 + +# Darwin amd64 +COPY <<'ZIGWRAP' /usr/local/bin/zcc-darwin-amd64 +#!/bin/sh +ARGS="" +SKIP_NEXT=0 +for arg in "$@"; do + if [ $SKIP_NEXT -eq 1 ]; then + SKIP_NEXT=0 + continue + fi + case "$arg" in + -target) SKIP_NEXT=1 ;; + -mmacosx-version-min=*) ;; + *) ARGS="$ARGS $arg" ;; + esac +done +exec zig cc -fno-sanitize=all -target x86_64-macos-none -isysroot /opt/macos-sdk -I/opt/macos-sdk/usr/include -L/opt/macos-sdk/usr/lib -F/opt/macos-sdk/System/Library/Frameworks -w $ARGS +ZIGWRAP +RUN chmod +x /usr/local/bin/zcc-darwin-amd64 + +# Windows amd64 - uses Zig's bundled mingw +COPY <<'ZIGWRAP' /usr/local/bin/zcc-windows-amd64 +#!/bin/sh +ARGS="" +SKIP_NEXT=0 +for arg in "$@"; do + if [ $SKIP_NEXT -eq 1 ]; then + SKIP_NEXT=0 + continue + fi + case "$arg" in + -target) SKIP_NEXT=1 ;; + -Wl,*) ;; + *) ARGS="$ARGS $arg" ;; + esac +done +exec zig cc -target x86_64-windows-gnu $ARGS +ZIGWRAP +RUN chmod +x /usr/local/bin/zcc-windows-amd64 + +# Windows arm64 - uses Zig's bundled mingw +COPY <<'ZIGWRAP' /usr/local/bin/zcc-windows-arm64 +#!/bin/sh +ARGS="" +SKIP_NEXT=0 +for arg in "$@"; do + if [ $SKIP_NEXT -eq 1 ]; then + SKIP_NEXT=0 + continue + fi + case "$arg" in + -target) SKIP_NEXT=1 ;; + -Wl,*) ;; + *) ARGS="$ARGS $arg" ;; + esac +done +exec zig cc -target aarch64-windows-gnu $ARGS +ZIGWRAP +RUN chmod +x /usr/local/bin/zcc-windows-arm64 + +# Build script +COPY <<'SCRIPT' /usr/local/bin/build.sh +#!/bin/sh +set -e + +OS=${1:-darwin} +ARCH=${2:-arm64} + +case "${OS}-${ARCH}" in + darwin-arm64|darwin-aarch64) + export CC=zcc-darwin-arm64 + export GOARCH=arm64 + export GOOS=darwin + ;; + darwin-amd64|darwin-x86_64) + export CC=zcc-darwin-amd64 + export GOARCH=amd64 + export GOOS=darwin + ;; + linux-arm64|linux-aarch64) + export CC=gcc + export GOARCH=arm64 + export GOOS=linux + ;; + linux-amd64|linux-x86_64) + export CC=gcc + export GOARCH=amd64 + export GOOS=linux + ;; + windows-arm64|windows-aarch64) + export CC=zcc-windows-arm64 + export GOARCH=arm64 + export GOOS=windows + ;; + windows-amd64|windows-x86_64) + export CC=zcc-windows-amd64 + export GOARCH=amd64 + export GOOS=windows + ;; + *) + echo "Usage: " + echo " os: darwin, linux, windows" + echo " arch: amd64, arm64" + exit 1 + ;; +esac + +export CGO_ENABLED=1 +export CGO_CFLAGS="-w" + +# Build frontend if exists and not already built (host may have built it) +if [ -d "frontend" ] && [ -f "frontend/package.json" ] && [ ! -d "frontend/dist" ]; then + (cd frontend && npm install --silent && npm run build --silent) +fi + +# Build +APP=${APP_NAME:-$(basename $(pwd))} +mkdir -p bin + +EXT="" +LDFLAGS="-s -w" +if [ "$GOOS" = "windows" ]; then + EXT=".exe" + LDFLAGS="-s -w -H windowsgui" +fi + +TAGS="production" +if [ -n "$EXTRA_TAGS" ]; then + TAGS="${TAGS},${EXTRA_TAGS}" +fi + +go build -tags "$TAGS" -trimpath -buildvcs=false -ldflags="$LDFLAGS" -o bin/${APP}-${GOOS}-${GOARCH}${EXT} . +echo "Built: bin/${APP}-${GOOS}-${GOARCH}${EXT}" +SCRIPT +RUN chmod +x /usr/local/bin/build.sh + +WORKDIR /app +ENTRYPOINT ["/usr/local/bin/build.sh"] +CMD ["darwin", "arm64"] diff --git a/build/docker/Dockerfile.server b/build/docker/Dockerfile.server new file mode 100644 index 0000000..58fb64f --- /dev/null +++ b/build/docker/Dockerfile.server @@ -0,0 +1,41 @@ +# Wails Server Mode Dockerfile +# Multi-stage build for minimal image size + +# Build stage +FROM golang:alpine AS builder + +WORKDIR /app + +# Install build dependencies +RUN apk add --no-cache git + +# Copy source code +COPY . . + +# Remove local replace directive if present (for production builds) +RUN sed -i '/^replace/d' go.mod || true + +# Download dependencies +RUN go mod tidy + +# Build the server binary +RUN go build -tags server -ldflags="-s -w" -o server . + +# Runtime stage - minimal image +FROM gcr.io/distroless/static-debian12 + +# Copy the binary +COPY --from=builder /app/server /server + +# Copy frontend assets +COPY --from=builder /app/frontend/dist /frontend/dist + +# Expose the default port +EXPOSE 8080 + +# Bind to all interfaces (required for Docker) +# Can be overridden at runtime with -e WAILS_SERVER_HOST=... +ENV WAILS_SERVER_HOST=0.0.0.0 + +# Run the server +ENTRYPOINT ["/server"] diff --git a/build/ios/Assets.xcassets b/build/ios/Assets.xcassets new file mode 100644 index 0000000..46fbb87 --- /dev/null +++ b/build/ios/Assets.xcassets @@ -0,0 +1,116 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "images" : [ + { + "filename" : "icon-20@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "icon-20@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "icon-29@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "icon-29@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "icon-40@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "icon-40@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "icon-60@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "icon-60@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "icon-20.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "icon-20@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "icon-29.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "icon-29@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "icon-40.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "icon-40@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "icon-76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "icon-76@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "icon-83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "icon-1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ] +} \ No newline at end of file diff --git a/build/ios/Info.dev.plist b/build/ios/Info.dev.plist new file mode 100644 index 0000000..f7c5532 --- /dev/null +++ b/build/ios/Info.dev.plist @@ -0,0 +1,62 @@ + + + + + CFBundleExecutable + core-ide-test + CFBundleIdentifier + com.example.coreidetest.dev + CFBundleName + My Product (Dev) + CFBundleDisplayName + My Product (Dev) + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.1.0-dev + CFBundleVersion + 0.1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 15.0 + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + + WailsDevelopmentMode + + + NSHumanReadableCopyright + © 2026, My Company + + + CFBundleGetInfoString + This is a comment + + + \ No newline at end of file diff --git a/build/ios/Info.plist b/build/ios/Info.plist new file mode 100644 index 0000000..209d3a4 --- /dev/null +++ b/build/ios/Info.plist @@ -0,0 +1,59 @@ + + + + + CFBundleExecutable + core-ide-test + CFBundleIdentifier + com.example.coreidetest + CFBundleName + My Product + CFBundleDisplayName + My Product + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.1.0 + CFBundleVersion + 0.1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 15.0 + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + + NSHumanReadableCopyright + © 2026, My Company + + + CFBundleGetInfoString + This is a comment + + + \ No newline at end of file diff --git a/build/ios/LaunchScreen.storyboard b/build/ios/LaunchScreen.storyboard new file mode 100644 index 0000000..bfd5162 --- /dev/null +++ b/build/ios/LaunchScreen.storyboard @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/ios/Taskfile.yml b/build/ios/Taskfile.yml new file mode 100644 index 0000000..8c27f08 --- /dev/null +++ b/build/ios/Taskfile.yml @@ -0,0 +1,293 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +vars: + BUNDLE_ID: '{{.BUNDLE_ID | default "com.wails.app"}}' + # SDK_PATH is computed lazily at task-level to avoid errors on non-macOS systems + # Each task that needs it defines SDK_PATH in its own vars section + +tasks: + install:deps: + summary: Check and install iOS development dependencies + cmds: + - go run build/ios/scripts/deps/install_deps.go + env: + TASK_FORCE_YES: '{{if .YES}}true{{else}}false{{end}}' + prompt: This will check and install iOS development dependencies. Continue? + + # Note: Bindings generation may show CGO warnings for iOS C imports. + # These warnings are harmless and don't affect the generated bindings, + # as the generator only needs to parse Go types, not C implementations. + build: + summary: Creates a build of the application for iOS + deps: + - task: generate:ios:overlay + - task: generate:ios:xcode + - task: common:go:mod:tidy + - task: generate:ios:bindings + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + PRODUCTION: + ref: .PRODUCTION + - task: common:generate:icons + cmds: + - echo "Building iOS app {{.APP_NAME}}..." + - go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json {{.BUILD_FLAGS}} -o {{.OUTPUT}}.a + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,ios -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags ios,debug -buildvcs=false -gcflags=all="-l"{{end}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + SDK_PATH: + sh: xcrun --sdk iphonesimulator --show-sdk-path + env: + GOOS: ios + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default "arm64"}}' + PRODUCTION: '{{.PRODUCTION | default "false"}}' + CGO_CFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0' + CGO_LDFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator' + + compile:objc: + summary: Compile Objective-C iOS wrapper + vars: + SDK_PATH: + sh: xcrun --sdk iphonesimulator --show-sdk-path + cmds: + - xcrun -sdk iphonesimulator clang -target arm64-apple-ios15.0-simulator -isysroot {{.SDK_PATH}} -framework Foundation -framework UIKit -framework WebKit -o {{.BIN_DIR}}/{{.APP_NAME}} build/ios/main.m + - codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}" + + package: + summary: Packages a production build of the application into a `.app` bundle + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: create:app:bundle + + create:app:bundle: + summary: Creates an iOS `.app` bundle + cmds: + - rm -rf "{{.BIN_DIR}}/{{.APP_NAME}}.app" + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app" + - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.app/" + - cp build/ios/Info.plist "{{.BIN_DIR}}/{{.APP_NAME}}.app/" + - | + # Compile asset catalog and embed icons in the app bundle + APP_BUNDLE="{{.BIN_DIR}}/{{.APP_NAME}}.app" + AC_IN="build/ios/xcode/main/Assets.xcassets" + if [ -d "$AC_IN" ]; then + TMP_AC=$(mktemp -d) + xcrun actool \ + --compile "$TMP_AC" \ + --app-icon AppIcon \ + --platform iphonesimulator \ + --minimum-deployment-target 15.0 \ + --product-type com.apple.product-type.application \ + --target-device iphone \ + --target-device ipad \ + --output-partial-info-plist "$APP_BUNDLE/assetcatalog_generated_info.plist" \ + "$AC_IN" + if [ -f "$TMP_AC/Assets.car" ]; then + cp -f "$TMP_AC/Assets.car" "$APP_BUNDLE/Assets.car" + fi + rm -rf "$TMP_AC" + if [ -f "$APP_BUNDLE/assetcatalog_generated_info.plist" ]; then + /usr/libexec/PlistBuddy -c "Merge $APP_BUNDLE/assetcatalog_generated_info.plist" "$APP_BUNDLE/Info.plist" || true + fi + fi + - codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.app" + + deploy-simulator: + summary: Deploy to iOS Simulator + deps: [package] + cmds: + - xcrun simctl terminate booted {{.BUNDLE_ID}} 2>/dev/null || true + - xcrun simctl uninstall booted {{.BUNDLE_ID}} 2>/dev/null || true + - xcrun simctl install booted "{{.BIN_DIR}}/{{.APP_NAME}}.app" + - xcrun simctl launch booted {{.BUNDLE_ID}} + + compile:ios: + summary: Compile the iOS executable from Go archive and main.m + deps: + - task: build + vars: + SDK_PATH: + sh: xcrun --sdk iphonesimulator --show-sdk-path + cmds: + - | + MAIN_M=build/ios/xcode/main/main.m + if [ ! -f "$MAIN_M" ]; then + MAIN_M=build/ios/main.m + fi + xcrun -sdk iphonesimulator clang \ + -target arm64-apple-ios15.0-simulator \ + -isysroot {{.SDK_PATH}} \ + -framework Foundation -framework UIKit -framework WebKit \ + -framework Security -framework CoreFoundation \ + -lresolv \ + -o "{{.BIN_DIR}}/{{.APP_NAME | lower}}" \ + "$MAIN_M" "{{.BIN_DIR}}/{{.APP_NAME}}.a" + + generate:ios:bindings: + internal: true + summary: Generates bindings for iOS with proper CGO flags + sources: + - "**/*.go" + - go.mod + - go.sum + generates: + - frontend/bindings/**/* + vars: + SDK_PATH: + sh: xcrun --sdk iphonesimulator --show-sdk-path + cmds: + - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true + env: + GOOS: ios + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default "arm64"}}' + CGO_CFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0' + CGO_LDFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator' + + ensure-simulator: + internal: true + summary: Ensure iOS Simulator is running and booted + silent: true + cmds: + - | + if ! xcrun simctl list devices booted | grep -q "Booted"; then + echo "Starting iOS Simulator..." + # Get first available iPhone device + DEVICE_ID=$(xcrun simctl list devices available | grep "iPhone" | head -1 | grep -o "[A-F0-9-]\{36\}" || true) + if [ -z "$DEVICE_ID" ]; then + echo "No iPhone simulator found. Creating one..." + RUNTIME=$(xcrun simctl list runtimes | grep iOS | tail -1 | awk '{print $NF}') + DEVICE_ID=$(xcrun simctl create "iPhone 15 Pro" "iPhone 15 Pro" "$RUNTIME") + fi + # Boot the device + echo "Booting device $DEVICE_ID..." + xcrun simctl boot "$DEVICE_ID" 2>/dev/null || true + # Open Simulator app + open -a Simulator + # Wait for boot (max 30 seconds) + for i in {1..30}; do + if xcrun simctl list devices booted | grep -q "Booted"; then + echo "Simulator booted successfully" + break + fi + sleep 1 + done + # Final check + if ! xcrun simctl list devices booted | grep -q "Booted"; then + echo "Failed to boot simulator after 30 seconds" + exit 1 + fi + fi + preconditions: + - sh: command -v xcrun + msg: "xcrun not found. Please run 'wails3 task ios:install:deps' to install iOS development dependencies" + + generate:ios:overlay: + internal: true + summary: Generate Go build overlay and iOS shim + sources: + - build/config.yml + generates: + - build/ios/xcode/overlay.json + - build/ios/xcode/gen/main_ios.gen.go + cmds: + - wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml + + generate:ios:xcode: + internal: true + summary: Generate iOS Xcode project structure and assets + sources: + - build/config.yml + - build/appicon.png + generates: + - build/ios/xcode/main/main.m + - build/ios/xcode/main/Assets.xcassets/**/* + - build/ios/xcode/project.pbxproj + cmds: + - wails3 ios xcode:gen -outdir build/ios/xcode -config build/config.yml + + run: + summary: Run the application in iOS Simulator + deps: + - task: ensure-simulator + - task: compile:ios + cmds: + - rm -rf "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" + - cp "{{.BIN_DIR}}/{{.APP_NAME | lower}}" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/{{.APP_NAME | lower}}" + - cp build/ios/Info.dev.plist "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Info.plist" + - | + # Compile asset catalog and embed icons for dev bundle + APP_BUNDLE="{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" + AC_IN="build/ios/xcode/main/Assets.xcassets" + if [ -d "$AC_IN" ]; then + TMP_AC=$(mktemp -d) + xcrun actool \ + --compile "$TMP_AC" \ + --app-icon AppIcon \ + --platform iphonesimulator \ + --minimum-deployment-target 15.0 \ + --product-type com.apple.product-type.application \ + --target-device iphone \ + --target-device ipad \ + --output-partial-info-plist "$APP_BUNDLE/assetcatalog_generated_info.plist" \ + "$AC_IN" + if [ -f "$TMP_AC/Assets.car" ]; then + cp -f "$TMP_AC/Assets.car" "$APP_BUNDLE/Assets.car" + fi + rm -rf "$TMP_AC" + if [ -f "$APP_BUNDLE/assetcatalog_generated_info.plist" ]; then + /usr/libexec/PlistBuddy -c "Merge $APP_BUNDLE/assetcatalog_generated_info.plist" "$APP_BUNDLE/Info.plist" || true + fi + fi + - codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" + - xcrun simctl terminate booted "com.wails.{{.APP_NAME | lower}}.dev" 2>/dev/null || true + - xcrun simctl uninstall booted "com.wails.{{.APP_NAME | lower}}.dev" 2>/dev/null || true + - xcrun simctl install booted "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" + - xcrun simctl launch booted "com.wails.{{.APP_NAME | lower}}.dev" + + xcode: + summary: Open the generated Xcode project for this app + cmds: + - task: generate:ios:xcode + - open build/ios/xcode/main.xcodeproj + + logs: + summary: Stream iOS Simulator logs filtered to this app + cmds: + - | + xcrun simctl spawn booted log stream \ + --level debug \ + --style compact \ + --predicate 'senderImagePath CONTAINS[c] "{{.APP_NAME | lower}}.app/" OR composedMessage CONTAINS[c] "{{.APP_NAME | lower}}" OR eventMessage CONTAINS[c] "{{.APP_NAME | lower}}" OR process == "{{.APP_NAME | lower}}" OR category CONTAINS[c] "{{.APP_NAME | lower}}"' + + logs:dev: + summary: Stream logs for the dev bundle (used by `task ios:run`) + cmds: + - | + xcrun simctl spawn booted log stream \ + --level debug \ + --style compact \ + --predicate 'senderImagePath CONTAINS[c] ".dev.app/" OR subsystem == "com.wails.{{.APP_NAME | lower}}.dev" OR process == "{{.APP_NAME | lower}}"' + + logs:wide: + summary: Wide log stream to help discover the exact process/bundle identifiers + cmds: + - | + xcrun simctl spawn booted log stream \ + --level debug \ + --style compact \ + --predicate 'senderImagePath CONTAINS[c] ".app/"' \ No newline at end of file diff --git a/build/ios/app_options_default.go b/build/ios/app_options_default.go new file mode 100644 index 0000000..04e4f1b --- /dev/null +++ b/build/ios/app_options_default.go @@ -0,0 +1,10 @@ +//go:build !ios + +package main + +import "github.com/wailsapp/wails/v3/pkg/application" + +// modifyOptionsForIOS is a no-op on non-iOS platforms +func modifyOptionsForIOS(opts *application.Options) { + // No modifications needed for non-iOS platforms +} \ No newline at end of file diff --git a/build/ios/app_options_ios.go b/build/ios/app_options_ios.go new file mode 100644 index 0000000..8f6ac31 --- /dev/null +++ b/build/ios/app_options_ios.go @@ -0,0 +1,11 @@ +//go:build ios + +package main + +import "github.com/wailsapp/wails/v3/pkg/application" + +// modifyOptionsForIOS adjusts the application options for iOS +func modifyOptionsForIOS(opts *application.Options) { + // Disable signal handlers on iOS to prevent crashes + opts.DisableDefaultSignalHandler = true +} \ No newline at end of file diff --git a/build/ios/build.sh b/build/ios/build.sh new file mode 100644 index 0000000..bf042ee --- /dev/null +++ b/build/ios/build.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +# Build configuration +APP_NAME="core-ide-test" +BUNDLE_ID="com.example.coreidetest" +VERSION="0.1.0" +BUILD_NUMBER="0.1.0" +BUILD_DIR="build/ios" +TARGET="simulator" + +echo "Building iOS app: $APP_NAME" +echo "Bundle ID: $BUNDLE_ID" +echo "Version: $VERSION ($BUILD_NUMBER)" +echo "Target: $TARGET" + +# Ensure build directory exists +mkdir -p "$BUILD_DIR" + +# Determine SDK and target architecture +if [ "$TARGET" = "simulator" ]; then + SDK="iphonesimulator" + ARCH="arm64-apple-ios15.0-simulator" +elif [ "$TARGET" = "device" ]; then + SDK="iphoneos" + ARCH="arm64-apple-ios15.0" +else + echo "Unknown target: $TARGET" + exit 1 +fi + +# Get SDK path +SDK_PATH=$(xcrun --sdk $SDK --show-sdk-path) + +# Compile the application +echo "Compiling with SDK: $SDK" +xcrun -sdk $SDK clang \ + -target $ARCH \ + -isysroot "$SDK_PATH" \ + -framework Foundation \ + -framework UIKit \ + -framework WebKit \ + -framework CoreGraphics \ + -o "$BUILD_DIR/$APP_NAME" \ + "$BUILD_DIR/main.m" + +# Create app bundle +echo "Creating app bundle..." +APP_BUNDLE="$BUILD_DIR/$APP_NAME.app" +rm -rf "$APP_BUNDLE" +mkdir -p "$APP_BUNDLE" + +# Move executable +mv "$BUILD_DIR/$APP_NAME" "$APP_BUNDLE/" + +# Copy Info.plist +cp "$BUILD_DIR/Info.plist" "$APP_BUNDLE/" + +# Sign the app +echo "Signing app..." +codesign --force --sign - "$APP_BUNDLE" + +echo "Build complete: $APP_BUNDLE" + +# Deploy to simulator if requested +if [ "$TARGET" = "simulator" ]; then + echo "Deploying to simulator..." + xcrun simctl terminate booted "$BUNDLE_ID" 2>/dev/null || true + xcrun simctl install booted "$APP_BUNDLE" + xcrun simctl launch booted "$BUNDLE_ID" + echo "App launched on simulator" +fi \ No newline at end of file diff --git a/build/ios/entitlements.plist b/build/ios/entitlements.plist new file mode 100644 index 0000000..cc5d958 --- /dev/null +++ b/build/ios/entitlements.plist @@ -0,0 +1,21 @@ + + + + + + get-task-allow + + + + com.apple.security.app-sandbox + + + + com.apple.security.network.client + + + + com.apple.security.files.user-selected.read-only + + + \ No newline at end of file diff --git a/build/ios/icon.png b/build/ios/icon.png new file mode 100644 index 0000000..be7d591 --- /dev/null +++ b/build/ios/icon.png @@ -0,0 +1,3 @@ +# iOS Icon Placeholder +# This file should be replaced with the actual app icon (1024x1024 PNG) +# The build process will generate all required icon sizes from this base icon \ No newline at end of file diff --git a/build/ios/main.m b/build/ios/main.m new file mode 100644 index 0000000..366767a --- /dev/null +++ b/build/ios/main.m @@ -0,0 +1,23 @@ +//go:build ios +// Minimal bootstrap: delegate comes from Go archive (WailsAppDelegate) +#import +#include + +// External Go initialization function from the c-archive (declare before use) +extern void WailsIOSMain(); + +int main(int argc, char * argv[]) { + @autoreleasepool { + // Disable buffering so stdout/stderr from Go log.Printf flush immediately + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + // Start Go runtime on a background queue to avoid blocking main thread/UI + dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ + WailsIOSMain(); + }); + + // Run UIApplicationMain using WailsAppDelegate provided by the Go archive + return UIApplicationMain(argc, argv, nil, @"WailsAppDelegate"); + } +} \ No newline at end of file diff --git a/build/ios/main_ios.go b/build/ios/main_ios.go new file mode 100644 index 0000000..b75a403 --- /dev/null +++ b/build/ios/main_ios.go @@ -0,0 +1,24 @@ +//go:build ios + +package main + +import ( + "C" +) + +// For iOS builds, we need to export a function that can be called from Objective-C +// This wrapper allows us to keep the original main.go unmodified + +//export WailsIOSMain +func WailsIOSMain() { + // DO NOT lock the goroutine to the current OS thread on iOS! + // This causes signal handling issues: + // "signal 16 received on thread with no signal stack" + // "fatal error: non-Go code disabled sigaltstack" + // iOS apps run in a sandboxed environment where the Go runtime's + // signal handling doesn't work the same way as desktop platforms. + + // Call the actual main function from main.go + // This ensures all the user's code is executed + main() +} \ No newline at end of file diff --git a/build/ios/project.pbxproj b/build/ios/project.pbxproj new file mode 100644 index 0000000..89a1690 --- /dev/null +++ b/build/ios/project.pbxproj @@ -0,0 +1,222 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = {}; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + C0DEBEEF0000000000000001 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000002 /* main.m */; }; + C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000101 /* UIKit.framework */; }; + C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000102 /* Foundation.framework */; }; + C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000103 /* WebKit.framework */; }; + C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000104 /* Security.framework */; }; + C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000105 /* CoreFoundation.framework */; }; + C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000106 /* libresolv.tbd */; }; + C0DEBEEF00000000000000F7 /* My Product.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000107 /* My Product.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C0DEBEEF0000000000000002 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C0DEBEEF0000000000000003 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C0DEBEEF0000000000000004 /* My Product.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "My Product.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + C0DEBEEF0000000000000101 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000102 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000103 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000104 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000105 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000106 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.text-based-dylib-definition; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000107 /* My Product.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "My Product.a"; path = ../../../bin/My Product.a; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + C0DEBEEF0000000000000010 = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000020 /* Products */, + C0DEBEEF0000000000000045 /* Frameworks */, + C0DEBEEF0000000000000030 /* main */, + ); + sourceTree = ""; + }; + C0DEBEEF0000000000000020 /* Products */ = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000004 /* My Product.app */, + ); + name = Products; + sourceTree = ""; + }; + C0DEBEEF0000000000000030 /* main */ = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000002 /* main.m */, + C0DEBEEF0000000000000003 /* Info.plist */, + ); + path = main; + sourceTree = SOURCE_ROOT; + }; + C0DEBEEF0000000000000045 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000101 /* UIKit.framework */, + C0DEBEEF0000000000000102 /* Foundation.framework */, + C0DEBEEF0000000000000103 /* WebKit.framework */, + C0DEBEEF0000000000000104 /* Security.framework */, + C0DEBEEF0000000000000105 /* CoreFoundation.framework */, + C0DEBEEF0000000000000106 /* libresolv.tbd */, + C0DEBEEF0000000000000107 /* My Product.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C0DEBEEF0000000000000040 /* My Product */ = { + isa = PBXNativeTarget; + buildConfigurationList = C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "My Product" */; + buildPhases = ( + C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */, + C0DEBEEF0000000000000050 /* Sources */, + C0DEBEEF0000000000000056 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "My Product"; + productName = "My Product"; + productReference = C0DEBEEF0000000000000004 /* My Product.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C0DEBEEF0000000000000060 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1500; + ORGANIZATIONNAME = "My Company"; + TargetAttributes = { + C0DEBEEF0000000000000040 = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */; + compatibilityVersion = "Xcode 15.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C0DEBEEF0000000000000010; + productRefGroup = C0DEBEEF0000000000000020 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C0DEBEEF0000000000000040 /* My Product */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXFrameworksBuildPhase section */ + C0DEBEEF0000000000000056 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C0DEBEEF00000000000000F7 /* My Product.a in Frameworks */, + C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */, + C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */, + C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */, + C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */, + C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */, + C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Prebuild: Wails Go Archive"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\nAPP_ROOT=\"${PROJECT_DIR}/../../..\"\nSDK_PATH=$(xcrun --sdk iphonesimulator --show-sdk-path)\nexport GOOS=ios\nexport GOARCH=arm64\nexport CGO_ENABLED=1\nexport CGO_CFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0\"\nexport CGO_LDFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator\"\ncd \"${APP_ROOT}\"\n# Ensure overlay exists\nif [ ! -f build/ios/xcode/overlay.json ]; then\n wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml || true\nfi\n# Build Go c-archive if missing or older than sources\nif [ ! -f bin/My Product.a ]; then\n echo \"Building Go c-archive...\"\n go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json -o bin/My Product.a\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C0DEBEEF0000000000000050 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C0DEBEEF0000000000000001 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C0DEBEEF0000000000000090 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = main/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.example.coreidetest"; + PRODUCT_NAME = "My Product"; + CODE_SIGNING_ALLOWED = NO; + SDKROOT = iphonesimulator; + }; + name = Debug; + }; + C0DEBEEF00000000000000A0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = main/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.example.coreidetest"; + PRODUCT_NAME = "My Product"; + CODE_SIGNING_ALLOWED = NO; + SDKROOT = iphonesimulator; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "My Product" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0DEBEEF0000000000000090 /* Debug */, + C0DEBEEF00000000000000A0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0DEBEEF0000000000000090 /* Debug */, + C0DEBEEF00000000000000A0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = C0DEBEEF0000000000000060 /* Project object */; +} diff --git a/build/ios/scripts/deps/install_deps.go b/build/ios/scripts/deps/install_deps.go new file mode 100644 index 0000000..88ed47a --- /dev/null +++ b/build/ios/scripts/deps/install_deps.go @@ -0,0 +1,319 @@ +// install_deps.go - iOS development dependency checker +// This script checks for required iOS development tools. +// It's designed to be portable across different shells by using Go instead of shell scripts. +// +// Usage: +// go run install_deps.go # Interactive mode +// TASK_FORCE_YES=true go run install_deps.go # Auto-accept prompts +// CI=true go run install_deps.go # CI mode (auto-accept) + +package main + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "strings" +) + +type Dependency struct { + Name string + CheckFunc func() (bool, string) // Returns (success, details) + Required bool + InstallCmd []string + InstallMsg string + SuccessMsg string + FailureMsg string +} + +func main() { + fmt.Println("Checking iOS development dependencies...") + fmt.Println("=" + strings.Repeat("=", 50)) + fmt.Println() + + hasErrors := false + dependencies := []Dependency{ + { + Name: "Xcode", + CheckFunc: func() (bool, string) { + // Check if xcodebuild exists + if !checkCommand([]string{"xcodebuild", "-version"}) { + return false, "" + } + // Get version info + out, err := exec.Command("xcodebuild", "-version").Output() + if err != nil { + return false, "" + } + lines := strings.Split(string(out), "\n") + if len(lines) > 0 { + return true, strings.TrimSpace(lines[0]) + } + return true, "" + }, + Required: true, + InstallMsg: "Please install Xcode from the Mac App Store:\n https://apps.apple.com/app/xcode/id497799835\n Xcode is REQUIRED for iOS development (includes iOS SDKs, simulators, and frameworks)", + SuccessMsg: "✅ Xcode found", + FailureMsg: "❌ Xcode not found (REQUIRED)", + }, + { + Name: "Xcode Developer Path", + CheckFunc: func() (bool, string) { + // Check if xcode-select points to a valid Xcode path + out, err := exec.Command("xcode-select", "-p").Output() + if err != nil { + return false, "xcode-select not configured" + } + path := strings.TrimSpace(string(out)) + + // Check if path exists and is in Xcode.app + if _, err := os.Stat(path); err != nil { + return false, "Invalid Xcode path" + } + + // Verify it's pointing to Xcode.app (not just Command Line Tools) + if !strings.Contains(path, "Xcode.app") { + return false, fmt.Sprintf("Points to %s (should be Xcode.app)", path) + } + + return true, path + }, + Required: true, + InstallCmd: []string{"sudo", "xcode-select", "-s", "/Applications/Xcode.app/Contents/Developer"}, + InstallMsg: "Xcode developer path needs to be configured", + SuccessMsg: "✅ Xcode developer path configured", + FailureMsg: "❌ Xcode developer path not configured correctly", + }, + { + Name: "iOS SDK", + CheckFunc: func() (bool, string) { + // Get the iOS Simulator SDK path + cmd := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-path") + output, err := cmd.Output() + if err != nil { + return false, "Cannot find iOS SDK" + } + sdkPath := strings.TrimSpace(string(output)) + + // Check if the SDK path exists + if _, err := os.Stat(sdkPath); err != nil { + return false, "iOS SDK path not found" + } + + // Check for UIKit framework (essential for iOS development) + uikitPath := fmt.Sprintf("%s/System/Library/Frameworks/UIKit.framework", sdkPath) + if _, err := os.Stat(uikitPath); err != nil { + return false, "UIKit.framework not found" + } + + // Get SDK version + versionCmd := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-version") + versionOut, _ := versionCmd.Output() + version := strings.TrimSpace(string(versionOut)) + + return true, fmt.Sprintf("iOS %s SDK", version) + }, + Required: true, + InstallMsg: "iOS SDK comes with Xcode. Please ensure Xcode is properly installed.", + SuccessMsg: "✅ iOS SDK found with UIKit framework", + FailureMsg: "❌ iOS SDK not found or incomplete", + }, + { + Name: "iOS Simulator Runtime", + CheckFunc: func() (bool, string) { + if !checkCommand([]string{"xcrun", "simctl", "help"}) { + return false, "" + } + // Check if we can list runtimes + out, err := exec.Command("xcrun", "simctl", "list", "runtimes").Output() + if err != nil { + return false, "Cannot access simulator" + } + // Count iOS runtimes + lines := strings.Split(string(out), "\n") + count := 0 + var versions []string + for _, line := range lines { + if strings.Contains(line, "iOS") && !strings.Contains(line, "unavailable") { + count++ + // Extract version number + if parts := strings.Fields(line); len(parts) > 2 { + for _, part := range parts { + if strings.HasPrefix(part, "(") && strings.HasSuffix(part, ")") { + versions = append(versions, strings.Trim(part, "()")) + break + } + } + } + } + } + if count > 0 { + return true, fmt.Sprintf("%d runtime(s): %s", count, strings.Join(versions, ", ")) + } + return false, "No iOS runtimes installed" + }, + Required: true, + InstallMsg: "iOS Simulator runtimes come with Xcode. You may need to download them:\n Xcode → Settings → Platforms → iOS", + SuccessMsg: "✅ iOS Simulator runtime available", + FailureMsg: "❌ iOS Simulator runtime not available", + }, + } + + // Check each dependency + for _, dep := range dependencies { + success, details := dep.CheckFunc() + if success { + msg := dep.SuccessMsg + if details != "" { + msg = fmt.Sprintf("%s (%s)", dep.SuccessMsg, details) + } + fmt.Println(msg) + } else { + fmt.Println(dep.FailureMsg) + if details != "" { + fmt.Printf(" Details: %s\n", details) + } + if dep.Required { + hasErrors = true + if len(dep.InstallCmd) > 0 { + fmt.Println() + fmt.Println(" " + dep.InstallMsg) + fmt.Printf(" Fix command: %s\n", strings.Join(dep.InstallCmd, " ")) + if promptUser("Do you want to run this command?") { + fmt.Println("Running command...") + cmd := exec.Command(dep.InstallCmd[0], dep.InstallCmd[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + if err := cmd.Run(); err != nil { + fmt.Printf("Command failed: %v\n", err) + os.Exit(1) + } + fmt.Println("✅ Command completed. Please run this check again.") + } else { + fmt.Printf(" Please run manually: %s\n", strings.Join(dep.InstallCmd, " ")) + } + } else { + fmt.Println(" " + dep.InstallMsg) + } + } + } + } + + // Check for iPhone simulators + fmt.Println() + fmt.Println("Checking for iPhone simulator devices...") + if !checkCommand([]string{"xcrun", "simctl", "list", "devices"}) { + fmt.Println("❌ Cannot check for iPhone simulators") + hasErrors = true + } else { + out, err := exec.Command("xcrun", "simctl", "list", "devices").Output() + if err != nil { + fmt.Println("❌ Failed to list simulator devices") + hasErrors = true + } else if !strings.Contains(string(out), "iPhone") { + fmt.Println("⚠️ No iPhone simulator devices found") + fmt.Println() + + // Get the latest iOS runtime + runtimeOut, err := exec.Command("xcrun", "simctl", "list", "runtimes").Output() + if err != nil { + fmt.Println(" Failed to get iOS runtimes:", err) + } else { + lines := strings.Split(string(runtimeOut), "\n") + var latestRuntime string + for _, line := range lines { + if strings.Contains(line, "iOS") && !strings.Contains(line, "unavailable") { + // Extract runtime identifier + parts := strings.Fields(line) + if len(parts) > 0 { + latestRuntime = parts[len(parts)-1] + } + } + } + + if latestRuntime == "" { + fmt.Println(" No iOS runtime found. Please install iOS simulators in Xcode:") + fmt.Println(" Xcode → Settings → Platforms → iOS") + } else { + fmt.Println(" Would you like to create an iPhone 15 Pro simulator?") + createCmd := []string{"xcrun", "simctl", "create", "iPhone 15 Pro", "iPhone 15 Pro", latestRuntime} + fmt.Printf(" Command: %s\n", strings.Join(createCmd, " ")) + if promptUser("Create simulator?") { + cmd := exec.Command(createCmd[0], createCmd[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Printf(" Failed to create simulator: %v\n", err) + } else { + fmt.Println(" ✅ iPhone 15 Pro simulator created") + } + } else { + fmt.Println(" Skipping simulator creation") + fmt.Printf(" Create manually: %s\n", strings.Join(createCmd, " ")) + } + } + } + } else { + // Count iPhone devices + count := 0 + lines := strings.Split(string(out), "\n") + for _, line := range lines { + if strings.Contains(line, "iPhone") && !strings.Contains(line, "unavailable") { + count++ + } + } + fmt.Printf("✅ %d iPhone simulator device(s) available\n", count) + } + } + + // Final summary + fmt.Println() + fmt.Println("=" + strings.Repeat("=", 50)) + if hasErrors { + fmt.Println("❌ Some required dependencies are missing or misconfigured.") + fmt.Println() + fmt.Println("Quick setup guide:") + fmt.Println("1. Install Xcode from Mac App Store (if not installed)") + fmt.Println("2. Open Xcode once and agree to the license") + fmt.Println("3. Install additional components when prompted") + fmt.Println("4. Run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer") + fmt.Println("5. Download iOS simulators: Xcode → Settings → Platforms → iOS") + fmt.Println("6. Run this check again") + os.Exit(1) + } else { + fmt.Println("✅ All required dependencies are installed!") + fmt.Println(" You're ready for iOS development with Wails!") + } +} + +func checkCommand(args []string) bool { + if len(args) == 0 { + return false + } + cmd := exec.Command(args[0], args[1:]...) + cmd.Stdout = nil + cmd.Stderr = nil + err := cmd.Run() + return err == nil +} + +func promptUser(question string) bool { + // Check if we're in a non-interactive environment + if os.Getenv("CI") != "" || os.Getenv("TASK_FORCE_YES") == "true" { + fmt.Printf("%s [y/N]: y (auto-accepted)\n", question) + return true + } + + reader := bufio.NewReader(os.Stdin) + fmt.Printf("%s [y/N]: ", question) + + response, err := reader.ReadString('\n') + if err != nil { + return false + } + + response = strings.ToLower(strings.TrimSpace(response)) + return response == "y" || response == "yes" +} \ No newline at end of file diff --git a/build/linux/Taskfile.yml b/build/linux/Taskfile.yml index 7ddf9f3..a5e583d 100644 --- a/build/linux/Taskfile.yml +++ b/build/linux/Taskfile.yml @@ -3,34 +3,108 @@ version: '3' includes: common: ../Taskfile.yml +vars: + # Signing configuration - edit these values for your project + # PGP_KEY: "path/to/signing-key.asc" + # SIGN_ROLE: "builder" # Options: origin, maint, archive, builder + # + # Password is stored securely in system keychain. Run: wails3 setup signing + + # Docker image for cross-compilation (used when building on non-Linux or no CC available) + CROSS_IMAGE: wails-cross + tasks: build: summary: Builds the application for Linux + cmds: + # Linux requires CGO - use Docker when: + # 1. Cross-compiling from non-Linux, OR + # 2. No C compiler is available, OR + # 3. Target architecture differs from host architecture (cross-arch compilation) + - task: '{{if and (eq OS "linux") (eq .HAS_CC "true") (eq .TARGET_ARCH ARCH)}}build:native{{else}}build:docker{{end}}' + vars: + ARCH: '{{.ARCH}}' + DEV: '{{.DEV}}' + OUTPUT: '{{.OUTPUT}}' + EXTRA_TAGS: '{{.EXTRA_TAGS}}' + vars: + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + # Determine target architecture (defaults to host ARCH if not specified) + TARGET_ARCH: '{{.ARCH | default ARCH}}' + # Check if a C compiler is available (gcc or clang) + HAS_CC: + sh: '(command -v gcc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1) && echo "true" || echo "false"' + + build:native: + summary: Builds the application natively on Linux + internal: true deps: - task: common:go:mod:tidy - task: common:build:frontend vars: BUILD_FLAGS: ref: .BUILD_FLAGS - PRODUCTION: - ref: .PRODUCTION + DEV: + ref: .DEV - task: common:generate:icons + - task: generate:dotdesktop cmds: - - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}} + - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} vars: - BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' env: GOOS: linux CGO_ENABLED: 1 GOARCH: '{{.ARCH | default ARCH}}' - PRODUCTION: '{{.PRODUCTION | default "false"}}' + + build:docker: + summary: Builds for Linux using Docker (for non-Linux hosts or when no C compiler available) + internal: true + deps: + - task: common:build:frontend + - task: common:generate:icons + - task: generate:dotdesktop + preconditions: + - sh: docker info > /dev/null 2>&1 + msg: "Docker is required for cross-compilation to Linux. Please install Docker." + - sh: docker image inspect {{.CROSS_IMAGE}} > /dev/null 2>&1 + msg: | + Docker image '{{.CROSS_IMAGE}}' not found. + Build it first: wails3 task setup:docker + cmds: + - docker run --rm -v "{{.ROOT_DIR}}:/app" {{.GO_CACHE_MOUNT}} {{.REPLACE_MOUNTS}} -e APP_NAME="{{.APP_NAME}}" {{if .EXTRA_TAGS}}-e EXTRA_TAGS="{{.EXTRA_TAGS}}"{{end}} "{{.CROSS_IMAGE}}" linux {{.DOCKER_ARCH}} + - docker run --rm -v "{{.ROOT_DIR}}:/app" alpine chown -R $(id -u):$(id -g) /app/bin + - mkdir -p {{.BIN_DIR}} + - mv "bin/{{.APP_NAME}}-linux-{{.DOCKER_ARCH}}" "{{.OUTPUT}}" + vars: + DOCKER_ARCH: '{{.ARCH | default "amd64"}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + # Mount Go module cache for faster builds + GO_CACHE_MOUNT: + sh: 'echo "-v ${GOPATH:-$HOME/go}/pkg/mod:/go/pkg/mod"' + # Extract replace directives from go.mod and create -v mounts for each + REPLACE_MOUNTS: + sh: | + grep -E '^replace .* => ' go.mod 2>/dev/null | while read -r line; do + path=$(echo "$line" | sed -E 's/^replace .* => //' | tr -d '\r') + # Convert relative paths to absolute + if [ "${path#/}" = "$path" ]; then + path="$(cd "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")" + fi + # Only mount if directory exists + if [ -d "$path" ]; then + echo "-v $path:$path:ro" + fi + done | tr '\n' ' ' package: - summary: Packages a production build of the application for Linux + summary: Packages the application for Linux deps: - task: build - vars: - PRODUCTION: "true" cmds: - task: create:appimage - task: create:deb @@ -42,13 +116,11 @@ tasks: dir: build/linux/appimage deps: - task: build - vars: - PRODUCTION: "true" - task: generate:dotdesktop cmds: - - cp {{.APP_BINARY}} {{.APP_NAME}} - - cp ../../appicon.png {{.APP_NAME}}.png - - wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build + - cp "{{.APP_BINARY}}" "{{.APP_NAME}}" + - cp ../../appicon.png "{{.APP_NAME}}.png" + - wails3 generate appimage -binary "{{.APP_NAME}}" -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build vars: APP_NAME: '{{.APP_NAME}}' APP_BINARY: '../../../bin/{{.APP_NAME}}' @@ -60,8 +132,6 @@ tasks: summary: Creates a deb package deps: - task: build - vars: - PRODUCTION: "true" cmds: - task: generate:dotdesktop - task: generate:deb @@ -70,8 +140,6 @@ tasks: summary: Creates a rpm package deps: - task: build - vars: - PRODUCTION: "true" cmds: - task: generate:dotdesktop - task: generate:rpm @@ -80,8 +148,6 @@ tasks: summary: Creates a arch linux packager package deps: - task: build - vars: - PRODUCTION: "true" cmds: - task: generate:dotdesktop - task: generate:aur @@ -89,24 +155,24 @@ tasks: generate:deb: summary: Creates a deb package cmds: - - wails3 tool package -name {{.APP_NAME}} -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + - wails3 tool package -name "{{.APP_NAME}}" -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin generate:rpm: summary: Creates a rpm package cmds: - - wails3 tool package -name {{.APP_NAME}} -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + - wails3 tool package -name "{{.APP_NAME}}" -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin generate:aur: summary: Creates a arch linux packager package cmds: - - wails3 tool package -name {{.APP_NAME}} -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + - wails3 tool package -name "{{.APP_NAME}}" -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin generate:dotdesktop: summary: Generates a `.desktop` file dir: build cmds: - mkdir -p {{.ROOT_DIR}}/build/linux/appimage - - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile {{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop -categories "{{.CATEGORIES}}" + - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" -categories "{{.CATEGORIES}}" vars: APP_NAME: '{{.APP_NAME}}' EXEC: '{{.APP_NAME}}' @@ -117,3 +183,44 @@ tasks: run: cmds: - '{{.BIN_DIR}}/{{.APP_NAME}}' + + sign:deb: + summary: Signs the DEB package + desc: | + Signs the .deb package with a PGP key. + Configure PGP_KEY in the vars section at the top of this file. + Password is retrieved from system keychain (run: wails3 setup signing) + deps: + - task: create:deb + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}*.deb" --pgp-key {{.PGP_KEY}} {{if .SIGN_ROLE}}--role {{.SIGN_ROLE}}{{end}} + preconditions: + - sh: '[ -n "{{.PGP_KEY}}" ]' + msg: "PGP_KEY is required. Set it in the vars section at the top of build/linux/Taskfile.yml" + + sign:rpm: + summary: Signs the RPM package + desc: | + Signs the .rpm package with a PGP key. + Configure PGP_KEY in the vars section at the top of this file. + Password is retrieved from system keychain (run: wails3 setup signing) + deps: + - task: create:rpm + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}*.rpm" --pgp-key {{.PGP_KEY}} + preconditions: + - sh: '[ -n "{{.PGP_KEY}}" ]' + msg: "PGP_KEY is required. Set it in the vars section at the top of build/linux/Taskfile.yml" + + sign:packages: + summary: Signs all Linux packages (DEB and RPM) + desc: | + Signs both .deb and .rpm packages with a PGP key. + Configure PGP_KEY in the vars section at the top of this file. + Password is retrieved from system keychain (run: wails3 setup signing) + cmds: + - task: sign:deb + - task: sign:rpm + preconditions: + - sh: '[ -n "{{.PGP_KEY}}" ]' + msg: "PGP_KEY is required. Set it in the vars section at the top of build/linux/Taskfile.yml" diff --git a/build/windows/Taskfile.yml b/build/windows/Taskfile.yml index 12ec591..a579f85 100644 --- a/build/windows/Taskfile.yml +++ b/build/windows/Taskfile.yml @@ -3,42 +3,99 @@ version: '3' includes: common: ../Taskfile.yml +vars: + # Signing configuration - edit these values for your project + # SIGN_CERTIFICATE: "path/to/certificate.pfx" + # SIGN_THUMBPRINT: "certificate-thumbprint" # Alternative to SIGN_CERTIFICATE + # TIMESTAMP_SERVER: "http://timestamp.digicert.com" + # + # Password is stored securely in system keychain. Run: wails3 setup signing + + # Docker image for cross-compilation with CGO (used when CGO_ENABLED=1 on non-Windows) + CROSS_IMAGE: wails-cross + tasks: build: summary: Builds the application for Windows + cmds: + # Auto-detect CGO: if CGO_ENABLED=1, use Docker; otherwise use native Go cross-compile + - task: '{{if and (ne OS "windows") (eq .CGO_ENABLED "1")}}build:docker{{else}}build:native{{end}}' + vars: + ARCH: '{{.ARCH}}' + DEV: '{{.DEV}}' + EXTRA_TAGS: '{{.EXTRA_TAGS}}' + vars: + # Default to CGO_ENABLED=0 if not explicitly set + CGO_ENABLED: '{{.CGO_ENABLED | default "0"}}' + + build:native: + summary: Builds the application using native Go cross-compilation + internal: true deps: - task: common:go:mod:tidy - task: common:build:frontend vars: BUILD_FLAGS: ref: .BUILD_FLAGS - PRODUCTION: - ref: .PRODUCTION + DEV: + ref: .DEV - task: common:generate:icons cmds: - task: generate:syso - - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}.exe + - go build {{.BUILD_FLAGS}} -o "{{.BIN_DIR}}/{{.APP_NAME}}.exe" - cmd: powershell Remove-item *.syso platforms: [windows] - cmd: rm -f *.syso platforms: [linux, darwin] vars: - BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{end}}' env: GOOS: windows - CGO_ENABLED: 0 + CGO_ENABLED: '{{.CGO_ENABLED | default "0"}}' GOARCH: '{{.ARCH | default ARCH}}' - PRODUCTION: '{{.PRODUCTION | default "false"}}' + + build:docker: + summary: Cross-compiles for Windows using Docker with Zig (for CGO builds on non-Windows) + internal: true + deps: + - task: common:build:frontend + - task: common:generate:icons + preconditions: + - sh: docker info > /dev/null 2>&1 + msg: "Docker is required for CGO cross-compilation. Please install Docker." + - sh: docker image inspect {{.CROSS_IMAGE}} > /dev/null 2>&1 + msg: | + Docker image '{{.CROSS_IMAGE}}' not found. + Build it first: wails3 task setup:docker + cmds: + - task: generate:syso + - docker run --rm -v "{{.ROOT_DIR}}:/app" {{.GO_CACHE_MOUNT}} {{.REPLACE_MOUNTS}} -e APP_NAME="{{.APP_NAME}}" {{if .EXTRA_TAGS}}-e EXTRA_TAGS="{{.EXTRA_TAGS}}"{{end}} {{.CROSS_IMAGE}} windows {{.DOCKER_ARCH}} + - docker run --rm -v "{{.ROOT_DIR}}:/app" alpine chown -R $(id -u):$(id -g) /app/bin + - rm -f *.syso + vars: + DOCKER_ARCH: '{{.ARCH | default "amd64"}}' + # Mount Go module cache for faster builds + GO_CACHE_MOUNT: + sh: 'echo "-v ${GOPATH:-$HOME/go}/pkg/mod:/go/pkg/mod"' + # Extract replace directives from go.mod and create -v mounts for each + REPLACE_MOUNTS: + sh: | + grep -E '^replace .* => ' go.mod 2>/dev/null | while read -r line; do + path=$(echo "$line" | sed -E 's/^replace .* => //' | tr -d '\r') + # Convert relative paths to absolute + if [ "${path#/}" = "$path" ]; then + path="$(cd "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")" + fi + # Only mount if directory exists + if [ -d "$path" ]; then + echo "-v $path:$path:ro" + fi + done | tr '\n' ' ' package: - summary: Packages a production build of the application + summary: Packages the application cmds: - - |- - if [ "{{.FORMAT | default "nsis"}}" = "msix" ]; then - task create:msix:package - else - task create:nsis:installer - fi + - task: '{{if eq (.FORMAT | default "nsis") "msix"}}create:msix:package{{else}}create:nsis:installer{{end}}' vars: FORMAT: '{{.FORMAT | default "nsis"}}' @@ -55,12 +112,15 @@ tasks: dir: build/windows/nsis deps: - task: build - vars: - PRODUCTION: "true" cmds: # Create the Microsoft WebView2 bootstrapper if it doesn't exist - wails3 generate webview2bootstrapper -dir "{{.ROOT_DIR}}/build/windows/nsis" - - makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}/{{.BIN_DIR}}/{{.APP_NAME}}.exe" project.nsi + - | + {{if eq OS "windows"}} + makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}\{{.BIN_DIR}}\{{.APP_NAME}}.exe" project.nsi + {{else}} + makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}/{{.BIN_DIR}}/{{.APP_NAME}}.exe" project.nsi + {{end}} vars: ARCH: '{{.ARCH | default ARCH}}' ARG_FLAG: '{{if eq .ARCH "amd64"}}AMD64{{else}}ARM64{{end}}' @@ -69,8 +129,6 @@ tasks: summary: Creates an MSIX package deps: - task: build - vars: - PRODUCTION: "true" cmds: - |- wails3 tool msix \ @@ -96,3 +154,31 @@ tasks: run: cmds: - '{{.BIN_DIR}}/{{.APP_NAME}}.exe' + + sign: + summary: Signs the Windows executable + desc: | + Signs the .exe with an Authenticode certificate. + Configure SIGN_CERTIFICATE or SIGN_THUMBPRINT in the vars section at the top of this file. + Password is retrieved from system keychain (run: wails3 setup signing) + deps: + - task: build + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.exe" {{if .SIGN_CERTIFICATE}}--certificate {{.SIGN_CERTIFICATE}}{{end}} {{if .SIGN_THUMBPRINT}}--thumbprint {{.SIGN_THUMBPRINT}}{{end}} {{if .TIMESTAMP_SERVER}}--timestamp {{.TIMESTAMP_SERVER}}{{end}} + preconditions: + - sh: '[ -n "{{.SIGN_CERTIFICATE}}" ] || [ -n "{{.SIGN_THUMBPRINT}}" ]' + msg: "Either SIGN_CERTIFICATE or SIGN_THUMBPRINT is required. Set it in the vars section at the top of build/windows/Taskfile.yml" + + sign:installer: + summary: Signs the NSIS installer + desc: | + Creates and signs the NSIS installer. + Configure SIGN_CERTIFICATE or SIGN_THUMBPRINT in the vars section at the top of this file. + Password is retrieved from system keychain (run: wails3 setup signing) + deps: + - task: create:nsis:installer + cmds: + - wails3 tool sign --input "build/windows/nsis/{{.APP_NAME}}-installer.exe" {{if .SIGN_CERTIFICATE}}--certificate {{.SIGN_CERTIFICATE}}{{end}} {{if .SIGN_THUMBPRINT}}--thumbprint {{.SIGN_THUMBPRINT}}{{end}} {{if .TIMESTAMP_SERVER}}--timestamp {{.TIMESTAMP_SERVER}}{{end}} + preconditions: + - sh: '[ -n "{{.SIGN_CERTIFICATE}}" ] || [ -n "{{.SIGN_THUMBPRINT}}" ]' + msg: "Either SIGN_CERTIFICATE or SIGN_THUMBPRINT is required. Set it in the vars section at the top of build/windows/Taskfile.yml" diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 833602e..0fd28f9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,13 +8,13 @@ "name": "wails-angular-template", "version": "0.0.0", "dependencies": { - "@angular/common": "^20.3.14", - "@angular/compiler": "^20.3.16", - "@angular/core": "^21.1.2", - "@angular/forms": "^20.3.0", - "@angular/platform-browser": "^20.3.0", - "@angular/platform-server": "^20.3.0", - "@angular/router": "^20.3.0", + "@angular/common": "~20.3.16", + "@angular/compiler": "~20.3.16", + "@angular/core": "~20.3.16", + "@angular/forms": "~20.3.16", + "@angular/platform-browser": "~20.3.16", + "@angular/platform-server": "~20.3.16", + "@angular/router": "~20.3.16", "@angular/ssr": "^20.3.6", "@wailsio/runtime": "3.0.0-alpha.72", "express": "^5.1.0", @@ -23,9 +23,9 @@ "zone.js": "~0.15.0" }, "devDependencies": { - "@angular/build": "^21.1.2", - "@angular/cli": "^21.1.3", - "@angular/compiler-cli": "^20.3.0", + "@angular/build": "^20.3.6", + "@angular/cli": "^20.3.6", + "@angular/compiler-cli": "~20.3.16", "@types/express": "^5.0.1", "@types/jasmine": "~5.1.0", "@types/node": "^20.17.19", @@ -39,57 +39,57 @@ } }, "node_modules/@algolia/abtesting": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.1.tgz", - "integrity": "sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.1.0.tgz", + "integrity": "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-abtesting": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.48.1.tgz", - "integrity": "sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.35.0.tgz", + "integrity": "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.48.1.tgz", - "integrity": "sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.35.0.tgz", + "integrity": "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.48.1.tgz", - "integrity": "sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.35.0.tgz", + "integrity": "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w==", "dev": true, "license": "MIT", "engines": { @@ -97,151 +97,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.48.1.tgz", - "integrity": "sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.35.0.tgz", + "integrity": "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.48.1.tgz", - "integrity": "sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.35.0.tgz", + "integrity": "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.48.1.tgz", - "integrity": "sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.35.0.tgz", + "integrity": "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.48.1.tgz", - "integrity": "sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.35.0.tgz", + "integrity": "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.48.1.tgz", - "integrity": "sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w==", + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.35.0.tgz", + "integrity": "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.48.1.tgz", - "integrity": "sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw==", + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.35.0.tgz", + "integrity": "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.48.1.tgz", - "integrity": "sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.35.0.tgz", + "integrity": "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.48.1.tgz", - "integrity": "sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.35.0.tgz", + "integrity": "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1" + "@algolia/client-common": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.48.1.tgz", - "integrity": "sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.35.0.tgz", + "integrity": "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1" + "@algolia/client-common": "5.35.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.48.1.tgz", - "integrity": "sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.35.0.tgz", + "integrity": "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1" + "@algolia/client-common": "5.35.0" }, "engines": { "node": ">= 14.0.0" @@ -262,18 +262,15 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.2.tgz", - "integrity": "sha512-CDvFtXwyBtMRkTQnm+LfBNLL0yLV8ZGskrM1T6VkcGwXGFDott1FxUdj96ViodYsYL5fbJr0MNA6TlLcanV3kQ==", + "version": "0.2003.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.20.tgz", + "integrity": "sha512-1g7q37Aq4dvDdQDW0PtWXfiX5hBV78K74QUtFkAXGIXU3DkguwOQaqHILCnIRAVr0wFlWDckWVuO5OT6Cl9HeQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.2", + "@angular-devkit/core": "20.3.20", "rxjs": "7.8.2" }, - "bin": { - "architect": "bin/cli.js" - }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -281,9 +278,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.2.tgz", - "integrity": "sha512-xUeKGe4BDQpkz0E6fnAPIJXE0y0nqtap0KhJIBhvN7xi3NenIzTmoi6T9Yv5OOBUdLZbOm4SOel8MhdXiIBpAQ==", + "version": "20.3.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.20.tgz", + "integrity": "sha512-Iobw7He3yJVR2aQ6JN9Kq/2ldD8+uHzJZwd41SQ91A+TzPrBRSV0t80WHHrANZ7xnAjtHDc7zSSGp/i7DzUc9g==", "dev": true, "license": "MIT", "dependencies": { @@ -300,7 +297,7 @@ "yarn": ">= 1.13.0" }, "peerDependencies": { - "chokidar": "^5.0.0" + "chokidar": "^4.0.0" }, "peerDependenciesMeta": { "chokidar": { @@ -309,16 +306,16 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.2.tgz", - "integrity": "sha512-CCeyQxGUq+oyGnHd7PfcYIVbj9pRnqjQq0rAojoAqs1BJdtInx9weLBCLy+AjM3NHePeZrnwm+wEVr8apED8kg==", + "version": "20.3.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.20.tgz", + "integrity": "sha512-+NNHQhQHcgQWZopStZ6os30YuP99lRzNS4wOnkJmoROy40SZct8lPnl2QW50a9Vc0AtaHx1a1NUZ+ohbf6fXqw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.2", + "@angular-devkit/core": "20.3.20", "jsonc-parser": "3.3.1", - "magic-string": "0.30.21", - "ora": "9.3.0", + "magic-string": "0.30.17", + "ora": "8.2.0", "rxjs": "7.8.2" }, "engines": { @@ -328,39 +325,38 @@ } }, "node_modules/@angular/build": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.2.tgz", - "integrity": "sha512-Vq2eIneNxzhHm1MwEmRqEJDwHU9ODfSRDaMWwtysGMhpoMQmLdfTqkQDmkC2qVUr8mV8Z1i5I+oe5ZJaMr/PlQ==", + "version": "20.3.20", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.20.tgz", + "integrity": "sha512-+uWqGU+Qyso2uJKL1xNjAm+E3m3ncv5InMUG5BC/UhFnXTsL1o7oySGc6hHa+8rQunuifUhdy20HxZjU6QlqTw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.2", - "@babel/core": "7.29.0", + "@angular-devkit/architect": "0.2003.20", + "@babel/core": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", - "@inquirer/confirm": "5.1.21", - "@vitejs/plugin-basic-ssl": "2.1.4", - "beasties": "0.4.1", - "browserslist": "^4.26.0", - "esbuild": "0.27.3", + "@inquirer/confirm": "5.1.14", + "@vitejs/plugin-basic-ssl": "2.1.0", + "beasties": "0.3.5", + "browserslist": "^4.23.0", + "esbuild": "0.25.9", "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", - "listr2": "9.0.5", - "magic-string": "0.30.21", + "listr2": "9.0.1", + "magic-string": "0.30.17", "mrmime": "2.0.1", "parse5-html-rewriting-stream": "8.0.0", "picomatch": "4.0.3", - "piscina": "5.1.4", - "rolldown": "1.0.0-rc.4", - "sass": "1.97.3", - "semver": "7.7.4", + "piscina": "5.1.3", + "rollup": "4.59.0", + "sass": "1.90.0", + "semver": "7.7.2", "source-map-support": "0.5.21", - "tinyglobby": "0.2.15", - "undici": "7.22.0", - "vite": "7.3.1", - "watchpack": "2.5.1" + "tinyglobby": "0.2.14", + "vite": "7.1.11", + "watchpack": "2.4.4" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", @@ -368,25 +364,25 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "lmdb": "3.5.1" + "lmdb": "3.4.2" }, "peerDependencies": { - "@angular/compiler": "^21.0.0", - "@angular/compiler-cli": "^21.0.0", - "@angular/core": "^21.0.0", - "@angular/localize": "^21.0.0", - "@angular/platform-browser": "^21.0.0", - "@angular/platform-server": "^21.0.0", - "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.2", + "@angular/compiler": "^20.0.0", + "@angular/compiler-cli": "^20.0.0", + "@angular/core": "^20.0.0", + "@angular/localize": "^20.0.0", + "@angular/platform-browser": "^20.0.0", + "@angular/platform-server": "^20.0.0", + "@angular/service-worker": "^20.0.0", + "@angular/ssr": "^20.3.20", "karma": "^6.4.0", "less": "^4.2.0", - "ng-packagr": "^21.0.0", + "ng-packagr": "^20.0.0", "postcss": "^8.4.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "tslib": "^2.3.0", - "typescript": ">=5.9 <6.0", - "vitest": "^4.0.8" + "typescript": ">=5.8 <6.0", + "vitest": "^3.1.1" }, "peerDependenciesMeta": { "@angular/core": { @@ -427,79 +423,44 @@ } } }, - "node_modules/@angular/build/node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/build/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@angular/build/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@angular/build/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular/cli": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.2.tgz", - "integrity": "sha512-eZo8/qX+ZIpIWc0CN+cCX13Lbgi/031wAp8DRVhDDO6SMVtcr/ObOQ2S16+pQdOMXxiG3vby6IhzJuz9WACzMQ==", + "version": "20.3.20", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.20.tgz", + "integrity": "sha512-wHMo0BWhoBMXcsZ1U+yJ0eOH2B5NgCWW7PTrJ1P/QbocbCSh7eqw8wKnEthIKyhrEWtAo67Jw7i8CgbeIZgmMw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.2", - "@angular-devkit/core": "21.2.2", - "@angular-devkit/schematics": "21.2.2", - "@inquirer/prompts": "7.10.1", - "@listr2/prompt-adapter-inquirer": "3.0.5", + "@angular-devkit/architect": "0.2003.20", + "@angular-devkit/core": "20.3.20", + "@angular-devkit/schematics": "20.3.20", + "@inquirer/prompts": "7.8.2", + "@listr2/prompt-adapter-inquirer": "3.0.1", "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.2", + "@schematics/angular": "20.3.20", "@yarnpkg/lockfile": "1.1.0", - "algoliasearch": "5.48.1", - "ini": "6.0.0", + "algoliasearch": "5.35.0", + "ini": "5.0.0", "jsonc-parser": "3.3.1", - "listr2": "9.0.5", - "npm-package-arg": "13.0.2", - "pacote": "21.3.1", - "parse5-html-rewriting-stream": "8.0.0", - "semver": "7.7.4", + "listr2": "9.0.1", + "npm-package-arg": "13.0.0", + "pacote": "21.0.4", + "resolve": "1.22.10", + "semver": "7.7.2", "yargs": "18.0.0", - "zod": "4.3.6" + "zod": "4.1.13" }, "bin": { "ng": "bin/ng.js" @@ -510,10 +471,33 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/zod": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@angular/common": { - "version": "20.3.14", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.14.tgz", - "integrity": "sha512-OOUvjTtnpktJLsNupA+GFT2q5zNocPdpOENA8aSrXvAheNybLjgi+otO3U3sQsvB1VwaoEZ9GT5O3lZlstnA/A==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.18.tgz", + "integrity": "sha512-M62oQbSTRmnGavIVCwimoadg/PDWadgNhactMm9fgH0eM9rx+iWBAYJk4VufO0bwOhysFpRZpJgXlFjOifz/Jw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -522,7 +506,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.14", + "@angular/core": "20.3.18", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -539,9 +523,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.9.tgz", - "integrity": "sha512-Fe7MIg2NWXoK+M4GtclxaYNoTdZX2U8f/Fd3N8zxtEMcRsvliJOnJ4oQtpx5kqMAuZVO4zY3wuIY1wAGXYCUbQ==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.18.tgz", + "integrity": "sha512-zsoEgLgnblmRbi47YwMghKirJ8IBKJ3+I8TxLBRIBrhx+KHFp+6oeDeLyu9H+djdyk88zexVd09wzR/YK73F0g==", "dev": true, "license": "MIT", "dependencies": { @@ -562,7 +546,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.9", + "@angular/compiler": "20.3.18", "typescript": ">=5.8 <6.0" }, "peerDependenciesMeta": { @@ -572,9 +556,9 @@ } }, "node_modules/@angular/core": { - "version": "21.1.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.1.2.tgz", - "integrity": "sha512-W2xxRb7noOD1DdMwKaZ3chFhii6nutaNIXt7dfWsMWoujg3Kqpdn1ukeyW5aHKQZvCJTIGr4f3whZ8Sj/17aCA==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.18.tgz", + "integrity": "sha512-B+NQQngd/aDbcfW0zGLis3wTLDeHTeTYMl/mGKQH+HwdPaRCKI1wEtaXaOYVJXkP2FeThocPevB8gLwNlPQUUw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -583,9 +567,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.1.2", + "@angular/compiler": "20.3.18", "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.15.0 || ~0.16.0" + "zone.js": "~0.15.0" }, "peerDependenciesMeta": { "@angular/compiler": { @@ -597,9 +581,9 @@ } }, "node_modules/@angular/forms": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.9.tgz", - "integrity": "sha512-jSlhU1IyuxxSYNN5Gg3oBb0nAqIl5Mwf1hywtkbyMay+3sENYGvBRseWp00R308isKe+n8bKi6hF54A1lhozzg==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.18.tgz", + "integrity": "sha512-x6/99LfxolyZIFUL3Wr0OrtuXHEDwEz/rwx+WzE7NL+n35yO40t3kp0Sn5uMFwI94i91QZJmXHltMpZhrVLuYg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -608,16 +592,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.9", - "@angular/core": "20.3.9", - "@angular/platform-browser": "20.3.9", + "@angular/common": "20.3.18", + "@angular/core": "20.3.18", + "@angular/platform-browser": "20.3.18", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.9.tgz", - "integrity": "sha512-q9uyNIKto3PmIh3q9/OX0HYN/SMYqCJ7MyQHBuF9Rel0vXi0gWyk2dgsWAl/tSTLlqHWtGZZ3rvJyxYQmxFo4w==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.18.tgz", + "integrity": "sha512-q6s5rEN1yYazpHYp+k4pboXRzMsRB9auzTRBEhyXSGYxqzrnn3qHN0DqgsLC9WAdyhCgnIEMFA8kRT+W277DqQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -626,9 +610,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.3.9", - "@angular/common": "20.3.9", - "@angular/core": "20.3.9" + "@angular/animations": "20.3.18", + "@angular/common": "20.3.18", + "@angular/core": "20.3.18" }, "peerDependenciesMeta": { "@angular/animations": { @@ -637,9 +621,9 @@ } }, "node_modules/@angular/platform-server": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-20.3.9.tgz", - "integrity": "sha512-rLE3hFxEs2D0wmKcrNiVLUajEyHBZvHN/YDt7ujaZNR0gVSj45CJOWn2/V2+AnP/73RjmvZgukh15sqFR2j6LQ==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-20.3.18.tgz", + "integrity": "sha512-iw4QSmEWEKbyMT5u8QdhalNiPqRc7cRuo6lulU75pjXqVLwLb3Gq8it+Vo+LSKY6qI/bMO7olS7iyw09wXJ0OQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0", @@ -649,17 +633,17 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.9", - "@angular/compiler": "20.3.9", - "@angular/core": "20.3.9", - "@angular/platform-browser": "20.3.9", + "@angular/common": "20.3.18", + "@angular/compiler": "20.3.18", + "@angular/core": "20.3.18", + "@angular/platform-browser": "20.3.18", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/router": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.9.tgz", - "integrity": "sha512-wsilSrTtR85OFd6XP0b9rMakx1pEw5sHEYBrfoSQc+NfYCsP5a5qFBJ5CWOQKgWjKlfPgpkaheD6JdqN9WpFoQ==", + "version": "20.3.18", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.18.tgz", + "integrity": "sha512-3CWejsEYr+ze+ktvWN/qHdyq5WLrj96QZpGYJyxh1pchIcpMPE9MmLpdjf0CUrWYB7g/85u0Geq/xsz72JrGng==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -668,9 +652,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.9", - "@angular/core": "20.3.9", - "@angular/platform-browser": "20.3.9", + "@angular/common": "20.3.18", + "@angular/core": "20.3.18", + "@angular/platform-browser": "20.3.18", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -997,44 +981,10 @@ "node": ">=0.1.90" } }, - "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -1049,9 +999,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -1066,9 +1016,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -1083,9 +1033,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -1100,9 +1050,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -1117,9 +1067,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -1134,9 +1084,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -1151,9 +1101,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -1168,9 +1118,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -1185,9 +1135,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -1202,9 +1152,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -1219,9 +1169,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -1236,9 +1186,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -1253,9 +1203,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -1270,9 +1220,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -1287,9 +1237,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -1304,9 +1254,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -1321,9 +1271,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -1338,9 +1288,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -1355,9 +1305,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -1372,9 +1322,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -1389,9 +1339,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", "cpu": [ "arm64" ], @@ -1406,9 +1356,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -1423,9 +1373,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -1440,9 +1390,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -1457,9 +1407,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -1486,14 +1436,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@harperfast/extended-iterable": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", - "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", - "dev": true, - "license": "Apache-2.0", - "optional": true - }, "node_modules/@hono/node-server": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", @@ -1543,14 +1485,14 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.21", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", - "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1738,22 +1680,22 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", - "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.2.tgz", + "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.3.2", - "@inquirer/confirm": "^5.1.21", - "@inquirer/editor": "^4.2.23", - "@inquirer/expand": "^4.0.23", - "@inquirer/input": "^4.3.1", - "@inquirer/number": "^3.0.23", - "@inquirer/password": "^4.0.23", - "@inquirer/rawlist": "^4.1.11", - "@inquirer/search": "^3.2.2", - "@inquirer/select": "^4.4.2" + "@inquirer/checkbox": "^4.2.1", + "@inquirer/confirm": "^5.1.14", + "@inquirer/editor": "^4.2.17", + "@inquirer/expand": "^4.0.17", + "@inquirer/input": "^4.2.1", + "@inquirer/number": "^3.0.17", + "@inquirer/password": "^4.0.17", + "@inquirer/rawlist": "^4.1.5", + "@inquirer/search": "^3.1.0", + "@inquirer/select": "^4.3.1" }, "engines": { "node": ">=18" @@ -1891,17 +1833,6 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -1931,26 +1862,26 @@ } }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", - "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.1.tgz", + "integrity": "sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^3.0.8" + "@inquirer/type": "^3.0.7" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { "@inquirer/prompts": ">= 3 < 8", - "listr2": "9.0.5" + "listr2": "9.0.1" } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", - "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.2.tgz", + "integrity": "sha512-NK80WwDoODyPaSazKbzd3NEJ3ygePrkERilZshxBViBARNz21rmediktGHExoj9n5t9+ChlgLlxecdFKLCuCKg==", "cpu": [ "arm64" ], @@ -1962,9 +1893,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", - "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.2.tgz", + "integrity": "sha512-zevaowQNmrp3U7Fz1s9pls5aIgpKRsKb3dZWDINtLiozh3jZI9fBrI19lYYBxqdyiIyNdlyiidPnwPShj4aK+w==", "cpu": [ "x64" ], @@ -1976,9 +1907,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", - "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.2.tgz", + "integrity": "sha512-OmHCULY17rkx/RoCoXlzU7LyR8xqrksgdYWwtYa14l/sseezZ8seKWXcogHcjulBddER5NnEFV4L/Jtr2nyxeg==", "cpu": [ "arm" ], @@ -1990,9 +1921,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", - "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.2.tgz", + "integrity": "sha512-ZBEfbNZdkneebvZs98Lq30jMY8V9IJzckVeigGivV7nTHJc+89Ctomp1kAIWKlwIG0ovCDrFI448GzFPORANYg==", "cpu": [ "arm64" ], @@ -2004,9 +1935,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", - "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.2.tgz", + "integrity": "sha512-vL9nM17C77lohPYE4YaAQvfZCSVJSryE4fXdi8M7uWPBnU+9DJabgKVAeyDb84ZM2vcFseoBE4/AagVtJeRE7g==", "cpu": [ "x64" ], @@ -2018,9 +1949,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", - "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.2.tgz", + "integrity": "sha512-SXWjdBfNDze4ZPeLtYIzsIeDJDJ/SdsA0pEXcUBayUIMO0FQBHfVZZyHXQjjHr4cvOAzANBgIiqaXRwfMhzmLw==", "cpu": [ "arm64" ], @@ -2032,9 +1963,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", - "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.2.tgz", + "integrity": "sha512-IY+r3bxKW6Q6sIPiMC0L533DEfRJSXibjSI3Ft/w9Q8KQBNqEIvUFXt+09wV8S5BRk0a8uSF19YWxuRwEfI90g==", "cpu": [ "x64" ], @@ -2514,23 +2445,6 @@ "node": ">= 10" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, "node_modules/@npmcli/agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", @@ -2591,6 +2505,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/@npmcli/git/node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/@npmcli/git/node_modules/isexe": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", @@ -2611,6 +2535,16 @@ "node": "20 || >=22" } }, + "node_modules/@npmcli/git/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/@npmcli/git/node_modules/which": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", @@ -2730,6 +2664,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/package-json/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/@npmcli/promise-spawn": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", @@ -2796,14 +2740,14 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@oxc-project/types": { - "version": "0.113.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", - "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", + "node_modules/@npmcli/run-script/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@parcel/watcher": { @@ -3142,246 +3086,6 @@ "license": "MIT", "optional": true }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", - "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", - "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", - "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", @@ -3772,14 +3476,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.2.tgz", - "integrity": "sha512-Ywa6HDtX7TRBQZTVMMnxX3Mk7yVnG8KtSFaXWrkx779+q8tqYdBwNwAqbNd4Zatr1GccKaz9xcptHJta5+DTxw==", + "version": "20.3.20", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.20.tgz", + "integrity": "sha512-LyoHwenNi8lZZO5zafAjcN8DcaOdjFrkbZdrCkvdpmOFz5wy8ZGchY6XSZEDD6kdHvR8oU7WWnGTMgCfExBKCg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.2", - "@angular-devkit/schematics": "21.2.2", + "@angular-devkit/core": "20.3.20", + "@angular-devkit/schematics": "20.3.20", "jsonc-parser": "3.3.1" }, "engines": { @@ -3839,6 +3543,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/@sigstore/sign/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/@sigstore/tuf": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.1.tgz", @@ -3938,17 +3652,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", @@ -4091,9 +3794,9 @@ } }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", - "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", + "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==", "dev": true, "license": "MIT", "engines": { @@ -4185,26 +3888,26 @@ } }, "node_modules/algoliasearch": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.48.1.tgz", - "integrity": "sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg==", + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.35.0.tgz", + "integrity": "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/abtesting": "1.14.1", - "@algolia/client-abtesting": "5.48.1", - "@algolia/client-analytics": "5.48.1", - "@algolia/client-common": "5.48.1", - "@algolia/client-insights": "5.48.1", - "@algolia/client-personalization": "5.48.1", - "@algolia/client-query-suggestions": "5.48.1", - "@algolia/client-search": "5.48.1", - "@algolia/ingestion": "1.48.1", - "@algolia/monitoring": "1.48.1", - "@algolia/recommend": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/abtesting": "1.1.0", + "@algolia/client-abtesting": "5.35.0", + "@algolia/client-analytics": "5.35.0", + "@algolia/client-common": "5.35.0", + "@algolia/client-insights": "5.35.0", + "@algolia/client-personalization": "5.35.0", + "@algolia/client-query-suggestions": "5.35.0", + "@algolia/client-search": "5.35.0", + "@algolia/ingestion": "1.35.0", + "@algolia/monitoring": "1.35.0", + "@algolia/recommend": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" }, "engines": { "node": ">= 14.0.0" @@ -4307,9 +4010,9 @@ } }, "node_modules/beasties": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", - "integrity": "sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz", + "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4320,11 +4023,10 @@ "htmlparser2": "^10.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.49", - "postcss-media-query-parser": "^0.2.3", - "postcss-safe-parser": "^7.0.1" + "postcss-media-query-parser": "^0.2.3" }, "engines": { - "node": ">=18.0.0" + "node": ">=14.0.0" } }, "node_modules/binary-extensions": { @@ -4648,47 +4350,30 @@ } }, "node_modules/cli-spinners": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", - "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.20" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, "license": "MIT", "dependencies": { - "slice-ansi": "^8.0.0", - "string-width": "^8.2.0" + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" }, "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5334,9 +5019,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5347,32 +5032,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/escalade": { @@ -6116,13 +5801,13 @@ "license": "ISC" }, "node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz", + "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==", "dev": true, "license": "ISC", "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/ip-address": { @@ -6157,6 +5842,22 @@ "node": ">=8" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6168,16 +5869,13 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6932,13 +6630,13 @@ } }, "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", + "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "dev": true, "license": "MIT", "dependencies": { - "cli-truncate": "^5.0.0", + "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", @@ -6975,15 +6673,14 @@ } }, "node_modules/lmdb": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.1.tgz", - "integrity": "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.2.tgz", + "integrity": "sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==", "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { - "@harperfast/extended-iterable": "^1.0.3", "msgpackr": "^1.11.2", "node-addon-api": "^6.1.0", "node-gyp-build-optional-packages": "5.2.2", @@ -6994,13 +6691,13 @@ "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.5.1", - "@lmdb/lmdb-darwin-x64": "3.5.1", - "@lmdb/lmdb-linux-arm": "3.5.1", - "@lmdb/lmdb-linux-arm64": "3.5.1", - "@lmdb/lmdb-linux-x64": "3.5.1", - "@lmdb/lmdb-win32-arm64": "3.5.1", - "@lmdb/lmdb-win32-x64": "3.5.1" + "@lmdb/lmdb-darwin-arm64": "3.4.2", + "@lmdb/lmdb-darwin-x64": "3.4.2", + "@lmdb/lmdb-linux-arm": "3.4.2", + "@lmdb/lmdb-linux-arm64": "3.4.2", + "@lmdb/lmdb-linux-x64": "3.4.2", + "@lmdb/lmdb-win32-arm64": "3.4.2", + "@lmdb/lmdb-win32-x64": "3.4.2" } }, "node_modules/lodash": { @@ -7011,14 +6708,14 @@ "license": "MIT" }, "node_modules/log-symbols": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", - "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", "dev": true, "license": "MIT", "dependencies": { - "is-unicode-supported": "^2.0.0", - "yoctocolors": "^2.1.1" + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" }, "engines": { "node": ">=18" @@ -7027,6 +6724,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -7047,6 +6757,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", @@ -7110,13 +6836,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/make-dir": { @@ -7158,6 +6884,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -7569,6 +7305,16 @@ "node": ">=20" } }, + "node_modules/node-gyp/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/node-gyp/node_modules/which": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", @@ -7655,16 +7401,16 @@ } }, "node_modules/npm-package-arg": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", - "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.0.tgz", + "integrity": "sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==", "dev": true, "license": "ISC", "dependencies": { "hosted-git-info": "^9.0.0", - "proc-log": "^6.0.0", + "proc-log": "^5.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^7.0.0" + "validate-npm-package-name": "^6.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -7684,6 +7430,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/npm-packlist/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/npm-pick-manifest": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", @@ -7720,6 +7476,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/npm-registry-fetch/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -7793,40 +7559,24 @@ } }, "node_modules/ora": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", - "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.6.2", - "cli-cursor": "^5.0.0", - "cli-spinners": "^3.2.0", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.1.0", - "log-symbols": "^7.0.1", - "stdin-discarder": "^0.3.1", - "string-width": "^8.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/string-width": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", "dev": true, "license": "MIT", "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=20" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7854,9 +7604,9 @@ } }, "node_modules/pacote": { - "version": "21.3.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz", - "integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==", + "version": "21.0.4", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.4.tgz", + "integrity": "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA==", "dev": true, "license": "ISC", "dependencies": { @@ -7885,6 +7635,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/pacote/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -7981,6 +7741,13 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/path-scurry": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", @@ -8039,9 +7806,9 @@ } }, "node_modules/piscina": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.4.tgz", - "integrity": "sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz", + "integrity": "sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==", "dev": true, "license": "MIT", "engines": { @@ -8097,41 +7864,14 @@ "dev": true, "license": "MIT" }, - "node_modules/postcss-safe-parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", - "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, "node_modules/proc-log": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", - "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", "dev": true, "license": "ISC", "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/promise-retry": { @@ -8275,6 +8015,27 @@ "dev": true, "license": "MIT" }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -8326,38 +8087,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rolldown": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", - "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.113.0", - "@rolldown/pluginutils": "1.0.0-rc.4" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.4", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", - "@rolldown/binding-darwin-x64": "1.0.0-rc.4", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" - } - }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -8473,9 +8202,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.97.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "version": "1.90.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", + "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8676,17 +8405,17 @@ } }, "node_modules/slice-ansi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.3", - "is-fullwidth-code-point": "^5.1.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { - "node": ">=20" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" @@ -8967,9 +8696,9 @@ } }, "node_modules/stdin-discarder": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.1.tgz", - "integrity": "sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", "dev": true, "license": "MIT", "engines": { @@ -9041,6 +8770,19 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tar": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", @@ -9069,14 +8811,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "fdir": "^6.4.4", + "picomatch": "^4.0.2" }, "engines": { "node": ">=12.0.0" @@ -9193,16 +8935,6 @@ "node": "*" } }, - "node_modules/undici": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", - "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -9297,13 +9029,13 @@ } }, "node_modules/validate-npm-package-name": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", - "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", + "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", "dev": true, "license": "ISC", "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/vary": { @@ -9316,13 +9048,13 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "7.1.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", + "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", + "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", @@ -9390,6 +9122,23 @@ } } }, + "node_modules/vite/node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -9401,9 +9150,9 @@ } }, "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "dev": true, "license": "MIT", "dependencies": { @@ -9606,19 +9355,6 @@ "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yoctocolors-cjs": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 24f50a7..e95bd7c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,13 +25,13 @@ }, "private": true, "dependencies": { - "@angular/common": "^20.3.14", - "@angular/compiler": "^20.3.16", - "@angular/core": "^21.1.2", - "@angular/forms": "^20.3.0", - "@angular/platform-browser": "^20.3.0", - "@angular/platform-server": "^20.3.0", - "@angular/router": "^20.3.0", + "@angular/common": "~20.3.16", + "@angular/compiler": "~20.3.16", + "@angular/core": "~20.3.16", + "@angular/forms": "~20.3.16", + "@angular/platform-browser": "~20.3.16", + "@angular/platform-server": "~20.3.16", + "@angular/router": "~20.3.16", "@angular/ssr": "^20.3.6", "@wailsio/runtime": "3.0.0-alpha.72", "express": "^5.1.0", @@ -40,9 +40,9 @@ "zone.js": "~0.15.0" }, "devDependencies": { - "@angular/build": "^21.1.2", - "@angular/cli": "^21.1.3", - "@angular/compiler-cli": "^20.3.0", + "@angular/build": "^20.3.6", + "@angular/cli": "^20.3.6", + "@angular/compiler-cli": "~20.3.16", "@types/express": "^5.0.1", "@types/jasmine": "~5.1.0", "@types/node": "^20.17.19", diff --git a/go.mod b/go.mod index 5809633..67a3330 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( forge.lthn.ai/core/api v0.1.0 forge.lthn.ai/core/config v0.1.0 forge.lthn.ai/core/go v0.2.2 - forge.lthn.ai/core/go-process v0.1.0 + forge.lthn.ai/core/go-process v0.1.2 forge.lthn.ai/core/go-ws v0.1.3 forge.lthn.ai/core/gui v0.0.0 forge.lthn.ai/core/mcp v0.0.0 diff --git a/go.sum b/go.sum index 011acb7..101f17f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= forge.lthn.ai/core/api v0.1.0 h1:ZKnQx+L9vxLQSEjwpsD1eNcIQrE4YKV1c2AlMtseM6o= +forge.lthn.ai/core/api v0.1.0/go.mod h1:c86Lk9AmaS0xbiRCEG/+du8s9KyYNHnp8RED35gR/Fo= forge.lthn.ai/core/config v0.1.0 h1:qj14x/dnOWcsXMBQWAT3FtA+/sy6Qd+1NFTg5Xoil1I= +forge.lthn.ai/core/config v0.1.0/go.mod h1:8HYA29drAWlX+bO4VI1JhmKUgGU66E2Xge8D3tKd3Dg= forge.lthn.ai/core/go v0.2.2 h1:JCWaFfiG+agb0f7b5DO1g+h40x6nb4UydxJ7D+oZk5k= forge.lthn.ai/core/go v0.2.2/go.mod h1:gE6c8h+PJ2287qNhVUJ5SOe1kopEwHEquvinstpuyJc= forge.lthn.ai/core/go-ai v0.1.5 h1:iOKW5Wv4Pquc5beDw0QqaKspq3pUvqXxT8IEdCT13Go= @@ -18,8 +20,11 @@ forge.lthn.ai/core/go-mlx v0.1.0 h1:nMDhMma3M9iSm2ymNyqMe+aAbJDasNnxgi/1dZ+Zq7c= forge.lthn.ai/core/go-mlx v0.1.0/go.mod h1:b4BJX67nx9QZiyREl2lmYIPJ+Yp5amZug3y7vXaRy/Y= forge.lthn.ai/core/go-process v0.1.0 h1:lRpliQuu/Omt+kAHMFoQYOb5PKEIKg8yTMchFhejpK8= forge.lthn.ai/core/go-process v0.1.0/go.mod h1:GGEDrgDLBlj55BkyyZTQpgbcEkAttJznxbUDBRxaAww= +forge.lthn.ai/core/go-process v0.1.2 h1:0fdLJq/DPssilN9E5yude/xHNfZRKHghIjo++b5aXgc= +forge.lthn.ai/core/go-process v0.1.2/go.mod h1:9oxVALrZaZCqFe8YDdheIS5bRUV1SBz4tVW/MflAtxM= forge.lthn.ai/core/go-rag v0.1.0 h1:H5umiRryuq6J6l889s0OsxWpmq5P5c3A9Bkj0cQyO7k= forge.lthn.ai/core/go-rag v0.1.0/go.mod h1:bB8Fy98G2zxVoe7k2B85gXvim6frJdbAMnDyW4peUVU= +forge.lthn.ai/core/go-scm v0.1.0/go.mod h1:QrSFTqkBS/KgFiNrVngrY8nEwS0u41BjUAu/IEpXiRI= forge.lthn.ai/core/go-webview v0.1.2 h1:KC5AlkAg1SkmeUVsW4ZeEyrNxy+cZLaHu6SPwWLBi1A= forge.lthn.ai/core/go-webview v0.1.2/go.mod h1:AcIN8cASb7N9c/G5VMmFMIXcPvf6Kk7HcbOQxfiylQ8= forge.lthn.ai/core/go-ws v0.1.3 h1:TzqFpEcDYcZUFFmrTznfEuVcVdnp2jsRNwAGHeTyXN0= @@ -144,6 +149,7 @@ github.com/gin-contrib/static v1.1.5/go.mod h1:8JSEXwZHcQ0uCrLPcsvnAJ4g+ODxeupP8 github.com/gin-contrib/timeout v1.1.0 h1:WAmWseo5gfBUbMrMJu5hJxDclehfSJUmK2wGwCC/EFw= github.com/gin-contrib/timeout v1.1.0/go.mod h1:NpRo4gd1Ad8ZQ4T6bQLVFDqiplCmPRs2nvfckxS2Fw4= github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= +github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -396,6 +402,7 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= +go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.65.0 h1:LSJsvNqhj2sBNFb5NWHbyDK4QJ/skQ2ydjeOZ9OYNZ4= @@ -441,6 +448,7 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -486,6 +494,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=