diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index 91a9c5aa..00000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1,2 +0,0 @@ -8dc8fb393740bdeff43773eab9a898b81016a8ab -dbf303713f26a59fa5b8f60c86f181a9895d7c1c diff --git a/.gitignore b/.gitignore index 04aa6706..1ad5c4be 100644 --- a/.gitignore +++ b/.gitignore @@ -87,7 +87,7 @@ dsa_pub.pem # Public key (safe to commit if needed) codesign* *.bak *.backup - +*.provisionprofile # Release artifacts (keep in build/ folder) # Uncomment these if you want to commit release artifacts: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e5846f5..ff1a50a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ Please be respectful to maintainers and disclose AI assistance. 2. Run the setup script to install tools, configure git hooks, and generate the Xcode project: ```bash - ./setup.sh + ./scripts/setup.sh ``` 3. Open in Xcode and build: @@ -42,7 +42,7 @@ Please be respectful to maintainers and disclose AI assistance. ### Formatting & Linting -Code formatting and linting are automatically enforced via git hooks (installed by `./setup.sh`): +Code formatting and linting are automatically enforced via git hooks (installed by `./scripts/setup.sh`): - **SwiftFormat**: Handles code formatting - **SwiftLint**: Enforces coding standards @@ -176,7 +176,7 @@ Ora uses [Sparkle](https://sparkle-project.org/) for automatic updates. All buil ```bash brew install --cask sparkle ./setup-sparkle-tools.sh - ./setup-sparkle.sh + ./scripts/setup-sparkle.sh ``` This generates DSA keys in `build/` directory. @@ -187,7 +187,7 @@ Ora uses [Sparkle](https://sparkle-project.org/) for automatic updates. All buil 4. **Create a release:** ```bash - ./create-release.sh 0.0.2 build/dsa_priv.pem + ./scripts/create-release.sh 0.0.2 build/dsa_priv.pem ``` This builds, signs, and prepares release files in `build/`. diff --git a/README.md b/README.md index ee5b64af..e1c327d4 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ See the [Wiki](https://github.com/the-ora/browser/wiki) for comprehensive docume ```bash git clone https://github.com/the-ora/browser.git cd browser - ./setup.sh + ./scripts/setup.sh ``` 2. Open and build: diff --git a/SECURITY.md b/SECURITY.md index 1f117714..61a6f722 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -19,7 +19,7 @@ Ora Browser uses Ed25519 cryptographic keys to sign and verify app updates for s ### Setup Process 1. **First machine**: Keys auto-generated and saved appropriately 2. **Additional machines**: Copy `.env` file from first machine -3. **Release process**: `./create-release.sh` handles key management automatically +3. **Release process**: `./scripts/create-release.sh` handles key management automatically ### Security Notes - `.env` is in `.gitignore` - it will never be committed @@ -29,7 +29,7 @@ Ora Browser uses Ed25519 cryptographic keys to sign and verify app updates for s ## 🔍 Security Checks -Run `./check-security.sh` to verify: +Run `./scripts/check-security.sh` to verify: - Private key exists but is not tracked by git - Public key is available for app integration - `.gitignore` properly excludes sensitive files diff --git a/docs/HOSTING_SETUP.md b/docs/HOSTING_SETUP.md deleted file mode 100644 index 3818cc0c..00000000 --- a/docs/HOSTING_SETUP.md +++ /dev/null @@ -1,286 +0,0 @@ -# Ora Browser Hosting Setup Guide - -This guide explains how to set up hosting for Ora Browser's automatic update system using Sparkle. - -## Overview - -Ora Browser uses [Sparkle](https://sparkle-project.org/) for automatic updates. The system requires: - -1. **Appcast Feed** (`appcast.xml`) - Tells Sparkle about available updates -2. **App Distribution** (`Ora-Browser.dmg`) - The actual app download -3. **Digital Signatures** - Ensures update integrity and security - -## What Needs to Be Hosted - -### 1. Appcast XML File -**File:** `appcast.xml` -**Purpose:** Update feed that Sparkle reads to check for new versions -**Content:** Release information, download URLs, version numbers, and digital signatures - -### 2. App DMG File -**File:** `Ora-Browser.dmg` -**Purpose:** The actual application installer that users download -**Content:** Signed and notarized macOS application bundle - -## Hosting Options - -### Option A: GitHub Pages (Recommended) - -#### Step 1: Create GitHub Pages Branch -```bash -# Create and switch to gh-pages branch -git checkout -b gh-pages - -# Remove all files except what we need for hosting -git rm -rf . -git reset -- docs/ # Keep docs if you want - -# Copy appcast.xml -cp ../appcast.xml . - -# Commit and push -git add appcast.xml -git commit -m "Add appcast.xml for Sparkle updates" -git push origin gh-pages -``` - -#### Step 2: Enable GitHub Pages -1. Go to your GitHub repository -2. Navigate to **Settings** → **Pages** -3. Set **Source** to "Deploy from a branch" -4. Set **Branch** to `gh-pages` and folder to `/ (root)` -5. Click **Save** - -#### Step 3: Get Your URLs -- **Appcast URL:** `https://the-ora.github.io/browser/appcast.xml` -- **DMG URL:** `https://github.com/the-ora/browser/releases/download/v0.0.1/Ora-Browser.dmg` - -### Option B: Your Own Web Server - -#### Requirements -- Public web server with HTTPS -- Ability to upload files -- CORS headers configured (if needed) - -#### Setup Steps -1. Upload `appcast.xml` to your web server -2. Ensure it's accessible via HTTPS -3. Update the enclosure URL in `appcast.xml` to point to your DMG location - -#### Example URLs -- **Appcast URL:** `https://updates.yourdomain.com/appcast.xml` -- **DMG URL:** `https://downloads.yourdomain.com/Ora-Browser.dmg` - -### Option C: GitHub Releases Only - -#### Setup Steps -1. Upload both `appcast.xml` and `Ora-Browser.dmg` to GitHub Releases -2. Use raw GitHub URLs for both files - -#### URLs -- **Appcast URL:** `https://raw.githubusercontent.com/the-ora/browser/main/appcast.xml` -- **DMG URL:** `https://github.com/the-ora/browser/releases/download/v0.0.1/Ora-Browser.dmg` - -## Digital Signature Setup - -### Generate DSA Keys -```bash -# Install Sparkle -brew install --cask sparkle - -# Setup command-line tools -./setup-sparkle-tools.sh - -# Generate keys (run once) -./setup-sparkle.sh - -# This creates in build/: -# - build/dsa_priv.pem (private key - keep secure!) -# - build/dsa_pub.pem (public key - safe to share) -``` - -### Sign Your Release -```bash -# Sign the DMG with your private key -sign_update -f Ora-Browser.dmg -k dsa_priv.pem - -# Copy the signature output -``` - -### Update Appcast with Real Signature -Replace the placeholder in `appcast.xml`: -```xml - -sparkle:dsaSignature="PLACEHOLDER_SIGNATURE_REPLACE_WITH_ACTUAL_SIGNATURE" - - -``` - -## App Configuration - -### Update Info.plist -Add these keys to your `Info.plist` or `project.yml`: - -```xml -SUFeedURL -https://the-ora.github.io/browser/appcast.xml - -SUPublicEDKey -YOUR_PUBLIC_KEY_HERE -``` - -### XcodeGen Configuration -If using XcodeGen, update `project.yml`: -```yaml -settings: - base: - SUFeedURL: https://the-ora.github.io/browser/appcast.xml - SUPublicEDKey: YOUR_PUBLIC_KEY_HERE -``` - -## Release Process - -### Step 1: Build Release -```bash -# Build and package the app -./build-release.sh - -# Or use the comprehensive release script (auto-increments version) -./create-release.sh -``` - -### Step 2: Sign Release -```bash -# Sign with Sparkle -sign_update -f Ora-Browser.dmg -k dsa_priv.pem -``` - -### Step 3: Update Appcast -```bash -# Update version numbers, dates, and signature in appcast.xml -# Update enclosure URL to point to your hosted DMG -``` - -### Step 4: Host Files -1. Upload `appcast.xml` to your chosen hosting location -2. Upload `Ora-Browser.dmg` to GitHub Releases -3. Update your app's `SUFeedURL` if needed - -### Step 5: Test Updates -1. Build and run your app -2. Go to Settings → General → Updates -3. Click "Check for Updates" -4. Verify the update notification appears - -## File Structure - -``` -your-project/ -├── build/ # Build artifacts directory -│ ├── appcast.xml # Update feed (public) -│ ├── Ora-Browser.dmg # App installer -│ ├── dsa_priv.pem # Private key (keep secure!) -│ └── dsa_pub.pem # Public key -└── docs/ # Documentation - ├── HOSTING_SETUP.md # This guide - └── QUICK_START.md # Quick setup guide -``` - -## Security Considerations - -### Private Key Security -- **Never commit `dsa_priv.pem`** to version control -- Store securely (password manager, secure server) -- Use different keys for different environments if needed - -### HTTPS Requirement -- Always host `appcast.xml` over HTTPS -- GitHub Pages automatically provides HTTPS -- Custom servers must have valid SSL certificates - -### Signature Verification -- Sparkle automatically verifies signatures -- Users cannot install updates without valid signatures -- Invalid signatures will be rejected by macOS Gatekeeper - -## Troubleshooting - -### Update Not Detected -1. Check `SUFeedURL` in Info.plist is correct -2. Verify `appcast.xml` is accessible via browser -3. Check signature is valid (not placeholder) -4. Verify version numbers are incrementing - -### Download Fails -1. Check DMG URL in `appcast.xml` is correct -2. Verify DMG is publicly accessible -3. Check file permissions on hosting server -4. Ensure DMG is properly signed and notarized - -### Signature Invalid -1. Verify you're using the correct private key -2. Check the signature was copied correctly -3. Ensure no extra whitespace in signature -4. Test with a fresh signature generation - -## Maintenance - -### Regular Updates -1. Build new release with incremented version -2. Sign with private key -3. Update `appcast.xml` with new version info -4. Upload new DMG to releases -5. Update appcast on hosting server - -### Version Numbering -- Use semantic versioning (e.g., 1.0.0, 1.0.1, 1.1.0) -- Update both `CFBundleShortVersionString` and `CFBundleVersion` -- Ensure version numbers increment for each release - -## Support - -For issues with: -- **Sparkle framework:** https://sparkle-project.org/documentation/ -- **GitHub Pages:** https://docs.github.com/en/pages -- **App signing:** https://developer.apple.com/support/code-signing/ - -## Example Appcast - -```xml - - - - Ora Browser Changelog - Most recent changes with links to updates. - en - - Ora Browser 0.0.1 - - Initial Release -

Ora Browser is a fast, secure, and beautiful browser built for macOS.

-
    -
  • Native macOS UI built with SwiftUI
  • -
  • Fast browsing powered by WebKit
  • -
  • Privacy-first with built-in content blocker
  • -
- ]]> -
- Thu, 04 Sep 2025 14:51:08 +0000 - -
-
-
-``` - ---- - -**Last Updated:** September 4, 2025 -**Ora Browser Version:** 0.0.1 - -/Users/keni/code/ora/browser/docs/HOSTING_SETUP.md \ No newline at end of file diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md deleted file mode 100644 index 7055b6f9..00000000 --- a/docs/QUICK_START.md +++ /dev/null @@ -1,92 +0,0 @@ -# Ora Browser Quick Start - Hosting Setup - -## 🚀 Quick Setup (5 minutes) - -**Note:** The release script now auto-increments version numbers. Just run `./create-release.sh` without arguments for patch releases. - -### 1. Setup Sparkle Tools -```bash -brew install --cask sparkle -./setup-sparkle-tools.sh -./setup-sparkle.sh -``` - -### 2. Build & Sign Release -```bash -# Auto-increment version (recommended) -./create-release.sh - -# Or specify version manually -./create-release.sh 0.0.1 -``` - -### 3. Host Files - -#### Option A: GitHub Pages (Easiest) -```bash -# Create gh-pages branch -git checkout -b gh-pages -git rm -rf . -cp ../appcast.xml . -git add appcast.xml -git commit -m "Add appcast for updates" -git push origin gh-pages - -# Enable in GitHub: Settings → Pages → Source: gh-pages -``` - -#### Option B: GitHub Releases -- Upload `Ora-Browser.dmg` to GitHub Releases -- Upload `appcast.xml` to any web host - -### 4. Update App Config -Edit `project.yml`: -```yaml -settings: - base: - SUFeedURL: https://the-ora.github.io/browser/appcast.xml - SUPublicEDKey: YOUR_PUBLIC_KEY_HERE -``` - -### 5. Test -```bash -xcodegen -# Build and run app -# Go to Settings → General → Check for Updates -``` - -## 📋 What Gets Hosted Where - -| File | Location | Purpose | -|------|----------|---------| -| `build/appcast.xml` | Public web server | Update feed for Sparkle | -| `build/Ora-Browser.dmg` | GitHub Releases | App installer download | -| `build/dsa_pub.pem` | App bundle | Public key for verification | - -## 🔗 URLs You'll Need - -- **Appcast:** `https://the-ora.github.io/browser/appcast.xml` -- **DMG:** `https://github.com/the-ora/browser/releases/download/v{VERSION}/Ora-Browser.dmg` -- **Public Key:** Copy from `dsa_pub.pem` - -## ✅ Checklist - -- [ ] DSA keys generated (`dsa_priv.pem`, `dsa_pub.pem`) -- [ ] Release built and signed (`Ora-Browser.dmg`) -- [ ] Appcast updated with real signature -- [ ] Appcast hosted at public URL -- [ ] DMG uploaded to GitHub Releases -- [ ] `SUFeedURL` updated in app -- [ ] `SUPublicEDKey` added to app -- [ ] Xcode project regenerated - -## 🆘 Need Help? - -- **Keys not working:** Run `./setup-sparkle.sh` again -- **Signature invalid:** Use `sign_update` command output exactly -- **Update not found:** Check `SUFeedURL` in Info.plist -- **DMG won't download:** Verify GitHub release is public - -See `docs/HOSTING_SETUP.md` for detailed instructions. - -/Users/keni/code/ora/browser/docs/QUICK_START.md \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 15448643..00000000 --- a/docs/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Ora Browser Documentation - -This directory contains documentation for Ora Browser development, deployment, and maintenance. - -## 📚 Documentation Index - -### 🚀 Getting Started -- **[QUICK_START.md](QUICK_START.md)** - 5-minute setup guide for hosting and updates -- **[../README.md](../README.md)** - Main project README with installation instructions - -### 📦 Hosting & Deployment -- **[HOSTING_SETUP.md](HOSTING_SETUP.md)** - Complete guide for setting up update hosting -- **[../.github/workflows/release.yml](../.github/workflows/release.yml)** - GitHub Actions for automated releases - -### 🔧 Development -- **[../ora/Services/UpdateService.swift](../ora/Services/UpdateService.swift)** - Update service implementation -- **[../ora/Modules/Settings/Sections/GeneralSettingsView.swift](../ora/Modules/Settings/Sections/GeneralSettingsView.swift)** - Settings UI with update controls -- **[../project.yml](../project.yml)** - XcodeGen project configuration - -### 🏗️ Build & Release -- **[../build-release.sh](../build-release.sh)** - Release build script -- **[../create-release.sh](../create-release.sh)** - Complete release creation script (auto-increments versions) -- **[../setup-sparkle.sh](../setup-sparkle.sh)** - Sparkle key generation setup - -## 🎯 Key Files for Updates - -### Configuration Files -- `appcast.xml` - Update feed (host publicly) -- `dsa_priv.pem` - Private key (keep secure!) -- `dsa_pub.pem` - Public key (add to app) - -### App Files -- `Ora-Browser.dmg` - Release installer (upload to GitHub Releases) -- `ora/Services/UpdateService.swift` - Update checking logic -- `ora/Modules/Settings/Sections/GeneralSettingsView.swift` - Update UI - -## 🔄 Update Flow - -1. **Build:** `./create-release.sh` (auto-increments version) or `./create-release.sh 1.0.0` (manual version) -2. **Sign:** Use `dsa_priv.pem` to sign DMG -3. **Host:** Upload `appcast.xml` to public web server -4. **Release:** Upload DMG to GitHub Releases -5. **Configure:** Update `SUFeedURL` in app -6. **Test:** Users get automatic update notifications - -## 📞 Support - -- **Sparkle Documentation:** https://sparkle-project.org/documentation/ -- **GitHub Pages:** https://docs.github.com/en/pages -- **Code Signing:** https://developer.apple.com/support/code-signing/ - -## 📝 Contributing - -When updating documentation: -1. Keep `QUICK_START.md` for 5-minute setup -2. Use `HOSTING_SETUP.md` for detailed procedures -3. Update this README when adding new docs - ---- - -**Ora Browser** | *Fast, secure, and beautiful browser for macOS* - -/Users/keni/code/ora/browser/docs/README.md \ No newline at end of file diff --git a/mark.js b/mark.js deleted file mode 100644 index 1eea0533..00000000 --- a/mark.js +++ /dev/null @@ -1,7 +0,0 @@ -/*!*************************************************** -* mark.js v8.11.1 -* https://markjs.io/ -* Copyright (c) 2014–2018, Julian Kühnel -* Released under the MIT license https://git.io/vwTVl -*****************************************************/ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t=e.getAttribute("src").trim();return"about:blank"===e.contentWindow.location.href&&"about:blank"!==t&&t}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function o(e){t(this,o),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(o,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(a)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];)if(n(i[a],t)){var s=i.index;if(0!==a)for(var c=1;c/dev/null || echo "build-release.sh not found in current directory" + ls -la scripts/build-release.sh 2>/dev/null || echo "scripts/build-release.sh not found in current directory" exit 1 fi @@ -529,9 +529,9 @@ deploy_to_github_pages() { # Upload DMG to GitHub releases echo "📤 Uploading DMG to GitHub releases..." -if [ -f "upload-dmg.sh" ]; then - chmod +x upload-dmg.sh - ./upload-dmg.sh "$VERSION" "$DMG_FILE" +if [ -f "scripts/upload-dmg.sh" ]; then + chmod +x scripts/upload-dmg.sh + ./scripts/upload-dmg.sh "$VERSION" "$DMG_FILE" else echo "⚠️ upload-dmg.sh not found, skipping automatic upload" fi diff --git a/setup-sparkle.sh b/scripts/setup-sparkle.sh similarity index 100% rename from setup-sparkle.sh rename to scripts/setup-sparkle.sh diff --git a/setup.sh b/scripts/setup.sh similarity index 100% rename from setup.sh rename to scripts/setup.sh diff --git a/upload-dmg.sh b/scripts/upload-dmg.sh similarity index 100% rename from upload-dmg.sh rename to scripts/upload-dmg.sh diff --git a/xcbuild-debug.sh b/scripts/xcbuild-debug.sh similarity index 100% rename from xcbuild-debug.sh rename to scripts/xcbuild-debug.sh